Mercurial > repos > pieterlukasse > nist_wrapper
comparison templates/lib/jquery.dataTables.js @ 0:cce6989ed423
new NIST wrapper demo tools
author | pieter.lukasse@wur.nl |
---|---|
date | Thu, 22 Jan 2015 16:14:57 +0100 |
parents | |
children |
comparison
equal
deleted
inserted
replaced
-1:000000000000 | 0:cce6989ed423 |
---|---|
1 /*! DataTables 1.10.4 | |
2 * ©2008-2014 SpryMedia Ltd - datatables.net/license | |
3 */ | |
4 | |
5 /** | |
6 * @summary DataTables | |
7 * @description Paginate, search and order HTML tables | |
8 * @version 1.10.4 | |
9 * @file jquery.dataTables.js | |
10 * @author SpryMedia Ltd (www.sprymedia.co.uk) | |
11 * @contact www.sprymedia.co.uk/contact | |
12 * @copyright Copyright 2008-2014 SpryMedia Ltd. | |
13 * | |
14 * This source file is free software, available under the following license: | |
15 * MIT license - http://datatables.net/license | |
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 /*jslint evil: true, undef: true, browser: true */ | |
25 /*globals $,require,jQuery,define,_selector_run,_selector_opts,_selector_first,_selector_row_indexes,_ext,_Api,_api_register,_api_registerPlural,_re_new_lines,_re_html,_re_formatted_numeric,_re_escape_regex,_empty,_intVal,_numToDecimal,_isNumber,_isHtml,_htmlNumeric,_pluck,_pluck_order,_range,_stripHtml,_unique,_fnBuildAjax,_fnAjaxUpdate,_fnAjaxParameters,_fnAjaxUpdateDraw,_fnAjaxDataSrc,_fnAddColumn,_fnColumnOptions,_fnAdjustColumnSizing,_fnVisibleToColumnIndex,_fnColumnIndexToVisible,_fnVisbleColumns,_fnGetColumns,_fnColumnTypes,_fnApplyColumnDefs,_fnHungarianMap,_fnCamelToHungarian,_fnLanguageCompat,_fnBrowserDetect,_fnAddData,_fnAddTr,_fnNodeToDataIndex,_fnNodeToColumnIndex,_fnGetCellData,_fnSetCellData,_fnSplitObjNotation,_fnGetObjectDataFn,_fnSetObjectDataFn,_fnGetDataMaster,_fnClearTable,_fnDeleteIndex,_fnInvalidate,_fnGetRowElements,_fnCreateTr,_fnBuildHead,_fnDrawHead,_fnDraw,_fnReDraw,_fnAddOptionsHtml,_fnDetectHeader,_fnGetUniqueThs,_fnFeatureHtmlFilter,_fnFilterComplete,_fnFilterCustom,_fnFilterColumn,_fnFilter,_fnFilterCreateSearch,_fnEscapeRegex,_fnFilterData,_fnFeatureHtmlInfo,_fnUpdateInfo,_fnInfoMacros,_fnInitialise,_fnInitComplete,_fnLengthChange,_fnFeatureHtmlLength,_fnFeatureHtmlPaginate,_fnPageChange,_fnFeatureHtmlProcessing,_fnProcessingDisplay,_fnFeatureHtmlTable,_fnScrollDraw,_fnApplyToChildren,_fnCalculateColumnWidths,_fnThrottle,_fnConvertToWidth,_fnScrollingWidthAdjust,_fnGetWidestNode,_fnGetMaxLenString,_fnStringToCss,_fnScrollBarWidth,_fnSortFlatten,_fnSort,_fnSortAria,_fnSortListener,_fnSortAttachListener,_fnSortingClasses,_fnSortData,_fnSaveState,_fnLoadState,_fnSettingsFromNode,_fnLog,_fnMap,_fnBindAction,_fnCallbackReg,_fnCallbackFire,_fnLengthOverflow,_fnRenderer,_fnDataSource,_fnRowAttributes*/ | |
26 | |
27 (/** @lends <global> */function( window, document, undefined ) { | |
28 | |
29 (function( factory ) { | |
30 "use strict"; | |
31 | |
32 if ( typeof define === 'function' && define.amd ) { | |
33 // Define as an AMD module if possible | |
34 define( 'datatables', ['jquery'], factory ); | |
35 } | |
36 else if ( typeof exports === 'object' ) { | |
37 // Node/CommonJS | |
38 factory( require( 'jquery' ) ); | |
39 } | |
40 else if ( jQuery && !jQuery.fn.dataTable ) { | |
41 // Define using browser globals otherwise | |
42 // Prevent multiple instantiations if the script is loaded twice | |
43 factory( jQuery ); | |
44 } | |
45 } | |
46 (/** @lends <global> */function( $ ) { | |
47 "use strict"; | |
48 | |
49 /** | |
50 * DataTables is a plug-in for the jQuery Javascript library. It is a highly | |
51 * flexible tool, based upon the foundations of progressive enhancement, | |
52 * which will add advanced interaction controls to any HTML table. For a | |
53 * full list of features please refer to | |
54 * [DataTables.net](href="http://datatables.net). | |
55 * | |
56 * Note that the `DataTable` object is not a global variable but is aliased | |
57 * to `jQuery.fn.DataTable` and `jQuery.fn.dataTable` through which it may | |
58 * be accessed. | |
59 * | |
60 * @class | |
61 * @param {object} [init={}] Configuration object for DataTables. Options | |
62 * are defined by {@link DataTable.defaults} | |
63 * @requires jQuery 1.7+ | |
64 * | |
65 * @example | |
66 * // Basic initialisation | |
67 * $(document).ready( function { | |
68 * $('#example').dataTable(); | |
69 * } ); | |
70 * | |
71 * @example | |
72 * // Initialisation with configuration options - in this case, disable | |
73 * // pagination and sorting. | |
74 * $(document).ready( function { | |
75 * $('#example').dataTable( { | |
76 * "paginate": false, | |
77 * "sort": false | |
78 * } ); | |
79 * } ); | |
80 */ | |
81 var DataTable; | |
82 | |
83 | |
84 /* | |
85 * It is useful to have variables which are scoped locally so only the | |
86 * DataTables functions can access them and they don't leak into global space. | |
87 * At the same time these functions are often useful over multiple files in the | |
88 * core and API, so we list, or at least document, all variables which are used | |
89 * by DataTables as private variables here. This also ensures that there is no | |
90 * clashing of variable names and that they can easily referenced for reuse. | |
91 */ | |
92 | |
93 | |
94 // Defined else where | |
95 // _selector_run | |
96 // _selector_opts | |
97 // _selector_first | |
98 // _selector_row_indexes | |
99 | |
100 var _ext; // DataTable.ext | |
101 var _Api; // DataTable.Api | |
102 var _api_register; // DataTable.Api.register | |
103 var _api_registerPlural; // DataTable.Api.registerPlural | |
104 | |
105 var _re_dic = {}; | |
106 var _re_new_lines = /[\r\n]/g; | |
107 var _re_html = /<.*?>/g; | |
108 var _re_date_start = /^[\w\+\-]/; | |
109 var _re_date_end = /[\w\+\-]$/; | |
110 | |
111 // Escape regular expression special characters | |
112 var _re_escape_regex = new RegExp( '(\\' + [ '/', '.', '*', '+', '?', '|', '(', ')', '[', ']', '{', '}', '\\', '$', '^', '-' ].join('|\\') + ')', 'g' ); | |
113 | |
114 // U+2009 is thin space and U+202F is narrow no-break space, both used in many | |
115 // standards as thousands separators | |
116 var _re_formatted_numeric = /[',$£€¥%\u2009\u202F]/g; | |
117 | |
118 | |
119 var _empty = function ( d ) { | |
120 return !d || d === true || d === '-' ? true : false; | |
121 }; | |
122 | |
123 | |
124 var _intVal = function ( s ) { | |
125 var integer = parseInt( s, 10 ); | |
126 return !isNaN(integer) && isFinite(s) ? integer : null; | |
127 }; | |
128 | |
129 // Convert from a formatted number with characters other than `.` as the | |
130 // decimal place, to a Javascript number | |
131 var _numToDecimal = function ( num, decimalPoint ) { | |
132 // Cache created regular expressions for speed as this function is called often | |
133 if ( ! _re_dic[ decimalPoint ] ) { | |
134 _re_dic[ decimalPoint ] = new RegExp( _fnEscapeRegex( decimalPoint ), 'g' ); | |
135 } | |
136 return typeof num === 'string' && decimalPoint !== '.' ? | |
137 num.replace( /\./g, '' ).replace( _re_dic[ decimalPoint ], '.' ) : | |
138 num; | |
139 }; | |
140 | |
141 | |
142 var _isNumber = function ( d, decimalPoint, formatted ) { | |
143 var strType = typeof d === 'string'; | |
144 | |
145 if ( decimalPoint && strType ) { | |
146 d = _numToDecimal( d, decimalPoint ); | |
147 } | |
148 | |
149 if ( formatted && strType ) { | |
150 d = d.replace( _re_formatted_numeric, '' ); | |
151 } | |
152 | |
153 return _empty( d ) || (!isNaN( parseFloat(d) ) && isFinite( d )); | |
154 }; | |
155 | |
156 | |
157 // A string without HTML in it can be considered to be HTML still | |
158 var _isHtml = function ( d ) { | |
159 return _empty( d ) || typeof d === 'string'; | |
160 }; | |
161 | |
162 | |
163 var _htmlNumeric = function ( d, decimalPoint, formatted ) { | |
164 if ( _empty( d ) ) { | |
165 return true; | |
166 } | |
167 | |
168 var html = _isHtml( d ); | |
169 return ! html ? | |
170 null : | |
171 _isNumber( _stripHtml( d ), decimalPoint, formatted ) ? | |
172 true : | |
173 null; | |
174 }; | |
175 | |
176 | |
177 var _pluck = function ( a, prop, prop2 ) { | |
178 var out = []; | |
179 var i=0, ien=a.length; | |
180 | |
181 // Could have the test in the loop for slightly smaller code, but speed | |
182 // is essential here | |
183 if ( prop2 !== undefined ) { | |
184 for ( ; i<ien ; i++ ) { | |
185 if ( a[i] && a[i][ prop ] ) { | |
186 out.push( a[i][ prop ][ prop2 ] ); | |
187 } | |
188 } | |
189 } | |
190 else { | |
191 for ( ; i<ien ; i++ ) { | |
192 if ( a[i] ) { | |
193 out.push( a[i][ prop ] ); | |
194 } | |
195 } | |
196 } | |
197 | |
198 return out; | |
199 }; | |
200 | |
201 | |
202 // Basically the same as _pluck, but rather than looping over `a` we use `order` | |
203 // as the indexes to pick from `a` | |
204 var _pluck_order = function ( a, order, prop, prop2 ) | |
205 { | |
206 var out = []; | |
207 var i=0, ien=order.length; | |
208 | |
209 // Could have the test in the loop for slightly smaller code, but speed | |
210 // is essential here | |
211 if ( prop2 !== undefined ) { | |
212 for ( ; i<ien ; i++ ) { | |
213 if ( a[ order[i] ][ prop ] ) { | |
214 out.push( a[ order[i] ][ prop ][ prop2 ] ); | |
215 } | |
216 } | |
217 } | |
218 else { | |
219 for ( ; i<ien ; i++ ) { | |
220 out.push( a[ order[i] ][ prop ] ); | |
221 } | |
222 } | |
223 | |
224 return out; | |
225 }; | |
226 | |
227 | |
228 var _range = function ( len, start ) | |
229 { | |
230 var out = []; | |
231 var end; | |
232 | |
233 if ( start === undefined ) { | |
234 start = 0; | |
235 end = len; | |
236 } | |
237 else { | |
238 end = start; | |
239 start = len; | |
240 } | |
241 | |
242 for ( var i=start ; i<end ; i++ ) { | |
243 out.push( i ); | |
244 } | |
245 | |
246 return out; | |
247 }; | |
248 | |
249 | |
250 var _removeEmpty = function ( a ) | |
251 { | |
252 var out = []; | |
253 | |
254 for ( var i=0, ien=a.length ; i<ien ; i++ ) { | |
255 if ( a[i] ) { // careful - will remove all falsy values! | |
256 out.push( a[i] ); | |
257 } | |
258 } | |
259 | |
260 return out; | |
261 }; | |
262 | |
263 | |
264 var _stripHtml = function ( d ) { | |
265 return d.replace( _re_html, '' ); | |
266 }; | |
267 | |
268 | |
269 /** | |
270 * Find the unique elements in a source array. | |
271 * | |
272 * @param {array} src Source array | |
273 * @return {array} Array of unique items | |
274 * @ignore | |
275 */ | |
276 var _unique = function ( src ) | |
277 { | |
278 // A faster unique method is to use object keys to identify used values, | |
279 // but this doesn't work with arrays or objects, which we must also | |
280 // consider. See jsperf.com/compare-array-unique-versions/4 for more | |
281 // information. | |
282 var | |
283 out = [], | |
284 val, | |
285 i, ien=src.length, | |
286 j, k=0; | |
287 | |
288 again: for ( i=0 ; i<ien ; i++ ) { | |
289 val = src[i]; | |
290 | |
291 for ( j=0 ; j<k ; j++ ) { | |
292 if ( out[j] === val ) { | |
293 continue again; | |
294 } | |
295 } | |
296 | |
297 out.push( val ); | |
298 k++; | |
299 } | |
300 | |
301 return out; | |
302 }; | |
303 | |
304 | |
305 | |
306 /** | |
307 * Create a mapping object that allows camel case parameters to be looked up | |
308 * for their Hungarian counterparts. The mapping is stored in a private | |
309 * parameter called `_hungarianMap` which can be accessed on the source object. | |
310 * @param {object} o | |
311 * @memberof DataTable#oApi | |
312 */ | |
313 function _fnHungarianMap ( o ) | |
314 { | |
315 var | |
316 hungarian = 'a aa ai ao as b fn i m o s ', | |
317 match, | |
318 newKey, | |
319 map = {}; | |
320 | |
321 $.each( o, function (key, val) { | |
322 match = key.match(/^([^A-Z]+?)([A-Z])/); | |
323 | |
324 if ( match && hungarian.indexOf(match[1]+' ') !== -1 ) | |
325 { | |
326 newKey = key.replace( match[0], match[2].toLowerCase() ); | |
327 map[ newKey ] = key; | |
328 | |
329 if ( match[1] === 'o' ) | |
330 { | |
331 _fnHungarianMap( o[key] ); | |
332 } | |
333 } | |
334 } ); | |
335 | |
336 o._hungarianMap = map; | |
337 } | |
338 | |
339 | |
340 /** | |
341 * Convert from camel case parameters to Hungarian, based on a Hungarian map | |
342 * created by _fnHungarianMap. | |
343 * @param {object} src The model object which holds all parameters that can be | |
344 * mapped. | |
345 * @param {object} user The object to convert from camel case to Hungarian. | |
346 * @param {boolean} force When set to `true`, properties which already have a | |
347 * Hungarian value in the `user` object will be overwritten. Otherwise they | |
348 * won't be. | |
349 * @memberof DataTable#oApi | |
350 */ | |
351 function _fnCamelToHungarian ( src, user, force ) | |
352 { | |
353 if ( ! src._hungarianMap ) { | |
354 _fnHungarianMap( src ); | |
355 } | |
356 | |
357 var hungarianKey; | |
358 | |
359 $.each( user, function (key, val) { | |
360 hungarianKey = src._hungarianMap[ key ]; | |
361 | |
362 if ( hungarianKey !== undefined && (force || user[hungarianKey] === undefined) ) | |
363 { | |
364 // For objects, we need to buzz down into the object to copy parameters | |
365 if ( hungarianKey.charAt(0) === 'o' ) | |
366 { | |
367 // Copy the camelCase options over to the hungarian | |
368 if ( ! user[ hungarianKey ] ) { | |
369 user[ hungarianKey ] = {}; | |
370 } | |
371 $.extend( true, user[hungarianKey], user[key] ); | |
372 | |
373 _fnCamelToHungarian( src[hungarianKey], user[hungarianKey], force ); | |
374 } | |
375 else { | |
376 user[hungarianKey] = user[ key ]; | |
377 } | |
378 } | |
379 } ); | |
380 } | |
381 | |
382 | |
383 /** | |
384 * Language compatibility - when certain options are given, and others aren't, we | |
385 * need to duplicate the values over, in order to provide backwards compatibility | |
386 * with older language files. | |
387 * @param {object} oSettings dataTables settings object | |
388 * @memberof DataTable#oApi | |
389 */ | |
390 function _fnLanguageCompat( lang ) | |
391 { | |
392 var defaults = DataTable.defaults.oLanguage; | |
393 var zeroRecords = lang.sZeroRecords; | |
394 | |
395 /* Backwards compatibility - if there is no sEmptyTable given, then use the same as | |
396 * sZeroRecords - assuming that is given. | |
397 */ | |
398 if ( ! lang.sEmptyTable && zeroRecords && | |
399 defaults.sEmptyTable === "No data available in table" ) | |
400 { | |
401 _fnMap( lang, lang, 'sZeroRecords', 'sEmptyTable' ); | |
402 } | |
403 | |
404 /* Likewise with loading records */ | |
405 if ( ! lang.sLoadingRecords && zeroRecords && | |
406 defaults.sLoadingRecords === "Loading..." ) | |
407 { | |
408 _fnMap( lang, lang, 'sZeroRecords', 'sLoadingRecords' ); | |
409 } | |
410 | |
411 // Old parameter name of the thousands separator mapped onto the new | |
412 if ( lang.sInfoThousands ) { | |
413 lang.sThousands = lang.sInfoThousands; | |
414 } | |
415 | |
416 var decimal = lang.sDecimal; | |
417 if ( decimal ) { | |
418 _addNumericSort( decimal ); | |
419 } | |
420 } | |
421 | |
422 | |
423 /** | |
424 * Map one parameter onto another | |
425 * @param {object} o Object to map | |
426 * @param {*} knew The new parameter name | |
427 * @param {*} old The old parameter name | |
428 */ | |
429 var _fnCompatMap = function ( o, knew, old ) { | |
430 if ( o[ knew ] !== undefined ) { | |
431 o[ old ] = o[ knew ]; | |
432 } | |
433 }; | |
434 | |
435 | |
436 /** | |
437 * Provide backwards compatibility for the main DT options. Note that the new | |
438 * options are mapped onto the old parameters, so this is an external interface | |
439 * change only. | |
440 * @param {object} init Object to map | |
441 */ | |
442 function _fnCompatOpts ( init ) | |
443 { | |
444 _fnCompatMap( init, 'ordering', 'bSort' ); | |
445 _fnCompatMap( init, 'orderMulti', 'bSortMulti' ); | |
446 _fnCompatMap( init, 'orderClasses', 'bSortClasses' ); | |
447 _fnCompatMap( init, 'orderCellsTop', 'bSortCellsTop' ); | |
448 _fnCompatMap( init, 'order', 'aaSorting' ); | |
449 _fnCompatMap( init, 'orderFixed', 'aaSortingFixed' ); | |
450 _fnCompatMap( init, 'paging', 'bPaginate' ); | |
451 _fnCompatMap( init, 'pagingType', 'sPaginationType' ); | |
452 _fnCompatMap( init, 'pageLength', 'iDisplayLength' ); | |
453 _fnCompatMap( init, 'searching', 'bFilter' ); | |
454 | |
455 // Column search objects are in an array, so it needs to be converted | |
456 // element by element | |
457 var searchCols = init.aoSearchCols; | |
458 | |
459 if ( searchCols ) { | |
460 for ( var i=0, ien=searchCols.length ; i<ien ; i++ ) { | |
461 if ( searchCols[i] ) { | |
462 _fnCamelToHungarian( DataTable.models.oSearch, searchCols[i] ); | |
463 } | |
464 } | |
465 } | |
466 } | |
467 | |
468 | |
469 /** | |
470 * Provide backwards compatibility for column options. Note that the new options | |
471 * are mapped onto the old parameters, so this is an external interface change | |
472 * only. | |
473 * @param {object} init Object to map | |
474 */ | |
475 function _fnCompatCols ( init ) | |
476 { | |
477 _fnCompatMap( init, 'orderable', 'bSortable' ); | |
478 _fnCompatMap( init, 'orderData', 'aDataSort' ); | |
479 _fnCompatMap( init, 'orderSequence', 'asSorting' ); | |
480 _fnCompatMap( init, 'orderDataType', 'sortDataType' ); | |
481 } | |
482 | |
483 | |
484 /** | |
485 * Browser feature detection for capabilities, quirks | |
486 * @param {object} settings dataTables settings object | |
487 * @memberof DataTable#oApi | |
488 */ | |
489 function _fnBrowserDetect( settings ) | |
490 { | |
491 var browser = settings.oBrowser; | |
492 | |
493 // Scrolling feature / quirks detection | |
494 var n = $('<div/>') | |
495 .css( { | |
496 position: 'absolute', | |
497 top: 0, | |
498 left: 0, | |
499 height: 1, | |
500 width: 1, | |
501 overflow: 'hidden' | |
502 } ) | |
503 .append( | |
504 $('<div/>') | |
505 .css( { | |
506 position: 'absolute', | |
507 top: 1, | |
508 left: 1, | |
509 width: 100, | |
510 overflow: 'scroll' | |
511 } ) | |
512 .append( | |
513 $('<div class="test"/>') | |
514 .css( { | |
515 width: '100%', | |
516 height: 10 | |
517 } ) | |
518 ) | |
519 ) | |
520 .appendTo( 'body' ); | |
521 | |
522 var test = n.find('.test'); | |
523 | |
524 // IE6/7 will oversize a width 100% element inside a scrolling element, to | |
525 // include the width of the scrollbar, while other browsers ensure the inner | |
526 // element is contained without forcing scrolling | |
527 browser.bScrollOversize = test[0].offsetWidth === 100; | |
528 | |
529 // In rtl text layout, some browsers (most, but not all) will place the | |
530 // scrollbar on the left, rather than the right. | |
531 browser.bScrollbarLeft = test.offset().left !== 1; | |
532 | |
533 n.remove(); | |
534 } | |
535 | |
536 | |
537 /** | |
538 * Array.prototype reduce[Right] method, used for browsers which don't support | |
539 * JS 1.6. Done this way to reduce code size, since we iterate either way | |
540 * @param {object} settings dataTables settings object | |
541 * @memberof DataTable#oApi | |
542 */ | |
543 function _fnReduce ( that, fn, init, start, end, inc ) | |
544 { | |
545 var | |
546 i = start, | |
547 value, | |
548 isSet = false; | |
549 | |
550 if ( init !== undefined ) { | |
551 value = init; | |
552 isSet = true; | |
553 } | |
554 | |
555 while ( i !== end ) { | |
556 if ( ! that.hasOwnProperty(i) ) { | |
557 continue; | |
558 } | |
559 | |
560 value = isSet ? | |
561 fn( value, that[i], i, that ) : | |
562 that[i]; | |
563 | |
564 isSet = true; | |
565 i += inc; | |
566 } | |
567 | |
568 return value; | |
569 } | |
570 | |
571 /** | |
572 * Add a column to the list used for the table with default values | |
573 * @param {object} oSettings dataTables settings object | |
574 * @param {node} nTh The th element for this column | |
575 * @memberof DataTable#oApi | |
576 */ | |
577 function _fnAddColumn( oSettings, nTh ) | |
578 { | |
579 // Add column to aoColumns array | |
580 var oDefaults = DataTable.defaults.column; | |
581 var iCol = oSettings.aoColumns.length; | |
582 var oCol = $.extend( {}, DataTable.models.oColumn, oDefaults, { | |
583 "nTh": nTh ? nTh : document.createElement('th'), | |
584 "sTitle": oDefaults.sTitle ? oDefaults.sTitle : nTh ? nTh.innerHTML : '', | |
585 "aDataSort": oDefaults.aDataSort ? oDefaults.aDataSort : [iCol], | |
586 "mData": oDefaults.mData ? oDefaults.mData : iCol, | |
587 idx: iCol | |
588 } ); | |
589 oSettings.aoColumns.push( oCol ); | |
590 | |
591 // Add search object for column specific search. Note that the `searchCols[ iCol ]` | |
592 // passed into extend can be undefined. This allows the user to give a default | |
593 // with only some of the parameters defined, and also not give a default | |
594 var searchCols = oSettings.aoPreSearchCols; | |
595 searchCols[ iCol ] = $.extend( {}, DataTable.models.oSearch, searchCols[ iCol ] ); | |
596 | |
597 // Use the default column options function to initialise classes etc | |
598 _fnColumnOptions( oSettings, iCol, null ); | |
599 } | |
600 | |
601 | |
602 /** | |
603 * Apply options for a column | |
604 * @param {object} oSettings dataTables settings object | |
605 * @param {int} iCol column index to consider | |
606 * @param {object} oOptions object with sType, bVisible and bSearchable etc | |
607 * @memberof DataTable#oApi | |
608 */ | |
609 function _fnColumnOptions( oSettings, iCol, oOptions ) | |
610 { | |
611 var oCol = oSettings.aoColumns[ iCol ]; | |
612 var oClasses = oSettings.oClasses; | |
613 var th = $(oCol.nTh); | |
614 | |
615 // Try to get width information from the DOM. We can't get it from CSS | |
616 // as we'd need to parse the CSS stylesheet. `width` option can override | |
617 if ( ! oCol.sWidthOrig ) { | |
618 // Width attribute | |
619 oCol.sWidthOrig = th.attr('width') || null; | |
620 | |
621 // Style attribute | |
622 var t = (th.attr('style') || '').match(/width:\s*(\d+[pxem%]+)/); | |
623 if ( t ) { | |
624 oCol.sWidthOrig = t[1]; | |
625 } | |
626 } | |
627 | |
628 /* User specified column options */ | |
629 if ( oOptions !== undefined && oOptions !== null ) | |
630 { | |
631 // Backwards compatibility | |
632 _fnCompatCols( oOptions ); | |
633 | |
634 // Map camel case parameters to their Hungarian counterparts | |
635 _fnCamelToHungarian( DataTable.defaults.column, oOptions ); | |
636 | |
637 /* Backwards compatibility for mDataProp */ | |
638 if ( oOptions.mDataProp !== undefined && !oOptions.mData ) | |
639 { | |
640 oOptions.mData = oOptions.mDataProp; | |
641 } | |
642 | |
643 if ( oOptions.sType ) | |
644 { | |
645 oCol._sManualType = oOptions.sType; | |
646 } | |
647 | |
648 // `class` is a reserved word in Javascript, so we need to provide | |
649 // the ability to use a valid name for the camel case input | |
650 if ( oOptions.className && ! oOptions.sClass ) | |
651 { | |
652 oOptions.sClass = oOptions.className; | |
653 } | |
654 | |
655 $.extend( oCol, oOptions ); | |
656 _fnMap( oCol, oOptions, "sWidth", "sWidthOrig" ); | |
657 | |
658 /* iDataSort to be applied (backwards compatibility), but aDataSort will take | |
659 * priority if defined | |
660 */ | |
661 if ( typeof oOptions.iDataSort === 'number' ) | |
662 { | |
663 oCol.aDataSort = [ oOptions.iDataSort ]; | |
664 } | |
665 _fnMap( oCol, oOptions, "aDataSort" ); | |
666 } | |
667 | |
668 /* Cache the data get and set functions for speed */ | |
669 var mDataSrc = oCol.mData; | |
670 var mData = _fnGetObjectDataFn( mDataSrc ); | |
671 var mRender = oCol.mRender ? _fnGetObjectDataFn( oCol.mRender ) : null; | |
672 | |
673 var attrTest = function( src ) { | |
674 return typeof src === 'string' && src.indexOf('@') !== -1; | |
675 }; | |
676 oCol._bAttrSrc = $.isPlainObject( mDataSrc ) && ( | |
677 attrTest(mDataSrc.sort) || attrTest(mDataSrc.type) || attrTest(mDataSrc.filter) | |
678 ); | |
679 | |
680 oCol.fnGetData = function (rowData, type, meta) { | |
681 var innerData = mData( rowData, type, undefined, meta ); | |
682 | |
683 return mRender && type ? | |
684 mRender( innerData, type, rowData, meta ) : | |
685 innerData; | |
686 }; | |
687 oCol.fnSetData = function ( rowData, val, meta ) { | |
688 return _fnSetObjectDataFn( mDataSrc )( rowData, val, meta ); | |
689 }; | |
690 | |
691 // Indicate if DataTables should read DOM data as an object or array | |
692 // Used in _fnGetRowElements | |
693 if ( typeof mDataSrc !== 'number' ) { | |
694 oSettings._rowReadObject = true; | |
695 } | |
696 | |
697 /* Feature sorting overrides column specific when off */ | |
698 if ( !oSettings.oFeatures.bSort ) | |
699 { | |
700 oCol.bSortable = false; | |
701 th.addClass( oClasses.sSortableNone ); // Have to add class here as order event isn't called | |
702 } | |
703 | |
704 /* Check that the class assignment is correct for sorting */ | |
705 var bAsc = $.inArray('asc', oCol.asSorting) !== -1; | |
706 var bDesc = $.inArray('desc', oCol.asSorting) !== -1; | |
707 if ( !oCol.bSortable || (!bAsc && !bDesc) ) | |
708 { | |
709 oCol.sSortingClass = oClasses.sSortableNone; | |
710 oCol.sSortingClassJUI = ""; | |
711 } | |
712 else if ( bAsc && !bDesc ) | |
713 { | |
714 oCol.sSortingClass = oClasses.sSortableAsc; | |
715 oCol.sSortingClassJUI = oClasses.sSortJUIAscAllowed; | |
716 } | |
717 else if ( !bAsc && bDesc ) | |
718 { | |
719 oCol.sSortingClass = oClasses.sSortableDesc; | |
720 oCol.sSortingClassJUI = oClasses.sSortJUIDescAllowed; | |
721 } | |
722 else | |
723 { | |
724 oCol.sSortingClass = oClasses.sSortable; | |
725 oCol.sSortingClassJUI = oClasses.sSortJUI; | |
726 } | |
727 } | |
728 | |
729 | |
730 /** | |
731 * Adjust the table column widths for new data. Note: you would probably want to | |
732 * do a redraw after calling this function! | |
733 * @param {object} settings dataTables settings object | |
734 * @memberof DataTable#oApi | |
735 */ | |
736 function _fnAdjustColumnSizing ( settings ) | |
737 { | |
738 /* Not interested in doing column width calculation if auto-width is disabled */ | |
739 if ( settings.oFeatures.bAutoWidth !== false ) | |
740 { | |
741 var columns = settings.aoColumns; | |
742 | |
743 _fnCalculateColumnWidths( settings ); | |
744 for ( var i=0 , iLen=columns.length ; i<iLen ; i++ ) | |
745 { | |
746 columns[i].nTh.style.width = columns[i].sWidth; | |
747 } | |
748 } | |
749 | |
750 var scroll = settings.oScroll; | |
751 if ( scroll.sY !== '' || scroll.sX !== '') | |
752 { | |
753 _fnScrollDraw( settings ); | |
754 } | |
755 | |
756 _fnCallbackFire( settings, null, 'column-sizing', [settings] ); | |
757 } | |
758 | |
759 | |
760 /** | |
761 * Covert the index of a visible column to the index in the data array (take account | |
762 * of hidden columns) | |
763 * @param {object} oSettings dataTables settings object | |
764 * @param {int} iMatch Visible column index to lookup | |
765 * @returns {int} i the data index | |
766 * @memberof DataTable#oApi | |
767 */ | |
768 function _fnVisibleToColumnIndex( oSettings, iMatch ) | |
769 { | |
770 var aiVis = _fnGetColumns( oSettings, 'bVisible' ); | |
771 | |
772 return typeof aiVis[iMatch] === 'number' ? | |
773 aiVis[iMatch] : | |
774 null; | |
775 } | |
776 | |
777 | |
778 /** | |
779 * Covert the index of an index in the data array and convert it to the visible | |
780 * column index (take account of hidden columns) | |
781 * @param {int} iMatch Column index to lookup | |
782 * @param {object} oSettings dataTables settings object | |
783 * @returns {int} i the data index | |
784 * @memberof DataTable#oApi | |
785 */ | |
786 function _fnColumnIndexToVisible( oSettings, iMatch ) | |
787 { | |
788 var aiVis = _fnGetColumns( oSettings, 'bVisible' ); | |
789 var iPos = $.inArray( iMatch, aiVis ); | |
790 | |
791 return iPos !== -1 ? iPos : null; | |
792 } | |
793 | |
794 | |
795 /** | |
796 * Get the number of visible columns | |
797 * @param {object} oSettings dataTables settings object | |
798 * @returns {int} i the number of visible columns | |
799 * @memberof DataTable#oApi | |
800 */ | |
801 function _fnVisbleColumns( oSettings ) | |
802 { | |
803 return _fnGetColumns( oSettings, 'bVisible' ).length; | |
804 } | |
805 | |
806 | |
807 /** | |
808 * Get an array of column indexes that match a given property | |
809 * @param {object} oSettings dataTables settings object | |
810 * @param {string} sParam Parameter in aoColumns to look for - typically | |
811 * bVisible or bSearchable | |
812 * @returns {array} Array of indexes with matched properties | |
813 * @memberof DataTable#oApi | |
814 */ | |
815 function _fnGetColumns( oSettings, sParam ) | |
816 { | |
817 var a = []; | |
818 | |
819 $.map( oSettings.aoColumns, function(val, i) { | |
820 if ( val[sParam] ) { | |
821 a.push( i ); | |
822 } | |
823 } ); | |
824 | |
825 return a; | |
826 } | |
827 | |
828 | |
829 /** | |
830 * Calculate the 'type' of a column | |
831 * @param {object} settings dataTables settings object | |
832 * @memberof DataTable#oApi | |
833 */ | |
834 function _fnColumnTypes ( settings ) | |
835 { | |
836 var columns = settings.aoColumns; | |
837 var data = settings.aoData; | |
838 var types = DataTable.ext.type.detect; | |
839 var i, ien, j, jen, k, ken; | |
840 var col, cell, detectedType, cache; | |
841 | |
842 // For each column, spin over the | |
843 for ( i=0, ien=columns.length ; i<ien ; i++ ) { | |
844 col = columns[i]; | |
845 cache = []; | |
846 | |
847 if ( ! col.sType && col._sManualType ) { | |
848 col.sType = col._sManualType; | |
849 } | |
850 else if ( ! col.sType ) { | |
851 for ( j=0, jen=types.length ; j<jen ; j++ ) { | |
852 for ( k=0, ken=data.length ; k<ken ; k++ ) { | |
853 // Use a cache array so we only need to get the type data | |
854 // from the formatter once (when using multiple detectors) | |
855 if ( cache[k] === undefined ) { | |
856 cache[k] = _fnGetCellData( settings, k, i, 'type' ); | |
857 } | |
858 | |
859 detectedType = types[j]( cache[k], settings ); | |
860 | |
861 // If null, then this type can't apply to this column, so | |
862 // rather than testing all cells, break out. There is an | |
863 // exception for the last type which is `html`. We need to | |
864 // scan all rows since it is possible to mix string and HTML | |
865 // types | |
866 if ( ! detectedType && j !== types.length-1 ) { | |
867 break; | |
868 } | |
869 | |
870 // Only a single match is needed for html type since it is | |
871 // bottom of the pile and very similar to string | |
872 if ( detectedType === 'html' ) { | |
873 break; | |
874 } | |
875 } | |
876 | |
877 // Type is valid for all data points in the column - use this | |
878 // type | |
879 if ( detectedType ) { | |
880 col.sType = detectedType; | |
881 break; | |
882 } | |
883 } | |
884 | |
885 // Fall back - if no type was detected, always use string | |
886 if ( ! col.sType ) { | |
887 col.sType = 'string'; | |
888 } | |
889 } | |
890 } | |
891 } | |
892 | |
893 | |
894 /** | |
895 * Take the column definitions and static columns arrays and calculate how | |
896 * they relate to column indexes. The callback function will then apply the | |
897 * definition found for a column to a suitable configuration object. | |
898 * @param {object} oSettings dataTables settings object | |
899 * @param {array} aoColDefs The aoColumnDefs array that is to be applied | |
900 * @param {array} aoCols The aoColumns array that defines columns individually | |
901 * @param {function} fn Callback function - takes two parameters, the calculated | |
902 * column index and the definition for that column. | |
903 * @memberof DataTable#oApi | |
904 */ | |
905 function _fnApplyColumnDefs( oSettings, aoColDefs, aoCols, fn ) | |
906 { | |
907 var i, iLen, j, jLen, k, kLen, def; | |
908 var columns = oSettings.aoColumns; | |
909 | |
910 // Column definitions with aTargets | |
911 if ( aoColDefs ) | |
912 { | |
913 /* Loop over the definitions array - loop in reverse so first instance has priority */ | |
914 for ( i=aoColDefs.length-1 ; i>=0 ; i-- ) | |
915 { | |
916 def = aoColDefs[i]; | |
917 | |
918 /* Each definition can target multiple columns, as it is an array */ | |
919 var aTargets = def.targets !== undefined ? | |
920 def.targets : | |
921 def.aTargets; | |
922 | |
923 if ( ! $.isArray( aTargets ) ) | |
924 { | |
925 aTargets = [ aTargets ]; | |
926 } | |
927 | |
928 for ( j=0, jLen=aTargets.length ; j<jLen ; j++ ) | |
929 { | |
930 if ( typeof aTargets[j] === 'number' && aTargets[j] >= 0 ) | |
931 { | |
932 /* Add columns that we don't yet know about */ | |
933 while( columns.length <= aTargets[j] ) | |
934 { | |
935 _fnAddColumn( oSettings ); | |
936 } | |
937 | |
938 /* Integer, basic index */ | |
939 fn( aTargets[j], def ); | |
940 } | |
941 else if ( typeof aTargets[j] === 'number' && aTargets[j] < 0 ) | |
942 { | |
943 /* Negative integer, right to left column counting */ | |
944 fn( columns.length+aTargets[j], def ); | |
945 } | |
946 else if ( typeof aTargets[j] === 'string' ) | |
947 { | |
948 /* Class name matching on TH element */ | |
949 for ( k=0, kLen=columns.length ; k<kLen ; k++ ) | |
950 { | |
951 if ( aTargets[j] == "_all" || | |
952 $(columns[k].nTh).hasClass( aTargets[j] ) ) | |
953 { | |
954 fn( k, def ); | |
955 } | |
956 } | |
957 } | |
958 } | |
959 } | |
960 } | |
961 | |
962 // Statically defined columns array | |
963 if ( aoCols ) | |
964 { | |
965 for ( i=0, iLen=aoCols.length ; i<iLen ; i++ ) | |
966 { | |
967 fn( i, aoCols[i] ); | |
968 } | |
969 } | |
970 } | |
971 | |
972 /** | |
973 * Add a data array to the table, creating DOM node etc. This is the parallel to | |
974 * _fnGatherData, but for adding rows from a Javascript source, rather than a | |
975 * DOM source. | |
976 * @param {object} oSettings dataTables settings object | |
977 * @param {array} aData data array to be added | |
978 * @param {node} [nTr] TR element to add to the table - optional. If not given, | |
979 * DataTables will create a row automatically | |
980 * @param {array} [anTds] Array of TD|TH elements for the row - must be given | |
981 * if nTr is. | |
982 * @returns {int} >=0 if successful (index of new aoData entry), -1 if failed | |
983 * @memberof DataTable#oApi | |
984 */ | |
985 function _fnAddData ( oSettings, aDataIn, nTr, anTds ) | |
986 { | |
987 /* Create the object for storing information about this new row */ | |
988 var iRow = oSettings.aoData.length; | |
989 var oData = $.extend( true, {}, DataTable.models.oRow, { | |
990 src: nTr ? 'dom' : 'data' | |
991 } ); | |
992 | |
993 oData._aData = aDataIn; | |
994 oSettings.aoData.push( oData ); | |
995 | |
996 /* Create the cells */ | |
997 var nTd, sThisType; | |
998 var columns = oSettings.aoColumns; | |
999 for ( var i=0, iLen=columns.length ; i<iLen ; i++ ) | |
1000 { | |
1001 // When working with a row, the data source object must be populated. In | |
1002 // all other cases, the data source object is already populated, so we | |
1003 // don't overwrite it, which might break bindings etc | |
1004 if ( nTr ) { | |
1005 _fnSetCellData( oSettings, iRow, i, _fnGetCellData( oSettings, iRow, i ) ); | |
1006 } | |
1007 columns[i].sType = null; | |
1008 } | |
1009 | |
1010 /* Add to the display array */ | |
1011 oSettings.aiDisplayMaster.push( iRow ); | |
1012 | |
1013 /* Create the DOM information, or register it if already present */ | |
1014 if ( nTr || ! oSettings.oFeatures.bDeferRender ) | |
1015 { | |
1016 _fnCreateTr( oSettings, iRow, nTr, anTds ); | |
1017 } | |
1018 | |
1019 return iRow; | |
1020 } | |
1021 | |
1022 | |
1023 /** | |
1024 * Add one or more TR elements to the table. Generally we'd expect to | |
1025 * use this for reading data from a DOM sourced table, but it could be | |
1026 * used for an TR element. Note that if a TR is given, it is used (i.e. | |
1027 * it is not cloned). | |
1028 * @param {object} settings dataTables settings object | |
1029 * @param {array|node|jQuery} trs The TR element(s) to add to the table | |
1030 * @returns {array} Array of indexes for the added rows | |
1031 * @memberof DataTable#oApi | |
1032 */ | |
1033 function _fnAddTr( settings, trs ) | |
1034 { | |
1035 var row; | |
1036 | |
1037 // Allow an individual node to be passed in | |
1038 if ( ! (trs instanceof $) ) { | |
1039 trs = $(trs); | |
1040 } | |
1041 | |
1042 return trs.map( function (i, el) { | |
1043 row = _fnGetRowElements( settings, el ); | |
1044 return _fnAddData( settings, row.data, el, row.cells ); | |
1045 } ); | |
1046 } | |
1047 | |
1048 | |
1049 /** | |
1050 * Take a TR element and convert it to an index in aoData | |
1051 * @param {object} oSettings dataTables settings object | |
1052 * @param {node} n the TR element to find | |
1053 * @returns {int} index if the node is found, null if not | |
1054 * @memberof DataTable#oApi | |
1055 */ | |
1056 function _fnNodeToDataIndex( oSettings, n ) | |
1057 { | |
1058 return (n._DT_RowIndex!==undefined) ? n._DT_RowIndex : null; | |
1059 } | |
1060 | |
1061 | |
1062 /** | |
1063 * Take a TD element and convert it into a column data index (not the visible index) | |
1064 * @param {object} oSettings dataTables settings object | |
1065 * @param {int} iRow The row number the TD/TH can be found in | |
1066 * @param {node} n The TD/TH element to find | |
1067 * @returns {int} index if the node is found, -1 if not | |
1068 * @memberof DataTable#oApi | |
1069 */ | |
1070 function _fnNodeToColumnIndex( oSettings, iRow, n ) | |
1071 { | |
1072 return $.inArray( n, oSettings.aoData[ iRow ].anCells ); | |
1073 } | |
1074 | |
1075 | |
1076 /** | |
1077 * Get the data for a given cell from the internal cache, taking into account data mapping | |
1078 * @param {object} settings dataTables settings object | |
1079 * @param {int} rowIdx aoData row id | |
1080 * @param {int} colIdx Column index | |
1081 * @param {string} type data get type ('display', 'type' 'filter' 'sort') | |
1082 * @returns {*} Cell data | |
1083 * @memberof DataTable#oApi | |
1084 */ | |
1085 function _fnGetCellData( settings, rowIdx, colIdx, type ) | |
1086 { | |
1087 var draw = settings.iDraw; | |
1088 var col = settings.aoColumns[colIdx]; | |
1089 var rowData = settings.aoData[rowIdx]._aData; | |
1090 var defaultContent = col.sDefaultContent; | |
1091 var cellData = col.fnGetData( rowData, type, { | |
1092 settings: settings, | |
1093 row: rowIdx, | |
1094 col: colIdx | |
1095 } ); | |
1096 | |
1097 if ( cellData === undefined ) { | |
1098 if ( settings.iDrawError != draw && defaultContent === null ) { | |
1099 _fnLog( settings, 0, "Requested unknown parameter "+ | |
1100 (typeof col.mData=='function' ? '{function}' : "'"+col.mData+"'")+ | |
1101 " for row "+rowIdx, 4 ); | |
1102 settings.iDrawError = draw; | |
1103 } | |
1104 return defaultContent; | |
1105 } | |
1106 | |
1107 /* When the data source is null, we can use default column data */ | |
1108 if ( (cellData === rowData || cellData === null) && defaultContent !== null ) { | |
1109 cellData = defaultContent; | |
1110 } | |
1111 else if ( typeof cellData === 'function' ) { | |
1112 // If the data source is a function, then we run it and use the return, | |
1113 // executing in the scope of the data object (for instances) | |
1114 return cellData.call( rowData ); | |
1115 } | |
1116 | |
1117 if ( cellData === null && type == 'display' ) { | |
1118 return ''; | |
1119 } | |
1120 return cellData; | |
1121 } | |
1122 | |
1123 | |
1124 /** | |
1125 * Set the value for a specific cell, into the internal data cache | |
1126 * @param {object} settings dataTables settings object | |
1127 * @param {int} rowIdx aoData row id | |
1128 * @param {int} colIdx Column index | |
1129 * @param {*} val Value to set | |
1130 * @memberof DataTable#oApi | |
1131 */ | |
1132 function _fnSetCellData( settings, rowIdx, colIdx, val ) | |
1133 { | |
1134 var col = settings.aoColumns[colIdx]; | |
1135 var rowData = settings.aoData[rowIdx]._aData; | |
1136 | |
1137 col.fnSetData( rowData, val, { | |
1138 settings: settings, | |
1139 row: rowIdx, | |
1140 col: colIdx | |
1141 } ); | |
1142 } | |
1143 | |
1144 | |
1145 // Private variable that is used to match action syntax in the data property object | |
1146 var __reArray = /\[.*?\]$/; | |
1147 var __reFn = /\(\)$/; | |
1148 | |
1149 /** | |
1150 * Split string on periods, taking into account escaped periods | |
1151 * @param {string} str String to split | |
1152 * @return {array} Split string | |
1153 */ | |
1154 function _fnSplitObjNotation( str ) | |
1155 { | |
1156 return $.map( str.match(/(\\.|[^\.])+/g), function ( s ) { | |
1157 return s.replace(/\\./g, '.'); | |
1158 } ); | |
1159 } | |
1160 | |
1161 | |
1162 /** | |
1163 * Return a function that can be used to get data from a source object, taking | |
1164 * into account the ability to use nested objects as a source | |
1165 * @param {string|int|function} mSource The data source for the object | |
1166 * @returns {function} Data get function | |
1167 * @memberof DataTable#oApi | |
1168 */ | |
1169 function _fnGetObjectDataFn( mSource ) | |
1170 { | |
1171 if ( $.isPlainObject( mSource ) ) | |
1172 { | |
1173 /* Build an object of get functions, and wrap them in a single call */ | |
1174 var o = {}; | |
1175 $.each( mSource, function (key, val) { | |
1176 if ( val ) { | |
1177 o[key] = _fnGetObjectDataFn( val ); | |
1178 } | |
1179 } ); | |
1180 | |
1181 return function (data, type, row, meta) { | |
1182 var t = o[type] || o._; | |
1183 return t !== undefined ? | |
1184 t(data, type, row, meta) : | |
1185 data; | |
1186 }; | |
1187 } | |
1188 else if ( mSource === null ) | |
1189 { | |
1190 /* Give an empty string for rendering / sorting etc */ | |
1191 return function (data) { // type, row and meta also passed, but not used | |
1192 return data; | |
1193 }; | |
1194 } | |
1195 else if ( typeof mSource === 'function' ) | |
1196 { | |
1197 return function (data, type, row, meta) { | |
1198 return mSource( data, type, row, meta ); | |
1199 }; | |
1200 } | |
1201 else if ( typeof mSource === 'string' && (mSource.indexOf('.') !== -1 || | |
1202 mSource.indexOf('[') !== -1 || mSource.indexOf('(') !== -1) ) | |
1203 { | |
1204 /* If there is a . in the source string then the data source is in a | |
1205 * nested object so we loop over the data for each level to get the next | |
1206 * level down. On each loop we test for undefined, and if found immediately | |
1207 * return. This allows entire objects to be missing and sDefaultContent to | |
1208 * be used if defined, rather than throwing an error | |
1209 */ | |
1210 var fetchData = function (data, type, src) { | |
1211 var arrayNotation, funcNotation, out, innerSrc; | |
1212 | |
1213 if ( src !== "" ) | |
1214 { | |
1215 var a = _fnSplitObjNotation( src ); | |
1216 | |
1217 for ( var i=0, iLen=a.length ; i<iLen ; i++ ) | |
1218 { | |
1219 // Check if we are dealing with special notation | |
1220 arrayNotation = a[i].match(__reArray); | |
1221 funcNotation = a[i].match(__reFn); | |
1222 | |
1223 if ( arrayNotation ) | |
1224 { | |
1225 // Array notation | |
1226 a[i] = a[i].replace(__reArray, ''); | |
1227 | |
1228 // Condition allows simply [] to be passed in | |
1229 if ( a[i] !== "" ) { | |
1230 data = data[ a[i] ]; | |
1231 } | |
1232 out = []; | |
1233 | |
1234 // Get the remainder of the nested object to get | |
1235 a.splice( 0, i+1 ); | |
1236 innerSrc = a.join('.'); | |
1237 | |
1238 // Traverse each entry in the array getting the properties requested | |
1239 for ( var j=0, jLen=data.length ; j<jLen ; j++ ) { | |
1240 out.push( fetchData( data[j], type, innerSrc ) ); | |
1241 } | |
1242 | |
1243 // If a string is given in between the array notation indicators, that | |
1244 // is used to join the strings together, otherwise an array is returned | |
1245 var join = arrayNotation[0].substring(1, arrayNotation[0].length-1); | |
1246 data = (join==="") ? out : out.join(join); | |
1247 | |
1248 // The inner call to fetchData has already traversed through the remainder | |
1249 // of the source requested, so we exit from the loop | |
1250 break; | |
1251 } | |
1252 else if ( funcNotation ) | |
1253 { | |
1254 // Function call | |
1255 a[i] = a[i].replace(__reFn, ''); | |
1256 data = data[ a[i] ](); | |
1257 continue; | |
1258 } | |
1259 | |
1260 if ( data === null || data[ a[i] ] === undefined ) | |
1261 { | |
1262 return undefined; | |
1263 } | |
1264 data = data[ a[i] ]; | |
1265 } | |
1266 } | |
1267 | |
1268 return data; | |
1269 }; | |
1270 | |
1271 return function (data, type) { // row and meta also passed, but not used | |
1272 return fetchData( data, type, mSource ); | |
1273 }; | |
1274 } | |
1275 else | |
1276 { | |
1277 /* Array or flat object mapping */ | |
1278 return function (data, type) { // row and meta also passed, but not used | |
1279 return data[mSource]; | |
1280 }; | |
1281 } | |
1282 } | |
1283 | |
1284 | |
1285 /** | |
1286 * Return a function that can be used to set data from a source object, taking | |
1287 * into account the ability to use nested objects as a source | |
1288 * @param {string|int|function} mSource The data source for the object | |
1289 * @returns {function} Data set function | |
1290 * @memberof DataTable#oApi | |
1291 */ | |
1292 function _fnSetObjectDataFn( mSource ) | |
1293 { | |
1294 if ( $.isPlainObject( mSource ) ) | |
1295 { | |
1296 /* Unlike get, only the underscore (global) option is used for for | |
1297 * setting data since we don't know the type here. This is why an object | |
1298 * option is not documented for `mData` (which is read/write), but it is | |
1299 * for `mRender` which is read only. | |
1300 */ | |
1301 return _fnSetObjectDataFn( mSource._ ); | |
1302 } | |
1303 else if ( mSource === null ) | |
1304 { | |
1305 /* Nothing to do when the data source is null */ | |
1306 return function () {}; | |
1307 } | |
1308 else if ( typeof mSource === 'function' ) | |
1309 { | |
1310 return function (data, val, meta) { | |
1311 mSource( data, 'set', val, meta ); | |
1312 }; | |
1313 } | |
1314 else if ( typeof mSource === 'string' && (mSource.indexOf('.') !== -1 || | |
1315 mSource.indexOf('[') !== -1 || mSource.indexOf('(') !== -1) ) | |
1316 { | |
1317 /* Like the get, we need to get data from a nested object */ | |
1318 var setData = function (data, val, src) { | |
1319 var a = _fnSplitObjNotation( src ), b; | |
1320 var aLast = a[a.length-1]; | |
1321 var arrayNotation, funcNotation, o, innerSrc; | |
1322 | |
1323 for ( var i=0, iLen=a.length-1 ; i<iLen ; i++ ) | |
1324 { | |
1325 // Check if we are dealing with an array notation request | |
1326 arrayNotation = a[i].match(__reArray); | |
1327 funcNotation = a[i].match(__reFn); | |
1328 | |
1329 if ( arrayNotation ) | |
1330 { | |
1331 a[i] = a[i].replace(__reArray, ''); | |
1332 data[ a[i] ] = []; | |
1333 | |
1334 // Get the remainder of the nested object to set so we can recurse | |
1335 b = a.slice(); | |
1336 b.splice( 0, i+1 ); | |
1337 innerSrc = b.join('.'); | |
1338 | |
1339 // Traverse each entry in the array setting the properties requested | |
1340 for ( var j=0, jLen=val.length ; j<jLen ; j++ ) | |
1341 { | |
1342 o = {}; | |
1343 setData( o, val[j], innerSrc ); | |
1344 data[ a[i] ].push( o ); | |
1345 } | |
1346 | |
1347 // The inner call to setData has already traversed through the remainder | |
1348 // of the source and has set the data, thus we can exit here | |
1349 return; | |
1350 } | |
1351 else if ( funcNotation ) | |
1352 { | |
1353 // Function call | |
1354 a[i] = a[i].replace(__reFn, ''); | |
1355 data = data[ a[i] ]( val ); | |
1356 } | |
1357 | |
1358 // If the nested object doesn't currently exist - since we are | |
1359 // trying to set the value - create it | |
1360 if ( data[ a[i] ] === null || data[ a[i] ] === undefined ) | |
1361 { | |
1362 data[ a[i] ] = {}; | |
1363 } | |
1364 data = data[ a[i] ]; | |
1365 } | |
1366 | |
1367 // Last item in the input - i.e, the actual set | |
1368 if ( aLast.match(__reFn ) ) | |
1369 { | |
1370 // Function call | |
1371 data = data[ aLast.replace(__reFn, '') ]( val ); | |
1372 } | |
1373 else | |
1374 { | |
1375 // If array notation is used, we just want to strip it and use the property name | |
1376 // and assign the value. If it isn't used, then we get the result we want anyway | |
1377 data[ aLast.replace(__reArray, '') ] = val; | |
1378 } | |
1379 }; | |
1380 | |
1381 return function (data, val) { // meta is also passed in, but not used | |
1382 return setData( data, val, mSource ); | |
1383 }; | |
1384 } | |
1385 else | |
1386 { | |
1387 /* Array or flat object mapping */ | |
1388 return function (data, val) { // meta is also passed in, but not used | |
1389 data[mSource] = val; | |
1390 }; | |
1391 } | |
1392 } | |
1393 | |
1394 | |
1395 /** | |
1396 * Return an array with the full table data | |
1397 * @param {object} oSettings dataTables settings object | |
1398 * @returns array {array} aData Master data array | |
1399 * @memberof DataTable#oApi | |
1400 */ | |
1401 function _fnGetDataMaster ( settings ) | |
1402 { | |
1403 return _pluck( settings.aoData, '_aData' ); | |
1404 } | |
1405 | |
1406 | |
1407 /** | |
1408 * Nuke the table | |
1409 * @param {object} oSettings dataTables settings object | |
1410 * @memberof DataTable#oApi | |
1411 */ | |
1412 function _fnClearTable( settings ) | |
1413 { | |
1414 settings.aoData.length = 0; | |
1415 settings.aiDisplayMaster.length = 0; | |
1416 settings.aiDisplay.length = 0; | |
1417 } | |
1418 | |
1419 | |
1420 /** | |
1421 * Take an array of integers (index array) and remove a target integer (value - not | |
1422 * the key!) | |
1423 * @param {array} a Index array to target | |
1424 * @param {int} iTarget value to find | |
1425 * @memberof DataTable#oApi | |
1426 */ | |
1427 function _fnDeleteIndex( a, iTarget, splice ) | |
1428 { | |
1429 var iTargetIndex = -1; | |
1430 | |
1431 for ( var i=0, iLen=a.length ; i<iLen ; i++ ) | |
1432 { | |
1433 if ( a[i] == iTarget ) | |
1434 { | |
1435 iTargetIndex = i; | |
1436 } | |
1437 else if ( a[i] > iTarget ) | |
1438 { | |
1439 a[i]--; | |
1440 } | |
1441 } | |
1442 | |
1443 if ( iTargetIndex != -1 && splice === undefined ) | |
1444 { | |
1445 a.splice( iTargetIndex, 1 ); | |
1446 } | |
1447 } | |
1448 | |
1449 | |
1450 /** | |
1451 * Mark cached data as invalid such that a re-read of the data will occur when | |
1452 * the cached data is next requested. Also update from the data source object. | |
1453 * | |
1454 * @param {object} settings DataTables settings object | |
1455 * @param {int} rowIdx Row index to invalidate | |
1456 * @param {string} [src] Source to invalidate from: undefined, 'auto', 'dom' | |
1457 * or 'data' | |
1458 * @param {int} [colIdx] Column index to invalidate. If undefined the whole | |
1459 * row will be invalidated | |
1460 * @memberof DataTable#oApi | |
1461 * | |
1462 * @todo For the modularisation of v1.11 this will need to become a callback, so | |
1463 * the sort and filter methods can subscribe to it. That will required | |
1464 * initialisation options for sorting, which is why it is not already baked in | |
1465 */ | |
1466 function _fnInvalidate( settings, rowIdx, src, colIdx ) | |
1467 { | |
1468 var row = settings.aoData[ rowIdx ]; | |
1469 var i, ien; | |
1470 var cellWrite = function ( cell, col ) { | |
1471 // This is very frustrating, but in IE if you just write directly | |
1472 // to innerHTML, and elements that are overwritten are GC'ed, | |
1473 // even if there is a reference to them elsewhere | |
1474 while ( cell.childNodes.length ) { | |
1475 cell.removeChild( cell.firstChild ); | |
1476 } | |
1477 | |
1478 cell.innerHTML = _fnGetCellData( settings, rowIdx, col, 'display' ); | |
1479 }; | |
1480 | |
1481 // Are we reading last data from DOM or the data object? | |
1482 if ( src === 'dom' || ((! src || src === 'auto') && row.src === 'dom') ) { | |
1483 // Read the data from the DOM | |
1484 row._aData = _fnGetRowElements( | |
1485 settings, row, colIdx, colIdx === undefined ? undefined : row._aData | |
1486 ) | |
1487 .data; | |
1488 } | |
1489 else { | |
1490 // Reading from data object, update the DOM | |
1491 var cells = row.anCells; | |
1492 | |
1493 if ( cells ) { | |
1494 if ( colIdx !== undefined ) { | |
1495 cellWrite( cells[colIdx], colIdx ); | |
1496 } | |
1497 else { | |
1498 for ( i=0, ien=cells.length ; i<ien ; i++ ) { | |
1499 cellWrite( cells[i], i ); | |
1500 } | |
1501 } | |
1502 } | |
1503 } | |
1504 | |
1505 // For both row and cell invalidation, the cached data for sorting and | |
1506 // filtering is nulled out | |
1507 row._aSortData = null; | |
1508 row._aFilterData = null; | |
1509 | |
1510 // Invalidate the type for a specific column (if given) or all columns since | |
1511 // the data might have changed | |
1512 var cols = settings.aoColumns; | |
1513 if ( colIdx !== undefined ) { | |
1514 cols[ colIdx ].sType = null; | |
1515 } | |
1516 else { | |
1517 for ( i=0, ien=cols.length ; i<ien ; i++ ) { | |
1518 cols[i].sType = null; | |
1519 } | |
1520 | |
1521 // Update DataTables special `DT_*` attributes for the row | |
1522 _fnRowAttributes( row ); | |
1523 } | |
1524 } | |
1525 | |
1526 | |
1527 /** | |
1528 * Build a data source object from an HTML row, reading the contents of the | |
1529 * cells that are in the row. | |
1530 * | |
1531 * @param {object} settings DataTables settings object | |
1532 * @param {node|object} TR element from which to read data or existing row | |
1533 * object from which to re-read the data from the cells | |
1534 * @param {int} [colIdx] Optional column index | |
1535 * @param {array|object} [d] Data source object. If `colIdx` is given then this | |
1536 * parameter should also be given and will be used to write the data into. | |
1537 * Only the column in question will be written | |
1538 * @returns {object} Object with two parameters: `data` the data read, in | |
1539 * document order, and `cells` and array of nodes (they can be useful to the | |
1540 * caller, so rather than needing a second traversal to get them, just return | |
1541 * them from here). | |
1542 * @memberof DataTable#oApi | |
1543 */ | |
1544 function _fnGetRowElements( settings, row, colIdx, d ) | |
1545 { | |
1546 var | |
1547 tds = [], | |
1548 td = row.firstChild, | |
1549 name, col, o, i=0, contents, | |
1550 columns = settings.aoColumns, | |
1551 objectRead = settings._rowReadObject; | |
1552 | |
1553 // Allow the data object to be passed in, or construct | |
1554 d = d || objectRead ? {} : []; | |
1555 | |
1556 var attr = function ( str, td ) { | |
1557 if ( typeof str === 'string' ) { | |
1558 var idx = str.indexOf('@'); | |
1559 | |
1560 if ( idx !== -1 ) { | |
1561 var attr = str.substring( idx+1 ); | |
1562 var setter = _fnSetObjectDataFn( str ); | |
1563 setter( d, td.getAttribute( attr ) ); | |
1564 } | |
1565 } | |
1566 }; | |
1567 | |
1568 // Read data from a cell and store into the data object | |
1569 var cellProcess = function ( cell ) { | |
1570 if ( colIdx === undefined || colIdx === i ) { | |
1571 col = columns[i]; | |
1572 contents = $.trim(cell.innerHTML); | |
1573 | |
1574 if ( col && col._bAttrSrc ) { | |
1575 var setter = _fnSetObjectDataFn( col.mData._ ); | |
1576 setter( d, contents ); | |
1577 | |
1578 attr( col.mData.sort, cell ); | |
1579 attr( col.mData.type, cell ); | |
1580 attr( col.mData.filter, cell ); | |
1581 } | |
1582 else { | |
1583 // Depending on the `data` option for the columns the data can | |
1584 // be read to either an object or an array. | |
1585 if ( objectRead ) { | |
1586 if ( ! col._setter ) { | |
1587 // Cache the setter function | |
1588 col._setter = _fnSetObjectDataFn( col.mData ); | |
1589 } | |
1590 col._setter( d, contents ); | |
1591 } | |
1592 else { | |
1593 d[i] = contents; | |
1594 } | |
1595 } | |
1596 } | |
1597 | |
1598 i++; | |
1599 }; | |
1600 | |
1601 if ( td ) { | |
1602 // `tr` element was passed in | |
1603 while ( td ) { | |
1604 name = td.nodeName.toUpperCase(); | |
1605 | |
1606 if ( name == "TD" || name == "TH" ) { | |
1607 cellProcess( td ); | |
1608 tds.push( td ); | |
1609 } | |
1610 | |
1611 td = td.nextSibling; | |
1612 } | |
1613 } | |
1614 else { | |
1615 // Existing row object passed in | |
1616 tds = row.anCells; | |
1617 | |
1618 for ( var j=0, jen=tds.length ; j<jen ; j++ ) { | |
1619 cellProcess( tds[j] ); | |
1620 } | |
1621 } | |
1622 | |
1623 return { | |
1624 data: d, | |
1625 cells: tds | |
1626 }; | |
1627 } | |
1628 /** | |
1629 * Create a new TR element (and it's TD children) for a row | |
1630 * @param {object} oSettings dataTables settings object | |
1631 * @param {int} iRow Row to consider | |
1632 * @param {node} [nTrIn] TR element to add to the table - optional. If not given, | |
1633 * DataTables will create a row automatically | |
1634 * @param {array} [anTds] Array of TD|TH elements for the row - must be given | |
1635 * if nTr is. | |
1636 * @memberof DataTable#oApi | |
1637 */ | |
1638 function _fnCreateTr ( oSettings, iRow, nTrIn, anTds ) | |
1639 { | |
1640 var | |
1641 row = oSettings.aoData[iRow], | |
1642 rowData = row._aData, | |
1643 cells = [], | |
1644 nTr, nTd, oCol, | |
1645 i, iLen; | |
1646 | |
1647 if ( row.nTr === null ) | |
1648 { | |
1649 nTr = nTrIn || document.createElement('tr'); | |
1650 | |
1651 row.nTr = nTr; | |
1652 row.anCells = cells; | |
1653 | |
1654 /* Use a private property on the node to allow reserve mapping from the node | |
1655 * to the aoData array for fast look up | |
1656 */ | |
1657 nTr._DT_RowIndex = iRow; | |
1658 | |
1659 /* Special parameters can be given by the data source to be used on the row */ | |
1660 _fnRowAttributes( row ); | |
1661 | |
1662 /* Process each column */ | |
1663 for ( i=0, iLen=oSettings.aoColumns.length ; i<iLen ; i++ ) | |
1664 { | |
1665 oCol = oSettings.aoColumns[i]; | |
1666 | |
1667 nTd = nTrIn ? anTds[i] : document.createElement( oCol.sCellType ); | |
1668 cells.push( nTd ); | |
1669 | |
1670 // Need to create the HTML if new, or if a rendering function is defined | |
1671 if ( !nTrIn || oCol.mRender || oCol.mData !== i ) | |
1672 { | |
1673 nTd.innerHTML = _fnGetCellData( oSettings, iRow, i, 'display' ); | |
1674 } | |
1675 | |
1676 /* Add user defined class */ | |
1677 if ( oCol.sClass ) | |
1678 { | |
1679 nTd.className += ' '+oCol.sClass; | |
1680 } | |
1681 | |
1682 // Visibility - add or remove as required | |
1683 if ( oCol.bVisible && ! nTrIn ) | |
1684 { | |
1685 nTr.appendChild( nTd ); | |
1686 } | |
1687 else if ( ! oCol.bVisible && nTrIn ) | |
1688 { | |
1689 nTd.parentNode.removeChild( nTd ); | |
1690 } | |
1691 | |
1692 if ( oCol.fnCreatedCell ) | |
1693 { | |
1694 oCol.fnCreatedCell.call( oSettings.oInstance, | |
1695 nTd, _fnGetCellData( oSettings, iRow, i ), rowData, iRow, i | |
1696 ); | |
1697 } | |
1698 } | |
1699 | |
1700 _fnCallbackFire( oSettings, 'aoRowCreatedCallback', null, [nTr, rowData, iRow] ); | |
1701 } | |
1702 | |
1703 // Remove once webkit bug 131819 and Chromium bug 365619 have been resolved | |
1704 // and deployed | |
1705 row.nTr.setAttribute( 'role', 'row' ); | |
1706 } | |
1707 | |
1708 | |
1709 /** | |
1710 * Add attributes to a row based on the special `DT_*` parameters in a data | |
1711 * source object. | |
1712 * @param {object} DataTables row object for the row to be modified | |
1713 * @memberof DataTable#oApi | |
1714 */ | |
1715 function _fnRowAttributes( row ) | |
1716 { | |
1717 var tr = row.nTr; | |
1718 var data = row._aData; | |
1719 | |
1720 if ( tr ) { | |
1721 if ( data.DT_RowId ) { | |
1722 tr.id = data.DT_RowId; | |
1723 } | |
1724 | |
1725 if ( data.DT_RowClass ) { | |
1726 // Remove any classes added by DT_RowClass before | |
1727 var a = data.DT_RowClass.split(' '); | |
1728 row.__rowc = row.__rowc ? | |
1729 _unique( row.__rowc.concat( a ) ) : | |
1730 a; | |
1731 | |
1732 $(tr) | |
1733 .removeClass( row.__rowc.join(' ') ) | |
1734 .addClass( data.DT_RowClass ); | |
1735 } | |
1736 | |
1737 if ( data.DT_RowData ) { | |
1738 $(tr).data( data.DT_RowData ); | |
1739 } | |
1740 } | |
1741 } | |
1742 | |
1743 | |
1744 /** | |
1745 * Create the HTML header for the table | |
1746 * @param {object} oSettings dataTables settings object | |
1747 * @memberof DataTable#oApi | |
1748 */ | |
1749 function _fnBuildHead( oSettings ) | |
1750 { | |
1751 var i, ien, cell, row, column; | |
1752 var thead = oSettings.nTHead; | |
1753 var tfoot = oSettings.nTFoot; | |
1754 var createHeader = $('th, td', thead).length === 0; | |
1755 var classes = oSettings.oClasses; | |
1756 var columns = oSettings.aoColumns; | |
1757 | |
1758 if ( createHeader ) { | |
1759 row = $('<tr/>').appendTo( thead ); | |
1760 } | |
1761 | |
1762 for ( i=0, ien=columns.length ; i<ien ; i++ ) { | |
1763 column = columns[i]; | |
1764 cell = $( column.nTh ).addClass( column.sClass ); | |
1765 | |
1766 if ( createHeader ) { | |
1767 cell.appendTo( row ); | |
1768 } | |
1769 | |
1770 // 1.11 move into sorting | |
1771 if ( oSettings.oFeatures.bSort ) { | |
1772 cell.addClass( column.sSortingClass ); | |
1773 | |
1774 if ( column.bSortable !== false ) { | |
1775 cell | |
1776 .attr( 'tabindex', oSettings.iTabIndex ) | |
1777 .attr( 'aria-controls', oSettings.sTableId ); | |
1778 | |
1779 _fnSortAttachListener( oSettings, column.nTh, i ); | |
1780 } | |
1781 } | |
1782 | |
1783 if ( column.sTitle != cell.html() ) { | |
1784 cell.html( column.sTitle ); | |
1785 } | |
1786 | |
1787 _fnRenderer( oSettings, 'header' )( | |
1788 oSettings, cell, column, classes | |
1789 ); | |
1790 } | |
1791 | |
1792 if ( createHeader ) { | |
1793 _fnDetectHeader( oSettings.aoHeader, thead ); | |
1794 } | |
1795 | |
1796 /* ARIA role for the rows */ | |
1797 $(thead).find('>tr').attr('role', 'row'); | |
1798 | |
1799 /* Deal with the footer - add classes if required */ | |
1800 $(thead).find('>tr>th, >tr>td').addClass( classes.sHeaderTH ); | |
1801 $(tfoot).find('>tr>th, >tr>td').addClass( classes.sFooterTH ); | |
1802 | |
1803 // Cache the footer cells. Note that we only take the cells from the first | |
1804 // row in the footer. If there is more than one row the user wants to | |
1805 // interact with, they need to use the table().foot() method. Note also this | |
1806 // allows cells to be used for multiple columns using colspan | |
1807 if ( tfoot !== null ) { | |
1808 var cells = oSettings.aoFooter[0]; | |
1809 | |
1810 for ( i=0, ien=cells.length ; i<ien ; i++ ) { | |
1811 column = columns[i]; | |
1812 column.nTf = cells[i].cell; | |
1813 | |
1814 if ( column.sClass ) { | |
1815 $(column.nTf).addClass( column.sClass ); | |
1816 } | |
1817 } | |
1818 } | |
1819 } | |
1820 | |
1821 | |
1822 /** | |
1823 * Draw the header (or footer) element based on the column visibility states. The | |
1824 * methodology here is to use the layout array from _fnDetectHeader, modified for | |
1825 * the instantaneous column visibility, to construct the new layout. The grid is | |
1826 * traversed over cell at a time in a rows x columns grid fashion, although each | |
1827 * cell insert can cover multiple elements in the grid - which is tracks using the | |
1828 * aApplied array. Cell inserts in the grid will only occur where there isn't | |
1829 * already a cell in that position. | |
1830 * @param {object} oSettings dataTables settings object | |
1831 * @param array {objects} aoSource Layout array from _fnDetectHeader | |
1832 * @param {boolean} [bIncludeHidden=false] If true then include the hidden columns in the calc, | |
1833 * @memberof DataTable#oApi | |
1834 */ | |
1835 function _fnDrawHead( oSettings, aoSource, bIncludeHidden ) | |
1836 { | |
1837 var i, iLen, j, jLen, k, kLen, n, nLocalTr; | |
1838 var aoLocal = []; | |
1839 var aApplied = []; | |
1840 var iColumns = oSettings.aoColumns.length; | |
1841 var iRowspan, iColspan; | |
1842 | |
1843 if ( ! aoSource ) | |
1844 { | |
1845 return; | |
1846 } | |
1847 | |
1848 if ( bIncludeHidden === undefined ) | |
1849 { | |
1850 bIncludeHidden = false; | |
1851 } | |
1852 | |
1853 /* Make a copy of the master layout array, but without the visible columns in it */ | |
1854 for ( i=0, iLen=aoSource.length ; i<iLen ; i++ ) | |
1855 { | |
1856 aoLocal[i] = aoSource[i].slice(); | |
1857 aoLocal[i].nTr = aoSource[i].nTr; | |
1858 | |
1859 /* Remove any columns which are currently hidden */ | |
1860 for ( j=iColumns-1 ; j>=0 ; j-- ) | |
1861 { | |
1862 if ( !oSettings.aoColumns[j].bVisible && !bIncludeHidden ) | |
1863 { | |
1864 aoLocal[i].splice( j, 1 ); | |
1865 } | |
1866 } | |
1867 | |
1868 /* Prep the applied array - it needs an element for each row */ | |
1869 aApplied.push( [] ); | |
1870 } | |
1871 | |
1872 for ( i=0, iLen=aoLocal.length ; i<iLen ; i++ ) | |
1873 { | |
1874 nLocalTr = aoLocal[i].nTr; | |
1875 | |
1876 /* All cells are going to be replaced, so empty out the row */ | |
1877 if ( nLocalTr ) | |
1878 { | |
1879 while( (n = nLocalTr.firstChild) ) | |
1880 { | |
1881 nLocalTr.removeChild( n ); | |
1882 } | |
1883 } | |
1884 | |
1885 for ( j=0, jLen=aoLocal[i].length ; j<jLen ; j++ ) | |
1886 { | |
1887 iRowspan = 1; | |
1888 iColspan = 1; | |
1889 | |
1890 /* Check to see if there is already a cell (row/colspan) covering our target | |
1891 * insert point. If there is, then there is nothing to do. | |
1892 */ | |
1893 if ( aApplied[i][j] === undefined ) | |
1894 { | |
1895 nLocalTr.appendChild( aoLocal[i][j].cell ); | |
1896 aApplied[i][j] = 1; | |
1897 | |
1898 /* Expand the cell to cover as many rows as needed */ | |
1899 while ( aoLocal[i+iRowspan] !== undefined && | |
1900 aoLocal[i][j].cell == aoLocal[i+iRowspan][j].cell ) | |
1901 { | |
1902 aApplied[i+iRowspan][j] = 1; | |
1903 iRowspan++; | |
1904 } | |
1905 | |
1906 /* Expand the cell to cover as many columns as needed */ | |
1907 while ( aoLocal[i][j+iColspan] !== undefined && | |
1908 aoLocal[i][j].cell == aoLocal[i][j+iColspan].cell ) | |
1909 { | |
1910 /* Must update the applied array over the rows for the columns */ | |
1911 for ( k=0 ; k<iRowspan ; k++ ) | |
1912 { | |
1913 aApplied[i+k][j+iColspan] = 1; | |
1914 } | |
1915 iColspan++; | |
1916 } | |
1917 | |
1918 /* Do the actual expansion in the DOM */ | |
1919 $(aoLocal[i][j].cell) | |
1920 .attr('rowspan', iRowspan) | |
1921 .attr('colspan', iColspan); | |
1922 } | |
1923 } | |
1924 } | |
1925 } | |
1926 | |
1927 | |
1928 /** | |
1929 * Insert the required TR nodes into the table for display | |
1930 * @param {object} oSettings dataTables settings object | |
1931 * @memberof DataTable#oApi | |
1932 */ | |
1933 function _fnDraw( oSettings ) | |
1934 { | |
1935 /* Provide a pre-callback function which can be used to cancel the draw is false is returned */ | |
1936 var aPreDraw = _fnCallbackFire( oSettings, 'aoPreDrawCallback', 'preDraw', [oSettings] ); | |
1937 if ( $.inArray( false, aPreDraw ) !== -1 ) | |
1938 { | |
1939 _fnProcessingDisplay( oSettings, false ); | |
1940 return; | |
1941 } | |
1942 | |
1943 var i, iLen, n; | |
1944 var anRows = []; | |
1945 var iRowCount = 0; | |
1946 var asStripeClasses = oSettings.asStripeClasses; | |
1947 var iStripes = asStripeClasses.length; | |
1948 var iOpenRows = oSettings.aoOpenRows.length; | |
1949 var oLang = oSettings.oLanguage; | |
1950 var iInitDisplayStart = oSettings.iInitDisplayStart; | |
1951 var bServerSide = _fnDataSource( oSettings ) == 'ssp'; | |
1952 var aiDisplay = oSettings.aiDisplay; | |
1953 | |
1954 oSettings.bDrawing = true; | |
1955 | |
1956 /* Check and see if we have an initial draw position from state saving */ | |
1957 if ( iInitDisplayStart !== undefined && iInitDisplayStart !== -1 ) | |
1958 { | |
1959 oSettings._iDisplayStart = bServerSide ? | |
1960 iInitDisplayStart : | |
1961 iInitDisplayStart >= oSettings.fnRecordsDisplay() ? | |
1962 0 : | |
1963 iInitDisplayStart; | |
1964 | |
1965 oSettings.iInitDisplayStart = -1; | |
1966 } | |
1967 | |
1968 var iDisplayStart = oSettings._iDisplayStart; | |
1969 var iDisplayEnd = oSettings.fnDisplayEnd(); | |
1970 | |
1971 /* Server-side processing draw intercept */ | |
1972 if ( oSettings.bDeferLoading ) | |
1973 { | |
1974 oSettings.bDeferLoading = false; | |
1975 oSettings.iDraw++; | |
1976 _fnProcessingDisplay( oSettings, false ); | |
1977 } | |
1978 else if ( !bServerSide ) | |
1979 { | |
1980 oSettings.iDraw++; | |
1981 } | |
1982 else if ( !oSettings.bDestroying && !_fnAjaxUpdate( oSettings ) ) | |
1983 { | |
1984 return; | |
1985 } | |
1986 | |
1987 if ( aiDisplay.length !== 0 ) | |
1988 { | |
1989 var iStart = bServerSide ? 0 : iDisplayStart; | |
1990 var iEnd = bServerSide ? oSettings.aoData.length : iDisplayEnd; | |
1991 | |
1992 for ( var j=iStart ; j<iEnd ; j++ ) | |
1993 { | |
1994 var iDataIndex = aiDisplay[j]; | |
1995 var aoData = oSettings.aoData[ iDataIndex ]; | |
1996 if ( aoData.nTr === null ) | |
1997 { | |
1998 _fnCreateTr( oSettings, iDataIndex ); | |
1999 } | |
2000 | |
2001 var nRow = aoData.nTr; | |
2002 | |
2003 /* Remove the old striping classes and then add the new one */ | |
2004 if ( iStripes !== 0 ) | |
2005 { | |
2006 var sStripe = asStripeClasses[ iRowCount % iStripes ]; | |
2007 if ( aoData._sRowStripe != sStripe ) | |
2008 { | |
2009 $(nRow).removeClass( aoData._sRowStripe ).addClass( sStripe ); | |
2010 aoData._sRowStripe = sStripe; | |
2011 } | |
2012 } | |
2013 | |
2014 // Row callback functions - might want to manipulate the row | |
2015 // iRowCount and j are not currently documented. Are they at all | |
2016 // useful? | |
2017 _fnCallbackFire( oSettings, 'aoRowCallback', null, | |
2018 [nRow, aoData._aData, iRowCount, j] ); | |
2019 | |
2020 anRows.push( nRow ); | |
2021 iRowCount++; | |
2022 } | |
2023 } | |
2024 else | |
2025 { | |
2026 /* Table is empty - create a row with an empty message in it */ | |
2027 var sZero = oLang.sZeroRecords; | |
2028 if ( oSettings.iDraw == 1 && _fnDataSource( oSettings ) == 'ajax' ) | |
2029 { | |
2030 sZero = oLang.sLoadingRecords; | |
2031 } | |
2032 else if ( oLang.sEmptyTable && oSettings.fnRecordsTotal() === 0 ) | |
2033 { | |
2034 sZero = oLang.sEmptyTable; | |
2035 } | |
2036 | |
2037 anRows[ 0 ] = $( '<tr/>', { 'class': iStripes ? asStripeClasses[0] : '' } ) | |
2038 .append( $('<td />', { | |
2039 'valign': 'top', | |
2040 'colSpan': _fnVisbleColumns( oSettings ), | |
2041 'class': oSettings.oClasses.sRowEmpty | |
2042 } ).html( sZero ) )[0]; | |
2043 } | |
2044 | |
2045 /* Header and footer callbacks */ | |
2046 _fnCallbackFire( oSettings, 'aoHeaderCallback', 'header', [ $(oSettings.nTHead).children('tr')[0], | |
2047 _fnGetDataMaster( oSettings ), iDisplayStart, iDisplayEnd, aiDisplay ] ); | |
2048 | |
2049 _fnCallbackFire( oSettings, 'aoFooterCallback', 'footer', [ $(oSettings.nTFoot).children('tr')[0], | |
2050 _fnGetDataMaster( oSettings ), iDisplayStart, iDisplayEnd, aiDisplay ] ); | |
2051 | |
2052 var body = $(oSettings.nTBody); | |
2053 | |
2054 body.children().detach(); | |
2055 body.append( $(anRows) ); | |
2056 | |
2057 /* Call all required callback functions for the end of a draw */ | |
2058 _fnCallbackFire( oSettings, 'aoDrawCallback', 'draw', [oSettings] ); | |
2059 | |
2060 /* Draw is complete, sorting and filtering must be as well */ | |
2061 oSettings.bSorted = false; | |
2062 oSettings.bFiltered = false; | |
2063 oSettings.bDrawing = false; | |
2064 } | |
2065 | |
2066 | |
2067 /** | |
2068 * Redraw the table - taking account of the various features which are enabled | |
2069 * @param {object} oSettings dataTables settings object | |
2070 * @param {boolean} [holdPosition] Keep the current paging position. By default | |
2071 * the paging is reset to the first page | |
2072 * @memberof DataTable#oApi | |
2073 */ | |
2074 function _fnReDraw( settings, holdPosition ) | |
2075 { | |
2076 var | |
2077 features = settings.oFeatures, | |
2078 sort = features.bSort, | |
2079 filter = features.bFilter; | |
2080 | |
2081 if ( sort ) { | |
2082 _fnSort( settings ); | |
2083 } | |
2084 | |
2085 if ( filter ) { | |
2086 _fnFilterComplete( settings, settings.oPreviousSearch ); | |
2087 } | |
2088 else { | |
2089 // No filtering, so we want to just use the display master | |
2090 settings.aiDisplay = settings.aiDisplayMaster.slice(); | |
2091 } | |
2092 | |
2093 if ( holdPosition !== true ) { | |
2094 settings._iDisplayStart = 0; | |
2095 } | |
2096 | |
2097 // Let any modules know about the draw hold position state (used by | |
2098 // scrolling internally) | |
2099 settings._drawHold = holdPosition; | |
2100 | |
2101 _fnDraw( settings ); | |
2102 | |
2103 settings._drawHold = false; | |
2104 } | |
2105 | |
2106 | |
2107 /** | |
2108 * Add the options to the page HTML for the table | |
2109 * @param {object} oSettings dataTables settings object | |
2110 * @memberof DataTable#oApi | |
2111 */ | |
2112 function _fnAddOptionsHtml ( oSettings ) | |
2113 { | |
2114 var classes = oSettings.oClasses; | |
2115 var table = $(oSettings.nTable); | |
2116 var holding = $('<div/>').insertBefore( table ); // Holding element for speed | |
2117 var features = oSettings.oFeatures; | |
2118 | |
2119 // All DataTables are wrapped in a div | |
2120 var insert = $('<div/>', { | |
2121 id: oSettings.sTableId+'_wrapper', | |
2122 'class': classes.sWrapper + (oSettings.nTFoot ? '' : ' '+classes.sNoFooter) | |
2123 } ); | |
2124 | |
2125 oSettings.nHolding = holding[0]; | |
2126 oSettings.nTableWrapper = insert[0]; | |
2127 oSettings.nTableReinsertBefore = oSettings.nTable.nextSibling; | |
2128 | |
2129 /* Loop over the user set positioning and place the elements as needed */ | |
2130 var aDom = oSettings.sDom.split(''); | |
2131 var featureNode, cOption, nNewNode, cNext, sAttr, j; | |
2132 for ( var i=0 ; i<aDom.length ; i++ ) | |
2133 { | |
2134 featureNode = null; | |
2135 cOption = aDom[i]; | |
2136 | |
2137 if ( cOption == '<' ) | |
2138 { | |
2139 /* New container div */ | |
2140 nNewNode = $('<div/>')[0]; | |
2141 | |
2142 /* Check to see if we should append an id and/or a class name to the container */ | |
2143 cNext = aDom[i+1]; | |
2144 if ( cNext == "'" || cNext == '"' ) | |
2145 { | |
2146 sAttr = ""; | |
2147 j = 2; | |
2148 while ( aDom[i+j] != cNext ) | |
2149 { | |
2150 sAttr += aDom[i+j]; | |
2151 j++; | |
2152 } | |
2153 | |
2154 /* Replace jQuery UI constants @todo depreciated */ | |
2155 if ( sAttr == "H" ) | |
2156 { | |
2157 sAttr = classes.sJUIHeader; | |
2158 } | |
2159 else if ( sAttr == "F" ) | |
2160 { | |
2161 sAttr = classes.sJUIFooter; | |
2162 } | |
2163 | |
2164 /* The attribute can be in the format of "#id.class", "#id" or "class" This logic | |
2165 * breaks the string into parts and applies them as needed | |
2166 */ | |
2167 if ( sAttr.indexOf('.') != -1 ) | |
2168 { | |
2169 var aSplit = sAttr.split('.'); | |
2170 nNewNode.id = aSplit[0].substr(1, aSplit[0].length-1); | |
2171 nNewNode.className = aSplit[1]; | |
2172 } | |
2173 else if ( sAttr.charAt(0) == "#" ) | |
2174 { | |
2175 nNewNode.id = sAttr.substr(1, sAttr.length-1); | |
2176 } | |
2177 else | |
2178 { | |
2179 nNewNode.className = sAttr; | |
2180 } | |
2181 | |
2182 i += j; /* Move along the position array */ | |
2183 } | |
2184 | |
2185 insert.append( nNewNode ); | |
2186 insert = $(nNewNode); | |
2187 } | |
2188 else if ( cOption == '>' ) | |
2189 { | |
2190 /* End container div */ | |
2191 insert = insert.parent(); | |
2192 } | |
2193 // @todo Move options into their own plugins? | |
2194 else if ( cOption == 'l' && features.bPaginate && features.bLengthChange ) | |
2195 { | |
2196 /* Length */ | |
2197 featureNode = _fnFeatureHtmlLength( oSettings ); | |
2198 } | |
2199 else if ( cOption == 'f' && features.bFilter ) | |
2200 { | |
2201 /* Filter */ | |
2202 featureNode = _fnFeatureHtmlFilter( oSettings ); | |
2203 } | |
2204 else if ( cOption == 'r' && features.bProcessing ) | |
2205 { | |
2206 /* pRocessing */ | |
2207 featureNode = _fnFeatureHtmlProcessing( oSettings ); | |
2208 } | |
2209 else if ( cOption == 't' ) | |
2210 { | |
2211 /* Table */ | |
2212 featureNode = _fnFeatureHtmlTable( oSettings ); | |
2213 } | |
2214 else if ( cOption == 'i' && features.bInfo ) | |
2215 { | |
2216 /* Info */ | |
2217 featureNode = _fnFeatureHtmlInfo( oSettings ); | |
2218 } | |
2219 else if ( cOption == 'p' && features.bPaginate ) | |
2220 { | |
2221 /* Pagination */ | |
2222 featureNode = _fnFeatureHtmlPaginate( oSettings ); | |
2223 } | |
2224 else if ( DataTable.ext.feature.length !== 0 ) | |
2225 { | |
2226 /* Plug-in features */ | |
2227 var aoFeatures = DataTable.ext.feature; | |
2228 for ( var k=0, kLen=aoFeatures.length ; k<kLen ; k++ ) | |
2229 { | |
2230 if ( cOption == aoFeatures[k].cFeature ) | |
2231 { | |
2232 featureNode = aoFeatures[k].fnInit( oSettings ); | |
2233 break; | |
2234 } | |
2235 } | |
2236 } | |
2237 | |
2238 /* Add to the 2D features array */ | |
2239 if ( featureNode ) | |
2240 { | |
2241 var aanFeatures = oSettings.aanFeatures; | |
2242 | |
2243 if ( ! aanFeatures[cOption] ) | |
2244 { | |
2245 aanFeatures[cOption] = []; | |
2246 } | |
2247 | |
2248 aanFeatures[cOption].push( featureNode ); | |
2249 insert.append( featureNode ); | |
2250 } | |
2251 } | |
2252 | |
2253 /* Built our DOM structure - replace the holding div with what we want */ | |
2254 holding.replaceWith( insert ); | |
2255 } | |
2256 | |
2257 | |
2258 /** | |
2259 * Use the DOM source to create up an array of header cells. The idea here is to | |
2260 * create a layout grid (array) of rows x columns, which contains a reference | |
2261 * to the cell that that point in the grid (regardless of col/rowspan), such that | |
2262 * any column / row could be removed and the new grid constructed | |
2263 * @param array {object} aLayout Array to store the calculated layout in | |
2264 * @param {node} nThead The header/footer element for the table | |
2265 * @memberof DataTable#oApi | |
2266 */ | |
2267 function _fnDetectHeader ( aLayout, nThead ) | |
2268 { | |
2269 var nTrs = $(nThead).children('tr'); | |
2270 var nTr, nCell; | |
2271 var i, k, l, iLen, jLen, iColShifted, iColumn, iColspan, iRowspan; | |
2272 var bUnique; | |
2273 var fnShiftCol = function ( a, i, j ) { | |
2274 var k = a[i]; | |
2275 while ( k[j] ) { | |
2276 j++; | |
2277 } | |
2278 return j; | |
2279 }; | |
2280 | |
2281 aLayout.splice( 0, aLayout.length ); | |
2282 | |
2283 /* We know how many rows there are in the layout - so prep it */ | |
2284 for ( i=0, iLen=nTrs.length ; i<iLen ; i++ ) | |
2285 { | |
2286 aLayout.push( [] ); | |
2287 } | |
2288 | |
2289 /* Calculate a layout array */ | |
2290 for ( i=0, iLen=nTrs.length ; i<iLen ; i++ ) | |
2291 { | |
2292 nTr = nTrs[i]; | |
2293 iColumn = 0; | |
2294 | |
2295 /* For every cell in the row... */ | |
2296 nCell = nTr.firstChild; | |
2297 while ( nCell ) { | |
2298 if ( nCell.nodeName.toUpperCase() == "TD" || | |
2299 nCell.nodeName.toUpperCase() == "TH" ) | |
2300 { | |
2301 /* Get the col and rowspan attributes from the DOM and sanitise them */ | |
2302 iColspan = nCell.getAttribute('colspan') * 1; | |
2303 iRowspan = nCell.getAttribute('rowspan') * 1; | |
2304 iColspan = (!iColspan || iColspan===0 || iColspan===1) ? 1 : iColspan; | |
2305 iRowspan = (!iRowspan || iRowspan===0 || iRowspan===1) ? 1 : iRowspan; | |
2306 | |
2307 /* There might be colspan cells already in this row, so shift our target | |
2308 * accordingly | |
2309 */ | |
2310 iColShifted = fnShiftCol( aLayout, i, iColumn ); | |
2311 | |
2312 /* Cache calculation for unique columns */ | |
2313 bUnique = iColspan === 1 ? true : false; | |
2314 | |
2315 /* If there is col / rowspan, copy the information into the layout grid */ | |
2316 for ( l=0 ; l<iColspan ; l++ ) | |
2317 { | |
2318 for ( k=0 ; k<iRowspan ; k++ ) | |
2319 { | |
2320 aLayout[i+k][iColShifted+l] = { | |
2321 "cell": nCell, | |
2322 "unique": bUnique | |
2323 }; | |
2324 aLayout[i+k].nTr = nTr; | |
2325 } | |
2326 } | |
2327 } | |
2328 nCell = nCell.nextSibling; | |
2329 } | |
2330 } | |
2331 } | |
2332 | |
2333 | |
2334 /** | |
2335 * Get an array of unique th elements, one for each column | |
2336 * @param {object} oSettings dataTables settings object | |
2337 * @param {node} nHeader automatically detect the layout from this node - optional | |
2338 * @param {array} aLayout thead/tfoot layout from _fnDetectHeader - optional | |
2339 * @returns array {node} aReturn list of unique th's | |
2340 * @memberof DataTable#oApi | |
2341 */ | |
2342 function _fnGetUniqueThs ( oSettings, nHeader, aLayout ) | |
2343 { | |
2344 var aReturn = []; | |
2345 if ( !aLayout ) | |
2346 { | |
2347 aLayout = oSettings.aoHeader; | |
2348 if ( nHeader ) | |
2349 { | |
2350 aLayout = []; | |
2351 _fnDetectHeader( aLayout, nHeader ); | |
2352 } | |
2353 } | |
2354 | |
2355 for ( var i=0, iLen=aLayout.length ; i<iLen ; i++ ) | |
2356 { | |
2357 for ( var j=0, jLen=aLayout[i].length ; j<jLen ; j++ ) | |
2358 { | |
2359 if ( aLayout[i][j].unique && | |
2360 (!aReturn[j] || !oSettings.bSortCellsTop) ) | |
2361 { | |
2362 aReturn[j] = aLayout[i][j].cell; | |
2363 } | |
2364 } | |
2365 } | |
2366 | |
2367 return aReturn; | |
2368 } | |
2369 | |
2370 | |
2371 | |
2372 /** | |
2373 * Create an Ajax call based on the table's settings, taking into account that | |
2374 * parameters can have multiple forms, and backwards compatibility. | |
2375 * | |
2376 * @param {object} oSettings dataTables settings object | |
2377 * @param {array} data Data to send to the server, required by | |
2378 * DataTables - may be augmented by developer callbacks | |
2379 * @param {function} fn Callback function to run when data is obtained | |
2380 */ | |
2381 function _fnBuildAjax( oSettings, data, fn ) | |
2382 { | |
2383 // Compatibility with 1.9-, allow fnServerData and event to manipulate | |
2384 _fnCallbackFire( oSettings, 'aoServerParams', 'serverParams', [data] ); | |
2385 | |
2386 // Convert to object based for 1.10+ if using the old array scheme which can | |
2387 // come from server-side processing or serverParams | |
2388 if ( data && $.isArray(data) ) { | |
2389 var tmp = {}; | |
2390 var rbracket = /(.*?)\[\]$/; | |
2391 | |
2392 $.each( data, function (key, val) { | |
2393 var match = val.name.match(rbracket); | |
2394 | |
2395 if ( match ) { | |
2396 // Support for arrays | |
2397 var name = match[0]; | |
2398 | |
2399 if ( ! tmp[ name ] ) { | |
2400 tmp[ name ] = []; | |
2401 } | |
2402 tmp[ name ].push( val.value ); | |
2403 } | |
2404 else { | |
2405 tmp[val.name] = val.value; | |
2406 } | |
2407 } ); | |
2408 data = tmp; | |
2409 } | |
2410 | |
2411 var ajaxData; | |
2412 var ajax = oSettings.ajax; | |
2413 var instance = oSettings.oInstance; | |
2414 | |
2415 if ( $.isPlainObject( ajax ) && ajax.data ) | |
2416 { | |
2417 ajaxData = ajax.data; | |
2418 | |
2419 var newData = $.isFunction( ajaxData ) ? | |
2420 ajaxData( data ) : // fn can manipulate data or return an object | |
2421 ajaxData; // object or array to merge | |
2422 | |
2423 // If the function returned an object, use that alone | |
2424 data = $.isFunction( ajaxData ) && newData ? | |
2425 newData : | |
2426 $.extend( true, data, newData ); | |
2427 | |
2428 // Remove the data property as we've resolved it already and don't want | |
2429 // jQuery to do it again (it is restored at the end of the function) | |
2430 delete ajax.data; | |
2431 } | |
2432 | |
2433 var baseAjax = { | |
2434 "data": data, | |
2435 "success": function (json) { | |
2436 var error = json.error || json.sError; | |
2437 if ( error ) { | |
2438 oSettings.oApi._fnLog( oSettings, 0, error ); | |
2439 } | |
2440 | |
2441 oSettings.json = json; | |
2442 _fnCallbackFire( oSettings, null, 'xhr', [oSettings, json] ); | |
2443 fn( json ); | |
2444 }, | |
2445 "dataType": "json", | |
2446 "cache": false, | |
2447 "type": oSettings.sServerMethod, | |
2448 "error": function (xhr, error, thrown) { | |
2449 var log = oSettings.oApi._fnLog; | |
2450 | |
2451 if ( error == "parsererror" ) { | |
2452 log( oSettings, 0, 'Invalid JSON response', 1 ); | |
2453 } | |
2454 else if ( xhr.readyState === 4 ) { | |
2455 log( oSettings, 0, 'Ajax error', 7 ); | |
2456 } | |
2457 | |
2458 _fnProcessingDisplay( oSettings, false ); | |
2459 } | |
2460 }; | |
2461 | |
2462 // Store the data submitted for the API | |
2463 oSettings.oAjaxData = data; | |
2464 | |
2465 // Allow plug-ins and external processes to modify the data | |
2466 _fnCallbackFire( oSettings, null, 'preXhr', [oSettings, data] ); | |
2467 | |
2468 if ( oSettings.fnServerData ) | |
2469 { | |
2470 // DataTables 1.9- compatibility | |
2471 oSettings.fnServerData.call( instance, | |
2472 oSettings.sAjaxSource, | |
2473 $.map( data, function (val, key) { // Need to convert back to 1.9 trad format | |
2474 return { name: key, value: val }; | |
2475 } ), | |
2476 fn, | |
2477 oSettings | |
2478 ); | |
2479 } | |
2480 else if ( oSettings.sAjaxSource || typeof ajax === 'string' ) | |
2481 { | |
2482 // DataTables 1.9- compatibility | |
2483 oSettings.jqXHR = $.ajax( $.extend( baseAjax, { | |
2484 url: ajax || oSettings.sAjaxSource | |
2485 } ) ); | |
2486 } | |
2487 else if ( $.isFunction( ajax ) ) | |
2488 { | |
2489 // Is a function - let the caller define what needs to be done | |
2490 oSettings.jqXHR = ajax.call( instance, data, fn, oSettings ); | |
2491 } | |
2492 else | |
2493 { | |
2494 // Object to extend the base settings | |
2495 oSettings.jqXHR = $.ajax( $.extend( baseAjax, ajax ) ); | |
2496 | |
2497 // Restore for next time around | |
2498 ajax.data = ajaxData; | |
2499 } | |
2500 } | |
2501 | |
2502 | |
2503 /** | |
2504 * Update the table using an Ajax call | |
2505 * @param {object} settings dataTables settings object | |
2506 * @returns {boolean} Block the table drawing or not | |
2507 * @memberof DataTable#oApi | |
2508 */ | |
2509 function _fnAjaxUpdate( settings ) | |
2510 { | |
2511 if ( settings.bAjaxDataGet ) { | |
2512 settings.iDraw++; | |
2513 _fnProcessingDisplay( settings, true ); | |
2514 | |
2515 _fnBuildAjax( | |
2516 settings, | |
2517 _fnAjaxParameters( settings ), | |
2518 function(json) { | |
2519 _fnAjaxUpdateDraw( settings, json ); | |
2520 } | |
2521 ); | |
2522 | |
2523 return false; | |
2524 } | |
2525 return true; | |
2526 } | |
2527 | |
2528 | |
2529 /** | |
2530 * Build up the parameters in an object needed for a server-side processing | |
2531 * request. Note that this is basically done twice, is different ways - a modern | |
2532 * method which is used by default in DataTables 1.10 which uses objects and | |
2533 * arrays, or the 1.9- method with is name / value pairs. 1.9 method is used if | |
2534 * the sAjaxSource option is used in the initialisation, or the legacyAjax | |
2535 * option is set. | |
2536 * @param {object} oSettings dataTables settings object | |
2537 * @returns {bool} block the table drawing or not | |
2538 * @memberof DataTable#oApi | |
2539 */ | |
2540 function _fnAjaxParameters( settings ) | |
2541 { | |
2542 var | |
2543 columns = settings.aoColumns, | |
2544 columnCount = columns.length, | |
2545 features = settings.oFeatures, | |
2546 preSearch = settings.oPreviousSearch, | |
2547 preColSearch = settings.aoPreSearchCols, | |
2548 i, data = [], dataProp, column, columnSearch, | |
2549 sort = _fnSortFlatten( settings ), | |
2550 displayStart = settings._iDisplayStart, | |
2551 displayLength = features.bPaginate !== false ? | |
2552 settings._iDisplayLength : | |
2553 -1; | |
2554 | |
2555 var param = function ( name, value ) { | |
2556 data.push( { 'name': name, 'value': value } ); | |
2557 }; | |
2558 | |
2559 // DataTables 1.9- compatible method | |
2560 param( 'sEcho', settings.iDraw ); | |
2561 param( 'iColumns', columnCount ); | |
2562 param( 'sColumns', _pluck( columns, 'sName' ).join(',') ); | |
2563 param( 'iDisplayStart', displayStart ); | |
2564 param( 'iDisplayLength', displayLength ); | |
2565 | |
2566 // DataTables 1.10+ method | |
2567 var d = { | |
2568 draw: settings.iDraw, | |
2569 columns: [], | |
2570 order: [], | |
2571 start: displayStart, | |
2572 length: displayLength, | |
2573 search: { | |
2574 value: preSearch.sSearch, | |
2575 regex: preSearch.bRegex | |
2576 } | |
2577 }; | |
2578 | |
2579 for ( i=0 ; i<columnCount ; i++ ) { | |
2580 column = columns[i]; | |
2581 columnSearch = preColSearch[i]; | |
2582 dataProp = typeof column.mData=="function" ? 'function' : column.mData ; | |
2583 | |
2584 d.columns.push( { | |
2585 data: dataProp, | |
2586 name: column.sName, | |
2587 searchable: column.bSearchable, | |
2588 orderable: column.bSortable, | |
2589 search: { | |
2590 value: columnSearch.sSearch, | |
2591 regex: columnSearch.bRegex | |
2592 } | |
2593 } ); | |
2594 | |
2595 param( "mDataProp_"+i, dataProp ); | |
2596 | |
2597 if ( features.bFilter ) { | |
2598 param( 'sSearch_'+i, columnSearch.sSearch ); | |
2599 param( 'bRegex_'+i, columnSearch.bRegex ); | |
2600 param( 'bSearchable_'+i, column.bSearchable ); | |
2601 } | |
2602 | |
2603 if ( features.bSort ) { | |
2604 param( 'bSortable_'+i, column.bSortable ); | |
2605 } | |
2606 } | |
2607 | |
2608 if ( features.bFilter ) { | |
2609 param( 'sSearch', preSearch.sSearch ); | |
2610 param( 'bRegex', preSearch.bRegex ); | |
2611 } | |
2612 | |
2613 if ( features.bSort ) { | |
2614 $.each( sort, function ( i, val ) { | |
2615 d.order.push( { column: val.col, dir: val.dir } ); | |
2616 | |
2617 param( 'iSortCol_'+i, val.col ); | |
2618 param( 'sSortDir_'+i, val.dir ); | |
2619 } ); | |
2620 | |
2621 param( 'iSortingCols', sort.length ); | |
2622 } | |
2623 | |
2624 // If the legacy.ajax parameter is null, then we automatically decide which | |
2625 // form to use, based on sAjaxSource | |
2626 var legacy = DataTable.ext.legacy.ajax; | |
2627 if ( legacy === null ) { | |
2628 return settings.sAjaxSource ? data : d; | |
2629 } | |
2630 | |
2631 // Otherwise, if legacy has been specified then we use that to decide on the | |
2632 // form | |
2633 return legacy ? data : d; | |
2634 } | |
2635 | |
2636 | |
2637 /** | |
2638 * Data the data from the server (nuking the old) and redraw the table | |
2639 * @param {object} oSettings dataTables settings object | |
2640 * @param {object} json json data return from the server. | |
2641 * @param {string} json.sEcho Tracking flag for DataTables to match requests | |
2642 * @param {int} json.iTotalRecords Number of records in the data set, not accounting for filtering | |
2643 * @param {int} json.iTotalDisplayRecords Number of records in the data set, accounting for filtering | |
2644 * @param {array} json.aaData The data to display on this page | |
2645 * @param {string} [json.sColumns] Column ordering (sName, comma separated) | |
2646 * @memberof DataTable#oApi | |
2647 */ | |
2648 function _fnAjaxUpdateDraw ( settings, json ) | |
2649 { | |
2650 // v1.10 uses camelCase variables, while 1.9 uses Hungarian notation. | |
2651 // Support both | |
2652 var compat = function ( old, modern ) { | |
2653 return json[old] !== undefined ? json[old] : json[modern]; | |
2654 }; | |
2655 | |
2656 var draw = compat( 'sEcho', 'draw' ); | |
2657 var recordsTotal = compat( 'iTotalRecords', 'recordsTotal' ); | |
2658 var recordsFiltered = compat( 'iTotalDisplayRecords', 'recordsFiltered' ); | |
2659 | |
2660 if ( draw ) { | |
2661 // Protect against out of sequence returns | |
2662 if ( draw*1 < settings.iDraw ) { | |
2663 return; | |
2664 } | |
2665 settings.iDraw = draw * 1; | |
2666 } | |
2667 | |
2668 _fnClearTable( settings ); | |
2669 settings._iRecordsTotal = parseInt(recordsTotal, 10); | |
2670 settings._iRecordsDisplay = parseInt(recordsFiltered, 10); | |
2671 | |
2672 var data = _fnAjaxDataSrc( settings, json ); | |
2673 for ( var i=0, ien=data.length ; i<ien ; i++ ) { | |
2674 _fnAddData( settings, data[i] ); | |
2675 } | |
2676 settings.aiDisplay = settings.aiDisplayMaster.slice(); | |
2677 | |
2678 settings.bAjaxDataGet = false; | |
2679 _fnDraw( settings ); | |
2680 | |
2681 if ( ! settings._bInitComplete ) { | |
2682 _fnInitComplete( settings, json ); | |
2683 } | |
2684 | |
2685 settings.bAjaxDataGet = true; | |
2686 _fnProcessingDisplay( settings, false ); | |
2687 } | |
2688 | |
2689 | |
2690 /** | |
2691 * Get the data from the JSON data source to use for drawing a table. Using | |
2692 * `_fnGetObjectDataFn` allows the data to be sourced from a property of the | |
2693 * source object, or from a processing function. | |
2694 * @param {object} oSettings dataTables settings object | |
2695 * @param {object} json Data source object / array from the server | |
2696 * @return {array} Array of data to use | |
2697 */ | |
2698 function _fnAjaxDataSrc ( oSettings, json ) | |
2699 { | |
2700 var dataSrc = $.isPlainObject( oSettings.ajax ) && oSettings.ajax.dataSrc !== undefined ? | |
2701 oSettings.ajax.dataSrc : | |
2702 oSettings.sAjaxDataProp; // Compatibility with 1.9-. | |
2703 | |
2704 // Compatibility with 1.9-. In order to read from aaData, check if the | |
2705 // default has been changed, if not, check for aaData | |
2706 if ( dataSrc === 'data' ) { | |
2707 return json.aaData || json[dataSrc]; | |
2708 } | |
2709 | |
2710 return dataSrc !== "" ? | |
2711 _fnGetObjectDataFn( dataSrc )( json ) : | |
2712 json; | |
2713 } | |
2714 | |
2715 | |
2716 /** | |
2717 * Generate the node required for filtering text | |
2718 * @returns {node} Filter control element | |
2719 * @param {object} oSettings dataTables settings object | |
2720 * @memberof DataTable#oApi | |
2721 */ | |
2722 function _fnFeatureHtmlFilter ( settings ) | |
2723 { | |
2724 var classes = settings.oClasses; | |
2725 var tableId = settings.sTableId; | |
2726 var language = settings.oLanguage; | |
2727 var previousSearch = settings.oPreviousSearch; | |
2728 var features = settings.aanFeatures; | |
2729 var input = '<input type="search" class="'+classes.sFilterInput+'"/>'; | |
2730 | |
2731 var str = language.sSearch; | |
2732 str = str.match(/_INPUT_/) ? | |
2733 str.replace('_INPUT_', input) : | |
2734 str+input; | |
2735 | |
2736 var filter = $('<div/>', { | |
2737 'id': ! features.f ? tableId+'_filter' : null, | |
2738 'class': classes.sFilter | |
2739 } ) | |
2740 .append( $('<label/>' ).append( str ) ); | |
2741 | |
2742 var searchFn = function() { | |
2743 /* Update all other filter input elements for the new display */ | |
2744 var n = features.f; | |
2745 var val = !this.value ? "" : this.value; // mental IE8 fix :-( | |
2746 | |
2747 /* Now do the filter */ | |
2748 if ( val != previousSearch.sSearch ) { | |
2749 _fnFilterComplete( settings, { | |
2750 "sSearch": val, | |
2751 "bRegex": previousSearch.bRegex, | |
2752 "bSmart": previousSearch.bSmart , | |
2753 "bCaseInsensitive": previousSearch.bCaseInsensitive | |
2754 } ); | |
2755 | |
2756 // Need to redraw, without resorting | |
2757 settings._iDisplayStart = 0; | |
2758 _fnDraw( settings ); | |
2759 } | |
2760 }; | |
2761 | |
2762 var searchDelay = settings.searchDelay !== null ? | |
2763 settings.searchDelay : | |
2764 _fnDataSource( settings ) === 'ssp' ? | |
2765 400 : | |
2766 0; | |
2767 | |
2768 var jqFilter = $('input', filter) | |
2769 .val( previousSearch.sSearch ) | |
2770 .attr( 'placeholder', language.sSearchPlaceholder ) | |
2771 .bind( | |
2772 'keyup.DT search.DT input.DT paste.DT cut.DT', | |
2773 searchDelay ? | |
2774 _fnThrottle( searchFn, searchDelay ) : | |
2775 searchFn | |
2776 ) | |
2777 .bind( 'keypress.DT', function(e) { | |
2778 /* Prevent form submission */ | |
2779 if ( e.keyCode == 13 ) { | |
2780 return false; | |
2781 } | |
2782 } ) | |
2783 .attr('aria-controls', tableId); | |
2784 | |
2785 // Update the input elements whenever the table is filtered | |
2786 $(settings.nTable).on( 'search.dt.DT', function ( ev, s ) { | |
2787 if ( settings === s ) { | |
2788 // IE9 throws an 'unknown error' if document.activeElement is used | |
2789 // inside an iframe or frame... | |
2790 try { | |
2791 if ( jqFilter[0] !== document.activeElement ) { | |
2792 jqFilter.val( previousSearch.sSearch ); | |
2793 } | |
2794 } | |
2795 catch ( e ) {} | |
2796 } | |
2797 } ); | |
2798 | |
2799 return filter[0]; | |
2800 } | |
2801 | |
2802 | |
2803 /** | |
2804 * Filter the table using both the global filter and column based filtering | |
2805 * @param {object} oSettings dataTables settings object | |
2806 * @param {object} oSearch search information | |
2807 * @param {int} [iForce] force a research of the master array (1) or not (undefined or 0) | |
2808 * @memberof DataTable#oApi | |
2809 */ | |
2810 function _fnFilterComplete ( oSettings, oInput, iForce ) | |
2811 { | |
2812 var oPrevSearch = oSettings.oPreviousSearch; | |
2813 var aoPrevSearch = oSettings.aoPreSearchCols; | |
2814 var fnSaveFilter = function ( oFilter ) { | |
2815 /* Save the filtering values */ | |
2816 oPrevSearch.sSearch = oFilter.sSearch; | |
2817 oPrevSearch.bRegex = oFilter.bRegex; | |
2818 oPrevSearch.bSmart = oFilter.bSmart; | |
2819 oPrevSearch.bCaseInsensitive = oFilter.bCaseInsensitive; | |
2820 }; | |
2821 var fnRegex = function ( o ) { | |
2822 // Backwards compatibility with the bEscapeRegex option | |
2823 return o.bEscapeRegex !== undefined ? !o.bEscapeRegex : o.bRegex; | |
2824 }; | |
2825 | |
2826 // Resolve any column types that are unknown due to addition or invalidation | |
2827 // @todo As per sort - can this be moved into an event handler? | |
2828 _fnColumnTypes( oSettings ); | |
2829 | |
2830 /* In server-side processing all filtering is done by the server, so no point hanging around here */ | |
2831 if ( _fnDataSource( oSettings ) != 'ssp' ) | |
2832 { | |
2833 /* Global filter */ | |
2834 _fnFilter( oSettings, oInput.sSearch, iForce, fnRegex(oInput), oInput.bSmart, oInput.bCaseInsensitive ); | |
2835 fnSaveFilter( oInput ); | |
2836 | |
2837 /* Now do the individual column filter */ | |
2838 for ( var i=0 ; i<aoPrevSearch.length ; i++ ) | |
2839 { | |
2840 _fnFilterColumn( oSettings, aoPrevSearch[i].sSearch, i, fnRegex(aoPrevSearch[i]), | |
2841 aoPrevSearch[i].bSmart, aoPrevSearch[i].bCaseInsensitive ); | |
2842 } | |
2843 | |
2844 /* Custom filtering */ | |
2845 _fnFilterCustom( oSettings ); | |
2846 } | |
2847 else | |
2848 { | |
2849 fnSaveFilter( oInput ); | |
2850 } | |
2851 | |
2852 /* Tell the draw function we have been filtering */ | |
2853 oSettings.bFiltered = true; | |
2854 _fnCallbackFire( oSettings, null, 'search', [oSettings] ); | |
2855 } | |
2856 | |
2857 | |
2858 /** | |
2859 * Apply custom filtering functions | |
2860 * @param {object} oSettings dataTables settings object | |
2861 * @memberof DataTable#oApi | |
2862 */ | |
2863 function _fnFilterCustom( settings ) | |
2864 { | |
2865 var filters = DataTable.ext.search; | |
2866 var displayRows = settings.aiDisplay; | |
2867 var row, rowIdx; | |
2868 | |
2869 for ( var i=0, ien=filters.length ; i<ien ; i++ ) { | |
2870 var rows = []; | |
2871 | |
2872 // Loop over each row and see if it should be included | |
2873 for ( var j=0, jen=displayRows.length ; j<jen ; j++ ) { | |
2874 rowIdx = displayRows[ j ]; | |
2875 row = settings.aoData[ rowIdx ]; | |
2876 | |
2877 if ( filters[i]( settings, row._aFilterData, rowIdx, row._aData, j ) ) { | |
2878 rows.push( rowIdx ); | |
2879 } | |
2880 } | |
2881 | |
2882 // So the array reference doesn't break set the results into the | |
2883 // existing array | |
2884 displayRows.length = 0; | |
2885 displayRows.push.apply( displayRows, rows ); | |
2886 } | |
2887 } | |
2888 | |
2889 | |
2890 /** | |
2891 * Filter the table on a per-column basis | |
2892 * @param {object} oSettings dataTables settings object | |
2893 * @param {string} sInput string to filter on | |
2894 * @param {int} iColumn column to filter | |
2895 * @param {bool} bRegex treat search string as a regular expression or not | |
2896 * @param {bool} bSmart use smart filtering or not | |
2897 * @param {bool} bCaseInsensitive Do case insenstive matching or not | |
2898 * @memberof DataTable#oApi | |
2899 */ | |
2900 function _fnFilterColumn ( settings, searchStr, colIdx, regex, smart, caseInsensitive ) | |
2901 { | |
2902 if ( searchStr === '' ) { | |
2903 return; | |
2904 } | |
2905 | |
2906 var data; | |
2907 var display = settings.aiDisplay; | |
2908 var rpSearch = _fnFilterCreateSearch( searchStr, regex, smart, caseInsensitive ); | |
2909 | |
2910 for ( var i=display.length-1 ; i>=0 ; i-- ) { | |
2911 data = settings.aoData[ display[i] ]._aFilterData[ colIdx ]; | |
2912 | |
2913 if ( ! rpSearch.test( data ) ) { | |
2914 display.splice( i, 1 ); | |
2915 } | |
2916 } | |
2917 } | |
2918 | |
2919 | |
2920 /** | |
2921 * Filter the data table based on user input and draw the table | |
2922 * @param {object} settings dataTables settings object | |
2923 * @param {string} input string to filter on | |
2924 * @param {int} force optional - force a research of the master array (1) or not (undefined or 0) | |
2925 * @param {bool} regex treat as a regular expression or not | |
2926 * @param {bool} smart perform smart filtering or not | |
2927 * @param {bool} caseInsensitive Do case insenstive matching or not | |
2928 * @memberof DataTable#oApi | |
2929 */ | |
2930 function _fnFilter( settings, input, force, regex, smart, caseInsensitive ) | |
2931 { | |
2932 var rpSearch = _fnFilterCreateSearch( input, regex, smart, caseInsensitive ); | |
2933 var prevSearch = settings.oPreviousSearch.sSearch; | |
2934 var displayMaster = settings.aiDisplayMaster; | |
2935 var display, invalidated, i; | |
2936 | |
2937 // Need to take account of custom filtering functions - always filter | |
2938 if ( DataTable.ext.search.length !== 0 ) { | |
2939 force = true; | |
2940 } | |
2941 | |
2942 // Check if any of the rows were invalidated | |
2943 invalidated = _fnFilterData( settings ); | |
2944 | |
2945 // If the input is blank - we just want the full data set | |
2946 if ( input.length <= 0 ) { | |
2947 settings.aiDisplay = displayMaster.slice(); | |
2948 } | |
2949 else { | |
2950 // New search - start from the master array | |
2951 if ( invalidated || | |
2952 force || | |
2953 prevSearch.length > input.length || | |
2954 input.indexOf(prevSearch) !== 0 || | |
2955 settings.bSorted // On resort, the display master needs to be | |
2956 // re-filtered since indexes will have changed | |
2957 ) { | |
2958 settings.aiDisplay = displayMaster.slice(); | |
2959 } | |
2960 | |
2961 // Search the display array | |
2962 display = settings.aiDisplay; | |
2963 | |
2964 for ( i=display.length-1 ; i>=0 ; i-- ) { | |
2965 if ( ! rpSearch.test( settings.aoData[ display[i] ]._sFilterRow ) ) { | |
2966 display.splice( i, 1 ); | |
2967 } | |
2968 } | |
2969 } | |
2970 } | |
2971 | |
2972 | |
2973 /** | |
2974 * Build a regular expression object suitable for searching a table | |
2975 * @param {string} sSearch string to search for | |
2976 * @param {bool} bRegex treat as a regular expression or not | |
2977 * @param {bool} bSmart perform smart filtering or not | |
2978 * @param {bool} bCaseInsensitive Do case insensitive matching or not | |
2979 * @returns {RegExp} constructed object | |
2980 * @memberof DataTable#oApi | |
2981 */ | |
2982 function _fnFilterCreateSearch( search, regex, smart, caseInsensitive ) | |
2983 { | |
2984 search = regex ? | |
2985 search : | |
2986 _fnEscapeRegex( search ); | |
2987 | |
2988 if ( smart ) { | |
2989 /* For smart filtering we want to allow the search to work regardless of | |
2990 * word order. We also want double quoted text to be preserved, so word | |
2991 * order is important - a la google. So this is what we want to | |
2992 * generate: | |
2993 * | |
2994 * ^(?=.*?\bone\b)(?=.*?\btwo three\b)(?=.*?\bfour\b).*$ | |
2995 */ | |
2996 var a = $.map( search.match( /"[^"]+"|[^ ]+/g ) || '', function ( word ) { | |
2997 if ( word.charAt(0) === '"' ) { | |
2998 var m = word.match( /^"(.*)"$/ ); | |
2999 word = m ? m[1] : word; | |
3000 } | |
3001 | |
3002 return word.replace('"', ''); | |
3003 } ); | |
3004 | |
3005 search = '^(?=.*?'+a.join( ')(?=.*?' )+').*$'; | |
3006 } | |
3007 | |
3008 return new RegExp( search, caseInsensitive ? 'i' : '' ); | |
3009 } | |
3010 | |
3011 | |
3012 /** | |
3013 * Escape a string such that it can be used in a regular expression | |
3014 * @param {string} sVal string to escape | |
3015 * @returns {string} escaped string | |
3016 * @memberof DataTable#oApi | |
3017 */ | |
3018 function _fnEscapeRegex ( sVal ) | |
3019 { | |
3020 return sVal.replace( _re_escape_regex, '\\$1' ); | |
3021 } | |
3022 | |
3023 | |
3024 | |
3025 var __filter_div = $('<div>')[0]; | |
3026 var __filter_div_textContent = __filter_div.textContent !== undefined; | |
3027 | |
3028 // Update the filtering data for each row if needed (by invalidation or first run) | |
3029 function _fnFilterData ( settings ) | |
3030 { | |
3031 var columns = settings.aoColumns; | |
3032 var column; | |
3033 var i, j, ien, jen, filterData, cellData, row; | |
3034 var fomatters = DataTable.ext.type.search; | |
3035 var wasInvalidated = false; | |
3036 | |
3037 for ( i=0, ien=settings.aoData.length ; i<ien ; i++ ) { | |
3038 row = settings.aoData[i]; | |
3039 | |
3040 if ( ! row._aFilterData ) { | |
3041 filterData = []; | |
3042 | |
3043 for ( j=0, jen=columns.length ; j<jen ; j++ ) { | |
3044 column = columns[j]; | |
3045 | |
3046 if ( column.bSearchable ) { | |
3047 cellData = _fnGetCellData( settings, i, j, 'filter' ); | |
3048 | |
3049 if ( fomatters[ column.sType ] ) { | |
3050 cellData = fomatters[ column.sType ]( cellData ); | |
3051 } | |
3052 | |
3053 // Search in DataTables 1.10 is string based. In 1.11 this | |
3054 // should be altered to also allow strict type checking. | |
3055 if ( cellData === null ) { | |
3056 cellData = ''; | |
3057 } | |
3058 | |
3059 if ( typeof cellData !== 'string' && cellData.toString ) { | |
3060 cellData = cellData.toString(); | |
3061 } | |
3062 } | |
3063 else { | |
3064 cellData = ''; | |
3065 } | |
3066 | |
3067 // If it looks like there is an HTML entity in the string, | |
3068 // attempt to decode it so sorting works as expected. Note that | |
3069 // we could use a single line of jQuery to do this, but the DOM | |
3070 // method used here is much faster http://jsperf.com/html-decode | |
3071 if ( cellData.indexOf && cellData.indexOf('&') !== -1 ) { | |
3072 __filter_div.innerHTML = cellData; | |
3073 cellData = __filter_div_textContent ? | |
3074 __filter_div.textContent : | |
3075 __filter_div.innerText; | |
3076 } | |
3077 | |
3078 if ( cellData.replace ) { | |
3079 cellData = cellData.replace(/[\r\n]/g, ''); | |
3080 } | |
3081 | |
3082 filterData.push( cellData ); | |
3083 } | |
3084 | |
3085 row._aFilterData = filterData; | |
3086 row._sFilterRow = filterData.join(' '); | |
3087 wasInvalidated = true; | |
3088 } | |
3089 } | |
3090 | |
3091 return wasInvalidated; | |
3092 } | |
3093 | |
3094 | |
3095 /** | |
3096 * Convert from the internal Hungarian notation to camelCase for external | |
3097 * interaction | |
3098 * @param {object} obj Object to convert | |
3099 * @returns {object} Inverted object | |
3100 * @memberof DataTable#oApi | |
3101 */ | |
3102 function _fnSearchToCamel ( obj ) | |
3103 { | |
3104 return { | |
3105 search: obj.sSearch, | |
3106 smart: obj.bSmart, | |
3107 regex: obj.bRegex, | |
3108 caseInsensitive: obj.bCaseInsensitive | |
3109 }; | |
3110 } | |
3111 | |
3112 | |
3113 | |
3114 /** | |
3115 * Convert from camelCase notation to the internal Hungarian. We could use the | |
3116 * Hungarian convert function here, but this is cleaner | |
3117 * @param {object} obj Object to convert | |
3118 * @returns {object} Inverted object | |
3119 * @memberof DataTable#oApi | |
3120 */ | |
3121 function _fnSearchToHung ( obj ) | |
3122 { | |
3123 return { | |
3124 sSearch: obj.search, | |
3125 bSmart: obj.smart, | |
3126 bRegex: obj.regex, | |
3127 bCaseInsensitive: obj.caseInsensitive | |
3128 }; | |
3129 } | |
3130 | |
3131 /** | |
3132 * Generate the node required for the info display | |
3133 * @param {object} oSettings dataTables settings object | |
3134 * @returns {node} Information element | |
3135 * @memberof DataTable#oApi | |
3136 */ | |
3137 function _fnFeatureHtmlInfo ( settings ) | |
3138 { | |
3139 var | |
3140 tid = settings.sTableId, | |
3141 nodes = settings.aanFeatures.i, | |
3142 n = $('<div/>', { | |
3143 'class': settings.oClasses.sInfo, | |
3144 'id': ! nodes ? tid+'_info' : null | |
3145 } ); | |
3146 | |
3147 if ( ! nodes ) { | |
3148 // Update display on each draw | |
3149 settings.aoDrawCallback.push( { | |
3150 "fn": _fnUpdateInfo, | |
3151 "sName": "information" | |
3152 } ); | |
3153 | |
3154 n | |
3155 .attr( 'role', 'status' ) | |
3156 .attr( 'aria-live', 'polite' ); | |
3157 | |
3158 // Table is described by our info div | |
3159 $(settings.nTable).attr( 'aria-describedby', tid+'_info' ); | |
3160 } | |
3161 | |
3162 return n[0]; | |
3163 } | |
3164 | |
3165 | |
3166 /** | |
3167 * Update the information elements in the display | |
3168 * @param {object} settings dataTables settings object | |
3169 * @memberof DataTable#oApi | |
3170 */ | |
3171 function _fnUpdateInfo ( settings ) | |
3172 { | |
3173 /* Show information about the table */ | |
3174 var nodes = settings.aanFeatures.i; | |
3175 if ( nodes.length === 0 ) { | |
3176 return; | |
3177 } | |
3178 | |
3179 var | |
3180 lang = settings.oLanguage, | |
3181 start = settings._iDisplayStart+1, | |
3182 end = settings.fnDisplayEnd(), | |
3183 max = settings.fnRecordsTotal(), | |
3184 total = settings.fnRecordsDisplay(), | |
3185 out = total ? | |
3186 lang.sInfo : | |
3187 lang.sInfoEmpty; | |
3188 | |
3189 if ( total !== max ) { | |
3190 /* Record set after filtering */ | |
3191 out += ' ' + lang.sInfoFiltered; | |
3192 } | |
3193 | |
3194 // Convert the macros | |
3195 out += lang.sInfoPostFix; | |
3196 out = _fnInfoMacros( settings, out ); | |
3197 | |
3198 var callback = lang.fnInfoCallback; | |
3199 if ( callback !== null ) { | |
3200 out = callback.call( settings.oInstance, | |
3201 settings, start, end, max, total, out | |
3202 ); | |
3203 } | |
3204 | |
3205 $(nodes).html( out ); | |
3206 } | |
3207 | |
3208 | |
3209 function _fnInfoMacros ( settings, str ) | |
3210 { | |
3211 // When infinite scrolling, we are always starting at 1. _iDisplayStart is used only | |
3212 // internally | |
3213 var | |
3214 formatter = settings.fnFormatNumber, | |
3215 start = settings._iDisplayStart+1, | |
3216 len = settings._iDisplayLength, | |
3217 vis = settings.fnRecordsDisplay(), | |
3218 all = len === -1; | |
3219 | |
3220 return str. | |
3221 replace(/_START_/g, formatter.call( settings, start ) ). | |
3222 replace(/_END_/g, formatter.call( settings, settings.fnDisplayEnd() ) ). | |
3223 replace(/_MAX_/g, formatter.call( settings, settings.fnRecordsTotal() ) ). | |
3224 replace(/_TOTAL_/g, formatter.call( settings, vis ) ). | |
3225 replace(/_PAGE_/g, formatter.call( settings, all ? 1 : Math.ceil( start / len ) ) ). | |
3226 replace(/_PAGES_/g, formatter.call( settings, all ? 1 : Math.ceil( vis / len ) ) ); | |
3227 } | |
3228 | |
3229 | |
3230 | |
3231 /** | |
3232 * Draw the table for the first time, adding all required features | |
3233 * @param {object} settings dataTables settings object | |
3234 * @memberof DataTable#oApi | |
3235 */ | |
3236 function _fnInitialise ( settings ) | |
3237 { | |
3238 var i, iLen, iAjaxStart=settings.iInitDisplayStart; | |
3239 var columns = settings.aoColumns, column; | |
3240 var features = settings.oFeatures; | |
3241 | |
3242 /* Ensure that the table data is fully initialised */ | |
3243 if ( ! settings.bInitialised ) { | |
3244 setTimeout( function(){ _fnInitialise( settings ); }, 200 ); | |
3245 return; | |
3246 } | |
3247 | |
3248 /* Show the display HTML options */ | |
3249 _fnAddOptionsHtml( settings ); | |
3250 | |
3251 /* Build and draw the header / footer for the table */ | |
3252 _fnBuildHead( settings ); | |
3253 _fnDrawHead( settings, settings.aoHeader ); | |
3254 _fnDrawHead( settings, settings.aoFooter ); | |
3255 | |
3256 /* Okay to show that something is going on now */ | |
3257 _fnProcessingDisplay( settings, true ); | |
3258 | |
3259 /* Calculate sizes for columns */ | |
3260 if ( features.bAutoWidth ) { | |
3261 _fnCalculateColumnWidths( settings ); | |
3262 } | |
3263 | |
3264 for ( i=0, iLen=columns.length ; i<iLen ; i++ ) { | |
3265 column = columns[i]; | |
3266 | |
3267 if ( column.sWidth ) { | |
3268 column.nTh.style.width = _fnStringToCss( column.sWidth ); | |
3269 } | |
3270 } | |
3271 | |
3272 // If there is default sorting required - let's do it. The sort function | |
3273 // will do the drawing for us. Otherwise we draw the table regardless of the | |
3274 // Ajax source - this allows the table to look initialised for Ajax sourcing | |
3275 // data (show 'loading' message possibly) | |
3276 _fnReDraw( settings ); | |
3277 | |
3278 // Server-side processing init complete is done by _fnAjaxUpdateDraw | |
3279 var dataSrc = _fnDataSource( settings ); | |
3280 if ( dataSrc != 'ssp' ) { | |
3281 // if there is an ajax source load the data | |
3282 if ( dataSrc == 'ajax' ) { | |
3283 _fnBuildAjax( settings, [], function(json) { | |
3284 var aData = _fnAjaxDataSrc( settings, json ); | |
3285 | |
3286 // Got the data - add it to the table | |
3287 for ( i=0 ; i<aData.length ; i++ ) { | |
3288 _fnAddData( settings, aData[i] ); | |
3289 } | |
3290 | |
3291 // Reset the init display for cookie saving. We've already done | |
3292 // a filter, and therefore cleared it before. So we need to make | |
3293 // it appear 'fresh' | |
3294 settings.iInitDisplayStart = iAjaxStart; | |
3295 | |
3296 _fnReDraw( settings ); | |
3297 | |
3298 _fnProcessingDisplay( settings, false ); | |
3299 _fnInitComplete( settings, json ); | |
3300 }, settings ); | |
3301 } | |
3302 else { | |
3303 _fnProcessingDisplay( settings, false ); | |
3304 _fnInitComplete( settings ); | |
3305 } | |
3306 } | |
3307 } | |
3308 | |
3309 | |
3310 /** | |
3311 * Draw the table for the first time, adding all required features | |
3312 * @param {object} oSettings dataTables settings object | |
3313 * @param {object} [json] JSON from the server that completed the table, if using Ajax source | |
3314 * with client-side processing (optional) | |
3315 * @memberof DataTable#oApi | |
3316 */ | |
3317 function _fnInitComplete ( settings, json ) | |
3318 { | |
3319 settings._bInitComplete = true; | |
3320 | |
3321 // On an Ajax load we now have data and therefore want to apply the column | |
3322 // sizing | |
3323 if ( json ) { | |
3324 _fnAdjustColumnSizing( settings ); | |
3325 } | |
3326 | |
3327 _fnCallbackFire( settings, 'aoInitComplete', 'init', [settings, json] ); | |
3328 } | |
3329 | |
3330 | |
3331 function _fnLengthChange ( settings, val ) | |
3332 { | |
3333 var len = parseInt( val, 10 ); | |
3334 settings._iDisplayLength = len; | |
3335 | |
3336 _fnLengthOverflow( settings ); | |
3337 | |
3338 // Fire length change event | |
3339 _fnCallbackFire( settings, null, 'length', [settings, len] ); | |
3340 } | |
3341 | |
3342 | |
3343 /** | |
3344 * Generate the node required for user display length changing | |
3345 * @param {object} settings dataTables settings object | |
3346 * @returns {node} Display length feature node | |
3347 * @memberof DataTable#oApi | |
3348 */ | |
3349 function _fnFeatureHtmlLength ( settings ) | |
3350 { | |
3351 var | |
3352 classes = settings.oClasses, | |
3353 tableId = settings.sTableId, | |
3354 menu = settings.aLengthMenu, | |
3355 d2 = $.isArray( menu[0] ), | |
3356 lengths = d2 ? menu[0] : menu, | |
3357 language = d2 ? menu[1] : menu; | |
3358 | |
3359 var select = $('<select/>', { | |
3360 'name': tableId+'_length', | |
3361 'aria-controls': tableId, | |
3362 'class': classes.sLengthSelect | |
3363 } ); | |
3364 | |
3365 for ( var i=0, ien=lengths.length ; i<ien ; i++ ) { | |
3366 select[0][ i ] = new Option( language[i], lengths[i] ); | |
3367 } | |
3368 | |
3369 var div = $('<div><label/></div>').addClass( classes.sLength ); | |
3370 if ( ! settings.aanFeatures.l ) { | |
3371 div[0].id = tableId+'_length'; | |
3372 } | |
3373 | |
3374 div.children().append( | |
3375 settings.oLanguage.sLengthMenu.replace( '_MENU_', select[0].outerHTML ) | |
3376 ); | |
3377 | |
3378 // Can't use `select` variable as user might provide their own and the | |
3379 // reference is broken by the use of outerHTML | |
3380 $('select', div) | |
3381 .val( settings._iDisplayLength ) | |
3382 .bind( 'change.DT', function(e) { | |
3383 _fnLengthChange( settings, $(this).val() ); | |
3384 _fnDraw( settings ); | |
3385 } ); | |
3386 | |
3387 // Update node value whenever anything changes the table's length | |
3388 $(settings.nTable).bind( 'length.dt.DT', function (e, s, len) { | |
3389 if ( settings === s ) { | |
3390 $('select', div).val( len ); | |
3391 } | |
3392 } ); | |
3393 | |
3394 return div[0]; | |
3395 } | |
3396 | |
3397 | |
3398 | |
3399 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * | |
3400 * Note that most of the paging logic is done in | |
3401 * DataTable.ext.pager | |
3402 */ | |
3403 | |
3404 /** | |
3405 * Generate the node required for default pagination | |
3406 * @param {object} oSettings dataTables settings object | |
3407 * @returns {node} Pagination feature node | |
3408 * @memberof DataTable#oApi | |
3409 */ | |
3410 function _fnFeatureHtmlPaginate ( settings ) | |
3411 { | |
3412 var | |
3413 type = settings.sPaginationType, | |
3414 plugin = DataTable.ext.pager[ type ], | |
3415 modern = typeof plugin === 'function', | |
3416 redraw = function( settings ) { | |
3417 _fnDraw( settings ); | |
3418 }, | |
3419 node = $('<div/>').addClass( settings.oClasses.sPaging + type )[0], | |
3420 features = settings.aanFeatures; | |
3421 | |
3422 if ( ! modern ) { | |
3423 plugin.fnInit( settings, node, redraw ); | |
3424 } | |
3425 | |
3426 /* Add a draw callback for the pagination on first instance, to update the paging display */ | |
3427 if ( ! features.p ) | |
3428 { | |
3429 node.id = settings.sTableId+'_paginate'; | |
3430 | |
3431 settings.aoDrawCallback.push( { | |
3432 "fn": function( settings ) { | |
3433 if ( modern ) { | |
3434 var | |
3435 start = settings._iDisplayStart, | |
3436 len = settings._iDisplayLength, | |
3437 visRecords = settings.fnRecordsDisplay(), | |
3438 all = len === -1, | |
3439 page = all ? 0 : Math.ceil( start / len ), | |
3440 pages = all ? 1 : Math.ceil( visRecords / len ), | |
3441 buttons = plugin(page, pages), | |
3442 i, ien; | |
3443 | |
3444 for ( i=0, ien=features.p.length ; i<ien ; i++ ) { | |
3445 _fnRenderer( settings, 'pageButton' )( | |
3446 settings, features.p[i], i, buttons, page, pages | |
3447 ); | |
3448 } | |
3449 } | |
3450 else { | |
3451 plugin.fnUpdate( settings, redraw ); | |
3452 } | |
3453 }, | |
3454 "sName": "pagination" | |
3455 } ); | |
3456 } | |
3457 | |
3458 return node; | |
3459 } | |
3460 | |
3461 | |
3462 /** | |
3463 * Alter the display settings to change the page | |
3464 * @param {object} settings DataTables settings object | |
3465 * @param {string|int} action Paging action to take: "first", "previous", | |
3466 * "next" or "last" or page number to jump to (integer) | |
3467 * @param [bool] redraw Automatically draw the update or not | |
3468 * @returns {bool} true page has changed, false - no change | |
3469 * @memberof DataTable#oApi | |
3470 */ | |
3471 function _fnPageChange ( settings, action, redraw ) | |
3472 { | |
3473 var | |
3474 start = settings._iDisplayStart, | |
3475 len = settings._iDisplayLength, | |
3476 records = settings.fnRecordsDisplay(); | |
3477 | |
3478 if ( records === 0 || len === -1 ) | |
3479 { | |
3480 start = 0; | |
3481 } | |
3482 else if ( typeof action === "number" ) | |
3483 { | |
3484 start = action * len; | |
3485 | |
3486 if ( start > records ) | |
3487 { | |
3488 start = 0; | |
3489 } | |
3490 } | |
3491 else if ( action == "first" ) | |
3492 { | |
3493 start = 0; | |
3494 } | |
3495 else if ( action == "previous" ) | |
3496 { | |
3497 start = len >= 0 ? | |
3498 start - len : | |
3499 0; | |
3500 | |
3501 if ( start < 0 ) | |
3502 { | |
3503 start = 0; | |
3504 } | |
3505 } | |
3506 else if ( action == "next" ) | |
3507 { | |
3508 if ( start + len < records ) | |
3509 { | |
3510 start += len; | |
3511 } | |
3512 } | |
3513 else if ( action == "last" ) | |
3514 { | |
3515 start = Math.floor( (records-1) / len) * len; | |
3516 } | |
3517 else | |
3518 { | |
3519 _fnLog( settings, 0, "Unknown paging action: "+action, 5 ); | |
3520 } | |
3521 | |
3522 var changed = settings._iDisplayStart !== start; | |
3523 settings._iDisplayStart = start; | |
3524 | |
3525 if ( changed ) { | |
3526 _fnCallbackFire( settings, null, 'page', [settings] ); | |
3527 | |
3528 if ( redraw ) { | |
3529 _fnDraw( settings ); | |
3530 } | |
3531 } | |
3532 | |
3533 return changed; | |
3534 } | |
3535 | |
3536 | |
3537 | |
3538 /** | |
3539 * Generate the node required for the processing node | |
3540 * @param {object} settings dataTables settings object | |
3541 * @returns {node} Processing element | |
3542 * @memberof DataTable#oApi | |
3543 */ | |
3544 function _fnFeatureHtmlProcessing ( settings ) | |
3545 { | |
3546 return $('<div/>', { | |
3547 'id': ! settings.aanFeatures.r ? settings.sTableId+'_processing' : null, | |
3548 'class': settings.oClasses.sProcessing | |
3549 } ) | |
3550 .html( settings.oLanguage.sProcessing ) | |
3551 .insertBefore( settings.nTable )[0]; | |
3552 } | |
3553 | |
3554 | |
3555 /** | |
3556 * Display or hide the processing indicator | |
3557 * @param {object} settings dataTables settings object | |
3558 * @param {bool} show Show the processing indicator (true) or not (false) | |
3559 * @memberof DataTable#oApi | |
3560 */ | |
3561 function _fnProcessingDisplay ( settings, show ) | |
3562 { | |
3563 if ( settings.oFeatures.bProcessing ) { | |
3564 $(settings.aanFeatures.r).css( 'display', show ? 'block' : 'none' ); | |
3565 } | |
3566 | |
3567 _fnCallbackFire( settings, null, 'processing', [settings, show] ); | |
3568 } | |
3569 | |
3570 /** | |
3571 * Add any control elements for the table - specifically scrolling | |
3572 * @param {object} settings dataTables settings object | |
3573 * @returns {node} Node to add to the DOM | |
3574 * @memberof DataTable#oApi | |
3575 */ | |
3576 function _fnFeatureHtmlTable ( settings ) | |
3577 { | |
3578 var table = $(settings.nTable); | |
3579 | |
3580 // Add the ARIA grid role to the table | |
3581 table.attr( 'role', 'grid' ); | |
3582 | |
3583 // Scrolling from here on in | |
3584 var scroll = settings.oScroll; | |
3585 | |
3586 if ( scroll.sX === '' && scroll.sY === '' ) { | |
3587 return settings.nTable; | |
3588 } | |
3589 | |
3590 var scrollX = scroll.sX; | |
3591 var scrollY = scroll.sY; | |
3592 var classes = settings.oClasses; | |
3593 var caption = table.children('caption'); | |
3594 var captionSide = caption.length ? caption[0]._captionSide : null; | |
3595 var headerClone = $( table[0].cloneNode(false) ); | |
3596 var footerClone = $( table[0].cloneNode(false) ); | |
3597 var footer = table.children('tfoot'); | |
3598 var _div = '<div/>'; | |
3599 var size = function ( s ) { | |
3600 return !s ? null : _fnStringToCss( s ); | |
3601 }; | |
3602 | |
3603 // This is fairly messy, but with x scrolling enabled, if the table has a | |
3604 // width attribute, regardless of any width applied using the column width | |
3605 // options, the browser will shrink or grow the table as needed to fit into | |
3606 // that 100%. That would make the width options useless. So we remove it. | |
3607 // This is okay, under the assumption that width:100% is applied to the | |
3608 // table in CSS (it is in the default stylesheet) which will set the table | |
3609 // width as appropriate (the attribute and css behave differently...) | |
3610 if ( scroll.sX && table.attr('width') === '100%' ) { | |
3611 table.removeAttr('width'); | |
3612 } | |
3613 | |
3614 if ( ! footer.length ) { | |
3615 footer = null; | |
3616 } | |
3617 | |
3618 /* | |
3619 * The HTML structure that we want to generate in this function is: | |
3620 * div - scroller | |
3621 * div - scroll head | |
3622 * div - scroll head inner | |
3623 * table - scroll head table | |
3624 * thead - thead | |
3625 * div - scroll body | |
3626 * table - table (master table) | |
3627 * thead - thead clone for sizing | |
3628 * tbody - tbody | |
3629 * div - scroll foot | |
3630 * div - scroll foot inner | |
3631 * table - scroll foot table | |
3632 * tfoot - tfoot | |
3633 */ | |
3634 var scroller = $( _div, { 'class': classes.sScrollWrapper } ) | |
3635 .append( | |
3636 $(_div, { 'class': classes.sScrollHead } ) | |
3637 .css( { | |
3638 overflow: 'hidden', | |
3639 position: 'relative', | |
3640 border: 0, | |
3641 width: scrollX ? size(scrollX) : '100%' | |
3642 } ) | |
3643 .append( | |
3644 $(_div, { 'class': classes.sScrollHeadInner } ) | |
3645 .css( { | |
3646 'box-sizing': 'content-box', | |
3647 width: scroll.sXInner || '100%' | |
3648 } ) | |
3649 .append( | |
3650 headerClone | |
3651 .removeAttr('id') | |
3652 .css( 'margin-left', 0 ) | |
3653 .append( captionSide === 'top' ? caption : null ) | |
3654 .append( | |
3655 table.children('thead') | |
3656 ) | |
3657 ) | |
3658 ) | |
3659 ) | |
3660 .append( | |
3661 $(_div, { 'class': classes.sScrollBody } ) | |
3662 .css( { | |
3663 overflow: 'auto', | |
3664 height: size( scrollY ), | |
3665 width: size( scrollX ) | |
3666 } ) | |
3667 .append( table ) | |
3668 ); | |
3669 | |
3670 if ( footer ) { | |
3671 scroller.append( | |
3672 $(_div, { 'class': classes.sScrollFoot } ) | |
3673 .css( { | |
3674 overflow: 'hidden', | |
3675 border: 0, | |
3676 width: scrollX ? size(scrollX) : '100%' | |
3677 } ) | |
3678 .append( | |
3679 $(_div, { 'class': classes.sScrollFootInner } ) | |
3680 .append( | |
3681 footerClone | |
3682 .removeAttr('id') | |
3683 .css( 'margin-left', 0 ) | |
3684 .append( captionSide === 'bottom' ? caption : null ) | |
3685 .append( | |
3686 table.children('tfoot') | |
3687 ) | |
3688 ) | |
3689 ) | |
3690 ); | |
3691 } | |
3692 | |
3693 var children = scroller.children(); | |
3694 var scrollHead = children[0]; | |
3695 var scrollBody = children[1]; | |
3696 var scrollFoot = footer ? children[2] : null; | |
3697 | |
3698 // When the body is scrolled, then we also want to scroll the headers | |
3699 if ( scrollX ) { | |
3700 $(scrollBody).scroll( function (e) { | |
3701 var scrollLeft = this.scrollLeft; | |
3702 | |
3703 scrollHead.scrollLeft = scrollLeft; | |
3704 | |
3705 if ( footer ) { | |
3706 scrollFoot.scrollLeft = scrollLeft; | |
3707 } | |
3708 } ); | |
3709 } | |
3710 | |
3711 settings.nScrollHead = scrollHead; | |
3712 settings.nScrollBody = scrollBody; | |
3713 settings.nScrollFoot = scrollFoot; | |
3714 | |
3715 // On redraw - align columns | |
3716 settings.aoDrawCallback.push( { | |
3717 "fn": _fnScrollDraw, | |
3718 "sName": "scrolling" | |
3719 } ); | |
3720 | |
3721 return scroller[0]; | |
3722 } | |
3723 | |
3724 | |
3725 | |
3726 /** | |
3727 * Update the header, footer and body tables for resizing - i.e. column | |
3728 * alignment. | |
3729 * | |
3730 * Welcome to the most horrible function DataTables. The process that this | |
3731 * function follows is basically: | |
3732 * 1. Re-create the table inside the scrolling div | |
3733 * 2. Take live measurements from the DOM | |
3734 * 3. Apply the measurements to align the columns | |
3735 * 4. Clean up | |
3736 * | |
3737 * @param {object} settings dataTables settings object | |
3738 * @memberof DataTable#oApi | |
3739 */ | |
3740 function _fnScrollDraw ( settings ) | |
3741 { | |
3742 // Given that this is such a monster function, a lot of variables are use | |
3743 // to try and keep the minimised size as small as possible | |
3744 var | |
3745 scroll = settings.oScroll, | |
3746 scrollX = scroll.sX, | |
3747 scrollXInner = scroll.sXInner, | |
3748 scrollY = scroll.sY, | |
3749 barWidth = scroll.iBarWidth, | |
3750 divHeader = $(settings.nScrollHead), | |
3751 divHeaderStyle = divHeader[0].style, | |
3752 divHeaderInner = divHeader.children('div'), | |
3753 divHeaderInnerStyle = divHeaderInner[0].style, | |
3754 divHeaderTable = divHeaderInner.children('table'), | |
3755 divBodyEl = settings.nScrollBody, | |
3756 divBody = $(divBodyEl), | |
3757 divBodyStyle = divBodyEl.style, | |
3758 divFooter = $(settings.nScrollFoot), | |
3759 divFooterInner = divFooter.children('div'), | |
3760 divFooterTable = divFooterInner.children('table'), | |
3761 header = $(settings.nTHead), | |
3762 table = $(settings.nTable), | |
3763 tableEl = table[0], | |
3764 tableStyle = tableEl.style, | |
3765 footer = settings.nTFoot ? $(settings.nTFoot) : null, | |
3766 browser = settings.oBrowser, | |
3767 ie67 = browser.bScrollOversize, | |
3768 headerTrgEls, footerTrgEls, | |
3769 headerSrcEls, footerSrcEls, | |
3770 headerCopy, footerCopy, | |
3771 headerWidths=[], footerWidths=[], | |
3772 headerContent=[], | |
3773 idx, correction, sanityWidth, | |
3774 zeroOut = function(nSizer) { | |
3775 var style = nSizer.style; | |
3776 style.paddingTop = "0"; | |
3777 style.paddingBottom = "0"; | |
3778 style.borderTopWidth = "0"; | |
3779 style.borderBottomWidth = "0"; | |
3780 style.height = 0; | |
3781 }; | |
3782 | |
3783 /* | |
3784 * 1. Re-create the table inside the scrolling div | |
3785 */ | |
3786 | |
3787 // Remove the old minimised thead and tfoot elements in the inner table | |
3788 table.children('thead, tfoot').remove(); | |
3789 | |
3790 // Clone the current header and footer elements and then place it into the inner table | |
3791 headerCopy = header.clone().prependTo( table ); | |
3792 headerTrgEls = header.find('tr'); // original header is in its own table | |
3793 headerSrcEls = headerCopy.find('tr'); | |
3794 headerCopy.find('th, td').removeAttr('tabindex'); | |
3795 | |
3796 if ( footer ) { | |
3797 footerCopy = footer.clone().prependTo( table ); | |
3798 footerTrgEls = footer.find('tr'); // the original tfoot is in its own table and must be sized | |
3799 footerSrcEls = footerCopy.find('tr'); | |
3800 } | |
3801 | |
3802 | |
3803 /* | |
3804 * 2. Take live measurements from the DOM - do not alter the DOM itself! | |
3805 */ | |
3806 | |
3807 // Remove old sizing and apply the calculated column widths | |
3808 // Get the unique column headers in the newly created (cloned) header. We want to apply the | |
3809 // calculated sizes to this header | |
3810 if ( ! scrollX ) | |
3811 { | |
3812 divBodyStyle.width = '100%'; | |
3813 divHeader[0].style.width = '100%'; | |
3814 } | |
3815 | |
3816 $.each( _fnGetUniqueThs( settings, headerCopy ), function ( i, el ) { | |
3817 idx = _fnVisibleToColumnIndex( settings, i ); | |
3818 el.style.width = settings.aoColumns[idx].sWidth; | |
3819 } ); | |
3820 | |
3821 if ( footer ) { | |
3822 _fnApplyToChildren( function(n) { | |
3823 n.style.width = ""; | |
3824 }, footerSrcEls ); | |
3825 } | |
3826 | |
3827 // If scroll collapse is enabled, when we put the headers back into the body for sizing, we | |
3828 // will end up forcing the scrollbar to appear, making our measurements wrong for when we | |
3829 // then hide it (end of this function), so add the header height to the body scroller. | |
3830 if ( scroll.bCollapse && scrollY !== "" ) { | |
3831 divBodyStyle.height = (divBody[0].offsetHeight + header[0].offsetHeight)+"px"; | |
3832 } | |
3833 | |
3834 // Size the table as a whole | |
3835 sanityWidth = table.outerWidth(); | |
3836 if ( scrollX === "" ) { | |
3837 // No x scrolling | |
3838 tableStyle.width = "100%"; | |
3839 | |
3840 // IE7 will make the width of the table when 100% include the scrollbar | |
3841 // - which is shouldn't. When there is a scrollbar we need to take this | |
3842 // into account. | |
3843 if ( ie67 && (table.find('tbody').height() > divBodyEl.offsetHeight || | |
3844 divBody.css('overflow-y') == "scroll") | |
3845 ) { | |
3846 tableStyle.width = _fnStringToCss( table.outerWidth() - barWidth); | |
3847 } | |
3848 } | |
3849 else | |
3850 { | |
3851 // x scrolling | |
3852 if ( scrollXInner !== "" ) { | |
3853 // x scroll inner has been given - use it | |
3854 tableStyle.width = _fnStringToCss(scrollXInner); | |
3855 } | |
3856 else if ( sanityWidth == divBody.width() && divBody.height() < table.height() ) { | |
3857 // There is y-scrolling - try to take account of the y scroll bar | |
3858 tableStyle.width = _fnStringToCss( sanityWidth-barWidth ); | |
3859 if ( table.outerWidth() > sanityWidth-barWidth ) { | |
3860 // Not possible to take account of it | |
3861 tableStyle.width = _fnStringToCss( sanityWidth ); | |
3862 } | |
3863 } | |
3864 else { | |
3865 // When all else fails | |
3866 tableStyle.width = _fnStringToCss( sanityWidth ); | |
3867 } | |
3868 } | |
3869 | |
3870 // Recalculate the sanity width - now that we've applied the required width, | |
3871 // before it was a temporary variable. This is required because the column | |
3872 // width calculation is done before this table DOM is created. | |
3873 sanityWidth = table.outerWidth(); | |
3874 | |
3875 // Hidden header should have zero height, so remove padding and borders. Then | |
3876 // set the width based on the real headers | |
3877 | |
3878 // Apply all styles in one pass | |
3879 _fnApplyToChildren( zeroOut, headerSrcEls ); | |
3880 | |
3881 // Read all widths in next pass | |
3882 _fnApplyToChildren( function(nSizer) { | |
3883 headerContent.push( nSizer.innerHTML ); | |
3884 headerWidths.push( _fnStringToCss( $(nSizer).css('width') ) ); | |
3885 }, headerSrcEls ); | |
3886 | |
3887 // Apply all widths in final pass | |
3888 _fnApplyToChildren( function(nToSize, i) { | |
3889 nToSize.style.width = headerWidths[i]; | |
3890 }, headerTrgEls ); | |
3891 | |
3892 $(headerSrcEls).height(0); | |
3893 | |
3894 /* Same again with the footer if we have one */ | |
3895 if ( footer ) | |
3896 { | |
3897 _fnApplyToChildren( zeroOut, footerSrcEls ); | |
3898 | |
3899 _fnApplyToChildren( function(nSizer) { | |
3900 footerWidths.push( _fnStringToCss( $(nSizer).css('width') ) ); | |
3901 }, footerSrcEls ); | |
3902 | |
3903 _fnApplyToChildren( function(nToSize, i) { | |
3904 nToSize.style.width = footerWidths[i]; | |
3905 }, footerTrgEls ); | |
3906 | |
3907 $(footerSrcEls).height(0); | |
3908 } | |
3909 | |
3910 | |
3911 /* | |
3912 * 3. Apply the measurements | |
3913 */ | |
3914 | |
3915 // "Hide" the header and footer that we used for the sizing. We need to keep | |
3916 // the content of the cell so that the width applied to the header and body | |
3917 // both match, but we want to hide it completely. We want to also fix their | |
3918 // width to what they currently are | |
3919 _fnApplyToChildren( function(nSizer, i) { | |
3920 nSizer.innerHTML = '<div class="dataTables_sizing" style="height:0;overflow:hidden;">'+headerContent[i]+'</div>'; | |
3921 nSizer.style.width = headerWidths[i]; | |
3922 }, headerSrcEls ); | |
3923 | |
3924 if ( footer ) | |
3925 { | |
3926 _fnApplyToChildren( function(nSizer, i) { | |
3927 nSizer.innerHTML = ""; | |
3928 nSizer.style.width = footerWidths[i]; | |
3929 }, footerSrcEls ); | |
3930 } | |
3931 | |
3932 // Sanity check that the table is of a sensible width. If not then we are going to get | |
3933 // misalignment - try to prevent this by not allowing the table to shrink below its min width | |
3934 if ( table.outerWidth() < sanityWidth ) | |
3935 { | |
3936 // The min width depends upon if we have a vertical scrollbar visible or not */ | |
3937 correction = ((divBodyEl.scrollHeight > divBodyEl.offsetHeight || | |
3938 divBody.css('overflow-y') == "scroll")) ? | |
3939 sanityWidth+barWidth : | |
3940 sanityWidth; | |
3941 | |
3942 // IE6/7 are a law unto themselves... | |
3943 if ( ie67 && (divBodyEl.scrollHeight > | |
3944 divBodyEl.offsetHeight || divBody.css('overflow-y') == "scroll") | |
3945 ) { | |
3946 tableStyle.width = _fnStringToCss( correction-barWidth ); | |
3947 } | |
3948 | |
3949 // And give the user a warning that we've stopped the table getting too small | |
3950 if ( scrollX === "" || scrollXInner !== "" ) { | |
3951 _fnLog( settings, 1, 'Possible column misalignment', 6 ); | |
3952 } | |
3953 } | |
3954 else | |
3955 { | |
3956 correction = '100%'; | |
3957 } | |
3958 | |
3959 // Apply to the container elements | |
3960 divBodyStyle.width = _fnStringToCss( correction ); | |
3961 divHeaderStyle.width = _fnStringToCss( correction ); | |
3962 | |
3963 if ( footer ) { | |
3964 settings.nScrollFoot.style.width = _fnStringToCss( correction ); | |
3965 } | |
3966 | |
3967 | |
3968 /* | |
3969 * 4. Clean up | |
3970 */ | |
3971 if ( ! scrollY ) { | |
3972 /* IE7< puts a vertical scrollbar in place (when it shouldn't be) due to subtracting | |
3973 * the scrollbar height from the visible display, rather than adding it on. We need to | |
3974 * set the height in order to sort this. Don't want to do it in any other browsers. | |
3975 */ | |
3976 if ( ie67 ) { | |
3977 divBodyStyle.height = _fnStringToCss( tableEl.offsetHeight+barWidth ); | |
3978 } | |
3979 } | |
3980 | |
3981 if ( scrollY && scroll.bCollapse ) { | |
3982 divBodyStyle.height = _fnStringToCss( scrollY ); | |
3983 | |
3984 var iExtra = (scrollX && tableEl.offsetWidth > divBodyEl.offsetWidth) ? | |
3985 barWidth : | |
3986 0; | |
3987 | |
3988 if ( tableEl.offsetHeight < divBodyEl.offsetHeight ) { | |
3989 divBodyStyle.height = _fnStringToCss( tableEl.offsetHeight+iExtra ); | |
3990 } | |
3991 } | |
3992 | |
3993 /* Finally set the width's of the header and footer tables */ | |
3994 var iOuterWidth = table.outerWidth(); | |
3995 divHeaderTable[0].style.width = _fnStringToCss( iOuterWidth ); | |
3996 divHeaderInnerStyle.width = _fnStringToCss( iOuterWidth ); | |
3997 | |
3998 // Figure out if there are scrollbar present - if so then we need a the header and footer to | |
3999 // provide a bit more space to allow "overflow" scrolling (i.e. past the scrollbar) | |
4000 var bScrolling = table.height() > divBodyEl.clientHeight || divBody.css('overflow-y') == "scroll"; | |
4001 var padding = 'padding' + (browser.bScrollbarLeft ? 'Left' : 'Right' ); | |
4002 divHeaderInnerStyle[ padding ] = bScrolling ? barWidth+"px" : "0px"; | |
4003 | |
4004 if ( footer ) { | |
4005 divFooterTable[0].style.width = _fnStringToCss( iOuterWidth ); | |
4006 divFooterInner[0].style.width = _fnStringToCss( iOuterWidth ); | |
4007 divFooterInner[0].style[padding] = bScrolling ? barWidth+"px" : "0px"; | |
4008 } | |
4009 | |
4010 /* Adjust the position of the header in case we loose the y-scrollbar */ | |
4011 divBody.scroll(); | |
4012 | |
4013 // If sorting or filtering has occurred, jump the scrolling back to the top | |
4014 // only if we aren't holding the position | |
4015 if ( (settings.bSorted || settings.bFiltered) && ! settings._drawHold ) { | |
4016 divBodyEl.scrollTop = 0; | |
4017 } | |
4018 } | |
4019 | |
4020 | |
4021 | |
4022 /** | |
4023 * Apply a given function to the display child nodes of an element array (typically | |
4024 * TD children of TR rows | |
4025 * @param {function} fn Method to apply to the objects | |
4026 * @param array {nodes} an1 List of elements to look through for display children | |
4027 * @param array {nodes} an2 Another list (identical structure to the first) - optional | |
4028 * @memberof DataTable#oApi | |
4029 */ | |
4030 function _fnApplyToChildren( fn, an1, an2 ) | |
4031 { | |
4032 var index=0, i=0, iLen=an1.length; | |
4033 var nNode1, nNode2; | |
4034 | |
4035 while ( i < iLen ) { | |
4036 nNode1 = an1[i].firstChild; | |
4037 nNode2 = an2 ? an2[i].firstChild : null; | |
4038 | |
4039 while ( nNode1 ) { | |
4040 if ( nNode1.nodeType === 1 ) { | |
4041 if ( an2 ) { | |
4042 fn( nNode1, nNode2, index ); | |
4043 } | |
4044 else { | |
4045 fn( nNode1, index ); | |
4046 } | |
4047 | |
4048 index++; | |
4049 } | |
4050 | |
4051 nNode1 = nNode1.nextSibling; | |
4052 nNode2 = an2 ? nNode2.nextSibling : null; | |
4053 } | |
4054 | |
4055 i++; | |
4056 } | |
4057 } | |
4058 | |
4059 | |
4060 | |
4061 var __re_html_remove = /<.*?>/g; | |
4062 | |
4063 | |
4064 /** | |
4065 * Calculate the width of columns for the table | |
4066 * @param {object} oSettings dataTables settings object | |
4067 * @memberof DataTable#oApi | |
4068 */ | |
4069 function _fnCalculateColumnWidths ( oSettings ) | |
4070 { | |
4071 var | |
4072 table = oSettings.nTable, | |
4073 columns = oSettings.aoColumns, | |
4074 scroll = oSettings.oScroll, | |
4075 scrollY = scroll.sY, | |
4076 scrollX = scroll.sX, | |
4077 scrollXInner = scroll.sXInner, | |
4078 columnCount = columns.length, | |
4079 visibleColumns = _fnGetColumns( oSettings, 'bVisible' ), | |
4080 headerCells = $('th', oSettings.nTHead), | |
4081 tableWidthAttr = table.getAttribute('width'), | |
4082 tableContainer = table.parentNode, | |
4083 userInputs = false, | |
4084 i, column, columnIdx, width, outerWidth; | |
4085 | |
4086 /* Convert any user input sizes into pixel sizes */ | |
4087 for ( i=0 ; i<visibleColumns.length ; i++ ) { | |
4088 column = columns[ visibleColumns[i] ]; | |
4089 | |
4090 if ( column.sWidth !== null ) { | |
4091 column.sWidth = _fnConvertToWidth( column.sWidthOrig, tableContainer ); | |
4092 | |
4093 userInputs = true; | |
4094 } | |
4095 } | |
4096 | |
4097 /* If the number of columns in the DOM equals the number that we have to | |
4098 * process in DataTables, then we can use the offsets that are created by | |
4099 * the web- browser. No custom sizes can be set in order for this to happen, | |
4100 * nor scrolling used | |
4101 */ | |
4102 if ( ! userInputs && ! scrollX && ! scrollY && | |
4103 columnCount == _fnVisbleColumns( oSettings ) && | |
4104 columnCount == headerCells.length | |
4105 ) { | |
4106 for ( i=0 ; i<columnCount ; i++ ) { | |
4107 columns[i].sWidth = _fnStringToCss( headerCells.eq(i).width() ); | |
4108 } | |
4109 } | |
4110 else | |
4111 { | |
4112 // Otherwise construct a single row table with the widest node in the | |
4113 // data, assign any user defined widths, then insert it into the DOM and | |
4114 // allow the browser to do all the hard work of calculating table widths | |
4115 var tmpTable = $(table).clone() // don't use cloneNode - IE8 will remove events on the main table | |
4116 .empty() | |
4117 .css( 'visibility', 'hidden' ) | |
4118 .removeAttr( 'id' ) | |
4119 .append( $(oSettings.nTHead).clone( false ) ) | |
4120 .append( $(oSettings.nTFoot).clone( false ) ) | |
4121 .append( $('<tbody><tr/></tbody>') ); | |
4122 | |
4123 // Remove any assigned widths from the footer (from scrolling) | |
4124 tmpTable.find('tfoot th, tfoot td').css('width', ''); | |
4125 | |
4126 var tr = tmpTable.find( 'tbody tr' ); | |
4127 | |
4128 // Apply custom sizing to the cloned header | |
4129 headerCells = _fnGetUniqueThs( oSettings, tmpTable.find('thead')[0] ); | |
4130 | |
4131 for ( i=0 ; i<visibleColumns.length ; i++ ) { | |
4132 column = columns[ visibleColumns[i] ]; | |
4133 | |
4134 headerCells[i].style.width = column.sWidthOrig !== null && column.sWidthOrig !== '' ? | |
4135 _fnStringToCss( column.sWidthOrig ) : | |
4136 ''; | |
4137 } | |
4138 | |
4139 // Find the widest cell for each column and put it into the table | |
4140 if ( oSettings.aoData.length ) { | |
4141 for ( i=0 ; i<visibleColumns.length ; i++ ) { | |
4142 columnIdx = visibleColumns[i]; | |
4143 column = columns[ columnIdx ]; | |
4144 | |
4145 $( _fnGetWidestNode( oSettings, columnIdx ) ) | |
4146 .clone( false ) | |
4147 .append( column.sContentPadding ) | |
4148 .appendTo( tr ); | |
4149 } | |
4150 } | |
4151 | |
4152 // Table has been built, attach to the document so we can work with it | |
4153 tmpTable.appendTo( tableContainer ); | |
4154 | |
4155 // When scrolling (X or Y) we want to set the width of the table as | |
4156 // appropriate. However, when not scrolling leave the table width as it | |
4157 // is. This results in slightly different, but I think correct behaviour | |
4158 if ( scrollX && scrollXInner ) { | |
4159 tmpTable.width( scrollXInner ); | |
4160 } | |
4161 else if ( scrollX ) { | |
4162 tmpTable.css( 'width', 'auto' ); | |
4163 | |
4164 if ( tmpTable.width() < tableContainer.offsetWidth ) { | |
4165 tmpTable.width( tableContainer.offsetWidth ); | |
4166 } | |
4167 } | |
4168 else if ( scrollY ) { | |
4169 tmpTable.width( tableContainer.offsetWidth ); | |
4170 } | |
4171 else if ( tableWidthAttr ) { | |
4172 tmpTable.width( tableWidthAttr ); | |
4173 } | |
4174 | |
4175 // Take into account the y scrollbar | |
4176 _fnScrollingWidthAdjust( oSettings, tmpTable[0] ); | |
4177 | |
4178 // Browsers need a bit of a hand when a width is assigned to any columns | |
4179 // when x-scrolling as they tend to collapse the table to the min-width, | |
4180 // even if we sent the column widths. So we need to keep track of what | |
4181 // the table width should be by summing the user given values, and the | |
4182 // automatic values | |
4183 if ( scrollX ) | |
4184 { | |
4185 var total = 0; | |
4186 | |
4187 for ( i=0 ; i<visibleColumns.length ; i++ ) { | |
4188 column = columns[ visibleColumns[i] ]; | |
4189 outerWidth = $(headerCells[i]).outerWidth(); | |
4190 | |
4191 total += column.sWidthOrig === null ? | |
4192 outerWidth : | |
4193 parseInt( column.sWidth, 10 ) + outerWidth - $(headerCells[i]).width(); | |
4194 } | |
4195 | |
4196 tmpTable.width( _fnStringToCss( total ) ); | |
4197 table.style.width = _fnStringToCss( total ); | |
4198 } | |
4199 | |
4200 // Get the width of each column in the constructed table | |
4201 for ( i=0 ; i<visibleColumns.length ; i++ ) { | |
4202 column = columns[ visibleColumns[i] ]; | |
4203 width = $(headerCells[i]).width(); | |
4204 | |
4205 if ( width ) { | |
4206 column.sWidth = _fnStringToCss( width ); | |
4207 } | |
4208 } | |
4209 | |
4210 table.style.width = _fnStringToCss( tmpTable.css('width') ); | |
4211 | |
4212 // Finished with the table - ditch it | |
4213 tmpTable.remove(); | |
4214 } | |
4215 | |
4216 // If there is a width attr, we want to attach an event listener which | |
4217 // allows the table sizing to automatically adjust when the window is | |
4218 // resized. Use the width attr rather than CSS, since we can't know if the | |
4219 // CSS is a relative value or absolute - DOM read is always px. | |
4220 if ( tableWidthAttr ) { | |
4221 table.style.width = _fnStringToCss( tableWidthAttr ); | |
4222 } | |
4223 | |
4224 if ( (tableWidthAttr || scrollX) && ! oSettings._reszEvt ) { | |
4225 $(window).bind('resize.DT-'+oSettings.sInstance, _fnThrottle( function () { | |
4226 _fnAdjustColumnSizing( oSettings ); | |
4227 } ) ); | |
4228 | |
4229 oSettings._reszEvt = true; | |
4230 } | |
4231 } | |
4232 | |
4233 | |
4234 /** | |
4235 * Throttle the calls to a function. Arguments and context are maintained for | |
4236 * the throttled function | |
4237 * @param {function} fn Function to be called | |
4238 * @param {int} [freq=200] call frequency in mS | |
4239 * @returns {function} wrapped function | |
4240 * @memberof DataTable#oApi | |
4241 */ | |
4242 function _fnThrottle( fn, freq ) { | |
4243 var | |
4244 frequency = freq !== undefined ? freq : 200, | |
4245 last, | |
4246 timer; | |
4247 | |
4248 return function () { | |
4249 var | |
4250 that = this, | |
4251 now = +new Date(), | |
4252 args = arguments; | |
4253 | |
4254 if ( last && now < last + frequency ) { | |
4255 clearTimeout( timer ); | |
4256 | |
4257 timer = setTimeout( function () { | |
4258 last = undefined; | |
4259 fn.apply( that, args ); | |
4260 }, frequency ); | |
4261 } | |
4262 else if ( last ) { | |
4263 last = now; | |
4264 fn.apply( that, args ); | |
4265 } | |
4266 else { | |
4267 last = now; | |
4268 } | |
4269 }; | |
4270 } | |
4271 | |
4272 | |
4273 /** | |
4274 * Convert a CSS unit width to pixels (e.g. 2em) | |
4275 * @param {string} width width to be converted | |
4276 * @param {node} parent parent to get the with for (required for relative widths) - optional | |
4277 * @returns {int} width in pixels | |
4278 * @memberof DataTable#oApi | |
4279 */ | |
4280 function _fnConvertToWidth ( width, parent ) | |
4281 { | |
4282 if ( ! width ) { | |
4283 return 0; | |
4284 } | |
4285 | |
4286 var n = $('<div/>') | |
4287 .css( 'width', _fnStringToCss( width ) ) | |
4288 .appendTo( parent || document.body ); | |
4289 | |
4290 var val = n[0].offsetWidth; | |
4291 n.remove(); | |
4292 | |
4293 return val; | |
4294 } | |
4295 | |
4296 | |
4297 /** | |
4298 * Adjust a table's width to take account of vertical scroll bar | |
4299 * @param {object} oSettings dataTables settings object | |
4300 * @param {node} n table node | |
4301 * @memberof DataTable#oApi | |
4302 */ | |
4303 | |
4304 function _fnScrollingWidthAdjust ( settings, n ) | |
4305 { | |
4306 var scroll = settings.oScroll; | |
4307 | |
4308 if ( scroll.sX || scroll.sY ) { | |
4309 // When y-scrolling only, we want to remove the width of the scroll bar | |
4310 // so the table + scroll bar will fit into the area available, otherwise | |
4311 // we fix the table at its current size with no adjustment | |
4312 var correction = ! scroll.sX ? scroll.iBarWidth : 0; | |
4313 n.style.width = _fnStringToCss( $(n).outerWidth() - correction ); | |
4314 } | |
4315 } | |
4316 | |
4317 | |
4318 /** | |
4319 * Get the widest node | |
4320 * @param {object} settings dataTables settings object | |
4321 * @param {int} colIdx column of interest | |
4322 * @returns {node} widest table node | |
4323 * @memberof DataTable#oApi | |
4324 */ | |
4325 function _fnGetWidestNode( settings, colIdx ) | |
4326 { | |
4327 var idx = _fnGetMaxLenString( settings, colIdx ); | |
4328 if ( idx < 0 ) { | |
4329 return null; | |
4330 } | |
4331 | |
4332 var data = settings.aoData[ idx ]; | |
4333 return ! data.nTr ? // Might not have been created when deferred rendering | |
4334 $('<td/>').html( _fnGetCellData( settings, idx, colIdx, 'display' ) )[0] : | |
4335 data.anCells[ colIdx ]; | |
4336 } | |
4337 | |
4338 | |
4339 /** | |
4340 * Get the maximum strlen for each data column | |
4341 * @param {object} settings dataTables settings object | |
4342 * @param {int} colIdx column of interest | |
4343 * @returns {string} max string length for each column | |
4344 * @memberof DataTable#oApi | |
4345 */ | |
4346 function _fnGetMaxLenString( settings, colIdx ) | |
4347 { | |
4348 var s, max=-1, maxIdx = -1; | |
4349 | |
4350 for ( var i=0, ien=settings.aoData.length ; i<ien ; i++ ) { | |
4351 s = _fnGetCellData( settings, i, colIdx, 'display' )+''; | |
4352 s = s.replace( __re_html_remove, '' ); | |
4353 | |
4354 if ( s.length > max ) { | |
4355 max = s.length; | |
4356 maxIdx = i; | |
4357 } | |
4358 } | |
4359 | |
4360 return maxIdx; | |
4361 } | |
4362 | |
4363 | |
4364 /** | |
4365 * Append a CSS unit (only if required) to a string | |
4366 * @param {string} value to css-ify | |
4367 * @returns {string} value with css unit | |
4368 * @memberof DataTable#oApi | |
4369 */ | |
4370 function _fnStringToCss( s ) | |
4371 { | |
4372 if ( s === null ) { | |
4373 return '0px'; | |
4374 } | |
4375 | |
4376 if ( typeof s == 'number' ) { | |
4377 return s < 0 ? | |
4378 '0px' : | |
4379 s+'px'; | |
4380 } | |
4381 | |
4382 // Check it has a unit character already | |
4383 return s.match(/\d$/) ? | |
4384 s+'px' : | |
4385 s; | |
4386 } | |
4387 | |
4388 | |
4389 /** | |
4390 * Get the width of a scroll bar in this browser being used | |
4391 * @returns {int} width in pixels | |
4392 * @memberof DataTable#oApi | |
4393 */ | |
4394 function _fnScrollBarWidth () | |
4395 { | |
4396 // On first run a static variable is set, since this is only needed once. | |
4397 // Subsequent runs will just use the previously calculated value | |
4398 if ( ! DataTable.__scrollbarWidth ) { | |
4399 var inner = $('<p/>').css( { | |
4400 width: '100%', | |
4401 height: 200, | |
4402 padding: 0 | |
4403 } )[0]; | |
4404 | |
4405 var outer = $('<div/>') | |
4406 .css( { | |
4407 position: 'absolute', | |
4408 top: 0, | |
4409 left: 0, | |
4410 width: 200, | |
4411 height: 150, | |
4412 padding: 0, | |
4413 overflow: 'hidden', | |
4414 visibility: 'hidden' | |
4415 } ) | |
4416 .append( inner ) | |
4417 .appendTo( 'body' ); | |
4418 | |
4419 var w1 = inner.offsetWidth; | |
4420 outer.css( 'overflow', 'scroll' ); | |
4421 var w2 = inner.offsetWidth; | |
4422 | |
4423 if ( w1 === w2 ) { | |
4424 w2 = outer[0].clientWidth; | |
4425 } | |
4426 | |
4427 outer.remove(); | |
4428 | |
4429 DataTable.__scrollbarWidth = w1 - w2; | |
4430 } | |
4431 | |
4432 return DataTable.__scrollbarWidth; | |
4433 } | |
4434 | |
4435 | |
4436 | |
4437 function _fnSortFlatten ( settings ) | |
4438 { | |
4439 var | |
4440 i, iLen, k, kLen, | |
4441 aSort = [], | |
4442 aiOrig = [], | |
4443 aoColumns = settings.aoColumns, | |
4444 aDataSort, iCol, sType, srcCol, | |
4445 fixed = settings.aaSortingFixed, | |
4446 fixedObj = $.isPlainObject( fixed ), | |
4447 nestedSort = [], | |
4448 add = function ( a ) { | |
4449 if ( a.length && ! $.isArray( a[0] ) ) { | |
4450 // 1D array | |
4451 nestedSort.push( a ); | |
4452 } | |
4453 else { | |
4454 // 2D array | |
4455 nestedSort.push.apply( nestedSort, a ); | |
4456 } | |
4457 }; | |
4458 | |
4459 // Build the sort array, with pre-fix and post-fix options if they have been | |
4460 // specified | |
4461 if ( $.isArray( fixed ) ) { | |
4462 add( fixed ); | |
4463 } | |
4464 | |
4465 if ( fixedObj && fixed.pre ) { | |
4466 add( fixed.pre ); | |
4467 } | |
4468 | |
4469 add( settings.aaSorting ); | |
4470 | |
4471 if (fixedObj && fixed.post ) { | |
4472 add( fixed.post ); | |
4473 } | |
4474 | |
4475 for ( i=0 ; i<nestedSort.length ; i++ ) | |
4476 { | |
4477 srcCol = nestedSort[i][0]; | |
4478 aDataSort = aoColumns[ srcCol ].aDataSort; | |
4479 | |
4480 for ( k=0, kLen=aDataSort.length ; k<kLen ; k++ ) | |
4481 { | |
4482 iCol = aDataSort[k]; | |
4483 sType = aoColumns[ iCol ].sType || 'string'; | |
4484 | |
4485 if ( nestedSort[i]._idx === undefined ) { | |
4486 nestedSort[i]._idx = $.inArray( nestedSort[i][1], aoColumns[iCol].asSorting ); | |
4487 } | |
4488 | |
4489 aSort.push( { | |
4490 src: srcCol, | |
4491 col: iCol, | |
4492 dir: nestedSort[i][1], | |
4493 index: nestedSort[i]._idx, | |
4494 type: sType, | |
4495 formatter: DataTable.ext.type.order[ sType+"-pre" ] | |
4496 } ); | |
4497 } | |
4498 } | |
4499 | |
4500 return aSort; | |
4501 } | |
4502 | |
4503 /** | |
4504 * Change the order of the table | |
4505 * @param {object} oSettings dataTables settings object | |
4506 * @memberof DataTable#oApi | |
4507 * @todo This really needs split up! | |
4508 */ | |
4509 function _fnSort ( oSettings ) | |
4510 { | |
4511 var | |
4512 i, ien, iLen, j, jLen, k, kLen, | |
4513 sDataType, nTh, | |
4514 aiOrig = [], | |
4515 oExtSort = DataTable.ext.type.order, | |
4516 aoData = oSettings.aoData, | |
4517 aoColumns = oSettings.aoColumns, | |
4518 aDataSort, data, iCol, sType, oSort, | |
4519 formatters = 0, | |
4520 sortCol, | |
4521 displayMaster = oSettings.aiDisplayMaster, | |
4522 aSort; | |
4523 | |
4524 // Resolve any column types that are unknown due to addition or invalidation | |
4525 // @todo Can this be moved into a 'data-ready' handler which is called when | |
4526 // data is going to be used in the table? | |
4527 _fnColumnTypes( oSettings ); | |
4528 | |
4529 aSort = _fnSortFlatten( oSettings ); | |
4530 | |
4531 for ( i=0, ien=aSort.length ; i<ien ; i++ ) { | |
4532 sortCol = aSort[i]; | |
4533 | |
4534 // Track if we can use the fast sort algorithm | |
4535 if ( sortCol.formatter ) { | |
4536 formatters++; | |
4537 } | |
4538 | |
4539 // Load the data needed for the sort, for each cell | |
4540 _fnSortData( oSettings, sortCol.col ); | |
4541 } | |
4542 | |
4543 /* No sorting required if server-side or no sorting array */ | |
4544 if ( _fnDataSource( oSettings ) != 'ssp' && aSort.length !== 0 ) | |
4545 { | |
4546 // Create a value - key array of the current row positions such that we can use their | |
4547 // current position during the sort, if values match, in order to perform stable sorting | |
4548 for ( i=0, iLen=displayMaster.length ; i<iLen ; i++ ) { | |
4549 aiOrig[ displayMaster[i] ] = i; | |
4550 } | |
4551 | |
4552 /* Do the sort - here we want multi-column sorting based on a given data source (column) | |
4553 * and sorting function (from oSort) in a certain direction. It's reasonably complex to | |
4554 * follow on it's own, but this is what we want (example two column sorting): | |
4555 * fnLocalSorting = function(a,b){ | |
4556 * var iTest; | |
4557 * iTest = oSort['string-asc']('data11', 'data12'); | |
4558 * if (iTest !== 0) | |
4559 * return iTest; | |
4560 * iTest = oSort['numeric-desc']('data21', 'data22'); | |
4561 * if (iTest !== 0) | |
4562 * return iTest; | |
4563 * return oSort['numeric-asc']( aiOrig[a], aiOrig[b] ); | |
4564 * } | |
4565 * Basically we have a test for each sorting column, if the data in that column is equal, | |
4566 * test the next column. If all columns match, then we use a numeric sort on the row | |
4567 * positions in the original data array to provide a stable sort. | |
4568 * | |
4569 * Note - I know it seems excessive to have two sorting methods, but the first is around | |
4570 * 15% faster, so the second is only maintained for backwards compatibility with sorting | |
4571 * methods which do not have a pre-sort formatting function. | |
4572 */ | |
4573 if ( formatters === aSort.length ) { | |
4574 // All sort types have formatting functions | |
4575 displayMaster.sort( function ( a, b ) { | |
4576 var | |
4577 x, y, k, test, sort, | |
4578 len=aSort.length, | |
4579 dataA = aoData[a]._aSortData, | |
4580 dataB = aoData[b]._aSortData; | |
4581 | |
4582 for ( k=0 ; k<len ; k++ ) { | |
4583 sort = aSort[k]; | |
4584 | |
4585 x = dataA[ sort.col ]; | |
4586 y = dataB[ sort.col ]; | |
4587 | |
4588 test = x<y ? -1 : x>y ? 1 : 0; | |
4589 if ( test !== 0 ) { | |
4590 return sort.dir === 'asc' ? test : -test; | |
4591 } | |
4592 } | |
4593 | |
4594 x = aiOrig[a]; | |
4595 y = aiOrig[b]; | |
4596 return x<y ? -1 : x>y ? 1 : 0; | |
4597 } ); | |
4598 } | |
4599 else { | |
4600 // Depreciated - remove in 1.11 (providing a plug-in option) | |
4601 // Not all sort types have formatting methods, so we have to call their sorting | |
4602 // methods. | |
4603 displayMaster.sort( function ( a, b ) { | |
4604 var | |
4605 x, y, k, l, test, sort, fn, | |
4606 len=aSort.length, | |
4607 dataA = aoData[a]._aSortData, | |
4608 dataB = aoData[b]._aSortData; | |
4609 | |
4610 for ( k=0 ; k<len ; k++ ) { | |
4611 sort = aSort[k]; | |
4612 | |
4613 x = dataA[ sort.col ]; | |
4614 y = dataB[ sort.col ]; | |
4615 | |
4616 fn = oExtSort[ sort.type+"-"+sort.dir ] || oExtSort[ "string-"+sort.dir ]; | |
4617 test = fn( x, y ); | |
4618 if ( test !== 0 ) { | |
4619 return test; | |
4620 } | |
4621 } | |
4622 | |
4623 x = aiOrig[a]; | |
4624 y = aiOrig[b]; | |
4625 return x<y ? -1 : x>y ? 1 : 0; | |
4626 } ); | |
4627 } | |
4628 } | |
4629 | |
4630 /* Tell the draw function that we have sorted the data */ | |
4631 oSettings.bSorted = true; | |
4632 } | |
4633 | |
4634 | |
4635 function _fnSortAria ( settings ) | |
4636 { | |
4637 var label; | |
4638 var nextSort; | |
4639 var columns = settings.aoColumns; | |
4640 var aSort = _fnSortFlatten( settings ); | |
4641 var oAria = settings.oLanguage.oAria; | |
4642 | |
4643 // ARIA attributes - need to loop all columns, to update all (removing old | |
4644 // attributes as needed) | |
4645 for ( var i=0, iLen=columns.length ; i<iLen ; i++ ) | |
4646 { | |
4647 var col = columns[i]; | |
4648 var asSorting = col.asSorting; | |
4649 var sTitle = col.sTitle.replace( /<.*?>/g, "" ); | |
4650 var th = col.nTh; | |
4651 | |
4652 // IE7 is throwing an error when setting these properties with jQuery's | |
4653 // attr() and removeAttr() methods... | |
4654 th.removeAttribute('aria-sort'); | |
4655 | |
4656 /* In ARIA only the first sorting column can be marked as sorting - no multi-sort option */ | |
4657 if ( col.bSortable ) { | |
4658 if ( aSort.length > 0 && aSort[0].col == i ) { | |
4659 th.setAttribute('aria-sort', aSort[0].dir=="asc" ? "ascending" : "descending" ); | |
4660 nextSort = asSorting[ aSort[0].index+1 ] || asSorting[0]; | |
4661 } | |
4662 else { | |
4663 nextSort = asSorting[0]; | |
4664 } | |
4665 | |
4666 label = sTitle + ( nextSort === "asc" ? | |
4667 oAria.sSortAscending : | |
4668 oAria.sSortDescending | |
4669 ); | |
4670 } | |
4671 else { | |
4672 label = sTitle; | |
4673 } | |
4674 | |
4675 th.setAttribute('aria-label', label); | |
4676 } | |
4677 } | |
4678 | |
4679 | |
4680 /** | |
4681 * Function to run on user sort request | |
4682 * @param {object} settings dataTables settings object | |
4683 * @param {node} attachTo node to attach the handler to | |
4684 * @param {int} colIdx column sorting index | |
4685 * @param {boolean} [append=false] Append the requested sort to the existing | |
4686 * sort if true (i.e. multi-column sort) | |
4687 * @param {function} [callback] callback function | |
4688 * @memberof DataTable#oApi | |
4689 */ | |
4690 function _fnSortListener ( settings, colIdx, append, callback ) | |
4691 { | |
4692 var col = settings.aoColumns[ colIdx ]; | |
4693 var sorting = settings.aaSorting; | |
4694 var asSorting = col.asSorting; | |
4695 var nextSortIdx; | |
4696 var next = function ( a, overflow ) { | |
4697 var idx = a._idx; | |
4698 if ( idx === undefined ) { | |
4699 idx = $.inArray( a[1], asSorting ); | |
4700 } | |
4701 | |
4702 return idx+1 < asSorting.length ? | |
4703 idx+1 : | |
4704 overflow ? | |
4705 null : | |
4706 0; | |
4707 }; | |
4708 | |
4709 // Convert to 2D array if needed | |
4710 if ( typeof sorting[0] === 'number' ) { | |
4711 sorting = settings.aaSorting = [ sorting ]; | |
4712 } | |
4713 | |
4714 // If appending the sort then we are multi-column sorting | |
4715 if ( append && settings.oFeatures.bSortMulti ) { | |
4716 // Are we already doing some kind of sort on this column? | |
4717 var sortIdx = $.inArray( colIdx, _pluck(sorting, '0') ); | |
4718 | |
4719 if ( sortIdx !== -1 ) { | |
4720 // Yes, modify the sort | |
4721 nextSortIdx = next( sorting[sortIdx], true ); | |
4722 | |
4723 if ( nextSortIdx === null ) { | |
4724 sorting.splice( sortIdx, 1 ); | |
4725 } | |
4726 else { | |
4727 sorting[sortIdx][1] = asSorting[ nextSortIdx ]; | |
4728 sorting[sortIdx]._idx = nextSortIdx; | |
4729 } | |
4730 } | |
4731 else { | |
4732 // No sort on this column yet | |
4733 sorting.push( [ colIdx, asSorting[0], 0 ] ); | |
4734 sorting[sorting.length-1]._idx = 0; | |
4735 } | |
4736 } | |
4737 else if ( sorting.length && sorting[0][0] == colIdx ) { | |
4738 // Single column - already sorting on this column, modify the sort | |
4739 nextSortIdx = next( sorting[0] ); | |
4740 | |
4741 sorting.length = 1; | |
4742 sorting[0][1] = asSorting[ nextSortIdx ]; | |
4743 sorting[0]._idx = nextSortIdx; | |
4744 } | |
4745 else { | |
4746 // Single column - sort only on this column | |
4747 sorting.length = 0; | |
4748 sorting.push( [ colIdx, asSorting[0] ] ); | |
4749 sorting[0]._idx = 0; | |
4750 } | |
4751 | |
4752 // Run the sort by calling a full redraw | |
4753 _fnReDraw( settings ); | |
4754 | |
4755 // callback used for async user interaction | |
4756 if ( typeof callback == 'function' ) { | |
4757 callback( settings ); | |
4758 } | |
4759 } | |
4760 | |
4761 | |
4762 /** | |
4763 * Attach a sort handler (click) to a node | |
4764 * @param {object} settings dataTables settings object | |
4765 * @param {node} attachTo node to attach the handler to | |
4766 * @param {int} colIdx column sorting index | |
4767 * @param {function} [callback] callback function | |
4768 * @memberof DataTable#oApi | |
4769 */ | |
4770 function _fnSortAttachListener ( settings, attachTo, colIdx, callback ) | |
4771 { | |
4772 var col = settings.aoColumns[ colIdx ]; | |
4773 | |
4774 _fnBindAction( attachTo, {}, function (e) { | |
4775 /* If the column is not sortable - don't to anything */ | |
4776 if ( col.bSortable === false ) { | |
4777 return; | |
4778 } | |
4779 | |
4780 // If processing is enabled use a timeout to allow the processing | |
4781 // display to be shown - otherwise to it synchronously | |
4782 if ( settings.oFeatures.bProcessing ) { | |
4783 _fnProcessingDisplay( settings, true ); | |
4784 | |
4785 setTimeout( function() { | |
4786 _fnSortListener( settings, colIdx, e.shiftKey, callback ); | |
4787 | |
4788 // In server-side processing, the draw callback will remove the | |
4789 // processing display | |
4790 if ( _fnDataSource( settings ) !== 'ssp' ) { | |
4791 _fnProcessingDisplay( settings, false ); | |
4792 } | |
4793 }, 0 ); | |
4794 } | |
4795 else { | |
4796 _fnSortListener( settings, colIdx, e.shiftKey, callback ); | |
4797 } | |
4798 } ); | |
4799 } | |
4800 | |
4801 | |
4802 /** | |
4803 * Set the sorting classes on table's body, Note: it is safe to call this function | |
4804 * when bSort and bSortClasses are false | |
4805 * @param {object} oSettings dataTables settings object | |
4806 * @memberof DataTable#oApi | |
4807 */ | |
4808 function _fnSortingClasses( settings ) | |
4809 { | |
4810 var oldSort = settings.aLastSort; | |
4811 var sortClass = settings.oClasses.sSortColumn; | |
4812 var sort = _fnSortFlatten( settings ); | |
4813 var features = settings.oFeatures; | |
4814 var i, ien, colIdx; | |
4815 | |
4816 if ( features.bSort && features.bSortClasses ) { | |
4817 // Remove old sorting classes | |
4818 for ( i=0, ien=oldSort.length ; i<ien ; i++ ) { | |
4819 colIdx = oldSort[i].src; | |
4820 | |
4821 // Remove column sorting | |
4822 $( _pluck( settings.aoData, 'anCells', colIdx ) ) | |
4823 .removeClass( sortClass + (i<2 ? i+1 : 3) ); | |
4824 } | |
4825 | |
4826 // Add new column sorting | |
4827 for ( i=0, ien=sort.length ; i<ien ; i++ ) { | |
4828 colIdx = sort[i].src; | |
4829 | |
4830 $( _pluck( settings.aoData, 'anCells', colIdx ) ) | |
4831 .addClass( sortClass + (i<2 ? i+1 : 3) ); | |
4832 } | |
4833 } | |
4834 | |
4835 settings.aLastSort = sort; | |
4836 } | |
4837 | |
4838 | |
4839 // Get the data to sort a column, be it from cache, fresh (populating the | |
4840 // cache), or from a sort formatter | |
4841 function _fnSortData( settings, idx ) | |
4842 { | |
4843 // Custom sorting function - provided by the sort data type | |
4844 var column = settings.aoColumns[ idx ]; | |
4845 var customSort = DataTable.ext.order[ column.sSortDataType ]; | |
4846 var customData; | |
4847 | |
4848 if ( customSort ) { | |
4849 customData = customSort.call( settings.oInstance, settings, idx, | |
4850 _fnColumnIndexToVisible( settings, idx ) | |
4851 ); | |
4852 } | |
4853 | |
4854 // Use / populate cache | |
4855 var row, cellData; | |
4856 var formatter = DataTable.ext.type.order[ column.sType+"-pre" ]; | |
4857 | |
4858 for ( var i=0, ien=settings.aoData.length ; i<ien ; i++ ) { | |
4859 row = settings.aoData[i]; | |
4860 | |
4861 if ( ! row._aSortData ) { | |
4862 row._aSortData = []; | |
4863 } | |
4864 | |
4865 if ( ! row._aSortData[idx] || customSort ) { | |
4866 cellData = customSort ? | |
4867 customData[i] : // If there was a custom sort function, use data from there | |
4868 _fnGetCellData( settings, i, idx, 'sort' ); | |
4869 | |
4870 row._aSortData[ idx ] = formatter ? | |
4871 formatter( cellData ) : | |
4872 cellData; | |
4873 } | |
4874 } | |
4875 } | |
4876 | |
4877 | |
4878 | |
4879 /** | |
4880 * Save the state of a table | |
4881 * @param {object} oSettings dataTables settings object | |
4882 * @memberof DataTable#oApi | |
4883 */ | |
4884 function _fnSaveState ( settings ) | |
4885 { | |
4886 if ( !settings.oFeatures.bStateSave || settings.bDestroying ) | |
4887 { | |
4888 return; | |
4889 } | |
4890 | |
4891 /* Store the interesting variables */ | |
4892 var state = { | |
4893 time: +new Date(), | |
4894 start: settings._iDisplayStart, | |
4895 length: settings._iDisplayLength, | |
4896 order: $.extend( true, [], settings.aaSorting ), | |
4897 search: _fnSearchToCamel( settings.oPreviousSearch ), | |
4898 columns: $.map( settings.aoColumns, function ( col, i ) { | |
4899 return { | |
4900 visible: col.bVisible, | |
4901 search: _fnSearchToCamel( settings.aoPreSearchCols[i] ) | |
4902 }; | |
4903 } ) | |
4904 }; | |
4905 | |
4906 _fnCallbackFire( settings, "aoStateSaveParams", 'stateSaveParams', [settings, state] ); | |
4907 | |
4908 settings.oSavedState = state; | |
4909 settings.fnStateSaveCallback.call( settings.oInstance, settings, state ); | |
4910 } | |
4911 | |
4912 | |
4913 /** | |
4914 * Attempt to load a saved table state | |
4915 * @param {object} oSettings dataTables settings object | |
4916 * @param {object} oInit DataTables init object so we can override settings | |
4917 * @memberof DataTable#oApi | |
4918 */ | |
4919 function _fnLoadState ( settings, oInit ) | |
4920 { | |
4921 var i, ien; | |
4922 var columns = settings.aoColumns; | |
4923 | |
4924 if ( ! settings.oFeatures.bStateSave ) { | |
4925 return; | |
4926 } | |
4927 | |
4928 var state = settings.fnStateLoadCallback.call( settings.oInstance, settings ); | |
4929 if ( ! state || ! state.time ) { | |
4930 return; | |
4931 } | |
4932 | |
4933 /* Allow custom and plug-in manipulation functions to alter the saved data set and | |
4934 * cancelling of loading by returning false | |
4935 */ | |
4936 var abStateLoad = _fnCallbackFire( settings, 'aoStateLoadParams', 'stateLoadParams', [settings, state] ); | |
4937 if ( $.inArray( false, abStateLoad ) !== -1 ) { | |
4938 return; | |
4939 } | |
4940 | |
4941 /* Reject old data */ | |
4942 var duration = settings.iStateDuration; | |
4943 if ( duration > 0 && state.time < +new Date() - (duration*1000) ) { | |
4944 return; | |
4945 } | |
4946 | |
4947 // Number of columns have changed - all bets are off, no restore of settings | |
4948 if ( columns.length !== state.columns.length ) { | |
4949 return; | |
4950 } | |
4951 | |
4952 // Store the saved state so it might be accessed at any time | |
4953 settings.oLoadedState = $.extend( true, {}, state ); | |
4954 | |
4955 // Restore key features - todo - for 1.11 this needs to be done by | |
4956 // subscribed events | |
4957 settings._iDisplayStart = state.start; | |
4958 settings.iInitDisplayStart = state.start; | |
4959 settings._iDisplayLength = state.length; | |
4960 settings.aaSorting = []; | |
4961 | |
4962 // Order | |
4963 $.each( state.order, function ( i, col ) { | |
4964 settings.aaSorting.push( col[0] >= columns.length ? | |
4965 [ 0, col[1] ] : | |
4966 col | |
4967 ); | |
4968 } ); | |
4969 | |
4970 // Search | |
4971 $.extend( settings.oPreviousSearch, _fnSearchToHung( state.search ) ); | |
4972 | |
4973 // Columns | |
4974 for ( i=0, ien=state.columns.length ; i<ien ; i++ ) { | |
4975 var col = state.columns[i]; | |
4976 | |
4977 // Visibility | |
4978 columns[i].bVisible = col.visible; | |
4979 | |
4980 // Search | |
4981 $.extend( settings.aoPreSearchCols[i], _fnSearchToHung( col.search ) ); | |
4982 } | |
4983 | |
4984 _fnCallbackFire( settings, 'aoStateLoaded', 'stateLoaded', [settings, state] ); | |
4985 } | |
4986 | |
4987 | |
4988 /** | |
4989 * Return the settings object for a particular table | |
4990 * @param {node} table table we are using as a dataTable | |
4991 * @returns {object} Settings object - or null if not found | |
4992 * @memberof DataTable#oApi | |
4993 */ | |
4994 function _fnSettingsFromNode ( table ) | |
4995 { | |
4996 var settings = DataTable.settings; | |
4997 var idx = $.inArray( table, _pluck( settings, 'nTable' ) ); | |
4998 | |
4999 return idx !== -1 ? | |
5000 settings[ idx ] : | |
5001 null; | |
5002 } | |
5003 | |
5004 | |
5005 /** | |
5006 * Log an error message | |
5007 * @param {object} settings dataTables settings object | |
5008 * @param {int} level log error messages, or display them to the user | |
5009 * @param {string} msg error message | |
5010 * @param {int} tn Technical note id to get more information about the error. | |
5011 * @memberof DataTable#oApi | |
5012 */ | |
5013 function _fnLog( settings, level, msg, tn ) | |
5014 { | |
5015 msg = 'DataTables warning: '+ | |
5016 (settings!==null ? 'table id='+settings.sTableId+' - ' : '')+msg; | |
5017 | |
5018 if ( tn ) { | |
5019 msg += '. For more information about this error, please see '+ | |
5020 'http://datatables.net/tn/'+tn; | |
5021 } | |
5022 | |
5023 if ( ! level ) { | |
5024 // Backwards compatibility pre 1.10 | |
5025 var ext = DataTable.ext; | |
5026 var type = ext.sErrMode || ext.errMode; | |
5027 | |
5028 if ( type == 'alert' ) { | |
5029 alert( msg ); | |
5030 } | |
5031 else { | |
5032 throw new Error(msg); | |
5033 } | |
5034 } | |
5035 else if ( window.console && console.log ) { | |
5036 console.log( msg ); | |
5037 } | |
5038 } | |
5039 | |
5040 | |
5041 /** | |
5042 * See if a property is defined on one object, if so assign it to the other object | |
5043 * @param {object} ret target object | |
5044 * @param {object} src source object | |
5045 * @param {string} name property | |
5046 * @param {string} [mappedName] name to map too - optional, name used if not given | |
5047 * @memberof DataTable#oApi | |
5048 */ | |
5049 function _fnMap( ret, src, name, mappedName ) | |
5050 { | |
5051 if ( $.isArray( name ) ) { | |
5052 $.each( name, function (i, val) { | |
5053 if ( $.isArray( val ) ) { | |
5054 _fnMap( ret, src, val[0], val[1] ); | |
5055 } | |
5056 else { | |
5057 _fnMap( ret, src, val ); | |
5058 } | |
5059 } ); | |
5060 | |
5061 return; | |
5062 } | |
5063 | |
5064 if ( mappedName === undefined ) { | |
5065 mappedName = name; | |
5066 } | |
5067 | |
5068 if ( src[name] !== undefined ) { | |
5069 ret[mappedName] = src[name]; | |
5070 } | |
5071 } | |
5072 | |
5073 | |
5074 /** | |
5075 * Extend objects - very similar to jQuery.extend, but deep copy objects, and | |
5076 * shallow copy arrays. The reason we need to do this, is that we don't want to | |
5077 * deep copy array init values (such as aaSorting) since the dev wouldn't be | |
5078 * able to override them, but we do want to deep copy arrays. | |
5079 * @param {object} out Object to extend | |
5080 * @param {object} extender Object from which the properties will be applied to | |
5081 * out | |
5082 * @param {boolean} breakRefs If true, then arrays will be sliced to take an | |
5083 * independent copy with the exception of the `data` or `aaData` parameters | |
5084 * if they are present. This is so you can pass in a collection to | |
5085 * DataTables and have that used as your data source without breaking the | |
5086 * references | |
5087 * @returns {object} out Reference, just for convenience - out === the return. | |
5088 * @memberof DataTable#oApi | |
5089 * @todo This doesn't take account of arrays inside the deep copied objects. | |
5090 */ | |
5091 function _fnExtend( out, extender, breakRefs ) | |
5092 { | |
5093 var val; | |
5094 | |
5095 for ( var prop in extender ) { | |
5096 if ( extender.hasOwnProperty(prop) ) { | |
5097 val = extender[prop]; | |
5098 | |
5099 if ( $.isPlainObject( val ) ) { | |
5100 if ( ! $.isPlainObject( out[prop] ) ) { | |
5101 out[prop] = {}; | |
5102 } | |
5103 $.extend( true, out[prop], val ); | |
5104 } | |
5105 else if ( breakRefs && prop !== 'data' && prop !== 'aaData' && $.isArray(val) ) { | |
5106 out[prop] = val.slice(); | |
5107 } | |
5108 else { | |
5109 out[prop] = val; | |
5110 } | |
5111 } | |
5112 } | |
5113 | |
5114 return out; | |
5115 } | |
5116 | |
5117 | |
5118 /** | |
5119 * Bind an event handers to allow a click or return key to activate the callback. | |
5120 * This is good for accessibility since a return on the keyboard will have the | |
5121 * same effect as a click, if the element has focus. | |
5122 * @param {element} n Element to bind the action to | |
5123 * @param {object} oData Data object to pass to the triggered function | |
5124 * @param {function} fn Callback function for when the event is triggered | |
5125 * @memberof DataTable#oApi | |
5126 */ | |
5127 function _fnBindAction( n, oData, fn ) | |
5128 { | |
5129 $(n) | |
5130 .bind( 'click.DT', oData, function (e) { | |
5131 n.blur(); // Remove focus outline for mouse users | |
5132 fn(e); | |
5133 } ) | |
5134 .bind( 'keypress.DT', oData, function (e){ | |
5135 if ( e.which === 13 ) { | |
5136 e.preventDefault(); | |
5137 fn(e); | |
5138 } | |
5139 } ) | |
5140 .bind( 'selectstart.DT', function () { | |
5141 /* Take the brutal approach to cancelling text selection */ | |
5142 return false; | |
5143 } ); | |
5144 } | |
5145 | |
5146 | |
5147 /** | |
5148 * Register a callback function. Easily allows a callback function to be added to | |
5149 * an array store of callback functions that can then all be called together. | |
5150 * @param {object} oSettings dataTables settings object | |
5151 * @param {string} sStore Name of the array storage for the callbacks in oSettings | |
5152 * @param {function} fn Function to be called back | |
5153 * @param {string} sName Identifying name for the callback (i.e. a label) | |
5154 * @memberof DataTable#oApi | |
5155 */ | |
5156 function _fnCallbackReg( oSettings, sStore, fn, sName ) | |
5157 { | |
5158 if ( fn ) | |
5159 { | |
5160 oSettings[sStore].push( { | |
5161 "fn": fn, | |
5162 "sName": sName | |
5163 } ); | |
5164 } | |
5165 } | |
5166 | |
5167 | |
5168 /** | |
5169 * Fire callback functions and trigger events. Note that the loop over the | |
5170 * callback array store is done backwards! Further note that you do not want to | |
5171 * fire off triggers in time sensitive applications (for example cell creation) | |
5172 * as its slow. | |
5173 * @param {object} settings dataTables settings object | |
5174 * @param {string} callbackArr Name of the array storage for the callbacks in | |
5175 * oSettings | |
5176 * @param {string} event Name of the jQuery custom event to trigger. If null no | |
5177 * trigger is fired | |
5178 * @param {array} args Array of arguments to pass to the callback function / | |
5179 * trigger | |
5180 * @memberof DataTable#oApi | |
5181 */ | |
5182 function _fnCallbackFire( settings, callbackArr, e, args ) | |
5183 { | |
5184 var ret = []; | |
5185 | |
5186 if ( callbackArr ) { | |
5187 ret = $.map( settings[callbackArr].slice().reverse(), function (val, i) { | |
5188 return val.fn.apply( settings.oInstance, args ); | |
5189 } ); | |
5190 } | |
5191 | |
5192 if ( e !== null ) { | |
5193 $(settings.nTable).trigger( e+'.dt', args ); | |
5194 } | |
5195 | |
5196 return ret; | |
5197 } | |
5198 | |
5199 | |
5200 function _fnLengthOverflow ( settings ) | |
5201 { | |
5202 var | |
5203 start = settings._iDisplayStart, | |
5204 end = settings.fnDisplayEnd(), | |
5205 len = settings._iDisplayLength; | |
5206 | |
5207 /* If we have space to show extra rows (backing up from the end point - then do so */ | |
5208 if ( start >= end ) | |
5209 { | |
5210 start = end - len; | |
5211 } | |
5212 | |
5213 // Keep the start record on the current page | |
5214 start -= (start % len); | |
5215 | |
5216 if ( len === -1 || start < 0 ) | |
5217 { | |
5218 start = 0; | |
5219 } | |
5220 | |
5221 settings._iDisplayStart = start; | |
5222 } | |
5223 | |
5224 | |
5225 function _fnRenderer( settings, type ) | |
5226 { | |
5227 var renderer = settings.renderer; | |
5228 var host = DataTable.ext.renderer[type]; | |
5229 | |
5230 if ( $.isPlainObject( renderer ) && renderer[type] ) { | |
5231 // Specific renderer for this type. If available use it, otherwise use | |
5232 // the default. | |
5233 return host[renderer[type]] || host._; | |
5234 } | |
5235 else if ( typeof renderer === 'string' ) { | |
5236 // Common renderer - if there is one available for this type use it, | |
5237 // otherwise use the default | |
5238 return host[renderer] || host._; | |
5239 } | |
5240 | |
5241 // Use the default | |
5242 return host._; | |
5243 } | |
5244 | |
5245 | |
5246 /** | |
5247 * Detect the data source being used for the table. Used to simplify the code | |
5248 * a little (ajax) and to make it compress a little smaller. | |
5249 * | |
5250 * @param {object} settings dataTables settings object | |
5251 * @returns {string} Data source | |
5252 * @memberof DataTable#oApi | |
5253 */ | |
5254 function _fnDataSource ( settings ) | |
5255 { | |
5256 if ( settings.oFeatures.bServerSide ) { | |
5257 return 'ssp'; | |
5258 } | |
5259 else if ( settings.ajax || settings.sAjaxSource ) { | |
5260 return 'ajax'; | |
5261 } | |
5262 return 'dom'; | |
5263 } | |
5264 | |
5265 | |
5266 DataTable = function( options ) | |
5267 { | |
5268 /** | |
5269 * Perform a jQuery selector action on the table's TR elements (from the tbody) and | |
5270 * return the resulting jQuery object. | |
5271 * @param {string|node|jQuery} sSelector jQuery selector or node collection to act on | |
5272 * @param {object} [oOpts] Optional parameters for modifying the rows to be included | |
5273 * @param {string} [oOpts.filter=none] Select TR elements that meet the current filter | |
5274 * criterion ("applied") or all TR elements (i.e. no filter). | |
5275 * @param {string} [oOpts.order=current] Order of the TR elements in the processed array. | |
5276 * Can be either 'current', whereby the current sorting of the table is used, or | |
5277 * 'original' whereby the original order the data was read into the table is used. | |
5278 * @param {string} [oOpts.page=all] Limit the selection to the currently displayed page | |
5279 * ("current") or not ("all"). If 'current' is given, then order is assumed to be | |
5280 * 'current' and filter is 'applied', regardless of what they might be given as. | |
5281 * @returns {object} jQuery object, filtered by the given selector. | |
5282 * @dtopt API | |
5283 * @deprecated Since v1.10 | |
5284 * | |
5285 * @example | |
5286 * $(document).ready(function() { | |
5287 * var oTable = $('#example').dataTable(); | |
5288 * | |
5289 * // Highlight every second row | |
5290 * oTable.$('tr:odd').css('backgroundColor', 'blue'); | |
5291 * } ); | |
5292 * | |
5293 * @example | |
5294 * $(document).ready(function() { | |
5295 * var oTable = $('#example').dataTable(); | |
5296 * | |
5297 * // Filter to rows with 'Webkit' in them, add a background colour and then | |
5298 * // remove the filter, thus highlighting the 'Webkit' rows only. | |
5299 * oTable.fnFilter('Webkit'); | |
5300 * oTable.$('tr', {"search": "applied"}).css('backgroundColor', 'blue'); | |
5301 * oTable.fnFilter(''); | |
5302 * } ); | |
5303 */ | |
5304 this.$ = function ( sSelector, oOpts ) | |
5305 { | |
5306 return this.api(true).$( sSelector, oOpts ); | |
5307 }; | |
5308 | |
5309 | |
5310 /** | |
5311 * Almost identical to $ in operation, but in this case returns the data for the matched | |
5312 * rows - as such, the jQuery selector used should match TR row nodes or TD/TH cell nodes | |
5313 * rather than any descendants, so the data can be obtained for the row/cell. If matching | |
5314 * rows are found, the data returned is the original data array/object that was used to | |
5315 * create the row (or a generated array if from a DOM source). | |
5316 * | |
5317 * This method is often useful in-combination with $ where both functions are given the | |
5318 * same parameters and the array indexes will match identically. | |
5319 * @param {string|node|jQuery} sSelector jQuery selector or node collection to act on | |
5320 * @param {object} [oOpts] Optional parameters for modifying the rows to be included | |
5321 * @param {string} [oOpts.filter=none] Select elements that meet the current filter | |
5322 * criterion ("applied") or all elements (i.e. no filter). | |
5323 * @param {string} [oOpts.order=current] Order of the data in the processed array. | |
5324 * Can be either 'current', whereby the current sorting of the table is used, or | |
5325 * 'original' whereby the original order the data was read into the table is used. | |
5326 * @param {string} [oOpts.page=all] Limit the selection to the currently displayed page | |
5327 * ("current") or not ("all"). If 'current' is given, then order is assumed to be | |
5328 * 'current' and filter is 'applied', regardless of what they might be given as. | |
5329 * @returns {array} Data for the matched elements. If any elements, as a result of the | |
5330 * selector, were not TR, TD or TH elements in the DataTable, they will have a null | |
5331 * entry in the array. | |
5332 * @dtopt API | |
5333 * @deprecated Since v1.10 | |
5334 * | |
5335 * @example | |
5336 * $(document).ready(function() { | |
5337 * var oTable = $('#example').dataTable(); | |
5338 * | |
5339 * // Get the data from the first row in the table | |
5340 * var data = oTable._('tr:first'); | |
5341 * | |
5342 * // Do something useful with the data | |
5343 * alert( "First cell is: "+data[0] ); | |
5344 * } ); | |
5345 * | |
5346 * @example | |
5347 * $(document).ready(function() { | |
5348 * var oTable = $('#example').dataTable(); | |
5349 * | |
5350 * // Filter to 'Webkit' and get all data for | |
5351 * oTable.fnFilter('Webkit'); | |
5352 * var data = oTable._('tr', {"search": "applied"}); | |
5353 * | |
5354 * // Do something with the data | |
5355 * alert( data.length+" rows matched the search" ); | |
5356 * } ); | |
5357 */ | |
5358 this._ = function ( sSelector, oOpts ) | |
5359 { | |
5360 return this.api(true).rows( sSelector, oOpts ).data(); | |
5361 }; | |
5362 | |
5363 | |
5364 /** | |
5365 * Create a DataTables Api instance, with the currently selected tables for | |
5366 * the Api's context. | |
5367 * @param {boolean} [traditional=false] Set the API instance's context to be | |
5368 * only the table referred to by the `DataTable.ext.iApiIndex` option, as was | |
5369 * used in the API presented by DataTables 1.9- (i.e. the traditional mode), | |
5370 * or if all tables captured in the jQuery object should be used. | |
5371 * @return {DataTables.Api} | |
5372 */ | |
5373 this.api = function ( traditional ) | |
5374 { | |
5375 return traditional ? | |
5376 new _Api( | |
5377 _fnSettingsFromNode( this[ _ext.iApiIndex ] ) | |
5378 ) : | |
5379 new _Api( this ); | |
5380 }; | |
5381 | |
5382 | |
5383 /** | |
5384 * Add a single new row or multiple rows of data to the table. Please note | |
5385 * that this is suitable for client-side processing only - if you are using | |
5386 * server-side processing (i.e. "bServerSide": true), then to add data, you | |
5387 * must add it to the data source, i.e. the server-side, through an Ajax call. | |
5388 * @param {array|object} data The data to be added to the table. This can be: | |
5389 * <ul> | |
5390 * <li>1D array of data - add a single row with the data provided</li> | |
5391 * <li>2D array of arrays - add multiple rows in a single call</li> | |
5392 * <li>object - data object when using <i>mData</i></li> | |
5393 * <li>array of objects - multiple data objects when using <i>mData</i></li> | |
5394 * </ul> | |
5395 * @param {bool} [redraw=true] redraw the table or not | |
5396 * @returns {array} An array of integers, representing the list of indexes in | |
5397 * <i>aoData</i> ({@link DataTable.models.oSettings}) that have been added to | |
5398 * the table. | |
5399 * @dtopt API | |
5400 * @deprecated Since v1.10 | |
5401 * | |
5402 * @example | |
5403 * // Global var for counter | |
5404 * var giCount = 2; | |
5405 * | |
5406 * $(document).ready(function() { | |
5407 * $('#example').dataTable(); | |
5408 * } ); | |
5409 * | |
5410 * function fnClickAddRow() { | |
5411 * $('#example').dataTable().fnAddData( [ | |
5412 * giCount+".1", | |
5413 * giCount+".2", | |
5414 * giCount+".3", | |
5415 * giCount+".4" ] | |
5416 * ); | |
5417 * | |
5418 * giCount++; | |
5419 * } | |
5420 */ | |
5421 this.fnAddData = function( data, redraw ) | |
5422 { | |
5423 var api = this.api( true ); | |
5424 | |
5425 /* Check if we want to add multiple rows or not */ | |
5426 var rows = $.isArray(data) && ( $.isArray(data[0]) || $.isPlainObject(data[0]) ) ? | |
5427 api.rows.add( data ) : | |
5428 api.row.add( data ); | |
5429 | |
5430 if ( redraw === undefined || redraw ) { | |
5431 api.draw(); | |
5432 } | |
5433 | |
5434 return rows.flatten().toArray(); | |
5435 }; | |
5436 | |
5437 | |
5438 /** | |
5439 * This function will make DataTables recalculate the column sizes, based on the data | |
5440 * contained in the table and the sizes applied to the columns (in the DOM, CSS or | |
5441 * through the sWidth parameter). This can be useful when the width of the table's | |
5442 * parent element changes (for example a window resize). | |
5443 * @param {boolean} [bRedraw=true] Redraw the table or not, you will typically want to | |
5444 * @dtopt API | |
5445 * @deprecated Since v1.10 | |
5446 * | |
5447 * @example | |
5448 * $(document).ready(function() { | |
5449 * var oTable = $('#example').dataTable( { | |
5450 * "sScrollY": "200px", | |
5451 * "bPaginate": false | |
5452 * } ); | |
5453 * | |
5454 * $(window).bind('resize', function () { | |
5455 * oTable.fnAdjustColumnSizing(); | |
5456 * } ); | |
5457 * } ); | |
5458 */ | |
5459 this.fnAdjustColumnSizing = function ( bRedraw ) | |
5460 { | |
5461 var api = this.api( true ).columns.adjust(); | |
5462 var settings = api.settings()[0]; | |
5463 var scroll = settings.oScroll; | |
5464 | |
5465 if ( bRedraw === undefined || bRedraw ) { | |
5466 api.draw( false ); | |
5467 } | |
5468 else if ( scroll.sX !== "" || scroll.sY !== "" ) { | |
5469 /* If not redrawing, but scrolling, we want to apply the new column sizes anyway */ | |
5470 _fnScrollDraw( settings ); | |
5471 } | |
5472 }; | |
5473 | |
5474 | |
5475 /** | |
5476 * Quickly and simply clear a table | |
5477 * @param {bool} [bRedraw=true] redraw the table or not | |
5478 * @dtopt API | |
5479 * @deprecated Since v1.10 | |
5480 * | |
5481 * @example | |
5482 * $(document).ready(function() { | |
5483 * var oTable = $('#example').dataTable(); | |
5484 * | |
5485 * // Immediately 'nuke' the current rows (perhaps waiting for an Ajax callback...) | |
5486 * oTable.fnClearTable(); | |
5487 * } ); | |
5488 */ | |
5489 this.fnClearTable = function( bRedraw ) | |
5490 { | |
5491 var api = this.api( true ).clear(); | |
5492 | |
5493 if ( bRedraw === undefined || bRedraw ) { | |
5494 api.draw(); | |
5495 } | |
5496 }; | |
5497 | |
5498 | |
5499 /** | |
5500 * The exact opposite of 'opening' a row, this function will close any rows which | |
5501 * are currently 'open'. | |
5502 * @param {node} nTr the table row to 'close' | |
5503 * @returns {int} 0 on success, or 1 if failed (can't find the row) | |
5504 * @dtopt API | |
5505 * @deprecated Since v1.10 | |
5506 * | |
5507 * @example | |
5508 * $(document).ready(function() { | |
5509 * var oTable; | |
5510 * | |
5511 * // 'open' an information row when a row is clicked on | |
5512 * $('#example tbody tr').click( function () { | |
5513 * if ( oTable.fnIsOpen(this) ) { | |
5514 * oTable.fnClose( this ); | |
5515 * } else { | |
5516 * oTable.fnOpen( this, "Temporary row opened", "info_row" ); | |
5517 * } | |
5518 * } ); | |
5519 * | |
5520 * oTable = $('#example').dataTable(); | |
5521 * } ); | |
5522 */ | |
5523 this.fnClose = function( nTr ) | |
5524 { | |
5525 this.api( true ).row( nTr ).child.hide(); | |
5526 }; | |
5527 | |
5528 | |
5529 /** | |
5530 * Remove a row for the table | |
5531 * @param {mixed} target The index of the row from aoData to be deleted, or | |
5532 * the TR element you want to delete | |
5533 * @param {function|null} [callBack] Callback function | |
5534 * @param {bool} [redraw=true] Redraw the table or not | |
5535 * @returns {array} The row that was deleted | |
5536 * @dtopt API | |
5537 * @deprecated Since v1.10 | |
5538 * | |
5539 * @example | |
5540 * $(document).ready(function() { | |
5541 * var oTable = $('#example').dataTable(); | |
5542 * | |
5543 * // Immediately remove the first row | |
5544 * oTable.fnDeleteRow( 0 ); | |
5545 * } ); | |
5546 */ | |
5547 this.fnDeleteRow = function( target, callback, redraw ) | |
5548 { | |
5549 var api = this.api( true ); | |
5550 var rows = api.rows( target ); | |
5551 var settings = rows.settings()[0]; | |
5552 var data = settings.aoData[ rows[0][0] ]; | |
5553 | |
5554 rows.remove(); | |
5555 | |
5556 if ( callback ) { | |
5557 callback.call( this, settings, data ); | |
5558 } | |
5559 | |
5560 if ( redraw === undefined || redraw ) { | |
5561 api.draw(); | |
5562 } | |
5563 | |
5564 return data; | |
5565 }; | |
5566 | |
5567 | |
5568 /** | |
5569 * Restore the table to it's original state in the DOM by removing all of DataTables | |
5570 * enhancements, alterations to the DOM structure of the table and event listeners. | |
5571 * @param {boolean} [remove=false] Completely remove the table from the DOM | |
5572 * @dtopt API | |
5573 * @deprecated Since v1.10 | |
5574 * | |
5575 * @example | |
5576 * $(document).ready(function() { | |
5577 * // This example is fairly pointless in reality, but shows how fnDestroy can be used | |
5578 * var oTable = $('#example').dataTable(); | |
5579 * oTable.fnDestroy(); | |
5580 * } ); | |
5581 */ | |
5582 this.fnDestroy = function ( remove ) | |
5583 { | |
5584 this.api( true ).destroy( remove ); | |
5585 }; | |
5586 | |
5587 | |
5588 /** | |
5589 * Redraw the table | |
5590 * @param {bool} [complete=true] Re-filter and resort (if enabled) the table before the draw. | |
5591 * @dtopt API | |
5592 * @deprecated Since v1.10 | |
5593 * | |
5594 * @example | |
5595 * $(document).ready(function() { | |
5596 * var oTable = $('#example').dataTable(); | |
5597 * | |
5598 * // Re-draw the table - you wouldn't want to do it here, but it's an example :-) | |
5599 * oTable.fnDraw(); | |
5600 * } ); | |
5601 */ | |
5602 this.fnDraw = function( complete ) | |
5603 { | |
5604 // Note that this isn't an exact match to the old call to _fnDraw - it takes | |
5605 // into account the new data, but can old position. | |
5606 this.api( true ).draw( ! complete ); | |
5607 }; | |
5608 | |
5609 | |
5610 /** | |
5611 * Filter the input based on data | |
5612 * @param {string} sInput String to filter the table on | |
5613 * @param {int|null} [iColumn] Column to limit filtering to | |
5614 * @param {bool} [bRegex=false] Treat as regular expression or not | |
5615 * @param {bool} [bSmart=true] Perform smart filtering or not | |
5616 * @param {bool} [bShowGlobal=true] Show the input global filter in it's input box(es) | |
5617 * @param {bool} [bCaseInsensitive=true] Do case-insensitive matching (true) or not (false) | |
5618 * @dtopt API | |
5619 * @deprecated Since v1.10 | |
5620 * | |
5621 * @example | |
5622 * $(document).ready(function() { | |
5623 * var oTable = $('#example').dataTable(); | |
5624 * | |
5625 * // Sometime later - filter... | |
5626 * oTable.fnFilter( 'test string' ); | |
5627 * } ); | |
5628 */ | |
5629 this.fnFilter = function( sInput, iColumn, bRegex, bSmart, bShowGlobal, bCaseInsensitive ) | |
5630 { | |
5631 var api = this.api( true ); | |
5632 | |
5633 if ( iColumn === null || iColumn === undefined ) { | |
5634 api.search( sInput, bRegex, bSmart, bCaseInsensitive ); | |
5635 } | |
5636 else { | |
5637 api.column( iColumn ).search( sInput, bRegex, bSmart, bCaseInsensitive ); | |
5638 } | |
5639 | |
5640 api.draw(); | |
5641 }; | |
5642 | |
5643 | |
5644 /** | |
5645 * Get the data for the whole table, an individual row or an individual cell based on the | |
5646 * provided parameters. | |
5647 * @param {int|node} [src] A TR row node, TD/TH cell node or an integer. If given as | |
5648 * a TR node then the data source for the whole row will be returned. If given as a | |
5649 * TD/TH cell node then iCol will be automatically calculated and the data for the | |
5650 * cell returned. If given as an integer, then this is treated as the aoData internal | |
5651 * data index for the row (see fnGetPosition) and the data for that row used. | |
5652 * @param {int} [col] Optional column index that you want the data of. | |
5653 * @returns {array|object|string} If mRow is undefined, then the data for all rows is | |
5654 * returned. If mRow is defined, just data for that row, and is iCol is | |
5655 * defined, only data for the designated cell is returned. | |
5656 * @dtopt API | |
5657 * @deprecated Since v1.10 | |
5658 * | |
5659 * @example | |
5660 * // Row data | |
5661 * $(document).ready(function() { | |
5662 * oTable = $('#example').dataTable(); | |
5663 * | |
5664 * oTable.$('tr').click( function () { | |
5665 * var data = oTable.fnGetData( this ); | |
5666 * // ... do something with the array / object of data for the row | |
5667 * } ); | |
5668 * } ); | |
5669 * | |
5670 * @example | |
5671 * // Individual cell data | |
5672 * $(document).ready(function() { | |
5673 * oTable = $('#example').dataTable(); | |
5674 * | |
5675 * oTable.$('td').click( function () { | |
5676 * var sData = oTable.fnGetData( this ); | |
5677 * alert( 'The cell clicked on had the value of '+sData ); | |
5678 * } ); | |
5679 * } ); | |
5680 */ | |
5681 this.fnGetData = function( src, col ) | |
5682 { | |
5683 var api = this.api( true ); | |
5684 | |
5685 if ( src !== undefined ) { | |
5686 var type = src.nodeName ? src.nodeName.toLowerCase() : ''; | |
5687 | |
5688 return col !== undefined || type == 'td' || type == 'th' ? | |
5689 api.cell( src, col ).data() : | |
5690 api.row( src ).data() || null; | |
5691 } | |
5692 | |
5693 return api.data().toArray(); | |
5694 }; | |
5695 | |
5696 | |
5697 /** | |
5698 * Get an array of the TR nodes that are used in the table's body. Note that you will | |
5699 * typically want to use the '$' API method in preference to this as it is more | |
5700 * flexible. | |
5701 * @param {int} [iRow] Optional row index for the TR element you want | |
5702 * @returns {array|node} If iRow is undefined, returns an array of all TR elements | |
5703 * in the table's body, or iRow is defined, just the TR element requested. | |
5704 * @dtopt API | |
5705 * @deprecated Since v1.10 | |
5706 * | |
5707 * @example | |
5708 * $(document).ready(function() { | |
5709 * var oTable = $('#example').dataTable(); | |
5710 * | |
5711 * // Get the nodes from the table | |
5712 * var nNodes = oTable.fnGetNodes( ); | |
5713 * } ); | |
5714 */ | |
5715 this.fnGetNodes = function( iRow ) | |
5716 { | |
5717 var api = this.api( true ); | |
5718 | |
5719 return iRow !== undefined ? | |
5720 api.row( iRow ).node() : | |
5721 api.rows().nodes().flatten().toArray(); | |
5722 }; | |
5723 | |
5724 | |
5725 /** | |
5726 * Get the array indexes of a particular cell from it's DOM element | |
5727 * and column index including hidden columns | |
5728 * @param {node} node this can either be a TR, TD or TH in the table's body | |
5729 * @returns {int} If nNode is given as a TR, then a single index is returned, or | |
5730 * if given as a cell, an array of [row index, column index (visible), | |
5731 * column index (all)] is given. | |
5732 * @dtopt API | |
5733 * @deprecated Since v1.10 | |
5734 * | |
5735 * @example | |
5736 * $(document).ready(function() { | |
5737 * $('#example tbody td').click( function () { | |
5738 * // Get the position of the current data from the node | |
5739 * var aPos = oTable.fnGetPosition( this ); | |
5740 * | |
5741 * // Get the data array for this row | |
5742 * var aData = oTable.fnGetData( aPos[0] ); | |
5743 * | |
5744 * // Update the data array and return the value | |
5745 * aData[ aPos[1] ] = 'clicked'; | |
5746 * this.innerHTML = 'clicked'; | |
5747 * } ); | |
5748 * | |
5749 * // Init DataTables | |
5750 * oTable = $('#example').dataTable(); | |
5751 * } ); | |
5752 */ | |
5753 this.fnGetPosition = function( node ) | |
5754 { | |
5755 var api = this.api( true ); | |
5756 var nodeName = node.nodeName.toUpperCase(); | |
5757 | |
5758 if ( nodeName == 'TR' ) { | |
5759 return api.row( node ).index(); | |
5760 } | |
5761 else if ( nodeName == 'TD' || nodeName == 'TH' ) { | |
5762 var cell = api.cell( node ).index(); | |
5763 | |
5764 return [ | |
5765 cell.row, | |
5766 cell.columnVisible, | |
5767 cell.column | |
5768 ]; | |
5769 } | |
5770 return null; | |
5771 }; | |
5772 | |
5773 | |
5774 /** | |
5775 * Check to see if a row is 'open' or not. | |
5776 * @param {node} nTr the table row to check | |
5777 * @returns {boolean} true if the row is currently open, false otherwise | |
5778 * @dtopt API | |
5779 * @deprecated Since v1.10 | |
5780 * | |
5781 * @example | |
5782 * $(document).ready(function() { | |
5783 * var oTable; | |
5784 * | |
5785 * // 'open' an information row when a row is clicked on | |
5786 * $('#example tbody tr').click( function () { | |
5787 * if ( oTable.fnIsOpen(this) ) { | |
5788 * oTable.fnClose( this ); | |
5789 * } else { | |
5790 * oTable.fnOpen( this, "Temporary row opened", "info_row" ); | |
5791 * } | |
5792 * } ); | |
5793 * | |
5794 * oTable = $('#example').dataTable(); | |
5795 * } ); | |
5796 */ | |
5797 this.fnIsOpen = function( nTr ) | |
5798 { | |
5799 return this.api( true ).row( nTr ).child.isShown(); | |
5800 }; | |
5801 | |
5802 | |
5803 /** | |
5804 * This function will place a new row directly after a row which is currently | |
5805 * on display on the page, with the HTML contents that is passed into the | |
5806 * function. This can be used, for example, to ask for confirmation that a | |
5807 * particular record should be deleted. | |
5808 * @param {node} nTr The table row to 'open' | |
5809 * @param {string|node|jQuery} mHtml The HTML to put into the row | |
5810 * @param {string} sClass Class to give the new TD cell | |
5811 * @returns {node} The row opened. Note that if the table row passed in as the | |
5812 * first parameter, is not found in the table, this method will silently | |
5813 * return. | |
5814 * @dtopt API | |
5815 * @deprecated Since v1.10 | |
5816 * | |
5817 * @example | |
5818 * $(document).ready(function() { | |
5819 * var oTable; | |
5820 * | |
5821 * // 'open' an information row when a row is clicked on | |
5822 * $('#example tbody tr').click( function () { | |
5823 * if ( oTable.fnIsOpen(this) ) { | |
5824 * oTable.fnClose( this ); | |
5825 * } else { | |
5826 * oTable.fnOpen( this, "Temporary row opened", "info_row" ); | |
5827 * } | |
5828 * } ); | |
5829 * | |
5830 * oTable = $('#example').dataTable(); | |
5831 * } ); | |
5832 */ | |
5833 this.fnOpen = function( nTr, mHtml, sClass ) | |
5834 { | |
5835 return this.api( true ) | |
5836 .row( nTr ) | |
5837 .child( mHtml, sClass ) | |
5838 .show() | |
5839 .child()[0]; | |
5840 }; | |
5841 | |
5842 | |
5843 /** | |
5844 * Change the pagination - provides the internal logic for pagination in a simple API | |
5845 * function. With this function you can have a DataTables table go to the next, | |
5846 * previous, first or last pages. | |
5847 * @param {string|int} mAction Paging action to take: "first", "previous", "next" or "last" | |
5848 * or page number to jump to (integer), note that page 0 is the first page. | |
5849 * @param {bool} [bRedraw=true] Redraw the table or not | |
5850 * @dtopt API | |
5851 * @deprecated Since v1.10 | |
5852 * | |
5853 * @example | |
5854 * $(document).ready(function() { | |
5855 * var oTable = $('#example').dataTable(); | |
5856 * oTable.fnPageChange( 'next' ); | |
5857 * } ); | |
5858 */ | |
5859 this.fnPageChange = function ( mAction, bRedraw ) | |
5860 { | |
5861 var api = this.api( true ).page( mAction ); | |
5862 | |
5863 if ( bRedraw === undefined || bRedraw ) { | |
5864 api.draw(false); | |
5865 } | |
5866 }; | |
5867 | |
5868 | |
5869 /** | |
5870 * Show a particular column | |
5871 * @param {int} iCol The column whose display should be changed | |
5872 * @param {bool} bShow Show (true) or hide (false) the column | |
5873 * @param {bool} [bRedraw=true] Redraw the table or not | |
5874 * @dtopt API | |
5875 * @deprecated Since v1.10 | |
5876 * | |
5877 * @example | |
5878 * $(document).ready(function() { | |
5879 * var oTable = $('#example').dataTable(); | |
5880 * | |
5881 * // Hide the second column after initialisation | |
5882 * oTable.fnSetColumnVis( 1, false ); | |
5883 * } ); | |
5884 */ | |
5885 this.fnSetColumnVis = function ( iCol, bShow, bRedraw ) | |
5886 { | |
5887 var api = this.api( true ).column( iCol ).visible( bShow ); | |
5888 | |
5889 if ( bRedraw === undefined || bRedraw ) { | |
5890 api.columns.adjust().draw(); | |
5891 } | |
5892 }; | |
5893 | |
5894 | |
5895 /** | |
5896 * Get the settings for a particular table for external manipulation | |
5897 * @returns {object} DataTables settings object. See | |
5898 * {@link DataTable.models.oSettings} | |
5899 * @dtopt API | |
5900 * @deprecated Since v1.10 | |
5901 * | |
5902 * @example | |
5903 * $(document).ready(function() { | |
5904 * var oTable = $('#example').dataTable(); | |
5905 * var oSettings = oTable.fnSettings(); | |
5906 * | |
5907 * // Show an example parameter from the settings | |
5908 * alert( oSettings._iDisplayStart ); | |
5909 * } ); | |
5910 */ | |
5911 this.fnSettings = function() | |
5912 { | |
5913 return _fnSettingsFromNode( this[_ext.iApiIndex] ); | |
5914 }; | |
5915 | |
5916 | |
5917 /** | |
5918 * Sort the table by a particular column | |
5919 * @param {int} iCol the data index to sort on. Note that this will not match the | |
5920 * 'display index' if you have hidden data entries | |
5921 * @dtopt API | |
5922 * @deprecated Since v1.10 | |
5923 * | |
5924 * @example | |
5925 * $(document).ready(function() { | |
5926 * var oTable = $('#example').dataTable(); | |
5927 * | |
5928 * // Sort immediately with columns 0 and 1 | |
5929 * oTable.fnSort( [ [0,'asc'], [1,'asc'] ] ); | |
5930 * } ); | |
5931 */ | |
5932 this.fnSort = function( aaSort ) | |
5933 { | |
5934 this.api( true ).order( aaSort ).draw(); | |
5935 }; | |
5936 | |
5937 | |
5938 /** | |
5939 * Attach a sort listener to an element for a given column | |
5940 * @param {node} nNode the element to attach the sort listener to | |
5941 * @param {int} iColumn the column that a click on this node will sort on | |
5942 * @param {function} [fnCallback] callback function when sort is run | |
5943 * @dtopt API | |
5944 * @deprecated Since v1.10 | |
5945 * | |
5946 * @example | |
5947 * $(document).ready(function() { | |
5948 * var oTable = $('#example').dataTable(); | |
5949 * | |
5950 * // Sort on column 1, when 'sorter' is clicked on | |
5951 * oTable.fnSortListener( document.getElementById('sorter'), 1 ); | |
5952 * } ); | |
5953 */ | |
5954 this.fnSortListener = function( nNode, iColumn, fnCallback ) | |
5955 { | |
5956 this.api( true ).order.listener( nNode, iColumn, fnCallback ); | |
5957 }; | |
5958 | |
5959 | |
5960 /** | |
5961 * Update a table cell or row - this method will accept either a single value to | |
5962 * update the cell with, an array of values with one element for each column or | |
5963 * an object in the same format as the original data source. The function is | |
5964 * self-referencing in order to make the multi column updates easier. | |
5965 * @param {object|array|string} mData Data to update the cell/row with | |
5966 * @param {node|int} mRow TR element you want to update or the aoData index | |
5967 * @param {int} [iColumn] The column to update, give as null or undefined to | |
5968 * update a whole row. | |
5969 * @param {bool} [bRedraw=true] Redraw the table or not | |
5970 * @param {bool} [bAction=true] Perform pre-draw actions or not | |
5971 * @returns {int} 0 on success, 1 on error | |
5972 * @dtopt API | |
5973 * @deprecated Since v1.10 | |
5974 * | |
5975 * @example | |
5976 * $(document).ready(function() { | |
5977 * var oTable = $('#example').dataTable(); | |
5978 * oTable.fnUpdate( 'Example update', 0, 0 ); // Single cell | |
5979 * oTable.fnUpdate( ['a', 'b', 'c', 'd', 'e'], $('tbody tr')[0] ); // Row | |
5980 * } ); | |
5981 */ | |
5982 this.fnUpdate = function( mData, mRow, iColumn, bRedraw, bAction ) | |
5983 { | |
5984 var api = this.api( true ); | |
5985 | |
5986 if ( iColumn === undefined || iColumn === null ) { | |
5987 api.row( mRow ).data( mData ); | |
5988 } | |
5989 else { | |
5990 api.cell( mRow, iColumn ).data( mData ); | |
5991 } | |
5992 | |
5993 if ( bAction === undefined || bAction ) { | |
5994 api.columns.adjust(); | |
5995 } | |
5996 | |
5997 if ( bRedraw === undefined || bRedraw ) { | |
5998 api.draw(); | |
5999 } | |
6000 return 0; | |
6001 }; | |
6002 | |
6003 | |
6004 /** | |
6005 * Provide a common method for plug-ins to check the version of DataTables being used, in order | |
6006 * to ensure compatibility. | |
6007 * @param {string} sVersion Version string to check for, in the format "X.Y.Z". Note that the | |
6008 * formats "X" and "X.Y" are also acceptable. | |
6009 * @returns {boolean} true if this version of DataTables is greater or equal to the required | |
6010 * version, or false if this version of DataTales is not suitable | |
6011 * @method | |
6012 * @dtopt API | |
6013 * @deprecated Since v1.10 | |
6014 * | |
6015 * @example | |
6016 * $(document).ready(function() { | |
6017 * var oTable = $('#example').dataTable(); | |
6018 * alert( oTable.fnVersionCheck( '1.9.0' ) ); | |
6019 * } ); | |
6020 */ | |
6021 this.fnVersionCheck = _ext.fnVersionCheck; | |
6022 | |
6023 | |
6024 var _that = this; | |
6025 var emptyInit = options === undefined; | |
6026 var len = this.length; | |
6027 | |
6028 if ( emptyInit ) { | |
6029 options = {}; | |
6030 } | |
6031 | |
6032 this.oApi = this.internal = _ext.internal; | |
6033 | |
6034 // Extend with old style plug-in API methods | |
6035 for ( var fn in DataTable.ext.internal ) { | |
6036 if ( fn ) { | |
6037 this[fn] = _fnExternApiFunc(fn); | |
6038 } | |
6039 } | |
6040 | |
6041 this.each(function() { | |
6042 // For each initialisation we want to give it a clean initialisation | |
6043 // object that can be bashed around | |
6044 var o = {}; | |
6045 var oInit = len > 1 ? // optimisation for single table case | |
6046 _fnExtend( o, options, true ) : | |
6047 options; | |
6048 | |
6049 /*global oInit,_that,emptyInit*/ | |
6050 var i=0, iLen, j, jLen, k, kLen; | |
6051 var sId = this.getAttribute( 'id' ); | |
6052 var bInitHandedOff = false; | |
6053 var defaults = DataTable.defaults; | |
6054 | |
6055 | |
6056 /* Sanity check */ | |
6057 if ( this.nodeName.toLowerCase() != 'table' ) | |
6058 { | |
6059 _fnLog( null, 0, 'Non-table node initialisation ('+this.nodeName+')', 2 ); | |
6060 return; | |
6061 } | |
6062 | |
6063 /* Backwards compatibility for the defaults */ | |
6064 _fnCompatOpts( defaults ); | |
6065 _fnCompatCols( defaults.column ); | |
6066 | |
6067 /* Convert the camel-case defaults to Hungarian */ | |
6068 _fnCamelToHungarian( defaults, defaults, true ); | |
6069 _fnCamelToHungarian( defaults.column, defaults.column, true ); | |
6070 | |
6071 /* Setting up the initialisation object */ | |
6072 _fnCamelToHungarian( defaults, oInit ); | |
6073 | |
6074 /* Check to see if we are re-initialising a table */ | |
6075 var allSettings = DataTable.settings; | |
6076 for ( i=0, iLen=allSettings.length ; i<iLen ; i++ ) | |
6077 { | |
6078 /* Base check on table node */ | |
6079 if ( allSettings[i].nTable == this ) | |
6080 { | |
6081 var bRetrieve = oInit.bRetrieve !== undefined ? oInit.bRetrieve : defaults.bRetrieve; | |
6082 var bDestroy = oInit.bDestroy !== undefined ? oInit.bDestroy : defaults.bDestroy; | |
6083 | |
6084 if ( emptyInit || bRetrieve ) | |
6085 { | |
6086 return allSettings[i].oInstance; | |
6087 } | |
6088 else if ( bDestroy ) | |
6089 { | |
6090 allSettings[i].oInstance.fnDestroy(); | |
6091 break; | |
6092 } | |
6093 else | |
6094 { | |
6095 _fnLog( allSettings[i], 0, 'Cannot reinitialise DataTable', 3 ); | |
6096 return; | |
6097 } | |
6098 } | |
6099 | |
6100 /* If the element we are initialising has the same ID as a table which was previously | |
6101 * initialised, but the table nodes don't match (from before) then we destroy the old | |
6102 * instance by simply deleting it. This is under the assumption that the table has been | |
6103 * destroyed by other methods. Anyone using non-id selectors will need to do this manually | |
6104 */ | |
6105 if ( allSettings[i].sTableId == this.id ) | |
6106 { | |
6107 allSettings.splice( i, 1 ); | |
6108 break; | |
6109 } | |
6110 } | |
6111 | |
6112 /* Ensure the table has an ID - required for accessibility */ | |
6113 if ( sId === null || sId === "" ) | |
6114 { | |
6115 sId = "DataTables_Table_"+(DataTable.ext._unique++); | |
6116 this.id = sId; | |
6117 } | |
6118 | |
6119 /* Create the settings object for this table and set some of the default parameters */ | |
6120 var oSettings = $.extend( true, {}, DataTable.models.oSettings, { | |
6121 "nTable": this, | |
6122 "oApi": _that.internal, | |
6123 "oInit": oInit, | |
6124 "sDestroyWidth": $(this)[0].style.width, | |
6125 "sInstance": sId, | |
6126 "sTableId": sId | |
6127 } ); | |
6128 allSettings.push( oSettings ); | |
6129 | |
6130 // Need to add the instance after the instance after the settings object has been added | |
6131 // to the settings array, so we can self reference the table instance if more than one | |
6132 oSettings.oInstance = (_that.length===1) ? _that : $(this).dataTable(); | |
6133 | |
6134 // Backwards compatibility, before we apply all the defaults | |
6135 _fnCompatOpts( oInit ); | |
6136 | |
6137 if ( oInit.oLanguage ) | |
6138 { | |
6139 _fnLanguageCompat( oInit.oLanguage ); | |
6140 } | |
6141 | |
6142 // If the length menu is given, but the init display length is not, use the length menu | |
6143 if ( oInit.aLengthMenu && ! oInit.iDisplayLength ) | |
6144 { | |
6145 oInit.iDisplayLength = $.isArray( oInit.aLengthMenu[0] ) ? | |
6146 oInit.aLengthMenu[0][0] : oInit.aLengthMenu[0]; | |
6147 } | |
6148 | |
6149 // Apply the defaults and init options to make a single init object will all | |
6150 // options defined from defaults and instance options. | |
6151 oInit = _fnExtend( $.extend( true, {}, defaults ), oInit ); | |
6152 | |
6153 | |
6154 // Map the initialisation options onto the settings object | |
6155 _fnMap( oSettings.oFeatures, oInit, [ | |
6156 "bPaginate", | |
6157 "bLengthChange", | |
6158 "bFilter", | |
6159 "bSort", | |
6160 "bSortMulti", | |
6161 "bInfo", | |
6162 "bProcessing", | |
6163 "bAutoWidth", | |
6164 "bSortClasses", | |
6165 "bServerSide", | |
6166 "bDeferRender" | |
6167 ] ); | |
6168 _fnMap( oSettings, oInit, [ | |
6169 "asStripeClasses", | |
6170 "ajax", | |
6171 "fnServerData", | |
6172 "fnFormatNumber", | |
6173 "sServerMethod", | |
6174 "aaSorting", | |
6175 "aaSortingFixed", | |
6176 "aLengthMenu", | |
6177 "sPaginationType", | |
6178 "sAjaxSource", | |
6179 "sAjaxDataProp", | |
6180 "iStateDuration", | |
6181 "sDom", | |
6182 "bSortCellsTop", | |
6183 "iTabIndex", | |
6184 "fnStateLoadCallback", | |
6185 "fnStateSaveCallback", | |
6186 "renderer", | |
6187 "searchDelay", | |
6188 [ "iCookieDuration", "iStateDuration" ], // backwards compat | |
6189 [ "oSearch", "oPreviousSearch" ], | |
6190 [ "aoSearchCols", "aoPreSearchCols" ], | |
6191 [ "iDisplayLength", "_iDisplayLength" ], | |
6192 [ "bJQueryUI", "bJUI" ] | |
6193 ] ); | |
6194 _fnMap( oSettings.oScroll, oInit, [ | |
6195 [ "sScrollX", "sX" ], | |
6196 [ "sScrollXInner", "sXInner" ], | |
6197 [ "sScrollY", "sY" ], | |
6198 [ "bScrollCollapse", "bCollapse" ] | |
6199 ] ); | |
6200 _fnMap( oSettings.oLanguage, oInit, "fnInfoCallback" ); | |
6201 | |
6202 /* Callback functions which are array driven */ | |
6203 _fnCallbackReg( oSettings, 'aoDrawCallback', oInit.fnDrawCallback, 'user' ); | |
6204 _fnCallbackReg( oSettings, 'aoServerParams', oInit.fnServerParams, 'user' ); | |
6205 _fnCallbackReg( oSettings, 'aoStateSaveParams', oInit.fnStateSaveParams, 'user' ); | |
6206 _fnCallbackReg( oSettings, 'aoStateLoadParams', oInit.fnStateLoadParams, 'user' ); | |
6207 _fnCallbackReg( oSettings, 'aoStateLoaded', oInit.fnStateLoaded, 'user' ); | |
6208 _fnCallbackReg( oSettings, 'aoRowCallback', oInit.fnRowCallback, 'user' ); | |
6209 _fnCallbackReg( oSettings, 'aoRowCreatedCallback', oInit.fnCreatedRow, 'user' ); | |
6210 _fnCallbackReg( oSettings, 'aoHeaderCallback', oInit.fnHeaderCallback, 'user' ); | |
6211 _fnCallbackReg( oSettings, 'aoFooterCallback', oInit.fnFooterCallback, 'user' ); | |
6212 _fnCallbackReg( oSettings, 'aoInitComplete', oInit.fnInitComplete, 'user' ); | |
6213 _fnCallbackReg( oSettings, 'aoPreDrawCallback', oInit.fnPreDrawCallback, 'user' ); | |
6214 | |
6215 var oClasses = oSettings.oClasses; | |
6216 | |
6217 // @todo Remove in 1.11 | |
6218 if ( oInit.bJQueryUI ) | |
6219 { | |
6220 /* Use the JUI classes object for display. You could clone the oStdClasses object if | |
6221 * you want to have multiple tables with multiple independent classes | |
6222 */ | |
6223 $.extend( oClasses, DataTable.ext.oJUIClasses, oInit.oClasses ); | |
6224 | |
6225 if ( oInit.sDom === defaults.sDom && defaults.sDom === "lfrtip" ) | |
6226 { | |
6227 /* Set the DOM to use a layout suitable for jQuery UI's theming */ | |
6228 oSettings.sDom = '<"H"lfr>t<"F"ip>'; | |
6229 } | |
6230 | |
6231 if ( ! oSettings.renderer ) { | |
6232 oSettings.renderer = 'jqueryui'; | |
6233 } | |
6234 else if ( $.isPlainObject( oSettings.renderer ) && ! oSettings.renderer.header ) { | |
6235 oSettings.renderer.header = 'jqueryui'; | |
6236 } | |
6237 } | |
6238 else | |
6239 { | |
6240 $.extend( oClasses, DataTable.ext.classes, oInit.oClasses ); | |
6241 } | |
6242 $(this).addClass( oClasses.sTable ); | |
6243 | |
6244 /* Calculate the scroll bar width and cache it for use later on */ | |
6245 if ( oSettings.oScroll.sX !== "" || oSettings.oScroll.sY !== "" ) | |
6246 { | |
6247 oSettings.oScroll.iBarWidth = _fnScrollBarWidth(); | |
6248 } | |
6249 if ( oSettings.oScroll.sX === true ) { // Easy initialisation of x-scrolling | |
6250 oSettings.oScroll.sX = '100%'; | |
6251 } | |
6252 | |
6253 if ( oSettings.iInitDisplayStart === undefined ) | |
6254 { | |
6255 /* Display start point, taking into account the save saving */ | |
6256 oSettings.iInitDisplayStart = oInit.iDisplayStart; | |
6257 oSettings._iDisplayStart = oInit.iDisplayStart; | |
6258 } | |
6259 | |
6260 if ( oInit.iDeferLoading !== null ) | |
6261 { | |
6262 oSettings.bDeferLoading = true; | |
6263 var tmp = $.isArray( oInit.iDeferLoading ); | |
6264 oSettings._iRecordsDisplay = tmp ? oInit.iDeferLoading[0] : oInit.iDeferLoading; | |
6265 oSettings._iRecordsTotal = tmp ? oInit.iDeferLoading[1] : oInit.iDeferLoading; | |
6266 } | |
6267 | |
6268 /* Language definitions */ | |
6269 var oLanguage = oSettings.oLanguage; | |
6270 $.extend( true, oLanguage, oInit.oLanguage ); | |
6271 | |
6272 if ( oLanguage.sUrl !== "" ) | |
6273 { | |
6274 /* Get the language definitions from a file - because this Ajax call makes the language | |
6275 * get async to the remainder of this function we use bInitHandedOff to indicate that | |
6276 * _fnInitialise will be fired by the returned Ajax handler, rather than the constructor | |
6277 */ | |
6278 $.ajax( { | |
6279 dataType: 'json', | |
6280 url: oLanguage.sUrl, | |
6281 success: function ( json ) { | |
6282 _fnLanguageCompat( json ); | |
6283 _fnCamelToHungarian( defaults.oLanguage, json ); | |
6284 $.extend( true, oLanguage, json ); | |
6285 _fnInitialise( oSettings ); | |
6286 }, | |
6287 error: function () { | |
6288 // Error occurred loading language file, continue on as best we can | |
6289 _fnInitialise( oSettings ); | |
6290 } | |
6291 } ); | |
6292 bInitHandedOff = true; | |
6293 } | |
6294 | |
6295 /* | |
6296 * Stripes | |
6297 */ | |
6298 if ( oInit.asStripeClasses === null ) | |
6299 { | |
6300 oSettings.asStripeClasses =[ | |
6301 oClasses.sStripeOdd, | |
6302 oClasses.sStripeEven | |
6303 ]; | |
6304 } | |
6305 | |
6306 /* Remove row stripe classes if they are already on the table row */ | |
6307 var stripeClasses = oSettings.asStripeClasses; | |
6308 var rowOne = $('tbody tr:eq(0)', this); | |
6309 if ( $.inArray( true, $.map( stripeClasses, function(el, i) { | |
6310 return rowOne.hasClass(el); | |
6311 } ) ) !== -1 ) { | |
6312 $('tbody tr', this).removeClass( stripeClasses.join(' ') ); | |
6313 oSettings.asDestroyStripes = stripeClasses.slice(); | |
6314 } | |
6315 | |
6316 /* | |
6317 * Columns | |
6318 * See if we should load columns automatically or use defined ones | |
6319 */ | |
6320 var anThs = []; | |
6321 var aoColumnsInit; | |
6322 var nThead = this.getElementsByTagName('thead'); | |
6323 if ( nThead.length !== 0 ) | |
6324 { | |
6325 _fnDetectHeader( oSettings.aoHeader, nThead[0] ); | |
6326 anThs = _fnGetUniqueThs( oSettings ); | |
6327 } | |
6328 | |
6329 /* If not given a column array, generate one with nulls */ | |
6330 if ( oInit.aoColumns === null ) | |
6331 { | |
6332 aoColumnsInit = []; | |
6333 for ( i=0, iLen=anThs.length ; i<iLen ; i++ ) | |
6334 { | |
6335 aoColumnsInit.push( null ); | |
6336 } | |
6337 } | |
6338 else | |
6339 { | |
6340 aoColumnsInit = oInit.aoColumns; | |
6341 } | |
6342 | |
6343 /* Add the columns */ | |
6344 for ( i=0, iLen=aoColumnsInit.length ; i<iLen ; i++ ) | |
6345 { | |
6346 _fnAddColumn( oSettings, anThs ? anThs[i] : null ); | |
6347 } | |
6348 | |
6349 /* Apply the column definitions */ | |
6350 _fnApplyColumnDefs( oSettings, oInit.aoColumnDefs, aoColumnsInit, function (iCol, oDef) { | |
6351 _fnColumnOptions( oSettings, iCol, oDef ); | |
6352 } ); | |
6353 | |
6354 /* HTML5 attribute detection - build an mData object automatically if the | |
6355 * attributes are found | |
6356 */ | |
6357 if ( rowOne.length ) { | |
6358 var a = function ( cell, name ) { | |
6359 return cell.getAttribute( 'data-'+name ) ? name : null; | |
6360 }; | |
6361 | |
6362 $.each( _fnGetRowElements( oSettings, rowOne[0] ).cells, function (i, cell) { | |
6363 var col = oSettings.aoColumns[i]; | |
6364 | |
6365 if ( col.mData === i ) { | |
6366 var sort = a( cell, 'sort' ) || a( cell, 'order' ); | |
6367 var filter = a( cell, 'filter' ) || a( cell, 'search' ); | |
6368 | |
6369 if ( sort !== null || filter !== null ) { | |
6370 col.mData = { | |
6371 _: i+'.display', | |
6372 sort: sort !== null ? i+'.@data-'+sort : undefined, | |
6373 type: sort !== null ? i+'.@data-'+sort : undefined, | |
6374 filter: filter !== null ? i+'.@data-'+filter : undefined | |
6375 }; | |
6376 | |
6377 _fnColumnOptions( oSettings, i ); | |
6378 } | |
6379 } | |
6380 } ); | |
6381 } | |
6382 | |
6383 var features = oSettings.oFeatures; | |
6384 | |
6385 /* Must be done after everything which can be overridden by the state saving! */ | |
6386 if ( oInit.bStateSave ) | |
6387 { | |
6388 features.bStateSave = true; | |
6389 _fnLoadState( oSettings, oInit ); | |
6390 _fnCallbackReg( oSettings, 'aoDrawCallback', _fnSaveState, 'state_save' ); | |
6391 } | |
6392 | |
6393 | |
6394 /* | |
6395 * Sorting | |
6396 * @todo For modularisation (1.11) this needs to do into a sort start up handler | |
6397 */ | |
6398 | |
6399 // If aaSorting is not defined, then we use the first indicator in asSorting | |
6400 // in case that has been altered, so the default sort reflects that option | |
6401 if ( oInit.aaSorting === undefined ) | |
6402 { | |
6403 var sorting = oSettings.aaSorting; | |
6404 for ( i=0, iLen=sorting.length ; i<iLen ; i++ ) | |
6405 { | |
6406 sorting[i][1] = oSettings.aoColumns[ i ].asSorting[0]; | |
6407 } | |
6408 } | |
6409 | |
6410 /* Do a first pass on the sorting classes (allows any size changes to be taken into | |
6411 * account, and also will apply sorting disabled classes if disabled | |
6412 */ | |
6413 _fnSortingClasses( oSettings ); | |
6414 | |
6415 if ( features.bSort ) | |
6416 { | |
6417 _fnCallbackReg( oSettings, 'aoDrawCallback', function () { | |
6418 if ( oSettings.bSorted ) { | |
6419 var aSort = _fnSortFlatten( oSettings ); | |
6420 var sortedColumns = {}; | |
6421 | |
6422 $.each( aSort, function (i, val) { | |
6423 sortedColumns[ val.src ] = val.dir; | |
6424 } ); | |
6425 | |
6426 _fnCallbackFire( oSettings, null, 'order', [oSettings, aSort, sortedColumns] ); | |
6427 _fnSortAria( oSettings ); | |
6428 } | |
6429 } ); | |
6430 } | |
6431 | |
6432 _fnCallbackReg( oSettings, 'aoDrawCallback', function () { | |
6433 if ( oSettings.bSorted || _fnDataSource( oSettings ) === 'ssp' || features.bDeferRender ) { | |
6434 _fnSortingClasses( oSettings ); | |
6435 } | |
6436 }, 'sc' ); | |
6437 | |
6438 | |
6439 /* | |
6440 * Final init | |
6441 * Cache the header, body and footer as required, creating them if needed | |
6442 */ | |
6443 | |
6444 /* Browser support detection */ | |
6445 _fnBrowserDetect( oSettings ); | |
6446 | |
6447 // Work around for Webkit bug 83867 - store the caption-side before removing from doc | |
6448 var captions = $(this).children('caption').each( function () { | |
6449 this._captionSide = $(this).css('caption-side'); | |
6450 } ); | |
6451 | |
6452 var thead = $(this).children('thead'); | |
6453 if ( thead.length === 0 ) | |
6454 { | |
6455 thead = $('<thead/>').appendTo(this); | |
6456 } | |
6457 oSettings.nTHead = thead[0]; | |
6458 | |
6459 var tbody = $(this).children('tbody'); | |
6460 if ( tbody.length === 0 ) | |
6461 { | |
6462 tbody = $('<tbody/>').appendTo(this); | |
6463 } | |
6464 oSettings.nTBody = tbody[0]; | |
6465 | |
6466 var tfoot = $(this).children('tfoot'); | |
6467 if ( tfoot.length === 0 && captions.length > 0 && (oSettings.oScroll.sX !== "" || oSettings.oScroll.sY !== "") ) | |
6468 { | |
6469 // If we are a scrolling table, and no footer has been given, then we need to create | |
6470 // a tfoot element for the caption element to be appended to | |
6471 tfoot = $('<tfoot/>').appendTo(this); | |
6472 } | |
6473 | |
6474 if ( tfoot.length === 0 || tfoot.children().length === 0 ) { | |
6475 $(this).addClass( oClasses.sNoFooter ); | |
6476 } | |
6477 else if ( tfoot.length > 0 ) { | |
6478 oSettings.nTFoot = tfoot[0]; | |
6479 _fnDetectHeader( oSettings.aoFooter, oSettings.nTFoot ); | |
6480 } | |
6481 | |
6482 /* Check if there is data passing into the constructor */ | |
6483 if ( oInit.aaData ) | |
6484 { | |
6485 for ( i=0 ; i<oInit.aaData.length ; i++ ) | |
6486 { | |
6487 _fnAddData( oSettings, oInit.aaData[ i ] ); | |
6488 } | |
6489 } | |
6490 else if ( oSettings.bDeferLoading || _fnDataSource( oSettings ) == 'dom' ) | |
6491 { | |
6492 /* Grab the data from the page - only do this when deferred loading or no Ajax | |
6493 * source since there is no point in reading the DOM data if we are then going | |
6494 * to replace it with Ajax data | |
6495 */ | |
6496 _fnAddTr( oSettings, $(oSettings.nTBody).children('tr') ); | |
6497 } | |
6498 | |
6499 /* Copy the data index array */ | |
6500 oSettings.aiDisplay = oSettings.aiDisplayMaster.slice(); | |
6501 | |
6502 /* Initialisation complete - table can be drawn */ | |
6503 oSettings.bInitialised = true; | |
6504 | |
6505 /* Check if we need to initialise the table (it might not have been handed off to the | |
6506 * language processor) | |
6507 */ | |
6508 if ( bInitHandedOff === false ) | |
6509 { | |
6510 _fnInitialise( oSettings ); | |
6511 } | |
6512 } ); | |
6513 _that = null; | |
6514 return this; | |
6515 }; | |
6516 | |
6517 | |
6518 | |
6519 /** | |
6520 * Computed structure of the DataTables API, defined by the options passed to | |
6521 * `DataTable.Api.register()` when building the API. | |
6522 * | |
6523 * The structure is built in order to speed creation and extension of the Api | |
6524 * objects since the extensions are effectively pre-parsed. | |
6525 * | |
6526 * The array is an array of objects with the following structure, where this | |
6527 * base array represents the Api prototype base: | |
6528 * | |
6529 * [ | |
6530 * { | |
6531 * name: 'data' -- string - Property name | |
6532 * val: function () {}, -- function - Api method (or undefined if just an object | |
6533 * methodExt: [ ... ], -- array - Array of Api object definitions to extend the method result | |
6534 * propExt: [ ... ] -- array - Array of Api object definitions to extend the property | |
6535 * }, | |
6536 * { | |
6537 * name: 'row' | |
6538 * val: {}, | |
6539 * methodExt: [ ... ], | |
6540 * propExt: [ | |
6541 * { | |
6542 * name: 'data' | |
6543 * val: function () {}, | |
6544 * methodExt: [ ... ], | |
6545 * propExt: [ ... ] | |
6546 * }, | |
6547 * ... | |
6548 * ] | |
6549 * } | |
6550 * ] | |
6551 * | |
6552 * @type {Array} | |
6553 * @ignore | |
6554 */ | |
6555 var __apiStruct = []; | |
6556 | |
6557 | |
6558 /** | |
6559 * `Array.prototype` reference. | |
6560 * | |
6561 * @type object | |
6562 * @ignore | |
6563 */ | |
6564 var __arrayProto = Array.prototype; | |
6565 | |
6566 | |
6567 /** | |
6568 * Abstraction for `context` parameter of the `Api` constructor to allow it to | |
6569 * take several different forms for ease of use. | |
6570 * | |
6571 * Each of the input parameter types will be converted to a DataTables settings | |
6572 * object where possible. | |
6573 * | |
6574 * @param {string|node|jQuery|object} mixed DataTable identifier. Can be one | |
6575 * of: | |
6576 * | |
6577 * * `string` - jQuery selector. Any DataTables' matching the given selector | |
6578 * with be found and used. | |
6579 * * `node` - `TABLE` node which has already been formed into a DataTable. | |
6580 * * `jQuery` - A jQuery object of `TABLE` nodes. | |
6581 * * `object` - DataTables settings object | |
6582 * * `DataTables.Api` - API instance | |
6583 * @return {array|null} Matching DataTables settings objects. `null` or | |
6584 * `undefined` is returned if no matching DataTable is found. | |
6585 * @ignore | |
6586 */ | |
6587 var _toSettings = function ( mixed ) | |
6588 { | |
6589 var idx, jq; | |
6590 var settings = DataTable.settings; | |
6591 var tables = $.map( settings, function (el, i) { | |
6592 return el.nTable; | |
6593 } ); | |
6594 | |
6595 if ( ! mixed ) { | |
6596 return []; | |
6597 } | |
6598 else if ( mixed.nTable && mixed.oApi ) { | |
6599 // DataTables settings object | |
6600 return [ mixed ]; | |
6601 } | |
6602 else if ( mixed.nodeName && mixed.nodeName.toLowerCase() === 'table' ) { | |
6603 // Table node | |
6604 idx = $.inArray( mixed, tables ); | |
6605 return idx !== -1 ? [ settings[idx] ] : null; | |
6606 } | |
6607 else if ( mixed && typeof mixed.settings === 'function' ) { | |
6608 return mixed.settings().toArray(); | |
6609 } | |
6610 else if ( typeof mixed === 'string' ) { | |
6611 // jQuery selector | |
6612 jq = $(mixed); | |
6613 } | |
6614 else if ( mixed instanceof $ ) { | |
6615 // jQuery object (also DataTables instance) | |
6616 jq = mixed; | |
6617 } | |
6618 | |
6619 if ( jq ) { | |
6620 return jq.map( function(i) { | |
6621 idx = $.inArray( this, tables ); | |
6622 return idx !== -1 ? settings[idx] : null; | |
6623 } ).toArray(); | |
6624 } | |
6625 }; | |
6626 | |
6627 | |
6628 /** | |
6629 * DataTables API class - used to control and interface with one or more | |
6630 * DataTables enhanced tables. | |
6631 * | |
6632 * The API class is heavily based on jQuery, presenting a chainable interface | |
6633 * that you can use to interact with tables. Each instance of the API class has | |
6634 * a "context" - i.e. the tables that it will operate on. This could be a single | |
6635 * table, all tables on a page or a sub-set thereof. | |
6636 * | |
6637 * Additionally the API is designed to allow you to easily work with the data in | |
6638 * the tables, retrieving and manipulating it as required. This is done by | |
6639 * presenting the API class as an array like interface. The contents of the | |
6640 * array depend upon the actions requested by each method (for example | |
6641 * `rows().nodes()` will return an array of nodes, while `rows().data()` will | |
6642 * return an array of objects or arrays depending upon your table's | |
6643 * configuration). The API object has a number of array like methods (`push`, | |
6644 * `pop`, `reverse` etc) as well as additional helper methods (`each`, `pluck`, | |
6645 * `unique` etc) to assist your working with the data held in a table. | |
6646 * | |
6647 * Most methods (those which return an Api instance) are chainable, which means | |
6648 * the return from a method call also has all of the methods available that the | |
6649 * top level object had. For example, these two calls are equivalent: | |
6650 * | |
6651 * // Not chained | |
6652 * api.row.add( {...} ); | |
6653 * api.draw(); | |
6654 * | |
6655 * // Chained | |
6656 * api.row.add( {...} ).draw(); | |
6657 * | |
6658 * @class DataTable.Api | |
6659 * @param {array|object|string|jQuery} context DataTable identifier. This is | |
6660 * used to define which DataTables enhanced tables this API will operate on. | |
6661 * Can be one of: | |
6662 * | |
6663 * * `string` - jQuery selector. Any DataTables' matching the given selector | |
6664 * with be found and used. | |
6665 * * `node` - `TABLE` node which has already been formed into a DataTable. | |
6666 * * `jQuery` - A jQuery object of `TABLE` nodes. | |
6667 * * `object` - DataTables settings object | |
6668 * @param {array} [data] Data to initialise the Api instance with. | |
6669 * | |
6670 * @example | |
6671 * // Direct initialisation during DataTables construction | |
6672 * var api = $('#example').DataTable(); | |
6673 * | |
6674 * @example | |
6675 * // Initialisation using a DataTables jQuery object | |
6676 * var api = $('#example').dataTable().api(); | |
6677 * | |
6678 * @example | |
6679 * // Initialisation as a constructor | |
6680 * var api = new $.fn.DataTable.Api( 'table.dataTable' ); | |
6681 */ | |
6682 _Api = function ( context, data ) | |
6683 { | |
6684 if ( ! this instanceof _Api ) { | |
6685 throw 'DT API must be constructed as a new object'; | |
6686 // or should it do the 'new' for the caller? | |
6687 // return new _Api.apply( this, arguments ); | |
6688 } | |
6689 | |
6690 var settings = []; | |
6691 var ctxSettings = function ( o ) { | |
6692 var a = _toSettings( o ); | |
6693 if ( a ) { | |
6694 settings.push.apply( settings, a ); | |
6695 } | |
6696 }; | |
6697 | |
6698 if ( $.isArray( context ) ) { | |
6699 for ( var i=0, ien=context.length ; i<ien ; i++ ) { | |
6700 ctxSettings( context[i] ); | |
6701 } | |
6702 } | |
6703 else { | |
6704 ctxSettings( context ); | |
6705 } | |
6706 | |
6707 // Remove duplicates | |
6708 this.context = _unique( settings ); | |
6709 | |
6710 // Initial data | |
6711 if ( data ) { | |
6712 this.push.apply( this, data.toArray ? data.toArray() : data ); | |
6713 } | |
6714 | |
6715 // selector | |
6716 this.selector = { | |
6717 rows: null, | |
6718 cols: null, | |
6719 opts: null | |
6720 }; | |
6721 | |
6722 _Api.extend( this, this, __apiStruct ); | |
6723 }; | |
6724 | |
6725 DataTable.Api = _Api; | |
6726 | |
6727 _Api.prototype = /** @lends DataTables.Api */{ | |
6728 /** | |
6729 * Return a new Api instance, comprised of the data held in the current | |
6730 * instance, join with the other array(s) and/or value(s). | |
6731 * | |
6732 * An alias for `Array.prototype.concat`. | |
6733 * | |
6734 * @type method | |
6735 * @param {*} value1 Arrays and/or values to concatenate. | |
6736 * @param {*} [...] Additional arrays and/or values to concatenate. | |
6737 * @returns {DataTables.Api} New API instance, comprising of the combined | |
6738 * array. | |
6739 */ | |
6740 concat: __arrayProto.concat, | |
6741 | |
6742 | |
6743 context: [], // array of table settings objects | |
6744 | |
6745 | |
6746 each: function ( fn ) | |
6747 { | |
6748 for ( var i=0, ien=this.length ; i<ien; i++ ) { | |
6749 fn.call( this, this[i], i, this ); | |
6750 } | |
6751 | |
6752 return this; | |
6753 }, | |
6754 | |
6755 | |
6756 eq: function ( idx ) | |
6757 { | |
6758 var ctx = this.context; | |
6759 | |
6760 return ctx.length > idx ? | |
6761 new _Api( ctx[idx], this[idx] ) : | |
6762 null; | |
6763 }, | |
6764 | |
6765 | |
6766 filter: function ( fn ) | |
6767 { | |
6768 var a = []; | |
6769 | |
6770 if ( __arrayProto.filter ) { | |
6771 a = __arrayProto.filter.call( this, fn, this ); | |
6772 } | |
6773 else { | |
6774 // Compatibility for browsers without EMCA-252-5 (JS 1.6) | |
6775 for ( var i=0, ien=this.length ; i<ien ; i++ ) { | |
6776 if ( fn.call( this, this[i], i, this ) ) { | |
6777 a.push( this[i] ); | |
6778 } | |
6779 } | |
6780 } | |
6781 | |
6782 return new _Api( this.context, a ); | |
6783 }, | |
6784 | |
6785 | |
6786 flatten: function () | |
6787 { | |
6788 var a = []; | |
6789 return new _Api( this.context, a.concat.apply( a, this.toArray() ) ); | |
6790 }, | |
6791 | |
6792 | |
6793 join: __arrayProto.join, | |
6794 | |
6795 | |
6796 indexOf: __arrayProto.indexOf || function (obj, start) | |
6797 { | |
6798 for ( var i=(start || 0), ien=this.length ; i<ien ; i++ ) { | |
6799 if ( this[i] === obj ) { | |
6800 return i; | |
6801 } | |
6802 } | |
6803 return -1; | |
6804 }, | |
6805 | |
6806 // Note that `alwaysNew` is internal - use iteratorNew externally | |
6807 iterator: function ( flatten, type, fn, alwaysNew ) { | |
6808 var | |
6809 a = [], ret, | |
6810 i, ien, j, jen, | |
6811 context = this.context, | |
6812 rows, items, item, | |
6813 selector = this.selector; | |
6814 | |
6815 // Argument shifting | |
6816 if ( typeof flatten === 'string' ) { | |
6817 alwaysNew = fn; | |
6818 fn = type; | |
6819 type = flatten; | |
6820 flatten = false; | |
6821 } | |
6822 | |
6823 for ( i=0, ien=context.length ; i<ien ; i++ ) { | |
6824 var apiInst = new _Api( context[i] ); | |
6825 | |
6826 if ( type === 'table' ) { | |
6827 ret = fn.call( apiInst, context[i], i ); | |
6828 | |
6829 if ( ret !== undefined ) { | |
6830 a.push( ret ); | |
6831 } | |
6832 } | |
6833 else if ( type === 'columns' || type === 'rows' ) { | |
6834 // this has same length as context - one entry for each table | |
6835 ret = fn.call( apiInst, context[i], this[i], i ); | |
6836 | |
6837 if ( ret !== undefined ) { | |
6838 a.push( ret ); | |
6839 } | |
6840 } | |
6841 else if ( type === 'column' || type === 'column-rows' || type === 'row' || type === 'cell' ) { | |
6842 // columns and rows share the same structure. | |
6843 // 'this' is an array of column indexes for each context | |
6844 items = this[i]; | |
6845 | |
6846 if ( type === 'column-rows' ) { | |
6847 rows = _selector_row_indexes( context[i], selector.opts ); | |
6848 } | |
6849 | |
6850 for ( j=0, jen=items.length ; j<jen ; j++ ) { | |
6851 item = items[j]; | |
6852 | |
6853 if ( type === 'cell' ) { | |
6854 ret = fn.call( apiInst, context[i], item.row, item.column, i, j ); | |
6855 } | |
6856 else { | |
6857 ret = fn.call( apiInst, context[i], item, i, j, rows ); | |
6858 } | |
6859 | |
6860 if ( ret !== undefined ) { | |
6861 a.push( ret ); | |
6862 } | |
6863 } | |
6864 } | |
6865 } | |
6866 | |
6867 if ( a.length || alwaysNew ) { | |
6868 var api = new _Api( context, flatten ? a.concat.apply( [], a ) : a ); | |
6869 var apiSelector = api.selector; | |
6870 apiSelector.rows = selector.rows; | |
6871 apiSelector.cols = selector.cols; | |
6872 apiSelector.opts = selector.opts; | |
6873 return api; | |
6874 } | |
6875 return this; | |
6876 }, | |
6877 | |
6878 | |
6879 lastIndexOf: __arrayProto.lastIndexOf || function (obj, start) | |
6880 { | |
6881 // Bit cheeky... | |
6882 return this.indexOf.apply( this.toArray.reverse(), arguments ); | |
6883 }, | |
6884 | |
6885 | |
6886 length: 0, | |
6887 | |
6888 | |
6889 map: function ( fn ) | |
6890 { | |
6891 var a = []; | |
6892 | |
6893 if ( __arrayProto.map ) { | |
6894 a = __arrayProto.map.call( this, fn, this ); | |
6895 } | |
6896 else { | |
6897 // Compatibility for browsers without EMCA-252-5 (JS 1.6) | |
6898 for ( var i=0, ien=this.length ; i<ien ; i++ ) { | |
6899 a.push( fn.call( this, this[i], i ) ); | |
6900 } | |
6901 } | |
6902 | |
6903 return new _Api( this.context, a ); | |
6904 }, | |
6905 | |
6906 | |
6907 pluck: function ( prop ) | |
6908 { | |
6909 return this.map( function ( el ) { | |
6910 return el[ prop ]; | |
6911 } ); | |
6912 }, | |
6913 | |
6914 pop: __arrayProto.pop, | |
6915 | |
6916 | |
6917 push: __arrayProto.push, | |
6918 | |
6919 | |
6920 // Does not return an API instance | |
6921 reduce: __arrayProto.reduce || function ( fn, init ) | |
6922 { | |
6923 return _fnReduce( this, fn, init, 0, this.length, 1 ); | |
6924 }, | |
6925 | |
6926 | |
6927 reduceRight: __arrayProto.reduceRight || function ( fn, init ) | |
6928 { | |
6929 return _fnReduce( this, fn, init, this.length-1, -1, -1 ); | |
6930 }, | |
6931 | |
6932 | |
6933 reverse: __arrayProto.reverse, | |
6934 | |
6935 | |
6936 // Object with rows, columns and opts | |
6937 selector: null, | |
6938 | |
6939 | |
6940 shift: __arrayProto.shift, | |
6941 | |
6942 | |
6943 sort: __arrayProto.sort, // ? name - order? | |
6944 | |
6945 | |
6946 splice: __arrayProto.splice, | |
6947 | |
6948 | |
6949 toArray: function () | |
6950 { | |
6951 return __arrayProto.slice.call( this ); | |
6952 }, | |
6953 | |
6954 | |
6955 to$: function () | |
6956 { | |
6957 return $( this ); | |
6958 }, | |
6959 | |
6960 | |
6961 toJQuery: function () | |
6962 { | |
6963 return $( this ); | |
6964 }, | |
6965 | |
6966 | |
6967 unique: function () | |
6968 { | |
6969 return new _Api( this.context, _unique(this) ); | |
6970 }, | |
6971 | |
6972 | |
6973 unshift: __arrayProto.unshift | |
6974 }; | |
6975 | |
6976 | |
6977 _Api.extend = function ( scope, obj, ext ) | |
6978 { | |
6979 // Only extend API instances and static properties of the API | |
6980 if ( ! obj || ( ! (obj instanceof _Api) && ! obj.__dt_wrapper ) ) { | |
6981 return; | |
6982 } | |
6983 | |
6984 var | |
6985 i, ien, | |
6986 j, jen, | |
6987 struct, inner, | |
6988 methodScoping = function ( scope, fn, struc ) { | |
6989 return function () { | |
6990 var ret = fn.apply( scope, arguments ); | |
6991 | |
6992 // Method extension | |
6993 _Api.extend( ret, ret, struc.methodExt ); | |
6994 return ret; | |
6995 }; | |
6996 }; | |
6997 | |
6998 for ( i=0, ien=ext.length ; i<ien ; i++ ) { | |
6999 struct = ext[i]; | |
7000 | |
7001 // Value | |
7002 obj[ struct.name ] = typeof struct.val === 'function' ? | |
7003 methodScoping( scope, struct.val, struct ) : | |
7004 $.isPlainObject( struct.val ) ? | |
7005 {} : | |
7006 struct.val; | |
7007 | |
7008 obj[ struct.name ].__dt_wrapper = true; | |
7009 | |
7010 // Property extension | |
7011 _Api.extend( scope, obj[ struct.name ], struct.propExt ); | |
7012 } | |
7013 }; | |
7014 | |
7015 | |
7016 // @todo - Is there need for an augment function? | |
7017 // _Api.augment = function ( inst, name ) | |
7018 // { | |
7019 // // Find src object in the structure from the name | |
7020 // var parts = name.split('.'); | |
7021 | |
7022 // _Api.extend( inst, obj ); | |
7023 // }; | |
7024 | |
7025 | |
7026 // [ | |
7027 // { | |
7028 // name: 'data' -- string - Property name | |
7029 // val: function () {}, -- function - Api method (or undefined if just an object | |
7030 // methodExt: [ ... ], -- array - Array of Api object definitions to extend the method result | |
7031 // propExt: [ ... ] -- array - Array of Api object definitions to extend the property | |
7032 // }, | |
7033 // { | |
7034 // name: 'row' | |
7035 // val: {}, | |
7036 // methodExt: [ ... ], | |
7037 // propExt: [ | |
7038 // { | |
7039 // name: 'data' | |
7040 // val: function () {}, | |
7041 // methodExt: [ ... ], | |
7042 // propExt: [ ... ] | |
7043 // }, | |
7044 // ... | |
7045 // ] | |
7046 // } | |
7047 // ] | |
7048 | |
7049 _Api.register = _api_register = function ( name, val ) | |
7050 { | |
7051 if ( $.isArray( name ) ) { | |
7052 for ( var j=0, jen=name.length ; j<jen ; j++ ) { | |
7053 _Api.register( name[j], val ); | |
7054 } | |
7055 return; | |
7056 } | |
7057 | |
7058 var | |
7059 i, ien, | |
7060 heir = name.split('.'), | |
7061 struct = __apiStruct, | |
7062 key, method; | |
7063 | |
7064 var find = function ( src, name ) { | |
7065 for ( var i=0, ien=src.length ; i<ien ; i++ ) { | |
7066 if ( src[i].name === name ) { | |
7067 return src[i]; | |
7068 } | |
7069 } | |
7070 return null; | |
7071 }; | |
7072 | |
7073 for ( i=0, ien=heir.length ; i<ien ; i++ ) { | |
7074 method = heir[i].indexOf('()') !== -1; | |
7075 key = method ? | |
7076 heir[i].replace('()', '') : | |
7077 heir[i]; | |
7078 | |
7079 var src = find( struct, key ); | |
7080 if ( ! src ) { | |
7081 src = { | |
7082 name: key, | |
7083 val: {}, | |
7084 methodExt: [], | |
7085 propExt: [] | |
7086 }; | |
7087 struct.push( src ); | |
7088 } | |
7089 | |
7090 if ( i === ien-1 ) { | |
7091 src.val = val; | |
7092 } | |
7093 else { | |
7094 struct = method ? | |
7095 src.methodExt : | |
7096 src.propExt; | |
7097 } | |
7098 } | |
7099 }; | |
7100 | |
7101 | |
7102 _Api.registerPlural = _api_registerPlural = function ( pluralName, singularName, val ) { | |
7103 _Api.register( pluralName, val ); | |
7104 | |
7105 _Api.register( singularName, function () { | |
7106 var ret = val.apply( this, arguments ); | |
7107 | |
7108 if ( ret === this ) { | |
7109 // Returned item is the API instance that was passed in, return it | |
7110 return this; | |
7111 } | |
7112 else if ( ret instanceof _Api ) { | |
7113 // New API instance returned, want the value from the first item | |
7114 // in the returned array for the singular result. | |
7115 return ret.length ? | |
7116 $.isArray( ret[0] ) ? | |
7117 new _Api( ret.context, ret[0] ) : // Array results are 'enhanced' | |
7118 ret[0] : | |
7119 undefined; | |
7120 } | |
7121 | |
7122 // Non-API return - just fire it back | |
7123 return ret; | |
7124 } ); | |
7125 }; | |
7126 | |
7127 | |
7128 /** | |
7129 * Selector for HTML tables. Apply the given selector to the give array of | |
7130 * DataTables settings objects. | |
7131 * | |
7132 * @param {string|integer} [selector] jQuery selector string or integer | |
7133 * @param {array} Array of DataTables settings objects to be filtered | |
7134 * @return {array} | |
7135 * @ignore | |
7136 */ | |
7137 var __table_selector = function ( selector, a ) | |
7138 { | |
7139 // Integer is used to pick out a table by index | |
7140 if ( typeof selector === 'number' ) { | |
7141 return [ a[ selector ] ]; | |
7142 } | |
7143 | |
7144 // Perform a jQuery selector on the table nodes | |
7145 var nodes = $.map( a, function (el, i) { | |
7146 return el.nTable; | |
7147 } ); | |
7148 | |
7149 return $(nodes) | |
7150 .filter( selector ) | |
7151 .map( function (i) { | |
7152 // Need to translate back from the table node to the settings | |
7153 var idx = $.inArray( this, nodes ); | |
7154 return a[ idx ]; | |
7155 } ) | |
7156 .toArray(); | |
7157 }; | |
7158 | |
7159 | |
7160 | |
7161 /** | |
7162 * Context selector for the API's context (i.e. the tables the API instance | |
7163 * refers to. | |
7164 * | |
7165 * @name DataTable.Api#tables | |
7166 * @param {string|integer} [selector] Selector to pick which tables the iterator | |
7167 * should operate on. If not given, all tables in the current context are | |
7168 * used. This can be given as a jQuery selector (for example `':gt(0)'`) to | |
7169 * select multiple tables or as an integer to select a single table. | |
7170 * @returns {DataTable.Api} Returns a new API instance if a selector is given. | |
7171 */ | |
7172 _api_register( 'tables()', function ( selector ) { | |
7173 // A new instance is created if there was a selector specified | |
7174 return selector ? | |
7175 new _Api( __table_selector( selector, this.context ) ) : | |
7176 this; | |
7177 } ); | |
7178 | |
7179 | |
7180 _api_register( 'table()', function ( selector ) { | |
7181 var tables = this.tables( selector ); | |
7182 var ctx = tables.context; | |
7183 | |
7184 // Truncate to the first matched table | |
7185 return ctx.length ? | |
7186 new _Api( ctx[0] ) : | |
7187 tables; | |
7188 } ); | |
7189 | |
7190 | |
7191 _api_registerPlural( 'tables().nodes()', 'table().node()' , function () { | |
7192 return this.iterator( 'table', function ( ctx ) { | |
7193 return ctx.nTable; | |
7194 }, 1 ); | |
7195 } ); | |
7196 | |
7197 | |
7198 _api_registerPlural( 'tables().body()', 'table().body()' , function () { | |
7199 return this.iterator( 'table', function ( ctx ) { | |
7200 return ctx.nTBody; | |
7201 }, 1 ); | |
7202 } ); | |
7203 | |
7204 | |
7205 _api_registerPlural( 'tables().header()', 'table().header()' , function () { | |
7206 return this.iterator( 'table', function ( ctx ) { | |
7207 return ctx.nTHead; | |
7208 }, 1 ); | |
7209 } ); | |
7210 | |
7211 | |
7212 _api_registerPlural( 'tables().footer()', 'table().footer()' , function () { | |
7213 return this.iterator( 'table', function ( ctx ) { | |
7214 return ctx.nTFoot; | |
7215 }, 1 ); | |
7216 } ); | |
7217 | |
7218 | |
7219 _api_registerPlural( 'tables().containers()', 'table().container()' , function () { | |
7220 return this.iterator( 'table', function ( ctx ) { | |
7221 return ctx.nTableWrapper; | |
7222 }, 1 ); | |
7223 } ); | |
7224 | |
7225 | |
7226 | |
7227 /** | |
7228 * Redraw the tables in the current context. | |
7229 * | |
7230 * @param {boolean} [reset=true] Reset (default) or hold the current paging | |
7231 * position. A full re-sort and re-filter is performed when this method is | |
7232 * called, which is why the pagination reset is the default action. | |
7233 * @returns {DataTables.Api} this | |
7234 */ | |
7235 _api_register( 'draw()', function ( resetPaging ) { | |
7236 return this.iterator( 'table', function ( settings ) { | |
7237 _fnReDraw( settings, resetPaging===false ); | |
7238 } ); | |
7239 } ); | |
7240 | |
7241 | |
7242 | |
7243 /** | |
7244 * Get the current page index. | |
7245 * | |
7246 * @return {integer} Current page index (zero based) | |
7247 *//** | |
7248 * Set the current page. | |
7249 * | |
7250 * Note that if you attempt to show a page which does not exist, DataTables will | |
7251 * not throw an error, but rather reset the paging. | |
7252 * | |
7253 * @param {integer|string} action The paging action to take. This can be one of: | |
7254 * * `integer` - The page index to jump to | |
7255 * * `string` - An action to take: | |
7256 * * `first` - Jump to first page. | |
7257 * * `next` - Jump to the next page | |
7258 * * `previous` - Jump to previous page | |
7259 * * `last` - Jump to the last page. | |
7260 * @returns {DataTables.Api} this | |
7261 */ | |
7262 _api_register( 'page()', function ( action ) { | |
7263 if ( action === undefined ) { | |
7264 return this.page.info().page; // not an expensive call | |
7265 } | |
7266 | |
7267 // else, have an action to take on all tables | |
7268 return this.iterator( 'table', function ( settings ) { | |
7269 _fnPageChange( settings, action ); | |
7270 } ); | |
7271 } ); | |
7272 | |
7273 | |
7274 /** | |
7275 * Paging information for the first table in the current context. | |
7276 * | |
7277 * If you require paging information for another table, use the `table()` method | |
7278 * with a suitable selector. | |
7279 * | |
7280 * @return {object} Object with the following properties set: | |
7281 * * `page` - Current page index (zero based - i.e. the first page is `0`) | |
7282 * * `pages` - Total number of pages | |
7283 * * `start` - Display index for the first record shown on the current page | |
7284 * * `end` - Display index for the last record shown on the current page | |
7285 * * `length` - Display length (number of records). Note that generally `start | |
7286 * + length = end`, but this is not always true, for example if there are | |
7287 * only 2 records to show on the final page, with a length of 10. | |
7288 * * `recordsTotal` - Full data set length | |
7289 * * `recordsDisplay` - Data set length once the current filtering criterion | |
7290 * are applied. | |
7291 */ | |
7292 _api_register( 'page.info()', function ( action ) { | |
7293 if ( this.context.length === 0 ) { | |
7294 return undefined; | |
7295 } | |
7296 | |
7297 var | |
7298 settings = this.context[0], | |
7299 start = settings._iDisplayStart, | |
7300 len = settings._iDisplayLength, | |
7301 visRecords = settings.fnRecordsDisplay(), | |
7302 all = len === -1; | |
7303 | |
7304 return { | |
7305 "page": all ? 0 : Math.floor( start / len ), | |
7306 "pages": all ? 1 : Math.ceil( visRecords / len ), | |
7307 "start": start, | |
7308 "end": settings.fnDisplayEnd(), | |
7309 "length": len, | |
7310 "recordsTotal": settings.fnRecordsTotal(), | |
7311 "recordsDisplay": visRecords | |
7312 }; | |
7313 } ); | |
7314 | |
7315 | |
7316 /** | |
7317 * Get the current page length. | |
7318 * | |
7319 * @return {integer} Current page length. Note `-1` indicates that all records | |
7320 * are to be shown. | |
7321 *//** | |
7322 * Set the current page length. | |
7323 * | |
7324 * @param {integer} Page length to set. Use `-1` to show all records. | |
7325 * @returns {DataTables.Api} this | |
7326 */ | |
7327 _api_register( 'page.len()', function ( len ) { | |
7328 // Note that we can't call this function 'length()' because `length` | |
7329 // is a Javascript property of functions which defines how many arguments | |
7330 // the function expects. | |
7331 if ( len === undefined ) { | |
7332 return this.context.length !== 0 ? | |
7333 this.context[0]._iDisplayLength : | |
7334 undefined; | |
7335 } | |
7336 | |
7337 // else, set the page length | |
7338 return this.iterator( 'table', function ( settings ) { | |
7339 _fnLengthChange( settings, len ); | |
7340 } ); | |
7341 } ); | |
7342 | |
7343 | |
7344 | |
7345 var __reload = function ( settings, holdPosition, callback ) { | |
7346 if ( _fnDataSource( settings ) == 'ssp' ) { | |
7347 _fnReDraw( settings, holdPosition ); | |
7348 } | |
7349 else { | |
7350 // Trigger xhr | |
7351 _fnProcessingDisplay( settings, true ); | |
7352 | |
7353 _fnBuildAjax( settings, [], function( json ) { | |
7354 _fnClearTable( settings ); | |
7355 | |
7356 var data = _fnAjaxDataSrc( settings, json ); | |
7357 for ( var i=0, ien=data.length ; i<ien ; i++ ) { | |
7358 _fnAddData( settings, data[i] ); | |
7359 } | |
7360 | |
7361 _fnReDraw( settings, holdPosition ); | |
7362 _fnProcessingDisplay( settings, false ); | |
7363 } ); | |
7364 } | |
7365 | |
7366 // Use the draw event to trigger a callback, regardless of if it is an async | |
7367 // or sync draw | |
7368 if ( callback ) { | |
7369 var api = new _Api( settings ); | |
7370 | |
7371 api.one( 'draw', function () { | |
7372 callback( api.ajax.json() ); | |
7373 } ); | |
7374 } | |
7375 }; | |
7376 | |
7377 | |
7378 /** | |
7379 * Get the JSON response from the last Ajax request that DataTables made to the | |
7380 * server. Note that this returns the JSON from the first table in the current | |
7381 * context. | |
7382 * | |
7383 * @return {object} JSON received from the server. | |
7384 */ | |
7385 _api_register( 'ajax.json()', function () { | |
7386 var ctx = this.context; | |
7387 | |
7388 if ( ctx.length > 0 ) { | |
7389 return ctx[0].json; | |
7390 } | |
7391 | |
7392 // else return undefined; | |
7393 } ); | |
7394 | |
7395 | |
7396 /** | |
7397 * Get the data submitted in the last Ajax request | |
7398 */ | |
7399 _api_register( 'ajax.params()', function () { | |
7400 var ctx = this.context; | |
7401 | |
7402 if ( ctx.length > 0 ) { | |
7403 return ctx[0].oAjaxData; | |
7404 } | |
7405 | |
7406 // else return undefined; | |
7407 } ); | |
7408 | |
7409 | |
7410 /** | |
7411 * Reload tables from the Ajax data source. Note that this function will | |
7412 * automatically re-draw the table when the remote data has been loaded. | |
7413 * | |
7414 * @param {boolean} [reset=true] Reset (default) or hold the current paging | |
7415 * position. A full re-sort and re-filter is performed when this method is | |
7416 * called, which is why the pagination reset is the default action. | |
7417 * @returns {DataTables.Api} this | |
7418 */ | |
7419 _api_register( 'ajax.reload()', function ( callback, resetPaging ) { | |
7420 return this.iterator( 'table', function (settings) { | |
7421 __reload( settings, resetPaging===false, callback ); | |
7422 } ); | |
7423 } ); | |
7424 | |
7425 | |
7426 /** | |
7427 * Get the current Ajax URL. Note that this returns the URL from the first | |
7428 * table in the current context. | |
7429 * | |
7430 * @return {string} Current Ajax source URL | |
7431 *//** | |
7432 * Set the Ajax URL. Note that this will set the URL for all tables in the | |
7433 * current context. | |
7434 * | |
7435 * @param {string} url URL to set. | |
7436 * @returns {DataTables.Api} this | |
7437 */ | |
7438 _api_register( 'ajax.url()', function ( url ) { | |
7439 var ctx = this.context; | |
7440 | |
7441 if ( url === undefined ) { | |
7442 // get | |
7443 if ( ctx.length === 0 ) { | |
7444 return undefined; | |
7445 } | |
7446 ctx = ctx[0]; | |
7447 | |
7448 return ctx.ajax ? | |
7449 $.isPlainObject( ctx.ajax ) ? | |
7450 ctx.ajax.url : | |
7451 ctx.ajax : | |
7452 ctx.sAjaxSource; | |
7453 } | |
7454 | |
7455 // set | |
7456 return this.iterator( 'table', function ( settings ) { | |
7457 if ( $.isPlainObject( settings.ajax ) ) { | |
7458 settings.ajax.url = url; | |
7459 } | |
7460 else { | |
7461 settings.ajax = url; | |
7462 } | |
7463 // No need to consider sAjaxSource here since DataTables gives priority | |
7464 // to `ajax` over `sAjaxSource`. So setting `ajax` here, renders any | |
7465 // value of `sAjaxSource` redundant. | |
7466 } ); | |
7467 } ); | |
7468 | |
7469 | |
7470 /** | |
7471 * Load data from the newly set Ajax URL. Note that this method is only | |
7472 * available when `ajax.url()` is used to set a URL. Additionally, this method | |
7473 * has the same effect as calling `ajax.reload()` but is provided for | |
7474 * convenience when setting a new URL. Like `ajax.reload()` it will | |
7475 * automatically redraw the table once the remote data has been loaded. | |
7476 * | |
7477 * @returns {DataTables.Api} this | |
7478 */ | |
7479 _api_register( 'ajax.url().load()', function ( callback, resetPaging ) { | |
7480 // Same as a reload, but makes sense to present it for easy access after a | |
7481 // url change | |
7482 return this.iterator( 'table', function ( ctx ) { | |
7483 __reload( ctx, resetPaging===false, callback ); | |
7484 } ); | |
7485 } ); | |
7486 | |
7487 | |
7488 | |
7489 | |
7490 var _selector_run = function ( selector, select ) | |
7491 { | |
7492 var | |
7493 out = [], res, | |
7494 a, i, ien, j, jen, | |
7495 selectorType = typeof selector; | |
7496 | |
7497 // Can't just check for isArray here, as an API or jQuery instance might be | |
7498 // given with their array like look | |
7499 if ( ! selector || selectorType === 'string' || selectorType === 'function' || selector.length === undefined ) { | |
7500 selector = [ selector ]; | |
7501 } | |
7502 | |
7503 for ( i=0, ien=selector.length ; i<ien ; i++ ) { | |
7504 a = selector[i] && selector[i].split ? | |
7505 selector[i].split(',') : | |
7506 [ selector[i] ]; | |
7507 | |
7508 for ( j=0, jen=a.length ; j<jen ; j++ ) { | |
7509 res = select( typeof a[j] === 'string' ? $.trim(a[j]) : a[j] ); | |
7510 | |
7511 if ( res && res.length ) { | |
7512 out.push.apply( out, res ); | |
7513 } | |
7514 } | |
7515 } | |
7516 | |
7517 return out; | |
7518 }; | |
7519 | |
7520 | |
7521 var _selector_opts = function ( opts ) | |
7522 { | |
7523 if ( ! opts ) { | |
7524 opts = {}; | |
7525 } | |
7526 | |
7527 // Backwards compatibility for 1.9- which used the terminology filter rather | |
7528 // than search | |
7529 if ( opts.filter && ! opts.search ) { | |
7530 opts.search = opts.filter; | |
7531 } | |
7532 | |
7533 return { | |
7534 search: opts.search || 'none', | |
7535 order: opts.order || 'current', | |
7536 page: opts.page || 'all' | |
7537 }; | |
7538 }; | |
7539 | |
7540 | |
7541 var _selector_first = function ( inst ) | |
7542 { | |
7543 // Reduce the API instance to the first item found | |
7544 for ( var i=0, ien=inst.length ; i<ien ; i++ ) { | |
7545 if ( inst[i].length > 0 ) { | |
7546 // Assign the first element to the first item in the instance | |
7547 // and truncate the instance and context | |
7548 inst[0] = inst[i]; | |
7549 inst.length = 1; | |
7550 inst.context = [ inst.context[i] ]; | |
7551 | |
7552 return inst; | |
7553 } | |
7554 } | |
7555 | |
7556 // Not found - return an empty instance | |
7557 inst.length = 0; | |
7558 return inst; | |
7559 }; | |
7560 | |
7561 | |
7562 var _selector_row_indexes = function ( settings, opts ) | |
7563 { | |
7564 var | |
7565 i, ien, tmp, a=[], | |
7566 displayFiltered = settings.aiDisplay, | |
7567 displayMaster = settings.aiDisplayMaster; | |
7568 | |
7569 var | |
7570 search = opts.search, // none, applied, removed | |
7571 order = opts.order, // applied, current, index (original - compatibility with 1.9) | |
7572 page = opts.page; // all, current | |
7573 | |
7574 if ( _fnDataSource( settings ) == 'ssp' ) { | |
7575 // In server-side processing mode, most options are irrelevant since | |
7576 // rows not shown don't exist and the index order is the applied order | |
7577 // Removed is a special case - for consistency just return an empty | |
7578 // array | |
7579 return search === 'removed' ? | |
7580 [] : | |
7581 _range( 0, displayMaster.length ); | |
7582 } | |
7583 else if ( page == 'current' ) { | |
7584 // Current page implies that order=current and fitler=applied, since it is | |
7585 // fairly senseless otherwise, regardless of what order and search actually | |
7586 // are | |
7587 for ( i=settings._iDisplayStart, ien=settings.fnDisplayEnd() ; i<ien ; i++ ) { | |
7588 a.push( displayFiltered[i] ); | |
7589 } | |
7590 } | |
7591 else if ( order == 'current' || order == 'applied' ) { | |
7592 a = search == 'none' ? | |
7593 displayMaster.slice() : // no search | |
7594 search == 'applied' ? | |
7595 displayFiltered.slice() : // applied search | |
7596 $.map( displayMaster, function (el, i) { // removed search | |
7597 return $.inArray( el, displayFiltered ) === -1 ? el : null; | |
7598 } ); | |
7599 } | |
7600 else if ( order == 'index' || order == 'original' ) { | |
7601 for ( i=0, ien=settings.aoData.length ; i<ien ; i++ ) { | |
7602 if ( search == 'none' ) { | |
7603 a.push( i ); | |
7604 } | |
7605 else { // applied | removed | |
7606 tmp = $.inArray( i, displayFiltered ); | |
7607 | |
7608 if ((tmp === -1 && search == 'removed') || | |
7609 (tmp >= 0 && search == 'applied') ) | |
7610 { | |
7611 a.push( i ); | |
7612 } | |
7613 } | |
7614 } | |
7615 } | |
7616 | |
7617 return a; | |
7618 }; | |
7619 | |
7620 | |
7621 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * | |
7622 * Rows | |
7623 * | |
7624 * {} - no selector - use all available rows | |
7625 * {integer} - row aoData index | |
7626 * {node} - TR node | |
7627 * {string} - jQuery selector to apply to the TR elements | |
7628 * {array} - jQuery array of nodes, or simply an array of TR nodes | |
7629 * | |
7630 */ | |
7631 | |
7632 | |
7633 var __row_selector = function ( settings, selector, opts ) | |
7634 { | |
7635 return _selector_run( selector, function ( sel ) { | |
7636 var selInt = _intVal( sel ); | |
7637 var i, ien; | |
7638 | |
7639 // Short cut - selector is a number and no options provided (default is | |
7640 // all records, so no need to check if the index is in there, since it | |
7641 // must be - dev error if the index doesn't exist). | |
7642 if ( selInt !== null && ! opts ) { | |
7643 return [ selInt ]; | |
7644 } | |
7645 | |
7646 var rows = _selector_row_indexes( settings, opts ); | |
7647 | |
7648 if ( selInt !== null && $.inArray( selInt, rows ) !== -1 ) { | |
7649 // Selector - integer | |
7650 return [ selInt ]; | |
7651 } | |
7652 else if ( ! sel ) { | |
7653 // Selector - none | |
7654 return rows; | |
7655 } | |
7656 | |
7657 // Selector - function | |
7658 if ( typeof sel === 'function' ) { | |
7659 return $.map( rows, function (idx) { | |
7660 var row = settings.aoData[ idx ]; | |
7661 return sel( idx, row._aData, row.nTr ) ? idx : null; | |
7662 } ); | |
7663 } | |
7664 | |
7665 // Get nodes in the order from the `rows` array with null values removed | |
7666 var nodes = _removeEmpty( | |
7667 _pluck_order( settings.aoData, rows, 'nTr' ) | |
7668 ); | |
7669 | |
7670 // Selector - node | |
7671 if ( sel.nodeName ) { | |
7672 if ( $.inArray( sel, nodes ) !== -1 ) { | |
7673 return [ sel._DT_RowIndex ]; // sel is a TR node that is in the table | |
7674 // and DataTables adds a prop for fast lookup | |
7675 } | |
7676 } | |
7677 | |
7678 // Selector - jQuery selector string, array of nodes or jQuery object/ | |
7679 // As jQuery's .filter() allows jQuery objects to be passed in filter, | |
7680 // it also allows arrays, so this will cope with all three options | |
7681 return $(nodes) | |
7682 .filter( sel ) | |
7683 .map( function () { | |
7684 return this._DT_RowIndex; | |
7685 } ) | |
7686 .toArray(); | |
7687 } ); | |
7688 }; | |
7689 | |
7690 | |
7691 /** | |
7692 * | |
7693 */ | |
7694 _api_register( 'rows()', function ( selector, opts ) { | |
7695 // argument shifting | |
7696 if ( selector === undefined ) { | |
7697 selector = ''; | |
7698 } | |
7699 else if ( $.isPlainObject( selector ) ) { | |
7700 opts = selector; | |
7701 selector = ''; | |
7702 } | |
7703 | |
7704 opts = _selector_opts( opts ); | |
7705 | |
7706 var inst = this.iterator( 'table', function ( settings ) { | |
7707 return __row_selector( settings, selector, opts ); | |
7708 }, 1 ); | |
7709 | |
7710 // Want argument shifting here and in __row_selector? | |
7711 inst.selector.rows = selector; | |
7712 inst.selector.opts = opts; | |
7713 | |
7714 return inst; | |
7715 } ); | |
7716 | |
7717 | |
7718 _api_register( 'rows().nodes()', function () { | |
7719 return this.iterator( 'row', function ( settings, row ) { | |
7720 return settings.aoData[ row ].nTr || undefined; | |
7721 }, 1 ); | |
7722 } ); | |
7723 | |
7724 _api_register( 'rows().data()', function () { | |
7725 return this.iterator( true, 'rows', function ( settings, rows ) { | |
7726 return _pluck_order( settings.aoData, rows, '_aData' ); | |
7727 }, 1 ); | |
7728 } ); | |
7729 | |
7730 _api_registerPlural( 'rows().cache()', 'row().cache()', function ( type ) { | |
7731 return this.iterator( 'row', function ( settings, row ) { | |
7732 var r = settings.aoData[ row ]; | |
7733 return type === 'search' ? r._aFilterData : r._aSortData; | |
7734 }, 1 ); | |
7735 } ); | |
7736 | |
7737 _api_registerPlural( 'rows().invalidate()', 'row().invalidate()', function ( src ) { | |
7738 return this.iterator( 'row', function ( settings, row ) { | |
7739 _fnInvalidate( settings, row, src ); | |
7740 } ); | |
7741 } ); | |
7742 | |
7743 _api_registerPlural( 'rows().indexes()', 'row().index()', function () { | |
7744 return this.iterator( 'row', function ( settings, row ) { | |
7745 return row; | |
7746 }, 1 ); | |
7747 } ); | |
7748 | |
7749 _api_registerPlural( 'rows().remove()', 'row().remove()', function () { | |
7750 var that = this; | |
7751 | |
7752 return this.iterator( 'row', function ( settings, row, thatIdx ) { | |
7753 var data = settings.aoData; | |
7754 | |
7755 data.splice( row, 1 ); | |
7756 | |
7757 // Update the _DT_RowIndex parameter on all rows in the table | |
7758 for ( var i=0, ien=data.length ; i<ien ; i++ ) { | |
7759 if ( data[i].nTr !== null ) { | |
7760 data[i].nTr._DT_RowIndex = i; | |
7761 } | |
7762 } | |
7763 | |
7764 // Remove the target row from the search array | |
7765 var displayIndex = $.inArray( row, settings.aiDisplay ); | |
7766 | |
7767 // Delete from the display arrays | |
7768 _fnDeleteIndex( settings.aiDisplayMaster, row ); | |
7769 _fnDeleteIndex( settings.aiDisplay, row ); | |
7770 _fnDeleteIndex( that[ thatIdx ], row, false ); // maintain local indexes | |
7771 | |
7772 // Check for an 'overflow' they case for displaying the table | |
7773 _fnLengthOverflow( settings ); | |
7774 } ); | |
7775 } ); | |
7776 | |
7777 | |
7778 _api_register( 'rows.add()', function ( rows ) { | |
7779 var newRows = this.iterator( 'table', function ( settings ) { | |
7780 var row, i, ien; | |
7781 var out = []; | |
7782 | |
7783 for ( i=0, ien=rows.length ; i<ien ; i++ ) { | |
7784 row = rows[i]; | |
7785 | |
7786 if ( row.nodeName && row.nodeName.toUpperCase() === 'TR' ) { | |
7787 out.push( _fnAddTr( settings, row )[0] ); | |
7788 } | |
7789 else { | |
7790 out.push( _fnAddData( settings, row ) ); | |
7791 } | |
7792 } | |
7793 | |
7794 return out; | |
7795 }, 1 ); | |
7796 | |
7797 // Return an Api.rows() extended instance, so rows().nodes() etc can be used | |
7798 var modRows = this.rows( -1 ); | |
7799 modRows.pop(); | |
7800 modRows.push.apply( modRows, newRows.toArray() ); | |
7801 | |
7802 return modRows; | |
7803 } ); | |
7804 | |
7805 | |
7806 | |
7807 | |
7808 | |
7809 /** | |
7810 * | |
7811 */ | |
7812 _api_register( 'row()', function ( selector, opts ) { | |
7813 return _selector_first( this.rows( selector, opts ) ); | |
7814 } ); | |
7815 | |
7816 | |
7817 _api_register( 'row().data()', function ( data ) { | |
7818 var ctx = this.context; | |
7819 | |
7820 if ( data === undefined ) { | |
7821 // Get | |
7822 return ctx.length && this.length ? | |
7823 ctx[0].aoData[ this[0] ]._aData : | |
7824 undefined; | |
7825 } | |
7826 | |
7827 // Set | |
7828 ctx[0].aoData[ this[0] ]._aData = data; | |
7829 | |
7830 // Automatically invalidate | |
7831 _fnInvalidate( ctx[0], this[0], 'data' ); | |
7832 | |
7833 return this; | |
7834 } ); | |
7835 | |
7836 | |
7837 _api_register( 'row().node()', function () { | |
7838 var ctx = this.context; | |
7839 | |
7840 return ctx.length && this.length ? | |
7841 ctx[0].aoData[ this[0] ].nTr || null : | |
7842 null; | |
7843 } ); | |
7844 | |
7845 | |
7846 _api_register( 'row.add()', function ( row ) { | |
7847 // Allow a jQuery object to be passed in - only a single row is added from | |
7848 // it though - the first element in the set | |
7849 if ( row instanceof $ && row.length ) { | |
7850 row = row[0]; | |
7851 } | |
7852 | |
7853 var rows = this.iterator( 'table', function ( settings ) { | |
7854 if ( row.nodeName && row.nodeName.toUpperCase() === 'TR' ) { | |
7855 return _fnAddTr( settings, row )[0]; | |
7856 } | |
7857 return _fnAddData( settings, row ); | |
7858 } ); | |
7859 | |
7860 // Return an Api.rows() extended instance, with the newly added row selected | |
7861 return this.row( rows[0] ); | |
7862 } ); | |
7863 | |
7864 | |
7865 | |
7866 var __details_add = function ( ctx, row, data, klass ) | |
7867 { | |
7868 // Convert to array of TR elements | |
7869 var rows = []; | |
7870 var addRow = function ( r, k ) { | |
7871 // If we get a TR element, then just add it directly - up to the dev | |
7872 // to add the correct number of columns etc | |
7873 if ( r.nodeName && r.nodeName.toLowerCase() === 'tr' ) { | |
7874 rows.push( r ); | |
7875 } | |
7876 else { | |
7877 // Otherwise create a row with a wrapper | |
7878 var created = $('<tr><td/></tr>').addClass( k ); | |
7879 $('td', created) | |
7880 .addClass( k ) | |
7881 .html( r ) | |
7882 [0].colSpan = _fnVisbleColumns( ctx ); | |
7883 | |
7884 rows.push( created[0] ); | |
7885 } | |
7886 }; | |
7887 | |
7888 if ( $.isArray( data ) || data instanceof $ ) { | |
7889 for ( var i=0, ien=data.length ; i<ien ; i++ ) { | |
7890 addRow( data[i], klass ); | |
7891 } | |
7892 } | |
7893 else { | |
7894 addRow( data, klass ); | |
7895 } | |
7896 | |
7897 if ( row._details ) { | |
7898 row._details.remove(); | |
7899 } | |
7900 | |
7901 row._details = $(rows); | |
7902 | |
7903 // If the children were already shown, that state should be retained | |
7904 if ( row._detailsShow ) { | |
7905 row._details.insertAfter( row.nTr ); | |
7906 } | |
7907 }; | |
7908 | |
7909 | |
7910 var __details_remove = function ( api, idx ) | |
7911 { | |
7912 var ctx = api.context; | |
7913 | |
7914 if ( ctx.length ) { | |
7915 var row = ctx[0].aoData[ idx !== undefined ? idx : api[0] ]; | |
7916 | |
7917 if ( row._details ) { | |
7918 row._details.remove(); | |
7919 | |
7920 row._detailsShow = undefined; | |
7921 row._details = undefined; | |
7922 } | |
7923 } | |
7924 }; | |
7925 | |
7926 | |
7927 var __details_display = function ( api, show ) { | |
7928 var ctx = api.context; | |
7929 | |
7930 if ( ctx.length && api.length ) { | |
7931 var row = ctx[0].aoData[ api[0] ]; | |
7932 | |
7933 if ( row._details ) { | |
7934 row._detailsShow = show; | |
7935 | |
7936 if ( show ) { | |
7937 row._details.insertAfter( row.nTr ); | |
7938 } | |
7939 else { | |
7940 row._details.detach(); | |
7941 } | |
7942 | |
7943 __details_events( ctx[0] ); | |
7944 } | |
7945 } | |
7946 }; | |
7947 | |
7948 | |
7949 var __details_events = function ( settings ) | |
7950 { | |
7951 var api = new _Api( settings ); | |
7952 var namespace = '.dt.DT_details'; | |
7953 var drawEvent = 'draw'+namespace; | |
7954 var colvisEvent = 'column-visibility'+namespace; | |
7955 var destroyEvent = 'destroy'+namespace; | |
7956 var data = settings.aoData; | |
7957 | |
7958 api.off( drawEvent +' '+ colvisEvent +' '+ destroyEvent ); | |
7959 | |
7960 if ( _pluck( data, '_details' ).length > 0 ) { | |
7961 // On each draw, insert the required elements into the document | |
7962 api.on( drawEvent, function ( e, ctx ) { | |
7963 if ( settings !== ctx ) { | |
7964 return; | |
7965 } | |
7966 | |
7967 api.rows( {page:'current'} ).eq(0).each( function (idx) { | |
7968 // Internal data grab | |
7969 var row = data[ idx ]; | |
7970 | |
7971 if ( row._detailsShow ) { | |
7972 row._details.insertAfter( row.nTr ); | |
7973 } | |
7974 } ); | |
7975 } ); | |
7976 | |
7977 // Column visibility change - update the colspan | |
7978 api.on( colvisEvent, function ( e, ctx, idx, vis ) { | |
7979 if ( settings !== ctx ) { | |
7980 return; | |
7981 } | |
7982 | |
7983 // Update the colspan for the details rows (note, only if it already has | |
7984 // a colspan) | |
7985 var row, visible = _fnVisbleColumns( ctx ); | |
7986 | |
7987 for ( var i=0, ien=data.length ; i<ien ; i++ ) { | |
7988 row = data[i]; | |
7989 | |
7990 if ( row._details ) { | |
7991 row._details.children('td[colspan]').attr('colspan', visible ); | |
7992 } | |
7993 } | |
7994 } ); | |
7995 | |
7996 // Table destroyed - nuke any child rows | |
7997 api.on( destroyEvent, function ( e, ctx ) { | |
7998 if ( settings !== ctx ) { | |
7999 return; | |
8000 } | |
8001 | |
8002 for ( var i=0, ien=data.length ; i<ien ; i++ ) { | |
8003 if ( data[i]._details ) { | |
8004 __details_remove( api, i ); | |
8005 } | |
8006 } | |
8007 } ); | |
8008 } | |
8009 }; | |
8010 | |
8011 // Strings for the method names to help minification | |
8012 var _emp = ''; | |
8013 var _child_obj = _emp+'row().child'; | |
8014 var _child_mth = _child_obj+'()'; | |
8015 | |
8016 // data can be: | |
8017 // tr | |
8018 // string | |
8019 // jQuery or array of any of the above | |
8020 _api_register( _child_mth, function ( data, klass ) { | |
8021 var ctx = this.context; | |
8022 | |
8023 if ( data === undefined ) { | |
8024 // get | |
8025 return ctx.length && this.length ? | |
8026 ctx[0].aoData[ this[0] ]._details : | |
8027 undefined; | |
8028 } | |
8029 else if ( data === true ) { | |
8030 // show | |
8031 this.child.show(); | |
8032 } | |
8033 else if ( data === false ) { | |
8034 // remove | |
8035 __details_remove( this ); | |
8036 } | |
8037 else if ( ctx.length && this.length ) { | |
8038 // set | |
8039 __details_add( ctx[0], ctx[0].aoData[ this[0] ], data, klass ); | |
8040 } | |
8041 | |
8042 return this; | |
8043 } ); | |
8044 | |
8045 | |
8046 _api_register( [ | |
8047 _child_obj+'.show()', | |
8048 _child_mth+'.show()' // only when `child()` was called with parameters (without | |
8049 ], function ( show ) { // it returns an object and this method is not executed) | |
8050 __details_display( this, true ); | |
8051 return this; | |
8052 } ); | |
8053 | |
8054 | |
8055 _api_register( [ | |
8056 _child_obj+'.hide()', | |
8057 _child_mth+'.hide()' // only when `child()` was called with parameters (without | |
8058 ], function () { // it returns an object and this method is not executed) | |
8059 __details_display( this, false ); | |
8060 return this; | |
8061 } ); | |
8062 | |
8063 | |
8064 _api_register( [ | |
8065 _child_obj+'.remove()', | |
8066 _child_mth+'.remove()' // only when `child()` was called with parameters (without | |
8067 ], function () { // it returns an object and this method is not executed) | |
8068 __details_remove( this ); | |
8069 return this; | |
8070 } ); | |
8071 | |
8072 | |
8073 _api_register( _child_obj+'.isShown()', function () { | |
8074 var ctx = this.context; | |
8075 | |
8076 if ( ctx.length && this.length ) { | |
8077 // _detailsShown as false or undefined will fall through to return false | |
8078 return ctx[0].aoData[ this[0] ]._detailsShow || false; | |
8079 } | |
8080 return false; | |
8081 } ); | |
8082 | |
8083 | |
8084 | |
8085 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * | |
8086 * Columns | |
8087 * | |
8088 * {integer} - column index (>=0 count from left, <0 count from right) | |
8089 * "{integer}:visIdx" - visible column index (i.e. translate to column index) (>=0 count from left, <0 count from right) | |
8090 * "{integer}:visible" - alias for {integer}:visIdx (>=0 count from left, <0 count from right) | |
8091 * "{string}:name" - column name | |
8092 * "{string}" - jQuery selector on column header nodes | |
8093 * | |
8094 */ | |
8095 | |
8096 // can be an array of these items, comma separated list, or an array of comma | |
8097 // separated lists | |
8098 | |
8099 var __re_column_selector = /^(.+):(name|visIdx|visible)$/; | |
8100 | |
8101 | |
8102 // r1 and r2 are redundant - but it means that the parameters match for the | |
8103 // iterator callback in columns().data() | |
8104 var __columnData = function ( settings, column, r1, r2, rows ) { | |
8105 var a = []; | |
8106 for ( var row=0, ien=rows.length ; row<ien ; row++ ) { | |
8107 a.push( _fnGetCellData( settings, rows[row], column ) ); | |
8108 } | |
8109 return a; | |
8110 }; | |
8111 | |
8112 | |
8113 var __column_selector = function ( settings, selector, opts ) | |
8114 { | |
8115 var | |
8116 columns = settings.aoColumns, | |
8117 names = _pluck( columns, 'sName' ), | |
8118 nodes = _pluck( columns, 'nTh' ); | |
8119 | |
8120 return _selector_run( selector, function ( s ) { | |
8121 var selInt = _intVal( s ); | |
8122 | |
8123 // Selector - all | |
8124 if ( s === '' ) { | |
8125 return _range( columns.length ); | |
8126 } | |
8127 | |
8128 // Selector - index | |
8129 if ( selInt !== null ) { | |
8130 return [ selInt >= 0 ? | |
8131 selInt : // Count from left | |
8132 columns.length + selInt // Count from right (+ because its a negative value) | |
8133 ]; | |
8134 } | |
8135 | |
8136 // Selector = function | |
8137 if ( typeof s === 'function' ) { | |
8138 var rows = _selector_row_indexes( settings, opts ); | |
8139 | |
8140 return $.map( columns, function (col, idx) { | |
8141 return s( | |
8142 idx, | |
8143 __columnData( settings, idx, 0, 0, rows ), | |
8144 nodes[ idx ] | |
8145 ) ? idx : null; | |
8146 } ); | |
8147 } | |
8148 | |
8149 // jQuery or string selector | |
8150 var match = typeof s === 'string' ? | |
8151 s.match( __re_column_selector ) : | |
8152 ''; | |
8153 | |
8154 if ( match ) { | |
8155 switch( match[2] ) { | |
8156 case 'visIdx': | |
8157 case 'visible': | |
8158 var idx = parseInt( match[1], 10 ); | |
8159 // Visible index given, convert to column index | |
8160 if ( idx < 0 ) { | |
8161 // Counting from the right | |
8162 var visColumns = $.map( columns, function (col,i) { | |
8163 return col.bVisible ? i : null; | |
8164 } ); | |
8165 return [ visColumns[ visColumns.length + idx ] ]; | |
8166 } | |
8167 // Counting from the left | |
8168 return [ _fnVisibleToColumnIndex( settings, idx ) ]; | |
8169 | |
8170 case 'name': | |
8171 // match by name. `names` is column index complete and in order | |
8172 return $.map( names, function (name, i) { | |
8173 return name === match[1] ? i : null; | |
8174 } ); | |
8175 } | |
8176 } | |
8177 else { | |
8178 // jQuery selector on the TH elements for the columns | |
8179 return $( nodes ) | |
8180 .filter( s ) | |
8181 .map( function () { | |
8182 return $.inArray( this, nodes ); // `nodes` is column index complete and in order | |
8183 } ) | |
8184 .toArray(); | |
8185 } | |
8186 } ); | |
8187 }; | |
8188 | |
8189 | |
8190 var __setColumnVis = function ( settings, column, vis, recalc ) { | |
8191 var | |
8192 cols = settings.aoColumns, | |
8193 col = cols[ column ], | |
8194 data = settings.aoData, | |
8195 row, cells, i, ien, tr; | |
8196 | |
8197 // Get | |
8198 if ( vis === undefined ) { | |
8199 return col.bVisible; | |
8200 } | |
8201 | |
8202 // Set | |
8203 // No change | |
8204 if ( col.bVisible === vis ) { | |
8205 return; | |
8206 } | |
8207 | |
8208 if ( vis ) { | |
8209 // Insert column | |
8210 // Need to decide if we should use appendChild or insertBefore | |
8211 var insertBefore = $.inArray( true, _pluck(cols, 'bVisible'), column+1 ); | |
8212 | |
8213 for ( i=0, ien=data.length ; i<ien ; i++ ) { | |
8214 tr = data[i].nTr; | |
8215 cells = data[i].anCells; | |
8216 | |
8217 if ( tr ) { | |
8218 // insertBefore can act like appendChild if 2nd arg is null | |
8219 tr.insertBefore( cells[ column ], cells[ insertBefore ] || null ); | |
8220 } | |
8221 } | |
8222 } | |
8223 else { | |
8224 // Remove column | |
8225 $( _pluck( settings.aoData, 'anCells', column ) ).detach(); | |
8226 } | |
8227 | |
8228 // Common actions | |
8229 col.bVisible = vis; | |
8230 _fnDrawHead( settings, settings.aoHeader ); | |
8231 _fnDrawHead( settings, settings.aoFooter ); | |
8232 | |
8233 if ( recalc === undefined || recalc ) { | |
8234 // Automatically adjust column sizing | |
8235 _fnAdjustColumnSizing( settings ); | |
8236 | |
8237 // Realign columns for scrolling | |
8238 if ( settings.oScroll.sX || settings.oScroll.sY ) { | |
8239 _fnScrollDraw( settings ); | |
8240 } | |
8241 } | |
8242 | |
8243 _fnCallbackFire( settings, null, 'column-visibility', [settings, column, vis] ); | |
8244 | |
8245 _fnSaveState( settings ); | |
8246 }; | |
8247 | |
8248 | |
8249 /** | |
8250 * | |
8251 */ | |
8252 _api_register( 'columns()', function ( selector, opts ) { | |
8253 // argument shifting | |
8254 if ( selector === undefined ) { | |
8255 selector = ''; | |
8256 } | |
8257 else if ( $.isPlainObject( selector ) ) { | |
8258 opts = selector; | |
8259 selector = ''; | |
8260 } | |
8261 | |
8262 opts = _selector_opts( opts ); | |
8263 | |
8264 var inst = this.iterator( 'table', function ( settings ) { | |
8265 return __column_selector( settings, selector, opts ); | |
8266 }, 1 ); | |
8267 | |
8268 // Want argument shifting here and in _row_selector? | |
8269 inst.selector.cols = selector; | |
8270 inst.selector.opts = opts; | |
8271 | |
8272 return inst; | |
8273 } ); | |
8274 | |
8275 | |
8276 /** | |
8277 * | |
8278 */ | |
8279 _api_registerPlural( 'columns().header()', 'column().header()', function ( selector, opts ) { | |
8280 return this.iterator( 'column', function ( settings, column ) { | |
8281 return settings.aoColumns[column].nTh; | |
8282 }, 1 ); | |
8283 } ); | |
8284 | |
8285 | |
8286 /** | |
8287 * | |
8288 */ | |
8289 _api_registerPlural( 'columns().footer()', 'column().footer()', function ( selector, opts ) { | |
8290 return this.iterator( 'column', function ( settings, column ) { | |
8291 return settings.aoColumns[column].nTf; | |
8292 }, 1 ); | |
8293 } ); | |
8294 | |
8295 | |
8296 /** | |
8297 * | |
8298 */ | |
8299 _api_registerPlural( 'columns().data()', 'column().data()', function () { | |
8300 return this.iterator( 'column-rows', __columnData, 1 ); | |
8301 } ); | |
8302 | |
8303 | |
8304 _api_registerPlural( 'columns().dataSrc()', 'column().dataSrc()', function () { | |
8305 return this.iterator( 'column', function ( settings, column ) { | |
8306 return settings.aoColumns[column].mData; | |
8307 }, 1 ); | |
8308 } ); | |
8309 | |
8310 | |
8311 _api_registerPlural( 'columns().cache()', 'column().cache()', function ( type ) { | |
8312 return this.iterator( 'column-rows', function ( settings, column, i, j, rows ) { | |
8313 return _pluck_order( settings.aoData, rows, | |
8314 type === 'search' ? '_aFilterData' : '_aSortData', column | |
8315 ); | |
8316 }, 1 ); | |
8317 } ); | |
8318 | |
8319 | |
8320 _api_registerPlural( 'columns().nodes()', 'column().nodes()', function () { | |
8321 return this.iterator( 'column-rows', function ( settings, column, i, j, rows ) { | |
8322 return _pluck_order( settings.aoData, rows, 'anCells', column ) ; | |
8323 }, 1 ); | |
8324 } ); | |
8325 | |
8326 | |
8327 | |
8328 _api_registerPlural( 'columns().visible()', 'column().visible()', function ( vis, calc ) { | |
8329 return this.iterator( 'column', function ( settings, column ) { | |
8330 if ( vis === undefined ) { | |
8331 return settings.aoColumns[ column ].bVisible; | |
8332 } // else | |
8333 __setColumnVis( settings, column, vis, calc ); | |
8334 } ); | |
8335 } ); | |
8336 | |
8337 | |
8338 | |
8339 _api_registerPlural( 'columns().indexes()', 'column().index()', function ( type ) { | |
8340 return this.iterator( 'column', function ( settings, column ) { | |
8341 return type === 'visible' ? | |
8342 _fnColumnIndexToVisible( settings, column ) : | |
8343 column; | |
8344 }, 1 ); | |
8345 } ); | |
8346 | |
8347 | |
8348 // _api_register( 'columns().show()', function () { | |
8349 // var selector = this.selector; | |
8350 // return this.columns( selector.cols, selector.opts ).visible( true ); | |
8351 // } ); | |
8352 | |
8353 | |
8354 // _api_register( 'columns().hide()', function () { | |
8355 // var selector = this.selector; | |
8356 // return this.columns( selector.cols, selector.opts ).visible( false ); | |
8357 // } ); | |
8358 | |
8359 | |
8360 | |
8361 _api_register( 'columns.adjust()', function () { | |
8362 return this.iterator( 'table', function ( settings ) { | |
8363 _fnAdjustColumnSizing( settings ); | |
8364 }, 1 ); | |
8365 } ); | |
8366 | |
8367 | |
8368 // Convert from one column index type, to another type | |
8369 _api_register( 'column.index()', function ( type, idx ) { | |
8370 if ( this.context.length !== 0 ) { | |
8371 var ctx = this.context[0]; | |
8372 | |
8373 if ( type === 'fromVisible' || type === 'toData' ) { | |
8374 return _fnVisibleToColumnIndex( ctx, idx ); | |
8375 } | |
8376 else if ( type === 'fromData' || type === 'toVisible' ) { | |
8377 return _fnColumnIndexToVisible( ctx, idx ); | |
8378 } | |
8379 } | |
8380 } ); | |
8381 | |
8382 | |
8383 _api_register( 'column()', function ( selector, opts ) { | |
8384 return _selector_first( this.columns( selector, opts ) ); | |
8385 } ); | |
8386 | |
8387 | |
8388 | |
8389 | |
8390 var __cell_selector = function ( settings, selector, opts ) | |
8391 { | |
8392 var data = settings.aoData; | |
8393 var rows = _selector_row_indexes( settings, opts ); | |
8394 var cells = _removeEmpty( _pluck_order( data, rows, 'anCells' ) ); | |
8395 var allCells = $( [].concat.apply([], cells) ); | |
8396 var row; | |
8397 var columns = settings.aoColumns.length; | |
8398 var a, i, ien, j, o, host; | |
8399 | |
8400 return _selector_run( selector, function ( s ) { | |
8401 var fnSelector = typeof s === 'function'; | |
8402 | |
8403 if ( s === null || s === undefined || fnSelector ) { | |
8404 // All cells and function selectors | |
8405 a = []; | |
8406 | |
8407 for ( i=0, ien=rows.length ; i<ien ; i++ ) { | |
8408 row = rows[i]; | |
8409 | |
8410 for ( j=0 ; j<columns ; j++ ) { | |
8411 o = { | |
8412 row: row, | |
8413 column: j | |
8414 }; | |
8415 | |
8416 if ( fnSelector ) { | |
8417 // Selector - function | |
8418 host = settings.aoData[ row ]; | |
8419 | |
8420 if ( s( o, _fnGetCellData(settings, row, j), host.anCells[j] ) ) { | |
8421 a.push( o ); | |
8422 } | |
8423 } | |
8424 else { | |
8425 // Selector - all | |
8426 a.push( o ); | |
8427 } | |
8428 } | |
8429 } | |
8430 | |
8431 return a; | |
8432 } | |
8433 | |
8434 // Selector - index | |
8435 if ( $.isPlainObject( s ) ) { | |
8436 return [s]; | |
8437 } | |
8438 | |
8439 // Selector - jQuery filtered cells | |
8440 return allCells | |
8441 .filter( s ) | |
8442 .map( function (i, el) { | |
8443 row = el.parentNode._DT_RowIndex; | |
8444 | |
8445 return { | |
8446 row: row, | |
8447 column: $.inArray( el, data[ row ].anCells ) | |
8448 }; | |
8449 } ) | |
8450 .toArray(); | |
8451 } ); | |
8452 }; | |
8453 | |
8454 | |
8455 | |
8456 | |
8457 _api_register( 'cells()', function ( rowSelector, columnSelector, opts ) { | |
8458 // Argument shifting | |
8459 if ( $.isPlainObject( rowSelector ) ) { | |
8460 // Indexes | |
8461 if ( typeof rowSelector.row !== undefined ) { | |
8462 opts = columnSelector; | |
8463 columnSelector = null; | |
8464 } | |
8465 else { | |
8466 opts = rowSelector; | |
8467 rowSelector = null; | |
8468 } | |
8469 } | |
8470 if ( $.isPlainObject( columnSelector ) ) { | |
8471 opts = columnSelector; | |
8472 columnSelector = null; | |
8473 } | |
8474 | |
8475 // Cell selector | |
8476 if ( columnSelector === null || columnSelector === undefined ) { | |
8477 return this.iterator( 'table', function ( settings ) { | |
8478 return __cell_selector( settings, rowSelector, _selector_opts( opts ) ); | |
8479 } ); | |
8480 } | |
8481 | |
8482 // Row + column selector | |
8483 var columns = this.columns( columnSelector, opts ); | |
8484 var rows = this.rows( rowSelector, opts ); | |
8485 var a, i, ien, j, jen; | |
8486 | |
8487 var cells = this.iterator( 'table', function ( settings, idx ) { | |
8488 a = []; | |
8489 | |
8490 for ( i=0, ien=rows[idx].length ; i<ien ; i++ ) { | |
8491 for ( j=0, jen=columns[idx].length ; j<jen ; j++ ) { | |
8492 a.push( { | |
8493 row: rows[idx][i], | |
8494 column: columns[idx][j] | |
8495 } ); | |
8496 } | |
8497 } | |
8498 | |
8499 return a; | |
8500 }, 1 ); | |
8501 | |
8502 $.extend( cells.selector, { | |
8503 cols: columnSelector, | |
8504 rows: rowSelector, | |
8505 opts: opts | |
8506 } ); | |
8507 | |
8508 return cells; | |
8509 } ); | |
8510 | |
8511 | |
8512 _api_registerPlural( 'cells().nodes()', 'cell().node()', function () { | |
8513 return this.iterator( 'cell', function ( settings, row, column ) { | |
8514 var cells = settings.aoData[ row ].anCells; | |
8515 return cells ? | |
8516 cells[ column ] : | |
8517 undefined; | |
8518 }, 1 ); | |
8519 } ); | |
8520 | |
8521 | |
8522 _api_register( 'cells().data()', function () { | |
8523 return this.iterator( 'cell', function ( settings, row, column ) { | |
8524 return _fnGetCellData( settings, row, column ); | |
8525 }, 1 ); | |
8526 } ); | |
8527 | |
8528 | |
8529 _api_registerPlural( 'cells().cache()', 'cell().cache()', function ( type ) { | |
8530 type = type === 'search' ? '_aFilterData' : '_aSortData'; | |
8531 | |
8532 return this.iterator( 'cell', function ( settings, row, column ) { | |
8533 return settings.aoData[ row ][ type ][ column ]; | |
8534 }, 1 ); | |
8535 } ); | |
8536 | |
8537 | |
8538 _api_registerPlural( 'cells().render()', 'cell().render()', function ( type ) { | |
8539 return this.iterator( 'cell', function ( settings, row, column ) { | |
8540 return _fnGetCellData( settings, row, column, type ); | |
8541 }, 1 ); | |
8542 } ); | |
8543 | |
8544 | |
8545 _api_registerPlural( 'cells().indexes()', 'cell().index()', function () { | |
8546 return this.iterator( 'cell', function ( settings, row, column ) { | |
8547 return { | |
8548 row: row, | |
8549 column: column, | |
8550 columnVisible: _fnColumnIndexToVisible( settings, column ) | |
8551 }; | |
8552 }, 1 ); | |
8553 } ); | |
8554 | |
8555 | |
8556 _api_registerPlural( 'cells().invalidate()', 'cell().invalidate()', function ( src ) { | |
8557 return this.iterator( 'cell', function ( settings, row, column ) { | |
8558 _fnInvalidate( settings, row, src, column ); | |
8559 } ); | |
8560 } ); | |
8561 | |
8562 | |
8563 | |
8564 _api_register( 'cell()', function ( rowSelector, columnSelector, opts ) { | |
8565 return _selector_first( this.cells( rowSelector, columnSelector, opts ) ); | |
8566 } ); | |
8567 | |
8568 | |
8569 _api_register( 'cell().data()', function ( data ) { | |
8570 var ctx = this.context; | |
8571 var cell = this[0]; | |
8572 | |
8573 if ( data === undefined ) { | |
8574 // Get | |
8575 return ctx.length && cell.length ? | |
8576 _fnGetCellData( ctx[0], cell[0].row, cell[0].column ) : | |
8577 undefined; | |
8578 } | |
8579 | |
8580 // Set | |
8581 _fnSetCellData( ctx[0], cell[0].row, cell[0].column, data ); | |
8582 _fnInvalidate( ctx[0], cell[0].row, 'data', cell[0].column ); | |
8583 | |
8584 return this; | |
8585 } ); | |
8586 | |
8587 | |
8588 | |
8589 /** | |
8590 * Get current ordering (sorting) that has been applied to the table. | |
8591 * | |
8592 * @returns {array} 2D array containing the sorting information for the first | |
8593 * table in the current context. Each element in the parent array represents | |
8594 * a column being sorted upon (i.e. multi-sorting with two columns would have | |
8595 * 2 inner arrays). The inner arrays may have 2 or 3 elements. The first is | |
8596 * the column index that the sorting condition applies to, the second is the | |
8597 * direction of the sort (`desc` or `asc`) and, optionally, the third is the | |
8598 * index of the sorting order from the `column.sorting` initialisation array. | |
8599 *//** | |
8600 * Set the ordering for the table. | |
8601 * | |
8602 * @param {integer} order Column index to sort upon. | |
8603 * @param {string} direction Direction of the sort to be applied (`asc` or `desc`) | |
8604 * @returns {DataTables.Api} this | |
8605 *//** | |
8606 * Set the ordering for the table. | |
8607 * | |
8608 * @param {array} order 1D array of sorting information to be applied. | |
8609 * @param {array} [...] Optional additional sorting conditions | |
8610 * @returns {DataTables.Api} this | |
8611 *//** | |
8612 * Set the ordering for the table. | |
8613 * | |
8614 * @param {array} order 2D array of sorting information to be applied. | |
8615 * @returns {DataTables.Api} this | |
8616 */ | |
8617 _api_register( 'order()', function ( order, dir ) { | |
8618 var ctx = this.context; | |
8619 | |
8620 if ( order === undefined ) { | |
8621 // get | |
8622 return ctx.length !== 0 ? | |
8623 ctx[0].aaSorting : | |
8624 undefined; | |
8625 } | |
8626 | |
8627 // set | |
8628 if ( typeof order === 'number' ) { | |
8629 // Simple column / direction passed in | |
8630 order = [ [ order, dir ] ]; | |
8631 } | |
8632 else if ( ! $.isArray( order[0] ) ) { | |
8633 // Arguments passed in (list of 1D arrays) | |
8634 order = Array.prototype.slice.call( arguments ); | |
8635 } | |
8636 // otherwise a 2D array was passed in | |
8637 | |
8638 return this.iterator( 'table', function ( settings ) { | |
8639 settings.aaSorting = order.slice(); | |
8640 } ); | |
8641 } ); | |
8642 | |
8643 | |
8644 /** | |
8645 * Attach a sort listener to an element for a given column | |
8646 * | |
8647 * @param {node|jQuery|string} node Identifier for the element(s) to attach the | |
8648 * listener to. This can take the form of a single DOM node, a jQuery | |
8649 * collection of nodes or a jQuery selector which will identify the node(s). | |
8650 * @param {integer} column the column that a click on this node will sort on | |
8651 * @param {function} [callback] callback function when sort is run | |
8652 * @returns {DataTables.Api} this | |
8653 */ | |
8654 _api_register( 'order.listener()', function ( node, column, callback ) { | |
8655 return this.iterator( 'table', function ( settings ) { | |
8656 _fnSortAttachListener( settings, node, column, callback ); | |
8657 } ); | |
8658 } ); | |
8659 | |
8660 | |
8661 // Order by the selected column(s) | |
8662 _api_register( [ | |
8663 'columns().order()', | |
8664 'column().order()' | |
8665 ], function ( dir ) { | |
8666 var that = this; | |
8667 | |
8668 return this.iterator( 'table', function ( settings, i ) { | |
8669 var sort = []; | |
8670 | |
8671 $.each( that[i], function (j, col) { | |
8672 sort.push( [ col, dir ] ); | |
8673 } ); | |
8674 | |
8675 settings.aaSorting = sort; | |
8676 } ); | |
8677 } ); | |
8678 | |
8679 | |
8680 | |
8681 _api_register( 'search()', function ( input, regex, smart, caseInsen ) { | |
8682 var ctx = this.context; | |
8683 | |
8684 if ( input === undefined ) { | |
8685 // get | |
8686 return ctx.length !== 0 ? | |
8687 ctx[0].oPreviousSearch.sSearch : | |
8688 undefined; | |
8689 } | |
8690 | |
8691 // set | |
8692 return this.iterator( 'table', function ( settings ) { | |
8693 if ( ! settings.oFeatures.bFilter ) { | |
8694 return; | |
8695 } | |
8696 | |
8697 _fnFilterComplete( settings, $.extend( {}, settings.oPreviousSearch, { | |
8698 "sSearch": input+"", | |
8699 "bRegex": regex === null ? false : regex, | |
8700 "bSmart": smart === null ? true : smart, | |
8701 "bCaseInsensitive": caseInsen === null ? true : caseInsen | |
8702 } ), 1 ); | |
8703 } ); | |
8704 } ); | |
8705 | |
8706 | |
8707 _api_registerPlural( | |
8708 'columns().search()', | |
8709 'column().search()', | |
8710 function ( input, regex, smart, caseInsen ) { | |
8711 return this.iterator( 'column', function ( settings, column ) { | |
8712 var preSearch = settings.aoPreSearchCols; | |
8713 | |
8714 if ( input === undefined ) { | |
8715 // get | |
8716 return preSearch[ column ].sSearch; | |
8717 } | |
8718 | |
8719 // set | |
8720 if ( ! settings.oFeatures.bFilter ) { | |
8721 return; | |
8722 } | |
8723 | |
8724 $.extend( preSearch[ column ], { | |
8725 "sSearch": input+"", | |
8726 "bRegex": regex === null ? false : regex, | |
8727 "bSmart": smart === null ? true : smart, | |
8728 "bCaseInsensitive": caseInsen === null ? true : caseInsen | |
8729 } ); | |
8730 | |
8731 _fnFilterComplete( settings, settings.oPreviousSearch, 1 ); | |
8732 } ); | |
8733 } | |
8734 ); | |
8735 | |
8736 /* | |
8737 * State API methods | |
8738 */ | |
8739 | |
8740 _api_register( 'state()', function () { | |
8741 return this.context.length ? | |
8742 this.context[0].oSavedState : | |
8743 null; | |
8744 } ); | |
8745 | |
8746 | |
8747 _api_register( 'state.clear()', function () { | |
8748 return this.iterator( 'table', function ( settings ) { | |
8749 // Save an empty object | |
8750 settings.fnStateSaveCallback.call( settings.oInstance, settings, {} ); | |
8751 } ); | |
8752 } ); | |
8753 | |
8754 | |
8755 _api_register( 'state.loaded()', function () { | |
8756 return this.context.length ? | |
8757 this.context[0].oLoadedState : | |
8758 null; | |
8759 } ); | |
8760 | |
8761 | |
8762 _api_register( 'state.save()', function () { | |
8763 return this.iterator( 'table', function ( settings ) { | |
8764 _fnSaveState( settings ); | |
8765 } ); | |
8766 } ); | |
8767 | |
8768 | |
8769 | |
8770 /** | |
8771 * Provide a common method for plug-ins to check the version of DataTables being | |
8772 * used, in order to ensure compatibility. | |
8773 * | |
8774 * @param {string} version Version string to check for, in the format "X.Y.Z". | |
8775 * Note that the formats "X" and "X.Y" are also acceptable. | |
8776 * @returns {boolean} true if this version of DataTables is greater or equal to | |
8777 * the required version, or false if this version of DataTales is not | |
8778 * suitable | |
8779 * @static | |
8780 * @dtopt API-Static | |
8781 * | |
8782 * @example | |
8783 * alert( $.fn.dataTable.versionCheck( '1.9.0' ) ); | |
8784 */ | |
8785 DataTable.versionCheck = DataTable.fnVersionCheck = function( version ) | |
8786 { | |
8787 var aThis = DataTable.version.split('.'); | |
8788 var aThat = version.split('.'); | |
8789 var iThis, iThat; | |
8790 | |
8791 for ( var i=0, iLen=aThat.length ; i<iLen ; i++ ) { | |
8792 iThis = parseInt( aThis[i], 10 ) || 0; | |
8793 iThat = parseInt( aThat[i], 10 ) || 0; | |
8794 | |
8795 // Parts are the same, keep comparing | |
8796 if (iThis === iThat) { | |
8797 continue; | |
8798 } | |
8799 | |
8800 // Parts are different, return immediately | |
8801 return iThis > iThat; | |
8802 } | |
8803 | |
8804 return true; | |
8805 }; | |
8806 | |
8807 | |
8808 /** | |
8809 * Check if a `<table>` node is a DataTable table already or not. | |
8810 * | |
8811 * @param {node|jquery|string} table Table node, jQuery object or jQuery | |
8812 * selector for the table to test. Note that if more than more than one | |
8813 * table is passed on, only the first will be checked | |
8814 * @returns {boolean} true the table given is a DataTable, or false otherwise | |
8815 * @static | |
8816 * @dtopt API-Static | |
8817 * | |
8818 * @example | |
8819 * if ( ! $.fn.DataTable.isDataTable( '#example' ) ) { | |
8820 * $('#example').dataTable(); | |
8821 * } | |
8822 */ | |
8823 DataTable.isDataTable = DataTable.fnIsDataTable = function ( table ) | |
8824 { | |
8825 var t = $(table).get(0); | |
8826 var is = false; | |
8827 | |
8828 $.each( DataTable.settings, function (i, o) { | |
8829 if ( o.nTable === t || o.nScrollHead === t || o.nScrollFoot === t ) { | |
8830 is = true; | |
8831 } | |
8832 } ); | |
8833 | |
8834 return is; | |
8835 }; | |
8836 | |
8837 | |
8838 /** | |
8839 * Get all DataTable tables that have been initialised - optionally you can | |
8840 * select to get only currently visible tables. | |
8841 * | |
8842 * @param {boolean} [visible=false] Flag to indicate if you want all (default) | |
8843 * or visible tables only. | |
8844 * @returns {array} Array of `table` nodes (not DataTable instances) which are | |
8845 * DataTables | |
8846 * @static | |
8847 * @dtopt API-Static | |
8848 * | |
8849 * @example | |
8850 * $.each( $.fn.dataTable.tables(true), function () { | |
8851 * $(table).DataTable().columns.adjust(); | |
8852 * } ); | |
8853 */ | |
8854 DataTable.tables = DataTable.fnTables = function ( visible ) | |
8855 { | |
8856 return $.map( DataTable.settings, function (o) { | |
8857 if ( !visible || (visible && $(o.nTable).is(':visible')) ) { | |
8858 return o.nTable; | |
8859 } | |
8860 } ); | |
8861 }; | |
8862 | |
8863 | |
8864 /** | |
8865 * DataTables utility methods | |
8866 * | |
8867 * This namespace provides helper methods that DataTables uses internally to | |
8868 * create a DataTable, but which are not exclusively used only for DataTables. | |
8869 * These methods can be used by extension authors to save the duplication of | |
8870 * code. | |
8871 * | |
8872 * @namespace | |
8873 */ | |
8874 DataTable.util = { | |
8875 /** | |
8876 * Throttle the calls to a function. Arguments and context are maintained | |
8877 * for the throttled function. | |
8878 * | |
8879 * @param {function} fn Function to be called | |
8880 * @param {integer} freq Call frequency in mS | |
8881 * @return {function} Wrapped function | |
8882 */ | |
8883 throttle: _fnThrottle, | |
8884 | |
8885 | |
8886 /** | |
8887 * Escape a string such that it can be used in a regular expression | |
8888 * | |
8889 * @param {string} sVal string to escape | |
8890 * @returns {string} escaped string | |
8891 */ | |
8892 escapeRegex: _fnEscapeRegex | |
8893 }; | |
8894 | |
8895 | |
8896 /** | |
8897 * Convert from camel case parameters to Hungarian notation. This is made public | |
8898 * for the extensions to provide the same ability as DataTables core to accept | |
8899 * either the 1.9 style Hungarian notation, or the 1.10+ style camelCase | |
8900 * parameters. | |
8901 * | |
8902 * @param {object} src The model object which holds all parameters that can be | |
8903 * mapped. | |
8904 * @param {object} user The object to convert from camel case to Hungarian. | |
8905 * @param {boolean} force When set to `true`, properties which already have a | |
8906 * Hungarian value in the `user` object will be overwritten. Otherwise they | |
8907 * won't be. | |
8908 */ | |
8909 DataTable.camelToHungarian = _fnCamelToHungarian; | |
8910 | |
8911 | |
8912 | |
8913 /** | |
8914 * | |
8915 */ | |
8916 _api_register( '$()', function ( selector, opts ) { | |
8917 var | |
8918 rows = this.rows( opts ).nodes(), // Get all rows | |
8919 jqRows = $(rows); | |
8920 | |
8921 return $( [].concat( | |
8922 jqRows.filter( selector ).toArray(), | |
8923 jqRows.find( selector ).toArray() | |
8924 ) ); | |
8925 } ); | |
8926 | |
8927 | |
8928 // jQuery functions to operate on the tables | |
8929 $.each( [ 'on', 'one', 'off' ], function (i, key) { | |
8930 _api_register( key+'()', function ( /* event, handler */ ) { | |
8931 var args = Array.prototype.slice.call(arguments); | |
8932 | |
8933 // Add the `dt` namespace automatically if it isn't already present | |
8934 if ( ! args[0].match(/\.dt\b/) ) { | |
8935 args[0] += '.dt'; | |
8936 } | |
8937 | |
8938 var inst = $( this.tables().nodes() ); | |
8939 inst[key].apply( inst, args ); | |
8940 return this; | |
8941 } ); | |
8942 } ); | |
8943 | |
8944 | |
8945 _api_register( 'clear()', function () { | |
8946 return this.iterator( 'table', function ( settings ) { | |
8947 _fnClearTable( settings ); | |
8948 } ); | |
8949 } ); | |
8950 | |
8951 | |
8952 _api_register( 'settings()', function () { | |
8953 return new _Api( this.context, this.context ); | |
8954 } ); | |
8955 | |
8956 | |
8957 _api_register( 'data()', function () { | |
8958 return this.iterator( 'table', function ( settings ) { | |
8959 return _pluck( settings.aoData, '_aData' ); | |
8960 } ).flatten(); | |
8961 } ); | |
8962 | |
8963 | |
8964 _api_register( 'destroy()', function ( remove ) { | |
8965 remove = remove || false; | |
8966 | |
8967 return this.iterator( 'table', function ( settings ) { | |
8968 var orig = settings.nTableWrapper.parentNode; | |
8969 var classes = settings.oClasses; | |
8970 var table = settings.nTable; | |
8971 var tbody = settings.nTBody; | |
8972 var thead = settings.nTHead; | |
8973 var tfoot = settings.nTFoot; | |
8974 var jqTable = $(table); | |
8975 var jqTbody = $(tbody); | |
8976 var jqWrapper = $(settings.nTableWrapper); | |
8977 var rows = $.map( settings.aoData, function (r) { return r.nTr; } ); | |
8978 var i, ien; | |
8979 | |
8980 // Flag to note that the table is currently being destroyed - no action | |
8981 // should be taken | |
8982 settings.bDestroying = true; | |
8983 | |
8984 // Fire off the destroy callbacks for plug-ins etc | |
8985 _fnCallbackFire( settings, "aoDestroyCallback", "destroy", [settings] ); | |
8986 | |
8987 // If not being removed from the document, make all columns visible | |
8988 if ( ! remove ) { | |
8989 new _Api( settings ).columns().visible( true ); | |
8990 } | |
8991 | |
8992 // Blitz all `DT` namespaced events (these are internal events, the | |
8993 // lowercase, `dt` events are user subscribed and they are responsible | |
8994 // for removing them | |
8995 jqWrapper.unbind('.DT').find(':not(tbody *)').unbind('.DT'); | |
8996 $(window).unbind('.DT-'+settings.sInstance); | |
8997 | |
8998 // When scrolling we had to break the table up - restore it | |
8999 if ( table != thead.parentNode ) { | |
9000 jqTable.children('thead').detach(); | |
9001 jqTable.append( thead ); | |
9002 } | |
9003 | |
9004 if ( tfoot && table != tfoot.parentNode ) { | |
9005 jqTable.children('tfoot').detach(); | |
9006 jqTable.append( tfoot ); | |
9007 } | |
9008 | |
9009 // Remove the DataTables generated nodes, events and classes | |
9010 jqTable.detach(); | |
9011 jqWrapper.detach(); | |
9012 | |
9013 settings.aaSorting = []; | |
9014 settings.aaSortingFixed = []; | |
9015 _fnSortingClasses( settings ); | |
9016 | |
9017 $( rows ).removeClass( settings.asStripeClasses.join(' ') ); | |
9018 | |
9019 $('th, td', thead).removeClass( classes.sSortable+' '+ | |
9020 classes.sSortableAsc+' '+classes.sSortableDesc+' '+classes.sSortableNone | |
9021 ); | |
9022 | |
9023 if ( settings.bJUI ) { | |
9024 $('th span.'+classes.sSortIcon+ ', td span.'+classes.sSortIcon, thead).detach(); | |
9025 $('th, td', thead).each( function () { | |
9026 var wrapper = $('div.'+classes.sSortJUIWrapper, this); | |
9027 $(this).append( wrapper.contents() ); | |
9028 wrapper.detach(); | |
9029 } ); | |
9030 } | |
9031 | |
9032 if ( ! remove && orig ) { | |
9033 // insertBefore acts like appendChild if !arg[1] | |
9034 orig.insertBefore( table, settings.nTableReinsertBefore ); | |
9035 } | |
9036 | |
9037 // Add the TR elements back into the table in their original order | |
9038 jqTbody.children().detach(); | |
9039 jqTbody.append( rows ); | |
9040 | |
9041 // Restore the width of the original table - was read from the style property, | |
9042 // so we can restore directly to that | |
9043 jqTable | |
9044 .css( 'width', settings.sDestroyWidth ) | |
9045 .removeClass( classes.sTable ); | |
9046 | |
9047 // If the were originally stripe classes - then we add them back here. | |
9048 // Note this is not fool proof (for example if not all rows had stripe | |
9049 // classes - but it's a good effort without getting carried away | |
9050 ien = settings.asDestroyStripes.length; | |
9051 | |
9052 if ( ien ) { | |
9053 jqTbody.children().each( function (i) { | |
9054 $(this).addClass( settings.asDestroyStripes[i % ien] ); | |
9055 } ); | |
9056 } | |
9057 | |
9058 /* Remove the settings object from the settings array */ | |
9059 var idx = $.inArray( settings, DataTable.settings ); | |
9060 if ( idx !== -1 ) { | |
9061 DataTable.settings.splice( idx, 1 ); | |
9062 } | |
9063 } ); | |
9064 } ); | |
9065 | |
9066 | |
9067 /** | |
9068 * Version string for plug-ins to check compatibility. Allowed format is | |
9069 * `a.b.c-d` where: a:int, b:int, c:int, d:string(dev|beta|alpha). `d` is used | |
9070 * only for non-release builds. See http://semver.org/ for more information. | |
9071 * @member | |
9072 * @type string | |
9073 * @default Version number | |
9074 */ | |
9075 DataTable.version = "1.10.4"; | |
9076 | |
9077 /** | |
9078 * Private data store, containing all of the settings objects that are | |
9079 * created for the tables on a given page. | |
9080 * | |
9081 * Note that the `DataTable.settings` object is aliased to | |
9082 * `jQuery.fn.dataTableExt` through which it may be accessed and | |
9083 * manipulated, or `jQuery.fn.dataTable.settings`. | |
9084 * @member | |
9085 * @type array | |
9086 * @default [] | |
9087 * @private | |
9088 */ | |
9089 DataTable.settings = []; | |
9090 | |
9091 /** | |
9092 * Object models container, for the various models that DataTables has | |
9093 * available to it. These models define the objects that are used to hold | |
9094 * the active state and configuration of the table. | |
9095 * @namespace | |
9096 */ | |
9097 DataTable.models = {}; | |
9098 | |
9099 | |
9100 | |
9101 /** | |
9102 * Template object for the way in which DataTables holds information about | |
9103 * search information for the global filter and individual column filters. | |
9104 * @namespace | |
9105 */ | |
9106 DataTable.models.oSearch = { | |
9107 /** | |
9108 * Flag to indicate if the filtering should be case insensitive or not | |
9109 * @type boolean | |
9110 * @default true | |
9111 */ | |
9112 "bCaseInsensitive": true, | |
9113 | |
9114 /** | |
9115 * Applied search term | |
9116 * @type string | |
9117 * @default <i>Empty string</i> | |
9118 */ | |
9119 "sSearch": "", | |
9120 | |
9121 /** | |
9122 * Flag to indicate if the search term should be interpreted as a | |
9123 * regular expression (true) or not (false) and therefore and special | |
9124 * regex characters escaped. | |
9125 * @type boolean | |
9126 * @default false | |
9127 */ | |
9128 "bRegex": false, | |
9129 | |
9130 /** | |
9131 * Flag to indicate if DataTables is to use its smart filtering or not. | |
9132 * @type boolean | |
9133 * @default true | |
9134 */ | |
9135 "bSmart": true | |
9136 }; | |
9137 | |
9138 | |
9139 | |
9140 | |
9141 /** | |
9142 * Template object for the way in which DataTables holds information about | |
9143 * each individual row. This is the object format used for the settings | |
9144 * aoData array. | |
9145 * @namespace | |
9146 */ | |
9147 DataTable.models.oRow = { | |
9148 /** | |
9149 * TR element for the row | |
9150 * @type node | |
9151 * @default null | |
9152 */ | |
9153 "nTr": null, | |
9154 | |
9155 /** | |
9156 * Array of TD elements for each row. This is null until the row has been | |
9157 * created. | |
9158 * @type array nodes | |
9159 * @default [] | |
9160 */ | |
9161 "anCells": null, | |
9162 | |
9163 /** | |
9164 * Data object from the original data source for the row. This is either | |
9165 * an array if using the traditional form of DataTables, or an object if | |
9166 * using mData options. The exact type will depend on the passed in | |
9167 * data from the data source, or will be an array if using DOM a data | |
9168 * source. | |
9169 * @type array|object | |
9170 * @default [] | |
9171 */ | |
9172 "_aData": [], | |
9173 | |
9174 /** | |
9175 * Sorting data cache - this array is ostensibly the same length as the | |
9176 * number of columns (although each index is generated only as it is | |
9177 * needed), and holds the data that is used for sorting each column in the | |
9178 * row. We do this cache generation at the start of the sort in order that | |
9179 * the formatting of the sort data need be done only once for each cell | |
9180 * per sort. This array should not be read from or written to by anything | |
9181 * other than the master sorting methods. | |
9182 * @type array | |
9183 * @default null | |
9184 * @private | |
9185 */ | |
9186 "_aSortData": null, | |
9187 | |
9188 /** | |
9189 * Per cell filtering data cache. As per the sort data cache, used to | |
9190 * increase the performance of the filtering in DataTables | |
9191 * @type array | |
9192 * @default null | |
9193 * @private | |
9194 */ | |
9195 "_aFilterData": null, | |
9196 | |
9197 /** | |
9198 * Filtering data cache. This is the same as the cell filtering cache, but | |
9199 * in this case a string rather than an array. This is easily computed with | |
9200 * a join on `_aFilterData`, but is provided as a cache so the join isn't | |
9201 * needed on every search (memory traded for performance) | |
9202 * @type array | |
9203 * @default null | |
9204 * @private | |
9205 */ | |
9206 "_sFilterRow": null, | |
9207 | |
9208 /** | |
9209 * Cache of the class name that DataTables has applied to the row, so we | |
9210 * can quickly look at this variable rather than needing to do a DOM check | |
9211 * on className for the nTr property. | |
9212 * @type string | |
9213 * @default <i>Empty string</i> | |
9214 * @private | |
9215 */ | |
9216 "_sRowStripe": "", | |
9217 | |
9218 /** | |
9219 * Denote if the original data source was from the DOM, or the data source | |
9220 * object. This is used for invalidating data, so DataTables can | |
9221 * automatically read data from the original source, unless uninstructed | |
9222 * otherwise. | |
9223 * @type string | |
9224 * @default null | |
9225 * @private | |
9226 */ | |
9227 "src": null | |
9228 }; | |
9229 | |
9230 | |
9231 /** | |
9232 * Template object for the column information object in DataTables. This object | |
9233 * is held in the settings aoColumns array and contains all the information that | |
9234 * DataTables needs about each individual column. | |
9235 * | |
9236 * Note that this object is related to {@link DataTable.defaults.column} | |
9237 * but this one is the internal data store for DataTables's cache of columns. | |
9238 * It should NOT be manipulated outside of DataTables. Any configuration should | |
9239 * be done through the initialisation options. | |
9240 * @namespace | |
9241 */ | |
9242 DataTable.models.oColumn = { | |
9243 /** | |
9244 * Column index. This could be worked out on-the-fly with $.inArray, but it | |
9245 * is faster to just hold it as a variable | |
9246 * @type integer | |
9247 * @default null | |
9248 */ | |
9249 "idx": null, | |
9250 | |
9251 /** | |
9252 * A list of the columns that sorting should occur on when this column | |
9253 * is sorted. That this property is an array allows multi-column sorting | |
9254 * to be defined for a column (for example first name / last name columns | |
9255 * would benefit from this). The values are integers pointing to the | |
9256 * columns to be sorted on (typically it will be a single integer pointing | |
9257 * at itself, but that doesn't need to be the case). | |
9258 * @type array | |
9259 */ | |
9260 "aDataSort": null, | |
9261 | |
9262 /** | |
9263 * Define the sorting directions that are applied to the column, in sequence | |
9264 * as the column is repeatedly sorted upon - i.e. the first value is used | |
9265 * as the sorting direction when the column if first sorted (clicked on). | |
9266 * Sort it again (click again) and it will move on to the next index. | |
9267 * Repeat until loop. | |
9268 * @type array | |
9269 */ | |
9270 "asSorting": null, | |
9271 | |
9272 /** | |
9273 * Flag to indicate if the column is searchable, and thus should be included | |
9274 * in the filtering or not. | |
9275 * @type boolean | |
9276 */ | |
9277 "bSearchable": null, | |
9278 | |
9279 /** | |
9280 * Flag to indicate if the column is sortable or not. | |
9281 * @type boolean | |
9282 */ | |
9283 "bSortable": null, | |
9284 | |
9285 /** | |
9286 * Flag to indicate if the column is currently visible in the table or not | |
9287 * @type boolean | |
9288 */ | |
9289 "bVisible": null, | |
9290 | |
9291 /** | |
9292 * Store for manual type assignment using the `column.type` option. This | |
9293 * is held in store so we can manipulate the column's `sType` property. | |
9294 * @type string | |
9295 * @default null | |
9296 * @private | |
9297 */ | |
9298 "_sManualType": null, | |
9299 | |
9300 /** | |
9301 * Flag to indicate if HTML5 data attributes should be used as the data | |
9302 * source for filtering or sorting. True is either are. | |
9303 * @type boolean | |
9304 * @default false | |
9305 * @private | |
9306 */ | |
9307 "_bAttrSrc": false, | |
9308 | |
9309 /** | |
9310 * Developer definable function that is called whenever a cell is created (Ajax source, | |
9311 * etc) or processed for input (DOM source). This can be used as a compliment to mRender | |
9312 * allowing you to modify the DOM element (add background colour for example) when the | |
9313 * element is available. | |
9314 * @type function | |
9315 * @param {element} nTd The TD node that has been created | |
9316 * @param {*} sData The Data for the cell | |
9317 * @param {array|object} oData The data for the whole row | |
9318 * @param {int} iRow The row index for the aoData data store | |
9319 * @default null | |
9320 */ | |
9321 "fnCreatedCell": null, | |
9322 | |
9323 /** | |
9324 * Function to get data from a cell in a column. You should <b>never</b> | |
9325 * access data directly through _aData internally in DataTables - always use | |
9326 * the method attached to this property. It allows mData to function as | |
9327 * required. This function is automatically assigned by the column | |
9328 * initialisation method | |
9329 * @type function | |
9330 * @param {array|object} oData The data array/object for the array | |
9331 * (i.e. aoData[]._aData) | |
9332 * @param {string} sSpecific The specific data type you want to get - | |
9333 * 'display', 'type' 'filter' 'sort' | |
9334 * @returns {*} The data for the cell from the given row's data | |
9335 * @default null | |
9336 */ | |
9337 "fnGetData": null, | |
9338 | |
9339 /** | |
9340 * Function to set data for a cell in the column. You should <b>never</b> | |
9341 * set the data directly to _aData internally in DataTables - always use | |
9342 * this method. It allows mData to function as required. This function | |
9343 * is automatically assigned by the column initialisation method | |
9344 * @type function | |
9345 * @param {array|object} oData The data array/object for the array | |
9346 * (i.e. aoData[]._aData) | |
9347 * @param {*} sValue Value to set | |
9348 * @default null | |
9349 */ | |
9350 "fnSetData": null, | |
9351 | |
9352 /** | |
9353 * Property to read the value for the cells in the column from the data | |
9354 * source array / object. If null, then the default content is used, if a | |
9355 * function is given then the return from the function is used. | |
9356 * @type function|int|string|null | |
9357 * @default null | |
9358 */ | |
9359 "mData": null, | |
9360 | |
9361 /** | |
9362 * Partner property to mData which is used (only when defined) to get | |
9363 * the data - i.e. it is basically the same as mData, but without the | |
9364 * 'set' option, and also the data fed to it is the result from mData. | |
9365 * This is the rendering method to match the data method of mData. | |
9366 * @type function|int|string|null | |
9367 * @default null | |
9368 */ | |
9369 "mRender": null, | |
9370 | |
9371 /** | |
9372 * Unique header TH/TD element for this column - this is what the sorting | |
9373 * listener is attached to (if sorting is enabled.) | |
9374 * @type node | |
9375 * @default null | |
9376 */ | |
9377 "nTh": null, | |
9378 | |
9379 /** | |
9380 * Unique footer TH/TD element for this column (if there is one). Not used | |
9381 * in DataTables as such, but can be used for plug-ins to reference the | |
9382 * footer for each column. | |
9383 * @type node | |
9384 * @default null | |
9385 */ | |
9386 "nTf": null, | |
9387 | |
9388 /** | |
9389 * The class to apply to all TD elements in the table's TBODY for the column | |
9390 * @type string | |
9391 * @default null | |
9392 */ | |
9393 "sClass": null, | |
9394 | |
9395 /** | |
9396 * When DataTables calculates the column widths to assign to each column, | |
9397 * it finds the longest string in each column and then constructs a | |
9398 * temporary table and reads the widths from that. The problem with this | |
9399 * is that "mmm" is much wider then "iiii", but the latter is a longer | |
9400 * string - thus the calculation can go wrong (doing it properly and putting | |
9401 * it into an DOM object and measuring that is horribly(!) slow). Thus as | |
9402 * a "work around" we provide this option. It will append its value to the | |
9403 * text that is found to be the longest string for the column - i.e. padding. | |
9404 * @type string | |
9405 */ | |
9406 "sContentPadding": null, | |
9407 | |
9408 /** | |
9409 * Allows a default value to be given for a column's data, and will be used | |
9410 * whenever a null data source is encountered (this can be because mData | |
9411 * is set to null, or because the data source itself is null). | |
9412 * @type string | |
9413 * @default null | |
9414 */ | |
9415 "sDefaultContent": null, | |
9416 | |
9417 /** | |
9418 * Name for the column, allowing reference to the column by name as well as | |
9419 * by index (needs a lookup to work by name). | |
9420 * @type string | |
9421 */ | |
9422 "sName": null, | |
9423 | |
9424 /** | |
9425 * Custom sorting data type - defines which of the available plug-ins in | |
9426 * afnSortData the custom sorting will use - if any is defined. | |
9427 * @type string | |
9428 * @default std | |
9429 */ | |
9430 "sSortDataType": 'std', | |
9431 | |
9432 /** | |
9433 * Class to be applied to the header element when sorting on this column | |
9434 * @type string | |
9435 * @default null | |
9436 */ | |
9437 "sSortingClass": null, | |
9438 | |
9439 /** | |
9440 * Class to be applied to the header element when sorting on this column - | |
9441 * when jQuery UI theming is used. | |
9442 * @type string | |
9443 * @default null | |
9444 */ | |
9445 "sSortingClassJUI": null, | |
9446 | |
9447 /** | |
9448 * Title of the column - what is seen in the TH element (nTh). | |
9449 * @type string | |
9450 */ | |
9451 "sTitle": null, | |
9452 | |
9453 /** | |
9454 * Column sorting and filtering type | |
9455 * @type string | |
9456 * @default null | |
9457 */ | |
9458 "sType": null, | |
9459 | |
9460 /** | |
9461 * Width of the column | |
9462 * @type string | |
9463 * @default null | |
9464 */ | |
9465 "sWidth": null, | |
9466 | |
9467 /** | |
9468 * Width of the column when it was first "encountered" | |
9469 * @type string | |
9470 * @default null | |
9471 */ | |
9472 "sWidthOrig": null | |
9473 }; | |
9474 | |
9475 | |
9476 /* | |
9477 * Developer note: The properties of the object below are given in Hungarian | |
9478 * notation, that was used as the interface for DataTables prior to v1.10, however | |
9479 * from v1.10 onwards the primary interface is camel case. In order to avoid | |
9480 * breaking backwards compatibility utterly with this change, the Hungarian | |
9481 * version is still, internally the primary interface, but is is not documented | |
9482 * - hence the @name tags in each doc comment. This allows a Javascript function | |
9483 * to create a map from Hungarian notation to camel case (going the other direction | |
9484 * would require each property to be listed, which would at around 3K to the size | |
9485 * of DataTables, while this method is about a 0.5K hit. | |
9486 * | |
9487 * Ultimately this does pave the way for Hungarian notation to be dropped | |
9488 * completely, but that is a massive amount of work and will break current | |
9489 * installs (therefore is on-hold until v2). | |
9490 */ | |
9491 | |
9492 /** | |
9493 * Initialisation options that can be given to DataTables at initialisation | |
9494 * time. | |
9495 * @namespace | |
9496 */ | |
9497 DataTable.defaults = { | |
9498 /** | |
9499 * An array of data to use for the table, passed in at initialisation which | |
9500 * will be used in preference to any data which is already in the DOM. This is | |
9501 * particularly useful for constructing tables purely in Javascript, for | |
9502 * example with a custom Ajax call. | |
9503 * @type array | |
9504 * @default null | |
9505 * | |
9506 * @dtopt Option | |
9507 * @name DataTable.defaults.data | |
9508 * | |
9509 * @example | |
9510 * // Using a 2D array data source | |
9511 * $(document).ready( function () { | |
9512 * $('#example').dataTable( { | |
9513 * "data": [ | |
9514 * ['Trident', 'Internet Explorer 4.0', 'Win 95+', 4, 'X'], | |
9515 * ['Trident', 'Internet Explorer 5.0', 'Win 95+', 5, 'C'], | |
9516 * ], | |
9517 * "columns": [ | |
9518 * { "title": "Engine" }, | |
9519 * { "title": "Browser" }, | |
9520 * { "title": "Platform" }, | |
9521 * { "title": "Version" }, | |
9522 * { "title": "Grade" } | |
9523 * ] | |
9524 * } ); | |
9525 * } ); | |
9526 * | |
9527 * @example | |
9528 * // Using an array of objects as a data source (`data`) | |
9529 * $(document).ready( function () { | |
9530 * $('#example').dataTable( { | |
9531 * "data": [ | |
9532 * { | |
9533 * "engine": "Trident", | |
9534 * "browser": "Internet Explorer 4.0", | |
9535 * "platform": "Win 95+", | |
9536 * "version": 4, | |
9537 * "grade": "X" | |
9538 * }, | |
9539 * { | |
9540 * "engine": "Trident", | |
9541 * "browser": "Internet Explorer 5.0", | |
9542 * "platform": "Win 95+", | |
9543 * "version": 5, | |
9544 * "grade": "C" | |
9545 * } | |
9546 * ], | |
9547 * "columns": [ | |
9548 * { "title": "Engine", "data": "engine" }, | |
9549 * { "title": "Browser", "data": "browser" }, | |
9550 * { "title": "Platform", "data": "platform" }, | |
9551 * { "title": "Version", "data": "version" }, | |
9552 * { "title": "Grade", "data": "grade" } | |
9553 * ] | |
9554 * } ); | |
9555 * } ); | |
9556 */ | |
9557 "aaData": null, | |
9558 | |
9559 | |
9560 /** | |
9561 * If ordering is enabled, then DataTables will perform a first pass sort on | |
9562 * initialisation. You can define which column(s) the sort is performed | |
9563 * upon, and the sorting direction, with this variable. The `sorting` array | |
9564 * should contain an array for each column to be sorted initially containing | |
9565 * the column's index and a direction string ('asc' or 'desc'). | |
9566 * @type array | |
9567 * @default [[0,'asc']] | |
9568 * | |
9569 * @dtopt Option | |
9570 * @name DataTable.defaults.order | |
9571 * | |
9572 * @example | |
9573 * // Sort by 3rd column first, and then 4th column | |
9574 * $(document).ready( function() { | |
9575 * $('#example').dataTable( { | |
9576 * "order": [[2,'asc'], [3,'desc']] | |
9577 * } ); | |
9578 * } ); | |
9579 * | |
9580 * // No initial sorting | |
9581 * $(document).ready( function() { | |
9582 * $('#example').dataTable( { | |
9583 * "order": [] | |
9584 * } ); | |
9585 * } ); | |
9586 */ | |
9587 "aaSorting": [[0,'asc']], | |
9588 | |
9589 | |
9590 /** | |
9591 * This parameter is basically identical to the `sorting` parameter, but | |
9592 * cannot be overridden by user interaction with the table. What this means | |
9593 * is that you could have a column (visible or hidden) which the sorting | |
9594 * will always be forced on first - any sorting after that (from the user) | |
9595 * will then be performed as required. This can be useful for grouping rows | |
9596 * together. | |
9597 * @type array | |
9598 * @default null | |
9599 * | |
9600 * @dtopt Option | |
9601 * @name DataTable.defaults.orderFixed | |
9602 * | |
9603 * @example | |
9604 * $(document).ready( function() { | |
9605 * $('#example').dataTable( { | |
9606 * "orderFixed": [[0,'asc']] | |
9607 * } ); | |
9608 * } ) | |
9609 */ | |
9610 "aaSortingFixed": [], | |
9611 | |
9612 | |
9613 /** | |
9614 * DataTables can be instructed to load data to display in the table from a | |
9615 * Ajax source. This option defines how that Ajax call is made and where to. | |
9616 * | |
9617 * The `ajax` property has three different modes of operation, depending on | |
9618 * how it is defined. These are: | |
9619 * | |
9620 * * `string` - Set the URL from where the data should be loaded from. | |
9621 * * `object` - Define properties for `jQuery.ajax`. | |
9622 * * `function` - Custom data get function | |
9623 * | |
9624 * `string` | |
9625 * -------- | |
9626 * | |
9627 * As a string, the `ajax` property simply defines the URL from which | |
9628 * DataTables will load data. | |
9629 * | |
9630 * `object` | |
9631 * -------- | |
9632 * | |
9633 * As an object, the parameters in the object are passed to | |
9634 * [jQuery.ajax](http://api.jquery.com/jQuery.ajax/) allowing fine control | |
9635 * of the Ajax request. DataTables has a number of default parameters which | |
9636 * you can override using this option. Please refer to the jQuery | |
9637 * documentation for a full description of the options available, although | |
9638 * the following parameters provide additional options in DataTables or | |
9639 * require special consideration: | |
9640 * | |
9641 * * `data` - As with jQuery, `data` can be provided as an object, but it | |
9642 * can also be used as a function to manipulate the data DataTables sends | |
9643 * to the server. The function takes a single parameter, an object of | |
9644 * parameters with the values that DataTables has readied for sending. An | |
9645 * object may be returned which will be merged into the DataTables | |
9646 * defaults, or you can add the items to the object that was passed in and | |
9647 * not return anything from the function. This supersedes `fnServerParams` | |
9648 * from DataTables 1.9-. | |
9649 * | |
9650 * * `dataSrc` - By default DataTables will look for the property `data` (or | |
9651 * `aaData` for compatibility with DataTables 1.9-) when obtaining data | |
9652 * from an Ajax source or for server-side processing - this parameter | |
9653 * allows that property to be changed. You can use Javascript dotted | |
9654 * object notation to get a data source for multiple levels of nesting, or | |
9655 * it my be used as a function. As a function it takes a single parameter, | |
9656 * the JSON returned from the server, which can be manipulated as | |
9657 * required, with the returned value being that used by DataTables as the | |
9658 * data source for the table. This supersedes `sAjaxDataProp` from | |
9659 * DataTables 1.9-. | |
9660 * | |
9661 * * `success` - Should not be overridden it is used internally in | |
9662 * DataTables. To manipulate / transform the data returned by the server | |
9663 * use `ajax.dataSrc`, or use `ajax` as a function (see below). | |
9664 * | |
9665 * `function` | |
9666 * ---------- | |
9667 * | |
9668 * As a function, making the Ajax call is left up to yourself allowing | |
9669 * complete control of the Ajax request. Indeed, if desired, a method other | |
9670 * than Ajax could be used to obtain the required data, such as Web storage | |
9671 * or an AIR database. | |
9672 * | |
9673 * The function is given four parameters and no return is required. The | |
9674 * parameters are: | |
9675 * | |
9676 * 1. _object_ - Data to send to the server | |
9677 * 2. _function_ - Callback function that must be executed when the required | |
9678 * data has been obtained. That data should be passed into the callback | |
9679 * as the only parameter | |
9680 * 3. _object_ - DataTables settings object for the table | |
9681 * | |
9682 * Note that this supersedes `fnServerData` from DataTables 1.9-. | |
9683 * | |
9684 * @type string|object|function | |
9685 * @default null | |
9686 * | |
9687 * @dtopt Option | |
9688 * @name DataTable.defaults.ajax | |
9689 * @since 1.10.0 | |
9690 * | |
9691 * @example | |
9692 * // Get JSON data from a file via Ajax. | |
9693 * // Note DataTables expects data in the form `{ data: [ ...data... ] }` by default). | |
9694 * $('#example').dataTable( { | |
9695 * "ajax": "data.json" | |
9696 * } ); | |
9697 * | |
9698 * @example | |
9699 * // Get JSON data from a file via Ajax, using `dataSrc` to change | |
9700 * // `data` to `tableData` (i.e. `{ tableData: [ ...data... ] }`) | |
9701 * $('#example').dataTable( { | |
9702 * "ajax": { | |
9703 * "url": "data.json", | |
9704 * "dataSrc": "tableData" | |
9705 * } | |
9706 * } ); | |
9707 * | |
9708 * @example | |
9709 * // Get JSON data from a file via Ajax, using `dataSrc` to read data | |
9710 * // from a plain array rather than an array in an object | |
9711 * $('#example').dataTable( { | |
9712 * "ajax": { | |
9713 * "url": "data.json", | |
9714 * "dataSrc": "" | |
9715 * } | |
9716 * } ); | |
9717 * | |
9718 * @example | |
9719 * // Manipulate the data returned from the server - add a link to data | |
9720 * // (note this can, should, be done using `render` for the column - this | |
9721 * // is just a simple example of how the data can be manipulated). | |
9722 * $('#example').dataTable( { | |
9723 * "ajax": { | |
9724 * "url": "data.json", | |
9725 * "dataSrc": function ( json ) { | |
9726 * for ( var i=0, ien=json.length ; i<ien ; i++ ) { | |
9727 * json[i][0] = '<a href="/message/'+json[i][0]+'>View message</a>'; | |
9728 * } | |
9729 * return json; | |
9730 * } | |
9731 * } | |
9732 * } ); | |
9733 * | |
9734 * @example | |
9735 * // Add data to the request | |
9736 * $('#example').dataTable( { | |
9737 * "ajax": { | |
9738 * "url": "data.json", | |
9739 * "data": function ( d ) { | |
9740 * return { | |
9741 * "extra_search": $('#extra').val() | |
9742 * }; | |
9743 * } | |
9744 * } | |
9745 * } ); | |
9746 * | |
9747 * @example | |
9748 * // Send request as POST | |
9749 * $('#example').dataTable( { | |
9750 * "ajax": { | |
9751 * "url": "data.json", | |
9752 * "type": "POST" | |
9753 * } | |
9754 * } ); | |
9755 * | |
9756 * @example | |
9757 * // Get the data from localStorage (could interface with a form for | |
9758 * // adding, editing and removing rows). | |
9759 * $('#example').dataTable( { | |
9760 * "ajax": function (data, callback, settings) { | |
9761 * callback( | |
9762 * JSON.parse( localStorage.getItem('dataTablesData') ) | |
9763 * ); | |
9764 * } | |
9765 * } ); | |
9766 */ | |
9767 "ajax": null, | |
9768 | |
9769 | |
9770 /** | |
9771 * This parameter allows you to readily specify the entries in the length drop | |
9772 * down menu that DataTables shows when pagination is enabled. It can be | |
9773 * either a 1D array of options which will be used for both the displayed | |
9774 * option and the value, or a 2D array which will use the array in the first | |
9775 * position as the value, and the array in the second position as the | |
9776 * displayed options (useful for language strings such as 'All'). | |
9777 * | |
9778 * Note that the `pageLength` property will be automatically set to the | |
9779 * first value given in this array, unless `pageLength` is also provided. | |
9780 * @type array | |
9781 * @default [ 10, 25, 50, 100 ] | |
9782 * | |
9783 * @dtopt Option | |
9784 * @name DataTable.defaults.lengthMenu | |
9785 * | |
9786 * @example | |
9787 * $(document).ready( function() { | |
9788 * $('#example').dataTable( { | |
9789 * "lengthMenu": [[10, 25, 50, -1], [10, 25, 50, "All"]] | |
9790 * } ); | |
9791 * } ); | |
9792 */ | |
9793 "aLengthMenu": [ 10, 25, 50, 100 ], | |
9794 | |
9795 | |
9796 /** | |
9797 * The `columns` option in the initialisation parameter allows you to define | |
9798 * details about the way individual columns behave. For a full list of | |
9799 * column options that can be set, please see | |
9800 * {@link DataTable.defaults.column}. Note that if you use `columns` to | |
9801 * define your columns, you must have an entry in the array for every single | |
9802 * column that you have in your table (these can be null if you don't which | |
9803 * to specify any options). | |
9804 * @member | |
9805 * | |
9806 * @name DataTable.defaults.column | |
9807 */ | |
9808 "aoColumns": null, | |
9809 | |
9810 /** | |
9811 * Very similar to `columns`, `columnDefs` allows you to target a specific | |
9812 * column, multiple columns, or all columns, using the `targets` property of | |
9813 * each object in the array. This allows great flexibility when creating | |
9814 * tables, as the `columnDefs` arrays can be of any length, targeting the | |
9815 * columns you specifically want. `columnDefs` may use any of the column | |
9816 * options available: {@link DataTable.defaults.column}, but it _must_ | |
9817 * have `targets` defined in each object in the array. Values in the `targets` | |
9818 * array may be: | |
9819 * <ul> | |
9820 * <li>a string - class name will be matched on the TH for the column</li> | |
9821 * <li>0 or a positive integer - column index counting from the left</li> | |
9822 * <li>a negative integer - column index counting from the right</li> | |
9823 * <li>the string "_all" - all columns (i.e. assign a default)</li> | |
9824 * </ul> | |
9825 * @member | |
9826 * | |
9827 * @name DataTable.defaults.columnDefs | |
9828 */ | |
9829 "aoColumnDefs": null, | |
9830 | |
9831 | |
9832 /** | |
9833 * Basically the same as `search`, this parameter defines the individual column | |
9834 * filtering state at initialisation time. The array must be of the same size | |
9835 * as the number of columns, and each element be an object with the parameters | |
9836 * `search` and `escapeRegex` (the latter is optional). 'null' is also | |
9837 * accepted and the default will be used. | |
9838 * @type array | |
9839 * @default [] | |
9840 * | |
9841 * @dtopt Option | |
9842 * @name DataTable.defaults.searchCols | |
9843 * | |
9844 * @example | |
9845 * $(document).ready( function() { | |
9846 * $('#example').dataTable( { | |
9847 * "searchCols": [ | |
9848 * null, | |
9849 * { "search": "My filter" }, | |
9850 * null, | |
9851 * { "search": "^[0-9]", "escapeRegex": false } | |
9852 * ] | |
9853 * } ); | |
9854 * } ) | |
9855 */ | |
9856 "aoSearchCols": [], | |
9857 | |
9858 | |
9859 /** | |
9860 * An array of CSS classes that should be applied to displayed rows. This | |
9861 * array may be of any length, and DataTables will apply each class | |
9862 * sequentially, looping when required. | |
9863 * @type array | |
9864 * @default null <i>Will take the values determined by the `oClasses.stripe*` | |
9865 * options</i> | |
9866 * | |
9867 * @dtopt Option | |
9868 * @name DataTable.defaults.stripeClasses | |
9869 * | |
9870 * @example | |
9871 * $(document).ready( function() { | |
9872 * $('#example').dataTable( { | |
9873 * "stripeClasses": [ 'strip1', 'strip2', 'strip3' ] | |
9874 * } ); | |
9875 * } ) | |
9876 */ | |
9877 "asStripeClasses": null, | |
9878 | |
9879 | |
9880 /** | |
9881 * Enable or disable automatic column width calculation. This can be disabled | |
9882 * as an optimisation (it takes some time to calculate the widths) if the | |
9883 * tables widths are passed in using `columns`. | |
9884 * @type boolean | |
9885 * @default true | |
9886 * | |
9887 * @dtopt Features | |
9888 * @name DataTable.defaults.autoWidth | |
9889 * | |
9890 * @example | |
9891 * $(document).ready( function () { | |
9892 * $('#example').dataTable( { | |
9893 * "autoWidth": false | |
9894 * } ); | |
9895 * } ); | |
9896 */ | |
9897 "bAutoWidth": true, | |
9898 | |
9899 | |
9900 /** | |
9901 * Deferred rendering can provide DataTables with a huge speed boost when you | |
9902 * are using an Ajax or JS data source for the table. This option, when set to | |
9903 * true, will cause DataTables to defer the creation of the table elements for | |
9904 * each row until they are needed for a draw - saving a significant amount of | |
9905 * time. | |
9906 * @type boolean | |
9907 * @default false | |
9908 * | |
9909 * @dtopt Features | |
9910 * @name DataTable.defaults.deferRender | |
9911 * | |
9912 * @example | |
9913 * $(document).ready( function() { | |
9914 * $('#example').dataTable( { | |
9915 * "ajax": "sources/arrays.txt", | |
9916 * "deferRender": true | |
9917 * } ); | |
9918 * } ); | |
9919 */ | |
9920 "bDeferRender": false, | |
9921 | |
9922 | |
9923 /** | |
9924 * Replace a DataTable which matches the given selector and replace it with | |
9925 * one which has the properties of the new initialisation object passed. If no | |
9926 * table matches the selector, then the new DataTable will be constructed as | |
9927 * per normal. | |
9928 * @type boolean | |
9929 * @default false | |
9930 * | |
9931 * @dtopt Options | |
9932 * @name DataTable.defaults.destroy | |
9933 * | |
9934 * @example | |
9935 * $(document).ready( function() { | |
9936 * $('#example').dataTable( { | |
9937 * "srollY": "200px", | |
9938 * "paginate": false | |
9939 * } ); | |
9940 * | |
9941 * // Some time later.... | |
9942 * $('#example').dataTable( { | |
9943 * "filter": false, | |
9944 * "destroy": true | |
9945 * } ); | |
9946 * } ); | |
9947 */ | |
9948 "bDestroy": false, | |
9949 | |
9950 | |
9951 /** | |
9952 * Enable or disable filtering of data. Filtering in DataTables is "smart" in | |
9953 * that it allows the end user to input multiple words (space separated) and | |
9954 * will match a row containing those words, even if not in the order that was | |
9955 * specified (this allow matching across multiple columns). Note that if you | |
9956 * wish to use filtering in DataTables this must remain 'true' - to remove the | |
9957 * default filtering input box and retain filtering abilities, please use | |
9958 * {@link DataTable.defaults.dom}. | |
9959 * @type boolean | |
9960 * @default true | |
9961 * | |
9962 * @dtopt Features | |
9963 * @name DataTable.defaults.searching | |
9964 * | |
9965 * @example | |
9966 * $(document).ready( function () { | |
9967 * $('#example').dataTable( { | |
9968 * "searching": false | |
9969 * } ); | |
9970 * } ); | |
9971 */ | |
9972 "bFilter": true, | |
9973 | |
9974 | |
9975 /** | |
9976 * Enable or disable the table information display. This shows information | |
9977 * about the data that is currently visible on the page, including information | |
9978 * about filtered data if that action is being performed. | |
9979 * @type boolean | |
9980 * @default true | |
9981 * | |
9982 * @dtopt Features | |
9983 * @name DataTable.defaults.info | |
9984 * | |
9985 * @example | |
9986 * $(document).ready( function () { | |
9987 * $('#example').dataTable( { | |
9988 * "info": false | |
9989 * } ); | |
9990 * } ); | |
9991 */ | |
9992 "bInfo": true, | |
9993 | |
9994 | |
9995 /** | |
9996 * Enable jQuery UI ThemeRoller support (required as ThemeRoller requires some | |
9997 * slightly different and additional mark-up from what DataTables has | |
9998 * traditionally used). | |
9999 * @type boolean | |
10000 * @default false | |
10001 * | |
10002 * @dtopt Features | |
10003 * @name DataTable.defaults.jQueryUI | |
10004 * | |
10005 * @example | |
10006 * $(document).ready( function() { | |
10007 * $('#example').dataTable( { | |
10008 * "jQueryUI": true | |
10009 * } ); | |
10010 * } ); | |
10011 */ | |
10012 "bJQueryUI": false, | |
10013 | |
10014 | |
10015 /** | |
10016 * Allows the end user to select the size of a formatted page from a select | |
10017 * menu (sizes are 10, 25, 50 and 100). Requires pagination (`paginate`). | |
10018 * @type boolean | |
10019 * @default true | |
10020 * | |
10021 * @dtopt Features | |
10022 * @name DataTable.defaults.lengthChange | |
10023 * | |
10024 * @example | |
10025 * $(document).ready( function () { | |
10026 * $('#example').dataTable( { | |
10027 * "lengthChange": false | |
10028 * } ); | |
10029 * } ); | |
10030 */ | |
10031 "bLengthChange": true, | |
10032 | |
10033 | |
10034 /** | |
10035 * Enable or disable pagination. | |
10036 * @type boolean | |
10037 * @default true | |
10038 * | |
10039 * @dtopt Features | |
10040 * @name DataTable.defaults.paging | |
10041 * | |
10042 * @example | |
10043 * $(document).ready( function () { | |
10044 * $('#example').dataTable( { | |
10045 * "paging": false | |
10046 * } ); | |
10047 * } ); | |
10048 */ | |
10049 "bPaginate": true, | |
10050 | |
10051 | |
10052 /** | |
10053 * Enable or disable the display of a 'processing' indicator when the table is | |
10054 * being processed (e.g. a sort). This is particularly useful for tables with | |
10055 * large amounts of data where it can take a noticeable amount of time to sort | |
10056 * the entries. | |
10057 * @type boolean | |
10058 * @default false | |
10059 * | |
10060 * @dtopt Features | |
10061 * @name DataTable.defaults.processing | |
10062 * | |
10063 * @example | |
10064 * $(document).ready( function () { | |
10065 * $('#example').dataTable( { | |
10066 * "processing": true | |
10067 * } ); | |
10068 * } ); | |
10069 */ | |
10070 "bProcessing": false, | |
10071 | |
10072 | |
10073 /** | |
10074 * Retrieve the DataTables object for the given selector. Note that if the | |
10075 * table has already been initialised, this parameter will cause DataTables | |
10076 * to simply return the object that has already been set up - it will not take | |
10077 * account of any changes you might have made to the initialisation object | |
10078 * passed to DataTables (setting this parameter to true is an acknowledgement | |
10079 * that you understand this). `destroy` can be used to reinitialise a table if | |
10080 * you need. | |
10081 * @type boolean | |
10082 * @default false | |
10083 * | |
10084 * @dtopt Options | |
10085 * @name DataTable.defaults.retrieve | |
10086 * | |
10087 * @example | |
10088 * $(document).ready( function() { | |
10089 * initTable(); | |
10090 * tableActions(); | |
10091 * } ); | |
10092 * | |
10093 * function initTable () | |
10094 * { | |
10095 * return $('#example').dataTable( { | |
10096 * "scrollY": "200px", | |
10097 * "paginate": false, | |
10098 * "retrieve": true | |
10099 * } ); | |
10100 * } | |
10101 * | |
10102 * function tableActions () | |
10103 * { | |
10104 * var table = initTable(); | |
10105 * // perform API operations with oTable | |
10106 * } | |
10107 */ | |
10108 "bRetrieve": false, | |
10109 | |
10110 | |
10111 /** | |
10112 * When vertical (y) scrolling is enabled, DataTables will force the height of | |
10113 * the table's viewport to the given height at all times (useful for layout). | |
10114 * However, this can look odd when filtering data down to a small data set, | |
10115 * and the footer is left "floating" further down. This parameter (when | |
10116 * enabled) will cause DataTables to collapse the table's viewport down when | |
10117 * the result set will fit within the given Y height. | |
10118 * @type boolean | |
10119 * @default false | |
10120 * | |
10121 * @dtopt Options | |
10122 * @name DataTable.defaults.scrollCollapse | |
10123 * | |
10124 * @example | |
10125 * $(document).ready( function() { | |
10126 * $('#example').dataTable( { | |
10127 * "scrollY": "200", | |
10128 * "scrollCollapse": true | |
10129 * } ); | |
10130 * } ); | |
10131 */ | |
10132 "bScrollCollapse": false, | |
10133 | |
10134 | |
10135 /** | |
10136 * Configure DataTables to use server-side processing. Note that the | |
10137 * `ajax` parameter must also be given in order to give DataTables a | |
10138 * source to obtain the required data for each draw. | |
10139 * @type boolean | |
10140 * @default false | |
10141 * | |
10142 * @dtopt Features | |
10143 * @dtopt Server-side | |
10144 * @name DataTable.defaults.serverSide | |
10145 * | |
10146 * @example | |
10147 * $(document).ready( function () { | |
10148 * $('#example').dataTable( { | |
10149 * "serverSide": true, | |
10150 * "ajax": "xhr.php" | |
10151 * } ); | |
10152 * } ); | |
10153 */ | |
10154 "bServerSide": false, | |
10155 | |
10156 | |
10157 /** | |
10158 * Enable or disable sorting of columns. Sorting of individual columns can be | |
10159 * disabled by the `sortable` option for each column. | |
10160 * @type boolean | |
10161 * @default true | |
10162 * | |
10163 * @dtopt Features | |
10164 * @name DataTable.defaults.ordering | |
10165 * | |
10166 * @example | |
10167 * $(document).ready( function () { | |
10168 * $('#example').dataTable( { | |
10169 * "ordering": false | |
10170 * } ); | |
10171 * } ); | |
10172 */ | |
10173 "bSort": true, | |
10174 | |
10175 | |
10176 /** | |
10177 * Enable or display DataTables' ability to sort multiple columns at the | |
10178 * same time (activated by shift-click by the user). | |
10179 * @type boolean | |
10180 * @default true | |
10181 * | |
10182 * @dtopt Options | |
10183 * @name DataTable.defaults.orderMulti | |
10184 * | |
10185 * @example | |
10186 * // Disable multiple column sorting ability | |
10187 * $(document).ready( function () { | |
10188 * $('#example').dataTable( { | |
10189 * "orderMulti": false | |
10190 * } ); | |
10191 * } ); | |
10192 */ | |
10193 "bSortMulti": true, | |
10194 | |
10195 | |
10196 /** | |
10197 * Allows control over whether DataTables should use the top (true) unique | |
10198 * cell that is found for a single column, or the bottom (false - default). | |
10199 * This is useful when using complex headers. | |
10200 * @type boolean | |
10201 * @default false | |
10202 * | |
10203 * @dtopt Options | |
10204 * @name DataTable.defaults.orderCellsTop | |
10205 * | |
10206 * @example | |
10207 * $(document).ready( function() { | |
10208 * $('#example').dataTable( { | |
10209 * "orderCellsTop": true | |
10210 * } ); | |
10211 * } ); | |
10212 */ | |
10213 "bSortCellsTop": false, | |
10214 | |
10215 | |
10216 /** | |
10217 * Enable or disable the addition of the classes `sorting\_1`, `sorting\_2` and | |
10218 * `sorting\_3` to the columns which are currently being sorted on. This is | |
10219 * presented as a feature switch as it can increase processing time (while | |
10220 * classes are removed and added) so for large data sets you might want to | |
10221 * turn this off. | |
10222 * @type boolean | |
10223 * @default true | |
10224 * | |
10225 * @dtopt Features | |
10226 * @name DataTable.defaults.orderClasses | |
10227 * | |
10228 * @example | |
10229 * $(document).ready( function () { | |
10230 * $('#example').dataTable( { | |
10231 * "orderClasses": false | |
10232 * } ); | |
10233 * } ); | |
10234 */ | |
10235 "bSortClasses": true, | |
10236 | |
10237 | |
10238 /** | |
10239 * Enable or disable state saving. When enabled HTML5 `localStorage` will be | |
10240 * used to save table display information such as pagination information, | |
10241 * display length, filtering and sorting. As such when the end user reloads | |
10242 * the page the display display will match what thy had previously set up. | |
10243 * | |
10244 * Due to the use of `localStorage` the default state saving is not supported | |
10245 * in IE6 or 7. If state saving is required in those browsers, use | |
10246 * `stateSaveCallback` to provide a storage solution such as cookies. | |
10247 * @type boolean | |
10248 * @default false | |
10249 * | |
10250 * @dtopt Features | |
10251 * @name DataTable.defaults.stateSave | |
10252 * | |
10253 * @example | |
10254 * $(document).ready( function () { | |
10255 * $('#example').dataTable( { | |
10256 * "stateSave": true | |
10257 * } ); | |
10258 * } ); | |
10259 */ | |
10260 "bStateSave": false, | |
10261 | |
10262 | |
10263 /** | |
10264 * This function is called when a TR element is created (and all TD child | |
10265 * elements have been inserted), or registered if using a DOM source, allowing | |
10266 * manipulation of the TR element (adding classes etc). | |
10267 * @type function | |
10268 * @param {node} row "TR" element for the current row | |
10269 * @param {array} data Raw data array for this row | |
10270 * @param {int} dataIndex The index of this row in the internal aoData array | |
10271 * | |
10272 * @dtopt Callbacks | |
10273 * @name DataTable.defaults.createdRow | |
10274 * | |
10275 * @example | |
10276 * $(document).ready( function() { | |
10277 * $('#example').dataTable( { | |
10278 * "createdRow": function( row, data, dataIndex ) { | |
10279 * // Bold the grade for all 'A' grade browsers | |
10280 * if ( data[4] == "A" ) | |
10281 * { | |
10282 * $('td:eq(4)', row).html( '<b>A</b>' ); | |
10283 * } | |
10284 * } | |
10285 * } ); | |
10286 * } ); | |
10287 */ | |
10288 "fnCreatedRow": null, | |
10289 | |
10290 | |
10291 /** | |
10292 * This function is called on every 'draw' event, and allows you to | |
10293 * dynamically modify any aspect you want about the created DOM. | |
10294 * @type function | |
10295 * @param {object} settings DataTables settings object | |
10296 * | |
10297 * @dtopt Callbacks | |
10298 * @name DataTable.defaults.drawCallback | |
10299 * | |
10300 * @example | |
10301 * $(document).ready( function() { | |
10302 * $('#example').dataTable( { | |
10303 * "drawCallback": function( settings ) { | |
10304 * alert( 'DataTables has redrawn the table' ); | |
10305 * } | |
10306 * } ); | |
10307 * } ); | |
10308 */ | |
10309 "fnDrawCallback": null, | |
10310 | |
10311 | |
10312 /** | |
10313 * Identical to fnHeaderCallback() but for the table footer this function | |
10314 * allows you to modify the table footer on every 'draw' event. | |
10315 * @type function | |
10316 * @param {node} foot "TR" element for the footer | |
10317 * @param {array} data Full table data (as derived from the original HTML) | |
10318 * @param {int} start Index for the current display starting point in the | |
10319 * display array | |
10320 * @param {int} end Index for the current display ending point in the | |
10321 * display array | |
10322 * @param {array int} display Index array to translate the visual position | |
10323 * to the full data array | |
10324 * | |
10325 * @dtopt Callbacks | |
10326 * @name DataTable.defaults.footerCallback | |
10327 * | |
10328 * @example | |
10329 * $(document).ready( function() { | |
10330 * $('#example').dataTable( { | |
10331 * "footerCallback": function( tfoot, data, start, end, display ) { | |
10332 * tfoot.getElementsByTagName('th')[0].innerHTML = "Starting index is "+start; | |
10333 * } | |
10334 * } ); | |
10335 * } ) | |
10336 */ | |
10337 "fnFooterCallback": null, | |
10338 | |
10339 | |
10340 /** | |
10341 * When rendering large numbers in the information element for the table | |
10342 * (i.e. "Showing 1 to 10 of 57 entries") DataTables will render large numbers | |
10343 * to have a comma separator for the 'thousands' units (e.g. 1 million is | |
10344 * rendered as "1,000,000") to help readability for the end user. This | |
10345 * function will override the default method DataTables uses. | |
10346 * @type function | |
10347 * @member | |
10348 * @param {int} toFormat number to be formatted | |
10349 * @returns {string} formatted string for DataTables to show the number | |
10350 * | |
10351 * @dtopt Callbacks | |
10352 * @name DataTable.defaults.formatNumber | |
10353 * | |
10354 * @example | |
10355 * // Format a number using a single quote for the separator (note that | |
10356 * // this can also be done with the language.thousands option) | |
10357 * $(document).ready( function() { | |
10358 * $('#example').dataTable( { | |
10359 * "formatNumber": function ( toFormat ) { | |
10360 * return toFormat.toString().replace( | |
10361 * /\B(?=(\d{3})+(?!\d))/g, "'" | |
10362 * ); | |
10363 * }; | |
10364 * } ); | |
10365 * } ); | |
10366 */ | |
10367 "fnFormatNumber": function ( toFormat ) { | |
10368 return toFormat.toString().replace( | |
10369 /\B(?=(\d{3})+(?!\d))/g, | |
10370 this.oLanguage.sThousands | |
10371 ); | |
10372 }, | |
10373 | |
10374 | |
10375 /** | |
10376 * This function is called on every 'draw' event, and allows you to | |
10377 * dynamically modify the header row. This can be used to calculate and | |
10378 * display useful information about the table. | |
10379 * @type function | |
10380 * @param {node} head "TR" element for the header | |
10381 * @param {array} data Full table data (as derived from the original HTML) | |
10382 * @param {int} start Index for the current display starting point in the | |
10383 * display array | |
10384 * @param {int} end Index for the current display ending point in the | |
10385 * display array | |
10386 * @param {array int} display Index array to translate the visual position | |
10387 * to the full data array | |
10388 * | |
10389 * @dtopt Callbacks | |
10390 * @name DataTable.defaults.headerCallback | |
10391 * | |
10392 * @example | |
10393 * $(document).ready( function() { | |
10394 * $('#example').dataTable( { | |
10395 * "fheaderCallback": function( head, data, start, end, display ) { | |
10396 * head.getElementsByTagName('th')[0].innerHTML = "Displaying "+(end-start)+" records"; | |
10397 * } | |
10398 * } ); | |
10399 * } ) | |
10400 */ | |
10401 "fnHeaderCallback": null, | |
10402 | |
10403 | |
10404 /** | |
10405 * The information element can be used to convey information about the current | |
10406 * state of the table. Although the internationalisation options presented by | |
10407 * DataTables are quite capable of dealing with most customisations, there may | |
10408 * be times where you wish to customise the string further. This callback | |
10409 * allows you to do exactly that. | |
10410 * @type function | |
10411 * @param {object} oSettings DataTables settings object | |
10412 * @param {int} start Starting position in data for the draw | |
10413 * @param {int} end End position in data for the draw | |
10414 * @param {int} max Total number of rows in the table (regardless of | |
10415 * filtering) | |
10416 * @param {int} total Total number of rows in the data set, after filtering | |
10417 * @param {string} pre The string that DataTables has formatted using it's | |
10418 * own rules | |
10419 * @returns {string} The string to be displayed in the information element. | |
10420 * | |
10421 * @dtopt Callbacks | |
10422 * @name DataTable.defaults.infoCallback | |
10423 * | |
10424 * @example | |
10425 * $('#example').dataTable( { | |
10426 * "infoCallback": function( settings, start, end, max, total, pre ) { | |
10427 * return start +" to "+ end; | |
10428 * } | |
10429 * } ); | |
10430 */ | |
10431 "fnInfoCallback": null, | |
10432 | |
10433 | |
10434 /** | |
10435 * Called when the table has been initialised. Normally DataTables will | |
10436 * initialise sequentially and there will be no need for this function, | |
10437 * however, this does not hold true when using external language information | |
10438 * since that is obtained using an async XHR call. | |
10439 * @type function | |
10440 * @param {object} settings DataTables settings object | |
10441 * @param {object} json The JSON object request from the server - only | |
10442 * present if client-side Ajax sourced data is used | |
10443 * | |
10444 * @dtopt Callbacks | |
10445 * @name DataTable.defaults.initComplete | |
10446 * | |
10447 * @example | |
10448 * $(document).ready( function() { | |
10449 * $('#example').dataTable( { | |
10450 * "initComplete": function(settings, json) { | |
10451 * alert( 'DataTables has finished its initialisation.' ); | |
10452 * } | |
10453 * } ); | |
10454 * } ) | |
10455 */ | |
10456 "fnInitComplete": null, | |
10457 | |
10458 | |
10459 /** | |
10460 * Called at the very start of each table draw and can be used to cancel the | |
10461 * draw by returning false, any other return (including undefined) results in | |
10462 * the full draw occurring). | |
10463 * @type function | |
10464 * @param {object} settings DataTables settings object | |
10465 * @returns {boolean} False will cancel the draw, anything else (including no | |
10466 * return) will allow it to complete. | |
10467 * | |
10468 * @dtopt Callbacks | |
10469 * @name DataTable.defaults.preDrawCallback | |
10470 * | |
10471 * @example | |
10472 * $(document).ready( function() { | |
10473 * $('#example').dataTable( { | |
10474 * "preDrawCallback": function( settings ) { | |
10475 * if ( $('#test').val() == 1 ) { | |
10476 * return false; | |
10477 * } | |
10478 * } | |
10479 * } ); | |
10480 * } ); | |
10481 */ | |
10482 "fnPreDrawCallback": null, | |
10483 | |
10484 | |
10485 /** | |
10486 * This function allows you to 'post process' each row after it have been | |
10487 * generated for each table draw, but before it is rendered on screen. This | |
10488 * function might be used for setting the row class name etc. | |
10489 * @type function | |
10490 * @param {node} row "TR" element for the current row | |
10491 * @param {array} data Raw data array for this row | |
10492 * @param {int} displayIndex The display index for the current table draw | |
10493 * @param {int} displayIndexFull The index of the data in the full list of | |
10494 * rows (after filtering) | |
10495 * | |
10496 * @dtopt Callbacks | |
10497 * @name DataTable.defaults.rowCallback | |
10498 * | |
10499 * @example | |
10500 * $(document).ready( function() { | |
10501 * $('#example').dataTable( { | |
10502 * "rowCallback": function( row, data, displayIndex, displayIndexFull ) { | |
10503 * // Bold the grade for all 'A' grade browsers | |
10504 * if ( data[4] == "A" ) { | |
10505 * $('td:eq(4)', row).html( '<b>A</b>' ); | |
10506 * } | |
10507 * } | |
10508 * } ); | |
10509 * } ); | |
10510 */ | |
10511 "fnRowCallback": null, | |
10512 | |
10513 | |
10514 /** | |
10515 * __Deprecated__ The functionality provided by this parameter has now been | |
10516 * superseded by that provided through `ajax`, which should be used instead. | |
10517 * | |
10518 * This parameter allows you to override the default function which obtains | |
10519 * the data from the server so something more suitable for your application. | |
10520 * For example you could use POST data, or pull information from a Gears or | |
10521 * AIR database. | |
10522 * @type function | |
10523 * @member | |
10524 * @param {string} source HTTP source to obtain the data from (`ajax`) | |
10525 * @param {array} data A key/value pair object containing the data to send | |
10526 * to the server | |
10527 * @param {function} callback to be called on completion of the data get | |
10528 * process that will draw the data on the page. | |
10529 * @param {object} settings DataTables settings object | |
10530 * | |
10531 * @dtopt Callbacks | |
10532 * @dtopt Server-side | |
10533 * @name DataTable.defaults.serverData | |
10534 * | |
10535 * @deprecated 1.10. Please use `ajax` for this functionality now. | |
10536 */ | |
10537 "fnServerData": null, | |
10538 | |
10539 | |
10540 /** | |
10541 * __Deprecated__ The functionality provided by this parameter has now been | |
10542 * superseded by that provided through `ajax`, which should be used instead. | |
10543 * | |
10544 * It is often useful to send extra data to the server when making an Ajax | |
10545 * request - for example custom filtering information, and this callback | |
10546 * function makes it trivial to send extra information to the server. The | |
10547 * passed in parameter is the data set that has been constructed by | |
10548 * DataTables, and you can add to this or modify it as you require. | |
10549 * @type function | |
10550 * @param {array} data Data array (array of objects which are name/value | |
10551 * pairs) that has been constructed by DataTables and will be sent to the | |
10552 * server. In the case of Ajax sourced data with server-side processing | |
10553 * this will be an empty array, for server-side processing there will be a | |
10554 * significant number of parameters! | |
10555 * @returns {undefined} Ensure that you modify the data array passed in, | |
10556 * as this is passed by reference. | |
10557 * | |
10558 * @dtopt Callbacks | |
10559 * @dtopt Server-side | |
10560 * @name DataTable.defaults.serverParams | |
10561 * | |
10562 * @deprecated 1.10. Please use `ajax` for this functionality now. | |
10563 */ | |
10564 "fnServerParams": null, | |
10565 | |
10566 | |
10567 /** | |
10568 * Load the table state. With this function you can define from where, and how, the | |
10569 * state of a table is loaded. By default DataTables will load from `localStorage` | |
10570 * but you might wish to use a server-side database or cookies. | |
10571 * @type function | |
10572 * @member | |
10573 * @param {object} settings DataTables settings object | |
10574 * @return {object} The DataTables state object to be loaded | |
10575 * | |
10576 * @dtopt Callbacks | |
10577 * @name DataTable.defaults.stateLoadCallback | |
10578 * | |
10579 * @example | |
10580 * $(document).ready( function() { | |
10581 * $('#example').dataTable( { | |
10582 * "stateSave": true, | |
10583 * "stateLoadCallback": function (settings) { | |
10584 * var o; | |
10585 * | |
10586 * // Send an Ajax request to the server to get the data. Note that | |
10587 * // this is a synchronous request. | |
10588 * $.ajax( { | |
10589 * "url": "/state_load", | |
10590 * "async": false, | |
10591 * "dataType": "json", | |
10592 * "success": function (json) { | |
10593 * o = json; | |
10594 * } | |
10595 * } ); | |
10596 * | |
10597 * return o; | |
10598 * } | |
10599 * } ); | |
10600 * } ); | |
10601 */ | |
10602 "fnStateLoadCallback": function ( settings ) { | |
10603 try { | |
10604 return JSON.parse( | |
10605 (settings.iStateDuration === -1 ? sessionStorage : localStorage).getItem( | |
10606 'DataTables_'+settings.sInstance+'_'+location.pathname | |
10607 ) | |
10608 ); | |
10609 } catch (e) {} | |
10610 }, | |
10611 | |
10612 | |
10613 /** | |
10614 * Callback which allows modification of the saved state prior to loading that state. | |
10615 * This callback is called when the table is loading state from the stored data, but | |
10616 * prior to the settings object being modified by the saved state. Note that for | |
10617 * plug-in authors, you should use the `stateLoadParams` event to load parameters for | |
10618 * a plug-in. | |
10619 * @type function | |
10620 * @param {object} settings DataTables settings object | |
10621 * @param {object} data The state object that is to be loaded | |
10622 * | |
10623 * @dtopt Callbacks | |
10624 * @name DataTable.defaults.stateLoadParams | |
10625 * | |
10626 * @example | |
10627 * // Remove a saved filter, so filtering is never loaded | |
10628 * $(document).ready( function() { | |
10629 * $('#example').dataTable( { | |
10630 * "stateSave": true, | |
10631 * "stateLoadParams": function (settings, data) { | |
10632 * data.oSearch.sSearch = ""; | |
10633 * } | |
10634 * } ); | |
10635 * } ); | |
10636 * | |
10637 * @example | |
10638 * // Disallow state loading by returning false | |
10639 * $(document).ready( function() { | |
10640 * $('#example').dataTable( { | |
10641 * "stateSave": true, | |
10642 * "stateLoadParams": function (settings, data) { | |
10643 * return false; | |
10644 * } | |
10645 * } ); | |
10646 * } ); | |
10647 */ | |
10648 "fnStateLoadParams": null, | |
10649 | |
10650 | |
10651 /** | |
10652 * Callback that is called when the state has been loaded from the state saving method | |
10653 * and the DataTables settings object has been modified as a result of the loaded state. | |
10654 * @type function | |
10655 * @param {object} settings DataTables settings object | |
10656 * @param {object} data The state object that was loaded | |
10657 * | |
10658 * @dtopt Callbacks | |
10659 * @name DataTable.defaults.stateLoaded | |
10660 * | |
10661 * @example | |
10662 * // Show an alert with the filtering value that was saved | |
10663 * $(document).ready( function() { | |
10664 * $('#example').dataTable( { | |
10665 * "stateSave": true, | |
10666 * "stateLoaded": function (settings, data) { | |
10667 * alert( 'Saved filter was: '+data.oSearch.sSearch ); | |
10668 * } | |
10669 * } ); | |
10670 * } ); | |
10671 */ | |
10672 "fnStateLoaded": null, | |
10673 | |
10674 | |
10675 /** | |
10676 * Save the table state. This function allows you to define where and how the state | |
10677 * information for the table is stored By default DataTables will use `localStorage` | |
10678 * but you might wish to use a server-side database or cookies. | |
10679 * @type function | |
10680 * @member | |
10681 * @param {object} settings DataTables settings object | |
10682 * @param {object} data The state object to be saved | |
10683 * | |
10684 * @dtopt Callbacks | |
10685 * @name DataTable.defaults.stateSaveCallback | |
10686 * | |
10687 * @example | |
10688 * $(document).ready( function() { | |
10689 * $('#example').dataTable( { | |
10690 * "stateSave": true, | |
10691 * "stateSaveCallback": function (settings, data) { | |
10692 * // Send an Ajax request to the server with the state object | |
10693 * $.ajax( { | |
10694 * "url": "/state_save", | |
10695 * "data": data, | |
10696 * "dataType": "json", | |
10697 * "method": "POST" | |
10698 * "success": function () {} | |
10699 * } ); | |
10700 * } | |
10701 * } ); | |
10702 * } ); | |
10703 */ | |
10704 "fnStateSaveCallback": function ( settings, data ) { | |
10705 try { | |
10706 (settings.iStateDuration === -1 ? sessionStorage : localStorage).setItem( | |
10707 'DataTables_'+settings.sInstance+'_'+location.pathname, | |
10708 JSON.stringify( data ) | |
10709 ); | |
10710 } catch (e) {} | |
10711 }, | |
10712 | |
10713 | |
10714 /** | |
10715 * Callback which allows modification of the state to be saved. Called when the table | |
10716 * has changed state a new state save is required. This method allows modification of | |
10717 * the state saving object prior to actually doing the save, including addition or | |
10718 * other state properties or modification. Note that for plug-in authors, you should | |
10719 * use the `stateSaveParams` event to save parameters for a plug-in. | |
10720 * @type function | |
10721 * @param {object} settings DataTables settings object | |
10722 * @param {object} data The state object to be saved | |
10723 * | |
10724 * @dtopt Callbacks | |
10725 * @name DataTable.defaults.stateSaveParams | |
10726 * | |
10727 * @example | |
10728 * // Remove a saved filter, so filtering is never saved | |
10729 * $(document).ready( function() { | |
10730 * $('#example').dataTable( { | |
10731 * "stateSave": true, | |
10732 * "stateSaveParams": function (settings, data) { | |
10733 * data.oSearch.sSearch = ""; | |
10734 * } | |
10735 * } ); | |
10736 * } ); | |
10737 */ | |
10738 "fnStateSaveParams": null, | |
10739 | |
10740 | |
10741 /** | |
10742 * Duration for which the saved state information is considered valid. After this period | |
10743 * has elapsed the state will be returned to the default. | |
10744 * Value is given in seconds. | |
10745 * @type int | |
10746 * @default 7200 <i>(2 hours)</i> | |
10747 * | |
10748 * @dtopt Options | |
10749 * @name DataTable.defaults.stateDuration | |
10750 * | |
10751 * @example | |
10752 * $(document).ready( function() { | |
10753 * $('#example').dataTable( { | |
10754 * "stateDuration": 60*60*24; // 1 day | |
10755 * } ); | |
10756 * } ) | |
10757 */ | |
10758 "iStateDuration": 7200, | |
10759 | |
10760 | |
10761 /** | |
10762 * When enabled DataTables will not make a request to the server for the first | |
10763 * page draw - rather it will use the data already on the page (no sorting etc | |
10764 * will be applied to it), thus saving on an XHR at load time. `deferLoading` | |
10765 * is used to indicate that deferred loading is required, but it is also used | |
10766 * to tell DataTables how many records there are in the full table (allowing | |
10767 * the information element and pagination to be displayed correctly). In the case | |
10768 * where a filtering is applied to the table on initial load, this can be | |
10769 * indicated by giving the parameter as an array, where the first element is | |
10770 * the number of records available after filtering and the second element is the | |
10771 * number of records without filtering (allowing the table information element | |
10772 * to be shown correctly). | |
10773 * @type int | array | |
10774 * @default null | |
10775 * | |
10776 * @dtopt Options | |
10777 * @name DataTable.defaults.deferLoading | |
10778 * | |
10779 * @example | |
10780 * // 57 records available in the table, no filtering applied | |
10781 * $(document).ready( function() { | |
10782 * $('#example').dataTable( { | |
10783 * "serverSide": true, | |
10784 * "ajax": "scripts/server_processing.php", | |
10785 * "deferLoading": 57 | |
10786 * } ); | |
10787 * } ); | |
10788 * | |
10789 * @example | |
10790 * // 57 records after filtering, 100 without filtering (an initial filter applied) | |
10791 * $(document).ready( function() { | |
10792 * $('#example').dataTable( { | |
10793 * "serverSide": true, | |
10794 * "ajax": "scripts/server_processing.php", | |
10795 * "deferLoading": [ 57, 100 ], | |
10796 * "search": { | |
10797 * "search": "my_filter" | |
10798 * } | |
10799 * } ); | |
10800 * } ); | |
10801 */ | |
10802 "iDeferLoading": null, | |
10803 | |
10804 | |
10805 /** | |
10806 * Number of rows to display on a single page when using pagination. If | |
10807 * feature enabled (`lengthChange`) then the end user will be able to override | |
10808 * this to a custom setting using a pop-up menu. | |
10809 * @type int | |
10810 * @default 10 | |
10811 * | |
10812 * @dtopt Options | |
10813 * @name DataTable.defaults.pageLength | |
10814 * | |
10815 * @example | |
10816 * $(document).ready( function() { | |
10817 * $('#example').dataTable( { | |
10818 * "pageLength": 50 | |
10819 * } ); | |
10820 * } ) | |
10821 */ | |
10822 "iDisplayLength": 10, | |
10823 | |
10824 | |
10825 /** | |
10826 * Define the starting point for data display when using DataTables with | |
10827 * pagination. Note that this parameter is the number of records, rather than | |
10828 * the page number, so if you have 10 records per page and want to start on | |
10829 * the third page, it should be "20". | |
10830 * @type int | |
10831 * @default 0 | |
10832 * | |
10833 * @dtopt Options | |
10834 * @name DataTable.defaults.displayStart | |
10835 * | |
10836 * @example | |
10837 * $(document).ready( function() { | |
10838 * $('#example').dataTable( { | |
10839 * "displayStart": 20 | |
10840 * } ); | |
10841 * } ) | |
10842 */ | |
10843 "iDisplayStart": 0, | |
10844 | |
10845 | |
10846 /** | |
10847 * By default DataTables allows keyboard navigation of the table (sorting, paging, | |
10848 * and filtering) by adding a `tabindex` attribute to the required elements. This | |
10849 * allows you to tab through the controls and press the enter key to activate them. | |
10850 * The tabindex is default 0, meaning that the tab follows the flow of the document. | |
10851 * You can overrule this using this parameter if you wish. Use a value of -1 to | |
10852 * disable built-in keyboard navigation. | |
10853 * @type int | |
10854 * @default 0 | |
10855 * | |
10856 * @dtopt Options | |
10857 * @name DataTable.defaults.tabIndex | |
10858 * | |
10859 * @example | |
10860 * $(document).ready( function() { | |
10861 * $('#example').dataTable( { | |
10862 * "tabIndex": 1 | |
10863 * } ); | |
10864 * } ); | |
10865 */ | |
10866 "iTabIndex": 0, | |
10867 | |
10868 | |
10869 /** | |
10870 * Classes that DataTables assigns to the various components and features | |
10871 * that it adds to the HTML table. This allows classes to be configured | |
10872 * during initialisation in addition to through the static | |
10873 * {@link DataTable.ext.oStdClasses} object). | |
10874 * @namespace | |
10875 * @name DataTable.defaults.classes | |
10876 */ | |
10877 "oClasses": {}, | |
10878 | |
10879 | |
10880 /** | |
10881 * All strings that DataTables uses in the user interface that it creates | |
10882 * are defined in this object, allowing you to modified them individually or | |
10883 * completely replace them all as required. | |
10884 * @namespace | |
10885 * @name DataTable.defaults.language | |
10886 */ | |
10887 "oLanguage": { | |
10888 /** | |
10889 * Strings that are used for WAI-ARIA labels and controls only (these are not | |
10890 * actually visible on the page, but will be read by screenreaders, and thus | |
10891 * must be internationalised as well). | |
10892 * @namespace | |
10893 * @name DataTable.defaults.language.aria | |
10894 */ | |
10895 "oAria": { | |
10896 /** | |
10897 * ARIA label that is added to the table headers when the column may be | |
10898 * sorted ascending by activing the column (click or return when focused). | |
10899 * Note that the column header is prefixed to this string. | |
10900 * @type string | |
10901 * @default : activate to sort column ascending | |
10902 * | |
10903 * @dtopt Language | |
10904 * @name DataTable.defaults.language.aria.sortAscending | |
10905 * | |
10906 * @example | |
10907 * $(document).ready( function() { | |
10908 * $('#example').dataTable( { | |
10909 * "language": { | |
10910 * "aria": { | |
10911 * "sortAscending": " - click/return to sort ascending" | |
10912 * } | |
10913 * } | |
10914 * } ); | |
10915 * } ); | |
10916 */ | |
10917 "sSortAscending": ": activate to sort column ascending", | |
10918 | |
10919 /** | |
10920 * ARIA label that is added to the table headers when the column may be | |
10921 * sorted descending by activing the column (click or return when focused). | |
10922 * Note that the column header is prefixed to this string. | |
10923 * @type string | |
10924 * @default : activate to sort column ascending | |
10925 * | |
10926 * @dtopt Language | |
10927 * @name DataTable.defaults.language.aria.sortDescending | |
10928 * | |
10929 * @example | |
10930 * $(document).ready( function() { | |
10931 * $('#example').dataTable( { | |
10932 * "language": { | |
10933 * "aria": { | |
10934 * "sortDescending": " - click/return to sort descending" | |
10935 * } | |
10936 * } | |
10937 * } ); | |
10938 * } ); | |
10939 */ | |
10940 "sSortDescending": ": activate to sort column descending" | |
10941 }, | |
10942 | |
10943 /** | |
10944 * Pagination string used by DataTables for the built-in pagination | |
10945 * control types. | |
10946 * @namespace | |
10947 * @name DataTable.defaults.language.paginate | |
10948 */ | |
10949 "oPaginate": { | |
10950 /** | |
10951 * Text to use when using the 'full_numbers' type of pagination for the | |
10952 * button to take the user to the first page. | |
10953 * @type string | |
10954 * @default First | |
10955 * | |
10956 * @dtopt Language | |
10957 * @name DataTable.defaults.language.paginate.first | |
10958 * | |
10959 * @example | |
10960 * $(document).ready( function() { | |
10961 * $('#example').dataTable( { | |
10962 * "language": { | |
10963 * "paginate": { | |
10964 * "first": "First page" | |
10965 * } | |
10966 * } | |
10967 * } ); | |
10968 * } ); | |
10969 */ | |
10970 "sFirst": "First", | |
10971 | |
10972 | |
10973 /** | |
10974 * Text to use when using the 'full_numbers' type of pagination for the | |
10975 * button to take the user to the last page. | |
10976 * @type string | |
10977 * @default Last | |
10978 * | |
10979 * @dtopt Language | |
10980 * @name DataTable.defaults.language.paginate.last | |
10981 * | |
10982 * @example | |
10983 * $(document).ready( function() { | |
10984 * $('#example').dataTable( { | |
10985 * "language": { | |
10986 * "paginate": { | |
10987 * "last": "Last page" | |
10988 * } | |
10989 * } | |
10990 * } ); | |
10991 * } ); | |
10992 */ | |
10993 "sLast": "Last", | |
10994 | |
10995 | |
10996 /** | |
10997 * Text to use for the 'next' pagination button (to take the user to the | |
10998 * next page). | |
10999 * @type string | |
11000 * @default Next | |
11001 * | |
11002 * @dtopt Language | |
11003 * @name DataTable.defaults.language.paginate.next | |
11004 * | |
11005 * @example | |
11006 * $(document).ready( function() { | |
11007 * $('#example').dataTable( { | |
11008 * "language": { | |
11009 * "paginate": { | |
11010 * "next": "Next page" | |
11011 * } | |
11012 * } | |
11013 * } ); | |
11014 * } ); | |
11015 */ | |
11016 "sNext": "Next", | |
11017 | |
11018 | |
11019 /** | |
11020 * Text to use for the 'previous' pagination button (to take the user to | |
11021 * the previous page). | |
11022 * @type string | |
11023 * @default Previous | |
11024 * | |
11025 * @dtopt Language | |
11026 * @name DataTable.defaults.language.paginate.previous | |
11027 * | |
11028 * @example | |
11029 * $(document).ready( function() { | |
11030 * $('#example').dataTable( { | |
11031 * "language": { | |
11032 * "paginate": { | |
11033 * "previous": "Previous page" | |
11034 * } | |
11035 * } | |
11036 * } ); | |
11037 * } ); | |
11038 */ | |
11039 "sPrevious": "Previous" | |
11040 }, | |
11041 | |
11042 /** | |
11043 * This string is shown in preference to `zeroRecords` when the table is | |
11044 * empty of data (regardless of filtering). Note that this is an optional | |
11045 * parameter - if it is not given, the value of `zeroRecords` will be used | |
11046 * instead (either the default or given value). | |
11047 * @type string | |
11048 * @default No data available in table | |
11049 * | |
11050 * @dtopt Language | |
11051 * @name DataTable.defaults.language.emptyTable | |
11052 * | |
11053 * @example | |
11054 * $(document).ready( function() { | |
11055 * $('#example').dataTable( { | |
11056 * "language": { | |
11057 * "emptyTable": "No data available in table" | |
11058 * } | |
11059 * } ); | |
11060 * } ); | |
11061 */ | |
11062 "sEmptyTable": "No data available in table", | |
11063 | |
11064 | |
11065 /** | |
11066 * This string gives information to the end user about the information | |
11067 * that is current on display on the page. The following tokens can be | |
11068 * used in the string and will be dynamically replaced as the table | |
11069 * display updates. This tokens can be placed anywhere in the string, or | |
11070 * removed as needed by the language requires: | |
11071 * | |
11072 * * `\_START\_` - Display index of the first record on the current page | |
11073 * * `\_END\_` - Display index of the last record on the current page | |
11074 * * `\_TOTAL\_` - Number of records in the table after filtering | |
11075 * * `\_MAX\_` - Number of records in the table without filtering | |
11076 * * `\_PAGE\_` - Current page number | |
11077 * * `\_PAGES\_` - Total number of pages of data in the table | |
11078 * | |
11079 * @type string | |
11080 * @default Showing _START_ to _END_ of _TOTAL_ entries | |
11081 * | |
11082 * @dtopt Language | |
11083 * @name DataTable.defaults.language.info | |
11084 * | |
11085 * @example | |
11086 * $(document).ready( function() { | |
11087 * $('#example').dataTable( { | |
11088 * "language": { | |
11089 * "info": "Showing page _PAGE_ of _PAGES_" | |
11090 * } | |
11091 * } ); | |
11092 * } ); | |
11093 */ | |
11094 "sInfo": "Showing _START_ to _END_ of _TOTAL_ entries", | |
11095 | |
11096 | |
11097 /** | |
11098 * Display information string for when the table is empty. Typically the | |
11099 * format of this string should match `info`. | |
11100 * @type string | |
11101 * @default Showing 0 to 0 of 0 entries | |
11102 * | |
11103 * @dtopt Language | |
11104 * @name DataTable.defaults.language.infoEmpty | |
11105 * | |
11106 * @example | |
11107 * $(document).ready( function() { | |
11108 * $('#example').dataTable( { | |
11109 * "language": { | |
11110 * "infoEmpty": "No entries to show" | |
11111 * } | |
11112 * } ); | |
11113 * } ); | |
11114 */ | |
11115 "sInfoEmpty": "Showing 0 to 0 of 0 entries", | |
11116 | |
11117 | |
11118 /** | |
11119 * When a user filters the information in a table, this string is appended | |
11120 * to the information (`info`) to give an idea of how strong the filtering | |
11121 * is. The variable _MAX_ is dynamically updated. | |
11122 * @type string | |
11123 * @default (filtered from _MAX_ total entries) | |
11124 * | |
11125 * @dtopt Language | |
11126 * @name DataTable.defaults.language.infoFiltered | |
11127 * | |
11128 * @example | |
11129 * $(document).ready( function() { | |
11130 * $('#example').dataTable( { | |
11131 * "language": { | |
11132 * "infoFiltered": " - filtering from _MAX_ records" | |
11133 * } | |
11134 * } ); | |
11135 * } ); | |
11136 */ | |
11137 "sInfoFiltered": "(filtered from _MAX_ total entries)", | |
11138 | |
11139 | |
11140 /** | |
11141 * If can be useful to append extra information to the info string at times, | |
11142 * and this variable does exactly that. This information will be appended to | |
11143 * the `info` (`infoEmpty` and `infoFiltered` in whatever combination they are | |
11144 * being used) at all times. | |
11145 * @type string | |
11146 * @default <i>Empty string</i> | |
11147 * | |
11148 * @dtopt Language | |
11149 * @name DataTable.defaults.language.infoPostFix | |
11150 * | |
11151 * @example | |
11152 * $(document).ready( function() { | |
11153 * $('#example').dataTable( { | |
11154 * "language": { | |
11155 * "infoPostFix": "All records shown are derived from real information." | |
11156 * } | |
11157 * } ); | |
11158 * } ); | |
11159 */ | |
11160 "sInfoPostFix": "", | |
11161 | |
11162 | |
11163 /** | |
11164 * This decimal place operator is a little different from the other | |
11165 * language options since DataTables doesn't output floating point | |
11166 * numbers, so it won't ever use this for display of a number. Rather, | |
11167 * what this parameter does is modify the sort methods of the table so | |
11168 * that numbers which are in a format which has a character other than | |
11169 * a period (`.`) as a decimal place will be sorted numerically. | |
11170 * | |
11171 * Note that numbers with different decimal places cannot be shown in | |
11172 * the same table and still be sortable, the table must be consistent. | |
11173 * However, multiple different tables on the page can use different | |
11174 * decimal place characters. | |
11175 * @type string | |
11176 * @default | |
11177 * | |
11178 * @dtopt Language | |
11179 * @name DataTable.defaults.language.decimal | |
11180 * | |
11181 * @example | |
11182 * $(document).ready( function() { | |
11183 * $('#example').dataTable( { | |
11184 * "language": { | |
11185 * "decimal": "," | |
11186 * "thousands": "." | |
11187 * } | |
11188 * } ); | |
11189 * } ); | |
11190 */ | |
11191 "sDecimal": "", | |
11192 | |
11193 | |
11194 /** | |
11195 * DataTables has a build in number formatter (`formatNumber`) which is | |
11196 * used to format large numbers that are used in the table information. | |
11197 * By default a comma is used, but this can be trivially changed to any | |
11198 * character you wish with this parameter. | |
11199 * @type string | |
11200 * @default , | |
11201 * | |
11202 * @dtopt Language | |
11203 * @name DataTable.defaults.language.thousands | |
11204 * | |
11205 * @example | |
11206 * $(document).ready( function() { | |
11207 * $('#example').dataTable( { | |
11208 * "language": { | |
11209 * "thousands": "'" | |
11210 * } | |
11211 * } ); | |
11212 * } ); | |
11213 */ | |
11214 "sThousands": ",", | |
11215 | |
11216 | |
11217 /** | |
11218 * Detail the action that will be taken when the drop down menu for the | |
11219 * pagination length option is changed. The '_MENU_' variable is replaced | |
11220 * with a default select list of 10, 25, 50 and 100, and can be replaced | |
11221 * with a custom select box if required. | |
11222 * @type string | |
11223 * @default Show _MENU_ entries | |
11224 * | |
11225 * @dtopt Language | |
11226 * @name DataTable.defaults.language.lengthMenu | |
11227 * | |
11228 * @example | |
11229 * // Language change only | |
11230 * $(document).ready( function() { | |
11231 * $('#example').dataTable( { | |
11232 * "language": { | |
11233 * "lengthMenu": "Display _MENU_ records" | |
11234 * } | |
11235 * } ); | |
11236 * } ); | |
11237 * | |
11238 * @example | |
11239 * // Language and options change | |
11240 * $(document).ready( function() { | |
11241 * $('#example').dataTable( { | |
11242 * "language": { | |
11243 * "lengthMenu": 'Display <select>'+ | |
11244 * '<option value="10">10</option>'+ | |
11245 * '<option value="20">20</option>'+ | |
11246 * '<option value="30">30</option>'+ | |
11247 * '<option value="40">40</option>'+ | |
11248 * '<option value="50">50</option>'+ | |
11249 * '<option value="-1">All</option>'+ | |
11250 * '</select> records' | |
11251 * } | |
11252 * } ); | |
11253 * } ); | |
11254 */ | |
11255 "sLengthMenu": "Show _MENU_ entries", | |
11256 | |
11257 | |
11258 /** | |
11259 * When using Ajax sourced data and during the first draw when DataTables is | |
11260 * gathering the data, this message is shown in an empty row in the table to | |
11261 * indicate to the end user the the data is being loaded. Note that this | |
11262 * parameter is not used when loading data by server-side processing, just | |
11263 * Ajax sourced data with client-side processing. | |
11264 * @type string | |
11265 * @default Loading... | |
11266 * | |
11267 * @dtopt Language | |
11268 * @name DataTable.defaults.language.loadingRecords | |
11269 * | |
11270 * @example | |
11271 * $(document).ready( function() { | |
11272 * $('#example').dataTable( { | |
11273 * "language": { | |
11274 * "loadingRecords": "Please wait - loading..." | |
11275 * } | |
11276 * } ); | |
11277 * } ); | |
11278 */ | |
11279 "sLoadingRecords": "Loading...", | |
11280 | |
11281 | |
11282 /** | |
11283 * Text which is displayed when the table is processing a user action | |
11284 * (usually a sort command or similar). | |
11285 * @type string | |
11286 * @default Processing... | |
11287 * | |
11288 * @dtopt Language | |
11289 * @name DataTable.defaults.language.processing | |
11290 * | |
11291 * @example | |
11292 * $(document).ready( function() { | |
11293 * $('#example').dataTable( { | |
11294 * "language": { | |
11295 * "processing": "DataTables is currently busy" | |
11296 * } | |
11297 * } ); | |
11298 * } ); | |
11299 */ | |
11300 "sProcessing": "Processing...", | |
11301 | |
11302 | |
11303 /** | |
11304 * Details the actions that will be taken when the user types into the | |
11305 * filtering input text box. The variable "_INPUT_", if used in the string, | |
11306 * is replaced with the HTML text box for the filtering input allowing | |
11307 * control over where it appears in the string. If "_INPUT_" is not given | |
11308 * then the input box is appended to the string automatically. | |
11309 * @type string | |
11310 * @default Search: | |
11311 * | |
11312 * @dtopt Language | |
11313 * @name DataTable.defaults.language.search | |
11314 * | |
11315 * @example | |
11316 * // Input text box will be appended at the end automatically | |
11317 * $(document).ready( function() { | |
11318 * $('#example').dataTable( { | |
11319 * "language": { | |
11320 * "search": "Filter records:" | |
11321 * } | |
11322 * } ); | |
11323 * } ); | |
11324 * | |
11325 * @example | |
11326 * // Specify where the filter should appear | |
11327 * $(document).ready( function() { | |
11328 * $('#example').dataTable( { | |
11329 * "language": { | |
11330 * "search": "Apply filter _INPUT_ to table" | |
11331 * } | |
11332 * } ); | |
11333 * } ); | |
11334 */ | |
11335 "sSearch": "Search:", | |
11336 | |
11337 | |
11338 /** | |
11339 * Assign a `placeholder` attribute to the search `input` element | |
11340 * @type string | |
11341 * @default | |
11342 * | |
11343 * @dtopt Language | |
11344 * @name DataTable.defaults.language.searchPlaceholder | |
11345 */ | |
11346 "sSearchPlaceholder": "", | |
11347 | |
11348 | |
11349 /** | |
11350 * All of the language information can be stored in a file on the | |
11351 * server-side, which DataTables will look up if this parameter is passed. | |
11352 * It must store the URL of the language file, which is in a JSON format, | |
11353 * and the object has the same properties as the oLanguage object in the | |
11354 * initialiser object (i.e. the above parameters). Please refer to one of | |
11355 * the example language files to see how this works in action. | |
11356 * @type string | |
11357 * @default <i>Empty string - i.e. disabled</i> | |
11358 * | |
11359 * @dtopt Language | |
11360 * @name DataTable.defaults.language.url | |
11361 * | |
11362 * @example | |
11363 * $(document).ready( function() { | |
11364 * $('#example').dataTable( { | |
11365 * "language": { | |
11366 * "url": "http://www.sprymedia.co.uk/dataTables/lang.txt" | |
11367 * } | |
11368 * } ); | |
11369 * } ); | |
11370 */ | |
11371 "sUrl": "", | |
11372 | |
11373 | |
11374 /** | |
11375 * Text shown inside the table records when the is no information to be | |
11376 * displayed after filtering. `emptyTable` is shown when there is simply no | |
11377 * information in the table at all (regardless of filtering). | |
11378 * @type string | |
11379 * @default No matching records found | |
11380 * | |
11381 * @dtopt Language | |
11382 * @name DataTable.defaults.language.zeroRecords | |
11383 * | |
11384 * @example | |
11385 * $(document).ready( function() { | |
11386 * $('#example').dataTable( { | |
11387 * "language": { | |
11388 * "zeroRecords": "No records to display" | |
11389 * } | |
11390 * } ); | |
11391 * } ); | |
11392 */ | |
11393 "sZeroRecords": "No matching records found" | |
11394 }, | |
11395 | |
11396 | |
11397 /** | |
11398 * This parameter allows you to have define the global filtering state at | |
11399 * initialisation time. As an object the `search` parameter must be | |
11400 * defined, but all other parameters are optional. When `regex` is true, | |
11401 * the search string will be treated as a regular expression, when false | |
11402 * (default) it will be treated as a straight string. When `smart` | |
11403 * DataTables will use it's smart filtering methods (to word match at | |
11404 * any point in the data), when false this will not be done. | |
11405 * @namespace | |
11406 * @extends DataTable.models.oSearch | |
11407 * | |
11408 * @dtopt Options | |
11409 * @name DataTable.defaults.search | |
11410 * | |
11411 * @example | |
11412 * $(document).ready( function() { | |
11413 * $('#example').dataTable( { | |
11414 * "search": {"search": "Initial search"} | |
11415 * } ); | |
11416 * } ) | |
11417 */ | |
11418 "oSearch": $.extend( {}, DataTable.models.oSearch ), | |
11419 | |
11420 | |
11421 /** | |
11422 * __Deprecated__ The functionality provided by this parameter has now been | |
11423 * superseded by that provided through `ajax`, which should be used instead. | |
11424 * | |
11425 * By default DataTables will look for the property `data` (or `aaData` for | |
11426 * compatibility with DataTables 1.9-) when obtaining data from an Ajax | |
11427 * source or for server-side processing - this parameter allows that | |
11428 * property to be changed. You can use Javascript dotted object notation to | |
11429 * get a data source for multiple levels of nesting. | |
11430 * @type string | |
11431 * @default data | |
11432 * | |
11433 * @dtopt Options | |
11434 * @dtopt Server-side | |
11435 * @name DataTable.defaults.ajaxDataProp | |
11436 * | |
11437 * @deprecated 1.10. Please use `ajax` for this functionality now. | |
11438 */ | |
11439 "sAjaxDataProp": "data", | |
11440 | |
11441 | |
11442 /** | |
11443 * __Deprecated__ The functionality provided by this parameter has now been | |
11444 * superseded by that provided through `ajax`, which should be used instead. | |
11445 * | |
11446 * You can instruct DataTables to load data from an external | |
11447 * source using this parameter (use aData if you want to pass data in you | |
11448 * already have). Simply provide a url a JSON object can be obtained from. | |
11449 * @type string | |
11450 * @default null | |
11451 * | |
11452 * @dtopt Options | |
11453 * @dtopt Server-side | |
11454 * @name DataTable.defaults.ajaxSource | |
11455 * | |
11456 * @deprecated 1.10. Please use `ajax` for this functionality now. | |
11457 */ | |
11458 "sAjaxSource": null, | |
11459 | |
11460 | |
11461 /** | |
11462 * This initialisation variable allows you to specify exactly where in the | |
11463 * DOM you want DataTables to inject the various controls it adds to the page | |
11464 * (for example you might want the pagination controls at the top of the | |
11465 * table). DIV elements (with or without a custom class) can also be added to | |
11466 * aid styling. The follow syntax is used: | |
11467 * <ul> | |
11468 * <li>The following options are allowed: | |
11469 * <ul> | |
11470 * <li>'l' - Length changing</li> | |
11471 * <li>'f' - Filtering input</li> | |
11472 * <li>'t' - The table!</li> | |
11473 * <li>'i' - Information</li> | |
11474 * <li>'p' - Pagination</li> | |
11475 * <li>'r' - pRocessing</li> | |
11476 * </ul> | |
11477 * </li> | |
11478 * <li>The following constants are allowed: | |
11479 * <ul> | |
11480 * <li>'H' - jQueryUI theme "header" classes ('fg-toolbar ui-widget-header ui-corner-tl ui-corner-tr ui-helper-clearfix')</li> | |
11481 * <li>'F' - jQueryUI theme "footer" classes ('fg-toolbar ui-widget-header ui-corner-bl ui-corner-br ui-helper-clearfix')</li> | |
11482 * </ul> | |
11483 * </li> | |
11484 * <li>The following syntax is expected: | |
11485 * <ul> | |
11486 * <li>'<' and '>' - div elements</li> | |
11487 * <li>'<"class" and '>' - div with a class</li> | |
11488 * <li>'<"#id" and '>' - div with an ID</li> | |
11489 * </ul> | |
11490 * </li> | |
11491 * <li>Examples: | |
11492 * <ul> | |
11493 * <li>'<"wrapper"flipt>'</li> | |
11494 * <li>'<lf<t>ip>'</li> | |
11495 * </ul> | |
11496 * </li> | |
11497 * </ul> | |
11498 * @type string | |
11499 * @default lfrtip <i>(when `jQueryUI` is false)</i> <b>or</b> | |
11500 * <"H"lfr>t<"F"ip> <i>(when `jQueryUI` is true)</i> | |
11501 * | |
11502 * @dtopt Options | |
11503 * @name DataTable.defaults.dom | |
11504 * | |
11505 * @example | |
11506 * $(document).ready( function() { | |
11507 * $('#example').dataTable( { | |
11508 * "dom": '<"top"i>rt<"bottom"flp><"clear">' | |
11509 * } ); | |
11510 * } ); | |
11511 */ | |
11512 "sDom": "lfrtip", | |
11513 | |
11514 | |
11515 /** | |
11516 * Search delay option. This will throttle full table searches that use the | |
11517 * DataTables provided search input element (it does not effect calls to | |
11518 * `dt-api search()`, providing a delay before the search is made. | |
11519 * @type integer | |
11520 * @default 0 | |
11521 * | |
11522 * @dtopt Options | |
11523 * @name DataTable.defaults.searchDelay | |
11524 * | |
11525 * @example | |
11526 * $(document).ready( function() { | |
11527 * $('#example').dataTable( { | |
11528 * "searchDelay": 200 | |
11529 * } ); | |
11530 * } ) | |
11531 */ | |
11532 "searchDelay": null, | |
11533 | |
11534 | |
11535 /** | |
11536 * DataTables features four different built-in options for the buttons to | |
11537 * display for pagination control: | |
11538 * | |
11539 * * `simple` - 'Previous' and 'Next' buttons only | |
11540 * * 'simple_numbers` - 'Previous' and 'Next' buttons, plus page numbers | |
11541 * * `full` - 'First', 'Previous', 'Next' and 'Last' buttons | |
11542 * * `full_numbers` - 'First', 'Previous', 'Next' and 'Last' buttons, plus | |
11543 * page numbers | |
11544 * | |
11545 * Further methods can be added using {@link DataTable.ext.oPagination}. | |
11546 * @type string | |
11547 * @default simple_numbers | |
11548 * | |
11549 * @dtopt Options | |
11550 * @name DataTable.defaults.pagingType | |
11551 * | |
11552 * @example | |
11553 * $(document).ready( function() { | |
11554 * $('#example').dataTable( { | |
11555 * "pagingType": "full_numbers" | |
11556 * } ); | |
11557 * } ) | |
11558 */ | |
11559 "sPaginationType": "simple_numbers", | |
11560 | |
11561 | |
11562 /** | |
11563 * Enable horizontal scrolling. When a table is too wide to fit into a | |
11564 * certain layout, or you have a large number of columns in the table, you | |
11565 * can enable x-scrolling to show the table in a viewport, which can be | |
11566 * scrolled. This property can be `true` which will allow the table to | |
11567 * scroll horizontally when needed, or any CSS unit, or a number (in which | |
11568 * case it will be treated as a pixel measurement). Setting as simply `true` | |
11569 * is recommended. | |
11570 * @type boolean|string | |
11571 * @default <i>blank string - i.e. disabled</i> | |
11572 * | |
11573 * @dtopt Features | |
11574 * @name DataTable.defaults.scrollX | |
11575 * | |
11576 * @example | |
11577 * $(document).ready( function() { | |
11578 * $('#example').dataTable( { | |
11579 * "scrollX": true, | |
11580 * "scrollCollapse": true | |
11581 * } ); | |
11582 * } ); | |
11583 */ | |
11584 "sScrollX": "", | |
11585 | |
11586 | |
11587 /** | |
11588 * This property can be used to force a DataTable to use more width than it | |
11589 * might otherwise do when x-scrolling is enabled. For example if you have a | |
11590 * table which requires to be well spaced, this parameter is useful for | |
11591 * "over-sizing" the table, and thus forcing scrolling. This property can by | |
11592 * any CSS unit, or a number (in which case it will be treated as a pixel | |
11593 * measurement). | |
11594 * @type string | |
11595 * @default <i>blank string - i.e. disabled</i> | |
11596 * | |
11597 * @dtopt Options | |
11598 * @name DataTable.defaults.scrollXInner | |
11599 * | |
11600 * @example | |
11601 * $(document).ready( function() { | |
11602 * $('#example').dataTable( { | |
11603 * "scrollX": "100%", | |
11604 * "scrollXInner": "110%" | |
11605 * } ); | |
11606 * } ); | |
11607 */ | |
11608 "sScrollXInner": "", | |
11609 | |
11610 | |
11611 /** | |
11612 * Enable vertical scrolling. Vertical scrolling will constrain the DataTable | |
11613 * to the given height, and enable scrolling for any data which overflows the | |
11614 * current viewport. This can be used as an alternative to paging to display | |
11615 * a lot of data in a small area (although paging and scrolling can both be | |
11616 * enabled at the same time). This property can be any CSS unit, or a number | |
11617 * (in which case it will be treated as a pixel measurement). | |
11618 * @type string | |
11619 * @default <i>blank string - i.e. disabled</i> | |
11620 * | |
11621 * @dtopt Features | |
11622 * @name DataTable.defaults.scrollY | |
11623 * | |
11624 * @example | |
11625 * $(document).ready( function() { | |
11626 * $('#example').dataTable( { | |
11627 * "scrollY": "200px", | |
11628 * "paginate": false | |
11629 * } ); | |
11630 * } ); | |
11631 */ | |
11632 "sScrollY": "", | |
11633 | |
11634 | |
11635 /** | |
11636 * __Deprecated__ The functionality provided by this parameter has now been | |
11637 * superseded by that provided through `ajax`, which should be used instead. | |
11638 * | |
11639 * Set the HTTP method that is used to make the Ajax call for server-side | |
11640 * processing or Ajax sourced data. | |
11641 * @type string | |
11642 * @default GET | |
11643 * | |
11644 * @dtopt Options | |
11645 * @dtopt Server-side | |
11646 * @name DataTable.defaults.serverMethod | |
11647 * | |
11648 * @deprecated 1.10. Please use `ajax` for this functionality now. | |
11649 */ | |
11650 "sServerMethod": "GET", | |
11651 | |
11652 | |
11653 /** | |
11654 * DataTables makes use of renderers when displaying HTML elements for | |
11655 * a table. These renderers can be added or modified by plug-ins to | |
11656 * generate suitable mark-up for a site. For example the Bootstrap | |
11657 * integration plug-in for DataTables uses a paging button renderer to | |
11658 * display pagination buttons in the mark-up required by Bootstrap. | |
11659 * | |
11660 * For further information about the renderers available see | |
11661 * DataTable.ext.renderer | |
11662 * @type string|object | |
11663 * @default null | |
11664 * | |
11665 * @name DataTable.defaults.renderer | |
11666 * | |
11667 */ | |
11668 "renderer": null | |
11669 }; | |
11670 | |
11671 _fnHungarianMap( DataTable.defaults ); | |
11672 | |
11673 | |
11674 | |
11675 /* | |
11676 * Developer note - See note in model.defaults.js about the use of Hungarian | |
11677 * notation and camel case. | |
11678 */ | |
11679 | |
11680 /** | |
11681 * Column options that can be given to DataTables at initialisation time. | |
11682 * @namespace | |
11683 */ | |
11684 DataTable.defaults.column = { | |
11685 /** | |
11686 * Define which column(s) an order will occur on for this column. This | |
11687 * allows a column's ordering to take multiple columns into account when | |
11688 * doing a sort or use the data from a different column. For example first | |
11689 * name / last name columns make sense to do a multi-column sort over the | |
11690 * two columns. | |
11691 * @type array|int | |
11692 * @default null <i>Takes the value of the column index automatically</i> | |
11693 * | |
11694 * @name DataTable.defaults.column.orderData | |
11695 * @dtopt Columns | |
11696 * | |
11697 * @example | |
11698 * // Using `columnDefs` | |
11699 * $(document).ready( function() { | |
11700 * $('#example').dataTable( { | |
11701 * "columnDefs": [ | |
11702 * { "orderData": [ 0, 1 ], "targets": [ 0 ] }, | |
11703 * { "orderData": [ 1, 0 ], "targets": [ 1 ] }, | |
11704 * { "orderData": 2, "targets": [ 2 ] } | |
11705 * ] | |
11706 * } ); | |
11707 * } ); | |
11708 * | |
11709 * @example | |
11710 * // Using `columns` | |
11711 * $(document).ready( function() { | |
11712 * $('#example').dataTable( { | |
11713 * "columns": [ | |
11714 * { "orderData": [ 0, 1 ] }, | |
11715 * { "orderData": [ 1, 0 ] }, | |
11716 * { "orderData": 2 }, | |
11717 * null, | |
11718 * null | |
11719 * ] | |
11720 * } ); | |
11721 * } ); | |
11722 */ | |
11723 "aDataSort": null, | |
11724 "iDataSort": -1, | |
11725 | |
11726 | |
11727 /** | |
11728 * You can control the default ordering direction, and even alter the | |
11729 * behaviour of the sort handler (i.e. only allow ascending ordering etc) | |
11730 * using this parameter. | |
11731 * @type array | |
11732 * @default [ 'asc', 'desc' ] | |
11733 * | |
11734 * @name DataTable.defaults.column.orderSequence | |
11735 * @dtopt Columns | |
11736 * | |
11737 * @example | |
11738 * // Using `columnDefs` | |
11739 * $(document).ready( function() { | |
11740 * $('#example').dataTable( { | |
11741 * "columnDefs": [ | |
11742 * { "orderSequence": [ "asc" ], "targets": [ 1 ] }, | |
11743 * { "orderSequence": [ "desc", "asc", "asc" ], "targets": [ 2 ] }, | |
11744 * { "orderSequence": [ "desc" ], "targets": [ 3 ] } | |
11745 * ] | |
11746 * } ); | |
11747 * } ); | |
11748 * | |
11749 * @example | |
11750 * // Using `columns` | |
11751 * $(document).ready( function() { | |
11752 * $('#example').dataTable( { | |
11753 * "columns": [ | |
11754 * null, | |
11755 * { "orderSequence": [ "asc" ] }, | |
11756 * { "orderSequence": [ "desc", "asc", "asc" ] }, | |
11757 * { "orderSequence": [ "desc" ] }, | |
11758 * null | |
11759 * ] | |
11760 * } ); | |
11761 * } ); | |
11762 */ | |
11763 "asSorting": [ 'asc', 'desc' ], | |
11764 | |
11765 | |
11766 /** | |
11767 * Enable or disable filtering on the data in this column. | |
11768 * @type boolean | |
11769 * @default true | |
11770 * | |
11771 * @name DataTable.defaults.column.searchable | |
11772 * @dtopt Columns | |
11773 * | |
11774 * @example | |
11775 * // Using `columnDefs` | |
11776 * $(document).ready( function() { | |
11777 * $('#example').dataTable( { | |
11778 * "columnDefs": [ | |
11779 * { "searchable": false, "targets": [ 0 ] } | |
11780 * ] } ); | |
11781 * } ); | |
11782 * | |
11783 * @example | |
11784 * // Using `columns` | |
11785 * $(document).ready( function() { | |
11786 * $('#example').dataTable( { | |
11787 * "columns": [ | |
11788 * { "searchable": false }, | |
11789 * null, | |
11790 * null, | |
11791 * null, | |
11792 * null | |
11793 * ] } ); | |
11794 * } ); | |
11795 */ | |
11796 "bSearchable": true, | |
11797 | |
11798 | |
11799 /** | |
11800 * Enable or disable ordering on this column. | |
11801 * @type boolean | |
11802 * @default true | |
11803 * | |
11804 * @name DataTable.defaults.column.orderable | |
11805 * @dtopt Columns | |
11806 * | |
11807 * @example | |
11808 * // Using `columnDefs` | |
11809 * $(document).ready( function() { | |
11810 * $('#example').dataTable( { | |
11811 * "columnDefs": [ | |
11812 * { "orderable": false, "targets": [ 0 ] } | |
11813 * ] } ); | |
11814 * } ); | |
11815 * | |
11816 * @example | |
11817 * // Using `columns` | |
11818 * $(document).ready( function() { | |
11819 * $('#example').dataTable( { | |
11820 * "columns": [ | |
11821 * { "orderable": false }, | |
11822 * null, | |
11823 * null, | |
11824 * null, | |
11825 * null | |
11826 * ] } ); | |
11827 * } ); | |
11828 */ | |
11829 "bSortable": true, | |
11830 | |
11831 | |
11832 /** | |
11833 * Enable or disable the display of this column. | |
11834 * @type boolean | |
11835 * @default true | |
11836 * | |
11837 * @name DataTable.defaults.column.visible | |
11838 * @dtopt Columns | |
11839 * | |
11840 * @example | |
11841 * // Using `columnDefs` | |
11842 * $(document).ready( function() { | |
11843 * $('#example').dataTable( { | |
11844 * "columnDefs": [ | |
11845 * { "visible": false, "targets": [ 0 ] } | |
11846 * ] } ); | |
11847 * } ); | |
11848 * | |
11849 * @example | |
11850 * // Using `columns` | |
11851 * $(document).ready( function() { | |
11852 * $('#example').dataTable( { | |
11853 * "columns": [ | |
11854 * { "visible": false }, | |
11855 * null, | |
11856 * null, | |
11857 * null, | |
11858 * null | |
11859 * ] } ); | |
11860 * } ); | |
11861 */ | |
11862 "bVisible": true, | |
11863 | |
11864 | |
11865 /** | |
11866 * Developer definable function that is called whenever a cell is created (Ajax source, | |
11867 * etc) or processed for input (DOM source). This can be used as a compliment to mRender | |
11868 * allowing you to modify the DOM element (add background colour for example) when the | |
11869 * element is available. | |
11870 * @type function | |
11871 * @param {element} td The TD node that has been created | |
11872 * @param {*} cellData The Data for the cell | |
11873 * @param {array|object} rowData The data for the whole row | |
11874 * @param {int} row The row index for the aoData data store | |
11875 * @param {int} col The column index for aoColumns | |
11876 * | |
11877 * @name DataTable.defaults.column.createdCell | |
11878 * @dtopt Columns | |
11879 * | |
11880 * @example | |
11881 * $(document).ready( function() { | |
11882 * $('#example').dataTable( { | |
11883 * "columnDefs": [ { | |
11884 * "targets": [3], | |
11885 * "createdCell": function (td, cellData, rowData, row, col) { | |
11886 * if ( cellData == "1.7" ) { | |
11887 * $(td).css('color', 'blue') | |
11888 * } | |
11889 * } | |
11890 * } ] | |
11891 * }); | |
11892 * } ); | |
11893 */ | |
11894 "fnCreatedCell": null, | |
11895 | |
11896 | |
11897 /** | |
11898 * This parameter has been replaced by `data` in DataTables to ensure naming | |
11899 * consistency. `dataProp` can still be used, as there is backwards | |
11900 * compatibility in DataTables for this option, but it is strongly | |
11901 * recommended that you use `data` in preference to `dataProp`. | |
11902 * @name DataTable.defaults.column.dataProp | |
11903 */ | |
11904 | |
11905 | |
11906 /** | |
11907 * This property can be used to read data from any data source property, | |
11908 * including deeply nested objects / properties. `data` can be given in a | |
11909 * number of different ways which effect its behaviour: | |
11910 * | |
11911 * * `integer` - treated as an array index for the data source. This is the | |
11912 * default that DataTables uses (incrementally increased for each column). | |
11913 * * `string` - read an object property from the data source. There are | |
11914 * three 'special' options that can be used in the string to alter how | |
11915 * DataTables reads the data from the source object: | |
11916 * * `.` - Dotted Javascript notation. Just as you use a `.` in | |
11917 * Javascript to read from nested objects, so to can the options | |
11918 * specified in `data`. For example: `browser.version` or | |
11919 * `browser.name`. If your object parameter name contains a period, use | |
11920 * `\\` to escape it - i.e. `first\\.name`. | |
11921 * * `[]` - Array notation. DataTables can automatically combine data | |
11922 * from and array source, joining the data with the characters provided | |
11923 * between the two brackets. For example: `name[, ]` would provide a | |
11924 * comma-space separated list from the source array. If no characters | |
11925 * are provided between the brackets, the original array source is | |
11926 * returned. | |
11927 * * `()` - Function notation. Adding `()` to the end of a parameter will | |
11928 * execute a function of the name given. For example: `browser()` for a | |
11929 * simple function on the data source, `browser.version()` for a | |
11930 * function in a nested property or even `browser().version` to get an | |
11931 * object property if the function called returns an object. Note that | |
11932 * function notation is recommended for use in `render` rather than | |
11933 * `data` as it is much simpler to use as a renderer. | |
11934 * * `null` - use the original data source for the row rather than plucking | |
11935 * data directly from it. This action has effects on two other | |
11936 * initialisation options: | |
11937 * * `defaultContent` - When null is given as the `data` option and | |
11938 * `defaultContent` is specified for the column, the value defined by | |
11939 * `defaultContent` will be used for the cell. | |
11940 * * `render` - When null is used for the `data` option and the `render` | |
11941 * option is specified for the column, the whole data source for the | |
11942 * row is used for the renderer. | |
11943 * * `function` - the function given will be executed whenever DataTables | |
11944 * needs to set or get the data for a cell in the column. The function | |
11945 * takes three parameters: | |
11946 * * Parameters: | |
11947 * * `{array|object}` The data source for the row | |
11948 * * `{string}` The type call data requested - this will be 'set' when | |
11949 * setting data or 'filter', 'display', 'type', 'sort' or undefined | |
11950 * when gathering data. Note that when `undefined` is given for the | |
11951 * type DataTables expects to get the raw data for the object back< | |
11952 * * `{*}` Data to set when the second parameter is 'set'. | |
11953 * * Return: | |
11954 * * The return value from the function is not required when 'set' is | |
11955 * the type of call, but otherwise the return is what will be used | |
11956 * for the data requested. | |
11957 * | |
11958 * Note that `data` is a getter and setter option. If you just require | |
11959 * formatting of data for output, you will likely want to use `render` which | |
11960 * is simply a getter and thus simpler to use. | |
11961 * | |
11962 * Note that prior to DataTables 1.9.2 `data` was called `mDataProp`. The | |
11963 * name change reflects the flexibility of this property and is consistent | |
11964 * with the naming of mRender. If 'mDataProp' is given, then it will still | |
11965 * be used by DataTables, as it automatically maps the old name to the new | |
11966 * if required. | |
11967 * | |
11968 * @type string|int|function|null | |
11969 * @default null <i>Use automatically calculated column index</i> | |
11970 * | |
11971 * @name DataTable.defaults.column.data | |
11972 * @dtopt Columns | |
11973 * | |
11974 * @example | |
11975 * // Read table data from objects | |
11976 * // JSON structure for each row: | |
11977 * // { | |
11978 * // "engine": {value}, | |
11979 * // "browser": {value}, | |
11980 * // "platform": {value}, | |
11981 * // "version": {value}, | |
11982 * // "grade": {value} | |
11983 * // } | |
11984 * $(document).ready( function() { | |
11985 * $('#example').dataTable( { | |
11986 * "ajaxSource": "sources/objects.txt", | |
11987 * "columns": [ | |
11988 * { "data": "engine" }, | |
11989 * { "data": "browser" }, | |
11990 * { "data": "platform" }, | |
11991 * { "data": "version" }, | |
11992 * { "data": "grade" } | |
11993 * ] | |
11994 * } ); | |
11995 * } ); | |
11996 * | |
11997 * @example | |
11998 * // Read information from deeply nested objects | |
11999 * // JSON structure for each row: | |
12000 * // { | |
12001 * // "engine": {value}, | |
12002 * // "browser": {value}, | |
12003 * // "platform": { | |
12004 * // "inner": {value} | |
12005 * // }, | |
12006 * // "details": [ | |
12007 * // {value}, {value} | |
12008 * // ] | |
12009 * // } | |
12010 * $(document).ready( function() { | |
12011 * $('#example').dataTable( { | |
12012 * "ajaxSource": "sources/deep.txt", | |
12013 * "columns": [ | |
12014 * { "data": "engine" }, | |
12015 * { "data": "browser" }, | |
12016 * { "data": "platform.inner" }, | |
12017 * { "data": "platform.details.0" }, | |
12018 * { "data": "platform.details.1" } | |
12019 * ] | |
12020 * } ); | |
12021 * } ); | |
12022 * | |
12023 * @example | |
12024 * // Using `data` as a function to provide different information for | |
12025 * // sorting, filtering and display. In this case, currency (price) | |
12026 * $(document).ready( function() { | |
12027 * $('#example').dataTable( { | |
12028 * "columnDefs": [ { | |
12029 * "targets": [ 0 ], | |
12030 * "data": function ( source, type, val ) { | |
12031 * if (type === 'set') { | |
12032 * source.price = val; | |
12033 * // Store the computed dislay and filter values for efficiency | |
12034 * source.price_display = val=="" ? "" : "$"+numberFormat(val); | |
12035 * source.price_filter = val=="" ? "" : "$"+numberFormat(val)+" "+val; | |
12036 * return; | |
12037 * } | |
12038 * else if (type === 'display') { | |
12039 * return source.price_display; | |
12040 * } | |
12041 * else if (type === 'filter') { | |
12042 * return source.price_filter; | |
12043 * } | |
12044 * // 'sort', 'type' and undefined all just use the integer | |
12045 * return source.price; | |
12046 * } | |
12047 * } ] | |
12048 * } ); | |
12049 * } ); | |
12050 * | |
12051 * @example | |
12052 * // Using default content | |
12053 * $(document).ready( function() { | |
12054 * $('#example').dataTable( { | |
12055 * "columnDefs": [ { | |
12056 * "targets": [ 0 ], | |
12057 * "data": null, | |
12058 * "defaultContent": "Click to edit" | |
12059 * } ] | |
12060 * } ); | |
12061 * } ); | |
12062 * | |
12063 * @example | |
12064 * // Using array notation - outputting a list from an array | |
12065 * $(document).ready( function() { | |
12066 * $('#example').dataTable( { | |
12067 * "columnDefs": [ { | |
12068 * "targets": [ 0 ], | |
12069 * "data": "name[, ]" | |
12070 * } ] | |
12071 * } ); | |
12072 * } ); | |
12073 * | |
12074 */ | |
12075 "mData": null, | |
12076 | |
12077 | |
12078 /** | |
12079 * This property is the rendering partner to `data` and it is suggested that | |
12080 * when you want to manipulate data for display (including filtering, | |
12081 * sorting etc) without altering the underlying data for the table, use this | |
12082 * property. `render` can be considered to be the the read only companion to | |
12083 * `data` which is read / write (then as such more complex). Like `data` | |
12084 * this option can be given in a number of different ways to effect its | |
12085 * behaviour: | |
12086 * | |
12087 * * `integer` - treated as an array index for the data source. This is the | |
12088 * default that DataTables uses (incrementally increased for each column). | |
12089 * * `string` - read an object property from the data source. There are | |
12090 * three 'special' options that can be used in the string to alter how | |
12091 * DataTables reads the data from the source object: | |
12092 * * `.` - Dotted Javascript notation. Just as you use a `.` in | |
12093 * Javascript to read from nested objects, so to can the options | |
12094 * specified in `data`. For example: `browser.version` or | |
12095 * `browser.name`. If your object parameter name contains a period, use | |
12096 * `\\` to escape it - i.e. `first\\.name`. | |
12097 * * `[]` - Array notation. DataTables can automatically combine data | |
12098 * from and array source, joining the data with the characters provided | |
12099 * between the two brackets. For example: `name[, ]` would provide a | |
12100 * comma-space separated list from the source array. If no characters | |
12101 * are provided between the brackets, the original array source is | |
12102 * returned. | |
12103 * * `()` - Function notation. Adding `()` to the end of a parameter will | |
12104 * execute a function of the name given. For example: `browser()` for a | |
12105 * simple function on the data source, `browser.version()` for a | |
12106 * function in a nested property or even `browser().version` to get an | |
12107 * object property if the function called returns an object. | |
12108 * * `object` - use different data for the different data types requested by | |
12109 * DataTables ('filter', 'display', 'type' or 'sort'). The property names | |
12110 * of the object is the data type the property refers to and the value can | |
12111 * defined using an integer, string or function using the same rules as | |
12112 * `render` normally does. Note that an `_` option _must_ be specified. | |
12113 * This is the default value to use if you haven't specified a value for | |
12114 * the data type requested by DataTables. | |
12115 * * `function` - the function given will be executed whenever DataTables | |
12116 * needs to set or get the data for a cell in the column. The function | |
12117 * takes three parameters: | |
12118 * * Parameters: | |
12119 * * {array|object} The data source for the row (based on `data`) | |
12120 * * {string} The type call data requested - this will be 'filter', | |
12121 * 'display', 'type' or 'sort'. | |
12122 * * {array|object} The full data source for the row (not based on | |
12123 * `data`) | |
12124 * * Return: | |
12125 * * The return value from the function is what will be used for the | |
12126 * data requested. | |
12127 * | |
12128 * @type string|int|function|object|null | |
12129 * @default null Use the data source value. | |
12130 * | |
12131 * @name DataTable.defaults.column.render | |
12132 * @dtopt Columns | |
12133 * | |
12134 * @example | |
12135 * // Create a comma separated list from an array of objects | |
12136 * $(document).ready( function() { | |
12137 * $('#example').dataTable( { | |
12138 * "ajaxSource": "sources/deep.txt", | |
12139 * "columns": [ | |
12140 * { "data": "engine" }, | |
12141 * { "data": "browser" }, | |
12142 * { | |
12143 * "data": "platform", | |
12144 * "render": "[, ].name" | |
12145 * } | |
12146 * ] | |
12147 * } ); | |
12148 * } ); | |
12149 * | |
12150 * @example | |
12151 * // Execute a function to obtain data | |
12152 * $(document).ready( function() { | |
12153 * $('#example').dataTable( { | |
12154 * "columnDefs": [ { | |
12155 * "targets": [ 0 ], | |
12156 * "data": null, // Use the full data source object for the renderer's source | |
12157 * "render": "browserName()" | |
12158 * } ] | |
12159 * } ); | |
12160 * } ); | |
12161 * | |
12162 * @example | |
12163 * // As an object, extracting different data for the different types | |
12164 * // This would be used with a data source such as: | |
12165 * // { "phone": 5552368, "phone_filter": "5552368 555-2368", "phone_display": "555-2368" } | |
12166 * // Here the `phone` integer is used for sorting and type detection, while `phone_filter` | |
12167 * // (which has both forms) is used for filtering for if a user inputs either format, while | |
12168 * // the formatted phone number is the one that is shown in the table. | |
12169 * $(document).ready( function() { | |
12170 * $('#example').dataTable( { | |
12171 * "columnDefs": [ { | |
12172 * "targets": [ 0 ], | |
12173 * "data": null, // Use the full data source object for the renderer's source | |
12174 * "render": { | |
12175 * "_": "phone", | |
12176 * "filter": "phone_filter", | |
12177 * "display": "phone_display" | |
12178 * } | |
12179 * } ] | |
12180 * } ); | |
12181 * } ); | |
12182 * | |
12183 * @example | |
12184 * // Use as a function to create a link from the data source | |
12185 * $(document).ready( function() { | |
12186 * $('#example').dataTable( { | |
12187 * "columnDefs": [ { | |
12188 * "targets": [ 0 ], | |
12189 * "data": "download_link", | |
12190 * "render": function ( data, type, full ) { | |
12191 * return '<a href="'+data+'">Download</a>'; | |
12192 * } | |
12193 * } ] | |
12194 * } ); | |
12195 * } ); | |
12196 */ | |
12197 "mRender": null, | |
12198 | |
12199 | |
12200 /** | |
12201 * Change the cell type created for the column - either TD cells or TH cells. This | |
12202 * can be useful as TH cells have semantic meaning in the table body, allowing them | |
12203 * to act as a header for a row (you may wish to add scope='row' to the TH elements). | |
12204 * @type string | |
12205 * @default td | |
12206 * | |
12207 * @name DataTable.defaults.column.cellType | |
12208 * @dtopt Columns | |
12209 * | |
12210 * @example | |
12211 * // Make the first column use TH cells | |
12212 * $(document).ready( function() { | |
12213 * $('#example').dataTable( { | |
12214 * "columnDefs": [ { | |
12215 * "targets": [ 0 ], | |
12216 * "cellType": "th" | |
12217 * } ] | |
12218 * } ); | |
12219 * } ); | |
12220 */ | |
12221 "sCellType": "td", | |
12222 | |
12223 | |
12224 /** | |
12225 * Class to give to each cell in this column. | |
12226 * @type string | |
12227 * @default <i>Empty string</i> | |
12228 * | |
12229 * @name DataTable.defaults.column.class | |
12230 * @dtopt Columns | |
12231 * | |
12232 * @example | |
12233 * // Using `columnDefs` | |
12234 * $(document).ready( function() { | |
12235 * $('#example').dataTable( { | |
12236 * "columnDefs": [ | |
12237 * { "class": "my_class", "targets": [ 0 ] } | |
12238 * ] | |
12239 * } ); | |
12240 * } ); | |
12241 * | |
12242 * @example | |
12243 * // Using `columns` | |
12244 * $(document).ready( function() { | |
12245 * $('#example').dataTable( { | |
12246 * "columns": [ | |
12247 * { "class": "my_class" }, | |
12248 * null, | |
12249 * null, | |
12250 * null, | |
12251 * null | |
12252 * ] | |
12253 * } ); | |
12254 * } ); | |
12255 */ | |
12256 "sClass": "", | |
12257 | |
12258 /** | |
12259 * When DataTables calculates the column widths to assign to each column, | |
12260 * it finds the longest string in each column and then constructs a | |
12261 * temporary table and reads the widths from that. The problem with this | |
12262 * is that "mmm" is much wider then "iiii", but the latter is a longer | |
12263 * string - thus the calculation can go wrong (doing it properly and putting | |
12264 * it into an DOM object and measuring that is horribly(!) slow). Thus as | |
12265 * a "work around" we provide this option. It will append its value to the | |
12266 * text that is found to be the longest string for the column - i.e. padding. | |
12267 * Generally you shouldn't need this! | |
12268 * @type string | |
12269 * @default <i>Empty string<i> | |
12270 * | |
12271 * @name DataTable.defaults.column.contentPadding | |
12272 * @dtopt Columns | |
12273 * | |
12274 * @example | |
12275 * // Using `columns` | |
12276 * $(document).ready( function() { | |
12277 * $('#example').dataTable( { | |
12278 * "columns": [ | |
12279 * null, | |
12280 * null, | |
12281 * null, | |
12282 * { | |
12283 * "contentPadding": "mmm" | |
12284 * } | |
12285 * ] | |
12286 * } ); | |
12287 * } ); | |
12288 */ | |
12289 "sContentPadding": "", | |
12290 | |
12291 | |
12292 /** | |
12293 * Allows a default value to be given for a column's data, and will be used | |
12294 * whenever a null data source is encountered (this can be because `data` | |
12295 * is set to null, or because the data source itself is null). | |
12296 * @type string | |
12297 * @default null | |
12298 * | |
12299 * @name DataTable.defaults.column.defaultContent | |
12300 * @dtopt Columns | |
12301 * | |
12302 * @example | |
12303 * // Using `columnDefs` | |
12304 * $(document).ready( function() { | |
12305 * $('#example').dataTable( { | |
12306 * "columnDefs": [ | |
12307 * { | |
12308 * "data": null, | |
12309 * "defaultContent": "Edit", | |
12310 * "targets": [ -1 ] | |
12311 * } | |
12312 * ] | |
12313 * } ); | |
12314 * } ); | |
12315 * | |
12316 * @example | |
12317 * // Using `columns` | |
12318 * $(document).ready( function() { | |
12319 * $('#example').dataTable( { | |
12320 * "columns": [ | |
12321 * null, | |
12322 * null, | |
12323 * null, | |
12324 * { | |
12325 * "data": null, | |
12326 * "defaultContent": "Edit" | |
12327 * } | |
12328 * ] | |
12329 * } ); | |
12330 * } ); | |
12331 */ | |
12332 "sDefaultContent": null, | |
12333 | |
12334 | |
12335 /** | |
12336 * This parameter is only used in DataTables' server-side processing. It can | |
12337 * be exceptionally useful to know what columns are being displayed on the | |
12338 * client side, and to map these to database fields. When defined, the names | |
12339 * also allow DataTables to reorder information from the server if it comes | |
12340 * back in an unexpected order (i.e. if you switch your columns around on the | |
12341 * client-side, your server-side code does not also need updating). | |
12342 * @type string | |
12343 * @default <i>Empty string</i> | |
12344 * | |
12345 * @name DataTable.defaults.column.name | |
12346 * @dtopt Columns | |
12347 * | |
12348 * @example | |
12349 * // Using `columnDefs` | |
12350 * $(document).ready( function() { | |
12351 * $('#example').dataTable( { | |
12352 * "columnDefs": [ | |
12353 * { "name": "engine", "targets": [ 0 ] }, | |
12354 * { "name": "browser", "targets": [ 1 ] }, | |
12355 * { "name": "platform", "targets": [ 2 ] }, | |
12356 * { "name": "version", "targets": [ 3 ] }, | |
12357 * { "name": "grade", "targets": [ 4 ] } | |
12358 * ] | |
12359 * } ); | |
12360 * } ); | |
12361 * | |
12362 * @example | |
12363 * // Using `columns` | |
12364 * $(document).ready( function() { | |
12365 * $('#example').dataTable( { | |
12366 * "columns": [ | |
12367 * { "name": "engine" }, | |
12368 * { "name": "browser" }, | |
12369 * { "name": "platform" }, | |
12370 * { "name": "version" }, | |
12371 * { "name": "grade" } | |
12372 * ] | |
12373 * } ); | |
12374 * } ); | |
12375 */ | |
12376 "sName": "", | |
12377 | |
12378 | |
12379 /** | |
12380 * Defines a data source type for the ordering which can be used to read | |
12381 * real-time information from the table (updating the internally cached | |
12382 * version) prior to ordering. This allows ordering to occur on user | |
12383 * editable elements such as form inputs. | |
12384 * @type string | |
12385 * @default std | |
12386 * | |
12387 * @name DataTable.defaults.column.orderDataType | |
12388 * @dtopt Columns | |
12389 * | |
12390 * @example | |
12391 * // Using `columnDefs` | |
12392 * $(document).ready( function() { | |
12393 * $('#example').dataTable( { | |
12394 * "columnDefs": [ | |
12395 * { "orderDataType": "dom-text", "targets": [ 2, 3 ] }, | |
12396 * { "type": "numeric", "targets": [ 3 ] }, | |
12397 * { "orderDataType": "dom-select", "targets": [ 4 ] }, | |
12398 * { "orderDataType": "dom-checkbox", "targets": [ 5 ] } | |
12399 * ] | |
12400 * } ); | |
12401 * } ); | |
12402 * | |
12403 * @example | |
12404 * // Using `columns` | |
12405 * $(document).ready( function() { | |
12406 * $('#example').dataTable( { | |
12407 * "columns": [ | |
12408 * null, | |
12409 * null, | |
12410 * { "orderDataType": "dom-text" }, | |
12411 * { "orderDataType": "dom-text", "type": "numeric" }, | |
12412 * { "orderDataType": "dom-select" }, | |
12413 * { "orderDataType": "dom-checkbox" } | |
12414 * ] | |
12415 * } ); | |
12416 * } ); | |
12417 */ | |
12418 "sSortDataType": "std", | |
12419 | |
12420 | |
12421 /** | |
12422 * The title of this column. | |
12423 * @type string | |
12424 * @default null <i>Derived from the 'TH' value for this column in the | |
12425 * original HTML table.</i> | |
12426 * | |
12427 * @name DataTable.defaults.column.title | |
12428 * @dtopt Columns | |
12429 * | |
12430 * @example | |
12431 * // Using `columnDefs` | |
12432 * $(document).ready( function() { | |
12433 * $('#example').dataTable( { | |
12434 * "columnDefs": [ | |
12435 * { "title": "My column title", "targets": [ 0 ] } | |
12436 * ] | |
12437 * } ); | |
12438 * } ); | |
12439 * | |
12440 * @example | |
12441 * // Using `columns` | |
12442 * $(document).ready( function() { | |
12443 * $('#example').dataTable( { | |
12444 * "columns": [ | |
12445 * { "title": "My column title" }, | |
12446 * null, | |
12447 * null, | |
12448 * null, | |
12449 * null | |
12450 * ] | |
12451 * } ); | |
12452 * } ); | |
12453 */ | |
12454 "sTitle": null, | |
12455 | |
12456 | |
12457 /** | |
12458 * The type allows you to specify how the data for this column will be | |
12459 * ordered. Four types (string, numeric, date and html (which will strip | |
12460 * HTML tags before ordering)) are currently available. Note that only date | |
12461 * formats understood by Javascript's Date() object will be accepted as type | |
12462 * date. For example: "Mar 26, 2008 5:03 PM". May take the values: 'string', | |
12463 * 'numeric', 'date' or 'html' (by default). Further types can be adding | |
12464 * through plug-ins. | |
12465 * @type string | |
12466 * @default null <i>Auto-detected from raw data</i> | |
12467 * | |
12468 * @name DataTable.defaults.column.type | |
12469 * @dtopt Columns | |
12470 * | |
12471 * @example | |
12472 * // Using `columnDefs` | |
12473 * $(document).ready( function() { | |
12474 * $('#example').dataTable( { | |
12475 * "columnDefs": [ | |
12476 * { "type": "html", "targets": [ 0 ] } | |
12477 * ] | |
12478 * } ); | |
12479 * } ); | |
12480 * | |
12481 * @example | |
12482 * // Using `columns` | |
12483 * $(document).ready( function() { | |
12484 * $('#example').dataTable( { | |
12485 * "columns": [ | |
12486 * { "type": "html" }, | |
12487 * null, | |
12488 * null, | |
12489 * null, | |
12490 * null | |
12491 * ] | |
12492 * } ); | |
12493 * } ); | |
12494 */ | |
12495 "sType": null, | |
12496 | |
12497 | |
12498 /** | |
12499 * Defining the width of the column, this parameter may take any CSS value | |
12500 * (3em, 20px etc). DataTables applies 'smart' widths to columns which have not | |
12501 * been given a specific width through this interface ensuring that the table | |
12502 * remains readable. | |
12503 * @type string | |
12504 * @default null <i>Automatic</i> | |
12505 * | |
12506 * @name DataTable.defaults.column.width | |
12507 * @dtopt Columns | |
12508 * | |
12509 * @example | |
12510 * // Using `columnDefs` | |
12511 * $(document).ready( function() { | |
12512 * $('#example').dataTable( { | |
12513 * "columnDefs": [ | |
12514 * { "width": "20%", "targets": [ 0 ] } | |
12515 * ] | |
12516 * } ); | |
12517 * } ); | |
12518 * | |
12519 * @example | |
12520 * // Using `columns` | |
12521 * $(document).ready( function() { | |
12522 * $('#example').dataTable( { | |
12523 * "columns": [ | |
12524 * { "width": "20%" }, | |
12525 * null, | |
12526 * null, | |
12527 * null, | |
12528 * null | |
12529 * ] | |
12530 * } ); | |
12531 * } ); | |
12532 */ | |
12533 "sWidth": null | |
12534 }; | |
12535 | |
12536 _fnHungarianMap( DataTable.defaults.column ); | |
12537 | |
12538 | |
12539 | |
12540 /** | |
12541 * DataTables settings object - this holds all the information needed for a | |
12542 * given table, including configuration, data and current application of the | |
12543 * table options. DataTables does not have a single instance for each DataTable | |
12544 * with the settings attached to that instance, but rather instances of the | |
12545 * DataTable "class" are created on-the-fly as needed (typically by a | |
12546 * $().dataTable() call) and the settings object is then applied to that | |
12547 * instance. | |
12548 * | |
12549 * Note that this object is related to {@link DataTable.defaults} but this | |
12550 * one is the internal data store for DataTables's cache of columns. It should | |
12551 * NOT be manipulated outside of DataTables. Any configuration should be done | |
12552 * through the initialisation options. | |
12553 * @namespace | |
12554 * @todo Really should attach the settings object to individual instances so we | |
12555 * don't need to create new instances on each $().dataTable() call (if the | |
12556 * table already exists). It would also save passing oSettings around and | |
12557 * into every single function. However, this is a very significant | |
12558 * architecture change for DataTables and will almost certainly break | |
12559 * backwards compatibility with older installations. This is something that | |
12560 * will be done in 2.0. | |
12561 */ | |
12562 DataTable.models.oSettings = { | |
12563 /** | |
12564 * Primary features of DataTables and their enablement state. | |
12565 * @namespace | |
12566 */ | |
12567 "oFeatures": { | |
12568 | |
12569 /** | |
12570 * Flag to say if DataTables should automatically try to calculate the | |
12571 * optimum table and columns widths (true) or not (false). | |
12572 * Note that this parameter will be set by the initialisation routine. To | |
12573 * set a default use {@link DataTable.defaults}. | |
12574 * @type boolean | |
12575 */ | |
12576 "bAutoWidth": null, | |
12577 | |
12578 /** | |
12579 * Delay the creation of TR and TD elements until they are actually | |
12580 * needed by a driven page draw. This can give a significant speed | |
12581 * increase for Ajax source and Javascript source data, but makes no | |
12582 * difference at all fro DOM and server-side processing tables. | |
12583 * Note that this parameter will be set by the initialisation routine. To | |
12584 * set a default use {@link DataTable.defaults}. | |
12585 * @type boolean | |
12586 */ | |
12587 "bDeferRender": null, | |
12588 | |
12589 /** | |
12590 * Enable filtering on the table or not. Note that if this is disabled | |
12591 * then there is no filtering at all on the table, including fnFilter. | |
12592 * To just remove the filtering input use sDom and remove the 'f' option. | |
12593 * Note that this parameter will be set by the initialisation routine. To | |
12594 * set a default use {@link DataTable.defaults}. | |
12595 * @type boolean | |
12596 */ | |
12597 "bFilter": null, | |
12598 | |
12599 /** | |
12600 * Table information element (the 'Showing x of y records' div) enable | |
12601 * flag. | |
12602 * Note that this parameter will be set by the initialisation routine. To | |
12603 * set a default use {@link DataTable.defaults}. | |
12604 * @type boolean | |
12605 */ | |
12606 "bInfo": null, | |
12607 | |
12608 /** | |
12609 * Present a user control allowing the end user to change the page size | |
12610 * when pagination is enabled. | |
12611 * Note that this parameter will be set by the initialisation routine. To | |
12612 * set a default use {@link DataTable.defaults}. | |
12613 * @type boolean | |
12614 */ | |
12615 "bLengthChange": null, | |
12616 | |
12617 /** | |
12618 * Pagination enabled or not. Note that if this is disabled then length | |
12619 * changing must also be disabled. | |
12620 * Note that this parameter will be set by the initialisation routine. To | |
12621 * set a default use {@link DataTable.defaults}. | |
12622 * @type boolean | |
12623 */ | |
12624 "bPaginate": null, | |
12625 | |
12626 /** | |
12627 * Processing indicator enable flag whenever DataTables is enacting a | |
12628 * user request - typically an Ajax request for server-side processing. | |
12629 * Note that this parameter will be set by the initialisation routine. To | |
12630 * set a default use {@link DataTable.defaults}. | |
12631 * @type boolean | |
12632 */ | |
12633 "bProcessing": null, | |
12634 | |
12635 /** | |
12636 * Server-side processing enabled flag - when enabled DataTables will | |
12637 * get all data from the server for every draw - there is no filtering, | |
12638 * sorting or paging done on the client-side. | |
12639 * Note that this parameter will be set by the initialisation routine. To | |
12640 * set a default use {@link DataTable.defaults}. | |
12641 * @type boolean | |
12642 */ | |
12643 "bServerSide": null, | |
12644 | |
12645 /** | |
12646 * Sorting enablement flag. | |
12647 * Note that this parameter will be set by the initialisation routine. To | |
12648 * set a default use {@link DataTable.defaults}. | |
12649 * @type boolean | |
12650 */ | |
12651 "bSort": null, | |
12652 | |
12653 /** | |
12654 * Multi-column sorting | |
12655 * Note that this parameter will be set by the initialisation routine. To | |
12656 * set a default use {@link DataTable.defaults}. | |
12657 * @type boolean | |
12658 */ | |
12659 "bSortMulti": null, | |
12660 | |
12661 /** | |
12662 * Apply a class to the columns which are being sorted to provide a | |
12663 * visual highlight or not. This can slow things down when enabled since | |
12664 * there is a lot of DOM interaction. | |
12665 * Note that this parameter will be set by the initialisation routine. To | |
12666 * set a default use {@link DataTable.defaults}. | |
12667 * @type boolean | |
12668 */ | |
12669 "bSortClasses": null, | |
12670 | |
12671 /** | |
12672 * State saving enablement flag. | |
12673 * Note that this parameter will be set by the initialisation routine. To | |
12674 * set a default use {@link DataTable.defaults}. | |
12675 * @type boolean | |
12676 */ | |
12677 "bStateSave": null | |
12678 }, | |
12679 | |
12680 | |
12681 /** | |
12682 * Scrolling settings for a table. | |
12683 * @namespace | |
12684 */ | |
12685 "oScroll": { | |
12686 /** | |
12687 * When the table is shorter in height than sScrollY, collapse the | |
12688 * table container down to the height of the table (when true). | |
12689 * Note that this parameter will be set by the initialisation routine. To | |
12690 * set a default use {@link DataTable.defaults}. | |
12691 * @type boolean | |
12692 */ | |
12693 "bCollapse": null, | |
12694 | |
12695 /** | |
12696 * Width of the scrollbar for the web-browser's platform. Calculated | |
12697 * during table initialisation. | |
12698 * @type int | |
12699 * @default 0 | |
12700 */ | |
12701 "iBarWidth": 0, | |
12702 | |
12703 /** | |
12704 * Viewport width for horizontal scrolling. Horizontal scrolling is | |
12705 * disabled if an empty string. | |
12706 * Note that this parameter will be set by the initialisation routine. To | |
12707 * set a default use {@link DataTable.defaults}. | |
12708 * @type string | |
12709 */ | |
12710 "sX": null, | |
12711 | |
12712 /** | |
12713 * Width to expand the table to when using x-scrolling. Typically you | |
12714 * should not need to use this. | |
12715 * Note that this parameter will be set by the initialisation routine. To | |
12716 * set a default use {@link DataTable.defaults}. | |
12717 * @type string | |
12718 * @deprecated | |
12719 */ | |
12720 "sXInner": null, | |
12721 | |
12722 /** | |
12723 * Viewport height for vertical scrolling. Vertical scrolling is disabled | |
12724 * if an empty string. | |
12725 * Note that this parameter will be set by the initialisation routine. To | |
12726 * set a default use {@link DataTable.defaults}. | |
12727 * @type string | |
12728 */ | |
12729 "sY": null | |
12730 }, | |
12731 | |
12732 /** | |
12733 * Language information for the table. | |
12734 * @namespace | |
12735 * @extends DataTable.defaults.oLanguage | |
12736 */ | |
12737 "oLanguage": { | |
12738 /** | |
12739 * Information callback function. See | |
12740 * {@link DataTable.defaults.fnInfoCallback} | |
12741 * @type function | |
12742 * @default null | |
12743 */ | |
12744 "fnInfoCallback": null | |
12745 }, | |
12746 | |
12747 /** | |
12748 * Browser support parameters | |
12749 * @namespace | |
12750 */ | |
12751 "oBrowser": { | |
12752 /** | |
12753 * Indicate if the browser incorrectly calculates width:100% inside a | |
12754 * scrolling element (IE6/7) | |
12755 * @type boolean | |
12756 * @default false | |
12757 */ | |
12758 "bScrollOversize": false, | |
12759 | |
12760 /** | |
12761 * Determine if the vertical scrollbar is on the right or left of the | |
12762 * scrolling container - needed for rtl language layout, although not | |
12763 * all browsers move the scrollbar (Safari). | |
12764 * @type boolean | |
12765 * @default false | |
12766 */ | |
12767 "bScrollbarLeft": false | |
12768 }, | |
12769 | |
12770 | |
12771 "ajax": null, | |
12772 | |
12773 | |
12774 /** | |
12775 * Array referencing the nodes which are used for the features. The | |
12776 * parameters of this object match what is allowed by sDom - i.e. | |
12777 * <ul> | |
12778 * <li>'l' - Length changing</li> | |
12779 * <li>'f' - Filtering input</li> | |
12780 * <li>'t' - The table!</li> | |
12781 * <li>'i' - Information</li> | |
12782 * <li>'p' - Pagination</li> | |
12783 * <li>'r' - pRocessing</li> | |
12784 * </ul> | |
12785 * @type array | |
12786 * @default [] | |
12787 */ | |
12788 "aanFeatures": [], | |
12789 | |
12790 /** | |
12791 * Store data information - see {@link DataTable.models.oRow} for detailed | |
12792 * information. | |
12793 * @type array | |
12794 * @default [] | |
12795 */ | |
12796 "aoData": [], | |
12797 | |
12798 /** | |
12799 * Array of indexes which are in the current display (after filtering etc) | |
12800 * @type array | |
12801 * @default [] | |
12802 */ | |
12803 "aiDisplay": [], | |
12804 | |
12805 /** | |
12806 * Array of indexes for display - no filtering | |
12807 * @type array | |
12808 * @default [] | |
12809 */ | |
12810 "aiDisplayMaster": [], | |
12811 | |
12812 /** | |
12813 * Store information about each column that is in use | |
12814 * @type array | |
12815 * @default [] | |
12816 */ | |
12817 "aoColumns": [], | |
12818 | |
12819 /** | |
12820 * Store information about the table's header | |
12821 * @type array | |
12822 * @default [] | |
12823 */ | |
12824 "aoHeader": [], | |
12825 | |
12826 /** | |
12827 * Store information about the table's footer | |
12828 * @type array | |
12829 * @default [] | |
12830 */ | |
12831 "aoFooter": [], | |
12832 | |
12833 /** | |
12834 * Store the applied global search information in case we want to force a | |
12835 * research or compare the old search to a new one. | |
12836 * Note that this parameter will be set by the initialisation routine. To | |
12837 * set a default use {@link DataTable.defaults}. | |
12838 * @namespace | |
12839 * @extends DataTable.models.oSearch | |
12840 */ | |
12841 "oPreviousSearch": {}, | |
12842 | |
12843 /** | |
12844 * Store the applied search for each column - see | |
12845 * {@link DataTable.models.oSearch} for the format that is used for the | |
12846 * filtering information for each column. | |
12847 * @type array | |
12848 * @default [] | |
12849 */ | |
12850 "aoPreSearchCols": [], | |
12851 | |
12852 /** | |
12853 * Sorting that is applied to the table. Note that the inner arrays are | |
12854 * used in the following manner: | |
12855 * <ul> | |
12856 * <li>Index 0 - column number</li> | |
12857 * <li>Index 1 - current sorting direction</li> | |
12858 * </ul> | |
12859 * Note that this parameter will be set by the initialisation routine. To | |
12860 * set a default use {@link DataTable.defaults}. | |
12861 * @type array | |
12862 * @todo These inner arrays should really be objects | |
12863 */ | |
12864 "aaSorting": null, | |
12865 | |
12866 /** | |
12867 * Sorting that is always applied to the table (i.e. prefixed in front of | |
12868 * aaSorting). | |
12869 * Note that this parameter will be set by the initialisation routine. To | |
12870 * set a default use {@link DataTable.defaults}. | |
12871 * @type array | |
12872 * @default [] | |
12873 */ | |
12874 "aaSortingFixed": [], | |
12875 | |
12876 /** | |
12877 * Classes to use for the striping of a table. | |
12878 * Note that this parameter will be set by the initialisation routine. To | |
12879 * set a default use {@link DataTable.defaults}. | |
12880 * @type array | |
12881 * @default [] | |
12882 */ | |
12883 "asStripeClasses": null, | |
12884 | |
12885 /** | |
12886 * If restoring a table - we should restore its striping classes as well | |
12887 * @type array | |
12888 * @default [] | |
12889 */ | |
12890 "asDestroyStripes": [], | |
12891 | |
12892 /** | |
12893 * If restoring a table - we should restore its width | |
12894 * @type int | |
12895 * @default 0 | |
12896 */ | |
12897 "sDestroyWidth": 0, | |
12898 | |
12899 /** | |
12900 * Callback functions array for every time a row is inserted (i.e. on a draw). | |
12901 * @type array | |
12902 * @default [] | |
12903 */ | |
12904 "aoRowCallback": [], | |
12905 | |
12906 /** | |
12907 * Callback functions for the header on each draw. | |
12908 * @type array | |
12909 * @default [] | |
12910 */ | |
12911 "aoHeaderCallback": [], | |
12912 | |
12913 /** | |
12914 * Callback function for the footer on each draw. | |
12915 * @type array | |
12916 * @default [] | |
12917 */ | |
12918 "aoFooterCallback": [], | |
12919 | |
12920 /** | |
12921 * Array of callback functions for draw callback functions | |
12922 * @type array | |
12923 * @default [] | |
12924 */ | |
12925 "aoDrawCallback": [], | |
12926 | |
12927 /** | |
12928 * Array of callback functions for row created function | |
12929 * @type array | |
12930 * @default [] | |
12931 */ | |
12932 "aoRowCreatedCallback": [], | |
12933 | |
12934 /** | |
12935 * Callback functions for just before the table is redrawn. A return of | |
12936 * false will be used to cancel the draw. | |
12937 * @type array | |
12938 * @default [] | |
12939 */ | |
12940 "aoPreDrawCallback": [], | |
12941 | |
12942 /** | |
12943 * Callback functions for when the table has been initialised. | |
12944 * @type array | |
12945 * @default [] | |
12946 */ | |
12947 "aoInitComplete": [], | |
12948 | |
12949 | |
12950 /** | |
12951 * Callbacks for modifying the settings to be stored for state saving, prior to | |
12952 * saving state. | |
12953 * @type array | |
12954 * @default [] | |
12955 */ | |
12956 "aoStateSaveParams": [], | |
12957 | |
12958 /** | |
12959 * Callbacks for modifying the settings that have been stored for state saving | |
12960 * prior to using the stored values to restore the state. | |
12961 * @type array | |
12962 * @default [] | |
12963 */ | |
12964 "aoStateLoadParams": [], | |
12965 | |
12966 /** | |
12967 * Callbacks for operating on the settings object once the saved state has been | |
12968 * loaded | |
12969 * @type array | |
12970 * @default [] | |
12971 */ | |
12972 "aoStateLoaded": [], | |
12973 | |
12974 /** | |
12975 * Cache the table ID for quick access | |
12976 * @type string | |
12977 * @default <i>Empty string</i> | |
12978 */ | |
12979 "sTableId": "", | |
12980 | |
12981 /** | |
12982 * The TABLE node for the main table | |
12983 * @type node | |
12984 * @default null | |
12985 */ | |
12986 "nTable": null, | |
12987 | |
12988 /** | |
12989 * Permanent ref to the thead element | |
12990 * @type node | |
12991 * @default null | |
12992 */ | |
12993 "nTHead": null, | |
12994 | |
12995 /** | |
12996 * Permanent ref to the tfoot element - if it exists | |
12997 * @type node | |
12998 * @default null | |
12999 */ | |
13000 "nTFoot": null, | |
13001 | |
13002 /** | |
13003 * Permanent ref to the tbody element | |
13004 * @type node | |
13005 * @default null | |
13006 */ | |
13007 "nTBody": null, | |
13008 | |
13009 /** | |
13010 * Cache the wrapper node (contains all DataTables controlled elements) | |
13011 * @type node | |
13012 * @default null | |
13013 */ | |
13014 "nTableWrapper": null, | |
13015 | |
13016 /** | |
13017 * Indicate if when using server-side processing the loading of data | |
13018 * should be deferred until the second draw. | |
13019 * Note that this parameter will be set by the initialisation routine. To | |
13020 * set a default use {@link DataTable.defaults}. | |
13021 * @type boolean | |
13022 * @default false | |
13023 */ | |
13024 "bDeferLoading": false, | |
13025 | |
13026 /** | |
13027 * Indicate if all required information has been read in | |
13028 * @type boolean | |
13029 * @default false | |
13030 */ | |
13031 "bInitialised": false, | |
13032 | |
13033 /** | |
13034 * Information about open rows. Each object in the array has the parameters | |
13035 * 'nTr' and 'nParent' | |
13036 * @type array | |
13037 * @default [] | |
13038 */ | |
13039 "aoOpenRows": [], | |
13040 | |
13041 /** | |
13042 * Dictate the positioning of DataTables' control elements - see | |
13043 * {@link DataTable.model.oInit.sDom}. | |
13044 * Note that this parameter will be set by the initialisation routine. To | |
13045 * set a default use {@link DataTable.defaults}. | |
13046 * @type string | |
13047 * @default null | |
13048 */ | |
13049 "sDom": null, | |
13050 | |
13051 /** | |
13052 * Search delay (in mS) | |
13053 * @type integer | |
13054 * @default null | |
13055 */ | |
13056 "searchDelay": null, | |
13057 | |
13058 /** | |
13059 * Which type of pagination should be used. | |
13060 * Note that this parameter will be set by the initialisation routine. To | |
13061 * set a default use {@link DataTable.defaults}. | |
13062 * @type string | |
13063 * @default two_button | |
13064 */ | |
13065 "sPaginationType": "two_button", | |
13066 | |
13067 /** | |
13068 * The state duration (for `stateSave`) in seconds. | |
13069 * Note that this parameter will be set by the initialisation routine. To | |
13070 * set a default use {@link DataTable.defaults}. | |
13071 * @type int | |
13072 * @default 0 | |
13073 */ | |
13074 "iStateDuration": 0, | |
13075 | |
13076 /** | |
13077 * Array of callback functions for state saving. Each array element is an | |
13078 * object with the following parameters: | |
13079 * <ul> | |
13080 * <li>function:fn - function to call. Takes two parameters, oSettings | |
13081 * and the JSON string to save that has been thus far created. Returns | |
13082 * a JSON string to be inserted into a json object | |
13083 * (i.e. '"param": [ 0, 1, 2]')</li> | |
13084 * <li>string:sName - name of callback</li> | |
13085 * </ul> | |
13086 * @type array | |
13087 * @default [] | |
13088 */ | |
13089 "aoStateSave": [], | |
13090 | |
13091 /** | |
13092 * Array of callback functions for state loading. Each array element is an | |
13093 * object with the following parameters: | |
13094 * <ul> | |
13095 * <li>function:fn - function to call. Takes two parameters, oSettings | |
13096 * and the object stored. May return false to cancel state loading</li> | |
13097 * <li>string:sName - name of callback</li> | |
13098 * </ul> | |
13099 * @type array | |
13100 * @default [] | |
13101 */ | |
13102 "aoStateLoad": [], | |
13103 | |
13104 /** | |
13105 * State that was saved. Useful for back reference | |
13106 * @type object | |
13107 * @default null | |
13108 */ | |
13109 "oSavedState": null, | |
13110 | |
13111 /** | |
13112 * State that was loaded. Useful for back reference | |
13113 * @type object | |
13114 * @default null | |
13115 */ | |
13116 "oLoadedState": null, | |
13117 | |
13118 /** | |
13119 * Source url for AJAX data for the table. | |
13120 * Note that this parameter will be set by the initialisation routine. To | |
13121 * set a default use {@link DataTable.defaults}. | |
13122 * @type string | |
13123 * @default null | |
13124 */ | |
13125 "sAjaxSource": null, | |
13126 | |
13127 /** | |
13128 * Property from a given object from which to read the table data from. This | |
13129 * can be an empty string (when not server-side processing), in which case | |
13130 * it is assumed an an array is given directly. | |
13131 * Note that this parameter will be set by the initialisation routine. To | |
13132 * set a default use {@link DataTable.defaults}. | |
13133 * @type string | |
13134 */ | |
13135 "sAjaxDataProp": null, | |
13136 | |
13137 /** | |
13138 * Note if draw should be blocked while getting data | |
13139 * @type boolean | |
13140 * @default true | |
13141 */ | |
13142 "bAjaxDataGet": true, | |
13143 | |
13144 /** | |
13145 * The last jQuery XHR object that was used for server-side data gathering. | |
13146 * This can be used for working with the XHR information in one of the | |
13147 * callbacks | |
13148 * @type object | |
13149 * @default null | |
13150 */ | |
13151 "jqXHR": null, | |
13152 | |
13153 /** | |
13154 * JSON returned from the server in the last Ajax request | |
13155 * @type object | |
13156 * @default undefined | |
13157 */ | |
13158 "json": undefined, | |
13159 | |
13160 /** | |
13161 * Data submitted as part of the last Ajax request | |
13162 * @type object | |
13163 * @default undefined | |
13164 */ | |
13165 "oAjaxData": undefined, | |
13166 | |
13167 /** | |
13168 * Function to get the server-side data. | |
13169 * Note that this parameter will be set by the initialisation routine. To | |
13170 * set a default use {@link DataTable.defaults}. | |
13171 * @type function | |
13172 */ | |
13173 "fnServerData": null, | |
13174 | |
13175 /** | |
13176 * Functions which are called prior to sending an Ajax request so extra | |
13177 * parameters can easily be sent to the server | |
13178 * @type array | |
13179 * @default [] | |
13180 */ | |
13181 "aoServerParams": [], | |
13182 | |
13183 /** | |
13184 * Send the XHR HTTP method - GET or POST (could be PUT or DELETE if | |
13185 * required). | |
13186 * Note that this parameter will be set by the initialisation routine. To | |
13187 * set a default use {@link DataTable.defaults}. | |
13188 * @type string | |
13189 */ | |
13190 "sServerMethod": null, | |
13191 | |
13192 /** | |
13193 * Format numbers for display. | |
13194 * Note that this parameter will be set by the initialisation routine. To | |
13195 * set a default use {@link DataTable.defaults}. | |
13196 * @type function | |
13197 */ | |
13198 "fnFormatNumber": null, | |
13199 | |
13200 /** | |
13201 * List of options that can be used for the user selectable length menu. | |
13202 * Note that this parameter will be set by the initialisation routine. To | |
13203 * set a default use {@link DataTable.defaults}. | |
13204 * @type array | |
13205 * @default [] | |
13206 */ | |
13207 "aLengthMenu": null, | |
13208 | |
13209 /** | |
13210 * Counter for the draws that the table does. Also used as a tracker for | |
13211 * server-side processing | |
13212 * @type int | |
13213 * @default 0 | |
13214 */ | |
13215 "iDraw": 0, | |
13216 | |
13217 /** | |
13218 * Indicate if a redraw is being done - useful for Ajax | |
13219 * @type boolean | |
13220 * @default false | |
13221 */ | |
13222 "bDrawing": false, | |
13223 | |
13224 /** | |
13225 * Draw index (iDraw) of the last error when parsing the returned data | |
13226 * @type int | |
13227 * @default -1 | |
13228 */ | |
13229 "iDrawError": -1, | |
13230 | |
13231 /** | |
13232 * Paging display length | |
13233 * @type int | |
13234 * @default 10 | |
13235 */ | |
13236 "_iDisplayLength": 10, | |
13237 | |
13238 /** | |
13239 * Paging start point - aiDisplay index | |
13240 * @type int | |
13241 * @default 0 | |
13242 */ | |
13243 "_iDisplayStart": 0, | |
13244 | |
13245 /** | |
13246 * Server-side processing - number of records in the result set | |
13247 * (i.e. before filtering), Use fnRecordsTotal rather than | |
13248 * this property to get the value of the number of records, regardless of | |
13249 * the server-side processing setting. | |
13250 * @type int | |
13251 * @default 0 | |
13252 * @private | |
13253 */ | |
13254 "_iRecordsTotal": 0, | |
13255 | |
13256 /** | |
13257 * Server-side processing - number of records in the current display set | |
13258 * (i.e. after filtering). Use fnRecordsDisplay rather than | |
13259 * this property to get the value of the number of records, regardless of | |
13260 * the server-side processing setting. | |
13261 * @type boolean | |
13262 * @default 0 | |
13263 * @private | |
13264 */ | |
13265 "_iRecordsDisplay": 0, | |
13266 | |
13267 /** | |
13268 * Flag to indicate if jQuery UI marking and classes should be used. | |
13269 * Note that this parameter will be set by the initialisation routine. To | |
13270 * set a default use {@link DataTable.defaults}. | |
13271 * @type boolean | |
13272 */ | |
13273 "bJUI": null, | |
13274 | |
13275 /** | |
13276 * The classes to use for the table | |
13277 * @type object | |
13278 * @default {} | |
13279 */ | |
13280 "oClasses": {}, | |
13281 | |
13282 /** | |
13283 * Flag attached to the settings object so you can check in the draw | |
13284 * callback if filtering has been done in the draw. Deprecated in favour of | |
13285 * events. | |
13286 * @type boolean | |
13287 * @default false | |
13288 * @deprecated | |
13289 */ | |
13290 "bFiltered": false, | |
13291 | |
13292 /** | |
13293 * Flag attached to the settings object so you can check in the draw | |
13294 * callback if sorting has been done in the draw. Deprecated in favour of | |
13295 * events. | |
13296 * @type boolean | |
13297 * @default false | |
13298 * @deprecated | |
13299 */ | |
13300 "bSorted": false, | |
13301 | |
13302 /** | |
13303 * Indicate that if multiple rows are in the header and there is more than | |
13304 * one unique cell per column, if the top one (true) or bottom one (false) | |
13305 * should be used for sorting / title by DataTables. | |
13306 * Note that this parameter will be set by the initialisation routine. To | |
13307 * set a default use {@link DataTable.defaults}. | |
13308 * @type boolean | |
13309 */ | |
13310 "bSortCellsTop": null, | |
13311 | |
13312 /** | |
13313 * Initialisation object that is used for the table | |
13314 * @type object | |
13315 * @default null | |
13316 */ | |
13317 "oInit": null, | |
13318 | |
13319 /** | |
13320 * Destroy callback functions - for plug-ins to attach themselves to the | |
13321 * destroy so they can clean up markup and events. | |
13322 * @type array | |
13323 * @default [] | |
13324 */ | |
13325 "aoDestroyCallback": [], | |
13326 | |
13327 | |
13328 /** | |
13329 * Get the number of records in the current record set, before filtering | |
13330 * @type function | |
13331 */ | |
13332 "fnRecordsTotal": function () | |
13333 { | |
13334 return _fnDataSource( this ) == 'ssp' ? | |
13335 this._iRecordsTotal * 1 : | |
13336 this.aiDisplayMaster.length; | |
13337 }, | |
13338 | |
13339 /** | |
13340 * Get the number of records in the current record set, after filtering | |
13341 * @type function | |
13342 */ | |
13343 "fnRecordsDisplay": function () | |
13344 { | |
13345 return _fnDataSource( this ) == 'ssp' ? | |
13346 this._iRecordsDisplay * 1 : | |
13347 this.aiDisplay.length; | |
13348 }, | |
13349 | |
13350 /** | |
13351 * Get the display end point - aiDisplay index | |
13352 * @type function | |
13353 */ | |
13354 "fnDisplayEnd": function () | |
13355 { | |
13356 var | |
13357 len = this._iDisplayLength, | |
13358 start = this._iDisplayStart, | |
13359 calc = start + len, | |
13360 records = this.aiDisplay.length, | |
13361 features = this.oFeatures, | |
13362 paginate = features.bPaginate; | |
13363 | |
13364 if ( features.bServerSide ) { | |
13365 return paginate === false || len === -1 ? | |
13366 start + records : | |
13367 Math.min( start+len, this._iRecordsDisplay ); | |
13368 } | |
13369 else { | |
13370 return ! paginate || calc>records || len===-1 ? | |
13371 records : | |
13372 calc; | |
13373 } | |
13374 }, | |
13375 | |
13376 /** | |
13377 * The DataTables object for this table | |
13378 * @type object | |
13379 * @default null | |
13380 */ | |
13381 "oInstance": null, | |
13382 | |
13383 /** | |
13384 * Unique identifier for each instance of the DataTables object. If there | |
13385 * is an ID on the table node, then it takes that value, otherwise an | |
13386 * incrementing internal counter is used. | |
13387 * @type string | |
13388 * @default null | |
13389 */ | |
13390 "sInstance": null, | |
13391 | |
13392 /** | |
13393 * tabindex attribute value that is added to DataTables control elements, allowing | |
13394 * keyboard navigation of the table and its controls. | |
13395 */ | |
13396 "iTabIndex": 0, | |
13397 | |
13398 /** | |
13399 * DIV container for the footer scrolling table if scrolling | |
13400 */ | |
13401 "nScrollHead": null, | |
13402 | |
13403 /** | |
13404 * DIV container for the footer scrolling table if scrolling | |
13405 */ | |
13406 "nScrollFoot": null, | |
13407 | |
13408 /** | |
13409 * Last applied sort | |
13410 * @type array | |
13411 * @default [] | |
13412 */ | |
13413 "aLastSort": [], | |
13414 | |
13415 /** | |
13416 * Stored plug-in instances | |
13417 * @type object | |
13418 * @default {} | |
13419 */ | |
13420 "oPlugins": {} | |
13421 }; | |
13422 | |
13423 /** | |
13424 * Extension object for DataTables that is used to provide all extension | |
13425 * options. | |
13426 * | |
13427 * Note that the `DataTable.ext` object is available through | |
13428 * `jQuery.fn.dataTable.ext` where it may be accessed and manipulated. It is | |
13429 * also aliased to `jQuery.fn.dataTableExt` for historic reasons. | |
13430 * @namespace | |
13431 * @extends DataTable.models.ext | |
13432 */ | |
13433 | |
13434 | |
13435 /** | |
13436 * DataTables extensions | |
13437 * | |
13438 * This namespace acts as a collection area for plug-ins that can be used to | |
13439 * extend DataTables capabilities. Indeed many of the build in methods | |
13440 * use this method to provide their own capabilities (sorting methods for | |
13441 * example). | |
13442 * | |
13443 * Note that this namespace is aliased to `jQuery.fn.dataTableExt` for legacy | |
13444 * reasons | |
13445 * | |
13446 * @namespace | |
13447 */ | |
13448 DataTable.ext = _ext = { | |
13449 /** | |
13450 * Element class names | |
13451 * | |
13452 * @type object | |
13453 * @default {} | |
13454 */ | |
13455 classes: {}, | |
13456 | |
13457 | |
13458 /** | |
13459 * Error reporting. | |
13460 * | |
13461 * How should DataTables report an error. Can take the value 'alert' or | |
13462 * 'throw' | |
13463 * | |
13464 * @type string | |
13465 * @default alert | |
13466 */ | |
13467 errMode: "alert", | |
13468 | |
13469 | |
13470 /** | |
13471 * Feature plug-ins. | |
13472 * | |
13473 * This is an array of objects which describe the feature plug-ins that are | |
13474 * available to DataTables. These feature plug-ins are then available for | |
13475 * use through the `dom` initialisation option. | |
13476 * | |
13477 * Each feature plug-in is described by an object which must have the | |
13478 * following properties: | |
13479 * | |
13480 * * `fnInit` - function that is used to initialise the plug-in, | |
13481 * * `cFeature` - a character so the feature can be enabled by the `dom` | |
13482 * instillation option. This is case sensitive. | |
13483 * | |
13484 * The `fnInit` function has the following input parameters: | |
13485 * | |
13486 * 1. `{object}` DataTables settings object: see | |
13487 * {@link DataTable.models.oSettings} | |
13488 * | |
13489 * And the following return is expected: | |
13490 * | |
13491 * * {node|null} The element which contains your feature. Note that the | |
13492 * return may also be void if your plug-in does not require to inject any | |
13493 * DOM elements into DataTables control (`dom`) - for example this might | |
13494 * be useful when developing a plug-in which allows table control via | |
13495 * keyboard entry | |
13496 * | |
13497 * @type array | |
13498 * | |
13499 * @example | |
13500 * $.fn.dataTable.ext.features.push( { | |
13501 * "fnInit": function( oSettings ) { | |
13502 * return new TableTools( { "oDTSettings": oSettings } ); | |
13503 * }, | |
13504 * "cFeature": "T" | |
13505 * } ); | |
13506 */ | |
13507 feature: [], | |
13508 | |
13509 | |
13510 /** | |
13511 * Row searching. | |
13512 * | |
13513 * This method of searching is complimentary to the default type based | |
13514 * searching, and a lot more comprehensive as it allows you complete control | |
13515 * over the searching logic. Each element in this array is a function | |
13516 * (parameters described below) that is called for every row in the table, | |
13517 * and your logic decides if it should be included in the searching data set | |
13518 * or not. | |
13519 * | |
13520 * Searching functions have the following input parameters: | |
13521 * | |
13522 * 1. `{object}` DataTables settings object: see | |
13523 * {@link DataTable.models.oSettings} | |
13524 * 2. `{array|object}` Data for the row to be processed (same as the | |
13525 * original format that was passed in as the data source, or an array | |
13526 * from a DOM data source | |
13527 * 3. `{int}` Row index ({@link DataTable.models.oSettings.aoData}), which | |
13528 * can be useful to retrieve the `TR` element if you need DOM interaction. | |
13529 * | |
13530 * And the following return is expected: | |
13531 * | |
13532 * * {boolean} Include the row in the searched result set (true) or not | |
13533 * (false) | |
13534 * | |
13535 * Note that as with the main search ability in DataTables, technically this | |
13536 * is "filtering", since it is subtractive. However, for consistency in | |
13537 * naming we call it searching here. | |
13538 * | |
13539 * @type array | |
13540 * @default [] | |
13541 * | |
13542 * @example | |
13543 * // The following example shows custom search being applied to the | |
13544 * // fourth column (i.e. the data[3] index) based on two input values | |
13545 * // from the end-user, matching the data in a certain range. | |
13546 * $.fn.dataTable.ext.search.push( | |
13547 * function( settings, data, dataIndex ) { | |
13548 * var min = document.getElementById('min').value * 1; | |
13549 * var max = document.getElementById('max').value * 1; | |
13550 * var version = data[3] == "-" ? 0 : data[3]*1; | |
13551 * | |
13552 * if ( min == "" && max == "" ) { | |
13553 * return true; | |
13554 * } | |
13555 * else if ( min == "" && version < max ) { | |
13556 * return true; | |
13557 * } | |
13558 * else if ( min < version && "" == max ) { | |
13559 * return true; | |
13560 * } | |
13561 * else if ( min < version && version < max ) { | |
13562 * return true; | |
13563 * } | |
13564 * return false; | |
13565 * } | |
13566 * ); | |
13567 */ | |
13568 search: [], | |
13569 | |
13570 | |
13571 /** | |
13572 * Internal functions, exposed for used in plug-ins. | |
13573 * | |
13574 * Please note that you should not need to use the internal methods for | |
13575 * anything other than a plug-in (and even then, try to avoid if possible). | |
13576 * The internal function may change between releases. | |
13577 * | |
13578 * @type object | |
13579 * @default {} | |
13580 */ | |
13581 internal: {}, | |
13582 | |
13583 | |
13584 /** | |
13585 * Legacy configuration options. Enable and disable legacy options that | |
13586 * are available in DataTables. | |
13587 * | |
13588 * @type object | |
13589 */ | |
13590 legacy: { | |
13591 /** | |
13592 * Enable / disable DataTables 1.9 compatible server-side processing | |
13593 * requests | |
13594 * | |
13595 * @type boolean | |
13596 * @default null | |
13597 */ | |
13598 ajax: null | |
13599 }, | |
13600 | |
13601 | |
13602 /** | |
13603 * Pagination plug-in methods. | |
13604 * | |
13605 * Each entry in this object is a function and defines which buttons should | |
13606 * be shown by the pagination rendering method that is used for the table: | |
13607 * {@link DataTable.ext.renderer.pageButton}. The renderer addresses how the | |
13608 * buttons are displayed in the document, while the functions here tell it | |
13609 * what buttons to display. This is done by returning an array of button | |
13610 * descriptions (what each button will do). | |
13611 * | |
13612 * Pagination types (the four built in options and any additional plug-in | |
13613 * options defined here) can be used through the `paginationType` | |
13614 * initialisation parameter. | |
13615 * | |
13616 * The functions defined take two parameters: | |
13617 * | |
13618 * 1. `{int} page` The current page index | |
13619 * 2. `{int} pages` The number of pages in the table | |
13620 * | |
13621 * Each function is expected to return an array where each element of the | |
13622 * array can be one of: | |
13623 * | |
13624 * * `first` - Jump to first page when activated | |
13625 * * `last` - Jump to last page when activated | |
13626 * * `previous` - Show previous page when activated | |
13627 * * `next` - Show next page when activated | |
13628 * * `{int}` - Show page of the index given | |
13629 * * `{array}` - A nested array containing the above elements to add a | |
13630 * containing 'DIV' element (might be useful for styling). | |
13631 * | |
13632 * Note that DataTables v1.9- used this object slightly differently whereby | |
13633 * an object with two functions would be defined for each plug-in. That | |
13634 * ability is still supported by DataTables 1.10+ to provide backwards | |
13635 * compatibility, but this option of use is now decremented and no longer | |
13636 * documented in DataTables 1.10+. | |
13637 * | |
13638 * @type object | |
13639 * @default {} | |
13640 * | |
13641 * @example | |
13642 * // Show previous, next and current page buttons only | |
13643 * $.fn.dataTableExt.oPagination.current = function ( page, pages ) { | |
13644 * return [ 'previous', page, 'next' ]; | |
13645 * }; | |
13646 */ | |
13647 pager: {}, | |
13648 | |
13649 | |
13650 renderer: { | |
13651 pageButton: {}, | |
13652 header: {} | |
13653 }, | |
13654 | |
13655 | |
13656 /** | |
13657 * Ordering plug-ins - custom data source | |
13658 * | |
13659 * The extension options for ordering of data available here is complimentary | |
13660 * to the default type based ordering that DataTables typically uses. It | |
13661 * allows much greater control over the the data that is being used to | |
13662 * order a column, but is necessarily therefore more complex. | |
13663 * | |
13664 * This type of ordering is useful if you want to do ordering based on data | |
13665 * live from the DOM (for example the contents of an 'input' element) rather | |
13666 * than just the static string that DataTables knows of. | |
13667 * | |
13668 * The way these plug-ins work is that you create an array of the values you | |
13669 * wish to be ordering for the column in question and then return that | |
13670 * array. The data in the array much be in the index order of the rows in | |
13671 * the table (not the currently ordering order!). Which order data gathering | |
13672 * function is run here depends on the `dt-init columns.orderDataType` | |
13673 * parameter that is used for the column (if any). | |
13674 * | |
13675 * The functions defined take two parameters: | |
13676 * | |
13677 * 1. `{object}` DataTables settings object: see | |
13678 * {@link DataTable.models.oSettings} | |
13679 * 2. `{int}` Target column index | |
13680 * | |
13681 * Each function is expected to return an array: | |
13682 * | |
13683 * * `{array}` Data for the column to be ordering upon | |
13684 * | |
13685 * @type array | |
13686 * | |
13687 * @example | |
13688 * // Ordering using `input` node values | |
13689 * $.fn.dataTable.ext.order['dom-text'] = function ( settings, col ) | |
13690 * { | |
13691 * return this.api().column( col, {order:'index'} ).nodes().map( function ( td, i ) { | |
13692 * return $('input', td).val(); | |
13693 * } ); | |
13694 * } | |
13695 */ | |
13696 order: {}, | |
13697 | |
13698 | |
13699 /** | |
13700 * Type based plug-ins. | |
13701 * | |
13702 * Each column in DataTables has a type assigned to it, either by automatic | |
13703 * detection or by direct assignment using the `type` option for the column. | |
13704 * The type of a column will effect how it is ordering and search (plug-ins | |
13705 * can also make use of the column type if required). | |
13706 * | |
13707 * @namespace | |
13708 */ | |
13709 type: { | |
13710 /** | |
13711 * Type detection functions. | |
13712 * | |
13713 * The functions defined in this object are used to automatically detect | |
13714 * a column's type, making initialisation of DataTables super easy, even | |
13715 * when complex data is in the table. | |
13716 * | |
13717 * The functions defined take two parameters: | |
13718 * | |
13719 * 1. `{*}` Data from the column cell to be analysed | |
13720 * 2. `{settings}` DataTables settings object. This can be used to | |
13721 * perform context specific type detection - for example detection | |
13722 * based on language settings such as using a comma for a decimal | |
13723 * place. Generally speaking the options from the settings will not | |
13724 * be required | |
13725 * | |
13726 * Each function is expected to return: | |
13727 * | |
13728 * * `{string|null}` Data type detected, or null if unknown (and thus | |
13729 * pass it on to the other type detection functions. | |
13730 * | |
13731 * @type array | |
13732 * | |
13733 * @example | |
13734 * // Currency type detection plug-in: | |
13735 * $.fn.dataTable.ext.type.detect.push( | |
13736 * function ( data, settings ) { | |
13737 * // Check the numeric part | |
13738 * if ( ! $.isNumeric( data.substring(1) ) ) { | |
13739 * return null; | |
13740 * } | |
13741 * | |
13742 * // Check prefixed by currency | |
13743 * if ( data.charAt(0) == '$' || data.charAt(0) == '£' ) { | |
13744 * return 'currency'; | |
13745 * } | |
13746 * return null; | |
13747 * } | |
13748 * ); | |
13749 */ | |
13750 detect: [], | |
13751 | |
13752 | |
13753 /** | |
13754 * Type based search formatting. | |
13755 * | |
13756 * The type based searching functions can be used to pre-format the | |
13757 * data to be search on. For example, it can be used to strip HTML | |
13758 * tags or to de-format telephone numbers for numeric only searching. | |
13759 * | |
13760 * Note that is a search is not defined for a column of a given type, | |
13761 * no search formatting will be performed. | |
13762 * | |
13763 * Pre-processing of searching data plug-ins - When you assign the sType | |
13764 * for a column (or have it automatically detected for you by DataTables | |
13765 * or a type detection plug-in), you will typically be using this for | |
13766 * custom sorting, but it can also be used to provide custom searching | |
13767 * by allowing you to pre-processing the data and returning the data in | |
13768 * the format that should be searched upon. This is done by adding | |
13769 * functions this object with a parameter name which matches the sType | |
13770 * for that target column. This is the corollary of <i>afnSortData</i> | |
13771 * for searching data. | |
13772 * | |
13773 * The functions defined take a single parameter: | |
13774 * | |
13775 * 1. `{*}` Data from the column cell to be prepared for searching | |
13776 * | |
13777 * Each function is expected to return: | |
13778 * | |
13779 * * `{string|null}` Formatted string that will be used for the searching. | |
13780 * | |
13781 * @type object | |
13782 * @default {} | |
13783 * | |
13784 * @example | |
13785 * $.fn.dataTable.ext.type.search['title-numeric'] = function ( d ) { | |
13786 * return d.replace(/\n/g," ").replace( /<.*?>/g, "" ); | |
13787 * } | |
13788 */ | |
13789 search: {}, | |
13790 | |
13791 | |
13792 /** | |
13793 * Type based ordering. | |
13794 * | |
13795 * The column type tells DataTables what ordering to apply to the table | |
13796 * when a column is sorted upon. The order for each type that is defined, | |
13797 * is defined by the functions available in this object. | |
13798 * | |
13799 * Each ordering option can be described by three properties added to | |
13800 * this object: | |
13801 * | |
13802 * * `{type}-pre` - Pre-formatting function | |
13803 * * `{type}-asc` - Ascending order function | |
13804 * * `{type}-desc` - Descending order function | |
13805 * | |
13806 * All three can be used together, only `{type}-pre` or only | |
13807 * `{type}-asc` and `{type}-desc` together. It is generally recommended | |
13808 * that only `{type}-pre` is used, as this provides the optimal | |
13809 * implementation in terms of speed, although the others are provided | |
13810 * for compatibility with existing Javascript sort functions. | |
13811 * | |
13812 * `{type}-pre`: Functions defined take a single parameter: | |
13813 * | |
13814 * 1. `{*}` Data from the column cell to be prepared for ordering | |
13815 * | |
13816 * And return: | |
13817 * | |
13818 * * `{*}` Data to be sorted upon | |
13819 * | |
13820 * `{type}-asc` and `{type}-desc`: Functions are typical Javascript sort | |
13821 * functions, taking two parameters: | |
13822 * | |
13823 * 1. `{*}` Data to compare to the second parameter | |
13824 * 2. `{*}` Data to compare to the first parameter | |
13825 * | |
13826 * And returning: | |
13827 * | |
13828 * * `{*}` Ordering match: <0 if first parameter should be sorted lower | |
13829 * than the second parameter, ===0 if the two parameters are equal and | |
13830 * >0 if the first parameter should be sorted height than the second | |
13831 * parameter. | |
13832 * | |
13833 * @type object | |
13834 * @default {} | |
13835 * | |
13836 * @example | |
13837 * // Numeric ordering of formatted numbers with a pre-formatter | |
13838 * $.extend( $.fn.dataTable.ext.type.order, { | |
13839 * "string-pre": function(x) { | |
13840 * a = (a === "-" || a === "") ? 0 : a.replace( /[^\d\-\.]/g, "" ); | |
13841 * return parseFloat( a ); | |
13842 * } | |
13843 * } ); | |
13844 * | |
13845 * @example | |
13846 * // Case-sensitive string ordering, with no pre-formatting method | |
13847 * $.extend( $.fn.dataTable.ext.order, { | |
13848 * "string-case-asc": function(x,y) { | |
13849 * return ((x < y) ? -1 : ((x > y) ? 1 : 0)); | |
13850 * }, | |
13851 * "string-case-desc": function(x,y) { | |
13852 * return ((x < y) ? 1 : ((x > y) ? -1 : 0)); | |
13853 * } | |
13854 * } ); | |
13855 */ | |
13856 order: {} | |
13857 }, | |
13858 | |
13859 /** | |
13860 * Unique DataTables instance counter | |
13861 * | |
13862 * @type int | |
13863 * @private | |
13864 */ | |
13865 _unique: 0, | |
13866 | |
13867 | |
13868 // | |
13869 // Depreciated | |
13870 // The following properties are retained for backwards compatiblity only. | |
13871 // The should not be used in new projects and will be removed in a future | |
13872 // version | |
13873 // | |
13874 | |
13875 /** | |
13876 * Version check function. | |
13877 * @type function | |
13878 * @depreciated Since 1.10 | |
13879 */ | |
13880 fnVersionCheck: DataTable.fnVersionCheck, | |
13881 | |
13882 | |
13883 /** | |
13884 * Index for what 'this' index API functions should use | |
13885 * @type int | |
13886 * @deprecated Since v1.10 | |
13887 */ | |
13888 iApiIndex: 0, | |
13889 | |
13890 | |
13891 /** | |
13892 * jQuery UI class container | |
13893 * @type object | |
13894 * @deprecated Since v1.10 | |
13895 */ | |
13896 oJUIClasses: {}, | |
13897 | |
13898 | |
13899 /** | |
13900 * Software version | |
13901 * @type string | |
13902 * @deprecated Since v1.10 | |
13903 */ | |
13904 sVersion: DataTable.version | |
13905 }; | |
13906 | |
13907 | |
13908 // | |
13909 // Backwards compatibility. Alias to pre 1.10 Hungarian notation counter parts | |
13910 // | |
13911 $.extend( _ext, { | |
13912 afnFiltering: _ext.search, | |
13913 aTypes: _ext.type.detect, | |
13914 ofnSearch: _ext.type.search, | |
13915 oSort: _ext.type.order, | |
13916 afnSortData: _ext.order, | |
13917 aoFeatures: _ext.feature, | |
13918 oApi: _ext.internal, | |
13919 oStdClasses: _ext.classes, | |
13920 oPagination: _ext.pager | |
13921 } ); | |
13922 | |
13923 | |
13924 $.extend( DataTable.ext.classes, { | |
13925 "sTable": "dataTable", | |
13926 "sNoFooter": "no-footer", | |
13927 | |
13928 /* Paging buttons */ | |
13929 "sPageButton": "paginate_button", | |
13930 "sPageButtonActive": "current", | |
13931 "sPageButtonDisabled": "disabled", | |
13932 | |
13933 /* Striping classes */ | |
13934 "sStripeOdd": "odd", | |
13935 "sStripeEven": "even", | |
13936 | |
13937 /* Empty row */ | |
13938 "sRowEmpty": "dataTables_empty", | |
13939 | |
13940 /* Features */ | |
13941 "sWrapper": "dataTables_wrapper", | |
13942 "sFilter": "dataTables_filter", | |
13943 "sInfo": "dataTables_info", | |
13944 "sPaging": "dataTables_paginate paging_", /* Note that the type is postfixed */ | |
13945 "sLength": "dataTables_length", | |
13946 "sProcessing": "dataTables_processing", | |
13947 | |
13948 /* Sorting */ | |
13949 "sSortAsc": "sorting_asc", | |
13950 "sSortDesc": "sorting_desc", | |
13951 "sSortable": "sorting", /* Sortable in both directions */ | |
13952 "sSortableAsc": "sorting_asc_disabled", | |
13953 "sSortableDesc": "sorting_desc_disabled", | |
13954 "sSortableNone": "sorting_disabled", | |
13955 "sSortColumn": "sorting_", /* Note that an int is postfixed for the sorting order */ | |
13956 | |
13957 /* Filtering */ | |
13958 "sFilterInput": "", | |
13959 | |
13960 /* Page length */ | |
13961 "sLengthSelect": "", | |
13962 | |
13963 /* Scrolling */ | |
13964 "sScrollWrapper": "dataTables_scroll", | |
13965 "sScrollHead": "dataTables_scrollHead", | |
13966 "sScrollHeadInner": "dataTables_scrollHeadInner", | |
13967 "sScrollBody": "dataTables_scrollBody", | |
13968 "sScrollFoot": "dataTables_scrollFoot", | |
13969 "sScrollFootInner": "dataTables_scrollFootInner", | |
13970 | |
13971 /* Misc */ | |
13972 "sHeaderTH": "", | |
13973 "sFooterTH": "", | |
13974 | |
13975 // Deprecated | |
13976 "sSortJUIAsc": "", | |
13977 "sSortJUIDesc": "", | |
13978 "sSortJUI": "", | |
13979 "sSortJUIAscAllowed": "", | |
13980 "sSortJUIDescAllowed": "", | |
13981 "sSortJUIWrapper": "", | |
13982 "sSortIcon": "", | |
13983 "sJUIHeader": "", | |
13984 "sJUIFooter": "" | |
13985 } ); | |
13986 | |
13987 | |
13988 (function() { | |
13989 | |
13990 // Reused strings for better compression. Closure compiler appears to have a | |
13991 // weird edge case where it is trying to expand strings rather than use the | |
13992 // variable version. This results in about 200 bytes being added, for very | |
13993 // little preference benefit since it this run on script load only. | |
13994 var _empty = ''; | |
13995 _empty = ''; | |
13996 | |
13997 var _stateDefault = _empty + 'ui-state-default'; | |
13998 var _sortIcon = _empty + 'css_right ui-icon ui-icon-'; | |
13999 var _headerFooter = _empty + 'fg-toolbar ui-toolbar ui-widget-header ui-helper-clearfix'; | |
14000 | |
14001 $.extend( DataTable.ext.oJUIClasses, DataTable.ext.classes, { | |
14002 /* Full numbers paging buttons */ | |
14003 "sPageButton": "fg-button ui-button "+_stateDefault, | |
14004 "sPageButtonActive": "ui-state-disabled", | |
14005 "sPageButtonDisabled": "ui-state-disabled", | |
14006 | |
14007 /* Features */ | |
14008 "sPaging": "dataTables_paginate fg-buttonset ui-buttonset fg-buttonset-multi "+ | |
14009 "ui-buttonset-multi paging_", /* Note that the type is postfixed */ | |
14010 | |
14011 /* Sorting */ | |
14012 "sSortAsc": _stateDefault+" sorting_asc", | |
14013 "sSortDesc": _stateDefault+" sorting_desc", | |
14014 "sSortable": _stateDefault+" sorting", | |
14015 "sSortableAsc": _stateDefault+" sorting_asc_disabled", | |
14016 "sSortableDesc": _stateDefault+" sorting_desc_disabled", | |
14017 "sSortableNone": _stateDefault+" sorting_disabled", | |
14018 "sSortJUIAsc": _sortIcon+"triangle-1-n", | |
14019 "sSortJUIDesc": _sortIcon+"triangle-1-s", | |
14020 "sSortJUI": _sortIcon+"carat-2-n-s", | |
14021 "sSortJUIAscAllowed": _sortIcon+"carat-1-n", | |
14022 "sSortJUIDescAllowed": _sortIcon+"carat-1-s", | |
14023 "sSortJUIWrapper": "DataTables_sort_wrapper", | |
14024 "sSortIcon": "DataTables_sort_icon", | |
14025 | |
14026 /* Scrolling */ | |
14027 "sScrollHead": "dataTables_scrollHead "+_stateDefault, | |
14028 "sScrollFoot": "dataTables_scrollFoot "+_stateDefault, | |
14029 | |
14030 /* Misc */ | |
14031 "sHeaderTH": _stateDefault, | |
14032 "sFooterTH": _stateDefault, | |
14033 "sJUIHeader": _headerFooter+" ui-corner-tl ui-corner-tr", | |
14034 "sJUIFooter": _headerFooter+" ui-corner-bl ui-corner-br" | |
14035 } ); | |
14036 | |
14037 }()); | |
14038 | |
14039 | |
14040 | |
14041 var extPagination = DataTable.ext.pager; | |
14042 | |
14043 function _numbers ( page, pages ) { | |
14044 var | |
14045 numbers = [], | |
14046 buttons = extPagination.numbers_length, | |
14047 half = Math.floor( buttons / 2 ), | |
14048 i = 1; | |
14049 | |
14050 if ( pages <= buttons ) { | |
14051 numbers = _range( 0, pages ); | |
14052 } | |
14053 else if ( page <= half ) { | |
14054 numbers = _range( 0, buttons-2 ); | |
14055 numbers.push( 'ellipsis' ); | |
14056 numbers.push( pages-1 ); | |
14057 } | |
14058 else if ( page >= pages - 1 - half ) { | |
14059 numbers = _range( pages-(buttons-2), pages ); | |
14060 numbers.splice( 0, 0, 'ellipsis' ); // no unshift in ie6 | |
14061 numbers.splice( 0, 0, 0 ); | |
14062 } | |
14063 else { | |
14064 numbers = _range( page-1, page+2 ); | |
14065 numbers.push( 'ellipsis' ); | |
14066 numbers.push( pages-1 ); | |
14067 numbers.splice( 0, 0, 'ellipsis' ); | |
14068 numbers.splice( 0, 0, 0 ); | |
14069 } | |
14070 | |
14071 numbers.DT_el = 'span'; | |
14072 return numbers; | |
14073 } | |
14074 | |
14075 | |
14076 $.extend( extPagination, { | |
14077 simple: function ( page, pages ) { | |
14078 return [ 'previous', 'next' ]; | |
14079 }, | |
14080 | |
14081 full: function ( page, pages ) { | |
14082 return [ 'first', 'previous', 'next', 'last' ]; | |
14083 }, | |
14084 | |
14085 simple_numbers: function ( page, pages ) { | |
14086 return [ 'previous', _numbers(page, pages), 'next' ]; | |
14087 }, | |
14088 | |
14089 full_numbers: function ( page, pages ) { | |
14090 return [ 'first', 'previous', _numbers(page, pages), 'next', 'last' ]; | |
14091 }, | |
14092 | |
14093 // For testing and plug-ins to use | |
14094 _numbers: _numbers, | |
14095 numbers_length: 7 | |
14096 } ); | |
14097 | |
14098 | |
14099 $.extend( true, DataTable.ext.renderer, { | |
14100 pageButton: { | |
14101 _: function ( settings, host, idx, buttons, page, pages ) { | |
14102 var classes = settings.oClasses; | |
14103 var lang = settings.oLanguage.oPaginate; | |
14104 var btnDisplay, btnClass, counter=0; | |
14105 | |
14106 var attach = function( container, buttons ) { | |
14107 var i, ien, node, button; | |
14108 var clickHandler = function ( e ) { | |
14109 _fnPageChange( settings, e.data.action, true ); | |
14110 }; | |
14111 | |
14112 for ( i=0, ien=buttons.length ; i<ien ; i++ ) { | |
14113 button = buttons[i]; | |
14114 | |
14115 if ( $.isArray( button ) ) { | |
14116 var inner = $( '<'+(button.DT_el || 'div')+'/>' ) | |
14117 .appendTo( container ); | |
14118 attach( inner, button ); | |
14119 } | |
14120 else { | |
14121 btnDisplay = ''; | |
14122 btnClass = ''; | |
14123 | |
14124 switch ( button ) { | |
14125 case 'ellipsis': | |
14126 container.append('<span>…</span>'); | |
14127 break; | |
14128 | |
14129 case 'first': | |
14130 btnDisplay = lang.sFirst; | |
14131 btnClass = button + (page > 0 ? | |
14132 '' : ' '+classes.sPageButtonDisabled); | |
14133 break; | |
14134 | |
14135 case 'previous': | |
14136 btnDisplay = lang.sPrevious; | |
14137 btnClass = button + (page > 0 ? | |
14138 '' : ' '+classes.sPageButtonDisabled); | |
14139 break; | |
14140 | |
14141 case 'next': | |
14142 btnDisplay = lang.sNext; | |
14143 btnClass = button + (page < pages-1 ? | |
14144 '' : ' '+classes.sPageButtonDisabled); | |
14145 break; | |
14146 | |
14147 case 'last': | |
14148 btnDisplay = lang.sLast; | |
14149 btnClass = button + (page < pages-1 ? | |
14150 '' : ' '+classes.sPageButtonDisabled); | |
14151 break; | |
14152 | |
14153 default: | |
14154 btnDisplay = button + 1; | |
14155 btnClass = page === button ? | |
14156 classes.sPageButtonActive : ''; | |
14157 break; | |
14158 } | |
14159 | |
14160 if ( btnDisplay ) { | |
14161 node = $('<a>', { | |
14162 'class': classes.sPageButton+' '+btnClass, | |
14163 'aria-controls': settings.sTableId, | |
14164 'data-dt-idx': counter, | |
14165 'tabindex': settings.iTabIndex, | |
14166 'id': idx === 0 && typeof button === 'string' ? | |
14167 settings.sTableId +'_'+ button : | |
14168 null | |
14169 } ) | |
14170 .html( btnDisplay ) | |
14171 .appendTo( container ); | |
14172 | |
14173 _fnBindAction( | |
14174 node, {action: button}, clickHandler | |
14175 ); | |
14176 | |
14177 counter++; | |
14178 } | |
14179 } | |
14180 } | |
14181 }; | |
14182 | |
14183 // IE9 throws an 'unknown error' if document.activeElement is used | |
14184 // inside an iframe or frame. Try / catch the error. Not good for | |
14185 // accessibility, but neither are frames. | |
14186 try { | |
14187 // Because this approach is destroying and recreating the paging | |
14188 // elements, focus is lost on the select button which is bad for | |
14189 // accessibility. So we want to restore focus once the draw has | |
14190 // completed | |
14191 var activeEl = $(document.activeElement).data('dt-idx'); | |
14192 | |
14193 attach( $(host).empty(), buttons ); | |
14194 | |
14195 if ( activeEl !== null ) { | |
14196 $(host).find( '[data-dt-idx='+activeEl+']' ).focus(); | |
14197 } | |
14198 } | |
14199 catch (e) {} | |
14200 } | |
14201 } | |
14202 } ); | |
14203 | |
14204 | |
14205 | |
14206 // Built in type detection. See model.ext.aTypes for information about | |
14207 // what is required from this methods. | |
14208 $.extend( DataTable.ext.type.detect, [ | |
14209 // Plain numbers - first since V8 detects some plain numbers as dates | |
14210 // e.g. Date.parse('55') (but not all, e.g. Date.parse('22')...). | |
14211 function ( d, settings ) | |
14212 { | |
14213 var decimal = settings.oLanguage.sDecimal; | |
14214 return _isNumber( d, decimal ) ? 'num'+decimal : null; | |
14215 }, | |
14216 | |
14217 // Dates (only those recognised by the browser's Date.parse) | |
14218 function ( d, settings ) | |
14219 { | |
14220 // V8 will remove any unknown characters at the start and end of the | |
14221 // expression, leading to false matches such as `$245.12` or `10%` being | |
14222 // a valid date. See forum thread 18941 for detail. | |
14223 if ( d && !(d instanceof Date) && ( ! _re_date_start.test(d) || ! _re_date_end.test(d) ) ) { | |
14224 return null; | |
14225 } | |
14226 var parsed = Date.parse(d); | |
14227 return (parsed !== null && !isNaN(parsed)) || _empty(d) ? 'date' : null; | |
14228 }, | |
14229 | |
14230 // Formatted numbers | |
14231 function ( d, settings ) | |
14232 { | |
14233 var decimal = settings.oLanguage.sDecimal; | |
14234 return _isNumber( d, decimal, true ) ? 'num-fmt'+decimal : null; | |
14235 }, | |
14236 | |
14237 // HTML numeric | |
14238 function ( d, settings ) | |
14239 { | |
14240 var decimal = settings.oLanguage.sDecimal; | |
14241 return _htmlNumeric( d, decimal ) ? 'html-num'+decimal : null; | |
14242 }, | |
14243 | |
14244 // HTML numeric, formatted | |
14245 function ( d, settings ) | |
14246 { | |
14247 var decimal = settings.oLanguage.sDecimal; | |
14248 return _htmlNumeric( d, decimal, true ) ? 'html-num-fmt'+decimal : null; | |
14249 }, | |
14250 | |
14251 // HTML (this is strict checking - there must be html) | |
14252 function ( d, settings ) | |
14253 { | |
14254 return _empty( d ) || (typeof d === 'string' && d.indexOf('<') !== -1) ? | |
14255 'html' : null; | |
14256 } | |
14257 ] ); | |
14258 | |
14259 | |
14260 | |
14261 // Filter formatting functions. See model.ext.ofnSearch for information about | |
14262 // what is required from these methods. | |
14263 // | |
14264 // Note that additional search methods are added for the html numbers and | |
14265 // html formatted numbers by `_addNumericSort()` when we know what the decimal | |
14266 // place is | |
14267 | |
14268 | |
14269 $.extend( DataTable.ext.type.search, { | |
14270 html: function ( data ) { | |
14271 return _empty(data) ? | |
14272 data : | |
14273 typeof data === 'string' ? | |
14274 data | |
14275 .replace( _re_new_lines, " " ) | |
14276 .replace( _re_html, "" ) : | |
14277 ''; | |
14278 }, | |
14279 | |
14280 string: function ( data ) { | |
14281 return _empty(data) ? | |
14282 data : | |
14283 typeof data === 'string' ? | |
14284 data.replace( _re_new_lines, " " ) : | |
14285 data; | |
14286 } | |
14287 } ); | |
14288 | |
14289 | |
14290 | |
14291 var __numericReplace = function ( d, decimalPlace, re1, re2 ) { | |
14292 if ( d !== 0 && (!d || d === '-') ) { | |
14293 return -Infinity; | |
14294 } | |
14295 | |
14296 // If a decimal place other than `.` is used, it needs to be given to the | |
14297 // function so we can detect it and replace with a `.` which is the only | |
14298 // decimal place Javascript recognises - it is not locale aware. | |
14299 if ( decimalPlace ) { | |
14300 d = _numToDecimal( d, decimalPlace ); | |
14301 } | |
14302 | |
14303 if ( d.replace ) { | |
14304 if ( re1 ) { | |
14305 d = d.replace( re1, '' ); | |
14306 } | |
14307 | |
14308 if ( re2 ) { | |
14309 d = d.replace( re2, '' ); | |
14310 } | |
14311 } | |
14312 | |
14313 return d * 1; | |
14314 }; | |
14315 | |
14316 | |
14317 // Add the numeric 'deformatting' functions for sorting and search. This is done | |
14318 // in a function to provide an easy ability for the language options to add | |
14319 // additional methods if a non-period decimal place is used. | |
14320 function _addNumericSort ( decimalPlace ) { | |
14321 $.each( | |
14322 { | |
14323 // Plain numbers | |
14324 "num": function ( d ) { | |
14325 return __numericReplace( d, decimalPlace ); | |
14326 }, | |
14327 | |
14328 // Formatted numbers | |
14329 "num-fmt": function ( d ) { | |
14330 return __numericReplace( d, decimalPlace, _re_formatted_numeric ); | |
14331 }, | |
14332 | |
14333 // HTML numeric | |
14334 "html-num": function ( d ) { | |
14335 return __numericReplace( d, decimalPlace, _re_html ); | |
14336 }, | |
14337 | |
14338 // HTML numeric, formatted | |
14339 "html-num-fmt": function ( d ) { | |
14340 return __numericReplace( d, decimalPlace, _re_html, _re_formatted_numeric ); | |
14341 } | |
14342 }, | |
14343 function ( key, fn ) { | |
14344 // Add the ordering method | |
14345 _ext.type.order[ key+decimalPlace+'-pre' ] = fn; | |
14346 | |
14347 // For HTML types add a search formatter that will strip the HTML | |
14348 if ( key.match(/^html\-/) ) { | |
14349 _ext.type.search[ key+decimalPlace ] = _ext.type.search.html; | |
14350 } | |
14351 } | |
14352 ); | |
14353 } | |
14354 | |
14355 | |
14356 // Default sort methods | |
14357 $.extend( _ext.type.order, { | |
14358 // Dates | |
14359 "date-pre": function ( d ) { | |
14360 return Date.parse( d ) || 0; | |
14361 }, | |
14362 | |
14363 // html | |
14364 "html-pre": function ( a ) { | |
14365 return _empty(a) ? | |
14366 '' : | |
14367 a.replace ? | |
14368 a.replace( /<.*?>/g, "" ).toLowerCase() : | |
14369 a+''; | |
14370 }, | |
14371 | |
14372 // string | |
14373 "string-pre": function ( a ) { | |
14374 // This is a little complex, but faster than always calling toString, | |
14375 // http://jsperf.com/tostring-v-check | |
14376 return _empty(a) ? | |
14377 '' : | |
14378 typeof a === 'string' ? | |
14379 a.toLowerCase() : | |
14380 ! a.toString ? | |
14381 '' : | |
14382 a.toString(); | |
14383 }, | |
14384 | |
14385 // string-asc and -desc are retained only for compatibility with the old | |
14386 // sort methods | |
14387 "string-asc": function ( x, y ) { | |
14388 return ((x < y) ? -1 : ((x > y) ? 1 : 0)); | |
14389 }, | |
14390 | |
14391 "string-desc": function ( x, y ) { | |
14392 return ((x < y) ? 1 : ((x > y) ? -1 : 0)); | |
14393 } | |
14394 } ); | |
14395 | |
14396 | |
14397 // Numeric sorting types - order doesn't matter here | |
14398 _addNumericSort( '' ); | |
14399 | |
14400 | |
14401 $.extend( true, DataTable.ext.renderer, { | |
14402 header: { | |
14403 _: function ( settings, cell, column, classes ) { | |
14404 // No additional mark-up required | |
14405 // Attach a sort listener to update on sort - note that using the | |
14406 // `DT` namespace will allow the event to be removed automatically | |
14407 // on destroy, while the `dt` namespaced event is the one we are | |
14408 // listening for | |
14409 $(settings.nTable).on( 'order.dt.DT', function ( e, ctx, sorting, columns ) { | |
14410 if ( settings !== ctx ) { // need to check this this is the host | |
14411 return; // table, not a nested one | |
14412 } | |
14413 | |
14414 var colIdx = column.idx; | |
14415 | |
14416 cell | |
14417 .removeClass( | |
14418 column.sSortingClass +' '+ | |
14419 classes.sSortAsc +' '+ | |
14420 classes.sSortDesc | |
14421 ) | |
14422 .addClass( columns[ colIdx ] == 'asc' ? | |
14423 classes.sSortAsc : columns[ colIdx ] == 'desc' ? | |
14424 classes.sSortDesc : | |
14425 column.sSortingClass | |
14426 ); | |
14427 } ); | |
14428 }, | |
14429 | |
14430 jqueryui: function ( settings, cell, column, classes ) { | |
14431 $('<div/>') | |
14432 .addClass( classes.sSortJUIWrapper ) | |
14433 .append( cell.contents() ) | |
14434 .append( $('<span/>') | |
14435 .addClass( classes.sSortIcon+' '+column.sSortingClassJUI ) | |
14436 ) | |
14437 .appendTo( cell ); | |
14438 | |
14439 // Attach a sort listener to update on sort | |
14440 $(settings.nTable).on( 'order.dt.DT', function ( e, ctx, sorting, columns ) { | |
14441 if ( settings !== ctx ) { | |
14442 return; | |
14443 } | |
14444 | |
14445 var colIdx = column.idx; | |
14446 | |
14447 cell | |
14448 .removeClass( classes.sSortAsc +" "+classes.sSortDesc ) | |
14449 .addClass( columns[ colIdx ] == 'asc' ? | |
14450 classes.sSortAsc : columns[ colIdx ] == 'desc' ? | |
14451 classes.sSortDesc : | |
14452 column.sSortingClass | |
14453 ); | |
14454 | |
14455 cell | |
14456 .find( 'span.'+classes.sSortIcon ) | |
14457 .removeClass( | |
14458 classes.sSortJUIAsc +" "+ | |
14459 classes.sSortJUIDesc +" "+ | |
14460 classes.sSortJUI +" "+ | |
14461 classes.sSortJUIAscAllowed +" "+ | |
14462 classes.sSortJUIDescAllowed | |
14463 ) | |
14464 .addClass( columns[ colIdx ] == 'asc' ? | |
14465 classes.sSortJUIAsc : columns[ colIdx ] == 'desc' ? | |
14466 classes.sSortJUIDesc : | |
14467 column.sSortingClassJUI | |
14468 ); | |
14469 } ); | |
14470 } | |
14471 } | |
14472 } ); | |
14473 | |
14474 /* | |
14475 * Public helper functions. These aren't used internally by DataTables, or | |
14476 * called by any of the options passed into DataTables, but they can be used | |
14477 * externally by developers working with DataTables. They are helper functions | |
14478 * to make working with DataTables a little bit easier. | |
14479 */ | |
14480 | |
14481 /** | |
14482 * Helpers for `columns.render`. | |
14483 * | |
14484 * The options defined here can be used with the `columns.render` initialisation | |
14485 * option to provide a display renderer. The following functions are defined: | |
14486 * | |
14487 * * `number` - Will format numeric data (defined by `columns.data`) for | |
14488 * display, retaining the original unformatted data for sorting and filtering. | |
14489 * It takes 4 parameters: | |
14490 * * `string` - Thousands grouping separator | |
14491 * * `string` - Decimal point indicator | |
14492 * * `integer` - Number of decimal points to show | |
14493 * * `string` (optional) - Prefix. | |
14494 * | |
14495 * @example | |
14496 * // Column definition using the number renderer | |
14497 * { | |
14498 * data: "salary", | |
14499 * render: $.fn.dataTable.render.number( '\'', '.', 0, '$' ) | |
14500 * } | |
14501 * | |
14502 * @namespace | |
14503 */ | |
14504 DataTable.render = { | |
14505 number: function ( thousands, decimal, precision, prefix ) { | |
14506 return { | |
14507 display: function ( d ) { | |
14508 var negative = d < 0 ? '-' : ''; | |
14509 d = Math.abs( parseFloat( d ) ); | |
14510 | |
14511 var intPart = parseInt( d, 10 ); | |
14512 var floatPart = precision ? | |
14513 decimal+(d - intPart).toFixed( precision ).substring( 2 ): | |
14514 ''; | |
14515 | |
14516 return negative + (prefix||'') + | |
14517 intPart.toString().replace( | |
14518 /\B(?=(\d{3})+(?!\d))/g, thousands | |
14519 ) + | |
14520 floatPart; | |
14521 } | |
14522 }; | |
14523 } | |
14524 }; | |
14525 | |
14526 | |
14527 /* | |
14528 * This is really a good bit rubbish this method of exposing the internal methods | |
14529 * publicly... - To be fixed in 2.0 using methods on the prototype | |
14530 */ | |
14531 | |
14532 | |
14533 /** | |
14534 * Create a wrapper function for exporting an internal functions to an external API. | |
14535 * @param {string} fn API function name | |
14536 * @returns {function} wrapped function | |
14537 * @memberof DataTable#internal | |
14538 */ | |
14539 function _fnExternApiFunc (fn) | |
14540 { | |
14541 return function() { | |
14542 var args = [_fnSettingsFromNode( this[DataTable.ext.iApiIndex] )].concat( | |
14543 Array.prototype.slice.call(arguments) | |
14544 ); | |
14545 return DataTable.ext.internal[fn].apply( this, args ); | |
14546 }; | |
14547 } | |
14548 | |
14549 | |
14550 /** | |
14551 * Reference to internal functions for use by plug-in developers. Note that | |
14552 * these methods are references to internal functions and are considered to be | |
14553 * private. If you use these methods, be aware that they are liable to change | |
14554 * between versions. | |
14555 * @namespace | |
14556 */ | |
14557 $.extend( DataTable.ext.internal, { | |
14558 _fnExternApiFunc: _fnExternApiFunc, | |
14559 _fnBuildAjax: _fnBuildAjax, | |
14560 _fnAjaxUpdate: _fnAjaxUpdate, | |
14561 _fnAjaxParameters: _fnAjaxParameters, | |
14562 _fnAjaxUpdateDraw: _fnAjaxUpdateDraw, | |
14563 _fnAjaxDataSrc: _fnAjaxDataSrc, | |
14564 _fnAddColumn: _fnAddColumn, | |
14565 _fnColumnOptions: _fnColumnOptions, | |
14566 _fnAdjustColumnSizing: _fnAdjustColumnSizing, | |
14567 _fnVisibleToColumnIndex: _fnVisibleToColumnIndex, | |
14568 _fnColumnIndexToVisible: _fnColumnIndexToVisible, | |
14569 _fnVisbleColumns: _fnVisbleColumns, | |
14570 _fnGetColumns: _fnGetColumns, | |
14571 _fnColumnTypes: _fnColumnTypes, | |
14572 _fnApplyColumnDefs: _fnApplyColumnDefs, | |
14573 _fnHungarianMap: _fnHungarianMap, | |
14574 _fnCamelToHungarian: _fnCamelToHungarian, | |
14575 _fnLanguageCompat: _fnLanguageCompat, | |
14576 _fnBrowserDetect: _fnBrowserDetect, | |
14577 _fnAddData: _fnAddData, | |
14578 _fnAddTr: _fnAddTr, | |
14579 _fnNodeToDataIndex: _fnNodeToDataIndex, | |
14580 _fnNodeToColumnIndex: _fnNodeToColumnIndex, | |
14581 _fnGetCellData: _fnGetCellData, | |
14582 _fnSetCellData: _fnSetCellData, | |
14583 _fnSplitObjNotation: _fnSplitObjNotation, | |
14584 _fnGetObjectDataFn: _fnGetObjectDataFn, | |
14585 _fnSetObjectDataFn: _fnSetObjectDataFn, | |
14586 _fnGetDataMaster: _fnGetDataMaster, | |
14587 _fnClearTable: _fnClearTable, | |
14588 _fnDeleteIndex: _fnDeleteIndex, | |
14589 _fnInvalidate: _fnInvalidate, | |
14590 _fnGetRowElements: _fnGetRowElements, | |
14591 _fnCreateTr: _fnCreateTr, | |
14592 _fnBuildHead: _fnBuildHead, | |
14593 _fnDrawHead: _fnDrawHead, | |
14594 _fnDraw: _fnDraw, | |
14595 _fnReDraw: _fnReDraw, | |
14596 _fnAddOptionsHtml: _fnAddOptionsHtml, | |
14597 _fnDetectHeader: _fnDetectHeader, | |
14598 _fnGetUniqueThs: _fnGetUniqueThs, | |
14599 _fnFeatureHtmlFilter: _fnFeatureHtmlFilter, | |
14600 _fnFilterComplete: _fnFilterComplete, | |
14601 _fnFilterCustom: _fnFilterCustom, | |
14602 _fnFilterColumn: _fnFilterColumn, | |
14603 _fnFilter: _fnFilter, | |
14604 _fnFilterCreateSearch: _fnFilterCreateSearch, | |
14605 _fnEscapeRegex: _fnEscapeRegex, | |
14606 _fnFilterData: _fnFilterData, | |
14607 _fnFeatureHtmlInfo: _fnFeatureHtmlInfo, | |
14608 _fnUpdateInfo: _fnUpdateInfo, | |
14609 _fnInfoMacros: _fnInfoMacros, | |
14610 _fnInitialise: _fnInitialise, | |
14611 _fnInitComplete: _fnInitComplete, | |
14612 _fnLengthChange: _fnLengthChange, | |
14613 _fnFeatureHtmlLength: _fnFeatureHtmlLength, | |
14614 _fnFeatureHtmlPaginate: _fnFeatureHtmlPaginate, | |
14615 _fnPageChange: _fnPageChange, | |
14616 _fnFeatureHtmlProcessing: _fnFeatureHtmlProcessing, | |
14617 _fnProcessingDisplay: _fnProcessingDisplay, | |
14618 _fnFeatureHtmlTable: _fnFeatureHtmlTable, | |
14619 _fnScrollDraw: _fnScrollDraw, | |
14620 _fnApplyToChildren: _fnApplyToChildren, | |
14621 _fnCalculateColumnWidths: _fnCalculateColumnWidths, | |
14622 _fnThrottle: _fnThrottle, | |
14623 _fnConvertToWidth: _fnConvertToWidth, | |
14624 _fnScrollingWidthAdjust: _fnScrollingWidthAdjust, | |
14625 _fnGetWidestNode: _fnGetWidestNode, | |
14626 _fnGetMaxLenString: _fnGetMaxLenString, | |
14627 _fnStringToCss: _fnStringToCss, | |
14628 _fnScrollBarWidth: _fnScrollBarWidth, | |
14629 _fnSortFlatten: _fnSortFlatten, | |
14630 _fnSort: _fnSort, | |
14631 _fnSortAria: _fnSortAria, | |
14632 _fnSortListener: _fnSortListener, | |
14633 _fnSortAttachListener: _fnSortAttachListener, | |
14634 _fnSortingClasses: _fnSortingClasses, | |
14635 _fnSortData: _fnSortData, | |
14636 _fnSaveState: _fnSaveState, | |
14637 _fnLoadState: _fnLoadState, | |
14638 _fnSettingsFromNode: _fnSettingsFromNode, | |
14639 _fnLog: _fnLog, | |
14640 _fnMap: _fnMap, | |
14641 _fnBindAction: _fnBindAction, | |
14642 _fnCallbackReg: _fnCallbackReg, | |
14643 _fnCallbackFire: _fnCallbackFire, | |
14644 _fnLengthOverflow: _fnLengthOverflow, | |
14645 _fnRenderer: _fnRenderer, | |
14646 _fnDataSource: _fnDataSource, | |
14647 _fnRowAttributes: _fnRowAttributes, | |
14648 _fnCalculateEnd: function () {} // Used by a lot of plug-ins, but redundant | |
14649 // in 1.10, so this dead-end function is | |
14650 // added to prevent errors | |
14651 } ); | |
14652 | |
14653 | |
14654 // jQuery access | |
14655 $.fn.dataTable = DataTable; | |
14656 | |
14657 // Legacy aliases | |
14658 $.fn.dataTableSettings = DataTable.settings; | |
14659 $.fn.dataTableExt = DataTable.ext; | |
14660 | |
14661 // With a capital `D` we return a DataTables API instance rather than a | |
14662 // jQuery object | |
14663 $.fn.DataTable = function ( opts ) { | |
14664 return $(this).dataTable( opts ).api(); | |
14665 }; | |
14666 | |
14667 // All properties that are available to $.fn.dataTable should also be | |
14668 // available on $.fn.DataTable | |
14669 $.each( DataTable, function ( prop, val ) { | |
14670 $.fn.DataTable[ prop ] = val; | |
14671 } ); | |
14672 | |
14673 | |
14674 // Information about events fired by DataTables - for documentation. | |
14675 /** | |
14676 * Draw event, fired whenever the table is redrawn on the page, at the same | |
14677 * point as fnDrawCallback. This may be useful for binding events or | |
14678 * performing calculations when the table is altered at all. | |
14679 * @name DataTable#draw.dt | |
14680 * @event | |
14681 * @param {event} e jQuery event object | |
14682 * @param {object} o DataTables settings object {@link DataTable.models.oSettings} | |
14683 */ | |
14684 | |
14685 /** | |
14686 * Search event, fired when the searching applied to the table (using the | |
14687 * built-in global search, or column filters) is altered. | |
14688 * @name DataTable#search.dt | |
14689 * @event | |
14690 * @param {event} e jQuery event object | |
14691 * @param {object} o DataTables settings object {@link DataTable.models.oSettings} | |
14692 */ | |
14693 | |
14694 /** | |
14695 * Page change event, fired when the paging of the table is altered. | |
14696 * @name DataTable#page.dt | |
14697 * @event | |
14698 * @param {event} e jQuery event object | |
14699 * @param {object} o DataTables settings object {@link DataTable.models.oSettings} | |
14700 */ | |
14701 | |
14702 /** | |
14703 * Order event, fired when the ordering applied to the table is altered. | |
14704 * @name DataTable#order.dt | |
14705 * @event | |
14706 * @param {event} e jQuery event object | |
14707 * @param {object} o DataTables settings object {@link DataTable.models.oSettings} | |
14708 */ | |
14709 | |
14710 /** | |
14711 * DataTables initialisation complete event, fired when the table is fully | |
14712 * drawn, including Ajax data loaded, if Ajax data is required. | |
14713 * @name DataTable#init.dt | |
14714 * @event | |
14715 * @param {event} e jQuery event object | |
14716 * @param {object} oSettings DataTables settings object | |
14717 * @param {object} json The JSON object request from the server - only | |
14718 * present if client-side Ajax sourced data is used</li></ol> | |
14719 */ | |
14720 | |
14721 /** | |
14722 * State save event, fired when the table has changed state a new state save | |
14723 * is required. This event allows modification of the state saving object | |
14724 * prior to actually doing the save, including addition or other state | |
14725 * properties (for plug-ins) or modification of a DataTables core property. | |
14726 * @name DataTable#stateSaveParams.dt | |
14727 * @event | |
14728 * @param {event} e jQuery event object | |
14729 * @param {object} oSettings DataTables settings object | |
14730 * @param {object} json The state information to be saved | |
14731 */ | |
14732 | |
14733 /** | |
14734 * State load event, fired when the table is loading state from the stored | |
14735 * data, but prior to the settings object being modified by the saved state | |
14736 * - allowing modification of the saved state is required or loading of | |
14737 * state for a plug-in. | |
14738 * @name DataTable#stateLoadParams.dt | |
14739 * @event | |
14740 * @param {event} e jQuery event object | |
14741 * @param {object} oSettings DataTables settings object | |
14742 * @param {object} json The saved state information | |
14743 */ | |
14744 | |
14745 /** | |
14746 * State loaded event, fired when state has been loaded from stored data and | |
14747 * the settings object has been modified by the loaded data. | |
14748 * @name DataTable#stateLoaded.dt | |
14749 * @event | |
14750 * @param {event} e jQuery event object | |
14751 * @param {object} oSettings DataTables settings object | |
14752 * @param {object} json The saved state information | |
14753 */ | |
14754 | |
14755 /** | |
14756 * Processing event, fired when DataTables is doing some kind of processing | |
14757 * (be it, order, searcg or anything else). It can be used to indicate to | |
14758 * the end user that there is something happening, or that something has | |
14759 * finished. | |
14760 * @name DataTable#processing.dt | |
14761 * @event | |
14762 * @param {event} e jQuery event object | |
14763 * @param {object} oSettings DataTables settings object | |
14764 * @param {boolean} bShow Flag for if DataTables is doing processing or not | |
14765 */ | |
14766 | |
14767 /** | |
14768 * Ajax (XHR) event, fired whenever an Ajax request is completed from a | |
14769 * request to made to the server for new data. This event is called before | |
14770 * DataTables processed the returned data, so it can also be used to pre- | |
14771 * process the data returned from the server, if needed. | |
14772 * | |
14773 * Note that this trigger is called in `fnServerData`, if you override | |
14774 * `fnServerData` and which to use this event, you need to trigger it in you | |
14775 * success function. | |
14776 * @name DataTable#xhr.dt | |
14777 * @event | |
14778 * @param {event} e jQuery event object | |
14779 * @param {object} o DataTables settings object {@link DataTable.models.oSettings} | |
14780 * @param {object} json JSON returned from the server | |
14781 * | |
14782 * @example | |
14783 * // Use a custom property returned from the server in another DOM element | |
14784 * $('#table').dataTable().on('xhr.dt', function (e, settings, json) { | |
14785 * $('#status').html( json.status ); | |
14786 * } ); | |
14787 * | |
14788 * @example | |
14789 * // Pre-process the data returned from the server | |
14790 * $('#table').dataTable().on('xhr.dt', function (e, settings, json) { | |
14791 * for ( var i=0, ien=json.aaData.length ; i<ien ; i++ ) { | |
14792 * json.aaData[i].sum = json.aaData[i].one + json.aaData[i].two; | |
14793 * } | |
14794 * // Note no return - manipulate the data directly in the JSON object. | |
14795 * } ); | |
14796 */ | |
14797 | |
14798 /** | |
14799 * Destroy event, fired when the DataTable is destroyed by calling fnDestroy | |
14800 * or passing the bDestroy:true parameter in the initialisation object. This | |
14801 * can be used to remove bound events, added DOM nodes, etc. | |
14802 * @name DataTable#destroy.dt | |
14803 * @event | |
14804 * @param {event} e jQuery event object | |
14805 * @param {object} o DataTables settings object {@link DataTable.models.oSettings} | |
14806 */ | |
14807 | |
14808 /** | |
14809 * Page length change event, fired when number of records to show on each | |
14810 * page (the length) is changed. | |
14811 * @name DataTable#length.dt | |
14812 * @event | |
14813 * @param {event} e jQuery event object | |
14814 * @param {object} o DataTables settings object {@link DataTable.models.oSettings} | |
14815 * @param {integer} len New length | |
14816 */ | |
14817 | |
14818 /** | |
14819 * Column sizing has changed. | |
14820 * @name DataTable#column-sizing.dt | |
14821 * @event | |
14822 * @param {event} e jQuery event object | |
14823 * @param {object} o DataTables settings object {@link DataTable.models.oSettings} | |
14824 */ | |
14825 | |
14826 /** | |
14827 * Column visibility has changed. | |
14828 * @name DataTable#column-visibility.dt | |
14829 * @event | |
14830 * @param {event} e jQuery event object | |
14831 * @param {object} o DataTables settings object {@link DataTable.models.oSettings} | |
14832 * @param {int} column Column index | |
14833 * @param {bool} vis `false` if column now hidden, or `true` if visible | |
14834 */ | |
14835 | |
14836 return $.fn.dataTable; | |
14837 })); | |
14838 | |
14839 }(window, document)); | |
14840 |