]> git.proxmox.com Git - ceph.git/blob - ceph/src/pybind/mgr/dashboard/static/AdminLTE-2.3.7/plugins/datatables/jquery.dataTables.js
bump version to 12.2.2-pve1
[ceph.git] / ceph / src / pybind / mgr / dashboard / static / AdminLTE-2.3.7 / plugins / datatables / jquery.dataTables.js
1 /*! DataTables 1.10.7
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.7
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 module.exports = 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 // http://en.wikipedia.org/wiki/Foreign_exchange_market
115 // - \u20BD - Russian ruble.
116 // - \u20a9 - South Korean Won
117 // - \u20BA - Turkish Lira
118 // - \u20B9 - Indian Rupee
119 // - R - Brazil (R$) and South Africa
120 // - fr - Swiss Franc
121 // - kr - Swedish krona, Norwegian krone and Danish krone
122 // - \u2009 is thin space and \u202F is narrow no-break space, both used in many
123 // standards as thousands separators.
124 var _re_formatted_numeric = /[',$£€¥%\u2009\u202F\u20BD\u20a9\u20BArfk]/gi;
125
126
127 var _empty = function ( d ) {
128 return !d || d === true || d === '-' ? true : false;
129 };
130
131
132 var _intVal = function ( s ) {
133 var integer = parseInt( s, 10 );
134 return !isNaN(integer) && isFinite(s) ? integer : null;
135 };
136
137 // Convert from a formatted number with characters other than `.` as the
138 // decimal place, to a Javascript number
139 var _numToDecimal = function ( num, decimalPoint ) {
140 // Cache created regular expressions for speed as this function is called often
141 if ( ! _re_dic[ decimalPoint ] ) {
142 _re_dic[ decimalPoint ] = new RegExp( _fnEscapeRegex( decimalPoint ), 'g' );
143 }
144 return typeof num === 'string' && decimalPoint !== '.' ?
145 num.replace( /\./g, '' ).replace( _re_dic[ decimalPoint ], '.' ) :
146 num;
147 };
148
149
150 var _isNumber = function ( d, decimalPoint, formatted ) {
151 var strType = typeof d === 'string';
152
153 // If empty return immediately so there must be a number if it is a
154 // formatted string (this stops the string "k", or "kr", etc being detected
155 // as a formatted number for currency
156 if ( _empty( d ) ) {
157 return true;
158 }
159
160 if ( decimalPoint && strType ) {
161 d = _numToDecimal( d, decimalPoint );
162 }
163
164 if ( formatted && strType ) {
165 d = d.replace( _re_formatted_numeric, '' );
166 }
167
168 return !isNaN( parseFloat(d) ) && isFinite( d );
169 };
170
171
172 // A string without HTML in it can be considered to be HTML still
173 var _isHtml = function ( d ) {
174 return _empty( d ) || typeof d === 'string';
175 };
176
177
178 var _htmlNumeric = function ( d, decimalPoint, formatted ) {
179 if ( _empty( d ) ) {
180 return true;
181 }
182
183 var html = _isHtml( d );
184 return ! html ?
185 null :
186 _isNumber( _stripHtml( d ), decimalPoint, formatted ) ?
187 true :
188 null;
189 };
190
191
192 var _pluck = function ( a, prop, prop2 ) {
193 var out = [];
194 var i=0, ien=a.length;
195
196 // Could have the test in the loop for slightly smaller code, but speed
197 // is essential here
198 if ( prop2 !== undefined ) {
199 for ( ; i<ien ; i++ ) {
200 if ( a[i] && a[i][ prop ] ) {
201 out.push( a[i][ prop ][ prop2 ] );
202 }
203 }
204 }
205 else {
206 for ( ; i<ien ; i++ ) {
207 if ( a[i] ) {
208 out.push( a[i][ prop ] );
209 }
210 }
211 }
212
213 return out;
214 };
215
216
217 // Basically the same as _pluck, but rather than looping over `a` we use `order`
218 // as the indexes to pick from `a`
219 var _pluck_order = function ( a, order, prop, prop2 )
220 {
221 var out = [];
222 var i=0, ien=order.length;
223
224 // Could have the test in the loop for slightly smaller code, but speed
225 // is essential here
226 if ( prop2 !== undefined ) {
227 for ( ; i<ien ; i++ ) {
228 if ( a[ order[i] ][ prop ] ) {
229 out.push( a[ order[i] ][ prop ][ prop2 ] );
230 }
231 }
232 }
233 else {
234 for ( ; i<ien ; i++ ) {
235 out.push( a[ order[i] ][ prop ] );
236 }
237 }
238
239 return out;
240 };
241
242
243 var _range = function ( len, start )
244 {
245 var out = [];
246 var end;
247
248 if ( start === undefined ) {
249 start = 0;
250 end = len;
251 }
252 else {
253 end = start;
254 start = len;
255 }
256
257 for ( var i=start ; i<end ; i++ ) {
258 out.push( i );
259 }
260
261 return out;
262 };
263
264
265 var _removeEmpty = function ( a )
266 {
267 var out = [];
268
269 for ( var i=0, ien=a.length ; i<ien ; i++ ) {
270 if ( a[i] ) { // careful - will remove all falsy values!
271 out.push( a[i] );
272 }
273 }
274
275 return out;
276 };
277
278
279 var _stripHtml = function ( d ) {
280 return d.replace( _re_html, '' );
281 };
282
283
284 /**
285 * Find the unique elements in a source array.
286 *
287 * @param {array} src Source array
288 * @return {array} Array of unique items
289 * @ignore
290 */
291 var _unique = function ( src )
292 {
293 // A faster unique method is to use object keys to identify used values,
294 // but this doesn't work with arrays or objects, which we must also
295 // consider. See jsperf.com/compare-array-unique-versions/4 for more
296 // information.
297 var
298 out = [],
299 val,
300 i, ien=src.length,
301 j, k=0;
302
303 again: for ( i=0 ; i<ien ; i++ ) {
304 val = src[i];
305
306 for ( j=0 ; j<k ; j++ ) {
307 if ( out[j] === val ) {
308 continue again;
309 }
310 }
311
312 out.push( val );
313 k++;
314 }
315
316 return out;
317 };
318
319
320
321 /**
322 * Create a mapping object that allows camel case parameters to be looked up
323 * for their Hungarian counterparts. The mapping is stored in a private
324 * parameter called `_hungarianMap` which can be accessed on the source object.
325 * @param {object} o
326 * @memberof DataTable#oApi
327 */
328 function _fnHungarianMap ( o )
329 {
330 var
331 hungarian = 'a aa ai ao as b fn i m o s ',
332 match,
333 newKey,
334 map = {};
335
336 $.each( o, function (key, val) {
337 match = key.match(/^([^A-Z]+?)([A-Z])/);
338
339 if ( match && hungarian.indexOf(match[1]+' ') !== -1 )
340 {
341 newKey = key.replace( match[0], match[2].toLowerCase() );
342 map[ newKey ] = key;
343
344 if ( match[1] === 'o' )
345 {
346 _fnHungarianMap( o[key] );
347 }
348 }
349 } );
350
351 o._hungarianMap = map;
352 }
353
354
355 /**
356 * Convert from camel case parameters to Hungarian, based on a Hungarian map
357 * created by _fnHungarianMap.
358 * @param {object} src The model object which holds all parameters that can be
359 * mapped.
360 * @param {object} user The object to convert from camel case to Hungarian.
361 * @param {boolean} force When set to `true`, properties which already have a
362 * Hungarian value in the `user` object will be overwritten. Otherwise they
363 * won't be.
364 * @memberof DataTable#oApi
365 */
366 function _fnCamelToHungarian ( src, user, force )
367 {
368 if ( ! src._hungarianMap ) {
369 _fnHungarianMap( src );
370 }
371
372 var hungarianKey;
373
374 $.each( user, function (key, val) {
375 hungarianKey = src._hungarianMap[ key ];
376
377 if ( hungarianKey !== undefined && (force || user[hungarianKey] === undefined) )
378 {
379 // For objects, we need to buzz down into the object to copy parameters
380 if ( hungarianKey.charAt(0) === 'o' )
381 {
382 // Copy the camelCase options over to the hungarian
383 if ( ! user[ hungarianKey ] ) {
384 user[ hungarianKey ] = {};
385 }
386 $.extend( true, user[hungarianKey], user[key] );
387
388 _fnCamelToHungarian( src[hungarianKey], user[hungarianKey], force );
389 }
390 else {
391 user[hungarianKey] = user[ key ];
392 }
393 }
394 } );
395 }
396
397
398 /**
399 * Language compatibility - when certain options are given, and others aren't, we
400 * need to duplicate the values over, in order to provide backwards compatibility
401 * with older language files.
402 * @param {object} oSettings dataTables settings object
403 * @memberof DataTable#oApi
404 */
405 function _fnLanguageCompat( lang )
406 {
407 var defaults = DataTable.defaults.oLanguage;
408 var zeroRecords = lang.sZeroRecords;
409
410 /* Backwards compatibility - if there is no sEmptyTable given, then use the same as
411 * sZeroRecords - assuming that is given.
412 */
413 if ( ! lang.sEmptyTable && zeroRecords &&
414 defaults.sEmptyTable === "No data available in table" )
415 {
416 _fnMap( lang, lang, 'sZeroRecords', 'sEmptyTable' );
417 }
418
419 /* Likewise with loading records */
420 if ( ! lang.sLoadingRecords && zeroRecords &&
421 defaults.sLoadingRecords === "Loading..." )
422 {
423 _fnMap( lang, lang, 'sZeroRecords', 'sLoadingRecords' );
424 }
425
426 // Old parameter name of the thousands separator mapped onto the new
427 if ( lang.sInfoThousands ) {
428 lang.sThousands = lang.sInfoThousands;
429 }
430
431 var decimal = lang.sDecimal;
432 if ( decimal ) {
433 _addNumericSort( decimal );
434 }
435 }
436
437
438 /**
439 * Map one parameter onto another
440 * @param {object} o Object to map
441 * @param {*} knew The new parameter name
442 * @param {*} old The old parameter name
443 */
444 var _fnCompatMap = function ( o, knew, old ) {
445 if ( o[ knew ] !== undefined ) {
446 o[ old ] = o[ knew ];
447 }
448 };
449
450
451 /**
452 * Provide backwards compatibility for the main DT options. Note that the new
453 * options are mapped onto the old parameters, so this is an external interface
454 * change only.
455 * @param {object} init Object to map
456 */
457 function _fnCompatOpts ( init )
458 {
459 _fnCompatMap( init, 'ordering', 'bSort' );
460 _fnCompatMap( init, 'orderMulti', 'bSortMulti' );
461 _fnCompatMap( init, 'orderClasses', 'bSortClasses' );
462 _fnCompatMap( init, 'orderCellsTop', 'bSortCellsTop' );
463 _fnCompatMap( init, 'order', 'aaSorting' );
464 _fnCompatMap( init, 'orderFixed', 'aaSortingFixed' );
465 _fnCompatMap( init, 'paging', 'bPaginate' );
466 _fnCompatMap( init, 'pagingType', 'sPaginationType' );
467 _fnCompatMap( init, 'pageLength', 'iDisplayLength' );
468 _fnCompatMap( init, 'searching', 'bFilter' );
469
470 // Column search objects are in an array, so it needs to be converted
471 // element by element
472 var searchCols = init.aoSearchCols;
473
474 if ( searchCols ) {
475 for ( var i=0, ien=searchCols.length ; i<ien ; i++ ) {
476 if ( searchCols[i] ) {
477 _fnCamelToHungarian( DataTable.models.oSearch, searchCols[i] );
478 }
479 }
480 }
481 }
482
483
484 /**
485 * Provide backwards compatibility for column options. Note that the new options
486 * are mapped onto the old parameters, so this is an external interface change
487 * only.
488 * @param {object} init Object to map
489 */
490 function _fnCompatCols ( init )
491 {
492 _fnCompatMap( init, 'orderable', 'bSortable' );
493 _fnCompatMap( init, 'orderData', 'aDataSort' );
494 _fnCompatMap( init, 'orderSequence', 'asSorting' );
495 _fnCompatMap( init, 'orderDataType', 'sortDataType' );
496
497 // orderData can be given as an integer
498 var dataSort = init.aDataSort;
499 if ( dataSort && ! $.isArray( dataSort ) ) {
500 init.aDataSort = [ dataSort ];
501 }
502 }
503
504
505 /**
506 * Browser feature detection for capabilities, quirks
507 * @param {object} settings dataTables settings object
508 * @memberof DataTable#oApi
509 */
510 function _fnBrowserDetect( settings )
511 {
512 var browser = settings.oBrowser;
513
514 // Scrolling feature / quirks detection
515 var n = $('<div/>')
516 .css( {
517 position: 'absolute',
518 top: 0,
519 left: 0,
520 height: 1,
521 width: 1,
522 overflow: 'hidden'
523 } )
524 .append(
525 $('<div/>')
526 .css( {
527 position: 'absolute',
528 top: 1,
529 left: 1,
530 width: 100,
531 overflow: 'scroll'
532 } )
533 .append(
534 $('<div class="test"/>')
535 .css( {
536 width: '100%',
537 height: 10
538 } )
539 )
540 )
541 .appendTo( 'body' );
542
543 var test = n.find('.test');
544
545 // IE6/7 will oversize a width 100% element inside a scrolling element, to
546 // include the width of the scrollbar, while other browsers ensure the inner
547 // element is contained without forcing scrolling
548 browser.bScrollOversize = test[0].offsetWidth === 100;
549
550 // In rtl text layout, some browsers (most, but not all) will place the
551 // scrollbar on the left, rather than the right.
552 browser.bScrollbarLeft = Math.round( test.offset().left ) !== 1;
553
554 n.remove();
555 }
556
557
558 /**
559 * Array.prototype reduce[Right] method, used for browsers which don't support
560 * JS 1.6. Done this way to reduce code size, since we iterate either way
561 * @param {object} settings dataTables settings object
562 * @memberof DataTable#oApi
563 */
564 function _fnReduce ( that, fn, init, start, end, inc )
565 {
566 var
567 i = start,
568 value,
569 isSet = false;
570
571 if ( init !== undefined ) {
572 value = init;
573 isSet = true;
574 }
575
576 while ( i !== end ) {
577 if ( ! that.hasOwnProperty(i) ) {
578 continue;
579 }
580
581 value = isSet ?
582 fn( value, that[i], i, that ) :
583 that[i];
584
585 isSet = true;
586 i += inc;
587 }
588
589 return value;
590 }
591
592 /**
593 * Add a column to the list used for the table with default values
594 * @param {object} oSettings dataTables settings object
595 * @param {node} nTh The th element for this column
596 * @memberof DataTable#oApi
597 */
598 function _fnAddColumn( oSettings, nTh )
599 {
600 // Add column to aoColumns array
601 var oDefaults = DataTable.defaults.column;
602 var iCol = oSettings.aoColumns.length;
603 var oCol = $.extend( {}, DataTable.models.oColumn, oDefaults, {
604 "nTh": nTh ? nTh : document.createElement('th'),
605 "sTitle": oDefaults.sTitle ? oDefaults.sTitle : nTh ? nTh.innerHTML : '',
606 "aDataSort": oDefaults.aDataSort ? oDefaults.aDataSort : [iCol],
607 "mData": oDefaults.mData ? oDefaults.mData : iCol,
608 idx: iCol
609 } );
610 oSettings.aoColumns.push( oCol );
611
612 // Add search object for column specific search. Note that the `searchCols[ iCol ]`
613 // passed into extend can be undefined. This allows the user to give a default
614 // with only some of the parameters defined, and also not give a default
615 var searchCols = oSettings.aoPreSearchCols;
616 searchCols[ iCol ] = $.extend( {}, DataTable.models.oSearch, searchCols[ iCol ] );
617
618 // Use the default column options function to initialise classes etc
619 _fnColumnOptions( oSettings, iCol, $(nTh).data() );
620 }
621
622
623 /**
624 * Apply options for a column
625 * @param {object} oSettings dataTables settings object
626 * @param {int} iCol column index to consider
627 * @param {object} oOptions object with sType, bVisible and bSearchable etc
628 * @memberof DataTable#oApi
629 */
630 function _fnColumnOptions( oSettings, iCol, oOptions )
631 {
632 var oCol = oSettings.aoColumns[ iCol ];
633 var oClasses = oSettings.oClasses;
634 var th = $(oCol.nTh);
635
636 // Try to get width information from the DOM. We can't get it from CSS
637 // as we'd need to parse the CSS stylesheet. `width` option can override
638 if ( ! oCol.sWidthOrig ) {
639 // Width attribute
640 oCol.sWidthOrig = th.attr('width') || null;
641
642 // Style attribute
643 var t = (th.attr('style') || '').match(/width:\s*(\d+[pxem%]+)/);
644 if ( t ) {
645 oCol.sWidthOrig = t[1];
646 }
647 }
648
649 /* User specified column options */
650 if ( oOptions !== undefined && oOptions !== null )
651 {
652 // Backwards compatibility
653 _fnCompatCols( oOptions );
654
655 // Map camel case parameters to their Hungarian counterparts
656 _fnCamelToHungarian( DataTable.defaults.column, oOptions );
657
658 /* Backwards compatibility for mDataProp */
659 if ( oOptions.mDataProp !== undefined && !oOptions.mData )
660 {
661 oOptions.mData = oOptions.mDataProp;
662 }
663
664 if ( oOptions.sType )
665 {
666 oCol._sManualType = oOptions.sType;
667 }
668
669 // `class` is a reserved word in Javascript, so we need to provide
670 // the ability to use a valid name for the camel case input
671 if ( oOptions.className && ! oOptions.sClass )
672 {
673 oOptions.sClass = oOptions.className;
674 }
675
676 $.extend( oCol, oOptions );
677 _fnMap( oCol, oOptions, "sWidth", "sWidthOrig" );
678
679 /* iDataSort to be applied (backwards compatibility), but aDataSort will take
680 * priority if defined
681 */
682 if ( oOptions.iDataSort !== undefined )
683 {
684 oCol.aDataSort = [ oOptions.iDataSort ];
685 }
686 _fnMap( oCol, oOptions, "aDataSort" );
687 }
688
689 /* Cache the data get and set functions for speed */
690 var mDataSrc = oCol.mData;
691 var mData = _fnGetObjectDataFn( mDataSrc );
692 var mRender = oCol.mRender ? _fnGetObjectDataFn( oCol.mRender ) : null;
693
694 var attrTest = function( src ) {
695 return typeof src === 'string' && src.indexOf('@') !== -1;
696 };
697 oCol._bAttrSrc = $.isPlainObject( mDataSrc ) && (
698 attrTest(mDataSrc.sort) || attrTest(mDataSrc.type) || attrTest(mDataSrc.filter)
699 );
700
701 oCol.fnGetData = function (rowData, type, meta) {
702 var innerData = mData( rowData, type, undefined, meta );
703
704 return mRender && type ?
705 mRender( innerData, type, rowData, meta ) :
706 innerData;
707 };
708 oCol.fnSetData = function ( rowData, val, meta ) {
709 return _fnSetObjectDataFn( mDataSrc )( rowData, val, meta );
710 };
711
712 // Indicate if DataTables should read DOM data as an object or array
713 // Used in _fnGetRowElements
714 if ( typeof mDataSrc !== 'number' ) {
715 oSettings._rowReadObject = true;
716 }
717
718 /* Feature sorting overrides column specific when off */
719 if ( !oSettings.oFeatures.bSort )
720 {
721 oCol.bSortable = false;
722 th.addClass( oClasses.sSortableNone ); // Have to add class here as order event isn't called
723 }
724
725 /* Check that the class assignment is correct for sorting */
726 var bAsc = $.inArray('asc', oCol.asSorting) !== -1;
727 var bDesc = $.inArray('desc', oCol.asSorting) !== -1;
728 if ( !oCol.bSortable || (!bAsc && !bDesc) )
729 {
730 oCol.sSortingClass = oClasses.sSortableNone;
731 oCol.sSortingClassJUI = "";
732 }
733 else if ( bAsc && !bDesc )
734 {
735 oCol.sSortingClass = oClasses.sSortableAsc;
736 oCol.sSortingClassJUI = oClasses.sSortJUIAscAllowed;
737 }
738 else if ( !bAsc && bDesc )
739 {
740 oCol.sSortingClass = oClasses.sSortableDesc;
741 oCol.sSortingClassJUI = oClasses.sSortJUIDescAllowed;
742 }
743 else
744 {
745 oCol.sSortingClass = oClasses.sSortable;
746 oCol.sSortingClassJUI = oClasses.sSortJUI;
747 }
748 }
749
750
751 /**
752 * Adjust the table column widths for new data. Note: you would probably want to
753 * do a redraw after calling this function!
754 * @param {object} settings dataTables settings object
755 * @memberof DataTable#oApi
756 */
757 function _fnAdjustColumnSizing ( settings )
758 {
759 /* Not interested in doing column width calculation if auto-width is disabled */
760 if ( settings.oFeatures.bAutoWidth !== false )
761 {
762 var columns = settings.aoColumns;
763
764 _fnCalculateColumnWidths( settings );
765 for ( var i=0 , iLen=columns.length ; i<iLen ; i++ )
766 {
767 columns[i].nTh.style.width = columns[i].sWidth;
768 }
769 }
770
771 var scroll = settings.oScroll;
772 if ( scroll.sY !== '' || scroll.sX !== '')
773 {
774 _fnScrollDraw( settings );
775 }
776
777 _fnCallbackFire( settings, null, 'column-sizing', [settings] );
778 }
779
780
781 /**
782 * Covert the index of a visible column to the index in the data array (take account
783 * of hidden columns)
784 * @param {object} oSettings dataTables settings object
785 * @param {int} iMatch Visible column index to lookup
786 * @returns {int} i the data index
787 * @memberof DataTable#oApi
788 */
789 function _fnVisibleToColumnIndex( oSettings, iMatch )
790 {
791 var aiVis = _fnGetColumns( oSettings, 'bVisible' );
792
793 return typeof aiVis[iMatch] === 'number' ?
794 aiVis[iMatch] :
795 null;
796 }
797
798
799 /**
800 * Covert the index of an index in the data array and convert it to the visible
801 * column index (take account of hidden columns)
802 * @param {int} iMatch Column index to lookup
803 * @param {object} oSettings dataTables settings object
804 * @returns {int} i the data index
805 * @memberof DataTable#oApi
806 */
807 function _fnColumnIndexToVisible( oSettings, iMatch )
808 {
809 var aiVis = _fnGetColumns( oSettings, 'bVisible' );
810 var iPos = $.inArray( iMatch, aiVis );
811
812 return iPos !== -1 ? iPos : null;
813 }
814
815
816 /**
817 * Get the number of visible columns
818 * @param {object} oSettings dataTables settings object
819 * @returns {int} i the number of visible columns
820 * @memberof DataTable#oApi
821 */
822 function _fnVisbleColumns( oSettings )
823 {
824 return _fnGetColumns( oSettings, 'bVisible' ).length;
825 }
826
827
828 /**
829 * Get an array of column indexes that match a given property
830 * @param {object} oSettings dataTables settings object
831 * @param {string} sParam Parameter in aoColumns to look for - typically
832 * bVisible or bSearchable
833 * @returns {array} Array of indexes with matched properties
834 * @memberof DataTable#oApi
835 */
836 function _fnGetColumns( oSettings, sParam )
837 {
838 var a = [];
839
840 $.map( oSettings.aoColumns, function(val, i) {
841 if ( val[sParam] ) {
842 a.push( i );
843 }
844 } );
845
846 return a;
847 }
848
849
850 /**
851 * Calculate the 'type' of a column
852 * @param {object} settings dataTables settings object
853 * @memberof DataTable#oApi
854 */
855 function _fnColumnTypes ( settings )
856 {
857 var columns = settings.aoColumns;
858 var data = settings.aoData;
859 var types = DataTable.ext.type.detect;
860 var i, ien, j, jen, k, ken;
861 var col, cell, detectedType, cache;
862
863 // For each column, spin over the
864 for ( i=0, ien=columns.length ; i<ien ; i++ ) {
865 col = columns[i];
866 cache = [];
867
868 if ( ! col.sType && col._sManualType ) {
869 col.sType = col._sManualType;
870 }
871 else if ( ! col.sType ) {
872 for ( j=0, jen=types.length ; j<jen ; j++ ) {
873 for ( k=0, ken=data.length ; k<ken ; k++ ) {
874 // Use a cache array so we only need to get the type data
875 // from the formatter once (when using multiple detectors)
876 if ( cache[k] === undefined ) {
877 cache[k] = _fnGetCellData( settings, k, i, 'type' );
878 }
879
880 detectedType = types[j]( cache[k], settings );
881
882 // If null, then this type can't apply to this column, so
883 // rather than testing all cells, break out. There is an
884 // exception for the last type which is `html`. We need to
885 // scan all rows since it is possible to mix string and HTML
886 // types
887 if ( ! detectedType && j !== types.length-1 ) {
888 break;
889 }
890
891 // Only a single match is needed for html type since it is
892 // bottom of the pile and very similar to string
893 if ( detectedType === 'html' ) {
894 break;
895 }
896 }
897
898 // Type is valid for all data points in the column - use this
899 // type
900 if ( detectedType ) {
901 col.sType = detectedType;
902 break;
903 }
904 }
905
906 // Fall back - if no type was detected, always use string
907 if ( ! col.sType ) {
908 col.sType = 'string';
909 }
910 }
911 }
912 }
913
914
915 /**
916 * Take the column definitions and static columns arrays and calculate how
917 * they relate to column indexes. The callback function will then apply the
918 * definition found for a column to a suitable configuration object.
919 * @param {object} oSettings dataTables settings object
920 * @param {array} aoColDefs The aoColumnDefs array that is to be applied
921 * @param {array} aoCols The aoColumns array that defines columns individually
922 * @param {function} fn Callback function - takes two parameters, the calculated
923 * column index and the definition for that column.
924 * @memberof DataTable#oApi
925 */
926 function _fnApplyColumnDefs( oSettings, aoColDefs, aoCols, fn )
927 {
928 var i, iLen, j, jLen, k, kLen, def;
929 var columns = oSettings.aoColumns;
930
931 // Column definitions with aTargets
932 if ( aoColDefs )
933 {
934 /* Loop over the definitions array - loop in reverse so first instance has priority */
935 for ( i=aoColDefs.length-1 ; i>=0 ; i-- )
936 {
937 def = aoColDefs[i];
938
939 /* Each definition can target multiple columns, as it is an array */
940 var aTargets = def.targets !== undefined ?
941 def.targets :
942 def.aTargets;
943
944 if ( ! $.isArray( aTargets ) )
945 {
946 aTargets = [ aTargets ];
947 }
948
949 for ( j=0, jLen=aTargets.length ; j<jLen ; j++ )
950 {
951 if ( typeof aTargets[j] === 'number' && aTargets[j] >= 0 )
952 {
953 /* Add columns that we don't yet know about */
954 while( columns.length <= aTargets[j] )
955 {
956 _fnAddColumn( oSettings );
957 }
958
959 /* Integer, basic index */
960 fn( aTargets[j], def );
961 }
962 else if ( typeof aTargets[j] === 'number' && aTargets[j] < 0 )
963 {
964 /* Negative integer, right to left column counting */
965 fn( columns.length+aTargets[j], def );
966 }
967 else if ( typeof aTargets[j] === 'string' )
968 {
969 /* Class name matching on TH element */
970 for ( k=0, kLen=columns.length ; k<kLen ; k++ )
971 {
972 if ( aTargets[j] == "_all" ||
973 $(columns[k].nTh).hasClass( aTargets[j] ) )
974 {
975 fn( k, def );
976 }
977 }
978 }
979 }
980 }
981 }
982
983 // Statically defined columns array
984 if ( aoCols )
985 {
986 for ( i=0, iLen=aoCols.length ; i<iLen ; i++ )
987 {
988 fn( i, aoCols[i] );
989 }
990 }
991 }
992
993 /**
994 * Add a data array to the table, creating DOM node etc. This is the parallel to
995 * _fnGatherData, but for adding rows from a Javascript source, rather than a
996 * DOM source.
997 * @param {object} oSettings dataTables settings object
998 * @param {array} aData data array to be added
999 * @param {node} [nTr] TR element to add to the table - optional. If not given,
1000 * DataTables will create a row automatically
1001 * @param {array} [anTds] Array of TD|TH elements for the row - must be given
1002 * if nTr is.
1003 * @returns {int} >=0 if successful (index of new aoData entry), -1 if failed
1004 * @memberof DataTable#oApi
1005 */
1006 function _fnAddData ( oSettings, aDataIn, nTr, anTds )
1007 {
1008 /* Create the object for storing information about this new row */
1009 var iRow = oSettings.aoData.length;
1010 var oData = $.extend( true, {}, DataTable.models.oRow, {
1011 src: nTr ? 'dom' : 'data'
1012 } );
1013
1014 oData._aData = aDataIn;
1015 oSettings.aoData.push( oData );
1016
1017 /* Create the cells */
1018 var nTd, sThisType;
1019 var columns = oSettings.aoColumns;
1020 for ( var i=0, iLen=columns.length ; i<iLen ; i++ )
1021 {
1022 // When working with a row, the data source object must be populated. In
1023 // all other cases, the data source object is already populated, so we
1024 // don't overwrite it, which might break bindings etc
1025 if ( nTr ) {
1026 _fnSetCellData( oSettings, iRow, i, _fnGetCellData( oSettings, iRow, i ) );
1027 }
1028 columns[i].sType = null;
1029 }
1030
1031 /* Add to the display array */
1032 oSettings.aiDisplayMaster.push( iRow );
1033
1034 /* Create the DOM information, or register it if already present */
1035 if ( nTr || ! oSettings.oFeatures.bDeferRender )
1036 {
1037 _fnCreateTr( oSettings, iRow, nTr, anTds );
1038 }
1039
1040 return iRow;
1041 }
1042
1043
1044 /**
1045 * Add one or more TR elements to the table. Generally we'd expect to
1046 * use this for reading data from a DOM sourced table, but it could be
1047 * used for an TR element. Note that if a TR is given, it is used (i.e.
1048 * it is not cloned).
1049 * @param {object} settings dataTables settings object
1050 * @param {array|node|jQuery} trs The TR element(s) to add to the table
1051 * @returns {array} Array of indexes for the added rows
1052 * @memberof DataTable#oApi
1053 */
1054 function _fnAddTr( settings, trs )
1055 {
1056 var row;
1057
1058 // Allow an individual node to be passed in
1059 if ( ! (trs instanceof $) ) {
1060 trs = $(trs);
1061 }
1062
1063 return trs.map( function (i, el) {
1064 row = _fnGetRowElements( settings, el );
1065 return _fnAddData( settings, row.data, el, row.cells );
1066 } );
1067 }
1068
1069
1070 /**
1071 * Take a TR element and convert it to an index in aoData
1072 * @param {object} oSettings dataTables settings object
1073 * @param {node} n the TR element to find
1074 * @returns {int} index if the node is found, null if not
1075 * @memberof DataTable#oApi
1076 */
1077 function _fnNodeToDataIndex( oSettings, n )
1078 {
1079 return (n._DT_RowIndex!==undefined) ? n._DT_RowIndex : null;
1080 }
1081
1082
1083 /**
1084 * Take a TD element and convert it into a column data index (not the visible index)
1085 * @param {object} oSettings dataTables settings object
1086 * @param {int} iRow The row number the TD/TH can be found in
1087 * @param {node} n The TD/TH element to find
1088 * @returns {int} index if the node is found, -1 if not
1089 * @memberof DataTable#oApi
1090 */
1091 function _fnNodeToColumnIndex( oSettings, iRow, n )
1092 {
1093 return $.inArray( n, oSettings.aoData[ iRow ].anCells );
1094 }
1095
1096
1097 /**
1098 * Get the data for a given cell from the internal cache, taking into account data mapping
1099 * @param {object} settings dataTables settings object
1100 * @param {int} rowIdx aoData row id
1101 * @param {int} colIdx Column index
1102 * @param {string} type data get type ('display', 'type' 'filter' 'sort')
1103 * @returns {*} Cell data
1104 * @memberof DataTable#oApi
1105 */
1106 function _fnGetCellData( settings, rowIdx, colIdx, type )
1107 {
1108 var draw = settings.iDraw;
1109 var col = settings.aoColumns[colIdx];
1110 var rowData = settings.aoData[rowIdx]._aData;
1111 var defaultContent = col.sDefaultContent;
1112 var cellData = col.fnGetData( rowData, type, {
1113 settings: settings,
1114 row: rowIdx,
1115 col: colIdx
1116 } );
1117
1118 if ( cellData === undefined ) {
1119 if ( settings.iDrawError != draw && defaultContent === null ) {
1120 _fnLog( settings, 0, "Requested unknown parameter "+
1121 (typeof col.mData=='function' ? '{function}' : "'"+col.mData+"'")+
1122 " for row "+rowIdx, 4 );
1123 settings.iDrawError = draw;
1124 }
1125 return defaultContent;
1126 }
1127
1128 /* When the data source is null, we can use default column data */
1129 if ( (cellData === rowData || cellData === null) && defaultContent !== null ) {
1130 cellData = defaultContent;
1131 }
1132 else if ( typeof cellData === 'function' ) {
1133 // If the data source is a function, then we run it and use the return,
1134 // executing in the scope of the data object (for instances)
1135 return cellData.call( rowData );
1136 }
1137
1138 if ( cellData === null && type == 'display' ) {
1139 return '';
1140 }
1141 return cellData;
1142 }
1143
1144
1145 /**
1146 * Set the value for a specific cell, into the internal data cache
1147 * @param {object} settings dataTables settings object
1148 * @param {int} rowIdx aoData row id
1149 * @param {int} colIdx Column index
1150 * @param {*} val Value to set
1151 * @memberof DataTable#oApi
1152 */
1153 function _fnSetCellData( settings, rowIdx, colIdx, val )
1154 {
1155 var col = settings.aoColumns[colIdx];
1156 var rowData = settings.aoData[rowIdx]._aData;
1157
1158 col.fnSetData( rowData, val, {
1159 settings: settings,
1160 row: rowIdx,
1161 col: colIdx
1162 } );
1163 }
1164
1165
1166 // Private variable that is used to match action syntax in the data property object
1167 var __reArray = /\[.*?\]$/;
1168 var __reFn = /\(\)$/;
1169
1170 /**
1171 * Split string on periods, taking into account escaped periods
1172 * @param {string} str String to split
1173 * @return {array} Split string
1174 */
1175 function _fnSplitObjNotation( str )
1176 {
1177 return $.map( str.match(/(\\.|[^\.])+/g), function ( s ) {
1178 return s.replace(/\\./g, '.');
1179 } );
1180 }
1181
1182
1183 /**
1184 * Return a function that can be used to get data from a source object, taking
1185 * into account the ability to use nested objects as a source
1186 * @param {string|int|function} mSource The data source for the object
1187 * @returns {function} Data get function
1188 * @memberof DataTable#oApi
1189 */
1190 function _fnGetObjectDataFn( mSource )
1191 {
1192 if ( $.isPlainObject( mSource ) )
1193 {
1194 /* Build an object of get functions, and wrap them in a single call */
1195 var o = {};
1196 $.each( mSource, function (key, val) {
1197 if ( val ) {
1198 o[key] = _fnGetObjectDataFn( val );
1199 }
1200 } );
1201
1202 return function (data, type, row, meta) {
1203 var t = o[type] || o._;
1204 return t !== undefined ?
1205 t(data, type, row, meta) :
1206 data;
1207 };
1208 }
1209 else if ( mSource === null )
1210 {
1211 /* Give an empty string for rendering / sorting etc */
1212 return function (data) { // type, row and meta also passed, but not used
1213 return data;
1214 };
1215 }
1216 else if ( typeof mSource === 'function' )
1217 {
1218 return function (data, type, row, meta) {
1219 return mSource( data, type, row, meta );
1220 };
1221 }
1222 else if ( typeof mSource === 'string' && (mSource.indexOf('.') !== -1 ||
1223 mSource.indexOf('[') !== -1 || mSource.indexOf('(') !== -1) )
1224 {
1225 /* If there is a . in the source string then the data source is in a
1226 * nested object so we loop over the data for each level to get the next
1227 * level down. On each loop we test for undefined, and if found immediately
1228 * return. This allows entire objects to be missing and sDefaultContent to
1229 * be used if defined, rather than throwing an error
1230 */
1231 var fetchData = function (data, type, src) {
1232 var arrayNotation, funcNotation, out, innerSrc;
1233
1234 if ( src !== "" )
1235 {
1236 var a = _fnSplitObjNotation( src );
1237
1238 for ( var i=0, iLen=a.length ; i<iLen ; i++ )
1239 {
1240 // Check if we are dealing with special notation
1241 arrayNotation = a[i].match(__reArray);
1242 funcNotation = a[i].match(__reFn);
1243
1244 if ( arrayNotation )
1245 {
1246 // Array notation
1247 a[i] = a[i].replace(__reArray, '');
1248
1249 // Condition allows simply [] to be passed in
1250 if ( a[i] !== "" ) {
1251 data = data[ a[i] ];
1252 }
1253 out = [];
1254
1255 // Get the remainder of the nested object to get
1256 a.splice( 0, i+1 );
1257 innerSrc = a.join('.');
1258
1259 // Traverse each entry in the array getting the properties requested
1260 for ( var j=0, jLen=data.length ; j<jLen ; j++ ) {
1261 out.push( fetchData( data[j], type, innerSrc ) );
1262 }
1263
1264 // If a string is given in between the array notation indicators, that
1265 // is used to join the strings together, otherwise an array is returned
1266 var join = arrayNotation[0].substring(1, arrayNotation[0].length-1);
1267 data = (join==="") ? out : out.join(join);
1268
1269 // The inner call to fetchData has already traversed through the remainder
1270 // of the source requested, so we exit from the loop
1271 break;
1272 }
1273 else if ( funcNotation )
1274 {
1275 // Function call
1276 a[i] = a[i].replace(__reFn, '');
1277 data = data[ a[i] ]();
1278 continue;
1279 }
1280
1281 if ( data === null || data[ a[i] ] === undefined )
1282 {
1283 return undefined;
1284 }
1285 data = data[ a[i] ];
1286 }
1287 }
1288
1289 return data;
1290 };
1291
1292 return function (data, type) { // row and meta also passed, but not used
1293 return fetchData( data, type, mSource );
1294 };
1295 }
1296 else
1297 {
1298 /* Array or flat object mapping */
1299 return function (data, type) { // row and meta also passed, but not used
1300 return data[mSource];
1301 };
1302 }
1303 }
1304
1305
1306 /**
1307 * Return a function that can be used to set data from a source object, taking
1308 * into account the ability to use nested objects as a source
1309 * @param {string|int|function} mSource The data source for the object
1310 * @returns {function} Data set function
1311 * @memberof DataTable#oApi
1312 */
1313 function _fnSetObjectDataFn( mSource )
1314 {
1315 if ( $.isPlainObject( mSource ) )
1316 {
1317 /* Unlike get, only the underscore (global) option is used for for
1318 * setting data since we don't know the type here. This is why an object
1319 * option is not documented for `mData` (which is read/write), but it is
1320 * for `mRender` which is read only.
1321 */
1322 return _fnSetObjectDataFn( mSource._ );
1323 }
1324 else if ( mSource === null )
1325 {
1326 /* Nothing to do when the data source is null */
1327 return function () {};
1328 }
1329 else if ( typeof mSource === 'function' )
1330 {
1331 return function (data, val, meta) {
1332 mSource( data, 'set', val, meta );
1333 };
1334 }
1335 else if ( typeof mSource === 'string' && (mSource.indexOf('.') !== -1 ||
1336 mSource.indexOf('[') !== -1 || mSource.indexOf('(') !== -1) )
1337 {
1338 /* Like the get, we need to get data from a nested object */
1339 var setData = function (data, val, src) {
1340 var a = _fnSplitObjNotation( src ), b;
1341 var aLast = a[a.length-1];
1342 var arrayNotation, funcNotation, o, innerSrc;
1343
1344 for ( var i=0, iLen=a.length-1 ; i<iLen ; i++ )
1345 {
1346 // Check if we are dealing with an array notation request
1347 arrayNotation = a[i].match(__reArray);
1348 funcNotation = a[i].match(__reFn);
1349
1350 if ( arrayNotation )
1351 {
1352 a[i] = a[i].replace(__reArray, '');
1353 data[ a[i] ] = [];
1354
1355 // Get the remainder of the nested object to set so we can recurse
1356 b = a.slice();
1357 b.splice( 0, i+1 );
1358 innerSrc = b.join('.');
1359
1360 // Traverse each entry in the array setting the properties requested
1361 for ( var j=0, jLen=val.length ; j<jLen ; j++ )
1362 {
1363 o = {};
1364 setData( o, val[j], innerSrc );
1365 data[ a[i] ].push( o );
1366 }
1367
1368 // The inner call to setData has already traversed through the remainder
1369 // of the source and has set the data, thus we can exit here
1370 return;
1371 }
1372 else if ( funcNotation )
1373 {
1374 // Function call
1375 a[i] = a[i].replace(__reFn, '');
1376 data = data[ a[i] ]( val );
1377 }
1378
1379 // If the nested object doesn't currently exist - since we are
1380 // trying to set the value - create it
1381 if ( data[ a[i] ] === null || data[ a[i] ] === undefined )
1382 {
1383 data[ a[i] ] = {};
1384 }
1385 data = data[ a[i] ];
1386 }
1387
1388 // Last item in the input - i.e, the actual set
1389 if ( aLast.match(__reFn ) )
1390 {
1391 // Function call
1392 data = data[ aLast.replace(__reFn, '') ]( val );
1393 }
1394 else
1395 {
1396 // If array notation is used, we just want to strip it and use the property name
1397 // and assign the value. If it isn't used, then we get the result we want anyway
1398 data[ aLast.replace(__reArray, '') ] = val;
1399 }
1400 };
1401
1402 return function (data, val) { // meta is also passed in, but not used
1403 return setData( data, val, mSource );
1404 };
1405 }
1406 else
1407 {
1408 /* Array or flat object mapping */
1409 return function (data, val) { // meta is also passed in, but not used
1410 data[mSource] = val;
1411 };
1412 }
1413 }
1414
1415
1416 /**
1417 * Return an array with the full table data
1418 * @param {object} oSettings dataTables settings object
1419 * @returns array {array} aData Master data array
1420 * @memberof DataTable#oApi
1421 */
1422 function _fnGetDataMaster ( settings )
1423 {
1424 return _pluck( settings.aoData, '_aData' );
1425 }
1426
1427
1428 /**
1429 * Nuke the table
1430 * @param {object} oSettings dataTables settings object
1431 * @memberof DataTable#oApi
1432 */
1433 function _fnClearTable( settings )
1434 {
1435 settings.aoData.length = 0;
1436 settings.aiDisplayMaster.length = 0;
1437 settings.aiDisplay.length = 0;
1438 }
1439
1440
1441 /**
1442 * Take an array of integers (index array) and remove a target integer (value - not
1443 * the key!)
1444 * @param {array} a Index array to target
1445 * @param {int} iTarget value to find
1446 * @memberof DataTable#oApi
1447 */
1448 function _fnDeleteIndex( a, iTarget, splice )
1449 {
1450 var iTargetIndex = -1;
1451
1452 for ( var i=0, iLen=a.length ; i<iLen ; i++ )
1453 {
1454 if ( a[i] == iTarget )
1455 {
1456 iTargetIndex = i;
1457 }
1458 else if ( a[i] > iTarget )
1459 {
1460 a[i]--;
1461 }
1462 }
1463
1464 if ( iTargetIndex != -1 && splice === undefined )
1465 {
1466 a.splice( iTargetIndex, 1 );
1467 }
1468 }
1469
1470
1471 /**
1472 * Mark cached data as invalid such that a re-read of the data will occur when
1473 * the cached data is next requested. Also update from the data source object.
1474 *
1475 * @param {object} settings DataTables settings object
1476 * @param {int} rowIdx Row index to invalidate
1477 * @param {string} [src] Source to invalidate from: undefined, 'auto', 'dom'
1478 * or 'data'
1479 * @param {int} [colIdx] Column index to invalidate. If undefined the whole
1480 * row will be invalidated
1481 * @memberof DataTable#oApi
1482 *
1483 * @todo For the modularisation of v1.11 this will need to become a callback, so
1484 * the sort and filter methods can subscribe to it. That will required
1485 * initialisation options for sorting, which is why it is not already baked in
1486 */
1487 function _fnInvalidate( settings, rowIdx, src, colIdx )
1488 {
1489 var row = settings.aoData[ rowIdx ];
1490 var i, ien;
1491 var cellWrite = function ( cell, col ) {
1492 // This is very frustrating, but in IE if you just write directly
1493 // to innerHTML, and elements that are overwritten are GC'ed,
1494 // even if there is a reference to them elsewhere
1495 while ( cell.childNodes.length ) {
1496 cell.removeChild( cell.firstChild );
1497 }
1498
1499 cell.innerHTML = _fnGetCellData( settings, rowIdx, col, 'display' );
1500 };
1501
1502 // Are we reading last data from DOM or the data object?
1503 if ( src === 'dom' || ((! src || src === 'auto') && row.src === 'dom') ) {
1504 // Read the data from the DOM
1505 row._aData = _fnGetRowElements(
1506 settings, row, colIdx, colIdx === undefined ? undefined : row._aData
1507 )
1508 .data;
1509 }
1510 else {
1511 // Reading from data object, update the DOM
1512 var cells = row.anCells;
1513
1514 if ( cells ) {
1515 if ( colIdx !== undefined ) {
1516 cellWrite( cells[colIdx], colIdx );
1517 }
1518 else {
1519 for ( i=0, ien=cells.length ; i<ien ; i++ ) {
1520 cellWrite( cells[i], i );
1521 }
1522 }
1523 }
1524 }
1525
1526 // For both row and cell invalidation, the cached data for sorting and
1527 // filtering is nulled out
1528 row._aSortData = null;
1529 row._aFilterData = null;
1530
1531 // Invalidate the type for a specific column (if given) or all columns since
1532 // the data might have changed
1533 var cols = settings.aoColumns;
1534 if ( colIdx !== undefined ) {
1535 cols[ colIdx ].sType = null;
1536 }
1537 else {
1538 for ( i=0, ien=cols.length ; i<ien ; i++ ) {
1539 cols[i].sType = null;
1540 }
1541
1542 // Update DataTables special `DT_*` attributes for the row
1543 _fnRowAttributes( row );
1544 }
1545 }
1546
1547
1548 /**
1549 * Build a data source object from an HTML row, reading the contents of the
1550 * cells that are in the row.
1551 *
1552 * @param {object} settings DataTables settings object
1553 * @param {node|object} TR element from which to read data or existing row
1554 * object from which to re-read the data from the cells
1555 * @param {int} [colIdx] Optional column index
1556 * @param {array|object} [d] Data source object. If `colIdx` is given then this
1557 * parameter should also be given and will be used to write the data into.
1558 * Only the column in question will be written
1559 * @returns {object} Object with two parameters: `data` the data read, in
1560 * document order, and `cells` and array of nodes (they can be useful to the
1561 * caller, so rather than needing a second traversal to get them, just return
1562 * them from here).
1563 * @memberof DataTable#oApi
1564 */
1565 function _fnGetRowElements( settings, row, colIdx, d )
1566 {
1567 var
1568 tds = [],
1569 td = row.firstChild,
1570 name, col, o, i=0, contents,
1571 columns = settings.aoColumns,
1572 objectRead = settings._rowReadObject;
1573
1574 // Allow the data object to be passed in, or construct
1575 d = d || objectRead ? {} : [];
1576
1577 var attr = function ( str, td ) {
1578 if ( typeof str === 'string' ) {
1579 var idx = str.indexOf('@');
1580
1581 if ( idx !== -1 ) {
1582 var attr = str.substring( idx+1 );
1583 var setter = _fnSetObjectDataFn( str );
1584 setter( d, td.getAttribute( attr ) );
1585 }
1586 }
1587 };
1588
1589 // Read data from a cell and store into the data object
1590 var cellProcess = function ( cell ) {
1591 if ( colIdx === undefined || colIdx === i ) {
1592 col = columns[i];
1593 contents = $.trim(cell.innerHTML);
1594
1595 if ( col && col._bAttrSrc ) {
1596 var setter = _fnSetObjectDataFn( col.mData._ );
1597 setter( d, contents );
1598
1599 attr( col.mData.sort, cell );
1600 attr( col.mData.type, cell );
1601 attr( col.mData.filter, cell );
1602 }
1603 else {
1604 // Depending on the `data` option for the columns the data can
1605 // be read to either an object or an array.
1606 if ( objectRead ) {
1607 if ( ! col._setter ) {
1608 // Cache the setter function
1609 col._setter = _fnSetObjectDataFn( col.mData );
1610 }
1611 col._setter( d, contents );
1612 }
1613 else {
1614 d[i] = contents;
1615 }
1616 }
1617 }
1618
1619 i++;
1620 };
1621
1622 if ( td ) {
1623 // `tr` element was passed in
1624 while ( td ) {
1625 name = td.nodeName.toUpperCase();
1626
1627 if ( name == "TD" || name == "TH" ) {
1628 cellProcess( td );
1629 tds.push( td );
1630 }
1631
1632 td = td.nextSibling;
1633 }
1634 }
1635 else {
1636 // Existing row object passed in
1637 tds = row.anCells;
1638
1639 for ( var j=0, jen=tds.length ; j<jen ; j++ ) {
1640 cellProcess( tds[j] );
1641 }
1642 }
1643
1644 return {
1645 data: d,
1646 cells: tds
1647 };
1648 }
1649 /**
1650 * Create a new TR element (and it's TD children) for a row
1651 * @param {object} oSettings dataTables settings object
1652 * @param {int} iRow Row to consider
1653 * @param {node} [nTrIn] TR element to add to the table - optional. If not given,
1654 * DataTables will create a row automatically
1655 * @param {array} [anTds] Array of TD|TH elements for the row - must be given
1656 * if nTr is.
1657 * @memberof DataTable#oApi
1658 */
1659 function _fnCreateTr ( oSettings, iRow, nTrIn, anTds )
1660 {
1661 var
1662 row = oSettings.aoData[iRow],
1663 rowData = row._aData,
1664 cells = [],
1665 nTr, nTd, oCol,
1666 i, iLen;
1667
1668 if ( row.nTr === null )
1669 {
1670 nTr = nTrIn || document.createElement('tr');
1671
1672 row.nTr = nTr;
1673 row.anCells = cells;
1674
1675 /* Use a private property on the node to allow reserve mapping from the node
1676 * to the aoData array for fast look up
1677 */
1678 nTr._DT_RowIndex = iRow;
1679
1680 /* Special parameters can be given by the data source to be used on the row */
1681 _fnRowAttributes( row );
1682
1683 /* Process each column */
1684 for ( i=0, iLen=oSettings.aoColumns.length ; i<iLen ; i++ )
1685 {
1686 oCol = oSettings.aoColumns[i];
1687
1688 nTd = nTrIn ? anTds[i] : document.createElement( oCol.sCellType );
1689 cells.push( nTd );
1690
1691 // Need to create the HTML if new, or if a rendering function is defined
1692 if ( !nTrIn || oCol.mRender || oCol.mData !== i )
1693 {
1694 nTd.innerHTML = _fnGetCellData( oSettings, iRow, i, 'display' );
1695 }
1696
1697 /* Add user defined class */
1698 if ( oCol.sClass )
1699 {
1700 nTd.className += ' '+oCol.sClass;
1701 }
1702
1703 // Visibility - add or remove as required
1704 if ( oCol.bVisible && ! nTrIn )
1705 {
1706 nTr.appendChild( nTd );
1707 }
1708 else if ( ! oCol.bVisible && nTrIn )
1709 {
1710 nTd.parentNode.removeChild( nTd );
1711 }
1712
1713 if ( oCol.fnCreatedCell )
1714 {
1715 oCol.fnCreatedCell.call( oSettings.oInstance,
1716 nTd, _fnGetCellData( oSettings, iRow, i ), rowData, iRow, i
1717 );
1718 }
1719 }
1720
1721 _fnCallbackFire( oSettings, 'aoRowCreatedCallback', null, [nTr, rowData, iRow] );
1722 }
1723
1724 // Remove once webkit bug 131819 and Chromium bug 365619 have been resolved
1725 // and deployed
1726 row.nTr.setAttribute( 'role', 'row' );
1727 }
1728
1729
1730 /**
1731 * Add attributes to a row based on the special `DT_*` parameters in a data
1732 * source object.
1733 * @param {object} DataTables row object for the row to be modified
1734 * @memberof DataTable#oApi
1735 */
1736 function _fnRowAttributes( row )
1737 {
1738 var tr = row.nTr;
1739 var data = row._aData;
1740
1741 if ( tr ) {
1742 if ( data.DT_RowId ) {
1743 tr.id = data.DT_RowId;
1744 }
1745
1746 if ( data.DT_RowClass ) {
1747 // Remove any classes added by DT_RowClass before
1748 var a = data.DT_RowClass.split(' ');
1749 row.__rowc = row.__rowc ?
1750 _unique( row.__rowc.concat( a ) ) :
1751 a;
1752
1753 $(tr)
1754 .removeClass( row.__rowc.join(' ') )
1755 .addClass( data.DT_RowClass );
1756 }
1757
1758 if ( data.DT_RowAttr ) {
1759 $(tr).attr( data.DT_RowAttr );
1760 }
1761
1762 if ( data.DT_RowData ) {
1763 $(tr).data( data.DT_RowData );
1764 }
1765 }
1766 }
1767
1768
1769 /**
1770 * Create the HTML header for the table
1771 * @param {object} oSettings dataTables settings object
1772 * @memberof DataTable#oApi
1773 */
1774 function _fnBuildHead( oSettings )
1775 {
1776 var i, ien, cell, row, column;
1777 var thead = oSettings.nTHead;
1778 var tfoot = oSettings.nTFoot;
1779 var createHeader = $('th, td', thead).length === 0;
1780 var classes = oSettings.oClasses;
1781 var columns = oSettings.aoColumns;
1782
1783 if ( createHeader ) {
1784 row = $('<tr/>').appendTo( thead );
1785 }
1786
1787 for ( i=0, ien=columns.length ; i<ien ; i++ ) {
1788 column = columns[i];
1789 cell = $( column.nTh ).addClass( column.sClass );
1790
1791 if ( createHeader ) {
1792 cell.appendTo( row );
1793 }
1794
1795 // 1.11 move into sorting
1796 if ( oSettings.oFeatures.bSort ) {
1797 cell.addClass( column.sSortingClass );
1798
1799 if ( column.bSortable !== false ) {
1800 cell
1801 .attr( 'tabindex', oSettings.iTabIndex )
1802 .attr( 'aria-controls', oSettings.sTableId );
1803
1804 _fnSortAttachListener( oSettings, column.nTh, i );
1805 }
1806 }
1807
1808 if ( column.sTitle != cell.html() ) {
1809 cell.html( column.sTitle );
1810 }
1811
1812 _fnRenderer( oSettings, 'header' )(
1813 oSettings, cell, column, classes
1814 );
1815 }
1816
1817 if ( createHeader ) {
1818 _fnDetectHeader( oSettings.aoHeader, thead );
1819 }
1820
1821 /* ARIA role for the rows */
1822 $(thead).find('>tr').attr('role', 'row');
1823
1824 /* Deal with the footer - add classes if required */
1825 $(thead).find('>tr>th, >tr>td').addClass( classes.sHeaderTH );
1826 $(tfoot).find('>tr>th, >tr>td').addClass( classes.sFooterTH );
1827
1828 // Cache the footer cells. Note that we only take the cells from the first
1829 // row in the footer. If there is more than one row the user wants to
1830 // interact with, they need to use the table().foot() method. Note also this
1831 // allows cells to be used for multiple columns using colspan
1832 if ( tfoot !== null ) {
1833 var cells = oSettings.aoFooter[0];
1834
1835 for ( i=0, ien=cells.length ; i<ien ; i++ ) {
1836 column = columns[i];
1837 column.nTf = cells[i].cell;
1838
1839 if ( column.sClass ) {
1840 $(column.nTf).addClass( column.sClass );
1841 }
1842 }
1843 }
1844 }
1845
1846
1847 /**
1848 * Draw the header (or footer) element based on the column visibility states. The
1849 * methodology here is to use the layout array from _fnDetectHeader, modified for
1850 * the instantaneous column visibility, to construct the new layout. The grid is
1851 * traversed over cell at a time in a rows x columns grid fashion, although each
1852 * cell insert can cover multiple elements in the grid - which is tracks using the
1853 * aApplied array. Cell inserts in the grid will only occur where there isn't
1854 * already a cell in that position.
1855 * @param {object} oSettings dataTables settings object
1856 * @param array {objects} aoSource Layout array from _fnDetectHeader
1857 * @param {boolean} [bIncludeHidden=false] If true then include the hidden columns in the calc,
1858 * @memberof DataTable#oApi
1859 */
1860 function _fnDrawHead( oSettings, aoSource, bIncludeHidden )
1861 {
1862 var i, iLen, j, jLen, k, kLen, n, nLocalTr;
1863 var aoLocal = [];
1864 var aApplied = [];
1865 var iColumns = oSettings.aoColumns.length;
1866 var iRowspan, iColspan;
1867
1868 if ( ! aoSource )
1869 {
1870 return;
1871 }
1872
1873 if ( bIncludeHidden === undefined )
1874 {
1875 bIncludeHidden = false;
1876 }
1877
1878 /* Make a copy of the master layout array, but without the visible columns in it */
1879 for ( i=0, iLen=aoSource.length ; i<iLen ; i++ )
1880 {
1881 aoLocal[i] = aoSource[i].slice();
1882 aoLocal[i].nTr = aoSource[i].nTr;
1883
1884 /* Remove any columns which are currently hidden */
1885 for ( j=iColumns-1 ; j>=0 ; j-- )
1886 {
1887 if ( !oSettings.aoColumns[j].bVisible && !bIncludeHidden )
1888 {
1889 aoLocal[i].splice( j, 1 );
1890 }
1891 }
1892
1893 /* Prep the applied array - it needs an element for each row */
1894 aApplied.push( [] );
1895 }
1896
1897 for ( i=0, iLen=aoLocal.length ; i<iLen ; i++ )
1898 {
1899 nLocalTr = aoLocal[i].nTr;
1900
1901 /* All cells are going to be replaced, so empty out the row */
1902 if ( nLocalTr )
1903 {
1904 while( (n = nLocalTr.firstChild) )
1905 {
1906 nLocalTr.removeChild( n );
1907 }
1908 }
1909
1910 for ( j=0, jLen=aoLocal[i].length ; j<jLen ; j++ )
1911 {
1912 iRowspan = 1;
1913 iColspan = 1;
1914
1915 /* Check to see if there is already a cell (row/colspan) covering our target
1916 * insert point. If there is, then there is nothing to do.
1917 */
1918 if ( aApplied[i][j] === undefined )
1919 {
1920 nLocalTr.appendChild( aoLocal[i][j].cell );
1921 aApplied[i][j] = 1;
1922
1923 /* Expand the cell to cover as many rows as needed */
1924 while ( aoLocal[i+iRowspan] !== undefined &&
1925 aoLocal[i][j].cell == aoLocal[i+iRowspan][j].cell )
1926 {
1927 aApplied[i+iRowspan][j] = 1;
1928 iRowspan++;
1929 }
1930
1931 /* Expand the cell to cover as many columns as needed */
1932 while ( aoLocal[i][j+iColspan] !== undefined &&
1933 aoLocal[i][j].cell == aoLocal[i][j+iColspan].cell )
1934 {
1935 /* Must update the applied array over the rows for the columns */
1936 for ( k=0 ; k<iRowspan ; k++ )
1937 {
1938 aApplied[i+k][j+iColspan] = 1;
1939 }
1940 iColspan++;
1941 }
1942
1943 /* Do the actual expansion in the DOM */
1944 $(aoLocal[i][j].cell)
1945 .attr('rowspan', iRowspan)
1946 .attr('colspan', iColspan);
1947 }
1948 }
1949 }
1950 }
1951
1952
1953 /**
1954 * Insert the required TR nodes into the table for display
1955 * @param {object} oSettings dataTables settings object
1956 * @memberof DataTable#oApi
1957 */
1958 function _fnDraw( oSettings )
1959 {
1960 /* Provide a pre-callback function which can be used to cancel the draw is false is returned */
1961 var aPreDraw = _fnCallbackFire( oSettings, 'aoPreDrawCallback', 'preDraw', [oSettings] );
1962 if ( $.inArray( false, aPreDraw ) !== -1 )
1963 {
1964 _fnProcessingDisplay( oSettings, false );
1965 return;
1966 }
1967
1968 var i, iLen, n;
1969 var anRows = [];
1970 var iRowCount = 0;
1971 var asStripeClasses = oSettings.asStripeClasses;
1972 var iStripes = asStripeClasses.length;
1973 var iOpenRows = oSettings.aoOpenRows.length;
1974 var oLang = oSettings.oLanguage;
1975 var iInitDisplayStart = oSettings.iInitDisplayStart;
1976 var bServerSide = _fnDataSource( oSettings ) == 'ssp';
1977 var aiDisplay = oSettings.aiDisplay;
1978
1979 oSettings.bDrawing = true;
1980
1981 /* Check and see if we have an initial draw position from state saving */
1982 if ( iInitDisplayStart !== undefined && iInitDisplayStart !== -1 )
1983 {
1984 oSettings._iDisplayStart = bServerSide ?
1985 iInitDisplayStart :
1986 iInitDisplayStart >= oSettings.fnRecordsDisplay() ?
1987 0 :
1988 iInitDisplayStart;
1989
1990 oSettings.iInitDisplayStart = -1;
1991 }
1992
1993 var iDisplayStart = oSettings._iDisplayStart;
1994 var iDisplayEnd = oSettings.fnDisplayEnd();
1995
1996 /* Server-side processing draw intercept */
1997 if ( oSettings.bDeferLoading )
1998 {
1999 oSettings.bDeferLoading = false;
2000 oSettings.iDraw++;
2001 _fnProcessingDisplay( oSettings, false );
2002 }
2003 else if ( !bServerSide )
2004 {
2005 oSettings.iDraw++;
2006 }
2007 else if ( !oSettings.bDestroying && !_fnAjaxUpdate( oSettings ) )
2008 {
2009 return;
2010 }
2011
2012 if ( aiDisplay.length !== 0 )
2013 {
2014 var iStart = bServerSide ? 0 : iDisplayStart;
2015 var iEnd = bServerSide ? oSettings.aoData.length : iDisplayEnd;
2016
2017 for ( var j=iStart ; j<iEnd ; j++ )
2018 {
2019 var iDataIndex = aiDisplay[j];
2020 var aoData = oSettings.aoData[ iDataIndex ];
2021 if ( aoData.nTr === null )
2022 {
2023 _fnCreateTr( oSettings, iDataIndex );
2024 }
2025
2026 var nRow = aoData.nTr;
2027
2028 /* Remove the old striping classes and then add the new one */
2029 if ( iStripes !== 0 )
2030 {
2031 var sStripe = asStripeClasses[ iRowCount % iStripes ];
2032 if ( aoData._sRowStripe != sStripe )
2033 {
2034 $(nRow).removeClass( aoData._sRowStripe ).addClass( sStripe );
2035 aoData._sRowStripe = sStripe;
2036 }
2037 }
2038
2039 // Row callback functions - might want to manipulate the row
2040 // iRowCount and j are not currently documented. Are they at all
2041 // useful?
2042 _fnCallbackFire( oSettings, 'aoRowCallback', null,
2043 [nRow, aoData._aData, iRowCount, j] );
2044
2045 anRows.push( nRow );
2046 iRowCount++;
2047 }
2048 }
2049 else
2050 {
2051 /* Table is empty - create a row with an empty message in it */
2052 var sZero = oLang.sZeroRecords;
2053 if ( oSettings.iDraw == 1 && _fnDataSource( oSettings ) == 'ajax' )
2054 {
2055 sZero = oLang.sLoadingRecords;
2056 }
2057 else if ( oLang.sEmptyTable && oSettings.fnRecordsTotal() === 0 )
2058 {
2059 sZero = oLang.sEmptyTable;
2060 }
2061
2062 anRows[ 0 ] = $( '<tr/>', { 'class': iStripes ? asStripeClasses[0] : '' } )
2063 .append( $('<td />', {
2064 'valign': 'top',
2065 'colSpan': _fnVisbleColumns( oSettings ),
2066 'class': oSettings.oClasses.sRowEmpty
2067 } ).html( sZero ) )[0];
2068 }
2069
2070 /* Header and footer callbacks */
2071 _fnCallbackFire( oSettings, 'aoHeaderCallback', 'header', [ $(oSettings.nTHead).children('tr')[0],
2072 _fnGetDataMaster( oSettings ), iDisplayStart, iDisplayEnd, aiDisplay ] );
2073
2074 _fnCallbackFire( oSettings, 'aoFooterCallback', 'footer', [ $(oSettings.nTFoot).children('tr')[0],
2075 _fnGetDataMaster( oSettings ), iDisplayStart, iDisplayEnd, aiDisplay ] );
2076
2077 var body = $(oSettings.nTBody);
2078
2079 body.children().detach();
2080 body.append( $(anRows) );
2081
2082 /* Call all required callback functions for the end of a draw */
2083 _fnCallbackFire( oSettings, 'aoDrawCallback', 'draw', [oSettings] );
2084
2085 /* Draw is complete, sorting and filtering must be as well */
2086 oSettings.bSorted = false;
2087 oSettings.bFiltered = false;
2088 oSettings.bDrawing = false;
2089 }
2090
2091
2092 /**
2093 * Redraw the table - taking account of the various features which are enabled
2094 * @param {object} oSettings dataTables settings object
2095 * @param {boolean} [holdPosition] Keep the current paging position. By default
2096 * the paging is reset to the first page
2097 * @memberof DataTable#oApi
2098 */
2099 function _fnReDraw( settings, holdPosition )
2100 {
2101 var
2102 features = settings.oFeatures,
2103 sort = features.bSort,
2104 filter = features.bFilter;
2105
2106 if ( sort ) {
2107 _fnSort( settings );
2108 }
2109
2110 if ( filter ) {
2111 _fnFilterComplete( settings, settings.oPreviousSearch );
2112 }
2113 else {
2114 // No filtering, so we want to just use the display master
2115 settings.aiDisplay = settings.aiDisplayMaster.slice();
2116 }
2117
2118 if ( holdPosition !== true ) {
2119 settings._iDisplayStart = 0;
2120 }
2121
2122 // Let any modules know about the draw hold position state (used by
2123 // scrolling internally)
2124 settings._drawHold = holdPosition;
2125
2126 _fnDraw( settings );
2127
2128 settings._drawHold = false;
2129 }
2130
2131
2132 /**
2133 * Add the options to the page HTML for the table
2134 * @param {object} oSettings dataTables settings object
2135 * @memberof DataTable#oApi
2136 */
2137 function _fnAddOptionsHtml ( oSettings )
2138 {
2139 var classes = oSettings.oClasses;
2140 var table = $(oSettings.nTable);
2141 var holding = $('<div/>').insertBefore( table ); // Holding element for speed
2142 var features = oSettings.oFeatures;
2143
2144 // All DataTables are wrapped in a div
2145 var insert = $('<div/>', {
2146 id: oSettings.sTableId+'_wrapper',
2147 'class': classes.sWrapper + (oSettings.nTFoot ? '' : ' '+classes.sNoFooter)
2148 } );
2149
2150 oSettings.nHolding = holding[0];
2151 oSettings.nTableWrapper = insert[0];
2152 oSettings.nTableReinsertBefore = oSettings.nTable.nextSibling;
2153
2154 /* Loop over the user set positioning and place the elements as needed */
2155 var aDom = oSettings.sDom.split('');
2156 var featureNode, cOption, nNewNode, cNext, sAttr, j;
2157 for ( var i=0 ; i<aDom.length ; i++ )
2158 {
2159 featureNode = null;
2160 cOption = aDom[i];
2161
2162 if ( cOption == '<' )
2163 {
2164 /* New container div */
2165 nNewNode = $('<div/>')[0];
2166
2167 /* Check to see if we should append an id and/or a class name to the container */
2168 cNext = aDom[i+1];
2169 if ( cNext == "'" || cNext == '"' )
2170 {
2171 sAttr = "";
2172 j = 2;
2173 while ( aDom[i+j] != cNext )
2174 {
2175 sAttr += aDom[i+j];
2176 j++;
2177 }
2178
2179 /* Replace jQuery UI constants @todo depreciated */
2180 if ( sAttr == "H" )
2181 {
2182 sAttr = classes.sJUIHeader;
2183 }
2184 else if ( sAttr == "F" )
2185 {
2186 sAttr = classes.sJUIFooter;
2187 }
2188
2189 /* The attribute can be in the format of "#id.class", "#id" or "class" This logic
2190 * breaks the string into parts and applies them as needed
2191 */
2192 if ( sAttr.indexOf('.') != -1 )
2193 {
2194 var aSplit = sAttr.split('.');
2195 nNewNode.id = aSplit[0].substr(1, aSplit[0].length-1);
2196 nNewNode.className = aSplit[1];
2197 }
2198 else if ( sAttr.charAt(0) == "#" )
2199 {
2200 nNewNode.id = sAttr.substr(1, sAttr.length-1);
2201 }
2202 else
2203 {
2204 nNewNode.className = sAttr;
2205 }
2206
2207 i += j; /* Move along the position array */
2208 }
2209
2210 insert.append( nNewNode );
2211 insert = $(nNewNode);
2212 }
2213 else if ( cOption == '>' )
2214 {
2215 /* End container div */
2216 insert = insert.parent();
2217 }
2218 // @todo Move options into their own plugins?
2219 else if ( cOption == 'l' && features.bPaginate && features.bLengthChange )
2220 {
2221 /* Length */
2222 featureNode = _fnFeatureHtmlLength( oSettings );
2223 }
2224 else if ( cOption == 'f' && features.bFilter )
2225 {
2226 /* Filter */
2227 featureNode = _fnFeatureHtmlFilter( oSettings );
2228 }
2229 else if ( cOption == 'r' && features.bProcessing )
2230 {
2231 /* pRocessing */
2232 featureNode = _fnFeatureHtmlProcessing( oSettings );
2233 }
2234 else if ( cOption == 't' )
2235 {
2236 /* Table */
2237 featureNode = _fnFeatureHtmlTable( oSettings );
2238 }
2239 else if ( cOption == 'i' && features.bInfo )
2240 {
2241 /* Info */
2242 featureNode = _fnFeatureHtmlInfo( oSettings );
2243 }
2244 else if ( cOption == 'p' && features.bPaginate )
2245 {
2246 /* Pagination */
2247 featureNode = _fnFeatureHtmlPaginate( oSettings );
2248 }
2249 else if ( DataTable.ext.feature.length !== 0 )
2250 {
2251 /* Plug-in features */
2252 var aoFeatures = DataTable.ext.feature;
2253 for ( var k=0, kLen=aoFeatures.length ; k<kLen ; k++ )
2254 {
2255 if ( cOption == aoFeatures[k].cFeature )
2256 {
2257 featureNode = aoFeatures[k].fnInit( oSettings );
2258 break;
2259 }
2260 }
2261 }
2262
2263 /* Add to the 2D features array */
2264 if ( featureNode )
2265 {
2266 var aanFeatures = oSettings.aanFeatures;
2267
2268 if ( ! aanFeatures[cOption] )
2269 {
2270 aanFeatures[cOption] = [];
2271 }
2272
2273 aanFeatures[cOption].push( featureNode );
2274 insert.append( featureNode );
2275 }
2276 }
2277
2278 /* Built our DOM structure - replace the holding div with what we want */
2279 holding.replaceWith( insert );
2280 }
2281
2282
2283 /**
2284 * Use the DOM source to create up an array of header cells. The idea here is to
2285 * create a layout grid (array) of rows x columns, which contains a reference
2286 * to the cell that that point in the grid (regardless of col/rowspan), such that
2287 * any column / row could be removed and the new grid constructed
2288 * @param array {object} aLayout Array to store the calculated layout in
2289 * @param {node} nThead The header/footer element for the table
2290 * @memberof DataTable#oApi
2291 */
2292 function _fnDetectHeader ( aLayout, nThead )
2293 {
2294 var nTrs = $(nThead).children('tr');
2295 var nTr, nCell;
2296 var i, k, l, iLen, jLen, iColShifted, iColumn, iColspan, iRowspan;
2297 var bUnique;
2298 var fnShiftCol = function ( a, i, j ) {
2299 var k = a[i];
2300 while ( k[j] ) {
2301 j++;
2302 }
2303 return j;
2304 };
2305
2306 aLayout.splice( 0, aLayout.length );
2307
2308 /* We know how many rows there are in the layout - so prep it */
2309 for ( i=0, iLen=nTrs.length ; i<iLen ; i++ )
2310 {
2311 aLayout.push( [] );
2312 }
2313
2314 /* Calculate a layout array */
2315 for ( i=0, iLen=nTrs.length ; i<iLen ; i++ )
2316 {
2317 nTr = nTrs[i];
2318 iColumn = 0;
2319
2320 /* For every cell in the row... */
2321 nCell = nTr.firstChild;
2322 while ( nCell ) {
2323 if ( nCell.nodeName.toUpperCase() == "TD" ||
2324 nCell.nodeName.toUpperCase() == "TH" )
2325 {
2326 /* Get the col and rowspan attributes from the DOM and sanitise them */
2327 iColspan = nCell.getAttribute('colspan') * 1;
2328 iRowspan = nCell.getAttribute('rowspan') * 1;
2329 iColspan = (!iColspan || iColspan===0 || iColspan===1) ? 1 : iColspan;
2330 iRowspan = (!iRowspan || iRowspan===0 || iRowspan===1) ? 1 : iRowspan;
2331
2332 /* There might be colspan cells already in this row, so shift our target
2333 * accordingly
2334 */
2335 iColShifted = fnShiftCol( aLayout, i, iColumn );
2336
2337 /* Cache calculation for unique columns */
2338 bUnique = iColspan === 1 ? true : false;
2339
2340 /* If there is col / rowspan, copy the information into the layout grid */
2341 for ( l=0 ; l<iColspan ; l++ )
2342 {
2343 for ( k=0 ; k<iRowspan ; k++ )
2344 {
2345 aLayout[i+k][iColShifted+l] = {
2346 "cell": nCell,
2347 "unique": bUnique
2348 };
2349 aLayout[i+k].nTr = nTr;
2350 }
2351 }
2352 }
2353 nCell = nCell.nextSibling;
2354 }
2355 }
2356 }
2357
2358
2359 /**
2360 * Get an array of unique th elements, one for each column
2361 * @param {object} oSettings dataTables settings object
2362 * @param {node} nHeader automatically detect the layout from this node - optional
2363 * @param {array} aLayout thead/tfoot layout from _fnDetectHeader - optional
2364 * @returns array {node} aReturn list of unique th's
2365 * @memberof DataTable#oApi
2366 */
2367 function _fnGetUniqueThs ( oSettings, nHeader, aLayout )
2368 {
2369 var aReturn = [];
2370 if ( !aLayout )
2371 {
2372 aLayout = oSettings.aoHeader;
2373 if ( nHeader )
2374 {
2375 aLayout = [];
2376 _fnDetectHeader( aLayout, nHeader );
2377 }
2378 }
2379
2380 for ( var i=0, iLen=aLayout.length ; i<iLen ; i++ )
2381 {
2382 for ( var j=0, jLen=aLayout[i].length ; j<jLen ; j++ )
2383 {
2384 if ( aLayout[i][j].unique &&
2385 (!aReturn[j] || !oSettings.bSortCellsTop) )
2386 {
2387 aReturn[j] = aLayout[i][j].cell;
2388 }
2389 }
2390 }
2391
2392 return aReturn;
2393 }
2394
2395 /**
2396 * Create an Ajax call based on the table's settings, taking into account that
2397 * parameters can have multiple forms, and backwards compatibility.
2398 *
2399 * @param {object} oSettings dataTables settings object
2400 * @param {array} data Data to send to the server, required by
2401 * DataTables - may be augmented by developer callbacks
2402 * @param {function} fn Callback function to run when data is obtained
2403 */
2404 function _fnBuildAjax( oSettings, data, fn )
2405 {
2406 // Compatibility with 1.9-, allow fnServerData and event to manipulate
2407 _fnCallbackFire( oSettings, 'aoServerParams', 'serverParams', [data] );
2408
2409 // Convert to object based for 1.10+ if using the old array scheme which can
2410 // come from server-side processing or serverParams
2411 if ( data && $.isArray(data) ) {
2412 var tmp = {};
2413 var rbracket = /(.*?)\[\]$/;
2414
2415 $.each( data, function (key, val) {
2416 var match = val.name.match(rbracket);
2417
2418 if ( match ) {
2419 // Support for arrays
2420 var name = match[0];
2421
2422 if ( ! tmp[ name ] ) {
2423 tmp[ name ] = [];
2424 }
2425 tmp[ name ].push( val.value );
2426 }
2427 else {
2428 tmp[val.name] = val.value;
2429 }
2430 } );
2431 data = tmp;
2432 }
2433
2434 var ajaxData;
2435 var ajax = oSettings.ajax;
2436 var instance = oSettings.oInstance;
2437 var callback = function ( json ) {
2438 _fnCallbackFire( oSettings, null, 'xhr', [oSettings, json, oSettings.jqXHR] );
2439 fn( json );
2440 };
2441
2442 if ( $.isPlainObject( ajax ) && ajax.data )
2443 {
2444 ajaxData = ajax.data;
2445
2446 var newData = $.isFunction( ajaxData ) ?
2447 ajaxData( data, oSettings ) : // fn can manipulate data or return
2448 ajaxData; // an object object or array to merge
2449
2450 // If the function returned something, use that alone
2451 data = $.isFunction( ajaxData ) && newData ?
2452 newData :
2453 $.extend( true, data, newData );
2454
2455 // Remove the data property as we've resolved it already and don't want
2456 // jQuery to do it again (it is restored at the end of the function)
2457 delete ajax.data;
2458 }
2459
2460 var baseAjax = {
2461 "data": data,
2462 "success": function (json) {
2463 var error = json.error || json.sError;
2464 if ( error ) {
2465 _fnLog( oSettings, 0, error );
2466 }
2467
2468 oSettings.json = json;
2469 callback( json );
2470 },
2471 "dataType": "json",
2472 "cache": false,
2473 "type": oSettings.sServerMethod,
2474 "error": function (xhr, error, thrown) {
2475 var ret = _fnCallbackFire( oSettings, null, 'xhr', [oSettings, null, oSettings.jqXHR] );
2476
2477 if ( $.inArray( true, ret ) === -1 ) {
2478 if ( error == "parsererror" ) {
2479 _fnLog( oSettings, 0, 'Invalid JSON response', 1 );
2480 }
2481 else if ( xhr.readyState === 4 ) {
2482 _fnLog( oSettings, 0, 'Ajax error', 7 );
2483 }
2484 }
2485
2486 _fnProcessingDisplay( oSettings, false );
2487 }
2488 };
2489
2490 // Store the data submitted for the API
2491 oSettings.oAjaxData = data;
2492
2493 // Allow plug-ins and external processes to modify the data
2494 _fnCallbackFire( oSettings, null, 'preXhr', [oSettings, data] );
2495
2496 if ( oSettings.fnServerData )
2497 {
2498 // DataTables 1.9- compatibility
2499 oSettings.fnServerData.call( instance,
2500 oSettings.sAjaxSource,
2501 $.map( data, function (val, key) { // Need to convert back to 1.9 trad format
2502 return { name: key, value: val };
2503 } ),
2504 callback,
2505 oSettings
2506 );
2507 }
2508 else if ( oSettings.sAjaxSource || typeof ajax === 'string' )
2509 {
2510 // DataTables 1.9- compatibility
2511 oSettings.jqXHR = $.ajax( $.extend( baseAjax, {
2512 url: ajax || oSettings.sAjaxSource
2513 } ) );
2514 }
2515 else if ( $.isFunction( ajax ) )
2516 {
2517 // Is a function - let the caller define what needs to be done
2518 oSettings.jqXHR = ajax.call( instance, data, callback, oSettings );
2519 }
2520 else
2521 {
2522 // Object to extend the base settings
2523 oSettings.jqXHR = $.ajax( $.extend( baseAjax, ajax ) );
2524
2525 // Restore for next time around
2526 ajax.data = ajaxData;
2527 }
2528 }
2529
2530
2531 /**
2532 * Update the table using an Ajax call
2533 * @param {object} settings dataTables settings object
2534 * @returns {boolean} Block the table drawing or not
2535 * @memberof DataTable#oApi
2536 */
2537 function _fnAjaxUpdate( settings )
2538 {
2539 if ( settings.bAjaxDataGet ) {
2540 settings.iDraw++;
2541 _fnProcessingDisplay( settings, true );
2542
2543 _fnBuildAjax(
2544 settings,
2545 _fnAjaxParameters( settings ),
2546 function(json) {
2547 _fnAjaxUpdateDraw( settings, json );
2548 }
2549 );
2550
2551 return false;
2552 }
2553 return true;
2554 }
2555
2556
2557 /**
2558 * Build up the parameters in an object needed for a server-side processing
2559 * request. Note that this is basically done twice, is different ways - a modern
2560 * method which is used by default in DataTables 1.10 which uses objects and
2561 * arrays, or the 1.9- method with is name / value pairs. 1.9 method is used if
2562 * the sAjaxSource option is used in the initialisation, or the legacyAjax
2563 * option is set.
2564 * @param {object} oSettings dataTables settings object
2565 * @returns {bool} block the table drawing or not
2566 * @memberof DataTable#oApi
2567 */
2568 function _fnAjaxParameters( settings )
2569 {
2570 var
2571 columns = settings.aoColumns,
2572 columnCount = columns.length,
2573 features = settings.oFeatures,
2574 preSearch = settings.oPreviousSearch,
2575 preColSearch = settings.aoPreSearchCols,
2576 i, data = [], dataProp, column, columnSearch,
2577 sort = _fnSortFlatten( settings ),
2578 displayStart = settings._iDisplayStart,
2579 displayLength = features.bPaginate !== false ?
2580 settings._iDisplayLength :
2581 -1;
2582
2583 var param = function ( name, value ) {
2584 data.push( { 'name': name, 'value': value } );
2585 };
2586
2587 // DataTables 1.9- compatible method
2588 param( 'sEcho', settings.iDraw );
2589 param( 'iColumns', columnCount );
2590 param( 'sColumns', _pluck( columns, 'sName' ).join(',') );
2591 param( 'iDisplayStart', displayStart );
2592 param( 'iDisplayLength', displayLength );
2593
2594 // DataTables 1.10+ method
2595 var d = {
2596 draw: settings.iDraw,
2597 columns: [],
2598 order: [],
2599 start: displayStart,
2600 length: displayLength,
2601 search: {
2602 value: preSearch.sSearch,
2603 regex: preSearch.bRegex
2604 }
2605 };
2606
2607 for ( i=0 ; i<columnCount ; i++ ) {
2608 column = columns[i];
2609 columnSearch = preColSearch[i];
2610 dataProp = typeof column.mData=="function" ? 'function' : column.mData ;
2611
2612 d.columns.push( {
2613 data: dataProp,
2614 name: column.sName,
2615 searchable: column.bSearchable,
2616 orderable: column.bSortable,
2617 search: {
2618 value: columnSearch.sSearch,
2619 regex: columnSearch.bRegex
2620 }
2621 } );
2622
2623 param( "mDataProp_"+i, dataProp );
2624
2625 if ( features.bFilter ) {
2626 param( 'sSearch_'+i, columnSearch.sSearch );
2627 param( 'bRegex_'+i, columnSearch.bRegex );
2628 param( 'bSearchable_'+i, column.bSearchable );
2629 }
2630
2631 if ( features.bSort ) {
2632 param( 'bSortable_'+i, column.bSortable );
2633 }
2634 }
2635
2636 if ( features.bFilter ) {
2637 param( 'sSearch', preSearch.sSearch );
2638 param( 'bRegex', preSearch.bRegex );
2639 }
2640
2641 if ( features.bSort ) {
2642 $.each( sort, function ( i, val ) {
2643 d.order.push( { column: val.col, dir: val.dir } );
2644
2645 param( 'iSortCol_'+i, val.col );
2646 param( 'sSortDir_'+i, val.dir );
2647 } );
2648
2649 param( 'iSortingCols', sort.length );
2650 }
2651
2652 // If the legacy.ajax parameter is null, then we automatically decide which
2653 // form to use, based on sAjaxSource
2654 var legacy = DataTable.ext.legacy.ajax;
2655 if ( legacy === null ) {
2656 return settings.sAjaxSource ? data : d;
2657 }
2658
2659 // Otherwise, if legacy has been specified then we use that to decide on the
2660 // form
2661 return legacy ? data : d;
2662 }
2663
2664
2665 /**
2666 * Data the data from the server (nuking the old) and redraw the table
2667 * @param {object} oSettings dataTables settings object
2668 * @param {object} json json data return from the server.
2669 * @param {string} json.sEcho Tracking flag for DataTables to match requests
2670 * @param {int} json.iTotalRecords Number of records in the data set, not accounting for filtering
2671 * @param {int} json.iTotalDisplayRecords Number of records in the data set, accounting for filtering
2672 * @param {array} json.aaData The data to display on this page
2673 * @param {string} [json.sColumns] Column ordering (sName, comma separated)
2674 * @memberof DataTable#oApi
2675 */
2676 function _fnAjaxUpdateDraw ( settings, json )
2677 {
2678 // v1.10 uses camelCase variables, while 1.9 uses Hungarian notation.
2679 // Support both
2680 var compat = function ( old, modern ) {
2681 return json[old] !== undefined ? json[old] : json[modern];
2682 };
2683
2684 var data = _fnAjaxDataSrc( settings, json );
2685 var draw = compat( 'sEcho', 'draw' );
2686 var recordsTotal = compat( 'iTotalRecords', 'recordsTotal' );
2687 var recordsFiltered = compat( 'iTotalDisplayRecords', 'recordsFiltered' );
2688
2689 if ( draw ) {
2690 // Protect against out of sequence returns
2691 if ( draw*1 < settings.iDraw ) {
2692 return;
2693 }
2694 settings.iDraw = draw * 1;
2695 }
2696
2697 _fnClearTable( settings );
2698 settings._iRecordsTotal = parseInt(recordsTotal, 10);
2699 settings._iRecordsDisplay = parseInt(recordsFiltered, 10);
2700
2701 for ( var i=0, ien=data.length ; i<ien ; i++ ) {
2702 _fnAddData( settings, data[i] );
2703 }
2704 settings.aiDisplay = settings.aiDisplayMaster.slice();
2705
2706 settings.bAjaxDataGet = false;
2707 _fnDraw( settings );
2708
2709 if ( ! settings._bInitComplete ) {
2710 _fnInitComplete( settings, json );
2711 }
2712
2713 settings.bAjaxDataGet = true;
2714 _fnProcessingDisplay( settings, false );
2715 }
2716
2717
2718 /**
2719 * Get the data from the JSON data source to use for drawing a table. Using
2720 * `_fnGetObjectDataFn` allows the data to be sourced from a property of the
2721 * source object, or from a processing function.
2722 * @param {object} oSettings dataTables settings object
2723 * @param {object} json Data source object / array from the server
2724 * @return {array} Array of data to use
2725 */
2726 function _fnAjaxDataSrc ( oSettings, json )
2727 {
2728 var dataSrc = $.isPlainObject( oSettings.ajax ) && oSettings.ajax.dataSrc !== undefined ?
2729 oSettings.ajax.dataSrc :
2730 oSettings.sAjaxDataProp; // Compatibility with 1.9-.
2731
2732 // Compatibility with 1.9-. In order to read from aaData, check if the
2733 // default has been changed, if not, check for aaData
2734 if ( dataSrc === 'data' ) {
2735 return json.aaData || json[dataSrc];
2736 }
2737
2738 return dataSrc !== "" ?
2739 _fnGetObjectDataFn( dataSrc )( json ) :
2740 json;
2741 }
2742
2743 /**
2744 * Generate the node required for filtering text
2745 * @returns {node} Filter control element
2746 * @param {object} oSettings dataTables settings object
2747 * @memberof DataTable#oApi
2748 */
2749 function _fnFeatureHtmlFilter ( settings )
2750 {
2751 var classes = settings.oClasses;
2752 var tableId = settings.sTableId;
2753 var language = settings.oLanguage;
2754 var previousSearch = settings.oPreviousSearch;
2755 var features = settings.aanFeatures;
2756 var input = '<input type="search" class="'+classes.sFilterInput+'"/>';
2757
2758 var str = language.sSearch;
2759 str = str.match(/_INPUT_/) ?
2760 str.replace('_INPUT_', input) :
2761 str+input;
2762
2763 var filter = $('<div/>', {
2764 'id': ! features.f ? tableId+'_filter' : null,
2765 'class': classes.sFilter
2766 } )
2767 .append( $('<label/>' ).append( str ) );
2768
2769 var searchFn = function() {
2770 /* Update all other filter input elements for the new display */
2771 var n = features.f;
2772 var val = !this.value ? "" : this.value; // mental IE8 fix :-(
2773
2774 /* Now do the filter */
2775 if ( val != previousSearch.sSearch ) {
2776 _fnFilterComplete( settings, {
2777 "sSearch": val,
2778 "bRegex": previousSearch.bRegex,
2779 "bSmart": previousSearch.bSmart ,
2780 "bCaseInsensitive": previousSearch.bCaseInsensitive
2781 } );
2782
2783 // Need to redraw, without resorting
2784 settings._iDisplayStart = 0;
2785 _fnDraw( settings );
2786 }
2787 };
2788
2789 var searchDelay = settings.searchDelay !== null ?
2790 settings.searchDelay :
2791 _fnDataSource( settings ) === 'ssp' ?
2792 400 :
2793 0;
2794
2795 var jqFilter = $('input', filter)
2796 .val( previousSearch.sSearch )
2797 .attr( 'placeholder', language.sSearchPlaceholder )
2798 .bind(
2799 'keyup.DT search.DT input.DT paste.DT cut.DT',
2800 searchDelay ?
2801 _fnThrottle( searchFn, searchDelay ) :
2802 searchFn
2803 )
2804 .bind( 'keypress.DT', function(e) {
2805 /* Prevent form submission */
2806 if ( e.keyCode == 13 ) {
2807 return false;
2808 }
2809 } )
2810 .attr('aria-controls', tableId);
2811
2812 // Update the input elements whenever the table is filtered
2813 $(settings.nTable).on( 'search.dt.DT', function ( ev, s ) {
2814 if ( settings === s ) {
2815 // IE9 throws an 'unknown error' if document.activeElement is used
2816 // inside an iframe or frame...
2817 try {
2818 if ( jqFilter[0] !== document.activeElement ) {
2819 jqFilter.val( previousSearch.sSearch );
2820 }
2821 }
2822 catch ( e ) {}
2823 }
2824 } );
2825
2826 return filter[0];
2827 }
2828
2829
2830 /**
2831 * Filter the table using both the global filter and column based filtering
2832 * @param {object} oSettings dataTables settings object
2833 * @param {object} oSearch search information
2834 * @param {int} [iForce] force a research of the master array (1) or not (undefined or 0)
2835 * @memberof DataTable#oApi
2836 */
2837 function _fnFilterComplete ( oSettings, oInput, iForce )
2838 {
2839 var oPrevSearch = oSettings.oPreviousSearch;
2840 var aoPrevSearch = oSettings.aoPreSearchCols;
2841 var fnSaveFilter = function ( oFilter ) {
2842 /* Save the filtering values */
2843 oPrevSearch.sSearch = oFilter.sSearch;
2844 oPrevSearch.bRegex = oFilter.bRegex;
2845 oPrevSearch.bSmart = oFilter.bSmart;
2846 oPrevSearch.bCaseInsensitive = oFilter.bCaseInsensitive;
2847 };
2848 var fnRegex = function ( o ) {
2849 // Backwards compatibility with the bEscapeRegex option
2850 return o.bEscapeRegex !== undefined ? !o.bEscapeRegex : o.bRegex;
2851 };
2852
2853 // Resolve any column types that are unknown due to addition or invalidation
2854 // @todo As per sort - can this be moved into an event handler?
2855 _fnColumnTypes( oSettings );
2856
2857 /* In server-side processing all filtering is done by the server, so no point hanging around here */
2858 if ( _fnDataSource( oSettings ) != 'ssp' )
2859 {
2860 /* Global filter */
2861 _fnFilter( oSettings, oInput.sSearch, iForce, fnRegex(oInput), oInput.bSmart, oInput.bCaseInsensitive );
2862 fnSaveFilter( oInput );
2863
2864 /* Now do the individual column filter */
2865 for ( var i=0 ; i<aoPrevSearch.length ; i++ )
2866 {
2867 _fnFilterColumn( oSettings, aoPrevSearch[i].sSearch, i, fnRegex(aoPrevSearch[i]),
2868 aoPrevSearch[i].bSmart, aoPrevSearch[i].bCaseInsensitive );
2869 }
2870
2871 /* Custom filtering */
2872 _fnFilterCustom( oSettings );
2873 }
2874 else
2875 {
2876 fnSaveFilter( oInput );
2877 }
2878
2879 /* Tell the draw function we have been filtering */
2880 oSettings.bFiltered = true;
2881 _fnCallbackFire( oSettings, null, 'search', [oSettings] );
2882 }
2883
2884
2885 /**
2886 * Apply custom filtering functions
2887 * @param {object} oSettings dataTables settings object
2888 * @memberof DataTable#oApi
2889 */
2890 function _fnFilterCustom( settings )
2891 {
2892 var filters = DataTable.ext.search;
2893 var displayRows = settings.aiDisplay;
2894 var row, rowIdx;
2895
2896 for ( var i=0, ien=filters.length ; i<ien ; i++ ) {
2897 var rows = [];
2898
2899 // Loop over each row and see if it should be included
2900 for ( var j=0, jen=displayRows.length ; j<jen ; j++ ) {
2901 rowIdx = displayRows[ j ];
2902 row = settings.aoData[ rowIdx ];
2903
2904 if ( filters[i]( settings, row._aFilterData, rowIdx, row._aData, j ) ) {
2905 rows.push( rowIdx );
2906 }
2907 }
2908
2909 // So the array reference doesn't break set the results into the
2910 // existing array
2911 displayRows.length = 0;
2912 displayRows.push.apply( displayRows, rows );
2913 }
2914 }
2915
2916
2917 /**
2918 * Filter the table on a per-column basis
2919 * @param {object} oSettings dataTables settings object
2920 * @param {string} sInput string to filter on
2921 * @param {int} iColumn column to filter
2922 * @param {bool} bRegex treat search string as a regular expression or not
2923 * @param {bool} bSmart use smart filtering or not
2924 * @param {bool} bCaseInsensitive Do case insenstive matching or not
2925 * @memberof DataTable#oApi
2926 */
2927 function _fnFilterColumn ( settings, searchStr, colIdx, regex, smart, caseInsensitive )
2928 {
2929 if ( searchStr === '' ) {
2930 return;
2931 }
2932
2933 var data;
2934 var display = settings.aiDisplay;
2935 var rpSearch = _fnFilterCreateSearch( searchStr, regex, smart, caseInsensitive );
2936
2937 for ( var i=display.length-1 ; i>=0 ; i-- ) {
2938 data = settings.aoData[ display[i] ]._aFilterData[ colIdx ];
2939
2940 if ( ! rpSearch.test( data ) ) {
2941 display.splice( i, 1 );
2942 }
2943 }
2944 }
2945
2946
2947 /**
2948 * Filter the data table based on user input and draw the table
2949 * @param {object} settings dataTables settings object
2950 * @param {string} input string to filter on
2951 * @param {int} force optional - force a research of the master array (1) or not (undefined or 0)
2952 * @param {bool} regex treat as a regular expression or not
2953 * @param {bool} smart perform smart filtering or not
2954 * @param {bool} caseInsensitive Do case insenstive matching or not
2955 * @memberof DataTable#oApi
2956 */
2957 function _fnFilter( settings, input, force, regex, smart, caseInsensitive )
2958 {
2959 var rpSearch = _fnFilterCreateSearch( input, regex, smart, caseInsensitive );
2960 var prevSearch = settings.oPreviousSearch.sSearch;
2961 var displayMaster = settings.aiDisplayMaster;
2962 var display, invalidated, i;
2963
2964 // Need to take account of custom filtering functions - always filter
2965 if ( DataTable.ext.search.length !== 0 ) {
2966 force = true;
2967 }
2968
2969 // Check if any of the rows were invalidated
2970 invalidated = _fnFilterData( settings );
2971
2972 // If the input is blank - we just want the full data set
2973 if ( input.length <= 0 ) {
2974 settings.aiDisplay = displayMaster.slice();
2975 }
2976 else {
2977 // New search - start from the master array
2978 if ( invalidated ||
2979 force ||
2980 prevSearch.length > input.length ||
2981 input.indexOf(prevSearch) !== 0 ||
2982 settings.bSorted // On resort, the display master needs to be
2983 // re-filtered since indexes will have changed
2984 ) {
2985 settings.aiDisplay = displayMaster.slice();
2986 }
2987
2988 // Search the display array
2989 display = settings.aiDisplay;
2990
2991 for ( i=display.length-1 ; i>=0 ; i-- ) {
2992 if ( ! rpSearch.test( settings.aoData[ display[i] ]._sFilterRow ) ) {
2993 display.splice( i, 1 );
2994 }
2995 }
2996 }
2997 }
2998
2999
3000 /**
3001 * Build a regular expression object suitable for searching a table
3002 * @param {string} sSearch string to search for
3003 * @param {bool} bRegex treat as a regular expression or not
3004 * @param {bool} bSmart perform smart filtering or not
3005 * @param {bool} bCaseInsensitive Do case insensitive matching or not
3006 * @returns {RegExp} constructed object
3007 * @memberof DataTable#oApi
3008 */
3009 function _fnFilterCreateSearch( search, regex, smart, caseInsensitive )
3010 {
3011 search = regex ?
3012 search :
3013 _fnEscapeRegex( search );
3014
3015 if ( smart ) {
3016 /* For smart filtering we want to allow the search to work regardless of
3017 * word order. We also want double quoted text to be preserved, so word
3018 * order is important - a la google. So this is what we want to
3019 * generate:
3020 *
3021 * ^(?=.*?\bone\b)(?=.*?\btwo three\b)(?=.*?\bfour\b).*$
3022 */
3023 var a = $.map( search.match( /"[^"]+"|[^ ]+/g ) || [''], function ( word ) {
3024 if ( word.charAt(0) === '"' ) {
3025 var m = word.match( /^"(.*)"$/ );
3026 word = m ? m[1] : word;
3027 }
3028
3029 return word.replace('"', '');
3030 } );
3031
3032 search = '^(?=.*?'+a.join( ')(?=.*?' )+').*$';
3033 }
3034
3035 return new RegExp( search, caseInsensitive ? 'i' : '' );
3036 }
3037
3038
3039 /**
3040 * Escape a string such that it can be used in a regular expression
3041 * @param {string} sVal string to escape
3042 * @returns {string} escaped string
3043 * @memberof DataTable#oApi
3044 */
3045 function _fnEscapeRegex ( sVal )
3046 {
3047 return sVal.replace( _re_escape_regex, '\\$1' );
3048 }
3049
3050
3051
3052 var __filter_div = $('<div>')[0];
3053 var __filter_div_textContent = __filter_div.textContent !== undefined;
3054
3055 // Update the filtering data for each row if needed (by invalidation or first run)
3056 function _fnFilterData ( settings )
3057 {
3058 var columns = settings.aoColumns;
3059 var column;
3060 var i, j, ien, jen, filterData, cellData, row;
3061 var fomatters = DataTable.ext.type.search;
3062 var wasInvalidated = false;
3063
3064 for ( i=0, ien=settings.aoData.length ; i<ien ; i++ ) {
3065 row = settings.aoData[i];
3066
3067 if ( ! row._aFilterData ) {
3068 filterData = [];
3069
3070 for ( j=0, jen=columns.length ; j<jen ; j++ ) {
3071 column = columns[j];
3072
3073 if ( column.bSearchable ) {
3074 cellData = _fnGetCellData( settings, i, j, 'filter' );
3075
3076 if ( fomatters[ column.sType ] ) {
3077 cellData = fomatters[ column.sType ]( cellData );
3078 }
3079
3080 // Search in DataTables 1.10 is string based. In 1.11 this
3081 // should be altered to also allow strict type checking.
3082 if ( cellData === null ) {
3083 cellData = '';
3084 }
3085
3086 if ( typeof cellData !== 'string' && cellData.toString ) {
3087 cellData = cellData.toString();
3088 }
3089 }
3090 else {
3091 cellData = '';
3092 }
3093
3094 // If it looks like there is an HTML entity in the string,
3095 // attempt to decode it so sorting works as expected. Note that
3096 // we could use a single line of jQuery to do this, but the DOM
3097 // method used here is much faster http://jsperf.com/html-decode
3098 if ( cellData.indexOf && cellData.indexOf('&') !== -1 ) {
3099 __filter_div.innerHTML = cellData;
3100 cellData = __filter_div_textContent ?
3101 __filter_div.textContent :
3102 __filter_div.innerText;
3103 }
3104
3105 if ( cellData.replace ) {
3106 cellData = cellData.replace(/[\r\n]/g, '');
3107 }
3108
3109 filterData.push( cellData );
3110 }
3111
3112 row._aFilterData = filterData;
3113 row._sFilterRow = filterData.join(' ');
3114 wasInvalidated = true;
3115 }
3116 }
3117
3118 return wasInvalidated;
3119 }
3120
3121
3122 /**
3123 * Convert from the internal Hungarian notation to camelCase for external
3124 * interaction
3125 * @param {object} obj Object to convert
3126 * @returns {object} Inverted object
3127 * @memberof DataTable#oApi
3128 */
3129 function _fnSearchToCamel ( obj )
3130 {
3131 return {
3132 search: obj.sSearch,
3133 smart: obj.bSmart,
3134 regex: obj.bRegex,
3135 caseInsensitive: obj.bCaseInsensitive
3136 };
3137 }
3138
3139
3140
3141 /**
3142 * Convert from camelCase notation to the internal Hungarian. We could use the
3143 * Hungarian convert function here, but this is cleaner
3144 * @param {object} obj Object to convert
3145 * @returns {object} Inverted object
3146 * @memberof DataTable#oApi
3147 */
3148 function _fnSearchToHung ( obj )
3149 {
3150 return {
3151 sSearch: obj.search,
3152 bSmart: obj.smart,
3153 bRegex: obj.regex,
3154 bCaseInsensitive: obj.caseInsensitive
3155 };
3156 }
3157
3158 /**
3159 * Generate the node required for the info display
3160 * @param {object} oSettings dataTables settings object
3161 * @returns {node} Information element
3162 * @memberof DataTable#oApi
3163 */
3164 function _fnFeatureHtmlInfo ( settings )
3165 {
3166 var
3167 tid = settings.sTableId,
3168 nodes = settings.aanFeatures.i,
3169 n = $('<div/>', {
3170 'class': settings.oClasses.sInfo,
3171 'id': ! nodes ? tid+'_info' : null
3172 } );
3173
3174 if ( ! nodes ) {
3175 // Update display on each draw
3176 settings.aoDrawCallback.push( {
3177 "fn": _fnUpdateInfo,
3178 "sName": "information"
3179 } );
3180
3181 n
3182 .attr( 'role', 'status' )
3183 .attr( 'aria-live', 'polite' );
3184
3185 // Table is described by our info div
3186 $(settings.nTable).attr( 'aria-describedby', tid+'_info' );
3187 }
3188
3189 return n[0];
3190 }
3191
3192
3193 /**
3194 * Update the information elements in the display
3195 * @param {object} settings dataTables settings object
3196 * @memberof DataTable#oApi
3197 */
3198 function _fnUpdateInfo ( settings )
3199 {
3200 /* Show information about the table */
3201 var nodes = settings.aanFeatures.i;
3202 if ( nodes.length === 0 ) {
3203 return;
3204 }
3205
3206 var
3207 lang = settings.oLanguage,
3208 start = settings._iDisplayStart+1,
3209 end = settings.fnDisplayEnd(),
3210 max = settings.fnRecordsTotal(),
3211 total = settings.fnRecordsDisplay(),
3212 out = total ?
3213 lang.sInfo :
3214 lang.sInfoEmpty;
3215
3216 if ( total !== max ) {
3217 /* Record set after filtering */
3218 out += ' ' + lang.sInfoFiltered;
3219 }
3220
3221 // Convert the macros
3222 out += lang.sInfoPostFix;
3223 out = _fnInfoMacros( settings, out );
3224
3225 var callback = lang.fnInfoCallback;
3226 if ( callback !== null ) {
3227 out = callback.call( settings.oInstance,
3228 settings, start, end, max, total, out
3229 );
3230 }
3231
3232 $(nodes).html( out );
3233 }
3234
3235
3236 function _fnInfoMacros ( settings, str )
3237 {
3238 // When infinite scrolling, we are always starting at 1. _iDisplayStart is used only
3239 // internally
3240 var
3241 formatter = settings.fnFormatNumber,
3242 start = settings._iDisplayStart+1,
3243 len = settings._iDisplayLength,
3244 vis = settings.fnRecordsDisplay(),
3245 all = len === -1;
3246
3247 return str.
3248 replace(/_START_/g, formatter.call( settings, start ) ).
3249 replace(/_END_/g, formatter.call( settings, settings.fnDisplayEnd() ) ).
3250 replace(/_MAX_/g, formatter.call( settings, settings.fnRecordsTotal() ) ).
3251 replace(/_TOTAL_/g, formatter.call( settings, vis ) ).
3252 replace(/_PAGE_/g, formatter.call( settings, all ? 1 : Math.ceil( start / len ) ) ).
3253 replace(/_PAGES_/g, formatter.call( settings, all ? 1 : Math.ceil( vis / len ) ) );
3254 }
3255
3256
3257
3258 /**
3259 * Draw the table for the first time, adding all required features
3260 * @param {object} settings dataTables settings object
3261 * @memberof DataTable#oApi
3262 */
3263 function _fnInitialise ( settings )
3264 {
3265 var i, iLen, iAjaxStart=settings.iInitDisplayStart;
3266 var columns = settings.aoColumns, column;
3267 var features = settings.oFeatures;
3268
3269 /* Ensure that the table data is fully initialised */
3270 if ( ! settings.bInitialised ) {
3271 setTimeout( function(){ _fnInitialise( settings ); }, 200 );
3272 return;
3273 }
3274
3275 /* Show the display HTML options */
3276 _fnAddOptionsHtml( settings );
3277
3278 /* Build and draw the header / footer for the table */
3279 _fnBuildHead( settings );
3280 _fnDrawHead( settings, settings.aoHeader );
3281 _fnDrawHead( settings, settings.aoFooter );
3282
3283 /* Okay to show that something is going on now */
3284 _fnProcessingDisplay( settings, true );
3285
3286 /* Calculate sizes for columns */
3287 if ( features.bAutoWidth ) {
3288 _fnCalculateColumnWidths( settings );
3289 }
3290
3291 for ( i=0, iLen=columns.length ; i<iLen ; i++ ) {
3292 column = columns[i];
3293
3294 if ( column.sWidth ) {
3295 column.nTh.style.width = _fnStringToCss( column.sWidth );
3296 }
3297 }
3298
3299 // If there is default sorting required - let's do it. The sort function
3300 // will do the drawing for us. Otherwise we draw the table regardless of the
3301 // Ajax source - this allows the table to look initialised for Ajax sourcing
3302 // data (show 'loading' message possibly)
3303 _fnReDraw( settings );
3304
3305 // Server-side processing init complete is done by _fnAjaxUpdateDraw
3306 var dataSrc = _fnDataSource( settings );
3307 if ( dataSrc != 'ssp' ) {
3308 // if there is an ajax source load the data
3309 if ( dataSrc == 'ajax' ) {
3310 _fnBuildAjax( settings, [], function(json) {
3311 var aData = _fnAjaxDataSrc( settings, json );
3312
3313 // Got the data - add it to the table
3314 for ( i=0 ; i<aData.length ; i++ ) {
3315 _fnAddData( settings, aData[i] );
3316 }
3317
3318 // Reset the init display for cookie saving. We've already done
3319 // a filter, and therefore cleared it before. So we need to make
3320 // it appear 'fresh'
3321 settings.iInitDisplayStart = iAjaxStart;
3322
3323 _fnReDraw( settings );
3324
3325 _fnProcessingDisplay( settings, false );
3326 _fnInitComplete( settings, json );
3327 }, settings );
3328 }
3329 else {
3330 _fnProcessingDisplay( settings, false );
3331 _fnInitComplete( settings );
3332 }
3333 }
3334 }
3335
3336
3337 /**
3338 * Draw the table for the first time, adding all required features
3339 * @param {object} oSettings dataTables settings object
3340 * @param {object} [json] JSON from the server that completed the table, if using Ajax source
3341 * with client-side processing (optional)
3342 * @memberof DataTable#oApi
3343 */
3344 function _fnInitComplete ( settings, json )
3345 {
3346 settings._bInitComplete = true;
3347
3348 // On an Ajax load we now have data and therefore want to apply the column
3349 // sizing
3350 if ( json ) {
3351 _fnAdjustColumnSizing( settings );
3352 }
3353
3354 _fnCallbackFire( settings, 'aoInitComplete', 'init', [settings, json] );
3355 }
3356
3357
3358 function _fnLengthChange ( settings, val )
3359 {
3360 var len = parseInt( val, 10 );
3361 settings._iDisplayLength = len;
3362
3363 _fnLengthOverflow( settings );
3364
3365 // Fire length change event
3366 _fnCallbackFire( settings, null, 'length', [settings, len] );
3367 }
3368
3369
3370 /**
3371 * Generate the node required for user display length changing
3372 * @param {object} settings dataTables settings object
3373 * @returns {node} Display length feature node
3374 * @memberof DataTable#oApi
3375 */
3376 function _fnFeatureHtmlLength ( settings )
3377 {
3378 var
3379 classes = settings.oClasses,
3380 tableId = settings.sTableId,
3381 menu = settings.aLengthMenu,
3382 d2 = $.isArray( menu[0] ),
3383 lengths = d2 ? menu[0] : menu,
3384 language = d2 ? menu[1] : menu;
3385
3386 var select = $('<select/>', {
3387 'name': tableId+'_length',
3388 'aria-controls': tableId,
3389 'class': classes.sLengthSelect
3390 } );
3391
3392 for ( var i=0, ien=lengths.length ; i<ien ; i++ ) {
3393 select[0][ i ] = new Option( language[i], lengths[i] );
3394 }
3395
3396 var div = $('<div><label/></div>').addClass( classes.sLength );
3397 if ( ! settings.aanFeatures.l ) {
3398 div[0].id = tableId+'_length';
3399 }
3400
3401 div.children().append(
3402 settings.oLanguage.sLengthMenu.replace( '_MENU_', select[0].outerHTML )
3403 );
3404
3405 // Can't use `select` variable as user might provide their own and the
3406 // reference is broken by the use of outerHTML
3407 $('select', div)
3408 .val( settings._iDisplayLength )
3409 .bind( 'change.DT', function(e) {
3410 _fnLengthChange( settings, $(this).val() );
3411 _fnDraw( settings );
3412 } );
3413
3414 // Update node value whenever anything changes the table's length
3415 $(settings.nTable).bind( 'length.dt.DT', function (e, s, len) {
3416 if ( settings === s ) {
3417 $('select', div).val( len );
3418 }
3419 } );
3420
3421 return div[0];
3422 }
3423
3424
3425
3426 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
3427 * Note that most of the paging logic is done in
3428 * DataTable.ext.pager
3429 */
3430
3431 /**
3432 * Generate the node required for default pagination
3433 * @param {object} oSettings dataTables settings object
3434 * @returns {node} Pagination feature node
3435 * @memberof DataTable#oApi
3436 */
3437 function _fnFeatureHtmlPaginate ( settings )
3438 {
3439 var
3440 type = settings.sPaginationType,
3441 plugin = DataTable.ext.pager[ type ],
3442 modern = typeof plugin === 'function',
3443 redraw = function( settings ) {
3444 _fnDraw( settings );
3445 },
3446 node = $('<div/>').addClass( settings.oClasses.sPaging + type )[0],
3447 features = settings.aanFeatures;
3448
3449 if ( ! modern ) {
3450 plugin.fnInit( settings, node, redraw );
3451 }
3452
3453 /* Add a draw callback for the pagination on first instance, to update the paging display */
3454 if ( ! features.p )
3455 {
3456 node.id = settings.sTableId+'_paginate';
3457
3458 settings.aoDrawCallback.push( {
3459 "fn": function( settings ) {
3460 if ( modern ) {
3461 var
3462 start = settings._iDisplayStart,
3463 len = settings._iDisplayLength,
3464 visRecords = settings.fnRecordsDisplay(),
3465 all = len === -1,
3466 page = all ? 0 : Math.ceil( start / len ),
3467 pages = all ? 1 : Math.ceil( visRecords / len ),
3468 buttons = plugin(page, pages),
3469 i, ien;
3470
3471 for ( i=0, ien=features.p.length ; i<ien ; i++ ) {
3472 _fnRenderer( settings, 'pageButton' )(
3473 settings, features.p[i], i, buttons, page, pages
3474 );
3475 }
3476 }
3477 else {
3478 plugin.fnUpdate( settings, redraw );
3479 }
3480 },
3481 "sName": "pagination"
3482 } );
3483 }
3484
3485 return node;
3486 }
3487
3488
3489 /**
3490 * Alter the display settings to change the page
3491 * @param {object} settings DataTables settings object
3492 * @param {string|int} action Paging action to take: "first", "previous",
3493 * "next" or "last" or page number to jump to (integer)
3494 * @param [bool] redraw Automatically draw the update or not
3495 * @returns {bool} true page has changed, false - no change
3496 * @memberof DataTable#oApi
3497 */
3498 function _fnPageChange ( settings, action, redraw )
3499 {
3500 var
3501 start = settings._iDisplayStart,
3502 len = settings._iDisplayLength,
3503 records = settings.fnRecordsDisplay();
3504
3505 if ( records === 0 || len === -1 )
3506 {
3507 start = 0;
3508 }
3509 else if ( typeof action === "number" )
3510 {
3511 start = action * len;
3512
3513 if ( start > records )
3514 {
3515 start = 0;
3516 }
3517 }
3518 else if ( action == "first" )
3519 {
3520 start = 0;
3521 }
3522 else if ( action == "previous" )
3523 {
3524 start = len >= 0 ?
3525 start - len :
3526 0;
3527
3528 if ( start < 0 )
3529 {
3530 start = 0;
3531 }
3532 }
3533 else if ( action == "next" )
3534 {
3535 if ( start + len < records )
3536 {
3537 start += len;
3538 }
3539 }
3540 else if ( action == "last" )
3541 {
3542 start = Math.floor( (records-1) / len) * len;
3543 }
3544 else
3545 {
3546 _fnLog( settings, 0, "Unknown paging action: "+action, 5 );
3547 }
3548
3549 var changed = settings._iDisplayStart !== start;
3550 settings._iDisplayStart = start;
3551
3552 if ( changed ) {
3553 _fnCallbackFire( settings, null, 'page', [settings] );
3554
3555 if ( redraw ) {
3556 _fnDraw( settings );
3557 }
3558 }
3559
3560 return changed;
3561 }
3562
3563
3564
3565 /**
3566 * Generate the node required for the processing node
3567 * @param {object} settings dataTables settings object
3568 * @returns {node} Processing element
3569 * @memberof DataTable#oApi
3570 */
3571 function _fnFeatureHtmlProcessing ( settings )
3572 {
3573 return $('<div/>', {
3574 'id': ! settings.aanFeatures.r ? settings.sTableId+'_processing' : null,
3575 'class': settings.oClasses.sProcessing
3576 } )
3577 .html( settings.oLanguage.sProcessing )
3578 .insertBefore( settings.nTable )[0];
3579 }
3580
3581
3582 /**
3583 * Display or hide the processing indicator
3584 * @param {object} settings dataTables settings object
3585 * @param {bool} show Show the processing indicator (true) or not (false)
3586 * @memberof DataTable#oApi
3587 */
3588 function _fnProcessingDisplay ( settings, show )
3589 {
3590 if ( settings.oFeatures.bProcessing ) {
3591 $(settings.aanFeatures.r).css( 'display', show ? 'block' : 'none' );
3592 }
3593
3594 _fnCallbackFire( settings, null, 'processing', [settings, show] );
3595 }
3596
3597 /**
3598 * Add any control elements for the table - specifically scrolling
3599 * @param {object} settings dataTables settings object
3600 * @returns {node} Node to add to the DOM
3601 * @memberof DataTable#oApi
3602 */
3603 function _fnFeatureHtmlTable ( settings )
3604 {
3605 var table = $(settings.nTable);
3606
3607 // Add the ARIA grid role to the table
3608 table.attr( 'role', 'grid' );
3609
3610 // Scrolling from here on in
3611 var scroll = settings.oScroll;
3612
3613 if ( scroll.sX === '' && scroll.sY === '' ) {
3614 return settings.nTable;
3615 }
3616
3617 var scrollX = scroll.sX;
3618 var scrollY = scroll.sY;
3619 var classes = settings.oClasses;
3620 var caption = table.children('caption');
3621 var captionSide = caption.length ? caption[0]._captionSide : null;
3622 var headerClone = $( table[0].cloneNode(false) );
3623 var footerClone = $( table[0].cloneNode(false) );
3624 var footer = table.children('tfoot');
3625 var _div = '<div/>';
3626 var size = function ( s ) {
3627 return !s ? null : _fnStringToCss( s );
3628 };
3629
3630 // This is fairly messy, but with x scrolling enabled, if the table has a
3631 // width attribute, regardless of any width applied using the column width
3632 // options, the browser will shrink or grow the table as needed to fit into
3633 // that 100%. That would make the width options useless. So we remove it.
3634 // This is okay, under the assumption that width:100% is applied to the
3635 // table in CSS (it is in the default stylesheet) which will set the table
3636 // width as appropriate (the attribute and css behave differently...)
3637 if ( scroll.sX && table.attr('width') === '100%' ) {
3638 table.removeAttr('width');
3639 }
3640
3641 if ( ! footer.length ) {
3642 footer = null;
3643 }
3644
3645 /*
3646 * The HTML structure that we want to generate in this function is:
3647 * div - scroller
3648 * div - scroll head
3649 * div - scroll head inner
3650 * table - scroll head table
3651 * thead - thead
3652 * div - scroll body
3653 * table - table (master table)
3654 * thead - thead clone for sizing
3655 * tbody - tbody
3656 * div - scroll foot
3657 * div - scroll foot inner
3658 * table - scroll foot table
3659 * tfoot - tfoot
3660 */
3661 var scroller = $( _div, { 'class': classes.sScrollWrapper } )
3662 .append(
3663 $(_div, { 'class': classes.sScrollHead } )
3664 .css( {
3665 overflow: 'hidden',
3666 position: 'relative',
3667 border: 0,
3668 width: scrollX ? size(scrollX) : '100%'
3669 } )
3670 .append(
3671 $(_div, { 'class': classes.sScrollHeadInner } )
3672 .css( {
3673 'box-sizing': 'content-box',
3674 width: scroll.sXInner || '100%'
3675 } )
3676 .append(
3677 headerClone
3678 .removeAttr('id')
3679 .css( 'margin-left', 0 )
3680 .append( captionSide === 'top' ? caption : null )
3681 .append(
3682 table.children('thead')
3683 )
3684 )
3685 )
3686 )
3687 .append(
3688 $(_div, { 'class': classes.sScrollBody } )
3689 .css( {
3690 overflow: 'auto',
3691 height: size( scrollY ),
3692 width: size( scrollX )
3693 } )
3694 .append( table )
3695 );
3696
3697 if ( footer ) {
3698 scroller.append(
3699 $(_div, { 'class': classes.sScrollFoot } )
3700 .css( {
3701 overflow: 'hidden',
3702 border: 0,
3703 width: scrollX ? size(scrollX) : '100%'
3704 } )
3705 .append(
3706 $(_div, { 'class': classes.sScrollFootInner } )
3707 .append(
3708 footerClone
3709 .removeAttr('id')
3710 .css( 'margin-left', 0 )
3711 .append( captionSide === 'bottom' ? caption : null )
3712 .append(
3713 table.children('tfoot')
3714 )
3715 )
3716 )
3717 );
3718 }
3719
3720 var children = scroller.children();
3721 var scrollHead = children[0];
3722 var scrollBody = children[1];
3723 var scrollFoot = footer ? children[2] : null;
3724
3725 // When the body is scrolled, then we also want to scroll the headers
3726 if ( scrollX ) {
3727 $(scrollBody).on( 'scroll.DT', function (e) {
3728 var scrollLeft = this.scrollLeft;
3729
3730 scrollHead.scrollLeft = scrollLeft;
3731
3732 if ( footer ) {
3733 scrollFoot.scrollLeft = scrollLeft;
3734 }
3735 } );
3736 }
3737
3738 settings.nScrollHead = scrollHead;
3739 settings.nScrollBody = scrollBody;
3740 settings.nScrollFoot = scrollFoot;
3741
3742 // On redraw - align columns
3743 settings.aoDrawCallback.push( {
3744 "fn": _fnScrollDraw,
3745 "sName": "scrolling"
3746 } );
3747
3748 return scroller[0];
3749 }
3750
3751
3752
3753 /**
3754 * Update the header, footer and body tables for resizing - i.e. column
3755 * alignment.
3756 *
3757 * Welcome to the most horrible function DataTables. The process that this
3758 * function follows is basically:
3759 * 1. Re-create the table inside the scrolling div
3760 * 2. Take live measurements from the DOM
3761 * 3. Apply the measurements to align the columns
3762 * 4. Clean up
3763 *
3764 * @param {object} settings dataTables settings object
3765 * @memberof DataTable#oApi
3766 */
3767 function _fnScrollDraw ( settings )
3768 {
3769 // Given that this is such a monster function, a lot of variables are use
3770 // to try and keep the minimised size as small as possible
3771 var
3772 scroll = settings.oScroll,
3773 scrollX = scroll.sX,
3774 scrollXInner = scroll.sXInner,
3775 scrollY = scroll.sY,
3776 barWidth = scroll.iBarWidth,
3777 divHeader = $(settings.nScrollHead),
3778 divHeaderStyle = divHeader[0].style,
3779 divHeaderInner = divHeader.children('div'),
3780 divHeaderInnerStyle = divHeaderInner[0].style,
3781 divHeaderTable = divHeaderInner.children('table'),
3782 divBodyEl = settings.nScrollBody,
3783 divBody = $(divBodyEl),
3784 divBodyStyle = divBodyEl.style,
3785 divFooter = $(settings.nScrollFoot),
3786 divFooterInner = divFooter.children('div'),
3787 divFooterTable = divFooterInner.children('table'),
3788 header = $(settings.nTHead),
3789 table = $(settings.nTable),
3790 tableEl = table[0],
3791 tableStyle = tableEl.style,
3792 footer = settings.nTFoot ? $(settings.nTFoot) : null,
3793 browser = settings.oBrowser,
3794 ie67 = browser.bScrollOversize,
3795 headerTrgEls, footerTrgEls,
3796 headerSrcEls, footerSrcEls,
3797 headerCopy, footerCopy,
3798 headerWidths=[], footerWidths=[],
3799 headerContent=[],
3800 idx, correction, sanityWidth,
3801 zeroOut = function(nSizer) {
3802 var style = nSizer.style;
3803 style.paddingTop = "0";
3804 style.paddingBottom = "0";
3805 style.borderTopWidth = "0";
3806 style.borderBottomWidth = "0";
3807 style.height = 0;
3808 };
3809
3810 /*
3811 * 1. Re-create the table inside the scrolling div
3812 */
3813
3814 // Remove the old minimised thead and tfoot elements in the inner table
3815 table.children('thead, tfoot').remove();
3816
3817 // Clone the current header and footer elements and then place it into the inner table
3818 headerCopy = header.clone().prependTo( table );
3819 headerTrgEls = header.find('tr'); // original header is in its own table
3820 headerSrcEls = headerCopy.find('tr');
3821 headerCopy.find('th, td').removeAttr('tabindex');
3822
3823 if ( footer ) {
3824 footerCopy = footer.clone().prependTo( table );
3825 footerTrgEls = footer.find('tr'); // the original tfoot is in its own table and must be sized
3826 footerSrcEls = footerCopy.find('tr');
3827 }
3828
3829
3830 /*
3831 * 2. Take live measurements from the DOM - do not alter the DOM itself!
3832 */
3833
3834 // Remove old sizing and apply the calculated column widths
3835 // Get the unique column headers in the newly created (cloned) header. We want to apply the
3836 // calculated sizes to this header
3837 if ( ! scrollX )
3838 {
3839 divBodyStyle.width = '100%';
3840 divHeader[0].style.width = '100%';
3841 }
3842
3843 $.each( _fnGetUniqueThs( settings, headerCopy ), function ( i, el ) {
3844 idx = _fnVisibleToColumnIndex( settings, i );
3845 el.style.width = settings.aoColumns[idx].sWidth;
3846 } );
3847
3848 if ( footer ) {
3849 _fnApplyToChildren( function(n) {
3850 n.style.width = "";
3851 }, footerSrcEls );
3852 }
3853
3854 // If scroll collapse is enabled, when we put the headers back into the body for sizing, we
3855 // will end up forcing the scrollbar to appear, making our measurements wrong for when we
3856 // then hide it (end of this function), so add the header height to the body scroller.
3857 if ( scroll.bCollapse && scrollY !== "" ) {
3858 divBodyStyle.height = (divBody[0].offsetHeight + header[0].offsetHeight)+"px";
3859 }
3860
3861 // Size the table as a whole
3862 sanityWidth = table.outerWidth();
3863 if ( scrollX === "" ) {
3864 // No x scrolling
3865 tableStyle.width = "100%";
3866
3867 // IE7 will make the width of the table when 100% include the scrollbar
3868 // - which is shouldn't. When there is a scrollbar we need to take this
3869 // into account.
3870 if ( ie67 && (table.find('tbody').height() > divBodyEl.offsetHeight ||
3871 divBody.css('overflow-y') == "scroll")
3872 ) {
3873 tableStyle.width = _fnStringToCss( table.outerWidth() - barWidth);
3874 }
3875 }
3876 else
3877 {
3878 // x scrolling
3879 if ( scrollXInner !== "" ) {
3880 // x scroll inner has been given - use it
3881 tableStyle.width = _fnStringToCss(scrollXInner);
3882 }
3883 else if ( sanityWidth == divBody.width() && divBody.height() < table.height() ) {
3884 // There is y-scrolling - try to take account of the y scroll bar
3885 tableStyle.width = _fnStringToCss( sanityWidth-barWidth );
3886 if ( table.outerWidth() > sanityWidth-barWidth ) {
3887 // Not possible to take account of it
3888 tableStyle.width = _fnStringToCss( sanityWidth );
3889 }
3890 }
3891 else {
3892 // When all else fails
3893 tableStyle.width = _fnStringToCss( sanityWidth );
3894 }
3895 }
3896
3897 // Recalculate the sanity width - now that we've applied the required width,
3898 // before it was a temporary variable. This is required because the column
3899 // width calculation is done before this table DOM is created.
3900 sanityWidth = table.outerWidth();
3901
3902 // Hidden header should have zero height, so remove padding and borders. Then
3903 // set the width based on the real headers
3904
3905 // Apply all styles in one pass
3906 _fnApplyToChildren( zeroOut, headerSrcEls );
3907
3908 // Read all widths in next pass
3909 _fnApplyToChildren( function(nSizer) {
3910 headerContent.push( nSizer.innerHTML );
3911 headerWidths.push( _fnStringToCss( $(nSizer).css('width') ) );
3912 }, headerSrcEls );
3913
3914 // Apply all widths in final pass
3915 _fnApplyToChildren( function(nToSize, i) {
3916 nToSize.style.width = headerWidths[i];
3917 }, headerTrgEls );
3918
3919 $(headerSrcEls).height(0);
3920
3921 /* Same again with the footer if we have one */
3922 if ( footer )
3923 {
3924 _fnApplyToChildren( zeroOut, footerSrcEls );
3925
3926 _fnApplyToChildren( function(nSizer) {
3927 footerWidths.push( _fnStringToCss( $(nSizer).css('width') ) );
3928 }, footerSrcEls );
3929
3930 _fnApplyToChildren( function(nToSize, i) {
3931 nToSize.style.width = footerWidths[i];
3932 }, footerTrgEls );
3933
3934 $(footerSrcEls).height(0);
3935 }
3936
3937
3938 /*
3939 * 3. Apply the measurements
3940 */
3941
3942 // "Hide" the header and footer that we used for the sizing. We need to keep
3943 // the content of the cell so that the width applied to the header and body
3944 // both match, but we want to hide it completely. We want to also fix their
3945 // width to what they currently are
3946 _fnApplyToChildren( function(nSizer, i) {
3947 nSizer.innerHTML = '<div class="dataTables_sizing" style="height:0;overflow:hidden;">'+headerContent[i]+'</div>';
3948 nSizer.style.width = headerWidths[i];
3949 }, headerSrcEls );
3950
3951 if ( footer )
3952 {
3953 _fnApplyToChildren( function(nSizer, i) {
3954 nSizer.innerHTML = "";
3955 nSizer.style.width = footerWidths[i];
3956 }, footerSrcEls );
3957 }
3958
3959 // Sanity check that the table is of a sensible width. If not then we are going to get
3960 // misalignment - try to prevent this by not allowing the table to shrink below its min width
3961 if ( table.outerWidth() < sanityWidth )
3962 {
3963 // The min width depends upon if we have a vertical scrollbar visible or not */
3964 correction = ((divBodyEl.scrollHeight > divBodyEl.offsetHeight ||
3965 divBody.css('overflow-y') == "scroll")) ?
3966 sanityWidth+barWidth :
3967 sanityWidth;
3968
3969 // IE6/7 are a law unto themselves...
3970 if ( ie67 && (divBodyEl.scrollHeight >
3971 divBodyEl.offsetHeight || divBody.css('overflow-y') == "scroll")
3972 ) {
3973 tableStyle.width = _fnStringToCss( correction-barWidth );
3974 }
3975
3976 // And give the user a warning that we've stopped the table getting too small
3977 if ( scrollX === "" || scrollXInner !== "" ) {
3978 _fnLog( settings, 1, 'Possible column misalignment', 6 );
3979 }
3980 }
3981 else
3982 {
3983 correction = '100%';
3984 }
3985
3986 // Apply to the container elements
3987 divBodyStyle.width = _fnStringToCss( correction );
3988 divHeaderStyle.width = _fnStringToCss( correction );
3989
3990 if ( footer ) {
3991 settings.nScrollFoot.style.width = _fnStringToCss( correction );
3992 }
3993
3994
3995 /*
3996 * 4. Clean up
3997 */
3998 if ( ! scrollY ) {
3999 /* IE7< puts a vertical scrollbar in place (when it shouldn't be) due to subtracting
4000 * the scrollbar height from the visible display, rather than adding it on. We need to
4001 * set the height in order to sort this. Don't want to do it in any other browsers.
4002 */
4003 if ( ie67 ) {
4004 divBodyStyle.height = _fnStringToCss( tableEl.offsetHeight+barWidth );
4005 }
4006 }
4007
4008 if ( scrollY && scroll.bCollapse ) {
4009 divBodyStyle.height = _fnStringToCss( scrollY );
4010
4011 var iExtra = (scrollX && tableEl.offsetWidth > divBodyEl.offsetWidth) ?
4012 barWidth :
4013 0;
4014
4015 if ( tableEl.offsetHeight < divBodyEl.offsetHeight ) {
4016 divBodyStyle.height = _fnStringToCss( tableEl.offsetHeight+iExtra );
4017 }
4018 }
4019
4020 /* Finally set the width's of the header and footer tables */
4021 var iOuterWidth = table.outerWidth();
4022 divHeaderTable[0].style.width = _fnStringToCss( iOuterWidth );
4023 divHeaderInnerStyle.width = _fnStringToCss( iOuterWidth );
4024
4025 // Figure out if there are scrollbar present - if so then we need a the header and footer to
4026 // provide a bit more space to allow "overflow" scrolling (i.e. past the scrollbar)
4027 var bScrolling = table.height() > divBodyEl.clientHeight || divBody.css('overflow-y') == "scroll";
4028 var padding = 'padding' + (browser.bScrollbarLeft ? 'Left' : 'Right' );
4029 divHeaderInnerStyle[ padding ] = bScrolling ? barWidth+"px" : "0px";
4030
4031 if ( footer ) {
4032 divFooterTable[0].style.width = _fnStringToCss( iOuterWidth );
4033 divFooterInner[0].style.width = _fnStringToCss( iOuterWidth );
4034 divFooterInner[0].style[padding] = bScrolling ? barWidth+"px" : "0px";
4035 }
4036
4037 /* Adjust the position of the header in case we loose the y-scrollbar */
4038 divBody.scroll();
4039
4040 // If sorting or filtering has occurred, jump the scrolling back to the top
4041 // only if we aren't holding the position
4042 if ( (settings.bSorted || settings.bFiltered) && ! settings._drawHold ) {
4043 divBodyEl.scrollTop = 0;
4044 }
4045 }
4046
4047
4048
4049 /**
4050 * Apply a given function to the display child nodes of an element array (typically
4051 * TD children of TR rows
4052 * @param {function} fn Method to apply to the objects
4053 * @param array {nodes} an1 List of elements to look through for display children
4054 * @param array {nodes} an2 Another list (identical structure to the first) - optional
4055 * @memberof DataTable#oApi
4056 */
4057 function _fnApplyToChildren( fn, an1, an2 )
4058 {
4059 var index=0, i=0, iLen=an1.length;
4060 var nNode1, nNode2;
4061
4062 while ( i < iLen ) {
4063 nNode1 = an1[i].firstChild;
4064 nNode2 = an2 ? an2[i].firstChild : null;
4065
4066 while ( nNode1 ) {
4067 if ( nNode1.nodeType === 1 ) {
4068 if ( an2 ) {
4069 fn( nNode1, nNode2, index );
4070 }
4071 else {
4072 fn( nNode1, index );
4073 }
4074
4075 index++;
4076 }
4077
4078 nNode1 = nNode1.nextSibling;
4079 nNode2 = an2 ? nNode2.nextSibling : null;
4080 }
4081
4082 i++;
4083 }
4084 }
4085
4086
4087
4088 var __re_html_remove = /<.*?>/g;
4089
4090
4091 /**
4092 * Calculate the width of columns for the table
4093 * @param {object} oSettings dataTables settings object
4094 * @memberof DataTable#oApi
4095 */
4096 function _fnCalculateColumnWidths ( oSettings )
4097 {
4098 var
4099 table = oSettings.nTable,
4100 columns = oSettings.aoColumns,
4101 scroll = oSettings.oScroll,
4102 scrollY = scroll.sY,
4103 scrollX = scroll.sX,
4104 scrollXInner = scroll.sXInner,
4105 columnCount = columns.length,
4106 visibleColumns = _fnGetColumns( oSettings, 'bVisible' ),
4107 headerCells = $('th', oSettings.nTHead),
4108 tableWidthAttr = table.getAttribute('width'), // from DOM element
4109 tableContainer = table.parentNode,
4110 userInputs = false,
4111 i, column, columnIdx, width, outerWidth;
4112
4113 var styleWidth = table.style.width;
4114 if ( styleWidth && styleWidth.indexOf('%') !== -1 ) {
4115 tableWidthAttr = styleWidth;
4116 }
4117
4118 /* Convert any user input sizes into pixel sizes */
4119 for ( i=0 ; i<visibleColumns.length ; i++ ) {
4120 column = columns[ visibleColumns[i] ];
4121
4122 if ( column.sWidth !== null ) {
4123 column.sWidth = _fnConvertToWidth( column.sWidthOrig, tableContainer );
4124
4125 userInputs = true;
4126 }
4127 }
4128
4129 /* If the number of columns in the DOM equals the number that we have to
4130 * process in DataTables, then we can use the offsets that are created by
4131 * the web- browser. No custom sizes can be set in order for this to happen,
4132 * nor scrolling used
4133 */
4134 if ( ! userInputs && ! scrollX && ! scrollY &&
4135 columnCount == _fnVisbleColumns( oSettings ) &&
4136 columnCount == headerCells.length
4137 ) {
4138 for ( i=0 ; i<columnCount ; i++ ) {
4139 columns[i].sWidth = _fnStringToCss( headerCells.eq(i).width() );
4140 }
4141 }
4142 else
4143 {
4144 // Otherwise construct a single row, worst case, table with the widest
4145 // node in the data, assign any user defined widths, then insert it into
4146 // the DOM and allow the browser to do all the hard work of calculating
4147 // table widths
4148 var tmpTable = $(table).clone() // don't use cloneNode - IE8 will remove events on the main table
4149 .css( 'visibility', 'hidden' )
4150 .removeAttr( 'id' );
4151
4152 // Clean up the table body
4153 tmpTable.find('tbody tr').remove();
4154 var tr = $('<tr/>').appendTo( tmpTable.find('tbody') );
4155
4156 // Remove any assigned widths from the footer (from scrolling)
4157 tmpTable.find('tfoot th, tfoot td').css('width', '');
4158
4159 // Apply custom sizing to the cloned header
4160 headerCells = _fnGetUniqueThs( oSettings, tmpTable.find('thead')[0] );
4161
4162 for ( i=0 ; i<visibleColumns.length ; i++ ) {
4163 column = columns[ visibleColumns[i] ];
4164
4165 headerCells[i].style.width = column.sWidthOrig !== null && column.sWidthOrig !== '' ?
4166 _fnStringToCss( column.sWidthOrig ) :
4167 '';
4168 }
4169
4170 // Find the widest cell for each column and put it into the table
4171 if ( oSettings.aoData.length ) {
4172 for ( i=0 ; i<visibleColumns.length ; i++ ) {
4173 columnIdx = visibleColumns[i];
4174 column = columns[ columnIdx ];
4175
4176 $( _fnGetWidestNode( oSettings, columnIdx ) )
4177 .clone( false )
4178 .append( column.sContentPadding )
4179 .appendTo( tr );
4180 }
4181 }
4182
4183 // Table has been built, attach to the document so we can work with it
4184 tmpTable.appendTo( tableContainer );
4185
4186 // When scrolling (X or Y) we want to set the width of the table as
4187 // appropriate. However, when not scrolling leave the table width as it
4188 // is. This results in slightly different, but I think correct behaviour
4189 if ( scrollX && scrollXInner ) {
4190 tmpTable.width( scrollXInner );
4191 }
4192 else if ( scrollX ) {
4193 tmpTable.css( 'width', 'auto' );
4194
4195 if ( tmpTable.width() < tableContainer.offsetWidth ) {
4196 tmpTable.width( tableContainer.offsetWidth );
4197 }
4198 }
4199 else if ( scrollY ) {
4200 tmpTable.width( tableContainer.offsetWidth );
4201 }
4202 else if ( tableWidthAttr ) {
4203 tmpTable.width( tableWidthAttr );
4204 }
4205
4206 // Take into account the y scrollbar
4207 _fnScrollingWidthAdjust( oSettings, tmpTable[0] );
4208
4209 // Browsers need a bit of a hand when a width is assigned to any columns
4210 // when x-scrolling as they tend to collapse the table to the min-width,
4211 // even if we sent the column widths. So we need to keep track of what
4212 // the table width should be by summing the user given values, and the
4213 // automatic values
4214 if ( scrollX )
4215 {
4216 var total = 0;
4217
4218 for ( i=0 ; i<visibleColumns.length ; i++ ) {
4219 column = columns[ visibleColumns[i] ];
4220 outerWidth = $(headerCells[i]).outerWidth();
4221
4222 total += column.sWidthOrig === null ?
4223 outerWidth :
4224 parseInt( column.sWidth, 10 ) + outerWidth - $(headerCells[i]).width();
4225 }
4226
4227 tmpTable.width( _fnStringToCss( total ) );
4228 table.style.width = _fnStringToCss( total );
4229 }
4230
4231 // Get the width of each column in the constructed table
4232 for ( i=0 ; i<visibleColumns.length ; i++ ) {
4233 column = columns[ visibleColumns[i] ];
4234 width = $(headerCells[i]).width();
4235
4236 if ( width ) {
4237 column.sWidth = _fnStringToCss( width );
4238 }
4239 }
4240
4241 table.style.width = _fnStringToCss( tmpTable.css('width') );
4242
4243 // Finished with the table - ditch it
4244 tmpTable.remove();
4245 }
4246
4247 // If there is a width attr, we want to attach an event listener which
4248 // allows the table sizing to automatically adjust when the window is
4249 // resized. Use the width attr rather than CSS, since we can't know if the
4250 // CSS is a relative value or absolute - DOM read is always px.
4251 if ( tableWidthAttr ) {
4252 table.style.width = _fnStringToCss( tableWidthAttr );
4253 }
4254
4255 if ( (tableWidthAttr || scrollX) && ! oSettings._reszEvt ) {
4256 var bindResize = function () {
4257 $(window).bind('resize.DT-'+oSettings.sInstance, _fnThrottle( function () {
4258 _fnAdjustColumnSizing( oSettings );
4259 } ) );
4260 };
4261
4262 // IE6/7 will crash if we bind a resize event handler on page load.
4263 // To be removed in 1.11 which drops IE6/7 support
4264 if ( oSettings.oBrowser.bScrollOversize ) {
4265 setTimeout( bindResize, 1000 );
4266 }
4267 else {
4268 bindResize();
4269 }
4270
4271 oSettings._reszEvt = true;
4272 }
4273 }
4274
4275
4276 /**
4277 * Throttle the calls to a function. Arguments and context are maintained for
4278 * the throttled function
4279 * @param {function} fn Function to be called
4280 * @param {int} [freq=200] call frequency in mS
4281 * @returns {function} wrapped function
4282 * @memberof DataTable#oApi
4283 */
4284 function _fnThrottle( fn, freq ) {
4285 var
4286 frequency = freq !== undefined ? freq : 200,
4287 last,
4288 timer;
4289
4290 return function () {
4291 var
4292 that = this,
4293 now = +new Date(),
4294 args = arguments;
4295
4296 if ( last && now < last + frequency ) {
4297 clearTimeout( timer );
4298
4299 timer = setTimeout( function () {
4300 last = undefined;
4301 fn.apply( that, args );
4302 }, frequency );
4303 }
4304 else {
4305 last = now;
4306 fn.apply( that, args );
4307 }
4308 };
4309 }
4310
4311
4312 /**
4313 * Convert a CSS unit width to pixels (e.g. 2em)
4314 * @param {string} width width to be converted
4315 * @param {node} parent parent to get the with for (required for relative widths) - optional
4316 * @returns {int} width in pixels
4317 * @memberof DataTable#oApi
4318 */
4319 function _fnConvertToWidth ( width, parent )
4320 {
4321 if ( ! width ) {
4322 return 0;
4323 }
4324
4325 var n = $('<div/>')
4326 .css( 'width', _fnStringToCss( width ) )
4327 .appendTo( parent || document.body );
4328
4329 var val = n[0].offsetWidth;
4330 n.remove();
4331
4332 return val;
4333 }
4334
4335
4336 /**
4337 * Adjust a table's width to take account of vertical scroll bar
4338 * @param {object} oSettings dataTables settings object
4339 * @param {node} n table node
4340 * @memberof DataTable#oApi
4341 */
4342
4343 function _fnScrollingWidthAdjust ( settings, n )
4344 {
4345 var scroll = settings.oScroll;
4346
4347 if ( scroll.sX || scroll.sY ) {
4348 // When y-scrolling only, we want to remove the width of the scroll bar
4349 // so the table + scroll bar will fit into the area available, otherwise
4350 // we fix the table at its current size with no adjustment
4351 var correction = ! scroll.sX ? scroll.iBarWidth : 0;
4352 n.style.width = _fnStringToCss( $(n).outerWidth() - correction );
4353 }
4354 }
4355
4356
4357 /**
4358 * Get the widest node
4359 * @param {object} settings dataTables settings object
4360 * @param {int} colIdx column of interest
4361 * @returns {node} widest table node
4362 * @memberof DataTable#oApi
4363 */
4364 function _fnGetWidestNode( settings, colIdx )
4365 {
4366 var idx = _fnGetMaxLenString( settings, colIdx );
4367 if ( idx < 0 ) {
4368 return null;
4369 }
4370
4371 var data = settings.aoData[ idx ];
4372 return ! data.nTr ? // Might not have been created when deferred rendering
4373 $('<td/>').html( _fnGetCellData( settings, idx, colIdx, 'display' ) )[0] :
4374 data.anCells[ colIdx ];
4375 }
4376
4377
4378 /**
4379 * Get the maximum strlen for each data column
4380 * @param {object} settings dataTables settings object
4381 * @param {int} colIdx column of interest
4382 * @returns {string} max string length for each column
4383 * @memberof DataTable#oApi
4384 */
4385 function _fnGetMaxLenString( settings, colIdx )
4386 {
4387 var s, max=-1, maxIdx = -1;
4388
4389 for ( var i=0, ien=settings.aoData.length ; i<ien ; i++ ) {
4390 s = _fnGetCellData( settings, i, colIdx, 'display' )+'';
4391 s = s.replace( __re_html_remove, '' );
4392
4393 if ( s.length > max ) {
4394 max = s.length;
4395 maxIdx = i;
4396 }
4397 }
4398
4399 return maxIdx;
4400 }
4401
4402
4403 /**
4404 * Append a CSS unit (only if required) to a string
4405 * @param {string} value to css-ify
4406 * @returns {string} value with css unit
4407 * @memberof DataTable#oApi
4408 */
4409 function _fnStringToCss( s )
4410 {
4411 if ( s === null ) {
4412 return '0px';
4413 }
4414
4415 if ( typeof s == 'number' ) {
4416 return s < 0 ?
4417 '0px' :
4418 s+'px';
4419 }
4420
4421 // Check it has a unit character already
4422 return s.match(/\d$/) ?
4423 s+'px' :
4424 s;
4425 }
4426
4427
4428 /**
4429 * Get the width of a scroll bar in this browser being used
4430 * @returns {int} width in pixels
4431 * @memberof DataTable#oApi
4432 */
4433 function _fnScrollBarWidth ()
4434 {
4435 // On first run a static variable is set, since this is only needed once.
4436 // Subsequent runs will just use the previously calculated value
4437 var width = DataTable.__scrollbarWidth;
4438
4439 if ( width === undefined ) {
4440 var sizer = $('<p/>').css( {
4441 position: 'absolute',
4442 top: 0,
4443 left: 0,
4444 width: '100%',
4445 height: 150,
4446 padding: 0,
4447 overflow: 'scroll',
4448 visibility: 'hidden'
4449 } )
4450 .appendTo('body');
4451
4452 width = sizer[0].offsetWidth - sizer[0].clientWidth;
4453 DataTable.__scrollbarWidth = width;
4454
4455 sizer.remove();
4456 }
4457
4458 return width;
4459 }
4460
4461
4462
4463 function _fnSortFlatten ( settings )
4464 {
4465 var
4466 i, iLen, k, kLen,
4467 aSort = [],
4468 aiOrig = [],
4469 aoColumns = settings.aoColumns,
4470 aDataSort, iCol, sType, srcCol,
4471 fixed = settings.aaSortingFixed,
4472 fixedObj = $.isPlainObject( fixed ),
4473 nestedSort = [],
4474 add = function ( a ) {
4475 if ( a.length && ! $.isArray( a[0] ) ) {
4476 // 1D array
4477 nestedSort.push( a );
4478 }
4479 else {
4480 // 2D array
4481 nestedSort.push.apply( nestedSort, a );
4482 }
4483 };
4484
4485 // Build the sort array, with pre-fix and post-fix options if they have been
4486 // specified
4487 if ( $.isArray( fixed ) ) {
4488 add( fixed );
4489 }
4490
4491 if ( fixedObj && fixed.pre ) {
4492 add( fixed.pre );
4493 }
4494
4495 add( settings.aaSorting );
4496
4497 if (fixedObj && fixed.post ) {
4498 add( fixed.post );
4499 }
4500
4501 for ( i=0 ; i<nestedSort.length ; i++ )
4502 {
4503 srcCol = nestedSort[i][0];
4504 aDataSort = aoColumns[ srcCol ].aDataSort;
4505
4506 for ( k=0, kLen=aDataSort.length ; k<kLen ; k++ )
4507 {
4508 iCol = aDataSort[k];
4509 sType = aoColumns[ iCol ].sType || 'string';
4510
4511 if ( nestedSort[i]._idx === undefined ) {
4512 nestedSort[i]._idx = $.inArray( nestedSort[i][1], aoColumns[iCol].asSorting );
4513 }
4514
4515 aSort.push( {
4516 src: srcCol,
4517 col: iCol,
4518 dir: nestedSort[i][1],
4519 index: nestedSort[i]._idx,
4520 type: sType,
4521 formatter: DataTable.ext.type.order[ sType+"-pre" ]
4522 } );
4523 }
4524 }
4525
4526 return aSort;
4527 }
4528
4529 /**
4530 * Change the order of the table
4531 * @param {object} oSettings dataTables settings object
4532 * @memberof DataTable#oApi
4533 * @todo This really needs split up!
4534 */
4535 function _fnSort ( oSettings )
4536 {
4537 var
4538 i, ien, iLen, j, jLen, k, kLen,
4539 sDataType, nTh,
4540 aiOrig = [],
4541 oExtSort = DataTable.ext.type.order,
4542 aoData = oSettings.aoData,
4543 aoColumns = oSettings.aoColumns,
4544 aDataSort, data, iCol, sType, oSort,
4545 formatters = 0,
4546 sortCol,
4547 displayMaster = oSettings.aiDisplayMaster,
4548 aSort;
4549
4550 // Resolve any column types that are unknown due to addition or invalidation
4551 // @todo Can this be moved into a 'data-ready' handler which is called when
4552 // data is going to be used in the table?
4553 _fnColumnTypes( oSettings );
4554
4555 aSort = _fnSortFlatten( oSettings );
4556
4557 for ( i=0, ien=aSort.length ; i<ien ; i++ ) {
4558 sortCol = aSort[i];
4559
4560 // Track if we can use the fast sort algorithm
4561 if ( sortCol.formatter ) {
4562 formatters++;
4563 }
4564
4565 // Load the data needed for the sort, for each cell
4566 _fnSortData( oSettings, sortCol.col );
4567 }
4568
4569 /* No sorting required if server-side or no sorting array */
4570 if ( _fnDataSource( oSettings ) != 'ssp' && aSort.length !== 0 )
4571 {
4572 // Create a value - key array of the current row positions such that we can use their
4573 // current position during the sort, if values match, in order to perform stable sorting
4574 for ( i=0, iLen=displayMaster.length ; i<iLen ; i++ ) {
4575 aiOrig[ displayMaster[i] ] = i;
4576 }
4577
4578 /* Do the sort - here we want multi-column sorting based on a given data source (column)
4579 * and sorting function (from oSort) in a certain direction. It's reasonably complex to
4580 * follow on it's own, but this is what we want (example two column sorting):
4581 * fnLocalSorting = function(a,b){
4582 * var iTest;
4583 * iTest = oSort['string-asc']('data11', 'data12');
4584 * if (iTest !== 0)
4585 * return iTest;
4586 * iTest = oSort['numeric-desc']('data21', 'data22');
4587 * if (iTest !== 0)
4588 * return iTest;
4589 * return oSort['numeric-asc']( aiOrig[a], aiOrig[b] );
4590 * }
4591 * Basically we have a test for each sorting column, if the data in that column is equal,
4592 * test the next column. If all columns match, then we use a numeric sort on the row
4593 * positions in the original data array to provide a stable sort.
4594 *
4595 * Note - I know it seems excessive to have two sorting methods, but the first is around
4596 * 15% faster, so the second is only maintained for backwards compatibility with sorting
4597 * methods which do not have a pre-sort formatting function.
4598 */
4599 if ( formatters === aSort.length ) {
4600 // All sort types have formatting functions
4601 displayMaster.sort( function ( a, b ) {
4602 var
4603 x, y, k, test, sort,
4604 len=aSort.length,
4605 dataA = aoData[a]._aSortData,
4606 dataB = aoData[b]._aSortData;
4607
4608 for ( k=0 ; k<len ; k++ ) {
4609 sort = aSort[k];
4610
4611 x = dataA[ sort.col ];
4612 y = dataB[ sort.col ];
4613
4614 test = x<y ? -1 : x>y ? 1 : 0;
4615 if ( test !== 0 ) {
4616 return sort.dir === 'asc' ? test : -test;
4617 }
4618 }
4619
4620 x = aiOrig[a];
4621 y = aiOrig[b];
4622 return x<y ? -1 : x>y ? 1 : 0;
4623 } );
4624 }
4625 else {
4626 // Depreciated - remove in 1.11 (providing a plug-in option)
4627 // Not all sort types have formatting methods, so we have to call their sorting
4628 // methods.
4629 displayMaster.sort( function ( a, b ) {
4630 var
4631 x, y, k, l, test, sort, fn,
4632 len=aSort.length,
4633 dataA = aoData[a]._aSortData,
4634 dataB = aoData[b]._aSortData;
4635
4636 for ( k=0 ; k<len ; k++ ) {
4637 sort = aSort[k];
4638
4639 x = dataA[ sort.col ];
4640 y = dataB[ sort.col ];
4641
4642 fn = oExtSort[ sort.type+"-"+sort.dir ] || oExtSort[ "string-"+sort.dir ];
4643 test = fn( x, y );
4644 if ( test !== 0 ) {
4645 return test;
4646 }
4647 }
4648
4649 x = aiOrig[a];
4650 y = aiOrig[b];
4651 return x<y ? -1 : x>y ? 1 : 0;
4652 } );
4653 }
4654 }
4655
4656 /* Tell the draw function that we have sorted the data */
4657 oSettings.bSorted = true;
4658 }
4659
4660
4661 function _fnSortAria ( settings )
4662 {
4663 var label;
4664 var nextSort;
4665 var columns = settings.aoColumns;
4666 var aSort = _fnSortFlatten( settings );
4667 var oAria = settings.oLanguage.oAria;
4668
4669 // ARIA attributes - need to loop all columns, to update all (removing old
4670 // attributes as needed)
4671 for ( var i=0, iLen=columns.length ; i<iLen ; i++ )
4672 {
4673 var col = columns[i];
4674 var asSorting = col.asSorting;
4675 var sTitle = col.sTitle.replace( /<.*?>/g, "" );
4676 var th = col.nTh;
4677
4678 // IE7 is throwing an error when setting these properties with jQuery's
4679 // attr() and removeAttr() methods...
4680 th.removeAttribute('aria-sort');
4681
4682 /* In ARIA only the first sorting column can be marked as sorting - no multi-sort option */
4683 if ( col.bSortable ) {
4684 if ( aSort.length > 0 && aSort[0].col == i ) {
4685 th.setAttribute('aria-sort', aSort[0].dir=="asc" ? "ascending" : "descending" );
4686 nextSort = asSorting[ aSort[0].index+1 ] || asSorting[0];
4687 }
4688 else {
4689 nextSort = asSorting[0];
4690 }
4691
4692 label = sTitle + ( nextSort === "asc" ?
4693 oAria.sSortAscending :
4694 oAria.sSortDescending
4695 );
4696 }
4697 else {
4698 label = sTitle;
4699 }
4700
4701 th.setAttribute('aria-label', label);
4702 }
4703 }
4704
4705
4706 /**
4707 * Function to run on user sort request
4708 * @param {object} settings dataTables settings object
4709 * @param {node} attachTo node to attach the handler to
4710 * @param {int} colIdx column sorting index
4711 * @param {boolean} [append=false] Append the requested sort to the existing
4712 * sort if true (i.e. multi-column sort)
4713 * @param {function} [callback] callback function
4714 * @memberof DataTable#oApi
4715 */
4716 function _fnSortListener ( settings, colIdx, append, callback )
4717 {
4718 var col = settings.aoColumns[ colIdx ];
4719 var sorting = settings.aaSorting;
4720 var asSorting = col.asSorting;
4721 var nextSortIdx;
4722 var next = function ( a, overflow ) {
4723 var idx = a._idx;
4724 if ( idx === undefined ) {
4725 idx = $.inArray( a[1], asSorting );
4726 }
4727
4728 return idx+1 < asSorting.length ?
4729 idx+1 :
4730 overflow ?
4731 null :
4732 0;
4733 };
4734
4735 // Convert to 2D array if needed
4736 if ( typeof sorting[0] === 'number' ) {
4737 sorting = settings.aaSorting = [ sorting ];
4738 }
4739
4740 // If appending the sort then we are multi-column sorting
4741 if ( append && settings.oFeatures.bSortMulti ) {
4742 // Are we already doing some kind of sort on this column?
4743 var sortIdx = $.inArray( colIdx, _pluck(sorting, '0') );
4744
4745 if ( sortIdx !== -1 ) {
4746 // Yes, modify the sort
4747 nextSortIdx = next( sorting[sortIdx], true );
4748
4749 if ( nextSortIdx === null && sorting.length === 1 ) {
4750 nextSortIdx = 0; // can't remove sorting completely
4751 }
4752
4753 if ( nextSortIdx === null ) {
4754 sorting.splice( sortIdx, 1 );
4755 }
4756 else {
4757 sorting[sortIdx][1] = asSorting[ nextSortIdx ];
4758 sorting[sortIdx]._idx = nextSortIdx;
4759 }
4760 }
4761 else {
4762 // No sort on this column yet
4763 sorting.push( [ colIdx, asSorting[0], 0 ] );
4764 sorting[sorting.length-1]._idx = 0;
4765 }
4766 }
4767 else if ( sorting.length && sorting[0][0] == colIdx ) {
4768 // Single column - already sorting on this column, modify the sort
4769 nextSortIdx = next( sorting[0] );
4770
4771 sorting.length = 1;
4772 sorting[0][1] = asSorting[ nextSortIdx ];
4773 sorting[0]._idx = nextSortIdx;
4774 }
4775 else {
4776 // Single column - sort only on this column
4777 sorting.length = 0;
4778 sorting.push( [ colIdx, asSorting[0] ] );
4779 sorting[0]._idx = 0;
4780 }
4781
4782 // Run the sort by calling a full redraw
4783 _fnReDraw( settings );
4784
4785 // callback used for async user interaction
4786 if ( typeof callback == 'function' ) {
4787 callback( settings );
4788 }
4789 }
4790
4791
4792 /**
4793 * Attach a sort handler (click) to a node
4794 * @param {object} settings dataTables settings object
4795 * @param {node} attachTo node to attach the handler to
4796 * @param {int} colIdx column sorting index
4797 * @param {function} [callback] callback function
4798 * @memberof DataTable#oApi
4799 */
4800 function _fnSortAttachListener ( settings, attachTo, colIdx, callback )
4801 {
4802 var col = settings.aoColumns[ colIdx ];
4803
4804 _fnBindAction( attachTo, {}, function (e) {
4805 /* If the column is not sortable - don't to anything */
4806 if ( col.bSortable === false ) {
4807 return;
4808 }
4809
4810 // If processing is enabled use a timeout to allow the processing
4811 // display to be shown - otherwise to it synchronously
4812 if ( settings.oFeatures.bProcessing ) {
4813 _fnProcessingDisplay( settings, true );
4814
4815 setTimeout( function() {
4816 _fnSortListener( settings, colIdx, e.shiftKey, callback );
4817
4818 // In server-side processing, the draw callback will remove the
4819 // processing display
4820 if ( _fnDataSource( settings ) !== 'ssp' ) {
4821 _fnProcessingDisplay( settings, false );
4822 }
4823 }, 0 );
4824 }
4825 else {
4826 _fnSortListener( settings, colIdx, e.shiftKey, callback );
4827 }
4828 } );
4829 }
4830
4831
4832 /**
4833 * Set the sorting classes on table's body, Note: it is safe to call this function
4834 * when bSort and bSortClasses are false
4835 * @param {object} oSettings dataTables settings object
4836 * @memberof DataTable#oApi
4837 */
4838 function _fnSortingClasses( settings )
4839 {
4840 var oldSort = settings.aLastSort;
4841 var sortClass = settings.oClasses.sSortColumn;
4842 var sort = _fnSortFlatten( settings );
4843 var features = settings.oFeatures;
4844 var i, ien, colIdx;
4845
4846 if ( features.bSort && features.bSortClasses ) {
4847 // Remove old sorting classes
4848 for ( i=0, ien=oldSort.length ; i<ien ; i++ ) {
4849 colIdx = oldSort[i].src;
4850
4851 // Remove column sorting
4852 $( _pluck( settings.aoData, 'anCells', colIdx ) )
4853 .removeClass( sortClass + (i<2 ? i+1 : 3) );
4854 }
4855
4856 // Add new column sorting
4857 for ( i=0, ien=sort.length ; i<ien ; i++ ) {
4858 colIdx = sort[i].src;
4859
4860 $( _pluck( settings.aoData, 'anCells', colIdx ) )
4861 .addClass( sortClass + (i<2 ? i+1 : 3) );
4862 }
4863 }
4864
4865 settings.aLastSort = sort;
4866 }
4867
4868
4869 // Get the data to sort a column, be it from cache, fresh (populating the
4870 // cache), or from a sort formatter
4871 function _fnSortData( settings, idx )
4872 {
4873 // Custom sorting function - provided by the sort data type
4874 var column = settings.aoColumns[ idx ];
4875 var customSort = DataTable.ext.order[ column.sSortDataType ];
4876 var customData;
4877
4878 if ( customSort ) {
4879 customData = customSort.call( settings.oInstance, settings, idx,
4880 _fnColumnIndexToVisible( settings, idx )
4881 );
4882 }
4883
4884 // Use / populate cache
4885 var row, cellData;
4886 var formatter = DataTable.ext.type.order[ column.sType+"-pre" ];
4887
4888 for ( var i=0, ien=settings.aoData.length ; i<ien ; i++ ) {
4889 row = settings.aoData[i];
4890
4891 if ( ! row._aSortData ) {
4892 row._aSortData = [];
4893 }
4894
4895 if ( ! row._aSortData[idx] || customSort ) {
4896 cellData = customSort ?
4897 customData[i] : // If there was a custom sort function, use data from there
4898 _fnGetCellData( settings, i, idx, 'sort' );
4899
4900 row._aSortData[ idx ] = formatter ?
4901 formatter( cellData ) :
4902 cellData;
4903 }
4904 }
4905 }
4906
4907
4908
4909 /**
4910 * Save the state of a table
4911 * @param {object} oSettings dataTables settings object
4912 * @memberof DataTable#oApi
4913 */
4914 function _fnSaveState ( settings )
4915 {
4916 if ( !settings.oFeatures.bStateSave || settings.bDestroying )
4917 {
4918 return;
4919 }
4920
4921 /* Store the interesting variables */
4922 var state = {
4923 time: +new Date(),
4924 start: settings._iDisplayStart,
4925 length: settings._iDisplayLength,
4926 order: $.extend( true, [], settings.aaSorting ),
4927 search: _fnSearchToCamel( settings.oPreviousSearch ),
4928 columns: $.map( settings.aoColumns, function ( col, i ) {
4929 return {
4930 visible: col.bVisible,
4931 search: _fnSearchToCamel( settings.aoPreSearchCols[i] )
4932 };
4933 } )
4934 };
4935
4936 _fnCallbackFire( settings, "aoStateSaveParams", 'stateSaveParams', [settings, state] );
4937
4938 settings.oSavedState = state;
4939 settings.fnStateSaveCallback.call( settings.oInstance, settings, state );
4940 }
4941
4942
4943 /**
4944 * Attempt to load a saved table state
4945 * @param {object} oSettings dataTables settings object
4946 * @param {object} oInit DataTables init object so we can override settings
4947 * @memberof DataTable#oApi
4948 */
4949 function _fnLoadState ( settings, oInit )
4950 {
4951 var i, ien;
4952 var columns = settings.aoColumns;
4953
4954 if ( ! settings.oFeatures.bStateSave ) {
4955 return;
4956 }
4957
4958 var state = settings.fnStateLoadCallback.call( settings.oInstance, settings );
4959 if ( ! state || ! state.time ) {
4960 return;
4961 }
4962
4963 /* Allow custom and plug-in manipulation functions to alter the saved data set and
4964 * cancelling of loading by returning false
4965 */
4966 var abStateLoad = _fnCallbackFire( settings, 'aoStateLoadParams', 'stateLoadParams', [settings, state] );
4967 if ( $.inArray( false, abStateLoad ) !== -1 ) {
4968 return;
4969 }
4970
4971 /* Reject old data */
4972 var duration = settings.iStateDuration;
4973 if ( duration > 0 && state.time < +new Date() - (duration*1000) ) {
4974 return;
4975 }
4976
4977 // Number of columns have changed - all bets are off, no restore of settings
4978 if ( columns.length !== state.columns.length ) {
4979 return;
4980 }
4981
4982 // Store the saved state so it might be accessed at any time
4983 settings.oLoadedState = $.extend( true, {}, state );
4984
4985 // Restore key features - todo - for 1.11 this needs to be done by
4986 // subscribed events
4987 if ( state.start !== undefined ) {
4988 settings._iDisplayStart = state.start;
4989 settings.iInitDisplayStart = state.start;
4990 }
4991 if ( state.length !== undefined ) {
4992 settings._iDisplayLength = state.length;
4993 }
4994
4995 // Order
4996 if ( state.order !== undefined ) {
4997 settings.aaSorting = [];
4998 $.each( state.order, function ( i, col ) {
4999 settings.aaSorting.push( col[0] >= columns.length ?
5000 [ 0, col[1] ] :
5001 col
5002 );
5003 } );
5004 }
5005
5006 // Search
5007 if ( state.search !== undefined ) {
5008 $.extend( settings.oPreviousSearch, _fnSearchToHung( state.search ) );
5009 }
5010
5011 // Columns
5012 for ( i=0, ien=state.columns.length ; i<ien ; i++ ) {
5013 var col = state.columns[i];
5014
5015 // Visibility
5016 if ( col.visible !== undefined ) {
5017 columns[i].bVisible = col.visible;
5018 }
5019
5020 // Search
5021 if ( col.search !== undefined ) {
5022 $.extend( settings.aoPreSearchCols[i], _fnSearchToHung( col.search ) );
5023 }
5024 }
5025
5026 _fnCallbackFire( settings, 'aoStateLoaded', 'stateLoaded', [settings, state] );
5027 }
5028
5029
5030 /**
5031 * Return the settings object for a particular table
5032 * @param {node} table table we are using as a dataTable
5033 * @returns {object} Settings object - or null if not found
5034 * @memberof DataTable#oApi
5035 */
5036 function _fnSettingsFromNode ( table )
5037 {
5038 var settings = DataTable.settings;
5039 var idx = $.inArray( table, _pluck( settings, 'nTable' ) );
5040
5041 return idx !== -1 ?
5042 settings[ idx ] :
5043 null;
5044 }
5045
5046
5047 /**
5048 * Log an error message
5049 * @param {object} settings dataTables settings object
5050 * @param {int} level log error messages, or display them to the user
5051 * @param {string} msg error message
5052 * @param {int} tn Technical note id to get more information about the error.
5053 * @memberof DataTable#oApi
5054 */
5055 function _fnLog( settings, level, msg, tn )
5056 {
5057 msg = 'DataTables warning: '+
5058 (settings!==null ? 'table id='+settings.sTableId+' - ' : '')+msg;
5059
5060 if ( tn ) {
5061 msg += '. For more information about this error, please see '+
5062 'http://datatables.net/tn/'+tn;
5063 }
5064
5065 if ( ! level ) {
5066 // Backwards compatibility pre 1.10
5067 var ext = DataTable.ext;
5068 var type = ext.sErrMode || ext.errMode;
5069
5070 _fnCallbackFire( settings, null, 'error', [ settings, tn, msg ] );
5071
5072 if ( type == 'alert' ) {
5073 alert( msg );
5074 }
5075 else if ( type == 'throw' ) {
5076 throw new Error(msg);
5077 }
5078 else if ( typeof type == 'function' ) {
5079 type( settings, tn, msg );
5080 }
5081 }
5082 else if ( window.console && console.log ) {
5083 console.log( msg );
5084 }
5085 }
5086
5087
5088 /**
5089 * See if a property is defined on one object, if so assign it to the other object
5090 * @param {object} ret target object
5091 * @param {object} src source object
5092 * @param {string} name property
5093 * @param {string} [mappedName] name to map too - optional, name used if not given
5094 * @memberof DataTable#oApi
5095 */
5096 function _fnMap( ret, src, name, mappedName )
5097 {
5098 if ( $.isArray( name ) ) {
5099 $.each( name, function (i, val) {
5100 if ( $.isArray( val ) ) {
5101 _fnMap( ret, src, val[0], val[1] );
5102 }
5103 else {
5104 _fnMap( ret, src, val );
5105 }
5106 } );
5107
5108 return;
5109 }
5110
5111 if ( mappedName === undefined ) {
5112 mappedName = name;
5113 }
5114
5115 if ( src[name] !== undefined ) {
5116 ret[mappedName] = src[name];
5117 }
5118 }
5119
5120
5121 /**
5122 * Extend objects - very similar to jQuery.extend, but deep copy objects, and
5123 * shallow copy arrays. The reason we need to do this, is that we don't want to
5124 * deep copy array init values (such as aaSorting) since the dev wouldn't be
5125 * able to override them, but we do want to deep copy arrays.
5126 * @param {object} out Object to extend
5127 * @param {object} extender Object from which the properties will be applied to
5128 * out
5129 * @param {boolean} breakRefs If true, then arrays will be sliced to take an
5130 * independent copy with the exception of the `data` or `aaData` parameters
5131 * if they are present. This is so you can pass in a collection to
5132 * DataTables and have that used as your data source without breaking the
5133 * references
5134 * @returns {object} out Reference, just for convenience - out === the return.
5135 * @memberof DataTable#oApi
5136 * @todo This doesn't take account of arrays inside the deep copied objects.
5137 */
5138 function _fnExtend( out, extender, breakRefs )
5139 {
5140 var val;
5141
5142 for ( var prop in extender ) {
5143 if ( extender.hasOwnProperty(prop) ) {
5144 val = extender[prop];
5145
5146 if ( $.isPlainObject( val ) ) {
5147 if ( ! $.isPlainObject( out[prop] ) ) {
5148 out[prop] = {};
5149 }
5150 $.extend( true, out[prop], val );
5151 }
5152 else if ( breakRefs && prop !== 'data' && prop !== 'aaData' && $.isArray(val) ) {
5153 out[prop] = val.slice();
5154 }
5155 else {
5156 out[prop] = val;
5157 }
5158 }
5159 }
5160
5161 return out;
5162 }
5163
5164
5165 /**
5166 * Bind an event handers to allow a click or return key to activate the callback.
5167 * This is good for accessibility since a return on the keyboard will have the
5168 * same effect as a click, if the element has focus.
5169 * @param {element} n Element to bind the action to
5170 * @param {object} oData Data object to pass to the triggered function
5171 * @param {function} fn Callback function for when the event is triggered
5172 * @memberof DataTable#oApi
5173 */
5174 function _fnBindAction( n, oData, fn )
5175 {
5176 $(n)
5177 .bind( 'click.DT', oData, function (e) {
5178 n.blur(); // Remove focus outline for mouse users
5179 fn(e);
5180 } )
5181 .bind( 'keypress.DT', oData, function (e){
5182 if ( e.which === 13 ) {
5183 e.preventDefault();
5184 fn(e);
5185 }
5186 } )
5187 .bind( 'selectstart.DT', function () {
5188 /* Take the brutal approach to cancelling text selection */
5189 return false;
5190 } );
5191 }
5192
5193
5194 /**
5195 * Register a callback function. Easily allows a callback function to be added to
5196 * an array store of callback functions that can then all be called together.
5197 * @param {object} oSettings dataTables settings object
5198 * @param {string} sStore Name of the array storage for the callbacks in oSettings
5199 * @param {function} fn Function to be called back
5200 * @param {string} sName Identifying name for the callback (i.e. a label)
5201 * @memberof DataTable#oApi
5202 */
5203 function _fnCallbackReg( oSettings, sStore, fn, sName )
5204 {
5205 if ( fn )
5206 {
5207 oSettings[sStore].push( {
5208 "fn": fn,
5209 "sName": sName
5210 } );
5211 }
5212 }
5213
5214
5215 /**
5216 * Fire callback functions and trigger events. Note that the loop over the
5217 * callback array store is done backwards! Further note that you do not want to
5218 * fire off triggers in time sensitive applications (for example cell creation)
5219 * as its slow.
5220 * @param {object} settings dataTables settings object
5221 * @param {string} callbackArr Name of the array storage for the callbacks in
5222 * oSettings
5223 * @param {string} eventName Name of the jQuery custom event to trigger. If
5224 * null no trigger is fired
5225 * @param {array} args Array of arguments to pass to the callback function /
5226 * trigger
5227 * @memberof DataTable#oApi
5228 */
5229 function _fnCallbackFire( settings, callbackArr, eventName, args )
5230 {
5231 var ret = [];
5232
5233 if ( callbackArr ) {
5234 ret = $.map( settings[callbackArr].slice().reverse(), function (val, i) {
5235 return val.fn.apply( settings.oInstance, args );
5236 } );
5237 }
5238
5239 if ( eventName !== null ) {
5240 var e = $.Event( eventName+'.dt' );
5241
5242 $(settings.nTable).trigger( e, args );
5243
5244 ret.push( e.result );
5245 }
5246
5247 return ret;
5248 }
5249
5250
5251 function _fnLengthOverflow ( settings )
5252 {
5253 var
5254 start = settings._iDisplayStart,
5255 end = settings.fnDisplayEnd(),
5256 len = settings._iDisplayLength;
5257
5258 /* If we have space to show extra rows (backing up from the end point - then do so */
5259 if ( start >= end )
5260 {
5261 start = end - len;
5262 }
5263
5264 // Keep the start record on the current page
5265 start -= (start % len);
5266
5267 if ( len === -1 || start < 0 )
5268 {
5269 start = 0;
5270 }
5271
5272 settings._iDisplayStart = start;
5273 }
5274
5275
5276 function _fnRenderer( settings, type )
5277 {
5278 var renderer = settings.renderer;
5279 var host = DataTable.ext.renderer[type];
5280
5281 if ( $.isPlainObject( renderer ) && renderer[type] ) {
5282 // Specific renderer for this type. If available use it, otherwise use
5283 // the default.
5284 return host[renderer[type]] || host._;
5285 }
5286 else if ( typeof renderer === 'string' ) {
5287 // Common renderer - if there is one available for this type use it,
5288 // otherwise use the default
5289 return host[renderer] || host._;
5290 }
5291
5292 // Use the default
5293 return host._;
5294 }
5295
5296
5297 /**
5298 * Detect the data source being used for the table. Used to simplify the code
5299 * a little (ajax) and to make it compress a little smaller.
5300 *
5301 * @param {object} settings dataTables settings object
5302 * @returns {string} Data source
5303 * @memberof DataTable#oApi
5304 */
5305 function _fnDataSource ( settings )
5306 {
5307 if ( settings.oFeatures.bServerSide ) {
5308 return 'ssp';
5309 }
5310 else if ( settings.ajax || settings.sAjaxSource ) {
5311 return 'ajax';
5312 }
5313 return 'dom';
5314 }
5315
5316
5317 DataTable = function( options )
5318 {
5319 /**
5320 * Perform a jQuery selector action on the table's TR elements (from the tbody) and
5321 * return the resulting jQuery object.
5322 * @param {string|node|jQuery} sSelector jQuery selector or node collection to act on
5323 * @param {object} [oOpts] Optional parameters for modifying the rows to be included
5324 * @param {string} [oOpts.filter=none] Select TR elements that meet the current filter
5325 * criterion ("applied") or all TR elements (i.e. no filter).
5326 * @param {string} [oOpts.order=current] Order of the TR elements in the processed array.
5327 * Can be either 'current', whereby the current sorting of the table is used, or
5328 * 'original' whereby the original order the data was read into the table is used.
5329 * @param {string} [oOpts.page=all] Limit the selection to the currently displayed page
5330 * ("current") or not ("all"). If 'current' is given, then order is assumed to be
5331 * 'current' and filter is 'applied', regardless of what they might be given as.
5332 * @returns {object} jQuery object, filtered by the given selector.
5333 * @dtopt API
5334 * @deprecated Since v1.10
5335 *
5336 * @example
5337 * $(document).ready(function() {
5338 * var oTable = $('#example').dataTable();
5339 *
5340 * // Highlight every second row
5341 * oTable.$('tr:odd').css('backgroundColor', 'blue');
5342 * } );
5343 *
5344 * @example
5345 * $(document).ready(function() {
5346 * var oTable = $('#example').dataTable();
5347 *
5348 * // Filter to rows with 'Webkit' in them, add a background colour and then
5349 * // remove the filter, thus highlighting the 'Webkit' rows only.
5350 * oTable.fnFilter('Webkit');
5351 * oTable.$('tr', {"search": "applied"}).css('backgroundColor', 'blue');
5352 * oTable.fnFilter('');
5353 * } );
5354 */
5355 this.$ = function ( sSelector, oOpts )
5356 {
5357 return this.api(true).$( sSelector, oOpts );
5358 };
5359
5360
5361 /**
5362 * Almost identical to $ in operation, but in this case returns the data for the matched
5363 * rows - as such, the jQuery selector used should match TR row nodes or TD/TH cell nodes
5364 * rather than any descendants, so the data can be obtained for the row/cell. If matching
5365 * rows are found, the data returned is the original data array/object that was used to
5366 * create the row (or a generated array if from a DOM source).
5367 *
5368 * This method is often useful in-combination with $ where both functions are given the
5369 * same parameters and the array indexes will match identically.
5370 * @param {string|node|jQuery} sSelector jQuery selector or node collection to act on
5371 * @param {object} [oOpts] Optional parameters for modifying the rows to be included
5372 * @param {string} [oOpts.filter=none] Select elements that meet the current filter
5373 * criterion ("applied") or all elements (i.e. no filter).
5374 * @param {string} [oOpts.order=current] Order of the data in the processed array.
5375 * Can be either 'current', whereby the current sorting of the table is used, or
5376 * 'original' whereby the original order the data was read into the table is used.
5377 * @param {string} [oOpts.page=all] Limit the selection to the currently displayed page
5378 * ("current") or not ("all"). If 'current' is given, then order is assumed to be
5379 * 'current' and filter is 'applied', regardless of what they might be given as.
5380 * @returns {array} Data for the matched elements. If any elements, as a result of the
5381 * selector, were not TR, TD or TH elements in the DataTable, they will have a null
5382 * entry in the array.
5383 * @dtopt API
5384 * @deprecated Since v1.10
5385 *
5386 * @example
5387 * $(document).ready(function() {
5388 * var oTable = $('#example').dataTable();
5389 *
5390 * // Get the data from the first row in the table
5391 * var data = oTable._('tr:first');
5392 *
5393 * // Do something useful with the data
5394 * alert( "First cell is: "+data[0] );
5395 * } );
5396 *
5397 * @example
5398 * $(document).ready(function() {
5399 * var oTable = $('#example').dataTable();
5400 *
5401 * // Filter to 'Webkit' and get all data for
5402 * oTable.fnFilter('Webkit');
5403 * var data = oTable._('tr', {"search": "applied"});
5404 *
5405 * // Do something with the data
5406 * alert( data.length+" rows matched the search" );
5407 * } );
5408 */
5409 this._ = function ( sSelector, oOpts )
5410 {
5411 return this.api(true).rows( sSelector, oOpts ).data();
5412 };
5413
5414
5415 /**
5416 * Create a DataTables Api instance, with the currently selected tables for
5417 * the Api's context.
5418 * @param {boolean} [traditional=false] Set the API instance's context to be
5419 * only the table referred to by the `DataTable.ext.iApiIndex` option, as was
5420 * used in the API presented by DataTables 1.9- (i.e. the traditional mode),
5421 * or if all tables captured in the jQuery object should be used.
5422 * @return {DataTables.Api}
5423 */
5424 this.api = function ( traditional )
5425 {
5426 return traditional ?
5427 new _Api(
5428 _fnSettingsFromNode( this[ _ext.iApiIndex ] )
5429 ) :
5430 new _Api( this );
5431 };
5432
5433
5434 /**
5435 * Add a single new row or multiple rows of data to the table. Please note
5436 * that this is suitable for client-side processing only - if you are using
5437 * server-side processing (i.e. "bServerSide": true), then to add data, you
5438 * must add it to the data source, i.e. the server-side, through an Ajax call.
5439 * @param {array|object} data The data to be added to the table. This can be:
5440 * <ul>
5441 * <li>1D array of data - add a single row with the data provided</li>
5442 * <li>2D array of arrays - add multiple rows in a single call</li>
5443 * <li>object - data object when using <i>mData</i></li>
5444 * <li>array of objects - multiple data objects when using <i>mData</i></li>
5445 * </ul>
5446 * @param {bool} [redraw=true] redraw the table or not
5447 * @returns {array} An array of integers, representing the list of indexes in
5448 * <i>aoData</i> ({@link DataTable.models.oSettings}) that have been added to
5449 * the table.
5450 * @dtopt API
5451 * @deprecated Since v1.10
5452 *
5453 * @example
5454 * // Global var for counter
5455 * var giCount = 2;
5456 *
5457 * $(document).ready(function() {
5458 * $('#example').dataTable();
5459 * } );
5460 *
5461 * function fnClickAddRow() {
5462 * $('#example').dataTable().fnAddData( [
5463 * giCount+".1",
5464 * giCount+".2",
5465 * giCount+".3",
5466 * giCount+".4" ]
5467 * );
5468 *
5469 * giCount++;
5470 * }
5471 */
5472 this.fnAddData = function( data, redraw )
5473 {
5474 var api = this.api( true );
5475
5476 /* Check if we want to add multiple rows or not */
5477 var rows = $.isArray(data) && ( $.isArray(data[0]) || $.isPlainObject(data[0]) ) ?
5478 api.rows.add( data ) :
5479 api.row.add( data );
5480
5481 if ( redraw === undefined || redraw ) {
5482 api.draw();
5483 }
5484
5485 return rows.flatten().toArray();
5486 };
5487
5488
5489 /**
5490 * This function will make DataTables recalculate the column sizes, based on the data
5491 * contained in the table and the sizes applied to the columns (in the DOM, CSS or
5492 * through the sWidth parameter). This can be useful when the width of the table's
5493 * parent element changes (for example a window resize).
5494 * @param {boolean} [bRedraw=true] Redraw the table or not, you will typically want to
5495 * @dtopt API
5496 * @deprecated Since v1.10
5497 *
5498 * @example
5499 * $(document).ready(function() {
5500 * var oTable = $('#example').dataTable( {
5501 * "sScrollY": "200px",
5502 * "bPaginate": false
5503 * } );
5504 *
5505 * $(window).bind('resize', function () {
5506 * oTable.fnAdjustColumnSizing();
5507 * } );
5508 * } );
5509 */
5510 this.fnAdjustColumnSizing = function ( bRedraw )
5511 {
5512 var api = this.api( true ).columns.adjust();
5513 var settings = api.settings()[0];
5514 var scroll = settings.oScroll;
5515
5516 if ( bRedraw === undefined || bRedraw ) {
5517 api.draw( false );
5518 }
5519 else if ( scroll.sX !== "" || scroll.sY !== "" ) {
5520 /* If not redrawing, but scrolling, we want to apply the new column sizes anyway */
5521 _fnScrollDraw( settings );
5522 }
5523 };
5524
5525
5526 /**
5527 * Quickly and simply clear a table
5528 * @param {bool} [bRedraw=true] redraw the table or not
5529 * @dtopt API
5530 * @deprecated Since v1.10
5531 *
5532 * @example
5533 * $(document).ready(function() {
5534 * var oTable = $('#example').dataTable();
5535 *
5536 * // Immediately 'nuke' the current rows (perhaps waiting for an Ajax callback...)
5537 * oTable.fnClearTable();
5538 * } );
5539 */
5540 this.fnClearTable = function( bRedraw )
5541 {
5542 var api = this.api( true ).clear();
5543
5544 if ( bRedraw === undefined || bRedraw ) {
5545 api.draw();
5546 }
5547 };
5548
5549
5550 /**
5551 * The exact opposite of 'opening' a row, this function will close any rows which
5552 * are currently 'open'.
5553 * @param {node} nTr the table row to 'close'
5554 * @returns {int} 0 on success, or 1 if failed (can't find the row)
5555 * @dtopt API
5556 * @deprecated Since v1.10
5557 *
5558 * @example
5559 * $(document).ready(function() {
5560 * var oTable;
5561 *
5562 * // 'open' an information row when a row is clicked on
5563 * $('#example tbody tr').click( function () {
5564 * if ( oTable.fnIsOpen(this) ) {
5565 * oTable.fnClose( this );
5566 * } else {
5567 * oTable.fnOpen( this, "Temporary row opened", "info_row" );
5568 * }
5569 * } );
5570 *
5571 * oTable = $('#example').dataTable();
5572 * } );
5573 */
5574 this.fnClose = function( nTr )
5575 {
5576 this.api( true ).row( nTr ).child.hide();
5577 };
5578
5579
5580 /**
5581 * Remove a row for the table
5582 * @param {mixed} target The index of the row from aoData to be deleted, or
5583 * the TR element you want to delete
5584 * @param {function|null} [callBack] Callback function
5585 * @param {bool} [redraw=true] Redraw the table or not
5586 * @returns {array} The row that was deleted
5587 * @dtopt API
5588 * @deprecated Since v1.10
5589 *
5590 * @example
5591 * $(document).ready(function() {
5592 * var oTable = $('#example').dataTable();
5593 *
5594 * // Immediately remove the first row
5595 * oTable.fnDeleteRow( 0 );
5596 * } );
5597 */
5598 this.fnDeleteRow = function( target, callback, redraw )
5599 {
5600 var api = this.api( true );
5601 var rows = api.rows( target );
5602 var settings = rows.settings()[0];
5603 var data = settings.aoData[ rows[0][0] ];
5604
5605 rows.remove();
5606
5607 if ( callback ) {
5608 callback.call( this, settings, data );
5609 }
5610
5611 if ( redraw === undefined || redraw ) {
5612 api.draw();
5613 }
5614
5615 return data;
5616 };
5617
5618
5619 /**
5620 * Restore the table to it's original state in the DOM by removing all of DataTables
5621 * enhancements, alterations to the DOM structure of the table and event listeners.
5622 * @param {boolean} [remove=false] Completely remove the table from the DOM
5623 * @dtopt API
5624 * @deprecated Since v1.10
5625 *
5626 * @example
5627 * $(document).ready(function() {
5628 * // This example is fairly pointless in reality, but shows how fnDestroy can be used
5629 * var oTable = $('#example').dataTable();
5630 * oTable.fnDestroy();
5631 * } );
5632 */
5633 this.fnDestroy = function ( remove )
5634 {
5635 this.api( true ).destroy( remove );
5636 };
5637
5638
5639 /**
5640 * Redraw the table
5641 * @param {bool} [complete=true] Re-filter and resort (if enabled) the table before the draw.
5642 * @dtopt API
5643 * @deprecated Since v1.10
5644 *
5645 * @example
5646 * $(document).ready(function() {
5647 * var oTable = $('#example').dataTable();
5648 *
5649 * // Re-draw the table - you wouldn't want to do it here, but it's an example :-)
5650 * oTable.fnDraw();
5651 * } );
5652 */
5653 this.fnDraw = function( complete )
5654 {
5655 // Note that this isn't an exact match to the old call to _fnDraw - it takes
5656 // into account the new data, but can hold position.
5657 this.api( true ).draw( complete );
5658 };
5659
5660
5661 /**
5662 * Filter the input based on data
5663 * @param {string} sInput String to filter the table on
5664 * @param {int|null} [iColumn] Column to limit filtering to
5665 * @param {bool} [bRegex=false] Treat as regular expression or not
5666 * @param {bool} [bSmart=true] Perform smart filtering or not
5667 * @param {bool} [bShowGlobal=true] Show the input global filter in it's input box(es)
5668 * @param {bool} [bCaseInsensitive=true] Do case-insensitive matching (true) or not (false)
5669 * @dtopt API
5670 * @deprecated Since v1.10
5671 *
5672 * @example
5673 * $(document).ready(function() {
5674 * var oTable = $('#example').dataTable();
5675 *
5676 * // Sometime later - filter...
5677 * oTable.fnFilter( 'test string' );
5678 * } );
5679 */
5680 this.fnFilter = function( sInput, iColumn, bRegex, bSmart, bShowGlobal, bCaseInsensitive )
5681 {
5682 var api = this.api( true );
5683
5684 if ( iColumn === null || iColumn === undefined ) {
5685 api.search( sInput, bRegex, bSmart, bCaseInsensitive );
5686 }
5687 else {
5688 api.column( iColumn ).search( sInput, bRegex, bSmart, bCaseInsensitive );
5689 }
5690
5691 api.draw();
5692 };
5693
5694
5695 /**
5696 * Get the data for the whole table, an individual row or an individual cell based on the
5697 * provided parameters.
5698 * @param {int|node} [src] A TR row node, TD/TH cell node or an integer. If given as
5699 * a TR node then the data source for the whole row will be returned. If given as a
5700 * TD/TH cell node then iCol will be automatically calculated and the data for the
5701 * cell returned. If given as an integer, then this is treated as the aoData internal
5702 * data index for the row (see fnGetPosition) and the data for that row used.
5703 * @param {int} [col] Optional column index that you want the data of.
5704 * @returns {array|object|string} If mRow is undefined, then the data for all rows is
5705 * returned. If mRow is defined, just data for that row, and is iCol is
5706 * defined, only data for the designated cell is returned.
5707 * @dtopt API
5708 * @deprecated Since v1.10
5709 *
5710 * @example
5711 * // Row data
5712 * $(document).ready(function() {
5713 * oTable = $('#example').dataTable();
5714 *
5715 * oTable.$('tr').click( function () {
5716 * var data = oTable.fnGetData( this );
5717 * // ... do something with the array / object of data for the row
5718 * } );
5719 * } );
5720 *
5721 * @example
5722 * // Individual cell data
5723 * $(document).ready(function() {
5724 * oTable = $('#example').dataTable();
5725 *
5726 * oTable.$('td').click( function () {
5727 * var sData = oTable.fnGetData( this );
5728 * alert( 'The cell clicked on had the value of '+sData );
5729 * } );
5730 * } );
5731 */
5732 this.fnGetData = function( src, col )
5733 {
5734 var api = this.api( true );
5735
5736 if ( src !== undefined ) {
5737 var type = src.nodeName ? src.nodeName.toLowerCase() : '';
5738
5739 return col !== undefined || type == 'td' || type == 'th' ?
5740 api.cell( src, col ).data() :
5741 api.row( src ).data() || null;
5742 }
5743
5744 return api.data().toArray();
5745 };
5746
5747
5748 /**
5749 * Get an array of the TR nodes that are used in the table's body. Note that you will
5750 * typically want to use the '$' API method in preference to this as it is more
5751 * flexible.
5752 * @param {int} [iRow] Optional row index for the TR element you want
5753 * @returns {array|node} If iRow is undefined, returns an array of all TR elements
5754 * in the table's body, or iRow is defined, just the TR element requested.
5755 * @dtopt API
5756 * @deprecated Since v1.10
5757 *
5758 * @example
5759 * $(document).ready(function() {
5760 * var oTable = $('#example').dataTable();
5761 *
5762 * // Get the nodes from the table
5763 * var nNodes = oTable.fnGetNodes( );
5764 * } );
5765 */
5766 this.fnGetNodes = function( iRow )
5767 {
5768 var api = this.api( true );
5769
5770 return iRow !== undefined ?
5771 api.row( iRow ).node() :
5772 api.rows().nodes().flatten().toArray();
5773 };
5774
5775
5776 /**
5777 * Get the array indexes of a particular cell from it's DOM element
5778 * and column index including hidden columns
5779 * @param {node} node this can either be a TR, TD or TH in the table's body
5780 * @returns {int} If nNode is given as a TR, then a single index is returned, or
5781 * if given as a cell, an array of [row index, column index (visible),
5782 * column index (all)] is given.
5783 * @dtopt API
5784 * @deprecated Since v1.10
5785 *
5786 * @example
5787 * $(document).ready(function() {
5788 * $('#example tbody td').click( function () {
5789 * // Get the position of the current data from the node
5790 * var aPos = oTable.fnGetPosition( this );
5791 *
5792 * // Get the data array for this row
5793 * var aData = oTable.fnGetData( aPos[0] );
5794 *
5795 * // Update the data array and return the value
5796 * aData[ aPos[1] ] = 'clicked';
5797 * this.innerHTML = 'clicked';
5798 * } );
5799 *
5800 * // Init DataTables
5801 * oTable = $('#example').dataTable();
5802 * } );
5803 */
5804 this.fnGetPosition = function( node )
5805 {
5806 var api = this.api( true );
5807 var nodeName = node.nodeName.toUpperCase();
5808
5809 if ( nodeName == 'TR' ) {
5810 return api.row( node ).index();
5811 }
5812 else if ( nodeName == 'TD' || nodeName == 'TH' ) {
5813 var cell = api.cell( node ).index();
5814
5815 return [
5816 cell.row,
5817 cell.columnVisible,
5818 cell.column
5819 ];
5820 }
5821 return null;
5822 };
5823
5824
5825 /**
5826 * Check to see if a row is 'open' or not.
5827 * @param {node} nTr the table row to check
5828 * @returns {boolean} true if the row is currently open, false otherwise
5829 * @dtopt API
5830 * @deprecated Since v1.10
5831 *
5832 * @example
5833 * $(document).ready(function() {
5834 * var oTable;
5835 *
5836 * // 'open' an information row when a row is clicked on
5837 * $('#example tbody tr').click( function () {
5838 * if ( oTable.fnIsOpen(this) ) {
5839 * oTable.fnClose( this );
5840 * } else {
5841 * oTable.fnOpen( this, "Temporary row opened", "info_row" );
5842 * }
5843 * } );
5844 *
5845 * oTable = $('#example').dataTable();
5846 * } );
5847 */
5848 this.fnIsOpen = function( nTr )
5849 {
5850 return this.api( true ).row( nTr ).child.isShown();
5851 };
5852
5853
5854 /**
5855 * This function will place a new row directly after a row which is currently
5856 * on display on the page, with the HTML contents that is passed into the
5857 * function. This can be used, for example, to ask for confirmation that a
5858 * particular record should be deleted.
5859 * @param {node} nTr The table row to 'open'
5860 * @param {string|node|jQuery} mHtml The HTML to put into the row
5861 * @param {string} sClass Class to give the new TD cell
5862 * @returns {node} The row opened. Note that if the table row passed in as the
5863 * first parameter, is not found in the table, this method will silently
5864 * return.
5865 * @dtopt API
5866 * @deprecated Since v1.10
5867 *
5868 * @example
5869 * $(document).ready(function() {
5870 * var oTable;
5871 *
5872 * // 'open' an information row when a row is clicked on
5873 * $('#example tbody tr').click( function () {
5874 * if ( oTable.fnIsOpen(this) ) {
5875 * oTable.fnClose( this );
5876 * } else {
5877 * oTable.fnOpen( this, "Temporary row opened", "info_row" );
5878 * }
5879 * } );
5880 *
5881 * oTable = $('#example').dataTable();
5882 * } );
5883 */
5884 this.fnOpen = function( nTr, mHtml, sClass )
5885 {
5886 return this.api( true )
5887 .row( nTr )
5888 .child( mHtml, sClass )
5889 .show()
5890 .child()[0];
5891 };
5892
5893
5894 /**
5895 * Change the pagination - provides the internal logic for pagination in a simple API
5896 * function. With this function you can have a DataTables table go to the next,
5897 * previous, first or last pages.
5898 * @param {string|int} mAction Paging action to take: "first", "previous", "next" or "last"
5899 * or page number to jump to (integer), note that page 0 is the first page.
5900 * @param {bool} [bRedraw=true] Redraw the table or not
5901 * @dtopt API
5902 * @deprecated Since v1.10
5903 *
5904 * @example
5905 * $(document).ready(function() {
5906 * var oTable = $('#example').dataTable();
5907 * oTable.fnPageChange( 'next' );
5908 * } );
5909 */
5910 this.fnPageChange = function ( mAction, bRedraw )
5911 {
5912 var api = this.api( true ).page( mAction );
5913
5914 if ( bRedraw === undefined || bRedraw ) {
5915 api.draw(false);
5916 }
5917 };
5918
5919
5920 /**
5921 * Show a particular column
5922 * @param {int} iCol The column whose display should be changed
5923 * @param {bool} bShow Show (true) or hide (false) the column
5924 * @param {bool} [bRedraw=true] Redraw the table or not
5925 * @dtopt API
5926 * @deprecated Since v1.10
5927 *
5928 * @example
5929 * $(document).ready(function() {
5930 * var oTable = $('#example').dataTable();
5931 *
5932 * // Hide the second column after initialisation
5933 * oTable.fnSetColumnVis( 1, false );
5934 * } );
5935 */
5936 this.fnSetColumnVis = function ( iCol, bShow, bRedraw )
5937 {
5938 var api = this.api( true ).column( iCol ).visible( bShow );
5939
5940 if ( bRedraw === undefined || bRedraw ) {
5941 api.columns.adjust().draw();
5942 }
5943 };
5944
5945
5946 /**
5947 * Get the settings for a particular table for external manipulation
5948 * @returns {object} DataTables settings object. See
5949 * {@link DataTable.models.oSettings}
5950 * @dtopt API
5951 * @deprecated Since v1.10
5952 *
5953 * @example
5954 * $(document).ready(function() {
5955 * var oTable = $('#example').dataTable();
5956 * var oSettings = oTable.fnSettings();
5957 *
5958 * // Show an example parameter from the settings
5959 * alert( oSettings._iDisplayStart );
5960 * } );
5961 */
5962 this.fnSettings = function()
5963 {
5964 return _fnSettingsFromNode( this[_ext.iApiIndex] );
5965 };
5966
5967
5968 /**
5969 * Sort the table by a particular column
5970 * @param {int} iCol the data index to sort on. Note that this will not match the
5971 * 'display index' if you have hidden data entries
5972 * @dtopt API
5973 * @deprecated Since v1.10
5974 *
5975 * @example
5976 * $(document).ready(function() {
5977 * var oTable = $('#example').dataTable();
5978 *
5979 * // Sort immediately with columns 0 and 1
5980 * oTable.fnSort( [ [0,'asc'], [1,'asc'] ] );
5981 * } );
5982 */
5983 this.fnSort = function( aaSort )
5984 {
5985 this.api( true ).order( aaSort ).draw();
5986 };
5987
5988
5989 /**
5990 * Attach a sort listener to an element for a given column
5991 * @param {node} nNode the element to attach the sort listener to
5992 * @param {int} iColumn the column that a click on this node will sort on
5993 * @param {function} [fnCallback] callback function when sort is run
5994 * @dtopt API
5995 * @deprecated Since v1.10
5996 *
5997 * @example
5998 * $(document).ready(function() {
5999 * var oTable = $('#example').dataTable();
6000 *
6001 * // Sort on column 1, when 'sorter' is clicked on
6002 * oTable.fnSortListener( document.getElementById('sorter'), 1 );
6003 * } );
6004 */
6005 this.fnSortListener = function( nNode, iColumn, fnCallback )
6006 {
6007 this.api( true ).order.listener( nNode, iColumn, fnCallback );
6008 };
6009
6010
6011 /**
6012 * Update a table cell or row - this method will accept either a single value to
6013 * update the cell with, an array of values with one element for each column or
6014 * an object in the same format as the original data source. The function is
6015 * self-referencing in order to make the multi column updates easier.
6016 * @param {object|array|string} mData Data to update the cell/row with
6017 * @param {node|int} mRow TR element you want to update or the aoData index
6018 * @param {int} [iColumn] The column to update, give as null or undefined to
6019 * update a whole row.
6020 * @param {bool} [bRedraw=true] Redraw the table or not
6021 * @param {bool} [bAction=true] Perform pre-draw actions or not
6022 * @returns {int} 0 on success, 1 on error
6023 * @dtopt API
6024 * @deprecated Since v1.10
6025 *
6026 * @example
6027 * $(document).ready(function() {
6028 * var oTable = $('#example').dataTable();
6029 * oTable.fnUpdate( 'Example update', 0, 0 ); // Single cell
6030 * oTable.fnUpdate( ['a', 'b', 'c', 'd', 'e'], $('tbody tr')[0] ); // Row
6031 * } );
6032 */
6033 this.fnUpdate = function( mData, mRow, iColumn, bRedraw, bAction )
6034 {
6035 var api = this.api( true );
6036
6037 if ( iColumn === undefined || iColumn === null ) {
6038 api.row( mRow ).data( mData );
6039 }
6040 else {
6041 api.cell( mRow, iColumn ).data( mData );
6042 }
6043
6044 if ( bAction === undefined || bAction ) {
6045 api.columns.adjust();
6046 }
6047
6048 if ( bRedraw === undefined || bRedraw ) {
6049 api.draw();
6050 }
6051 return 0;
6052 };
6053
6054
6055 /**
6056 * Provide a common method for plug-ins to check the version of DataTables being used, in order
6057 * to ensure compatibility.
6058 * @param {string} sVersion Version string to check for, in the format "X.Y.Z". Note that the
6059 * formats "X" and "X.Y" are also acceptable.
6060 * @returns {boolean} true if this version of DataTables is greater or equal to the required
6061 * version, or false if this version of DataTales is not suitable
6062 * @method
6063 * @dtopt API
6064 * @deprecated Since v1.10
6065 *
6066 * @example
6067 * $(document).ready(function() {
6068 * var oTable = $('#example').dataTable();
6069 * alert( oTable.fnVersionCheck( '1.9.0' ) );
6070 * } );
6071 */
6072 this.fnVersionCheck = _ext.fnVersionCheck;
6073
6074
6075 var _that = this;
6076 var emptyInit = options === undefined;
6077 var len = this.length;
6078
6079 if ( emptyInit ) {
6080 options = {};
6081 }
6082
6083 this.oApi = this.internal = _ext.internal;
6084
6085 // Extend with old style plug-in API methods
6086 for ( var fn in DataTable.ext.internal ) {
6087 if ( fn ) {
6088 this[fn] = _fnExternApiFunc(fn);
6089 }
6090 }
6091
6092 this.each(function() {
6093 // For each initialisation we want to give it a clean initialisation
6094 // object that can be bashed around
6095 var o = {};
6096 var oInit = len > 1 ? // optimisation for single table case
6097 _fnExtend( o, options, true ) :
6098 options;
6099
6100 /*global oInit,_that,emptyInit*/
6101 var i=0, iLen, j, jLen, k, kLen;
6102 var sId = this.getAttribute( 'id' );
6103 var bInitHandedOff = false;
6104 var defaults = DataTable.defaults;
6105 var $this = $(this);
6106
6107
6108 /* Sanity check */
6109 if ( this.nodeName.toLowerCase() != 'table' )
6110 {
6111 _fnLog( null, 0, 'Non-table node initialisation ('+this.nodeName+')', 2 );
6112 return;
6113 }
6114
6115 /* Backwards compatibility for the defaults */
6116 _fnCompatOpts( defaults );
6117 _fnCompatCols( defaults.column );
6118
6119 /* Convert the camel-case defaults to Hungarian */
6120 _fnCamelToHungarian( defaults, defaults, true );
6121 _fnCamelToHungarian( defaults.column, defaults.column, true );
6122
6123 /* Setting up the initialisation object */
6124 _fnCamelToHungarian( defaults, $.extend( oInit, $this.data() ) );
6125
6126
6127
6128 /* Check to see if we are re-initialising a table */
6129 var allSettings = DataTable.settings;
6130 for ( i=0, iLen=allSettings.length ; i<iLen ; i++ )
6131 {
6132 var s = allSettings[i];
6133
6134 /* Base check on table node */
6135 if ( s.nTable == this || s.nTHead.parentNode == this || (s.nTFoot && s.nTFoot.parentNode == this) )
6136 {
6137 var bRetrieve = oInit.bRetrieve !== undefined ? oInit.bRetrieve : defaults.bRetrieve;
6138 var bDestroy = oInit.bDestroy !== undefined ? oInit.bDestroy : defaults.bDestroy;
6139
6140 if ( emptyInit || bRetrieve )
6141 {
6142 return s.oInstance;
6143 }
6144 else if ( bDestroy )
6145 {
6146 s.oInstance.fnDestroy();
6147 break;
6148 }
6149 else
6150 {
6151 _fnLog( s, 0, 'Cannot reinitialise DataTable', 3 );
6152 return;
6153 }
6154 }
6155
6156 /* If the element we are initialising has the same ID as a table which was previously
6157 * initialised, but the table nodes don't match (from before) then we destroy the old
6158 * instance by simply deleting it. This is under the assumption that the table has been
6159 * destroyed by other methods. Anyone using non-id selectors will need to do this manually
6160 */
6161 if ( s.sTableId == this.id )
6162 {
6163 allSettings.splice( i, 1 );
6164 break;
6165 }
6166 }
6167
6168 /* Ensure the table has an ID - required for accessibility */
6169 if ( sId === null || sId === "" )
6170 {
6171 sId = "DataTables_Table_"+(DataTable.ext._unique++);
6172 this.id = sId;
6173 }
6174
6175 /* Create the settings object for this table and set some of the default parameters */
6176 var oSettings = $.extend( true, {}, DataTable.models.oSettings, {
6177 "sDestroyWidth": $this[0].style.width,
6178 "sInstance": sId,
6179 "sTableId": sId
6180 } );
6181 oSettings.nTable = this;
6182 oSettings.oApi = _that.internal;
6183 oSettings.oInit = oInit;
6184
6185 allSettings.push( oSettings );
6186
6187 // Need to add the instance after the instance after the settings object has been added
6188 // to the settings array, so we can self reference the table instance if more than one
6189 oSettings.oInstance = (_that.length===1) ? _that : $this.dataTable();
6190
6191 // Backwards compatibility, before we apply all the defaults
6192 _fnCompatOpts( oInit );
6193
6194 if ( oInit.oLanguage )
6195 {
6196 _fnLanguageCompat( oInit.oLanguage );
6197 }
6198
6199 // If the length menu is given, but the init display length is not, use the length menu
6200 if ( oInit.aLengthMenu && ! oInit.iDisplayLength )
6201 {
6202 oInit.iDisplayLength = $.isArray( oInit.aLengthMenu[0] ) ?
6203 oInit.aLengthMenu[0][0] : oInit.aLengthMenu[0];
6204 }
6205
6206 // Apply the defaults and init options to make a single init object will all
6207 // options defined from defaults and instance options.
6208 oInit = _fnExtend( $.extend( true, {}, defaults ), oInit );
6209
6210
6211 // Map the initialisation options onto the settings object
6212 _fnMap( oSettings.oFeatures, oInit, [
6213 "bPaginate",
6214 "bLengthChange",
6215 "bFilter",
6216 "bSort",
6217 "bSortMulti",
6218 "bInfo",
6219 "bProcessing",
6220 "bAutoWidth",
6221 "bSortClasses",
6222 "bServerSide",
6223 "bDeferRender"
6224 ] );
6225 _fnMap( oSettings, oInit, [
6226 "asStripeClasses",
6227 "ajax",
6228 "fnServerData",
6229 "fnFormatNumber",
6230 "sServerMethod",
6231 "aaSorting",
6232 "aaSortingFixed",
6233 "aLengthMenu",
6234 "sPaginationType",
6235 "sAjaxSource",
6236 "sAjaxDataProp",
6237 "iStateDuration",
6238 "sDom",
6239 "bSortCellsTop",
6240 "iTabIndex",
6241 "fnStateLoadCallback",
6242 "fnStateSaveCallback",
6243 "renderer",
6244 "searchDelay",
6245 [ "iCookieDuration", "iStateDuration" ], // backwards compat
6246 [ "oSearch", "oPreviousSearch" ],
6247 [ "aoSearchCols", "aoPreSearchCols" ],
6248 [ "iDisplayLength", "_iDisplayLength" ],
6249 [ "bJQueryUI", "bJUI" ]
6250 ] );
6251 _fnMap( oSettings.oScroll, oInit, [
6252 [ "sScrollX", "sX" ],
6253 [ "sScrollXInner", "sXInner" ],
6254 [ "sScrollY", "sY" ],
6255 [ "bScrollCollapse", "bCollapse" ]
6256 ] );
6257 _fnMap( oSettings.oLanguage, oInit, "fnInfoCallback" );
6258
6259 /* Callback functions which are array driven */
6260 _fnCallbackReg( oSettings, 'aoDrawCallback', oInit.fnDrawCallback, 'user' );
6261 _fnCallbackReg( oSettings, 'aoServerParams', oInit.fnServerParams, 'user' );
6262 _fnCallbackReg( oSettings, 'aoStateSaveParams', oInit.fnStateSaveParams, 'user' );
6263 _fnCallbackReg( oSettings, 'aoStateLoadParams', oInit.fnStateLoadParams, 'user' );
6264 _fnCallbackReg( oSettings, 'aoStateLoaded', oInit.fnStateLoaded, 'user' );
6265 _fnCallbackReg( oSettings, 'aoRowCallback', oInit.fnRowCallback, 'user' );
6266 _fnCallbackReg( oSettings, 'aoRowCreatedCallback', oInit.fnCreatedRow, 'user' );
6267 _fnCallbackReg( oSettings, 'aoHeaderCallback', oInit.fnHeaderCallback, 'user' );
6268 _fnCallbackReg( oSettings, 'aoFooterCallback', oInit.fnFooterCallback, 'user' );
6269 _fnCallbackReg( oSettings, 'aoInitComplete', oInit.fnInitComplete, 'user' );
6270 _fnCallbackReg( oSettings, 'aoPreDrawCallback', oInit.fnPreDrawCallback, 'user' );
6271
6272 var oClasses = oSettings.oClasses;
6273
6274 // @todo Remove in 1.11
6275 if ( oInit.bJQueryUI )
6276 {
6277 /* Use the JUI classes object for display. You could clone the oStdClasses object if
6278 * you want to have multiple tables with multiple independent classes
6279 */
6280 $.extend( oClasses, DataTable.ext.oJUIClasses, oInit.oClasses );
6281
6282 if ( oInit.sDom === defaults.sDom && defaults.sDom === "lfrtip" )
6283 {
6284 /* Set the DOM to use a layout suitable for jQuery UI's theming */
6285 oSettings.sDom = '<"H"lfr>t<"F"ip>';
6286 }
6287
6288 if ( ! oSettings.renderer ) {
6289 oSettings.renderer = 'jqueryui';
6290 }
6291 else if ( $.isPlainObject( oSettings.renderer ) && ! oSettings.renderer.header ) {
6292 oSettings.renderer.header = 'jqueryui';
6293 }
6294 }
6295 else
6296 {
6297 $.extend( oClasses, DataTable.ext.classes, oInit.oClasses );
6298 }
6299 $this.addClass( oClasses.sTable );
6300
6301 /* Calculate the scroll bar width and cache it for use later on */
6302 if ( oSettings.oScroll.sX !== "" || oSettings.oScroll.sY !== "" )
6303 {
6304 oSettings.oScroll.iBarWidth = _fnScrollBarWidth();
6305 }
6306 if ( oSettings.oScroll.sX === true ) { // Easy initialisation of x-scrolling
6307 oSettings.oScroll.sX = '100%';
6308 }
6309
6310 if ( oSettings.iInitDisplayStart === undefined )
6311 {
6312 /* Display start point, taking into account the save saving */
6313 oSettings.iInitDisplayStart = oInit.iDisplayStart;
6314 oSettings._iDisplayStart = oInit.iDisplayStart;
6315 }
6316
6317 if ( oInit.iDeferLoading !== null )
6318 {
6319 oSettings.bDeferLoading = true;
6320 var tmp = $.isArray( oInit.iDeferLoading );
6321 oSettings._iRecordsDisplay = tmp ? oInit.iDeferLoading[0] : oInit.iDeferLoading;
6322 oSettings._iRecordsTotal = tmp ? oInit.iDeferLoading[1] : oInit.iDeferLoading;
6323 }
6324
6325 /* Language definitions */
6326 var oLanguage = oSettings.oLanguage;
6327 $.extend( true, oLanguage, oInit.oLanguage );
6328
6329 if ( oLanguage.sUrl !== "" )
6330 {
6331 /* Get the language definitions from a file - because this Ajax call makes the language
6332 * get async to the remainder of this function we use bInitHandedOff to indicate that
6333 * _fnInitialise will be fired by the returned Ajax handler, rather than the constructor
6334 */
6335 $.ajax( {
6336 dataType: 'json',
6337 url: oLanguage.sUrl,
6338 success: function ( json ) {
6339 _fnLanguageCompat( json );
6340 _fnCamelToHungarian( defaults.oLanguage, json );
6341 $.extend( true, oLanguage, json );
6342 _fnInitialise( oSettings );
6343 },
6344 error: function () {
6345 // Error occurred loading language file, continue on as best we can
6346 _fnInitialise( oSettings );
6347 }
6348 } );
6349 bInitHandedOff = true;
6350 }
6351
6352 /*
6353 * Stripes
6354 */
6355 if ( oInit.asStripeClasses === null )
6356 {
6357 oSettings.asStripeClasses =[
6358 oClasses.sStripeOdd,
6359 oClasses.sStripeEven
6360 ];
6361 }
6362
6363 /* Remove row stripe classes if they are already on the table row */
6364 var stripeClasses = oSettings.asStripeClasses;
6365 var rowOne = $this.children('tbody').find('tr').eq(0);
6366 if ( $.inArray( true, $.map( stripeClasses, function(el, i) {
6367 return rowOne.hasClass(el);
6368 } ) ) !== -1 ) {
6369 $('tbody tr', this).removeClass( stripeClasses.join(' ') );
6370 oSettings.asDestroyStripes = stripeClasses.slice();
6371 }
6372
6373 /*
6374 * Columns
6375 * See if we should load columns automatically or use defined ones
6376 */
6377 var anThs = [];
6378 var aoColumnsInit;
6379 var nThead = this.getElementsByTagName('thead');
6380 if ( nThead.length !== 0 )
6381 {
6382 _fnDetectHeader( oSettings.aoHeader, nThead[0] );
6383 anThs = _fnGetUniqueThs( oSettings );
6384 }
6385
6386 /* If not given a column array, generate one with nulls */
6387 if ( oInit.aoColumns === null )
6388 {
6389 aoColumnsInit = [];
6390 for ( i=0, iLen=anThs.length ; i<iLen ; i++ )
6391 {
6392 aoColumnsInit.push( null );
6393 }
6394 }
6395 else
6396 {
6397 aoColumnsInit = oInit.aoColumns;
6398 }
6399
6400 /* Add the columns */
6401 for ( i=0, iLen=aoColumnsInit.length ; i<iLen ; i++ )
6402 {
6403 _fnAddColumn( oSettings, anThs ? anThs[i] : null );
6404 }
6405
6406 /* Apply the column definitions */
6407 _fnApplyColumnDefs( oSettings, oInit.aoColumnDefs, aoColumnsInit, function (iCol, oDef) {
6408 _fnColumnOptions( oSettings, iCol, oDef );
6409 } );
6410
6411 /* HTML5 attribute detection - build an mData object automatically if the
6412 * attributes are found
6413 */
6414 if ( rowOne.length ) {
6415 var a = function ( cell, name ) {
6416 return cell.getAttribute( 'data-'+name ) !== null ? name : null;
6417 };
6418
6419 $.each( _fnGetRowElements( oSettings, rowOne[0] ).cells, function (i, cell) {
6420 var col = oSettings.aoColumns[i];
6421
6422 if ( col.mData === i ) {
6423 var sort = a( cell, 'sort' ) || a( cell, 'order' );
6424 var filter = a( cell, 'filter' ) || a( cell, 'search' );
6425
6426 if ( sort !== null || filter !== null ) {
6427 col.mData = {
6428 _: i+'.display',
6429 sort: sort !== null ? i+'.@data-'+sort : undefined,
6430 type: sort !== null ? i+'.@data-'+sort : undefined,
6431 filter: filter !== null ? i+'.@data-'+filter : undefined
6432 };
6433
6434 _fnColumnOptions( oSettings, i );
6435 }
6436 }
6437 } );
6438 }
6439
6440 var features = oSettings.oFeatures;
6441
6442 /* Must be done after everything which can be overridden by the state saving! */
6443 if ( oInit.bStateSave )
6444 {
6445 features.bStateSave = true;
6446 _fnLoadState( oSettings, oInit );
6447 _fnCallbackReg( oSettings, 'aoDrawCallback', _fnSaveState, 'state_save' );
6448 }
6449
6450
6451 /*
6452 * Sorting
6453 * @todo For modularisation (1.11) this needs to do into a sort start up handler
6454 */
6455
6456 // If aaSorting is not defined, then we use the first indicator in asSorting
6457 // in case that has been altered, so the default sort reflects that option
6458 if ( oInit.aaSorting === undefined )
6459 {
6460 var sorting = oSettings.aaSorting;
6461 for ( i=0, iLen=sorting.length ; i<iLen ; i++ )
6462 {
6463 sorting[i][1] = oSettings.aoColumns[ i ].asSorting[0];
6464 }
6465 }
6466
6467 /* Do a first pass on the sorting classes (allows any size changes to be taken into
6468 * account, and also will apply sorting disabled classes if disabled
6469 */
6470 _fnSortingClasses( oSettings );
6471
6472 if ( features.bSort )
6473 {
6474 _fnCallbackReg( oSettings, 'aoDrawCallback', function () {
6475 if ( oSettings.bSorted ) {
6476 var aSort = _fnSortFlatten( oSettings );
6477 var sortedColumns = {};
6478
6479 $.each( aSort, function (i, val) {
6480 sortedColumns[ val.src ] = val.dir;
6481 } );
6482
6483 _fnCallbackFire( oSettings, null, 'order', [oSettings, aSort, sortedColumns] );
6484 _fnSortAria( oSettings );
6485 }
6486 } );
6487 }
6488
6489 _fnCallbackReg( oSettings, 'aoDrawCallback', function () {
6490 if ( oSettings.bSorted || _fnDataSource( oSettings ) === 'ssp' || features.bDeferRender ) {
6491 _fnSortingClasses( oSettings );
6492 }
6493 }, 'sc' );
6494
6495
6496 /*
6497 * Final init
6498 * Cache the header, body and footer as required, creating them if needed
6499 */
6500
6501 /* Browser support detection */
6502 _fnBrowserDetect( oSettings );
6503
6504 // Work around for Webkit bug 83867 - store the caption-side before removing from doc
6505 var captions = $this.children('caption').each( function () {
6506 this._captionSide = $this.css('caption-side');
6507 } );
6508
6509 var thead = $this.children('thead');
6510 if ( thead.length === 0 )
6511 {
6512 thead = $('<thead/>').appendTo(this);
6513 }
6514 oSettings.nTHead = thead[0];
6515
6516 var tbody = $this.children('tbody');
6517 if ( tbody.length === 0 )
6518 {
6519 tbody = $('<tbody/>').appendTo(this);
6520 }
6521 oSettings.nTBody = tbody[0];
6522
6523 var tfoot = $this.children('tfoot');
6524 if ( tfoot.length === 0 && captions.length > 0 && (oSettings.oScroll.sX !== "" || oSettings.oScroll.sY !== "") )
6525 {
6526 // If we are a scrolling table, and no footer has been given, then we need to create
6527 // a tfoot element for the caption element to be appended to
6528 tfoot = $('<tfoot/>').appendTo(this);
6529 }
6530
6531 if ( tfoot.length === 0 || tfoot.children().length === 0 ) {
6532 $this.addClass( oClasses.sNoFooter );
6533 }
6534 else if ( tfoot.length > 0 ) {
6535 oSettings.nTFoot = tfoot[0];
6536 _fnDetectHeader( oSettings.aoFooter, oSettings.nTFoot );
6537 }
6538
6539 /* Check if there is data passing into the constructor */
6540 if ( oInit.aaData )
6541 {
6542 for ( i=0 ; i<oInit.aaData.length ; i++ )
6543 {
6544 _fnAddData( oSettings, oInit.aaData[ i ] );
6545 }
6546 }
6547 else if ( oSettings.bDeferLoading || _fnDataSource( oSettings ) == 'dom' )
6548 {
6549 /* Grab the data from the page - only do this when deferred loading or no Ajax
6550 * source since there is no point in reading the DOM data if we are then going
6551 * to replace it with Ajax data
6552 */
6553 _fnAddTr( oSettings, $(oSettings.nTBody).children('tr') );
6554 }
6555
6556 /* Copy the data index array */
6557 oSettings.aiDisplay = oSettings.aiDisplayMaster.slice();
6558
6559 /* Initialisation complete - table can be drawn */
6560 oSettings.bInitialised = true;
6561
6562 /* Check if we need to initialise the table (it might not have been handed off to the
6563 * language processor)
6564 */
6565 if ( bInitHandedOff === false )
6566 {
6567 _fnInitialise( oSettings );
6568 }
6569 } );
6570 _that = null;
6571 return this;
6572 };
6573
6574
6575
6576 /**
6577 * Computed structure of the DataTables API, defined by the options passed to
6578 * `DataTable.Api.register()` when building the API.
6579 *
6580 * The structure is built in order to speed creation and extension of the Api
6581 * objects since the extensions are effectively pre-parsed.
6582 *
6583 * The array is an array of objects with the following structure, where this
6584 * base array represents the Api prototype base:
6585 *
6586 * [
6587 * {
6588 * name: 'data' -- string - Property name
6589 * val: function () {}, -- function - Api method (or undefined if just an object
6590 * methodExt: [ ... ], -- array - Array of Api object definitions to extend the method result
6591 * propExt: [ ... ] -- array - Array of Api object definitions to extend the property
6592 * },
6593 * {
6594 * name: 'row'
6595 * val: {},
6596 * methodExt: [ ... ],
6597 * propExt: [
6598 * {
6599 * name: 'data'
6600 * val: function () {},
6601 * methodExt: [ ... ],
6602 * propExt: [ ... ]
6603 * },
6604 * ...
6605 * ]
6606 * }
6607 * ]
6608 *
6609 * @type {Array}
6610 * @ignore
6611 */
6612 var __apiStruct = [];
6613
6614
6615 /**
6616 * `Array.prototype` reference.
6617 *
6618 * @type object
6619 * @ignore
6620 */
6621 var __arrayProto = Array.prototype;
6622
6623
6624 /**
6625 * Abstraction for `context` parameter of the `Api` constructor to allow it to
6626 * take several different forms for ease of use.
6627 *
6628 * Each of the input parameter types will be converted to a DataTables settings
6629 * object where possible.
6630 *
6631 * @param {string|node|jQuery|object} mixed DataTable identifier. Can be one
6632 * of:
6633 *
6634 * * `string` - jQuery selector. Any DataTables' matching the given selector
6635 * with be found and used.
6636 * * `node` - `TABLE` node which has already been formed into a DataTable.
6637 * * `jQuery` - A jQuery object of `TABLE` nodes.
6638 * * `object` - DataTables settings object
6639 * * `DataTables.Api` - API instance
6640 * @return {array|null} Matching DataTables settings objects. `null` or
6641 * `undefined` is returned if no matching DataTable is found.
6642 * @ignore
6643 */
6644 var _toSettings = function ( mixed )
6645 {
6646 var idx, jq;
6647 var settings = DataTable.settings;
6648 var tables = $.map( settings, function (el, i) {
6649 return el.nTable;
6650 } );
6651
6652 if ( ! mixed ) {
6653 return [];
6654 }
6655 else if ( mixed.nTable && mixed.oApi ) {
6656 // DataTables settings object
6657 return [ mixed ];
6658 }
6659 else if ( mixed.nodeName && mixed.nodeName.toLowerCase() === 'table' ) {
6660 // Table node
6661 idx = $.inArray( mixed, tables );
6662 return idx !== -1 ? [ settings[idx] ] : null;
6663 }
6664 else if ( mixed && typeof mixed.settings === 'function' ) {
6665 return mixed.settings().toArray();
6666 }
6667 else if ( typeof mixed === 'string' ) {
6668 // jQuery selector
6669 jq = $(mixed);
6670 }
6671 else if ( mixed instanceof $ ) {
6672 // jQuery object (also DataTables instance)
6673 jq = mixed;
6674 }
6675
6676 if ( jq ) {
6677 return jq.map( function(i) {
6678 idx = $.inArray( this, tables );
6679 return idx !== -1 ? settings[idx] : null;
6680 } ).toArray();
6681 }
6682 };
6683
6684
6685 /**
6686 * DataTables API class - used to control and interface with one or more
6687 * DataTables enhanced tables.
6688 *
6689 * The API class is heavily based on jQuery, presenting a chainable interface
6690 * that you can use to interact with tables. Each instance of the API class has
6691 * a "context" - i.e. the tables that it will operate on. This could be a single
6692 * table, all tables on a page or a sub-set thereof.
6693 *
6694 * Additionally the API is designed to allow you to easily work with the data in
6695 * the tables, retrieving and manipulating it as required. This is done by
6696 * presenting the API class as an array like interface. The contents of the
6697 * array depend upon the actions requested by each method (for example
6698 * `rows().nodes()` will return an array of nodes, while `rows().data()` will
6699 * return an array of objects or arrays depending upon your table's
6700 * configuration). The API object has a number of array like methods (`push`,
6701 * `pop`, `reverse` etc) as well as additional helper methods (`each`, `pluck`,
6702 * `unique` etc) to assist your working with the data held in a table.
6703 *
6704 * Most methods (those which return an Api instance) are chainable, which means
6705 * the return from a method call also has all of the methods available that the
6706 * top level object had. For example, these two calls are equivalent:
6707 *
6708 * // Not chained
6709 * api.row.add( {...} );
6710 * api.draw();
6711 *
6712 * // Chained
6713 * api.row.add( {...} ).draw();
6714 *
6715 * @class DataTable.Api
6716 * @param {array|object|string|jQuery} context DataTable identifier. This is
6717 * used to define which DataTables enhanced tables this API will operate on.
6718 * Can be one of:
6719 *
6720 * * `string` - jQuery selector. Any DataTables' matching the given selector
6721 * with be found and used.
6722 * * `node` - `TABLE` node which has already been formed into a DataTable.
6723 * * `jQuery` - A jQuery object of `TABLE` nodes.
6724 * * `object` - DataTables settings object
6725 * @param {array} [data] Data to initialise the Api instance with.
6726 *
6727 * @example
6728 * // Direct initialisation during DataTables construction
6729 * var api = $('#example').DataTable();
6730 *
6731 * @example
6732 * // Initialisation using a DataTables jQuery object
6733 * var api = $('#example').dataTable().api();
6734 *
6735 * @example
6736 * // Initialisation as a constructor
6737 * var api = new $.fn.DataTable.Api( 'table.dataTable' );
6738 */
6739 _Api = function ( context, data )
6740 {
6741 if ( ! (this instanceof _Api) ) {
6742 return new _Api( context, data );
6743 }
6744
6745 var settings = [];
6746 var ctxSettings = function ( o ) {
6747 var a = _toSettings( o );
6748 if ( a ) {
6749 settings.push.apply( settings, a );
6750 }
6751 };
6752
6753 if ( $.isArray( context ) ) {
6754 for ( var i=0, ien=context.length ; i<ien ; i++ ) {
6755 ctxSettings( context[i] );
6756 }
6757 }
6758 else {
6759 ctxSettings( context );
6760 }
6761
6762 // Remove duplicates
6763 this.context = _unique( settings );
6764
6765 // Initial data
6766 if ( data ) {
6767 this.push.apply( this, data.toArray ? data.toArray() : data );
6768 }
6769
6770 // selector
6771 this.selector = {
6772 rows: null,
6773 cols: null,
6774 opts: null
6775 };
6776
6777 _Api.extend( this, this, __apiStruct );
6778 };
6779
6780 DataTable.Api = _Api;
6781
6782 _Api.prototype = /** @lends DataTables.Api */{
6783 any: function ()
6784 {
6785 return this.flatten().length !== 0;
6786 },
6787
6788
6789 concat: __arrayProto.concat,
6790
6791
6792 context: [], // array of table settings objects
6793
6794
6795 each: function ( fn )
6796 {
6797 for ( var i=0, ien=this.length ; i<ien; i++ ) {
6798 fn.call( this, this[i], i, this );
6799 }
6800
6801 return this;
6802 },
6803
6804
6805 eq: function ( idx )
6806 {
6807 var ctx = this.context;
6808
6809 return ctx.length > idx ?
6810 new _Api( ctx[idx], this[idx] ) :
6811 null;
6812 },
6813
6814
6815 filter: function ( fn )
6816 {
6817 var a = [];
6818
6819 if ( __arrayProto.filter ) {
6820 a = __arrayProto.filter.call( this, fn, this );
6821 }
6822 else {
6823 // Compatibility for browsers without EMCA-252-5 (JS 1.6)
6824 for ( var i=0, ien=this.length ; i<ien ; i++ ) {
6825 if ( fn.call( this, this[i], i, this ) ) {
6826 a.push( this[i] );
6827 }
6828 }
6829 }
6830
6831 return new _Api( this.context, a );
6832 },
6833
6834
6835 flatten: function ()
6836 {
6837 var a = [];
6838 return new _Api( this.context, a.concat.apply( a, this.toArray() ) );
6839 },
6840
6841
6842 join: __arrayProto.join,
6843
6844
6845 indexOf: __arrayProto.indexOf || function (obj, start)
6846 {
6847 for ( var i=(start || 0), ien=this.length ; i<ien ; i++ ) {
6848 if ( this[i] === obj ) {
6849 return i;
6850 }
6851 }
6852 return -1;
6853 },
6854
6855 iterator: function ( flatten, type, fn, alwaysNew ) {
6856 var
6857 a = [], ret,
6858 i, ien, j, jen,
6859 context = this.context,
6860 rows, items, item,
6861 selector = this.selector;
6862
6863 // Argument shifting
6864 if ( typeof flatten === 'string' ) {
6865 alwaysNew = fn;
6866 fn = type;
6867 type = flatten;
6868 flatten = false;
6869 }
6870
6871 for ( i=0, ien=context.length ; i<ien ; i++ ) {
6872 var apiInst = new _Api( context[i] );
6873
6874 if ( type === 'table' ) {
6875 ret = fn.call( apiInst, context[i], i );
6876
6877 if ( ret !== undefined ) {
6878 a.push( ret );
6879 }
6880 }
6881 else if ( type === 'columns' || type === 'rows' ) {
6882 // this has same length as context - one entry for each table
6883 ret = fn.call( apiInst, context[i], this[i], i );
6884
6885 if ( ret !== undefined ) {
6886 a.push( ret );
6887 }
6888 }
6889 else if ( type === 'column' || type === 'column-rows' || type === 'row' || type === 'cell' ) {
6890 // columns and rows share the same structure.
6891 // 'this' is an array of column indexes for each context
6892 items = this[i];
6893
6894 if ( type === 'column-rows' ) {
6895 rows = _selector_row_indexes( context[i], selector.opts );
6896 }
6897
6898 for ( j=0, jen=items.length ; j<jen ; j++ ) {
6899 item = items[j];
6900
6901 if ( type === 'cell' ) {
6902 ret = fn.call( apiInst, context[i], item.row, item.column, i, j );
6903 }
6904 else {
6905 ret = fn.call( apiInst, context[i], item, i, j, rows );
6906 }
6907
6908 if ( ret !== undefined ) {
6909 a.push( ret );
6910 }
6911 }
6912 }
6913 }
6914
6915 if ( a.length || alwaysNew ) {
6916 var api = new _Api( context, flatten ? a.concat.apply( [], a ) : a );
6917 var apiSelector = api.selector;
6918 apiSelector.rows = selector.rows;
6919 apiSelector.cols = selector.cols;
6920 apiSelector.opts = selector.opts;
6921 return api;
6922 }
6923 return this;
6924 },
6925
6926
6927 lastIndexOf: __arrayProto.lastIndexOf || function (obj, start)
6928 {
6929 // Bit cheeky...
6930 return this.indexOf.apply( this.toArray.reverse(), arguments );
6931 },
6932
6933
6934 length: 0,
6935
6936
6937 map: function ( fn )
6938 {
6939 var a = [];
6940
6941 if ( __arrayProto.map ) {
6942 a = __arrayProto.map.call( this, fn, this );
6943 }
6944 else {
6945 // Compatibility for browsers without EMCA-252-5 (JS 1.6)
6946 for ( var i=0, ien=this.length ; i<ien ; i++ ) {
6947 a.push( fn.call( this, this[i], i ) );
6948 }
6949 }
6950
6951 return new _Api( this.context, a );
6952 },
6953
6954
6955 pluck: function ( prop )
6956 {
6957 return this.map( function ( el ) {
6958 return el[ prop ];
6959 } );
6960 },
6961
6962 pop: __arrayProto.pop,
6963
6964
6965 push: __arrayProto.push,
6966
6967
6968 // Does not return an API instance
6969 reduce: __arrayProto.reduce || function ( fn, init )
6970 {
6971 return _fnReduce( this, fn, init, 0, this.length, 1 );
6972 },
6973
6974
6975 reduceRight: __arrayProto.reduceRight || function ( fn, init )
6976 {
6977 return _fnReduce( this, fn, init, this.length-1, -1, -1 );
6978 },
6979
6980
6981 reverse: __arrayProto.reverse,
6982
6983
6984 // Object with rows, columns and opts
6985 selector: null,
6986
6987
6988 shift: __arrayProto.shift,
6989
6990
6991 sort: __arrayProto.sort, // ? name - order?
6992
6993
6994 splice: __arrayProto.splice,
6995
6996
6997 toArray: function ()
6998 {
6999 return __arrayProto.slice.call( this );
7000 },
7001
7002
7003 to$: function ()
7004 {
7005 return $( this );
7006 },
7007
7008
7009 toJQuery: function ()
7010 {
7011 return $( this );
7012 },
7013
7014
7015 unique: function ()
7016 {
7017 return new _Api( this.context, _unique(this) );
7018 },
7019
7020
7021 unshift: __arrayProto.unshift
7022 };
7023
7024
7025 _Api.extend = function ( scope, obj, ext )
7026 {
7027 // Only extend API instances and static properties of the API
7028 if ( ! ext.length || ! obj || ( ! (obj instanceof _Api) && ! obj.__dt_wrapper ) ) {
7029 return;
7030 }
7031
7032 var
7033 i, ien,
7034 j, jen,
7035 struct, inner,
7036 methodScoping = function ( scope, fn, struc ) {
7037 return function () {
7038 var ret = fn.apply( scope, arguments );
7039
7040 // Method extension
7041 _Api.extend( ret, ret, struc.methodExt );
7042 return ret;
7043 };
7044 };
7045
7046 for ( i=0, ien=ext.length ; i<ien ; i++ ) {
7047 struct = ext[i];
7048
7049 // Value
7050 obj[ struct.name ] = typeof struct.val === 'function' ?
7051 methodScoping( scope, struct.val, struct ) :
7052 $.isPlainObject( struct.val ) ?
7053 {} :
7054 struct.val;
7055
7056 obj[ struct.name ].__dt_wrapper = true;
7057
7058 // Property extension
7059 _Api.extend( scope, obj[ struct.name ], struct.propExt );
7060 }
7061 };
7062
7063
7064 // @todo - Is there need for an augment function?
7065 // _Api.augment = function ( inst, name )
7066 // {
7067 // // Find src object in the structure from the name
7068 // var parts = name.split('.');
7069
7070 // _Api.extend( inst, obj );
7071 // };
7072
7073
7074 // [
7075 // {
7076 // name: 'data' -- string - Property name
7077 // val: function () {}, -- function - Api method (or undefined if just an object
7078 // methodExt: [ ... ], -- array - Array of Api object definitions to extend the method result
7079 // propExt: [ ... ] -- array - Array of Api object definitions to extend the property
7080 // },
7081 // {
7082 // name: 'row'
7083 // val: {},
7084 // methodExt: [ ... ],
7085 // propExt: [
7086 // {
7087 // name: 'data'
7088 // val: function () {},
7089 // methodExt: [ ... ],
7090 // propExt: [ ... ]
7091 // },
7092 // ...
7093 // ]
7094 // }
7095 // ]
7096
7097 _Api.register = _api_register = function ( name, val )
7098 {
7099 if ( $.isArray( name ) ) {
7100 for ( var j=0, jen=name.length ; j<jen ; j++ ) {
7101 _Api.register( name[j], val );
7102 }
7103 return;
7104 }
7105
7106 var
7107 i, ien,
7108 heir = name.split('.'),
7109 struct = __apiStruct,
7110 key, method;
7111
7112 var find = function ( src, name ) {
7113 for ( var i=0, ien=src.length ; i<ien ; i++ ) {
7114 if ( src[i].name === name ) {
7115 return src[i];
7116 }
7117 }
7118 return null;
7119 };
7120
7121 for ( i=0, ien=heir.length ; i<ien ; i++ ) {
7122 method = heir[i].indexOf('()') !== -1;
7123 key = method ?
7124 heir[i].replace('()', '') :
7125 heir[i];
7126
7127 var src = find( struct, key );
7128 if ( ! src ) {
7129 src = {
7130 name: key,
7131 val: {},
7132 methodExt: [],
7133 propExt: []
7134 };
7135 struct.push( src );
7136 }
7137
7138 if ( i === ien-1 ) {
7139 src.val = val;
7140 }
7141 else {
7142 struct = method ?
7143 src.methodExt :
7144 src.propExt;
7145 }
7146 }
7147 };
7148
7149
7150 _Api.registerPlural = _api_registerPlural = function ( pluralName, singularName, val ) {
7151 _Api.register( pluralName, val );
7152
7153 _Api.register( singularName, function () {
7154 var ret = val.apply( this, arguments );
7155
7156 if ( ret === this ) {
7157 // Returned item is the API instance that was passed in, return it
7158 return this;
7159 }
7160 else if ( ret instanceof _Api ) {
7161 // New API instance returned, want the value from the first item
7162 // in the returned array for the singular result.
7163 return ret.length ?
7164 $.isArray( ret[0] ) ?
7165 new _Api( ret.context, ret[0] ) : // Array results are 'enhanced'
7166 ret[0] :
7167 undefined;
7168 }
7169
7170 // Non-API return - just fire it back
7171 return ret;
7172 } );
7173 };
7174
7175
7176 /**
7177 * Selector for HTML tables. Apply the given selector to the give array of
7178 * DataTables settings objects.
7179 *
7180 * @param {string|integer} [selector] jQuery selector string or integer
7181 * @param {array} Array of DataTables settings objects to be filtered
7182 * @return {array}
7183 * @ignore
7184 */
7185 var __table_selector = function ( selector, a )
7186 {
7187 // Integer is used to pick out a table by index
7188 if ( typeof selector === 'number' ) {
7189 return [ a[ selector ] ];
7190 }
7191
7192 // Perform a jQuery selector on the table nodes
7193 var nodes = $.map( a, function (el, i) {
7194 return el.nTable;
7195 } );
7196
7197 return $(nodes)
7198 .filter( selector )
7199 .map( function (i) {
7200 // Need to translate back from the table node to the settings
7201 var idx = $.inArray( this, nodes );
7202 return a[ idx ];
7203 } )
7204 .toArray();
7205 };
7206
7207
7208
7209 /**
7210 * Context selector for the API's context (i.e. the tables the API instance
7211 * refers to.
7212 *
7213 * @name DataTable.Api#tables
7214 * @param {string|integer} [selector] Selector to pick which tables the iterator
7215 * should operate on. If not given, all tables in the current context are
7216 * used. This can be given as a jQuery selector (for example `':gt(0)'`) to
7217 * select multiple tables or as an integer to select a single table.
7218 * @returns {DataTable.Api} Returns a new API instance if a selector is given.
7219 */
7220 _api_register( 'tables()', function ( selector ) {
7221 // A new instance is created if there was a selector specified
7222 return selector ?
7223 new _Api( __table_selector( selector, this.context ) ) :
7224 this;
7225 } );
7226
7227
7228 _api_register( 'table()', function ( selector ) {
7229 var tables = this.tables( selector );
7230 var ctx = tables.context;
7231
7232 // Truncate to the first matched table
7233 return ctx.length ?
7234 new _Api( ctx[0] ) :
7235 tables;
7236 } );
7237
7238
7239 _api_registerPlural( 'tables().nodes()', 'table().node()' , function () {
7240 return this.iterator( 'table', function ( ctx ) {
7241 return ctx.nTable;
7242 }, 1 );
7243 } );
7244
7245
7246 _api_registerPlural( 'tables().body()', 'table().body()' , function () {
7247 return this.iterator( 'table', function ( ctx ) {
7248 return ctx.nTBody;
7249 }, 1 );
7250 } );
7251
7252
7253 _api_registerPlural( 'tables().header()', 'table().header()' , function () {
7254 return this.iterator( 'table', function ( ctx ) {
7255 return ctx.nTHead;
7256 }, 1 );
7257 } );
7258
7259
7260 _api_registerPlural( 'tables().footer()', 'table().footer()' , function () {
7261 return this.iterator( 'table', function ( ctx ) {
7262 return ctx.nTFoot;
7263 }, 1 );
7264 } );
7265
7266
7267 _api_registerPlural( 'tables().containers()', 'table().container()' , function () {
7268 return this.iterator( 'table', function ( ctx ) {
7269 return ctx.nTableWrapper;
7270 }, 1 );
7271 } );
7272
7273
7274
7275 /**
7276 * Redraw the tables in the current context.
7277 *
7278 * @param {boolean} [reset=true] Reset (default) or hold the current paging
7279 * position. A full re-sort and re-filter is performed when this method is
7280 * called, which is why the pagination reset is the default action.
7281 * @returns {DataTables.Api} this
7282 */
7283 _api_register( 'draw()', function ( resetPaging ) {
7284 return this.iterator( 'table', function ( settings ) {
7285 _fnReDraw( settings, resetPaging===false );
7286 } );
7287 } );
7288
7289
7290
7291 /**
7292 * Get the current page index.
7293 *
7294 * @return {integer} Current page index (zero based)
7295 *//**
7296 * Set the current page.
7297 *
7298 * Note that if you attempt to show a page which does not exist, DataTables will
7299 * not throw an error, but rather reset the paging.
7300 *
7301 * @param {integer|string} action The paging action to take. This can be one of:
7302 * * `integer` - The page index to jump to
7303 * * `string` - An action to take:
7304 * * `first` - Jump to first page.
7305 * * `next` - Jump to the next page
7306 * * `previous` - Jump to previous page
7307 * * `last` - Jump to the last page.
7308 * @returns {DataTables.Api} this
7309 */
7310 _api_register( 'page()', function ( action ) {
7311 if ( action === undefined ) {
7312 return this.page.info().page; // not an expensive call
7313 }
7314
7315 // else, have an action to take on all tables
7316 return this.iterator( 'table', function ( settings ) {
7317 _fnPageChange( settings, action );
7318 } );
7319 } );
7320
7321
7322 /**
7323 * Paging information for the first table in the current context.
7324 *
7325 * If you require paging information for another table, use the `table()` method
7326 * with a suitable selector.
7327 *
7328 * @return {object} Object with the following properties set:
7329 * * `page` - Current page index (zero based - i.e. the first page is `0`)
7330 * * `pages` - Total number of pages
7331 * * `start` - Display index for the first record shown on the current page
7332 * * `end` - Display index for the last record shown on the current page
7333 * * `length` - Display length (number of records). Note that generally `start
7334 * + length = end`, but this is not always true, for example if there are
7335 * only 2 records to show on the final page, with a length of 10.
7336 * * `recordsTotal` - Full data set length
7337 * * `recordsDisplay` - Data set length once the current filtering criterion
7338 * are applied.
7339 */
7340 _api_register( 'page.info()', function ( action ) {
7341 if ( this.context.length === 0 ) {
7342 return undefined;
7343 }
7344
7345 var
7346 settings = this.context[0],
7347 start = settings._iDisplayStart,
7348 len = settings._iDisplayLength,
7349 visRecords = settings.fnRecordsDisplay(),
7350 all = len === -1;
7351
7352 return {
7353 "page": all ? 0 : Math.floor( start / len ),
7354 "pages": all ? 1 : Math.ceil( visRecords / len ),
7355 "start": start,
7356 "end": settings.fnDisplayEnd(),
7357 "length": len,
7358 "recordsTotal": settings.fnRecordsTotal(),
7359 "recordsDisplay": visRecords
7360 };
7361 } );
7362
7363
7364 /**
7365 * Get the current page length.
7366 *
7367 * @return {integer} Current page length. Note `-1` indicates that all records
7368 * are to be shown.
7369 *//**
7370 * Set the current page length.
7371 *
7372 * @param {integer} Page length to set. Use `-1` to show all records.
7373 * @returns {DataTables.Api} this
7374 */
7375 _api_register( 'page.len()', function ( len ) {
7376 // Note that we can't call this function 'length()' because `length`
7377 // is a Javascript property of functions which defines how many arguments
7378 // the function expects.
7379 if ( len === undefined ) {
7380 return this.context.length !== 0 ?
7381 this.context[0]._iDisplayLength :
7382 undefined;
7383 }
7384
7385 // else, set the page length
7386 return this.iterator( 'table', function ( settings ) {
7387 _fnLengthChange( settings, len );
7388 } );
7389 } );
7390
7391
7392
7393 var __reload = function ( settings, holdPosition, callback ) {
7394 // Use the draw event to trigger a callback
7395 if ( callback ) {
7396 var api = new _Api( settings );
7397
7398 api.one( 'draw', function () {
7399 callback( api.ajax.json() );
7400 } );
7401 }
7402
7403 if ( _fnDataSource( settings ) == 'ssp' ) {
7404 _fnReDraw( settings, holdPosition );
7405 }
7406 else {
7407 // Trigger xhr
7408 _fnProcessingDisplay( settings, true );
7409
7410 _fnBuildAjax( settings, [], function( json ) {
7411 _fnClearTable( settings );
7412
7413 var data = _fnAjaxDataSrc( settings, json );
7414 for ( var i=0, ien=data.length ; i<ien ; i++ ) {
7415 _fnAddData( settings, data[i] );
7416 }
7417
7418 _fnReDraw( settings, holdPosition );
7419 _fnProcessingDisplay( settings, false );
7420 } );
7421 }
7422 };
7423
7424
7425 /**
7426 * Get the JSON response from the last Ajax request that DataTables made to the
7427 * server. Note that this returns the JSON from the first table in the current
7428 * context.
7429 *
7430 * @return {object} JSON received from the server.
7431 */
7432 _api_register( 'ajax.json()', function () {
7433 var ctx = this.context;
7434
7435 if ( ctx.length > 0 ) {
7436 return ctx[0].json;
7437 }
7438
7439 // else return undefined;
7440 } );
7441
7442
7443 /**
7444 * Get the data submitted in the last Ajax request
7445 */
7446 _api_register( 'ajax.params()', function () {
7447 var ctx = this.context;
7448
7449 if ( ctx.length > 0 ) {
7450 return ctx[0].oAjaxData;
7451 }
7452
7453 // else return undefined;
7454 } );
7455
7456
7457 /**
7458 * Reload tables from the Ajax data source. Note that this function will
7459 * automatically re-draw the table when the remote data has been loaded.
7460 *
7461 * @param {boolean} [reset=true] Reset (default) or hold the current paging
7462 * position. A full re-sort and re-filter is performed when this method is
7463 * called, which is why the pagination reset is the default action.
7464 * @returns {DataTables.Api} this
7465 */
7466 _api_register( 'ajax.reload()', function ( callback, resetPaging ) {
7467 return this.iterator( 'table', function (settings) {
7468 __reload( settings, resetPaging===false, callback );
7469 } );
7470 } );
7471
7472
7473 /**
7474 * Get the current Ajax URL. Note that this returns the URL from the first
7475 * table in the current context.
7476 *
7477 * @return {string} Current Ajax source URL
7478 *//**
7479 * Set the Ajax URL. Note that this will set the URL for all tables in the
7480 * current context.
7481 *
7482 * @param {string} url URL to set.
7483 * @returns {DataTables.Api} this
7484 */
7485 _api_register( 'ajax.url()', function ( url ) {
7486 var ctx = this.context;
7487
7488 if ( url === undefined ) {
7489 // get
7490 if ( ctx.length === 0 ) {
7491 return undefined;
7492 }
7493 ctx = ctx[0];
7494
7495 return ctx.ajax ?
7496 $.isPlainObject( ctx.ajax ) ?
7497 ctx.ajax.url :
7498 ctx.ajax :
7499 ctx.sAjaxSource;
7500 }
7501
7502 // set
7503 return this.iterator( 'table', function ( settings ) {
7504 if ( $.isPlainObject( settings.ajax ) ) {
7505 settings.ajax.url = url;
7506 }
7507 else {
7508 settings.ajax = url;
7509 }
7510 // No need to consider sAjaxSource here since DataTables gives priority
7511 // to `ajax` over `sAjaxSource`. So setting `ajax` here, renders any
7512 // value of `sAjaxSource` redundant.
7513 } );
7514 } );
7515
7516
7517 /**
7518 * Load data from the newly set Ajax URL. Note that this method is only
7519 * available when `ajax.url()` is used to set a URL. Additionally, this method
7520 * has the same effect as calling `ajax.reload()` but is provided for
7521 * convenience when setting a new URL. Like `ajax.reload()` it will
7522 * automatically redraw the table once the remote data has been loaded.
7523 *
7524 * @returns {DataTables.Api} this
7525 */
7526 _api_register( 'ajax.url().load()', function ( callback, resetPaging ) {
7527 // Same as a reload, but makes sense to present it for easy access after a
7528 // url change
7529 return this.iterator( 'table', function ( ctx ) {
7530 __reload( ctx, resetPaging===false, callback );
7531 } );
7532 } );
7533
7534
7535
7536
7537 var _selector_run = function ( type, selector, selectFn, settings, opts )
7538 {
7539 var
7540 out = [], res,
7541 a, i, ien, j, jen,
7542 selectorType = typeof selector;
7543
7544 // Can't just check for isArray here, as an API or jQuery instance might be
7545 // given with their array like look
7546 if ( ! selector || selectorType === 'string' || selectorType === 'function' || selector.length === undefined ) {
7547 selector = [ selector ];
7548 }
7549
7550 for ( i=0, ien=selector.length ; i<ien ; i++ ) {
7551 a = selector[i] && selector[i].split ?
7552 selector[i].split(',') :
7553 [ selector[i] ];
7554
7555 for ( j=0, jen=a.length ; j<jen ; j++ ) {
7556 res = selectFn( typeof a[j] === 'string' ? $.trim(a[j]) : a[j] );
7557
7558 if ( res && res.length ) {
7559 out.push.apply( out, res );
7560 }
7561 }
7562 }
7563
7564 // selector extensions
7565 var ext = _ext.selector[ type ];
7566 if ( ext.length ) {
7567 for ( i=0, ien=ext.length ; i<ien ; i++ ) {
7568 out = ext[i]( settings, opts, out );
7569 }
7570 }
7571
7572 return out;
7573 };
7574
7575
7576 var _selector_opts = function ( opts )
7577 {
7578 if ( ! opts ) {
7579 opts = {};
7580 }
7581
7582 // Backwards compatibility for 1.9- which used the terminology filter rather
7583 // than search
7584 if ( opts.filter && opts.search === undefined ) {
7585 opts.search = opts.filter;
7586 }
7587
7588 return $.extend( {
7589 search: 'none',
7590 order: 'current',
7591 page: 'all'
7592 }, opts );
7593 };
7594
7595
7596 var _selector_first = function ( inst )
7597 {
7598 // Reduce the API instance to the first item found
7599 for ( var i=0, ien=inst.length ; i<ien ; i++ ) {
7600 if ( inst[i].length > 0 ) {
7601 // Assign the first element to the first item in the instance
7602 // and truncate the instance and context
7603 inst[0] = inst[i];
7604 inst[0].length = 1;
7605 inst.length = 1;
7606 inst.context = [ inst.context[i] ];
7607
7608 return inst;
7609 }
7610 }
7611
7612 // Not found - return an empty instance
7613 inst.length = 0;
7614 return inst;
7615 };
7616
7617
7618 var _selector_row_indexes = function ( settings, opts )
7619 {
7620 var
7621 i, ien, tmp, a=[],
7622 displayFiltered = settings.aiDisplay,
7623 displayMaster = settings.aiDisplayMaster;
7624
7625 var
7626 search = opts.search, // none, applied, removed
7627 order = opts.order, // applied, current, index (original - compatibility with 1.9)
7628 page = opts.page; // all, current
7629
7630 if ( _fnDataSource( settings ) == 'ssp' ) {
7631 // In server-side processing mode, most options are irrelevant since
7632 // rows not shown don't exist and the index order is the applied order
7633 // Removed is a special case - for consistency just return an empty
7634 // array
7635 return search === 'removed' ?
7636 [] :
7637 _range( 0, displayMaster.length );
7638 }
7639 else if ( page == 'current' ) {
7640 // Current page implies that order=current and fitler=applied, since it is
7641 // fairly senseless otherwise, regardless of what order and search actually
7642 // are
7643 for ( i=settings._iDisplayStart, ien=settings.fnDisplayEnd() ; i<ien ; i++ ) {
7644 a.push( displayFiltered[i] );
7645 }
7646 }
7647 else if ( order == 'current' || order == 'applied' ) {
7648 a = search == 'none' ?
7649 displayMaster.slice() : // no search
7650 search == 'applied' ?
7651 displayFiltered.slice() : // applied search
7652 $.map( displayMaster, function (el, i) { // removed search
7653 return $.inArray( el, displayFiltered ) === -1 ? el : null;
7654 } );
7655 }
7656 else if ( order == 'index' || order == 'original' ) {
7657 for ( i=0, ien=settings.aoData.length ; i<ien ; i++ ) {
7658 if ( search == 'none' ) {
7659 a.push( i );
7660 }
7661 else { // applied | removed
7662 tmp = $.inArray( i, displayFiltered );
7663
7664 if ((tmp === -1 && search == 'removed') ||
7665 (tmp >= 0 && search == 'applied') )
7666 {
7667 a.push( i );
7668 }
7669 }
7670 }
7671 }
7672
7673 return a;
7674 };
7675
7676
7677 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
7678 * Rows
7679 *
7680 * {} - no selector - use all available rows
7681 * {integer} - row aoData index
7682 * {node} - TR node
7683 * {string} - jQuery selector to apply to the TR elements
7684 * {array} - jQuery array of nodes, or simply an array of TR nodes
7685 *
7686 */
7687
7688
7689 var __row_selector = function ( settings, selector, opts )
7690 {
7691 var run = function ( sel ) {
7692 var selInt = _intVal( sel );
7693 var i, ien;
7694
7695 // Short cut - selector is a number and no options provided (default is
7696 // all records, so no need to check if the index is in there, since it
7697 // must be - dev error if the index doesn't exist).
7698 if ( selInt !== null && ! opts ) {
7699 return [ selInt ];
7700 }
7701
7702 var rows = _selector_row_indexes( settings, opts );
7703
7704 if ( selInt !== null && $.inArray( selInt, rows ) !== -1 ) {
7705 // Selector - integer
7706 return [ selInt ];
7707 }
7708 else if ( ! sel ) {
7709 // Selector - none
7710 return rows;
7711 }
7712
7713 // Selector - function
7714 if ( typeof sel === 'function' ) {
7715 return $.map( rows, function (idx) {
7716 var row = settings.aoData[ idx ];
7717 return sel( idx, row._aData, row.nTr ) ? idx : null;
7718 } );
7719 }
7720
7721 // Get nodes in the order from the `rows` array with null values removed
7722 var nodes = _removeEmpty(
7723 _pluck_order( settings.aoData, rows, 'nTr' )
7724 );
7725
7726 // Selector - node
7727 if ( sel.nodeName ) {
7728 if ( $.inArray( sel, nodes ) !== -1 ) {
7729 return [ sel._DT_RowIndex ]; // sel is a TR node that is in the table
7730 // and DataTables adds a prop for fast lookup
7731 }
7732 }
7733
7734 // Selector - jQuery selector string, array of nodes or jQuery object/
7735 // As jQuery's .filter() allows jQuery objects to be passed in filter,
7736 // it also allows arrays, so this will cope with all three options
7737 return $(nodes)
7738 .filter( sel )
7739 .map( function () {
7740 return this._DT_RowIndex;
7741 } )
7742 .toArray();
7743 };
7744
7745 return _selector_run( 'row', selector, run, settings, opts );
7746 };
7747
7748
7749 _api_register( 'rows()', function ( selector, opts ) {
7750 // argument shifting
7751 if ( selector === undefined ) {
7752 selector = '';
7753 }
7754 else if ( $.isPlainObject( selector ) ) {
7755 opts = selector;
7756 selector = '';
7757 }
7758
7759 opts = _selector_opts( opts );
7760
7761 var inst = this.iterator( 'table', function ( settings ) {
7762 return __row_selector( settings, selector, opts );
7763 }, 1 );
7764
7765 // Want argument shifting here and in __row_selector?
7766 inst.selector.rows = selector;
7767 inst.selector.opts = opts;
7768
7769 return inst;
7770 } );
7771
7772 _api_register( 'rows().nodes()', function () {
7773 return this.iterator( 'row', function ( settings, row ) {
7774 return settings.aoData[ row ].nTr || undefined;
7775 }, 1 );
7776 } );
7777
7778 _api_register( 'rows().data()', function () {
7779 return this.iterator( true, 'rows', function ( settings, rows ) {
7780 return _pluck_order( settings.aoData, rows, '_aData' );
7781 }, 1 );
7782 } );
7783
7784 _api_registerPlural( 'rows().cache()', 'row().cache()', function ( type ) {
7785 return this.iterator( 'row', function ( settings, row ) {
7786 var r = settings.aoData[ row ];
7787 return type === 'search' ? r._aFilterData : r._aSortData;
7788 }, 1 );
7789 } );
7790
7791 _api_registerPlural( 'rows().invalidate()', 'row().invalidate()', function ( src ) {
7792 return this.iterator( 'row', function ( settings, row ) {
7793 _fnInvalidate( settings, row, src );
7794 } );
7795 } );
7796
7797 _api_registerPlural( 'rows().indexes()', 'row().index()', function () {
7798 return this.iterator( 'row', function ( settings, row ) {
7799 return row;
7800 }, 1 );
7801 } );
7802
7803 _api_registerPlural( 'rows().remove()', 'row().remove()', function () {
7804 var that = this;
7805
7806 return this.iterator( 'row', function ( settings, row, thatIdx ) {
7807 var data = settings.aoData;
7808
7809 data.splice( row, 1 );
7810
7811 // Update the _DT_RowIndex parameter on all rows in the table
7812 for ( var i=0, ien=data.length ; i<ien ; i++ ) {
7813 if ( data[i].nTr !== null ) {
7814 data[i].nTr._DT_RowIndex = i;
7815 }
7816 }
7817
7818 // Remove the target row from the search array
7819 var displayIndex = $.inArray( row, settings.aiDisplay );
7820
7821 // Delete from the display arrays
7822 _fnDeleteIndex( settings.aiDisplayMaster, row );
7823 _fnDeleteIndex( settings.aiDisplay, row );
7824 _fnDeleteIndex( that[ thatIdx ], row, false ); // maintain local indexes
7825
7826 // Check for an 'overflow' they case for displaying the table
7827 _fnLengthOverflow( settings );
7828 } );
7829 } );
7830
7831
7832 _api_register( 'rows.add()', function ( rows ) {
7833 var newRows = this.iterator( 'table', function ( settings ) {
7834 var row, i, ien;
7835 var out = [];
7836
7837 for ( i=0, ien=rows.length ; i<ien ; i++ ) {
7838 row = rows[i];
7839
7840 if ( row.nodeName && row.nodeName.toUpperCase() === 'TR' ) {
7841 out.push( _fnAddTr( settings, row )[0] );
7842 }
7843 else {
7844 out.push( _fnAddData( settings, row ) );
7845 }
7846 }
7847
7848 return out;
7849 }, 1 );
7850
7851 // Return an Api.rows() extended instance, so rows().nodes() etc can be used
7852 var modRows = this.rows( -1 );
7853 modRows.pop();
7854 modRows.push.apply( modRows, newRows.toArray() );
7855
7856 return modRows;
7857 } );
7858
7859
7860
7861
7862
7863 /**
7864 *
7865 */
7866 _api_register( 'row()', function ( selector, opts ) {
7867 return _selector_first( this.rows( selector, opts ) );
7868 } );
7869
7870
7871 _api_register( 'row().data()', function ( data ) {
7872 var ctx = this.context;
7873
7874 if ( data === undefined ) {
7875 // Get
7876 return ctx.length && this.length ?
7877 ctx[0].aoData[ this[0] ]._aData :
7878 undefined;
7879 }
7880
7881 // Set
7882 ctx[0].aoData[ this[0] ]._aData = data;
7883
7884 // Automatically invalidate
7885 _fnInvalidate( ctx[0], this[0], 'data' );
7886
7887 return this;
7888 } );
7889
7890
7891 _api_register( 'row().node()', function () {
7892 var ctx = this.context;
7893
7894 return ctx.length && this.length ?
7895 ctx[0].aoData[ this[0] ].nTr || null :
7896 null;
7897 } );
7898
7899
7900 _api_register( 'row.add()', function ( row ) {
7901 // Allow a jQuery object to be passed in - only a single row is added from
7902 // it though - the first element in the set
7903 if ( row instanceof $ && row.length ) {
7904 row = row[0];
7905 }
7906
7907 var rows = this.iterator( 'table', function ( settings ) {
7908 if ( row.nodeName && row.nodeName.toUpperCase() === 'TR' ) {
7909 return _fnAddTr( settings, row )[0];
7910 }
7911 return _fnAddData( settings, row );
7912 } );
7913
7914 // Return an Api.rows() extended instance, with the newly added row selected
7915 return this.row( rows[0] );
7916 } );
7917
7918
7919
7920 var __details_add = function ( ctx, row, data, klass )
7921 {
7922 // Convert to array of TR elements
7923 var rows = [];
7924 var addRow = function ( r, k ) {
7925 // Recursion to allow for arrays of jQuery objects
7926 if ( $.isArray( r ) || r instanceof $ ) {
7927 for ( var i=0, ien=r.length ; i<ien ; i++ ) {
7928 addRow( r[i], k );
7929 }
7930 return;
7931 }
7932
7933 // If we get a TR element, then just add it directly - up to the dev
7934 // to add the correct number of columns etc
7935 if ( r.nodeName && r.nodeName.toLowerCase() === 'tr' ) {
7936 rows.push( r );
7937 }
7938 else {
7939 // Otherwise create a row with a wrapper
7940 var created = $('<tr><td/></tr>').addClass( k );
7941 $('td', created)
7942 .addClass( k )
7943 .html( r )
7944 [0].colSpan = _fnVisbleColumns( ctx );
7945
7946 rows.push( created[0] );
7947 }
7948 };
7949
7950 addRow( data, klass );
7951
7952 if ( row._details ) {
7953 row._details.remove();
7954 }
7955
7956 row._details = $(rows);
7957
7958 // If the children were already shown, that state should be retained
7959 if ( row._detailsShow ) {
7960 row._details.insertAfter( row.nTr );
7961 }
7962 };
7963
7964
7965 var __details_remove = function ( api, idx )
7966 {
7967 var ctx = api.context;
7968
7969 if ( ctx.length ) {
7970 var row = ctx[0].aoData[ idx !== undefined ? idx : api[0] ];
7971
7972 if ( row._details ) {
7973 row._details.remove();
7974
7975 row._detailsShow = undefined;
7976 row._details = undefined;
7977 }
7978 }
7979 };
7980
7981
7982 var __details_display = function ( api, show ) {
7983 var ctx = api.context;
7984
7985 if ( ctx.length && api.length ) {
7986 var row = ctx[0].aoData[ api[0] ];
7987
7988 if ( row._details ) {
7989 row._detailsShow = show;
7990
7991 if ( show ) {
7992 row._details.insertAfter( row.nTr );
7993 }
7994 else {
7995 row._details.detach();
7996 }
7997
7998 __details_events( ctx[0] );
7999 }
8000 }
8001 };
8002
8003
8004 var __details_events = function ( settings )
8005 {
8006 var api = new _Api( settings );
8007 var namespace = '.dt.DT_details';
8008 var drawEvent = 'draw'+namespace;
8009 var colvisEvent = 'column-visibility'+namespace;
8010 var destroyEvent = 'destroy'+namespace;
8011 var data = settings.aoData;
8012
8013 api.off( drawEvent +' '+ colvisEvent +' '+ destroyEvent );
8014
8015 if ( _pluck( data, '_details' ).length > 0 ) {
8016 // On each draw, insert the required elements into the document
8017 api.on( drawEvent, function ( e, ctx ) {
8018 if ( settings !== ctx ) {
8019 return;
8020 }
8021
8022 api.rows( {page:'current'} ).eq(0).each( function (idx) {
8023 // Internal data grab
8024 var row = data[ idx ];
8025
8026 if ( row._detailsShow ) {
8027 row._details.insertAfter( row.nTr );
8028 }
8029 } );
8030 } );
8031
8032 // Column visibility change - update the colspan
8033 api.on( colvisEvent, function ( e, ctx, idx, vis ) {
8034 if ( settings !== ctx ) {
8035 return;
8036 }
8037
8038 // Update the colspan for the details rows (note, only if it already has
8039 // a colspan)
8040 var row, visible = _fnVisbleColumns( ctx );
8041
8042 for ( var i=0, ien=data.length ; i<ien ; i++ ) {
8043 row = data[i];
8044
8045 if ( row._details ) {
8046 row._details.children('td[colspan]').attr('colspan', visible );
8047 }
8048 }
8049 } );
8050
8051 // Table destroyed - nuke any child rows
8052 api.on( destroyEvent, function ( e, ctx ) {
8053 if ( settings !== ctx ) {
8054 return;
8055 }
8056
8057 for ( var i=0, ien=data.length ; i<ien ; i++ ) {
8058 if ( data[i]._details ) {
8059 __details_remove( api, i );
8060 }
8061 }
8062 } );
8063 }
8064 };
8065
8066 // Strings for the method names to help minification
8067 var _emp = '';
8068 var _child_obj = _emp+'row().child';
8069 var _child_mth = _child_obj+'()';
8070
8071 // data can be:
8072 // tr
8073 // string
8074 // jQuery or array of any of the above
8075 _api_register( _child_mth, function ( data, klass ) {
8076 var ctx = this.context;
8077
8078 if ( data === undefined ) {
8079 // get
8080 return ctx.length && this.length ?
8081 ctx[0].aoData[ this[0] ]._details :
8082 undefined;
8083 }
8084 else if ( data === true ) {
8085 // show
8086 this.child.show();
8087 }
8088 else if ( data === false ) {
8089 // remove
8090 __details_remove( this );
8091 }
8092 else if ( ctx.length && this.length ) {
8093 // set
8094 __details_add( ctx[0], ctx[0].aoData[ this[0] ], data, klass );
8095 }
8096
8097 return this;
8098 } );
8099
8100
8101 _api_register( [
8102 _child_obj+'.show()',
8103 _child_mth+'.show()' // only when `child()` was called with parameters (without
8104 ], function ( show ) { // it returns an object and this method is not executed)
8105 __details_display( this, true );
8106 return this;
8107 } );
8108
8109
8110 _api_register( [
8111 _child_obj+'.hide()',
8112 _child_mth+'.hide()' // only when `child()` was called with parameters (without
8113 ], function () { // it returns an object and this method is not executed)
8114 __details_display( this, false );
8115 return this;
8116 } );
8117
8118
8119 _api_register( [
8120 _child_obj+'.remove()',
8121 _child_mth+'.remove()' // only when `child()` was called with parameters (without
8122 ], function () { // it returns an object and this method is not executed)
8123 __details_remove( this );
8124 return this;
8125 } );
8126
8127
8128 _api_register( _child_obj+'.isShown()', function () {
8129 var ctx = this.context;
8130
8131 if ( ctx.length && this.length ) {
8132 // _detailsShown as false or undefined will fall through to return false
8133 return ctx[0].aoData[ this[0] ]._detailsShow || false;
8134 }
8135 return false;
8136 } );
8137
8138
8139
8140 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
8141 * Columns
8142 *
8143 * {integer} - column index (>=0 count from left, <0 count from right)
8144 * "{integer}:visIdx" - visible column index (i.e. translate to column index) (>=0 count from left, <0 count from right)
8145 * "{integer}:visible" - alias for {integer}:visIdx (>=0 count from left, <0 count from right)
8146 * "{string}:name" - column name
8147 * "{string}" - jQuery selector on column header nodes
8148 *
8149 */
8150
8151 // can be an array of these items, comma separated list, or an array of comma
8152 // separated lists
8153
8154 var __re_column_selector = /^(.+):(name|visIdx|visible)$/;
8155
8156
8157 // r1 and r2 are redundant - but it means that the parameters match for the
8158 // iterator callback in columns().data()
8159 var __columnData = function ( settings, column, r1, r2, rows ) {
8160 var a = [];
8161 for ( var row=0, ien=rows.length ; row<ien ; row++ ) {
8162 a.push( _fnGetCellData( settings, rows[row], column ) );
8163 }
8164 return a;
8165 };
8166
8167
8168 var __column_selector = function ( settings, selector, opts )
8169 {
8170 var
8171 columns = settings.aoColumns,
8172 names = _pluck( columns, 'sName' ),
8173 nodes = _pluck( columns, 'nTh' );
8174
8175 var run = function ( s ) {
8176 var selInt = _intVal( s );
8177
8178 // Selector - all
8179 if ( s === '' ) {
8180 return _range( columns.length );
8181 }
8182
8183 // Selector - index
8184 if ( selInt !== null ) {
8185 return [ selInt >= 0 ?
8186 selInt : // Count from left
8187 columns.length + selInt // Count from right (+ because its a negative value)
8188 ];
8189 }
8190
8191 // Selector = function
8192 if ( typeof s === 'function' ) {
8193 var rows = _selector_row_indexes( settings, opts );
8194
8195 return $.map( columns, function (col, idx) {
8196 return s(
8197 idx,
8198 __columnData( settings, idx, 0, 0, rows ),
8199 nodes[ idx ]
8200 ) ? idx : null;
8201 } );
8202 }
8203
8204 // jQuery or string selector
8205 var match = typeof s === 'string' ?
8206 s.match( __re_column_selector ) :
8207 '';
8208
8209 if ( match ) {
8210 switch( match[2] ) {
8211 case 'visIdx':
8212 case 'visible':
8213 var idx = parseInt( match[1], 10 );
8214 // Visible index given, convert to column index
8215 if ( idx < 0 ) {
8216 // Counting from the right
8217 var visColumns = $.map( columns, function (col,i) {
8218 return col.bVisible ? i : null;
8219 } );
8220 return [ visColumns[ visColumns.length + idx ] ];
8221 }
8222 // Counting from the left
8223 return [ _fnVisibleToColumnIndex( settings, idx ) ];
8224
8225 case 'name':
8226 // match by name. `names` is column index complete and in order
8227 return $.map( names, function (name, i) {
8228 return name === match[1] ? i : null;
8229 } );
8230 }
8231 }
8232 else {
8233 // jQuery selector on the TH elements for the columns
8234 return $( nodes )
8235 .filter( s )
8236 .map( function () {
8237 return $.inArray( this, nodes ); // `nodes` is column index complete and in order
8238 } )
8239 .toArray();
8240 }
8241 };
8242
8243 return _selector_run( 'column', selector, run, settings, opts );
8244 };
8245
8246
8247 var __setColumnVis = function ( settings, column, vis, recalc ) {
8248 var
8249 cols = settings.aoColumns,
8250 col = cols[ column ],
8251 data = settings.aoData,
8252 row, cells, i, ien, tr;
8253
8254 // Get
8255 if ( vis === undefined ) {
8256 return col.bVisible;
8257 }
8258
8259 // Set
8260 // No change
8261 if ( col.bVisible === vis ) {
8262 return;
8263 }
8264
8265 if ( vis ) {
8266 // Insert column
8267 // Need to decide if we should use appendChild or insertBefore
8268 var insertBefore = $.inArray( true, _pluck(cols, 'bVisible'), column+1 );
8269
8270 for ( i=0, ien=data.length ; i<ien ; i++ ) {
8271 tr = data[i].nTr;
8272 cells = data[i].anCells;
8273
8274 if ( tr ) {
8275 // insertBefore can act like appendChild if 2nd arg is null
8276 tr.insertBefore( cells[ column ], cells[ insertBefore ] || null );
8277 }
8278 }
8279 }
8280 else {
8281 // Remove column
8282 $( _pluck( settings.aoData, 'anCells', column ) ).detach();
8283 }
8284
8285 // Common actions
8286 col.bVisible = vis;
8287 _fnDrawHead( settings, settings.aoHeader );
8288 _fnDrawHead( settings, settings.aoFooter );
8289
8290 if ( recalc === undefined || recalc ) {
8291 // Automatically adjust column sizing
8292 _fnAdjustColumnSizing( settings );
8293
8294 // Realign columns for scrolling
8295 if ( settings.oScroll.sX || settings.oScroll.sY ) {
8296 _fnScrollDraw( settings );
8297 }
8298 }
8299
8300 _fnCallbackFire( settings, null, 'column-visibility', [settings, column, vis] );
8301
8302 _fnSaveState( settings );
8303 };
8304
8305
8306 _api_register( 'columns()', function ( selector, opts ) {
8307 // argument shifting
8308 if ( selector === undefined ) {
8309 selector = '';
8310 }
8311 else if ( $.isPlainObject( selector ) ) {
8312 opts = selector;
8313 selector = '';
8314 }
8315
8316 opts = _selector_opts( opts );
8317
8318 var inst = this.iterator( 'table', function ( settings ) {
8319 return __column_selector( settings, selector, opts );
8320 }, 1 );
8321
8322 // Want argument shifting here and in _row_selector?
8323 inst.selector.cols = selector;
8324 inst.selector.opts = opts;
8325
8326 return inst;
8327 } );
8328
8329 _api_registerPlural( 'columns().header()', 'column().header()', function ( selector, opts ) {
8330 return this.iterator( 'column', function ( settings, column ) {
8331 return settings.aoColumns[column].nTh;
8332 }, 1 );
8333 } );
8334
8335 _api_registerPlural( 'columns().footer()', 'column().footer()', function ( selector, opts ) {
8336 return this.iterator( 'column', function ( settings, column ) {
8337 return settings.aoColumns[column].nTf;
8338 }, 1 );
8339 } );
8340
8341 _api_registerPlural( 'columns().data()', 'column().data()', function () {
8342 return this.iterator( 'column-rows', __columnData, 1 );
8343 } );
8344
8345 _api_registerPlural( 'columns().dataSrc()', 'column().dataSrc()', function () {
8346 return this.iterator( 'column', function ( settings, column ) {
8347 return settings.aoColumns[column].mData;
8348 }, 1 );
8349 } );
8350
8351 _api_registerPlural( 'columns().cache()', 'column().cache()', function ( type ) {
8352 return this.iterator( 'column-rows', function ( settings, column, i, j, rows ) {
8353 return _pluck_order( settings.aoData, rows,
8354 type === 'search' ? '_aFilterData' : '_aSortData', column
8355 );
8356 }, 1 );
8357 } );
8358
8359 _api_registerPlural( 'columns().nodes()', 'column().nodes()', function () {
8360 return this.iterator( 'column-rows', function ( settings, column, i, j, rows ) {
8361 return _pluck_order( settings.aoData, rows, 'anCells', column ) ;
8362 }, 1 );
8363 } );
8364
8365 _api_registerPlural( 'columns().visible()', 'column().visible()', function ( vis, calc ) {
8366 return this.iterator( 'column', function ( settings, column ) {
8367 if ( vis === undefined ) {
8368 return settings.aoColumns[ column ].bVisible;
8369 } // else
8370 __setColumnVis( settings, column, vis, calc );
8371 } );
8372 } );
8373
8374 _api_registerPlural( 'columns().indexes()', 'column().index()', function ( type ) {
8375 return this.iterator( 'column', function ( settings, column ) {
8376 return type === 'visible' ?
8377 _fnColumnIndexToVisible( settings, column ) :
8378 column;
8379 }, 1 );
8380 } );
8381
8382 _api_register( 'columns.adjust()', function () {
8383 return this.iterator( 'table', function ( settings ) {
8384 _fnAdjustColumnSizing( settings );
8385 }, 1 );
8386 } );
8387
8388 _api_register( 'column.index()', function ( type, idx ) {
8389 if ( this.context.length !== 0 ) {
8390 var ctx = this.context[0];
8391
8392 if ( type === 'fromVisible' || type === 'toData' ) {
8393 return _fnVisibleToColumnIndex( ctx, idx );
8394 }
8395 else if ( type === 'fromData' || type === 'toVisible' ) {
8396 return _fnColumnIndexToVisible( ctx, idx );
8397 }
8398 }
8399 } );
8400
8401 _api_register( 'column()', function ( selector, opts ) {
8402 return _selector_first( this.columns( selector, opts ) );
8403 } );
8404
8405
8406
8407
8408 var __cell_selector = function ( settings, selector, opts )
8409 {
8410 var data = settings.aoData;
8411 var rows = _selector_row_indexes( settings, opts );
8412 var cells = _removeEmpty( _pluck_order( data, rows, 'anCells' ) );
8413 var allCells = $( [].concat.apply([], cells) );
8414 var row;
8415 var columns = settings.aoColumns.length;
8416 var a, i, ien, j, o, host;
8417
8418 var run = function ( s ) {
8419 var fnSelector = typeof s === 'function';
8420
8421 if ( s === null || s === undefined || fnSelector ) {
8422 // All cells and function selectors
8423 a = [];
8424
8425 for ( i=0, ien=rows.length ; i<ien ; i++ ) {
8426 row = rows[i];
8427
8428 for ( j=0 ; j<columns ; j++ ) {
8429 o = {
8430 row: row,
8431 column: j
8432 };
8433
8434 if ( fnSelector ) {
8435 // Selector - function
8436 host = settings.aoData[ row ];
8437
8438 if ( s( o, _fnGetCellData(settings, row, j), host.anCells ? host.anCells[j] : null ) ) {
8439 a.push( o );
8440 }
8441 }
8442 else {
8443 // Selector - all
8444 a.push( o );
8445 }
8446 }
8447 }
8448
8449 return a;
8450 }
8451
8452 // Selector - index
8453 if ( $.isPlainObject( s ) ) {
8454 return [s];
8455 }
8456
8457 // Selector - jQuery filtered cells
8458 return allCells
8459 .filter( s )
8460 .map( function (i, el) {
8461 row = el.parentNode._DT_RowIndex;
8462
8463 return {
8464 row: row,
8465 column: $.inArray( el, data[ row ].anCells )
8466 };
8467 } )
8468 .toArray();
8469 };
8470
8471 return _selector_run( 'cell', selector, run, settings, opts );
8472 };
8473
8474
8475
8476
8477 _api_register( 'cells()', function ( rowSelector, columnSelector, opts ) {
8478 // Argument shifting
8479 if ( $.isPlainObject( rowSelector ) ) {
8480 // Indexes
8481 if ( rowSelector.row === undefined ) {
8482 // Selector options in first parameter
8483 opts = rowSelector;
8484 rowSelector = null;
8485 }
8486 else {
8487 // Cell index objects in first parameter
8488 opts = columnSelector;
8489 columnSelector = null;
8490 }
8491 }
8492 if ( $.isPlainObject( columnSelector ) ) {
8493 opts = columnSelector;
8494 columnSelector = null;
8495 }
8496
8497 // Cell selector
8498 if ( columnSelector === null || columnSelector === undefined ) {
8499 return this.iterator( 'table', function ( settings ) {
8500 return __cell_selector( settings, rowSelector, _selector_opts( opts ) );
8501 } );
8502 }
8503
8504 // Row + column selector
8505 var columns = this.columns( columnSelector, opts );
8506 var rows = this.rows( rowSelector, opts );
8507 var a, i, ien, j, jen;
8508
8509 var cells = this.iterator( 'table', function ( settings, idx ) {
8510 a = [];
8511
8512 for ( i=0, ien=rows[idx].length ; i<ien ; i++ ) {
8513 for ( j=0, jen=columns[idx].length ; j<jen ; j++ ) {
8514 a.push( {
8515 row: rows[idx][i],
8516 column: columns[idx][j]
8517 } );
8518 }
8519 }
8520
8521 return a;
8522 }, 1 );
8523
8524 $.extend( cells.selector, {
8525 cols: columnSelector,
8526 rows: rowSelector,
8527 opts: opts
8528 } );
8529
8530 return cells;
8531 } );
8532
8533
8534 _api_registerPlural( 'cells().nodes()', 'cell().node()', function () {
8535 return this.iterator( 'cell', function ( settings, row, column ) {
8536 var cells = settings.aoData[ row ].anCells;
8537 return cells ?
8538 cells[ column ] :
8539 undefined;
8540 }, 1 );
8541 } );
8542
8543
8544 _api_register( 'cells().data()', function () {
8545 return this.iterator( 'cell', function ( settings, row, column ) {
8546 return _fnGetCellData( settings, row, column );
8547 }, 1 );
8548 } );
8549
8550
8551 _api_registerPlural( 'cells().cache()', 'cell().cache()', function ( type ) {
8552 type = type === 'search' ? '_aFilterData' : '_aSortData';
8553
8554 return this.iterator( 'cell', function ( settings, row, column ) {
8555 return settings.aoData[ row ][ type ][ column ];
8556 }, 1 );
8557 } );
8558
8559
8560 _api_registerPlural( 'cells().render()', 'cell().render()', function ( type ) {
8561 return this.iterator( 'cell', function ( settings, row, column ) {
8562 return _fnGetCellData( settings, row, column, type );
8563 }, 1 );
8564 } );
8565
8566
8567 _api_registerPlural( 'cells().indexes()', 'cell().index()', function () {
8568 return this.iterator( 'cell', function ( settings, row, column ) {
8569 return {
8570 row: row,
8571 column: column,
8572 columnVisible: _fnColumnIndexToVisible( settings, column )
8573 };
8574 }, 1 );
8575 } );
8576
8577
8578 _api_registerPlural( 'cells().invalidate()', 'cell().invalidate()', function ( src ) {
8579 return this.iterator( 'cell', function ( settings, row, column ) {
8580 _fnInvalidate( settings, row, src, column );
8581 } );
8582 } );
8583
8584
8585
8586 _api_register( 'cell()', function ( rowSelector, columnSelector, opts ) {
8587 return _selector_first( this.cells( rowSelector, columnSelector, opts ) );
8588 } );
8589
8590
8591 _api_register( 'cell().data()', function ( data ) {
8592 var ctx = this.context;
8593 var cell = this[0];
8594
8595 if ( data === undefined ) {
8596 // Get
8597 return ctx.length && cell.length ?
8598 _fnGetCellData( ctx[0], cell[0].row, cell[0].column ) :
8599 undefined;
8600 }
8601
8602 // Set
8603 _fnSetCellData( ctx[0], cell[0].row, cell[0].column, data );
8604 _fnInvalidate( ctx[0], cell[0].row, 'data', cell[0].column );
8605
8606 return this;
8607 } );
8608
8609
8610
8611 /**
8612 * Get current ordering (sorting) that has been applied to the table.
8613 *
8614 * @returns {array} 2D array containing the sorting information for the first
8615 * table in the current context. Each element in the parent array represents
8616 * a column being sorted upon (i.e. multi-sorting with two columns would have
8617 * 2 inner arrays). The inner arrays may have 2 or 3 elements. The first is
8618 * the column index that the sorting condition applies to, the second is the
8619 * direction of the sort (`desc` or `asc`) and, optionally, the third is the
8620 * index of the sorting order from the `column.sorting` initialisation array.
8621 *//**
8622 * Set the ordering for the table.
8623 *
8624 * @param {integer} order Column index to sort upon.
8625 * @param {string} direction Direction of the sort to be applied (`asc` or `desc`)
8626 * @returns {DataTables.Api} this
8627 *//**
8628 * Set the ordering for the table.
8629 *
8630 * @param {array} order 1D array of sorting information to be applied.
8631 * @param {array} [...] Optional additional sorting conditions
8632 * @returns {DataTables.Api} this
8633 *//**
8634 * Set the ordering for the table.
8635 *
8636 * @param {array} order 2D array of sorting information to be applied.
8637 * @returns {DataTables.Api} this
8638 */
8639 _api_register( 'order()', function ( order, dir ) {
8640 var ctx = this.context;
8641
8642 if ( order === undefined ) {
8643 // get
8644 return ctx.length !== 0 ?
8645 ctx[0].aaSorting :
8646 undefined;
8647 }
8648
8649 // set
8650 if ( typeof order === 'number' ) {
8651 // Simple column / direction passed in
8652 order = [ [ order, dir ] ];
8653 }
8654 else if ( ! $.isArray( order[0] ) ) {
8655 // Arguments passed in (list of 1D arrays)
8656 order = Array.prototype.slice.call( arguments );
8657 }
8658 // otherwise a 2D array was passed in
8659
8660 return this.iterator( 'table', function ( settings ) {
8661 settings.aaSorting = order.slice();
8662 } );
8663 } );
8664
8665
8666 /**
8667 * Attach a sort listener to an element for a given column
8668 *
8669 * @param {node|jQuery|string} node Identifier for the element(s) to attach the
8670 * listener to. This can take the form of a single DOM node, a jQuery
8671 * collection of nodes or a jQuery selector which will identify the node(s).
8672 * @param {integer} column the column that a click on this node will sort on
8673 * @param {function} [callback] callback function when sort is run
8674 * @returns {DataTables.Api} this
8675 */
8676 _api_register( 'order.listener()', function ( node, column, callback ) {
8677 return this.iterator( 'table', function ( settings ) {
8678 _fnSortAttachListener( settings, node, column, callback );
8679 } );
8680 } );
8681
8682
8683 // Order by the selected column(s)
8684 _api_register( [
8685 'columns().order()',
8686 'column().order()'
8687 ], function ( dir ) {
8688 var that = this;
8689
8690 return this.iterator( 'table', function ( settings, i ) {
8691 var sort = [];
8692
8693 $.each( that[i], function (j, col) {
8694 sort.push( [ col, dir ] );
8695 } );
8696
8697 settings.aaSorting = sort;
8698 } );
8699 } );
8700
8701
8702
8703 _api_register( 'search()', function ( input, regex, smart, caseInsen ) {
8704 var ctx = this.context;
8705
8706 if ( input === undefined ) {
8707 // get
8708 return ctx.length !== 0 ?
8709 ctx[0].oPreviousSearch.sSearch :
8710 undefined;
8711 }
8712
8713 // set
8714 return this.iterator( 'table', function ( settings ) {
8715 if ( ! settings.oFeatures.bFilter ) {
8716 return;
8717 }
8718
8719 _fnFilterComplete( settings, $.extend( {}, settings.oPreviousSearch, {
8720 "sSearch": input+"",
8721 "bRegex": regex === null ? false : regex,
8722 "bSmart": smart === null ? true : smart,
8723 "bCaseInsensitive": caseInsen === null ? true : caseInsen
8724 } ), 1 );
8725 } );
8726 } );
8727
8728
8729 _api_registerPlural(
8730 'columns().search()',
8731 'column().search()',
8732 function ( input, regex, smart, caseInsen ) {
8733 return this.iterator( 'column', function ( settings, column ) {
8734 var preSearch = settings.aoPreSearchCols;
8735
8736 if ( input === undefined ) {
8737 // get
8738 return preSearch[ column ].sSearch;
8739 }
8740
8741 // set
8742 if ( ! settings.oFeatures.bFilter ) {
8743 return;
8744 }
8745
8746 $.extend( preSearch[ column ], {
8747 "sSearch": input+"",
8748 "bRegex": regex === null ? false : regex,
8749 "bSmart": smart === null ? true : smart,
8750 "bCaseInsensitive": caseInsen === null ? true : caseInsen
8751 } );
8752
8753 _fnFilterComplete( settings, settings.oPreviousSearch, 1 );
8754 } );
8755 }
8756 );
8757
8758 /*
8759 * State API methods
8760 */
8761
8762 _api_register( 'state()', function () {
8763 return this.context.length ?
8764 this.context[0].oSavedState :
8765 null;
8766 } );
8767
8768
8769 _api_register( 'state.clear()', function () {
8770 return this.iterator( 'table', function ( settings ) {
8771 // Save an empty object
8772 settings.fnStateSaveCallback.call( settings.oInstance, settings, {} );
8773 } );
8774 } );
8775
8776
8777 _api_register( 'state.loaded()', function () {
8778 return this.context.length ?
8779 this.context[0].oLoadedState :
8780 null;
8781 } );
8782
8783
8784 _api_register( 'state.save()', function () {
8785 return this.iterator( 'table', function ( settings ) {
8786 _fnSaveState( settings );
8787 } );
8788 } );
8789
8790
8791
8792 /**
8793 * Provide a common method for plug-ins to check the version of DataTables being
8794 * used, in order to ensure compatibility.
8795 *
8796 * @param {string} version Version string to check for, in the format "X.Y.Z".
8797 * Note that the formats "X" and "X.Y" are also acceptable.
8798 * @returns {boolean} true if this version of DataTables is greater or equal to
8799 * the required version, or false if this version of DataTales is not
8800 * suitable
8801 * @static
8802 * @dtopt API-Static
8803 *
8804 * @example
8805 * alert( $.fn.dataTable.versionCheck( '1.9.0' ) );
8806 */
8807 DataTable.versionCheck = DataTable.fnVersionCheck = function( version )
8808 {
8809 var aThis = DataTable.version.split('.');
8810 var aThat = version.split('.');
8811 var iThis, iThat;
8812
8813 for ( var i=0, iLen=aThat.length ; i<iLen ; i++ ) {
8814 iThis = parseInt( aThis[i], 10 ) || 0;
8815 iThat = parseInt( aThat[i], 10 ) || 0;
8816
8817 // Parts are the same, keep comparing
8818 if (iThis === iThat) {
8819 continue;
8820 }
8821
8822 // Parts are different, return immediately
8823 return iThis > iThat;
8824 }
8825
8826 return true;
8827 };
8828
8829
8830 /**
8831 * Check if a `<table>` node is a DataTable table already or not.
8832 *
8833 * @param {node|jquery|string} table Table node, jQuery object or jQuery
8834 * selector for the table to test. Note that if more than more than one
8835 * table is passed on, only the first will be checked
8836 * @returns {boolean} true the table given is a DataTable, or false otherwise
8837 * @static
8838 * @dtopt API-Static
8839 *
8840 * @example
8841 * if ( ! $.fn.DataTable.isDataTable( '#example' ) ) {
8842 * $('#example').dataTable();
8843 * }
8844 */
8845 DataTable.isDataTable = DataTable.fnIsDataTable = function ( table )
8846 {
8847 var t = $(table).get(0);
8848 var is = false;
8849
8850 $.each( DataTable.settings, function (i, o) {
8851 var head = o.nScrollHead ? $('table', o.nScrollHead)[0] : null;
8852 var foot = o.nScrollFoot ? $('table', o.nScrollFoot)[0] : null;
8853
8854 if ( o.nTable === t || head === t || foot === t ) {
8855 is = true;
8856 }
8857 } );
8858
8859 return is;
8860 };
8861
8862
8863 /**
8864 * Get all DataTable tables that have been initialised - optionally you can
8865 * select to get only currently visible tables.
8866 *
8867 * @param {boolean} [visible=false] Flag to indicate if you want all (default)
8868 * or visible tables only.
8869 * @returns {array} Array of `table` nodes (not DataTable instances) which are
8870 * DataTables
8871 * @static
8872 * @dtopt API-Static
8873 *
8874 * @example
8875 * $.each( $.fn.dataTable.tables(true), function () {
8876 * $(table).DataTable().columns.adjust();
8877 * } );
8878 */
8879 DataTable.tables = DataTable.fnTables = function ( visible )
8880 {
8881 return $.map( DataTable.settings, function (o) {
8882 if ( !visible || (visible && $(o.nTable).is(':visible')) ) {
8883 return o.nTable;
8884 }
8885 } );
8886 };
8887
8888
8889 /**
8890 * DataTables utility methods
8891 *
8892 * This namespace provides helper methods that DataTables uses internally to
8893 * create a DataTable, but which are not exclusively used only for DataTables.
8894 * These methods can be used by extension authors to save the duplication of
8895 * code.
8896 *
8897 * @namespace
8898 */
8899 DataTable.util = {
8900 /**
8901 * Throttle the calls to a function. Arguments and context are maintained
8902 * for the throttled function.
8903 *
8904 * @param {function} fn Function to be called
8905 * @param {integer} freq Call frequency in mS
8906 * @return {function} Wrapped function
8907 */
8908 throttle: _fnThrottle,
8909
8910
8911 /**
8912 * Escape a string such that it can be used in a regular expression
8913 *
8914 * @param {string} sVal string to escape
8915 * @returns {string} escaped string
8916 */
8917 escapeRegex: _fnEscapeRegex
8918 };
8919
8920
8921 /**
8922 * Convert from camel case parameters to Hungarian notation. This is made public
8923 * for the extensions to provide the same ability as DataTables core to accept
8924 * either the 1.9 style Hungarian notation, or the 1.10+ style camelCase
8925 * parameters.
8926 *
8927 * @param {object} src The model object which holds all parameters that can be
8928 * mapped.
8929 * @param {object} user The object to convert from camel case to Hungarian.
8930 * @param {boolean} force When set to `true`, properties which already have a
8931 * Hungarian value in the `user` object will be overwritten. Otherwise they
8932 * won't be.
8933 */
8934 DataTable.camelToHungarian = _fnCamelToHungarian;
8935
8936
8937
8938 /**
8939 *
8940 */
8941 _api_register( '$()', function ( selector, opts ) {
8942 var
8943 rows = this.rows( opts ).nodes(), // Get all rows
8944 jqRows = $(rows);
8945
8946 return $( [].concat(
8947 jqRows.filter( selector ).toArray(),
8948 jqRows.find( selector ).toArray()
8949 ) );
8950 } );
8951
8952
8953 // jQuery functions to operate on the tables
8954 $.each( [ 'on', 'one', 'off' ], function (i, key) {
8955 _api_register( key+'()', function ( /* event, handler */ ) {
8956 var args = Array.prototype.slice.call(arguments);
8957
8958 // Add the `dt` namespace automatically if it isn't already present
8959 if ( ! args[0].match(/\.dt\b/) ) {
8960 args[0] += '.dt';
8961 }
8962
8963 var inst = $( this.tables().nodes() );
8964 inst[key].apply( inst, args );
8965 return this;
8966 } );
8967 } );
8968
8969
8970 _api_register( 'clear()', function () {
8971 return this.iterator( 'table', function ( settings ) {
8972 _fnClearTable( settings );
8973 } );
8974 } );
8975
8976
8977 _api_register( 'settings()', function () {
8978 return new _Api( this.context, this.context );
8979 } );
8980
8981
8982 _api_register( 'init()', function () {
8983 var ctx = this.context;
8984 return ctx.length ? ctx[0].oInit : null;
8985 } );
8986
8987
8988 _api_register( 'data()', function () {
8989 return this.iterator( 'table', function ( settings ) {
8990 return _pluck( settings.aoData, '_aData' );
8991 } ).flatten();
8992 } );
8993
8994
8995 _api_register( 'destroy()', function ( remove ) {
8996 remove = remove || false;
8997
8998 return this.iterator( 'table', function ( settings ) {
8999 var orig = settings.nTableWrapper.parentNode;
9000 var classes = settings.oClasses;
9001 var table = settings.nTable;
9002 var tbody = settings.nTBody;
9003 var thead = settings.nTHead;
9004 var tfoot = settings.nTFoot;
9005 var jqTable = $(table);
9006 var jqTbody = $(tbody);
9007 var jqWrapper = $(settings.nTableWrapper);
9008 var rows = $.map( settings.aoData, function (r) { return r.nTr; } );
9009 var i, ien;
9010
9011 // Flag to note that the table is currently being destroyed - no action
9012 // should be taken
9013 settings.bDestroying = true;
9014
9015 // Fire off the destroy callbacks for plug-ins etc
9016 _fnCallbackFire( settings, "aoDestroyCallback", "destroy", [settings] );
9017
9018 // If not being removed from the document, make all columns visible
9019 if ( ! remove ) {
9020 new _Api( settings ).columns().visible( true );
9021 }
9022
9023 // Blitz all `DT` namespaced events (these are internal events, the
9024 // lowercase, `dt` events are user subscribed and they are responsible
9025 // for removing them
9026 jqWrapper.unbind('.DT').find(':not(tbody *)').unbind('.DT');
9027 $(window).unbind('.DT-'+settings.sInstance);
9028
9029 // When scrolling we had to break the table up - restore it
9030 if ( table != thead.parentNode ) {
9031 jqTable.children('thead').detach();
9032 jqTable.append( thead );
9033 }
9034
9035 if ( tfoot && table != tfoot.parentNode ) {
9036 jqTable.children('tfoot').detach();
9037 jqTable.append( tfoot );
9038 }
9039
9040 // Remove the DataTables generated nodes, events and classes
9041 jqTable.detach();
9042 jqWrapper.detach();
9043
9044 settings.aaSorting = [];
9045 settings.aaSortingFixed = [];
9046 _fnSortingClasses( settings );
9047
9048 $( rows ).removeClass( settings.asStripeClasses.join(' ') );
9049
9050 $('th, td', thead).removeClass( classes.sSortable+' '+
9051 classes.sSortableAsc+' '+classes.sSortableDesc+' '+classes.sSortableNone
9052 );
9053
9054 if ( settings.bJUI ) {
9055 $('th span.'+classes.sSortIcon+ ', td span.'+classes.sSortIcon, thead).detach();
9056 $('th, td', thead).each( function () {
9057 var wrapper = $('div.'+classes.sSortJUIWrapper, this);
9058 $(this).append( wrapper.contents() );
9059 wrapper.detach();
9060 } );
9061 }
9062
9063 if ( ! remove && orig ) {
9064 // insertBefore acts like appendChild if !arg[1]
9065 orig.insertBefore( table, settings.nTableReinsertBefore );
9066 }
9067
9068 // Add the TR elements back into the table in their original order
9069 jqTbody.children().detach();
9070 jqTbody.append( rows );
9071
9072 // Restore the width of the original table - was read from the style property,
9073 // so we can restore directly to that
9074 jqTable
9075 .css( 'width', settings.sDestroyWidth )
9076 .removeClass( classes.sTable );
9077
9078 // If the were originally stripe classes - then we add them back here.
9079 // Note this is not fool proof (for example if not all rows had stripe
9080 // classes - but it's a good effort without getting carried away
9081 ien = settings.asDestroyStripes.length;
9082
9083 if ( ien ) {
9084 jqTbody.children().each( function (i) {
9085 $(this).addClass( settings.asDestroyStripes[i % ien] );
9086 } );
9087 }
9088
9089 /* Remove the settings object from the settings array */
9090 var idx = $.inArray( settings, DataTable.settings );
9091 if ( idx !== -1 ) {
9092 DataTable.settings.splice( idx, 1 );
9093 }
9094 } );
9095 } );
9096
9097
9098 // Add the `every()` method for rows, columns and cells in a compact form
9099 $.each( [ 'column', 'row', 'cell' ], function ( i, type ) {
9100 _api_register( type+'s().every()', function ( fn ) {
9101 return this.iterator( type, function ( settings, idx, idx2 ) {
9102 // idx2 is undefined for rows and columns.
9103 fn.call( new _Api( settings )[ type ]( idx, idx2 ) );
9104 } );
9105 } );
9106 } );
9107
9108
9109 // i18n method for extensions to be able to use the language object from the
9110 // DataTable
9111 _api_register( 'i18n()', function ( token, def, plural ) {
9112 var ctx = this.context[0];
9113 var resolved = _fnGetObjectDataFn( token )( ctx.oLanguage );
9114
9115 if ( resolved === undefined ) {
9116 resolved = def;
9117 }
9118
9119 if ( plural !== undefined && $.isPlainObject( resolved ) ) {
9120 resolved = resolved[ plural ] !== undefined ?
9121 resolved[ plural ] :
9122 resolved._;
9123 }
9124
9125 return resolved.replace( '%d', plural ); // nb: plural might be undefined,
9126 } );
9127
9128 /**
9129 * Version string for plug-ins to check compatibility. Allowed format is
9130 * `a.b.c-d` where: a:int, b:int, c:int, d:string(dev|beta|alpha). `d` is used
9131 * only for non-release builds. See http://semver.org/ for more information.
9132 * @member
9133 * @type string
9134 * @default Version number
9135 */
9136 DataTable.version = "1.10.7";
9137
9138 /**
9139 * Private data store, containing all of the settings objects that are
9140 * created for the tables on a given page.
9141 *
9142 * Note that the `DataTable.settings` object is aliased to
9143 * `jQuery.fn.dataTableExt` through which it may be accessed and
9144 * manipulated, or `jQuery.fn.dataTable.settings`.
9145 * @member
9146 * @type array
9147 * @default []
9148 * @private
9149 */
9150 DataTable.settings = [];
9151
9152 /**
9153 * Object models container, for the various models that DataTables has
9154 * available to it. These models define the objects that are used to hold
9155 * the active state and configuration of the table.
9156 * @namespace
9157 */
9158 DataTable.models = {};
9159
9160
9161
9162 /**
9163 * Template object for the way in which DataTables holds information about
9164 * search information for the global filter and individual column filters.
9165 * @namespace
9166 */
9167 DataTable.models.oSearch = {
9168 /**
9169 * Flag to indicate if the filtering should be case insensitive or not
9170 * @type boolean
9171 * @default true
9172 */
9173 "bCaseInsensitive": true,
9174
9175 /**
9176 * Applied search term
9177 * @type string
9178 * @default <i>Empty string</i>
9179 */
9180 "sSearch": "",
9181
9182 /**
9183 * Flag to indicate if the search term should be interpreted as a
9184 * regular expression (true) or not (false) and therefore and special
9185 * regex characters escaped.
9186 * @type boolean
9187 * @default false
9188 */
9189 "bRegex": false,
9190
9191 /**
9192 * Flag to indicate if DataTables is to use its smart filtering or not.
9193 * @type boolean
9194 * @default true
9195 */
9196 "bSmart": true
9197 };
9198
9199
9200
9201
9202 /**
9203 * Template object for the way in which DataTables holds information about
9204 * each individual row. This is the object format used for the settings
9205 * aoData array.
9206 * @namespace
9207 */
9208 DataTable.models.oRow = {
9209 /**
9210 * TR element for the row
9211 * @type node
9212 * @default null
9213 */
9214 "nTr": null,
9215
9216 /**
9217 * Array of TD elements for each row. This is null until the row has been
9218 * created.
9219 * @type array nodes
9220 * @default []
9221 */
9222 "anCells": null,
9223
9224 /**
9225 * Data object from the original data source for the row. This is either
9226 * an array if using the traditional form of DataTables, or an object if
9227 * using mData options. The exact type will depend on the passed in
9228 * data from the data source, or will be an array if using DOM a data
9229 * source.
9230 * @type array|object
9231 * @default []
9232 */
9233 "_aData": [],
9234
9235 /**
9236 * Sorting data cache - this array is ostensibly the same length as the
9237 * number of columns (although each index is generated only as it is
9238 * needed), and holds the data that is used for sorting each column in the
9239 * row. We do this cache generation at the start of the sort in order that
9240 * the formatting of the sort data need be done only once for each cell
9241 * per sort. This array should not be read from or written to by anything
9242 * other than the master sorting methods.
9243 * @type array
9244 * @default null
9245 * @private
9246 */
9247 "_aSortData": null,
9248
9249 /**
9250 * Per cell filtering data cache. As per the sort data cache, used to
9251 * increase the performance of the filtering in DataTables
9252 * @type array
9253 * @default null
9254 * @private
9255 */
9256 "_aFilterData": null,
9257
9258 /**
9259 * Filtering data cache. This is the same as the cell filtering cache, but
9260 * in this case a string rather than an array. This is easily computed with
9261 * a join on `_aFilterData`, but is provided as a cache so the join isn't
9262 * needed on every search (memory traded for performance)
9263 * @type array
9264 * @default null
9265 * @private
9266 */
9267 "_sFilterRow": null,
9268
9269 /**
9270 * Cache of the class name that DataTables has applied to the row, so we
9271 * can quickly look at this variable rather than needing to do a DOM check
9272 * on className for the nTr property.
9273 * @type string
9274 * @default <i>Empty string</i>
9275 * @private
9276 */
9277 "_sRowStripe": "",
9278
9279 /**
9280 * Denote if the original data source was from the DOM, or the data source
9281 * object. This is used for invalidating data, so DataTables can
9282 * automatically read data from the original source, unless uninstructed
9283 * otherwise.
9284 * @type string
9285 * @default null
9286 * @private
9287 */
9288 "src": null
9289 };
9290
9291
9292 /**
9293 * Template object for the column information object in DataTables. This object
9294 * is held in the settings aoColumns array and contains all the information that
9295 * DataTables needs about each individual column.
9296 *
9297 * Note that this object is related to {@link DataTable.defaults.column}
9298 * but this one is the internal data store for DataTables's cache of columns.
9299 * It should NOT be manipulated outside of DataTables. Any configuration should
9300 * be done through the initialisation options.
9301 * @namespace
9302 */
9303 DataTable.models.oColumn = {
9304 /**
9305 * Column index. This could be worked out on-the-fly with $.inArray, but it
9306 * is faster to just hold it as a variable
9307 * @type integer
9308 * @default null
9309 */
9310 "idx": null,
9311
9312 /**
9313 * A list of the columns that sorting should occur on when this column
9314 * is sorted. That this property is an array allows multi-column sorting
9315 * to be defined for a column (for example first name / last name columns
9316 * would benefit from this). The values are integers pointing to the
9317 * columns to be sorted on (typically it will be a single integer pointing
9318 * at itself, but that doesn't need to be the case).
9319 * @type array
9320 */
9321 "aDataSort": null,
9322
9323 /**
9324 * Define the sorting directions that are applied to the column, in sequence
9325 * as the column is repeatedly sorted upon - i.e. the first value is used
9326 * as the sorting direction when the column if first sorted (clicked on).
9327 * Sort it again (click again) and it will move on to the next index.
9328 * Repeat until loop.
9329 * @type array
9330 */
9331 "asSorting": null,
9332
9333 /**
9334 * Flag to indicate if the column is searchable, and thus should be included
9335 * in the filtering or not.
9336 * @type boolean
9337 */
9338 "bSearchable": null,
9339
9340 /**
9341 * Flag to indicate if the column is sortable or not.
9342 * @type boolean
9343 */
9344 "bSortable": null,
9345
9346 /**
9347 * Flag to indicate if the column is currently visible in the table or not
9348 * @type boolean
9349 */
9350 "bVisible": null,
9351
9352 /**
9353 * Store for manual type assignment using the `column.type` option. This
9354 * is held in store so we can manipulate the column's `sType` property.
9355 * @type string
9356 * @default null
9357 * @private
9358 */
9359 "_sManualType": null,
9360
9361 /**
9362 * Flag to indicate if HTML5 data attributes should be used as the data
9363 * source for filtering or sorting. True is either are.
9364 * @type boolean
9365 * @default false
9366 * @private
9367 */
9368 "_bAttrSrc": false,
9369
9370 /**
9371 * Developer definable function that is called whenever a cell is created (Ajax source,
9372 * etc) or processed for input (DOM source). This can be used as a compliment to mRender
9373 * allowing you to modify the DOM element (add background colour for example) when the
9374 * element is available.
9375 * @type function
9376 * @param {element} nTd The TD node that has been created
9377 * @param {*} sData The Data for the cell
9378 * @param {array|object} oData The data for the whole row
9379 * @param {int} iRow The row index for the aoData data store
9380 * @default null
9381 */
9382 "fnCreatedCell": null,
9383
9384 /**
9385 * Function to get data from a cell in a column. You should <b>never</b>
9386 * access data directly through _aData internally in DataTables - always use
9387 * the method attached to this property. It allows mData to function as
9388 * required. This function is automatically assigned by the column
9389 * initialisation method
9390 * @type function
9391 * @param {array|object} oData The data array/object for the array
9392 * (i.e. aoData[]._aData)
9393 * @param {string} sSpecific The specific data type you want to get -
9394 * 'display', 'type' 'filter' 'sort'
9395 * @returns {*} The data for the cell from the given row's data
9396 * @default null
9397 */
9398 "fnGetData": null,
9399
9400 /**
9401 * Function to set data for a cell in the column. You should <b>never</b>
9402 * set the data directly to _aData internally in DataTables - always use
9403 * this method. It allows mData to function as required. This function
9404 * is automatically assigned by the column initialisation method
9405 * @type function
9406 * @param {array|object} oData The data array/object for the array
9407 * (i.e. aoData[]._aData)
9408 * @param {*} sValue Value to set
9409 * @default null
9410 */
9411 "fnSetData": null,
9412
9413 /**
9414 * Property to read the value for the cells in the column from the data
9415 * source array / object. If null, then the default content is used, if a
9416 * function is given then the return from the function is used.
9417 * @type function|int|string|null
9418 * @default null
9419 */
9420 "mData": null,
9421
9422 /**
9423 * Partner property to mData which is used (only when defined) to get
9424 * the data - i.e. it is basically the same as mData, but without the
9425 * 'set' option, and also the data fed to it is the result from mData.
9426 * This is the rendering method to match the data method of mData.
9427 * @type function|int|string|null
9428 * @default null
9429 */
9430 "mRender": null,
9431
9432 /**
9433 * Unique header TH/TD element for this column - this is what the sorting
9434 * listener is attached to (if sorting is enabled.)
9435 * @type node
9436 * @default null
9437 */
9438 "nTh": null,
9439
9440 /**
9441 * Unique footer TH/TD element for this column (if there is one). Not used
9442 * in DataTables as such, but can be used for plug-ins to reference the
9443 * footer for each column.
9444 * @type node
9445 * @default null
9446 */
9447 "nTf": null,
9448
9449 /**
9450 * The class to apply to all TD elements in the table's TBODY for the column
9451 * @type string
9452 * @default null
9453 */
9454 "sClass": null,
9455
9456 /**
9457 * When DataTables calculates the column widths to assign to each column,
9458 * it finds the longest string in each column and then constructs a
9459 * temporary table and reads the widths from that. The problem with this
9460 * is that "mmm" is much wider then "iiii", but the latter is a longer
9461 * string - thus the calculation can go wrong (doing it properly and putting
9462 * it into an DOM object and measuring that is horribly(!) slow). Thus as
9463 * a "work around" we provide this option. It will append its value to the
9464 * text that is found to be the longest string for the column - i.e. padding.
9465 * @type string
9466 */
9467 "sContentPadding": null,
9468
9469 /**
9470 * Allows a default value to be given for a column's data, and will be used
9471 * whenever a null data source is encountered (this can be because mData
9472 * is set to null, or because the data source itself is null).
9473 * @type string
9474 * @default null
9475 */
9476 "sDefaultContent": null,
9477
9478 /**
9479 * Name for the column, allowing reference to the column by name as well as
9480 * by index (needs a lookup to work by name).
9481 * @type string
9482 */
9483 "sName": null,
9484
9485 /**
9486 * Custom sorting data type - defines which of the available plug-ins in
9487 * afnSortData the custom sorting will use - if any is defined.
9488 * @type string
9489 * @default std
9490 */
9491 "sSortDataType": 'std',
9492
9493 /**
9494 * Class to be applied to the header element when sorting on this column
9495 * @type string
9496 * @default null
9497 */
9498 "sSortingClass": null,
9499
9500 /**
9501 * Class to be applied to the header element when sorting on this column -
9502 * when jQuery UI theming is used.
9503 * @type string
9504 * @default null
9505 */
9506 "sSortingClassJUI": null,
9507
9508 /**
9509 * Title of the column - what is seen in the TH element (nTh).
9510 * @type string
9511 */
9512 "sTitle": null,
9513
9514 /**
9515 * Column sorting and filtering type
9516 * @type string
9517 * @default null
9518 */
9519 "sType": null,
9520
9521 /**
9522 * Width of the column
9523 * @type string
9524 * @default null
9525 */
9526 "sWidth": null,
9527
9528 /**
9529 * Width of the column when it was first "encountered"
9530 * @type string
9531 * @default null
9532 */
9533 "sWidthOrig": null
9534 };
9535
9536
9537 /*
9538 * Developer note: The properties of the object below are given in Hungarian
9539 * notation, that was used as the interface for DataTables prior to v1.10, however
9540 * from v1.10 onwards the primary interface is camel case. In order to avoid
9541 * breaking backwards compatibility utterly with this change, the Hungarian
9542 * version is still, internally the primary interface, but is is not documented
9543 * - hence the @name tags in each doc comment. This allows a Javascript function
9544 * to create a map from Hungarian notation to camel case (going the other direction
9545 * would require each property to be listed, which would at around 3K to the size
9546 * of DataTables, while this method is about a 0.5K hit.
9547 *
9548 * Ultimately this does pave the way for Hungarian notation to be dropped
9549 * completely, but that is a massive amount of work and will break current
9550 * installs (therefore is on-hold until v2).
9551 */
9552
9553 /**
9554 * Initialisation options that can be given to DataTables at initialisation
9555 * time.
9556 * @namespace
9557 */
9558 DataTable.defaults = {
9559 /**
9560 * An array of data to use for the table, passed in at initialisation which
9561 * will be used in preference to any data which is already in the DOM. This is
9562 * particularly useful for constructing tables purely in Javascript, for
9563 * example with a custom Ajax call.
9564 * @type array
9565 * @default null
9566 *
9567 * @dtopt Option
9568 * @name DataTable.defaults.data
9569 *
9570 * @example
9571 * // Using a 2D array data source
9572 * $(document).ready( function () {
9573 * $('#example').dataTable( {
9574 * "data": [
9575 * ['Trident', 'Internet Explorer 4.0', 'Win 95+', 4, 'X'],
9576 * ['Trident', 'Internet Explorer 5.0', 'Win 95+', 5, 'C'],
9577 * ],
9578 * "columns": [
9579 * { "title": "Engine" },
9580 * { "title": "Browser" },
9581 * { "title": "Platform" },
9582 * { "title": "Version" },
9583 * { "title": "Grade" }
9584 * ]
9585 * } );
9586 * } );
9587 *
9588 * @example
9589 * // Using an array of objects as a data source (`data`)
9590 * $(document).ready( function () {
9591 * $('#example').dataTable( {
9592 * "data": [
9593 * {
9594 * "engine": "Trident",
9595 * "browser": "Internet Explorer 4.0",
9596 * "platform": "Win 95+",
9597 * "version": 4,
9598 * "grade": "X"
9599 * },
9600 * {
9601 * "engine": "Trident",
9602 * "browser": "Internet Explorer 5.0",
9603 * "platform": "Win 95+",
9604 * "version": 5,
9605 * "grade": "C"
9606 * }
9607 * ],
9608 * "columns": [
9609 * { "title": "Engine", "data": "engine" },
9610 * { "title": "Browser", "data": "browser" },
9611 * { "title": "Platform", "data": "platform" },
9612 * { "title": "Version", "data": "version" },
9613 * { "title": "Grade", "data": "grade" }
9614 * ]
9615 * } );
9616 * } );
9617 */
9618 "aaData": null,
9619
9620
9621 /**
9622 * If ordering is enabled, then DataTables will perform a first pass sort on
9623 * initialisation. You can define which column(s) the sort is performed
9624 * upon, and the sorting direction, with this variable. The `sorting` array
9625 * should contain an array for each column to be sorted initially containing
9626 * the column's index and a direction string ('asc' or 'desc').
9627 * @type array
9628 * @default [[0,'asc']]
9629 *
9630 * @dtopt Option
9631 * @name DataTable.defaults.order
9632 *
9633 * @example
9634 * // Sort by 3rd column first, and then 4th column
9635 * $(document).ready( function() {
9636 * $('#example').dataTable( {
9637 * "order": [[2,'asc'], [3,'desc']]
9638 * } );
9639 * } );
9640 *
9641 * // No initial sorting
9642 * $(document).ready( function() {
9643 * $('#example').dataTable( {
9644 * "order": []
9645 * } );
9646 * } );
9647 */
9648 "aaSorting": [[0,'asc']],
9649
9650
9651 /**
9652 * This parameter is basically identical to the `sorting` parameter, but
9653 * cannot be overridden by user interaction with the table. What this means
9654 * is that you could have a column (visible or hidden) which the sorting
9655 * will always be forced on first - any sorting after that (from the user)
9656 * will then be performed as required. This can be useful for grouping rows
9657 * together.
9658 * @type array
9659 * @default null
9660 *
9661 * @dtopt Option
9662 * @name DataTable.defaults.orderFixed
9663 *
9664 * @example
9665 * $(document).ready( function() {
9666 * $('#example').dataTable( {
9667 * "orderFixed": [[0,'asc']]
9668 * } );
9669 * } )
9670 */
9671 "aaSortingFixed": [],
9672
9673
9674 /**
9675 * DataTables can be instructed to load data to display in the table from a
9676 * Ajax source. This option defines how that Ajax call is made and where to.
9677 *
9678 * The `ajax` property has three different modes of operation, depending on
9679 * how it is defined. These are:
9680 *
9681 * * `string` - Set the URL from where the data should be loaded from.
9682 * * `object` - Define properties for `jQuery.ajax`.
9683 * * `function` - Custom data get function
9684 *
9685 * `string`
9686 * --------
9687 *
9688 * As a string, the `ajax` property simply defines the URL from which
9689 * DataTables will load data.
9690 *
9691 * `object`
9692 * --------
9693 *
9694 * As an object, the parameters in the object are passed to
9695 * [jQuery.ajax](http://api.jquery.com/jQuery.ajax/) allowing fine control
9696 * of the Ajax request. DataTables has a number of default parameters which
9697 * you can override using this option. Please refer to the jQuery
9698 * documentation for a full description of the options available, although
9699 * the following parameters provide additional options in DataTables or
9700 * require special consideration:
9701 *
9702 * * `data` - As with jQuery, `data` can be provided as an object, but it
9703 * can also be used as a function to manipulate the data DataTables sends
9704 * to the server. The function takes a single parameter, an object of
9705 * parameters with the values that DataTables has readied for sending. An
9706 * object may be returned which will be merged into the DataTables
9707 * defaults, or you can add the items to the object that was passed in and
9708 * not return anything from the function. This supersedes `fnServerParams`
9709 * from DataTables 1.9-.
9710 *
9711 * * `dataSrc` - By default DataTables will look for the property `data` (or
9712 * `aaData` for compatibility with DataTables 1.9-) when obtaining data
9713 * from an Ajax source or for server-side processing - this parameter
9714 * allows that property to be changed. You can use Javascript dotted
9715 * object notation to get a data source for multiple levels of nesting, or
9716 * it my be used as a function. As a function it takes a single parameter,
9717 * the JSON returned from the server, which can be manipulated as
9718 * required, with the returned value being that used by DataTables as the
9719 * data source for the table. This supersedes `sAjaxDataProp` from
9720 * DataTables 1.9-.
9721 *
9722 * * `success` - Should not be overridden it is used internally in
9723 * DataTables. To manipulate / transform the data returned by the server
9724 * use `ajax.dataSrc`, or use `ajax` as a function (see below).
9725 *
9726 * `function`
9727 * ----------
9728 *
9729 * As a function, making the Ajax call is left up to yourself allowing
9730 * complete control of the Ajax request. Indeed, if desired, a method other
9731 * than Ajax could be used to obtain the required data, such as Web storage
9732 * or an AIR database.
9733 *
9734 * The function is given four parameters and no return is required. The
9735 * parameters are:
9736 *
9737 * 1. _object_ - Data to send to the server
9738 * 2. _function_ - Callback function that must be executed when the required
9739 * data has been obtained. That data should be passed into the callback
9740 * as the only parameter
9741 * 3. _object_ - DataTables settings object for the table
9742 *
9743 * Note that this supersedes `fnServerData` from DataTables 1.9-.
9744 *
9745 * @type string|object|function
9746 * @default null
9747 *
9748 * @dtopt Option
9749 * @name DataTable.defaults.ajax
9750 * @since 1.10.0
9751 *
9752 * @example
9753 * // Get JSON data from a file via Ajax.
9754 * // Note DataTables expects data in the form `{ data: [ ...data... ] }` by default).
9755 * $('#example').dataTable( {
9756 * "ajax": "data.json"
9757 * } );
9758 *
9759 * @example
9760 * // Get JSON data from a file via Ajax, using `dataSrc` to change
9761 * // `data` to `tableData` (i.e. `{ tableData: [ ...data... ] }`)
9762 * $('#example').dataTable( {
9763 * "ajax": {
9764 * "url": "data.json",
9765 * "dataSrc": "tableData"
9766 * }
9767 * } );
9768 *
9769 * @example
9770 * // Get JSON data from a file via Ajax, using `dataSrc` to read data
9771 * // from a plain array rather than an array in an object
9772 * $('#example').dataTable( {
9773 * "ajax": {
9774 * "url": "data.json",
9775 * "dataSrc": ""
9776 * }
9777 * } );
9778 *
9779 * @example
9780 * // Manipulate the data returned from the server - add a link to data
9781 * // (note this can, should, be done using `render` for the column - this
9782 * // is just a simple example of how the data can be manipulated).
9783 * $('#example').dataTable( {
9784 * "ajax": {
9785 * "url": "data.json",
9786 * "dataSrc": function ( json ) {
9787 * for ( var i=0, ien=json.length ; i<ien ; i++ ) {
9788 * json[i][0] = '<a href="/message/'+json[i][0]+'>View message</a>';
9789 * }
9790 * return json;
9791 * }
9792 * }
9793 * } );
9794 *
9795 * @example
9796 * // Add data to the request
9797 * $('#example').dataTable( {
9798 * "ajax": {
9799 * "url": "data.json",
9800 * "data": function ( d ) {
9801 * return {
9802 * "extra_search": $('#extra').val()
9803 * };
9804 * }
9805 * }
9806 * } );
9807 *
9808 * @example
9809 * // Send request as POST
9810 * $('#example').dataTable( {
9811 * "ajax": {
9812 * "url": "data.json",
9813 * "type": "POST"
9814 * }
9815 * } );
9816 *
9817 * @example
9818 * // Get the data from localStorage (could interface with a form for
9819 * // adding, editing and removing rows).
9820 * $('#example').dataTable( {
9821 * "ajax": function (data, callback, settings) {
9822 * callback(
9823 * JSON.parse( localStorage.getItem('dataTablesData') )
9824 * );
9825 * }
9826 * } );
9827 */
9828 "ajax": null,
9829
9830
9831 /**
9832 * This parameter allows you to readily specify the entries in the length drop
9833 * down menu that DataTables shows when pagination is enabled. It can be
9834 * either a 1D array of options which will be used for both the displayed
9835 * option and the value, or a 2D array which will use the array in the first
9836 * position as the value, and the array in the second position as the
9837 * displayed options (useful for language strings such as 'All').
9838 *
9839 * Note that the `pageLength` property will be automatically set to the
9840 * first value given in this array, unless `pageLength` is also provided.
9841 * @type array
9842 * @default [ 10, 25, 50, 100 ]
9843 *
9844 * @dtopt Option
9845 * @name DataTable.defaults.lengthMenu
9846 *
9847 * @example
9848 * $(document).ready( function() {
9849 * $('#example').dataTable( {
9850 * "lengthMenu": [[10, 25, 50, -1], [10, 25, 50, "All"]]
9851 * } );
9852 * } );
9853 */
9854 "aLengthMenu": [ 10, 25, 50, 100 ],
9855
9856
9857 /**
9858 * The `columns` option in the initialisation parameter allows you to define
9859 * details about the way individual columns behave. For a full list of
9860 * column options that can be set, please see
9861 * {@link DataTable.defaults.column}. Note that if you use `columns` to
9862 * define your columns, you must have an entry in the array for every single
9863 * column that you have in your table (these can be null if you don't which
9864 * to specify any options).
9865 * @member
9866 *
9867 * @name DataTable.defaults.column
9868 */
9869 "aoColumns": null,
9870
9871 /**
9872 * Very similar to `columns`, `columnDefs` allows you to target a specific
9873 * column, multiple columns, or all columns, using the `targets` property of
9874 * each object in the array. This allows great flexibility when creating
9875 * tables, as the `columnDefs` arrays can be of any length, targeting the
9876 * columns you specifically want. `columnDefs` may use any of the column
9877 * options available: {@link DataTable.defaults.column}, but it _must_
9878 * have `targets` defined in each object in the array. Values in the `targets`
9879 * array may be:
9880 * <ul>
9881 * <li>a string - class name will be matched on the TH for the column</li>
9882 * <li>0 or a positive integer - column index counting from the left</li>
9883 * <li>a negative integer - column index counting from the right</li>
9884 * <li>the string "_all" - all columns (i.e. assign a default)</li>
9885 * </ul>
9886 * @member
9887 *
9888 * @name DataTable.defaults.columnDefs
9889 */
9890 "aoColumnDefs": null,
9891
9892
9893 /**
9894 * Basically the same as `search`, this parameter defines the individual column
9895 * filtering state at initialisation time. The array must be of the same size
9896 * as the number of columns, and each element be an object with the parameters
9897 * `search` and `escapeRegex` (the latter is optional). 'null' is also
9898 * accepted and the default will be used.
9899 * @type array
9900 * @default []
9901 *
9902 * @dtopt Option
9903 * @name DataTable.defaults.searchCols
9904 *
9905 * @example
9906 * $(document).ready( function() {
9907 * $('#example').dataTable( {
9908 * "searchCols": [
9909 * null,
9910 * { "search": "My filter" },
9911 * null,
9912 * { "search": "^[0-9]", "escapeRegex": false }
9913 * ]
9914 * } );
9915 * } )
9916 */
9917 "aoSearchCols": [],
9918
9919
9920 /**
9921 * An array of CSS classes that should be applied to displayed rows. This
9922 * array may be of any length, and DataTables will apply each class
9923 * sequentially, looping when required.
9924 * @type array
9925 * @default null <i>Will take the values determined by the `oClasses.stripe*`
9926 * options</i>
9927 *
9928 * @dtopt Option
9929 * @name DataTable.defaults.stripeClasses
9930 *
9931 * @example
9932 * $(document).ready( function() {
9933 * $('#example').dataTable( {
9934 * "stripeClasses": [ 'strip1', 'strip2', 'strip3' ]
9935 * } );
9936 * } )
9937 */
9938 "asStripeClasses": null,
9939
9940
9941 /**
9942 * Enable or disable automatic column width calculation. This can be disabled
9943 * as an optimisation (it takes some time to calculate the widths) if the
9944 * tables widths are passed in using `columns`.
9945 * @type boolean
9946 * @default true
9947 *
9948 * @dtopt Features
9949 * @name DataTable.defaults.autoWidth
9950 *
9951 * @example
9952 * $(document).ready( function () {
9953 * $('#example').dataTable( {
9954 * "autoWidth": false
9955 * } );
9956 * } );
9957 */
9958 "bAutoWidth": true,
9959
9960
9961 /**
9962 * Deferred rendering can provide DataTables with a huge speed boost when you
9963 * are using an Ajax or JS data source for the table. This option, when set to
9964 * true, will cause DataTables to defer the creation of the table elements for
9965 * each row until they are needed for a draw - saving a significant amount of
9966 * time.
9967 * @type boolean
9968 * @default false
9969 *
9970 * @dtopt Features
9971 * @name DataTable.defaults.deferRender
9972 *
9973 * @example
9974 * $(document).ready( function() {
9975 * $('#example').dataTable( {
9976 * "ajax": "sources/arrays.txt",
9977 * "deferRender": true
9978 * } );
9979 * } );
9980 */
9981 "bDeferRender": false,
9982
9983
9984 /**
9985 * Replace a DataTable which matches the given selector and replace it with
9986 * one which has the properties of the new initialisation object passed. If no
9987 * table matches the selector, then the new DataTable will be constructed as
9988 * per normal.
9989 * @type boolean
9990 * @default false
9991 *
9992 * @dtopt Options
9993 * @name DataTable.defaults.destroy
9994 *
9995 * @example
9996 * $(document).ready( function() {
9997 * $('#example').dataTable( {
9998 * "srollY": "200px",
9999 * "paginate": false
10000 * } );
10001 *
10002 * // Some time later....
10003 * $('#example').dataTable( {
10004 * "filter": false,
10005 * "destroy": true
10006 * } );
10007 * } );
10008 */
10009 "bDestroy": false,
10010
10011
10012 /**
10013 * Enable or disable filtering of data. Filtering in DataTables is "smart" in
10014 * that it allows the end user to input multiple words (space separated) and
10015 * will match a row containing those words, even if not in the order that was
10016 * specified (this allow matching across multiple columns). Note that if you
10017 * wish to use filtering in DataTables this must remain 'true' - to remove the
10018 * default filtering input box and retain filtering abilities, please use
10019 * {@link DataTable.defaults.dom}.
10020 * @type boolean
10021 * @default true
10022 *
10023 * @dtopt Features
10024 * @name DataTable.defaults.searching
10025 *
10026 * @example
10027 * $(document).ready( function () {
10028 * $('#example').dataTable( {
10029 * "searching": false
10030 * } );
10031 * } );
10032 */
10033 "bFilter": true,
10034
10035
10036 /**
10037 * Enable or disable the table information display. This shows information
10038 * about the data that is currently visible on the page, including information
10039 * about filtered data if that action is being performed.
10040 * @type boolean
10041 * @default true
10042 *
10043 * @dtopt Features
10044 * @name DataTable.defaults.info
10045 *
10046 * @example
10047 * $(document).ready( function () {
10048 * $('#example').dataTable( {
10049 * "info": false
10050 * } );
10051 * } );
10052 */
10053 "bInfo": true,
10054
10055
10056 /**
10057 * Enable jQuery UI ThemeRoller support (required as ThemeRoller requires some
10058 * slightly different and additional mark-up from what DataTables has
10059 * traditionally used).
10060 * @type boolean
10061 * @default false
10062 *
10063 * @dtopt Features
10064 * @name DataTable.defaults.jQueryUI
10065 *
10066 * @example
10067 * $(document).ready( function() {
10068 * $('#example').dataTable( {
10069 * "jQueryUI": true
10070 * } );
10071 * } );
10072 */
10073 "bJQueryUI": false,
10074
10075
10076 /**
10077 * Allows the end user to select the size of a formatted page from a select
10078 * menu (sizes are 10, 25, 50 and 100). Requires pagination (`paginate`).
10079 * @type boolean
10080 * @default true
10081 *
10082 * @dtopt Features
10083 * @name DataTable.defaults.lengthChange
10084 *
10085 * @example
10086 * $(document).ready( function () {
10087 * $('#example').dataTable( {
10088 * "lengthChange": false
10089 * } );
10090 * } );
10091 */
10092 "bLengthChange": true,
10093
10094
10095 /**
10096 * Enable or disable pagination.
10097 * @type boolean
10098 * @default true
10099 *
10100 * @dtopt Features
10101 * @name DataTable.defaults.paging
10102 *
10103 * @example
10104 * $(document).ready( function () {
10105 * $('#example').dataTable( {
10106 * "paging": false
10107 * } );
10108 * } );
10109 */
10110 "bPaginate": true,
10111
10112
10113 /**
10114 * Enable or disable the display of a 'processing' indicator when the table is
10115 * being processed (e.g. a sort). This is particularly useful for tables with
10116 * large amounts of data where it can take a noticeable amount of time to sort
10117 * the entries.
10118 * @type boolean
10119 * @default false
10120 *
10121 * @dtopt Features
10122 * @name DataTable.defaults.processing
10123 *
10124 * @example
10125 * $(document).ready( function () {
10126 * $('#example').dataTable( {
10127 * "processing": true
10128 * } );
10129 * } );
10130 */
10131 "bProcessing": false,
10132
10133
10134 /**
10135 * Retrieve the DataTables object for the given selector. Note that if the
10136 * table has already been initialised, this parameter will cause DataTables
10137 * to simply return the object that has already been set up - it will not take
10138 * account of any changes you might have made to the initialisation object
10139 * passed to DataTables (setting this parameter to true is an acknowledgement
10140 * that you understand this). `destroy` can be used to reinitialise a table if
10141 * you need.
10142 * @type boolean
10143 * @default false
10144 *
10145 * @dtopt Options
10146 * @name DataTable.defaults.retrieve
10147 *
10148 * @example
10149 * $(document).ready( function() {
10150 * initTable();
10151 * tableActions();
10152 * } );
10153 *
10154 * function initTable ()
10155 * {
10156 * return $('#example').dataTable( {
10157 * "scrollY": "200px",
10158 * "paginate": false,
10159 * "retrieve": true
10160 * } );
10161 * }
10162 *
10163 * function tableActions ()
10164 * {
10165 * var table = initTable();
10166 * // perform API operations with oTable
10167 * }
10168 */
10169 "bRetrieve": false,
10170
10171
10172 /**
10173 * When vertical (y) scrolling is enabled, DataTables will force the height of
10174 * the table's viewport to the given height at all times (useful for layout).
10175 * However, this can look odd when filtering data down to a small data set,
10176 * and the footer is left "floating" further down. This parameter (when
10177 * enabled) will cause DataTables to collapse the table's viewport down when
10178 * the result set will fit within the given Y height.
10179 * @type boolean
10180 * @default false
10181 *
10182 * @dtopt Options
10183 * @name DataTable.defaults.scrollCollapse
10184 *
10185 * @example
10186 * $(document).ready( function() {
10187 * $('#example').dataTable( {
10188 * "scrollY": "200",
10189 * "scrollCollapse": true
10190 * } );
10191 * } );
10192 */
10193 "bScrollCollapse": false,
10194
10195
10196 /**
10197 * Configure DataTables to use server-side processing. Note that the
10198 * `ajax` parameter must also be given in order to give DataTables a
10199 * source to obtain the required data for each draw.
10200 * @type boolean
10201 * @default false
10202 *
10203 * @dtopt Features
10204 * @dtopt Server-side
10205 * @name DataTable.defaults.serverSide
10206 *
10207 * @example
10208 * $(document).ready( function () {
10209 * $('#example').dataTable( {
10210 * "serverSide": true,
10211 * "ajax": "xhr.php"
10212 * } );
10213 * } );
10214 */
10215 "bServerSide": false,
10216
10217
10218 /**
10219 * Enable or disable sorting of columns. Sorting of individual columns can be
10220 * disabled by the `sortable` option for each column.
10221 * @type boolean
10222 * @default true
10223 *
10224 * @dtopt Features
10225 * @name DataTable.defaults.ordering
10226 *
10227 * @example
10228 * $(document).ready( function () {
10229 * $('#example').dataTable( {
10230 * "ordering": false
10231 * } );
10232 * } );
10233 */
10234 "bSort": true,
10235
10236
10237 /**
10238 * Enable or display DataTables' ability to sort multiple columns at the
10239 * same time (activated by shift-click by the user).
10240 * @type boolean
10241 * @default true
10242 *
10243 * @dtopt Options
10244 * @name DataTable.defaults.orderMulti
10245 *
10246 * @example
10247 * // Disable multiple column sorting ability
10248 * $(document).ready( function () {
10249 * $('#example').dataTable( {
10250 * "orderMulti": false
10251 * } );
10252 * } );
10253 */
10254 "bSortMulti": true,
10255
10256
10257 /**
10258 * Allows control over whether DataTables should use the top (true) unique
10259 * cell that is found for a single column, or the bottom (false - default).
10260 * This is useful when using complex headers.
10261 * @type boolean
10262 * @default false
10263 *
10264 * @dtopt Options
10265 * @name DataTable.defaults.orderCellsTop
10266 *
10267 * @example
10268 * $(document).ready( function() {
10269 * $('#example').dataTable( {
10270 * "orderCellsTop": true
10271 * } );
10272 * } );
10273 */
10274 "bSortCellsTop": false,
10275
10276
10277 /**
10278 * Enable or disable the addition of the classes `sorting\_1`, `sorting\_2` and
10279 * `sorting\_3` to the columns which are currently being sorted on. This is
10280 * presented as a feature switch as it can increase processing time (while
10281 * classes are removed and added) so for large data sets you might want to
10282 * turn this off.
10283 * @type boolean
10284 * @default true
10285 *
10286 * @dtopt Features
10287 * @name DataTable.defaults.orderClasses
10288 *
10289 * @example
10290 * $(document).ready( function () {
10291 * $('#example').dataTable( {
10292 * "orderClasses": false
10293 * } );
10294 * } );
10295 */
10296 "bSortClasses": true,
10297
10298
10299 /**
10300 * Enable or disable state saving. When enabled HTML5 `localStorage` will be
10301 * used to save table display information such as pagination information,
10302 * display length, filtering and sorting. As such when the end user reloads
10303 * the page the display display will match what thy had previously set up.
10304 *
10305 * Due to the use of `localStorage` the default state saving is not supported
10306 * in IE6 or 7. If state saving is required in those browsers, use
10307 * `stateSaveCallback` to provide a storage solution such as cookies.
10308 * @type boolean
10309 * @default false
10310 *
10311 * @dtopt Features
10312 * @name DataTable.defaults.stateSave
10313 *
10314 * @example
10315 * $(document).ready( function () {
10316 * $('#example').dataTable( {
10317 * "stateSave": true
10318 * } );
10319 * } );
10320 */
10321 "bStateSave": false,
10322
10323
10324 /**
10325 * This function is called when a TR element is created (and all TD child
10326 * elements have been inserted), or registered if using a DOM source, allowing
10327 * manipulation of the TR element (adding classes etc).
10328 * @type function
10329 * @param {node} row "TR" element for the current row
10330 * @param {array} data Raw data array for this row
10331 * @param {int} dataIndex The index of this row in the internal aoData array
10332 *
10333 * @dtopt Callbacks
10334 * @name DataTable.defaults.createdRow
10335 *
10336 * @example
10337 * $(document).ready( function() {
10338 * $('#example').dataTable( {
10339 * "createdRow": function( row, data, dataIndex ) {
10340 * // Bold the grade for all 'A' grade browsers
10341 * if ( data[4] == "A" )
10342 * {
10343 * $('td:eq(4)', row).html( '<b>A</b>' );
10344 * }
10345 * }
10346 * } );
10347 * } );
10348 */
10349 "fnCreatedRow": null,
10350
10351
10352 /**
10353 * This function is called on every 'draw' event, and allows you to
10354 * dynamically modify any aspect you want about the created DOM.
10355 * @type function
10356 * @param {object} settings DataTables settings object
10357 *
10358 * @dtopt Callbacks
10359 * @name DataTable.defaults.drawCallback
10360 *
10361 * @example
10362 * $(document).ready( function() {
10363 * $('#example').dataTable( {
10364 * "drawCallback": function( settings ) {
10365 * alert( 'DataTables has redrawn the table' );
10366 * }
10367 * } );
10368 * } );
10369 */
10370 "fnDrawCallback": null,
10371
10372
10373 /**
10374 * Identical to fnHeaderCallback() but for the table footer this function
10375 * allows you to modify the table footer on every 'draw' event.
10376 * @type function
10377 * @param {node} foot "TR" element for the footer
10378 * @param {array} data Full table data (as derived from the original HTML)
10379 * @param {int} start Index for the current display starting point in the
10380 * display array
10381 * @param {int} end Index for the current display ending point in the
10382 * display array
10383 * @param {array int} display Index array to translate the visual position
10384 * to the full data array
10385 *
10386 * @dtopt Callbacks
10387 * @name DataTable.defaults.footerCallback
10388 *
10389 * @example
10390 * $(document).ready( function() {
10391 * $('#example').dataTable( {
10392 * "footerCallback": function( tfoot, data, start, end, display ) {
10393 * tfoot.getElementsByTagName('th')[0].innerHTML = "Starting index is "+start;
10394 * }
10395 * } );
10396 * } )
10397 */
10398 "fnFooterCallback": null,
10399
10400
10401 /**
10402 * When rendering large numbers in the information element for the table
10403 * (i.e. "Showing 1 to 10 of 57 entries") DataTables will render large numbers
10404 * to have a comma separator for the 'thousands' units (e.g. 1 million is
10405 * rendered as "1,000,000") to help readability for the end user. This
10406 * function will override the default method DataTables uses.
10407 * @type function
10408 * @member
10409 * @param {int} toFormat number to be formatted
10410 * @returns {string} formatted string for DataTables to show the number
10411 *
10412 * @dtopt Callbacks
10413 * @name DataTable.defaults.formatNumber
10414 *
10415 * @example
10416 * // Format a number using a single quote for the separator (note that
10417 * // this can also be done with the language.thousands option)
10418 * $(document).ready( function() {
10419 * $('#example').dataTable( {
10420 * "formatNumber": function ( toFormat ) {
10421 * return toFormat.toString().replace(
10422 * /\B(?=(\d{3})+(?!\d))/g, "'"
10423 * );
10424 * };
10425 * } );
10426 * } );
10427 */
10428 "fnFormatNumber": function ( toFormat ) {
10429 return toFormat.toString().replace(
10430 /\B(?=(\d{3})+(?!\d))/g,
10431 this.oLanguage.sThousands
10432 );
10433 },
10434
10435
10436 /**
10437 * This function is called on every 'draw' event, and allows you to
10438 * dynamically modify the header row. This can be used to calculate and
10439 * display useful information about the table.
10440 * @type function
10441 * @param {node} head "TR" element for the header
10442 * @param {array} data Full table data (as derived from the original HTML)
10443 * @param {int} start Index for the current display starting point in the
10444 * display array
10445 * @param {int} end Index for the current display ending point in the
10446 * display array
10447 * @param {array int} display Index array to translate the visual position
10448 * to the full data array
10449 *
10450 * @dtopt Callbacks
10451 * @name DataTable.defaults.headerCallback
10452 *
10453 * @example
10454 * $(document).ready( function() {
10455 * $('#example').dataTable( {
10456 * "fheaderCallback": function( head, data, start, end, display ) {
10457 * head.getElementsByTagName('th')[0].innerHTML = "Displaying "+(end-start)+" records";
10458 * }
10459 * } );
10460 * } )
10461 */
10462 "fnHeaderCallback": null,
10463
10464
10465 /**
10466 * The information element can be used to convey information about the current
10467 * state of the table. Although the internationalisation options presented by
10468 * DataTables are quite capable of dealing with most customisations, there may
10469 * be times where you wish to customise the string further. This callback
10470 * allows you to do exactly that.
10471 * @type function
10472 * @param {object} oSettings DataTables settings object
10473 * @param {int} start Starting position in data for the draw
10474 * @param {int} end End position in data for the draw
10475 * @param {int} max Total number of rows in the table (regardless of
10476 * filtering)
10477 * @param {int} total Total number of rows in the data set, after filtering
10478 * @param {string} pre The string that DataTables has formatted using it's
10479 * own rules
10480 * @returns {string} The string to be displayed in the information element.
10481 *
10482 * @dtopt Callbacks
10483 * @name DataTable.defaults.infoCallback
10484 *
10485 * @example
10486 * $('#example').dataTable( {
10487 * "infoCallback": function( settings, start, end, max, total, pre ) {
10488 * return start +" to "+ end;
10489 * }
10490 * } );
10491 */
10492 "fnInfoCallback": null,
10493
10494
10495 /**
10496 * Called when the table has been initialised. Normally DataTables will
10497 * initialise sequentially and there will be no need for this function,
10498 * however, this does not hold true when using external language information
10499 * since that is obtained using an async XHR call.
10500 * @type function
10501 * @param {object} settings DataTables settings object
10502 * @param {object} json The JSON object request from the server - only
10503 * present if client-side Ajax sourced data is used
10504 *
10505 * @dtopt Callbacks
10506 * @name DataTable.defaults.initComplete
10507 *
10508 * @example
10509 * $(document).ready( function() {
10510 * $('#example').dataTable( {
10511 * "initComplete": function(settings, json) {
10512 * alert( 'DataTables has finished its initialisation.' );
10513 * }
10514 * } );
10515 * } )
10516 */
10517 "fnInitComplete": null,
10518
10519
10520 /**
10521 * Called at the very start of each table draw and can be used to cancel the
10522 * draw by returning false, any other return (including undefined) results in
10523 * the full draw occurring).
10524 * @type function
10525 * @param {object} settings DataTables settings object
10526 * @returns {boolean} False will cancel the draw, anything else (including no
10527 * return) will allow it to complete.
10528 *
10529 * @dtopt Callbacks
10530 * @name DataTable.defaults.preDrawCallback
10531 *
10532 * @example
10533 * $(document).ready( function() {
10534 * $('#example').dataTable( {
10535 * "preDrawCallback": function( settings ) {
10536 * if ( $('#test').val() == 1 ) {
10537 * return false;
10538 * }
10539 * }
10540 * } );
10541 * } );
10542 */
10543 "fnPreDrawCallback": null,
10544
10545
10546 /**
10547 * This function allows you to 'post process' each row after it have been
10548 * generated for each table draw, but before it is rendered on screen. This
10549 * function might be used for setting the row class name etc.
10550 * @type function
10551 * @param {node} row "TR" element for the current row
10552 * @param {array} data Raw data array for this row
10553 * @param {int} displayIndex The display index for the current table draw
10554 * @param {int} displayIndexFull The index of the data in the full list of
10555 * rows (after filtering)
10556 *
10557 * @dtopt Callbacks
10558 * @name DataTable.defaults.rowCallback
10559 *
10560 * @example
10561 * $(document).ready( function() {
10562 * $('#example').dataTable( {
10563 * "rowCallback": function( row, data, displayIndex, displayIndexFull ) {
10564 * // Bold the grade for all 'A' grade browsers
10565 * if ( data[4] == "A" ) {
10566 * $('td:eq(4)', row).html( '<b>A</b>' );
10567 * }
10568 * }
10569 * } );
10570 * } );
10571 */
10572 "fnRowCallback": null,
10573
10574
10575 /**
10576 * __Deprecated__ The functionality provided by this parameter has now been
10577 * superseded by that provided through `ajax`, which should be used instead.
10578 *
10579 * This parameter allows you to override the default function which obtains
10580 * the data from the server so something more suitable for your application.
10581 * For example you could use POST data, or pull information from a Gears or
10582 * AIR database.
10583 * @type function
10584 * @member
10585 * @param {string} source HTTP source to obtain the data from (`ajax`)
10586 * @param {array} data A key/value pair object containing the data to send
10587 * to the server
10588 * @param {function} callback to be called on completion of the data get
10589 * process that will draw the data on the page.
10590 * @param {object} settings DataTables settings object
10591 *
10592 * @dtopt Callbacks
10593 * @dtopt Server-side
10594 * @name DataTable.defaults.serverData
10595 *
10596 * @deprecated 1.10. Please use `ajax` for this functionality now.
10597 */
10598 "fnServerData": null,
10599
10600
10601 /**
10602 * __Deprecated__ The functionality provided by this parameter has now been
10603 * superseded by that provided through `ajax`, which should be used instead.
10604 *
10605 * It is often useful to send extra data to the server when making an Ajax
10606 * request - for example custom filtering information, and this callback
10607 * function makes it trivial to send extra information to the server. The
10608 * passed in parameter is the data set that has been constructed by
10609 * DataTables, and you can add to this or modify it as you require.
10610 * @type function
10611 * @param {array} data Data array (array of objects which are name/value
10612 * pairs) that has been constructed by DataTables and will be sent to the
10613 * server. In the case of Ajax sourced data with server-side processing
10614 * this will be an empty array, for server-side processing there will be a
10615 * significant number of parameters!
10616 * @returns {undefined} Ensure that you modify the data array passed in,
10617 * as this is passed by reference.
10618 *
10619 * @dtopt Callbacks
10620 * @dtopt Server-side
10621 * @name DataTable.defaults.serverParams
10622 *
10623 * @deprecated 1.10. Please use `ajax` for this functionality now.
10624 */
10625 "fnServerParams": null,
10626
10627
10628 /**
10629 * Load the table state. With this function you can define from where, and how, the
10630 * state of a table is loaded. By default DataTables will load from `localStorage`
10631 * but you might wish to use a server-side database or cookies.
10632 * @type function
10633 * @member
10634 * @param {object} settings DataTables settings object
10635 * @return {object} The DataTables state object to be loaded
10636 *
10637 * @dtopt Callbacks
10638 * @name DataTable.defaults.stateLoadCallback
10639 *
10640 * @example
10641 * $(document).ready( function() {
10642 * $('#example').dataTable( {
10643 * "stateSave": true,
10644 * "stateLoadCallback": function (settings) {
10645 * var o;
10646 *
10647 * // Send an Ajax request to the server to get the data. Note that
10648 * // this is a synchronous request.
10649 * $.ajax( {
10650 * "url": "/state_load",
10651 * "async": false,
10652 * "dataType": "json",
10653 * "success": function (json) {
10654 * o = json;
10655 * }
10656 * } );
10657 *
10658 * return o;
10659 * }
10660 * } );
10661 * } );
10662 */
10663 "fnStateLoadCallback": function ( settings ) {
10664 try {
10665 return JSON.parse(
10666 (settings.iStateDuration === -1 ? sessionStorage : localStorage).getItem(
10667 'DataTables_'+settings.sInstance+'_'+location.pathname
10668 )
10669 );
10670 } catch (e) {}
10671 },
10672
10673
10674 /**
10675 * Callback which allows modification of the saved state prior to loading that state.
10676 * This callback is called when the table is loading state from the stored data, but
10677 * prior to the settings object being modified by the saved state. Note that for
10678 * plug-in authors, you should use the `stateLoadParams` event to load parameters for
10679 * a plug-in.
10680 * @type function
10681 * @param {object} settings DataTables settings object
10682 * @param {object} data The state object that is to be loaded
10683 *
10684 * @dtopt Callbacks
10685 * @name DataTable.defaults.stateLoadParams
10686 *
10687 * @example
10688 * // Remove a saved filter, so filtering is never loaded
10689 * $(document).ready( function() {
10690 * $('#example').dataTable( {
10691 * "stateSave": true,
10692 * "stateLoadParams": function (settings, data) {
10693 * data.oSearch.sSearch = "";
10694 * }
10695 * } );
10696 * } );
10697 *
10698 * @example
10699 * // Disallow state loading by returning false
10700 * $(document).ready( function() {
10701 * $('#example').dataTable( {
10702 * "stateSave": true,
10703 * "stateLoadParams": function (settings, data) {
10704 * return false;
10705 * }
10706 * } );
10707 * } );
10708 */
10709 "fnStateLoadParams": null,
10710
10711
10712 /**
10713 * Callback that is called when the state has been loaded from the state saving method
10714 * and the DataTables settings object has been modified as a result of the loaded state.
10715 * @type function
10716 * @param {object} settings DataTables settings object
10717 * @param {object} data The state object that was loaded
10718 *
10719 * @dtopt Callbacks
10720 * @name DataTable.defaults.stateLoaded
10721 *
10722 * @example
10723 * // Show an alert with the filtering value that was saved
10724 * $(document).ready( function() {
10725 * $('#example').dataTable( {
10726 * "stateSave": true,
10727 * "stateLoaded": function (settings, data) {
10728 * alert( 'Saved filter was: '+data.oSearch.sSearch );
10729 * }
10730 * } );
10731 * } );
10732 */
10733 "fnStateLoaded": null,
10734
10735
10736 /**
10737 * Save the table state. This function allows you to define where and how the state
10738 * information for the table is stored By default DataTables will use `localStorage`
10739 * but you might wish to use a server-side database or cookies.
10740 * @type function
10741 * @member
10742 * @param {object} settings DataTables settings object
10743 * @param {object} data The state object to be saved
10744 *
10745 * @dtopt Callbacks
10746 * @name DataTable.defaults.stateSaveCallback
10747 *
10748 * @example
10749 * $(document).ready( function() {
10750 * $('#example').dataTable( {
10751 * "stateSave": true,
10752 * "stateSaveCallback": function (settings, data) {
10753 * // Send an Ajax request to the server with the state object
10754 * $.ajax( {
10755 * "url": "/state_save",
10756 * "data": data,
10757 * "dataType": "json",
10758 * "method": "POST"
10759 * "success": function () {}
10760 * } );
10761 * }
10762 * } );
10763 * } );
10764 */
10765 "fnStateSaveCallback": function ( settings, data ) {
10766 try {
10767 (settings.iStateDuration === -1 ? sessionStorage : localStorage).setItem(
10768 'DataTables_'+settings.sInstance+'_'+location.pathname,
10769 JSON.stringify( data )
10770 );
10771 } catch (e) {}
10772 },
10773
10774
10775 /**
10776 * Callback which allows modification of the state to be saved. Called when the table
10777 * has changed state a new state save is required. This method allows modification of
10778 * the state saving object prior to actually doing the save, including addition or
10779 * other state properties or modification. Note that for plug-in authors, you should
10780 * use the `stateSaveParams` event to save parameters for a plug-in.
10781 * @type function
10782 * @param {object} settings DataTables settings object
10783 * @param {object} data The state object to be saved
10784 *
10785 * @dtopt Callbacks
10786 * @name DataTable.defaults.stateSaveParams
10787 *
10788 * @example
10789 * // Remove a saved filter, so filtering is never saved
10790 * $(document).ready( function() {
10791 * $('#example').dataTable( {
10792 * "stateSave": true,
10793 * "stateSaveParams": function (settings, data) {
10794 * data.oSearch.sSearch = "";
10795 * }
10796 * } );
10797 * } );
10798 */
10799 "fnStateSaveParams": null,
10800
10801
10802 /**
10803 * Duration for which the saved state information is considered valid. After this period
10804 * has elapsed the state will be returned to the default.
10805 * Value is given in seconds.
10806 * @type int
10807 * @default 7200 <i>(2 hours)</i>
10808 *
10809 * @dtopt Options
10810 * @name DataTable.defaults.stateDuration
10811 *
10812 * @example
10813 * $(document).ready( function() {
10814 * $('#example').dataTable( {
10815 * "stateDuration": 60*60*24; // 1 day
10816 * } );
10817 * } )
10818 */
10819 "iStateDuration": 7200,
10820
10821
10822 /**
10823 * When enabled DataTables will not make a request to the server for the first
10824 * page draw - rather it will use the data already on the page (no sorting etc
10825 * will be applied to it), thus saving on an XHR at load time. `deferLoading`
10826 * is used to indicate that deferred loading is required, but it is also used
10827 * to tell DataTables how many records there are in the full table (allowing
10828 * the information element and pagination to be displayed correctly). In the case
10829 * where a filtering is applied to the table on initial load, this can be
10830 * indicated by giving the parameter as an array, where the first element is
10831 * the number of records available after filtering and the second element is the
10832 * number of records without filtering (allowing the table information element
10833 * to be shown correctly).
10834 * @type int | array
10835 * @default null
10836 *
10837 * @dtopt Options
10838 * @name DataTable.defaults.deferLoading
10839 *
10840 * @example
10841 * // 57 records available in the table, no filtering applied
10842 * $(document).ready( function() {
10843 * $('#example').dataTable( {
10844 * "serverSide": true,
10845 * "ajax": "scripts/server_processing.php",
10846 * "deferLoading": 57
10847 * } );
10848 * } );
10849 *
10850 * @example
10851 * // 57 records after filtering, 100 without filtering (an initial filter applied)
10852 * $(document).ready( function() {
10853 * $('#example').dataTable( {
10854 * "serverSide": true,
10855 * "ajax": "scripts/server_processing.php",
10856 * "deferLoading": [ 57, 100 ],
10857 * "search": {
10858 * "search": "my_filter"
10859 * }
10860 * } );
10861 * } );
10862 */
10863 "iDeferLoading": null,
10864
10865
10866 /**
10867 * Number of rows to display on a single page when using pagination. If
10868 * feature enabled (`lengthChange`) then the end user will be able to override
10869 * this to a custom setting using a pop-up menu.
10870 * @type int
10871 * @default 10
10872 *
10873 * @dtopt Options
10874 * @name DataTable.defaults.pageLength
10875 *
10876 * @example
10877 * $(document).ready( function() {
10878 * $('#example').dataTable( {
10879 * "pageLength": 50
10880 * } );
10881 * } )
10882 */
10883 "iDisplayLength": 10,
10884
10885
10886 /**
10887 * Define the starting point for data display when using DataTables with
10888 * pagination. Note that this parameter is the number of records, rather than
10889 * the page number, so if you have 10 records per page and want to start on
10890 * the third page, it should be "20".
10891 * @type int
10892 * @default 0
10893 *
10894 * @dtopt Options
10895 * @name DataTable.defaults.displayStart
10896 *
10897 * @example
10898 * $(document).ready( function() {
10899 * $('#example').dataTable( {
10900 * "displayStart": 20
10901 * } );
10902 * } )
10903 */
10904 "iDisplayStart": 0,
10905
10906
10907 /**
10908 * By default DataTables allows keyboard navigation of the table (sorting, paging,
10909 * and filtering) by adding a `tabindex` attribute to the required elements. This
10910 * allows you to tab through the controls and press the enter key to activate them.
10911 * The tabindex is default 0, meaning that the tab follows the flow of the document.
10912 * You can overrule this using this parameter if you wish. Use a value of -1 to
10913 * disable built-in keyboard navigation.
10914 * @type int
10915 * @default 0
10916 *
10917 * @dtopt Options
10918 * @name DataTable.defaults.tabIndex
10919 *
10920 * @example
10921 * $(document).ready( function() {
10922 * $('#example').dataTable( {
10923 * "tabIndex": 1
10924 * } );
10925 * } );
10926 */
10927 "iTabIndex": 0,
10928
10929
10930 /**
10931 * Classes that DataTables assigns to the various components and features
10932 * that it adds to the HTML table. This allows classes to be configured
10933 * during initialisation in addition to through the static
10934 * {@link DataTable.ext.oStdClasses} object).
10935 * @namespace
10936 * @name DataTable.defaults.classes
10937 */
10938 "oClasses": {},
10939
10940
10941 /**
10942 * All strings that DataTables uses in the user interface that it creates
10943 * are defined in this object, allowing you to modified them individually or
10944 * completely replace them all as required.
10945 * @namespace
10946 * @name DataTable.defaults.language
10947 */
10948 "oLanguage": {
10949 /**
10950 * Strings that are used for WAI-ARIA labels and controls only (these are not
10951 * actually visible on the page, but will be read by screenreaders, and thus
10952 * must be internationalised as well).
10953 * @namespace
10954 * @name DataTable.defaults.language.aria
10955 */
10956 "oAria": {
10957 /**
10958 * ARIA label that is added to the table headers when the column may be
10959 * sorted ascending by activing the column (click or return when focused).
10960 * Note that the column header is prefixed to this string.
10961 * @type string
10962 * @default : activate to sort column ascending
10963 *
10964 * @dtopt Language
10965 * @name DataTable.defaults.language.aria.sortAscending
10966 *
10967 * @example
10968 * $(document).ready( function() {
10969 * $('#example').dataTable( {
10970 * "language": {
10971 * "aria": {
10972 * "sortAscending": " - click/return to sort ascending"
10973 * }
10974 * }
10975 * } );
10976 * } );
10977 */
10978 "sSortAscending": ": activate to sort column ascending",
10979
10980 /**
10981 * ARIA label that is added to the table headers when the column may be
10982 * sorted descending by activing the column (click or return when focused).
10983 * Note that the column header is prefixed to this string.
10984 * @type string
10985 * @default : activate to sort column ascending
10986 *
10987 * @dtopt Language
10988 * @name DataTable.defaults.language.aria.sortDescending
10989 *
10990 * @example
10991 * $(document).ready( function() {
10992 * $('#example').dataTable( {
10993 * "language": {
10994 * "aria": {
10995 * "sortDescending": " - click/return to sort descending"
10996 * }
10997 * }
10998 * } );
10999 * } );
11000 */
11001 "sSortDescending": ": activate to sort column descending"
11002 },
11003
11004 /**
11005 * Pagination string used by DataTables for the built-in pagination
11006 * control types.
11007 * @namespace
11008 * @name DataTable.defaults.language.paginate
11009 */
11010 "oPaginate": {
11011 /**
11012 * Text to use when using the 'full_numbers' type of pagination for the
11013 * button to take the user to the first page.
11014 * @type string
11015 * @default First
11016 *
11017 * @dtopt Language
11018 * @name DataTable.defaults.language.paginate.first
11019 *
11020 * @example
11021 * $(document).ready( function() {
11022 * $('#example').dataTable( {
11023 * "language": {
11024 * "paginate": {
11025 * "first": "First page"
11026 * }
11027 * }
11028 * } );
11029 * } );
11030 */
11031 "sFirst": "First",
11032
11033
11034 /**
11035 * Text to use when using the 'full_numbers' type of pagination for the
11036 * button to take the user to the last page.
11037 * @type string
11038 * @default Last
11039 *
11040 * @dtopt Language
11041 * @name DataTable.defaults.language.paginate.last
11042 *
11043 * @example
11044 * $(document).ready( function() {
11045 * $('#example').dataTable( {
11046 * "language": {
11047 * "paginate": {
11048 * "last": "Last page"
11049 * }
11050 * }
11051 * } );
11052 * } );
11053 */
11054 "sLast": "Last",
11055
11056
11057 /**
11058 * Text to use for the 'next' pagination button (to take the user to the
11059 * next page).
11060 * @type string
11061 * @default Next
11062 *
11063 * @dtopt Language
11064 * @name DataTable.defaults.language.paginate.next
11065 *
11066 * @example
11067 * $(document).ready( function() {
11068 * $('#example').dataTable( {
11069 * "language": {
11070 * "paginate": {
11071 * "next": "Next page"
11072 * }
11073 * }
11074 * } );
11075 * } );
11076 */
11077 "sNext": "Next",
11078
11079
11080 /**
11081 * Text to use for the 'previous' pagination button (to take the user to
11082 * the previous page).
11083 * @type string
11084 * @default Previous
11085 *
11086 * @dtopt Language
11087 * @name DataTable.defaults.language.paginate.previous
11088 *
11089 * @example
11090 * $(document).ready( function() {
11091 * $('#example').dataTable( {
11092 * "language": {
11093 * "paginate": {
11094 * "previous": "Previous page"
11095 * }
11096 * }
11097 * } );
11098 * } );
11099 */
11100 "sPrevious": "Previous"
11101 },
11102
11103 /**
11104 * This string is shown in preference to `zeroRecords` when the table is
11105 * empty of data (regardless of filtering). Note that this is an optional
11106 * parameter - if it is not given, the value of `zeroRecords` will be used
11107 * instead (either the default or given value).
11108 * @type string
11109 * @default No data available in table
11110 *
11111 * @dtopt Language
11112 * @name DataTable.defaults.language.emptyTable
11113 *
11114 * @example
11115 * $(document).ready( function() {
11116 * $('#example').dataTable( {
11117 * "language": {
11118 * "emptyTable": "No data available in table"
11119 * }
11120 * } );
11121 * } );
11122 */
11123 "sEmptyTable": "No data available in table",
11124
11125
11126 /**
11127 * This string gives information to the end user about the information
11128 * that is current on display on the page. The following tokens can be
11129 * used in the string and will be dynamically replaced as the table
11130 * display updates. This tokens can be placed anywhere in the string, or
11131 * removed as needed by the language requires:
11132 *
11133 * * `\_START\_` - Display index of the first record on the current page
11134 * * `\_END\_` - Display index of the last record on the current page
11135 * * `\_TOTAL\_` - Number of records in the table after filtering
11136 * * `\_MAX\_` - Number of records in the table without filtering
11137 * * `\_PAGE\_` - Current page number
11138 * * `\_PAGES\_` - Total number of pages of data in the table
11139 *
11140 * @type string
11141 * @default Showing _START_ to _END_ of _TOTAL_ entries
11142 *
11143 * @dtopt Language
11144 * @name DataTable.defaults.language.info
11145 *
11146 * @example
11147 * $(document).ready( function() {
11148 * $('#example').dataTable( {
11149 * "language": {
11150 * "info": "Showing page _PAGE_ of _PAGES_"
11151 * }
11152 * } );
11153 * } );
11154 */
11155 "sInfo": "Showing _START_ to _END_ of _TOTAL_ entries",
11156
11157
11158 /**
11159 * Display information string for when the table is empty. Typically the
11160 * format of this string should match `info`.
11161 * @type string
11162 * @default Showing 0 to 0 of 0 entries
11163 *
11164 * @dtopt Language
11165 * @name DataTable.defaults.language.infoEmpty
11166 *
11167 * @example
11168 * $(document).ready( function() {
11169 * $('#example').dataTable( {
11170 * "language": {
11171 * "infoEmpty": "No entries to show"
11172 * }
11173 * } );
11174 * } );
11175 */
11176 "sInfoEmpty": "Showing 0 to 0 of 0 entries",
11177
11178
11179 /**
11180 * When a user filters the information in a table, this string is appended
11181 * to the information (`info`) to give an idea of how strong the filtering
11182 * is. The variable _MAX_ is dynamically updated.
11183 * @type string
11184 * @default (filtered from _MAX_ total entries)
11185 *
11186 * @dtopt Language
11187 * @name DataTable.defaults.language.infoFiltered
11188 *
11189 * @example
11190 * $(document).ready( function() {
11191 * $('#example').dataTable( {
11192 * "language": {
11193 * "infoFiltered": " - filtering from _MAX_ records"
11194 * }
11195 * } );
11196 * } );
11197 */
11198 "sInfoFiltered": "(filtered from _MAX_ total entries)",
11199
11200
11201 /**
11202 * If can be useful to append extra information to the info string at times,
11203 * and this variable does exactly that. This information will be appended to
11204 * the `info` (`infoEmpty` and `infoFiltered` in whatever combination they are
11205 * being used) at all times.
11206 * @type string
11207 * @default <i>Empty string</i>
11208 *
11209 * @dtopt Language
11210 * @name DataTable.defaults.language.infoPostFix
11211 *
11212 * @example
11213 * $(document).ready( function() {
11214 * $('#example').dataTable( {
11215 * "language": {
11216 * "infoPostFix": "All records shown are derived from real information."
11217 * }
11218 * } );
11219 * } );
11220 */
11221 "sInfoPostFix": "",
11222
11223
11224 /**
11225 * This decimal place operator is a little different from the other
11226 * language options since DataTables doesn't output floating point
11227 * numbers, so it won't ever use this for display of a number. Rather,
11228 * what this parameter does is modify the sort methods of the table so
11229 * that numbers which are in a format which has a character other than
11230 * a period (`.`) as a decimal place will be sorted numerically.
11231 *
11232 * Note that numbers with different decimal places cannot be shown in
11233 * the same table and still be sortable, the table must be consistent.
11234 * However, multiple different tables on the page can use different
11235 * decimal place characters.
11236 * @type string
11237 * @default
11238 *
11239 * @dtopt Language
11240 * @name DataTable.defaults.language.decimal
11241 *
11242 * @example
11243 * $(document).ready( function() {
11244 * $('#example').dataTable( {
11245 * "language": {
11246 * "decimal": ","
11247 * "thousands": "."
11248 * }
11249 * } );
11250 * } );
11251 */
11252 "sDecimal": "",
11253
11254
11255 /**
11256 * DataTables has a build in number formatter (`formatNumber`) which is
11257 * used to format large numbers that are used in the table information.
11258 * By default a comma is used, but this can be trivially changed to any
11259 * character you wish with this parameter.
11260 * @type string
11261 * @default ,
11262 *
11263 * @dtopt Language
11264 * @name DataTable.defaults.language.thousands
11265 *
11266 * @example
11267 * $(document).ready( function() {
11268 * $('#example').dataTable( {
11269 * "language": {
11270 * "thousands": "'"
11271 * }
11272 * } );
11273 * } );
11274 */
11275 "sThousands": ",",
11276
11277
11278 /**
11279 * Detail the action that will be taken when the drop down menu for the
11280 * pagination length option is changed. The '_MENU_' variable is replaced
11281 * with a default select list of 10, 25, 50 and 100, and can be replaced
11282 * with a custom select box if required.
11283 * @type string
11284 * @default Show _MENU_ entries
11285 *
11286 * @dtopt Language
11287 * @name DataTable.defaults.language.lengthMenu
11288 *
11289 * @example
11290 * // Language change only
11291 * $(document).ready( function() {
11292 * $('#example').dataTable( {
11293 * "language": {
11294 * "lengthMenu": "Display _MENU_ records"
11295 * }
11296 * } );
11297 * } );
11298 *
11299 * @example
11300 * // Language and options change
11301 * $(document).ready( function() {
11302 * $('#example').dataTable( {
11303 * "language": {
11304 * "lengthMenu": 'Display <select>'+
11305 * '<option value="10">10</option>'+
11306 * '<option value="20">20</option>'+
11307 * '<option value="30">30</option>'+
11308 * '<option value="40">40</option>'+
11309 * '<option value="50">50</option>'+
11310 * '<option value="-1">All</option>'+
11311 * '</select> records'
11312 * }
11313 * } );
11314 * } );
11315 */
11316 "sLengthMenu": "Show _MENU_ entries",
11317
11318
11319 /**
11320 * When using Ajax sourced data and during the first draw when DataTables is
11321 * gathering the data, this message is shown in an empty row in the table to
11322 * indicate to the end user the the data is being loaded. Note that this
11323 * parameter is not used when loading data by server-side processing, just
11324 * Ajax sourced data with client-side processing.
11325 * @type string
11326 * @default Loading...
11327 *
11328 * @dtopt Language
11329 * @name DataTable.defaults.language.loadingRecords
11330 *
11331 * @example
11332 * $(document).ready( function() {
11333 * $('#example').dataTable( {
11334 * "language": {
11335 * "loadingRecords": "Please wait - loading..."
11336 * }
11337 * } );
11338 * } );
11339 */
11340 "sLoadingRecords": "Loading...",
11341
11342
11343 /**
11344 * Text which is displayed when the table is processing a user action
11345 * (usually a sort command or similar).
11346 * @type string
11347 * @default Processing...
11348 *
11349 * @dtopt Language
11350 * @name DataTable.defaults.language.processing
11351 *
11352 * @example
11353 * $(document).ready( function() {
11354 * $('#example').dataTable( {
11355 * "language": {
11356 * "processing": "DataTables is currently busy"
11357 * }
11358 * } );
11359 * } );
11360 */
11361 "sProcessing": "Processing...",
11362
11363
11364 /**
11365 * Details the actions that will be taken when the user types into the
11366 * filtering input text box. The variable "_INPUT_", if used in the string,
11367 * is replaced with the HTML text box for the filtering input allowing
11368 * control over where it appears in the string. If "_INPUT_" is not given
11369 * then the input box is appended to the string automatically.
11370 * @type string
11371 * @default Search:
11372 *
11373 * @dtopt Language
11374 * @name DataTable.defaults.language.search
11375 *
11376 * @example
11377 * // Input text box will be appended at the end automatically
11378 * $(document).ready( function() {
11379 * $('#example').dataTable( {
11380 * "language": {
11381 * "search": "Filter records:"
11382 * }
11383 * } );
11384 * } );
11385 *
11386 * @example
11387 * // Specify where the filter should appear
11388 * $(document).ready( function() {
11389 * $('#example').dataTable( {
11390 * "language": {
11391 * "search": "Apply filter _INPUT_ to table"
11392 * }
11393 * } );
11394 * } );
11395 */
11396 "sSearch": "Search:",
11397
11398
11399 /**
11400 * Assign a `placeholder` attribute to the search `input` element
11401 * @type string
11402 * @default
11403 *
11404 * @dtopt Language
11405 * @name DataTable.defaults.language.searchPlaceholder
11406 */
11407 "sSearchPlaceholder": "",
11408
11409
11410 /**
11411 * All of the language information can be stored in a file on the
11412 * server-side, which DataTables will look up if this parameter is passed.
11413 * It must store the URL of the language file, which is in a JSON format,
11414 * and the object has the same properties as the oLanguage object in the
11415 * initialiser object (i.e. the above parameters). Please refer to one of
11416 * the example language files to see how this works in action.
11417 * @type string
11418 * @default <i>Empty string - i.e. disabled</i>
11419 *
11420 * @dtopt Language
11421 * @name DataTable.defaults.language.url
11422 *
11423 * @example
11424 * $(document).ready( function() {
11425 * $('#example').dataTable( {
11426 * "language": {
11427 * "url": "http://www.sprymedia.co.uk/dataTables/lang.txt"
11428 * }
11429 * } );
11430 * } );
11431 */
11432 "sUrl": "",
11433
11434
11435 /**
11436 * Text shown inside the table records when the is no information to be
11437 * displayed after filtering. `emptyTable` is shown when there is simply no
11438 * information in the table at all (regardless of filtering).
11439 * @type string
11440 * @default No matching records found
11441 *
11442 * @dtopt Language
11443 * @name DataTable.defaults.language.zeroRecords
11444 *
11445 * @example
11446 * $(document).ready( function() {
11447 * $('#example').dataTable( {
11448 * "language": {
11449 * "zeroRecords": "No records to display"
11450 * }
11451 * } );
11452 * } );
11453 */
11454 "sZeroRecords": "No matching records found"
11455 },
11456
11457
11458 /**
11459 * This parameter allows you to have define the global filtering state at
11460 * initialisation time. As an object the `search` parameter must be
11461 * defined, but all other parameters are optional. When `regex` is true,
11462 * the search string will be treated as a regular expression, when false
11463 * (default) it will be treated as a straight string. When `smart`
11464 * DataTables will use it's smart filtering methods (to word match at
11465 * any point in the data), when false this will not be done.
11466 * @namespace
11467 * @extends DataTable.models.oSearch
11468 *
11469 * @dtopt Options
11470 * @name DataTable.defaults.search
11471 *
11472 * @example
11473 * $(document).ready( function() {
11474 * $('#example').dataTable( {
11475 * "search": {"search": "Initial search"}
11476 * } );
11477 * } )
11478 */
11479 "oSearch": $.extend( {}, DataTable.models.oSearch ),
11480
11481
11482 /**
11483 * __Deprecated__ The functionality provided by this parameter has now been
11484 * superseded by that provided through `ajax`, which should be used instead.
11485 *
11486 * By default DataTables will look for the property `data` (or `aaData` for
11487 * compatibility with DataTables 1.9-) when obtaining data from an Ajax
11488 * source or for server-side processing - this parameter allows that
11489 * property to be changed. You can use Javascript dotted object notation to
11490 * get a data source for multiple levels of nesting.
11491 * @type string
11492 * @default data
11493 *
11494 * @dtopt Options
11495 * @dtopt Server-side
11496 * @name DataTable.defaults.ajaxDataProp
11497 *
11498 * @deprecated 1.10. Please use `ajax` for this functionality now.
11499 */
11500 "sAjaxDataProp": "data",
11501
11502
11503 /**
11504 * __Deprecated__ The functionality provided by this parameter has now been
11505 * superseded by that provided through `ajax`, which should be used instead.
11506 *
11507 * You can instruct DataTables to load data from an external
11508 * source using this parameter (use aData if you want to pass data in you
11509 * already have). Simply provide a url a JSON object can be obtained from.
11510 * @type string
11511 * @default null
11512 *
11513 * @dtopt Options
11514 * @dtopt Server-side
11515 * @name DataTable.defaults.ajaxSource
11516 *
11517 * @deprecated 1.10. Please use `ajax` for this functionality now.
11518 */
11519 "sAjaxSource": null,
11520
11521
11522 /**
11523 * This initialisation variable allows you to specify exactly where in the
11524 * DOM you want DataTables to inject the various controls it adds to the page
11525 * (for example you might want the pagination controls at the top of the
11526 * table). DIV elements (with or without a custom class) can also be added to
11527 * aid styling. The follow syntax is used:
11528 * <ul>
11529 * <li>The following options are allowed:
11530 * <ul>
11531 * <li>'l' - Length changing</li>
11532 * <li>'f' - Filtering input</li>
11533 * <li>'t' - The table!</li>
11534 * <li>'i' - Information</li>
11535 * <li>'p' - Pagination</li>
11536 * <li>'r' - pRocessing</li>
11537 * </ul>
11538 * </li>
11539 * <li>The following constants are allowed:
11540 * <ul>
11541 * <li>'H' - jQueryUI theme "header" classes ('fg-toolbar ui-widget-header ui-corner-tl ui-corner-tr ui-helper-clearfix')</li>
11542 * <li>'F' - jQueryUI theme "footer" classes ('fg-toolbar ui-widget-header ui-corner-bl ui-corner-br ui-helper-clearfix')</li>
11543 * </ul>
11544 * </li>
11545 * <li>The following syntax is expected:
11546 * <ul>
11547 * <li>'&lt;' and '&gt;' - div elements</li>
11548 * <li>'&lt;"class" and '&gt;' - div with a class</li>
11549 * <li>'&lt;"#id" and '&gt;' - div with an ID</li>
11550 * </ul>
11551 * </li>
11552 * <li>Examples:
11553 * <ul>
11554 * <li>'&lt;"wrapper"flipt&gt;'</li>
11555 * <li>'&lt;lf&lt;t&gt;ip&gt;'</li>
11556 * </ul>
11557 * </li>
11558 * </ul>
11559 * @type string
11560 * @default lfrtip <i>(when `jQueryUI` is false)</i> <b>or</b>
11561 * <"H"lfr>t<"F"ip> <i>(when `jQueryUI` is true)</i>
11562 *
11563 * @dtopt Options
11564 * @name DataTable.defaults.dom
11565 *
11566 * @example
11567 * $(document).ready( function() {
11568 * $('#example').dataTable( {
11569 * "dom": '&lt;"top"i&gt;rt&lt;"bottom"flp&gt;&lt;"clear"&gt;'
11570 * } );
11571 * } );
11572 */
11573 "sDom": "lfrtip",
11574
11575
11576 /**
11577 * Search delay option. This will throttle full table searches that use the
11578 * DataTables provided search input element (it does not effect calls to
11579 * `dt-api search()`, providing a delay before the search is made.
11580 * @type integer
11581 * @default 0
11582 *
11583 * @dtopt Options
11584 * @name DataTable.defaults.searchDelay
11585 *
11586 * @example
11587 * $(document).ready( function() {
11588 * $('#example').dataTable( {
11589 * "searchDelay": 200
11590 * } );
11591 * } )
11592 */
11593 "searchDelay": null,
11594
11595
11596 /**
11597 * DataTables features four different built-in options for the buttons to
11598 * display for pagination control:
11599 *
11600 * * `simple` - 'Previous' and 'Next' buttons only
11601 * * 'simple_numbers` - 'Previous' and 'Next' buttons, plus page numbers
11602 * * `full` - 'First', 'Previous', 'Next' and 'Last' buttons
11603 * * `full_numbers` - 'First', 'Previous', 'Next' and 'Last' buttons, plus
11604 * page numbers
11605 *
11606 * Further methods can be added using {@link DataTable.ext.oPagination}.
11607 * @type string
11608 * @default simple_numbers
11609 *
11610 * @dtopt Options
11611 * @name DataTable.defaults.pagingType
11612 *
11613 * @example
11614 * $(document).ready( function() {
11615 * $('#example').dataTable( {
11616 * "pagingType": "full_numbers"
11617 * } );
11618 * } )
11619 */
11620 "sPaginationType": "simple_numbers",
11621
11622
11623 /**
11624 * Enable horizontal scrolling. When a table is too wide to fit into a
11625 * certain layout, or you have a large number of columns in the table, you
11626 * can enable x-scrolling to show the table in a viewport, which can be
11627 * scrolled. This property can be `true` which will allow the table to
11628 * scroll horizontally when needed, or any CSS unit, or a number (in which
11629 * case it will be treated as a pixel measurement). Setting as simply `true`
11630 * is recommended.
11631 * @type boolean|string
11632 * @default <i>blank string - i.e. disabled</i>
11633 *
11634 * @dtopt Features
11635 * @name DataTable.defaults.scrollX
11636 *
11637 * @example
11638 * $(document).ready( function() {
11639 * $('#example').dataTable( {
11640 * "scrollX": true,
11641 * "scrollCollapse": true
11642 * } );
11643 * } );
11644 */
11645 "sScrollX": "",
11646
11647
11648 /**
11649 * This property can be used to force a DataTable to use more width than it
11650 * might otherwise do when x-scrolling is enabled. For example if you have a
11651 * table which requires to be well spaced, this parameter is useful for
11652 * "over-sizing" the table, and thus forcing scrolling. This property can by
11653 * any CSS unit, or a number (in which case it will be treated as a pixel
11654 * measurement).
11655 * @type string
11656 * @default <i>blank string - i.e. disabled</i>
11657 *
11658 * @dtopt Options
11659 * @name DataTable.defaults.scrollXInner
11660 *
11661 * @example
11662 * $(document).ready( function() {
11663 * $('#example').dataTable( {
11664 * "scrollX": "100%",
11665 * "scrollXInner": "110%"
11666 * } );
11667 * } );
11668 */
11669 "sScrollXInner": "",
11670
11671
11672 /**
11673 * Enable vertical scrolling. Vertical scrolling will constrain the DataTable
11674 * to the given height, and enable scrolling for any data which overflows the
11675 * current viewport. This can be used as an alternative to paging to display
11676 * a lot of data in a small area (although paging and scrolling can both be
11677 * enabled at the same time). This property can be any CSS unit, or a number
11678 * (in which case it will be treated as a pixel measurement).
11679 * @type string
11680 * @default <i>blank string - i.e. disabled</i>
11681 *
11682 * @dtopt Features
11683 * @name DataTable.defaults.scrollY
11684 *
11685 * @example
11686 * $(document).ready( function() {
11687 * $('#example').dataTable( {
11688 * "scrollY": "200px",
11689 * "paginate": false
11690 * } );
11691 * } );
11692 */
11693 "sScrollY": "",
11694
11695
11696 /**
11697 * __Deprecated__ The functionality provided by this parameter has now been
11698 * superseded by that provided through `ajax`, which should be used instead.
11699 *
11700 * Set the HTTP method that is used to make the Ajax call for server-side
11701 * processing or Ajax sourced data.
11702 * @type string
11703 * @default GET
11704 *
11705 * @dtopt Options
11706 * @dtopt Server-side
11707 * @name DataTable.defaults.serverMethod
11708 *
11709 * @deprecated 1.10. Please use `ajax` for this functionality now.
11710 */
11711 "sServerMethod": "GET",
11712
11713
11714 /**
11715 * DataTables makes use of renderers when displaying HTML elements for
11716 * a table. These renderers can be added or modified by plug-ins to
11717 * generate suitable mark-up for a site. For example the Bootstrap
11718 * integration plug-in for DataTables uses a paging button renderer to
11719 * display pagination buttons in the mark-up required by Bootstrap.
11720 *
11721 * For further information about the renderers available see
11722 * DataTable.ext.renderer
11723 * @type string|object
11724 * @default null
11725 *
11726 * @name DataTable.defaults.renderer
11727 *
11728 */
11729 "renderer": null
11730 };
11731
11732 _fnHungarianMap( DataTable.defaults );
11733
11734
11735
11736 /*
11737 * Developer note - See note in model.defaults.js about the use of Hungarian
11738 * notation and camel case.
11739 */
11740
11741 /**
11742 * Column options that can be given to DataTables at initialisation time.
11743 * @namespace
11744 */
11745 DataTable.defaults.column = {
11746 /**
11747 * Define which column(s) an order will occur on for this column. This
11748 * allows a column's ordering to take multiple columns into account when
11749 * doing a sort or use the data from a different column. For example first
11750 * name / last name columns make sense to do a multi-column sort over the
11751 * two columns.
11752 * @type array|int
11753 * @default null <i>Takes the value of the column index automatically</i>
11754 *
11755 * @name DataTable.defaults.column.orderData
11756 * @dtopt Columns
11757 *
11758 * @example
11759 * // Using `columnDefs`
11760 * $(document).ready( function() {
11761 * $('#example').dataTable( {
11762 * "columnDefs": [
11763 * { "orderData": [ 0, 1 ], "targets": [ 0 ] },
11764 * { "orderData": [ 1, 0 ], "targets": [ 1 ] },
11765 * { "orderData": 2, "targets": [ 2 ] }
11766 * ]
11767 * } );
11768 * } );
11769 *
11770 * @example
11771 * // Using `columns`
11772 * $(document).ready( function() {
11773 * $('#example').dataTable( {
11774 * "columns": [
11775 * { "orderData": [ 0, 1 ] },
11776 * { "orderData": [ 1, 0 ] },
11777 * { "orderData": 2 },
11778 * null,
11779 * null
11780 * ]
11781 * } );
11782 * } );
11783 */
11784 "aDataSort": null,
11785 "iDataSort": -1,
11786
11787
11788 /**
11789 * You can control the default ordering direction, and even alter the
11790 * behaviour of the sort handler (i.e. only allow ascending ordering etc)
11791 * using this parameter.
11792 * @type array
11793 * @default [ 'asc', 'desc' ]
11794 *
11795 * @name DataTable.defaults.column.orderSequence
11796 * @dtopt Columns
11797 *
11798 * @example
11799 * // Using `columnDefs`
11800 * $(document).ready( function() {
11801 * $('#example').dataTable( {
11802 * "columnDefs": [
11803 * { "orderSequence": [ "asc" ], "targets": [ 1 ] },
11804 * { "orderSequence": [ "desc", "asc", "asc" ], "targets": [ 2 ] },
11805 * { "orderSequence": [ "desc" ], "targets": [ 3 ] }
11806 * ]
11807 * } );
11808 * } );
11809 *
11810 * @example
11811 * // Using `columns`
11812 * $(document).ready( function() {
11813 * $('#example').dataTable( {
11814 * "columns": [
11815 * null,
11816 * { "orderSequence": [ "asc" ] },
11817 * { "orderSequence": [ "desc", "asc", "asc" ] },
11818 * { "orderSequence": [ "desc" ] },
11819 * null
11820 * ]
11821 * } );
11822 * } );
11823 */
11824 "asSorting": [ 'asc', 'desc' ],
11825
11826
11827 /**
11828 * Enable or disable filtering on the data in this column.
11829 * @type boolean
11830 * @default true
11831 *
11832 * @name DataTable.defaults.column.searchable
11833 * @dtopt Columns
11834 *
11835 * @example
11836 * // Using `columnDefs`
11837 * $(document).ready( function() {
11838 * $('#example').dataTable( {
11839 * "columnDefs": [
11840 * { "searchable": false, "targets": [ 0 ] }
11841 * ] } );
11842 * } );
11843 *
11844 * @example
11845 * // Using `columns`
11846 * $(document).ready( function() {
11847 * $('#example').dataTable( {
11848 * "columns": [
11849 * { "searchable": false },
11850 * null,
11851 * null,
11852 * null,
11853 * null
11854 * ] } );
11855 * } );
11856 */
11857 "bSearchable": true,
11858
11859
11860 /**
11861 * Enable or disable ordering on this column.
11862 * @type boolean
11863 * @default true
11864 *
11865 * @name DataTable.defaults.column.orderable
11866 * @dtopt Columns
11867 *
11868 * @example
11869 * // Using `columnDefs`
11870 * $(document).ready( function() {
11871 * $('#example').dataTable( {
11872 * "columnDefs": [
11873 * { "orderable": false, "targets": [ 0 ] }
11874 * ] } );
11875 * } );
11876 *
11877 * @example
11878 * // Using `columns`
11879 * $(document).ready( function() {
11880 * $('#example').dataTable( {
11881 * "columns": [
11882 * { "orderable": false },
11883 * null,
11884 * null,
11885 * null,
11886 * null
11887 * ] } );
11888 * } );
11889 */
11890 "bSortable": true,
11891
11892
11893 /**
11894 * Enable or disable the display of this column.
11895 * @type boolean
11896 * @default true
11897 *
11898 * @name DataTable.defaults.column.visible
11899 * @dtopt Columns
11900 *
11901 * @example
11902 * // Using `columnDefs`
11903 * $(document).ready( function() {
11904 * $('#example').dataTable( {
11905 * "columnDefs": [
11906 * { "visible": false, "targets": [ 0 ] }
11907 * ] } );
11908 * } );
11909 *
11910 * @example
11911 * // Using `columns`
11912 * $(document).ready( function() {
11913 * $('#example').dataTable( {
11914 * "columns": [
11915 * { "visible": false },
11916 * null,
11917 * null,
11918 * null,
11919 * null
11920 * ] } );
11921 * } );
11922 */
11923 "bVisible": true,
11924
11925
11926 /**
11927 * Developer definable function that is called whenever a cell is created (Ajax source,
11928 * etc) or processed for input (DOM source). This can be used as a compliment to mRender
11929 * allowing you to modify the DOM element (add background colour for example) when the
11930 * element is available.
11931 * @type function
11932 * @param {element} td The TD node that has been created
11933 * @param {*} cellData The Data for the cell
11934 * @param {array|object} rowData The data for the whole row
11935 * @param {int} row The row index for the aoData data store
11936 * @param {int} col The column index for aoColumns
11937 *
11938 * @name DataTable.defaults.column.createdCell
11939 * @dtopt Columns
11940 *
11941 * @example
11942 * $(document).ready( function() {
11943 * $('#example').dataTable( {
11944 * "columnDefs": [ {
11945 * "targets": [3],
11946 * "createdCell": function (td, cellData, rowData, row, col) {
11947 * if ( cellData == "1.7" ) {
11948 * $(td).css('color', 'blue')
11949 * }
11950 * }
11951 * } ]
11952 * });
11953 * } );
11954 */
11955 "fnCreatedCell": null,
11956
11957
11958 /**
11959 * This parameter has been replaced by `data` in DataTables to ensure naming
11960 * consistency. `dataProp` can still be used, as there is backwards
11961 * compatibility in DataTables for this option, but it is strongly
11962 * recommended that you use `data` in preference to `dataProp`.
11963 * @name DataTable.defaults.column.dataProp
11964 */
11965
11966
11967 /**
11968 * This property can be used to read data from any data source property,
11969 * including deeply nested objects / properties. `data` can be given in a
11970 * number of different ways which effect its behaviour:
11971 *
11972 * * `integer` - treated as an array index for the data source. This is the
11973 * default that DataTables uses (incrementally increased for each column).
11974 * * `string` - read an object property from the data source. There are
11975 * three 'special' options that can be used in the string to alter how
11976 * DataTables reads the data from the source object:
11977 * * `.` - Dotted Javascript notation. Just as you use a `.` in
11978 * Javascript to read from nested objects, so to can the options
11979 * specified in `data`. For example: `browser.version` or
11980 * `browser.name`. If your object parameter name contains a period, use
11981 * `\\` to escape it - i.e. `first\\.name`.
11982 * * `[]` - Array notation. DataTables can automatically combine data
11983 * from and array source, joining the data with the characters provided
11984 * between the two brackets. For example: `name[, ]` would provide a
11985 * comma-space separated list from the source array. If no characters
11986 * are provided between the brackets, the original array source is
11987 * returned.
11988 * * `()` - Function notation. Adding `()` to the end of a parameter will
11989 * execute a function of the name given. For example: `browser()` for a
11990 * simple function on the data source, `browser.version()` for a
11991 * function in a nested property or even `browser().version` to get an
11992 * object property if the function called returns an object. Note that
11993 * function notation is recommended for use in `render` rather than
11994 * `data` as it is much simpler to use as a renderer.
11995 * * `null` - use the original data source for the row rather than plucking
11996 * data directly from it. This action has effects on two other
11997 * initialisation options:
11998 * * `defaultContent` - When null is given as the `data` option and
11999 * `defaultContent` is specified for the column, the value defined by
12000 * `defaultContent` will be used for the cell.
12001 * * `render` - When null is used for the `data` option and the `render`
12002 * option is specified for the column, the whole data source for the
12003 * row is used for the renderer.
12004 * * `function` - the function given will be executed whenever DataTables
12005 * needs to set or get the data for a cell in the column. The function
12006 * takes three parameters:
12007 * * Parameters:
12008 * * `{array|object}` The data source for the row
12009 * * `{string}` The type call data requested - this will be 'set' when
12010 * setting data or 'filter', 'display', 'type', 'sort' or undefined
12011 * when gathering data. Note that when `undefined` is given for the
12012 * type DataTables expects to get the raw data for the object back<
12013 * * `{*}` Data to set when the second parameter is 'set'.
12014 * * Return:
12015 * * The return value from the function is not required when 'set' is
12016 * the type of call, but otherwise the return is what will be used
12017 * for the data requested.
12018 *
12019 * Note that `data` is a getter and setter option. If you just require
12020 * formatting of data for output, you will likely want to use `render` which
12021 * is simply a getter and thus simpler to use.
12022 *
12023 * Note that prior to DataTables 1.9.2 `data` was called `mDataProp`. The
12024 * name change reflects the flexibility of this property and is consistent
12025 * with the naming of mRender. If 'mDataProp' is given, then it will still
12026 * be used by DataTables, as it automatically maps the old name to the new
12027 * if required.
12028 *
12029 * @type string|int|function|null
12030 * @default null <i>Use automatically calculated column index</i>
12031 *
12032 * @name DataTable.defaults.column.data
12033 * @dtopt Columns
12034 *
12035 * @example
12036 * // Read table data from objects
12037 * // JSON structure for each row:
12038 * // {
12039 * // "engine": {value},
12040 * // "browser": {value},
12041 * // "platform": {value},
12042 * // "version": {value},
12043 * // "grade": {value}
12044 * // }
12045 * $(document).ready( function() {
12046 * $('#example').dataTable( {
12047 * "ajaxSource": "sources/objects.txt",
12048 * "columns": [
12049 * { "data": "engine" },
12050 * { "data": "browser" },
12051 * { "data": "platform" },
12052 * { "data": "version" },
12053 * { "data": "grade" }
12054 * ]
12055 * } );
12056 * } );
12057 *
12058 * @example
12059 * // Read information from deeply nested objects
12060 * // JSON structure for each row:
12061 * // {
12062 * // "engine": {value},
12063 * // "browser": {value},
12064 * // "platform": {
12065 * // "inner": {value}
12066 * // },
12067 * // "details": [
12068 * // {value}, {value}
12069 * // ]
12070 * // }
12071 * $(document).ready( function() {
12072 * $('#example').dataTable( {
12073 * "ajaxSource": "sources/deep.txt",
12074 * "columns": [
12075 * { "data": "engine" },
12076 * { "data": "browser" },
12077 * { "data": "platform.inner" },
12078 * { "data": "platform.details.0" },
12079 * { "data": "platform.details.1" }
12080 * ]
12081 * } );
12082 * } );
12083 *
12084 * @example
12085 * // Using `data` as a function to provide different information for
12086 * // sorting, filtering and display. In this case, currency (price)
12087 * $(document).ready( function() {
12088 * $('#example').dataTable( {
12089 * "columnDefs": [ {
12090 * "targets": [ 0 ],
12091 * "data": function ( source, type, val ) {
12092 * if (type === 'set') {
12093 * source.price = val;
12094 * // Store the computed dislay and filter values for efficiency
12095 * source.price_display = val=="" ? "" : "$"+numberFormat(val);
12096 * source.price_filter = val=="" ? "" : "$"+numberFormat(val)+" "+val;
12097 * return;
12098 * }
12099 * else if (type === 'display') {
12100 * return source.price_display;
12101 * }
12102 * else if (type === 'filter') {
12103 * return source.price_filter;
12104 * }
12105 * // 'sort', 'type' and undefined all just use the integer
12106 * return source.price;
12107 * }
12108 * } ]
12109 * } );
12110 * } );
12111 *
12112 * @example
12113 * // Using default content
12114 * $(document).ready( function() {
12115 * $('#example').dataTable( {
12116 * "columnDefs": [ {
12117 * "targets": [ 0 ],
12118 * "data": null,
12119 * "defaultContent": "Click to edit"
12120 * } ]
12121 * } );
12122 * } );
12123 *
12124 * @example
12125 * // Using array notation - outputting a list from an array
12126 * $(document).ready( function() {
12127 * $('#example').dataTable( {
12128 * "columnDefs": [ {
12129 * "targets": [ 0 ],
12130 * "data": "name[, ]"
12131 * } ]
12132 * } );
12133 * } );
12134 *
12135 */
12136 "mData": null,
12137
12138
12139 /**
12140 * This property is the rendering partner to `data` and it is suggested that
12141 * when you want to manipulate data for display (including filtering,
12142 * sorting etc) without altering the underlying data for the table, use this
12143 * property. `render` can be considered to be the the read only companion to
12144 * `data` which is read / write (then as such more complex). Like `data`
12145 * this option can be given in a number of different ways to effect its
12146 * behaviour:
12147 *
12148 * * `integer` - treated as an array index for the data source. This is the
12149 * default that DataTables uses (incrementally increased for each column).
12150 * * `string` - read an object property from the data source. There are
12151 * three 'special' options that can be used in the string to alter how
12152 * DataTables reads the data from the source object:
12153 * * `.` - Dotted Javascript notation. Just as you use a `.` in
12154 * Javascript to read from nested objects, so to can the options
12155 * specified in `data`. For example: `browser.version` or
12156 * `browser.name`. If your object parameter name contains a period, use
12157 * `\\` to escape it - i.e. `first\\.name`.
12158 * * `[]` - Array notation. DataTables can automatically combine data
12159 * from and array source, joining the data with the characters provided
12160 * between the two brackets. For example: `name[, ]` would provide a
12161 * comma-space separated list from the source array. If no characters
12162 * are provided between the brackets, the original array source is
12163 * returned.
12164 * * `()` - Function notation. Adding `()` to the end of a parameter will
12165 * execute a function of the name given. For example: `browser()` for a
12166 * simple function on the data source, `browser.version()` for a
12167 * function in a nested property or even `browser().version` to get an
12168 * object property if the function called returns an object.
12169 * * `object` - use different data for the different data types requested by
12170 * DataTables ('filter', 'display', 'type' or 'sort'). The property names
12171 * of the object is the data type the property refers to and the value can
12172 * defined using an integer, string or function using the same rules as
12173 * `render` normally does. Note that an `_` option _must_ be specified.
12174 * This is the default value to use if you haven't specified a value for
12175 * the data type requested by DataTables.
12176 * * `function` - the function given will be executed whenever DataTables
12177 * needs to set or get the data for a cell in the column. The function
12178 * takes three parameters:
12179 * * Parameters:
12180 * * {array|object} The data source for the row (based on `data`)
12181 * * {string} The type call data requested - this will be 'filter',
12182 * 'display', 'type' or 'sort'.
12183 * * {array|object} The full data source for the row (not based on
12184 * `data`)
12185 * * Return:
12186 * * The return value from the function is what will be used for the
12187 * data requested.
12188 *
12189 * @type string|int|function|object|null
12190 * @default null Use the data source value.
12191 *
12192 * @name DataTable.defaults.column.render
12193 * @dtopt Columns
12194 *
12195 * @example
12196 * // Create a comma separated list from an array of objects
12197 * $(document).ready( function() {
12198 * $('#example').dataTable( {
12199 * "ajaxSource": "sources/deep.txt",
12200 * "columns": [
12201 * { "data": "engine" },
12202 * { "data": "browser" },
12203 * {
12204 * "data": "platform",
12205 * "render": "[, ].name"
12206 * }
12207 * ]
12208 * } );
12209 * } );
12210 *
12211 * @example
12212 * // Execute a function to obtain data
12213 * $(document).ready( function() {
12214 * $('#example').dataTable( {
12215 * "columnDefs": [ {
12216 * "targets": [ 0 ],
12217 * "data": null, // Use the full data source object for the renderer's source
12218 * "render": "browserName()"
12219 * } ]
12220 * } );
12221 * } );
12222 *
12223 * @example
12224 * // As an object, extracting different data for the different types
12225 * // This would be used with a data source such as:
12226 * // { "phone": 5552368, "phone_filter": "5552368 555-2368", "phone_display": "555-2368" }
12227 * // Here the `phone` integer is used for sorting and type detection, while `phone_filter`
12228 * // (which has both forms) is used for filtering for if a user inputs either format, while
12229 * // the formatted phone number is the one that is shown in the table.
12230 * $(document).ready( function() {
12231 * $('#example').dataTable( {
12232 * "columnDefs": [ {
12233 * "targets": [ 0 ],
12234 * "data": null, // Use the full data source object for the renderer's source
12235 * "render": {
12236 * "_": "phone",
12237 * "filter": "phone_filter",
12238 * "display": "phone_display"
12239 * }
12240 * } ]
12241 * } );
12242 * } );
12243 *
12244 * @example
12245 * // Use as a function to create a link from the data source
12246 * $(document).ready( function() {
12247 * $('#example').dataTable( {
12248 * "columnDefs": [ {
12249 * "targets": [ 0 ],
12250 * "data": "download_link",
12251 * "render": function ( data, type, full ) {
12252 * return '<a href="'+data+'">Download</a>';
12253 * }
12254 * } ]
12255 * } );
12256 * } );
12257 */
12258 "mRender": null,
12259
12260
12261 /**
12262 * Change the cell type created for the column - either TD cells or TH cells. This
12263 * can be useful as TH cells have semantic meaning in the table body, allowing them
12264 * to act as a header for a row (you may wish to add scope='row' to the TH elements).
12265 * @type string
12266 * @default td
12267 *
12268 * @name DataTable.defaults.column.cellType
12269 * @dtopt Columns
12270 *
12271 * @example
12272 * // Make the first column use TH cells
12273 * $(document).ready( function() {
12274 * $('#example').dataTable( {
12275 * "columnDefs": [ {
12276 * "targets": [ 0 ],
12277 * "cellType": "th"
12278 * } ]
12279 * } );
12280 * } );
12281 */
12282 "sCellType": "td",
12283
12284
12285 /**
12286 * Class to give to each cell in this column.
12287 * @type string
12288 * @default <i>Empty string</i>
12289 *
12290 * @name DataTable.defaults.column.class
12291 * @dtopt Columns
12292 *
12293 * @example
12294 * // Using `columnDefs`
12295 * $(document).ready( function() {
12296 * $('#example').dataTable( {
12297 * "columnDefs": [
12298 * { "class": "my_class", "targets": [ 0 ] }
12299 * ]
12300 * } );
12301 * } );
12302 *
12303 * @example
12304 * // Using `columns`
12305 * $(document).ready( function() {
12306 * $('#example').dataTable( {
12307 * "columns": [
12308 * { "class": "my_class" },
12309 * null,
12310 * null,
12311 * null,
12312 * null
12313 * ]
12314 * } );
12315 * } );
12316 */
12317 "sClass": "",
12318
12319 /**
12320 * When DataTables calculates the column widths to assign to each column,
12321 * it finds the longest string in each column and then constructs a
12322 * temporary table and reads the widths from that. The problem with this
12323 * is that "mmm" is much wider then "iiii", but the latter is a longer
12324 * string - thus the calculation can go wrong (doing it properly and putting
12325 * it into an DOM object and measuring that is horribly(!) slow). Thus as
12326 * a "work around" we provide this option. It will append its value to the
12327 * text that is found to be the longest string for the column - i.e. padding.
12328 * Generally you shouldn't need this!
12329 * @type string
12330 * @default <i>Empty string<i>
12331 *
12332 * @name DataTable.defaults.column.contentPadding
12333 * @dtopt Columns
12334 *
12335 * @example
12336 * // Using `columns`
12337 * $(document).ready( function() {
12338 * $('#example').dataTable( {
12339 * "columns": [
12340 * null,
12341 * null,
12342 * null,
12343 * {
12344 * "contentPadding": "mmm"
12345 * }
12346 * ]
12347 * } );
12348 * } );
12349 */
12350 "sContentPadding": "",
12351
12352
12353 /**
12354 * Allows a default value to be given for a column's data, and will be used
12355 * whenever a null data source is encountered (this can be because `data`
12356 * is set to null, or because the data source itself is null).
12357 * @type string
12358 * @default null
12359 *
12360 * @name DataTable.defaults.column.defaultContent
12361 * @dtopt Columns
12362 *
12363 * @example
12364 * // Using `columnDefs`
12365 * $(document).ready( function() {
12366 * $('#example').dataTable( {
12367 * "columnDefs": [
12368 * {
12369 * "data": null,
12370 * "defaultContent": "Edit",
12371 * "targets": [ -1 ]
12372 * }
12373 * ]
12374 * } );
12375 * } );
12376 *
12377 * @example
12378 * // Using `columns`
12379 * $(document).ready( function() {
12380 * $('#example').dataTable( {
12381 * "columns": [
12382 * null,
12383 * null,
12384 * null,
12385 * {
12386 * "data": null,
12387 * "defaultContent": "Edit"
12388 * }
12389 * ]
12390 * } );
12391 * } );
12392 */
12393 "sDefaultContent": null,
12394
12395
12396 /**
12397 * This parameter is only used in DataTables' server-side processing. It can
12398 * be exceptionally useful to know what columns are being displayed on the
12399 * client side, and to map these to database fields. When defined, the names
12400 * also allow DataTables to reorder information from the server if it comes
12401 * back in an unexpected order (i.e. if you switch your columns around on the
12402 * client-side, your server-side code does not also need updating).
12403 * @type string
12404 * @default <i>Empty string</i>
12405 *
12406 * @name DataTable.defaults.column.name
12407 * @dtopt Columns
12408 *
12409 * @example
12410 * // Using `columnDefs`
12411 * $(document).ready( function() {
12412 * $('#example').dataTable( {
12413 * "columnDefs": [
12414 * { "name": "engine", "targets": [ 0 ] },
12415 * { "name": "browser", "targets": [ 1 ] },
12416 * { "name": "platform", "targets": [ 2 ] },
12417 * { "name": "version", "targets": [ 3 ] },
12418 * { "name": "grade", "targets": [ 4 ] }
12419 * ]
12420 * } );
12421 * } );
12422 *
12423 * @example
12424 * // Using `columns`
12425 * $(document).ready( function() {
12426 * $('#example').dataTable( {
12427 * "columns": [
12428 * { "name": "engine" },
12429 * { "name": "browser" },
12430 * { "name": "platform" },
12431 * { "name": "version" },
12432 * { "name": "grade" }
12433 * ]
12434 * } );
12435 * } );
12436 */
12437 "sName": "",
12438
12439
12440 /**
12441 * Defines a data source type for the ordering which can be used to read
12442 * real-time information from the table (updating the internally cached
12443 * version) prior to ordering. This allows ordering to occur on user
12444 * editable elements such as form inputs.
12445 * @type string
12446 * @default std
12447 *
12448 * @name DataTable.defaults.column.orderDataType
12449 * @dtopt Columns
12450 *
12451 * @example
12452 * // Using `columnDefs`
12453 * $(document).ready( function() {
12454 * $('#example').dataTable( {
12455 * "columnDefs": [
12456 * { "orderDataType": "dom-text", "targets": [ 2, 3 ] },
12457 * { "type": "numeric", "targets": [ 3 ] },
12458 * { "orderDataType": "dom-select", "targets": [ 4 ] },
12459 * { "orderDataType": "dom-checkbox", "targets": [ 5 ] }
12460 * ]
12461 * } );
12462 * } );
12463 *
12464 * @example
12465 * // Using `columns`
12466 * $(document).ready( function() {
12467 * $('#example').dataTable( {
12468 * "columns": [
12469 * null,
12470 * null,
12471 * { "orderDataType": "dom-text" },
12472 * { "orderDataType": "dom-text", "type": "numeric" },
12473 * { "orderDataType": "dom-select" },
12474 * { "orderDataType": "dom-checkbox" }
12475 * ]
12476 * } );
12477 * } );
12478 */
12479 "sSortDataType": "std",
12480
12481
12482 /**
12483 * The title of this column.
12484 * @type string
12485 * @default null <i>Derived from the 'TH' value for this column in the
12486 * original HTML table.</i>
12487 *
12488 * @name DataTable.defaults.column.title
12489 * @dtopt Columns
12490 *
12491 * @example
12492 * // Using `columnDefs`
12493 * $(document).ready( function() {
12494 * $('#example').dataTable( {
12495 * "columnDefs": [
12496 * { "title": "My column title", "targets": [ 0 ] }
12497 * ]
12498 * } );
12499 * } );
12500 *
12501 * @example
12502 * // Using `columns`
12503 * $(document).ready( function() {
12504 * $('#example').dataTable( {
12505 * "columns": [
12506 * { "title": "My column title" },
12507 * null,
12508 * null,
12509 * null,
12510 * null
12511 * ]
12512 * } );
12513 * } );
12514 */
12515 "sTitle": null,
12516
12517
12518 /**
12519 * The type allows you to specify how the data for this column will be
12520 * ordered. Four types (string, numeric, date and html (which will strip
12521 * HTML tags before ordering)) are currently available. Note that only date
12522 * formats understood by Javascript's Date() object will be accepted as type
12523 * date. For example: "Mar 26, 2008 5:03 PM". May take the values: 'string',
12524 * 'numeric', 'date' or 'html' (by default). Further types can be adding
12525 * through plug-ins.
12526 * @type string
12527 * @default null <i>Auto-detected from raw data</i>
12528 *
12529 * @name DataTable.defaults.column.type
12530 * @dtopt Columns
12531 *
12532 * @example
12533 * // Using `columnDefs`
12534 * $(document).ready( function() {
12535 * $('#example').dataTable( {
12536 * "columnDefs": [
12537 * { "type": "html", "targets": [ 0 ] }
12538 * ]
12539 * } );
12540 * } );
12541 *
12542 * @example
12543 * // Using `columns`
12544 * $(document).ready( function() {
12545 * $('#example').dataTable( {
12546 * "columns": [
12547 * { "type": "html" },
12548 * null,
12549 * null,
12550 * null,
12551 * null
12552 * ]
12553 * } );
12554 * } );
12555 */
12556 "sType": null,
12557
12558
12559 /**
12560 * Defining the width of the column, this parameter may take any CSS value
12561 * (3em, 20px etc). DataTables applies 'smart' widths to columns which have not
12562 * been given a specific width through this interface ensuring that the table
12563 * remains readable.
12564 * @type string
12565 * @default null <i>Automatic</i>
12566 *
12567 * @name DataTable.defaults.column.width
12568 * @dtopt Columns
12569 *
12570 * @example
12571 * // Using `columnDefs`
12572 * $(document).ready( function() {
12573 * $('#example').dataTable( {
12574 * "columnDefs": [
12575 * { "width": "20%", "targets": [ 0 ] }
12576 * ]
12577 * } );
12578 * } );
12579 *
12580 * @example
12581 * // Using `columns`
12582 * $(document).ready( function() {
12583 * $('#example').dataTable( {
12584 * "columns": [
12585 * { "width": "20%" },
12586 * null,
12587 * null,
12588 * null,
12589 * null
12590 * ]
12591 * } );
12592 * } );
12593 */
12594 "sWidth": null
12595 };
12596
12597 _fnHungarianMap( DataTable.defaults.column );
12598
12599
12600
12601 /**
12602 * DataTables settings object - this holds all the information needed for a
12603 * given table, including configuration, data and current application of the
12604 * table options. DataTables does not have a single instance for each DataTable
12605 * with the settings attached to that instance, but rather instances of the
12606 * DataTable "class" are created on-the-fly as needed (typically by a
12607 * $().dataTable() call) and the settings object is then applied to that
12608 * instance.
12609 *
12610 * Note that this object is related to {@link DataTable.defaults} but this
12611 * one is the internal data store for DataTables's cache of columns. It should
12612 * NOT be manipulated outside of DataTables. Any configuration should be done
12613 * through the initialisation options.
12614 * @namespace
12615 * @todo Really should attach the settings object to individual instances so we
12616 * don't need to create new instances on each $().dataTable() call (if the
12617 * table already exists). It would also save passing oSettings around and
12618 * into every single function. However, this is a very significant
12619 * architecture change for DataTables and will almost certainly break
12620 * backwards compatibility with older installations. This is something that
12621 * will be done in 2.0.
12622 */
12623 DataTable.models.oSettings = {
12624 /**
12625 * Primary features of DataTables and their enablement state.
12626 * @namespace
12627 */
12628 "oFeatures": {
12629
12630 /**
12631 * Flag to say if DataTables should automatically try to calculate the
12632 * optimum table and columns widths (true) or not (false).
12633 * Note that this parameter will be set by the initialisation routine. To
12634 * set a default use {@link DataTable.defaults}.
12635 * @type boolean
12636 */
12637 "bAutoWidth": null,
12638
12639 /**
12640 * Delay the creation of TR and TD elements until they are actually
12641 * needed by a driven page draw. This can give a significant speed
12642 * increase for Ajax source and Javascript source data, but makes no
12643 * difference at all fro DOM and server-side processing tables.
12644 * Note that this parameter will be set by the initialisation routine. To
12645 * set a default use {@link DataTable.defaults}.
12646 * @type boolean
12647 */
12648 "bDeferRender": null,
12649
12650 /**
12651 * Enable filtering on the table or not. Note that if this is disabled
12652 * then there is no filtering at all on the table, including fnFilter.
12653 * To just remove the filtering input use sDom and remove the 'f' option.
12654 * Note that this parameter will be set by the initialisation routine. To
12655 * set a default use {@link DataTable.defaults}.
12656 * @type boolean
12657 */
12658 "bFilter": null,
12659
12660 /**
12661 * Table information element (the 'Showing x of y records' div) enable
12662 * flag.
12663 * Note that this parameter will be set by the initialisation routine. To
12664 * set a default use {@link DataTable.defaults}.
12665 * @type boolean
12666 */
12667 "bInfo": null,
12668
12669 /**
12670 * Present a user control allowing the end user to change the page size
12671 * when pagination is enabled.
12672 * Note that this parameter will be set by the initialisation routine. To
12673 * set a default use {@link DataTable.defaults}.
12674 * @type boolean
12675 */
12676 "bLengthChange": null,
12677
12678 /**
12679 * Pagination enabled or not. Note that if this is disabled then length
12680 * changing must also be disabled.
12681 * Note that this parameter will be set by the initialisation routine. To
12682 * set a default use {@link DataTable.defaults}.
12683 * @type boolean
12684 */
12685 "bPaginate": null,
12686
12687 /**
12688 * Processing indicator enable flag whenever DataTables is enacting a
12689 * user request - typically an Ajax request for server-side processing.
12690 * Note that this parameter will be set by the initialisation routine. To
12691 * set a default use {@link DataTable.defaults}.
12692 * @type boolean
12693 */
12694 "bProcessing": null,
12695
12696 /**
12697 * Server-side processing enabled flag - when enabled DataTables will
12698 * get all data from the server for every draw - there is no filtering,
12699 * sorting or paging done on the client-side.
12700 * Note that this parameter will be set by the initialisation routine. To
12701 * set a default use {@link DataTable.defaults}.
12702 * @type boolean
12703 */
12704 "bServerSide": null,
12705
12706 /**
12707 * Sorting enablement flag.
12708 * Note that this parameter will be set by the initialisation routine. To
12709 * set a default use {@link DataTable.defaults}.
12710 * @type boolean
12711 */
12712 "bSort": null,
12713
12714 /**
12715 * Multi-column sorting
12716 * Note that this parameter will be set by the initialisation routine. To
12717 * set a default use {@link DataTable.defaults}.
12718 * @type boolean
12719 */
12720 "bSortMulti": null,
12721
12722 /**
12723 * Apply a class to the columns which are being sorted to provide a
12724 * visual highlight or not. This can slow things down when enabled since
12725 * there is a lot of DOM interaction.
12726 * Note that this parameter will be set by the initialisation routine. To
12727 * set a default use {@link DataTable.defaults}.
12728 * @type boolean
12729 */
12730 "bSortClasses": null,
12731
12732 /**
12733 * State saving enablement flag.
12734 * Note that this parameter will be set by the initialisation routine. To
12735 * set a default use {@link DataTable.defaults}.
12736 * @type boolean
12737 */
12738 "bStateSave": null
12739 },
12740
12741
12742 /**
12743 * Scrolling settings for a table.
12744 * @namespace
12745 */
12746 "oScroll": {
12747 /**
12748 * When the table is shorter in height than sScrollY, collapse the
12749 * table container down to the height of the table (when true).
12750 * Note that this parameter will be set by the initialisation routine. To
12751 * set a default use {@link DataTable.defaults}.
12752 * @type boolean
12753 */
12754 "bCollapse": null,
12755
12756 /**
12757 * Width of the scrollbar for the web-browser's platform. Calculated
12758 * during table initialisation.
12759 * @type int
12760 * @default 0
12761 */
12762 "iBarWidth": 0,
12763
12764 /**
12765 * Viewport width for horizontal scrolling. Horizontal scrolling is
12766 * disabled if an empty string.
12767 * Note that this parameter will be set by the initialisation routine. To
12768 * set a default use {@link DataTable.defaults}.
12769 * @type string
12770 */
12771 "sX": null,
12772
12773 /**
12774 * Width to expand the table to when using x-scrolling. Typically you
12775 * should not need to use this.
12776 * Note that this parameter will be set by the initialisation routine. To
12777 * set a default use {@link DataTable.defaults}.
12778 * @type string
12779 * @deprecated
12780 */
12781 "sXInner": null,
12782
12783 /**
12784 * Viewport height for vertical scrolling. Vertical scrolling is disabled
12785 * if an empty string.
12786 * Note that this parameter will be set by the initialisation routine. To
12787 * set a default use {@link DataTable.defaults}.
12788 * @type string
12789 */
12790 "sY": null
12791 },
12792
12793 /**
12794 * Language information for the table.
12795 * @namespace
12796 * @extends DataTable.defaults.oLanguage
12797 */
12798 "oLanguage": {
12799 /**
12800 * Information callback function. See
12801 * {@link DataTable.defaults.fnInfoCallback}
12802 * @type function
12803 * @default null
12804 */
12805 "fnInfoCallback": null
12806 },
12807
12808 /**
12809 * Browser support parameters
12810 * @namespace
12811 */
12812 "oBrowser": {
12813 /**
12814 * Indicate if the browser incorrectly calculates width:100% inside a
12815 * scrolling element (IE6/7)
12816 * @type boolean
12817 * @default false
12818 */
12819 "bScrollOversize": false,
12820
12821 /**
12822 * Determine if the vertical scrollbar is on the right or left of the
12823 * scrolling container - needed for rtl language layout, although not
12824 * all browsers move the scrollbar (Safari).
12825 * @type boolean
12826 * @default false
12827 */
12828 "bScrollbarLeft": false
12829 },
12830
12831
12832 "ajax": null,
12833
12834
12835 /**
12836 * Array referencing the nodes which are used for the features. The
12837 * parameters of this object match what is allowed by sDom - i.e.
12838 * <ul>
12839 * <li>'l' - Length changing</li>
12840 * <li>'f' - Filtering input</li>
12841 * <li>'t' - The table!</li>
12842 * <li>'i' - Information</li>
12843 * <li>'p' - Pagination</li>
12844 * <li>'r' - pRocessing</li>
12845 * </ul>
12846 * @type array
12847 * @default []
12848 */
12849 "aanFeatures": [],
12850
12851 /**
12852 * Store data information - see {@link DataTable.models.oRow} for detailed
12853 * information.
12854 * @type array
12855 * @default []
12856 */
12857 "aoData": [],
12858
12859 /**
12860 * Array of indexes which are in the current display (after filtering etc)
12861 * @type array
12862 * @default []
12863 */
12864 "aiDisplay": [],
12865
12866 /**
12867 * Array of indexes for display - no filtering
12868 * @type array
12869 * @default []
12870 */
12871 "aiDisplayMaster": [],
12872
12873 /**
12874 * Store information about each column that is in use
12875 * @type array
12876 * @default []
12877 */
12878 "aoColumns": [],
12879
12880 /**
12881 * Store information about the table's header
12882 * @type array
12883 * @default []
12884 */
12885 "aoHeader": [],
12886
12887 /**
12888 * Store information about the table's footer
12889 * @type array
12890 * @default []
12891 */
12892 "aoFooter": [],
12893
12894 /**
12895 * Store the applied global search information in case we want to force a
12896 * research or compare the old search to a new one.
12897 * Note that this parameter will be set by the initialisation routine. To
12898 * set a default use {@link DataTable.defaults}.
12899 * @namespace
12900 * @extends DataTable.models.oSearch
12901 */
12902 "oPreviousSearch": {},
12903
12904 /**
12905 * Store the applied search for each column - see
12906 * {@link DataTable.models.oSearch} for the format that is used for the
12907 * filtering information for each column.
12908 * @type array
12909 * @default []
12910 */
12911 "aoPreSearchCols": [],
12912
12913 /**
12914 * Sorting that is applied to the table. Note that the inner arrays are
12915 * used in the following manner:
12916 * <ul>
12917 * <li>Index 0 - column number</li>
12918 * <li>Index 1 - current sorting direction</li>
12919 * </ul>
12920 * Note that this parameter will be set by the initialisation routine. To
12921 * set a default use {@link DataTable.defaults}.
12922 * @type array
12923 * @todo These inner arrays should really be objects
12924 */
12925 "aaSorting": null,
12926
12927 /**
12928 * Sorting that is always applied to the table (i.e. prefixed in front of
12929 * aaSorting).
12930 * Note that this parameter will be set by the initialisation routine. To
12931 * set a default use {@link DataTable.defaults}.
12932 * @type array
12933 * @default []
12934 */
12935 "aaSortingFixed": [],
12936
12937 /**
12938 * Classes to use for the striping of a table.
12939 * Note that this parameter will be set by the initialisation routine. To
12940 * set a default use {@link DataTable.defaults}.
12941 * @type array
12942 * @default []
12943 */
12944 "asStripeClasses": null,
12945
12946 /**
12947 * If restoring a table - we should restore its striping classes as well
12948 * @type array
12949 * @default []
12950 */
12951 "asDestroyStripes": [],
12952
12953 /**
12954 * If restoring a table - we should restore its width
12955 * @type int
12956 * @default 0
12957 */
12958 "sDestroyWidth": 0,
12959
12960 /**
12961 * Callback functions array for every time a row is inserted (i.e. on a draw).
12962 * @type array
12963 * @default []
12964 */
12965 "aoRowCallback": [],
12966
12967 /**
12968 * Callback functions for the header on each draw.
12969 * @type array
12970 * @default []
12971 */
12972 "aoHeaderCallback": [],
12973
12974 /**
12975 * Callback function for the footer on each draw.
12976 * @type array
12977 * @default []
12978 */
12979 "aoFooterCallback": [],
12980
12981 /**
12982 * Array of callback functions for draw callback functions
12983 * @type array
12984 * @default []
12985 */
12986 "aoDrawCallback": [],
12987
12988 /**
12989 * Array of callback functions for row created function
12990 * @type array
12991 * @default []
12992 */
12993 "aoRowCreatedCallback": [],
12994
12995 /**
12996 * Callback functions for just before the table is redrawn. A return of
12997 * false will be used to cancel the draw.
12998 * @type array
12999 * @default []
13000 */
13001 "aoPreDrawCallback": [],
13002
13003 /**
13004 * Callback functions for when the table has been initialised.
13005 * @type array
13006 * @default []
13007 */
13008 "aoInitComplete": [],
13009
13010
13011 /**
13012 * Callbacks for modifying the settings to be stored for state saving, prior to
13013 * saving state.
13014 * @type array
13015 * @default []
13016 */
13017 "aoStateSaveParams": [],
13018
13019 /**
13020 * Callbacks for modifying the settings that have been stored for state saving
13021 * prior to using the stored values to restore the state.
13022 * @type array
13023 * @default []
13024 */
13025 "aoStateLoadParams": [],
13026
13027 /**
13028 * Callbacks for operating on the settings object once the saved state has been
13029 * loaded
13030 * @type array
13031 * @default []
13032 */
13033 "aoStateLoaded": [],
13034
13035 /**
13036 * Cache the table ID for quick access
13037 * @type string
13038 * @default <i>Empty string</i>
13039 */
13040 "sTableId": "",
13041
13042 /**
13043 * The TABLE node for the main table
13044 * @type node
13045 * @default null
13046 */
13047 "nTable": null,
13048
13049 /**
13050 * Permanent ref to the thead element
13051 * @type node
13052 * @default null
13053 */
13054 "nTHead": null,
13055
13056 /**
13057 * Permanent ref to the tfoot element - if it exists
13058 * @type node
13059 * @default null
13060 */
13061 "nTFoot": null,
13062
13063 /**
13064 * Permanent ref to the tbody element
13065 * @type node
13066 * @default null
13067 */
13068 "nTBody": null,
13069
13070 /**
13071 * Cache the wrapper node (contains all DataTables controlled elements)
13072 * @type node
13073 * @default null
13074 */
13075 "nTableWrapper": null,
13076
13077 /**
13078 * Indicate if when using server-side processing the loading of data
13079 * should be deferred until the second draw.
13080 * Note that this parameter will be set by the initialisation routine. To
13081 * set a default use {@link DataTable.defaults}.
13082 * @type boolean
13083 * @default false
13084 */
13085 "bDeferLoading": false,
13086
13087 /**
13088 * Indicate if all required information has been read in
13089 * @type boolean
13090 * @default false
13091 */
13092 "bInitialised": false,
13093
13094 /**
13095 * Information about open rows. Each object in the array has the parameters
13096 * 'nTr' and 'nParent'
13097 * @type array
13098 * @default []
13099 */
13100 "aoOpenRows": [],
13101
13102 /**
13103 * Dictate the positioning of DataTables' control elements - see
13104 * {@link DataTable.model.oInit.sDom}.
13105 * Note that this parameter will be set by the initialisation routine. To
13106 * set a default use {@link DataTable.defaults}.
13107 * @type string
13108 * @default null
13109 */
13110 "sDom": null,
13111
13112 /**
13113 * Search delay (in mS)
13114 * @type integer
13115 * @default null
13116 */
13117 "searchDelay": null,
13118
13119 /**
13120 * Which type of pagination should be used.
13121 * Note that this parameter will be set by the initialisation routine. To
13122 * set a default use {@link DataTable.defaults}.
13123 * @type string
13124 * @default two_button
13125 */
13126 "sPaginationType": "two_button",
13127
13128 /**
13129 * The state duration (for `stateSave`) in seconds.
13130 * Note that this parameter will be set by the initialisation routine. To
13131 * set a default use {@link DataTable.defaults}.
13132 * @type int
13133 * @default 0
13134 */
13135 "iStateDuration": 0,
13136
13137 /**
13138 * Array of callback functions for state saving. Each array element is an
13139 * object with the following parameters:
13140 * <ul>
13141 * <li>function:fn - function to call. Takes two parameters, oSettings
13142 * and the JSON string to save that has been thus far created. Returns
13143 * a JSON string to be inserted into a json object
13144 * (i.e. '"param": [ 0, 1, 2]')</li>
13145 * <li>string:sName - name of callback</li>
13146 * </ul>
13147 * @type array
13148 * @default []
13149 */
13150 "aoStateSave": [],
13151
13152 /**
13153 * Array of callback functions for state loading. Each array element is an
13154 * object with the following parameters:
13155 * <ul>
13156 * <li>function:fn - function to call. Takes two parameters, oSettings
13157 * and the object stored. May return false to cancel state loading</li>
13158 * <li>string:sName - name of callback</li>
13159 * </ul>
13160 * @type array
13161 * @default []
13162 */
13163 "aoStateLoad": [],
13164
13165 /**
13166 * State that was saved. Useful for back reference
13167 * @type object
13168 * @default null
13169 */
13170 "oSavedState": null,
13171
13172 /**
13173 * State that was loaded. Useful for back reference
13174 * @type object
13175 * @default null
13176 */
13177 "oLoadedState": null,
13178
13179 /**
13180 * Source url for AJAX data for the table.
13181 * Note that this parameter will be set by the initialisation routine. To
13182 * set a default use {@link DataTable.defaults}.
13183 * @type string
13184 * @default null
13185 */
13186 "sAjaxSource": null,
13187
13188 /**
13189 * Property from a given object from which to read the table data from. This
13190 * can be an empty string (when not server-side processing), in which case
13191 * it is assumed an an array is given directly.
13192 * Note that this parameter will be set by the initialisation routine. To
13193 * set a default use {@link DataTable.defaults}.
13194 * @type string
13195 */
13196 "sAjaxDataProp": null,
13197
13198 /**
13199 * Note if draw should be blocked while getting data
13200 * @type boolean
13201 * @default true
13202 */
13203 "bAjaxDataGet": true,
13204
13205 /**
13206 * The last jQuery XHR object that was used for server-side data gathering.
13207 * This can be used for working with the XHR information in one of the
13208 * callbacks
13209 * @type object
13210 * @default null
13211 */
13212 "jqXHR": null,
13213
13214 /**
13215 * JSON returned from the server in the last Ajax request
13216 * @type object
13217 * @default undefined
13218 */
13219 "json": undefined,
13220
13221 /**
13222 * Data submitted as part of the last Ajax request
13223 * @type object
13224 * @default undefined
13225 */
13226 "oAjaxData": undefined,
13227
13228 /**
13229 * Function to get the server-side data.
13230 * Note that this parameter will be set by the initialisation routine. To
13231 * set a default use {@link DataTable.defaults}.
13232 * @type function
13233 */
13234 "fnServerData": null,
13235
13236 /**
13237 * Functions which are called prior to sending an Ajax request so extra
13238 * parameters can easily be sent to the server
13239 * @type array
13240 * @default []
13241 */
13242 "aoServerParams": [],
13243
13244 /**
13245 * Send the XHR HTTP method - GET or POST (could be PUT or DELETE if
13246 * required).
13247 * Note that this parameter will be set by the initialisation routine. To
13248 * set a default use {@link DataTable.defaults}.
13249 * @type string
13250 */
13251 "sServerMethod": null,
13252
13253 /**
13254 * Format numbers for display.
13255 * Note that this parameter will be set by the initialisation routine. To
13256 * set a default use {@link DataTable.defaults}.
13257 * @type function
13258 */
13259 "fnFormatNumber": null,
13260
13261 /**
13262 * List of options that can be used for the user selectable length menu.
13263 * Note that this parameter will be set by the initialisation routine. To
13264 * set a default use {@link DataTable.defaults}.
13265 * @type array
13266 * @default []
13267 */
13268 "aLengthMenu": null,
13269
13270 /**
13271 * Counter for the draws that the table does. Also used as a tracker for
13272 * server-side processing
13273 * @type int
13274 * @default 0
13275 */
13276 "iDraw": 0,
13277
13278 /**
13279 * Indicate if a redraw is being done - useful for Ajax
13280 * @type boolean
13281 * @default false
13282 */
13283 "bDrawing": false,
13284
13285 /**
13286 * Draw index (iDraw) of the last error when parsing the returned data
13287 * @type int
13288 * @default -1
13289 */
13290 "iDrawError": -1,
13291
13292 /**
13293 * Paging display length
13294 * @type int
13295 * @default 10
13296 */
13297 "_iDisplayLength": 10,
13298
13299 /**
13300 * Paging start point - aiDisplay index
13301 * @type int
13302 * @default 0
13303 */
13304 "_iDisplayStart": 0,
13305
13306 /**
13307 * Server-side processing - number of records in the result set
13308 * (i.e. before filtering), Use fnRecordsTotal rather than
13309 * this property to get the value of the number of records, regardless of
13310 * the server-side processing setting.
13311 * @type int
13312 * @default 0
13313 * @private
13314 */
13315 "_iRecordsTotal": 0,
13316
13317 /**
13318 * Server-side processing - number of records in the current display set
13319 * (i.e. after filtering). Use fnRecordsDisplay rather than
13320 * this property to get the value of the number of records, regardless of
13321 * the server-side processing setting.
13322 * @type boolean
13323 * @default 0
13324 * @private
13325 */
13326 "_iRecordsDisplay": 0,
13327
13328 /**
13329 * Flag to indicate if jQuery UI marking and classes should be used.
13330 * Note that this parameter will be set by the initialisation routine. To
13331 * set a default use {@link DataTable.defaults}.
13332 * @type boolean
13333 */
13334 "bJUI": null,
13335
13336 /**
13337 * The classes to use for the table
13338 * @type object
13339 * @default {}
13340 */
13341 "oClasses": {},
13342
13343 /**
13344 * Flag attached to the settings object so you can check in the draw
13345 * callback if filtering has been done in the draw. Deprecated in favour of
13346 * events.
13347 * @type boolean
13348 * @default false
13349 * @deprecated
13350 */
13351 "bFiltered": false,
13352
13353 /**
13354 * Flag attached to the settings object so you can check in the draw
13355 * callback if sorting has been done in the draw. Deprecated in favour of
13356 * events.
13357 * @type boolean
13358 * @default false
13359 * @deprecated
13360 */
13361 "bSorted": false,
13362
13363 /**
13364 * Indicate that if multiple rows are in the header and there is more than
13365 * one unique cell per column, if the top one (true) or bottom one (false)
13366 * should be used for sorting / title by DataTables.
13367 * Note that this parameter will be set by the initialisation routine. To
13368 * set a default use {@link DataTable.defaults}.
13369 * @type boolean
13370 */
13371 "bSortCellsTop": null,
13372
13373 /**
13374 * Initialisation object that is used for the table
13375 * @type object
13376 * @default null
13377 */
13378 "oInit": null,
13379
13380 /**
13381 * Destroy callback functions - for plug-ins to attach themselves to the
13382 * destroy so they can clean up markup and events.
13383 * @type array
13384 * @default []
13385 */
13386 "aoDestroyCallback": [],
13387
13388
13389 /**
13390 * Get the number of records in the current record set, before filtering
13391 * @type function
13392 */
13393 "fnRecordsTotal": function ()
13394 {
13395 return _fnDataSource( this ) == 'ssp' ?
13396 this._iRecordsTotal * 1 :
13397 this.aiDisplayMaster.length;
13398 },
13399
13400 /**
13401 * Get the number of records in the current record set, after filtering
13402 * @type function
13403 */
13404 "fnRecordsDisplay": function ()
13405 {
13406 return _fnDataSource( this ) == 'ssp' ?
13407 this._iRecordsDisplay * 1 :
13408 this.aiDisplay.length;
13409 },
13410
13411 /**
13412 * Get the display end point - aiDisplay index
13413 * @type function
13414 */
13415 "fnDisplayEnd": function ()
13416 {
13417 var
13418 len = this._iDisplayLength,
13419 start = this._iDisplayStart,
13420 calc = start + len,
13421 records = this.aiDisplay.length,
13422 features = this.oFeatures,
13423 paginate = features.bPaginate;
13424
13425 if ( features.bServerSide ) {
13426 return paginate === false || len === -1 ?
13427 start + records :
13428 Math.min( start+len, this._iRecordsDisplay );
13429 }
13430 else {
13431 return ! paginate || calc>records || len===-1 ?
13432 records :
13433 calc;
13434 }
13435 },
13436
13437 /**
13438 * The DataTables object for this table
13439 * @type object
13440 * @default null
13441 */
13442 "oInstance": null,
13443
13444 /**
13445 * Unique identifier for each instance of the DataTables object. If there
13446 * is an ID on the table node, then it takes that value, otherwise an
13447 * incrementing internal counter is used.
13448 * @type string
13449 * @default null
13450 */
13451 "sInstance": null,
13452
13453 /**
13454 * tabindex attribute value that is added to DataTables control elements, allowing
13455 * keyboard navigation of the table and its controls.
13456 */
13457 "iTabIndex": 0,
13458
13459 /**
13460 * DIV container for the footer scrolling table if scrolling
13461 */
13462 "nScrollHead": null,
13463
13464 /**
13465 * DIV container for the footer scrolling table if scrolling
13466 */
13467 "nScrollFoot": null,
13468
13469 /**
13470 * Last applied sort
13471 * @type array
13472 * @default []
13473 */
13474 "aLastSort": [],
13475
13476 /**
13477 * Stored plug-in instances
13478 * @type object
13479 * @default {}
13480 */
13481 "oPlugins": {}
13482 };
13483
13484 /**
13485 * Extension object for DataTables that is used to provide all extension
13486 * options.
13487 *
13488 * Note that the `DataTable.ext` object is available through
13489 * `jQuery.fn.dataTable.ext` where it may be accessed and manipulated. It is
13490 * also aliased to `jQuery.fn.dataTableExt` for historic reasons.
13491 * @namespace
13492 * @extends DataTable.models.ext
13493 */
13494
13495
13496 /**
13497 * DataTables extensions
13498 *
13499 * This namespace acts as a collection area for plug-ins that can be used to
13500 * extend DataTables capabilities. Indeed many of the build in methods
13501 * use this method to provide their own capabilities (sorting methods for
13502 * example).
13503 *
13504 * Note that this namespace is aliased to `jQuery.fn.dataTableExt` for legacy
13505 * reasons
13506 *
13507 * @namespace
13508 */
13509 DataTable.ext = _ext = {
13510 /**
13511 * Buttons. For use with the Buttons extension for DataTables. This is
13512 * defined here so other extensions can define buttons regardless of load
13513 * order. It is _not_ used by DataTables core.
13514 *
13515 * @type object
13516 * @default {}
13517 */
13518 buttons: {},
13519
13520
13521 /**
13522 * Element class names
13523 *
13524 * @type object
13525 * @default {}
13526 */
13527 classes: {},
13528
13529
13530 /**
13531 * Error reporting.
13532 *
13533 * How should DataTables report an error. Can take the value 'alert',
13534 * 'throw', 'none' or a function.
13535 *
13536 * @type string|function
13537 * @default alert
13538 */
13539 errMode: "alert",
13540
13541
13542 /**
13543 * Feature plug-ins.
13544 *
13545 * This is an array of objects which describe the feature plug-ins that are
13546 * available to DataTables. These feature plug-ins are then available for
13547 * use through the `dom` initialisation option.
13548 *
13549 * Each feature plug-in is described by an object which must have the
13550 * following properties:
13551 *
13552 * * `fnInit` - function that is used to initialise the plug-in,
13553 * * `cFeature` - a character so the feature can be enabled by the `dom`
13554 * instillation option. This is case sensitive.
13555 *
13556 * The `fnInit` function has the following input parameters:
13557 *
13558 * 1. `{object}` DataTables settings object: see
13559 * {@link DataTable.models.oSettings}
13560 *
13561 * And the following return is expected:
13562 *
13563 * * {node|null} The element which contains your feature. Note that the
13564 * return may also be void if your plug-in does not require to inject any
13565 * DOM elements into DataTables control (`dom`) - for example this might
13566 * be useful when developing a plug-in which allows table control via
13567 * keyboard entry
13568 *
13569 * @type array
13570 *
13571 * @example
13572 * $.fn.dataTable.ext.features.push( {
13573 * "fnInit": function( oSettings ) {
13574 * return new TableTools( { "oDTSettings": oSettings } );
13575 * },
13576 * "cFeature": "T"
13577 * } );
13578 */
13579 feature: [],
13580
13581
13582 /**
13583 * Row searching.
13584 *
13585 * This method of searching is complimentary to the default type based
13586 * searching, and a lot more comprehensive as it allows you complete control
13587 * over the searching logic. Each element in this array is a function
13588 * (parameters described below) that is called for every row in the table,
13589 * and your logic decides if it should be included in the searching data set
13590 * or not.
13591 *
13592 * Searching functions have the following input parameters:
13593 *
13594 * 1. `{object}` DataTables settings object: see
13595 * {@link DataTable.models.oSettings}
13596 * 2. `{array|object}` Data for the row to be processed (same as the
13597 * original format that was passed in as the data source, or an array
13598 * from a DOM data source
13599 * 3. `{int}` Row index ({@link DataTable.models.oSettings.aoData}), which
13600 * can be useful to retrieve the `TR` element if you need DOM interaction.
13601 *
13602 * And the following return is expected:
13603 *
13604 * * {boolean} Include the row in the searched result set (true) or not
13605 * (false)
13606 *
13607 * Note that as with the main search ability in DataTables, technically this
13608 * is "filtering", since it is subtractive. However, for consistency in
13609 * naming we call it searching here.
13610 *
13611 * @type array
13612 * @default []
13613 *
13614 * @example
13615 * // The following example shows custom search being applied to the
13616 * // fourth column (i.e. the data[3] index) based on two input values
13617 * // from the end-user, matching the data in a certain range.
13618 * $.fn.dataTable.ext.search.push(
13619 * function( settings, data, dataIndex ) {
13620 * var min = document.getElementById('min').value * 1;
13621 * var max = document.getElementById('max').value * 1;
13622 * var version = data[3] == "-" ? 0 : data[3]*1;
13623 *
13624 * if ( min == "" && max == "" ) {
13625 * return true;
13626 * }
13627 * else if ( min == "" && version < max ) {
13628 * return true;
13629 * }
13630 * else if ( min < version && "" == max ) {
13631 * return true;
13632 * }
13633 * else if ( min < version && version < max ) {
13634 * return true;
13635 * }
13636 * return false;
13637 * }
13638 * );
13639 */
13640 search: [],
13641
13642
13643 /**
13644 * Selector extensions
13645 *
13646 * The `selector` option can be used to extend the options available for the
13647 * selector modifier options (`selector-modifier` object data type) that
13648 * each of the three built in selector types offer (row, column and cell +
13649 * their plural counterparts). For example the Select extension uses this
13650 * mechanism to provide an option to select only rows, columns and cells
13651 * that have been marked as selected by the end user (`{selected: true}`),
13652 * which can be used in conjunction with the existing built in selector
13653 * options.
13654 *
13655 * Each property is an array to which functions can be pushed. The functions
13656 * take three attributes:
13657 *
13658 * * Settings object for the host table
13659 * * Options object (`selector-modifier` object type)
13660 * * Array of selected item indexes
13661 *
13662 * The return is an array of the resulting item indexes after the custom
13663 * selector has been applied.
13664 *
13665 * @type object
13666 */
13667 selector: {
13668 cell: [],
13669 column: [],
13670 row: []
13671 },
13672
13673
13674 /**
13675 * Internal functions, exposed for used in plug-ins.
13676 *
13677 * Please note that you should not need to use the internal methods for
13678 * anything other than a plug-in (and even then, try to avoid if possible).
13679 * The internal function may change between releases.
13680 *
13681 * @type object
13682 * @default {}
13683 */
13684 internal: {},
13685
13686
13687 /**
13688 * Legacy configuration options. Enable and disable legacy options that
13689 * are available in DataTables.
13690 *
13691 * @type object
13692 */
13693 legacy: {
13694 /**
13695 * Enable / disable DataTables 1.9 compatible server-side processing
13696 * requests
13697 *
13698 * @type boolean
13699 * @default null
13700 */
13701 ajax: null
13702 },
13703
13704
13705 /**
13706 * Pagination plug-in methods.
13707 *
13708 * Each entry in this object is a function and defines which buttons should
13709 * be shown by the pagination rendering method that is used for the table:
13710 * {@link DataTable.ext.renderer.pageButton}. The renderer addresses how the
13711 * buttons are displayed in the document, while the functions here tell it
13712 * what buttons to display. This is done by returning an array of button
13713 * descriptions (what each button will do).
13714 *
13715 * Pagination types (the four built in options and any additional plug-in
13716 * options defined here) can be used through the `paginationType`
13717 * initialisation parameter.
13718 *
13719 * The functions defined take two parameters:
13720 *
13721 * 1. `{int} page` The current page index
13722 * 2. `{int} pages` The number of pages in the table
13723 *
13724 * Each function is expected to return an array where each element of the
13725 * array can be one of:
13726 *
13727 * * `first` - Jump to first page when activated
13728 * * `last` - Jump to last page when activated
13729 * * `previous` - Show previous page when activated
13730 * * `next` - Show next page when activated
13731 * * `{int}` - Show page of the index given
13732 * * `{array}` - A nested array containing the above elements to add a
13733 * containing 'DIV' element (might be useful for styling).
13734 *
13735 * Note that DataTables v1.9- used this object slightly differently whereby
13736 * an object with two functions would be defined for each plug-in. That
13737 * ability is still supported by DataTables 1.10+ to provide backwards
13738 * compatibility, but this option of use is now decremented and no longer
13739 * documented in DataTables 1.10+.
13740 *
13741 * @type object
13742 * @default {}
13743 *
13744 * @example
13745 * // Show previous, next and current page buttons only
13746 * $.fn.dataTableExt.oPagination.current = function ( page, pages ) {
13747 * return [ 'previous', page, 'next' ];
13748 * };
13749 */
13750 pager: {},
13751
13752
13753 renderer: {
13754 pageButton: {},
13755 header: {}
13756 },
13757
13758
13759 /**
13760 * Ordering plug-ins - custom data source
13761 *
13762 * The extension options for ordering of data available here is complimentary
13763 * to the default type based ordering that DataTables typically uses. It
13764 * allows much greater control over the the data that is being used to
13765 * order a column, but is necessarily therefore more complex.
13766 *
13767 * This type of ordering is useful if you want to do ordering based on data
13768 * live from the DOM (for example the contents of an 'input' element) rather
13769 * than just the static string that DataTables knows of.
13770 *
13771 * The way these plug-ins work is that you create an array of the values you
13772 * wish to be ordering for the column in question and then return that
13773 * array. The data in the array much be in the index order of the rows in
13774 * the table (not the currently ordering order!). Which order data gathering
13775 * function is run here depends on the `dt-init columns.orderDataType`
13776 * parameter that is used for the column (if any).
13777 *
13778 * The functions defined take two parameters:
13779 *
13780 * 1. `{object}` DataTables settings object: see
13781 * {@link DataTable.models.oSettings}
13782 * 2. `{int}` Target column index
13783 *
13784 * Each function is expected to return an array:
13785 *
13786 * * `{array}` Data for the column to be ordering upon
13787 *
13788 * @type array
13789 *
13790 * @example
13791 * // Ordering using `input` node values
13792 * $.fn.dataTable.ext.order['dom-text'] = function ( settings, col )
13793 * {
13794 * return this.api().column( col, {order:'index'} ).nodes().map( function ( td, i ) {
13795 * return $('input', td).val();
13796 * } );
13797 * }
13798 */
13799 order: {},
13800
13801
13802 /**
13803 * Type based plug-ins.
13804 *
13805 * Each column in DataTables has a type assigned to it, either by automatic
13806 * detection or by direct assignment using the `type` option for the column.
13807 * The type of a column will effect how it is ordering and search (plug-ins
13808 * can also make use of the column type if required).
13809 *
13810 * @namespace
13811 */
13812 type: {
13813 /**
13814 * Type detection functions.
13815 *
13816 * The functions defined in this object are used to automatically detect
13817 * a column's type, making initialisation of DataTables super easy, even
13818 * when complex data is in the table.
13819 *
13820 * The functions defined take two parameters:
13821 *
13822 * 1. `{*}` Data from the column cell to be analysed
13823 * 2. `{settings}` DataTables settings object. This can be used to
13824 * perform context specific type detection - for example detection
13825 * based on language settings such as using a comma for a decimal
13826 * place. Generally speaking the options from the settings will not
13827 * be required
13828 *
13829 * Each function is expected to return:
13830 *
13831 * * `{string|null}` Data type detected, or null if unknown (and thus
13832 * pass it on to the other type detection functions.
13833 *
13834 * @type array
13835 *
13836 * @example
13837 * // Currency type detection plug-in:
13838 * $.fn.dataTable.ext.type.detect.push(
13839 * function ( data, settings ) {
13840 * // Check the numeric part
13841 * if ( ! $.isNumeric( data.substring(1) ) ) {
13842 * return null;
13843 * }
13844 *
13845 * // Check prefixed by currency
13846 * if ( data.charAt(0) == '$' || data.charAt(0) == '&pound;' ) {
13847 * return 'currency';
13848 * }
13849 * return null;
13850 * }
13851 * );
13852 */
13853 detect: [],
13854
13855
13856 /**
13857 * Type based search formatting.
13858 *
13859 * The type based searching functions can be used to pre-format the
13860 * data to be search on. For example, it can be used to strip HTML
13861 * tags or to de-format telephone numbers for numeric only searching.
13862 *
13863 * Note that is a search is not defined for a column of a given type,
13864 * no search formatting will be performed.
13865 *
13866 * Pre-processing of searching data plug-ins - When you assign the sType
13867 * for a column (or have it automatically detected for you by DataTables
13868 * or a type detection plug-in), you will typically be using this for
13869 * custom sorting, but it can also be used to provide custom searching
13870 * by allowing you to pre-processing the data and returning the data in
13871 * the format that should be searched upon. This is done by adding
13872 * functions this object with a parameter name which matches the sType
13873 * for that target column. This is the corollary of <i>afnSortData</i>
13874 * for searching data.
13875 *
13876 * The functions defined take a single parameter:
13877 *
13878 * 1. `{*}` Data from the column cell to be prepared for searching
13879 *
13880 * Each function is expected to return:
13881 *
13882 * * `{string|null}` Formatted string that will be used for the searching.
13883 *
13884 * @type object
13885 * @default {}
13886 *
13887 * @example
13888 * $.fn.dataTable.ext.type.search['title-numeric'] = function ( d ) {
13889 * return d.replace(/\n/g," ").replace( /<.*?>/g, "" );
13890 * }
13891 */
13892 search: {},
13893
13894
13895 /**
13896 * Type based ordering.
13897 *
13898 * The column type tells DataTables what ordering to apply to the table
13899 * when a column is sorted upon. The order for each type that is defined,
13900 * is defined by the functions available in this object.
13901 *
13902 * Each ordering option can be described by three properties added to
13903 * this object:
13904 *
13905 * * `{type}-pre` - Pre-formatting function
13906 * * `{type}-asc` - Ascending order function
13907 * * `{type}-desc` - Descending order function
13908 *
13909 * All three can be used together, only `{type}-pre` or only
13910 * `{type}-asc` and `{type}-desc` together. It is generally recommended
13911 * that only `{type}-pre` is used, as this provides the optimal
13912 * implementation in terms of speed, although the others are provided
13913 * for compatibility with existing Javascript sort functions.
13914 *
13915 * `{type}-pre`: Functions defined take a single parameter:
13916 *
13917 * 1. `{*}` Data from the column cell to be prepared for ordering
13918 *
13919 * And return:
13920 *
13921 * * `{*}` Data to be sorted upon
13922 *
13923 * `{type}-asc` and `{type}-desc`: Functions are typical Javascript sort
13924 * functions, taking two parameters:
13925 *
13926 * 1. `{*}` Data to compare to the second parameter
13927 * 2. `{*}` Data to compare to the first parameter
13928 *
13929 * And returning:
13930 *
13931 * * `{*}` Ordering match: <0 if first parameter should be sorted lower
13932 * than the second parameter, ===0 if the two parameters are equal and
13933 * >0 if the first parameter should be sorted height than the second
13934 * parameter.
13935 *
13936 * @type object
13937 * @default {}
13938 *
13939 * @example
13940 * // Numeric ordering of formatted numbers with a pre-formatter
13941 * $.extend( $.fn.dataTable.ext.type.order, {
13942 * "string-pre": function(x) {
13943 * a = (a === "-" || a === "") ? 0 : a.replace( /[^\d\-\.]/g, "" );
13944 * return parseFloat( a );
13945 * }
13946 * } );
13947 *
13948 * @example
13949 * // Case-sensitive string ordering, with no pre-formatting method
13950 * $.extend( $.fn.dataTable.ext.order, {
13951 * "string-case-asc": function(x,y) {
13952 * return ((x < y) ? -1 : ((x > y) ? 1 : 0));
13953 * },
13954 * "string-case-desc": function(x,y) {
13955 * return ((x < y) ? 1 : ((x > y) ? -1 : 0));
13956 * }
13957 * } );
13958 */
13959 order: {}
13960 },
13961
13962 /**
13963 * Unique DataTables instance counter
13964 *
13965 * @type int
13966 * @private
13967 */
13968 _unique: 0,
13969
13970
13971 //
13972 // Depreciated
13973 // The following properties are retained for backwards compatiblity only.
13974 // The should not be used in new projects and will be removed in a future
13975 // version
13976 //
13977
13978 /**
13979 * Version check function.
13980 * @type function
13981 * @depreciated Since 1.10
13982 */
13983 fnVersionCheck: DataTable.fnVersionCheck,
13984
13985
13986 /**
13987 * Index for what 'this' index API functions should use
13988 * @type int
13989 * @deprecated Since v1.10
13990 */
13991 iApiIndex: 0,
13992
13993
13994 /**
13995 * jQuery UI class container
13996 * @type object
13997 * @deprecated Since v1.10
13998 */
13999 oJUIClasses: {},
14000
14001
14002 /**
14003 * Software version
14004 * @type string
14005 * @deprecated Since v1.10
14006 */
14007 sVersion: DataTable.version
14008 };
14009
14010
14011 //
14012 // Backwards compatibility. Alias to pre 1.10 Hungarian notation counter parts
14013 //
14014 $.extend( _ext, {
14015 afnFiltering: _ext.search,
14016 aTypes: _ext.type.detect,
14017 ofnSearch: _ext.type.search,
14018 oSort: _ext.type.order,
14019 afnSortData: _ext.order,
14020 aoFeatures: _ext.feature,
14021 oApi: _ext.internal,
14022 oStdClasses: _ext.classes,
14023 oPagination: _ext.pager
14024 } );
14025
14026
14027 $.extend( DataTable.ext.classes, {
14028 "sTable": "dataTable",
14029 "sNoFooter": "no-footer",
14030
14031 /* Paging buttons */
14032 "sPageButton": "paginate_button",
14033 "sPageButtonActive": "current",
14034 "sPageButtonDisabled": "disabled",
14035
14036 /* Striping classes */
14037 "sStripeOdd": "odd",
14038 "sStripeEven": "even",
14039
14040 /* Empty row */
14041 "sRowEmpty": "dataTables_empty",
14042
14043 /* Features */
14044 "sWrapper": "dataTables_wrapper",
14045 "sFilter": "dataTables_filter",
14046 "sInfo": "dataTables_info",
14047 "sPaging": "dataTables_paginate paging_", /* Note that the type is postfixed */
14048 "sLength": "dataTables_length",
14049 "sProcessing": "dataTables_processing",
14050
14051 /* Sorting */
14052 "sSortAsc": "sorting_asc",
14053 "sSortDesc": "sorting_desc",
14054 "sSortable": "sorting", /* Sortable in both directions */
14055 "sSortableAsc": "sorting_asc_disabled",
14056 "sSortableDesc": "sorting_desc_disabled",
14057 "sSortableNone": "sorting_disabled",
14058 "sSortColumn": "sorting_", /* Note that an int is postfixed for the sorting order */
14059
14060 /* Filtering */
14061 "sFilterInput": "",
14062
14063 /* Page length */
14064 "sLengthSelect": "",
14065
14066 /* Scrolling */
14067 "sScrollWrapper": "dataTables_scroll",
14068 "sScrollHead": "dataTables_scrollHead",
14069 "sScrollHeadInner": "dataTables_scrollHeadInner",
14070 "sScrollBody": "dataTables_scrollBody",
14071 "sScrollFoot": "dataTables_scrollFoot",
14072 "sScrollFootInner": "dataTables_scrollFootInner",
14073
14074 /* Misc */
14075 "sHeaderTH": "",
14076 "sFooterTH": "",
14077
14078 // Deprecated
14079 "sSortJUIAsc": "",
14080 "sSortJUIDesc": "",
14081 "sSortJUI": "",
14082 "sSortJUIAscAllowed": "",
14083 "sSortJUIDescAllowed": "",
14084 "sSortJUIWrapper": "",
14085 "sSortIcon": "",
14086 "sJUIHeader": "",
14087 "sJUIFooter": ""
14088 } );
14089
14090
14091 (function() {
14092
14093 // Reused strings for better compression. Closure compiler appears to have a
14094 // weird edge case where it is trying to expand strings rather than use the
14095 // variable version. This results in about 200 bytes being added, for very
14096 // little preference benefit since it this run on script load only.
14097 var _empty = '';
14098 _empty = '';
14099
14100 var _stateDefault = _empty + 'ui-state-default';
14101 var _sortIcon = _empty + 'css_right ui-icon ui-icon-';
14102 var _headerFooter = _empty + 'fg-toolbar ui-toolbar ui-widget-header ui-helper-clearfix';
14103
14104 $.extend( DataTable.ext.oJUIClasses, DataTable.ext.classes, {
14105 /* Full numbers paging buttons */
14106 "sPageButton": "fg-button ui-button "+_stateDefault,
14107 "sPageButtonActive": "ui-state-disabled",
14108 "sPageButtonDisabled": "ui-state-disabled",
14109
14110 /* Features */
14111 "sPaging": "dataTables_paginate fg-buttonset ui-buttonset fg-buttonset-multi "+
14112 "ui-buttonset-multi paging_", /* Note that the type is postfixed */
14113
14114 /* Sorting */
14115 "sSortAsc": _stateDefault+" sorting_asc",
14116 "sSortDesc": _stateDefault+" sorting_desc",
14117 "sSortable": _stateDefault+" sorting",
14118 "sSortableAsc": _stateDefault+" sorting_asc_disabled",
14119 "sSortableDesc": _stateDefault+" sorting_desc_disabled",
14120 "sSortableNone": _stateDefault+" sorting_disabled",
14121 "sSortJUIAsc": _sortIcon+"triangle-1-n",
14122 "sSortJUIDesc": _sortIcon+"triangle-1-s",
14123 "sSortJUI": _sortIcon+"carat-2-n-s",
14124 "sSortJUIAscAllowed": _sortIcon+"carat-1-n",
14125 "sSortJUIDescAllowed": _sortIcon+"carat-1-s",
14126 "sSortJUIWrapper": "DataTables_sort_wrapper",
14127 "sSortIcon": "DataTables_sort_icon",
14128
14129 /* Scrolling */
14130 "sScrollHead": "dataTables_scrollHead "+_stateDefault,
14131 "sScrollFoot": "dataTables_scrollFoot "+_stateDefault,
14132
14133 /* Misc */
14134 "sHeaderTH": _stateDefault,
14135 "sFooterTH": _stateDefault,
14136 "sJUIHeader": _headerFooter+" ui-corner-tl ui-corner-tr",
14137 "sJUIFooter": _headerFooter+" ui-corner-bl ui-corner-br"
14138 } );
14139
14140 }());
14141
14142
14143
14144 var extPagination = DataTable.ext.pager;
14145
14146 function _numbers ( page, pages ) {
14147 var
14148 numbers = [],
14149 buttons = extPagination.numbers_length,
14150 half = Math.floor( buttons / 2 ),
14151 i = 1;
14152
14153 if ( pages <= buttons ) {
14154 numbers = _range( 0, pages );
14155 }
14156 else if ( page <= half ) {
14157 numbers = _range( 0, buttons-2 );
14158 numbers.push( 'ellipsis' );
14159 numbers.push( pages-1 );
14160 }
14161 else if ( page >= pages - 1 - half ) {
14162 numbers = _range( pages-(buttons-2), pages );
14163 numbers.splice( 0, 0, 'ellipsis' ); // no unshift in ie6
14164 numbers.splice( 0, 0, 0 );
14165 }
14166 else {
14167 numbers = _range( page-half+2, page+half-1 );
14168 numbers.push( 'ellipsis' );
14169 numbers.push( pages-1 );
14170 numbers.splice( 0, 0, 'ellipsis' );
14171 numbers.splice( 0, 0, 0 );
14172 }
14173
14174 numbers.DT_el = 'span';
14175 return numbers;
14176 }
14177
14178
14179 $.extend( extPagination, {
14180 simple: function ( page, pages ) {
14181 return [ 'previous', 'next' ];
14182 },
14183
14184 full: function ( page, pages ) {
14185 return [ 'first', 'previous', 'next', 'last' ];
14186 },
14187
14188 simple_numbers: function ( page, pages ) {
14189 return [ 'previous', _numbers(page, pages), 'next' ];
14190 },
14191
14192 full_numbers: function ( page, pages ) {
14193 return [ 'first', 'previous', _numbers(page, pages), 'next', 'last' ];
14194 },
14195
14196 // For testing and plug-ins to use
14197 _numbers: _numbers,
14198
14199 // Number of number buttons (including ellipsis) to show. _Must be odd!_
14200 numbers_length: 7
14201 } );
14202
14203
14204 $.extend( true, DataTable.ext.renderer, {
14205 pageButton: {
14206 _: function ( settings, host, idx, buttons, page, pages ) {
14207 var classes = settings.oClasses;
14208 var lang = settings.oLanguage.oPaginate;
14209 var btnDisplay, btnClass, counter=0;
14210
14211 var attach = function( container, buttons ) {
14212 var i, ien, node, button;
14213 var clickHandler = function ( e ) {
14214 _fnPageChange( settings, e.data.action, true );
14215 };
14216
14217 for ( i=0, ien=buttons.length ; i<ien ; i++ ) {
14218 button = buttons[i];
14219
14220 if ( $.isArray( button ) ) {
14221 var inner = $( '<'+(button.DT_el || 'div')+'/>' )
14222 .appendTo( container );
14223 attach( inner, button );
14224 }
14225 else {
14226 btnDisplay = '';
14227 btnClass = '';
14228
14229 switch ( button ) {
14230 case 'ellipsis':
14231 container.append('<span class="ellipsis">&#x2026;</span>');
14232 break;
14233
14234 case 'first':
14235 btnDisplay = lang.sFirst;
14236 btnClass = button + (page > 0 ?
14237 '' : ' '+classes.sPageButtonDisabled);
14238 break;
14239
14240 case 'previous':
14241 btnDisplay = lang.sPrevious;
14242 btnClass = button + (page > 0 ?
14243 '' : ' '+classes.sPageButtonDisabled);
14244 break;
14245
14246 case 'next':
14247 btnDisplay = lang.sNext;
14248 btnClass = button + (page < pages-1 ?
14249 '' : ' '+classes.sPageButtonDisabled);
14250 break;
14251
14252 case 'last':
14253 btnDisplay = lang.sLast;
14254 btnClass = button + (page < pages-1 ?
14255 '' : ' '+classes.sPageButtonDisabled);
14256 break;
14257
14258 default:
14259 btnDisplay = button + 1;
14260 btnClass = page === button ?
14261 classes.sPageButtonActive : '';
14262 break;
14263 }
14264
14265 if ( btnDisplay ) {
14266 node = $('<a>', {
14267 'class': classes.sPageButton+' '+btnClass,
14268 'aria-controls': settings.sTableId,
14269 'data-dt-idx': counter,
14270 'tabindex': settings.iTabIndex,
14271 'id': idx === 0 && typeof button === 'string' ?
14272 settings.sTableId +'_'+ button :
14273 null
14274 } )
14275 .html( btnDisplay )
14276 .appendTo( container );
14277
14278 _fnBindAction(
14279 node, {action: button}, clickHandler
14280 );
14281
14282 counter++;
14283 }
14284 }
14285 }
14286 };
14287
14288 // IE9 throws an 'unknown error' if document.activeElement is used
14289 // inside an iframe or frame. Try / catch the error. Not good for
14290 // accessibility, but neither are frames.
14291 var activeEl;
14292
14293 try {
14294 // Because this approach is destroying and recreating the paging
14295 // elements, focus is lost on the select button which is bad for
14296 // accessibility. So we want to restore focus once the draw has
14297 // completed
14298 activeEl = $(document.activeElement).data('dt-idx');
14299 }
14300 catch (e) {}
14301
14302 attach( $(host).empty(), buttons );
14303
14304 if ( activeEl ) {
14305 $(host).find( '[data-dt-idx='+activeEl+']' ).focus();
14306 }
14307 }
14308 }
14309 } );
14310
14311
14312
14313 // Built in type detection. See model.ext.aTypes for information about
14314 // what is required from this methods.
14315 $.extend( DataTable.ext.type.detect, [
14316 // Plain numbers - first since V8 detects some plain numbers as dates
14317 // e.g. Date.parse('55') (but not all, e.g. Date.parse('22')...).
14318 function ( d, settings )
14319 {
14320 var decimal = settings.oLanguage.sDecimal;
14321 return _isNumber( d, decimal ) ? 'num'+decimal : null;
14322 },
14323
14324 // Dates (only those recognised by the browser's Date.parse)
14325 function ( d, settings )
14326 {
14327 // V8 will remove any unknown characters at the start and end of the
14328 // expression, leading to false matches such as `$245.12` or `10%` being
14329 // a valid date. See forum thread 18941 for detail.
14330 if ( d && !(d instanceof Date) && ( ! _re_date_start.test(d) || ! _re_date_end.test(d) ) ) {
14331 return null;
14332 }
14333 var parsed = Date.parse(d);
14334 return (parsed !== null && !isNaN(parsed)) || _empty(d) ? 'date' : null;
14335 },
14336
14337 // Formatted numbers
14338 function ( d, settings )
14339 {
14340 var decimal = settings.oLanguage.sDecimal;
14341 return _isNumber( d, decimal, true ) ? 'num-fmt'+decimal : null;
14342 },
14343
14344 // HTML numeric
14345 function ( d, settings )
14346 {
14347 var decimal = settings.oLanguage.sDecimal;
14348 return _htmlNumeric( d, decimal ) ? 'html-num'+decimal : null;
14349 },
14350
14351 // HTML numeric, formatted
14352 function ( d, settings )
14353 {
14354 var decimal = settings.oLanguage.sDecimal;
14355 return _htmlNumeric( d, decimal, true ) ? 'html-num-fmt'+decimal : null;
14356 },
14357
14358 // HTML (this is strict checking - there must be html)
14359 function ( d, settings )
14360 {
14361 return _empty( d ) || (typeof d === 'string' && d.indexOf('<') !== -1) ?
14362 'html' : null;
14363 }
14364 ] );
14365
14366
14367
14368 // Filter formatting functions. See model.ext.ofnSearch for information about
14369 // what is required from these methods.
14370 //
14371 // Note that additional search methods are added for the html numbers and
14372 // html formatted numbers by `_addNumericSort()` when we know what the decimal
14373 // place is
14374
14375
14376 $.extend( DataTable.ext.type.search, {
14377 html: function ( data ) {
14378 return _empty(data) ?
14379 data :
14380 typeof data === 'string' ?
14381 data
14382 .replace( _re_new_lines, " " )
14383 .replace( _re_html, "" ) :
14384 '';
14385 },
14386
14387 string: function ( data ) {
14388 return _empty(data) ?
14389 data :
14390 typeof data === 'string' ?
14391 data.replace( _re_new_lines, " " ) :
14392 data;
14393 }
14394 } );
14395
14396
14397
14398 var __numericReplace = function ( d, decimalPlace, re1, re2 ) {
14399 if ( d !== 0 && (!d || d === '-') ) {
14400 return -Infinity;
14401 }
14402
14403 // If a decimal place other than `.` is used, it needs to be given to the
14404 // function so we can detect it and replace with a `.` which is the only
14405 // decimal place Javascript recognises - it is not locale aware.
14406 if ( decimalPlace ) {
14407 d = _numToDecimal( d, decimalPlace );
14408 }
14409
14410 if ( d.replace ) {
14411 if ( re1 ) {
14412 d = d.replace( re1, '' );
14413 }
14414
14415 if ( re2 ) {
14416 d = d.replace( re2, '' );
14417 }
14418 }
14419
14420 return d * 1;
14421 };
14422
14423
14424 // Add the numeric 'deformatting' functions for sorting and search. This is done
14425 // in a function to provide an easy ability for the language options to add
14426 // additional methods if a non-period decimal place is used.
14427 function _addNumericSort ( decimalPlace ) {
14428 $.each(
14429 {
14430 // Plain numbers
14431 "num": function ( d ) {
14432 return __numericReplace( d, decimalPlace );
14433 },
14434
14435 // Formatted numbers
14436 "num-fmt": function ( d ) {
14437 return __numericReplace( d, decimalPlace, _re_formatted_numeric );
14438 },
14439
14440 // HTML numeric
14441 "html-num": function ( d ) {
14442 return __numericReplace( d, decimalPlace, _re_html );
14443 },
14444
14445 // HTML numeric, formatted
14446 "html-num-fmt": function ( d ) {
14447 return __numericReplace( d, decimalPlace, _re_html, _re_formatted_numeric );
14448 }
14449 },
14450 function ( key, fn ) {
14451 // Add the ordering method
14452 _ext.type.order[ key+decimalPlace+'-pre' ] = fn;
14453
14454 // For HTML types add a search formatter that will strip the HTML
14455 if ( key.match(/^html\-/) ) {
14456 _ext.type.search[ key+decimalPlace ] = _ext.type.search.html;
14457 }
14458 }
14459 );
14460 }
14461
14462
14463 // Default sort methods
14464 $.extend( _ext.type.order, {
14465 // Dates
14466 "date-pre": function ( d ) {
14467 return Date.parse( d ) || 0;
14468 },
14469
14470 // html
14471 "html-pre": function ( a ) {
14472 return _empty(a) ?
14473 '' :
14474 a.replace ?
14475 a.replace( /<.*?>/g, "" ).toLowerCase() :
14476 a+'';
14477 },
14478
14479 // string
14480 "string-pre": function ( a ) {
14481 // This is a little complex, but faster than always calling toString,
14482 // http://jsperf.com/tostring-v-check
14483 return _empty(a) ?
14484 '' :
14485 typeof a === 'string' ?
14486 a.toLowerCase() :
14487 ! a.toString ?
14488 '' :
14489 a.toString();
14490 },
14491
14492 // string-asc and -desc are retained only for compatibility with the old
14493 // sort methods
14494 "string-asc": function ( x, y ) {
14495 return ((x < y) ? -1 : ((x > y) ? 1 : 0));
14496 },
14497
14498 "string-desc": function ( x, y ) {
14499 return ((x < y) ? 1 : ((x > y) ? -1 : 0));
14500 }
14501 } );
14502
14503
14504 // Numeric sorting types - order doesn't matter here
14505 _addNumericSort( '' );
14506
14507
14508 $.extend( true, DataTable.ext.renderer, {
14509 header: {
14510 _: function ( settings, cell, column, classes ) {
14511 // No additional mark-up required
14512 // Attach a sort listener to update on sort - note that using the
14513 // `DT` namespace will allow the event to be removed automatically
14514 // on destroy, while the `dt` namespaced event is the one we are
14515 // listening for
14516 $(settings.nTable).on( 'order.dt.DT', function ( e, ctx, sorting, columns ) {
14517 if ( settings !== ctx ) { // need to check this this is the host
14518 return; // table, not a nested one
14519 }
14520
14521 var colIdx = column.idx;
14522
14523 cell
14524 .removeClass(
14525 column.sSortingClass +' '+
14526 classes.sSortAsc +' '+
14527 classes.sSortDesc
14528 )
14529 .addClass( columns[ colIdx ] == 'asc' ?
14530 classes.sSortAsc : columns[ colIdx ] == 'desc' ?
14531 classes.sSortDesc :
14532 column.sSortingClass
14533 );
14534 } );
14535 },
14536
14537 jqueryui: function ( settings, cell, column, classes ) {
14538 $('<div/>')
14539 .addClass( classes.sSortJUIWrapper )
14540 .append( cell.contents() )
14541 .append( $('<span/>')
14542 .addClass( classes.sSortIcon+' '+column.sSortingClassJUI )
14543 )
14544 .appendTo( cell );
14545
14546 // Attach a sort listener to update on sort
14547 $(settings.nTable).on( 'order.dt.DT', function ( e, ctx, sorting, columns ) {
14548 if ( settings !== ctx ) {
14549 return;
14550 }
14551
14552 var colIdx = column.idx;
14553
14554 cell
14555 .removeClass( classes.sSortAsc +" "+classes.sSortDesc )
14556 .addClass( columns[ colIdx ] == 'asc' ?
14557 classes.sSortAsc : columns[ colIdx ] == 'desc' ?
14558 classes.sSortDesc :
14559 column.sSortingClass
14560 );
14561
14562 cell
14563 .find( 'span.'+classes.sSortIcon )
14564 .removeClass(
14565 classes.sSortJUIAsc +" "+
14566 classes.sSortJUIDesc +" "+
14567 classes.sSortJUI +" "+
14568 classes.sSortJUIAscAllowed +" "+
14569 classes.sSortJUIDescAllowed
14570 )
14571 .addClass( columns[ colIdx ] == 'asc' ?
14572 classes.sSortJUIAsc : columns[ colIdx ] == 'desc' ?
14573 classes.sSortJUIDesc :
14574 column.sSortingClassJUI
14575 );
14576 } );
14577 }
14578 }
14579 } );
14580
14581 /*
14582 * Public helper functions. These aren't used internally by DataTables, or
14583 * called by any of the options passed into DataTables, but they can be used
14584 * externally by developers working with DataTables. They are helper functions
14585 * to make working with DataTables a little bit easier.
14586 */
14587
14588 /**
14589 * Helpers for `columns.render`.
14590 *
14591 * The options defined here can be used with the `columns.render` initialisation
14592 * option to provide a display renderer. The following functions are defined:
14593 *
14594 * * `number` - Will format numeric data (defined by `columns.data`) for
14595 * display, retaining the original unformatted data for sorting and filtering.
14596 * It takes 4 parameters:
14597 * * `string` - Thousands grouping separator
14598 * * `string` - Decimal point indicator
14599 * * `integer` - Number of decimal points to show
14600 * * `string` (optional) - Prefix.
14601 *
14602 * @example
14603 * // Column definition using the number renderer
14604 * {
14605 * data: "salary",
14606 * render: $.fn.dataTable.render.number( '\'', '.', 0, '$' )
14607 * }
14608 *
14609 * @namespace
14610 */
14611 DataTable.render = {
14612 number: function ( thousands, decimal, precision, prefix ) {
14613 return {
14614 display: function ( d ) {
14615 if ( typeof d !== 'number' && typeof d !== 'string' ) {
14616 return d;
14617 }
14618
14619 var negative = d < 0 ? '-' : '';
14620 d = Math.abs( parseFloat( d ) );
14621
14622 var intPart = parseInt( d, 10 );
14623 var floatPart = precision ?
14624 decimal+(d - intPart).toFixed( precision ).substring( 2 ):
14625 '';
14626
14627 return negative + (prefix||'') +
14628 intPart.toString().replace(
14629 /\B(?=(\d{3})+(?!\d))/g, thousands
14630 ) +
14631 floatPart;
14632 }
14633 };
14634 }
14635 };
14636
14637
14638 /*
14639 * This is really a good bit rubbish this method of exposing the internal methods
14640 * publicly... - To be fixed in 2.0 using methods on the prototype
14641 */
14642
14643
14644 /**
14645 * Create a wrapper function for exporting an internal functions to an external API.
14646 * @param {string} fn API function name
14647 * @returns {function} wrapped function
14648 * @memberof DataTable#internal
14649 */
14650 function _fnExternApiFunc (fn)
14651 {
14652 return function() {
14653 var args = [_fnSettingsFromNode( this[DataTable.ext.iApiIndex] )].concat(
14654 Array.prototype.slice.call(arguments)
14655 );
14656 return DataTable.ext.internal[fn].apply( this, args );
14657 };
14658 }
14659
14660
14661 /**
14662 * Reference to internal functions for use by plug-in developers. Note that
14663 * these methods are references to internal functions and are considered to be
14664 * private. If you use these methods, be aware that they are liable to change
14665 * between versions.
14666 * @namespace
14667 */
14668 $.extend( DataTable.ext.internal, {
14669 _fnExternApiFunc: _fnExternApiFunc,
14670 _fnBuildAjax: _fnBuildAjax,
14671 _fnAjaxUpdate: _fnAjaxUpdate,
14672 _fnAjaxParameters: _fnAjaxParameters,
14673 _fnAjaxUpdateDraw: _fnAjaxUpdateDraw,
14674 _fnAjaxDataSrc: _fnAjaxDataSrc,
14675 _fnAddColumn: _fnAddColumn,
14676 _fnColumnOptions: _fnColumnOptions,
14677 _fnAdjustColumnSizing: _fnAdjustColumnSizing,
14678 _fnVisibleToColumnIndex: _fnVisibleToColumnIndex,
14679 _fnColumnIndexToVisible: _fnColumnIndexToVisible,
14680 _fnVisbleColumns: _fnVisbleColumns,
14681 _fnGetColumns: _fnGetColumns,
14682 _fnColumnTypes: _fnColumnTypes,
14683 _fnApplyColumnDefs: _fnApplyColumnDefs,
14684 _fnHungarianMap: _fnHungarianMap,
14685 _fnCamelToHungarian: _fnCamelToHungarian,
14686 _fnLanguageCompat: _fnLanguageCompat,
14687 _fnBrowserDetect: _fnBrowserDetect,
14688 _fnAddData: _fnAddData,
14689 _fnAddTr: _fnAddTr,
14690 _fnNodeToDataIndex: _fnNodeToDataIndex,
14691 _fnNodeToColumnIndex: _fnNodeToColumnIndex,
14692 _fnGetCellData: _fnGetCellData,
14693 _fnSetCellData: _fnSetCellData,
14694 _fnSplitObjNotation: _fnSplitObjNotation,
14695 _fnGetObjectDataFn: _fnGetObjectDataFn,
14696 _fnSetObjectDataFn: _fnSetObjectDataFn,
14697 _fnGetDataMaster: _fnGetDataMaster,
14698 _fnClearTable: _fnClearTable,
14699 _fnDeleteIndex: _fnDeleteIndex,
14700 _fnInvalidate: _fnInvalidate,
14701 _fnGetRowElements: _fnGetRowElements,
14702 _fnCreateTr: _fnCreateTr,
14703 _fnBuildHead: _fnBuildHead,
14704 _fnDrawHead: _fnDrawHead,
14705 _fnDraw: _fnDraw,
14706 _fnReDraw: _fnReDraw,
14707 _fnAddOptionsHtml: _fnAddOptionsHtml,
14708 _fnDetectHeader: _fnDetectHeader,
14709 _fnGetUniqueThs: _fnGetUniqueThs,
14710 _fnFeatureHtmlFilter: _fnFeatureHtmlFilter,
14711 _fnFilterComplete: _fnFilterComplete,
14712 _fnFilterCustom: _fnFilterCustom,
14713 _fnFilterColumn: _fnFilterColumn,
14714 _fnFilter: _fnFilter,
14715 _fnFilterCreateSearch: _fnFilterCreateSearch,
14716 _fnEscapeRegex: _fnEscapeRegex,
14717 _fnFilterData: _fnFilterData,
14718 _fnFeatureHtmlInfo: _fnFeatureHtmlInfo,
14719 _fnUpdateInfo: _fnUpdateInfo,
14720 _fnInfoMacros: _fnInfoMacros,
14721 _fnInitialise: _fnInitialise,
14722 _fnInitComplete: _fnInitComplete,
14723 _fnLengthChange: _fnLengthChange,
14724 _fnFeatureHtmlLength: _fnFeatureHtmlLength,
14725 _fnFeatureHtmlPaginate: _fnFeatureHtmlPaginate,
14726 _fnPageChange: _fnPageChange,
14727 _fnFeatureHtmlProcessing: _fnFeatureHtmlProcessing,
14728 _fnProcessingDisplay: _fnProcessingDisplay,
14729 _fnFeatureHtmlTable: _fnFeatureHtmlTable,
14730 _fnScrollDraw: _fnScrollDraw,
14731 _fnApplyToChildren: _fnApplyToChildren,
14732 _fnCalculateColumnWidths: _fnCalculateColumnWidths,
14733 _fnThrottle: _fnThrottle,
14734 _fnConvertToWidth: _fnConvertToWidth,
14735 _fnScrollingWidthAdjust: _fnScrollingWidthAdjust,
14736 _fnGetWidestNode: _fnGetWidestNode,
14737 _fnGetMaxLenString: _fnGetMaxLenString,
14738 _fnStringToCss: _fnStringToCss,
14739 _fnScrollBarWidth: _fnScrollBarWidth,
14740 _fnSortFlatten: _fnSortFlatten,
14741 _fnSort: _fnSort,
14742 _fnSortAria: _fnSortAria,
14743 _fnSortListener: _fnSortListener,
14744 _fnSortAttachListener: _fnSortAttachListener,
14745 _fnSortingClasses: _fnSortingClasses,
14746 _fnSortData: _fnSortData,
14747 _fnSaveState: _fnSaveState,
14748 _fnLoadState: _fnLoadState,
14749 _fnSettingsFromNode: _fnSettingsFromNode,
14750 _fnLog: _fnLog,
14751 _fnMap: _fnMap,
14752 _fnBindAction: _fnBindAction,
14753 _fnCallbackReg: _fnCallbackReg,
14754 _fnCallbackFire: _fnCallbackFire,
14755 _fnLengthOverflow: _fnLengthOverflow,
14756 _fnRenderer: _fnRenderer,
14757 _fnDataSource: _fnDataSource,
14758 _fnRowAttributes: _fnRowAttributes,
14759 _fnCalculateEnd: function () {} // Used by a lot of plug-ins, but redundant
14760 // in 1.10, so this dead-end function is
14761 // added to prevent errors
14762 } );
14763
14764
14765 // jQuery access
14766 $.fn.dataTable = DataTable;
14767
14768 // Legacy aliases
14769 $.fn.dataTableSettings = DataTable.settings;
14770 $.fn.dataTableExt = DataTable.ext;
14771
14772 // With a capital `D` we return a DataTables API instance rather than a
14773 // jQuery object
14774 $.fn.DataTable = function ( opts ) {
14775 return $(this).dataTable( opts ).api();
14776 };
14777
14778 // All properties that are available to $.fn.dataTable should also be
14779 // available on $.fn.DataTable
14780 $.each( DataTable, function ( prop, val ) {
14781 $.fn.DataTable[ prop ] = val;
14782 } );
14783
14784
14785 // Information about events fired by DataTables - for documentation.
14786 /**
14787 * Draw event, fired whenever the table is redrawn on the page, at the same
14788 * point as fnDrawCallback. This may be useful for binding events or
14789 * performing calculations when the table is altered at all.
14790 * @name DataTable#draw.dt
14791 * @event
14792 * @param {event} e jQuery event object
14793 * @param {object} o DataTables settings object {@link DataTable.models.oSettings}
14794 */
14795
14796 /**
14797 * Search event, fired when the searching applied to the table (using the
14798 * built-in global search, or column filters) is altered.
14799 * @name DataTable#search.dt
14800 * @event
14801 * @param {event} e jQuery event object
14802 * @param {object} o DataTables settings object {@link DataTable.models.oSettings}
14803 */
14804
14805 /**
14806 * Page change event, fired when the paging of the table is altered.
14807 * @name DataTable#page.dt
14808 * @event
14809 * @param {event} e jQuery event object
14810 * @param {object} o DataTables settings object {@link DataTable.models.oSettings}
14811 */
14812
14813 /**
14814 * Order event, fired when the ordering applied to the table is altered.
14815 * @name DataTable#order.dt
14816 * @event
14817 * @param {event} e jQuery event object
14818 * @param {object} o DataTables settings object {@link DataTable.models.oSettings}
14819 */
14820
14821 /**
14822 * DataTables initialisation complete event, fired when the table is fully
14823 * drawn, including Ajax data loaded, if Ajax data is required.
14824 * @name DataTable#init.dt
14825 * @event
14826 * @param {event} e jQuery event object
14827 * @param {object} oSettings DataTables settings object
14828 * @param {object} json The JSON object request from the server - only
14829 * present if client-side Ajax sourced data is used</li></ol>
14830 */
14831
14832 /**
14833 * State save event, fired when the table has changed state a new state save
14834 * is required. This event allows modification of the state saving object
14835 * prior to actually doing the save, including addition or other state
14836 * properties (for plug-ins) or modification of a DataTables core property.
14837 * @name DataTable#stateSaveParams.dt
14838 * @event
14839 * @param {event} e jQuery event object
14840 * @param {object} oSettings DataTables settings object
14841 * @param {object} json The state information to be saved
14842 */
14843
14844 /**
14845 * State load event, fired when the table is loading state from the stored
14846 * data, but prior to the settings object being modified by the saved state
14847 * - allowing modification of the saved state is required or loading of
14848 * state for a plug-in.
14849 * @name DataTable#stateLoadParams.dt
14850 * @event
14851 * @param {event} e jQuery event object
14852 * @param {object} oSettings DataTables settings object
14853 * @param {object} json The saved state information
14854 */
14855
14856 /**
14857 * State loaded event, fired when state has been loaded from stored data and
14858 * the settings object has been modified by the loaded data.
14859 * @name DataTable#stateLoaded.dt
14860 * @event
14861 * @param {event} e jQuery event object
14862 * @param {object} oSettings DataTables settings object
14863 * @param {object} json The saved state information
14864 */
14865
14866 /**
14867 * Processing event, fired when DataTables is doing some kind of processing
14868 * (be it, order, searcg or anything else). It can be used to indicate to
14869 * the end user that there is something happening, or that something has
14870 * finished.
14871 * @name DataTable#processing.dt
14872 * @event
14873 * @param {event} e jQuery event object
14874 * @param {object} oSettings DataTables settings object
14875 * @param {boolean} bShow Flag for if DataTables is doing processing or not
14876 */
14877
14878 /**
14879 * Ajax (XHR) event, fired whenever an Ajax request is completed from a
14880 * request to made to the server for new data. This event is called before
14881 * DataTables processed the returned data, so it can also be used to pre-
14882 * process the data returned from the server, if needed.
14883 *
14884 * Note that this trigger is called in `fnServerData`, if you override
14885 * `fnServerData` and which to use this event, you need to trigger it in you
14886 * success function.
14887 * @name DataTable#xhr.dt
14888 * @event
14889 * @param {event} e jQuery event object
14890 * @param {object} o DataTables settings object {@link DataTable.models.oSettings}
14891 * @param {object} json JSON returned from the server
14892 *
14893 * @example
14894 * // Use a custom property returned from the server in another DOM element
14895 * $('#table').dataTable().on('xhr.dt', function (e, settings, json) {
14896 * $('#status').html( json.status );
14897 * } );
14898 *
14899 * @example
14900 * // Pre-process the data returned from the server
14901 * $('#table').dataTable().on('xhr.dt', function (e, settings, json) {
14902 * for ( var i=0, ien=json.aaData.length ; i<ien ; i++ ) {
14903 * json.aaData[i].sum = json.aaData[i].one + json.aaData[i].two;
14904 * }
14905 * // Note no return - manipulate the data directly in the JSON object.
14906 * } );
14907 */
14908
14909 /**
14910 * Destroy event, fired when the DataTable is destroyed by calling fnDestroy
14911 * or passing the bDestroy:true parameter in the initialisation object. This
14912 * can be used to remove bound events, added DOM nodes, etc.
14913 * @name DataTable#destroy.dt
14914 * @event
14915 * @param {event} e jQuery event object
14916 * @param {object} o DataTables settings object {@link DataTable.models.oSettings}
14917 */
14918
14919 /**
14920 * Page length change event, fired when number of records to show on each
14921 * page (the length) is changed.
14922 * @name DataTable#length.dt
14923 * @event
14924 * @param {event} e jQuery event object
14925 * @param {object} o DataTables settings object {@link DataTable.models.oSettings}
14926 * @param {integer} len New length
14927 */
14928
14929 /**
14930 * Column sizing has changed.
14931 * @name DataTable#column-sizing.dt
14932 * @event
14933 * @param {event} e jQuery event object
14934 * @param {object} o DataTables settings object {@link DataTable.models.oSettings}
14935 */
14936
14937 /**
14938 * Column visibility has changed.
14939 * @name DataTable#column-visibility.dt
14940 * @event
14941 * @param {event} e jQuery event object
14942 * @param {object} o DataTables settings object {@link DataTable.models.oSettings}
14943 * @param {int} column Column index
14944 * @param {bool} vis `false` if column now hidden, or `true` if visible
14945 */
14946
14947 return $.fn.dataTable;
14948 }));
14949
14950 }(window, document));
14951