r81866 MediaWiki - Code Review archive

Repository:MediaWiki
Revision:r81865‎ | r81866 | r81867 >
Date:02:16, 10 February 2011
Author:tparscal
Status:deferred
Tags:
Comment:
* Started adding table functionality for viewing surveys
* Removed datatables plugin
Modified paths:
  • /trunk/extensions/ResearchTools/SpecialResearchTools.php (modified) (history)
  • /trunk/extensions/ResearchTools/modules/ext.researchTools/ext.researchTools.js (modified) (history)
  • /trunk/extensions/ResearchTools/modules/jquery.dataTables.js (deleted) (history)
  • /trunk/extensions/ResearchTools/pages/ResearchToolsSurveysPage.php (modified) (history)

Diff [purge]

Index: trunk/extensions/ResearchTools/pages/ResearchToolsSurveysPage.php
@@ -4,7 +4,13 @@
55
66 public function main( array $steps ) {
77 ?>
8 - Hello surveys!
 8+ <table id="researchTools-surveyList">
 9+ <thead>
 10+ <th>Survey</th>
 11+ <th>Description</th>
 12+ </thead>
 13+ <tbody></tbody>
 14+ </table>
915 <?php
1016 }
1117 }
Index: trunk/extensions/ResearchTools/SpecialResearchTools.php
@@ -22,7 +22,7 @@
2323 public function execute( $par ) {
2424 global $wgUser, $wgOut, $wgRequest;
2525
26 - $wgOut->addModules( 'ext.researchTools' );
 26+ $wgOut->addModules( array( 'ext.researchTools' ) );
2727
2828 $this->setHeaders();
2929
Index: trunk/extensions/ResearchTools/modules/jquery.dataTables.js
@@ -1,6848 +0,0 @@
2 -/*
3 - * File: jquery.dataTables.js
4 - * Version: 1.7.5
5 - * Description: Paginate, search and sort HTML tables
6 - * Author: Allan Jardine (www.sprymedia.co.uk)
7 - * Created: 28/3/2008
8 - * Language: Javascript
9 - * License: GPL v2 or BSD 3 point style
10 - * Project: Mtaala
11 - * Contact: allan.jardine@sprymedia.co.uk
12 - *
13 - * Copyright 2008-2010 Allan Jardine, all rights reserved.
14 - *
15 - * This source file is free software, under either the GPL v2 license or a
16 - * BSD style license, as supplied with this software.
17 - *
18 - * This source file is distributed in the hope that it will be useful, but
19 - * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
20 - * or FITNESS FOR A PARTICULAR PURPOSE. See the license files for details.
21 - *
22 - * For details please refer to: http://www.datatables.net
23 - */
24 -
25 -/*
26 - * When considering jsLint, we need to allow eval() as it it is used for reading cookies and
27 - * building the dynamic multi-column sort functions.
28 - */
29 -/*jslint evil: true, undef: true, browser: true */
30 -/*globals $, jQuery,_fnExternApiFunc,_fnInitalise,_fnInitComplete,_fnLanguageProcess,_fnAddColumn,_fnColumnOptions,_fnAddData,_fnGatherData,_fnDrawHead,_fnDraw,_fnReDraw,_fnAjaxUpdate,_fnAjaxUpdateDraw,_fnAddOptionsHtml,_fnFeatureHtmlTable,_fnScrollDraw,_fnAjustColumnSizing,_fnFeatureHtmlFilter,_fnFilterComplete,_fnFilterCustom,_fnFilterColumn,_fnFilter,_fnBuildSearchArray,_fnBuildSearchRow,_fnFilterCreateSearch,_fnDataToSearch,_fnSort,_fnSortAttachListener,_fnSortingClasses,_fnFeatureHtmlPaginate,_fnPageChange,_fnFeatureHtmlInfo,_fnUpdateInfo,_fnFeatureHtmlLength,_fnFeatureHtmlProcessing,_fnProcessingDisplay,_fnVisibleToColumnIndex,_fnColumnIndexToVisible,_fnNodeToDataIndex,_fnVisbleColumns,_fnCalculateEnd,_fnConvertToWidth,_fnCalculateColumnWidths,_fnScrollingWidthAdjust,_fnGetWidestNode,_fnGetMaxLenString,_fnStringToCss,_fnArrayCmp,_fnDetectType,_fnSettingsFromNode,_fnGetDataMaster,_fnGetTrNodes,_fnGetTdNodes,_fnEscapeRegex,_fnDeleteIndex,_fnReOrderIndex,_fnColumnOrdering,_fnLog,_fnClearTable,_fnSaveState,_fnLoadState,_fnCreateCookie,_fnReadCookie,_fnGetUniqueThs,_fnScrollBarWidth,_fnApplyToChildren,_fnMap*/
31 -
32 -(function($, window, document) {
33 - /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
34 - * Section - DataTables variables
35 - * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
36 -
37 - /*
38 - * Variable: dataTableSettings
39 - * Purpose: Store the settings for each dataTables instance
40 - * Scope: jQuery.fn
41 - */
42 - $.fn.dataTableSettings = [];
43 - var _aoSettings = $.fn.dataTableSettings; /* Short reference for fast internal lookup */
44 -
45 - /*
46 - * Variable: dataTableExt
47 - * Purpose: Container for customisable parts of DataTables
48 - * Scope: jQuery.fn
49 - */
50 - $.fn.dataTableExt = {};
51 - var _oExt = $.fn.dataTableExt;
52 -
53 -
54 - /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
55 - * Section - DataTables extensible objects
56 - *
57 - * The _oExt object is used to provide an area where user dfined plugins can be
58 - * added to DataTables. The following properties of the object are used:
59 - * oApi - Plug-in API functions
60 - * aTypes - Auto-detection of types
61 - * oSort - Sorting functions used by DataTables (based on the type)
62 - * oPagination - Pagination functions for different input styles
63 - * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
64 -
65 - /*
66 - * Variable: sVersion
67 - * Purpose: Version string for plug-ins to check compatibility
68 - * Scope: jQuery.fn.dataTableExt
69 - * Notes: Allowed format is a.b.c.d.e where:
70 - * a:int, b:int, c:int, d:string(dev|beta), e:int. d and e are optional
71 - */
72 - _oExt.sVersion = "1.7.5";
73 -
74 - /*
75 - * Variable: sErrMode
76 - * Purpose: How should DataTables report an error. Can take the value 'alert' or 'throw'
77 - * Scope: jQuery.fn.dataTableExt
78 - */
79 - _oExt.sErrMode = "alert";
80 -
81 - /*
82 - * Variable: iApiIndex
83 - * Purpose: Index for what 'this' index API functions should use
84 - * Scope: jQuery.fn.dataTableExt
85 - */
86 - _oExt.iApiIndex = 0;
87 -
88 - /*
89 - * Variable: oApi
90 - * Purpose: Container for plugin API functions
91 - * Scope: jQuery.fn.dataTableExt
92 - */
93 - _oExt.oApi = { };
94 -
95 - /*
96 - * Variable: aFiltering
97 - * Purpose: Container for plugin filtering functions
98 - * Scope: jQuery.fn.dataTableExt
99 - */
100 - _oExt.afnFiltering = [ ];
101 -
102 - /*
103 - * Variable: aoFeatures
104 - * Purpose: Container for plugin function functions
105 - * Scope: jQuery.fn.dataTableExt
106 - * Notes: Array of objects with the following parameters:
107 - * fnInit: Function for initialisation of Feature. Takes oSettings and returns node
108 - * cFeature: Character that will be matched in sDom - case sensitive
109 - * sFeature: Feature name - just for completeness :-)
110 - */
111 - _oExt.aoFeatures = [ ];
112 -
113 - /*
114 - * Variable: ofnSearch
115 - * Purpose: Container for custom filtering functions
116 - * Scope: jQuery.fn.dataTableExt
117 - * Notes: This is an object (the name should match the type) for custom filtering function,
118 - * which can be used for live DOM checking or formatted text filtering
119 - */
120 - _oExt.ofnSearch = { };
121 -
122 - /*
123 - * Variable: afnSortData
124 - * Purpose: Container for custom sorting data source functions
125 - * Scope: jQuery.fn.dataTableExt
126 - * Notes: Array (associative) of functions which is run prior to a column of this
127 - * 'SortDataType' being sorted upon.
128 - * Function input parameters:
129 - * object:oSettings- DataTables settings object
130 - * int:iColumn - Target column number
131 - * Return value: Array of data which exactly matched the full data set size for the column to
132 - * be sorted upon
133 - */
134 - _oExt.afnSortData = [ ];
135 -
136 - /*
137 - * Variable: oStdClasses
138 - * Purpose: Storage for the various classes that DataTables uses
139 - * Scope: jQuery.fn.dataTableExt
140 - */
141 - _oExt.oStdClasses = {
142 - /* Two buttons buttons */
143 - "sPagePrevEnabled": "paginate_enabled_previous",
144 - "sPagePrevDisabled": "paginate_disabled_previous",
145 - "sPageNextEnabled": "paginate_enabled_next",
146 - "sPageNextDisabled": "paginate_disabled_next",
147 - "sPageJUINext": "",
148 - "sPageJUIPrev": "",
149 -
150 - /* Full numbers paging buttons */
151 - "sPageButton": "paginate_button",
152 - "sPageButtonActive": "paginate_active",
153 - "sPageButtonStaticDisabled": "paginate_button",
154 - "sPageFirst": "first",
155 - "sPagePrevious": "previous",
156 - "sPageNext": "next",
157 - "sPageLast": "last",
158 -
159 - /* Stripping classes */
160 - "sStripOdd": "odd",
161 - "sStripEven": "even",
162 -
163 - /* Empty row */
164 - "sRowEmpty": "dataTables_empty",
165 -
166 - /* Features */
167 - "sWrapper": "dataTables_wrapper",
168 - "sFilter": "dataTables_filter",
169 - "sInfo": "dataTables_info",
170 - "sPaging": "dataTables_paginate paging_", /* Note that the type is postfixed */
171 - "sLength": "dataTables_length",
172 - "sProcessing": "dataTables_processing",
173 -
174 - /* Sorting */
175 - "sSortAsc": "sorting_asc",
176 - "sSortDesc": "sorting_desc",
177 - "sSortable": "sorting", /* Sortable in both directions */
178 - "sSortableAsc": "sorting_asc_disabled",
179 - "sSortableDesc": "sorting_desc_disabled",
180 - "sSortableNone": "sorting_disabled",
181 - "sSortColumn": "sorting_", /* Note that an int is postfixed for the sorting order */
182 - "sSortJUIAsc": "",
183 - "sSortJUIDesc": "",
184 - "sSortJUI": "",
185 - "sSortJUIAscAllowed": "",
186 - "sSortJUIDescAllowed": "",
187 - "sSortJUIWrapper": "",
188 -
189 - /* Scrolling */
190 - "sScrollWrapper": "dataTables_scroll",
191 - "sScrollHead": "dataTables_scrollHead",
192 - "sScrollHeadInner": "dataTables_scrollHeadInner",
193 - "sScrollBody": "dataTables_scrollBody",
194 - "sScrollFoot": "dataTables_scrollFoot",
195 - "sScrollFootInner": "dataTables_scrollFootInner",
196 -
197 - /* Misc */
198 - "sFooterTH": ""
199 - };
200 -
201 - /*
202 - * Variable: oJUIClasses
203 - * Purpose: Storage for the various classes that DataTables uses - jQuery UI suitable
204 - * Scope: jQuery.fn.dataTableExt
205 - */
206 - _oExt.oJUIClasses = {
207 - /* Two buttons buttons */
208 - "sPagePrevEnabled": "fg-button ui-button ui-state-default ui-corner-left",
209 - "sPagePrevDisabled": "fg-button ui-button ui-state-default ui-corner-left ui-state-disabled",
210 - "sPageNextEnabled": "fg-button ui-button ui-state-default ui-corner-right",
211 - "sPageNextDisabled": "fg-button ui-button ui-state-default ui-corner-right ui-state-disabled",
212 - "sPageJUINext": "ui-icon ui-icon-circle-arrow-e",
213 - "sPageJUIPrev": "ui-icon ui-icon-circle-arrow-w",
214 -
215 - /* Full numbers paging buttons */
216 - "sPageButton": "fg-button ui-button ui-state-default",
217 - "sPageButtonActive": "fg-button ui-button ui-state-default ui-state-disabled",
218 - "sPageButtonStaticDisabled": "fg-button ui-button ui-state-default ui-state-disabled",
219 - "sPageFirst": "first ui-corner-tl ui-corner-bl",
220 - "sPagePrevious": "previous",
221 - "sPageNext": "next",
222 - "sPageLast": "last ui-corner-tr ui-corner-br",
223 -
224 - /* Stripping classes */
225 - "sStripOdd": "odd",
226 - "sStripEven": "even",
227 -
228 - /* Empty row */
229 - "sRowEmpty": "dataTables_empty",
230 -
231 - /* Features */
232 - "sWrapper": "dataTables_wrapper",
233 - "sFilter": "dataTables_filter",
234 - "sInfo": "dataTables_info",
235 - "sPaging": "dataTables_paginate fg-buttonset ui-buttonset fg-buttonset-multi "+
236 - "ui-buttonset-multi paging_", /* Note that the type is postfixed */
237 - "sLength": "dataTables_length",
238 - "sProcessing": "dataTables_processing",
239 -
240 - /* Sorting */
241 - "sSortAsc": "ui-state-default",
242 - "sSortDesc": "ui-state-default",
243 - "sSortable": "ui-state-default",
244 - "sSortableAsc": "ui-state-default",
245 - "sSortableDesc": "ui-state-default",
246 - "sSortableNone": "ui-state-default",
247 - "sSortColumn": "sorting_", /* Note that an int is postfixed for the sorting order */
248 - "sSortJUIAsc": "css_right ui-icon ui-icon-triangle-1-n",
249 - "sSortJUIDesc": "css_right ui-icon ui-icon-triangle-1-s",
250 - "sSortJUI": "css_right ui-icon ui-icon-carat-2-n-s",
251 - "sSortJUIAscAllowed": "css_right ui-icon ui-icon-carat-1-n",
252 - "sSortJUIDescAllowed": "css_right ui-icon ui-icon-carat-1-s",
253 - "sSortJUIWrapper": "DataTables_sort_wrapper",
254 -
255 - /* Scrolling */
256 - "sScrollWrapper": "dataTables_scroll",
257 - "sScrollHead": "dataTables_scrollHead ui-state-default",
258 - "sScrollHeadInner": "dataTables_scrollHeadInner",
259 - "sScrollBody": "dataTables_scrollBody",
260 - "sScrollFoot": "dataTables_scrollFoot ui-state-default",
261 - "sScrollFootInner": "dataTables_scrollFootInner",
262 -
263 - /* Misc */
264 - "sFooterTH": "ui-state-default"
265 - };
266 -
267 - /*
268 - * Variable: oPagination
269 - * Purpose: Container for the various type of pagination that dataTables supports
270 - * Scope: jQuery.fn.dataTableExt
271 - */
272 - _oExt.oPagination = {
273 - /*
274 - * Variable: two_button
275 - * Purpose: Standard two button (forward/back) pagination
276 - * Scope: jQuery.fn.dataTableExt.oPagination
277 - */
278 - "two_button": {
279 - /*
280 - * Function: oPagination.two_button.fnInit
281 - * Purpose: Initalise dom elements required for pagination with forward/back buttons only
282 - * Returns: -
283 - * Inputs: object:oSettings - dataTables settings object
284 - * node:nPaging - the DIV which contains this pagination control
285 - * function:fnCallbackDraw - draw function which must be called on update
286 - */
287 - "fnInit": function ( oSettings, nPaging, fnCallbackDraw )
288 - {
289 - var nPrevious, nNext, nPreviousInner, nNextInner;
290 -
291 - /* Store the next and previous elements in the oSettings object as they can be very
292 - * usful for automation - particularly testing
293 - */
294 - if ( !oSettings.bJUI )
295 - {
296 - nPrevious = document.createElement( 'div' );
297 - nNext = document.createElement( 'div' );
298 - }
299 - else
300 - {
301 - nPrevious = document.createElement( 'a' );
302 - nNext = document.createElement( 'a' );
303 -
304 - nNextInner = document.createElement('span');
305 - nNextInner.className = oSettings.oClasses.sPageJUINext;
306 - nNext.appendChild( nNextInner );
307 -
308 - nPreviousInner = document.createElement('span');
309 - nPreviousInner.className = oSettings.oClasses.sPageJUIPrev;
310 - nPrevious.appendChild( nPreviousInner );
311 - }
312 -
313 - nPrevious.className = oSettings.oClasses.sPagePrevDisabled;
314 - nNext.className = oSettings.oClasses.sPageNextDisabled;
315 -
316 - nPrevious.title = oSettings.oLanguage.oPaginate.sPrevious;
317 - nNext.title = oSettings.oLanguage.oPaginate.sNext;
318 -
319 - nPaging.appendChild( nPrevious );
320 - nPaging.appendChild( nNext );
321 -
322 - $(nPrevious).click( function() {
323 - if ( oSettings.oApi._fnPageChange( oSettings, "previous" ) )
324 - {
325 - /* Only draw when the page has actually changed */
326 - fnCallbackDraw( oSettings );
327 - }
328 - } );
329 -
330 - $(nNext).click( function() {
331 - if ( oSettings.oApi._fnPageChange( oSettings, "next" ) )
332 - {
333 - fnCallbackDraw( oSettings );
334 - }
335 - } );
336 -
337 - /* Take the brutal approach to cancelling text selection */
338 - $(nPrevious).bind( 'selectstart', function () { return false; } );
339 - $(nNext).bind( 'selectstart', function () { return false; } );
340 -
341 - /* ID the first elements only */
342 - if ( oSettings.sTableId !== '' && typeof oSettings.aanFeatures.p == "undefined" )
343 - {
344 - nPaging.setAttribute( 'id', oSettings.sTableId+'_paginate' );
345 - nPrevious.setAttribute( 'id', oSettings.sTableId+'_previous' );
346 - nNext.setAttribute( 'id', oSettings.sTableId+'_next' );
347 - }
348 - },
349 -
350 - /*
351 - * Function: oPagination.two_button.fnUpdate
352 - * Purpose: Update the two button pagination at the end of the draw
353 - * Returns: -
354 - * Inputs: object:oSettings - dataTables settings object
355 - * function:fnCallbackDraw - draw function to call on page change
356 - */
357 - "fnUpdate": function ( oSettings, fnCallbackDraw )
358 - {
359 - if ( !oSettings.aanFeatures.p )
360 - {
361 - return;
362 - }
363 -
364 - /* Loop over each instance of the pager */
365 - var an = oSettings.aanFeatures.p;
366 - for ( var i=0, iLen=an.length ; i<iLen ; i++ )
367 - {
368 - if ( an[i].childNodes.length !== 0 )
369 - {
370 - an[i].childNodes[0].className =
371 - ( oSettings._iDisplayStart === 0 ) ?
372 - oSettings.oClasses.sPagePrevDisabled : oSettings.oClasses.sPagePrevEnabled;
373 -
374 - an[i].childNodes[1].className =
375 - ( oSettings.fnDisplayEnd() == oSettings.fnRecordsDisplay() ) ?
376 - oSettings.oClasses.sPageNextDisabled : oSettings.oClasses.sPageNextEnabled;
377 - }
378 - }
379 - }
380 - },
381 -
382 -
383 - /*
384 - * Variable: iFullNumbersShowPages
385 - * Purpose: Change the number of pages which can be seen
386 - * Scope: jQuery.fn.dataTableExt.oPagination
387 - */
388 - "iFullNumbersShowPages": 5,
389 -
390 - /*
391 - * Variable: full_numbers
392 - * Purpose: Full numbers pagination
393 - * Scope: jQuery.fn.dataTableExt.oPagination
394 - */
395 - "full_numbers": {
396 - /*
397 - * Function: oPagination.full_numbers.fnInit
398 - * Purpose: Initalise dom elements required for pagination with a list of the pages
399 - * Returns: -
400 - * Inputs: object:oSettings - dataTables settings object
401 - * node:nPaging - the DIV which contains this pagination control
402 - * function:fnCallbackDraw - draw function which must be called on update
403 - */
404 - "fnInit": function ( oSettings, nPaging, fnCallbackDraw )
405 - {
406 - var nFirst = document.createElement( 'span' );
407 - var nPrevious = document.createElement( 'span' );
408 - var nList = document.createElement( 'span' );
409 - var nNext = document.createElement( 'span' );
410 - var nLast = document.createElement( 'span' );
411 -
412 - nFirst.innerHTML = oSettings.oLanguage.oPaginate.sFirst;
413 - nPrevious.innerHTML = oSettings.oLanguage.oPaginate.sPrevious;
414 - nNext.innerHTML = oSettings.oLanguage.oPaginate.sNext;
415 - nLast.innerHTML = oSettings.oLanguage.oPaginate.sLast;
416 -
417 - var oClasses = oSettings.oClasses;
418 - nFirst.className = oClasses.sPageButton+" "+oClasses.sPageFirst;
419 - nPrevious.className = oClasses.sPageButton+" "+oClasses.sPagePrevious;
420 - nNext.className= oClasses.sPageButton+" "+oClasses.sPageNext;
421 - nLast.className = oClasses.sPageButton+" "+oClasses.sPageLast;
422 -
423 - nPaging.appendChild( nFirst );
424 - nPaging.appendChild( nPrevious );
425 - nPaging.appendChild( nList );
426 - nPaging.appendChild( nNext );
427 - nPaging.appendChild( nLast );
428 -
429 - $(nFirst).click( function () {
430 - if ( oSettings.oApi._fnPageChange( oSettings, "first" ) )
431 - {
432 - fnCallbackDraw( oSettings );
433 - }
434 - } );
435 -
436 - $(nPrevious).click( function() {
437 - if ( oSettings.oApi._fnPageChange( oSettings, "previous" ) )
438 - {
439 - fnCallbackDraw( oSettings );
440 - }
441 - } );
442 -
443 - $(nNext).click( function() {
444 - if ( oSettings.oApi._fnPageChange( oSettings, "next" ) )
445 - {
446 - fnCallbackDraw( oSettings );
447 - }
448 - } );
449 -
450 - $(nLast).click( function() {
451 - if ( oSettings.oApi._fnPageChange( oSettings, "last" ) )
452 - {
453 - fnCallbackDraw( oSettings );
454 - }
455 - } );
456 -
457 - /* Take the brutal approach to cancelling text selection */
458 - $('span', nPaging)
459 - .bind( 'mousedown', function () { return false; } )
460 - .bind( 'selectstart', function () { return false; } );
461 -
462 - /* ID the first elements only */
463 - if ( oSettings.sTableId !== '' && typeof oSettings.aanFeatures.p == "undefined" )
464 - {
465 - nPaging.setAttribute( 'id', oSettings.sTableId+'_paginate' );
466 - nFirst.setAttribute( 'id', oSettings.sTableId+'_first' );
467 - nPrevious.setAttribute( 'id', oSettings.sTableId+'_previous' );
468 - nNext.setAttribute( 'id', oSettings.sTableId+'_next' );
469 - nLast.setAttribute( 'id', oSettings.sTableId+'_last' );
470 - }
471 - },
472 -
473 - /*
474 - * Function: oPagination.full_numbers.fnUpdate
475 - * Purpose: Update the list of page buttons shows
476 - * Returns: -
477 - * Inputs: object:oSettings - dataTables settings object
478 - * function:fnCallbackDraw - draw function to call on page change
479 - */
480 - "fnUpdate": function ( oSettings, fnCallbackDraw )
481 - {
482 - if ( !oSettings.aanFeatures.p )
483 - {
484 - return;
485 - }
486 -
487 - var iPageCount = _oExt.oPagination.iFullNumbersShowPages;
488 - var iPageCountHalf = Math.floor(iPageCount / 2);
489 - var iPages = Math.ceil((oSettings.fnRecordsDisplay()) / oSettings._iDisplayLength);
490 - var iCurrentPage = Math.ceil(oSettings._iDisplayStart / oSettings._iDisplayLength) + 1;
491 - var sList = "";
492 - var iStartButton, iEndButton, i, iLen;
493 - var oClasses = oSettings.oClasses;
494 -
495 - /* Pages calculation */
496 - if (iPages < iPageCount)
497 - {
498 - iStartButton = 1;
499 - iEndButton = iPages;
500 - }
501 - else
502 - {
503 - if (iCurrentPage <= iPageCountHalf)
504 - {
505 - iStartButton = 1;
506 - iEndButton = iPageCount;
507 - }
508 - else
509 - {
510 - if (iCurrentPage >= (iPages - iPageCountHalf))
511 - {
512 - iStartButton = iPages - iPageCount + 1;
513 - iEndButton = iPages;
514 - }
515 - else
516 - {
517 - iStartButton = iCurrentPage - Math.ceil(iPageCount / 2) + 1;
518 - iEndButton = iStartButton + iPageCount - 1;
519 - }
520 - }
521 - }
522 -
523 - /* Build the dynamic list */
524 - for ( i=iStartButton ; i<=iEndButton ; i++ )
525 - {
526 - if ( iCurrentPage != i )
527 - {
528 - sList += '<span class="'+oClasses.sPageButton+'">'+i+'</span>';
529 - }
530 - else
531 - {
532 - sList += '<span class="'+oClasses.sPageButtonActive+'">'+i+'</span>';
533 - }
534 - }
535 -
536 - /* Loop over each instance of the pager */
537 - var an = oSettings.aanFeatures.p;
538 - var anButtons, anStatic, nPaginateList;
539 - var fnClick = function() {
540 - /* Use the information in the element to jump to the required page */
541 - var iTarget = (this.innerHTML * 1) - 1;
542 - oSettings._iDisplayStart = iTarget * oSettings._iDisplayLength;
543 - fnCallbackDraw( oSettings );
544 - return false;
545 - };
546 - var fnFalse = function () { return false; };
547 -
548 - for ( i=0, iLen=an.length ; i<iLen ; i++ )
549 - {
550 - if ( an[i].childNodes.length === 0 )
551 - {
552 - continue;
553 - }
554 -
555 - /* Build up the dynamic list forst - html and listeners */
556 - var qjPaginateList = $('span:eq(2)', an[i]);
557 - qjPaginateList.html( sList );
558 - $('span', qjPaginateList).click( fnClick ).bind( 'mousedown', fnFalse )
559 - .bind( 'selectstart', fnFalse );
560 -
561 - /* Update the 'premanent botton's classes */
562 - anButtons = an[i].getElementsByTagName('span');
563 - anStatic = [
564 - anButtons[0], anButtons[1],
565 - anButtons[anButtons.length-2], anButtons[anButtons.length-1]
566 - ];
567 - $(anStatic).removeClass( oClasses.sPageButton+" "+oClasses.sPageButtonActive+" "+oClasses.sPageButtonStaticDisabled );
568 - if ( iCurrentPage == 1 )
569 - {
570 - anStatic[0].className += " "+oClasses.sPageButtonStaticDisabled;
571 - anStatic[1].className += " "+oClasses.sPageButtonStaticDisabled;
572 - }
573 - else
574 - {
575 - anStatic[0].className += " "+oClasses.sPageButton;
576 - anStatic[1].className += " "+oClasses.sPageButton;
577 - }
578 -
579 - if ( iPages === 0 || iCurrentPage == iPages || oSettings._iDisplayLength == -1 )
580 - {
581 - anStatic[2].className += " "+oClasses.sPageButtonStaticDisabled;
582 - anStatic[3].className += " "+oClasses.sPageButtonStaticDisabled;
583 - }
584 - else
585 - {
586 - anStatic[2].className += " "+oClasses.sPageButton;
587 - anStatic[3].className += " "+oClasses.sPageButton;
588 - }
589 - }
590 - }
591 - }
592 - };
593 -
594 - /*
595 - * Variable: oSort
596 - * Purpose: Wrapper for the sorting functions that can be used in DataTables
597 - * Scope: jQuery.fn.dataTableExt
598 - * Notes: The functions provided in this object are basically standard javascript sort
599 - * functions - they expect two inputs which they then compare and then return a priority
600 - * result. For each sort method added, two functions need to be defined, an ascending sort and
601 - * a descending sort.
602 - */
603 - _oExt.oSort = {
604 - /*
605 - * text sorting
606 - */
607 - "string-asc": function ( a, b )
608 - {
609 - var x = a.toLowerCase();
610 - var y = b.toLowerCase();
611 - return ((x < y) ? -1 : ((x > y) ? 1 : 0));
612 - },
613 -
614 - "string-desc": function ( a, b )
615 - {
616 - var x = a.toLowerCase();
617 - var y = b.toLowerCase();
618 - return ((x < y) ? 1 : ((x > y) ? -1 : 0));
619 - },
620 -
621 -
622 - /*
623 - * html sorting (ignore html tags)
624 - */
625 - "html-asc": function ( a, b )
626 - {
627 - var x = a.replace( /<.*?>/g, "" ).toLowerCase();
628 - var y = b.replace( /<.*?>/g, "" ).toLowerCase();
629 - return ((x < y) ? -1 : ((x > y) ? 1 : 0));
630 - },
631 -
632 - "html-desc": function ( a, b )
633 - {
634 - var x = a.replace( /<.*?>/g, "" ).toLowerCase();
635 - var y = b.replace( /<.*?>/g, "" ).toLowerCase();
636 - return ((x < y) ? 1 : ((x > y) ? -1 : 0));
637 - },
638 -
639 -
640 - /*
641 - * date sorting
642 - */
643 - "date-asc": function ( a, b )
644 - {
645 - var x = Date.parse( a );
646 - var y = Date.parse( b );
647 -
648 - if ( isNaN(x) || x==="" )
649 - {
650 - x = Date.parse( "01/01/1970 00:00:00" );
651 - }
652 - if ( isNaN(y) || y==="" )
653 - {
654 - y = Date.parse( "01/01/1970 00:00:00" );
655 - }
656 -
657 - return x - y;
658 - },
659 -
660 - "date-desc": function ( a, b )
661 - {
662 - var x = Date.parse( a );
663 - var y = Date.parse( b );
664 -
665 - if ( isNaN(x) || x==="" )
666 - {
667 - x = Date.parse( "01/01/1970 00:00:00" );
668 - }
669 - if ( isNaN(y) || y==="" )
670 - {
671 - y = Date.parse( "01/01/1970 00:00:00" );
672 - }
673 -
674 - return y - x;
675 - },
676 -
677 -
678 - /*
679 - * numerical sorting
680 - */
681 - "numeric-asc": function ( a, b )
682 - {
683 - var x = (a=="-" || a==="") ? 0 : a*1;
684 - var y = (b=="-" || b==="") ? 0 : b*1;
685 - return x - y;
686 - },
687 -
688 - "numeric-desc": function ( a, b )
689 - {
690 - var x = (a=="-" || a==="") ? 0 : a*1;
691 - var y = (b=="-" || b==="") ? 0 : b*1;
692 - return y - x;
693 - }
694 - };
695 -
696 -
697 - /*
698 - * Variable: aTypes
699 - * Purpose: Container for the various type of type detection that dataTables supports
700 - * Scope: jQuery.fn.dataTableExt
701 - * Notes: The functions in this array are expected to parse a string to see if it is a data
702 - * type that it recognises. If so then the function should return the name of the type (a
703 - * corresponding sort function should be defined!), if the type is not recognised then the
704 - * function should return null such that the parser and move on to check the next type.
705 - * Note that ordering is important in this array - the functions are processed linearly,
706 - * starting at index 0.
707 - * Note that the input for these functions is always a string! It cannot be any other data
708 - * type
709 - */
710 - _oExt.aTypes = [
711 - /*
712 - * Function: -
713 - * Purpose: Check to see if a string is numeric
714 - * Returns: string:'numeric' or null
715 - * Inputs: string:sText - string to check
716 - */
717 - function ( sData )
718 - {
719 - /* Allow zero length strings as a number */
720 - if ( sData.length === 0 )
721 - {
722 - return 'numeric';
723 - }
724 -
725 - var sValidFirstChars = "0123456789-";
726 - var sValidChars = "0123456789.";
727 - var Char;
728 - var bDecimal = false;
729 -
730 - /* Check for a valid first char (no period and allow negatives) */
731 - Char = sData.charAt(0);
732 - if (sValidFirstChars.indexOf(Char) == -1)
733 - {
734 - return null;
735 - }
736 -
737 - /* Check all the other characters are valid */
738 - for ( var i=1 ; i<sData.length ; i++ )
739 - {
740 - Char = sData.charAt(i);
741 - if (sValidChars.indexOf(Char) == -1)
742 - {
743 - return null;
744 - }
745 -
746 - /* Only allowed one decimal place... */
747 - if ( Char == "." )
748 - {
749 - if ( bDecimal )
750 - {
751 - return null;
752 - }
753 - bDecimal = true;
754 - }
755 - }
756 -
757 - return 'numeric';
758 - },
759 -
760 - /*
761 - * Function: -
762 - * Purpose: Check to see if a string is actually a formatted date
763 - * Returns: string:'date' or null
764 - * Inputs: string:sText - string to check
765 - */
766 - function ( sData )
767 - {
768 - var iParse = Date.parse(sData);
769 - if ( (iParse !== null && !isNaN(iParse)) || sData.length === 0 )
770 - {
771 - return 'date';
772 - }
773 - return null;
774 - },
775 -
776 - /*
777 - * Function: -
778 - * Purpose: Check to see if a string should be treated as an HTML string
779 - * Returns: string:'html' or null
780 - * Inputs: string:sText - string to check
781 - */
782 - function ( sData )
783 - {
784 - if ( sData.indexOf('<') != -1 && sData.indexOf('>') != -1 )
785 - {
786 - return 'html';
787 - }
788 - return null;
789 - }
790 - ];
791 -
792 - /*
793 - * Function: fnVersionCheck
794 - * Purpose: Check a version string against this version of DataTables. Useful for plug-ins
795 - * Returns: bool:true -this version of DataTables is greater or equal to the required version
796 - * false -this version of DataTales is not suitable
797 - * Inputs: string:sVersion - the version to check against. May be in the following formats:
798 - * "a", "a.b" or "a.b.c"
799 - * Notes: This function will only check the first three parts of a version string. It is
800 - * assumed that beta and dev versions will meet the requirements. This might change in future
801 - */
802 - _oExt.fnVersionCheck = function( sVersion )
803 - {
804 - /* This is cheap, but very effective */
805 - var fnZPad = function (Zpad, count)
806 - {
807 - while(Zpad.length < count) {
808 - Zpad += '0';
809 - }
810 - return Zpad;
811 - };
812 - var aThis = _oExt.sVersion.split('.');
813 - var aThat = sVersion.split('.');
814 - var sThis = '', sThat = '';
815 -
816 - for ( var i=0, iLen=aThat.length ; i<iLen ; i++ )
817 - {
818 - sThis += fnZPad( aThis[i], 3 );
819 - sThat += fnZPad( aThat[i], 3 );
820 - }
821 -
822 - return parseInt(sThis, 10) >= parseInt(sThat, 10);
823 - };
824 -
825 - /*
826 - * Variable: _oExternConfig
827 - * Purpose: Store information for DataTables to access globally about other instances
828 - * Scope: jQuery.fn.dataTableExt
829 - */
830 - _oExt._oExternConfig = {
831 - /* int:iNextUnique - next unique number for an instance */
832 - "iNextUnique": 0
833 - };
834 -
835 -
836 - /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
837 - * Section - DataTables prototype
838 - * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
839 -
840 - /*
841 - * Function: dataTable
842 - * Purpose: DataTables information
843 - * Returns: -
844 - * Inputs: object:oInit - initalisation options for the table
845 - */
846 - $.fn.dataTable = function( oInit )
847 - {
848 - /*
849 - * Function: classSettings
850 - * Purpose: Settings container function for all 'class' properties which are required
851 - * by dataTables
852 - * Returns: -
853 - * Inputs: -
854 - */
855 - function classSettings ()
856 - {
857 - this.fnRecordsTotal = function ()
858 - {
859 - if ( this.oFeatures.bServerSide ) {
860 - return parseInt(this._iRecordsTotal, 10);
861 - } else {
862 - return this.aiDisplayMaster.length;
863 - }
864 - };
865 -
866 - this.fnRecordsDisplay = function ()
867 - {
868 - if ( this.oFeatures.bServerSide ) {
869 - return parseInt(this._iRecordsDisplay, 10);
870 - } else {
871 - return this.aiDisplay.length;
872 - }
873 - };
874 -
875 - this.fnDisplayEnd = function ()
876 - {
877 - if ( this.oFeatures.bServerSide ) {
878 - if ( this.oFeatures.bPaginate === false || this._iDisplayLength == -1 ) {
879 - return this._iDisplayStart+this.aiDisplay.length;
880 - } else {
881 - return Math.min( this._iDisplayStart+this._iDisplayLength,
882 - this._iRecordsDisplay );
883 - }
884 - } else {
885 - return this._iDisplayEnd;
886 - }
887 - };
888 -
889 - /*
890 - * Variable: oInstance
891 - * Purpose: The DataTables object for this table
892 - * Scope: jQuery.dataTable.classSettings
893 - */
894 - this.oInstance = null;
895 -
896 - /*
897 - * Variable: sInstance
898 - * Purpose: Unique idendifier for each instance of the DataTables object
899 - * Scope: jQuery.dataTable.classSettings
900 - */
901 - this.sInstance = null;
902 -
903 - /*
904 - * Variable: oFeatures
905 - * Purpose: Indicate the enablement of key dataTable features
906 - * Scope: jQuery.dataTable.classSettings
907 - */
908 - this.oFeatures = {
909 - "bPaginate": true,
910 - "bLengthChange": true,
911 - "bFilter": true,
912 - "bSort": true,
913 - "bInfo": true,
914 - "bAutoWidth": true,
915 - "bProcessing": false,
916 - "bSortClasses": true,
917 - "bStateSave": false,
918 - "bServerSide": false
919 - };
920 -
921 - /*
922 - * Variable: oScroll
923 - * Purpose: Container for scrolling options
924 - * Scope: jQuery.dataTable.classSettings
925 - */
926 - this.oScroll = {
927 - "sX": "",
928 - "sXInner": "",
929 - "sY": "",
930 - "bCollapse": false,
931 - "bInfinite": false,
932 - "iLoadGap": 100,
933 - "iBarWidth": 0,
934 - "bAutoCss": true
935 - };
936 -
937 - /*
938 - * Variable: aanFeatures
939 - * Purpose: Array referencing the nodes which are used for the features
940 - * Scope: jQuery.dataTable.classSettings
941 - * Notes: The parameters of this object match what is allowed by sDom - i.e.
942 - * 'l' - Length changing
943 - * 'f' - Filtering input
944 - * 't' - The table!
945 - * 'i' - Information
946 - * 'p' - Pagination
947 - * 'r' - pRocessing
948 - */
949 - this.aanFeatures = [];
950 -
951 - /*
952 - * Variable: oLanguage
953 - * Purpose: Store the language strings used by dataTables
954 - * Scope: jQuery.dataTable.classSettings
955 - * Notes: The words in the format _VAR_ are variables which are dynamically replaced
956 - * by javascript
957 - */
958 - this.oLanguage = {
959 - "sProcessing": "Processing...",
960 - "sLengthMenu": "Show _MENU_ entries",
961 - "sZeroRecords": "No matching records found",
962 - "sEmptyTable": "No data available in table",
963 - "sInfo": "Showing _START_ to _END_ of _TOTAL_ entries",
964 - "sInfoEmpty": "Showing 0 to 0 of 0 entries",
965 - "sInfoFiltered": "(filtered from _MAX_ total entries)",
966 - "sInfoPostFix": "",
967 - "sSearch": "Search:",
968 - "sUrl": "",
969 - "oPaginate": {
970 - "sFirst": "First",
971 - "sPrevious": "Previous",
972 - "sNext": "Next",
973 - "sLast": "Last"
974 - },
975 - "fnInfoCallback": null
976 - };
977 -
978 - /*
979 - * Variable: aoData
980 - * Purpose: Store data information
981 - * Scope: jQuery.dataTable.classSettings
982 - * Notes: This is an array of objects with the following parameters:
983 - * int: _iId - internal id for tracking
984 - * array: _aData - internal data - used for sorting / filtering etc
985 - * node: nTr - display node
986 - * array node: _anHidden - hidden TD nodes
987 - * string: _sRowStripe
988 - */
989 - this.aoData = [];
990 -
991 - /*
992 - * Variable: aiDisplay
993 - * Purpose: Array of indexes which are in the current display (after filtering etc)
994 - * Scope: jQuery.dataTable.classSettings
995 - */
996 - this.aiDisplay = [];
997 -
998 - /*
999 - * Variable: aiDisplayMaster
1000 - * Purpose: Array of indexes for display - no filtering
1001 - * Scope: jQuery.dataTable.classSettings
1002 - */
1003 - this.aiDisplayMaster = [];
1004 -
1005 - /*
1006 - * Variable: aoColumns
1007 - * Purpose: Store information about each column that is in use
1008 - * Scope: jQuery.dataTable.classSettings
1009 - */
1010 - this.aoColumns = [];
1011 -
1012 - /*
1013 - * Variable: iNextId
1014 - * Purpose: Store the next unique id to be used for a new row
1015 - * Scope: jQuery.dataTable.classSettings
1016 - */
1017 - this.iNextId = 0;
1018 -
1019 - /*
1020 - * Variable: asDataSearch
1021 - * Purpose: Search data array for regular expression searching
1022 - * Scope: jQuery.dataTable.classSettings
1023 - */
1024 - this.asDataSearch = [];
1025 -
1026 - /*
1027 - * Variable: oPreviousSearch
1028 - * Purpose: Store the previous search incase we want to force a re-search
1029 - * or compare the old search to a new one
1030 - * Scope: jQuery.dataTable.classSettings
1031 - */
1032 - this.oPreviousSearch = {
1033 - "sSearch": "",
1034 - "bRegex": false,
1035 - "bSmart": true
1036 - };
1037 -
1038 - /*
1039 - * Variable: aoPreSearchCols
1040 - * Purpose: Store the previous search for each column
1041 - * Scope: jQuery.dataTable.classSettings
1042 - */
1043 - this.aoPreSearchCols = [];
1044 -
1045 - /*
1046 - * Variable: aaSorting
1047 - * Purpose: Sorting information
1048 - * Scope: jQuery.dataTable.classSettings
1049 - * Notes: Index 0 - column number
1050 - * Index 1 - current sorting direction
1051 - * Index 2 - index of asSorting for this column
1052 - */
1053 - this.aaSorting = [ [0, 'asc', 0] ];
1054 -
1055 - /*
1056 - * Variable: aaSortingFixed
1057 - * Purpose: Sorting information that is always applied
1058 - * Scope: jQuery.dataTable.classSettings
1059 - */
1060 - this.aaSortingFixed = null;
1061 -
1062 - /*
1063 - * Variable: asStripClasses
1064 - * Purpose: Classes to use for the striping of a table
1065 - * Scope: jQuery.dataTable.classSettings
1066 - */
1067 - this.asStripClasses = [];
1068 -
1069 - /*
1070 - * Variable: asDestoryStrips
1071 - * Purpose: If restoring a table - we should restore it's striping classes as well
1072 - * Scope: jQuery.dataTable.classSettings
1073 - */
1074 - this.asDestoryStrips = [];
1075 -
1076 - /*
1077 - * Variable: sDestroyWidth
1078 - * Purpose: If restoring a table - we should restore it's width
1079 - * Scope: jQuery.dataTable.classSettings
1080 - */
1081 - this.sDestroyWidth = 0;
1082 -
1083 - /*
1084 - * Variable: fnRowCallback
1085 - * Purpose: Call this function every time a row is inserted (draw)
1086 - * Scope: jQuery.dataTable.classSettings
1087 - */
1088 - this.fnRowCallback = null;
1089 -
1090 - /*
1091 - * Variable: fnHeaderCallback
1092 - * Purpose: Callback function for the header on each draw
1093 - * Scope: jQuery.dataTable.classSettings
1094 - */
1095 - this.fnHeaderCallback = null;
1096 -
1097 - /*
1098 - * Variable: fnFooterCallback
1099 - * Purpose: Callback function for the footer on each draw
1100 - * Scope: jQuery.dataTable.classSettings
1101 - */
1102 - this.fnFooterCallback = null;
1103 -
1104 - /*
1105 - * Variable: aoDrawCallback
1106 - * Purpose: Array of callback functions for draw callback functions
1107 - * Scope: jQuery.dataTable.classSettings
1108 - * Notes: Each array element is an object with the following parameters:
1109 - * function:fn - function to call
1110 - * string:sName - name callback (feature). useful for arranging array
1111 - */
1112 - this.aoDrawCallback = [];
1113 -
1114 - /*
1115 - * Variable: fnInitComplete
1116 - * Purpose: Callback function for when the table has been initalised
1117 - * Scope: jQuery.dataTable.classSettings
1118 - */
1119 - this.fnInitComplete = null;
1120 -
1121 - /*
1122 - * Variable: sTableId
1123 - * Purpose: Cache the table ID for quick access
1124 - * Scope: jQuery.dataTable.classSettings
1125 - */
1126 - this.sTableId = "";
1127 -
1128 - /*
1129 - * Variable: nTable
1130 - * Purpose: Cache the table node for quick access
1131 - * Scope: jQuery.dataTable.classSettings
1132 - */
1133 - this.nTable = null;
1134 -
1135 - /*
1136 - * Variable: nTHead
1137 - * Purpose: Permanent ref to the thead element
1138 - * Scope: jQuery.dataTable.classSettings
1139 - */
1140 - this.nTHead = null;
1141 -
1142 - /*
1143 - * Variable: nTFoot
1144 - * Purpose: Permanent ref to the tfoot element - if it exists
1145 - * Scope: jQuery.dataTable.classSettings
1146 - */
1147 - this.nTFoot = null;
1148 -
1149 - /*
1150 - * Variable: nTBody
1151 - * Purpose: Permanent ref to the tbody element
1152 - * Scope: jQuery.dataTable.classSettings
1153 - */
1154 - this.nTBody = null;
1155 -
1156 - /*
1157 - * Variable: nTableWrapper
1158 - * Purpose: Cache the wrapper node (contains all DataTables controlled elements)
1159 - * Scope: jQuery.dataTable.classSettings
1160 - */
1161 - this.nTableWrapper = null;
1162 -
1163 - /*
1164 - * Variable: bInitialised
1165 - * Purpose: Indicate if all required information has been read in
1166 - * Scope: jQuery.dataTable.classSettings
1167 - */
1168 - this.bInitialised = false;
1169 -
1170 - /*
1171 - * Variable: aoOpenRows
1172 - * Purpose: Information about open rows
1173 - * Scope: jQuery.dataTable.classSettings
1174 - * Notes: Has the parameters 'nTr' and 'nParent'
1175 - */
1176 - this.aoOpenRows = [];
1177 -
1178 - /*
1179 - * Variable: sDom
1180 - * Purpose: Dictate the positioning that the created elements will take
1181 - * Scope: jQuery.dataTable.classSettings
1182 - * Notes:
1183 - * The following options are allowed:
1184 - * 'l' - Length changing
1185 - * 'f' - Filtering input
1186 - * 't' - The table!
1187 - * 'i' - Information
1188 - * 'p' - Pagination
1189 - * 'r' - pRocessing
1190 - * The following constants are allowed:
1191 - * 'H' - jQueryUI theme "header" classes
1192 - * 'F' - jQueryUI theme "footer" classes
1193 - * The following syntax is expected:
1194 - * '<' and '>' - div elements
1195 - * '<"class" and '>' - div with a class
1196 - * Examples:
1197 - * '<"wrapper"flipt>', '<lf<t>ip>'
1198 - */
1199 - this.sDom = 'lfrtip';
1200 -
1201 - /*
1202 - * Variable: sPaginationType
1203 - * Purpose: Note which type of sorting should be used
1204 - * Scope: jQuery.dataTable.classSettings
1205 - */
1206 - this.sPaginationType = "two_button";
1207 -
1208 - /*
1209 - * Variable: iCookieDuration
1210 - * Purpose: The cookie duration (for bStateSave) in seconds - default 2 hours
1211 - * Scope: jQuery.dataTable.classSettings
1212 - */
1213 - this.iCookieDuration = 60 * 60 * 2;
1214 -
1215 - /*
1216 - * Variable: sCookiePrefix
1217 - * Purpose: The cookie name prefix
1218 - * Scope: jQuery.dataTable.classSettings
1219 - */
1220 - this.sCookiePrefix = "SpryMedia_DataTables_";
1221 -
1222 - /*
1223 - * Variable: fnCookieCallback
1224 - * Purpose: Callback function for cookie creation
1225 - * Scope: jQuery.dataTable.classSettings
1226 - */
1227 - this.fnCookieCallback = null;
1228 -
1229 - /*
1230 - * Variable: aoStateSave
1231 - * Purpose: Array of callback functions for state saving
1232 - * Scope: jQuery.dataTable.classSettings
1233 - * Notes: Each array element is an object with the following parameters:
1234 - * function:fn - function to call. Takes two parameters, oSettings and the JSON string to
1235 - * save that has been thus far created. Returns a JSON string to be inserted into a
1236 - * json object (i.e. '"param": [ 0, 1, 2]')
1237 - * string:sName - name of callback
1238 - */
1239 - this.aoStateSave = [];
1240 -
1241 - /*
1242 - * Variable: aoStateLoad
1243 - * Purpose: Array of callback functions for state loading
1244 - * Scope: jQuery.dataTable.classSettings
1245 - * Notes: Each array element is an object with the following parameters:
1246 - * function:fn - function to call. Takes two parameters, oSettings and the object stored.
1247 - * May return false to cancel state loading.
1248 - * string:sName - name of callback
1249 - */
1250 - this.aoStateLoad = [];
1251 -
1252 - /*
1253 - * Variable: oLoadedState
1254 - * Purpose: State that was loaded from the cookie. Useful for back reference
1255 - * Scope: jQuery.dataTable.classSettings
1256 - */
1257 - this.oLoadedState = null;
1258 -
1259 - /*
1260 - * Variable: sAjaxSource
1261 - * Purpose: Source url for AJAX data for the table
1262 - * Scope: jQuery.dataTable.classSettings
1263 - */
1264 - this.sAjaxSource = null;
1265 -
1266 - /*
1267 - * Variable: bAjaxDataGet
1268 - * Purpose: Note if draw should be blocked while getting data
1269 - * Scope: jQuery.dataTable.classSettings
1270 - */
1271 - this.bAjaxDataGet = true;
1272 -
1273 - /*
1274 - * Variable: fnServerData
1275 - * Purpose: Function to get the server-side data - can be overruled by the developer
1276 - * Scope: jQuery.dataTable.classSettings
1277 - */
1278 - this.fnServerData = function ( url, data, callback ) {
1279 - $.ajax( {
1280 - "url": url,
1281 - "data": data,
1282 - "success": callback,
1283 - "dataType": "json",
1284 - "cache": false,
1285 - "error": function (xhr, error, thrown) {
1286 - if ( error == "parsererror" ) {
1287 - alert( "DataTables warning: JSON data from server could not be parsed. "+
1288 - "This is caused by a JSON formatting error." );
1289 - }
1290 - }
1291 - } );
1292 - };
1293 -
1294 - /*
1295 - * Variable: fnFormatNumber
1296 - * Purpose: Format numbers for display
1297 - * Scope: jQuery.dataTable.classSettings
1298 - */
1299 - this.fnFormatNumber = function ( iIn )
1300 - {
1301 - if ( iIn < 1000 )
1302 - {
1303 - /* A small optimisation for what is likely to be the vast majority of use cases */
1304 - return iIn;
1305 - }
1306 - else
1307 - {
1308 - var s=(iIn+""), a=s.split(""), out="", iLen=s.length;
1309 -
1310 - for ( var i=0 ; i<iLen ; i++ )
1311 - {
1312 - if ( i%3 === 0 && i !== 0 )
1313 - {
1314 - out = ','+out;
1315 - }
1316 - out = a[iLen-i-1]+out;
1317 - }
1318 - }
1319 - return out;
1320 - };
1321 -
1322 - /*
1323 - * Variable: aLengthMenu
1324 - * Purpose: List of options that can be used for the user selectable length menu
1325 - * Scope: jQuery.dataTable.classSettings
1326 - * Note: This varaible can take for form of a 1D array, in which case the value and the
1327 - * displayed value in the menu are the same, or a 2D array in which case the value comes
1328 - * from the first array, and the displayed value to the end user comes from the second
1329 - * array. 2D example: [ [ 10, 25, 50, 100, -1 ], [ 10, 25, 50, 100, 'All' ] ];
1330 - */
1331 - this.aLengthMenu = [ 10, 25, 50, 100 ];
1332 -
1333 - /*
1334 - * Variable: iDraw
1335 - * Purpose: Counter for the draws that the table does. Also used as a tracker for
1336 - * server-side processing
1337 - * Scope: jQuery.dataTable.classSettings
1338 - */
1339 - this.iDraw = 0;
1340 -
1341 - /*
1342 - * Variable: bDrawing
1343 - * Purpose: Indicate if a redraw is being done - useful for Ajax
1344 - * Scope: jQuery.dataTable.classSettings
1345 - */
1346 - this.bDrawing = 0;
1347 -
1348 - /*
1349 - * Variable: iDrawError
1350 - * Purpose: Last draw error
1351 - * Scope: jQuery.dataTable.classSettings
1352 - */
1353 - this.iDrawError = -1;
1354 -
1355 - /*
1356 - * Variable: _iDisplayLength, _iDisplayStart, _iDisplayEnd
1357 - * Purpose: Display length variables
1358 - * Scope: jQuery.dataTable.classSettings
1359 - * Notes: These variable must NOT be used externally to get the data length. Rather, use
1360 - * the fnRecordsTotal() (etc) functions.
1361 - */
1362 - this._iDisplayLength = 10;
1363 - this._iDisplayStart = 0;
1364 - this._iDisplayEnd = 10;
1365 -
1366 - /*
1367 - * Variable: _iRecordsTotal, _iRecordsDisplay
1368 - * Purpose: Display length variables used for server side processing
1369 - * Scope: jQuery.dataTable.classSettings
1370 - * Notes: These variable must NOT be used externally to get the data length. Rather, use
1371 - * the fnRecordsTotal() (etc) functions.
1372 - */
1373 - this._iRecordsTotal = 0;
1374 - this._iRecordsDisplay = 0;
1375 -
1376 - /*
1377 - * Variable: bJUI
1378 - * Purpose: Should we add the markup needed for jQuery UI theming?
1379 - * Scope: jQuery.dataTable.classSettings
1380 - */
1381 - this.bJUI = false;
1382 -
1383 - /*
1384 - * Variable: bJUI
1385 - * Purpose: Should we add the markup needed for jQuery UI theming?
1386 - * Scope: jQuery.dataTable.classSettings
1387 - */
1388 - this.oClasses = _oExt.oStdClasses;
1389 -
1390 - /*
1391 - * Variable: bFiltered and bSorted
1392 - * Purpose: Flags to allow callback functions to see what actions have been performed
1393 - * Scope: jQuery.dataTable.classSettings
1394 - */
1395 - this.bFiltered = false;
1396 - this.bSorted = false;
1397 -
1398 - /*
1399 - * Variable: oInit
1400 - * Purpose: Initialisation object that is used for the table
1401 - * Scope: jQuery.dataTable.classSettings
1402 - */
1403 - this.oInit = null;
1404 - }
1405 -
1406 - /*
1407 - * Variable: oApi
1408 - * Purpose: Container for publicly exposed 'private' functions
1409 - * Scope: jQuery.dataTable
1410 - */
1411 - this.oApi = {};
1412 -
1413 -
1414 - /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
1415 - * Section - API functions
1416 - * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
1417 -
1418 - /*
1419 - * Function: fnDraw
1420 - * Purpose: Redraw the table
1421 - * Returns: -
1422 - * Inputs: bool:bComplete - Refilter and resort (if enabled) the table before the draw.
1423 - * Optional: default - true
1424 - */
1425 - this.fnDraw = function( bComplete )
1426 - {
1427 - var oSettings = _fnSettingsFromNode( this[_oExt.iApiIndex] );
1428 - if ( typeof bComplete != 'undefined' && bComplete === false )
1429 - {
1430 - _fnCalculateEnd( oSettings );
1431 - _fnDraw( oSettings );
1432 - }
1433 - else
1434 - {
1435 - _fnReDraw( oSettings );
1436 - }
1437 - };
1438 -
1439 - /*
1440 - * Function: fnFilter
1441 - * Purpose: Filter the input based on data
1442 - * Returns: -
1443 - * Inputs: string:sInput - string to filter the table on
1444 - * int:iColumn - optional - column to limit filtering to
1445 - * bool:bRegex - optional - treat as regular expression or not - default false
1446 - * bool:bSmart - optional - perform smart filtering or not - default true
1447 - * bool:bShowGlobal - optional - show the input global filter in it's input box(es)
1448 - * - default true
1449 - */
1450 - this.fnFilter = function( sInput, iColumn, bRegex, bSmart, bShowGlobal )
1451 - {
1452 - var oSettings = _fnSettingsFromNode( this[_oExt.iApiIndex] );
1453 -
1454 - if ( !oSettings.oFeatures.bFilter )
1455 - {
1456 - return;
1457 - }
1458 -
1459 - if ( typeof bRegex == 'undefined' )
1460 - {
1461 - bRegex = false;
1462 - }
1463 -
1464 - if ( typeof bSmart == 'undefined' )
1465 - {
1466 - bSmart = true;
1467 - }
1468 -
1469 - if ( typeof bShowGlobal == 'undefined' )
1470 - {
1471 - bShowGlobal = true;
1472 - }
1473 -
1474 - if ( typeof iColumn == "undefined" || iColumn === null )
1475 - {
1476 - /* Global filter */
1477 - _fnFilterComplete( oSettings, {
1478 - "sSearch":sInput,
1479 - "bRegex": bRegex,
1480 - "bSmart": bSmart
1481 - }, 1 );
1482 -
1483 - if ( bShowGlobal && typeof oSettings.aanFeatures.f != 'undefined' )
1484 - {
1485 - var n = oSettings.aanFeatures.f;
1486 - for ( var i=0, iLen=n.length ; i<iLen ; i++ )
1487 - {
1488 - $('input', n[i]).val( sInput );
1489 - }
1490 - }
1491 - }
1492 - else
1493 - {
1494 - /* Single column filter */
1495 - oSettings.aoPreSearchCols[ iColumn ].sSearch = sInput;
1496 - oSettings.aoPreSearchCols[ iColumn ].bRegex = bRegex;
1497 - oSettings.aoPreSearchCols[ iColumn ].bSmart = bSmart;
1498 - _fnFilterComplete( oSettings, oSettings.oPreviousSearch, 1 );
1499 - }
1500 - };
1501 -
1502 - /*
1503 - * Function: fnSettings
1504 - * Purpose: Get the settings for a particular table for extern. manipulation
1505 - * Returns: -
1506 - * Inputs: -
1507 - */
1508 - this.fnSettings = function( nNode )
1509 - {
1510 - return _fnSettingsFromNode( this[_oExt.iApiIndex] );
1511 - };
1512 -
1513 - /*
1514 - * Function: fnVersionCheck
1515 - * Notes: The function is the same as the 'static' function provided in the ext variable
1516 - */
1517 - this.fnVersionCheck = _oExt.fnVersionCheck;
1518 -
1519 - /*
1520 - * Function: fnSort
1521 - * Purpose: Sort the table by a particular row
1522 - * Returns: -
1523 - * Inputs: int:iCol - the data index to sort on. Note that this will
1524 - * not match the 'display index' if you have hidden data entries
1525 - */
1526 - this.fnSort = function( aaSort )
1527 - {
1528 - var oSettings = _fnSettingsFromNode( this[_oExt.iApiIndex] );
1529 - oSettings.aaSorting = aaSort;
1530 - _fnSort( oSettings );
1531 - };
1532 -
1533 - /*
1534 - * Function: fnSortListener
1535 - * Purpose: Attach a sort listener to an element for a given column
1536 - * Returns: -
1537 - * Inputs: node:nNode - the element to attach the sort listener to
1538 - * int:iColumn - the column that a click on this node will sort on
1539 - * function:fnCallback - callback function when sort is run - optional
1540 - */
1541 - this.fnSortListener = function( nNode, iColumn, fnCallback )
1542 - {
1543 - _fnSortAttachListener( _fnSettingsFromNode( this[_oExt.iApiIndex] ), nNode, iColumn,
1544 - fnCallback );
1545 - };
1546 -
1547 - /*
1548 - * Function: fnAddData
1549 - * Purpose: Add new row(s) into the table
1550 - * Returns: array int: array of indexes (aoData) which have been added (zero length on error)
1551 - * Inputs: array:mData - the data to be added. The length must match
1552 - * the original data from the DOM
1553 - * or
1554 - * array array:mData - 2D array of data to be added
1555 - * bool:bRedraw - redraw the table or not - default true
1556 - * Notes: Warning - the refilter here will cause the table to redraw
1557 - * starting at zero
1558 - * Notes: Thanks to Yekimov Denis for contributing the basis for this function!
1559 - */
1560 - this.fnAddData = function( mData, bRedraw )
1561 - {
1562 - if ( mData.length === 0 )
1563 - {
1564 - return [];
1565 - }
1566 -
1567 - var aiReturn = [];
1568 - var iTest;
1569 -
1570 - /* Find settings from table node */
1571 - var oSettings = _fnSettingsFromNode( this[_oExt.iApiIndex] );
1572 -
1573 - /* Check if we want to add multiple rows or not */
1574 - if ( typeof mData[0] == "object" )
1575 - {
1576 - for ( var i=0 ; i<mData.length ; i++ )
1577 - {
1578 - iTest = _fnAddData( oSettings, mData[i] );
1579 - if ( iTest == -1 )
1580 - {
1581 - return aiReturn;
1582 - }
1583 - aiReturn.push( iTest );
1584 - }
1585 - }
1586 - else
1587 - {
1588 - iTest = _fnAddData( oSettings, mData );
1589 - if ( iTest == -1 )
1590 - {
1591 - return aiReturn;
1592 - }
1593 - aiReturn.push( iTest );
1594 - }
1595 -
1596 - oSettings.aiDisplay = oSettings.aiDisplayMaster.slice();
1597 -
1598 - if ( typeof bRedraw == 'undefined' || bRedraw )
1599 - {
1600 - _fnReDraw( oSettings );
1601 - }
1602 - return aiReturn;
1603 - };
1604 -
1605 - /*
1606 - * Function: fnDeleteRow
1607 - * Purpose: Remove a row for the table
1608 - * Returns: array:aReturn - the row that was deleted
1609 - * Inputs: mixed:mTarget -
1610 - * int: - index of aoData to be deleted, or
1611 - * node(TR): - TR element you want to delete
1612 - * function:fnCallBack - callback function - default null
1613 - * bool:bRedraw - redraw the table or not - default true
1614 - */
1615 - this.fnDeleteRow = function( mTarget, fnCallBack, bRedraw )
1616 - {
1617 - /* Find settings from table node */
1618 - var oSettings = _fnSettingsFromNode( this[_oExt.iApiIndex] );
1619 - var i, iAODataIndex;
1620 -
1621 - iAODataIndex = (typeof mTarget == 'object') ?
1622 - _fnNodeToDataIndex(oSettings, mTarget) : mTarget;
1623 -
1624 - /* Return the data array from this row */
1625 - var oData = oSettings.aoData.splice( iAODataIndex, 1 );
1626 -
1627 - /* Remove the target row from the search array */
1628 - var iDisplayIndex = $.inArray( iAODataIndex, oSettings.aiDisplay );
1629 - oSettings.asDataSearch.splice( iDisplayIndex, 1 );
1630 -
1631 - /* Delete from the display arrays */
1632 - _fnDeleteIndex( oSettings.aiDisplayMaster, iAODataIndex );
1633 - _fnDeleteIndex( oSettings.aiDisplay, iAODataIndex );
1634 -
1635 - /* If there is a user callback function - call it */
1636 - if ( typeof fnCallBack == "function" )
1637 - {
1638 - fnCallBack.call( this, oSettings, oData );
1639 - }
1640 -
1641 - /* Check for an 'overflow' they case for dislaying the table */
1642 - if ( oSettings._iDisplayStart >= oSettings.aiDisplay.length )
1643 - {
1644 - oSettings._iDisplayStart -= oSettings._iDisplayLength;
1645 - if ( oSettings._iDisplayStart < 0 )
1646 - {
1647 - oSettings._iDisplayStart = 0;
1648 - }
1649 - }
1650 -
1651 - if ( typeof bRedraw == 'undefined' || bRedraw )
1652 - {
1653 - _fnCalculateEnd( oSettings );
1654 - _fnDraw( oSettings );
1655 - }
1656 -
1657 - return oData;
1658 - };
1659 -
1660 - /*
1661 - * Function: fnClearTable
1662 - * Purpose: Quickly and simply clear a table
1663 - * Returns: -
1664 - * Inputs: bool:bRedraw - redraw the table or not - default true
1665 - * Notes: Thanks to Yekimov Denis for contributing the basis for this function!
1666 - */
1667 - this.fnClearTable = function( bRedraw )
1668 - {
1669 - /* Find settings from table node */
1670 - var oSettings = _fnSettingsFromNode( this[_oExt.iApiIndex] );
1671 - _fnClearTable( oSettings );
1672 -
1673 - if ( typeof bRedraw == 'undefined' || bRedraw )
1674 - {
1675 - _fnDraw( oSettings );
1676 - }
1677 - };
1678 -
1679 - /*
1680 - * Function: fnOpen
1681 - * Purpose: Open a display row (append a row after the row in question)
1682 - * Returns: node:nNewRow - the row opened
1683 - * Inputs: node:nTr - the table row to 'open'
1684 - * string:sHtml - the HTML to put into the row
1685 - * string:sClass - class to give the new TD cell
1686 - */
1687 - this.fnOpen = function( nTr, sHtml, sClass )
1688 - {
1689 - /* Find settings from table node */
1690 - var oSettings = _fnSettingsFromNode( this[_oExt.iApiIndex] );
1691 -
1692 - /* the old open one if there is one */
1693 - this.fnClose( nTr );
1694 -
1695 - var nNewRow = document.createElement("tr");
1696 - var nNewCell = document.createElement("td");
1697 - nNewRow.appendChild( nNewCell );
1698 - nNewCell.className = sClass;
1699 - nNewCell.colSpan = _fnVisbleColumns( oSettings );
1700 - nNewCell.innerHTML = sHtml;
1701 -
1702 - /* If the nTr isn't on the page at the moment - then we don't insert at the moment */
1703 - var nTrs = $('tr', oSettings.nTBody);
1704 - if ( $.inArray(nTr, nTrs) != -1 )
1705 - {
1706 - $(nNewRow).insertAfter(nTr);
1707 - }
1708 -
1709 - oSettings.aoOpenRows.push( {
1710 - "nTr": nNewRow,
1711 - "nParent": nTr
1712 - } );
1713 -
1714 - return nNewRow;
1715 - };
1716 -
1717 - /*
1718 - * Function: fnClose
1719 - * Purpose: Close a display row
1720 - * Returns: int: 0 (success) or 1 (failed)
1721 - * Inputs: node:nTr - the table row to 'close'
1722 - */
1723 - this.fnClose = function( nTr )
1724 - {
1725 - /* Find settings from table node */
1726 - var oSettings = _fnSettingsFromNode( this[_oExt.iApiIndex] );
1727 -
1728 - for ( var i=0 ; i<oSettings.aoOpenRows.length ; i++ )
1729 - {
1730 - if ( oSettings.aoOpenRows[i].nParent == nTr )
1731 - {
1732 - var nTrParent = oSettings.aoOpenRows[i].nTr.parentNode;
1733 - if ( nTrParent )
1734 - {
1735 - /* Remove it if it is currently on display */
1736 - nTrParent.removeChild( oSettings.aoOpenRows[i].nTr );
1737 - }
1738 - oSettings.aoOpenRows.splice( i, 1 );
1739 - return 0;
1740 - }
1741 - }
1742 - return 1;
1743 - };
1744 -
1745 - /*
1746 - * Function: fnGetData
1747 - * Purpose: Return an array with the data which is used to make up the table
1748 - * Returns: array array string: 2d data array ([row][column]) or array string: 1d data array
1749 - * or
1750 - * array string (if iRow specified)
1751 - * Inputs: mixed:mRow - optional - if not present, then the full 2D array for the table
1752 - * if given then:
1753 - * int: - return 1D array for aoData entry of this index
1754 - * node(TR): - return 1D array for this TR element
1755 - * Inputs: int:iRow - optional - if present then the array returned will be the data for
1756 - * the row with the index 'iRow'
1757 - */
1758 - this.fnGetData = function( mRow )
1759 - {
1760 - var oSettings = _fnSettingsFromNode( this[_oExt.iApiIndex] );
1761 -
1762 - if ( typeof mRow != 'undefined' )
1763 - {
1764 - var iRow = (typeof mRow == 'object') ?
1765 - _fnNodeToDataIndex(oSettings, mRow) : mRow;
1766 - return oSettings.aoData[iRow]._aData;
1767 - }
1768 - return _fnGetDataMaster( oSettings );
1769 - };
1770 -
1771 - /*
1772 - * Function: fnGetNodes
1773 - * Purpose: Return an array with the TR nodes used for drawing the table
1774 - * Returns: array node: TR elements
1775 - * or
1776 - * node (if iRow specified)
1777 - * Inputs: int:iRow - optional - if present then the array returned will be the node for
1778 - * the row with the index 'iRow'
1779 - */
1780 - this.fnGetNodes = function( iRow )
1781 - {
1782 - var oSettings = _fnSettingsFromNode( this[_oExt.iApiIndex] );
1783 -
1784 - if ( typeof iRow != 'undefined' )
1785 - {
1786 - return oSettings.aoData[iRow].nTr;
1787 - }
1788 - return _fnGetTrNodes( oSettings );
1789 - };
1790 -
1791 - /*
1792 - * Function: fnGetPosition
1793 - * Purpose: Get the array indexes of a particular cell from it's DOM element
1794 - * Returns: int: - row index, or array[ int, int, int ]: - row index, column index (visible)
1795 - * and column index including hidden columns
1796 - * Inputs: node:nNode - this can either be a TR or a TD in the table, the return is
1797 - * dependent on this input
1798 - */
1799 - this.fnGetPosition = function( nNode )
1800 - {
1801 - var oSettings = _fnSettingsFromNode( this[_oExt.iApiIndex] );
1802 - var i;
1803 -
1804 - if ( nNode.nodeName.toUpperCase() == "TR" )
1805 - {
1806 - return _fnNodeToDataIndex(oSettings, nNode);
1807 - }
1808 - else if ( nNode.nodeName.toUpperCase() == "TD" )
1809 - {
1810 - var iDataIndex = _fnNodeToDataIndex(oSettings, nNode.parentNode);
1811 - var iCorrector = 0;
1812 - for ( var j=0 ; j<oSettings.aoColumns.length ; j++ )
1813 - {
1814 - if ( oSettings.aoColumns[j].bVisible )
1815 - {
1816 - if ( oSettings.aoData[iDataIndex].nTr.getElementsByTagName('td')[j-iCorrector] == nNode )
1817 - {
1818 - return [ iDataIndex, j-iCorrector, j ];
1819 - }
1820 - }
1821 - else
1822 - {
1823 - iCorrector++;
1824 - }
1825 - }
1826 - }
1827 - return null;
1828 - };
1829 -
1830 - /*
1831 - * Function: fnUpdate
1832 - * Purpose: Update a table cell or row
1833 - * Returns: int: 0 okay, 1 error
1834 - * Inputs: array string 'or' string:mData - data to update the cell/row with
1835 - * mixed:mRow -
1836 - * int: - index of aoData to be updated, or
1837 - * node(TR): - TR element you want to update
1838 - * int:iColumn - the column to update - optional (not used of mData is 2D)
1839 - * bool:bRedraw - redraw the table or not - default true
1840 - * bool:bAction - perform predraw actions or not (you will want this as 'true' if
1841 - * you have bRedraw as true) - default true
1842 - */
1843 - this.fnUpdate = function( mData, mRow, iColumn, bRedraw, bAction )
1844 - {
1845 - var oSettings = _fnSettingsFromNode( this[_oExt.iApiIndex] );
1846 - var iVisibleColumn;
1847 - var sDisplay;
1848 - var iRow = (typeof mRow == 'object') ?
1849 - _fnNodeToDataIndex(oSettings, mRow) : mRow;
1850 -
1851 - if ( typeof mData != 'object' )
1852 - {
1853 - sDisplay = mData;
1854 - oSettings.aoData[iRow]._aData[iColumn] = sDisplay;
1855 -
1856 - if ( oSettings.aoColumns[iColumn].fnRender !== null )
1857 - {
1858 - sDisplay = oSettings.aoColumns[iColumn].fnRender( {
1859 - "iDataRow": iRow,
1860 - "iDataColumn": iColumn,
1861 - "aData": oSettings.aoData[iRow]._aData,
1862 - "oSettings": oSettings
1863 - } );
1864 -
1865 - if ( oSettings.aoColumns[iColumn].bUseRendered )
1866 - {
1867 - oSettings.aoData[iRow]._aData[iColumn] = sDisplay;
1868 - }
1869 - }
1870 -
1871 - iVisibleColumn = _fnColumnIndexToVisible( oSettings, iColumn );
1872 - if ( iVisibleColumn !== null )
1873 - {
1874 - oSettings.aoData[iRow].nTr.getElementsByTagName('td')[iVisibleColumn].innerHTML =
1875 - sDisplay;
1876 - }
1877 - }
1878 - else
1879 - {
1880 - if ( mData.length != oSettings.aoColumns.length )
1881 - {
1882 - _fnLog( oSettings, 0, 'An array passed to fnUpdate must have the same number of '+
1883 - 'columns as the table in question - in this case '+oSettings.aoColumns.length );
1884 - return 1;
1885 - }
1886 -
1887 - for ( var i=0 ; i<mData.length ; i++ )
1888 - {
1889 - sDisplay = mData[i];
1890 - oSettings.aoData[iRow]._aData[i] = sDisplay;
1891 -
1892 - if ( oSettings.aoColumns[i].fnRender !== null )
1893 - {
1894 - sDisplay = oSettings.aoColumns[i].fnRender( {
1895 - "iDataRow": iRow,
1896 - "iDataColumn": i,
1897 - "aData": oSettings.aoData[iRow]._aData,
1898 - "oSettings": oSettings
1899 - } );
1900 -
1901 - if ( oSettings.aoColumns[i].bUseRendered )
1902 - {
1903 - oSettings.aoData[iRow]._aData[i] = sDisplay;
1904 - }
1905 - }
1906 -
1907 - iVisibleColumn = _fnColumnIndexToVisible( oSettings, i );
1908 - if ( iVisibleColumn !== null )
1909 - {
1910 - oSettings.aoData[iRow].nTr.getElementsByTagName('td')[iVisibleColumn].innerHTML =
1911 - sDisplay;
1912 - }
1913 - }
1914 - }
1915 -
1916 - /* Modify the search index for this row (strictly this is likely not needed, since fnReDraw
1917 - * will rebuild the search array - however, the redraw might be disabled by the user)
1918 - */
1919 - var iDisplayIndex = $.inArray( iRow, oSettings.aiDisplay );
1920 - oSettings.asDataSearch[iDisplayIndex] = _fnBuildSearchRow( oSettings,
1921 - oSettings.aoData[iRow]._aData );
1922 -
1923 - /* Perform pre-draw actions */
1924 - if ( typeof bAction == 'undefined' || bAction )
1925 - {
1926 - _fnAjustColumnSizing( oSettings );
1927 - }
1928 -
1929 - /* Redraw the table */
1930 - if ( typeof bRedraw == 'undefined' || bRedraw )
1931 - {
1932 - _fnReDraw( oSettings );
1933 - }
1934 - return 0;
1935 - };
1936 -
1937 -
1938 - /*
1939 - * Function: fnShowColoumn
1940 - * Purpose: Show a particular column
1941 - * Returns: -
1942 - * Inputs: int:iCol - the column whose display should be changed
1943 - * bool:bShow - show (true) or hide (false) the column
1944 - * bool:bRedraw - redraw the table or not - default true
1945 - */
1946 - this.fnSetColumnVis = function ( iCol, bShow, bRedraw )
1947 - {
1948 - var oSettings = _fnSettingsFromNode( this[_oExt.iApiIndex] );
1949 - var i, iLen;
1950 - var iColumns = oSettings.aoColumns.length;
1951 - var nTd, anTds, nCell, anTrs, jqChildren;
1952 -
1953 - /* No point in doing anything if we are requesting what is already true */
1954 - if ( oSettings.aoColumns[iCol].bVisible == bShow )
1955 - {
1956 - return;
1957 - }
1958 -
1959 - var nTrHead = $('>tr', oSettings.nTHead)[0];
1960 - var nTrFoot = $('>tr', oSettings.nTFoot)[0];
1961 - var anTheadTh = [];
1962 - var anTfootTh = [];
1963 - for ( i=0 ; i<iColumns ; i++ )
1964 - {
1965 - anTheadTh.push( oSettings.aoColumns[i].nTh );
1966 - anTfootTh.push( oSettings.aoColumns[i].nTf );
1967 - }
1968 -
1969 - /* Show the column */
1970 - if ( bShow )
1971 - {
1972 - var iInsert = 0;
1973 - for ( i=0 ; i<iCol ; i++ )
1974 - {
1975 - if ( oSettings.aoColumns[i].bVisible )
1976 - {
1977 - iInsert++;
1978 - }
1979 - }
1980 -
1981 - /* Need to decide if we should use appendChild or insertBefore */
1982 - if ( iInsert >= _fnVisbleColumns( oSettings ) )
1983 - {
1984 - nTrHead.appendChild( anTheadTh[iCol] );
1985 - anTrs = $('>tr', oSettings.nTHead);
1986 - for ( i=1, iLen=anTrs.length ; i<iLen ; i++ )
1987 - {
1988 - anTrs[i].appendChild( oSettings.aoColumns[iCol].anThExtra[i-1] );
1989 - }
1990 -
1991 - if ( nTrFoot )
1992 - {
1993 - nTrFoot.appendChild( anTfootTh[iCol] );
1994 - anTrs = $('>tr', oSettings.nTFoot);
1995 - for ( i=1, iLen=anTrs.length ; i<iLen ; i++ )
1996 - {
1997 - anTrs[i].appendChild( oSettings.aoColumns[iCol].anTfExtra[i-1] );
1998 - }
1999 - }
2000 -
2001 - for ( i=0, iLen=oSettings.aoData.length ; i<iLen ; i++ )
2002 - {
2003 - nTd = oSettings.aoData[i]._anHidden[iCol];
2004 - oSettings.aoData[i].nTr.appendChild( nTd );
2005 - }
2006 - }
2007 - else
2008 - {
2009 - /* Which coloumn should we be inserting before? */
2010 - var iBefore;
2011 - for ( i=iCol ; i<iColumns ; i++ )
2012 - {
2013 - iBefore = _fnColumnIndexToVisible( oSettings, i );
2014 - if ( iBefore !== null )
2015 - {
2016 - break;
2017 - }
2018 - }
2019 -
2020 - nTrHead.insertBefore( anTheadTh[iCol], nTrHead.getElementsByTagName('th')[iBefore] );
2021 - anTrs = $('>tr', oSettings.nTHead);
2022 - for ( i=1, iLen=anTrs.length ; i<iLen ; i++ )
2023 - {
2024 - jqChildren = $(anTrs[i]).children();
2025 - anTrs[i].insertBefore( oSettings.aoColumns[iCol].anThExtra[i-1], jqChildren[iBefore] );
2026 - }
2027 -
2028 - if ( nTrFoot )
2029 - {
2030 - nTrFoot.insertBefore( anTfootTh[iCol], nTrFoot.getElementsByTagName('th')[iBefore] );
2031 - anTrs = $('>tr', oSettings.nTFoot);
2032 - for ( i=1, iLen=anTrs.length ; i<iLen ; i++ )
2033 - {
2034 - jqChildren = $(anTrs[i]).children();
2035 - anTrs[i].insertBefore( oSettings.aoColumns[iCol].anTfExtra[i-1], jqChildren[iBefore] );
2036 - }
2037 - }
2038 -
2039 - anTds = _fnGetTdNodes( oSettings );
2040 - for ( i=0, iLen=oSettings.aoData.length ; i<iLen ; i++ )
2041 - {
2042 - nTd = oSettings.aoData[i]._anHidden[iCol];
2043 - oSettings.aoData[i].nTr.insertBefore( nTd, $('>td:eq('+iBefore+')',
2044 - oSettings.aoData[i].nTr)[0] );
2045 - }
2046 - }
2047 -
2048 - oSettings.aoColumns[iCol].bVisible = true;
2049 - }
2050 - else
2051 - {
2052 - /* Remove a column from display */
2053 - nTrHead.removeChild( anTheadTh[iCol] );
2054 - for ( i=0, iLen=oSettings.aoColumns[iCol].anThExtra.length ; i<iLen ; i++ )
2055 - {
2056 - nCell = oSettings.aoColumns[iCol].anThExtra[i];
2057 - nCell.parentNode.removeChild( nCell );
2058 - }
2059 -
2060 - if ( nTrFoot )
2061 - {
2062 - nTrFoot.removeChild( anTfootTh[iCol] );
2063 - for ( i=0, iLen=oSettings.aoColumns[iCol].anTfExtra.length ; i<iLen ; i++ )
2064 - {
2065 - nCell = oSettings.aoColumns[iCol].anTfExtra[i];
2066 - nCell.parentNode.removeChild( nCell );
2067 - }
2068 - }
2069 -
2070 - anTds = _fnGetTdNodes( oSettings );
2071 - for ( i=0, iLen=oSettings.aoData.length ; i<iLen ; i++ )
2072 - {
2073 - nTd = anTds[ ( i*oSettings.aoColumns.length) + (iCol*1) ];
2074 - oSettings.aoData[i]._anHidden[iCol] = nTd;
2075 - nTd.parentNode.removeChild( nTd );
2076 - }
2077 -
2078 - oSettings.aoColumns[iCol].bVisible = false;
2079 - }
2080 -
2081 - /* If there are any 'open' rows, then we need to alter the colspan for this col change */
2082 - for ( i=0, iLen=oSettings.aoOpenRows.length ; i<iLen ; i++ )
2083 - {
2084 - oSettings.aoOpenRows[i].nTr.colSpan = _fnVisbleColumns( oSettings );
2085 - }
2086 -
2087 - /* Do a redraw incase anything depending on the table columns needs it
2088 - * (built-in: scrolling)
2089 - */
2090 - if ( typeof bRedraw == 'undefined' || bRedraw )
2091 - {
2092 - _fnAjustColumnSizing( oSettings );
2093 - _fnDraw( oSettings );
2094 - }
2095 -
2096 - _fnSaveState( oSettings );
2097 - };
2098 -
2099 - /*
2100 - * Function: fnPageChange
2101 - * Purpose: Change the pagination
2102 - * Returns: -
2103 - * Inputs: string:sAction - paging action to take: "first", "previous", "next" or "last"
2104 - * bool:bRedraw - redraw the table or not - optional - default true
2105 - */
2106 - this.fnPageChange = function ( sAction, bRedraw )
2107 - {
2108 - var oSettings = _fnSettingsFromNode( this[_oExt.iApiIndex] );
2109 - _fnPageChange( oSettings, sAction );
2110 - _fnCalculateEnd( oSettings );
2111 -
2112 - if ( typeof bRedraw == 'undefined' || bRedraw )
2113 - {
2114 - _fnDraw( oSettings );
2115 - }
2116 - };
2117 -
2118 - /*
2119 - * Function: fnDestroy
2120 - * Purpose: Destructor for the DataTable
2121 - * Returns: -
2122 - * Inputs: -
2123 - */
2124 - this.fnDestroy = function ( )
2125 - {
2126 - var oSettings = _fnSettingsFromNode( this[_oExt.iApiIndex] );
2127 - var nOrig = oSettings.nTableWrapper.parentNode;
2128 - var nBody = oSettings.nTBody;
2129 - var i, iLen;
2130 -
2131 - /* Flag to note that the table is currently being destoryed - no action should be taken */
2132 - oSettings.bDestroying = true;
2133 -
2134 - /* Restore hidden columns */
2135 - for ( i=0, iLen=oSettings.aoColumns.length ; i<iLen ; i++ )
2136 - {
2137 - if ( oSettings.aoColumns[i].bVisible === false )
2138 - {
2139 - this.fnSetColumnVis( i, true );
2140 - }
2141 - }
2142 -
2143 - /* If there is an 'empty' indicator row, remove it */
2144 - $('tbody>tr>td.'+oSettings.oClasses.sRowEmpty, oSettings.nTable).parent().remove();
2145 -
2146 - /* When scrolling we had to break the table up - restore it */
2147 - if ( oSettings.nTable != oSettings.nTHead.parentNode )
2148 - {
2149 - $('>thead', oSettings.nTable).remove();
2150 - oSettings.nTable.appendChild( oSettings.nTHead );
2151 - }
2152 -
2153 - if ( oSettings.nTFoot && oSettings.nTable != oSettings.nTFoot.parentNode )
2154 - {
2155 - $('>tfoot', oSettings.nTable).remove();
2156 - oSettings.nTable.appendChild( oSettings.nTFoot );
2157 - }
2158 -
2159 - /* Remove the DataTables generated nodes, events and classes */
2160 - oSettings.nTable.parentNode.removeChild( oSettings.nTable );
2161 - $(oSettings.nTableWrapper).remove();
2162 -
2163 - oSettings.aaSorting = [];
2164 - oSettings.aaSortingFixed = [];
2165 - _fnSortingClasses( oSettings );
2166 -
2167 - $(_fnGetTrNodes( oSettings )).removeClass( oSettings.asStripClasses.join(' ') );
2168 -
2169 - if ( !oSettings.bJUI )
2170 - {
2171 - $('th', oSettings.nTHead).removeClass( [ _oExt.oStdClasses.sSortable,
2172 - _oExt.oStdClasses.sSortableAsc,
2173 - _oExt.oStdClasses.sSortableDesc,
2174 - _oExt.oStdClasses.sSortableNone ].join(' ')
2175 - );
2176 - }
2177 - else
2178 - {
2179 - $('th', oSettings.nTHead).removeClass( [ _oExt.oStdClasses.sSortable,
2180 - _oExt.oJUIClasses.sSortableAsc,
2181 - _oExt.oJUIClasses.sSortableDesc,
2182 - _oExt.oJUIClasses.sSortableNone ].join(' ')
2183 - );
2184 - $('th span', oSettings.nTHead).remove();
2185 - }
2186 -
2187 - /* Add the TR elements back into the table in their original order */
2188 - nOrig.appendChild( oSettings.nTable );
2189 - for ( i=0, iLen=oSettings.aoData.length ; i<iLen ; i++ )
2190 - {
2191 - nBody.appendChild( oSettings.aoData[i].nTr );
2192 - }
2193 -
2194 - /* Restore the width of the original table */
2195 - oSettings.nTable.style.width = _fnStringToCss(oSettings.sDestroyWidth);
2196 -
2197 - /* If the were originally odd/even type classes - then we add them back here. Note
2198 - * this is not fool proof (for example if not all rows as odd/even classes - but
2199 - * it's a good effort without getting carried away
2200 - */
2201 - $('>tr:even', nBody).addClass( oSettings.asDestoryStrips[0] );
2202 - $('>tr:odd', nBody).addClass( oSettings.asDestoryStrips[1] );
2203 -
2204 - /* Remove the settings object from the settings array */
2205 - for ( i=0, iLen=_aoSettings.length ; i<iLen ; i++ )
2206 - {
2207 - if ( _aoSettings[i] == oSettings )
2208 - {
2209 - _aoSettings.splice( i, 1 );
2210 - }
2211 - }
2212 -
2213 - /* End it all */
2214 - oSettings = null;
2215 - };
2216 -
2217 - /*
2218 - * Function: _fnAjustColumnSizing
2219 - * Purpose: Update tale sizing based on content. This would most likely be used for scrolling
2220 - * and will typically need a redraw after it.
2221 - * Returns: -
2222 - * Inputs: bool:bRedraw - redraw the table or not, you will typically want to - default true
2223 - */
2224 - this.fnAdjustColumnSizing = function ( bRedraw )
2225 - {
2226 - var oSettings = _fnSettingsFromNode(this[_oExt.iApiIndex]);
2227 - _fnAjustColumnSizing( oSettings );
2228 -
2229 - if ( typeof bRedraw == 'undefined' || bRedraw )
2230 - {
2231 - this.fnDraw( false );
2232 - }
2233 - else if ( oSettings.oScroll.sX !== "" || oSettings.oScroll.sY !== "" )
2234 - {
2235 - /* If not redrawing, but scrolling, we want to apply the new column sizes anyway */
2236 - this.oApi._fnScrollDraw(oSettings);
2237 - }
2238 - };
2239 -
2240 - /*
2241 - * Plugin API functions
2242 - *
2243 - * This call will add the functions which are defined in _oExt.oApi to the
2244 - * DataTables object, providing a rather nice way to allow plug-in API functions. Note that
2245 - * this is done here, so that API function can actually override the built in API functions if
2246 - * required for a particular purpose.
2247 - */
2248 -
2249 - /*
2250 - * Function: _fnExternApiFunc
2251 - * Purpose: Create a wrapper function for exporting an internal func to an external API func
2252 - * Returns: function: - wrapped function
2253 - * Inputs: string:sFunc - API function name
2254 - */
2255 - function _fnExternApiFunc (sFunc)
2256 - {
2257 - return function() {
2258 - var aArgs = [_fnSettingsFromNode(this[_oExt.iApiIndex])].concat(
2259 - Array.prototype.slice.call(arguments) );
2260 - return _oExt.oApi[sFunc].apply( this, aArgs );
2261 - };
2262 - }
2263 -
2264 - for ( var sFunc in _oExt.oApi )
2265 - {
2266 - if ( sFunc )
2267 - {
2268 - /*
2269 - * Function: anon
2270 - * Purpose: Wrap the plug-in API functions in order to provide the settings as 1st arg
2271 - * and execute in this scope
2272 - * Returns: -
2273 - * Inputs: -
2274 - */
2275 - this[sFunc] = _fnExternApiFunc(sFunc);
2276 - }
2277 - }
2278 -
2279 -
2280 -
2281 - /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
2282 - * Section - Local functions
2283 - * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2284 -
2285 - /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
2286 - * Section - Initalisation
2287 - */
2288 -
2289 - /*
2290 - * Function: _fnInitalise
2291 - * Purpose: Draw the table for the first time, adding all required features
2292 - * Returns: -
2293 - * Inputs: object:oSettings - dataTables settings object
2294 - */
2295 - function _fnInitalise ( oSettings )
2296 - {
2297 - var i, iLen;
2298 -
2299 - /* Ensure that the table data is fully initialised */
2300 - if ( oSettings.bInitialised === false )
2301 - {
2302 - setTimeout( function(){ _fnInitalise( oSettings ); }, 200 );
2303 - return;
2304 - }
2305 -
2306 - /* Show the display HTML options */
2307 - _fnAddOptionsHtml( oSettings );
2308 -
2309 - /* Draw the headers for the table */
2310 - _fnDrawHead( oSettings );
2311 -
2312 - /* Okay to show that something is going on now */
2313 - _fnProcessingDisplay( oSettings, true );
2314 -
2315 - /* Calculate sizes for columns */
2316 - if ( oSettings.oFeatures.bAutoWidth )
2317 - {
2318 - _fnCalculateColumnWidths( oSettings );
2319 - }
2320 -
2321 - for ( i=0, iLen=oSettings.aoColumns.length ; i<iLen ; i++ )
2322 - {
2323 - if ( oSettings.aoColumns[i].sWidth !== null )
2324 - {
2325 - oSettings.aoColumns[i].nTh.style.width = _fnStringToCss( oSettings.aoColumns[i].sWidth );
2326 - }
2327 - }
2328 -
2329 - /* If there is default sorting required - let's do it. The sort function will do the
2330 - * drawing for us. Otherwise we draw the table regardless of the Ajax source - this allows
2331 - * the table to look initialised for Ajax sourcing data (show 'loading' message possibly)
2332 - */
2333 - if ( oSettings.oFeatures.bSort )
2334 - {
2335 - _fnSort( oSettings );
2336 - }
2337 - else
2338 - {
2339 - oSettings.aiDisplay = oSettings.aiDisplayMaster.slice();
2340 - _fnCalculateEnd( oSettings );
2341 - _fnDraw( oSettings );
2342 - }
2343 -
2344 - /* if there is an ajax source load the data */
2345 - if ( oSettings.sAjaxSource !== null && !oSettings.oFeatures.bServerSide )
2346 - {
2347 - oSettings.fnServerData.call( oSettings.oInstance, oSettings.sAjaxSource, [], function(json) {
2348 - /* Got the data - add it to the table */
2349 - for ( i=0 ; i<json.aaData.length ; i++ )
2350 - {
2351 - _fnAddData( oSettings, json.aaData[i] );
2352 - }
2353 -
2354 - /* Reset the init display for cookie saving. We've already done a filter, and
2355 - * therefore cleared it before. So we need to make it appear 'fresh'
2356 - */
2357 - oSettings.iInitDisplayStart = oSettings._iDisplayStart;
2358 -
2359 - if ( oSettings.oFeatures.bSort )
2360 - {
2361 - _fnSort( oSettings );
2362 - }
2363 - else
2364 - {
2365 - oSettings.aiDisplay = oSettings.aiDisplayMaster.slice();
2366 - _fnCalculateEnd( oSettings );
2367 - _fnDraw( oSettings );
2368 - }
2369 -
2370 - _fnProcessingDisplay( oSettings, false );
2371 - _fnInitComplete( oSettings, json );
2372 - } );
2373 - return;
2374 - }
2375 -
2376 - /* Server-side processing initialisation complete is done at the end of _fnDraw */
2377 - if ( !oSettings.oFeatures.bServerSide )
2378 - {
2379 - _fnProcessingDisplay( oSettings, false );
2380 - _fnInitComplete( oSettings );
2381 - }
2382 - }
2383 -
2384 - /*
2385 - * Function: _fnInitalise
2386 - * Purpose: Draw the table for the first time, adding all required features
2387 - * Returns: -
2388 - * Inputs: object:oSettings - dataTables settings object
2389 - */
2390 - function _fnInitComplete ( oSettings, json )
2391 - {
2392 - oSettings._bInitComplete = true;
2393 - if ( typeof oSettings.fnInitComplete == 'function' )
2394 - {
2395 - if ( typeof json != 'undefined' )
2396 - {
2397 - oSettings.fnInitComplete.call( oSettings.oInstance, oSettings, json );
2398 - }
2399 - else
2400 - {
2401 - oSettings.fnInitComplete.call( oSettings.oInstance, oSettings );
2402 - }
2403 - }
2404 - }
2405 -
2406 - /*
2407 - * Function: _fnLanguageProcess
2408 - * Purpose: Copy language variables from remote object to a local one
2409 - * Returns: -
2410 - * Inputs: object:oSettings - dataTables settings object
2411 - * object:oLanguage - Language information
2412 - * bool:bInit - init once complete
2413 - */
2414 - function _fnLanguageProcess( oSettings, oLanguage, bInit )
2415 - {
2416 - _fnMap( oSettings.oLanguage, oLanguage, 'sProcessing' );
2417 - _fnMap( oSettings.oLanguage, oLanguage, 'sLengthMenu' );
2418 - _fnMap( oSettings.oLanguage, oLanguage, 'sEmptyTable' );
2419 - _fnMap( oSettings.oLanguage, oLanguage, 'sZeroRecords' );
2420 - _fnMap( oSettings.oLanguage, oLanguage, 'sInfo' );
2421 - _fnMap( oSettings.oLanguage, oLanguage, 'sInfoEmpty' );
2422 - _fnMap( oSettings.oLanguage, oLanguage, 'sInfoFiltered' );
2423 - _fnMap( oSettings.oLanguage, oLanguage, 'sInfoPostFix' );
2424 - _fnMap( oSettings.oLanguage, oLanguage, 'sSearch' );
2425 -
2426 - if ( typeof oLanguage.oPaginate != 'undefined' )
2427 - {
2428 - _fnMap( oSettings.oLanguage.oPaginate, oLanguage.oPaginate, 'sFirst' );
2429 - _fnMap( oSettings.oLanguage.oPaginate, oLanguage.oPaginate, 'sPrevious' );
2430 - _fnMap( oSettings.oLanguage.oPaginate, oLanguage.oPaginate, 'sNext' );
2431 - _fnMap( oSettings.oLanguage.oPaginate, oLanguage.oPaginate, 'sLast' );
2432 - }
2433 -
2434 - /* Backwards compatibility - if there is no sEmptyTable given, then use the same as
2435 - * sZeroRecords - assuming that is given.
2436 - */
2437 - if ( typeof oLanguage.sEmptyTable == 'undefined' &&
2438 - typeof oLanguage.sZeroRecords != 'undefined' )
2439 - {
2440 - _fnMap( oSettings.oLanguage, oLanguage, 'sZeroRecords', 'sEmptyTable' );
2441 - }
2442 -
2443 - if ( bInit )
2444 - {
2445 - _fnInitalise( oSettings );
2446 - }
2447 - }
2448 -
2449 - /*
2450 - * Function: _fnAddColumn
2451 - * Purpose: Add a column to the list used for the table with default values
2452 - * Returns: -
2453 - * Inputs: object:oSettings - dataTables settings object
2454 - * node:nTh - the th element for this column
2455 - */
2456 - function _fnAddColumn( oSettings, nTh )
2457 - {
2458 - oSettings.aoColumns[ oSettings.aoColumns.length++ ] = {
2459 - "sType": null,
2460 - "_bAutoType": true,
2461 - "bVisible": true,
2462 - "bSearchable": true,
2463 - "bSortable": true,
2464 - "asSorting": [ 'asc', 'desc' ],
2465 - "sSortingClass": oSettings.oClasses.sSortable,
2466 - "sSortingClassJUI": oSettings.oClasses.sSortJUI,
2467 - "sTitle": nTh ? nTh.innerHTML : '',
2468 - "sName": '',
2469 - "sWidth": null,
2470 - "sWidthOrig": null,
2471 - "sClass": null,
2472 - "fnRender": null,
2473 - "bUseRendered": true,
2474 - "iDataSort": oSettings.aoColumns.length-1,
2475 - "sSortDataType": 'std',
2476 - "nTh": nTh ? nTh : document.createElement('th'),
2477 - "nTf": null,
2478 - "anThExtra": [],
2479 - "anTfExtra": []
2480 - };
2481 -
2482 - var iCol = oSettings.aoColumns.length-1;
2483 - var oCol = oSettings.aoColumns[ iCol ];
2484 -
2485 - /* Add a column specific filter */
2486 - if ( typeof oSettings.aoPreSearchCols[ iCol ] == 'undefined' ||
2487 - oSettings.aoPreSearchCols[ iCol ] === null )
2488 - {
2489 - oSettings.aoPreSearchCols[ iCol ] = {
2490 - "sSearch": "",
2491 - "bRegex": false,
2492 - "bSmart": true
2493 - };
2494 - }
2495 - else
2496 - {
2497 - /* Don't require that the user must specify bRegex and / or bSmart */
2498 - if ( typeof oSettings.aoPreSearchCols[ iCol ].bRegex == 'undefined' )
2499 - {
2500 - oSettings.aoPreSearchCols[ iCol ].bRegex = true;
2501 - }
2502 -
2503 - if ( typeof oSettings.aoPreSearchCols[ iCol ].bSmart == 'undefined' )
2504 - {
2505 - oSettings.aoPreSearchCols[ iCol ].bSmart = true;
2506 - }
2507 - }
2508 -
2509 - /* Use the column options function to initialise classes etc */
2510 - _fnColumnOptions( oSettings, iCol, null );
2511 - }
2512 -
2513 - /*
2514 - * Function: _fnColumnOptions
2515 - * Purpose: Apply options for a column
2516 - * Returns: -
2517 - * Inputs: object:oSettings - dataTables settings object
2518 - * int:iCol - column index to consider
2519 - * object:oOptions - object with sType, bVisible and bSearchable
2520 - */
2521 - function _fnColumnOptions( oSettings, iCol, oOptions )
2522 - {
2523 - var oCol = oSettings.aoColumns[ iCol ];
2524 -
2525 - /* User specified column options */
2526 - if ( typeof oOptions != 'undefined' && oOptions !== null )
2527 - {
2528 - if ( typeof oOptions.sType != 'undefined' )
2529 - {
2530 - oCol.sType = oOptions.sType;
2531 - oCol._bAutoType = false;
2532 - }
2533 -
2534 - _fnMap( oCol, oOptions, "bVisible" );
2535 - _fnMap( oCol, oOptions, "bSearchable" );
2536 - _fnMap( oCol, oOptions, "bSortable" );
2537 - _fnMap( oCol, oOptions, "sTitle" );
2538 - _fnMap( oCol, oOptions, "sName" );
2539 - _fnMap( oCol, oOptions, "sWidth" );
2540 - _fnMap( oCol, oOptions, "sWidth", "sWidthOrig" );
2541 - _fnMap( oCol, oOptions, "sClass" );
2542 - _fnMap( oCol, oOptions, "fnRender" );
2543 - _fnMap( oCol, oOptions, "bUseRendered" );
2544 - _fnMap( oCol, oOptions, "iDataSort" );
2545 - _fnMap( oCol, oOptions, "asSorting" );
2546 - _fnMap( oCol, oOptions, "sSortDataType" );
2547 - }
2548 -
2549 - /* Feature sorting overrides column specific when off */
2550 - if ( !oSettings.oFeatures.bSort )
2551 - {
2552 - oCol.bSortable = false;
2553 - }
2554 -
2555 - /* Check that the class assignment is correct for sorting */
2556 - if ( !oCol.bSortable ||
2557 - ($.inArray('asc', oCol.asSorting) == -1 && $.inArray('desc', oCol.asSorting) == -1) )
2558 - {
2559 - oCol.sSortingClass = oSettings.oClasses.sSortableNone;
2560 - oCol.sSortingClassJUI = "";
2561 - }
2562 - else if ( $.inArray('asc', oCol.asSorting) != -1 && $.inArray('desc', oCol.asSorting) == -1 )
2563 - {
2564 - oCol.sSortingClass = oSettings.oClasses.sSortableAsc;
2565 - oCol.sSortingClassJUI = oSettings.oClasses.sSortJUIAscAllowed;
2566 - }
2567 - else if ( $.inArray('asc', oCol.asSorting) == -1 && $.inArray('desc', oCol.asSorting) != -1 )
2568 - {
2569 - oCol.sSortingClass = oSettings.oClasses.sSortableDesc;
2570 - oCol.sSortingClassJUI = oSettings.oClasses.sSortJUIDescAllowed;
2571 - }
2572 - }
2573 -
2574 - /*
2575 - * Function: _fnAddData
2576 - * Purpose: Add a data array to the table, creating DOM node etc
2577 - * Returns: int: - >=0 if successful (index of new aoData entry), -1 if failed
2578 - * Inputs: object:oSettings - dataTables settings object
2579 - * array:aData - data array to be added
2580 - * Notes: There are two basic methods for DataTables to get data to display - a JS array
2581 - * (which is dealt with by this function), and the DOM, which has it's own optimised
2582 - * function (_fnGatherData). Be careful to make the same changes here as there and vice-versa
2583 - */
2584 - function _fnAddData ( oSettings, aDataSupplied )
2585 - {
2586 - /* Sanity check the length of the new array */
2587 - if ( aDataSupplied.length != oSettings.aoColumns.length &&
2588 - oSettings.iDrawError != oSettings.iDraw )
2589 - {
2590 - _fnLog( oSettings, 0, "Added data (size "+aDataSupplied.length+") does not match known "+
2591 - "number of columns ("+oSettings.aoColumns.length+")" );
2592 - oSettings.iDrawError = oSettings.iDraw;
2593 - return -1;
2594 - }
2595 -
2596 -
2597 - /* Create the object for storing information about this new row */
2598 - var aData = aDataSupplied.slice();
2599 - var iThisIndex = oSettings.aoData.length;
2600 - oSettings.aoData.push( {
2601 - "nTr": document.createElement('tr'),
2602 - "_iId": oSettings.iNextId++,
2603 - "_aData": aData,
2604 - "_anHidden": [],
2605 - "_sRowStripe": ''
2606 - } );
2607 -
2608 - /* Create the cells */
2609 - var nTd, sThisType;
2610 - for ( var i=0 ; i<aData.length ; i++ )
2611 - {
2612 - nTd = document.createElement('td');
2613 -
2614 - /* Allow null data (from a data array) - simply deal with it as a blank string */
2615 - if ( aData[i] === null )
2616 - {
2617 - aData[i] = '';
2618 - }
2619 -
2620 - if ( typeof oSettings.aoColumns[i].fnRender == 'function' )
2621 - {
2622 - var sRendered = oSettings.aoColumns[i].fnRender( {
2623 - "iDataRow": iThisIndex,
2624 - "iDataColumn": i,
2625 - "aData": aData,
2626 - "oSettings": oSettings
2627 - } );
2628 - nTd.innerHTML = sRendered;
2629 - if ( oSettings.aoColumns[i].bUseRendered )
2630 - {
2631 - /* Use the rendered data for filtering/sorting */
2632 - oSettings.aoData[iThisIndex]._aData[i] = sRendered;
2633 - }
2634 - }
2635 - else
2636 - {
2637 - nTd.innerHTML = aData[i];
2638 - }
2639 -
2640 - /* Cast everything as a string - so we can treat everything equally when sorting */
2641 - if ( typeof aData[i] != 'string' )
2642 - {
2643 - aData[i] += "";
2644 - }
2645 - aData[i] = $.trim(aData[i]);
2646 -
2647 - /* Add user defined class */
2648 - if ( oSettings.aoColumns[i].sClass !== null )
2649 - {
2650 - nTd.className = oSettings.aoColumns[i].sClass;
2651 - }
2652 -
2653 - /* See if we should auto-detect the column type */
2654 - if ( oSettings.aoColumns[i]._bAutoType && oSettings.aoColumns[i].sType != 'string' )
2655 - {
2656 - /* Attempt to auto detect the type - same as _fnGatherData() */
2657 - sThisType = _fnDetectType( oSettings.aoData[iThisIndex]._aData[i] );
2658 - if ( oSettings.aoColumns[i].sType === null )
2659 - {
2660 - oSettings.aoColumns[i].sType = sThisType;
2661 - }
2662 - else if ( oSettings.aoColumns[i].sType != sThisType )
2663 - {
2664 - /* String is always the 'fallback' option */
2665 - oSettings.aoColumns[i].sType = 'string';
2666 - }
2667 - }
2668 -
2669 - if ( oSettings.aoColumns[i].bVisible )
2670 - {
2671 - oSettings.aoData[iThisIndex].nTr.appendChild( nTd );
2672 - oSettings.aoData[iThisIndex]._anHidden[i] = null;
2673 - }
2674 - else
2675 - {
2676 - oSettings.aoData[iThisIndex]._anHidden[i] = nTd;
2677 - }
2678 - }
2679 -
2680 - /* Add to the display array */
2681 - oSettings.aiDisplayMaster.push( iThisIndex );
2682 - return iThisIndex;
2683 - }
2684 -
2685 - /*
2686 - * Function: _fnGatherData
2687 - * Purpose: Read in the data from the target table from the DOM
2688 - * Returns: -
2689 - * Inputs: object:oSettings - dataTables settings object
2690 - * Notes: This is a optimised version of _fnAddData (more or less) for reading information
2691 - * from the DOM. The basic actions must be identical in the two functions.
2692 - */
2693 - function _fnGatherData( oSettings )
2694 - {
2695 - var iLoop, i, iLen, j, jLen, jInner,
2696 - nTds, nTrs, nTd, aLocalData, iThisIndex,
2697 - iRow, iRows, iColumn, iColumns;
2698 -
2699 - /*
2700 - * Process by row first
2701 - * Add the data object for the whole table - storing the tr node. Note - no point in getting
2702 - * DOM based data if we are going to go and replace it with Ajax source data.
2703 - */
2704 - if ( oSettings.sAjaxSource === null )
2705 - {
2706 - nTrs = oSettings.nTBody.childNodes;
2707 - for ( i=0, iLen=nTrs.length ; i<iLen ; i++ )
2708 - {
2709 - if ( nTrs[i].nodeName.toUpperCase() == "TR" )
2710 - {
2711 - iThisIndex = oSettings.aoData.length;
2712 - oSettings.aoData.push( {
2713 - "nTr": nTrs[i],
2714 - "_iId": oSettings.iNextId++,
2715 - "_aData": [],
2716 - "_anHidden": [],
2717 - "_sRowStripe": ''
2718 - } );
2719 -
2720 - oSettings.aiDisplayMaster.push( iThisIndex );
2721 -
2722 - aLocalData = oSettings.aoData[iThisIndex]._aData;
2723 - nTds = nTrs[i].childNodes;
2724 - jInner = 0;
2725 -
2726 - for ( j=0, jLen=nTds.length ; j<jLen ; j++ )
2727 - {
2728 - if ( nTds[j].nodeName.toUpperCase() == "TD" )
2729 - {
2730 - aLocalData[jInner] = $.trim(nTds[j].innerHTML);
2731 - jInner++;
2732 - }
2733 - }
2734 - }
2735 - }
2736 - }
2737 -
2738 - /* Gather in the TD elements of the Table - note that this is basically the same as
2739 - * fnGetTdNodes, but that function takes account of hidden columns, which we haven't yet
2740 - * setup!
2741 - */
2742 - nTrs = _fnGetTrNodes( oSettings );
2743 - nTds = [];
2744 - for ( i=0, iLen=nTrs.length ; i<iLen ; i++ )
2745 - {
2746 - for ( j=0, jLen=nTrs[i].childNodes.length ; j<jLen ; j++ )
2747 - {
2748 - nTd = nTrs[i].childNodes[j];
2749 - if ( nTd.nodeName.toUpperCase() == "TD" )
2750 - {
2751 - nTds.push( nTd );
2752 - }
2753 - }
2754 - }
2755 -
2756 - /* Sanity check */
2757 - if ( nTds.length != nTrs.length * oSettings.aoColumns.length )
2758 - {
2759 - _fnLog( oSettings, 1, "Unexpected number of TD elements. Expected "+
2760 - (nTrs.length * oSettings.aoColumns.length)+" and got "+nTds.length+". DataTables does "+
2761 - "not support rowspan / colspan in the table body, and there must be one cell for each "+
2762 - "row/column combination." );
2763 - }
2764 -
2765 - /* Now process by column */
2766 - for ( iColumn=0, iColumns=oSettings.aoColumns.length ; iColumn<iColumns ; iColumn++ )
2767 - {
2768 - /* Get the title of the column - unless there is a user set one */
2769 - if ( oSettings.aoColumns[iColumn].sTitle === null )
2770 - {
2771 - oSettings.aoColumns[iColumn].sTitle = oSettings.aoColumns[iColumn].nTh.innerHTML;
2772 - }
2773 -
2774 - var
2775 - bAutoType = oSettings.aoColumns[iColumn]._bAutoType,
2776 - bRender = typeof oSettings.aoColumns[iColumn].fnRender == 'function',
2777 - bClass = oSettings.aoColumns[iColumn].sClass !== null,
2778 - bVisible = oSettings.aoColumns[iColumn].bVisible,
2779 - nCell, sThisType, sRendered;
2780 -
2781 - /* A single loop to rule them all (and be more efficient) */
2782 - if ( bAutoType || bRender || bClass || !bVisible )
2783 - {
2784 - for ( iRow=0, iRows=oSettings.aoData.length ; iRow<iRows ; iRow++ )
2785 - {
2786 - nCell = nTds[ (iRow*iColumns) + iColumn ];
2787 -
2788 - /* Type detection */
2789 - if ( bAutoType )
2790 - {
2791 - if ( oSettings.aoColumns[iColumn].sType != 'string' )
2792 - {
2793 - sThisType = _fnDetectType( oSettings.aoData[iRow]._aData[iColumn] );
2794 - if ( oSettings.aoColumns[iColumn].sType === null )
2795 - {
2796 - oSettings.aoColumns[iColumn].sType = sThisType;
2797 - }
2798 - else if ( oSettings.aoColumns[iColumn].sType != sThisType )
2799 - {
2800 - /* String is always the 'fallback' option */
2801 - oSettings.aoColumns[iColumn].sType = 'string';
2802 - }
2803 - }
2804 - }
2805 -
2806 - /* Rendering */
2807 - if ( bRender )
2808 - {
2809 - sRendered = oSettings.aoColumns[iColumn].fnRender( {
2810 - "iDataRow": iRow,
2811 - "iDataColumn": iColumn,
2812 - "aData": oSettings.aoData[iRow]._aData,
2813 - "oSettings": oSettings
2814 - } );
2815 - nCell.innerHTML = sRendered;
2816 - if ( oSettings.aoColumns[iColumn].bUseRendered )
2817 - {
2818 - /* Use the rendered data for filtering/sorting */
2819 - oSettings.aoData[iRow]._aData[iColumn] = sRendered;
2820 - }
2821 - }
2822 -
2823 - /* Classes */
2824 - if ( bClass )
2825 - {
2826 - nCell.className += ' '+oSettings.aoColumns[iColumn].sClass;
2827 - }
2828 -
2829 - /* Column visability */
2830 - if ( !bVisible )
2831 - {
2832 - oSettings.aoData[iRow]._anHidden[iColumn] = nCell;
2833 - nCell.parentNode.removeChild( nCell );
2834 - }
2835 - else
2836 - {
2837 - oSettings.aoData[iRow]._anHidden[iColumn] = null;
2838 - }
2839 - }
2840 - }
2841 - }
2842 - }
2843 -
2844 -
2845 -
2846 - /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
2847 - * Section - Drawing functions
2848 - */
2849 -
2850 - /*
2851 - * Function: _fnDrawHead
2852 - * Purpose: Create the HTML header for the table
2853 - * Returns: -
2854 - * Inputs: object:oSettings - dataTables settings object
2855 - */
2856 - function _fnDrawHead( oSettings )
2857 - {
2858 - var i, nTh, iLen, j, jLen;
2859 - var anTr = oSettings.nTHead.getElementsByTagName('tr');
2860 - var iThs = oSettings.nTHead.getElementsByTagName('th').length;
2861 - var iCorrector = 0;
2862 - var jqChildren;
2863 -
2864 - /* If there is a header in place - then use it - otherwise it's going to get nuked... */
2865 - if ( iThs !== 0 )
2866 - {
2867 - /* We've got a thead from the DOM, so remove hidden columns and apply width to vis cols */
2868 - for ( i=0, iLen=oSettings.aoColumns.length ; i<iLen ; i++ )
2869 - {
2870 - nTh = oSettings.aoColumns[i].nTh;
2871 -
2872 - if ( oSettings.aoColumns[i].sClass !== null )
2873 - {
2874 - $(nTh).addClass( oSettings.aoColumns[i].sClass );
2875 - }
2876 -
2877 - /* Cache and remove (if needed) any extra elements for this column in the header */
2878 - for ( j=1, jLen=anTr.length ; j<jLen ; j++ )
2879 - {
2880 - jqChildren = $(anTr[j]).children();
2881 - oSettings.aoColumns[i].anThExtra.push( jqChildren[i-iCorrector] );
2882 - if ( !oSettings.aoColumns[i].bVisible )
2883 - {
2884 - anTr[j].removeChild( jqChildren[i-iCorrector] );
2885 - }
2886 - }
2887 -
2888 - if ( oSettings.aoColumns[i].bVisible )
2889 - {
2890 - /* Set the title of the column if it is user defined (not what was auto detected) */
2891 - if ( oSettings.aoColumns[i].sTitle != nTh.innerHTML )
2892 - {
2893 - nTh.innerHTML = oSettings.aoColumns[i].sTitle;
2894 - }
2895 - }
2896 - else
2897 - {
2898 - nTh.parentNode.removeChild( nTh );
2899 - iCorrector++;
2900 - }
2901 - }
2902 - }
2903 - else
2904 - {
2905 - /* We don't have a header in the DOM - so we are going to have to create one */
2906 - var nTr = document.createElement( "tr" );
2907 -
2908 - for ( i=0, iLen=oSettings.aoColumns.length ; i<iLen ; i++ )
2909 - {
2910 - nTh = oSettings.aoColumns[i].nTh;
2911 - nTh.innerHTML = oSettings.aoColumns[i].sTitle;
2912 -
2913 - if ( oSettings.aoColumns[i].sClass !== null )
2914 - {
2915 - $(nTh).addClass( oSettings.aoColumns[i].sClass );
2916 - }
2917 -
2918 - if ( oSettings.aoColumns[i].bVisible )
2919 - {
2920 - nTr.appendChild( nTh );
2921 - }
2922 - }
2923 - $(oSettings.nTHead).html( '' )[0].appendChild( nTr );
2924 - }
2925 -
2926 - /* Add the extra markup needed by jQuery UI's themes */
2927 - if ( oSettings.bJUI )
2928 - {
2929 - for ( i=0, iLen=oSettings.aoColumns.length ; i<iLen ; i++ )
2930 - {
2931 - nTh = oSettings.aoColumns[i].nTh;
2932 -
2933 - var nDiv = document.createElement('div');
2934 - nDiv.className = oSettings.oClasses.sSortJUIWrapper;
2935 - $(nTh).contents().appendTo(nDiv);
2936 -
2937 - nDiv.appendChild( document.createElement('span') );
2938 - nTh.appendChild( nDiv );
2939 - }
2940 - }
2941 -
2942 - /* Add sort listener */
2943 - var fnNoSelect = function (e) {
2944 - this.onselectstart = function() { return false; };
2945 - return false;
2946 - };
2947 -
2948 - if ( oSettings.oFeatures.bSort )
2949 - {
2950 - for ( i=0 ; i<oSettings.aoColumns.length ; i++ )
2951 - {
2952 - if ( oSettings.aoColumns[i].bSortable !== false )
2953 - {
2954 - _fnSortAttachListener( oSettings, oSettings.aoColumns[i].nTh, i );
2955 -
2956 - /* Take the brutal approach to cancelling text selection in header */
2957 - $(oSettings.aoColumns[i].nTh).mousedown( fnNoSelect );
2958 - }
2959 - else
2960 - {
2961 - $(oSettings.aoColumns[i].nTh).addClass( oSettings.oClasses.sSortableNone );
2962 - }
2963 - }
2964 - }
2965 -
2966 - /* Cache the footer elements */
2967 - if ( oSettings.nTFoot !== null )
2968 - {
2969 - iCorrector = 0;
2970 - anTr = oSettings.nTFoot.getElementsByTagName('tr');
2971 - var nTfs = anTr[0].getElementsByTagName('th');
2972 -
2973 - for ( i=0, iLen=nTfs.length ; i<iLen ; i++ )
2974 - {
2975 - if ( typeof oSettings.aoColumns[i] != 'undefined' )
2976 - {
2977 - oSettings.aoColumns[i].nTf = nTfs[i-iCorrector];
2978 -
2979 - if ( oSettings.oClasses.sFooterTH !== "" )
2980 - {
2981 - oSettings.aoColumns[i].nTf.className += " "+oSettings.oClasses.sFooterTH;
2982 - }
2983 -
2984 - /* Deal with any extra elements for this column from the footer */
2985 - for ( j=1, jLen=anTr.length ; j<jLen ; j++ )
2986 - {
2987 - jqChildren = $(anTr[j]).children();
2988 - oSettings.aoColumns[i].anTfExtra.push( jqChildren[i-iCorrector] );
2989 - if ( !oSettings.aoColumns[i].bVisible )
2990 - {
2991 - anTr[j].removeChild( jqChildren[i-iCorrector] );
2992 - }
2993 - }
2994 -
2995 - if ( !oSettings.aoColumns[i].bVisible )
2996 - {
2997 - nTfs[i-iCorrector].parentNode.removeChild( nTfs[i-iCorrector] );
2998 - iCorrector++;
2999 - }
3000 - }
3001 - }
3002 - }
3003 - }
3004 -
3005 - /*
3006 - * Function: _fnDraw
3007 - * Purpose: Insert the required TR nodes into the table for display
3008 - * Returns: -
3009 - * Inputs: object:oSettings - dataTables settings object
3010 - */
3011 - function _fnDraw( oSettings )
3012 - {
3013 - var i, iLen;
3014 - var anRows = [];
3015 - var iRowCount = 0;
3016 - var bRowError = false;
3017 - var iStrips = oSettings.asStripClasses.length;
3018 - var iOpenRows = oSettings.aoOpenRows.length;
3019 -
3020 - oSettings.bDrawing = true;
3021 -
3022 - /* Check and see if we have an initial draw position from state saving */
3023 - if ( typeof oSettings.iInitDisplayStart != 'undefined' && oSettings.iInitDisplayStart != -1 )
3024 - {
3025 - if ( oSettings.oFeatures.bServerSide )
3026 - {
3027 - oSettings._iDisplayStart = oSettings.iInitDisplayStart;
3028 - }
3029 - else
3030 - {
3031 - oSettings._iDisplayStart = (oSettings.iInitDisplayStart >= oSettings.fnRecordsDisplay()) ?
3032 - 0 : oSettings.iInitDisplayStart;
3033 - }
3034 - oSettings.iInitDisplayStart = -1;
3035 - _fnCalculateEnd( oSettings );
3036 - }
3037 -
3038 - /* If we are dealing with Ajax - do it here */
3039 - if ( !oSettings.bDestroying && oSettings.oFeatures.bServerSide &&
3040 - !_fnAjaxUpdate( oSettings ) )
3041 - {
3042 - return;
3043 - }
3044 - else if ( !oSettings.oFeatures.bServerSide )
3045 - {
3046 - oSettings.iDraw++;
3047 - }
3048 -
3049 - if ( oSettings.aiDisplay.length !== 0 )
3050 - {
3051 - var iStart = oSettings._iDisplayStart;
3052 - var iEnd = oSettings._iDisplayEnd;
3053 -
3054 - if ( oSettings.oFeatures.bServerSide )
3055 - {
3056 - iStart = 0;
3057 - iEnd = oSettings.aoData.length;
3058 - }
3059 -
3060 - for ( var j=iStart ; j<iEnd ; j++ )
3061 - {
3062 - var aoData = oSettings.aoData[ oSettings.aiDisplay[j] ];
3063 - var nRow = aoData.nTr;
3064 -
3065 - /* Remove the old stripping classes and then add the new one */
3066 - if ( iStrips !== 0 )
3067 - {
3068 - var sStrip = oSettings.asStripClasses[ iRowCount % iStrips ];
3069 - if ( aoData._sRowStripe != sStrip )
3070 - {
3071 - $(nRow).removeClass( aoData._sRowStripe ).addClass( sStrip );
3072 - aoData._sRowStripe = sStrip;
3073 - }
3074 - }
3075 -
3076 - /* Custom row callback function - might want to manipule the row */
3077 - if ( typeof oSettings.fnRowCallback == "function" )
3078 - {
3079 - nRow = oSettings.fnRowCallback.call( oSettings.oInstance, nRow,
3080 - oSettings.aoData[ oSettings.aiDisplay[j] ]._aData, iRowCount, j );
3081 - if ( !nRow && !bRowError )
3082 - {
3083 - _fnLog( oSettings, 0, "A node was not returned by fnRowCallback" );
3084 - bRowError = true;
3085 - }
3086 - }
3087 -
3088 - anRows.push( nRow );
3089 - iRowCount++;
3090 -
3091 - /* If there is an open row - and it is attached to this parent - attach it on redraw */
3092 - if ( iOpenRows !== 0 )
3093 - {
3094 - for ( var k=0 ; k<iOpenRows ; k++ )
3095 - {
3096 - if ( nRow == oSettings.aoOpenRows[k].nParent )
3097 - {
3098 - anRows.push( oSettings.aoOpenRows[k].nTr );
3099 - }
3100 - }
3101 - }
3102 - }
3103 - }
3104 - else
3105 - {
3106 - /* Table is empty - create a row with an empty message in it */
3107 - anRows[ 0 ] = document.createElement( 'tr' );
3108 -
3109 - if ( typeof oSettings.asStripClasses[0] != 'undefined' )
3110 - {
3111 - anRows[ 0 ].className = oSettings.asStripClasses[0];
3112 - }
3113 -
3114 - var nTd = document.createElement( 'td' );
3115 - nTd.setAttribute( 'valign', "top" );
3116 - nTd.colSpan = _fnVisbleColumns( oSettings );
3117 - nTd.className = oSettings.oClasses.sRowEmpty;
3118 - if ( typeof oSettings.oLanguage.sEmptyTable != 'undefined' &&
3119 - oSettings.fnRecordsTotal() === 0 )
3120 - {
3121 - nTd.innerHTML = oSettings.oLanguage.sEmptyTable;
3122 - }
3123 - else
3124 - {
3125 - nTd.innerHTML = oSettings.oLanguage.sZeroRecords.replace(
3126 - '_MAX_', oSettings.fnFormatNumber(oSettings.fnRecordsTotal()) );
3127 - }
3128 -
3129 - anRows[ iRowCount ].appendChild( nTd );
3130 - }
3131 -
3132 - /* Callback the header and footer custom funcation if there is one */
3133 - if ( typeof oSettings.fnHeaderCallback == 'function' )
3134 - {
3135 - oSettings.fnHeaderCallback.call( oSettings.oInstance, $('>tr', oSettings.nTHead)[0],
3136 - _fnGetDataMaster( oSettings ), oSettings._iDisplayStart, oSettings.fnDisplayEnd(),
3137 - oSettings.aiDisplay );
3138 - }
3139 -
3140 - if ( typeof oSettings.fnFooterCallback == 'function' )
3141 - {
3142 - oSettings.fnFooterCallback.call( oSettings.oInstance, $('>tr', oSettings.nTFoot)[0],
3143 - _fnGetDataMaster( oSettings ), oSettings._iDisplayStart, oSettings.fnDisplayEnd(),
3144 - oSettings.aiDisplay );
3145 - }
3146 -
3147 - /*
3148 - * Need to remove any old row from the display - note we can't just empty the tbody using
3149 - * $().html('') since this will unbind the jQuery event handlers (even although the node
3150 - * still exists!) - equally we can't use innerHTML, since IE throws an exception.
3151 - */
3152 - var
3153 - nAddFrag = document.createDocumentFragment(),
3154 - nRemoveFrag = document.createDocumentFragment(),
3155 - nBodyPar, nTrs;
3156 -
3157 - if ( oSettings.nTBody )
3158 - {
3159 - nBodyPar = oSettings.nTBody.parentNode;
3160 - nRemoveFrag.appendChild( oSettings.nTBody );
3161 -
3162 - /* When doing infinite scrolling, only remove child rows when sorting, filtering or start
3163 - * up. When not infinite scroll, always do it.
3164 - */
3165 - if ( !oSettings.oScroll.bInfinite || !oSettings._bInitComplete ||
3166 - oSettings.bSorted || oSettings.bFiltered )
3167 - {
3168 - nTrs = oSettings.nTBody.childNodes;
3169 - for ( i=nTrs.length-1 ; i>=0 ; i-- )
3170 - {
3171 - nTrs[i].parentNode.removeChild( nTrs[i] );
3172 - }
3173 - }
3174 -
3175 - /* Put the draw table into the dom */
3176 - for ( i=0, iLen=anRows.length ; i<iLen ; i++ )
3177 - {
3178 - nAddFrag.appendChild( anRows[i] );
3179 - }
3180 -
3181 - oSettings.nTBody.appendChild( nAddFrag );
3182 - if ( nBodyPar !== null )
3183 - {
3184 - nBodyPar.appendChild( oSettings.nTBody );
3185 - }
3186 - }
3187 -
3188 - /* Call all required callback functions for the end of a draw */
3189 - for ( i=oSettings.aoDrawCallback.length-1 ; i>=0 ; i-- )
3190 - {
3191 - oSettings.aoDrawCallback[i].fn.call( oSettings.oInstance, oSettings );
3192 - }
3193 -
3194 - /* Draw is complete, sorting and filtering must be as well */
3195 - oSettings.bSorted = false;
3196 - oSettings.bFiltered = false;
3197 - oSettings.bDrawing = false;
3198 -
3199 - if ( oSettings.oFeatures.bServerSide )
3200 - {
3201 - _fnProcessingDisplay( oSettings, false );
3202 - if ( typeof oSettings._bInitComplete == 'undefined' )
3203 - {
3204 - _fnInitComplete( oSettings );
3205 - }
3206 - }
3207 - }
3208 -
3209 - /*
3210 - * Function: _fnReDraw
3211 - * Purpose: Redraw the table - taking account of the various features which are enabled
3212 - * Returns: -
3213 - * Inputs: object:oSettings - dataTables settings object
3214 - */
3215 - function _fnReDraw( oSettings )
3216 - {
3217 - if ( oSettings.oFeatures.bSort )
3218 - {
3219 - /* Sorting will refilter and draw for us */
3220 - _fnSort( oSettings, oSettings.oPreviousSearch );
3221 - }
3222 - else if ( oSettings.oFeatures.bFilter )
3223 - {
3224 - /* Filtering will redraw for us */
3225 - _fnFilterComplete( oSettings, oSettings.oPreviousSearch );
3226 - }
3227 - else
3228 - {
3229 - _fnCalculateEnd( oSettings );
3230 - _fnDraw( oSettings );
3231 - }
3232 - }
3233 -
3234 - /*
3235 - * Function: _fnAjaxUpdate
3236 - * Purpose: Update the table using an Ajax call
3237 - * Returns: bool: block the table drawing or not
3238 - * Inputs: object:oSettings - dataTables settings object
3239 - */
3240 - function _fnAjaxUpdate( oSettings )
3241 - {
3242 - if ( oSettings.bAjaxDataGet )
3243 - {
3244 - _fnProcessingDisplay( oSettings, true );
3245 - var iColumns = oSettings.aoColumns.length;
3246 - var aoData = [];
3247 - var i;
3248 -
3249 - /* Paging and general */
3250 - oSettings.iDraw++;
3251 - aoData.push( { "name": "sEcho", "value": oSettings.iDraw } );
3252 - aoData.push( { "name": "iColumns", "value": iColumns } );
3253 - aoData.push( { "name": "sColumns", "value": _fnColumnOrdering(oSettings) } );
3254 - aoData.push( { "name": "iDisplayStart", "value": oSettings._iDisplayStart } );
3255 - aoData.push( { "name": "iDisplayLength", "value": oSettings.oFeatures.bPaginate !== false ?
3256 - oSettings._iDisplayLength : -1 } );
3257 -
3258 - /* Filtering */
3259 - if ( oSettings.oFeatures.bFilter !== false )
3260 - {
3261 - aoData.push( { "name": "sSearch", "value": oSettings.oPreviousSearch.sSearch } );
3262 - aoData.push( { "name": "bRegex", "value": oSettings.oPreviousSearch.bRegex } );
3263 - for ( i=0 ; i<iColumns ; i++ )
3264 - {
3265 - aoData.push( { "name": "sSearch_"+i, "value": oSettings.aoPreSearchCols[i].sSearch } );
3266 - aoData.push( { "name": "bRegex_"+i, "value": oSettings.aoPreSearchCols[i].bRegex } );
3267 - aoData.push( { "name": "bSearchable_"+i, "value": oSettings.aoColumns[i].bSearchable } );
3268 - }
3269 - }
3270 -
3271 - /* Sorting */
3272 - if ( oSettings.oFeatures.bSort !== false )
3273 - {
3274 - var iFixed = oSettings.aaSortingFixed !== null ? oSettings.aaSortingFixed.length : 0;
3275 - var iUser = oSettings.aaSorting.length;
3276 - aoData.push( { "name": "iSortingCols", "value": iFixed+iUser } );
3277 - for ( i=0 ; i<iFixed ; i++ )
3278 - {
3279 - aoData.push( { "name": "iSortCol_"+i, "value": oSettings.aaSortingFixed[i][0] } );
3280 - aoData.push( { "name": "sSortDir_"+i, "value": oSettings.aaSortingFixed[i][1] } );
3281 - }
3282 -
3283 - for ( i=0 ; i<iUser ; i++ )
3284 - {
3285 - aoData.push( { "name": "iSortCol_"+(i+iFixed), "value": oSettings.aaSorting[i][0] } );
3286 - aoData.push( { "name": "sSortDir_"+(i+iFixed), "value": oSettings.aaSorting[i][1] } );
3287 - }
3288 -
3289 - for ( i=0 ; i<iColumns ; i++ )
3290 - {
3291 - aoData.push( { "name": "bSortable_"+i, "value": oSettings.aoColumns[i].bSortable } );
3292 - }
3293 - }
3294 -
3295 - oSettings.fnServerData.call( oSettings.oInstance, oSettings.sAjaxSource, aoData,
3296 - function(json) {
3297 - _fnAjaxUpdateDraw( oSettings, json );
3298 - } );
3299 - return false;
3300 - }
3301 - else
3302 - {
3303 - return true;
3304 - }
3305 - }
3306 -
3307 - /*
3308 - * Function: _fnAjaxUpdateDraw
3309 - * Purpose: Data the data from the server (nuking the old) and redraw the table
3310 - * Returns: -
3311 - * Inputs: object:oSettings - dataTables settings object
3312 - * object:json - json data return from the server.
3313 - * The following must be defined:
3314 - * iTotalRecords, iTotalDisplayRecords, aaData
3315 - * The following may be defined:
3316 - * sColumns
3317 - */
3318 - function _fnAjaxUpdateDraw ( oSettings, json )
3319 - {
3320 - if ( typeof json.sEcho != 'undefined' )
3321 - {
3322 - /* Protect against old returns over-writing a new one. Possible when you get
3323 - * very fast interaction, and later queires are completed much faster
3324 - */
3325 - if ( json.sEcho*1 < oSettings.iDraw )
3326 - {
3327 - return;
3328 - }
3329 - else
3330 - {
3331 - oSettings.iDraw = json.sEcho * 1;
3332 - }
3333 - }
3334 -
3335 - if ( !oSettings.oScroll.bInfinite ||
3336 - (oSettings.oScroll.bInfinite && (oSettings.bSorted || oSettings.bFiltered)) )
3337 - {
3338 - _fnClearTable( oSettings );
3339 - }
3340 - oSettings._iRecordsTotal = json.iTotalRecords;
3341 - oSettings._iRecordsDisplay = json.iTotalDisplayRecords;
3342 -
3343 - /* Determine if reordering is required */
3344 - var sOrdering = _fnColumnOrdering(oSettings);
3345 - var bReOrder = (typeof json.sColumns != 'undefined' && sOrdering !== "" && json.sColumns != sOrdering );
3346 - if ( bReOrder )
3347 - {
3348 - var aiIndex = _fnReOrderIndex( oSettings, json.sColumns );
3349 - }
3350 -
3351 - for ( var i=0, iLen=json.aaData.length ; i<iLen ; i++ )
3352 - {
3353 - if ( bReOrder )
3354 - {
3355 - /* If we need to re-order, then create a new array with the correct order and add it */
3356 - var aData = [];
3357 - for ( var j=0, jLen=oSettings.aoColumns.length ; j<jLen ; j++ )
3358 - {
3359 - aData.push( json.aaData[i][ aiIndex[j] ] );
3360 - }
3361 - _fnAddData( oSettings, aData );
3362 - }
3363 - else
3364 - {
3365 - /* No re-order required, sever got it "right" - just straight add */
3366 - _fnAddData( oSettings, json.aaData[i] );
3367 - }
3368 - }
3369 - oSettings.aiDisplay = oSettings.aiDisplayMaster.slice();
3370 -
3371 - oSettings.bAjaxDataGet = false;
3372 - _fnDraw( oSettings );
3373 - oSettings.bAjaxDataGet = true;
3374 - _fnProcessingDisplay( oSettings, false );
3375 - }
3376 -
3377 -
3378 - /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
3379 - * Section - Options (features) HTML
3380 - */
3381 -
3382 - /*
3383 - * Function: _fnAddOptionsHtml
3384 - * Purpose: Add the options to the page HTML for the table
3385 - * Returns: -
3386 - * Inputs: object:oSettings - dataTables settings object
3387 - */
3388 - function _fnAddOptionsHtml ( oSettings )
3389 - {
3390 - /*
3391 - * Create a temporary, empty, div which we can later on replace with what we have generated
3392 - * we do it this way to rendering the 'options' html offline - speed :-)
3393 - */
3394 - var nHolding = document.createElement( 'div' );
3395 - oSettings.nTable.parentNode.insertBefore( nHolding, oSettings.nTable );
3396 -
3397 - /*
3398 - * All DataTables are wrapped in a div - this is not currently optional - backwards
3399 - * compatability. It can be removed if you don't want it.
3400 - */
3401 - oSettings.nTableWrapper = document.createElement( 'div' );
3402 - oSettings.nTableWrapper.className = oSettings.oClasses.sWrapper;
3403 - if ( oSettings.sTableId !== '' )
3404 - {
3405 - oSettings.nTableWrapper.setAttribute( 'id', oSettings.sTableId+'_wrapper' );
3406 - }
3407 -
3408 - /* Track where we want to insert the option */
3409 - var nInsertNode = oSettings.nTableWrapper;
3410 -
3411 - /* Loop over the user set positioning and place the elements as needed */
3412 - var aDom = oSettings.sDom.split('');
3413 - var nTmp, iPushFeature, cOption, nNewNode, cNext, sAttr, j;
3414 - for ( var i=0 ; i<aDom.length ; i++ )
3415 - {
3416 - iPushFeature = 0;
3417 - cOption = aDom[i];
3418 -
3419 - if ( cOption == '<' )
3420 - {
3421 - /* New container div */
3422 - nNewNode = document.createElement( 'div' );
3423 -
3424 - /* Check to see if we should append an id and/or a class name to the container */
3425 - cNext = aDom[i+1];
3426 - if ( cNext == "'" || cNext == '"' )
3427 - {
3428 - sAttr = "";
3429 - j = 2;
3430 - while ( aDom[i+j] != cNext )
3431 - {
3432 - sAttr += aDom[i+j];
3433 - j++;
3434 - }
3435 -
3436 - /* Replace jQuery UI constants */
3437 - if ( sAttr == "H" )
3438 - {
3439 - sAttr = "fg-toolbar ui-toolbar ui-widget-header ui-corner-tl ui-corner-tr ui-helper-clearfix";
3440 - }
3441 - else if ( sAttr == "F" )
3442 - {
3443 - sAttr = "fg-toolbar ui-toolbar ui-widget-header ui-corner-bl ui-corner-br ui-helper-clearfix";
3444 - }
3445 -
3446 - /* The attribute can be in the format of "#id.class", "#id" or "class" This logic
3447 - * breaks the string into parts and applies them as needed
3448 - */
3449 - if ( sAttr.indexOf('.') != -1 )
3450 - {
3451 - var aSplit = sAttr.split('.');
3452 - nNewNode.setAttribute('id', aSplit[0].substr(1, aSplit[0].length-1) );
3453 - nNewNode.className = aSplit[1];
3454 - }
3455 - else if ( sAttr.charAt(0) == "#" )
3456 - {
3457 - nNewNode.setAttribute('id', sAttr.substr(1, sAttr.length-1) );
3458 - }
3459 - else
3460 - {
3461 - nNewNode.className = sAttr;
3462 - }
3463 -
3464 - i += j; /* Move along the position array */
3465 - }
3466 -
3467 - nInsertNode.appendChild( nNewNode );
3468 - nInsertNode = nNewNode;
3469 - }
3470 - else if ( cOption == '>' )
3471 - {
3472 - /* End container div */
3473 - nInsertNode = nInsertNode.parentNode;
3474 - }
3475 - else if ( cOption == 'l' && oSettings.oFeatures.bPaginate && oSettings.oFeatures.bLengthChange )
3476 - {
3477 - /* Length */
3478 - nTmp = _fnFeatureHtmlLength( oSettings );
3479 - iPushFeature = 1;
3480 - }
3481 - else if ( cOption == 'f' && oSettings.oFeatures.bFilter )
3482 - {
3483 - /* Filter */
3484 - nTmp = _fnFeatureHtmlFilter( oSettings );
3485 - iPushFeature = 1;
3486 - }
3487 - else if ( cOption == 'r' && oSettings.oFeatures.bProcessing )
3488 - {
3489 - /* pRocessing */
3490 - nTmp = _fnFeatureHtmlProcessing( oSettings );
3491 - iPushFeature = 1;
3492 - }
3493 - else if ( cOption == 't' )
3494 - {
3495 - /* Table */
3496 - nTmp = _fnFeatureHtmlTable( oSettings );
3497 - iPushFeature = 1;
3498 - }
3499 - else if ( cOption == 'i' && oSettings.oFeatures.bInfo )
3500 - {
3501 - /* Info */
3502 - nTmp = _fnFeatureHtmlInfo( oSettings );
3503 - iPushFeature = 1;
3504 - }
3505 - else if ( cOption == 'p' && oSettings.oFeatures.bPaginate )
3506 - {
3507 - /* Pagination */
3508 - nTmp = _fnFeatureHtmlPaginate( oSettings );
3509 - iPushFeature = 1;
3510 - }
3511 - else if ( _oExt.aoFeatures.length !== 0 )
3512 - {
3513 - /* Plug-in features */
3514 - var aoFeatures = _oExt.aoFeatures;
3515 - for ( var k=0, kLen=aoFeatures.length ; k<kLen ; k++ )
3516 - {
3517 - if ( cOption == aoFeatures[k].cFeature )
3518 - {
3519 - nTmp = aoFeatures[k].fnInit( oSettings );
3520 - if ( nTmp )
3521 - {
3522 - iPushFeature = 1;
3523 - }
3524 - break;
3525 - }
3526 - }
3527 - }
3528 -
3529 - /* Add to the 2D features array */
3530 - if ( iPushFeature == 1 && nTmp !== null )
3531 - {
3532 - if ( typeof oSettings.aanFeatures[cOption] != 'object' )
3533 - {
3534 - oSettings.aanFeatures[cOption] = [];
3535 - }
3536 - oSettings.aanFeatures[cOption].push( nTmp );
3537 - nInsertNode.appendChild( nTmp );
3538 - }
3539 - }
3540 -
3541 - /* Built our DOM structure - replace the holding div with what we want */
3542 - nHolding.parentNode.replaceChild( oSettings.nTableWrapper, nHolding );
3543 - }
3544 -
3545 -
3546 - /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
3547 - * Section - Feature: Filtering
3548 - */
3549 -
3550 - /*
3551 - * Function: _fnFeatureHtmlTable
3552 - * Purpose: Add any control elements for the table - specifically scrolling
3553 - * Returns: node: - Node to add to the DOM
3554 - * Inputs: object:oSettings - dataTables settings object
3555 - */
3556 - function _fnFeatureHtmlTable ( oSettings )
3557 - {
3558 - /* Chack if scrolling is enabled or not - if not then leave the DOM unaltered */
3559 - if ( oSettings.oScroll.sX === "" && oSettings.oScroll.sY === "" )
3560 - {
3561 - return oSettings.nTable;
3562 - }
3563 -
3564 - /*
3565 - * The HTML structure that we want to generate in this function is:
3566 - * div - nScroller
3567 - * div - nScrollHead
3568 - * div - nScrollHeadInner
3569 - * table - nScrollHeadTable
3570 - * thead - nThead
3571 - * div - nScrollBody
3572 - * table - oSettings.nTable
3573 - * thead - nTheadSize
3574 - * tbody - nTbody
3575 - * div - nScrollFoot
3576 - * div - nScrollFootInner
3577 - * table - nScrollFootTable
3578 - * tfoot - nTfoot
3579 - */
3580 - var
3581 - nScroller = document.createElement('div'),
3582 - nScrollHead = document.createElement('div'),
3583 - nScrollHeadInner = document.createElement('div'),
3584 - nScrollBody = document.createElement('div'),
3585 - nScrollFoot = document.createElement('div'),
3586 - nScrollFootInner = document.createElement('div'),
3587 - nScrollHeadTable = oSettings.nTable.cloneNode(false),
3588 - nScrollFootTable = oSettings.nTable.cloneNode(false),
3589 - nThead = oSettings.nTable.getElementsByTagName('thead')[0],
3590 - nTfoot = oSettings.nTable.getElementsByTagName('tfoot').length === 0 ? null :
3591 - oSettings.nTable.getElementsByTagName('tfoot')[0],
3592 - oClasses = (typeof oInit.bJQueryUI != 'undefined' && oInit.bJQueryUI) ?
3593 - _oExt.oJUIClasses : _oExt.oStdClasses;
3594 -
3595 - nScrollHead.appendChild( nScrollHeadInner );
3596 - nScrollFoot.appendChild( nScrollFootInner );
3597 - nScrollBody.appendChild( oSettings.nTable );
3598 - nScroller.appendChild( nScrollHead );
3599 - nScroller.appendChild( nScrollBody );
3600 - nScrollHeadInner.appendChild( nScrollHeadTable );
3601 - nScrollHeadTable.appendChild( nThead );
3602 - if ( nTfoot !== null )
3603 - {
3604 - nScroller.appendChild( nScrollFoot );
3605 - nScrollFootInner.appendChild( nScrollFootTable );
3606 - nScrollFootTable.appendChild( nTfoot );
3607 - }
3608 -
3609 - nScroller.className = oClasses.sScrollWrapper;
3610 - nScrollHead.className = oClasses.sScrollHead;
3611 - nScrollHeadInner.className = oClasses.sScrollHeadInner;
3612 - nScrollBody.className = oClasses.sScrollBody;
3613 - nScrollFoot.className = oClasses.sScrollFoot;
3614 - nScrollFootInner.className = oClasses.sScrollFootInner;
3615 -
3616 - if ( oSettings.oScroll.bAutoCss )
3617 - {
3618 - nScrollHead.style.overflow = "hidden";
3619 - nScrollHead.style.position = "relative";
3620 - nScrollFoot.style.overflow = "hidden";
3621 - nScrollBody.style.overflow = "auto";
3622 - }
3623 -
3624 - nScrollHead.style.border = "0";
3625 - nScrollFoot.style.border = "0";
3626 - nScrollHeadInner.style.width = "150%"; /* will be overwritten */
3627 -
3628 - /* Modify attributes to respect the clones */
3629 - nScrollHeadTable.removeAttribute('id');
3630 - nScrollHeadTable.style.marginLeft = "0";
3631 - oSettings.nTable.style.marginLeft = "0";
3632 - if ( nTfoot !== null )
3633 - {
3634 - nScrollFootTable.removeAttribute('id');
3635 - nScrollFootTable.style.marginLeft = "0";
3636 - }
3637 -
3638 - /* Move any caption elements from the body to the header */
3639 - var nCaptions = $('>caption', oSettings.nTable);
3640 - for ( var i=0, iLen=nCaptions.length ; i<iLen ; i++ )
3641 - {
3642 - nScrollHeadTable.appendChild( nCaptions[i] );
3643 - }
3644 -
3645 - /*
3646 - * Sizing
3647 - */
3648 - /* When xscrolling add the width and a scroller to move the header with the body */
3649 - if ( oSettings.oScroll.sX !== "" )
3650 - {
3651 - nScrollHead.style.width = _fnStringToCss( oSettings.oScroll.sX );
3652 - nScrollBody.style.width = _fnStringToCss( oSettings.oScroll.sX );
3653 -
3654 - if ( nTfoot !== null )
3655 - {
3656 - nScrollFoot.style.width = _fnStringToCss( oSettings.oScroll.sX );
3657 - }
3658 -
3659 - /* When the body is scrolled, then we also want to scroll the headers */
3660 - $(nScrollBody).scroll( function (e) {
3661 - nScrollHead.scrollLeft = this.scrollLeft;
3662 -
3663 - if ( nTfoot !== null )
3664 - {
3665 - nScrollFoot.scrollLeft = this.scrollLeft;
3666 - }
3667 - } );
3668 - }
3669 -
3670 - /* When yscrolling, add the height */
3671 - if ( oSettings.oScroll.sY !== "" )
3672 - {
3673 - nScrollBody.style.height = _fnStringToCss( oSettings.oScroll.sY );
3674 - }
3675 -
3676 - /* Redraw - align columns across the tables */
3677 - oSettings.aoDrawCallback.push( {
3678 - "fn": _fnScrollDraw,
3679 - "sName": "scrolling"
3680 - } );
3681 -
3682 - /* Infinite scrolling event handlers */
3683 - if ( oSettings.oScroll.bInfinite )
3684 - {
3685 - $(nScrollBody).scroll( function() {
3686 - /* Use a blocker to stop scrolling from loading more data while other data is still loading */
3687 - if ( !oSettings.bDrawing )
3688 - {
3689 - /* Check if we should load the next data set */
3690 - if ( $(this).scrollTop() + $(this).height() >
3691 - $(oSettings.nTable).height() - oSettings.oScroll.iLoadGap )
3692 - {
3693 - /* Only do the redraw if we have to - we might be at the end of the data */
3694 - if ( oSettings.fnDisplayEnd() < oSettings.fnRecordsDisplay() )
3695 - {
3696 - _fnPageChange( oSettings, 'next' );
3697 - _fnCalculateEnd( oSettings );
3698 - _fnDraw( oSettings );
3699 - }
3700 - }
3701 - }
3702 - } );
3703 - }
3704 -
3705 - oSettings.nScrollHead = nScrollHead;
3706 - oSettings.nScrollFoot = nScrollFoot;
3707 -
3708 - return nScroller;
3709 - }
3710 -
3711 - /*
3712 - * Function: _fnScrollDraw
3713 - * Purpose: Update the various tables for resizing
3714 - * Returns: node: - Node to add to the DOM
3715 - * Inputs: object:o - dataTables settings object
3716 - * Notes: It's a bit of a pig this function, but basically the idea to:
3717 - * 1. Re-create the table inside the scrolling div
3718 - * 2. Take live measurements from the DOM
3719 - * 3. Apply the measurements
3720 - * 4. Clean up
3721 - */
3722 - function _fnScrollDraw ( o )
3723 - {
3724 - var
3725 - nScrollHeadInner = o.nScrollHead.getElementsByTagName('div')[0],
3726 - nScrollHeadTable = nScrollHeadInner.getElementsByTagName('table')[0],
3727 - nScrollBody = o.nTable.parentNode,
3728 - i, iLen, j, jLen, anHeadToSize, anHeadSizers, anFootSizers, anFootToSize, oStyle, iVis,
3729 - iWidth, aApplied=[], iSanityWidth;
3730 -
3731 - /*
3732 - * 1. Re-create the table inside the scrolling div
3733 - */
3734 -
3735 - /* Remove the old minimised thead and tfoot elements in the inner table */
3736 - var nTheadSize = o.nTable.getElementsByTagName('thead');
3737 - if ( nTheadSize.length > 0 )
3738 - {
3739 - o.nTable.removeChild( nTheadSize[0] );
3740 - }
3741 -
3742 - if ( o.nTFoot !== null )
3743 - {
3744 - /* Remove the old minimised footer element in the cloned header */
3745 - var nTfootSize = o.nTable.getElementsByTagName('tfoot');
3746 - if ( nTfootSize.length > 0 )
3747 - {
3748 - o.nTable.removeChild( nTfootSize[0] );
3749 - }
3750 - }
3751 -
3752 - /* Clone the current header and footer elements and then place it into the inner table */
3753 - nTheadSize = o.nTHead.cloneNode(true);
3754 - o.nTable.insertBefore( nTheadSize, o.nTable.childNodes[0] );
3755 -
3756 - if ( o.nTFoot !== null )
3757 - {
3758 - nTfootSize = o.nTFoot.cloneNode(true);
3759 - o.nTable.insertBefore( nTfootSize, o.nTable.childNodes[1] );
3760 - }
3761 -
3762 - /*
3763 - * 2. Take live measurements from the DOM - do not alter the DOM itself!
3764 - */
3765 -
3766 - /* Remove old sizing and apply the calculated column widths
3767 - * Get the unique column headers in the newly created (cloned) header. We want to apply the
3768 - * calclated sizes to this header
3769 - */
3770 - var nThs = _fnGetUniqueThs( nTheadSize );
3771 - for ( i=0, iLen=nThs.length ; i<iLen ; i++ )
3772 - {
3773 - iVis = _fnVisibleToColumnIndex( o, i );
3774 - nThs[i].style.width = o.aoColumns[iVis].sWidth;
3775 - }
3776 -
3777 - if ( o.nTFoot !== null )
3778 - {
3779 - _fnApplyToChildren( function(n) {
3780 - n.style.width = "";
3781 - }, nTfootSize.getElementsByTagName('tr') );
3782 - }
3783 -
3784 - /* Size the table as a whole */
3785 - iSanityWidth = $(o.nTable).outerWidth();
3786 - if ( o.oScroll.sX === "" )
3787 - {
3788 - /* No x scrolling */
3789 - o.nTable.style.width = "100%";
3790 -
3791 - /* I know this is rubbish - but IE7 will make the width of the table when 100% include
3792 - * the scrollbar - which is shouldn't. This needs feature detection in future - to do
3793 - */
3794 - if ( $.browser.msie && $.browser.version <= 7 )
3795 - {
3796 - o.nTable.style.width = _fnStringToCss( $(o.nTable).outerWidth()-o.oScroll.iBarWidth );
3797 - }
3798 - }
3799 - else
3800 - {
3801 - if ( o.oScroll.sXInner !== "" )
3802 - {
3803 - /* x scroll inner has been given - use it */
3804 - o.nTable.style.width = _fnStringToCss(o.oScroll.sXInner);
3805 - }
3806 - else if ( iSanityWidth == $(nScrollBody).width() &&
3807 - $(nScrollBody).height() < $(o.nTable).height() )
3808 - {
3809 - /* There is y-scrolling - try to take account of the y scroll bar */
3810 - o.nTable.style.width = _fnStringToCss( iSanityWidth-o.oScroll.iBarWidth );
3811 - if ( $(o.nTable).outerWidth() > iSanityWidth-o.oScroll.iBarWidth )
3812 - {
3813 - /* Not possible to take account of it */
3814 - o.nTable.style.width = _fnStringToCss( iSanityWidth );
3815 - }
3816 - }
3817 - else
3818 - {
3819 - /* All else fails */
3820 - o.nTable.style.width = _fnStringToCss( iSanityWidth );
3821 - }
3822 - }
3823 -
3824 - /* Recalculate the sanity width - now that we've applied the required width, before it was
3825 - * a temporary variable. This is required because the column width calculation is done
3826 - * before this table DOM is created.
3827 - */
3828 - iSanityWidth = $(o.nTable).outerWidth();
3829 -
3830 - /* We want the hidden header to have zero height, so remove padding and borders. Then
3831 - * set the width based on the real headers
3832 - */
3833 - anHeadToSize = o.nTHead.getElementsByTagName('tr');
3834 - anHeadSizers = nTheadSize.getElementsByTagName('tr');
3835 -
3836 - _fnApplyToChildren( function(nSizer, nToSize) {
3837 - oStyle = nSizer.style;
3838 - oStyle.paddingTop = "0";
3839 - oStyle.paddingBottom = "0";
3840 - oStyle.borderTopWidth = "0";
3841 - oStyle.borderBottomWidth = "0";
3842 - oStyle.height = 0;
3843 -
3844 - iWidth = $(nSizer).width();
3845 - nToSize.style.width = _fnStringToCss( iWidth );
3846 - aApplied.push( iWidth );
3847 - }, anHeadSizers, anHeadToSize );
3848 - $(anHeadSizers).height(0);
3849 -
3850 - if ( o.nTFoot !== null )
3851 - {
3852 - /* Clone the current footer and then place it into the body table as a "hidden header" */
3853 - anFootSizers = nTfootSize.getElementsByTagName('tr');
3854 - anFootToSize = o.nTFoot.getElementsByTagName('tr');
3855 -
3856 - _fnApplyToChildren( function(nSizer, nToSize) {
3857 - oStyle = nSizer.style;
3858 - oStyle.paddingTop = "0";
3859 - oStyle.paddingBottom = "0";
3860 - oStyle.borderTopWidth = "0";
3861 - oStyle.borderBottomWidth = "0";
3862 -
3863 - iWidth = $(nSizer).width();
3864 - nToSize.style.width = _fnStringToCss( iWidth );
3865 - aApplied.push( iWidth );
3866 - }, anFootSizers, anFootToSize );
3867 - $(anFootSizers).height(0);
3868 - }
3869 -
3870 - /*
3871 - * 3. Apply the measurements
3872 - */
3873 -
3874 - /* "Hide" the header and footer that we used for the sizing. We want to also fix their width
3875 - * to what they currently are
3876 - */
3877 - _fnApplyToChildren( function(nSizer) {
3878 - nSizer.innerHTML = "";
3879 - nSizer.style.width = _fnStringToCss( aApplied.shift() );
3880 - }, anHeadSizers );
3881 -
3882 - if ( o.nTFoot !== null )
3883 - {
3884 - _fnApplyToChildren( function(nSizer) {
3885 - nSizer.innerHTML = "";
3886 - nSizer.style.width = _fnStringToCss( aApplied.shift() );
3887 - }, anFootSizers );
3888 - }
3889 -
3890 - /* Sanity check that the table is of a sensible width. If not then we are going to get
3891 - * misalignment
3892 - */
3893 - if ( $(o.nTable).outerWidth() < iSanityWidth )
3894 - {
3895 - if ( o.oScroll.sX === "" )
3896 - {
3897 - _fnLog( o, 1, "The table cannot fit into the current element which will cause column"+
3898 - " misalignment. It is suggested that you enable x-scrolling or increase the width"+
3899 - " the table has in which to be drawn" );
3900 - }
3901 - else if ( o.oScroll.sXInner !== "" )
3902 - {
3903 - _fnLog( o, 1, "The table cannot fit into the current element which will cause column"+
3904 - " misalignment. It is suggested that you increase the sScrollXInner property to"+
3905 - " allow it to draw in a larger area, or simply remove that parameter to allow"+
3906 - " automatic calculation" );
3907 - }
3908 - }
3909 -
3910 -
3911 - /*
3912 - * 4. Clean up
3913 - */
3914 -
3915 - if ( o.oScroll.sY === "" )
3916 - {
3917 - /* IE7< puts a vertical scrollbar in place (when it shouldn't be) due to subtracting
3918 - * the scrollbar height from the visible display, rather than adding it on. We need to
3919 - * set the height in order to sort this. Don't want to do it in any other browsers.
3920 - */
3921 - if ( $.browser.msie && $.browser.version <= 7 )
3922 - {
3923 - nScrollBody.style.height = _fnStringToCss( o.nTable.offsetHeight+o.oScroll.iBarWidth );
3924 - }
3925 - }
3926 -
3927 - if ( o.oScroll.sY !== "" && o.oScroll.bCollapse )
3928 - {
3929 - nScrollBody.style.height = _fnStringToCss( o.oScroll.sY );
3930 -
3931 - var iExtra = (o.oScroll.sX !== "" && o.nTable.offsetWidth > nScrollBody.offsetWidth) ?
3932 - o.oScroll.iBarWidth : 0;
3933 - if ( o.nTable.offsetHeight < nScrollBody.offsetHeight )
3934 - {
3935 - nScrollBody.style.height = _fnStringToCss( $(o.nTable).height()+iExtra );
3936 - }
3937 - }
3938 -
3939 - /* Finally set the width's of the header and footer tables */
3940 - var iOuterWidth = $(o.nTable).outerWidth();
3941 - nScrollHeadTable.style.width = _fnStringToCss( iOuterWidth );
3942 - nScrollHeadInner.style.width = _fnStringToCss( iOuterWidth+o.oScroll.iBarWidth );
3943 - nScrollHeadInner.parentNode.style.width = _fnStringToCss( $(nScrollBody).width() );
3944 -
3945 - if ( o.nTFoot !== null )
3946 - {
3947 - var
3948 - nScrollFootInner = o.nScrollFoot.getElementsByTagName('div')[0],
3949 - nScrollFootTable = nScrollFootInner.getElementsByTagName('table')[0];
3950 -
3951 - nScrollFootInner.style.width = _fnStringToCss( o.nTable.offsetWidth+o.oScroll.iBarWidth );
3952 - nScrollFootTable.style.width = _fnStringToCss( o.nTable.offsetWidth );
3953 - }
3954 -
3955 - /* If sorting or filtering has occured, jump the scrolling back to the top */
3956 - if ( o.bSorted || o.bFiltered )
3957 - {
3958 - nScrollBody.scrollTop = 0;
3959 - }
3960 - }
3961 -
3962 - /*
3963 - * Function: _fnAjustColumnSizing
3964 - * Purpose: Ajust the table column widths for new data
3965 - * Returns: -
3966 - * Inputs: object:oSettings - dataTables settings object
3967 - * Notes: You would probably want to do a redraw after calling this function!
3968 - */
3969 - function _fnAjustColumnSizing ( oSettings )
3970 - {
3971 - /* Not interested in doing column width calculation if autowidth is disabled */
3972 - if ( oSettings.oFeatures.bAutoWidth === false )
3973 - {
3974 - return false;
3975 - }
3976 -
3977 - _fnCalculateColumnWidths( oSettings );
3978 - for ( var i=0 , iLen=oSettings.aoColumns.length ; i<iLen ; i++ )
3979 - {
3980 - oSettings.aoColumns[i].nTh.style.width = oSettings.aoColumns[i].sWidth;
3981 - }
3982 - }
3983 -
3984 -
3985 - /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
3986 - * Section - Feature: Filtering
3987 - */
3988 -
3989 - /*
3990 - * Function: _fnFeatureHtmlFilter
3991 - * Purpose: Generate the node required for filtering text
3992 - * Returns: node
3993 - * Inputs: object:oSettings - dataTables settings object
3994 - */
3995 - function _fnFeatureHtmlFilter ( oSettings )
3996 - {
3997 - var nFilter = document.createElement( 'div' );
3998 - if ( oSettings.sTableId !== '' && typeof oSettings.aanFeatures.f == "undefined" )
3999 - {
4000 - nFilter.setAttribute( 'id', oSettings.sTableId+'_filter' );
4001 - }
4002 - nFilter.className = oSettings.oClasses.sFilter;
4003 - var sSpace = oSettings.oLanguage.sSearch==="" ? "" : " ";
4004 - nFilter.innerHTML = oSettings.oLanguage.sSearch+sSpace+'<input type="text" />';
4005 -
4006 - var jqFilter = $("input", nFilter);
4007 - jqFilter.val( oSettings.oPreviousSearch.sSearch.replace('"','&quot;') );
4008 - jqFilter.keyup( function(e) {
4009 - /* Update all other filter input elements for the new display */
4010 - var n = oSettings.aanFeatures.f;
4011 - for ( var i=0, iLen=n.length ; i<iLen ; i++ )
4012 - {
4013 - if ( n[i] != this.parentNode )
4014 - {
4015 - $('input', n[i]).val( this.value );
4016 - }
4017 - }
4018 -
4019 - /* Now do the filter */
4020 - if ( this.value != oSettings.oPreviousSearch.sSearch )
4021 - {
4022 - _fnFilterComplete( oSettings, {
4023 - "sSearch": this.value,
4024 - "bRegex": oSettings.oPreviousSearch.bRegex,
4025 - "bSmart": oSettings.oPreviousSearch.bSmart
4026 - } );
4027 - }
4028 - } );
4029 -
4030 - jqFilter.keypress( function(e) {
4031 - /* Prevent default */
4032 - if ( e.keyCode == 13 )
4033 - {
4034 - return false;
4035 - }
4036 - } );
4037 -
4038 - return nFilter;
4039 - }
4040 -
4041 - /*
4042 - * Function: _fnFilterComplete
4043 - * Purpose: Filter the table using both the global filter and column based filtering
4044 - * Returns: -
4045 - * Inputs: object:oSettings - dataTables settings object
4046 - * object:oSearch: search information
4047 - * int:iForce - optional - force a research of the master array (1) or not (undefined or 0)
4048 - */
4049 - function _fnFilterComplete ( oSettings, oInput, iForce )
4050 - {
4051 - /* Filter on everything */
4052 - _fnFilter( oSettings, oInput.sSearch, iForce, oInput.bRegex, oInput.bSmart );
4053 -
4054 - /* Now do the individual column filter */
4055 - for ( var i=0 ; i<oSettings.aoPreSearchCols.length ; i++ )
4056 - {
4057 - _fnFilterColumn( oSettings, oSettings.aoPreSearchCols[i].sSearch, i,
4058 - oSettings.aoPreSearchCols[i].bRegex, oSettings.aoPreSearchCols[i].bSmart );
4059 - }
4060 -
4061 - /* Custom filtering */
4062 - if ( _oExt.afnFiltering.length !== 0 )
4063 - {
4064 - _fnFilterCustom( oSettings );
4065 - }
4066 -
4067 - /* Tell the draw function we have been filtering */
4068 - oSettings.bFiltered = true;
4069 -
4070 - /* Redraw the table */
4071 - oSettings._iDisplayStart = 0;
4072 - _fnCalculateEnd( oSettings );
4073 - _fnDraw( oSettings );
4074 -
4075 - /* Rebuild search array 'offline' */
4076 - _fnBuildSearchArray( oSettings, 0 );
4077 - }
4078 -
4079 - /*
4080 - * Function: _fnFilterCustom
4081 - * Purpose: Apply custom filtering functions
4082 - * Returns: -
4083 - * Inputs: object:oSettings - dataTables settings object
4084 - */
4085 - function _fnFilterCustom( oSettings )
4086 - {
4087 - var afnFilters = _oExt.afnFiltering;
4088 - for ( var i=0, iLen=afnFilters.length ; i<iLen ; i++ )
4089 - {
4090 - var iCorrector = 0;
4091 - for ( var j=0, jLen=oSettings.aiDisplay.length ; j<jLen ; j++ )
4092 - {
4093 - var iDisIndex = oSettings.aiDisplay[j-iCorrector];
4094 -
4095 - /* Check if we should use this row based on the filtering function */
4096 - if ( !afnFilters[i]( oSettings, oSettings.aoData[iDisIndex]._aData, iDisIndex ) )
4097 - {
4098 - oSettings.aiDisplay.splice( j-iCorrector, 1 );
4099 - iCorrector++;
4100 - }
4101 - }
4102 - }
4103 - }
4104 -
4105 - /*
4106 - * Function: _fnFilterColumn
4107 - * Purpose: Filter the table on a per-column basis
4108 - * Returns: -
4109 - * Inputs: object:oSettings - dataTables settings object
4110 - * string:sInput - string to filter on
4111 - * int:iColumn - column to filter
4112 - * bool:bRegex - treat search string as a regular expression or not
4113 - * bool:bSmart - use smart filtering or not
4114 - */
4115 - function _fnFilterColumn ( oSettings, sInput, iColumn, bRegex, bSmart )
4116 - {
4117 - if ( sInput === "" )
4118 - {
4119 - return;
4120 - }
4121 -
4122 - var iIndexCorrector = 0;
4123 - var rpSearch = _fnFilterCreateSearch( sInput, bRegex, bSmart );
4124 -
4125 - for ( var i=oSettings.aiDisplay.length-1 ; i>=0 ; i-- )
4126 - {
4127 - var sData = _fnDataToSearch( oSettings.aoData[ oSettings.aiDisplay[i] ]._aData[iColumn],
4128 - oSettings.aoColumns[iColumn].sType );
4129 - if ( ! rpSearch.test( sData ) )
4130 - {
4131 - oSettings.aiDisplay.splice( i, 1 );
4132 - iIndexCorrector++;
4133 - }
4134 - }
4135 - }
4136 -
4137 - /*
4138 - * Function: _fnFilter
4139 - * Purpose: Filter the data table based on user input and draw the table
4140 - * Returns: -
4141 - * Inputs: object:oSettings - dataTables settings object
4142 - * string:sInput - string to filter on
4143 - * int:iForce - optional - force a research of the master array (1) or not (undefined or 0)
4144 - * bool:bRegex - treat as a regular expression or not
4145 - * bool:bSmart - perform smart filtering or not
4146 - */
4147 - function _fnFilter( oSettings, sInput, iForce, bRegex, bSmart )
4148 - {
4149 - var i;
4150 - var rpSearch = _fnFilterCreateSearch( sInput, bRegex, bSmart );
4151 -
4152 - /* Check if we are forcing or not - optional parameter */
4153 - if ( typeof iForce == 'undefined' || iForce === null )
4154 - {
4155 - iForce = 0;
4156 - }
4157 -
4158 - /* Need to take account of custom filtering functions - always filter */
4159 - if ( _oExt.afnFiltering.length !== 0 )
4160 - {
4161 - iForce = 1;
4162 - }
4163 -
4164 - /*
4165 - * If the input is blank - we want the full data set
4166 - */
4167 - if ( sInput.length <= 0 )
4168 - {
4169 - oSettings.aiDisplay.splice( 0, oSettings.aiDisplay.length);
4170 - oSettings.aiDisplay = oSettings.aiDisplayMaster.slice();
4171 - }
4172 - else
4173 - {
4174 - /*
4175 - * We are starting a new search or the new search string is smaller
4176 - * then the old one (i.e. delete). Search from the master array
4177 - */
4178 - if ( oSettings.aiDisplay.length == oSettings.aiDisplayMaster.length ||
4179 - oSettings.oPreviousSearch.sSearch.length > sInput.length || iForce == 1 ||
4180 - sInput.indexOf(oSettings.oPreviousSearch.sSearch) !== 0 )
4181 - {
4182 - /* Nuke the old display array - we are going to rebuild it */
4183 - oSettings.aiDisplay.splice( 0, oSettings.aiDisplay.length);
4184 -
4185 - /* Force a rebuild of the search array */
4186 - _fnBuildSearchArray( oSettings, 1 );
4187 -
4188 - /* Search through all records to populate the search array
4189 - * The the oSettings.aiDisplayMaster and asDataSearch arrays have 1 to 1
4190 - * mapping
4191 - */
4192 - for ( i=0 ; i<oSettings.aiDisplayMaster.length ; i++ )
4193 - {
4194 - if ( rpSearch.test(oSettings.asDataSearch[i]) )
4195 - {
4196 - oSettings.aiDisplay.push( oSettings.aiDisplayMaster[i] );
4197 - }
4198 - }
4199 - }
4200 - else
4201 - {
4202 - /* Using old search array - refine it - do it this way for speed
4203 - * Don't have to search the whole master array again
4204 - */
4205 - var iIndexCorrector = 0;
4206 -
4207 - /* Search the current results */
4208 - for ( i=0 ; i<oSettings.asDataSearch.length ; i++ )
4209 - {
4210 - if ( ! rpSearch.test(oSettings.asDataSearch[i]) )
4211 - {
4212 - oSettings.aiDisplay.splice( i-iIndexCorrector, 1 );
4213 - iIndexCorrector++;
4214 - }
4215 - }
4216 - }
4217 - }
4218 - oSettings.oPreviousSearch.sSearch = sInput;
4219 - oSettings.oPreviousSearch.bRegex = bRegex;
4220 - oSettings.oPreviousSearch.bSmart = bSmart;
4221 - }
4222 -
4223 - /*
4224 - * Function: _fnBuildSearchArray
4225 - * Purpose: Create an array which can be quickly search through
4226 - * Returns: -
4227 - * Inputs: object:oSettings - dataTables settings object
4228 - * int:iMaster - use the master data array - optional
4229 - */
4230 - function _fnBuildSearchArray ( oSettings, iMaster )
4231 - {
4232 - /* Clear out the old data */
4233 - oSettings.asDataSearch.splice( 0, oSettings.asDataSearch.length );
4234 -
4235 - var aArray = (typeof iMaster != 'undefined' && iMaster == 1) ?
4236 - oSettings.aiDisplayMaster : oSettings.aiDisplay;
4237 -
4238 - for ( var i=0, iLen=aArray.length ; i<iLen ; i++ )
4239 - {
4240 - oSettings.asDataSearch[i] = _fnBuildSearchRow( oSettings,
4241 - oSettings.aoData[ aArray[i] ]._aData );
4242 - }
4243 - }
4244 -
4245 - /*
4246 - * Function: _fnBuildSearchRow
4247 - * Purpose: Create a searchable string from a single data row
4248 - * Returns: -
4249 - * Inputs: object:oSettings - dataTables settings object
4250 - * array:aData - aoData[]._aData array to use for the data to search
4251 - */
4252 - function _fnBuildSearchRow( oSettings, aData )
4253 - {
4254 - var sSearch = '';
4255 - var nTmp = document.createElement('div');
4256 -
4257 - for ( var j=0, jLen=oSettings.aoColumns.length ; j<jLen ; j++ )
4258 - {
4259 - if ( oSettings.aoColumns[j].bSearchable )
4260 - {
4261 - var sData = aData[j];
4262 - sSearch += _fnDataToSearch( sData, oSettings.aoColumns[j].sType )+' ';
4263 - }
4264 - }
4265 -
4266 - /* If it looks like there is an HTML entity in the string, attempt to decode it */
4267 - if ( sSearch.indexOf('&') !== -1 )
4268 - {
4269 - nTmp.innerHTML = sSearch;
4270 - sSearch = nTmp.textContent ? nTmp.textContent : nTmp.innerText;
4271 -
4272 - /* IE and Opera appear to put an newline where there is a <br> tag - remove it */
4273 - sSearch = sSearch.replace(/\n/g," ").replace(/\r/g,"");
4274 - }
4275 -
4276 - return sSearch;
4277 - }
4278 -
4279 - /*
4280 - * Function: _fnFilterCreateSearch
4281 - * Purpose: Build a regular expression object suitable for searching a table
4282 - * Returns: RegExp: - constructed object
4283 - * Inputs: string:sSearch - string to search for
4284 - * bool:bRegex - treat as a regular expression or not
4285 - * bool:bSmart - perform smart filtering or not
4286 - */
4287 - function _fnFilterCreateSearch( sSearch, bRegex, bSmart )
4288 - {
4289 - var asSearch, sRegExpString;
4290 -
4291 - if ( bSmart )
4292 - {
4293 - /* Generate the regular expression to use. Something along the lines of:
4294 - * ^(?=.*?\bone\b)(?=.*?\btwo\b)(?=.*?\bthree\b).*$
4295 - */
4296 - asSearch = bRegex ? sSearch.split( ' ' ) : _fnEscapeRegex( sSearch ).split( ' ' );
4297 - sRegExpString = '^(?=.*?'+asSearch.join( ')(?=.*?' )+').*$';
4298 - return new RegExp( sRegExpString, "i" );
4299 - }
4300 - else
4301 - {
4302 - sSearch = bRegex ? sSearch : _fnEscapeRegex( sSearch );
4303 - return new RegExp( sSearch, "i" );
4304 - }
4305 - }
4306 -
4307 - /*
4308 - * Function: _fnDataToSearch
4309 - * Purpose: Convert raw data into something that the user can search on
4310 - * Returns: string: - search string
4311 - * Inputs: string:sData - data to be modified
4312 - * string:sType - data type
4313 - */
4314 - function _fnDataToSearch ( sData, sType )
4315 - {
4316 - if ( typeof _oExt.ofnSearch[sType] == "function" )
4317 - {
4318 - return _oExt.ofnSearch[sType]( sData );
4319 - }
4320 - else if ( sType == "html" )
4321 - {
4322 - return sData.replace(/\n/g," ").replace( /<.*?>/g, "" );
4323 - }
4324 - else if ( typeof sData == "string" )
4325 - {
4326 - return sData.replace(/\n/g," ");
4327 - }
4328 - return sData;
4329 - }
4330 -
4331 -
4332 - /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
4333 - * Section - Feature: Sorting
4334 - */
4335 -
4336 - /*
4337 - * Function: _fnSort
4338 - * Purpose: Change the order of the table
4339 - * Returns: -
4340 - * Inputs: object:oSettings - dataTables settings object
4341 - * bool:bApplyClasses - optional - should we apply classes or not
4342 - * Notes: We always sort the master array and then apply a filter again
4343 - * if it is needed. This probably isn't optimal - but atm I can't think
4344 - * of any other way which is (each has disadvantages). we want to sort aiDisplayMaster -
4345 - * but according to aoData[]._aData
4346 - */
4347 - function _fnSort ( oSettings, bApplyClasses )
4348 - {
4349 - var
4350 - iDataSort, iDataType,
4351 - i, iLen, j, jLen,
4352 - aaSort = [],
4353 - aiOrig = [],
4354 - oSort = _oExt.oSort,
4355 - aoData = oSettings.aoData,
4356 - aoColumns = oSettings.aoColumns;
4357 -
4358 - /* No sorting required if server-side or no sorting array */
4359 - if ( !oSettings.oFeatures.bServerSide &&
4360 - (oSettings.aaSorting.length !== 0 || oSettings.aaSortingFixed !== null) )
4361 - {
4362 - if ( oSettings.aaSortingFixed !== null )
4363 - {
4364 - aaSort = oSettings.aaSortingFixed.concat( oSettings.aaSorting );
4365 - }
4366 - else
4367 - {
4368 - aaSort = oSettings.aaSorting.slice();
4369 - }
4370 -
4371 - /* If there is a sorting data type, and a fuction belonging to it, then we need to
4372 - * get the data from the developer's function and apply it for this column
4373 - */
4374 - for ( i=0 ; i<aaSort.length ; i++ )
4375 - {
4376 - var iColumn = aaSort[i][0];
4377 - var iVisColumn = _fnColumnIndexToVisible( oSettings, iColumn );
4378 - var sDataType = oSettings.aoColumns[ iColumn ].sSortDataType;
4379 - if ( typeof _oExt.afnSortData[sDataType] != 'undefined' )
4380 - {
4381 - var aData = _oExt.afnSortData[sDataType]( oSettings, iColumn, iVisColumn );
4382 - for ( j=0, jLen=aoData.length ; j<jLen ; j++ )
4383 - {
4384 - aoData[j]._aData[iColumn] = aData[j];
4385 - }
4386 - }
4387 - }
4388 -
4389 - /* Create a value - key array of the current row positions such that we can use their
4390 - * current position during the sort, if values match, in order to perform stable sorting
4391 - */
4392 - for ( i=0, iLen=oSettings.aiDisplayMaster.length ; i<iLen ; i++ )
4393 - {
4394 - aiOrig[ oSettings.aiDisplayMaster[i] ] = i;
4395 - }
4396 -
4397 - /* Do the sort - here we want multi-column sorting based on a given data source (column)
4398 - * and sorting function (from oSort) in a certain direction. It's reasonably complex to
4399 - * follow on it's own, but this is what we want (example two column sorting):
4400 - * fnLocalSorting = function(a,b){
4401 - * var iTest;
4402 - * iTest = oSort['string-asc']('data11', 'data12');
4403 - * if (iTest !== 0)
4404 - * return iTest;
4405 - * iTest = oSort['numeric-desc']('data21', 'data22');
4406 - * if (iTest !== 0)
4407 - * return iTest;
4408 - * return oSort['numeric-asc']( aiOrig[a], aiOrig[b] );
4409 - * }
4410 - * Basically we have a test for each sorting column, if the data in that column is equal,
4411 - * test the next column. If all columns match, then we use a numeric sort on the row
4412 - * positions in the original data array to provide a stable sort.
4413 - */
4414 - var iSortLen = aaSort.length;
4415 - oSettings.aiDisplayMaster.sort( function ( a, b ) {
4416 - var iTest;
4417 - for ( i=0 ; i<iSortLen ; i++ )
4418 - {
4419 - iDataSort = aoColumns[ aaSort[i][0] ].iDataSort;
4420 - iDataType = aoColumns[ iDataSort ].sType;
4421 - iTest = oSort[ iDataType+"-"+aaSort[i][1] ](
4422 - aoData[a]._aData[iDataSort],
4423 - aoData[b]._aData[iDataSort]
4424 - );
4425 -
4426 - if ( iTest !== 0 )
4427 - {
4428 - return iTest;
4429 - }
4430 - }
4431 -
4432 - return oSort['numeric-asc']( aiOrig[a], aiOrig[b] );
4433 - } );
4434 - }
4435 -
4436 - /* Alter the sorting classes to take account of the changes */
4437 - if ( typeof bApplyClasses == 'undefined' || bApplyClasses )
4438 - {
4439 - _fnSortingClasses( oSettings );
4440 - }
4441 -
4442 - /* Tell the draw function that we have sorted the data */
4443 - oSettings.bSorted = true;
4444 -
4445 - /* Copy the master data into the draw array and re-draw */
4446 - if ( oSettings.oFeatures.bFilter )
4447 - {
4448 - /* _fnFilter() will redraw the table for us */
4449 - _fnFilterComplete( oSettings, oSettings.oPreviousSearch, 1 );
4450 - }
4451 - else
4452 - {
4453 - oSettings.aiDisplay = oSettings.aiDisplayMaster.slice();
4454 - oSettings._iDisplayStart = 0; /* reset display back to page 0 */
4455 - _fnCalculateEnd( oSettings );
4456 - _fnDraw( oSettings );
4457 - }
4458 - }
4459 -
4460 - /*
4461 - * Function: _fnSortAttachListener
4462 - * Purpose: Attach a sort handler (click) to a node
4463 - * Returns: -
4464 - * Inputs: object:oSettings - dataTables settings object
4465 - * node:nNode - node to attach the handler to
4466 - * int:iDataIndex - column sorting index
4467 - * function:fnCallback - callback function - optional
4468 - */
4469 - function _fnSortAttachListener ( oSettings, nNode, iDataIndex, fnCallback )
4470 - {
4471 - $(nNode).click( function (e) {
4472 - /* If the column is not sortable - don't to anything */
4473 - if ( oSettings.aoColumns[iDataIndex].bSortable === false )
4474 - {
4475 - return;
4476 - }
4477 -
4478 - /*
4479 - * This is a little bit odd I admit... I declare a temporary function inside the scope of
4480 - * _fnDrawHead and the click handler in order that the code presented here can be used
4481 - * twice - once for when bProcessing is enabled, and another time for when it is
4482 - * disabled, as we need to perform slightly different actions.
4483 - * Basically the issue here is that the Javascript engine in modern browsers don't
4484 - * appear to allow the rendering engine to update the display while it is still excuting
4485 - * it's thread (well - it does but only after long intervals). This means that the
4486 - * 'processing' display doesn't appear for a table sort. To break the js thread up a bit
4487 - * I force an execution break by using setTimeout - but this breaks the expected
4488 - * thread continuation for the end-developer's point of view (their code would execute
4489 - * too early), so we on;y do it when we absolutely have to.
4490 - */
4491 - var fnInnerSorting = function () {
4492 - var iColumn, iNextSort;
4493 -
4494 - /* If the shift key is pressed then we are multipe column sorting */
4495 - if ( e.shiftKey )
4496 - {
4497 - /* Are we already doing some kind of sort on this column? */
4498 - var bFound = false;
4499 - for ( var i=0 ; i<oSettings.aaSorting.length ; i++ )
4500 - {
4501 - if ( oSettings.aaSorting[i][0] == iDataIndex )
4502 - {
4503 - bFound = true;
4504 - iColumn = oSettings.aaSorting[i][0];
4505 - iNextSort = oSettings.aaSorting[i][2]+1;
4506 -
4507 - if ( typeof oSettings.aoColumns[iColumn].asSorting[iNextSort] == 'undefined' )
4508 - {
4509 - /* Reached the end of the sorting options, remove from multi-col sort */
4510 - oSettings.aaSorting.splice( i, 1 );
4511 - }
4512 - else
4513 - {
4514 - /* Move onto next sorting direction */
4515 - oSettings.aaSorting[i][1] = oSettings.aoColumns[iColumn].asSorting[iNextSort];
4516 - oSettings.aaSorting[i][2] = iNextSort;
4517 - }
4518 - break;
4519 - }
4520 - }
4521 -
4522 - /* No sort yet - add it in */
4523 - if ( bFound === false )
4524 - {
4525 - oSettings.aaSorting.push( [ iDataIndex,
4526 - oSettings.aoColumns[iDataIndex].asSorting[0], 0 ] );
4527 - }
4528 - }
4529 - else
4530 - {
4531 - /* If no shift key then single column sort */
4532 - if ( oSettings.aaSorting.length == 1 && oSettings.aaSorting[0][0] == iDataIndex )
4533 - {
4534 - iColumn = oSettings.aaSorting[0][0];
4535 - iNextSort = oSettings.aaSorting[0][2]+1;
4536 - if ( typeof oSettings.aoColumns[iColumn].asSorting[iNextSort] == 'undefined' )
4537 - {
4538 - iNextSort = 0;
4539 - }
4540 - oSettings.aaSorting[0][1] = oSettings.aoColumns[iColumn].asSorting[iNextSort];
4541 - oSettings.aaSorting[0][2] = iNextSort;
4542 - }
4543 - else
4544 - {
4545 - oSettings.aaSorting.splice( 0, oSettings.aaSorting.length );
4546 - oSettings.aaSorting.push( [ iDataIndex,
4547 - oSettings.aoColumns[iDataIndex].asSorting[0], 0 ] );
4548 - }
4549 - }
4550 -
4551 - /* Run the sort */
4552 - _fnSort( oSettings );
4553 - }; /* /fnInnerSorting */
4554 -
4555 - if ( !oSettings.oFeatures.bProcessing )
4556 - {
4557 - fnInnerSorting();
4558 - }
4559 - else
4560 - {
4561 - _fnProcessingDisplay( oSettings, true );
4562 - setTimeout( function() {
4563 - fnInnerSorting();
4564 - if ( !oSettings.oFeatures.bServerSide )
4565 - {
4566 - _fnProcessingDisplay( oSettings, false );
4567 - }
4568 - }, 0 );
4569 - }
4570 -
4571 - /* Call the user specified callback function - used for async user interaction */
4572 - if ( typeof fnCallback == 'function' )
4573 - {
4574 - fnCallback( oSettings );
4575 - }
4576 - } );
4577 - }
4578 -
4579 - /*
4580 - * Function: _fnSortingClasses
4581 - * Purpose: Set the sortting classes on the header
4582 - * Returns: -
4583 - * Inputs: object:oSettings - dataTables settings object
4584 - * Notes: It is safe to call this function when bSort and bSortClasses are false
4585 - */
4586 - function _fnSortingClasses( oSettings )
4587 - {
4588 - var i, iLen, j, jLen, iFound;
4589 - var aaSort, sClass;
4590 - var iColumns = oSettings.aoColumns.length;
4591 - var oClasses = oSettings.oClasses;
4592 -
4593 - for ( i=0 ; i<iColumns ; i++ )
4594 - {
4595 - if ( oSettings.aoColumns[i].bSortable )
4596 - {
4597 - $(oSettings.aoColumns[i].nTh).removeClass( oClasses.sSortAsc +" "+ oClasses.sSortDesc +
4598 - " "+ oSettings.aoColumns[i].sSortingClass );
4599 - }
4600 - }
4601 -
4602 - if ( oSettings.aaSortingFixed !== null )
4603 - {
4604 - aaSort = oSettings.aaSortingFixed.concat( oSettings.aaSorting );
4605 - }
4606 - else
4607 - {
4608 - aaSort = oSettings.aaSorting.slice();
4609 - }
4610 -
4611 - /* Apply the required classes to the header */
4612 - for ( i=0 ; i<oSettings.aoColumns.length ; i++ )
4613 - {
4614 - if ( oSettings.aoColumns[i].bSortable )
4615 - {
4616 - sClass = oSettings.aoColumns[i].sSortingClass;
4617 - iFound = -1;
4618 - for ( j=0 ; j<aaSort.length ; j++ )
4619 - {
4620 - if ( aaSort[j][0] == i )
4621 - {
4622 - sClass = ( aaSort[j][1] == "asc" ) ?
4623 - oClasses.sSortAsc : oClasses.sSortDesc;
4624 - iFound = j;
4625 - break;
4626 - }
4627 - }
4628 - $(oSettings.aoColumns[i].nTh).addClass( sClass );
4629 -
4630 - if ( oSettings.bJUI )
4631 - {
4632 - /* jQuery UI uses extra markup */
4633 - var jqSpan = $("span", oSettings.aoColumns[i].nTh);
4634 - jqSpan.removeClass(oClasses.sSortJUIAsc +" "+ oClasses.sSortJUIDesc +" "+
4635 - oClasses.sSortJUI +" "+ oClasses.sSortJUIAscAllowed +" "+ oClasses.sSortJUIDescAllowed );
4636 -
4637 - var sSpanClass;
4638 - if ( iFound == -1 )
4639 - {
4640 - sSpanClass = oSettings.aoColumns[i].sSortingClassJUI;
4641 - }
4642 - else if ( aaSort[iFound][1] == "asc" )
4643 - {
4644 - sSpanClass = oClasses.sSortJUIAsc;
4645 - }
4646 - else
4647 - {
4648 - sSpanClass = oClasses.sSortJUIDesc;
4649 - }
4650 -
4651 - jqSpan.addClass( sSpanClass );
4652 - }
4653 - }
4654 - else
4655 - {
4656 - /* No sorting on this column, so add the base class. This will have been assigned by
4657 - * _fnAddColumn
4658 - */
4659 - $(oSettings.aoColumns[i].nTh).addClass( oSettings.aoColumns[i].sSortingClass );
4660 - }
4661 - }
4662 -
4663 - /*
4664 - * Apply the required classes to the table body
4665 - * Note that this is given as a feature switch since it can significantly slow down a sort
4666 - * on large data sets (adding and removing of classes is always slow at the best of times..)
4667 - * Further to this, note that this code is admitadly fairly ugly. It could be made a lot
4668 - * simpiler using jQuery selectors and add/removeClass, but that is significantly slower
4669 - * (on the order of 5 times slower) - hence the direct DOM manipulation here.
4670 - */
4671 - sClass = oClasses.sSortColumn;
4672 -
4673 - if ( oSettings.oFeatures.bSort && oSettings.oFeatures.bSortClasses )
4674 - {
4675 - var nTds = _fnGetTdNodes( oSettings );
4676 -
4677 - /* Remove the old classes */
4678 - if ( nTds.length >= iColumns )
4679 - {
4680 - for ( i=0 ; i<iColumns ; i++ )
4681 - {
4682 - if ( nTds[i].className.indexOf(sClass+"1") != -1 )
4683 - {
4684 - for ( j=0, jLen=(nTds.length/iColumns) ; j<jLen ; j++ )
4685 - {
4686 - nTds[(iColumns*j)+i].className =
4687 - $.trim( nTds[(iColumns*j)+i].className.replace( sClass+"1", "" ) );
4688 - }
4689 - }
4690 - else if ( nTds[i].className.indexOf(sClass+"2") != -1 )
4691 - {
4692 - for ( j=0, jLen=(nTds.length/iColumns) ; j<jLen ; j++ )
4693 - {
4694 - nTds[(iColumns*j)+i].className =
4695 - $.trim( nTds[(iColumns*j)+i].className.replace( sClass+"2", "" ) );
4696 - }
4697 - }
4698 - else if ( nTds[i].className.indexOf(sClass+"3") != -1 )
4699 - {
4700 - for ( j=0, jLen=(nTds.length/iColumns) ; j<jLen ; j++ )
4701 - {
4702 - nTds[(iColumns*j)+i].className =
4703 - $.trim( nTds[(iColumns*j)+i].className.replace( " "+sClass+"3", "" ) );
4704 - }
4705 - }
4706 - }
4707 - }
4708 -
4709 - /* Add the new classes to the table */
4710 - var iClass = 1, iTargetCol;
4711 - for ( i=0 ; i<aaSort.length ; i++ )
4712 - {
4713 - iTargetCol = parseInt( aaSort[i][0], 10 );
4714 - for ( j=0, jLen=(nTds.length/iColumns) ; j<jLen ; j++ )
4715 - {
4716 - nTds[(iColumns*j)+iTargetCol].className += " "+sClass+iClass;
4717 - }
4718 -
4719 - if ( iClass < 3 )
4720 - {
4721 - iClass++;
4722 - }
4723 - }
4724 - }
4725 - }
4726 -
4727 -
4728 - /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
4729 - * Section - Feature: Pagination. Note that most of the paging logic is done in
4730 - * _oExt.oPagination
4731 - */
4732 -
4733 - /*
4734 - * Function: _fnFeatureHtmlPaginate
4735 - * Purpose: Generate the node required for default pagination
4736 - * Returns: node
4737 - * Inputs: object:oSettings - dataTables settings object
4738 - */
4739 - function _fnFeatureHtmlPaginate ( oSettings )
4740 - {
4741 - if ( oSettings.oScroll.bInfinite )
4742 - {
4743 - return null;
4744 - }
4745 -
4746 - var nPaginate = document.createElement( 'div' );
4747 - nPaginate.className = oSettings.oClasses.sPaging+oSettings.sPaginationType;
4748 -
4749 - _oExt.oPagination[ oSettings.sPaginationType ].fnInit( oSettings, nPaginate,
4750 - function( oSettings ) {
4751 - _fnCalculateEnd( oSettings );
4752 - _fnDraw( oSettings );
4753 - }
4754 - );
4755 -
4756 - /* Add a draw callback for the pagination on first instance, to update the paging display */
4757 - if ( typeof oSettings.aanFeatures.p == "undefined" )
4758 - {
4759 - oSettings.aoDrawCallback.push( {
4760 - "fn": function( oSettings ) {
4761 - _oExt.oPagination[ oSettings.sPaginationType ].fnUpdate( oSettings, function( oSettings ) {
4762 - _fnCalculateEnd( oSettings );
4763 - _fnDraw( oSettings );
4764 - } );
4765 - },
4766 - "sName": "pagination"
4767 - } );
4768 - }
4769 - return nPaginate;
4770 - }
4771 -
4772 - /*
4773 - * Function: _fnPageChange
4774 - * Purpose: Alter the display settings to change the page
4775 - * Returns: bool:true - page has changed, false - no change (no effect) eg 'first' on page 1
4776 - * Inputs: object:oSettings - dataTables settings object
4777 - * string:sAction - paging action to take: "first", "previous", "next" or "last"
4778 - */
4779 - function _fnPageChange ( oSettings, sAction )
4780 - {
4781 - var iOldStart = oSettings._iDisplayStart;
4782 -
4783 - if ( sAction == "first" )
4784 - {
4785 - oSettings._iDisplayStart = 0;
4786 - }
4787 - else if ( sAction == "previous" )
4788 - {
4789 - oSettings._iDisplayStart = oSettings._iDisplayLength>=0 ?
4790 - oSettings._iDisplayStart - oSettings._iDisplayLength :
4791 - 0;
4792 -
4793 - /* Correct for underrun */
4794 - if ( oSettings._iDisplayStart < 0 )
4795 - {
4796 - oSettings._iDisplayStart = 0;
4797 - }
4798 - }
4799 - else if ( sAction == "next" )
4800 - {
4801 - if ( oSettings._iDisplayLength >= 0 )
4802 - {
4803 - /* Make sure we are not over running the display array */
4804 - if ( oSettings._iDisplayStart + oSettings._iDisplayLength < oSettings.fnRecordsDisplay() )
4805 - {
4806 - oSettings._iDisplayStart += oSettings._iDisplayLength;
4807 - }
4808 - }
4809 - else
4810 - {
4811 - oSettings._iDisplayStart = 0;
4812 - }
4813 - }
4814 - else if ( sAction == "last" )
4815 - {
4816 - if ( oSettings._iDisplayLength >= 0 )
4817 - {
4818 - var iPages = parseInt( (oSettings.fnRecordsDisplay()-1) / oSettings._iDisplayLength, 10 ) + 1;
4819 - oSettings._iDisplayStart = (iPages-1) * oSettings._iDisplayLength;
4820 - }
4821 - else
4822 - {
4823 - oSettings._iDisplayStart = 0;
4824 - }
4825 - }
4826 - else
4827 - {
4828 - _fnLog( oSettings, 0, "Unknown paging action: "+sAction );
4829 - }
4830 -
4831 - return iOldStart != oSettings._iDisplayStart;
4832 - }
4833 -
4834 -
4835 - /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
4836 - * Section - Feature: HTML info
4837 - */
4838 -
4839 - /*
4840 - * Function: _fnFeatureHtmlInfo
4841 - * Purpose: Generate the node required for the info display
4842 - * Returns: node
4843 - * Inputs: object:oSettings - dataTables settings object
4844 - */
4845 - function _fnFeatureHtmlInfo ( oSettings )
4846 - {
4847 - var nInfo = document.createElement( 'div' );
4848 - nInfo.className = oSettings.oClasses.sInfo;
4849 -
4850 - /* Actions that are to be taken once only for this feature */
4851 - if ( typeof oSettings.aanFeatures.i == "undefined" )
4852 - {
4853 - /* Add draw callback */
4854 - oSettings.aoDrawCallback.push( {
4855 - "fn": _fnUpdateInfo,
4856 - "sName": "information"
4857 - } );
4858 -
4859 - /* Add id */
4860 - if ( oSettings.sTableId !== '' )
4861 - {
4862 - nInfo.setAttribute( 'id', oSettings.sTableId+'_info' );
4863 - }
4864 - }
4865 -
4866 - return nInfo;
4867 - }
4868 -
4869 - /*
4870 - * Function: _fnUpdateInfo
4871 - * Purpose: Update the information elements in the display
4872 - * Returns: -
4873 - * Inputs: object:oSettings - dataTables settings object
4874 - */
4875 - function _fnUpdateInfo ( oSettings )
4876 - {
4877 - /* Show information about the table */
4878 - if ( !oSettings.oFeatures.bInfo || oSettings.aanFeatures.i.length === 0 )
4879 - {
4880 - return;
4881 - }
4882 -
4883 - var
4884 - iStart = oSettings._iDisplayStart+1, iEnd = oSettings.fnDisplayEnd(),
4885 - iMax = oSettings.fnRecordsTotal(), iTotal = oSettings.fnRecordsDisplay(),
4886 - sStart = oSettings.fnFormatNumber( iStart ), sEnd = oSettings.fnFormatNumber( iEnd ),
4887 - sMax = oSettings.fnFormatNumber( iMax ), sTotal = oSettings.fnFormatNumber( iTotal ),
4888 - sOut;
4889 -
4890 - /* When infinite scrolling, we are always starting at 1. _iDisplayStart is used only
4891 - * internally
4892 - */
4893 - if ( oSettings.oScroll.bInfinite )
4894 - {
4895 - sStart = oSettings.fnFormatNumber( 1 );
4896 - }
4897 -
4898 - if ( oSettings.fnRecordsDisplay() === 0 &&
4899 - oSettings.fnRecordsDisplay() == oSettings.fnRecordsTotal() )
4900 - {
4901 - /* Empty record set */
4902 - sOut = oSettings.oLanguage.sInfoEmpty+ oSettings.oLanguage.sInfoPostFix;
4903 - }
4904 - else if ( oSettings.fnRecordsDisplay() === 0 )
4905 - {
4906 - /* Rmpty record set after filtering */
4907 - sOut = oSettings.oLanguage.sInfoEmpty +' '+
4908 - oSettings.oLanguage.sInfoFiltered.replace('_MAX_', sMax)+
4909 - oSettings.oLanguage.sInfoPostFix;
4910 - }
4911 - else if ( oSettings.fnRecordsDisplay() == oSettings.fnRecordsTotal() )
4912 - {
4913 - /* Normal record set */
4914 - sOut = oSettings.oLanguage.sInfo.
4915 - replace('_START_', sStart).
4916 - replace('_END_', sEnd).
4917 - replace('_TOTAL_', sTotal)+
4918 - oSettings.oLanguage.sInfoPostFix;
4919 - }
4920 - else
4921 - {
4922 - /* Record set after filtering */
4923 - sOut = oSettings.oLanguage.sInfo.
4924 - replace('_START_', sStart).
4925 - replace('_END_', sEnd).
4926 - replace('_TOTAL_', sTotal) +' '+
4927 - oSettings.oLanguage.sInfoFiltered.replace('_MAX_',
4928 - oSettings.fnFormatNumber(oSettings.fnRecordsTotal()))+
4929 - oSettings.oLanguage.sInfoPostFix;
4930 - }
4931 -
4932 - if ( oSettings.oLanguage.fnInfoCallback !== null )
4933 - {
4934 - sOut = oSettings.oLanguage.fnInfoCallback( oSettings, iStart, iEnd, iMax, iTotal, sOut );
4935 - }
4936 -
4937 - var n = oSettings.aanFeatures.i;
4938 - for ( var i=0, iLen=n.length ; i<iLen ; i++ )
4939 - {
4940 - $(n[i]).html( sOut );
4941 - }
4942 - }
4943 -
4944 -
4945 - /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
4946 - * Section - Feature: Length change
4947 - */
4948 -
4949 - /*
4950 - * Function: _fnFeatureHtmlLength
4951 - * Purpose: Generate the node required for user display length changing
4952 - * Returns: node
4953 - * Inputs: object:oSettings - dataTables settings object
4954 - */
4955 - function _fnFeatureHtmlLength ( oSettings )
4956 - {
4957 - if ( oSettings.oScroll.bInfinite )
4958 - {
4959 - return null;
4960 - }
4961 -
4962 - /* This can be overruled by not using the _MENU_ var/macro in the language variable */
4963 - var sName = (oSettings.sTableId === "") ? "" : 'name="'+oSettings.sTableId+'_length"';
4964 - var sStdMenu = '<select size="1" '+sName+'>';
4965 - var i, iLen;
4966 -
4967 - if ( oSettings.aLengthMenu.length == 2 && typeof oSettings.aLengthMenu[0] == 'object' &&
4968 - typeof oSettings.aLengthMenu[1] == 'object' )
4969 - {
4970 - for ( i=0, iLen=oSettings.aLengthMenu[0].length ; i<iLen ; i++ )
4971 - {
4972 - sStdMenu += '<option value="'+oSettings.aLengthMenu[0][i]+'">'+
4973 - oSettings.aLengthMenu[1][i]+'</option>';
4974 - }
4975 - }
4976 - else
4977 - {
4978 - for ( i=0, iLen=oSettings.aLengthMenu.length ; i<iLen ; i++ )
4979 - {
4980 - sStdMenu += '<option value="'+oSettings.aLengthMenu[i]+'">'+
4981 - oSettings.aLengthMenu[i]+'</option>';
4982 - }
4983 - }
4984 - sStdMenu += '</select>';
4985 -
4986 - var nLength = document.createElement( 'div' );
4987 - if ( oSettings.sTableId !== '' && typeof oSettings.aanFeatures.l == "undefined" )
4988 - {
4989 - nLength.setAttribute( 'id', oSettings.sTableId+'_length' );
4990 - }
4991 - nLength.className = oSettings.oClasses.sLength;
4992 - nLength.innerHTML = oSettings.oLanguage.sLengthMenu.replace( '_MENU_', sStdMenu );
4993 -
4994 - /*
4995 - * Set the length to the current display length - thanks to Andrea Pavlovic for this fix,
4996 - * and Stefan Skopnik for fixing the fix!
4997 - */
4998 - $('select option[value="'+oSettings._iDisplayLength+'"]',nLength).attr("selected",true);
4999 -
5000 - $('select', nLength).change( function(e) {
5001 - var iVal = $(this).val();
5002 -
5003 - /* Update all other length options for the new display */
5004 - var n = oSettings.aanFeatures.l;
5005 - for ( i=0, iLen=n.length ; i<iLen ; i++ )
5006 - {
5007 - if ( n[i] != this.parentNode )
5008 - {
5009 - $('select', n[i]).val( iVal );
5010 - }
5011 - }
5012 -
5013 - /* Redraw the table */
5014 - oSettings._iDisplayLength = parseInt(iVal, 10);
5015 - _fnCalculateEnd( oSettings );
5016 -
5017 - /* If we have space to show extra rows (backing up from the end point - then do so */
5018 - if ( oSettings.fnDisplayEnd() == oSettings.fnRecordsDisplay() )
5019 - {
5020 - oSettings._iDisplayStart = oSettings.fnDisplayEnd() - oSettings._iDisplayLength;
5021 - if ( oSettings._iDisplayStart < 0 )
5022 - {
5023 - oSettings._iDisplayStart = 0;
5024 - }
5025 - }
5026 -
5027 - if ( oSettings._iDisplayLength == -1 )
5028 - {
5029 - oSettings._iDisplayStart = 0;
5030 - }
5031 -
5032 - _fnDraw( oSettings );
5033 - } );
5034 -
5035 - return nLength;
5036 - }
5037 -
5038 -
5039 - /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
5040 - * Section - Feature: Processing incidator
5041 - */
5042 -
5043 - /*
5044 - * Function: _fnFeatureHtmlProcessing
5045 - * Purpose: Generate the node required for the processing node
5046 - * Returns: node
5047 - * Inputs: object:oSettings - dataTables settings object
5048 - */
5049 - function _fnFeatureHtmlProcessing ( oSettings )
5050 - {
5051 - var nProcessing = document.createElement( 'div' );
5052 -
5053 - if ( oSettings.sTableId !== '' && typeof oSettings.aanFeatures.r == "undefined" )
5054 - {
5055 - nProcessing.setAttribute( 'id', oSettings.sTableId+'_processing' );
5056 - }
5057 - nProcessing.innerHTML = oSettings.oLanguage.sProcessing;
5058 - nProcessing.className = oSettings.oClasses.sProcessing;
5059 - oSettings.nTable.parentNode.insertBefore( nProcessing, oSettings.nTable );
5060 -
5061 - return nProcessing;
5062 - }
5063 -
5064 - /*
5065 - * Function: _fnProcessingDisplay
5066 - * Purpose: Display or hide the processing indicator
5067 - * Returns: -
5068 - * Inputs: object:oSettings - dataTables settings object
5069 - * bool:
5070 - * true - show the processing indicator
5071 - * false - don't show
5072 - */
5073 - function _fnProcessingDisplay ( oSettings, bShow )
5074 - {
5075 - if ( oSettings.oFeatures.bProcessing )
5076 - {
5077 - var an = oSettings.aanFeatures.r;
5078 - for ( var i=0, iLen=an.length ; i<iLen ; i++ )
5079 - {
5080 - an[i].style.visibility = bShow ? "visible" : "hidden";
5081 - }
5082 - }
5083 - }
5084 -
5085 -
5086 - /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
5087 - * Section - Support functions
5088 - */
5089 -
5090 - /*
5091 - * Function: _fnVisibleToColumnIndex
5092 - * Purpose: Covert the index of a visible column to the index in the data array (take account
5093 - * of hidden columns)
5094 - * Returns: int:i - the data index
5095 - * Inputs: object:oSettings - dataTables settings object
5096 - */
5097 - function _fnVisibleToColumnIndex( oSettings, iMatch )
5098 - {
5099 - var iColumn = -1;
5100 -
5101 - for ( var i=0 ; i<oSettings.aoColumns.length ; i++ )
5102 - {
5103 - if ( oSettings.aoColumns[i].bVisible === true )
5104 - {
5105 - iColumn++;
5106 - }
5107 -
5108 - if ( iColumn == iMatch )
5109 - {
5110 - return i;
5111 - }
5112 - }
5113 -
5114 - return null;
5115 - }
5116 -
5117 - /*
5118 - * Function: _fnColumnIndexToVisible
5119 - * Purpose: Covert the index of an index in the data array and convert it to the visible
5120 - * column index (take account of hidden columns)
5121 - * Returns: int:i - the data index
5122 - * Inputs: object:oSettings - dataTables settings object
5123 - */
5124 - function _fnColumnIndexToVisible( oSettings, iMatch )
5125 - {
5126 - var iVisible = -1;
5127 - for ( var i=0 ; i<oSettings.aoColumns.length ; i++ )
5128 - {
5129 - if ( oSettings.aoColumns[i].bVisible === true )
5130 - {
5131 - iVisible++;
5132 - }
5133 -
5134 - if ( i == iMatch )
5135 - {
5136 - return oSettings.aoColumns[i].bVisible === true ? iVisible : null;
5137 - }
5138 - }
5139 -
5140 - return null;
5141 - }
5142 -
5143 -
5144 - /*
5145 - * Function: _fnNodeToDataIndex
5146 - * Purpose: Take a TR element and convert it to an index in aoData
5147 - * Returns: int:i - index if found, null if not
5148 - * Inputs: object:s - dataTables settings object
5149 - * node:n - the TR element to find
5150 - */
5151 - function _fnNodeToDataIndex( s, n )
5152 - {
5153 - var i, iLen;
5154 -
5155 - /* Optimisation - see if the nodes which are currently visible match, since that is
5156 - * the most likely node to be asked for (a selector or event for example)
5157 - */
5158 - for ( i=s._iDisplayStart, iLen=s._iDisplayEnd ; i<iLen ; i++ )
5159 - {
5160 - if ( s.aoData[ s.aiDisplay[i] ].nTr == n )
5161 - {
5162 - return s.aiDisplay[i];
5163 - }
5164 - }
5165 -
5166 - /* Otherwise we are in for a slog through the whole data cache */
5167 - for ( i=0, iLen=s.aoData.length ; i<iLen ; i++ )
5168 - {
5169 - if ( s.aoData[i].nTr == n )
5170 - {
5171 - return i;
5172 - }
5173 - }
5174 - return null;
5175 - }
5176 -
5177 - /*
5178 - * Function: _fnVisbleColumns
5179 - * Purpose: Get the number of visible columns
5180 - * Returns: int:i - the number of visible columns
5181 - * Inputs: object:oS - dataTables settings object
5182 - */
5183 - function _fnVisbleColumns( oS )
5184 - {
5185 - var iVis = 0;
5186 - for ( var i=0 ; i<oS.aoColumns.length ; i++ )
5187 - {
5188 - if ( oS.aoColumns[i].bVisible === true )
5189 - {
5190 - iVis++;
5191 - }
5192 - }
5193 - return iVis;
5194 - }
5195 -
5196 - /*
5197 - * Function: _fnCalculateEnd
5198 - * Purpose: Rcalculate the end point based on the start point
5199 - * Returns: -
5200 - * Inputs: object:oSettings - dataTables settings object
5201 - */
5202 - function _fnCalculateEnd( oSettings )
5203 - {
5204 - if ( oSettings.oFeatures.bPaginate === false )
5205 - {
5206 - oSettings._iDisplayEnd = oSettings.aiDisplay.length;
5207 - }
5208 - else
5209 - {
5210 - /* Set the end point of the display - based on how many elements there are
5211 - * still to display
5212 - */
5213 - if ( oSettings._iDisplayStart + oSettings._iDisplayLength > oSettings.aiDisplay.length ||
5214 - oSettings._iDisplayLength == -1 )
5215 - {
5216 - oSettings._iDisplayEnd = oSettings.aiDisplay.length;
5217 - }
5218 - else
5219 - {
5220 - oSettings._iDisplayEnd = oSettings._iDisplayStart + oSettings._iDisplayLength;
5221 - }
5222 - }
5223 - }
5224 -
5225 - /*
5226 - * Function: _fnConvertToWidth
5227 - * Purpose: Convert a CSS unit width to pixels (e.g. 2em)
5228 - * Returns: int:iWidth - width in pixels
5229 - * Inputs: string:sWidth - width to be converted
5230 - * node:nParent - parent to get the with for (required for
5231 - * relative widths) - optional
5232 - */
5233 - function _fnConvertToWidth ( sWidth, nParent )
5234 - {
5235 - if ( !sWidth || sWidth === null || sWidth === '' )
5236 - {
5237 - return 0;
5238 - }
5239 -
5240 - if ( typeof nParent == "undefined" )
5241 - {
5242 - nParent = document.getElementsByTagName('body')[0];
5243 - }
5244 -
5245 - var iWidth;
5246 - var nTmp = document.createElement( "div" );
5247 - nTmp.style.width = sWidth;
5248 -
5249 - nParent.appendChild( nTmp );
5250 - iWidth = nTmp.offsetWidth;
5251 - nParent.removeChild( nTmp );
5252 -
5253 - return ( iWidth );
5254 - }
5255 -
5256 - /*
5257 - * Function: _fnCalculateColumnWidths
5258 - * Purpose: Calculate the width of columns for the table
5259 - * Returns: -
5260 - * Inputs: object:oSettings - dataTables settings object
5261 - */
5262 - function _fnCalculateColumnWidths ( oSettings )
5263 - {
5264 - var iTableWidth = oSettings.nTable.offsetWidth;
5265 - var iUserInputs = 0;
5266 - var iTmpWidth;
5267 - var iVisibleColumns = 0;
5268 - var iColums = oSettings.aoColumns.length;
5269 - var i;
5270 - var oHeaders = $('th', oSettings.nTHead);
5271 -
5272 - /* Convert any user input sizes into pixel sizes */
5273 - for ( i=0 ; i<iColums ; i++ )
5274 - {
5275 - if ( oSettings.aoColumns[i].bVisible )
5276 - {
5277 - iVisibleColumns++;
5278 -
5279 - if ( oSettings.aoColumns[i].sWidth !== null )
5280 - {
5281 - iTmpWidth = _fnConvertToWidth( oSettings.aoColumns[i].sWidthOrig,
5282 - oSettings.nTable.parentNode );
5283 - if ( iTmpWidth !== null )
5284 - {
5285 - oSettings.aoColumns[i].sWidth = _fnStringToCss( iTmpWidth );
5286 - }
5287 -
5288 - iUserInputs++;
5289 - }
5290 - }
5291 - }
5292 -
5293 - /* If the number of columns in the DOM equals the number that we have to process in
5294 - * DataTables, then we can use the offsets that are created by the web-browser. No custom
5295 - * sizes can be set in order for this to happen, nor scrolling used
5296 - */
5297 - if ( iColums == oHeaders.length && iUserInputs === 0 && iVisibleColumns == iColums &&
5298 - oSettings.oScroll.sX === "" && oSettings.oScroll.sY === "" )
5299 - {
5300 - for ( i=0 ; i<oSettings.aoColumns.length ; i++ )
5301 - {
5302 - iTmpWidth = $(oHeaders[i]).width();
5303 - if ( iTmpWidth !== null )
5304 - {
5305 - oSettings.aoColumns[i].sWidth = _fnStringToCss( iTmpWidth );
5306 - }
5307 - }
5308 - }
5309 - else
5310 - {
5311 - /* Otherwise we are going to have to do some calculations to get the width of each column.
5312 - * Construct a 1 row table with the widest node in the data, and any user defined widths,
5313 - * then insert it into the DOM and allow the browser to do all the hard work of
5314 - * calculating table widths.
5315 - */
5316 - var
5317 - nCalcTmp = oSettings.nTable.cloneNode( false ),
5318 - nBody = document.createElement( 'tbody' ),
5319 - nTr = document.createElement( 'tr' ),
5320 - nDivSizing;
5321 -
5322 - nCalcTmp.removeAttribute( "id" );
5323 - nCalcTmp.appendChild( oSettings.nTHead.cloneNode(true) );
5324 - if ( oSettings.nTFoot !== null )
5325 - {
5326 - nCalcTmp.appendChild( oSettings.nTFoot.cloneNode(true) );
5327 - _fnApplyToChildren( function(n) {
5328 - n.style.width = "";
5329 - }, nCalcTmp.getElementsByTagName('tr') );
5330 - }
5331 -
5332 - nCalcTmp.appendChild( nBody );
5333 - nBody.appendChild( nTr );
5334 -
5335 - /* Remove any sizing that was previously applied by the styles */
5336 - var jqColSizing = $('thead th', nCalcTmp);
5337 - if ( jqColSizing.length === 0 )
5338 - {
5339 - jqColSizing = $('tbody tr:eq(0)>td', nCalcTmp);
5340 - }
5341 - jqColSizing.each( function (i) {
5342 - this.style.width = "";
5343 -
5344 - var iIndex = _fnVisibleToColumnIndex( oSettings, i );
5345 - if ( iIndex !== null && oSettings.aoColumns[iIndex].sWidthOrig !== "" )
5346 - {
5347 - this.style.width = oSettings.aoColumns[iIndex].sWidthOrig;
5348 - }
5349 - } );
5350 -
5351 - /* Find the biggest td for each column and put it into the table */
5352 - for ( i=0 ; i<iColums ; i++ )
5353 - {
5354 - if ( oSettings.aoColumns[i].bVisible )
5355 - {
5356 - var nTd = _fnGetWidestNode( oSettings, i );
5357 - if ( nTd !== null )
5358 - {
5359 - nTd = nTd.cloneNode(true);
5360 - nTr.appendChild( nTd );
5361 - }
5362 - }
5363 - }
5364 -
5365 - /* Build the table and 'display' it */
5366 - var nWrapper = oSettings.nTable.parentNode;
5367 - nWrapper.appendChild( nCalcTmp );
5368 -
5369 - /* When scrolling (X or Y) we want to set the width of the table as appropriate. However,
5370 - * when not scrolling leave the table width as it is. This results in slightly different,
5371 - * but I think correct behaviour
5372 - */
5373 - if ( oSettings.oScroll.sX !== "" && oSettings.oScroll.sXInner !== "" )
5374 - {
5375 - nCalcTmp.style.width = _fnStringToCss(oSettings.oScroll.sXInner);
5376 - }
5377 - else if ( oSettings.oScroll.sX !== "" )
5378 - {
5379 - nCalcTmp.style.width = "";
5380 - if ( $(nCalcTmp).width() < nWrapper.offsetWidth )
5381 - {
5382 - nCalcTmp.style.width = _fnStringToCss( nWrapper.offsetWidth );
5383 - }
5384 - }
5385 - else if ( oSettings.oScroll.sY !== "" )
5386 - {
5387 - nCalcTmp.style.width = _fnStringToCss( nWrapper.offsetWidth );
5388 - }
5389 - nCalcTmp.style.visibility = "hidden";
5390 -
5391 - /* Scrolling considerations */
5392 - _fnScrollingWidthAdjust( oSettings, nCalcTmp );
5393 -
5394 - /* Read the width's calculated by the browser and store them for use by the caller. We
5395 - * first of all try to use the elements in the body, but it is possible that there are
5396 - * no elements there, under which circumstances we use the header elements
5397 - */
5398 - var oNodes = $("tbody tr:eq(0)>td", nCalcTmp);
5399 - if ( oNodes.length === 0 )
5400 - {
5401 - oNodes = $("thead tr:eq(0)>th", nCalcTmp);
5402 - }
5403 -
5404 - var iIndex, iCorrector = 0, iWidth;
5405 - for ( i=0 ; i<oSettings.aoColumns.length ; i++ )
5406 - {
5407 - if ( oSettings.aoColumns[i].bVisible )
5408 - {
5409 - iWidth = $(oNodes[iCorrector]).width();
5410 - if ( iWidth !== null && iWidth > 0 )
5411 - {
5412 - oSettings.aoColumns[i].sWidth = _fnStringToCss( iWidth );
5413 - }
5414 - iCorrector++;
5415 - }
5416 - }
5417 -
5418 - oSettings.nTable.style.width = _fnStringToCss( $(nCalcTmp).outerWidth() );
5419 - nCalcTmp.parentNode.removeChild( nCalcTmp );
5420 - }
5421 - }
5422 -
5423 - /*
5424 - * Function: _fnScrollingWidthAdjust
5425 - * Purpose: Adjust a table's width to take account of scrolling
5426 - * Returns: -
5427 - * Inputs: object:oSettings - dataTables settings object
5428 - * node:n - table node
5429 - */
5430 - function _fnScrollingWidthAdjust ( oSettings, n )
5431 - {
5432 - if ( oSettings.oScroll.sX === "" && oSettings.oScroll.sY !== "" )
5433 - {
5434 - /* When y-scrolling only, we want to remove the width of the scroll bar so the table
5435 - * + scroll bar will fit into the area avaialble.
5436 - */
5437 - var iOrigWidth = $(n).width();
5438 - n.style.width = _fnStringToCss( $(n).outerWidth()-oSettings.oScroll.iBarWidth );
5439 - }
5440 - else if ( oSettings.oScroll.sX !== "" )
5441 - {
5442 - /* When x-scrolling both ways, fix the table at it's current size, without adjusting */
5443 - n.style.width = _fnStringToCss( $(n).outerWidth() );
5444 - }
5445 - }
5446 -
5447 - /*
5448 - * Function: _fnGetWidestNode
5449 - * Purpose: Get the widest node
5450 - * Returns: string: - max strlens for each column
5451 - * Inputs: object:oSettings - dataTables settings object
5452 - * int:iCol - column of interest
5453 - * boolean:bFast - Should we use fast (but non-accurate) calculation - optional,
5454 - * default true
5455 - * Notes: This operation is _expensive_ (!!!). It requires a lot of DOM interaction, but
5456 - * this is the only way to reliably get the widest string. For example 'mmm' would be wider
5457 - * than 'iiii' so we can't just ocunt characters. If this can be optimised it would be good
5458 - * to do so!
5459 - */
5460 - function _fnGetWidestNode( oSettings, iCol, bFast )
5461 - {
5462 - /* Use fast not non-accurate calculate based on the strlen */
5463 - if ( typeof bFast == 'undefined' || bFast )
5464 - {
5465 - var iMaxLen = _fnGetMaxLenString( oSettings, iCol );
5466 - var iFastVis = _fnColumnIndexToVisible( oSettings, iCol);
5467 - if ( iMaxLen < 0 )
5468 - {
5469 - return null;
5470 - }
5471 - return oSettings.aoData[iMaxLen].nTr.getElementsByTagName('td')[iFastVis];
5472 - }
5473 -
5474 - /* Use the slow approach, but get high quality answers - note that this code is not actually
5475 - * used by DataTables by default. If you want to use it you can alter the call to
5476 - * _fnGetWidestNode to pass 'false' as the third argument
5477 - */
5478 - var
5479 - iMax = -1, i, iLen,
5480 - iMaxIndex = -1,
5481 - n = document.createElement('div');
5482 -
5483 - n.style.visibility = "hidden";
5484 - n.style.position = "absolute";
5485 - document.body.appendChild( n );
5486 -
5487 - for ( i=0, iLen=oSettings.aoData.length ; i<iLen ; i++ )
5488 - {
5489 - n.innerHTML = oSettings.aoData[i]._aData[iCol];
5490 - if ( n.offsetWidth > iMax )
5491 - {
5492 - iMax = n.offsetWidth;
5493 - iMaxIndex = i;
5494 - }
5495 - }
5496 - document.body.removeChild( n );
5497 -
5498 - if ( iMaxIndex >= 0 )
5499 - {
5500 - var iVis = _fnColumnIndexToVisible( oSettings, iCol);
5501 - var nRet = oSettings.aoData[iMaxIndex].nTr.getElementsByTagName('td')[iVis];
5502 - if ( nRet )
5503 - {
5504 - return nRet;
5505 - }
5506 - }
5507 - return null;
5508 - }
5509 -
5510 - /*
5511 - * Function: _fnGetMaxLenString
5512 - * Purpose: Get the maximum strlen for each data column
5513 - * Returns: string: - max strlens for each column
5514 - * Inputs: object:oSettings - dataTables settings object
5515 - * int:iCol - column of interest
5516 - */
5517 - function _fnGetMaxLenString( oSettings, iCol )
5518 - {
5519 - var iMax = -1;
5520 - var iMaxIndex = -1;
5521 -
5522 - for ( var i=0 ; i<oSettings.aoData.length ; i++ )
5523 - {
5524 - var s = oSettings.aoData[i]._aData[iCol];
5525 - if ( s.length > iMax )
5526 - {
5527 - iMax = s.length;
5528 - iMaxIndex = i;
5529 - }
5530 - }
5531 -
5532 - return iMaxIndex;
5533 - }
5534 -
5535 - /*
5536 - * Function: _fnStringToCss
5537 - * Purpose: Append a CSS unit (only if required) to a string
5538 - * Returns: 0 if match, 1 if length is different, 2 if no match
5539 - * Inputs: array:aArray1 - first array
5540 - * array:aArray2 - second array
5541 - */
5542 - function _fnStringToCss( s )
5543 - {
5544 - if ( s === null )
5545 - {
5546 - return "0px";
5547 - }
5548 -
5549 - if ( typeof s == 'number' )
5550 - {
5551 - if ( s < 0 )
5552 - {
5553 - return "0px";
5554 - }
5555 - return s+"px";
5556 - }
5557 -
5558 - /* Check if the last character is not 0-9 */
5559 - var c = s.charCodeAt( s.length-1 );
5560 - if (c < 0x30 || c > 0x39)
5561 - {
5562 - return s;
5563 - }
5564 - return s+"px";
5565 - }
5566 -
5567 - /*
5568 - * Function: _fnArrayCmp
5569 - * Purpose: Compare two arrays
5570 - * Returns: 0 if match, 1 if length is different, 2 if no match
5571 - * Inputs: array:aArray1 - first array
5572 - * array:aArray2 - second array
5573 - */
5574 - function _fnArrayCmp( aArray1, aArray2 )
5575 - {
5576 - if ( aArray1.length != aArray2.length )
5577 - {
5578 - return 1;
5579 - }
5580 -
5581 - for ( var i=0 ; i<aArray1.length ; i++ )
5582 - {
5583 - if ( aArray1[i] != aArray2[i] )
5584 - {
5585 - return 2;
5586 - }
5587 - }
5588 -
5589 - return 0;
5590 - }
5591 -
5592 - /*
5593 - * Function: _fnDetectType
5594 - * Purpose: Get the sort type based on an input string
5595 - * Returns: string: - type (defaults to 'string' if no type can be detected)
5596 - * Inputs: string:sData - data we wish to know the type of
5597 - * Notes: This function makes use of the DataTables plugin objct _oExt
5598 - * (.aTypes) such that new types can easily be added.
5599 - */
5600 - function _fnDetectType( sData )
5601 - {
5602 - var aTypes = _oExt.aTypes;
5603 - var iLen = aTypes.length;
5604 -
5605 - for ( var i=0 ; i<iLen ; i++ )
5606 - {
5607 - var sType = aTypes[i]( sData );
5608 - if ( sType !== null )
5609 - {
5610 - return sType;
5611 - }
5612 - }
5613 -
5614 - return 'string';
5615 - }
5616 -
5617 - /*
5618 - * Function: _fnSettingsFromNode
5619 - * Purpose: Return the settings object for a particular table
5620 - * Returns: object: Settings object - or null if not found
5621 - * Inputs: node:nTable - table we are using as a dataTable
5622 - */
5623 - function _fnSettingsFromNode ( nTable )
5624 - {
5625 - for ( var i=0 ; i<_aoSettings.length ; i++ )
5626 - {
5627 - if ( _aoSettings[i].nTable == nTable )
5628 - {
5629 - return _aoSettings[i];
5630 - }
5631 - }
5632 -
5633 - return null;
5634 - }
5635 -
5636 - /*
5637 - * Function: _fnGetDataMaster
5638 - * Purpose: Return an array with the full table data
5639 - * Returns: array array:aData - Master data array
5640 - * Inputs: object:oSettings - dataTables settings object
5641 - */
5642 - function _fnGetDataMaster ( oSettings )
5643 - {
5644 - var aData = [];
5645 - var iLen = oSettings.aoData.length;
5646 - for ( var i=0 ; i<iLen; i++ )
5647 - {
5648 - aData.push( oSettings.aoData[i]._aData );
5649 - }
5650 - return aData;
5651 - }
5652 -
5653 - /*
5654 - * Function: _fnGetTrNodes
5655 - * Purpose: Return an array with the TR nodes for the table
5656 - * Returns: array: - TR array
5657 - * Inputs: object:oSettings - dataTables settings object
5658 - */
5659 - function _fnGetTrNodes ( oSettings )
5660 - {
5661 - var aNodes = [];
5662 - var iLen = oSettings.aoData.length;
5663 - for ( var i=0 ; i<iLen ; i++ )
5664 - {
5665 - aNodes.push( oSettings.aoData[i].nTr );
5666 - }
5667 - return aNodes;
5668 - }
5669 -
5670 - /*
5671 - * Function: _fnGetTdNodes
5672 - * Purpose: Return an array with the TD nodes for the table
5673 - * Returns: array: - TD array
5674 - * Inputs: object:oSettings - dataTables settings object
5675 - */
5676 - function _fnGetTdNodes ( oSettings )
5677 - {
5678 - var nTrs = _fnGetTrNodes( oSettings );
5679 - var nTds = [], nTd;
5680 - var anReturn = [];
5681 - var iCorrector;
5682 - var iRow, iRows, iColumn, iColumns;
5683 -
5684 - for ( iRow=0, iRows=nTrs.length ; iRow<iRows ; iRow++ )
5685 - {
5686 - nTds = [];
5687 - for ( iColumn=0, iColumns=nTrs[iRow].childNodes.length ; iColumn<iColumns ; iColumn++ )
5688 - {
5689 - nTd = nTrs[iRow].childNodes[iColumn];
5690 - if ( nTd.nodeName.toUpperCase() == "TD" )
5691 - {
5692 - nTds.push( nTd );
5693 - }
5694 - }
5695 -
5696 - iCorrector = 0;
5697 - for ( iColumn=0, iColumns=oSettings.aoColumns.length ; iColumn<iColumns ; iColumn++ )
5698 - {
5699 - if ( oSettings.aoColumns[iColumn].bVisible )
5700 - {
5701 - anReturn.push( nTds[iColumn-iCorrector] );
5702 - }
5703 - else
5704 - {
5705 - anReturn.push( oSettings.aoData[iRow]._anHidden[iColumn] );
5706 - iCorrector++;
5707 - }
5708 - }
5709 - }
5710 - return anReturn;
5711 - }
5712 -
5713 - /*
5714 - * Function: _fnEscapeRegex
5715 - * Purpose: scape a string stuch that it can be used in a regular expression
5716 - * Returns: string: - escaped string
5717 - * Inputs: string:sVal - string to escape
5718 - */
5719 - function _fnEscapeRegex ( sVal )
5720 - {
5721 - var acEscape = [ '/', '.', '*', '+', '?', '|', '(', ')', '[', ']', '{', '}', '\\', '$', '^' ];
5722 - var reReplace = new RegExp( '(\\' + acEscape.join('|\\') + ')', 'g' );
5723 - return sVal.replace(reReplace, '\\$1');
5724 - }
5725 -
5726 - /*
5727 - * Function: _fnDeleteIndex
5728 - * Purpose: Take an array of integers (index array) and remove a target integer (value - not
5729 - * the key!)
5730 - * Returns: -
5731 - * Inputs: a:array int - Index array to target
5732 - * int:iTarget - value to find
5733 - */
5734 - function _fnDeleteIndex( a, iTarget )
5735 - {
5736 - var iTargetIndex = -1;
5737 -
5738 - for ( var i=0, iLen=a.length ; i<iLen ; i++ )
5739 - {
5740 - if ( a[i] == iTarget )
5741 - {
5742 - iTargetIndex = i;
5743 - }
5744 - else if ( a[i] > iTarget )
5745 - {
5746 - a[i]--;
5747 - }
5748 - }
5749 -
5750 - if ( iTargetIndex != -1 )
5751 - {
5752 - a.splice( iTargetIndex, 1 );
5753 - }
5754 - }
5755 -
5756 - /*
5757 - * Function: _fnReOrderIndex
5758 - * Purpose: Figure out how to reorder a display list
5759 - * Returns: array int:aiReturn - index list for reordering
5760 - * Inputs: object:oSettings - dataTables settings object
5761 - */
5762 - function _fnReOrderIndex ( oSettings, sColumns )
5763 - {
5764 - var aColumns = sColumns.split(',');
5765 - var aiReturn = [];
5766 -
5767 - for ( var i=0, iLen=oSettings.aoColumns.length ; i<iLen ; i++ )
5768 - {
5769 - for ( var j=0 ; j<iLen ; j++ )
5770 - {
5771 - if ( oSettings.aoColumns[i].sName == aColumns[j] )
5772 - {
5773 - aiReturn.push( j );
5774 - break;
5775 - }
5776 - }
5777 - }
5778 -
5779 - return aiReturn;
5780 - }
5781 -
5782 - /*
5783 - * Function: _fnColumnOrdering
5784 - * Purpose: Get the column ordering that DataTables expects
5785 - * Returns: string: - comma separated list of names
5786 - * Inputs: object:oSettings - dataTables settings object
5787 - */
5788 - function _fnColumnOrdering ( oSettings )
5789 - {
5790 - var sNames = '';
5791 - for ( var i=0, iLen=oSettings.aoColumns.length ; i<iLen ; i++ )
5792 - {
5793 - sNames += oSettings.aoColumns[i].sName+',';
5794 - }
5795 - if ( sNames.length == iLen )
5796 - {
5797 - return "";
5798 - }
5799 - return sNames.slice(0, -1);
5800 - }
5801 -
5802 - /*
5803 - * Function: _fnLog
5804 - * Purpose: Log an error message
5805 - * Returns: -
5806 - * Inputs: int:iLevel - log error messages, or display them to the user
5807 - * string:sMesg - error message
5808 - */
5809 - function _fnLog( oSettings, iLevel, sMesg )
5810 - {
5811 - var sAlert = oSettings.sTableId === "" ?
5812 - "DataTables warning: " +sMesg :
5813 - "DataTables warning (table id = '"+oSettings.sTableId+"'): " +sMesg;
5814 -
5815 - if ( iLevel === 0 )
5816 - {
5817 - if ( _oExt.sErrMode == 'alert' )
5818 - {
5819 - alert( sAlert );
5820 - }
5821 - else
5822 - {
5823 - throw sAlert;
5824 - }
5825 - return;
5826 - }
5827 - else if ( typeof console != 'undefined' && typeof console.log != 'undefined' )
5828 - {
5829 - console.log( sAlert );
5830 - }
5831 - }
5832 -
5833 - /*
5834 - * Function: _fnClearTable
5835 - * Purpose: Nuke the table
5836 - * Returns: -
5837 - * Inputs: object:oSettings - dataTables settings object
5838 - */
5839 - function _fnClearTable( oSettings )
5840 - {
5841 - oSettings.aoData.splice( 0, oSettings.aoData.length );
5842 - oSettings.aiDisplayMaster.splice( 0, oSettings.aiDisplayMaster.length );
5843 - oSettings.aiDisplay.splice( 0, oSettings.aiDisplay.length );
5844 - _fnCalculateEnd( oSettings );
5845 - }
5846 -
5847 - /*
5848 - * Function: _fnSaveState
5849 - * Purpose: Save the state of a table in a cookie such that the page can be reloaded
5850 - * Returns: -
5851 - * Inputs: object:oSettings - dataTables settings object
5852 - */
5853 - function _fnSaveState ( oSettings )
5854 - {
5855 - if ( !oSettings.oFeatures.bStateSave || typeof oSettings.bDestroying != 'undefined' )
5856 - {
5857 - return;
5858 - }
5859 -
5860 - /* Store the interesting variables */
5861 - var i, iLen, sTmp;
5862 - var sValue = "{";
5863 - sValue += '"iCreate":'+ new Date().getTime()+',';
5864 - sValue += '"iStart":'+ oSettings._iDisplayStart+',';
5865 - sValue += '"iEnd":'+ oSettings._iDisplayEnd+',';
5866 - sValue += '"iLength":'+ oSettings._iDisplayLength+',';
5867 - sValue += '"sFilter":"'+ encodeURIComponent(oSettings.oPreviousSearch.sSearch)+'",';
5868 - sValue += '"sFilterEsc":'+ !oSettings.oPreviousSearch.bRegex+',';
5869 -
5870 - sValue += '"aaSorting":[ ';
5871 - for ( i=0 ; i<oSettings.aaSorting.length ; i++ )
5872 - {
5873 - sValue += '['+oSettings.aaSorting[i][0]+',"'+oSettings.aaSorting[i][1]+'"],';
5874 - }
5875 - sValue = sValue.substring(0, sValue.length-1);
5876 - sValue += "],";
5877 -
5878 - sValue += '"aaSearchCols":[ ';
5879 - for ( i=0 ; i<oSettings.aoPreSearchCols.length ; i++ )
5880 - {
5881 - sValue += '["'+encodeURIComponent(oSettings.aoPreSearchCols[i].sSearch)+
5882 - '",'+!oSettings.aoPreSearchCols[i].bRegex+'],';
5883 - }
5884 - sValue = sValue.substring(0, sValue.length-1);
5885 - sValue += "],";
5886 -
5887 - sValue += '"abVisCols":[ ';
5888 - for ( i=0 ; i<oSettings.aoColumns.length ; i++ )
5889 - {
5890 - sValue += oSettings.aoColumns[i].bVisible+",";
5891 - }
5892 - sValue = sValue.substring(0, sValue.length-1);
5893 - sValue += "]";
5894 -
5895 - /* Save state from any plug-ins */
5896 - for ( i=0, iLen=oSettings.aoStateSave.length ; i<iLen ; i++ )
5897 - {
5898 - sTmp = oSettings.aoStateSave[i].fn( oSettings, sValue );
5899 - if ( sTmp !== "" )
5900 - {
5901 - sValue = sTmp;
5902 - }
5903 - }
5904 -
5905 - sValue += "}";
5906 -
5907 - _fnCreateCookie( oSettings.sCookiePrefix+oSettings.sInstance, sValue,
5908 - oSettings.iCookieDuration, oSettings.sCookiePrefix, oSettings.fnCookieCallback );
5909 - }
5910 -
5911 - /*
5912 - * Function: _fnLoadState
5913 - * Purpose: Attempt to load a saved table state from a cookie
5914 - * Returns: -
5915 - * Inputs: object:oSettings - dataTables settings object
5916 - * object:oInit - DataTables init object so we can override settings
5917 - */
5918 - function _fnLoadState ( oSettings, oInit )
5919 - {
5920 - if ( !oSettings.oFeatures.bStateSave )
5921 - {
5922 - return;
5923 - }
5924 -
5925 - var oData, i, iLen;
5926 - var sData = _fnReadCookie( oSettings.sCookiePrefix+oSettings.sInstance );
5927 - if ( sData !== null && sData !== '' )
5928 - {
5929 - /* Try/catch the JSON eval - if it is bad then we ignore it - note that 1.7.0 and before
5930 - * incorrectly used single quotes for some strings - hence the replace below
5931 - */
5932 - try
5933 - {
5934 - oData = (typeof $.parseJSON == 'function') ?
5935 - $.parseJSON( sData.replace(/'/g, '"') ) : eval( '('+sData+')' );
5936 - }
5937 - catch( e )
5938 - {
5939 - return;
5940 - }
5941 -
5942 - /* Allow custom and plug-in manipulation functions to alter the data set which was
5943 - * saved, and also reject any saved state by returning false
5944 - */
5945 - for ( i=0, iLen=oSettings.aoStateLoad.length ; i<iLen ; i++ )
5946 - {
5947 - if ( !oSettings.aoStateLoad[i].fn( oSettings, oData ) )
5948 - {
5949 - return;
5950 - }
5951 - }
5952 -
5953 - /* Store the saved state so it might be accessed at any time (particualrly a plug-in */
5954 - oSettings.oLoadedState = $.extend( true, {}, oData );
5955 -
5956 - /* Restore key features */
5957 - oSettings._iDisplayStart = oData.iStart;
5958 - oSettings.iInitDisplayStart = oData.iStart;
5959 - oSettings._iDisplayEnd = oData.iEnd;
5960 - oSettings._iDisplayLength = oData.iLength;
5961 - oSettings.oPreviousSearch.sSearch = decodeURIComponent(oData.sFilter);
5962 - oSettings.aaSorting = oData.aaSorting.slice();
5963 - oSettings.saved_aaSorting = oData.aaSorting.slice();
5964 -
5965 - /*
5966 - * Search filtering - global reference added in 1.4.1
5967 - * Note that we use a 'not' for the value of the regular expression indicator to maintain
5968 - * compatibility with pre 1.7 versions, where this was basically inverted. Added in 1.7.0
5969 - */
5970 - if ( typeof oData.sFilterEsc != 'undefined' )
5971 - {
5972 - oSettings.oPreviousSearch.bRegex = !oData.sFilterEsc;
5973 - }
5974 -
5975 - /* Column filtering - added in 1.5.0 beta 6 */
5976 - if ( typeof oData.aaSearchCols != 'undefined' )
5977 - {
5978 - for ( i=0 ; i<oData.aaSearchCols.length ; i++ )
5979 - {
5980 - oSettings.aoPreSearchCols[i] = {
5981 - "sSearch": decodeURIComponent(oData.aaSearchCols[i][0]),
5982 - "bRegex": !oData.aaSearchCols[i][1]
5983 - };
5984 - }
5985 - }
5986 -
5987 - /* Column visibility state - added in 1.5.0 beta 10 */
5988 - if ( typeof oData.abVisCols != 'undefined' )
5989 - {
5990 - /* Pass back visibiliy settings to the init handler, but to do not here override
5991 - * the init object that the user might have passed in
5992 - */
5993 - oInit.saved_aoColumns = [];
5994 - for ( i=0 ; i<oData.abVisCols.length ; i++ )
5995 - {
5996 - oInit.saved_aoColumns[i] = {};
5997 - oInit.saved_aoColumns[i].bVisible = oData.abVisCols[i];
5998 - }
5999 - }
6000 - }
6001 - }
6002 -
6003 - /*
6004 - * Function: _fnCreateCookie
6005 - * Purpose: Create a new cookie with a value to store the state of a table
6006 - * Returns: -
6007 - * Inputs: string:sName - name of the cookie to create
6008 - * string:sValue - the value the cookie should take
6009 - * int:iSecs - duration of the cookie
6010 - * string:sBaseName - sName is made up of the base + file name - this is the base
6011 - * function:fnCallback - User definable function to modify the cookie
6012 - */
6013 - function _fnCreateCookie ( sName, sValue, iSecs, sBaseName, fnCallback )
6014 - {
6015 - var date = new Date();
6016 - date.setTime( date.getTime()+(iSecs*1000) );
6017 -
6018 - /*
6019 - * Shocking but true - it would appear IE has major issues with having the path not having
6020 - * a trailing slash on it. We need the cookie to be available based on the path, so we
6021 - * have to append the file name to the cookie name. Appalling. Thanks to vex for adding the
6022 - * patch to use at least some of the path
6023 - */
6024 - var aParts = window.location.pathname.split('/');
6025 - var sNameFile = sName + '_' + aParts.pop().replace(/[\/:]/g,"").toLowerCase();
6026 - var sFullCookie, oData;
6027 -
6028 - if ( fnCallback !== null )
6029 - {
6030 - oData = (typeof $.parseJSON == 'function') ?
6031 - $.parseJSON( sValue ) : eval( '('+sValue+')' );
6032 - sFullCookie = fnCallback( sNameFile, oData, date.toGMTString(),
6033 - aParts.join('/')+"/" );
6034 - }
6035 - else
6036 - {
6037 - sFullCookie = sNameFile + "=" + encodeURIComponent(sValue) +
6038 - "; expires=" + date.toGMTString() +"; path=" + aParts.join('/')+"/";
6039 - }
6040 -
6041 - /* Are we going to go over the cookie limit of 4KiB? If so, try to delete a cookies
6042 - * belonging to DataTables. This is FAR from bullet proof
6043 - */
6044 - var sOldName="", iOldTime=9999999999999;
6045 - var iLength = _fnReadCookie( sNameFile )!==null ? document.cookie.length :
6046 - sFullCookie.length + document.cookie.length;
6047 -
6048 - if ( iLength+10 > 4096 ) /* Magic 10 for padding */
6049 - {
6050 - var aCookies =document.cookie.split(';');
6051 - for ( var i=0, iLen=aCookies.length ; i<iLen ; i++ )
6052 - {
6053 - if ( aCookies[i].indexOf( sBaseName ) != -1 )
6054 - {
6055 - /* It's a DataTables cookie, so eval it and check the time stamp */
6056 - var aSplitCookie = aCookies[i].split('=');
6057 - try { oData = eval( '('+decodeURIComponent(aSplitCookie[1])+')' ); }
6058 - catch( e ) { continue; }
6059 -
6060 - if ( typeof oData.iCreate != 'undefined' && oData.iCreate < iOldTime )
6061 - {
6062 - sOldName = aSplitCookie[0];
6063 - iOldTime = oData.iCreate;
6064 - }
6065 - }
6066 - }
6067 -
6068 - if ( sOldName !== "" )
6069 - {
6070 - document.cookie = sOldName+"=; expires=Thu, 01-Jan-1970 00:00:01 GMT; path="+
6071 - aParts.join('/') + "/";
6072 - }
6073 - }
6074 -
6075 - document.cookie = sFullCookie;
6076 - }
6077 -
6078 - /*
6079 - * Function: _fnReadCookie
6080 - * Purpose: Read an old cookie to get a cookie with an old table state
6081 - * Returns: string: - contents of the cookie - or null if no cookie with that name found
6082 - * Inputs: string:sName - name of the cookie to read
6083 - */
6084 - function _fnReadCookie ( sName )
6085 - {
6086 - var
6087 - aParts = window.location.pathname.split('/'),
6088 - sNameEQ = sName + '_' + aParts[aParts.length-1].replace(/[\/:]/g,"").toLowerCase() + '=',
6089 - sCookieContents = document.cookie.split(';');
6090 -
6091 - for( var i=0 ; i<sCookieContents.length ; i++ )
6092 - {
6093 - var c = sCookieContents[i];
6094 -
6095 - while (c.charAt(0)==' ')
6096 - {
6097 - c = c.substring(1,c.length);
6098 - }
6099 -
6100 - if (c.indexOf(sNameEQ) === 0)
6101 - {
6102 - return decodeURIComponent( c.substring(sNameEQ.length,c.length) );
6103 - }
6104 - }
6105 - return null;
6106 - }
6107 -
6108 - /*
6109 - * Function: _fnGetUniqueThs
6110 - * Purpose: Get an array of unique th elements, one for each column
6111 - * Returns: array node:aReturn - list of unique ths
6112 - * Inputs: node:nThead - The thead element for the table
6113 - */
6114 - function _fnGetUniqueThs ( nThead )
6115 - {
6116 - var nTrs = nThead.getElementsByTagName('tr');
6117 -
6118 - /* Nice simple case */
6119 - if ( nTrs.length == 1 )
6120 - {
6121 - return nTrs[0].getElementsByTagName('th');
6122 - }
6123 -
6124 - /* Otherwise we need to figure out the layout array to get the nodes */
6125 - var aLayout = [], aReturn = [];
6126 - var ROWSPAN = 2, COLSPAN = 3, TDELEM = 4;
6127 - var i, j, k, iLen, jLen, iColumnShifted;
6128 - var fnShiftCol = function ( a, i, j ) {
6129 - while ( typeof a[i][j] != 'undefined' ) {
6130 - j++;
6131 - }
6132 - return j;
6133 - };
6134 - var fnAddRow = function ( i ) {
6135 - if ( typeof aLayout[i] == 'undefined' ) {
6136 - aLayout[i] = [];
6137 - }
6138 - };
6139 -
6140 - /* Calculate a layout array */
6141 - for ( i=0, iLen=nTrs.length ; i<iLen ; i++ )
6142 - {
6143 - fnAddRow( i );
6144 - var iColumn = 0;
6145 - var nTds = [];
6146 -
6147 - for ( j=0, jLen=nTrs[i].childNodes.length ; j<jLen ; j++ )
6148 - {
6149 - if ( nTrs[i].childNodes[j].nodeName.toUpperCase() == "TD" ||
6150 - nTrs[i].childNodes[j].nodeName.toUpperCase() == "TH" )
6151 - {
6152 - nTds.push( nTrs[i].childNodes[j] );
6153 - }
6154 - }
6155 -
6156 - for ( j=0, jLen=nTds.length ; j<jLen ; j++ )
6157 - {
6158 - var iColspan = nTds[j].getAttribute('colspan') * 1;
6159 - var iRowspan = nTds[j].getAttribute('rowspan') * 1;
6160 -
6161 - if ( !iColspan || iColspan===0 || iColspan===1 )
6162 - {
6163 - iColumnShifted = fnShiftCol( aLayout, i, iColumn );
6164 - aLayout[i][iColumnShifted] = (nTds[j].nodeName.toUpperCase()=="TD") ? TDELEM : nTds[j];
6165 - if ( iRowspan || iRowspan===0 || iRowspan===1 )
6166 - {
6167 - for ( k=1 ; k<iRowspan ; k++ )
6168 - {
6169 - fnAddRow( i+k );
6170 - aLayout[i+k][iColumnShifted] = ROWSPAN;
6171 - }
6172 - }
6173 - iColumn++;
6174 - }
6175 - else
6176 - {
6177 - iColumnShifted = fnShiftCol( aLayout, i, iColumn );
6178 - for ( k=0 ; k<iColspan ; k++ )
6179 - {
6180 - aLayout[i][iColumnShifted+k] = COLSPAN;
6181 - }
6182 - iColumn += iColspan;
6183 - }
6184 - }
6185 - }
6186 -
6187 - /* Convert the layout array into a node array */
6188 - for ( i=0, iLen=aLayout.length ; i<iLen ; i++ )
6189 - {
6190 - for ( j=0, jLen=aLayout[i].length ; j<jLen ; j++ )
6191 - {
6192 - if ( typeof aLayout[i][j] == 'object' && typeof aReturn[j] == 'undefined' )
6193 - {
6194 - aReturn[j] = aLayout[i][j];
6195 - }
6196 - }
6197 - }
6198 -
6199 - return aReturn;
6200 - }
6201 -
6202 - /*
6203 - * Function: _fnScrollBarWidth
6204 - * Purpose: Get the width of a scroll bar in this browser being used
6205 - * Returns: int: - width in pixels
6206 - * Inputs: -
6207 - * Notes: All credit for this function belongs to Alexandre Gomes. Thanks for sharing!
6208 - * http://www.alexandre-gomes.com/?p=115
6209 - */
6210 - function _fnScrollBarWidth ()
6211 - {
6212 - var inner = document.createElement('p');
6213 - var style = inner.style;
6214 - style.width = "100%";
6215 - style.height = "200px";
6216 -
6217 - var outer = document.createElement('div');
6218 - style = outer.style;
6219 - style.position = "absolute";
6220 - style.top = "0px";
6221 - style.left = "0px";
6222 - style.visibility = "hidden";
6223 - style.width = "200px";
6224 - style.height = "150px";
6225 - style.overflow = "hidden";
6226 - outer.appendChild(inner);
6227 -
6228 - document.body.appendChild(outer);
6229 - var w1 = inner.offsetWidth;
6230 - outer.style.overflow = 'scroll';
6231 - var w2 = inner.offsetWidth;
6232 - if ( w1 == w2 )
6233 - {
6234 - w2 = outer.clientWidth;
6235 - }
6236 -
6237 - document.body.removeChild(outer);
6238 - return (w1 - w2);
6239 - }
6240 -
6241 - /*
6242 - * Function: _fnApplyToChildren
6243 - * Purpose: Apply a given function to the display child nodes of an element array (typically
6244 - * TD children of TR rows
6245 - * Returns: - (done by reference)
6246 - * Inputs: function:fn - Method to apply to the objects
6247 - * array nodes:an1 - List of elements to look through for display children
6248 - * array nodes:an2 - Another list (identical structure to the first) - optional
6249 - */
6250 - function _fnApplyToChildren( fn, an1, an2 )
6251 - {
6252 - for ( var i=0, iLen=an1.length ; i<iLen ; i++ )
6253 - {
6254 - for ( var j=0, jLen=an1[i].childNodes.length ; j<jLen ; j++ )
6255 - {
6256 - if ( an1[i].childNodes[j].nodeType == 1 )
6257 - {
6258 - if ( typeof an2 != 'undefined' )
6259 - {
6260 - fn( an1[i].childNodes[j], an2[i].childNodes[j] );
6261 - }
6262 - else
6263 - {
6264 - fn( an1[i].childNodes[j] );
6265 - }
6266 - }
6267 - }
6268 - }
6269 - }
6270 -
6271 - /*
6272 - * Function: _fnMap
6273 - * Purpose: See if a property is defined on one object, if so assign it to the other object
6274 - * Returns: - (done by reference)
6275 - * Inputs: object:oRet - target object
6276 - * object:oSrc - source object
6277 - * string:sName - property
6278 - * string:sMappedName - name to map too - optional, sName used if not given
6279 - */
6280 - function _fnMap( oRet, oSrc, sName, sMappedName )
6281 - {
6282 - if ( typeof sMappedName == 'undefined' )
6283 - {
6284 - sMappedName = sName;
6285 - }
6286 - if ( typeof oSrc[sName] != 'undefined' )
6287 - {
6288 - oRet[sMappedName] = oSrc[sName];
6289 - }
6290 - }
6291 -
6292 - /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
6293 - * Section - API
6294 - *
6295 - * I'm not overly happy with this solution - I'd much rather that there was a way of getting
6296 - * a list of all the private functions and do what we need to dynamically - but that doesn't
6297 - * appear to be possible. Bonkers. A better solution would be to provide a 'bind' type object
6298 - * To do - bind type method in DTs 2.x.
6299 - */
6300 - this.oApi._fnExternApiFunc = _fnExternApiFunc;
6301 - this.oApi._fnInitalise = _fnInitalise;
6302 - this.oApi._fnLanguageProcess = _fnLanguageProcess;
6303 - this.oApi._fnAddColumn = _fnAddColumn;
6304 - this.oApi._fnColumnOptions = _fnColumnOptions;
6305 - this.oApi._fnAddData = _fnAddData;
6306 - this.oApi._fnGatherData = _fnGatherData;
6307 - this.oApi._fnDrawHead = _fnDrawHead;
6308 - this.oApi._fnDraw = _fnDraw;
6309 - this.oApi._fnReDraw = _fnReDraw;
6310 - this.oApi._fnAjaxUpdate = _fnAjaxUpdate;
6311 - this.oApi._fnAjaxUpdateDraw = _fnAjaxUpdateDraw;
6312 - this.oApi._fnAddOptionsHtml = _fnAddOptionsHtml;
6313 - this.oApi._fnFeatureHtmlTable = _fnFeatureHtmlTable;
6314 - this.oApi._fnScrollDraw = _fnScrollDraw;
6315 - this.oApi._fnAjustColumnSizing = _fnAjustColumnSizing;
6316 - this.oApi._fnFeatureHtmlFilter = _fnFeatureHtmlFilter;
6317 - this.oApi._fnFilterComplete = _fnFilterComplete;
6318 - this.oApi._fnFilterCustom = _fnFilterCustom;
6319 - this.oApi._fnFilterColumn = _fnFilterColumn;
6320 - this.oApi._fnFilter = _fnFilter;
6321 - this.oApi._fnBuildSearchArray = _fnBuildSearchArray;
6322 - this.oApi._fnBuildSearchRow = _fnBuildSearchRow;
6323 - this.oApi._fnFilterCreateSearch = _fnFilterCreateSearch;
6324 - this.oApi._fnDataToSearch = _fnDataToSearch;
6325 - this.oApi._fnSort = _fnSort;
6326 - this.oApi._fnSortAttachListener = _fnSortAttachListener;
6327 - this.oApi._fnSortingClasses = _fnSortingClasses;
6328 - this.oApi._fnFeatureHtmlPaginate = _fnFeatureHtmlPaginate;
6329 - this.oApi._fnPageChange = _fnPageChange;
6330 - this.oApi._fnFeatureHtmlInfo = _fnFeatureHtmlInfo;
6331 - this.oApi._fnUpdateInfo = _fnUpdateInfo;
6332 - this.oApi._fnFeatureHtmlLength = _fnFeatureHtmlLength;
6333 - this.oApi._fnFeatureHtmlProcessing = _fnFeatureHtmlProcessing;
6334 - this.oApi._fnProcessingDisplay = _fnProcessingDisplay;
6335 - this.oApi._fnVisibleToColumnIndex = _fnVisibleToColumnIndex;
6336 - this.oApi._fnColumnIndexToVisible = _fnColumnIndexToVisible;
6337 - this.oApi._fnNodeToDataIndex = _fnNodeToDataIndex;
6338 - this.oApi._fnVisbleColumns = _fnVisbleColumns;
6339 - this.oApi._fnCalculateEnd = _fnCalculateEnd;
6340 - this.oApi._fnConvertToWidth = _fnConvertToWidth;
6341 - this.oApi._fnCalculateColumnWidths = _fnCalculateColumnWidths;
6342 - this.oApi._fnScrollingWidthAdjust = _fnScrollingWidthAdjust;
6343 - this.oApi._fnGetWidestNode = _fnGetWidestNode;
6344 - this.oApi._fnGetMaxLenString = _fnGetMaxLenString;
6345 - this.oApi._fnStringToCss = _fnStringToCss;
6346 - this.oApi._fnArrayCmp = _fnArrayCmp;
6347 - this.oApi._fnDetectType = _fnDetectType;
6348 - this.oApi._fnSettingsFromNode = _fnSettingsFromNode;
6349 - this.oApi._fnGetDataMaster = _fnGetDataMaster;
6350 - this.oApi._fnGetTrNodes = _fnGetTrNodes;
6351 - this.oApi._fnGetTdNodes = _fnGetTdNodes;
6352 - this.oApi._fnEscapeRegex = _fnEscapeRegex;
6353 - this.oApi._fnDeleteIndex = _fnDeleteIndex;
6354 - this.oApi._fnReOrderIndex = _fnReOrderIndex;
6355 - this.oApi._fnColumnOrdering = _fnColumnOrdering;
6356 - this.oApi._fnLog = _fnLog;
6357 - this.oApi._fnClearTable = _fnClearTable;
6358 - this.oApi._fnSaveState = _fnSaveState;
6359 - this.oApi._fnLoadState = _fnLoadState;
6360 - this.oApi._fnCreateCookie = _fnCreateCookie;
6361 - this.oApi._fnReadCookie = _fnReadCookie;
6362 - this.oApi._fnGetUniqueThs = _fnGetUniqueThs;
6363 - this.oApi._fnScrollBarWidth = _fnScrollBarWidth;
6364 - this.oApi._fnApplyToChildren = _fnApplyToChildren;
6365 - this.oApi._fnMap = _fnMap;
6366 -
6367 -
6368 - /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
6369 - * Section - Constructor
6370 - */
6371 -
6372 - /* Want to be able to reference "this" inside the this.each function */
6373 - var _that = this;
6374 - return this.each(function()
6375 - {
6376 - var i=0, iLen, j, jLen, k, kLen;
6377 -
6378 - /* Check to see if we are re-initalising a table */
6379 - for ( i=0, iLen=_aoSettings.length ; i<iLen ; i++ )
6380 - {
6381 - /* Base check on table node */
6382 - if ( _aoSettings[i].nTable == this )
6383 - {
6384 - if ( typeof oInit == 'undefined' ||
6385 - ( typeof oInit.bRetrieve != 'undefined' && oInit.bRetrieve === true ) )
6386 - {
6387 - return _aoSettings[i].oInstance;
6388 - }
6389 - else if ( typeof oInit.bDestroy != 'undefined' && oInit.bDestroy === true )
6390 - {
6391 - _aoSettings[i].oInstance.fnDestroy();
6392 - break;
6393 - }
6394 - else
6395 - {
6396 - _fnLog( _aoSettings[i], 0, "Cannot reinitialise DataTable.\n\n"+
6397 - "To retrieve the DataTables object for this table, please pass either no arguments "+
6398 - "to the dataTable() function, or set bRetrieve to true. Alternatively, to destory "+
6399 - "the old table and create a new one, set bDestroy to true (note that a lot of "+
6400 - "changes to the configuration can be made through the API which is usually much "+
6401 - "faster)." );
6402 - return;
6403 - }
6404 - }
6405 -
6406 - /* If the element we are initialising has the same ID as a table which was previously
6407 - * initialised, but the table nodes don't match (from before) then we destory the old
6408 - * instance by simply deleting it. This is under the assumption that the table has been
6409 - * destroyed by other methods. Anyone using non-id selectors will need to do this manually
6410 - */
6411 - if ( _aoSettings[i].sTableId !== "" && _aoSettings[i].sTableId == this.getAttribute('id') )
6412 - {
6413 - _aoSettings.splice( i, 1 );
6414 - break;
6415 - }
6416 - }
6417 -
6418 - /* Make a complete and independent copy of the settings object */
6419 - var oSettings = new classSettings();
6420 - _aoSettings.push( oSettings );
6421 -
6422 - var bInitHandedOff = false;
6423 - var bUsePassedData = false;
6424 -
6425 - /* Set the id */
6426 - var sId = this.getAttribute( 'id' );
6427 - if ( sId !== null )
6428 - {
6429 - oSettings.sTableId = sId;
6430 - oSettings.sInstance = sId;
6431 - }
6432 - else
6433 - {
6434 - oSettings.sInstance = _oExt._oExternConfig.iNextUnique ++;
6435 - }
6436 -
6437 - /* Sanity check */
6438 - if ( this.nodeName.toLowerCase() != 'table' )
6439 - {
6440 - _fnLog( oSettings, 0, "Attempted to initialise DataTables on a node which is not a "+
6441 - "table: "+this.nodeName );
6442 - return;
6443 - }
6444 -
6445 - /* Store 'this' in the settings object for later retrieval */
6446 - oSettings.oInstance = _that;
6447 -
6448 - /* Set the table node */
6449 - oSettings.nTable = this;
6450 -
6451 - /* Bind the API functions to the settings, so we can perform actions whenever oSettings is
6452 - * available
6453 - */
6454 - oSettings.oApi = _that.oApi;
6455 -
6456 - /* State the table's width for if a destroy is called at a later time */
6457 - oSettings.sDestroyWidth = $(this).width();
6458 -
6459 - /* Store the features that we have available */
6460 - if ( typeof oInit != 'undefined' && oInit !== null )
6461 - {
6462 - oSettings.oInit = oInit;
6463 - _fnMap( oSettings.oFeatures, oInit, "bPaginate" );
6464 - _fnMap( oSettings.oFeatures, oInit, "bLengthChange" );
6465 - _fnMap( oSettings.oFeatures, oInit, "bFilter" );
6466 - _fnMap( oSettings.oFeatures, oInit, "bSort" );
6467 - _fnMap( oSettings.oFeatures, oInit, "bInfo" );
6468 - _fnMap( oSettings.oFeatures, oInit, "bProcessing" );
6469 - _fnMap( oSettings.oFeatures, oInit, "bAutoWidth" );
6470 - _fnMap( oSettings.oFeatures, oInit, "bSortClasses" );
6471 - _fnMap( oSettings.oFeatures, oInit, "bServerSide" );
6472 - _fnMap( oSettings.oScroll, oInit, "sScrollX", "sX" );
6473 - _fnMap( oSettings.oScroll, oInit, "sScrollXInner", "sXInner" );
6474 - _fnMap( oSettings.oScroll, oInit, "sScrollY", "sY" );
6475 - _fnMap( oSettings.oScroll, oInit, "bScrollCollapse", "bCollapse" );
6476 - _fnMap( oSettings.oScroll, oInit, "bScrollInfinite", "bInfinite" );
6477 - _fnMap( oSettings.oScroll, oInit, "iScrollLoadGap", "iLoadGap" );
6478 - _fnMap( oSettings.oScroll, oInit, "bScrollAutoCss", "bAutoCss" );
6479 - _fnMap( oSettings, oInit, "asStripClasses" );
6480 - _fnMap( oSettings, oInit, "fnRowCallback" );
6481 - _fnMap( oSettings, oInit, "fnHeaderCallback" );
6482 - _fnMap( oSettings, oInit, "fnFooterCallback" );
6483 - _fnMap( oSettings, oInit, "fnCookieCallback" );
6484 - _fnMap( oSettings, oInit, "fnInitComplete" );
6485 - _fnMap( oSettings, oInit, "fnServerData" );
6486 - _fnMap( oSettings, oInit, "fnFormatNumber" );
6487 - _fnMap( oSettings, oInit, "aaSorting" );
6488 - _fnMap( oSettings, oInit, "aaSortingFixed" );
6489 - _fnMap( oSettings, oInit, "aLengthMenu" );
6490 - _fnMap( oSettings, oInit, "sPaginationType" );
6491 - _fnMap( oSettings, oInit, "sAjaxSource" );
6492 - _fnMap( oSettings, oInit, "iCookieDuration" );
6493 - _fnMap( oSettings, oInit, "sCookiePrefix" );
6494 - _fnMap( oSettings, oInit, "sDom" );
6495 - _fnMap( oSettings, oInit, "oSearch", "oPreviousSearch" );
6496 - _fnMap( oSettings, oInit, "aoSearchCols", "aoPreSearchCols" );
6497 - _fnMap( oSettings, oInit, "iDisplayLength", "_iDisplayLength" );
6498 - _fnMap( oSettings, oInit, "bJQueryUI", "bJUI" );
6499 - _fnMap( oSettings.oLanguage, oInit, "fnInfoCallback" );
6500 -
6501 - /* Callback functions which are array driven */
6502 - if ( typeof oInit.fnDrawCallback == 'function' )
6503 - {
6504 - oSettings.aoDrawCallback.push( {
6505 - "fn": oInit.fnDrawCallback,
6506 - "sName": "user"
6507 - } );
6508 - }
6509 -
6510 - if ( typeof oInit.fnStateSaveCallback == 'function' )
6511 - {
6512 - oSettings.aoStateSave.push( {
6513 - "fn": oInit.fnStateSaveCallback,
6514 - "sName": "user"
6515 - } );
6516 - }
6517 -
6518 - if ( typeof oInit.fnStateLoadCallback == 'function' )
6519 - {
6520 - oSettings.aoStateLoad.push( {
6521 - "fn": oInit.fnStateLoadCallback,
6522 - "sName": "user"
6523 - } );
6524 - }
6525 -
6526 - if ( oSettings.oFeatures.bServerSide && oSettings.oFeatures.bSort &&
6527 - oSettings.oFeatures.bSortClasses )
6528 - {
6529 - /* Enable sort classes for server-side processing. Safe to do it here, since server-side
6530 - * processing must be enabled by the developer
6531 - */
6532 - oSettings.aoDrawCallback.push( {
6533 - "fn": _fnSortingClasses,
6534 - "sName": "server_side_sort_classes"
6535 - } );
6536 - }
6537 -
6538 - if ( typeof oInit.bJQueryUI != 'undefined' && oInit.bJQueryUI )
6539 - {
6540 - /* Use the JUI classes object for display. You could clone the oStdClasses object if
6541 - * you want to have multiple tables with multiple independent classes
6542 - */
6543 - oSettings.oClasses = _oExt.oJUIClasses;
6544 -
6545 - if ( typeof oInit.sDom == 'undefined' )
6546 - {
6547 - /* Set the DOM to use a layout suitable for jQuery UI's theming */
6548 - oSettings.sDom = '<"H"lfr>t<"F"ip>';
6549 - }
6550 - }
6551 -
6552 - /* Calculate the scroll bar width and cache it for use later on */
6553 - if ( oSettings.oScroll.sX !== "" || oSettings.oScroll.sY !== "" )
6554 - {
6555 - oSettings.oScroll.iBarWidth = _fnScrollBarWidth();
6556 - }
6557 -
6558 - if ( typeof oInit.iDisplayStart != 'undefined' &&
6559 - typeof oSettings.iInitDisplayStart == 'undefined' )
6560 - {
6561 - /* Display start point, taking into account the save saving */
6562 - oSettings.iInitDisplayStart = oInit.iDisplayStart;
6563 - oSettings._iDisplayStart = oInit.iDisplayStart;
6564 - }
6565 -
6566 - /* Must be done after everything which can be overridden by a cookie! */
6567 - if ( typeof oInit.bStateSave != 'undefined' )
6568 - {
6569 - oSettings.oFeatures.bStateSave = oInit.bStateSave;
6570 - _fnLoadState( oSettings, oInit );
6571 - oSettings.aoDrawCallback.push( {
6572 - "fn": _fnSaveState,
6573 - "sName": "state_save"
6574 - } );
6575 - }
6576 -
6577 - if ( typeof oInit.aaData != 'undefined' )
6578 - {
6579 - bUsePassedData = true;
6580 - }
6581 -
6582 - /* Backwards compatability */
6583 - /* aoColumns / aoData - remove at some point... */
6584 - if ( typeof oInit != 'undefined' && typeof oInit.aoData != 'undefined' )
6585 - {
6586 - oInit.aoColumns = oInit.aoData;
6587 - }
6588 -
6589 - /* Language definitions */
6590 - if ( typeof oInit.oLanguage != 'undefined' )
6591 - {
6592 - if ( typeof oInit.oLanguage.sUrl != 'undefined' && oInit.oLanguage.sUrl !== "" )
6593 - {
6594 - /* Get the language definitions from a file */
6595 - oSettings.oLanguage.sUrl = oInit.oLanguage.sUrl;
6596 - $.getJSON( oSettings.oLanguage.sUrl, null, function( json ) {
6597 - _fnLanguageProcess( oSettings, json, true ); } );
6598 - bInitHandedOff = true;
6599 - }
6600 - else
6601 - {
6602 - _fnLanguageProcess( oSettings, oInit.oLanguage, false );
6603 - }
6604 - }
6605 - /* Warning: The _fnLanguageProcess function is async to the remainder of this function due
6606 - * to the XHR. We use _bInitialised in _fnLanguageProcess() to check this the processing
6607 - * below is complete. The reason for spliting it like this is optimisation - we can fire
6608 - * off the XHR (if needed) and then continue processing the data.
6609 - */
6610 - }
6611 - else
6612 - {
6613 - /* Create a dummy object for quick manipulation later on. */
6614 - oInit = {};
6615 - }
6616 -
6617 - /*
6618 - * Stripes
6619 - * Add the strip classes now that we know which classes to apply - unless overruled
6620 - */
6621 - if ( typeof oInit.asStripClasses == 'undefined' )
6622 - {
6623 - oSettings.asStripClasses.push( oSettings.oClasses.sStripOdd );
6624 - oSettings.asStripClasses.push( oSettings.oClasses.sStripEven );
6625 - }
6626 -
6627 - /* Remove row stripe classes if they are already on the table row */
6628 - var bStripeRemove = false;
6629 - var anRows = $('tbody>tr', this);
6630 - for ( i=0, iLen=oSettings.asStripClasses.length ; i<iLen ; i++ )
6631 - {
6632 - if ( anRows.filter(":lt(2)").hasClass( oSettings.asStripClasses[i]) )
6633 - {
6634 - bStripeRemove = true;
6635 - break;
6636 - }
6637 - }
6638 -
6639 - if ( bStripeRemove )
6640 - {
6641 - /* Store the classes which we are about to remove so they can be readded on destory */
6642 - oSettings.asDestoryStrips = [ '', '' ];
6643 - if ( $(anRows[0]).hasClass(oSettings.oClasses.sStripOdd) )
6644 - {
6645 - oSettings.asDestoryStrips[0] += oSettings.oClasses.sStripOdd+" ";
6646 - }
6647 - if ( $(anRows[0]).hasClass(oSettings.oClasses.sStripEven) )
6648 - {
6649 - oSettings.asDestoryStrips[0] += oSettings.oClasses.sStripEven;
6650 - }
6651 - if ( $(anRows[1]).hasClass(oSettings.oClasses.sStripOdd) )
6652 - {
6653 - oSettings.asDestoryStrips[1] += oSettings.oClasses.sStripOdd+" ";
6654 - }
6655 - if ( $(anRows[1]).hasClass(oSettings.oClasses.sStripEven) )
6656 - {
6657 - oSettings.asDestoryStrips[1] += oSettings.oClasses.sStripEven;
6658 - }
6659 -
6660 - anRows.removeClass( oSettings.asStripClasses.join(' ') );
6661 - }
6662 -
6663 - /*
6664 - * Columns
6665 - * See if we should load columns automatically or use defined ones
6666 - */
6667 - var nThead = this.getElementsByTagName('thead');
6668 - var anThs = nThead.length===0 ? [] : _fnGetUniqueThs( nThead[0] );
6669 - var aoColumnsInit;
6670 -
6671 - /* If not given a column array, generate one with nulls */
6672 - if ( typeof oInit.aoColumns == 'undefined' )
6673 - {
6674 - aoColumnsInit = [];
6675 - for ( i=0, iLen=anThs.length ; i<iLen ; i++ )
6676 - {
6677 - aoColumnsInit.push( null );
6678 - }
6679 - }
6680 - else
6681 - {
6682 - aoColumnsInit = oInit.aoColumns;
6683 - }
6684 -
6685 - /* Add the columns */
6686 - for ( i=0, iLen=aoColumnsInit.length ; i<iLen ; i++ )
6687 - {
6688 - /* Check if we have column visibilty state to restore */
6689 - if ( typeof oInit.saved_aoColumns != 'undefined' && oInit.saved_aoColumns.length == iLen )
6690 - {
6691 - if ( aoColumnsInit[i] === null )
6692 - {
6693 - aoColumnsInit[i] = {};
6694 - }
6695 - aoColumnsInit[i].bVisible = oInit.saved_aoColumns[i].bVisible;
6696 - }
6697 -
6698 - _fnAddColumn( oSettings, anThs ? anThs[i] : null );
6699 - }
6700 -
6701 - /* Add options from column definations */
6702 - if ( typeof oInit.aoColumnDefs != 'undefined' )
6703 - {
6704 - /* Loop over the column defs array - loop in reverse so first instace has priority */
6705 - for ( i=oInit.aoColumnDefs.length-1 ; i>=0 ; i-- )
6706 - {
6707 - /* Each column def can target multiple columns, as it is an array */
6708 - var aTargets = oInit.aoColumnDefs[i].aTargets;
6709 - if ( !$.isArray( aTargets ) )
6710 - {
6711 - _fnLog( oSettings, 1, 'aTargets must be an array of targets, not a '+(typeof aTargets) );
6712 - }
6713 - for ( j=0, jLen=aTargets.length ; j<jLen ; j++ )
6714 - {
6715 - if ( typeof aTargets[j] == 'number' && aTargets[j] >= 0 )
6716 - {
6717 - /* 0+ integer, left to right column counting. We add columns which are unknown
6718 - * automatically. Is this the right behaviour for this? We should at least
6719 - * log it in future. We cannot do this for the negative or class targets, only here.
6720 - */
6721 - while( oSettings.aoColumns.length <= aTargets[j] )
6722 - {
6723 - _fnAddColumn( oSettings );
6724 - }
6725 - _fnColumnOptions( oSettings, aTargets[j], oInit.aoColumnDefs[i] );
6726 - }
6727 - else if ( typeof aTargets[j] == 'number' && aTargets[j] < 0 )
6728 - {
6729 - /* Negative integer, right to left column counting */
6730 - _fnColumnOptions( oSettings, oSettings.aoColumns.length+aTargets[j],
6731 - oInit.aoColumnDefs[i] );
6732 - }
6733 - else if ( typeof aTargets[j] == 'string' )
6734 - {
6735 - /* Class name matching on TH element */
6736 - for ( k=0, kLen=oSettings.aoColumns.length ; k<kLen ; k++ )
6737 - {
6738 - if ( aTargets[j] == "_all" ||
6739 - oSettings.aoColumns[k].nTh.className.indexOf( aTargets[j] ) != -1 )
6740 - {
6741 - _fnColumnOptions( oSettings, k, oInit.aoColumnDefs[i] );
6742 - }
6743 - }
6744 - }
6745 - }
6746 - }
6747 - }
6748 -
6749 - /* Add options from column array - after the defs array so this has priority */
6750 - if ( typeof aoColumnsInit != 'undefined' )
6751 - {
6752 - for ( i=0, iLen=aoColumnsInit.length ; i<iLen ; i++ )
6753 - {
6754 - _fnColumnOptions( oSettings, i, aoColumnsInit[i] );
6755 - }
6756 - }
6757 -
6758 - /*
6759 - * Sorting
6760 - * Check the aaSorting array
6761 - */
6762 - for ( i=0, iLen=oSettings.aaSorting.length ; i<iLen ; i++ )
6763 - {
6764 - if ( oSettings.aaSorting[i][0] >= oSettings.aoColumns.length )
6765 - {
6766 - oSettings.aaSorting[i][0] = 0;
6767 - }
6768 - var oColumn = oSettings.aoColumns[ oSettings.aaSorting[i][0] ];
6769 -
6770 - /* Add a default sorting index */
6771 - if ( typeof oSettings.aaSorting[i][2] == 'undefined' )
6772 - {
6773 - oSettings.aaSorting[i][2] = 0;
6774 - }
6775 -
6776 - /* If aaSorting is not defined, then we use the first indicator in asSorting */
6777 - if ( typeof oInit.aaSorting == "undefined" &&
6778 - typeof oSettings.saved_aaSorting == "undefined" )
6779 - {
6780 - oSettings.aaSorting[i][1] = oColumn.asSorting[0];
6781 - }
6782 -
6783 - /* Set the current sorting index based on aoColumns.asSorting */
6784 - for ( j=0, jLen=oColumn.asSorting.length ; j<jLen ; j++ )
6785 - {
6786 - if ( oSettings.aaSorting[i][1] == oColumn.asSorting[j] )
6787 - {
6788 - oSettings.aaSorting[i][2] = j;
6789 - break;
6790 - }
6791 - }
6792 - }
6793 -
6794 - /* Do a first pass on the sorting classes (allows any size changes to be taken into
6795 - * account, and also will apply sorting disabled classes if disabled
6796 - */
6797 - _fnSortingClasses( oSettings );
6798 -
6799 - /*
6800 - * Final init
6801 - * Sanity check that there is a thead and tbody. If not let's just create them
6802 - */
6803 - if ( this.getElementsByTagName('thead').length === 0 )
6804 - {
6805 - this.appendChild( document.createElement( 'thead' ) );
6806 - }
6807 -
6808 - if ( this.getElementsByTagName('tbody').length === 0 )
6809 - {
6810 - this.appendChild( document.createElement( 'tbody' ) );
6811 - }
6812 -
6813 - oSettings.nTHead = this.getElementsByTagName('thead')[0];
6814 - oSettings.nTBody = this.getElementsByTagName('tbody')[0];
6815 - if ( this.getElementsByTagName('tfoot').length > 0 )
6816 - {
6817 - oSettings.nTFoot = this.getElementsByTagName('tfoot')[0];
6818 - }
6819 -
6820 - /* Check if there is data passing into the constructor */
6821 - if ( bUsePassedData )
6822 - {
6823 - for ( i=0 ; i<oInit.aaData.length ; i++ )
6824 - {
6825 - _fnAddData( oSettings, oInit.aaData[ i ] );
6826 - }
6827 - }
6828 - else
6829 - {
6830 - /* Grab the data from the page */
6831 - _fnGatherData( oSettings );
6832 - }
6833 -
6834 - /* Copy the data index array */
6835 - oSettings.aiDisplay = oSettings.aiDisplayMaster.slice();
6836 -
6837 - /* Initialisation complete - table can be drawn */
6838 - oSettings.bInitialised = true;
6839 -
6840 - /* Check if we need to initialise the table (it might not have been handed off to the
6841 - * language processor)
6842 - */
6843 - if ( bInitHandedOff === false )
6844 - {
6845 - _fnInitalise( oSettings );
6846 - }
6847 - });
6848 - };
6849 -})(jQuery, window, document);
Index: trunk/extensions/ResearchTools/modules/ext.researchTools/ext.researchTools.js
@@ -1,3 +1,6 @@
22 /*
33 * JavaScript for the ResearchTools Extension
4 - */
\ No newline at end of file
 4+ */
 5+$( document ).ready( function() {
 6+ $( '#researchTools-surveyList' ).dataTable();
 7+} );
\ No newline at end of file

Status & tagging log