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