· 7 years ago · Sep 30, 2018, 11:32 AM
1/*! DataTables 1.10.4
2 * ©2008-2014 SpryMedia Ltd - datatables.net/license
3 */
4
5/**
6 * @summary DataTables
7 * @description Paginate, search and order HTML tables
8 * @version 1.10.4
9 * @file jquery.dataTables.js
10 * @author SpryMedia Ltd (www.sprymedia.co.uk)
11 * @contact www.sprymedia.co.uk/contact
12 * @copyright Copyright 2008-2014 SpryMedia Ltd.
13 *
14 * This source file is free software, available under the following license:
15 * MIT license - http://datatables.net/license
16 *
17 * This source file is distributed in the hope that it will be useful, but
18 * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
19 * or FITNESS FOR A PARTICULAR PURPOSE. See the license files for details.
20 *
21 * For details please refer to: http://www.datatables.net
22 */
23
24/*jslint evil: true, undef: true, browser: true */
25/*globals $,require,jQuery,define,_selector_run,_selector_opts,_selector_first,_selector_row_indexes,_ext,_Api,_api_register,_api_registerPlural,_re_new_lines,_re_html,_re_formatted_numeric,_re_escape_regex,_empty,_intVal,_numToDecimal,_isNumber,_isHtml,_htmlNumeric,_pluck,_pluck_order,_range,_stripHtml,_unique,_fnBuildAjax,_fnAjaxUpdate,_fnAjaxParameters,_fnAjaxUpdateDraw,_fnAjaxDataSrc,_fnAddColumn,_fnColumnOptions,_fnAdjustColumnSizing,_fnVisibleToColumnIndex,_fnColumnIndexToVisible,_fnVisbleColumns,_fnGetColumns,_fnColumnTypes,_fnApplyColumnDefs,_fnHungarianMap,_fnCamelToHungarian,_fnLanguageCompat,_fnBrowserDetect,_fnAddData,_fnAddTr,_fnNodeToDataIndex,_fnNodeToColumnIndex,_fnGetCellData,_fnSetCellData,_fnSplitObjNotation,_fnGetObjectDataFn,_fnSetObjectDataFn,_fnGetDataMaster,_fnClearTable,_fnDeleteIndex,_fnInvalidate,_fnGetRowElements,_fnCreateTr,_fnBuildHead,_fnDrawHead,_fnDraw,_fnReDraw,_fnAddOptionsHtml,_fnDetectHeader,_fnGetUniqueThs,_fnFeatureHtmlFilter,_fnFilterComplete,_fnFilterCustom,_fnFilterColumn,_fnFilter,_fnFilterCreateSearch,_fnEscapeRegex,_fnFilterData,_fnFeatureHtmlInfo,_fnUpdateInfo,_fnInfoMacros,_fnInitialise,_fnInitComplete,_fnLengthChange,_fnFeatureHtmlLength,_fnFeatureHtmlPaginate,_fnPageChange,_fnFeatureHtmlProcessing,_fnProcessingDisplay,_fnFeatureHtmlTable,_fnScrollDraw,_fnApplyToChildren,_fnCalculateColumnWidths,_fnThrottle,_fnConvertToWidth,_fnScrollingWidthAdjust,_fnGetWidestNode,_fnGetMaxLenString,_fnStringToCss,_fnScrollBarWidth,_fnSortFlatten,_fnSort,_fnSortAria,_fnSortListener,_fnSortAttachListener,_fnSortingClasses,_fnSortData,_fnSaveState,_fnLoadState,_fnSettingsFromNode,_fnLog,_fnMap,_fnBindAction,_fnCallbackReg,_fnCallbackFire,_fnLengthOverflow,_fnRenderer,_fnDataSource,_fnRowAttributes*/
26
27(/** @lends <global> */function( window, document, undefined ) {
28
29(function( factory ) {
30 "use strict";
31
32 if ( typeof define === 'function' && define.amd ) {
33 // Define as an AMD module if possible
34 define( 'datatables', ['jquery'], factory );
35 }
36 else if ( typeof exports === 'object' ) {
37 // Node/CommonJS
38 factory( require( 'jquery' ) );
39 }
40 else if ( jQuery && !jQuery.fn.dataTable ) {
41 // Define using browser globals otherwise
42 // Prevent multiple instantiations if the script is loaded twice
43 factory( jQuery );
44 }
45}
46(/** @lends <global> */function( $ ) {
47 "use strict";
48
49 /**
50 * DataTables is a plug-in for the jQuery Javascript library. It is a highly
51 * flexible tool, based upon the foundations of progressive enhancement,
52 * which will add advanced interaction controls to any HTML table. For a
53 * full list of features please refer to
54 * [DataTables.net](href="http://datatables.net).
55 *
56 * Note that the `DataTable` object is not a global variable but is aliased
57 * to `jQuery.fn.DataTable` and `jQuery.fn.dataTable` through which it may
58 * be accessed.
59 *
60 * @class
61 * @param {object} [init={}] Configuration object for DataTables. Options
62 * are defined by {@link DataTable.defaults}
63 * @requires jQuery 1.7+
64 *
65 * @example
66 * // Basic initialisation
67 * $(document).ready( function {
68 * $('#example').dataTable();
69 * } );
70 *
71 * @example
72 * // Initialisation with configuration options - in this case, disable
73 * // pagination and sorting.
74 * $(document).ready( function {
75 * $('#example').dataTable( {
76 * "paginate": false,
77 * "sort": false
78 * } );
79 * } );
80 */
81 var DataTable;
82
83
84 /*
85 * It is useful to have variables which are scoped locally so only the
86 * DataTables functions can access them and they don't leak into global space.
87 * At the same time these functions are often useful over multiple files in the
88 * core and API, so we list, or at least document, all variables which are used
89 * by DataTables as private variables here. This also ensures that there is no
90 * clashing of variable names and that they can easily referenced for reuse.
91 */
92
93
94 // Defined else where
95 // _selector_run
96 // _selector_opts
97 // _selector_first
98 // _selector_row_indexes
99
100 var _ext; // DataTable.ext
101 var _Api; // DataTable.Api
102 var _api_register; // DataTable.Api.register
103 var _api_registerPlural; // DataTable.Api.registerPlural
104
105 var _re_dic = {};
106 var _re_new_lines = /[\r\n]/g;
107 var _re_html = /<.*?>/g;
108 var _re_date_start = /^[\w\+\-]/;
109 var _re_date_end = /[\w\+\-]$/;
110
111 // Escape regular expression special characters
112 var _re_escape_regex = new RegExp( '(\\' + [ '/', '.', '*', '+', '?', '|', '(', ')', '[', ']', '{', '}', '\\', '$', '^', '-' ].join('|\\') + ')', 'g' );
113
114 // U+2009 is thin space and U+202F is narrow no-break space, both used in many
115 // standards as thousands separators
116 var _re_formatted_numeric = /[',$£€¥%\u2009\u202F]/g;
117
118
119 var _empty = function ( d ) {
120 return !d || d === true || d === '-' ? true : false;
121 };
122
123
124 var _intVal = function ( s ) {
125 var integer = parseInt( s, 10 );
126 return !isNaN(integer) && isFinite(s) ? integer : null;
127 };
128
129 // Convert from a formatted number with characters other than `.` as the
130 // decimal place, to a Javascript number
131 var _numToDecimal = function ( num, decimalPoint ) {
132 // Cache created regular expressions for speed as this function is called often
133 if ( ! _re_dic[ decimalPoint ] ) {
134 _re_dic[ decimalPoint ] = new RegExp( _fnEscapeRegex( decimalPoint ), 'g' );
135 }
136 return typeof num === 'string' && decimalPoint !== '.' ?
137 num.replace( /\./g, '' ).replace( _re_dic[ decimalPoint ], '.' ) :
138 num;
139 };
140
141
142 var _isNumber = function ( d, decimalPoint, formatted ) {
143 var strType = typeof d === 'string';
144
145 if ( decimalPoint && strType ) {
146 d = _numToDecimal( d, decimalPoint );
147 }
148
149 if ( formatted && strType ) {
150 d = d.replace( _re_formatted_numeric, '' );
151 }
152
153 return _empty( d ) || (!isNaN( parseFloat(d) ) && isFinite( d ));
154 };
155
156
157 // A string without HTML in it can be considered to be HTML still
158 var _isHtml = function ( d ) {
159 return _empty( d ) || typeof d === 'string';
160 };
161
162
163 var _htmlNumeric = function ( d, decimalPoint, formatted ) {
164 if ( _empty( d ) ) {
165 return true;
166 }
167
168 var html = _isHtml( d );
169 return ! html ?
170 null :
171 _isNumber( _stripHtml( d ), decimalPoint, formatted ) ?
172 true :
173 null;
174 };
175
176
177 var _pluck = function ( a, prop, prop2 ) {
178 var out = [];
179 var i=0, ien=a.length;
180
181 // Could have the test in the loop for slightly smaller code, but speed
182 // is essential here
183 if ( prop2 !== undefined ) {
184 for ( ; i<ien ; i++ ) {
185 if ( a[i] && a[i][ prop ] ) {
186 out.push( a[i][ prop ][ prop2 ] );
187 }
188 }
189 }
190 else {
191 for ( ; i<ien ; i++ ) {
192 if ( a[i] ) {
193 out.push( a[i][ prop ] );
194 }
195 }
196 }
197
198 return out;
199 };
200
201
202 // Basically the same as _pluck, but rather than looping over `a` we use `order`
203 // as the indexes to pick from `a`
204 var _pluck_order = function ( a, order, prop, prop2 )
205 {
206 var out = [];
207 var i=0, ien=order.length;
208
209 // Could have the test in the loop for slightly smaller code, but speed
210 // is essential here
211 if ( prop2 !== undefined ) {
212 for ( ; i<ien ; i++ ) {
213 if ( a[ order[i] ][ prop ] ) {
214 out.push( a[ order[i] ][ prop ][ prop2 ] );
215 }
216 }
217 }
218 else {
219 for ( ; i<ien ; i++ ) {
220 out.push( a[ order[i] ][ prop ] );
221 }
222 }
223
224 return out;
225 };
226
227
228 var _range = function ( len, start )
229 {
230 var out = [];
231 var end;
232
233 if ( start === undefined ) {
234 start = 0;
235 end = len;
236 }
237 else {
238 end = start;
239 start = len;
240 }
241
242 for ( var i=start ; i<end ; i++ ) {
243 out.push( i );
244 }
245
246 return out;
247 };
248
249
250 var _removeEmpty = function ( a )
251 {
252 var out = [];
253
254 for ( var i=0, ien=a.length ; i<ien ; i++ ) {
255 if ( a[i] ) { // careful - will remove all falsy values!
256 out.push( a[i] );
257 }
258 }
259
260 return out;
261 };
262
263
264 var _stripHtml = function ( d ) {
265 return d.replace( _re_html, '' );
266 };
267
268
269 /**
270 * Find the unique elements in a source array.
271 *
272 * @param {array} src Source array
273 * @return {array} Array of unique items
274 * @ignore
275 */
276 var _unique = function ( src )
277 {
278 // A faster unique method is to use object keys to identify used values,
279 // but this doesn't work with arrays or objects, which we must also
280 // consider. See jsperf.com/compare-array-unique-versions/4 for more
281 // information.
282 var
283 out = [],
284 val,
285 i, ien=src.length,
286 j, k=0;
287
288 again: for ( i=0 ; i<ien ; i++ ) {
289 val = src[i];
290
291 for ( j=0 ; j<k ; j++ ) {
292 if ( out[j] === val ) {
293 continue again;
294 }
295 }
296
297 out.push( val );
298 k++;
299 }
300
301 return out;
302 };
303
304
305
306 /**
307 * Create a mapping object that allows camel case parameters to be looked up
308 * for their Hungarian counterparts. The mapping is stored in a private
309 * parameter called `_hungarianMap` which can be accessed on the source object.
310 * @param {object} o
311 * @memberof DataTable#oApi
312 */
313 function _fnHungarianMap ( o )
314 {
315 var
316 hungarian = 'a aa ai ao as b fn i m o s ',
317 match,
318 newKey,
319 map = {};
320
321 $.each( o, function (key, val) {
322 match = key.match(/^([^A-Z]+?)([A-Z])/);
323
324 if ( match && hungarian.indexOf(match[1]+' ') !== -1 )
325 {
326 newKey = key.replace( match[0], match[2].toLowerCase() );
327 map[ newKey ] = key;
328
329 if ( match[1] === 'o' )
330 {
331 _fnHungarianMap( o[key] );
332 }
333 }
334 } );
335
336 o._hungarianMap = map;
337 }
338
339
340 /**
341 * Convert from camel case parameters to Hungarian, based on a Hungarian map
342 * created by _fnHungarianMap.
343 * @param {object} src The model object which holds all parameters that can be
344 * mapped.
345 * @param {object} user The object to convert from camel case to Hungarian.
346 * @param {boolean} force When set to `true`, properties which already have a
347 * Hungarian value in the `user` object will be overwritten. Otherwise they
348 * won't be.
349 * @memberof DataTable#oApi
350 */
351 function _fnCamelToHungarian ( src, user, force )
352 {
353 if ( ! src._hungarianMap ) {
354 _fnHungarianMap( src );
355 }
356
357 var hungarianKey;
358
359 $.each( user, function (key, val) {
360 hungarianKey = src._hungarianMap[ key ];
361
362 if ( hungarianKey !== undefined && (force || user[hungarianKey] === undefined) )
363 {
364 // For objects, we need to buzz down into the object to copy parameters
365 if ( hungarianKey.charAt(0) === 'o' )
366 {
367 // Copy the camelCase options over to the hungarian
368 if ( ! user[ hungarianKey ] ) {
369 user[ hungarianKey ] = {};
370 }
371 $.extend( true, user[hungarianKey], user[key] );
372
373 _fnCamelToHungarian( src[hungarianKey], user[hungarianKey], force );
374 }
375 else {
376 user[hungarianKey] = user[ key ];
377 }
378 }
379 } );
380 }
381
382
383 /**
384 * Language compatibility - when certain options are given, and others aren't, we
385 * need to duplicate the values over, in order to provide backwards compatibility
386 * with older language files.
387 * @param {object} oSettings dataTables settings object
388 * @memberof DataTable#oApi
389 */
390 function _fnLanguageCompat( lang )
391 {
392 var defaults = DataTable.defaults.oLanguage;
393 var zeroRecords = lang.sZeroRecords;
394
395 /* Backwards compatibility - if there is no sEmptyTable given, then use the same as
396 * sZeroRecords - assuming that is given.
397 */
398 if ( ! lang.sEmptyTable && zeroRecords &&
399 defaults.sEmptyTable === "No data available in table" )
400 {
401 _fnMap( lang, lang, 'sZeroRecords', 'sEmptyTable' );
402 }
403
404 /* Likewise with loading records */
405 if ( ! lang.sLoadingRecords && zeroRecords &&
406 defaults.sLoadingRecords === "Loading..." )
407 {
408 _fnMap( lang, lang, 'sZeroRecords', 'sLoadingRecords' );
409 }
410
411 // Old parameter name of the thousands separator mapped onto the new
412 if ( lang.sInfoThousands ) {
413 lang.sThousands = lang.sInfoThousands;
414 }
415
416 var decimal = lang.sDecimal;
417 if ( decimal ) {
418 _addNumericSort( decimal );
419 }
420 }
421
422
423 /**
424 * Map one parameter onto another
425 * @param {object} o Object to map
426 * @param {*} knew The new parameter name
427 * @param {*} old The old parameter name
428 */
429 var _fnCompatMap = function ( o, knew, old ) {
430 if ( o[ knew ] !== undefined ) {
431 o[ old ] = o[ knew ];
432 }
433 };
434
435
436 /**
437 * Provide backwards compatibility for the main DT options. Note that the new
438 * options are mapped onto the old parameters, so this is an external interface
439 * change only.
440 * @param {object} init Object to map
441 */
442 function _fnCompatOpts ( init )
443 {
444 _fnCompatMap( init, 'ordering', 'bSort' );
445 _fnCompatMap( init, 'orderMulti', 'bSortMulti' );
446 _fnCompatMap( init, 'orderClasses', 'bSortClasses' );
447 _fnCompatMap( init, 'orderCellsTop', 'bSortCellsTop' );
448 _fnCompatMap( init, 'order', 'aaSorting' );
449 _fnCompatMap( init, 'orderFixed', 'aaSortingFixed' );
450 _fnCompatMap( init, 'paging', 'bPaginate' );
451 _fnCompatMap( init, 'pagingType', 'sPaginationType' );
452 _fnCompatMap( init, 'pageLength', 'iDisplayLength' );
453 _fnCompatMap( init, 'searching', 'bFilter' );
454
455 // Column search objects are in an array, so it needs to be converted
456 // element by element
457 var searchCols = init.aoSearchCols;
458
459 if ( searchCols ) {
460 for ( var i=0, ien=searchCols.length ; i<ien ; i++ ) {
461 if ( searchCols[i] ) {
462 _fnCamelToHungarian( DataTable.models.oSearch, searchCols[i] );
463 }
464 }
465 }
466 }
467
468
469 /**
470 * Provide backwards compatibility for column options. Note that the new options
471 * are mapped onto the old parameters, so this is an external interface change
472 * only.
473 * @param {object} init Object to map
474 */
475 function _fnCompatCols ( init )
476 {
477 _fnCompatMap( init, 'orderable', 'bSortable' );
478 _fnCompatMap( init, 'orderData', 'aDataSort' );
479 _fnCompatMap( init, 'orderSequence', 'asSorting' );
480 _fnCompatMap( init, 'orderDataType', 'sortDataType' );
481 }
482
483
484 /**
485 * Browser feature detection for capabilities, quirks
486 * @param {object} settings dataTables settings object
487 * @memberof DataTable#oApi
488 */
489 function _fnBrowserDetect( settings )
490 {
491 var browser = settings.oBrowser;
492
493 // Scrolling feature / quirks detection
494 var n = $('<div/>')
495 .css( {
496 position: 'absolute',
497 top: 0,
498 left: 0,
499 height: 1,
500 width: 1,
501 overflow: 'hidden'
502 } )
503 .append(
504 $('<div/>')
505 .css( {
506 position: 'absolute',
507 top: 1,
508 left: 1,
509 width: 100,
510 overflow: 'scroll'
511 } )
512 .append(
513 $('<div class="test"/>')
514 .css( {
515 width: '100%',
516 height: 10
517 } )
518 )
519 )
520 .appendTo( 'body' );
521
522 var test = n.find('.test');
523
524 // IE6/7 will oversize a width 100% element inside a scrolling element, to
525 // include the width of the scrollbar, while other browsers ensure the inner
526 // element is contained without forcing scrolling
527 browser.bScrollOversize = test[0].offsetWidth === 100;
528
529 // In rtl text layout, some browsers (most, but not all) will place the
530 // scrollbar on the left, rather than the right.
531 browser.bScrollbarLeft = test.offset().left !== 1;
532
533 n.remove();
534 }
535
536
537 /**
538 * Array.prototype reduce[Right] method, used for browsers which don't support
539 * JS 1.6. Done this way to reduce code size, since we iterate either way
540 * @param {object} settings dataTables settings object
541 * @memberof DataTable#oApi
542 */
543 function _fnReduce ( that, fn, init, start, end, inc )
544 {
545 var
546 i = start,
547 value,
548 isSet = false;
549
550 if ( init !== undefined ) {
551 value = init;
552 isSet = true;
553 }
554
555 while ( i !== end ) {
556 if ( ! that.hasOwnProperty(i) ) {
557 continue;
558 }
559
560 value = isSet ?
561 fn( value, that[i], i, that ) :
562 that[i];
563
564 isSet = true;
565 i += inc;
566 }
567
568 return value;
569 }
570
571 /**
572 * Add a column to the list used for the table with default values
573 * @param {object} oSettings dataTables settings object
574 * @param {node} nTh The th element for this column
575 * @memberof DataTable#oApi
576 */
577 function _fnAddColumn( oSettings, nTh )
578 {
579 // Add column to aoColumns array
580 var oDefaults = DataTable.defaults.column;
581 var iCol = oSettings.aoColumns.length;
582 var oCol = $.extend( {}, DataTable.models.oColumn, oDefaults, {
583 "nTh": nTh ? nTh : document.createElement('th'),
584 "sTitle": oDefaults.sTitle ? oDefaults.sTitle : nTh ? nTh.innerHTML : '',
585 "aDataSort": oDefaults.aDataSort ? oDefaults.aDataSort : [iCol],
586 "mData": oDefaults.mData ? oDefaults.mData : iCol,
587 idx: iCol
588 } );
589 oSettings.aoColumns.push( oCol );
590
591 // Add search object for column specific search. Note that the `searchCols[ iCol ]`
592 // passed into extend can be undefined. This allows the user to give a default
593 // with only some of the parameters defined, and also not give a default
594 var searchCols = oSettings.aoPreSearchCols;
595 searchCols[ iCol ] = $.extend( {}, DataTable.models.oSearch, searchCols[ iCol ] );
596
597 // Use the default column options function to initialise classes etc
598 _fnColumnOptions( oSettings, iCol, null );
599 }
600
601
602 /**
603 * Apply options for a column
604 * @param {object} oSettings dataTables settings object
605 * @param {int} iCol column index to consider
606 * @param {object} oOptions object with sType, bVisible and bSearchable etc
607 * @memberof DataTable#oApi
608 */
609 function _fnColumnOptions( oSettings, iCol, oOptions )
610 {
611 var oCol = oSettings.aoColumns[ iCol ];
612 var oClasses = oSettings.oClasses;
613 var th = $(oCol.nTh);
614
615 // Try to get width information from the DOM. We can't get it from CSS
616 // as we'd need to parse the CSS stylesheet. `width` option can override
617 if ( ! oCol.sWidthOrig ) {
618 // Width attribute
619 oCol.sWidthOrig = th.attr('width') || null;
620
621 // Style attribute
622 var t = (th.attr('style') || '').match(/width:\s*(\d+[pxem%]+)/);
623 if ( t ) {
624 oCol.sWidthOrig = t[1];
625 }
626 }
627
628 /* User specified column options */
629 if ( oOptions !== undefined && oOptions !== null )
630 {
631 // Backwards compatibility
632 _fnCompatCols( oOptions );
633
634 // Map camel case parameters to their Hungarian counterparts
635 _fnCamelToHungarian( DataTable.defaults.column, oOptions );
636
637 /* Backwards compatibility for mDataProp */
638 if ( oOptions.mDataProp !== undefined && !oOptions.mData )
639 {
640 oOptions.mData = oOptions.mDataProp;
641 }
642
643 if ( oOptions.sType )
644 {
645 oCol._sManualType = oOptions.sType;
646 }
647
648 // `class` is a reserved word in Javascript, so we need to provide
649 // the ability to use a valid name for the camel case input
650 if ( oOptions.className && ! oOptions.sClass )
651 {
652 oOptions.sClass = oOptions.className;
653 }
654
655 $.extend( oCol, oOptions );
656 _fnMap( oCol, oOptions, "sWidth", "sWidthOrig" );
657
658 /* iDataSort to be applied (backwards compatibility), but aDataSort will take
659 * priority if defined
660 */
661 if ( typeof oOptions.iDataSort === 'number' )
662 {
663 oCol.aDataSort = [ oOptions.iDataSort ];
664 }
665 _fnMap( oCol, oOptions, "aDataSort" );
666 }
667
668 /* Cache the data get and set functions for speed */
669 var mDataSrc = oCol.mData;
670 var mData = _fnGetObjectDataFn( mDataSrc );
671 var mRender = oCol.mRender ? _fnGetObjectDataFn( oCol.mRender ) : null;
672
673 var attrTest = function( src ) {
674 return typeof src === 'string' && src.indexOf('@') !== -1;
675 };
676 oCol._bAttrSrc = $.isPlainObject( mDataSrc ) && (
677 attrTest(mDataSrc.sort) || attrTest(mDataSrc.type) || attrTest(mDataSrc.filter)
678 );
679
680 oCol.fnGetData = function (rowData, type, meta) {
681 var innerData = mData( rowData, type, undefined, meta );
682
683 return mRender && type ?
684 mRender( innerData, type, rowData, meta ) :
685 innerData;
686 };
687 oCol.fnSetData = function ( rowData, val, meta ) {
688 return _fnSetObjectDataFn( mDataSrc )( rowData, val, meta );
689 };
690
691 // Indicate if DataTables should read DOM data as an object or array
692 // Used in _fnGetRowElements
693 if ( typeof mDataSrc !== 'number' ) {
694 oSettings._rowReadObject = true;
695 }
696
697 /* Feature sorting overrides column specific when off */
698 if ( !oSettings.oFeatures.bSort )
699 {
700 oCol.bSortable = false;
701 th.addClass( oClasses.sSortableNone ); // Have to add class here as order event isn't called
702 }
703
704 /* Check that the class assignment is correct for sorting */
705 var bAsc = $.inArray('asc', oCol.asSorting) !== -1;
706 var bDesc = $.inArray('desc', oCol.asSorting) !== -1;
707 if ( !oCol.bSortable || (!bAsc && !bDesc) )
708 {
709 oCol.sSortingClass = oClasses.sSortableNone;
710 oCol.sSortingClassJUI = "";
711 }
712 else if ( bAsc && !bDesc )
713 {
714 oCol.sSortingClass = oClasses.sSortableAsc;
715 oCol.sSortingClassJUI = oClasses.sSortJUIAscAllowed;
716 }
717 else if ( !bAsc && bDesc )
718 {
719 oCol.sSortingClass = oClasses.sSortableDesc;
720 oCol.sSortingClassJUI = oClasses.sSortJUIDescAllowed;
721 }
722 else
723 {
724 oCol.sSortingClass = oClasses.sSortable;
725 oCol.sSortingClassJUI = oClasses.sSortJUI;
726 }
727 }
728
729
730 /**
731 * Adjust the table column widths for new data. Note: you would probably want to
732 * do a redraw after calling this function!
733 * @param {object} settings dataTables settings object
734 * @memberof DataTable#oApi
735 */
736 function _fnAdjustColumnSizing ( settings )
737 {
738 /* Not interested in doing column width calculation if auto-width is disabled */
739 if ( settings.oFeatures.bAutoWidth !== false )
740 {
741 var columns = settings.aoColumns;
742
743 _fnCalculateColumnWidths( settings );
744 for ( var i=0 , iLen=columns.length ; i<iLen ; i++ )
745 {
746 columns[i].nTh.style.width = columns[i].sWidth;
747 }
748 }
749
750 var scroll = settings.oScroll;
751 if ( scroll.sY !== '' || scroll.sX !== '')
752 {
753 _fnScrollDraw( settings );
754 }
755
756 _fnCallbackFire( settings, null, 'column-sizing', [settings] );
757 }
758
759
760 /**
761 * Covert the index of a visible column to the index in the data array (take account
762 * of hidden columns)
763 * @param {object} oSettings dataTables settings object
764 * @param {int} iMatch Visible column index to lookup
765 * @returns {int} i the data index
766 * @memberof DataTable#oApi
767 */
768 function _fnVisibleToColumnIndex( oSettings, iMatch )
769 {
770 var aiVis = _fnGetColumns( oSettings, 'bVisible' );
771
772 return typeof aiVis[iMatch] === 'number' ?
773 aiVis[iMatch] :
774 null;
775 }
776
777
778 /**
779 * Covert the index of an index in the data array and convert it to the visible
780 * column index (take account of hidden columns)
781 * @param {int} iMatch Column index to lookup
782 * @param {object} oSettings dataTables settings object
783 * @returns {int} i the data index
784 * @memberof DataTable#oApi
785 */
786 function _fnColumnIndexToVisible( oSettings, iMatch )
787 {
788 var aiVis = _fnGetColumns( oSettings, 'bVisible' );
789 var iPos = $.inArray( iMatch, aiVis );
790
791 return iPos !== -1 ? iPos : null;
792 }
793
794
795 /**
796 * Get the number of visible columns
797 * @param {object} oSettings dataTables settings object
798 * @returns {int} i the number of visible columns
799 * @memberof DataTable#oApi
800 */
801 function _fnVisbleColumns( oSettings )
802 {
803 return _fnGetColumns( oSettings, 'bVisible' ).length;
804 }
805
806
807 /**
808 * Get an array of column indexes that match a given property
809 * @param {object} oSettings dataTables settings object
810 * @param {string} sParam Parameter in aoColumns to look for - typically
811 * bVisible or bSearchable
812 * @returns {array} Array of indexes with matched properties
813 * @memberof DataTable#oApi
814 */
815 function _fnGetColumns( oSettings, sParam )
816 {
817 var a = [];
818
819 $.map( oSettings.aoColumns, function(val, i) {
820 if ( val[sParam] ) {
821 a.push( i );
822 }
823 } );
824
825 return a;
826 }
827
828
829 /**
830 * Calculate the 'type' of a column
831 * @param {object} settings dataTables settings object
832 * @memberof DataTable#oApi
833 */
834 function _fnColumnTypes ( settings )
835 {
836 var columns = settings.aoColumns;
837 var data = settings.aoData;
838 var types = DataTable.ext.type.detect;
839 var i, ien, j, jen, k, ken;
840 var col, cell, detectedType, cache;
841
842 // For each column, spin over the
843 for ( i=0, ien=columns.length ; i<ien ; i++ ) {
844 col = columns[i];
845 cache = [];
846
847 if ( ! col.sType && col._sManualType ) {
848 col.sType = col._sManualType;
849 }
850 else if ( ! col.sType ) {
851 for ( j=0, jen=types.length ; j<jen ; j++ ) {
852 for ( k=0, ken=data.length ; k<ken ; k++ ) {
853 // Use a cache array so we only need to get the type data
854 // from the formatter once (when using multiple detectors)
855 if ( cache[k] === undefined ) {
856 cache[k] = _fnGetCellData( settings, k, i, 'type' );
857 }
858
859 detectedType = types[j]( cache[k], settings );
860
861 // If null, then this type can't apply to this column, so
862 // rather than testing all cells, break out. There is an
863 // exception for the last type which is `html`. We need to
864 // scan all rows since it is possible to mix string and HTML
865 // types
866 if ( ! detectedType && j !== types.length-1 ) {
867 break;
868 }
869
870 // Only a single match is needed for html type since it is
871 // bottom of the pile and very similar to string
872 if ( detectedType === 'html' ) {
873 break;
874 }
875 }
876
877 // Type is valid for all data points in the column - use this
878 // type
879 if ( detectedType ) {
880 col.sType = detectedType;
881 break;
882 }
883 }
884
885 // Fall back - if no type was detected, always use string
886 if ( ! col.sType ) {
887 col.sType = 'string';
888 }
889 }
890 }
891 }
892
893
894 /**
895 * Take the column definitions and static columns arrays and calculate how
896 * they relate to column indexes. The callback function will then apply the
897 * definition found for a column to a suitable configuration object.
898 * @param {object} oSettings dataTables settings object
899 * @param {array} aoColDefs The aoColumnDefs array that is to be applied
900 * @param {array} aoCols The aoColumns array that defines columns individually
901 * @param {function} fn Callback function - takes two parameters, the calculated
902 * column index and the definition for that column.
903 * @memberof DataTable#oApi
904 */
905 function _fnApplyColumnDefs( oSettings, aoColDefs, aoCols, fn )
906 {
907 var i, iLen, j, jLen, k, kLen, def;
908 var columns = oSettings.aoColumns;
909
910 // Column definitions with aTargets
911 if ( aoColDefs )
912 {
913 /* Loop over the definitions array - loop in reverse so first instance has priority */
914 for ( i=aoColDefs.length-1 ; i>=0 ; i-- )
915 {
916 def = aoColDefs[i];
917
918 /* Each definition can target multiple columns, as it is an array */
919 var aTargets = def.targets !== undefined ?
920 def.targets :
921 def.aTargets;
922
923 if ( ! $.isArray( aTargets ) )
924 {
925 aTargets = [ aTargets ];
926 }
927
928 for ( j=0, jLen=aTargets.length ; j<jLen ; j++ )
929 {
930 if ( typeof aTargets[j] === 'number' && aTargets[j] >= 0 )
931 {
932 /* Add columns that we don't yet know about */
933 while( columns.length <= aTargets[j] )
934 {
935 _fnAddColumn( oSettings );
936 }
937
938 /* Integer, basic index */
939 fn( aTargets[j], def );
940 }
941 else if ( typeof aTargets[j] === 'number' && aTargets[j] < 0 )
942 {
943 /* Negative integer, right to left column counting */
944 fn( columns.length+aTargets[j], def );
945 }
946 else if ( typeof aTargets[j] === 'string' )
947 {
948 /* Class name matching on TH element */
949 for ( k=0, kLen=columns.length ; k<kLen ; k++ )
950 {
951 if ( aTargets[j] == "_all" ||
952 $(columns[k].nTh).hasClass( aTargets[j] ) )
953 {
954 fn( k, def );
955 }
956 }
957 }
958 }
959 }
960 }
961
962 // Statically defined columns array
963 if ( aoCols )
964 {
965 for ( i=0, iLen=aoCols.length ; i<iLen ; i++ )
966 {
967 fn( i, aoCols[i] );
968 }
969 }
970 }
971
972 /**
973 * Add a data array to the table, creating DOM node etc. This is the parallel to
974 * _fnGatherData, but for adding rows from a Javascript source, rather than a
975 * DOM source.
976 * @param {object} oSettings dataTables settings object
977 * @param {array} aData data array to be added
978 * @param {node} [nTr] TR element to add to the table - optional. If not given,
979 * DataTables will create a row automatically
980 * @param {array} [anTds] Array of TD|TH elements for the row - must be given
981 * if nTr is.
982 * @returns {int} >=0 if successful (index of new aoData entry), -1 if failed
983 * @memberof DataTable#oApi
984 */
985 function _fnAddData ( oSettings, aDataIn, nTr, anTds )
986 {
987 /* Create the object for storing information about this new row */
988 var iRow = oSettings.aoData.length;
989 var oData = $.extend( true, {}, DataTable.models.oRow, {
990 src: nTr ? 'dom' : 'data'
991 } );
992
993 oData._aData = aDataIn;
994 oSettings.aoData.push( oData );
995
996 /* Create the cells */
997 var nTd, sThisType;
998 var columns = oSettings.aoColumns;
999 for ( var i=0, iLen=columns.length ; i<iLen ; i++ )
1000 {
1001 // When working with a row, the data source object must be populated. In
1002 // all other cases, the data source object is already populated, so we
1003 // don't overwrite it, which might break bindings etc
1004 if ( nTr ) {
1005 _fnSetCellData( oSettings, iRow, i, _fnGetCellData( oSettings, iRow, i ) );
1006 }
1007 columns[i].sType = null;
1008 }
1009
1010 /* Add to the display array */
1011 oSettings.aiDisplayMaster.push( iRow );
1012
1013 /* Create the DOM information, or register it if already present */
1014 if ( nTr || ! oSettings.oFeatures.bDeferRender )
1015 {
1016 _fnCreateTr( oSettings, iRow, nTr, anTds );
1017 }
1018
1019 return iRow;
1020 }
1021
1022
1023 /**
1024 * Add one or more TR elements to the table. Generally we'd expect to
1025 * use this for reading data from a DOM sourced table, but it could be
1026 * used for an TR element. Note that if a TR is given, it is used (i.e.
1027 * it is not cloned).
1028 * @param {object} settings dataTables settings object
1029 * @param {array|node|jQuery} trs The TR element(s) to add to the table
1030 * @returns {array} Array of indexes for the added rows
1031 * @memberof DataTable#oApi
1032 */
1033 function _fnAddTr( settings, trs )
1034 {
1035 var row;
1036
1037 // Allow an individual node to be passed in
1038 if ( ! (trs instanceof $) ) {
1039 trs = $(trs);
1040 }
1041
1042 return trs.map( function (i, el) {
1043 row = _fnGetRowElements( settings, el );
1044 return _fnAddData( settings, row.data, el, row.cells );
1045 } );
1046 }
1047
1048
1049 /**
1050 * Take a TR element and convert it to an index in aoData
1051 * @param {object} oSettings dataTables settings object
1052 * @param {node} n the TR element to find
1053 * @returns {int} index if the node is found, null if not
1054 * @memberof DataTable#oApi
1055 */
1056 function _fnNodeToDataIndex( oSettings, n )
1057 {
1058 return (n._DT_RowIndex!==undefined) ? n._DT_RowIndex : null;
1059 }
1060
1061
1062 /**
1063 * Take a TD element and convert it into a column data index (not the visible index)
1064 * @param {object} oSettings dataTables settings object
1065 * @param {int} iRow The row number the TD/TH can be found in
1066 * @param {node} n The TD/TH element to find
1067 * @returns {int} index if the node is found, -1 if not
1068 * @memberof DataTable#oApi
1069 */
1070 function _fnNodeToColumnIndex( oSettings, iRow, n )
1071 {
1072 return $.inArray( n, oSettings.aoData[ iRow ].anCells );
1073 }
1074
1075
1076 /**
1077 * Get the data for a given cell from the internal cache, taking into account data mapping
1078 * @param {object} settings dataTables settings object
1079 * @param {int} rowIdx aoData row id
1080 * @param {int} colIdx Column index
1081 * @param {string} type data get type ('display', 'type' 'filter' 'sort')
1082 * @returns {*} Cell data
1083 * @memberof DataTable#oApi
1084 */
1085 function _fnGetCellData( settings, rowIdx, colIdx, type )
1086 {
1087 var draw = settings.iDraw;
1088 var col = settings.aoColumns[colIdx];
1089 var rowData = settings.aoData[rowIdx]._aData;
1090 var defaultContent = col.sDefaultContent;
1091 var cellData = col.fnGetData( rowData, type, {
1092 settings: settings,
1093 row: rowIdx,
1094 col: colIdx
1095 } );
1096
1097 if ( cellData === undefined ) {
1098 if ( settings.iDrawError != draw && defaultContent === null ) {
1099 _fnLog( settings, 0, "Requested unknown parameter "+
1100 (typeof col.mData=='function' ? '{function}' : "'"+col.mData+"'")+
1101 " for row "+rowIdx, 4 );
1102 settings.iDrawError = draw;
1103 }
1104 return defaultContent;
1105 }
1106
1107 /* When the data source is null, we can use default column data */
1108 if ( (cellData === rowData || cellData === null) && defaultContent !== null ) {
1109 cellData = defaultContent;
1110 }
1111 else if ( typeof cellData === 'function' ) {
1112 // If the data source is a function, then we run it and use the return,
1113 // executing in the scope of the data object (for instances)
1114 return cellData.call( rowData );
1115 }
1116
1117 if ( cellData === null && type == 'display' ) {
1118 return '';
1119 }
1120 return cellData;
1121 }
1122
1123
1124 /**
1125 * Set the value for a specific cell, into the internal data cache
1126 * @param {object} settings dataTables settings object
1127 * @param {int} rowIdx aoData row id
1128 * @param {int} colIdx Column index
1129 * @param {*} val Value to set
1130 * @memberof DataTable#oApi
1131 */
1132 function _fnSetCellData( settings, rowIdx, colIdx, val )
1133 {
1134 var col = settings.aoColumns[colIdx];
1135 var rowData = settings.aoData[rowIdx]._aData;
1136
1137 col.fnSetData( rowData, val, {
1138 settings: settings,
1139 row: rowIdx,
1140 col: colIdx
1141 } );
1142 }
1143
1144
1145 // Private variable that is used to match action syntax in the data property object
1146 var __reArray = /\[.*?\]$/;
1147 var __reFn = /\(\)$/;
1148
1149 /**
1150 * Split string on periods, taking into account escaped periods
1151 * @param {string} str String to split
1152 * @return {array} Split string
1153 */
1154 function _fnSplitObjNotation( str )
1155 {
1156 return $.map( str.match(/(\\.|[^\.])+/g), function ( s ) {
1157 return s.replace(/\\./g, '.');
1158 } );
1159 }
1160
1161
1162 /**
1163 * Return a function that can be used to get data from a source object, taking
1164 * into account the ability to use nested objects as a source
1165 * @param {string|int|function} mSource The data source for the object
1166 * @returns {function} Data get function
1167 * @memberof DataTable#oApi
1168 */
1169 function _fnGetObjectDataFn( mSource )
1170 {
1171 if ( $.isPlainObject( mSource ) )
1172 {
1173 /* Build an object of get functions, and wrap them in a single call */
1174 var o = {};
1175 $.each( mSource, function (key, val) {
1176 if ( val ) {
1177 o[key] = _fnGetObjectDataFn( val );
1178 }
1179 } );
1180
1181 return function (data, type, row, meta) {
1182 var t = o[type] || o._;
1183 return t !== undefined ?
1184 t(data, type, row, meta) :
1185 data;
1186 };
1187 }
1188 else if ( mSource === null )
1189 {
1190 /* Give an empty string for rendering / sorting etc */
1191 return function (data) { // type, row and meta also passed, but not used
1192 return data;
1193 };
1194 }
1195 else if ( typeof mSource === 'function' )
1196 {
1197 return function (data, type, row, meta) {
1198 return mSource( data, type, row, meta );
1199 };
1200 }
1201 else if ( typeof mSource === 'string' && (mSource.indexOf('.') !== -1 ||
1202 mSource.indexOf('[') !== -1 || mSource.indexOf('(') !== -1) )
1203 {
1204 /* If there is a . in the source string then the data source is in a
1205 * nested object so we loop over the data for each level to get the next
1206 * level down. On each loop we test for undefined, and if found immediately
1207 * return. This allows entire objects to be missing and sDefaultContent to
1208 * be used if defined, rather than throwing an error
1209 */
1210 var fetchData = function (data, type, src) {
1211 var arrayNotation, funcNotation, out, innerSrc;
1212
1213 if ( src !== "" )
1214 {
1215 var a = _fnSplitObjNotation( src );
1216
1217 for ( var i=0, iLen=a.length ; i<iLen ; i++ )
1218 {
1219 // Check if we are dealing with special notation
1220 arrayNotation = a[i].match(__reArray);
1221 funcNotation = a[i].match(__reFn);
1222
1223 if ( arrayNotation )
1224 {
1225 // Array notation
1226 a[i] = a[i].replace(__reArray, '');
1227
1228 // Condition allows simply [] to be passed in
1229 if ( a[i] !== "" ) {
1230 data = data[ a[i] ];
1231 }
1232 out = [];
1233
1234 // Get the remainder of the nested object to get
1235 a.splice( 0, i+1 );
1236 innerSrc = a.join('.');
1237
1238 // Traverse each entry in the array getting the properties requested
1239 for ( var j=0, jLen=data.length ; j<jLen ; j++ ) {
1240 out.push( fetchData( data[j], type, innerSrc ) );
1241 }
1242
1243 // If a string is given in between the array notation indicators, that
1244 // is used to join the strings together, otherwise an array is returned
1245 var join = arrayNotation[0].substring(1, arrayNotation[0].length-1);
1246 data = (join==="") ? out : out.join(join);
1247
1248 // The inner call to fetchData has already traversed through the remainder
1249 // of the source requested, so we exit from the loop
1250 break;
1251 }
1252 else if ( funcNotation )
1253 {
1254 // Function call
1255 a[i] = a[i].replace(__reFn, '');
1256 data = data[ a[i] ]();
1257 continue;
1258 }
1259
1260 if ( data === null || data[ a[i] ] === undefined )
1261 {
1262 return undefined;
1263 }
1264 data = data[ a[i] ];
1265 }
1266 }
1267
1268 return data;
1269 };
1270
1271 return function (data, type) { // row and meta also passed, but not used
1272 return fetchData( data, type, mSource );
1273 };
1274 }
1275 else
1276 {
1277 /* Array or flat object mapping */
1278 return function (data, type) { // row and meta also passed, but not used
1279 return data[mSource];
1280 };
1281 }
1282 }
1283
1284
1285 /**
1286 * Return a function that can be used to set data from a source object, taking
1287 * into account the ability to use nested objects as a source
1288 * @param {string|int|function} mSource The data source for the object
1289 * @returns {function} Data set function
1290 * @memberof DataTable#oApi
1291 */
1292 function _fnSetObjectDataFn( mSource )
1293 {
1294 if ( $.isPlainObject( mSource ) )
1295 {
1296 /* Unlike get, only the underscore (global) option is used for for
1297 * setting data since we don't know the type here. This is why an object
1298 * option is not documented for `mData` (which is read/write), but it is
1299 * for `mRender` which is read only.
1300 */
1301 return _fnSetObjectDataFn( mSource._ );
1302 }
1303 else if ( mSource === null )
1304 {
1305 /* Nothing to do when the data source is null */
1306 return function () {};
1307 }
1308 else if ( typeof mSource === 'function' )
1309 {
1310 return function (data, val, meta) {
1311 mSource( data, 'set', val, meta );
1312 };
1313 }
1314 else if ( typeof mSource === 'string' && (mSource.indexOf('.') !== -1 ||
1315 mSource.indexOf('[') !== -1 || mSource.indexOf('(') !== -1) )
1316 {
1317 /* Like the get, we need to get data from a nested object */
1318 var setData = function (data, val, src) {
1319 var a = _fnSplitObjNotation( src ), b;
1320 var aLast = a[a.length-1];
1321 var arrayNotation, funcNotation, o, innerSrc;
1322
1323 for ( var i=0, iLen=a.length-1 ; i<iLen ; i++ )
1324 {
1325 // Check if we are dealing with an array notation request
1326 arrayNotation = a[i].match(__reArray);
1327 funcNotation = a[i].match(__reFn);
1328
1329 if ( arrayNotation )
1330 {
1331 a[i] = a[i].replace(__reArray, '');
1332 data[ a[i] ] = [];
1333
1334 // Get the remainder of the nested object to set so we can recurse
1335 b = a.slice();
1336 b.splice( 0, i+1 );
1337 innerSrc = b.join('.');
1338
1339 // Traverse each entry in the array setting the properties requested
1340 for ( var j=0, jLen=val.length ; j<jLen ; j++ )
1341 {
1342 o = {};
1343 setData( o, val[j], innerSrc );
1344 data[ a[i] ].push( o );
1345 }
1346
1347 // The inner call to setData has already traversed through the remainder
1348 // of the source and has set the data, thus we can exit here
1349 return;
1350 }
1351 else if ( funcNotation )
1352 {
1353 // Function call
1354 a[i] = a[i].replace(__reFn, '');
1355 data = data[ a[i] ]( val );
1356 }
1357
1358 // If the nested object doesn't currently exist - since we are
1359 // trying to set the value - create it
1360 if ( data[ a[i] ] === null || data[ a[i] ] === undefined )
1361 {
1362 data[ a[i] ] = {};
1363 }
1364 data = data[ a[i] ];
1365 }
1366
1367 // Last item in the input - i.e, the actual set
1368 if ( aLast.match(__reFn ) )
1369 {
1370 // Function call
1371 data = data[ aLast.replace(__reFn, '') ]( val );
1372 }
1373 else
1374 {
1375 // If array notation is used, we just want to strip it and use the property name
1376 // and assign the value. If it isn't used, then we get the result we want anyway
1377 data[ aLast.replace(__reArray, '') ] = val;
1378 }
1379 };
1380
1381 return function (data, val) { // meta is also passed in, but not used
1382 return setData( data, val, mSource );
1383 };
1384 }
1385 else
1386 {
1387 /* Array or flat object mapping */
1388 return function (data, val) { // meta is also passed in, but not used
1389 data[mSource] = val;
1390 };
1391 }
1392 }
1393
1394
1395 /**
1396 * Return an array with the full table data
1397 * @param {object} oSettings dataTables settings object
1398 * @returns array {array} aData Master data array
1399 * @memberof DataTable#oApi
1400 */
1401 function _fnGetDataMaster ( settings )
1402 {
1403 return _pluck( settings.aoData, '_aData' );
1404 }
1405
1406
1407 /**
1408 * Nuke the table
1409 * @param {object} oSettings dataTables settings object
1410 * @memberof DataTable#oApi
1411 */
1412 function _fnClearTable( settings )
1413 {
1414 settings.aoData.length = 0;
1415 settings.aiDisplayMaster.length = 0;
1416 settings.aiDisplay.length = 0;
1417 }
1418
1419
1420 /**
1421 * Take an array of integers (index array) and remove a target integer (value - not
1422 * the key!)
1423 * @param {array} a Index array to target
1424 * @param {int} iTarget value to find
1425 * @memberof DataTable#oApi
1426 */
1427 function _fnDeleteIndex( a, iTarget, splice )
1428 {
1429 var iTargetIndex = -1;
1430
1431 for ( var i=0, iLen=a.length ; i<iLen ; i++ )
1432 {
1433 if ( a[i] == iTarget )
1434 {
1435 iTargetIndex = i;
1436 }
1437 else if ( a[i] > iTarget )
1438 {
1439 a[i]--;
1440 }
1441 }
1442
1443 if ( iTargetIndex != -1 && splice === undefined )
1444 {
1445 a.splice( iTargetIndex, 1 );
1446 }
1447 }
1448
1449
1450 /**
1451 * Mark cached data as invalid such that a re-read of the data will occur when
1452 * the cached data is next requested. Also update from the data source object.
1453 *
1454 * @param {object} settings DataTables settings object
1455 * @param {int} rowIdx Row index to invalidate
1456 * @param {string} [src] Source to invalidate from: undefined, 'auto', 'dom'
1457 * or 'data'
1458 * @param {int} [colIdx] Column index to invalidate. If undefined the whole
1459 * row will be invalidated
1460 * @memberof DataTable#oApi
1461 *
1462 * @todo For the modularisation of v1.11 this will need to become a callback, so
1463 * the sort and filter methods can subscribe to it. That will required
1464 * initialisation options for sorting, which is why it is not already baked in
1465 */
1466 function _fnInvalidate( settings, rowIdx, src, colIdx )
1467 {
1468 var row = settings.aoData[ rowIdx ];
1469 var i, ien;
1470 var cellWrite = function ( cell, col ) {
1471 // This is very frustrating, but in IE if you just write directly
1472 // to innerHTML, and elements that are overwritten are GC'ed,
1473 // even if there is a reference to them elsewhere
1474 while ( cell.childNodes.length ) {
1475 cell.removeChild( cell.firstChild );
1476 }
1477
1478 cell.innerHTML = _fnGetCellData( settings, rowIdx, col, 'display' );
1479 };
1480
1481 // Are we reading last data from DOM or the data object?
1482 if ( src === 'dom' || ((! src || src === 'auto') && row.src === 'dom') ) {
1483 // Read the data from the DOM
1484 row._aData = _fnGetRowElements(
1485 settings, row, colIdx, colIdx === undefined ? undefined : row._aData
1486 )
1487 .data;
1488 }
1489 else {
1490 // Reading from data object, update the DOM
1491 var cells = row.anCells;
1492
1493 if ( cells ) {
1494 if ( colIdx !== undefined ) {
1495 cellWrite( cells[colIdx], colIdx );
1496 }
1497 else {
1498 for ( i=0, ien=cells.length ; i<ien ; i++ ) {
1499 cellWrite( cells[i], i );
1500 }
1501 }
1502 }
1503 }
1504
1505 // For both row and cell invalidation, the cached data for sorting and
1506 // filtering is nulled out
1507 row._aSortData = null;
1508 row._aFilterData = null;
1509
1510 // Invalidate the type for a specific column (if given) or all columns since
1511 // the data might have changed
1512 var cols = settings.aoColumns;
1513 if ( colIdx !== undefined ) {
1514 cols[ colIdx ].sType = null;
1515 }
1516 else {
1517 for ( i=0, ien=cols.length ; i<ien ; i++ ) {
1518 cols[i].sType = null;
1519 }
1520
1521 // Update DataTables special `DT_*` attributes for the row
1522 _fnRowAttributes( row );
1523 }
1524 }
1525
1526
1527 /**
1528 * Build a data source object from an HTML row, reading the contents of the
1529 * cells that are in the row.
1530 *
1531 * @param {object} settings DataTables settings object
1532 * @param {node|object} TR element from which to read data or existing row
1533 * object from which to re-read the data from the cells
1534 * @param {int} [colIdx] Optional column index
1535 * @param {array|object} [d] Data source object. If `colIdx` is given then this
1536 * parameter should also be given and will be used to write the data into.
1537 * Only the column in question will be written
1538 * @returns {object} Object with two parameters: `data` the data read, in
1539 * document order, and `cells` and array of nodes (they can be useful to the
1540 * caller, so rather than needing a second traversal to get them, just return
1541 * them from here).
1542 * @memberof DataTable#oApi
1543 */
1544 function _fnGetRowElements( settings, row, colIdx, d )
1545 {
1546 var
1547 tds = [],
1548 td = row.firstChild,
1549 name, col, o, i=0, contents,
1550 columns = settings.aoColumns,
1551 objectRead = settings._rowReadObject;
1552
1553 // Allow the data object to be passed in, or construct
1554 d = d || objectRead ? {} : [];
1555
1556 var attr = function ( str, td ) {
1557 if ( typeof str === 'string' ) {
1558 var idx = str.indexOf('@');
1559
1560 if ( idx !== -1 ) {
1561 var attr = str.substring( idx+1 );
1562 var setter = _fnSetObjectDataFn( str );
1563 setter( d, td.getAttribute( attr ) );
1564 }
1565 }
1566 };
1567
1568 // Read data from a cell and store into the data object
1569 var cellProcess = function ( cell ) {
1570 if ( colIdx === undefined || colIdx === i ) {
1571 col = columns[i];
1572 contents = $.trim(cell.innerHTML);
1573
1574 if ( col && col._bAttrSrc ) {
1575 var setter = _fnSetObjectDataFn( col.mData._ );
1576 setter( d, contents );
1577
1578 attr( col.mData.sort, cell );
1579 attr( col.mData.type, cell );
1580 attr( col.mData.filter, cell );
1581 }
1582 else {
1583 // Depending on the `data` option for the columns the data can
1584 // be read to either an object or an array.
1585 if ( objectRead ) {
1586 if ( ! col._setter ) {
1587 // Cache the setter function
1588 col._setter = _fnSetObjectDataFn( col.mData );
1589 }
1590 col._setter( d, contents );
1591 }
1592 else {
1593 d[i] = contents;
1594 }
1595 }
1596 }
1597
1598 i++;
1599 };
1600
1601 if ( td ) {
1602 // `tr` element was passed in
1603 while ( td ) {
1604 name = td.nodeName.toUpperCase();
1605
1606 if ( name == "TD" || name == "TH" ) {
1607 cellProcess( td );
1608 tds.push( td );
1609 }
1610
1611 td = td.nextSibling;
1612 }
1613 }
1614 else {
1615 // Existing row object passed in
1616 tds = row.anCells;
1617
1618 for ( var j=0, jen=tds.length ; j<jen ; j++ ) {
1619 cellProcess( tds[j] );
1620 }
1621 }
1622
1623 return {
1624 data: d,
1625 cells: tds
1626 };
1627 }
1628 /**
1629 * Create a new TR element (and it's TD children) for a row
1630 * @param {object} oSettings dataTables settings object
1631 * @param {int} iRow Row to consider
1632 * @param {node} [nTrIn] TR element to add to the table - optional. If not given,
1633 * DataTables will create a row automatically
1634 * @param {array} [anTds] Array of TD|TH elements for the row - must be given
1635 * if nTr is.
1636 * @memberof DataTable#oApi
1637 */
1638 function _fnCreateTr ( oSettings, iRow, nTrIn, anTds )
1639 {
1640 var
1641 row = oSettings.aoData[iRow],
1642 rowData = row._aData,
1643 cells = [],
1644 nTr, nTd, oCol,
1645 i, iLen;
1646
1647 if ( row.nTr === null )
1648 {
1649 nTr = nTrIn || document.createElement('tr');
1650
1651 row.nTr = nTr;
1652 row.anCells = cells;
1653
1654 /* Use a private property on the node to allow reserve mapping from the node
1655 * to the aoData array for fast look up
1656 */
1657 nTr._DT_RowIndex = iRow;
1658
1659 /* Special parameters can be given by the data source to be used on the row */
1660 _fnRowAttributes( row );
1661
1662 /* Process each column */
1663 for ( i=0, iLen=oSettings.aoColumns.length ; i<iLen ; i++ )
1664 {
1665 oCol = oSettings.aoColumns[i];
1666
1667 nTd = nTrIn ? anTds[i] : document.createElement( oCol.sCellType );
1668 cells.push( nTd );
1669
1670 // Need to create the HTML if new, or if a rendering function is defined
1671 if ( !nTrIn || oCol.mRender || oCol.mData !== i )
1672 {
1673 nTd.innerHTML = _fnGetCellData( oSettings, iRow, i, 'display' );
1674 }
1675
1676 /* Add user defined class */
1677 if ( oCol.sClass )
1678 {
1679 nTd.className += ' '+oCol.sClass;
1680 }
1681
1682 // Visibility - add or remove as required
1683 if ( oCol.bVisible && ! nTrIn )
1684 {
1685 nTr.appendChild( nTd );
1686 }
1687 else if ( ! oCol.bVisible && nTrIn )
1688 {
1689 nTd.parentNode.removeChild( nTd );
1690 }
1691
1692 if ( oCol.fnCreatedCell )
1693 {
1694 oCol.fnCreatedCell.call( oSettings.oInstance,
1695 nTd, _fnGetCellData( oSettings, iRow, i ), rowData, iRow, i
1696 );
1697 }
1698 }
1699
1700 _fnCallbackFire( oSettings, 'aoRowCreatedCallback', null, [nTr, rowData, iRow] );
1701 }
1702
1703 // Remove once webkit bug 131819 and Chromium bug 365619 have been resolved
1704 // and deployed
1705 row.nTr.setAttribute( 'role', 'row' );
1706 }
1707
1708
1709 /**
1710 * Add attributes to a row based on the special `DT_*` parameters in a data
1711 * source object.
1712 * @param {object} DataTables row object for the row to be modified
1713 * @memberof DataTable#oApi
1714 */
1715 function _fnRowAttributes( row )
1716 {
1717 var tr = row.nTr;
1718 var data = row._aData;
1719
1720 if ( tr ) {
1721 if ( data.DT_RowId ) {
1722 tr.id = data.DT_RowId;
1723 }
1724
1725 if ( data.DT_RowClass ) {
1726 // Remove any classes added by DT_RowClass before
1727 var a = data.DT_RowClass.split(' ');
1728 row.__rowc = row.__rowc ?
1729 _unique( row.__rowc.concat( a ) ) :
1730 a;
1731
1732 $(tr)
1733 .removeClass( row.__rowc.join(' ') )
1734 .addClass( data.DT_RowClass );
1735 }
1736
1737 if ( data.DT_RowData ) {
1738 $(tr).data( data.DT_RowData );
1739 }
1740 }
1741 }
1742
1743
1744 /**
1745 * Create the HTML header for the table
1746 * @param {object} oSettings dataTables settings object
1747 * @memberof DataTable#oApi
1748 */
1749 function _fnBuildHead( oSettings )
1750 {
1751 var i, ien, cell, row, column;
1752 var thead = oSettings.nTHead;
1753 var tfoot = oSettings.nTFoot;
1754 var createHeader = $('th, td', thead).length === 0;
1755 var classes = oSettings.oClasses;
1756 var columns = oSettings.aoColumns;
1757
1758 if ( createHeader ) {
1759 row = $('<tr/>').appendTo( thead );
1760 }
1761
1762 for ( i=0, ien=columns.length ; i<ien ; i++ ) {
1763 column = columns[i];
1764 cell = $( column.nTh ).addClass( column.sClass );
1765
1766 if ( createHeader ) {
1767 cell.appendTo( row );
1768 }
1769
1770 // 1.11 move into sorting
1771 if ( oSettings.oFeatures.bSort ) {
1772 cell.addClass( column.sSortingClass );
1773
1774 if ( column.bSortable !== false ) {
1775 cell
1776 .attr( 'tabindex', oSettings.iTabIndex )
1777 .attr( 'aria-controls', oSettings.sTableId );
1778
1779 _fnSortAttachListener( oSettings, column.nTh, i );
1780 }
1781 }
1782
1783 if ( column.sTitle != cell.html() ) {
1784 cell.html( column.sTitle );
1785 }
1786
1787 _fnRenderer( oSettings, 'header' )(
1788 oSettings, cell, column, classes
1789 );
1790 }
1791
1792 if ( createHeader ) {
1793 _fnDetectHeader( oSettings.aoHeader, thead );
1794 }
1795
1796 /* ARIA role for the rows */
1797 $(thead).find('>tr').attr('role', 'row');
1798
1799 /* Deal with the footer - add classes if required */
1800 $(thead).find('>tr>th, >tr>td').addClass( classes.sHeaderTH );
1801 $(tfoot).find('>tr>th, >tr>td').addClass( classes.sFooterTH );
1802
1803 // Cache the footer cells. Note that we only take the cells from the first
1804 // row in the footer. If there is more than one row the user wants to
1805 // interact with, they need to use the table().foot() method. Note also this
1806 // allows cells to be used for multiple columns using colspan
1807 if ( tfoot !== null ) {
1808 var cells = oSettings.aoFooter[0];
1809
1810 for ( i=0, ien=cells.length ; i<ien ; i++ ) {
1811 column = columns[i];
1812 column.nTf = cells[i].cell;
1813
1814 if ( column.sClass ) {
1815 $(column.nTf).addClass( column.sClass );
1816 }
1817 }
1818 }
1819 }
1820
1821
1822 /**
1823 * Draw the header (or footer) element based on the column visibility states. The
1824 * methodology here is to use the layout array from _fnDetectHeader, modified for
1825 * the instantaneous column visibility, to construct the new layout. The grid is
1826 * traversed over cell at a time in a rows x columns grid fashion, although each
1827 * cell insert can cover multiple elements in the grid - which is tracks using the
1828 * aApplied array. Cell inserts in the grid will only occur where there isn't
1829 * already a cell in that position.
1830 * @param {object} oSettings dataTables settings object
1831 * @param array {objects} aoSource Layout array from _fnDetectHeader
1832 * @param {boolean} [bIncludeHidden=false] If true then include the hidden columns in the calc,
1833 * @memberof DataTable#oApi
1834 */
1835 function _fnDrawHead( oSettings, aoSource, bIncludeHidden )
1836 {
1837 var i, iLen, j, jLen, k, kLen, n, nLocalTr;
1838 var aoLocal = [];
1839 var aApplied = [];
1840 var iColumns = oSettings.aoColumns.length;
1841 var iRowspan, iColspan;
1842
1843 if ( ! aoSource )
1844 {
1845 return;
1846 }
1847
1848 if ( bIncludeHidden === undefined )
1849 {
1850 bIncludeHidden = false;
1851 }
1852
1853 /* Make a copy of the master layout array, but without the visible columns in it */
1854 for ( i=0, iLen=aoSource.length ; i<iLen ; i++ )
1855 {
1856 aoLocal[i] = aoSource[i].slice();
1857 aoLocal[i].nTr = aoSource[i].nTr;
1858
1859 /* Remove any columns which are currently hidden */
1860 for ( j=iColumns-1 ; j>=0 ; j-- )
1861 {
1862 if ( !oSettings.aoColumns[j].bVisible && !bIncludeHidden )
1863 {
1864 aoLocal[i].splice( j, 1 );
1865 }
1866 }
1867
1868 /* Prep the applied array - it needs an element for each row */
1869 aApplied.push( [] );
1870 }
1871
1872 for ( i=0, iLen=aoLocal.length ; i<iLen ; i++ )
1873 {
1874 nLocalTr = aoLocal[i].nTr;
1875
1876 /* All cells are going to be replaced, so empty out the row */
1877 if ( nLocalTr )
1878 {
1879 while( (n = nLocalTr.firstChild) )
1880 {
1881 nLocalTr.removeChild( n );
1882 }
1883 }
1884
1885 for ( j=0, jLen=aoLocal[i].length ; j<jLen ; j++ )
1886 {
1887 iRowspan = 1;
1888 iColspan = 1;
1889
1890 /* Check to see if there is already a cell (row/colspan) covering our target
1891 * insert point. If there is, then there is nothing to do.
1892 */
1893 if ( aApplied[i][j] === undefined )
1894 {
1895 nLocalTr.appendChild( aoLocal[i][j].cell );
1896 aApplied[i][j] = 1;
1897
1898 /* Expand the cell to cover as many rows as needed */
1899 while ( aoLocal[i+iRowspan] !== undefined &&
1900 aoLocal[i][j].cell == aoLocal[i+iRowspan][j].cell )
1901 {
1902 aApplied[i+iRowspan][j] = 1;
1903 iRowspan++;
1904 }
1905
1906 /* Expand the cell to cover as many columns as needed */
1907 while ( aoLocal[i][j+iColspan] !== undefined &&
1908 aoLocal[i][j].cell == aoLocal[i][j+iColspan].cell )
1909 {
1910 /* Must update the applied array over the rows for the columns */
1911 for ( k=0 ; k<iRowspan ; k++ )
1912 {
1913 aApplied[i+k][j+iColspan] = 1;
1914 }
1915 iColspan++;
1916 }
1917
1918 /* Do the actual expansion in the DOM */
1919 $(aoLocal[i][j].cell)
1920 .attr('rowspan', iRowspan)
1921 .attr('colspan', iColspan);
1922 }
1923 }
1924 }
1925 }
1926
1927
1928 /**
1929 * Insert the required TR nodes into the table for display
1930 * @param {object} oSettings dataTables settings object
1931 * @memberof DataTable#oApi
1932 */
1933 function _fnDraw( oSettings )
1934 {
1935 /* Provide a pre-callback function which can be used to cancel the draw is false is returned */
1936 var aPreDraw = _fnCallbackFire( oSettings, 'aoPreDrawCallback', 'preDraw', [oSettings] );
1937 if ( $.inArray( false, aPreDraw ) !== -1 )
1938 {
1939 _fnProcessingDisplay( oSettings, false );
1940 return;
1941 }
1942
1943 var i, iLen, n;
1944 var anRows = [];
1945 var iRowCount = 0;
1946 var asStripeClasses = oSettings.asStripeClasses;
1947 var iStripes = asStripeClasses.length;
1948 var iOpenRows = oSettings.aoOpenRows.length;
1949 var oLang = oSettings.oLanguage;
1950 var iInitDisplayStart = oSettings.iInitDisplayStart;
1951 var bServerSide = _fnDataSource( oSettings ) == 'ssp';
1952 var aiDisplay = oSettings.aiDisplay;
1953
1954 oSettings.bDrawing = true;
1955
1956 /* Check and see if we have an initial draw position from state saving */
1957 if ( iInitDisplayStart !== undefined && iInitDisplayStart !== -1 )
1958 {
1959 oSettings._iDisplayStart = bServerSide ?
1960 iInitDisplayStart :
1961 iInitDisplayStart >= oSettings.fnRecordsDisplay() ?
1962 0 :
1963 iInitDisplayStart;
1964
1965 oSettings.iInitDisplayStart = -1;
1966 }
1967
1968 var iDisplayStart = oSettings._iDisplayStart;
1969 var iDisplayEnd = oSettings.fnDisplayEnd();
1970
1971 /* Server-side processing draw intercept */
1972 if ( oSettings.bDeferLoading )
1973 {
1974 oSettings.bDeferLoading = false;
1975 oSettings.iDraw++;
1976 _fnProcessingDisplay( oSettings, false );
1977 }
1978 else if ( !bServerSide )
1979 {
1980 oSettings.iDraw++;
1981 }
1982 else if ( !oSettings.bDestroying && !_fnAjaxUpdate( oSettings ) )
1983 {
1984 return;
1985 }
1986
1987 if ( aiDisplay.length !== 0 )
1988 {
1989 var iStart = bServerSide ? 0 : iDisplayStart;
1990 var iEnd = bServerSide ? oSettings.aoData.length : iDisplayEnd;
1991
1992 for ( var j=iStart ; j<iEnd ; j++ )
1993 {
1994 var iDataIndex = aiDisplay[j];
1995 var aoData = oSettings.aoData[ iDataIndex ];
1996 if ( aoData.nTr === null )
1997 {
1998 _fnCreateTr( oSettings, iDataIndex );
1999 }
2000
2001 var nRow = aoData.nTr;
2002
2003 /* Remove the old striping classes and then add the new one */
2004 if ( iStripes !== 0 )
2005 {
2006 var sStripe = asStripeClasses[ iRowCount % iStripes ];
2007 if ( aoData._sRowStripe != sStripe )
2008 {
2009 $(nRow).removeClass( aoData._sRowStripe ).addClass( sStripe );
2010 aoData._sRowStripe = sStripe;
2011 }
2012 }
2013
2014 // Row callback functions - might want to manipulate the row
2015 // iRowCount and j are not currently documented. Are they at all
2016 // useful?
2017 _fnCallbackFire( oSettings, 'aoRowCallback', null,
2018 [nRow, aoData._aData, iRowCount, j] );
2019
2020 anRows.push( nRow );
2021 iRowCount++;
2022 }
2023 }
2024 else
2025 {
2026 /* Table is empty - create a row with an empty message in it */
2027 var sZero = oLang.sZeroRecords;
2028 if ( oSettings.iDraw == 1 && _fnDataSource( oSettings ) == 'ajax' )
2029 {
2030 sZero = oLang.sLoadingRecords;
2031 }
2032 else if ( oLang.sEmptyTable && oSettings.fnRecordsTotal() === 0 )
2033 {
2034 sZero = oLang.sEmptyTable;
2035 }
2036
2037 anRows[ 0 ] = $( '<tr/>', { 'class': iStripes ? asStripeClasses[0] : '' } )
2038 .append( $('<td />', {
2039 'valign': 'top',
2040 'colSpan': _fnVisbleColumns( oSettings ),
2041 'class': oSettings.oClasses.sRowEmpty
2042 } ).html( sZero ) )[0];
2043 }
2044
2045 /* Header and footer callbacks */
2046 _fnCallbackFire( oSettings, 'aoHeaderCallback', 'header', [ $(oSettings.nTHead).children('tr')[0],
2047 _fnGetDataMaster( oSettings ), iDisplayStart, iDisplayEnd, aiDisplay ] );
2048
2049 _fnCallbackFire( oSettings, 'aoFooterCallback', 'footer', [ $(oSettings.nTFoot).children('tr')[0],
2050 _fnGetDataMaster( oSettings ), iDisplayStart, iDisplayEnd, aiDisplay ] );
2051
2052 var body = $(oSettings.nTBody);
2053
2054 body.children().detach();
2055 body.append( $(anRows) );
2056
2057 /* Call all required callback functions for the end of a draw */
2058 _fnCallbackFire( oSettings, 'aoDrawCallback', 'draw', [oSettings] );
2059
2060 /* Draw is complete, sorting and filtering must be as well */
2061 oSettings.bSorted = false;
2062 oSettings.bFiltered = false;
2063 oSettings.bDrawing = false;
2064 }
2065
2066
2067 /**
2068 * Redraw the table - taking account of the various features which are enabled
2069 * @param {object} oSettings dataTables settings object
2070 * @param {boolean} [holdPosition] Keep the current paging position. By default
2071 * the paging is reset to the first page
2072 * @memberof DataTable#oApi
2073 */
2074 function _fnReDraw( settings, holdPosition )
2075 {
2076 var
2077 features = settings.oFeatures,
2078 sort = features.bSort,
2079 filter = features.bFilter;
2080
2081 if ( sort ) {
2082 _fnSort( settings );
2083 }
2084
2085 if ( filter ) {
2086 _fnFilterComplete( settings, settings.oPreviousSearch );
2087 }
2088 else {
2089 // No filtering, so we want to just use the display master
2090 settings.aiDisplay = settings.aiDisplayMaster.slice();
2091 }
2092
2093 if ( holdPosition !== true ) {
2094 settings._iDisplayStart = 0;
2095 }
2096
2097 // Let any modules know about the draw hold position state (used by
2098 // scrolling internally)
2099 settings._drawHold = holdPosition;
2100
2101 _fnDraw( settings );
2102
2103 settings._drawHold = false;
2104 }
2105
2106
2107 /**
2108 * Add the options to the page HTML for the table
2109 * @param {object} oSettings dataTables settings object
2110 * @memberof DataTable#oApi
2111 */
2112 function _fnAddOptionsHtml ( oSettings )
2113 {
2114 var classes = oSettings.oClasses;
2115 var table = $(oSettings.nTable);
2116 var holding = $('<div/>').insertBefore( table ); // Holding element for speed
2117 var features = oSettings.oFeatures;
2118
2119 // All DataTables are wrapped in a div
2120 var insert = $('<div/>', {
2121 id: oSettings.sTableId+'_wrapper',
2122 'class': classes.sWrapper + (oSettings.nTFoot ? '' : ' '+classes.sNoFooter)
2123 } );
2124
2125 oSettings.nHolding = holding[0];
2126 oSettings.nTableWrapper = insert[0];
2127 oSettings.nTableReinsertBefore = oSettings.nTable.nextSibling;
2128
2129 /* Loop over the user set positioning and place the elements as needed */
2130 var aDom = oSettings.sDom.split('');
2131 var featureNode, cOption, nNewNode, cNext, sAttr, j;
2132 for ( var i=0 ; i<aDom.length ; i++ )
2133 {
2134 featureNode = null;
2135 cOption = aDom[i];
2136
2137 if ( cOption == '<' )
2138 {
2139 /* New container div */
2140 nNewNode = $('<div/>')[0];
2141
2142 /* Check to see if we should append an id and/or a class name to the container */
2143 cNext = aDom[i+1];
2144 if ( cNext == "'" || cNext == '"' )
2145 {
2146 sAttr = "";
2147 j = 2;
2148 while ( aDom[i+j] != cNext )
2149 {
2150 sAttr += aDom[i+j];
2151 j++;
2152 }
2153
2154 /* Replace jQuery UI constants @todo depreciated */
2155 if ( sAttr == "H" )
2156 {
2157 sAttr = classes.sJUIHeader;
2158 }
2159 else if ( sAttr == "F" )
2160 {
2161 sAttr = classes.sJUIFooter;
2162 }
2163
2164 /* The attribute can be in the format of "#id.class", "#id" or "class" This logic
2165 * breaks the string into parts and applies them as needed
2166 */
2167 if ( sAttr.indexOf('.') != -1 )
2168 {
2169 var aSplit = sAttr.split('.');
2170 nNewNode.id = aSplit[0].substr(1, aSplit[0].length-1);
2171 nNewNode.className = aSplit[1];
2172 }
2173 else if ( sAttr.charAt(0) == "#" )
2174 {
2175 nNewNode.id = sAttr.substr(1, sAttr.length-1);
2176 }
2177 else
2178 {
2179 nNewNode.className = sAttr;
2180 }
2181
2182 i += j; /* Move along the position array */
2183 }
2184
2185 insert.append( nNewNode );
2186 insert = $(nNewNode);
2187 }
2188 else if ( cOption == '>' )
2189 {
2190 /* End container div */
2191 insert = insert.parent();
2192 }
2193 // @todo Move options into their own plugins?
2194 else if ( cOption == 'l' && features.bPaginate && features.bLengthChange )
2195 {
2196 /* Length */
2197 featureNode = _fnFeatureHtmlLength( oSettings );
2198 }
2199 else if ( cOption == 'f' && features.bFilter )
2200 {
2201 /* Filter */
2202 featureNode = _fnFeatureHtmlFilter( oSettings );
2203 }
2204 else if ( cOption == 'r' && features.bProcessing )
2205 {
2206 /* pRocessing */
2207 featureNode = _fnFeatureHtmlProcessing( oSettings );
2208 }
2209 else if ( cOption == 't' )
2210 {
2211 /* Table */
2212 featureNode = _fnFeatureHtmlTable( oSettings );
2213 }
2214 else if ( cOption == 'i' && features.bInfo )
2215 {
2216 /* Info */
2217 featureNode = _fnFeatureHtmlInfo( oSettings );
2218 }
2219 else if ( cOption == 'p' && features.bPaginate )
2220 {
2221 /* Pagination */
2222 featureNode = _fnFeatureHtmlPaginate( oSettings );
2223 }
2224 else if ( DataTable.ext.feature.length !== 0 )
2225 {
2226 /* Plug-in features */
2227 var aoFeatures = DataTable.ext.feature;
2228 for ( var k=0, kLen=aoFeatures.length ; k<kLen ; k++ )
2229 {
2230 if ( cOption == aoFeatures[k].cFeature )
2231 {
2232 featureNode = aoFeatures[k].fnInit( oSettings );
2233 break;
2234 }
2235 }
2236 }
2237
2238 /* Add to the 2D features array */
2239 if ( featureNode )
2240 {
2241 var aanFeatures = oSettings.aanFeatures;
2242
2243 if ( ! aanFeatures[cOption] )
2244 {
2245 aanFeatures[cOption] = [];
2246 }
2247
2248 aanFeatures[cOption].push( featureNode );
2249 insert.append( featureNode );
2250 }
2251 }
2252
2253 /* Built our DOM structure - replace the holding div with what we want */
2254 holding.replaceWith( insert );
2255 }
2256
2257
2258 /**
2259 * Use the DOM source to create up an array of header cells. The idea here is to
2260 * create a layout grid (array) of rows x columns, which contains a reference
2261 * to the cell that that point in the grid (regardless of col/rowspan), such that
2262 * any column / row could be removed and the new grid constructed
2263 * @param array {object} aLayout Array to store the calculated layout in
2264 * @param {node} nThead The header/footer element for the table
2265 * @memberof DataTable#oApi
2266 */
2267 function _fnDetectHeader ( aLayout, nThead )
2268 {
2269 var nTrs = $(nThead).children('tr');
2270 var nTr, nCell;
2271 var i, k, l, iLen, jLen, iColShifted, iColumn, iColspan, iRowspan;
2272 var bUnique;
2273 var fnShiftCol = function ( a, i, j ) {
2274 var k = a[i];
2275 while ( k[j] ) {
2276 j++;
2277 }
2278 return j;
2279 };
2280
2281 aLayout.splice( 0, aLayout.length );
2282
2283 /* We know how many rows there are in the layout - so prep it */
2284 for ( i=0, iLen=nTrs.length ; i<iLen ; i++ )
2285 {
2286 aLayout.push( [] );
2287 }
2288
2289 /* Calculate a layout array */
2290 for ( i=0, iLen=nTrs.length ; i<iLen ; i++ )
2291 {
2292 nTr = nTrs[i];
2293 iColumn = 0;
2294
2295 /* For every cell in the row... */
2296 nCell = nTr.firstChild;
2297 while ( nCell ) {
2298 if ( nCell.nodeName.toUpperCase() == "TD" ||
2299 nCell.nodeName.toUpperCase() == "TH" )
2300 {
2301 /* Get the col and rowspan attributes from the DOM and sanitise them */
2302 iColspan = nCell.getAttribute('colspan') * 1;
2303 iRowspan = nCell.getAttribute('rowspan') * 1;
2304 iColspan = (!iColspan || iColspan===0 || iColspan===1) ? 1 : iColspan;
2305 iRowspan = (!iRowspan || iRowspan===0 || iRowspan===1) ? 1 : iRowspan;
2306
2307 /* There might be colspan cells already in this row, so shift our target
2308 * accordingly
2309 */
2310 iColShifted = fnShiftCol( aLayout, i, iColumn );
2311
2312 /* Cache calculation for unique columns */
2313 bUnique = iColspan === 1 ? true : false;
2314
2315 /* If there is col / rowspan, copy the information into the layout grid */
2316 for ( l=0 ; l<iColspan ; l++ )
2317 {
2318 for ( k=0 ; k<iRowspan ; k++ )
2319 {
2320 aLayout[i+k][iColShifted+l] = {
2321 "cell": nCell,
2322 "unique": bUnique
2323 };
2324 aLayout[i+k].nTr = nTr;
2325 }
2326 }
2327 }
2328 nCell = nCell.nextSibling;
2329 }
2330 }
2331 }
2332
2333
2334 /**
2335 * Get an array of unique th elements, one for each column
2336 * @param {object} oSettings dataTables settings object
2337 * @param {node} nHeader automatically detect the layout from this node - optional
2338 * @param {array} aLayout thead/tfoot layout from _fnDetectHeader - optional
2339 * @returns array {node} aReturn list of unique th's
2340 * @memberof DataTable#oApi
2341 */
2342 function _fnGetUniqueThs ( oSettings, nHeader, aLayout )
2343 {
2344 var aReturn = [];
2345 if ( !aLayout )
2346 {
2347 aLayout = oSettings.aoHeader;
2348 if ( nHeader )
2349 {
2350 aLayout = [];
2351 _fnDetectHeader( aLayout, nHeader );
2352 }
2353 }
2354
2355 for ( var i=0, iLen=aLayout.length ; i<iLen ; i++ )
2356 {
2357 for ( var j=0, jLen=aLayout[i].length ; j<jLen ; j++ )
2358 {
2359 if ( aLayout[i][j].unique &&
2360 (!aReturn[j] || !oSettings.bSortCellsTop) )
2361 {
2362 aReturn[j] = aLayout[i][j].cell;
2363 }
2364 }
2365 }
2366
2367 return aReturn;
2368 }
2369
2370
2371
2372 /**
2373 * Create an Ajax call based on the table's settings, taking into account that
2374 * parameters can have multiple forms, and backwards compatibility.
2375 *
2376 * @param {object} oSettings dataTables settings object
2377 * @param {array} data Data to send to the server, required by
2378 * DataTables - may be augmented by developer callbacks
2379 * @param {function} fn Callback function to run when data is obtained
2380 */
2381 function _fnBuildAjax( oSettings, data, fn )
2382 {
2383 // Compatibility with 1.9-, allow fnServerData and event to manipulate
2384 _fnCallbackFire( oSettings, 'aoServerParams', 'serverParams', [data] );
2385
2386 // Convert to object based for 1.10+ if using the old array scheme which can
2387 // come from server-side processing or serverParams
2388 if ( data && $.isArray(data) ) {
2389 var tmp = {};
2390 var rbracket = /(.*?)\[\]$/;
2391
2392 $.each( data, function (key, val) {
2393 var match = val.name.match(rbracket);
2394
2395 if ( match ) {
2396 // Support for arrays
2397 var name = match[0];
2398
2399 if ( ! tmp[ name ] ) {
2400 tmp[ name ] = [];
2401 }
2402 tmp[ name ].push( val.value );
2403 }
2404 else {
2405 tmp[val.name] = val.value;
2406 }
2407 } );
2408 data = tmp;
2409 }
2410
2411 var ajaxData;
2412 var ajax = oSettings.ajax;
2413 var instance = oSettings.oInstance;
2414
2415 if ( $.isPlainObject( ajax ) && ajax.data )
2416 {
2417 ajaxData = ajax.data;
2418
2419 var newData = $.isFunction( ajaxData ) ?
2420 ajaxData( data ) : // fn can manipulate data or return an object
2421 ajaxData; // object or array to merge
2422
2423 // If the function returned an object, use that alone
2424 data = $.isFunction( ajaxData ) && newData ?
2425 newData :
2426 $.extend( true, data, newData );
2427
2428 // Remove the data property as we've resolved it already and don't want
2429 // jQuery to do it again (it is restored at the end of the function)
2430 delete ajax.data;
2431 }
2432
2433 var baseAjax = {
2434 "data": data,
2435 "success": function (json) {
2436 var error = json.error || json.sError;
2437 if ( error ) {
2438 oSettings.oApi._fnLog( oSettings, 0, error );
2439 }
2440
2441 oSettings.json = json;
2442 _fnCallbackFire( oSettings, null, 'xhr', [oSettings, json] );
2443 fn( json );
2444 },
2445 "dataType": "json",
2446 "cache": false,
2447 "type": oSettings.sServerMethod,
2448 "error": function (xhr, error, thrown) {
2449 var log = oSettings.oApi._fnLog;
2450
2451 if ( error == "parsererror" ) {
2452 log( oSettings, 0, 'Invalid JSON response', 1 );
2453 }
2454 else if ( xhr.readyState === 4 ) {
2455 log( oSettings, 0, 'Ajax error', 7 );
2456 }
2457
2458 _fnProcessingDisplay( oSettings, false );
2459 }
2460 };
2461
2462 // Store the data submitted for the API
2463 oSettings.oAjaxData = data;
2464
2465 // Allow plug-ins and external processes to modify the data
2466 _fnCallbackFire( oSettings, null, 'preXhr', [oSettings, data] );
2467
2468 if ( oSettings.fnServerData )
2469 {
2470 // DataTables 1.9- compatibility
2471 oSettings.fnServerData.call( instance,
2472 oSettings.sAjaxSource,
2473 $.map( data, function (val, key) { // Need to convert back to 1.9 trad format
2474 return { name: key, value: val };
2475 } ),
2476 fn,
2477 oSettings
2478 );
2479 }
2480 else if ( oSettings.sAjaxSource || typeof ajax === 'string' )
2481 {
2482 // DataTables 1.9- compatibility
2483 oSettings.jqXHR = $.ajax( $.extend( baseAjax, {
2484 url: ajax || oSettings.sAjaxSource
2485 } ) );
2486 }
2487 else if ( $.isFunction( ajax ) )
2488 {
2489 // Is a function - let the caller define what needs to be done
2490 oSettings.jqXHR = ajax.call( instance, data, fn, oSettings );
2491 }
2492 else
2493 {
2494 // Object to extend the base settings
2495 oSettings.jqXHR = $.ajax( $.extend( baseAjax, ajax ) );
2496
2497 // Restore for next time around
2498 ajax.data = ajaxData;
2499 }
2500 }
2501
2502
2503 /**
2504 * Update the table using an Ajax call
2505 * @param {object} settings dataTables settings object
2506 * @returns {boolean} Block the table drawing or not
2507 * @memberof DataTable#oApi
2508 */
2509 function _fnAjaxUpdate( settings )
2510 {
2511 if ( settings.bAjaxDataGet ) {
2512 settings.iDraw++;
2513 _fnProcessingDisplay( settings, true );
2514
2515 _fnBuildAjax(
2516 settings,
2517 _fnAjaxParameters( settings ),
2518 function(json) {
2519 _fnAjaxUpdateDraw( settings, json );
2520 }
2521 );
2522
2523 return false;
2524 }
2525 return true;
2526 }
2527
2528
2529 /**
2530 * Build up the parameters in an object needed for a server-side processing
2531 * request. Note that this is basically done twice, is different ways - a modern
2532 * method which is used by default in DataTables 1.10 which uses objects and
2533 * arrays, or the 1.9- method with is name / value pairs. 1.9 method is used if
2534 * the sAjaxSource option is used in the initialisation, or the legacyAjax
2535 * option is set.
2536 * @param {object} oSettings dataTables settings object
2537 * @returns {bool} block the table drawing or not
2538 * @memberof DataTable#oApi
2539 */
2540 function _fnAjaxParameters( settings )
2541 {
2542 var
2543 columns = settings.aoColumns,
2544 columnCount = columns.length,
2545 features = settings.oFeatures,
2546 preSearch = settings.oPreviousSearch,
2547 preColSearch = settings.aoPreSearchCols,
2548 i, data = [], dataProp, column, columnSearch,
2549 sort = _fnSortFlatten( settings ),
2550 displayStart = settings._iDisplayStart,
2551 displayLength = features.bPaginate !== false ?
2552 settings._iDisplayLength :
2553 -1;
2554
2555 var param = function ( name, value ) {
2556 data.push( { 'name': name, 'value': value } );
2557 };
2558
2559 // DataTables 1.9- compatible method
2560 param( 'sEcho', settings.iDraw );
2561 param( 'iColumns', columnCount );
2562 param( 'sColumns', _pluck( columns, 'sName' ).join(',') );
2563 param( 'iDisplayStart', displayStart );
2564 param( 'iDisplayLength', displayLength );
2565
2566 // DataTables 1.10+ method
2567 var d = {
2568 draw: settings.iDraw,
2569 columns: [],
2570 order: [],
2571 start: displayStart,
2572 length: displayLength,
2573 search: {
2574 value: preSearch.sSearch,
2575 regex: preSearch.bRegex
2576 }
2577 };
2578
2579 for ( i=0 ; i<columnCount ; i++ ) {
2580 column = columns[i];
2581 columnSearch = preColSearch[i];
2582 dataProp = typeof column.mData=="function" ? 'function' : column.mData ;
2583
2584 d.columns.push( {
2585 data: dataProp,
2586 name: column.sName,
2587 searchable: column.bSearchable,
2588 orderable: column.bSortable,
2589 search: {
2590 value: columnSearch.sSearch,
2591 regex: columnSearch.bRegex
2592 }
2593 } );
2594
2595 param( "mDataProp_"+i, dataProp );
2596
2597 if ( features.bFilter ) {
2598 param( 'sSearch_'+i, columnSearch.sSearch );
2599 param( 'bRegex_'+i, columnSearch.bRegex );
2600 param( 'bSearchable_'+i, column.bSearchable );
2601 }
2602
2603 if ( features.bSort ) {
2604 param( 'bSortable_'+i, column.bSortable );
2605 }
2606 }
2607
2608 if ( features.bFilter ) {
2609 param( 'sSearch', preSearch.sSearch );
2610 param( 'bRegex', preSearch.bRegex );
2611 }
2612
2613 if ( features.bSort ) {
2614 $.each( sort, function ( i, val ) {
2615 d.order.push( { column: val.col, dir: val.dir } );
2616
2617 param( 'iSortCol_'+i, val.col );
2618 param( 'sSortDir_'+i, val.dir );
2619 } );
2620
2621 param( 'iSortingCols', sort.length );
2622 }
2623
2624 // If the legacy.ajax parameter is null, then we automatically decide which
2625 // form to use, based on sAjaxSource
2626 var legacy = DataTable.ext.legacy.ajax;
2627 if ( legacy === null ) {
2628 return settings.sAjaxSource ? data : d;
2629 }
2630
2631 // Otherwise, if legacy has been specified then we use that to decide on the
2632 // form
2633 return legacy ? data : d;
2634 }
2635
2636
2637 /**
2638 * Data the data from the server (nuking the old) and redraw the table
2639 * @param {object} oSettings dataTables settings object
2640 * @param {object} json json data return from the server.
2641 * @param {string} json.sEcho Tracking flag for DataTables to match requests
2642 * @param {int} json.iTotalRecords Number of records in the data set, not accounting for filtering
2643 * @param {int} json.iTotalDisplayRecords Number of records in the data set, accounting for filtering
2644 * @param {array} json.aaData The data to display on this page
2645 * @param {string} [json.sColumns] Column ordering (sName, comma separated)
2646 * @memberof DataTable#oApi
2647 */
2648 function _fnAjaxUpdateDraw ( settings, json )
2649 {
2650 // v1.10 uses camelCase variables, while 1.9 uses Hungarian notation.
2651 // Support both
2652 var compat = function ( old, modern ) {
2653 return json[old] !== undefined ? json[old] : json[modern];
2654 };
2655
2656 var draw = compat( 'sEcho', 'draw' );
2657 var recordsTotal = compat( 'iTotalRecords', 'recordsTotal' );
2658 var recordsFiltered = compat( 'iTotalDisplayRecords', 'recordsFiltered' );
2659
2660 if ( draw ) {
2661 // Protect against out of sequence returns
2662 if ( draw*1 < settings.iDraw ) {
2663 return;
2664 }
2665 settings.iDraw = draw * 1;
2666 }
2667
2668 _fnClearTable( settings );
2669 settings._iRecordsTotal = parseInt(recordsTotal, 10);
2670 settings._iRecordsDisplay = parseInt(recordsFiltered, 10);
2671
2672 var data = _fnAjaxDataSrc( settings, json );
2673 for ( var i=0, ien=data.length ; i<ien ; i++ ) {
2674 _fnAddData( settings, data[i] );
2675 }
2676 settings.aiDisplay = settings.aiDisplayMaster.slice();
2677
2678 settings.bAjaxDataGet = false;
2679 _fnDraw( settings );
2680
2681 if ( ! settings._bInitComplete ) {
2682 _fnInitComplete( settings, json );
2683 }
2684
2685 settings.bAjaxDataGet = true;
2686 _fnProcessingDisplay( settings, false );
2687 }
2688
2689
2690 /**
2691 * Get the data from the JSON data source to use for drawing a table. Using
2692 * `_fnGetObjectDataFn` allows the data to be sourced from a property of the
2693 * source object, or from a processing function.
2694 * @param {object} oSettings dataTables settings object
2695 * @param {object} json Data source object / array from the server
2696 * @return {array} Array of data to use
2697 */
2698 function _fnAjaxDataSrc ( oSettings, json )
2699 {
2700 var dataSrc = $.isPlainObject( oSettings.ajax ) && oSettings.ajax.dataSrc !== undefined ?
2701 oSettings.ajax.dataSrc :
2702 oSettings.sAjaxDataProp; // Compatibility with 1.9-.
2703
2704 // Compatibility with 1.9-. In order to read from aaData, check if the
2705 // default has been changed, if not, check for aaData
2706 if ( dataSrc === 'data' ) {
2707 return json.aaData || json[dataSrc];
2708 }
2709
2710 return dataSrc !== "" ?
2711 _fnGetObjectDataFn( dataSrc )( json ) :
2712 json;
2713 }
2714
2715
2716 /**
2717 * Generate the node required for filtering text
2718 * @returns {node} Filter control element
2719 * @param {object} oSettings dataTables settings object
2720 * @memberof DataTable#oApi
2721 */
2722 function _fnFeatureHtmlFilter ( settings )
2723 {
2724 var classes = settings.oClasses;
2725 var tableId = settings.sTableId;
2726 var language = settings.oLanguage;
2727 var previousSearch = settings.oPreviousSearch;
2728 var features = settings.aanFeatures;
2729 var input = '';
2730
2731 var str = language.sSearch;
2732 str = str.match(/_INPUT_/) ?
2733 str.replace('_INPUT_', input) :
2734 str+input;
2735
2736 var filter = $('<div/>', {
2737 'id': ! features.f ? tableId+'_filter' : null,
2738 'class': classes.sFilter
2739 } )
2740 .append( $('<label/>' ).append( str ) );
2741
2742
2743
2744
2745 }
2746
2747 /**
2748 * Filter the table using both the global filter and column based filtering
2749 * @param {object} oSettings dataTables settings object
2750 * @param {object} oSearch search information
2751 * @param {int} [iForce] force a research of the master array (1) or not (undefined or 0)
2752 * @memberof DataTable#oApi
2753 */
2754 function _fnFilterComplete ( oSettings, oInput, iForce )
2755 {
2756 var oPrevSearch = oSettings.oPreviousSearch;
2757 var aoPrevSearch = oSettings.aoPreSearchCols;
2758 var fnSaveFilter = function ( oFilter ) {
2759 /* Save the filtering values */
2760 oPrevSearch.sSearch = oFilter.sSearch;
2761 oPrevSearch.bRegex = oFilter.bRegex;
2762 oPrevSearch.bSmart = oFilter.bSmart;
2763 oPrevSearch.bCaseInsensitive = oFilter.bCaseInsensitive;
2764 };
2765 var fnRegex = function ( o ) {
2766 // Backwards compatibility with the bEscapeRegex option
2767 return o.bEscapeRegex !== undefined ? !o.bEscapeRegex : o.bRegex;
2768 };
2769
2770 // Resolve any column types that are unknown due to addition or invalidation
2771 // @todo As per sort - can this be moved into an event handler?
2772 _fnColumnTypes( oSettings );
2773
2774 /* In server-side processing all filtering is done by the server, so no point hanging around here */
2775 if ( _fnDataSource( oSettings ) != 'ssp' )
2776 {
2777 /* Global filter */
2778 _fnFilter( oSettings, oInput.sSearch, iForce, fnRegex(oInput), oInput.bSmart, oInput.bCaseInsensitive );
2779 fnSaveFilter( oInput );
2780
2781 /* Now do the individual column filter */
2782 for ( var i=0 ; i<aoPrevSearch.length ; i++ )
2783 {
2784 _fnFilterColumn( oSettings, aoPrevSearch[i].sSearch, i, fnRegex(aoPrevSearch[i]),
2785 aoPrevSearch[i].bSmart, aoPrevSearch[i].bCaseInsensitive );
2786 }
2787
2788 /* Custom filtering */
2789 _fnFilterCustom( oSettings );
2790 }
2791 else
2792 {
2793 fnSaveFilter( oInput );
2794 }
2795
2796 /* Tell the draw function we have been filtering */
2797 oSettings.bFiltered = true;
2798 _fnCallbackFire( oSettings, null, 'search', [oSettings] );
2799 }
2800
2801
2802 /**
2803 * Apply custom filtering functions
2804 * @param {object} oSettings dataTables settings object
2805 * @memberof DataTable#oApi
2806 */
2807 function _fnFilterCustom( settings )
2808 {
2809 var filters = DataTable.ext.search;
2810 var displayRows = settings.aiDisplay;
2811 var row, rowIdx;
2812
2813 for ( var i=0, ien=filters.length ; i<ien ; i++ ) {
2814 var rows = [];
2815
2816 // Loop over each row and see if it should be included
2817 for ( var j=0, jen=displayRows.length ; j<jen ; j++ ) {
2818 rowIdx = displayRows[ j ];
2819 row = settings.aoData[ rowIdx ];
2820
2821 if ( filters[i]( settings, row._aFilterData, rowIdx, row._aData, j ) ) {
2822 rows.push( rowIdx );
2823 }
2824 }
2825
2826 // So the array reference doesn't break set the results into the
2827 // existing array
2828 displayRows.length = 0;
2829 displayRows.push.apply( displayRows, rows );
2830 }
2831 }
2832
2833
2834 /**
2835 * Filter the table on a per-column basis
2836 * @param {object} oSettings dataTables settings object
2837 * @param {string} sInput string to filter on
2838 * @param {int} iColumn column to filter
2839 * @param {bool} bRegex treat search string as a regular expression or not
2840 * @param {bool} bSmart use smart filtering or not
2841 * @param {bool} bCaseInsensitive Do case insenstive matching or not
2842 * @memberof DataTable#oApi
2843 */
2844 function _fnFilterColumn ( settings, searchStr, colIdx, regex, smart, caseInsensitive )
2845 {
2846 if ( searchStr === '' ) {
2847 return;
2848 }
2849
2850 var data;
2851 var display = settings.aiDisplay;
2852 var rpSearch = _fnFilterCreateSearch( searchStr, regex, smart, caseInsensitive );
2853
2854 for ( var i=display.length-1 ; i>=0 ; i-- ) {
2855 data = settings.aoData[ display[i] ]._aFilterData[ colIdx ];
2856
2857 if ( ! rpSearch.test( data ) ) {
2858 display.splice( i, 1 );
2859 }
2860 }
2861 }
2862
2863
2864 /**
2865 * Filter the data table based on user input and draw the table
2866 * @param {object} settings dataTables settings object
2867 * @param {string} input string to filter on
2868 * @param {int} force optional - force a research of the master array (1) or not (undefined or 0)
2869 * @param {bool} regex treat as a regular expression or not
2870 * @param {bool} smart perform smart filtering or not
2871 * @param {bool} caseInsensitive Do case insenstive matching or not
2872 * @memberof DataTable#oApi
2873 */
2874 function _fnFilter( settings, input, force, regex, smart, caseInsensitive )
2875 {
2876 var rpSearch = _fnFilterCreateSearch( input, regex, smart, caseInsensitive );
2877 var prevSearch = settings.oPreviousSearch.sSearch;
2878 var displayMaster = settings.aiDisplayMaster;
2879 var display, invalidated, i;
2880
2881 // Need to take account of custom filtering functions - always filter
2882 if ( DataTable.ext.search.length !== 0 ) {
2883 force = true;
2884 }
2885
2886 // Check if any of the rows were invalidated
2887 invalidated = _fnFilterData( settings );
2888
2889 // If the input is blank - we just want the full data set
2890 if ( input.length <= 0 ) {
2891 settings.aiDisplay = displayMaster.slice();
2892 }
2893 else {
2894 // New search - start from the master array
2895 if ( invalidated ||
2896 force ||
2897 prevSearch.length > input.length ||
2898 input.indexOf(prevSearch) !== 0 ||
2899 settings.bSorted // On resort, the display master needs to be
2900 // re-filtered since indexes will have changed
2901 ) {
2902 settings.aiDisplay = displayMaster.slice();
2903 }
2904
2905 // Search the display array
2906 display = settings.aiDisplay;
2907
2908 for ( i=display.length-1 ; i>=0 ; i-- ) {
2909 if ( ! rpSearch.test( settings.aoData[ display[i] ]._sFilterRow ) ) {
2910 display.splice( i, 1 );
2911 }
2912 }
2913 }
2914 }
2915
2916
2917 /**
2918 * Build a regular expression object suitable for searching a table
2919 * @param {string} sSearch string to search for
2920 * @param {bool} bRegex treat as a regular expression or not
2921 * @param {bool} bSmart perform smart filtering or not
2922 * @param {bool} bCaseInsensitive Do case insensitive matching or not
2923 * @returns {RegExp} constructed object
2924 * @memberof DataTable#oApi
2925 */
2926 function _fnFilterCreateSearch( search, regex, smart, caseInsensitive )
2927 {
2928 search = regex ?
2929 search :
2930 _fnEscapeRegex( search );
2931
2932 if ( smart ) {
2933 /* For smart filtering we want to allow the search to work regardless of
2934 * word order. We also want double quoted text to be preserved, so word
2935 * order is important - a la google. So this is what we want to
2936 * generate:
2937 *
2938 * ^(?=.*?\bone\b)(?=.*?\btwo three\b)(?=.*?\bfour\b).*$
2939 */
2940 var a = $.map( search.match( /"[^"]+"|[^ ]+/g ) || '', function ( word ) {
2941 if ( word.charAt(0) === '"' ) {
2942 var m = word.match( /^"(.*)"$/ );
2943 word = m ? m[1] : word;
2944 }
2945
2946 return word.replace('"', '');
2947 } );
2948
2949 search = '^(?=.*?'+a.join( ')(?=.*?' )+').*$';
2950 }
2951
2952 return new RegExp( search, caseInsensitive ? 'i' : '' );
2953 }
2954
2955
2956 /**
2957 * Escape a string such that it can be used in a regular expression
2958 * @param {string} sVal string to escape
2959 * @returns {string} escaped string
2960 * @memberof DataTable#oApi
2961 */
2962 function _fnEscapeRegex ( sVal )
2963 {
2964 return sVal.replace( _re_escape_regex, '\\$1' );
2965 }
2966
2967
2968
2969 var __filter_div = $('<div>')[0];
2970 var __filter_div_textContent = __filter_div.textContent !== undefined;
2971
2972 // Update the filtering data for each row if needed (by invalidation or first run)
2973 function _fnFilterData ( settings )
2974 {
2975 var columns = settings.aoColumns;
2976 var column;
2977 var i, j, ien, jen, filterData, cellData, row;
2978 var fomatters = DataTable.ext.type.search;
2979 var wasInvalidated = false;
2980
2981 for ( i=0, ien=settings.aoData.length ; i<ien ; i++ ) {
2982 row = settings.aoData[i];
2983
2984 if ( ! row._aFilterData ) {
2985 filterData = [];
2986
2987 for ( j=0, jen=columns.length ; j<jen ; j++ ) {
2988 column = columns[j];
2989
2990 if ( column.bSearchable ) {
2991 cellData = _fnGetCellData( settings, i, j, 'filter' );
2992
2993 if ( fomatters[ column.sType ] ) {
2994 cellData = fomatters[ column.sType ]( cellData );
2995 }
2996
2997 // Search in DataTables 1.10 is string based. In 1.11 this
2998 // should be altered to also allow strict type checking.
2999 if ( cellData === null ) {
3000 cellData = '';
3001 }
3002
3003 if ( typeof cellData !== 'string' && cellData.toString ) {
3004 cellData = cellData.toString();
3005 }
3006 }
3007 else {
3008 cellData = '';
3009 }
3010
3011 // If it looks like there is an HTML entity in the string,
3012 // attempt to decode it so sorting works as expected. Note that
3013 // we could use a single line of jQuery to do this, but the DOM
3014 // method used here is much faster http://jsperf.com/html-decode
3015 if ( cellData.indexOf && cellData.indexOf('&') !== -1 ) {
3016 __filter_div.innerHTML = cellData;
3017 cellData = __filter_div_textContent ?
3018 __filter_div.textContent :
3019 __filter_div.innerText;
3020 }
3021
3022 if ( cellData.replace ) {
3023 cellData = cellData.replace(/[\r\n]/g, '');
3024 }
3025
3026 filterData.push( cellData );
3027 }
3028
3029 row._aFilterData = filterData;
3030 row._sFilterRow = filterData.join(' ');
3031 wasInvalidated = true;
3032 }
3033 }
3034
3035 return wasInvalidated;
3036 }
3037
3038
3039 /**
3040 * Convert from the internal Hungarian notation to camelCase for external
3041 * interaction
3042 * @param {object} obj Object to convert
3043 * @returns {object} Inverted object
3044 * @memberof DataTable#oApi
3045 */
3046 function _fnSearchToCamel ( obj )
3047 {
3048 return {
3049 search: obj.sSearch,
3050 smart: obj.bSmart,
3051 regex: obj.bRegex,
3052 caseInsensitive: obj.bCaseInsensitive
3053 };
3054 }
3055
3056
3057
3058 /**
3059 * Convert from camelCase notation to the internal Hungarian. We could use the
3060 * Hungarian convert function here, but this is cleaner
3061 * @param {object} obj Object to convert
3062 * @returns {object} Inverted object
3063 * @memberof DataTable#oApi
3064 */
3065 function _fnSearchToHung ( obj )
3066 {
3067 return {
3068 sSearch: obj.search,
3069 bSmart: obj.smart,
3070 bRegex: obj.regex,
3071 bCaseInsensitive: obj.caseInsensitive
3072 };
3073 }
3074
3075 /**
3076 * Generate the node required for the info display
3077 * @param {object} oSettings dataTables settings object
3078 * @returns {node} Information element
3079 * @memberof DataTable#oApi
3080 */
3081 function _fnFeatureHtmlInfo ( settings )
3082 {
3083 var
3084 tid = settings.sTableId,
3085 nodes = settings.aanFeatures.i,
3086 n = $('<div/>', {
3087 'class': settings.oClasses.sInfo,
3088 'id': ! nodes ? tid+'_info' : null
3089 } );
3090
3091 if ( ! nodes ) {
3092 // Update display on each draw
3093 settings.aoDrawCallback.push( {
3094 "fn": _fnUpdateInfo,
3095 "sName": "information"
3096 } );
3097
3098 n
3099 .attr( 'role', 'status' )
3100 .attr( 'aria-live', 'polite' );
3101
3102 // Table is described by our info div
3103 $(settings.nTable).attr( 'aria-describedby', tid+'_info' );
3104 }
3105
3106 return n[0];
3107 }
3108
3109
3110 /**
3111 * Update the information elements in the display
3112 * @param {object} settings dataTables settings object
3113 * @memberof DataTable#oApi
3114 */
3115 function _fnUpdateInfo ( settings )
3116 {
3117 /* Show information about the table */
3118 var nodes = settings.aanFeatures.i;
3119 if ( nodes.length === 0 ) {
3120 return;
3121 }
3122
3123 var
3124 lang = settings.oLanguage,
3125 start = settings._iDisplayStart+1,
3126 end = settings.fnDisplayEnd(),
3127 max = settings.fnRecordsTotal(),
3128 total = settings.fnRecordsDisplay(),
3129 out = total ?
3130 lang.sInfo :
3131 lang.sInfoEmpty;
3132
3133 if ( total !== max ) {
3134 /* Record set after filtering */
3135 out += ' ' + lang.sInfoFiltered;
3136 }
3137
3138 // Convert the macros
3139 out += lang.sInfoPostFix;
3140 out = _fnInfoMacros( settings, out );
3141
3142 var callback = lang.fnInfoCallback;
3143 if ( callback !== null ) {
3144 out = callback.call( settings.oInstance,
3145 settings, start, end, max, total, out
3146 );
3147 }
3148
3149 $(nodes).html( out );
3150 }
3151
3152
3153 function _fnInfoMacros ( settings, str )
3154 {
3155 // When infinite scrolling, we are always starting at 1. _iDisplayStart is used only
3156 // internally
3157 var
3158 formatter = settings.fnFormatNumber,
3159 start = settings._iDisplayStart+1,
3160 len = settings._iDisplayLength,
3161 vis = settings.fnRecordsDisplay(),
3162 all = len === -1;
3163
3164 return str.
3165 replace(/_START_/g, formatter.call( settings, start ) ).
3166 replace(/_END_/g, formatter.call( settings, settings.fnDisplayEnd() ) ).
3167 replace(/_MAX_/g, formatter.call( settings, settings.fnRecordsTotal() ) ).
3168 replace(/_TOTAL_/g, formatter.call( settings, vis ) ).
3169 replace(/_PAGE_/g, formatter.call( settings, all ? 1 : Math.ceil( start / len ) ) ).
3170 replace(/_PAGES_/g, formatter.call( settings, all ? 1 : Math.ceil( vis / len ) ) );
3171 }
3172
3173
3174
3175 /**
3176 * Draw the table for the first time, adding all required features
3177 * @param {object} settings dataTables settings object
3178 * @memberof DataTable#oApi
3179 */
3180 function _fnInitialise ( settings )
3181 {
3182 var i, iLen, iAjaxStart=settings.iInitDisplayStart;
3183 var columns = settings.aoColumns, column;
3184 var features = settings.oFeatures;
3185
3186 /* Ensure that the table data is fully initialised */
3187 if ( ! settings.bInitialised ) {
3188 setTimeout( function(){ _fnInitialise( settings ); }, 200 );
3189 return;
3190 }
3191
3192 /* Show the display HTML options */
3193 _fnAddOptionsHtml( settings );
3194
3195 /* Build and draw the header / footer for the table */
3196 _fnBuildHead( settings );
3197 _fnDrawHead( settings, settings.aoHeader );
3198 _fnDrawHead( settings, settings.aoFooter );
3199
3200 /* Okay to show that something is going on now */
3201 _fnProcessingDisplay( settings, true );
3202
3203 /* Calculate sizes for columns */
3204 if ( features.bAutoWidth ) {
3205 _fnCalculateColumnWidths( settings );
3206 }
3207
3208 for ( i=0, iLen=columns.length ; i<iLen ; i++ ) {
3209 column = columns[i];
3210
3211 if ( column.sWidth ) {
3212 column.nTh.style.width = _fnStringToCss( column.sWidth );
3213 }
3214 }
3215
3216 // If there is default sorting required - let's do it. The sort function
3217 // will do the drawing for us. Otherwise we draw the table regardless of the
3218 // Ajax source - this allows the table to look initialised for Ajax sourcing
3219 // data (show 'loading' message possibly)
3220 _fnReDraw( settings );
3221
3222 // Server-side processing init complete is done by _fnAjaxUpdateDraw
3223 var dataSrc = _fnDataSource( settings );
3224 if ( dataSrc != 'ssp' ) {
3225 // if there is an ajax source load the data
3226 if ( dataSrc == 'ajax' ) {
3227 _fnBuildAjax( settings, [], function(json) {
3228 var aData = _fnAjaxDataSrc( settings, json );
3229
3230 // Got the data - add it to the table
3231 for ( i=0 ; i<aData.length ; i++ ) {
3232 _fnAddData( settings, aData[i] );
3233 }
3234
3235 // Reset the init display for cookie saving. We've already done
3236 // a filter, and therefore cleared it before. So we need to make
3237 // it appear 'fresh'
3238 settings.iInitDisplayStart = iAjaxStart;
3239
3240 _fnReDraw( settings );
3241
3242 _fnProcessingDisplay( settings, false );
3243 _fnInitComplete( settings, json );
3244 }, settings );
3245 }
3246 else {
3247 _fnProcessingDisplay( settings, false );
3248 _fnInitComplete( settings );
3249 }
3250 }
3251 }
3252
3253
3254 /**
3255 * Draw the table for the first time, adding all required features
3256 * @param {object} oSettings dataTables settings object
3257 * @param {object} [json] JSON from the server that completed the table, if using Ajax source
3258 * with client-side processing (optional)
3259 * @memberof DataTable#oApi
3260 */
3261 function _fnInitComplete ( settings, json )
3262 {
3263 settings._bInitComplete = true;
3264
3265 // On an Ajax load we now have data and therefore want to apply the column
3266 // sizing
3267 if ( json ) {
3268 _fnAdjustColumnSizing( settings );
3269 }
3270
3271 _fnCallbackFire( settings, 'aoInitComplete', 'init', [settings, json] );
3272 }
3273
3274
3275 function _fnLengthChange ( settings, val )
3276 {
3277 var len = parseInt( val, 10 );
3278 settings._iDisplayLength = len;
3279
3280 _fnLengthOverflow( settings );
3281
3282 // Fire length change event
3283 _fnCallbackFire( settings, null, 'length', [settings, len] );
3284 }
3285
3286
3287 /**
3288 * Generate the node required for user display length changing
3289 * @param {object} settings dataTables settings object
3290 * @returns {node} Display length feature node
3291 * @memberof DataTable#oApi
3292 */
3293 function _fnFeatureHtmlLength ( settings )
3294 {
3295 var
3296 classes = settings.oClasses,
3297 tableId = settings.sTableId,
3298 menu = settings.aLengthMenu,
3299 d2 = $.isArray( menu[0] ),
3300 lengths = d2 ? menu[0] : menu,
3301 language = d2 ? menu[1] : menu;
3302
3303 var select = $('<select/>', {
3304 'name': tableId+'_length',
3305 'aria-controls': tableId,
3306 'class': classes.sLengthSelect
3307 } );
3308
3309 for ( var i=0, ien=lengths.length ; i<ien ; i++ ) {
3310 select[0][ i ] = new Option( language[i], lengths[i] );
3311 }
3312
3313 var div = $('<div><label/></div>').addClass( classes.sLength );
3314 if ( ! settings.aanFeatures.l ) {
3315 div[0].id = tableId+'_length';
3316 }
3317
3318 // Can't use `select` variable as user might provide their own and the
3319 // reference is broken by the use of outerHTML
3320 $('select', div)
3321 .val( settings._iDisplayLength )
3322 .bind( 'change.DT', function(e) {
3323 _fnLengthChange( settings, $(this).val() );
3324 _fnDraw( settings );
3325 } );
3326
3327 // Update node value whenever anything changes the table's length
3328 $(settings.nTable).bind( 'length.dt.DT', function (e, s, len) {
3329 if ( settings === s ) {
3330 $('select', div).val( len );
3331 }
3332 } );
3333
3334 return div[0];
3335 }
3336
3337
3338
3339 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
3340 * Note that most of the paging logic is done in
3341 * DataTable.ext.pager
3342 */
3343
3344 /**
3345 * Generate the node required for default pagination
3346 * @param {object} oSettings dataTables settings object
3347 * @returns {node} Pagination feature node
3348 * @memberof DataTable#oApi
3349 */
3350 function _fnFeatureHtmlPaginate ( settings )
3351 {
3352 var
3353 type = settings.sPaginationType,
3354 plugin = DataTable.ext.pager[ type ],
3355 modern = typeof plugin === 'function',
3356 redraw = function( settings ) {
3357 _fnDraw( settings );
3358 },
3359 node = $('<div/>').addClass( settings.oClasses.sPaging + type )[0],
3360 features = settings.aanFeatures;
3361
3362 if ( ! modern ) {
3363 plugin.fnInit( settings, node, redraw );
3364 }
3365
3366 /* Add a draw callback for the pagination on first instance, to update the paging display */
3367 if ( ! features.p )
3368 {
3369 node.id = settings.sTableId+'_paginate';
3370
3371 settings.aoDrawCallback.push( {
3372 "fn": function( settings ) {
3373 if ( modern ) {
3374 var
3375 start = settings._iDisplayStart,
3376 len = settings._iDisplayLength,
3377 visRecords = settings.fnRecordsDisplay(),
3378 all = len === -1,
3379 page = all ? 0 : Math.ceil( start / len ),
3380 pages = all ? 1 : Math.ceil( visRecords / len ),
3381 buttons = plugin(page, pages),
3382 i, ien;
3383
3384 for ( i=0, ien=features.p.length ; i<ien ; i++ ) {
3385 _fnRenderer( settings, 'pageButton' )(
3386 settings, features.p[i], i, buttons, page, pages
3387 );
3388 }
3389 }
3390 else {
3391 plugin.fnUpdate( settings, redraw );
3392 }
3393 },
3394 "sName": "pagination"
3395 } );
3396 }
3397
3398 return node;
3399 }
3400
3401
3402 /**
3403 * Alter the display settings to change the page
3404 * @param {object} settings DataTables settings object
3405 * @param {string|int} action Paging action to take: "first", "previous",
3406 * "next" or "last" or page number to jump to (integer)
3407 * @param [bool] redraw Automatically draw the update or not
3408 * @returns {bool} true page has changed, false - no change
3409 * @memberof DataTable#oApi
3410 */
3411 function _fnPageChange ( settings, action, redraw )
3412 {
3413 var
3414 start = settings._iDisplayStart,
3415 len = settings._iDisplayLength,
3416 records = settings.fnRecordsDisplay();
3417
3418 if ( records === 0 || len === -1 )
3419 {
3420 start = 0;
3421 }
3422 else if ( typeof action === "number" )
3423 {
3424 start = action * len;
3425
3426 if ( start > records )
3427 {
3428 start = 0;
3429 }
3430 }
3431 else if ( action == "first" )
3432 {
3433 start = 0;
3434 }
3435 else if ( action == "previous" )
3436 {
3437 start = len >= 0 ?
3438 start - len :
3439 0;
3440
3441 if ( start < 0 )
3442 {
3443 start = 0;
3444 }
3445 }
3446 else if ( action == "next" )
3447 {
3448 if ( start + len < records )
3449 {
3450 start += len;
3451 }
3452 }
3453 else if ( action == "last" )
3454 {
3455 start = Math.floor( (records-1) / len) * len;
3456 }
3457 else
3458 {
3459 _fnLog( settings, 0, "Unknown paging action: "+action, 5 );
3460 }
3461
3462 var changed = settings._iDisplayStart !== start;
3463 settings._iDisplayStart = start;
3464
3465 if ( changed ) {
3466 _fnCallbackFire( settings, null, 'page', [settings] );
3467
3468 if ( redraw ) {
3469 _fnDraw( settings );
3470 }
3471 }
3472
3473 return changed;
3474 }
3475
3476
3477
3478 /**
3479 * Generate the node required for the processing node
3480 * @param {object} settings dataTables settings object
3481 * @returns {node} Processing element
3482 * @memberof DataTable#oApi
3483 */
3484 function _fnFeatureHtmlProcessing ( settings )
3485 {
3486 return $('<div/>', {
3487 'id': ! settings.aanFeatures.r ? settings.sTableId+'_processing' : null,
3488 'class': settings.oClasses.sProcessing
3489 } )
3490 .html( settings.oLanguage.sProcessing )
3491 .insertBefore( settings.nTable )[0];
3492 }
3493
3494
3495 /**
3496 * Display or hide the processing indicator
3497 * @param {object} settings dataTables settings object
3498 * @param {bool} show Show the processing indicator (true) or not (false)
3499 * @memberof DataTable#oApi
3500 */
3501 function _fnProcessingDisplay ( settings, show )
3502 {
3503 if ( settings.oFeatures.bProcessing ) {
3504 $(settings.aanFeatures.r).css( 'display', show ? 'block' : 'none' );
3505 }
3506
3507 _fnCallbackFire( settings, null, 'processing', [settings, show] );
3508 }
3509
3510 /**
3511 * Add any control elements for the table - specifically scrolling
3512 * @param {object} settings dataTables settings object
3513 * @returns {node} Node to add to the DOM
3514 * @memberof DataTable#oApi
3515 */
3516 function _fnFeatureHtmlTable ( settings )
3517 {
3518 var table = $(settings.nTable);
3519
3520 // Add the ARIA grid role to the table
3521 table.attr( 'role', 'grid' );
3522
3523 // Scrolling from here on in
3524 var scroll = settings.oScroll;
3525
3526 if ( scroll.sX === '' && scroll.sY === '' ) {
3527 return settings.nTable;
3528 }
3529
3530 var scrollX = scroll.sX;
3531 var scrollY = scroll.sY;
3532 var classes = settings.oClasses;
3533 var caption = table.children('caption');
3534 var captionSide = caption.length ? caption[0]._captionSide : null;
3535 var headerClone = $( table[0].cloneNode(false) );
3536 var footerClone = $( table[0].cloneNode(false) );
3537 var footer = table.children('tfoot');
3538 var _div = '<div/>';
3539 var size = function ( s ) {
3540 return !s ? null : _fnStringToCss( s );
3541 };
3542
3543 // This is fairly messy, but with x scrolling enabled, if the table has a
3544 // width attribute, regardless of any width applied using the column width
3545 // options, the browser will shrink or grow the table as needed to fit into
3546 // that 100%. That would make the width options useless. So we remove it.
3547 // This is okay, under the assumption that width:100% is applied to the
3548 // table in CSS (it is in the default stylesheet) which will set the table
3549 // width as appropriate (the attribute and css behave differently...)
3550 if ( scroll.sX && table.attr('width') === '100%' ) {
3551 table.removeAttr('width');
3552 }
3553
3554 if ( ! footer.length ) {
3555 footer = null;
3556 }
3557
3558 /*
3559 * The HTML structure that we want to generate in this function is:
3560 * div - scroller
3561 * div - scroll head
3562 * div - scroll head inner
3563 * table - scroll head table
3564 * thead - thead
3565 * div - scroll body
3566 * table - table (master table)
3567 * thead - thead clone for sizing
3568 * tbody - tbody
3569 * div - scroll foot
3570 * div - scroll foot inner
3571 * table - scroll foot table
3572 * tfoot - tfoot
3573 */
3574 var scroller = $( _div, { 'class': classes.sScrollWrapper } )
3575 .append(
3576 $(_div, { 'class': classes.sScrollHead } )
3577 .css( {
3578 overflow: 'hidden',
3579 position: 'relative',
3580 border: 0,
3581 width: scrollX ? size(scrollX) : '100%'
3582 } )
3583 .append(
3584 $(_div, { 'class': classes.sScrollHeadInner } )
3585 .css( {
3586 'box-sizing': 'content-box',
3587 width: scroll.sXInner || '100%'
3588 } )
3589 .append(
3590 headerClone
3591 .removeAttr('id')
3592 .css( 'margin-left', 0 )
3593 .append( captionSide === 'top' ? caption : null )
3594 .append(
3595 table.children('thead')
3596 )
3597 )
3598 )
3599 )
3600 .append(
3601 $(_div, { 'class': classes.sScrollBody } )
3602 .css( {
3603 overflow: 'auto',
3604 height: size( scrollY ),
3605 width: size( scrollX )
3606 } )
3607 .append( table )
3608 );
3609
3610 if ( footer ) {
3611 scroller.append(
3612 $(_div, { 'class': classes.sScrollFoot } )
3613 .css( {
3614 overflow: 'hidden',
3615 border: 0,
3616 width: scrollX ? size(scrollX) : '100%'
3617 } )
3618 .append(
3619 $(_div, { 'class': classes.sScrollFootInner } )
3620 .append(
3621 footerClone
3622 .removeAttr('id')
3623 .css( 'margin-left', 0 )
3624 .append( captionSide === 'bottom' ? caption : null )
3625 .append(
3626 table.children('tfoot')
3627 )
3628 )
3629 )
3630 );
3631 }
3632
3633 var children = scroller.children();
3634 var scrollHead = children[0];
3635 var scrollBody = children[1];
3636 var scrollFoot = footer ? children[2] : null;
3637
3638 // When the body is scrolled, then we also want to scroll the headers
3639 if ( scrollX ) {
3640 $(scrollBody).scroll( function (e) {
3641 var scrollLeft = this.scrollLeft;
3642
3643 scrollHead.scrollLeft = scrollLeft;
3644
3645 if ( footer ) {
3646 scrollFoot.scrollLeft = scrollLeft;
3647 }
3648 } );
3649 }
3650
3651 settings.nScrollHead = scrollHead;
3652 settings.nScrollBody = scrollBody;
3653 settings.nScrollFoot = scrollFoot;
3654
3655 // On redraw - align columns
3656 settings.aoDrawCallback.push( {
3657 "fn": _fnScrollDraw,
3658 "sName": "scrolling"
3659 } );
3660
3661 return scroller[0];
3662 }
3663
3664
3665
3666 /**
3667 * Update the header, footer and body tables for resizing - i.e. column
3668 * alignment.
3669 *
3670 * Welcome to the most horrible function DataTables. The process that this
3671 * function follows is basically:
3672 * 1. Re-create the table inside the scrolling div
3673 * 2. Take live measurements from the DOM
3674 * 3. Apply the measurements to align the columns
3675 * 4. Clean up
3676 *
3677 * @param {object} settings dataTables settings object
3678 * @memberof DataTable#oApi
3679 */
3680 function _fnScrollDraw ( settings )
3681 {
3682 // Given that this is such a monster function, a lot of variables are use
3683 // to try and keep the minimised size as small as possible
3684 var
3685 scroll = settings.oScroll,
3686 scrollX = scroll.sX,
3687 scrollXInner = scroll.sXInner,
3688 scrollY = scroll.sY,
3689 barWidth = scroll.iBarWidth,
3690 divHeader = $(settings.nScrollHead),
3691 divHeaderStyle = divHeader[0].style,
3692 divHeaderInner = divHeader.children('div'),
3693 divHeaderInnerStyle = divHeaderInner[0].style,
3694 divHeaderTable = divHeaderInner.children('table'),
3695 divBodyEl = settings.nScrollBody,
3696 divBody = $(divBodyEl),
3697 divBodyStyle = divBodyEl.style,
3698 divFooter = $(settings.nScrollFoot),
3699 divFooterInner = divFooter.children('div'),
3700 divFooterTable = divFooterInner.children('table'),
3701 header = $(settings.nTHead),
3702 table = $(settings.nTable),
3703 tableEl = table[0],
3704 tableStyle = tableEl.style,
3705 footer = settings.nTFoot ? $(settings.nTFoot) : null,
3706 browser = settings.oBrowser,
3707 ie67 = browser.bScrollOversize,
3708 headerTrgEls, footerTrgEls,
3709 headerSrcEls, footerSrcEls,
3710 headerCopy, footerCopy,
3711 headerWidths=[], footerWidths=[],
3712 headerContent=[],
3713 idx, correction, sanityWidth,
3714 zeroOut = function(nSizer) {
3715 var style = nSizer.style;
3716 style.paddingTop = "0";
3717 style.paddingBottom = "0";
3718 style.borderTopWidth = "0";
3719 style.borderBottomWidth = "0";
3720 style.height = 0;
3721 };
3722
3723 /*
3724 * 1. Re-create the table inside the scrolling div
3725 */
3726
3727 // Remove the old minimised thead and tfoot elements in the inner table
3728 table.children('thead, tfoot').remove();
3729
3730 // Clone the current header and footer elements and then place it into the inner table
3731 headerCopy = header.clone().prependTo( table );
3732 headerTrgEls = header.find('tr'); // original header is in its own table
3733 headerSrcEls = headerCopy.find('tr');
3734 headerCopy.find('th, td').removeAttr('tabindex');
3735
3736 if ( footer ) {
3737 footerCopy = footer.clone().prependTo( table );
3738 footerTrgEls = footer.find('tr'); // the original tfoot is in its own table and must be sized
3739 footerSrcEls = footerCopy.find('tr');
3740 }
3741
3742
3743 /*
3744 * 2. Take live measurements from the DOM - do not alter the DOM itself!
3745 */
3746
3747 // Remove old sizing and apply the calculated column widths
3748 // Get the unique column headers in the newly created (cloned) header. We want to apply the
3749 // calculated sizes to this header
3750 if ( ! scrollX )
3751 {
3752 divBodyStyle.width = '100%';
3753 divHeader[0].style.width = '100%';
3754 }
3755
3756 $.each( _fnGetUniqueThs( settings, headerCopy ), function ( i, el ) {
3757 idx = _fnVisibleToColumnIndex( settings, i );
3758 el.style.width = settings.aoColumns[idx].sWidth;
3759 } );
3760
3761 if ( footer ) {
3762 _fnApplyToChildren( function(n) {
3763 n.style.width = "";
3764 }, footerSrcEls );
3765 }
3766
3767 // If scroll collapse is enabled, when we put the headers back into the body for sizing, we
3768 // will end up forcing the scrollbar to appear, making our measurements wrong for when we
3769 // then hide it (end of this function), so add the header height to the body scroller.
3770 if ( scroll.bCollapse && scrollY !== "" ) {
3771 divBodyStyle.height = (divBody[0].offsetHeight + header[0].offsetHeight)+"px";
3772 }
3773
3774 // Size the table as a whole
3775 sanityWidth = table.outerWidth();
3776 if ( scrollX === "" ) {
3777 // No x scrolling
3778 tableStyle.width = "100%";
3779
3780 // IE7 will make the width of the table when 100% include the scrollbar
3781 // - which is shouldn't. When there is a scrollbar we need to take this
3782 // into account.
3783 if ( ie67 && (table.find('tbody').height() > divBodyEl.offsetHeight ||
3784 divBody.css('overflow-y') == "scroll")
3785 ) {
3786 tableStyle.width = _fnStringToCss( table.outerWidth() - barWidth);
3787 }
3788 }
3789 else
3790 {
3791 // x scrolling
3792 if ( scrollXInner !== "" ) {
3793 // x scroll inner has been given - use it
3794 tableStyle.width = _fnStringToCss(scrollXInner);
3795 }
3796 else if ( sanityWidth == divBody.width() && divBody.height() < table.height() ) {
3797 // There is y-scrolling - try to take account of the y scroll bar
3798 tableStyle.width = _fnStringToCss( sanityWidth-barWidth );
3799 if ( table.outerWidth() > sanityWidth-barWidth ) {
3800 // Not possible to take account of it
3801 tableStyle.width = _fnStringToCss( sanityWidth );
3802 }
3803 }
3804 else {
3805 // When all else fails
3806 tableStyle.width = _fnStringToCss( sanityWidth );
3807 }
3808 }
3809
3810 // Recalculate the sanity width - now that we've applied the required width,
3811 // before it was a temporary variable. This is required because the column
3812 // width calculation is done before this table DOM is created.
3813 sanityWidth = table.outerWidth();
3814
3815 // Hidden header should have zero height, so remove padding and borders. Then
3816 // set the width based on the real headers
3817
3818 // Apply all styles in one pass
3819 _fnApplyToChildren( zeroOut, headerSrcEls );
3820
3821 // Read all widths in next pass
3822 _fnApplyToChildren( function(nSizer) {
3823 headerContent.push( nSizer.innerHTML );
3824 headerWidths.push( _fnStringToCss( $(nSizer).css('width') ) );
3825 }, headerSrcEls );
3826
3827 // Apply all widths in final pass
3828 _fnApplyToChildren( function(nToSize, i) {
3829 nToSize.style.width = headerWidths[i];
3830 }, headerTrgEls );
3831
3832 $(headerSrcEls).height(0);
3833
3834 /* Same again with the footer if we have one */
3835 if ( footer )
3836 {
3837 _fnApplyToChildren( zeroOut, footerSrcEls );
3838
3839 _fnApplyToChildren( function(nSizer) {
3840 footerWidths.push( _fnStringToCss( $(nSizer).css('width') ) );
3841 }, footerSrcEls );
3842
3843 _fnApplyToChildren( function(nToSize, i) {
3844 nToSize.style.width = footerWidths[i];
3845 }, footerTrgEls );
3846
3847 $(footerSrcEls).height(0);
3848 }
3849
3850
3851 /*
3852 * 3. Apply the measurements
3853 */
3854
3855 // "Hide" the header and footer that we used for the sizing. We need to keep
3856 // the content of the cell so that the width applied to the header and body
3857 // both match, but we want to hide it completely. We want to also fix their
3858 // width to what they currently are
3859 _fnApplyToChildren( function(nSizer, i) {
3860 nSizer.innerHTML = '<div class="dataTables_sizing" style="height:0;overflow:hidden;">'+headerContent[i]+'</div>';
3861 nSizer.style.width = headerWidths[i];
3862 }, headerSrcEls );
3863
3864 if ( footer )
3865 {
3866 _fnApplyToChildren( function(nSizer, i) {
3867 nSizer.innerHTML = "";
3868 nSizer.style.width = footerWidths[i];
3869 }, footerSrcEls );
3870 }
3871
3872 // Sanity check that the table is of a sensible width. If not then we are going to get
3873 // misalignment - try to prevent this by not allowing the table to shrink below its min width
3874 if ( table.outerWidth() < sanityWidth )
3875 {
3876 // The min width depends upon if we have a vertical scrollbar visible or not */
3877 correction = ((divBodyEl.scrollHeight > divBodyEl.offsetHeight ||
3878 divBody.css('overflow-y') == "scroll")) ?
3879 sanityWidth+barWidth :
3880 sanityWidth;
3881
3882 // IE6/7 are a law unto themselves...
3883 if ( ie67 && (divBodyEl.scrollHeight >
3884 divBodyEl.offsetHeight || divBody.css('overflow-y') == "scroll")
3885 ) {
3886 tableStyle.width = _fnStringToCss( correction-barWidth );
3887 }
3888
3889 // And give the user a warning that we've stopped the table getting too small
3890 if ( scrollX === "" || scrollXInner !== "" ) {
3891 _fnLog( settings, 1, 'Possible column misalignment', 6 );
3892 }
3893 }
3894 else
3895 {
3896 correction = '100%';
3897 }
3898
3899 // Apply to the container elements
3900 divBodyStyle.width = _fnStringToCss( correction );
3901 divHeaderStyle.width = _fnStringToCss( correction );
3902
3903 if ( footer ) {
3904 settings.nScrollFoot.style.width = _fnStringToCss( correction );
3905 }
3906
3907
3908 /*
3909 * 4. Clean up
3910 */
3911 if ( ! scrollY ) {
3912 /* IE7< puts a vertical scrollbar in place (when it shouldn't be) due to subtracting
3913 * the scrollbar height from the visible display, rather than adding it on. We need to
3914 * set the height in order to sort this. Don't want to do it in any other browsers.
3915 */
3916 if ( ie67 ) {
3917 divBodyStyle.height = _fnStringToCss( tableEl.offsetHeight+barWidth );
3918 }
3919 }
3920
3921 if ( scrollY && scroll.bCollapse ) {
3922 divBodyStyle.height = _fnStringToCss( scrollY );
3923
3924 var iExtra = (scrollX && tableEl.offsetWidth > divBodyEl.offsetWidth) ?
3925 barWidth :
3926 0;
3927
3928 if ( tableEl.offsetHeight < divBodyEl.offsetHeight ) {
3929 divBodyStyle.height = _fnStringToCss( tableEl.offsetHeight+iExtra );
3930 }
3931 }
3932
3933 /* Finally set the width's of the header and footer tables */
3934 var iOuterWidth = table.outerWidth();
3935 divHeaderTable[0].style.width = _fnStringToCss( iOuterWidth );
3936 divHeaderInnerStyle.width = _fnStringToCss( iOuterWidth );
3937
3938 // Figure out if there are scrollbar present - if so then we need a the header and footer to
3939 // provide a bit more space to allow "overflow" scrolling (i.e. past the scrollbar)
3940 var bScrolling = table.height() > divBodyEl.clientHeight || divBody.css('overflow-y') == "scroll";
3941 var padding = 'padding' + (browser.bScrollbarLeft ? 'Left' : 'Right' );
3942 divHeaderInnerStyle[ padding ] = bScrolling ? barWidth+"px" : "0px";
3943
3944 if ( footer ) {
3945 divFooterTable[0].style.width = _fnStringToCss( iOuterWidth );
3946 divFooterInner[0].style.width = _fnStringToCss( iOuterWidth );
3947 divFooterInner[0].style[padding] = bScrolling ? barWidth+"px" : "0px";
3948 }
3949
3950 /* Adjust the position of the header in case we loose the y-scrollbar */
3951 divBody.scroll();
3952
3953 // If sorting or filtering has occurred, jump the scrolling back to the top
3954 // only if we aren't holding the position
3955 if ( (settings.bSorted || settings.bFiltered) && ! settings._drawHold ) {
3956 divBodyEl.scrollTop = 0;
3957 }
3958 }
3959
3960
3961
3962 /**
3963 * Apply a given function to the display child nodes of an element array (typically
3964 * TD children of TR rows
3965 * @param {function} fn Method to apply to the objects
3966 * @param array {nodes} an1 List of elements to look through for display children
3967 * @param array {nodes} an2 Another list (identical structure to the first) - optional
3968 * @memberof DataTable#oApi
3969 */
3970 function _fnApplyToChildren( fn, an1, an2 )
3971 {
3972 var index=0, i=0, iLen=an1.length;
3973 var nNode1, nNode2;
3974
3975 while ( i < iLen ) {
3976 nNode1 = an1[i].firstChild;
3977 nNode2 = an2 ? an2[i].firstChild : null;
3978
3979 while ( nNode1 ) {
3980 if ( nNode1.nodeType === 1 ) {
3981 if ( an2 ) {
3982 fn( nNode1, nNode2, index );
3983 }
3984 else {
3985 fn( nNode1, index );
3986 }
3987
3988 index++;
3989 }
3990
3991 nNode1 = nNode1.nextSibling;
3992 nNode2 = an2 ? nNode2.nextSibling : null;
3993 }
3994
3995 i++;
3996 }
3997 }
3998
3999
4000
4001 var __re_html_remove = /<.*?>/g;
4002
4003
4004 /**
4005 * Calculate the width of columns for the table
4006 * @param {object} oSettings dataTables settings object
4007 * @memberof DataTable#oApi
4008 */
4009 function _fnCalculateColumnWidths ( oSettings )
4010 {
4011 var
4012 table = oSettings.nTable,
4013 columns = oSettings.aoColumns,
4014 scroll = oSettings.oScroll,
4015 scrollY = scroll.sY,
4016 scrollX = scroll.sX,
4017 scrollXInner = scroll.sXInner,
4018 columnCount = columns.length,
4019 visibleColumns = _fnGetColumns( oSettings, 'bVisible' ),
4020 headerCells = $('th', oSettings.nTHead),
4021 tableWidthAttr = table.getAttribute('width'),
4022 tableContainer = table.parentNode,
4023 userInputs = false,
4024 i, column, columnIdx, width, outerWidth;
4025
4026 /* Convert any user input sizes into pixel sizes */
4027 for ( i=0 ; i<visibleColumns.length ; i++ ) {
4028 column = columns[ visibleColumns[i] ];
4029
4030 if ( column.sWidth !== null ) {
4031 column.sWidth = _fnConvertToWidth( column.sWidthOrig, tableContainer );
4032
4033 userInputs = true;
4034 }
4035 }
4036
4037 /* If the number of columns in the DOM equals the number that we have to
4038 * process in DataTables, then we can use the offsets that are created by
4039 * the web- browser. No custom sizes can be set in order for this to happen,
4040 * nor scrolling used
4041 */
4042 if ( ! userInputs && ! scrollX && ! scrollY &&
4043 columnCount == _fnVisbleColumns( oSettings ) &&
4044 columnCount == headerCells.length
4045 ) {
4046 for ( i=0 ; i<columnCount ; i++ ) {
4047 columns[i].sWidth = _fnStringToCss( headerCells.eq(i).width() );
4048 }
4049 }
4050 else
4051 {
4052 // Otherwise construct a single row table with the widest node in the
4053 // data, assign any user defined widths, then insert it into the DOM and
4054 // allow the browser to do all the hard work of calculating table widths
4055 var tmpTable = $(table).clone() // don't use cloneNode - IE8 will remove events on the main table
4056 .empty()
4057 .css( 'visibility', 'hidden' )
4058 .removeAttr( 'id' )
4059 .append( $(oSettings.nTHead).clone( false ) )
4060 .append( $(oSettings.nTFoot).clone( false ) )
4061 .append( $('<tbody><tr/></tbody>') );
4062
4063 // Remove any assigned widths from the footer (from scrolling)
4064 tmpTable.find('tfoot th, tfoot td').css('width', '');
4065
4066 var tr = tmpTable.find( 'tbody tr' );
4067
4068 // Apply custom sizing to the cloned header
4069 headerCells = _fnGetUniqueThs( oSettings, tmpTable.find('thead')[0] );
4070
4071 for ( i=0 ; i<visibleColumns.length ; i++ ) {
4072 column = columns[ visibleColumns[i] ];
4073
4074 headerCells[i].style.width = column.sWidthOrig !== null && column.sWidthOrig !== '' ?
4075 _fnStringToCss( column.sWidthOrig ) :
4076 '';
4077 }
4078
4079 // Find the widest cell for each column and put it into the table
4080 if ( oSettings.aoData.length ) {
4081 for ( i=0 ; i<visibleColumns.length ; i++ ) {
4082 columnIdx = visibleColumns[i];
4083 column = columns[ columnIdx ];
4084
4085 $( _fnGetWidestNode( oSettings, columnIdx ) )
4086 .clone( false )
4087 .append( column.sContentPadding )
4088 .appendTo( tr );
4089 }
4090 }
4091
4092 // Table has been built, attach to the document so we can work with it
4093 tmpTable.appendTo( tableContainer );
4094
4095 // When scrolling (X or Y) we want to set the width of the table as
4096 // appropriate. However, when not scrolling leave the table width as it
4097 // is. This results in slightly different, but I think correct behaviour
4098 if ( scrollX && scrollXInner ) {
4099 tmpTable.width( scrollXInner );
4100 }
4101 else if ( scrollX ) {
4102 tmpTable.css( 'width', 'auto' );
4103
4104 if ( tmpTable.width() < tableContainer.offsetWidth ) {
4105 tmpTable.width( tableContainer.offsetWidth );
4106 }
4107 }
4108 else if ( scrollY ) {
4109 tmpTable.width( tableContainer.offsetWidth );
4110 }
4111 else if ( tableWidthAttr ) {
4112 tmpTable.width( tableWidthAttr );
4113 }
4114
4115 // Take into account the y scrollbar
4116 _fnScrollingWidthAdjust( oSettings, tmpTable[0] );
4117
4118 // Browsers need a bit of a hand when a width is assigned to any columns
4119 // when x-scrolling as they tend to collapse the table to the min-width,
4120 // even if we sent the column widths. So we need to keep track of what
4121 // the table width should be by summing the user given values, and the
4122 // automatic values
4123 if ( scrollX )
4124 {
4125 var total = 0;
4126
4127 for ( i=0 ; i<visibleColumns.length ; i++ ) {
4128 column = columns[ visibleColumns[i] ];
4129 outerWidth = $(headerCells[i]).outerWidth();
4130
4131 total += column.sWidthOrig === null ?
4132 outerWidth :
4133 parseInt( column.sWidth, 10 ) + outerWidth - $(headerCells[i]).width();
4134 }
4135
4136 tmpTable.width( _fnStringToCss( total ) );
4137 table.style.width = _fnStringToCss( total );
4138 }
4139
4140 // Get the width of each column in the constructed table
4141 for ( i=0 ; i<visibleColumns.length ; i++ ) {
4142 column = columns[ visibleColumns[i] ];
4143 width = $(headerCells[i]).width();
4144
4145 if ( width ) {
4146 column.sWidth = _fnStringToCss( width );
4147 }
4148 }
4149
4150 table.style.width = _fnStringToCss( tmpTable.css('width') );
4151
4152 // Finished with the table - ditch it
4153 tmpTable.remove();
4154 }
4155
4156 // If there is a width attr, we want to attach an event listener which
4157 // allows the table sizing to automatically adjust when the window is
4158 // resized. Use the width attr rather than CSS, since we can't know if the
4159 // CSS is a relative value or absolute - DOM read is always px.
4160 if ( tableWidthAttr ) {
4161 table.style.width = _fnStringToCss( tableWidthAttr );
4162 }
4163
4164 if ( (tableWidthAttr || scrollX) && ! oSettings._reszEvt ) {
4165 $(window).bind('resize.DT-'+oSettings.sInstance, _fnThrottle( function () {
4166 _fnAdjustColumnSizing( oSettings );
4167 } ) );
4168
4169 oSettings._reszEvt = true;
4170 }
4171 }
4172
4173
4174 /**
4175 * Throttle the calls to a function. Arguments and context are maintained for
4176 * the throttled function
4177 * @param {function} fn Function to be called
4178 * @param {int} [freq=200] call frequency in mS
4179 * @returns {function} wrapped function
4180 * @memberof DataTable#oApi
4181 */
4182 function _fnThrottle( fn, freq ) {
4183 var
4184 frequency = freq !== undefined ? freq : 200,
4185 last,
4186 timer;
4187
4188 return function () {
4189 var
4190 that = this,
4191 now = +new Date(),
4192 args = arguments;
4193
4194 if ( last && now < last + frequency ) {
4195 clearTimeout( timer );
4196
4197 timer = setTimeout( function () {
4198 last = undefined;
4199 fn.apply( that, args );
4200 }, frequency );
4201 }
4202 else if ( last ) {
4203 last = now;
4204 fn.apply( that, args );
4205 }
4206 else {
4207 last = now;
4208 }
4209 };
4210 }
4211
4212
4213 /**
4214 * Convert a CSS unit width to pixels (e.g. 2em)
4215 * @param {string} width width to be converted
4216 * @param {node} parent parent to get the with for (required for relative widths) - optional
4217 * @returns {int} width in pixels
4218 * @memberof DataTable#oApi
4219 */
4220 function _fnConvertToWidth ( width, parent )
4221 {
4222 if ( ! width ) {
4223 return 0;
4224 }
4225
4226 var n = $('<div/>')
4227 .css( 'width', _fnStringToCss( width ) )
4228 .appendTo( parent || document.body );
4229
4230 var val = n[0].offsetWidth;
4231 n.remove();
4232
4233 return val;
4234 }
4235
4236
4237 /**
4238 * Adjust a table's width to take account of vertical scroll bar
4239 * @param {object} oSettings dataTables settings object
4240 * @param {node} n table node
4241 * @memberof DataTable#oApi
4242 */
4243
4244 function _fnScrollingWidthAdjust ( settings, n )
4245 {
4246 var scroll = settings.oScroll;
4247
4248 if ( scroll.sX || scroll.sY ) {
4249 // When y-scrolling only, we want to remove the width of the scroll bar
4250 // so the table + scroll bar will fit into the area available, otherwise
4251 // we fix the table at its current size with no adjustment
4252 var correction = ! scroll.sX ? scroll.iBarWidth : 0;
4253 n.style.width = _fnStringToCss( $(n).outerWidth() - correction );
4254 }
4255 }
4256
4257
4258 /**
4259 * Get the widest node
4260 * @param {object} settings dataTables settings object
4261 * @param {int} colIdx column of interest
4262 * @returns {node} widest table node
4263 * @memberof DataTable#oApi
4264 */
4265 function _fnGetWidestNode( settings, colIdx )
4266 {
4267 var idx = _fnGetMaxLenString( settings, colIdx );
4268 if ( idx < 0 ) {
4269 return null;
4270 }
4271
4272 var data = settings.aoData[ idx ];
4273 return ! data.nTr ? // Might not have been created when deferred rendering
4274 $('<td/>').html( _fnGetCellData( settings, idx, colIdx, 'display' ) )[0] :
4275 data.anCells[ colIdx ];
4276 }
4277
4278
4279 /**
4280 * Get the maximum strlen for each data column
4281 * @param {object} settings dataTables settings object
4282 * @param {int} colIdx column of interest
4283 * @returns {string} max string length for each column
4284 * @memberof DataTable#oApi
4285 */
4286 function _fnGetMaxLenString( settings, colIdx )
4287 {
4288 var s, max=-1, maxIdx = -1;
4289
4290 for ( var i=0, ien=settings.aoData.length ; i<ien ; i++ ) {
4291 s = _fnGetCellData( settings, i, colIdx, 'display' )+'';
4292 s = s.replace( __re_html_remove, '' );
4293
4294 if ( s.length > max ) {
4295 max = s.length;
4296 maxIdx = i;
4297 }
4298 }
4299
4300 return maxIdx;
4301 }
4302
4303
4304 /**
4305 * Append a CSS unit (only if required) to a string
4306 * @param {string} value to css-ify
4307 * @returns {string} value with css unit
4308 * @memberof DataTable#oApi
4309 */
4310 function _fnStringToCss( s )
4311 {
4312 if ( s === null ) {
4313 return '0px';
4314 }
4315
4316 if ( typeof s == 'number' ) {
4317 return s < 0 ?
4318 '0px' :
4319 s+'px';
4320 }
4321
4322 // Check it has a unit character already
4323 return s.match(/\d$/) ?
4324 s+'px' :
4325 s;
4326 }
4327
4328
4329 /**
4330 * Get the width of a scroll bar in this browser being used
4331 * @returns {int} width in pixels
4332 * @memberof DataTable#oApi
4333 */
4334 function _fnScrollBarWidth ()
4335 {
4336 // On first run a static variable is set, since this is only needed once.
4337 // Subsequent runs will just use the previously calculated value
4338 if ( ! DataTable.__scrollbarWidth ) {
4339 var inner = $('<p/>').css( {
4340 width: '100%',
4341 height: 200,
4342 padding: 0
4343 } )[0];
4344
4345 var outer = $('<div/>')
4346 .css( {
4347 position: 'absolute',
4348 top: 0,
4349 left: 0,
4350 width: 200,
4351 height: 150,
4352 padding: 0,
4353 overflow: 'hidden',
4354 visibility: 'hidden'
4355 } )
4356 .append( inner )
4357 .appendTo( 'body' );
4358
4359 var w1 = inner.offsetWidth;
4360 outer.css( 'overflow', 'scroll' );
4361 var w2 = inner.offsetWidth;
4362
4363 if ( w1 === w2 ) {
4364 w2 = outer[0].clientWidth;
4365 }
4366
4367 outer.remove();
4368
4369 DataTable.__scrollbarWidth = w1 - w2;
4370 }
4371
4372 return DataTable.__scrollbarWidth;
4373 }
4374
4375
4376
4377 function _fnSortFlatten ( settings )
4378 {
4379 var
4380 i, iLen, k, kLen,
4381 aSort = [],
4382 aiOrig = [],
4383 aoColumns = settings.aoColumns,
4384 aDataSort, iCol, sType, srcCol,
4385 fixed = settings.aaSortingFixed,
4386 fixedObj = $.isPlainObject( fixed ),
4387 nestedSort = [],
4388 add = function ( a ) {
4389 if ( a.length && ! $.isArray( a[0] ) ) {
4390 // 1D array
4391 nestedSort.push( a );
4392 }
4393 else {
4394 // 2D array
4395 nestedSort.push.apply( nestedSort, a );
4396 }
4397 };
4398
4399 // Build the sort array, with pre-fix and post-fix options if they have been
4400 // specified
4401 if ( $.isArray( fixed ) ) {
4402 add( fixed );
4403 }
4404
4405 if ( fixedObj && fixed.pre ) {
4406 add( fixed.pre );
4407 }
4408
4409 add( settings.aaSorting );
4410
4411 if (fixedObj && fixed.post ) {
4412 add( fixed.post );
4413 }
4414
4415 for ( i=0 ; i<nestedSort.length ; i++ )
4416 {
4417 srcCol = nestedSort[i][0];
4418 aDataSort = aoColumns[ srcCol ].aDataSort;
4419
4420 for ( k=0, kLen=aDataSort.length ; k<kLen ; k++ )
4421 {
4422 iCol = aDataSort[k];
4423 sType = aoColumns[ iCol ].sType || 'string';
4424
4425 if ( nestedSort[i]._idx === undefined ) {
4426 nestedSort[i]._idx = $.inArray( nestedSort[i][1], aoColumns[iCol].asSorting );
4427 }
4428
4429 aSort.push( {
4430 src: srcCol,
4431 col: iCol,
4432 dir: nestedSort[i][1],
4433 index: nestedSort[i]._idx,
4434 type: sType,
4435 formatter: DataTable.ext.type.order[ sType+"-pre" ]
4436 } );
4437 }
4438 }
4439
4440 return aSort;
4441 }
4442
4443 /**
4444 * Change the order of the table
4445 * @param {object} oSettings dataTables settings object
4446 * @memberof DataTable#oApi
4447 * @todo This really needs split up!
4448 */
4449 function _fnSort ( oSettings )
4450 {
4451 var
4452 i, ien, iLen, j, jLen, k, kLen,
4453 sDataType, nTh,
4454 aiOrig = [],
4455 oExtSort = DataTable.ext.type.order,
4456 aoData = oSettings.aoData,
4457 aoColumns = oSettings.aoColumns,
4458 aDataSort, data, iCol, sType, oSort,
4459 formatters = 0,
4460 sortCol,
4461 displayMaster = oSettings.aiDisplayMaster,
4462 aSort;
4463
4464 // Resolve any column types that are unknown due to addition or invalidation
4465 // @todo Can this be moved into a 'data-ready' handler which is called when
4466 // data is going to be used in the table?
4467 _fnColumnTypes( oSettings );
4468
4469 aSort = _fnSortFlatten( oSettings );
4470
4471 for ( i=0, ien=aSort.length ; i<ien ; i++ ) {
4472 sortCol = aSort[i];
4473
4474 // Track if we can use the fast sort algorithm
4475 if ( sortCol.formatter ) {
4476 formatters++;
4477 }
4478
4479 // Load the data needed for the sort, for each cell
4480 _fnSortData( oSettings, sortCol.col );
4481 }
4482
4483 /* No sorting required if server-side or no sorting array */
4484 if ( _fnDataSource( oSettings ) != 'ssp' && aSort.length !== 0 )
4485 {
4486 // Create a value - key array of the current row positions such that we can use their
4487 // current position during the sort, if values match, in order to perform stable sorting
4488 for ( i=0, iLen=displayMaster.length ; i<iLen ; i++ ) {
4489 aiOrig[ displayMaster[i] ] = i;
4490 }
4491
4492 /* Do the sort - here we want multi-column sorting based on a given data source (column)
4493 * and sorting function (from oSort) in a certain direction. It's reasonably complex to
4494 * follow on it's own, but this is what we want (example two column sorting):
4495 * fnLocalSorting = function(a,b){
4496 * var iTest;
4497 * iTest = oSort['string-asc']('data11', 'data12');
4498 * if (iTest !== 0)
4499 * return iTest;
4500 * iTest = oSort['numeric-desc']('data21', 'data22');
4501 * if (iTest !== 0)
4502 * return iTest;
4503 * return oSort['numeric-asc']( aiOrig[a], aiOrig[b] );
4504 * }
4505 * Basically we have a test for each sorting column, if the data in that column is equal,
4506 * test the next column. If all columns match, then we use a numeric sort on the row
4507 * positions in the original data array to provide a stable sort.
4508 *
4509 * Note - I know it seems excessive to have two sorting methods, but the first is around
4510 * 15% faster, so the second is only maintained for backwards compatibility with sorting
4511 * methods which do not have a pre-sort formatting function.
4512 */
4513 if ( formatters === aSort.length ) {
4514 // All sort types have formatting functions
4515 displayMaster.sort( function ( a, b ) {
4516 var
4517 x, y, k, test, sort,
4518 len=aSort.length,
4519 dataA = aoData[a]._aSortData,
4520 dataB = aoData[b]._aSortData;
4521
4522 for ( k=0 ; k<len ; k++ ) {
4523 sort = aSort[k];
4524
4525 x = dataA[ sort.col ];
4526 y = dataB[ sort.col ];
4527
4528 test = x<y ? -1 : x>y ? 1 : 0;
4529 if ( test !== 0 ) {
4530 return sort.dir === 'asc' ? test : -test;
4531 }
4532 }
4533
4534 x = aiOrig[a];
4535 y = aiOrig[b];
4536 return x<y ? -1 : x>y ? 1 : 0;
4537 } );
4538 }
4539 else {
4540 // Depreciated - remove in 1.11 (providing a plug-in option)
4541 // Not all sort types have formatting methods, so we have to call their sorting
4542 // methods.
4543 displayMaster.sort( function ( a, b ) {
4544 var
4545 x, y, k, l, test, sort, fn,
4546 len=aSort.length,
4547 dataA = aoData[a]._aSortData,
4548 dataB = aoData[b]._aSortData;
4549
4550 for ( k=0 ; k<len ; k++ ) {
4551 sort = aSort[k];
4552
4553 x = dataA[ sort.col ];
4554 y = dataB[ sort.col ];
4555
4556 fn = oExtSort[ sort.type+"-"+sort.dir ] || oExtSort[ "string-"+sort.dir ];
4557 test = fn( x, y );
4558 if ( test !== 0 ) {
4559 return test;
4560 }
4561 }
4562
4563 x = aiOrig[a];
4564 y = aiOrig[b];
4565 return x<y ? -1 : x>y ? 1 : 0;
4566 } );
4567 }
4568 }
4569
4570 /* Tell the draw function that we have sorted the data */
4571 oSettings.bSorted = true;
4572 }
4573
4574
4575 function _fnSortAria ( settings )
4576 {
4577 var label;
4578 var nextSort;
4579 var columns = settings.aoColumns;
4580 var aSort = _fnSortFlatten( settings );
4581 var oAria = settings.oLanguage.oAria;
4582
4583 // ARIA attributes - need to loop all columns, to update all (removing old
4584 // attributes as needed)
4585 for ( var i=0, iLen=columns.length ; i<iLen ; i++ )
4586 {
4587 var col = columns[i];
4588 var asSorting = col.asSorting;
4589 var sTitle = col.sTitle.replace( /<.*?>/g, "" );
4590 var th = col.nTh;
4591
4592 // IE7 is throwing an error when setting these properties with jQuery's
4593 // attr() and removeAttr() methods...
4594 th.removeAttribute('aria-sort');
4595
4596 /* In ARIA only the first sorting column can be marked as sorting - no multi-sort option */
4597 if ( col.bSortable ) {
4598 if ( aSort.length > 0 && aSort[0].col == i ) {
4599 th.setAttribute('aria-sort', aSort[0].dir=="asc" ? "ascending" : "descending" );
4600 nextSort = asSorting[ aSort[0].index+1 ] || asSorting[0];
4601 }
4602 else {
4603 nextSort = asSorting[0];
4604 }
4605
4606 label = sTitle + ( nextSort === "asc" ?
4607 oAria.sSortAscending :
4608 oAria.sSortDescending
4609 );
4610 }
4611 else {
4612 label = sTitle;
4613 }
4614
4615 th.setAttribute('aria-label', label);
4616 }
4617 }
4618
4619
4620 /**
4621 * Function to run on user sort request
4622 * @param {object} settings dataTables settings object
4623 * @param {node} attachTo node to attach the handler to
4624 * @param {int} colIdx column sorting index
4625 * @param {boolean} [append=false] Append the requested sort to the existing
4626 * sort if true (i.e. multi-column sort)
4627 * @param {function} [callback] callback function
4628 * @memberof DataTable#oApi
4629 */
4630 function _fnSortListener ( settings, colIdx, append, callback )
4631 {
4632 var col = settings.aoColumns[ colIdx ];
4633 var sorting = settings.aaSorting;
4634 var asSorting = col.asSorting;
4635 var nextSortIdx;
4636 var next = function ( a, overflow ) {
4637 var idx = a._idx;
4638 if ( idx === undefined ) {
4639 idx = $.inArray( a[1], asSorting );
4640 }
4641
4642 return idx+1 < asSorting.length ?
4643 idx+1 :
4644 overflow ?
4645 null :
4646 0;
4647 };
4648
4649 // Convert to 2D array if needed
4650 if ( typeof sorting[0] === 'number' ) {
4651 sorting = settings.aaSorting = [ sorting ];
4652 }
4653
4654 // If appending the sort then we are multi-column sorting
4655 if ( append && settings.oFeatures.bSortMulti ) {
4656 // Are we already doing some kind of sort on this column?
4657 var sortIdx = $.inArray( colIdx, _pluck(sorting, '0') );
4658
4659 if ( sortIdx !== -1 ) {
4660 // Yes, modify the sort
4661 nextSortIdx = next( sorting[sortIdx], true );
4662
4663 if ( nextSortIdx === null ) {
4664 sorting.splice( sortIdx, 1 );
4665 }
4666 else {
4667 sorting[sortIdx][1] = asSorting[ nextSortIdx ];
4668 sorting[sortIdx]._idx = nextSortIdx;
4669 }
4670 }
4671 else {
4672 // No sort on this column yet
4673 sorting.push( [ colIdx, asSorting[0], 0 ] );
4674 sorting[sorting.length-1]._idx = 0;
4675 }
4676 }
4677 else if ( sorting.length && sorting[0][0] == colIdx ) {
4678 // Single column - already sorting on this column, modify the sort
4679 nextSortIdx = next( sorting[0] );
4680
4681 sorting.length = 1;
4682 sorting[0][1] = asSorting[ nextSortIdx ];
4683 sorting[0]._idx = nextSortIdx;
4684 }
4685 else {
4686 // Single column - sort only on this column
4687 sorting.length = 0;
4688 sorting.push( [ colIdx, asSorting[0] ] );
4689 sorting[0]._idx = 0;
4690 }
4691
4692 // Run the sort by calling a full redraw
4693 _fnReDraw( settings );
4694
4695 // callback used for async user interaction
4696 if ( typeof callback == 'function' ) {
4697 callback( settings );
4698 }
4699 }
4700
4701
4702 /**
4703 * Attach a sort handler (click) to a node
4704 * @param {object} settings dataTables settings object
4705 * @param {node} attachTo node to attach the handler to
4706 * @param {int} colIdx column sorting index
4707 * @param {function} [callback] callback function
4708 * @memberof DataTable#oApi
4709 */
4710 function _fnSortAttachListener ( settings, attachTo, colIdx, callback )
4711 {
4712 var col = settings.aoColumns[ colIdx ];
4713
4714 _fnBindAction( attachTo, {}, function (e) {
4715 /* If the column is not sortable - don't to anything */
4716 if ( col.bSortable === false ) {
4717 return;
4718 }
4719
4720 // If processing is enabled use a timeout to allow the processing
4721 // display to be shown - otherwise to it synchronously
4722 if ( settings.oFeatures.bProcessing ) {
4723 _fnProcessingDisplay( settings, true );
4724
4725 setTimeout( function() {
4726 _fnSortListener( settings, colIdx, e.shiftKey, callback );
4727
4728 // In server-side processing, the draw callback will remove the
4729 // processing display
4730 if ( _fnDataSource( settings ) !== 'ssp' ) {
4731 _fnProcessingDisplay( settings, false );
4732 }
4733 }, 0 );
4734 }
4735 else {
4736 _fnSortListener( settings, colIdx, e.shiftKey, callback );
4737 }
4738 } );
4739 }
4740
4741
4742 /**
4743 * Set the sorting classes on table's body, Note: it is safe to call this function
4744 * when bSort and bSortClasses are false
4745 * @param {object} oSettings dataTables settings object
4746 * @memberof DataTable#oApi
4747 */
4748 function _fnSortingClasses( settings )
4749 {
4750 var oldSort = settings.aLastSort;
4751 var sortClass = settings.oClasses.sSortColumn;
4752 var sort = _fnSortFlatten( settings );
4753 var features = settings.oFeatures;
4754 var i, ien, colIdx;
4755
4756 if ( features.bSort && features.bSortClasses ) {
4757 // Remove old sorting classes
4758 for ( i=0, ien=oldSort.length ; i<ien ; i++ ) {
4759 colIdx = oldSort[i].src;
4760
4761 // Remove column sorting
4762 $( _pluck( settings.aoData, 'anCells', colIdx ) )
4763 .removeClass( sortClass + (i<2 ? i+1 : 3) );
4764 }
4765
4766 // Add new column sorting
4767 for ( i=0, ien=sort.length ; i<ien ; i++ ) {
4768 colIdx = sort[i].src;
4769
4770 $( _pluck( settings.aoData, 'anCells', colIdx ) )
4771 .addClass( sortClass + (i<2 ? i+1 : 3) );
4772 }
4773 }
4774
4775 settings.aLastSort = sort;
4776 }
4777
4778
4779 // Get the data to sort a column, be it from cache, fresh (populating the
4780 // cache), or from a sort formatter
4781 function _fnSortData( settings, idx )
4782 {
4783 // Custom sorting function - provided by the sort data type
4784 var column = settings.aoColumns[ idx ];
4785 var customSort = DataTable.ext.order[ column.sSortDataType ];
4786 var customData;
4787
4788 if ( customSort ) {
4789 customData = customSort.call( settings.oInstance, settings, idx,
4790 _fnColumnIndexToVisible( settings, idx )
4791 );
4792 }
4793
4794 // Use / populate cache
4795 var row, cellData;
4796 var formatter = DataTable.ext.type.order[ column.sType+"-pre" ];
4797
4798 for ( var i=0, ien=settings.aoData.length ; i<ien ; i++ ) {
4799 row = settings.aoData[i];
4800
4801 if ( ! row._aSortData ) {
4802 row._aSortData = [];
4803 }
4804
4805 if ( ! row._aSortData[idx] || customSort ) {
4806 cellData = customSort ?
4807 customData[i] : // If there was a custom sort function, use data from there
4808 _fnGetCellData( settings, i, idx, 'sort' );
4809
4810 row._aSortData[ idx ] = formatter ?
4811 formatter( cellData ) :
4812 cellData;
4813 }
4814 }
4815 }
4816
4817
4818
4819 /**
4820 * Save the state of a table
4821 * @param {object} oSettings dataTables settings object
4822 * @memberof DataTable#oApi
4823 */
4824 function _fnSaveState ( settings )
4825 {
4826 if ( !settings.oFeatures.bStateSave || settings.bDestroying )
4827 {
4828 return;
4829 }
4830
4831 /* Store the interesting variables */
4832 var state = {
4833 time: +new Date(),
4834 start: settings._iDisplayStart,
4835 length: settings._iDisplayLength,
4836 order: $.extend( true, [], settings.aaSorting ),
4837 search: _fnSearchToCamel( settings.oPreviousSearch ),
4838 columns: $.map( settings.aoColumns, function ( col, i ) {
4839 return {
4840 visible: col.bVisible,
4841 search: _fnSearchToCamel( settings.aoPreSearchCols[i] )
4842 };
4843 } )
4844 };
4845
4846 _fnCallbackFire( settings, "aoStateSaveParams", 'stateSaveParams', [settings, state] );
4847
4848 settings.oSavedState = state;
4849 settings.fnStateSaveCallback.call( settings.oInstance, settings, state );
4850 }
4851
4852
4853 /**
4854 * Attempt to load a saved table state
4855 * @param {object} oSettings dataTables settings object
4856 * @param {object} oInit DataTables init object so we can override settings
4857 * @memberof DataTable#oApi
4858 */
4859 function _fnLoadState ( settings, oInit )
4860 {
4861 var i, ien;
4862 var columns = settings.aoColumns;
4863
4864 if ( ! settings.oFeatures.bStateSave ) {
4865 return;
4866 }
4867
4868 var state = settings.fnStateLoadCallback.call( settings.oInstance, settings );
4869 if ( ! state || ! state.time ) {
4870 return;
4871 }
4872
4873 /* Allow custom and plug-in manipulation functions to alter the saved data set and
4874 * cancelling of loading by returning false
4875 */
4876 var abStateLoad = _fnCallbackFire( settings, 'aoStateLoadParams', 'stateLoadParams', [settings, state] );
4877 if ( $.inArray( false, abStateLoad ) !== -1 ) {
4878 return;
4879 }
4880
4881 /* Reject old data */
4882 var duration = settings.iStateDuration;
4883 if ( duration > 0 && state.time < +new Date() - (duration*1000) ) {
4884 return;
4885 }
4886
4887 // Number of columns have changed - all bets are off, no restore of settings
4888 if ( columns.length !== state.columns.length ) {
4889 return;
4890 }
4891
4892 // Store the saved state so it might be accessed at any time
4893 settings.oLoadedState = $.extend( true, {}, state );
4894
4895 // Restore key features - todo - for 1.11 this needs to be done by
4896 // subscribed events
4897 settings._iDisplayStart = state.start;
4898 settings.iInitDisplayStart = state.start;
4899 settings._iDisplayLength = state.length;
4900 settings.aaSorting = [];
4901
4902 // Order
4903 $.each( state.order, function ( i, col ) {
4904 settings.aaSorting.push( col[0] >= columns.length ?
4905 [ 0, col[1] ] :
4906 col
4907 );
4908 } );
4909
4910 // Search
4911 $.extend( settings.oPreviousSearch, _fnSearchToHung( state.search ) );
4912
4913 // Columns
4914 for ( i=0, ien=state.columns.length ; i<ien ; i++ ) {
4915 var col = state.columns[i];
4916
4917 // Visibility
4918 columns[i].bVisible = col.visible;
4919
4920 // Search
4921 $.extend( settings.aoPreSearchCols[i], _fnSearchToHung( col.search ) );
4922 }
4923
4924 _fnCallbackFire( settings, 'aoStateLoaded', 'stateLoaded', [settings, state] );
4925 }
4926
4927
4928 /**
4929 * Return the settings object for a particular table
4930 * @param {node} table table we are using as a dataTable
4931 * @returns {object} Settings object - or null if not found
4932 * @memberof DataTable#oApi
4933 */
4934 function _fnSettingsFromNode ( table )
4935 {
4936 var settings = DataTable.settings;
4937 var idx = $.inArray( table, _pluck( settings, 'nTable' ) );
4938
4939 return idx !== -1 ?
4940 settings[ idx ] :
4941 null;
4942 }
4943
4944
4945 /**
4946 * Log an error message
4947 * @param {object} settings dataTables settings object
4948 * @param {int} level log error messages, or display them to the user
4949 * @param {string} msg error message
4950 * @param {int} tn Technical note id to get more information about the error.
4951 * @memberof DataTable#oApi
4952 */
4953 function _fnLog( settings, level, msg, tn )
4954 {
4955 msg = 'DataTables warning: '+
4956 (settings!==null ? 'table id='+settings.sTableId+' - ' : '')+msg;
4957
4958 if ( tn ) {
4959 msg += '. For more information about this error, please see '+
4960 'http://datatables.net/tn/'+tn;
4961 }
4962
4963 if ( ! level ) {
4964 // Backwards compatibility pre 1.10
4965 var ext = DataTable.ext;
4966 var type = ext.sErrMode || ext.errMode;
4967
4968 if ( type == 'alert' ) {
4969 alert( msg );
4970 }
4971 else {
4972 throw new Error(msg);
4973 }
4974 }
4975 else if ( window.console && console.log ) {
4976 console.log( msg );
4977 }
4978 }
4979
4980
4981 /**
4982 * See if a property is defined on one object, if so assign it to the other object
4983 * @param {object} ret target object
4984 * @param {object} src source object
4985 * @param {string} name property
4986 * @param {string} [mappedName] name to map too - optional, name used if not given
4987 * @memberof DataTable#oApi
4988 */
4989 function _fnMap( ret, src, name, mappedName )
4990 {
4991 if ( $.isArray( name ) ) {
4992 $.each( name, function (i, val) {
4993 if ( $.isArray( val ) ) {
4994 _fnMap( ret, src, val[0], val[1] );
4995 }
4996 else {
4997 _fnMap( ret, src, val );
4998 }
4999 } );
5000
5001 return;
5002 }
5003
5004 if ( mappedName === undefined ) {
5005 mappedName = name;
5006 }
5007
5008 if ( src[name] !== undefined ) {
5009 ret[mappedName] = src[name];
5010 }
5011 }
5012
5013
5014 /**
5015 * Extend objects - very similar to jQuery.extend, but deep copy objects, and
5016 * shallow copy arrays. The reason we need to do this, is that we don't want to
5017 * deep copy array init values (such as aaSorting) since the dev wouldn't be
5018 * able to override them, but we do want to deep copy arrays.
5019 * @param {object} out Object to extend
5020 * @param {object} extender Object from which the properties will be applied to
5021 * out
5022 * @param {boolean} breakRefs If true, then arrays will be sliced to take an
5023 * independent copy with the exception of the `data` or `aaData` parameters
5024 * if they are present. This is so you can pass in a collection to
5025 * DataTables and have that used as your data source without breaking the
5026 * references
5027 * @returns {object} out Reference, just for convenience - out === the return.
5028 * @memberof DataTable#oApi
5029 * @todo This doesn't take account of arrays inside the deep copied objects.
5030 */
5031 function _fnExtend( out, extender, breakRefs )
5032 {
5033 var val;
5034
5035 for ( var prop in extender ) {
5036 if ( extender.hasOwnProperty(prop) ) {
5037 val = extender[prop];
5038
5039 if ( $.isPlainObject( val ) ) {
5040 if ( ! $.isPlainObject( out[prop] ) ) {
5041 out[prop] = {};
5042 }
5043 $.extend( true, out[prop], val );
5044 }
5045 else if ( breakRefs && prop !== 'data' && prop !== 'aaData' && $.isArray(val) ) {
5046 out[prop] = val.slice();
5047 }
5048 else {
5049 out[prop] = val;
5050 }
5051 }
5052 }
5053
5054 return out;
5055 }
5056
5057
5058 /**
5059 * Bind an event handers to allow a click or return key to activate the callback.
5060 * This is good for accessibility since a return on the keyboard will have the
5061 * same effect as a click, if the element has focus.
5062 * @param {element} n Element to bind the action to
5063 * @param {object} oData Data object to pass to the triggered function
5064 * @param {function} fn Callback function for when the event is triggered
5065 * @memberof DataTable#oApi
5066 */
5067 function _fnBindAction( n, oData, fn )
5068 {
5069 $(n)
5070 .bind( 'click.DT', oData, function (e) {
5071 n.blur(); // Remove focus outline for mouse users
5072 fn(e);
5073 } )
5074 .bind( 'keypress.DT', oData, function (e){
5075 if ( e.which === 13 ) {
5076 e.preventDefault();
5077 fn(e);
5078 }
5079 } )
5080 .bind( 'selectstart.DT', function () {
5081 /* Take the brutal approach to cancelling text selection */
5082 return false;
5083 } );
5084 }
5085
5086
5087 /**
5088 * Register a callback function. Easily allows a callback function to be added to
5089 * an array store of callback functions that can then all be called together.
5090 * @param {object} oSettings dataTables settings object
5091 * @param {string} sStore Name of the array storage for the callbacks in oSettings
5092 * @param {function} fn Function to be called back
5093 * @param {string} sName Identifying name for the callback (i.e. a label)
5094 * @memberof DataTable#oApi
5095 */
5096 function _fnCallbackReg( oSettings, sStore, fn, sName )
5097 {
5098 if ( fn )
5099 {
5100 oSettings[sStore].push( {
5101 "fn": fn,
5102 "sName": sName
5103 } );
5104 }
5105 }
5106
5107
5108 /**
5109 * Fire callback functions and trigger events. Note that the loop over the
5110 * callback array store is done backwards! Further note that you do not want to
5111 * fire off triggers in time sensitive applications (for example cell creation)
5112 * as its slow.
5113 * @param {object} settings dataTables settings object
5114 * @param {string} callbackArr Name of the array storage for the callbacks in
5115 * oSettings
5116 * @param {string} event Name of the jQuery custom event to trigger. If null no
5117 * trigger is fired
5118 * @param {array} args Array of arguments to pass to the callback function /
5119 * trigger
5120 * @memberof DataTable#oApi
5121 */
5122 function _fnCallbackFire( settings, callbackArr, e, args )
5123 {
5124 var ret = [];
5125
5126 if ( callbackArr ) {
5127 ret = $.map( settings[callbackArr].slice().reverse(), function (val, i) {
5128 return val.fn.apply( settings.oInstance, args );
5129 } );
5130 }
5131
5132 if ( e !== null ) {
5133 $(settings.nTable).trigger( e+'.dt', args );
5134 }
5135
5136 return ret;
5137 }
5138
5139
5140 function _fnLengthOverflow ( settings )
5141 {
5142 var
5143 start = settings._iDisplayStart,
5144 end = settings.fnDisplayEnd(),
5145 len = settings._iDisplayLength;
5146
5147 /* If we have space to show extra rows (backing up from the end point - then do so */
5148 if ( start >= end )
5149 {
5150 start = end - len;
5151 }
5152
5153 // Keep the start record on the current page
5154 start -= (start % len);
5155
5156 if ( len === -1 || start < 0 )
5157 {
5158 start = 0;
5159 }
5160
5161 settings._iDisplayStart = start;
5162 }
5163
5164
5165 function _fnRenderer( settings, type )
5166 {
5167 var renderer = settings.renderer;
5168 var host = DataTable.ext.renderer[type];
5169
5170 if ( $.isPlainObject( renderer ) && renderer[type] ) {
5171 // Specific renderer for this type. If available use it, otherwise use
5172 // the default.
5173 return host[renderer[type]] || host._;
5174 }
5175 else if ( typeof renderer === 'string' ) {
5176 // Common renderer - if there is one available for this type use it,
5177 // otherwise use the default
5178 return host[renderer] || host._;
5179 }
5180
5181 // Use the default
5182 return host._;
5183 }
5184
5185
5186 /**
5187 * Detect the data source being used for the table. Used to simplify the code
5188 * a little (ajax) and to make it compress a little smaller.
5189 *
5190 * @param {object} settings dataTables settings object
5191 * @returns {string} Data source
5192 * @memberof DataTable#oApi
5193 */
5194 function _fnDataSource ( settings )
5195 {
5196 if ( settings.oFeatures.bServerSide ) {
5197 return 'ssp';
5198 }
5199 else if ( settings.ajax || settings.sAjaxSource ) {
5200 return 'ajax';
5201 }
5202 return 'dom';
5203 }
5204
5205
5206 DataTable = function( options )
5207 {
5208 /**
5209 * Perform a jQuery selector action on the table's TR elements (from the tbody) and
5210 * return the resulting jQuery object.
5211 * @param {string|node|jQuery} sSelector jQuery selector or node collection to act on
5212 * @param {object} [oOpts] Optional parameters for modifying the rows to be included
5213 * @param {string} [oOpts.filter=none] Select TR elements that meet the current filter
5214 * criterion ("applied") or all TR elements (i.e. no filter).
5215 * @param {string} [oOpts.order=current] Order of the TR elements in the processed array.
5216 * Can be either 'current', whereby the current sorting of the table is used, or
5217 * 'original' whereby the original order the data was read into the table is used.
5218 * @param {string} [oOpts.page=all] Limit the selection to the currently displayed page
5219 * ("current") or not ("all"). If 'current' is given, then order is assumed to be
5220 * 'current' and filter is 'applied', regardless of what they might be given as.
5221 * @returns {object} jQuery object, filtered by the given selector.
5222 * @dtopt API
5223 * @deprecated Since v1.10
5224 *
5225 * @example
5226 * $(document).ready(function() {
5227 * var oTable = $('#example').dataTable();
5228 *
5229 * // Highlight every second row
5230 * oTable.$('tr:odd').css('backgroundColor', 'blue');
5231 * } );
5232 *
5233 * @example
5234 * $(document).ready(function() {
5235 * var oTable = $('#example').dataTable();
5236 *
5237 * // Filter to rows with 'Webkit' in them, add a background colour and then
5238 * // remove the filter, thus highlighting the 'Webkit' rows only.
5239 * oTable.fnFilter('Webkit');
5240 * oTable.$('tr', {"search": "applied"}).css('backgroundColor', 'blue');
5241 * oTable.fnFilter('');
5242 * } );
5243 */
5244 this.$ = function ( sSelector, oOpts )
5245 {
5246 return this.api(true).$( sSelector, oOpts );
5247 };
5248
5249
5250 /**
5251 * Almost identical to $ in operation, but in this case returns the data for the matched
5252 * rows - as such, the jQuery selector used should match TR row nodes or TD/TH cell nodes
5253 * rather than any descendants, so the data can be obtained for the row/cell. If matching
5254 * rows are found, the data returned is the original data array/object that was used to
5255 * create the row (or a generated array if from a DOM source).
5256 *
5257 * This method is often useful in-combination with $ where both functions are given the
5258 * same parameters and the array indexes will match identically.
5259 * @param {string|node|jQuery} sSelector jQuery selector or node collection to act on
5260 * @param {object} [oOpts] Optional parameters for modifying the rows to be included
5261 * @param {string} [oOpts.filter=none] Select elements that meet the current filter
5262 * criterion ("applied") or all elements (i.e. no filter).
5263 * @param {string} [oOpts.order=current] Order of the data in the processed array.
5264 * Can be either 'current', whereby the current sorting of the table is used, or
5265 * 'original' whereby the original order the data was read into the table is used.
5266 * @param {string} [oOpts.page=all] Limit the selection to the currently displayed page
5267 * ("current") or not ("all"). If 'current' is given, then order is assumed to be
5268 * 'current' and filter is 'applied', regardless of what they might be given as.
5269 * @returns {array} Data for the matched elements. If any elements, as a result of the
5270 * selector, were not TR, TD or TH elements in the DataTable, they will have a null
5271 * entry in the array.
5272 * @dtopt API
5273 * @deprecated Since v1.10
5274 *
5275 * @example
5276 * $(document).ready(function() {
5277 * var oTable = $('#example').dataTable();
5278 *
5279 * // Get the data from the first row in the table
5280 * var data = oTable._('tr:first');
5281 *
5282 * // Do something useful with the data
5283 * alert( "First cell is: "+data[0] );
5284 * } );
5285 *
5286 * @example
5287 * $(document).ready(function() {
5288 * var oTable = $('#example').dataTable();
5289 *
5290 * // Filter to 'Webkit' and get all data for
5291 * oTable.fnFilter('Webkit');
5292 * var data = oTable._('tr', {"search": "applied"});
5293 *
5294 * // Do something with the data
5295 * alert( data.length+" rows matched the search" );
5296 * } );
5297 */
5298 this._ = function ( sSelector, oOpts )
5299 {
5300 return this.api(true).rows( sSelector, oOpts ).data();
5301 };
5302
5303
5304 /**
5305 * Create a DataTables Api instance, with the currently selected tables for
5306 * the Api's context.
5307 * @param {boolean} [traditional=false] Set the API instance's context to be
5308 * only the table referred to by the `DataTable.ext.iApiIndex` option, as was
5309 * used in the API presented by DataTables 1.9- (i.e. the traditional mode),
5310 * or if all tables captured in the jQuery object should be used.
5311 * @return {DataTables.Api}
5312 */
5313 this.api = function ( traditional )
5314 {
5315 return traditional ?
5316 new _Api(
5317 _fnSettingsFromNode( this[ _ext.iApiIndex ] )
5318 ) :
5319 new _Api( this );
5320 };
5321
5322
5323 /**
5324 * Add a single new row or multiple rows of data to the table. Please note
5325 * that this is suitable for client-side processing only - if you are using
5326 * server-side processing (i.e. "bServerSide": true), then to add data, you
5327 * must add it to the data source, i.e. the server-side, through an Ajax call.
5328 * @param {array|object} data The data to be added to the table. This can be:
5329 * <ul>
5330 * <li>1D array of data - add a single row with the data provided</li>
5331 * <li>2D array of arrays - add multiple rows in a single call</li>
5332 * <li>object - data object when using <i>mData</i></li>
5333 * <li>array of objects - multiple data objects when using <i>mData</i></li>
5334 * </ul>
5335 * @param {bool} [redraw=true] redraw the table or not
5336 * @returns {array} An array of integers, representing the list of indexes in
5337 * <i>aoData</i> ({@link DataTable.models.oSettings}) that have been added to
5338 * the table.
5339 * @dtopt API
5340 * @deprecated Since v1.10
5341 *
5342 * @example
5343 * // Global var for counter
5344 * var giCount = 2;
5345 *
5346 * $(document).ready(function() {
5347 * $('#example').dataTable();
5348 * } );
5349 *
5350 * function fnClickAddRow() {
5351 * $('#example').dataTable().fnAddData( [
5352 * giCount+".1",
5353 * giCount+".2",
5354 * giCount+".3",
5355 * giCount+".4" ]
5356 * );
5357 *
5358 * giCount++;
5359 * }
5360 */
5361 this.fnAddData = function( data, redraw )
5362 {
5363 var api = this.api( true );
5364
5365 /* Check if we want to add multiple rows or not */
5366 var rows = $.isArray(data) && ( $.isArray(data[0]) || $.isPlainObject(data[0]) ) ?
5367 api.rows.add( data ) :
5368 api.row.add( data );
5369
5370 if ( redraw === undefined || redraw ) {
5371 api.draw();
5372 }
5373
5374 return rows.flatten().toArray();
5375 };
5376
5377
5378 /**
5379 * This function will make DataTables recalculate the column sizes, based on the data
5380 * contained in the table and the sizes applied to the columns (in the DOM, CSS or
5381 * through the sWidth parameter). This can be useful when the width of the table's
5382 * parent element changes (for example a window resize).
5383 * @param {boolean} [bRedraw=true] Redraw the table or not, you will typically want to
5384 * @dtopt API
5385 * @deprecated Since v1.10
5386 *
5387 * @example
5388 * $(document).ready(function() {
5389 * var oTable = $('#example').dataTable( {
5390 * "sScrollY": "200px",
5391 * "bPaginate": false
5392 * } );
5393 *
5394 * $(window).bind('resize', function () {
5395 * oTable.fnAdjustColumnSizing();
5396 * } );
5397 * } );
5398 */
5399 this.fnAdjustColumnSizing = function ( bRedraw )
5400 {
5401 var api = this.api( true ).columns.adjust();
5402 var settings = api.settings()[0];
5403 var scroll = settings.oScroll;
5404
5405 if ( bRedraw === undefined || bRedraw ) {
5406 api.draw( false );
5407 }
5408 else if ( scroll.sX !== "" || scroll.sY !== "" ) {
5409 /* If not redrawing, but scrolling, we want to apply the new column sizes anyway */
5410 _fnScrollDraw( settings );
5411 }
5412 };
5413
5414
5415 /**
5416 * Quickly and simply clear a table
5417 * @param {bool} [bRedraw=true] redraw the table or not
5418 * @dtopt API
5419 * @deprecated Since v1.10
5420 *
5421 * @example
5422 * $(document).ready(function() {
5423 * var oTable = $('#example').dataTable();
5424 *
5425 * // Immediately 'nuke' the current rows (perhaps waiting for an Ajax callback...)
5426 * oTable.fnClearTable();
5427 * } );
5428 */
5429 this.fnClearTable = function( bRedraw )
5430 {
5431 var api = this.api( true ).clear();
5432
5433 if ( bRedraw === undefined || bRedraw ) {
5434 api.draw();
5435 }
5436 };
5437
5438
5439 /**
5440 * The exact opposite of 'opening' a row, this function will close any rows which
5441 * are currently 'open'.
5442 * @param {node} nTr the table row to 'close'
5443 * @returns {int} 0 on success, or 1 if failed (can't find the row)
5444 * @dtopt API
5445 * @deprecated Since v1.10
5446 *
5447 * @example
5448 * $(document).ready(function() {
5449 * var oTable;
5450 *
5451 * // 'open' an information row when a row is clicked on
5452 * $('#example tbody tr').click( function () {
5453 * if ( oTable.fnIsOpen(this) ) {
5454 * oTable.fnClose( this );
5455 * } else {
5456 * oTable.fnOpen( this, "Temporary row opened", "info_row" );
5457 * }
5458 * } );
5459 *
5460 * oTable = $('#example').dataTable();
5461 * } );
5462 */
5463 this.fnClose = function( nTr )
5464 {
5465 this.api( true ).row( nTr ).child.hide();
5466 };
5467
5468
5469 /**
5470 * Remove a row for the table
5471 * @param {mixed} target The index of the row from aoData to be deleted, or
5472 * the TR element you want to delete
5473 * @param {function|null} [callBack] Callback function
5474 * @param {bool} [redraw=true] Redraw the table or not
5475 * @returns {array} The row that was deleted
5476 * @dtopt API
5477 * @deprecated Since v1.10
5478 *
5479 * @example
5480 * $(document).ready(function() {
5481 * var oTable = $('#example').dataTable();
5482 *
5483 * // Immediately remove the first row
5484 * oTable.fnDeleteRow( 0 );
5485 * } );
5486 */
5487 this.fnDeleteRow = function( target, callback, redraw )
5488 {
5489 var api = this.api( true );
5490 var rows = api.rows( target );
5491 var settings = rows.settings()[0];
5492 var data = settings.aoData[ rows[0][0] ];
5493
5494 rows.remove();
5495
5496 if ( callback ) {
5497 callback.call( this, settings, data );
5498 }
5499
5500 if ( redraw === undefined || redraw ) {
5501 api.draw();
5502 }
5503
5504 return data;
5505 };
5506
5507
5508 /**
5509 * Restore the table to it's original state in the DOM by removing all of DataTables
5510 * enhancements, alterations to the DOM structure of the table and event listeners.
5511 * @param {boolean} [remove=false] Completely remove the table from the DOM
5512 * @dtopt API
5513 * @deprecated Since v1.10
5514 *
5515 * @example
5516 * $(document).ready(function() {
5517 * // This example is fairly pointless in reality, but shows how fnDestroy can be used
5518 * var oTable = $('#example').dataTable();
5519 * oTable.fnDestroy();
5520 * } );
5521 */
5522 this.fnDestroy = function ( remove )
5523 {
5524 this.api( true ).destroy( remove );
5525 };
5526
5527
5528 /**
5529 * Redraw the table
5530 * @param {bool} [complete=true] Re-filter and resort (if enabled) the table before the draw.
5531 * @dtopt API
5532 * @deprecated Since v1.10
5533 *
5534 * @example
5535 * $(document).ready(function() {
5536 * var oTable = $('#example').dataTable();
5537 *
5538 * // Re-draw the table - you wouldn't want to do it here, but it's an example :-)
5539 * oTable.fnDraw();
5540 * } );
5541 */
5542 this.fnDraw = function( complete )
5543 {
5544 // Note that this isn't an exact match to the old call to _fnDraw - it takes
5545 // into account the new data, but can old position.
5546 this.api( true ).draw( ! complete );
5547 };
5548
5549
5550 /**
5551 * Filter the input based on data
5552 * @param {string} sInput String to filter the table on
5553 * @param {int|null} [iColumn] Column to limit filtering to
5554 * @param {bool} [bRegex=false] Treat as regular expression or not
5555 * @param {bool} [bSmart=true] Perform smart filtering or not
5556 * @param {bool} [bShowGlobal=true] Show the input global filter in it's input box(es)
5557 * @param {bool} [bCaseInsensitive=true] Do case-insensitive matching (true) or not (false)
5558 * @dtopt API
5559 * @deprecated Since v1.10
5560 *
5561 * @example
5562 * $(document).ready(function() {
5563 * var oTable = $('#example').dataTable();
5564 *
5565 * // Sometime later - filter...
5566 * oTable.fnFilter( 'test string' );
5567 * } );
5568 */
5569 this.fnFilter = function( sInput, iColumn, bRegex, bSmart, bShowGlobal, bCaseInsensitive )
5570 {
5571 var api = this.api( true );
5572
5573 if ( iColumn === null || iColumn === undefined ) {
5574 api.search( sInput, bRegex, bSmart, bCaseInsensitive );
5575 }
5576 else {
5577 api.column( iColumn ).search( sInput, bRegex, bSmart, bCaseInsensitive );
5578 }
5579
5580 api.draw();
5581 };
5582
5583
5584 /**
5585 * Get the data for the whole table, an individual row or an individual cell based on the
5586 * provided parameters.
5587 * @param {int|node} [src] A TR row node, TD/TH cell node or an integer. If given as
5588 * a TR node then the data source for the whole row will be returned. If given as a
5589 * TD/TH cell node then iCol will be automatically calculated and the data for the
5590 * cell returned. If given as an integer, then this is treated as the aoData internal
5591 * data index for the row (see fnGetPosition) and the data for that row used.
5592 * @param {int} [col] Optional column index that you want the data of.
5593 * @returns {array|object|string} If mRow is undefined, then the data for all rows is
5594 * returned. If mRow is defined, just data for that row, and is iCol is
5595 * defined, only data for the designated cell is returned.
5596 * @dtopt API
5597 * @deprecated Since v1.10
5598 *
5599 * @example
5600 * // Row data
5601 * $(document).ready(function() {
5602 * oTable = $('#example').dataTable();
5603 *
5604 * oTable.$('tr').click( function () {
5605 * var data = oTable.fnGetData( this );
5606 * // ... do something with the array / object of data for the row
5607 * } );
5608 * } );
5609 *
5610 * @example
5611 * // Individual cell data
5612 * $(document).ready(function() {
5613 * oTable = $('#example').dataTable();
5614 *
5615 * oTable.$('td').click( function () {
5616 * var sData = oTable.fnGetData( this );
5617 * alert( 'The cell clicked on had the value of '+sData );
5618 * } );
5619 * } );
5620 */
5621 this.fnGetData = function( src, col )
5622 {
5623 var api = this.api( true );
5624
5625 if ( src !== undefined ) {
5626 var type = src.nodeName ? src.nodeName.toLowerCase() : '';
5627
5628 return col !== undefined || type == 'td' || type == 'th' ?
5629 api.cell( src, col ).data() :
5630 api.row( src ).data() || null;
5631 }
5632
5633 return api.data().toArray();
5634 };
5635
5636
5637 /**
5638 * Get an array of the TR nodes that are used in the table's body. Note that you will
5639 * typically want to use the '$' API method in preference to this as it is more
5640 * flexible.
5641 * @param {int} [iRow] Optional row index for the TR element you want
5642 * @returns {array|node} If iRow is undefined, returns an array of all TR elements
5643 * in the table's body, or iRow is defined, just the TR element requested.
5644 * @dtopt API
5645 * @deprecated Since v1.10
5646 *
5647 * @example
5648 * $(document).ready(function() {
5649 * var oTable = $('#example').dataTable();
5650 *
5651 * // Get the nodes from the table
5652 * var nNodes = oTable.fnGetNodes( );
5653 * } );
5654 */
5655 this.fnGetNodes = function( iRow )
5656 {
5657 var api = this.api( true );
5658
5659 return iRow !== undefined ?
5660 api.row( iRow ).node() :
5661 api.rows().nodes().flatten().toArray();
5662 };
5663
5664
5665 /**
5666 * Get the array indexes of a particular cell from it's DOM element
5667 * and column index including hidden columns
5668 * @param {node} node this can either be a TR, TD or TH in the table's body
5669 * @returns {int} If nNode is given as a TR, then a single index is returned, or
5670 * if given as a cell, an array of [row index, column index (visible),
5671 * column index (all)] is given.
5672 * @dtopt API
5673 * @deprecated Since v1.10
5674 *
5675 * @example
5676 * $(document).ready(function() {
5677 * $('#example tbody td').click( function () {
5678 * // Get the position of the current data from the node
5679 * var aPos = oTable.fnGetPosition( this );
5680 *
5681 * // Get the data array for this row
5682 * var aData = oTable.fnGetData( aPos[0] );
5683 *
5684 * // Update the data array and return the value
5685 * aData[ aPos[1] ] = 'clicked';
5686 * this.innerHTML = 'clicked';
5687 * } );
5688 *
5689 * // Init DataTables
5690 * oTable = $('#example').dataTable();
5691 * } );
5692 */
5693 this.fnGetPosition = function( node )
5694 {
5695 var api = this.api( true );
5696 var nodeName = node.nodeName.toUpperCase();
5697
5698 if ( nodeName == 'TR' ) {
5699 return api.row( node ).index();
5700 }
5701 else if ( nodeName == 'TD' || nodeName == 'TH' ) {
5702 var cell = api.cell( node ).index();
5703
5704 return [
5705 cell.row,
5706 cell.columnVisible,
5707 cell.column
5708 ];
5709 }
5710 return null;
5711 };
5712
5713
5714 /**
5715 * Check to see if a row is 'open' or not.
5716 * @param {node} nTr the table row to check
5717 * @returns {boolean} true if the row is currently open, false otherwise
5718 * @dtopt API
5719 * @deprecated Since v1.10
5720 *
5721 * @example
5722 * $(document).ready(function() {
5723 * var oTable;
5724 *
5725 * // 'open' an information row when a row is clicked on
5726 * $('#example tbody tr').click( function () {
5727 * if ( oTable.fnIsOpen(this) ) {
5728 * oTable.fnClose( this );
5729 * } else {
5730 * oTable.fnOpen( this, "Temporary row opened", "info_row" );
5731 * }
5732 * } );
5733 *
5734 * oTable = $('#example').dataTable();
5735 * } );
5736 */
5737 this.fnIsOpen = function( nTr )
5738 {
5739 return this.api( true ).row( nTr ).child.isShown();
5740 };
5741
5742
5743 /**
5744 * This function will place a new row directly after a row which is currently
5745 * on display on the page, with the HTML contents that is passed into the
5746 * function. This can be used, for example, to ask for confirmation that a
5747 * particular record should be deleted.
5748 * @param {node} nTr The table row to 'open'
5749 * @param {string|node|jQuery} mHtml The HTML to put into the row
5750 * @param {string} sClass Class to give the new TD cell
5751 * @returns {node} The row opened. Note that if the table row passed in as the
5752 * first parameter, is not found in the table, this method will silently
5753 * return.
5754 * @dtopt API
5755 * @deprecated Since v1.10
5756 *
5757 * @example
5758 * $(document).ready(function() {
5759 * var oTable;
5760 *
5761 * // 'open' an information row when a row is clicked on
5762 * $('#example tbody tr').click( function () {
5763 * if ( oTable.fnIsOpen(this) ) {
5764 * oTable.fnClose( this );
5765 * } else {
5766 * oTable.fnOpen( this, "Temporary row opened", "info_row" );
5767 * }
5768 * } );
5769 *
5770 * oTable = $('#example').dataTable();
5771 * } );
5772 */
5773 this.fnOpen = function( nTr, mHtml, sClass )
5774 {
5775 return this.api( true )
5776 .row( nTr )
5777 .child( mHtml, sClass )
5778 .show()
5779 .child()[0];
5780 };
5781
5782
5783 /**
5784 * Change the pagination - provides the internal logic for pagination in a simple API
5785 * function. With this function you can have a DataTables table go to the next,
5786 * previous, first or last pages.
5787 * @param {string|int} mAction Paging action to take: "first", "previous", "next" or "last"
5788 * or page number to jump to (integer), note that page 0 is the first page.
5789 * @param {bool} [bRedraw=true] Redraw the table or not
5790 * @dtopt API
5791 * @deprecated Since v1.10
5792 *
5793 * @example
5794 * $(document).ready(function() {
5795 * var oTable = $('#example').dataTable();
5796 * oTable.fnPageChange( 'next' );
5797 * } );
5798 */
5799 this.fnPageChange = function ( mAction, bRedraw )
5800 {
5801 var api = this.api( true ).page( mAction );
5802
5803 if ( bRedraw === undefined || bRedraw ) {
5804 api.draw(false);
5805 }
5806 };
5807
5808
5809 /**
5810 * Show a particular column
5811 * @param {int} iCol The column whose display should be changed
5812 * @param {bool} bShow Show (true) or hide (false) the column
5813 * @param {bool} [bRedraw=true] Redraw the table or not
5814 * @dtopt API
5815 * @deprecated Since v1.10
5816 *
5817 * @example
5818 * $(document).ready(function() {
5819 * var oTable = $('#example').dataTable();
5820 *
5821 * // Hide the second column after initialisation
5822 * oTable.fnSetColumnVis( 1, false );
5823 * } );
5824 */
5825 this.fnSetColumnVis = function ( iCol, bShow, bRedraw )
5826 {
5827 var api = this.api( true ).column( iCol ).visible( bShow );
5828
5829 if ( bRedraw === undefined || bRedraw ) {
5830 api.columns.adjust().draw();
5831 }
5832 };
5833
5834
5835 /**
5836 * Get the settings for a particular table for external manipulation
5837 * @returns {object} DataTables settings object. See
5838 * {@link DataTable.models.oSettings}
5839 * @dtopt API
5840 * @deprecated Since v1.10
5841 *
5842 * @example
5843 * $(document).ready(function() {
5844 * var oTable = $('#example').dataTable();
5845 * var oSettings = oTable.fnSettings();
5846 *
5847 * // Show an example parameter from the settings
5848 * alert( oSettings._iDisplayStart );
5849 * } );
5850 */
5851 this.fnSettings = function()
5852 {
5853 return _fnSettingsFromNode( this[_ext.iApiIndex] );
5854 };
5855
5856
5857 /**
5858 * Sort the table by a particular column
5859 * @param {int} iCol the data index to sort on. Note that this will not match the
5860 * 'display index' if you have hidden data entries
5861 * @dtopt API
5862 * @deprecated Since v1.10
5863 *
5864 * @example
5865 * $(document).ready(function() {
5866 * var oTable = $('#example').dataTable();
5867 *
5868 * // Sort immediately with columns 0 and 1
5869 * oTable.fnSort( [ [0,'asc'], [1,'asc'] ] );
5870 * } );
5871 */
5872 this.fnSort = function( aaSort )
5873 {
5874 this.api( true ).order( aaSort ).draw();
5875 };
5876
5877
5878 /**
5879 * Attach a sort listener to an element for a given column
5880 * @param {node} nNode the element to attach the sort listener to
5881 * @param {int} iColumn the column that a click on this node will sort on
5882 * @param {function} [fnCallback] callback function when sort is run
5883 * @dtopt API
5884 * @deprecated Since v1.10
5885 *
5886 * @example
5887 * $(document).ready(function() {
5888 * var oTable = $('#example').dataTable();
5889 *
5890 * // Sort on column 1, when 'sorter' is clicked on
5891 * oTable.fnSortListener( document.getElementById('sorter'), 1 );
5892 * } );
5893 */
5894 this.fnSortListener = function( nNode, iColumn, fnCallback )
5895 {
5896 this.api( true ).order.listener( nNode, iColumn, fnCallback );
5897 };
5898
5899
5900 /**
5901 * Update a table cell or row - this method will accept either a single value to
5902 * update the cell with, an array of values with one element for each column or
5903 * an object in the same format as the original data source. The function is
5904 * self-referencing in order to make the multi column updates easier.
5905 * @param {object|array|string} mData Data to update the cell/row with
5906 * @param {node|int} mRow TR element you want to update or the aoData index
5907 * @param {int} [iColumn] The column to update, give as null or undefined to
5908 * update a whole row.
5909 * @param {bool} [bRedraw=true] Redraw the table or not
5910 * @param {bool} [bAction=true] Perform pre-draw actions or not
5911 * @returns {int} 0 on success, 1 on error
5912 * @dtopt API
5913 * @deprecated Since v1.10
5914 *
5915 * @example
5916 * $(document).ready(function() {
5917 * var oTable = $('#example').dataTable();
5918 * oTable.fnUpdate( 'Example update', 0, 0 ); // Single cell
5919 * oTable.fnUpdate( ['a', 'b', 'c', 'd', 'e'], $('tbody tr')[0] ); // Row
5920 * } );
5921 */
5922 this.fnUpdate = function( mData, mRow, iColumn, bRedraw, bAction )
5923 {
5924 var api = this.api( true );
5925
5926 if ( iColumn === undefined || iColumn === null ) {
5927 api.row( mRow ).data( mData );
5928 }
5929 else {
5930 api.cell( mRow, iColumn ).data( mData );
5931 }
5932
5933 if ( bAction === undefined || bAction ) {
5934 api.columns.adjust();
5935 }
5936
5937 if ( bRedraw === undefined || bRedraw ) {
5938 api.draw();
5939 }
5940 return 0;
5941 };
5942
5943
5944 /**
5945 * Provide a common method for plug-ins to check the version of DataTables being used, in order
5946 * to ensure compatibility.
5947 * @param {string} sVersion Version string to check for, in the format "X.Y.Z". Note that the
5948 * formats "X" and "X.Y" are also acceptable.
5949 * @returns {boolean} true if this version of DataTables is greater or equal to the required
5950 * version, or false if this version of DataTales is not suitable
5951 * @method
5952 * @dtopt API
5953 * @deprecated Since v1.10
5954 *
5955 * @example
5956 * $(document).ready(function() {
5957 * var oTable = $('#example').dataTable();
5958 * alert( oTable.fnVersionCheck( '1.9.0' ) );
5959 * } );
5960 */
5961 this.fnVersionCheck = _ext.fnVersionCheck;
5962
5963
5964 var _that = this;
5965 var emptyInit = options === undefined;
5966 var len = this.length;
5967
5968 if ( emptyInit ) {
5969 options = {};
5970 }
5971
5972 this.oApi = this.internal = _ext.internal;
5973
5974 // Extend with old style plug-in API methods
5975 for ( var fn in DataTable.ext.internal ) {
5976 if ( fn ) {
5977 this[fn] = _fnExternApiFunc(fn);
5978 }
5979 }
5980
5981 this.each(function() {
5982 // For each initialisation we want to give it a clean initialisation
5983 // object that can be bashed around
5984 var o = {};
5985 var oInit = len > 1 ? // optimisation for single table case
5986 _fnExtend( o, options, true ) :
5987 options;
5988
5989 /*global oInit,_that,emptyInit*/
5990 var i=0, iLen, j, jLen, k, kLen;
5991 var sId = this.getAttribute( 'id' );
5992 var bInitHandedOff = false;
5993 var defaults = DataTable.defaults;
5994
5995
5996 /* Sanity check */
5997 if ( this.nodeName.toLowerCase() != 'table' )
5998 {
5999 _fnLog( null, 0, 'Non-table node initialisation ('+this.nodeName+')', 2 );
6000 return;
6001 }
6002
6003 /* Backwards compatibility for the defaults */
6004 _fnCompatOpts( defaults );
6005 _fnCompatCols( defaults.column );
6006
6007 /* Convert the camel-case defaults to Hungarian */
6008 _fnCamelToHungarian( defaults, defaults, true );
6009 _fnCamelToHungarian( defaults.column, defaults.column, true );
6010
6011 /* Setting up the initialisation object */
6012 _fnCamelToHungarian( defaults, oInit );
6013
6014 /* Check to see if we are re-initialising a table */
6015 var allSettings = DataTable.settings;
6016 for ( i=0, iLen=allSettings.length ; i<iLen ; i++ )
6017 {
6018 /* Base check on table node */
6019 if ( allSettings[i].nTable == this )
6020 {
6021 var bRetrieve = oInit.bRetrieve !== undefined ? oInit.bRetrieve : defaults.bRetrieve;
6022 var bDestroy = oInit.bDestroy !== undefined ? oInit.bDestroy : defaults.bDestroy;
6023
6024 if ( emptyInit || bRetrieve )
6025 {
6026 return allSettings[i].oInstance;
6027 }
6028 else if ( bDestroy )
6029 {
6030 allSettings[i].oInstance.fnDestroy();
6031 break;
6032 }
6033 else
6034 {
6035 _fnLog( allSettings[i], 0, 'Cannot reinitialise DataTable', 3 );
6036 return;
6037 }
6038 }
6039
6040 /* If the element we are initialising has the same ID as a table which was previously
6041 * initialised, but the table nodes don't match (from before) then we destroy the old
6042 * instance by simply deleting it. This is under the assumption that the table has been
6043 * destroyed by other methods. Anyone using non-id selectors will need to do this manually
6044 */
6045 if ( allSettings[i].sTableId == this.id )
6046 {
6047 allSettings.splice( i, 1 );
6048 break;
6049 }
6050 }
6051
6052 /* Ensure the table has an ID - required for accessibility */
6053 if ( sId === null || sId === "" )
6054 {
6055 sId = "DataTables_Table_"+(DataTable.ext._unique++);
6056 this.id = sId;
6057 }
6058
6059 /* Create the settings object for this table and set some of the default parameters */
6060 var oSettings = $.extend( true, {}, DataTable.models.oSettings, {
6061 "nTable": this,
6062 "oApi": _that.internal,
6063 "oInit": oInit,
6064 "sDestroyWidth": $(this)[0].style.width,
6065 "sInstance": sId,
6066 "sTableId": sId
6067 } );
6068 allSettings.push( oSettings );
6069
6070 // Need to add the instance after the instance after the settings object has been added
6071 // to the settings array, so we can self reference the table instance if more than one
6072 oSettings.oInstance = (_that.length===1) ? _that : $(this).dataTable();
6073
6074 // Backwards compatibility, before we apply all the defaults
6075 _fnCompatOpts( oInit );
6076
6077 if ( oInit.oLanguage )
6078 {
6079 _fnLanguageCompat( oInit.oLanguage );
6080 }
6081
6082 // If the length menu is given, but the init display length is not, use the length menu
6083 if ( oInit.aLengthMenu && ! oInit.iDisplayLength )
6084 {
6085 oInit.iDisplayLength = $.isArray( oInit.aLengthMenu[0] ) ?
6086 oInit.aLengthMenu[0][0] : oInit.aLengthMenu[0];
6087 }
6088
6089 // Apply the defaults and init options to make a single init object will all
6090 // options defined from defaults and instance options.
6091 oInit = _fnExtend( $.extend( true, {}, defaults ), oInit );
6092
6093
6094 // Map the initialisation options onto the settings object
6095 _fnMap( oSettings.oFeatures, oInit, [
6096 "bPaginate",
6097 "bLengthChange",
6098 "bFilter",
6099 "bSort",
6100 "bSortMulti",
6101 "bInfo",
6102 "bProcessing",
6103 "bAutoWidth",
6104 "bSortClasses",
6105 "bServerSide",
6106 "bDeferRender"
6107 ] );
6108 _fnMap( oSettings, oInit, [
6109 "asStripeClasses",
6110 "ajax",
6111 "fnServerData",
6112 "fnFormatNumber",
6113 "sServerMethod",
6114 "aaSorting",
6115 "aaSortingFixed",
6116 "aLengthMenu",
6117 "sPaginationType",
6118 "sAjaxSource",
6119 "sAjaxDataProp",
6120 "iStateDuration",
6121 "sDom",
6122 "bSortCellsTop",
6123 "iTabIndex",
6124 "fnStateLoadCallback",
6125 "fnStateSaveCallback",
6126 "renderer",
6127 "searchDelay",
6128 [ "iCookieDuration", "iStateDuration" ], // backwards compat
6129 [ "oSearch", "oPreviousSearch" ],
6130 [ "aoSearchCols", "aoPreSearchCols" ],
6131 [ "iDisplayLength", "_iDisplayLength" ],
6132 [ "bJQueryUI", "bJUI" ]
6133 ] );
6134 _fnMap( oSettings.oScroll, oInit, [
6135 [ "sScrollX", "sX" ],
6136 [ "sScrollXInner", "sXInner" ],
6137 [ "sScrollY", "sY" ],
6138 [ "bScrollCollapse", "bCollapse" ]
6139 ] );
6140 _fnMap( oSettings.oLanguage, oInit, "fnInfoCallback" );
6141
6142 /* Callback functions which are array driven */
6143 _fnCallbackReg( oSettings, 'aoDrawCallback', oInit.fnDrawCallback, 'user' );
6144 _fnCallbackReg( oSettings, 'aoServerParams', oInit.fnServerParams, 'user' );
6145 _fnCallbackReg( oSettings, 'aoStateSaveParams', oInit.fnStateSaveParams, 'user' );
6146 _fnCallbackReg( oSettings, 'aoStateLoadParams', oInit.fnStateLoadParams, 'user' );
6147 _fnCallbackReg( oSettings, 'aoStateLoaded', oInit.fnStateLoaded, 'user' );
6148 _fnCallbackReg( oSettings, 'aoRowCallback', oInit.fnRowCallback, 'user' );
6149 _fnCallbackReg( oSettings, 'aoRowCreatedCallback', oInit.fnCreatedRow, 'user' );
6150 _fnCallbackReg( oSettings, 'aoHeaderCallback', oInit.fnHeaderCallback, 'user' );
6151 _fnCallbackReg( oSettings, 'aoFooterCallback', oInit.fnFooterCallback, 'user' );
6152 _fnCallbackReg( oSettings, 'aoInitComplete', oInit.fnInitComplete, 'user' );
6153 _fnCallbackReg( oSettings, 'aoPreDrawCallback', oInit.fnPreDrawCallback, 'user' );
6154
6155 var oClasses = oSettings.oClasses;
6156
6157 // @todo Remove in 1.11
6158 if ( oInit.bJQueryUI )
6159 {
6160 /* Use the JUI classes object for display. You could clone the oStdClasses object if
6161 * you want to have multiple tables with multiple independent classes
6162 */
6163 $.extend( oClasses, DataTable.ext.oJUIClasses, oInit.oClasses );
6164
6165 if ( oInit.sDom === defaults.sDom && defaults.sDom === "lfrtip" )
6166 {
6167 /* Set the DOM to use a layout suitable for jQuery UI's theming */
6168 oSettings.sDom = '<"H"lfr>t<"F"ip>';
6169 }
6170
6171 if ( ! oSettings.renderer ) {
6172 oSettings.renderer = 'jqueryui';
6173 }
6174 else if ( $.isPlainObject( oSettings.renderer ) && ! oSettings.renderer.header ) {
6175 oSettings.renderer.header = 'jqueryui';
6176 }
6177 }
6178 else
6179 {
6180 $.extend( oClasses, DataTable.ext.classes, oInit.oClasses );
6181 }
6182 $(this).addClass( oClasses.sTable );
6183
6184 /* Calculate the scroll bar width and cache it for use later on */
6185 if ( oSettings.oScroll.sX !== "" || oSettings.oScroll.sY !== "" )
6186 {
6187 oSettings.oScroll.iBarWidth = _fnScrollBarWidth();
6188 }
6189 if ( oSettings.oScroll.sX === true ) { // Easy initialisation of x-scrolling
6190 oSettings.oScroll.sX = '100%';
6191 }
6192
6193 if ( oSettings.iInitDisplayStart === undefined )
6194 {
6195 /* Display start point, taking into account the save saving */
6196 oSettings.iInitDisplayStart = oInit.iDisplayStart;
6197 oSettings._iDisplayStart = oInit.iDisplayStart;
6198 }
6199
6200 if ( oInit.iDeferLoading !== null )
6201 {
6202 oSettings.bDeferLoading = true;
6203 var tmp = $.isArray( oInit.iDeferLoading );
6204 oSettings._iRecordsDisplay = tmp ? oInit.iDeferLoading[0] : oInit.iDeferLoading;
6205 oSettings._iRecordsTotal = tmp ? oInit.iDeferLoading[1] : oInit.iDeferLoading;
6206 }
6207
6208 /* Language definitions */
6209 var oLanguage = oSettings.oLanguage;
6210 $.extend( true, oLanguage, oInit.oLanguage );
6211
6212 if ( oLanguage.sUrl !== "" )
6213 {
6214 /* Get the language definitions from a file - because this Ajax call makes the language
6215 * get async to the remainder of this function we use bInitHandedOff to indicate that
6216 * _fnInitialise will be fired by the returned Ajax handler, rather than the constructor
6217 */
6218 $.ajax( {
6219 dataType: 'json',
6220 url: oLanguage.sUrl,
6221 success: function ( json ) {
6222 _fnLanguageCompat( json );
6223 _fnCamelToHungarian( defaults.oLanguage, json );
6224 $.extend( true, oLanguage, json );
6225 _fnInitialise( oSettings );
6226 },
6227 error: function () {
6228 // Error occurred loading language file, continue on as best we can
6229 _fnInitialise( oSettings );
6230 }
6231 } );
6232 bInitHandedOff = true;
6233 }
6234
6235 /*
6236 * Stripes
6237 */
6238 if ( oInit.asStripeClasses === null )
6239 {
6240 oSettings.asStripeClasses =[
6241 oClasses.sStripeOdd,
6242 oClasses.sStripeEven
6243 ];
6244 }
6245
6246 /* Remove row stripe classes if they are already on the table row */
6247 var stripeClasses = oSettings.asStripeClasses;
6248 var rowOne = $('tbody tr:eq(0)', this);
6249 if ( $.inArray( true, $.map( stripeClasses, function(el, i) {
6250 return rowOne.hasClass(el);
6251 } ) ) !== -1 ) {
6252 $('tbody tr', this).removeClass( stripeClasses.join(' ') );
6253 oSettings.asDestroyStripes = stripeClasses.slice();
6254 }
6255
6256 /*
6257 * Columns
6258 * See if we should load columns automatically or use defined ones
6259 */
6260 var anThs = [];
6261 var aoColumnsInit;
6262 var nThead = this.getElementsByTagName('thead');
6263 if ( nThead.length !== 0 )
6264 {
6265 _fnDetectHeader( oSettings.aoHeader, nThead[0] );
6266 anThs = _fnGetUniqueThs( oSettings );
6267 }
6268
6269 /* If not given a column array, generate one with nulls */
6270 if ( oInit.aoColumns === null )
6271 {
6272 aoColumnsInit = [];
6273 for ( i=0, iLen=anThs.length ; i<iLen ; i++ )
6274 {
6275 aoColumnsInit.push( null );
6276 }
6277 }
6278 else
6279 {
6280 aoColumnsInit = oInit.aoColumns;
6281 }
6282
6283 /* Add the columns */
6284 for ( i=0, iLen=aoColumnsInit.length ; i<iLen ; i++ )
6285 {
6286 _fnAddColumn( oSettings, anThs ? anThs[i] : null );
6287 }
6288
6289 /* Apply the column definitions */
6290 _fnApplyColumnDefs( oSettings, oInit.aoColumnDefs, aoColumnsInit, function (iCol, oDef) {
6291 _fnColumnOptions( oSettings, iCol, oDef );
6292 } );
6293
6294 /* HTML5 attribute detection - build an mData object automatically if the
6295 * attributes are found
6296 */
6297 if ( rowOne.length ) {
6298 var a = function ( cell, name ) {
6299 return cell.getAttribute( 'data-'+name ) ? name : null;
6300 };
6301
6302 $.each( _fnGetRowElements( oSettings, rowOne[0] ).cells, function (i, cell) {
6303 var col = oSettings.aoColumns[i];
6304
6305 if ( col.mData === i ) {
6306 var sort = a( cell, 'sort' ) || a( cell, 'order' );
6307 var filter = a( cell, 'filter' ) || a( cell, 'search' );
6308
6309 if ( sort !== null || filter !== null ) {
6310 col.mData = {
6311 _: i+'.display',
6312 sort: sort !== null ? i+'.@data-'+sort : undefined,
6313 type: sort !== null ? i+'.@data-'+sort : undefined,
6314 filter: filter !== null ? i+'.@data-'+filter : undefined
6315 };
6316
6317 _fnColumnOptions( oSettings, i );
6318 }
6319 }
6320 } );
6321 }
6322
6323 var features = oSettings.oFeatures;
6324
6325 /* Must be done after everything which can be overridden by the state saving! */
6326 if ( oInit.bStateSave )
6327 {
6328 features.bStateSave = true;
6329 _fnLoadState( oSettings, oInit );
6330 _fnCallbackReg( oSettings, 'aoDrawCallback', _fnSaveState, 'state_save' );
6331 }
6332
6333
6334 /*
6335 * Sorting
6336 * @todo For modularisation (1.11) this needs to do into a sort start up handler
6337 */
6338
6339 // If aaSorting is not defined, then we use the first indicator in asSorting
6340 // in case that has been altered, so the default sort reflects that option
6341 if ( oInit.aaSorting === undefined )
6342 {
6343 var sorting = oSettings.aaSorting;
6344 for ( i=0, iLen=sorting.length ; i<iLen ; i++ )
6345 {
6346 sorting[i][1] = oSettings.aoColumns[ i ].asSorting[0];
6347 }
6348 }
6349
6350 /* Do a first pass on the sorting classes (allows any size changes to be taken into
6351 * account, and also will apply sorting disabled classes if disabled
6352 */
6353 _fnSortingClasses( oSettings );
6354
6355 if ( features.bSort )
6356 {
6357 _fnCallbackReg( oSettings, 'aoDrawCallback', function () {
6358 if ( oSettings.bSorted ) {
6359 var aSort = _fnSortFlatten( oSettings );
6360 var sortedColumns = {};
6361
6362 $.each( aSort, function (i, val) {
6363 sortedColumns[ val.src ] = val.dir;
6364 } );
6365
6366 _fnCallbackFire( oSettings, null, 'order', [oSettings, aSort, sortedColumns] );
6367 _fnSortAria( oSettings );
6368 }
6369 } );
6370 }
6371
6372 _fnCallbackReg( oSettings, 'aoDrawCallback', function () {
6373 if ( oSettings.bSorted || _fnDataSource( oSettings ) === 'ssp' || features.bDeferRender ) {
6374 _fnSortingClasses( oSettings );
6375 }
6376 }, 'sc' );
6377
6378
6379 /*
6380 * Final init
6381 * Cache the header, body and footer as required, creating them if needed
6382 */
6383
6384 /* Browser support detection */
6385 _fnBrowserDetect( oSettings );
6386
6387 // Work around for Webkit bug 83867 - store the caption-side before removing from doc
6388 var captions = $(this).children('caption').each( function () {
6389 this._captionSide = $(this).css('caption-side');
6390 } );
6391
6392 var thead = $(this).children('thead');
6393 if ( thead.length === 0 )
6394 {
6395 thead = $('<thead/>').appendTo(this);
6396 }
6397 oSettings.nTHead = thead[0];
6398
6399 var tbody = $(this).children('tbody');
6400 if ( tbody.length === 0 )
6401 {
6402 tbody = $('<tbody/>').appendTo(this);
6403 }
6404 oSettings.nTBody = tbody[0];
6405
6406 var tfoot = $(this).children('tfoot');
6407 if ( tfoot.length === 0 && captions.length > 0 && (oSettings.oScroll.sX !== "" || oSettings.oScroll.sY !== "") )
6408 {
6409 // If we are a scrolling table, and no footer has been given, then we need to create
6410 // a tfoot element for the caption element to be appended to
6411 tfoot = $('<tfoot/>').appendTo(this);
6412 }
6413
6414 if ( tfoot.length === 0 || tfoot.children().length === 0 ) {
6415 $(this).addClass( oClasses.sNoFooter );
6416 }
6417 else if ( tfoot.length > 0 ) {
6418 oSettings.nTFoot = tfoot[0];
6419 _fnDetectHeader( oSettings.aoFooter, oSettings.nTFoot );
6420 }
6421
6422 /* Check if there is data passing into the constructor */
6423 if ( oInit.aaData )
6424 {
6425 for ( i=0 ; i<oInit.aaData.length ; i++ )
6426 {
6427 _fnAddData( oSettings, oInit.aaData[ i ] );
6428 }
6429 }
6430 else if ( oSettings.bDeferLoading || _fnDataSource( oSettings ) == 'dom' )
6431 {
6432 /* Grab the data from the page - only do this when deferred loading or no Ajax
6433 * source since there is no point in reading the DOM data if we are then going
6434 * to replace it with Ajax data
6435 */
6436 _fnAddTr( oSettings, $(oSettings.nTBody).children('tr') );
6437 }
6438
6439 /* Copy the data index array */
6440 oSettings.aiDisplay = oSettings.aiDisplayMaster.slice();
6441
6442 /* Initialisation complete - table can be drawn */
6443 oSettings.bInitialised = true;
6444
6445 /* Check if we need to initialise the table (it might not have been handed off to the
6446 * language processor)
6447 */
6448 if ( bInitHandedOff === false )
6449 {
6450 _fnInitialise( oSettings );
6451 }
6452 } );
6453 _that = null;
6454 return this;
6455 };
6456
6457
6458
6459 /**
6460 * Computed structure of the DataTables API, defined by the options passed to
6461 * `DataTable.Api.register()` when building the API.
6462 *
6463 * The structure is built in order to speed creation and extension of the Api
6464 * objects since the extensions are effectively pre-parsed.
6465 *
6466 * The array is an array of objects with the following structure, where this
6467 * base array represents the Api prototype base:
6468 *
6469 * [
6470 * {
6471 * name: 'data' -- string - Property name
6472 * val: function () {}, -- function - Api method (or undefined if just an object
6473 * methodExt: [ ... ], -- array - Array of Api object definitions to extend the method result
6474 * propExt: [ ... ] -- array - Array of Api object definitions to extend the property
6475 * },
6476 * {
6477 * name: 'row'
6478 * val: {},
6479 * methodExt: [ ... ],
6480 * propExt: [
6481 * {
6482 * name: 'data'
6483 * val: function () {},
6484 * methodExt: [ ... ],
6485 * propExt: [ ... ]
6486 * },
6487 * ...
6488 * ]
6489 * }
6490 * ]
6491 *
6492 * @type {Array}
6493 * @ignore
6494 */
6495 var __apiStruct = [];
6496
6497
6498 /**
6499 * `Array.prototype` reference.
6500 *
6501 * @type object
6502 * @ignore
6503 */
6504 var __arrayProto = Array.prototype;
6505
6506
6507 /**
6508 * Abstraction for `context` parameter of the `Api` constructor to allow it to
6509 * take several different forms for ease of use.
6510 *
6511 * Each of the input parameter types will be converted to a DataTables settings
6512 * object where possible.
6513 *
6514 * @param {string|node|jQuery|object} mixed DataTable identifier. Can be one
6515 * of:
6516 *
6517 * * `string` - jQuery selector. Any DataTables' matching the given selector
6518 * with be found and used.
6519 * * `node` - `TABLE` node which has already been formed into a DataTable.
6520 * * `jQuery` - A jQuery object of `TABLE` nodes.
6521 * * `object` - DataTables settings object
6522 * * `DataTables.Api` - API instance
6523 * @return {array|null} Matching DataTables settings objects. `null` or
6524 * `undefined` is returned if no matching DataTable is found.
6525 * @ignore
6526 */
6527 var _toSettings = function ( mixed )
6528 {
6529 var idx, jq;
6530 var settings = DataTable.settings;
6531 var tables = $.map( settings, function (el, i) {
6532 return el.nTable;
6533 } );
6534
6535 if ( ! mixed ) {
6536 return [];
6537 }
6538 else if ( mixed.nTable && mixed.oApi ) {
6539 // DataTables settings object
6540 return [ mixed ];
6541 }
6542 else if ( mixed.nodeName && mixed.nodeName.toLowerCase() === 'table' ) {
6543 // Table node
6544 idx = $.inArray( mixed, tables );
6545 return idx !== -1 ? [ settings[idx] ] : null;
6546 }
6547 else if ( mixed && typeof mixed.settings === 'function' ) {
6548 return mixed.settings().toArray();
6549 }
6550 else if ( typeof mixed === 'string' ) {
6551 // jQuery selector
6552 jq = $(mixed);
6553 }
6554 else if ( mixed instanceof $ ) {
6555 // jQuery object (also DataTables instance)
6556 jq = mixed;
6557 }
6558
6559 if ( jq ) {
6560 return jq.map( function(i) {
6561 idx = $.inArray( this, tables );
6562 return idx !== -1 ? settings[idx] : null;
6563 } ).toArray();
6564 }
6565 };
6566
6567
6568 /**
6569 * DataTables API class - used to control and interface with one or more
6570 * DataTables enhanced tables.
6571 *
6572 * The API class is heavily based on jQuery, presenting a chainable interface
6573 * that you can use to interact with tables. Each instance of the API class has
6574 * a "context" - i.e. the tables that it will operate on. This could be a single
6575 * table, all tables on a page or a sub-set thereof.
6576 *
6577 * Additionally the API is designed to allow you to easily work with the data in
6578 * the tables, retrieving and manipulating it as required. This is done by
6579 * presenting the API class as an array like interface. The contents of the
6580 * array depend upon the actions requested by each method (for example
6581 * `rows().nodes()` will return an array of nodes, while `rows().data()` will
6582 * return an array of objects or arrays depending upon your table's
6583 * configuration). The API object has a number of array like methods (`push`,
6584 * `pop`, `reverse` etc) as well as additional helper methods (`each`, `pluck`,
6585 * `unique` etc) to assist your working with the data held in a table.
6586 *
6587 * Most methods (those which return an Api instance) are chainable, which means
6588 * the return from a method call also has all of the methods available that the
6589 * top level object had. For example, these two calls are equivalent:
6590 *
6591 * // Not chained
6592 * api.row.add( {...} );
6593 * api.draw();
6594 *
6595 * // Chained
6596 * api.row.add( {...} ).draw();
6597 *
6598 * @class DataTable.Api
6599 * @param {array|object|string|jQuery} context DataTable identifier. This is
6600 * used to define which DataTables enhanced tables this API will operate on.
6601 * Can be one of:
6602 *
6603 * * `string` - jQuery selector. Any DataTables' matching the given selector
6604 * with be found and used.
6605 * * `node` - `TABLE` node which has already been formed into a DataTable.
6606 * * `jQuery` - A jQuery object of `TABLE` nodes.
6607 * * `object` - DataTables settings object
6608 * @param {array} [data] Data to initialise the Api instance with.
6609 *
6610 * @example
6611 * // Direct initialisation during DataTables construction
6612 * var api = $('#example').DataTable();
6613 *
6614 * @example
6615 * // Initialisation using a DataTables jQuery object
6616 * var api = $('#example').dataTable().api();
6617 *
6618 * @example
6619 * // Initialisation as a constructor
6620 * var api = new $.fn.DataTable.Api( 'table.dataTable' );
6621 */
6622 _Api = function ( context, data )
6623 {
6624 if ( ! this instanceof _Api ) {
6625 throw 'DT API must be constructed as a new object';
6626 // or should it do the 'new' for the caller?
6627 // return new _Api.apply( this, arguments );
6628 }
6629
6630 var settings = [];
6631 var ctxSettings = function ( o ) {
6632 var a = _toSettings( o );
6633 if ( a ) {
6634 settings.push.apply( settings, a );
6635 }
6636 };
6637
6638 if ( $.isArray( context ) ) {
6639 for ( var i=0, ien=context.length ; i<ien ; i++ ) {
6640 ctxSettings( context[i] );
6641 }
6642 }
6643 else {
6644 ctxSettings( context );
6645 }
6646
6647 // Remove duplicates
6648 this.context = _unique( settings );
6649
6650 // Initial data
6651 if ( data ) {
6652 this.push.apply( this, data.toArray ? data.toArray() : data );
6653 }
6654
6655 // selector
6656 this.selector = {
6657 rows: null,
6658 cols: null,
6659 opts: null
6660 };
6661
6662 _Api.extend( this, this, __apiStruct );
6663 };
6664
6665 DataTable.Api = _Api;
6666
6667 _Api.prototype = /** @lends DataTables.Api */{
6668 /**
6669 * Return a new Api instance, comprised of the data held in the current
6670 * instance, join with the other array(s) and/or value(s).
6671 *
6672 * An alias for `Array.prototype.concat`.
6673 *
6674 * @type method
6675 * @param {*} value1 Arrays and/or values to concatenate.
6676 * @param {*} [...] Additional arrays and/or values to concatenate.
6677 * @returns {DataTables.Api} New API instance, comprising of the combined
6678 * array.
6679 */
6680 concat: __arrayProto.concat,
6681
6682
6683 context: [], // array of table settings objects
6684
6685
6686 each: function ( fn )
6687 {
6688 for ( var i=0, ien=this.length ; i<ien; i++ ) {
6689 fn.call( this, this[i], i, this );
6690 }
6691
6692 return this;
6693 },
6694
6695
6696 eq: function ( idx )
6697 {
6698 var ctx = this.context;
6699
6700 return ctx.length > idx ?
6701 new _Api( ctx[idx], this[idx] ) :
6702 null;
6703 },
6704
6705
6706 filter: function ( fn )
6707 {
6708 var a = [];
6709
6710 if ( __arrayProto.filter ) {
6711 a = __arrayProto.filter.call( this, fn, this );
6712 }
6713 else {
6714 // Compatibility for browsers without EMCA-252-5 (JS 1.6)
6715 for ( var i=0, ien=this.length ; i<ien ; i++ ) {
6716 if ( fn.call( this, this[i], i, this ) ) {
6717 a.push( this[i] );
6718 }
6719 }
6720 }
6721
6722 return new _Api( this.context, a );
6723 },
6724
6725
6726 flatten: function ()
6727 {
6728 var a = [];
6729 return new _Api( this.context, a.concat.apply( a, this.toArray() ) );
6730 },
6731
6732
6733 join: __arrayProto.join,
6734
6735
6736 indexOf: __arrayProto.indexOf || function (obj, start)
6737 {
6738 for ( var i=(start || 0), ien=this.length ; i<ien ; i++ ) {
6739 if ( this[i] === obj ) {
6740 return i;
6741 }
6742 }
6743 return -1;
6744 },
6745
6746 // Note that `alwaysNew` is internal - use iteratorNew externally
6747 iterator: function ( flatten, type, fn, alwaysNew ) {
6748 var
6749 a = [], ret,
6750 i, ien, j, jen,
6751 context = this.context,
6752 rows, items, item,
6753 selector = this.selector;
6754
6755 // Argument shifting
6756 if ( typeof flatten === 'string' ) {
6757 alwaysNew = fn;
6758 fn = type;
6759 type = flatten;
6760 flatten = false;
6761 }
6762
6763 for ( i=0, ien=context.length ; i<ien ; i++ ) {
6764 var apiInst = new _Api( context[i] );
6765
6766 if ( type === 'table' ) {
6767 ret = fn.call( apiInst, context[i], i );
6768
6769 if ( ret !== undefined ) {
6770 a.push( ret );
6771 }
6772 }
6773 else if ( type === 'columns' || type === 'rows' ) {
6774 // this has same length as context - one entry for each table
6775 ret = fn.call( apiInst, context[i], this[i], i );
6776
6777 if ( ret !== undefined ) {
6778 a.push( ret );
6779 }
6780 }
6781 else if ( type === 'column' || type === 'column-rows' || type === 'row' || type === 'cell' ) {
6782 // columns and rows share the same structure.
6783 // 'this' is an array of column indexes for each context
6784 items = this[i];
6785
6786 if ( type === 'column-rows' ) {
6787 rows = _selector_row_indexes( context[i], selector.opts );
6788 }
6789
6790 for ( j=0, jen=items.length ; j<jen ; j++ ) {
6791 item = items[j];
6792
6793 if ( type === 'cell' ) {
6794 ret = fn.call( apiInst, context[i], item.row, item.column, i, j );
6795 }
6796 else {
6797 ret = fn.call( apiInst, context[i], item, i, j, rows );
6798 }
6799
6800 if ( ret !== undefined ) {
6801 a.push( ret );
6802 }
6803 }
6804 }
6805 }
6806
6807 if ( a.length || alwaysNew ) {
6808 var api = new _Api( context, flatten ? a.concat.apply( [], a ) : a );
6809 var apiSelector = api.selector;
6810 apiSelector.rows = selector.rows;
6811 apiSelector.cols = selector.cols;
6812 apiSelector.opts = selector.opts;
6813 return api;
6814 }
6815 return this;
6816 },
6817
6818
6819 lastIndexOf: __arrayProto.lastIndexOf || function (obj, start)
6820 {
6821 // Bit cheeky...
6822 return this.indexOf.apply( this.toArray.reverse(), arguments );
6823 },
6824
6825
6826 length: 0,
6827
6828
6829 map: function ( fn )
6830 {
6831 var a = [];
6832
6833 if ( __arrayProto.map ) {
6834 a = __arrayProto.map.call( this, fn, this );
6835 }
6836 else {
6837 // Compatibility for browsers without EMCA-252-5 (JS 1.6)
6838 for ( var i=0, ien=this.length ; i<ien ; i++ ) {
6839 a.push( fn.call( this, this[i], i ) );
6840 }
6841 }
6842
6843 return new _Api( this.context, a );
6844 },
6845
6846
6847 pluck: function ( prop )
6848 {
6849 return this.map( function ( el ) {
6850 return el[ prop ];
6851 } );
6852 },
6853
6854 pop: __arrayProto.pop,
6855
6856
6857 push: __arrayProto.push,
6858
6859
6860 // Does not return an API instance
6861 reduce: __arrayProto.reduce || function ( fn, init )
6862 {
6863 return _fnReduce( this, fn, init, 0, this.length, 1 );
6864 },
6865
6866
6867 reduceRight: __arrayProto.reduceRight || function ( fn, init )
6868 {
6869 return _fnReduce( this, fn, init, this.length-1, -1, -1 );
6870 },
6871
6872
6873 reverse: __arrayProto.reverse,
6874
6875
6876 // Object with rows, columns and opts
6877 selector: null,
6878
6879
6880 shift: __arrayProto.shift,
6881
6882
6883 sort: __arrayProto.sort, // ? name - order?
6884
6885
6886 splice: __arrayProto.splice,
6887
6888
6889 toArray: function ()
6890 {
6891 return __arrayProto.slice.call( this );
6892 },
6893
6894
6895 to$: function ()
6896 {
6897 return $( this );
6898 },
6899
6900
6901 toJQuery: function ()
6902 {
6903 return $( this );
6904 },
6905
6906
6907 unique: function ()
6908 {
6909 return new _Api( this.context, _unique(this) );
6910 },
6911
6912
6913 unshift: __arrayProto.unshift
6914 };
6915
6916
6917 _Api.extend = function ( scope, obj, ext )
6918 {
6919 // Only extend API instances and static properties of the API
6920 if ( ! obj || ( ! (obj instanceof _Api) && ! obj.__dt_wrapper ) ) {
6921 return;
6922 }
6923
6924 var
6925 i, ien,
6926 j, jen,
6927 struct, inner,
6928 methodScoping = function ( scope, fn, struc ) {
6929 return function () {
6930 var ret = fn.apply( scope, arguments );
6931
6932 // Method extension
6933 _Api.extend( ret, ret, struc.methodExt );
6934 return ret;
6935 };
6936 };
6937
6938 for ( i=0, ien=ext.length ; i<ien ; i++ ) {
6939 struct = ext[i];
6940
6941 // Value
6942 obj[ struct.name ] = typeof struct.val === 'function' ?
6943 methodScoping( scope, struct.val, struct ) :
6944 $.isPlainObject( struct.val ) ?
6945 {} :
6946 struct.val;
6947
6948 obj[ struct.name ].__dt_wrapper = true;
6949
6950 // Property extension
6951 _Api.extend( scope, obj[ struct.name ], struct.propExt );
6952 }
6953 };
6954
6955
6956 // @todo - Is there need for an augment function?
6957 // _Api.augment = function ( inst, name )
6958 // {
6959 // // Find src object in the structure from the name
6960 // var parts = name.split('.');
6961
6962 // _Api.extend( inst, obj );
6963 // };
6964
6965
6966 // [
6967 // {
6968 // name: 'data' -- string - Property name
6969 // val: function () {}, -- function - Api method (or undefined if just an object
6970 // methodExt: [ ... ], -- array - Array of Api object definitions to extend the method result
6971 // propExt: [ ... ] -- array - Array of Api object definitions to extend the property
6972 // },
6973 // {
6974 // name: 'row'
6975 // val: {},
6976 // methodExt: [ ... ],
6977 // propExt: [
6978 // {
6979 // name: 'data'
6980 // val: function () {},
6981 // methodExt: [ ... ],
6982 // propExt: [ ... ]
6983 // },
6984 // ...
6985 // ]
6986 // }
6987 // ]
6988
6989 _Api.register = _api_register = function ( name, val )
6990 {
6991 if ( $.isArray( name ) ) {
6992 for ( var j=0, jen=name.length ; j<jen ; j++ ) {
6993 _Api.register( name[j], val );
6994 }
6995 return;
6996 }
6997
6998 var
6999 i, ien,
7000 heir = name.split('.'),
7001 struct = __apiStruct,
7002 key, method;
7003
7004 var find = function ( src, name ) {
7005 for ( var i=0, ien=src.length ; i<ien ; i++ ) {
7006 if ( src[i].name === name ) {
7007 return src[i];
7008 }
7009 }
7010 return null;
7011 };
7012
7013 for ( i=0, ien=heir.length ; i<ien ; i++ ) {
7014 method = heir[i].indexOf('()') !== -1;
7015 key = method ?
7016 heir[i].replace('()', '') :
7017 heir[i];
7018
7019 var src = find( struct, key );
7020 if ( ! src ) {
7021 src = {
7022 name: key,
7023 val: {},
7024 methodExt: [],
7025 propExt: []
7026 };
7027 struct.push( src );
7028 }
7029
7030 if ( i === ien-1 ) {
7031 src.val = val;
7032 }
7033 else {
7034 struct = method ?
7035 src.methodExt :
7036 src.propExt;
7037 }
7038 }
7039 };
7040
7041
7042 _Api.registerPlural = _api_registerPlural = function ( pluralName, singularName, val ) {
7043 _Api.register( pluralName, val );
7044
7045 _Api.register( singularName, function () {
7046 var ret = val.apply( this, arguments );
7047
7048 if ( ret === this ) {
7049 // Returned item is the API instance that was passed in, return it
7050 return this;
7051 }
7052 else if ( ret instanceof _Api ) {
7053 // New API instance returned, want the value from the first item
7054 // in the returned array for the singular result.
7055 return ret.length ?
7056 $.isArray( ret[0] ) ?
7057 new _Api( ret.context, ret[0] ) : // Array results are 'enhanced'
7058 ret[0] :
7059 undefined;
7060 }
7061
7062 // Non-API return - just fire it back
7063 return ret;
7064 } );
7065 };
7066
7067
7068 /**
7069 * Selector for HTML tables. Apply the given selector to the give array of
7070 * DataTables settings objects.
7071 *
7072 * @param {string|integer} [selector] jQuery selector string or integer
7073 * @param {array} Array of DataTables settings objects to be filtered
7074 * @return {array}
7075 * @ignore
7076 */
7077 var __table_selector = function ( selector, a )
7078 {
7079 // Integer is used to pick out a table by index
7080 if ( typeof selector === 'number' ) {
7081 return [ a[ selector ] ];
7082 }
7083
7084 // Perform a jQuery selector on the table nodes
7085 var nodes = $.map( a, function (el, i) {
7086 return el.nTable;
7087 } );
7088
7089 return $(nodes)
7090 .filter( selector )
7091 .map( function (i) {
7092 // Need to translate back from the table node to the settings
7093 var idx = $.inArray( this, nodes );
7094 return a[ idx ];
7095 } )
7096 .toArray();
7097 };
7098
7099
7100
7101 /**
7102 * Context selector for the API's context (i.e. the tables the API instance
7103 * refers to.
7104 *
7105 * @name DataTable.Api#tables
7106 * @param {string|integer} [selector] Selector to pick which tables the iterator
7107 * should operate on. If not given, all tables in the current context are
7108 * used. This can be given as a jQuery selector (for example `':gt(0)'`) to
7109 * select multiple tables or as an integer to select a single table.
7110 * @returns {DataTable.Api} Returns a new API instance if a selector is given.
7111 */
7112 _api_register( 'tables()', function ( selector ) {
7113 // A new instance is created if there was a selector specified
7114 return selector ?
7115 new _Api( __table_selector( selector, this.context ) ) :
7116 this;
7117 } );
7118
7119
7120 _api_register( 'table()', function ( selector ) {
7121 var tables = this.tables( selector );
7122 var ctx = tables.context;
7123
7124 // Truncate to the first matched table
7125 return ctx.length ?
7126 new _Api( ctx[0] ) :
7127 tables;
7128 } );
7129
7130
7131 _api_registerPlural( 'tables().nodes()', 'table().node()' , function () {
7132 return this.iterator( 'table', function ( ctx ) {
7133 return ctx.nTable;
7134 }, 1 );
7135 } );
7136
7137
7138 _api_registerPlural( 'tables().body()', 'table().body()' , function () {
7139 return this.iterator( 'table', function ( ctx ) {
7140 return ctx.nTBody;
7141 }, 1 );
7142 } );
7143
7144
7145 _api_registerPlural( 'tables().header()', 'table().header()' , function () {
7146 return this.iterator( 'table', function ( ctx ) {
7147 return ctx.nTHead;
7148 }, 1 );
7149 } );
7150
7151
7152 _api_registerPlural( 'tables().footer()', 'table().footer()' , function () {
7153 return this.iterator( 'table', function ( ctx ) {
7154 return ctx.nTFoot;
7155 }, 1 );
7156 } );
7157
7158
7159 _api_registerPlural( 'tables().containers()', 'table().container()' , function () {
7160 return this.iterator( 'table', function ( ctx ) {
7161 return ctx.nTableWrapper;
7162 }, 1 );
7163 } );
7164
7165
7166
7167 /**
7168 * Redraw the tables in the current context.
7169 *
7170 * @param {boolean} [reset=true] Reset (default) or hold the current paging
7171 * position. A full re-sort and re-filter is performed when this method is
7172 * called, which is why the pagination reset is the default action.
7173 * @returns {DataTables.Api} this
7174 */
7175 _api_register( 'draw()', function ( resetPaging ) {
7176 return this.iterator( 'table', function ( settings ) {
7177 _fnReDraw( settings, resetPaging===false );
7178 } );
7179 } );
7180
7181
7182
7183 /**
7184 * Get the current page index.
7185 *
7186 * @return {integer} Current page index (zero based)
7187 *//**
7188 * Set the current page.
7189 *
7190 * Note that if you attempt to show a page which does not exist, DataTables will
7191 * not throw an error, but rather reset the paging.
7192 *
7193 * @param {integer|string} action The paging action to take. This can be one of:
7194 * * `integer` - The page index to jump to
7195 * * `string` - An action to take:
7196 * * `first` - Jump to first page.
7197 * * `next` - Jump to the next page
7198 * * `previous` - Jump to previous page
7199 * * `last` - Jump to the last page.
7200 * @returns {DataTables.Api} this
7201 */
7202 _api_register( 'page()', function ( action ) {
7203 if ( action === undefined ) {
7204 return this.page.info().page; // not an expensive call
7205 }
7206
7207 // else, have an action to take on all tables
7208 return this.iterator( 'table', function ( settings ) {
7209 _fnPageChange( settings, action );
7210 } );
7211 } );
7212
7213
7214 /**
7215 * Paging information for the first table in the current context.
7216 *
7217 * If you require paging information for another table, use the `table()` method
7218 * with a suitable selector.
7219 *
7220 * @return {object} Object with the following properties set:
7221 * * `page` - Current page index (zero based - i.e. the first page is `0`)
7222 * * `pages` - Total number of pages
7223 * * `start` - Display index for the first record shown on the current page
7224 * * `end` - Display index for the last record shown on the current page
7225 * * `length` - Display length (number of records). Note that generally `start
7226 * + length = end`, but this is not always true, for example if there are
7227 * only 2 records to show on the final page, with a length of 10.
7228 * * `recordsTotal` - Full data set length
7229 * * `recordsDisplay` - Data set length once the current filtering criterion
7230 * are applied.
7231 */
7232 _api_register( 'page.info()', function ( action ) {
7233 if ( this.context.length === 0 ) {
7234 return undefined;
7235 }
7236
7237 var
7238 settings = this.context[0],
7239 start = settings._iDisplayStart,
7240 len = settings._iDisplayLength,
7241 visRecords = settings.fnRecordsDisplay(),
7242 all = len === -1;
7243
7244 return {
7245 "page": all ? 0 : Math.floor( start / len ),
7246 "pages": all ? 1 : Math.ceil( visRecords / len ),
7247 "start": start,
7248 "end": settings.fnDisplayEnd(),
7249 "length": len,
7250 "recordsTotal": settings.fnRecordsTotal(),
7251 "recordsDisplay": visRecords
7252 };
7253 } );
7254
7255
7256 /**
7257 * Get the current page length.
7258 *
7259 * @return {integer} Current page length. Note `-1` indicates that all records
7260 * are to be shown.
7261 *//**
7262 * Set the current page length.
7263 *
7264 * @param {integer} Page length to set. Use `-1` to show all records.
7265 * @returns {DataTables.Api} this
7266 */
7267 _api_register( 'page.len()', function ( len ) {
7268 // Note that we can't call this function 'length()' because `length`
7269 // is a Javascript property of functions which defines how many arguments
7270 // the function expects.
7271 if ( len === undefined ) {
7272 return this.context.length !== 0 ?
7273 this.context[0]._iDisplayLength :
7274 undefined;
7275 }
7276
7277 // else, set the page length
7278 return this.iterator( 'table', function ( settings ) {
7279 _fnLengthChange( settings, len );
7280 } );
7281 } );
7282
7283
7284
7285 var __reload = function ( settings, holdPosition, callback ) {
7286 if ( _fnDataSource( settings ) == 'ssp' ) {
7287 _fnReDraw( settings, holdPosition );
7288 }
7289 else {
7290 // Trigger xhr
7291 _fnProcessingDisplay( settings, true );
7292
7293 _fnBuildAjax( settings, [], function( json ) {
7294 _fnClearTable( settings );
7295
7296 var data = _fnAjaxDataSrc( settings, json );
7297 for ( var i=0, ien=data.length ; i<ien ; i++ ) {
7298 _fnAddData( settings, data[i] );
7299 }
7300
7301 _fnReDraw( settings, holdPosition );
7302 _fnProcessingDisplay( settings, false );
7303 } );
7304 }
7305
7306 // Use the draw event to trigger a callback, regardless of if it is an async
7307 // or sync draw
7308 if ( callback ) {
7309 var api = new _Api( settings );
7310
7311 api.one( 'draw', function () {
7312 callback( api.ajax.json() );
7313 } );
7314 }
7315 };
7316
7317
7318 /**
7319 * Get the JSON response from the last Ajax request that DataTables made to the
7320 * server. Note that this returns the JSON from the first table in the current
7321 * context.
7322 *
7323 * @return {object} JSON received from the server.
7324 */
7325 _api_register( 'ajax.json()', function () {
7326 var ctx = this.context;
7327
7328 if ( ctx.length > 0 ) {
7329 return ctx[0].json;
7330 }
7331
7332 // else return undefined;
7333 } );
7334
7335
7336 /**
7337 * Get the data submitted in the last Ajax request
7338 */
7339 _api_register( 'ajax.params()', function () {
7340 var ctx = this.context;
7341
7342 if ( ctx.length > 0 ) {
7343 return ctx[0].oAjaxData;
7344 }
7345
7346 // else return undefined;
7347 } );
7348
7349
7350 /**
7351 * Reload tables from the Ajax data source. Note that this function will
7352 * automatically re-draw the table when the remote data has been loaded.
7353 *
7354 * @param {boolean} [reset=true] Reset (default) or hold the current paging
7355 * position. A full re-sort and re-filter is performed when this method is
7356 * called, which is why the pagination reset is the default action.
7357 * @returns {DataTables.Api} this
7358 */
7359 _api_register( 'ajax.reload()', function ( callback, resetPaging ) {
7360 return this.iterator( 'table', function (settings) {
7361 __reload( settings, resetPaging===false, callback );
7362 } );
7363 } );
7364
7365
7366 /**
7367 * Get the current Ajax URL. Note that this returns the URL from the first
7368 * table in the current context.
7369 *
7370 * @return {string} Current Ajax source URL
7371 *//**
7372 * Set the Ajax URL. Note that this will set the URL for all tables in the
7373 * current context.
7374 *
7375 * @param {string} url URL to set.
7376 * @returns {DataTables.Api} this
7377 */
7378 _api_register( 'ajax.url()', function ( url ) {
7379 var ctx = this.context;
7380
7381 if ( url === undefined ) {
7382 // get
7383 if ( ctx.length === 0 ) {
7384 return undefined;
7385 }
7386 ctx = ctx[0];
7387
7388 return ctx.ajax ?
7389 $.isPlainObject( ctx.ajax ) ?
7390 ctx.ajax.url :
7391 ctx.ajax :
7392 ctx.sAjaxSource;
7393 }
7394
7395 // set
7396 return this.iterator( 'table', function ( settings ) {
7397 if ( $.isPlainObject( settings.ajax ) ) {
7398 settings.ajax.url = url;
7399 }
7400 else {
7401 settings.ajax = url;
7402 }
7403 // No need to consider sAjaxSource here since DataTables gives priority
7404 // to `ajax` over `sAjaxSource`. So setting `ajax` here, renders any
7405 // value of `sAjaxSource` redundant.
7406 } );
7407 } );
7408
7409
7410 /**
7411 * Load data from the newly set Ajax URL. Note that this method is only
7412 * available when `ajax.url()` is used to set a URL. Additionally, this method
7413 * has the same effect as calling `ajax.reload()` but is provided for
7414 * convenience when setting a new URL. Like `ajax.reload()` it will
7415 * automatically redraw the table once the remote data has been loaded.
7416 *
7417 * @returns {DataTables.Api} this
7418 */
7419 _api_register( 'ajax.url().load()', function ( callback, resetPaging ) {
7420 // Same as a reload, but makes sense to present it for easy access after a
7421 // url change
7422 return this.iterator( 'table', function ( ctx ) {
7423 __reload( ctx, resetPaging===false, callback );
7424 } );
7425 } );
7426
7427
7428
7429
7430 var _selector_run = function ( selector, select )
7431 {
7432 var
7433 out = [], res,
7434 a, i, ien, j, jen,
7435 selectorType = typeof selector;
7436
7437 // Can't just check for isArray here, as an API or jQuery instance might be
7438 // given with their array like look
7439 if ( ! selector || selectorType === 'string' || selectorType === 'function' || selector.length === undefined ) {
7440 selector = [ selector ];
7441 }
7442
7443 for ( i=0, ien=selector.length ; i<ien ; i++ ) {
7444 a = selector[i] && selector[i].split ?
7445 selector[i].split(',') :
7446 [ selector[i] ];
7447
7448 for ( j=0, jen=a.length ; j<jen ; j++ ) {
7449 res = select( typeof a[j] === 'string' ? $.trim(a[j]) : a[j] );
7450
7451 if ( res && res.length ) {
7452 out.push.apply( out, res );
7453 }
7454 }
7455 }
7456
7457 return out;
7458 };
7459
7460
7461 var _selector_opts = function ( opts )
7462 {
7463 if ( ! opts ) {
7464 opts = {};
7465 }
7466
7467 // Backwards compatibility for 1.9- which used the terminology filter rather
7468 // than search
7469 if ( opts.filter && ! opts.search ) {
7470 opts.search = opts.filter;
7471 }
7472
7473 return {
7474 search: opts.search || 'none',
7475 order: opts.order || 'current',
7476 page: opts.page || 'all'
7477 };
7478 };
7479
7480
7481 var _selector_first = function ( inst )
7482 {
7483 // Reduce the API instance to the first item found
7484 for ( var i=0, ien=inst.length ; i<ien ; i++ ) {
7485 if ( inst[i].length > 0 ) {
7486 // Assign the first element to the first item in the instance
7487 // and truncate the instance and context
7488 inst[0] = inst[i];
7489 inst.length = 1;
7490 inst.context = [ inst.context[i] ];
7491
7492 return inst;
7493 }
7494 }
7495
7496 // Not found - return an empty instance
7497 inst.length = 0;
7498 return inst;
7499 };
7500
7501
7502 var _selector_row_indexes = function ( settings, opts )
7503 {
7504 var
7505 i, ien, tmp, a=[],
7506 displayFiltered = settings.aiDisplay,
7507 displayMaster = settings.aiDisplayMaster;
7508
7509 var
7510 search = opts.search, // none, applied, removed
7511 order = opts.order, // applied, current, index (original - compatibility with 1.9)
7512 page = opts.page; // all, current
7513
7514 if ( _fnDataSource( settings ) == 'ssp' ) {
7515 // In server-side processing mode, most options are irrelevant since
7516 // rows not shown don't exist and the index order is the applied order
7517 // Removed is a special case - for consistency just return an empty
7518 // array
7519 return search === 'removed' ?
7520 [] :
7521 _range( 0, displayMaster.length );
7522 }
7523 else if ( page == 'current' ) {
7524 // Current page implies that order=current and fitler=applied, since it is
7525 // fairly senseless otherwise, regardless of what order and search actually
7526 // are
7527 for ( i=settings._iDisplayStart, ien=settings.fnDisplayEnd() ; i<ien ; i++ ) {
7528 a.push( displayFiltered[i] );
7529 }
7530 }
7531 else if ( order == 'current' || order == 'applied' ) {
7532 a = search == 'none' ?
7533 displayMaster.slice() : // no search
7534 search == 'applied' ?
7535 displayFiltered.slice() : // applied search
7536 $.map( displayMaster, function (el, i) { // removed search
7537 return $.inArray( el, displayFiltered ) === -1 ? el : null;
7538 } );
7539 }
7540 else if ( order == 'index' || order == 'original' ) {
7541 for ( i=0, ien=settings.aoData.length ; i<ien ; i++ ) {
7542 if ( search == 'none' ) {
7543 a.push( i );
7544 }
7545 else { // applied | removed
7546 tmp = $.inArray( i, displayFiltered );
7547
7548 if ((tmp === -1 && search == 'removed') ||
7549 (tmp >= 0 && search == 'applied') )
7550 {
7551 a.push( i );
7552 }
7553 }
7554 }
7555 }
7556
7557 return a;
7558 };
7559
7560
7561 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
7562 * Rows
7563 *
7564 * {} - no selector - use all available rows
7565 * {integer} - row aoData index
7566 * {node} - TR node
7567 * {string} - jQuery selector to apply to the TR elements
7568 * {array} - jQuery array of nodes, or simply an array of TR nodes
7569 *
7570 */
7571
7572
7573 var __row_selector = function ( settings, selector, opts )
7574 {
7575 return _selector_run( selector, function ( sel ) {
7576 var selInt = _intVal( sel );
7577 var i, ien;
7578
7579 // Short cut - selector is a number and no options provided (default is
7580 // all records, so no need to check if the index is in there, since it
7581 // must be - dev error if the index doesn't exist).
7582 if ( selInt !== null && ! opts ) {
7583 return [ selInt ];
7584 }
7585
7586 var rows = _selector_row_indexes( settings, opts );
7587
7588 if ( selInt !== null && $.inArray( selInt, rows ) !== -1 ) {
7589 // Selector - integer
7590 return [ selInt ];
7591 }
7592 else if ( ! sel ) {
7593 // Selector - none
7594 return rows;
7595 }
7596
7597 // Selector - function
7598 if ( typeof sel === 'function' ) {
7599 return $.map( rows, function (idx) {
7600 var row = settings.aoData[ idx ];
7601 return sel( idx, row._aData, row.nTr ) ? idx : null;
7602 } );
7603 }
7604
7605 // Get nodes in the order from the `rows` array with null values removed
7606 var nodes = _removeEmpty(
7607 _pluck_order( settings.aoData, rows, 'nTr' )
7608 );
7609
7610 // Selector - node
7611 if ( sel.nodeName ) {
7612 if ( $.inArray( sel, nodes ) !== -1 ) {
7613 return [ sel._DT_RowIndex ]; // sel is a TR node that is in the table
7614 // and DataTables adds a prop for fast lookup
7615 }
7616 }
7617
7618 // Selector - jQuery selector string, array of nodes or jQuery object/
7619 // As jQuery's .filter() allows jQuery objects to be passed in filter,
7620 // it also allows arrays, so this will cope with all three options
7621 return $(nodes)
7622 .filter( sel )
7623 .map( function () {
7624 return this._DT_RowIndex;
7625 } )
7626 .toArray();
7627 } );
7628 };
7629
7630
7631 /**
7632 *
7633 */
7634 _api_register( 'rows()', function ( selector, opts ) {
7635 // argument shifting
7636 if ( selector === undefined ) {
7637 selector = '';
7638 }
7639 else if ( $.isPlainObject( selector ) ) {
7640 opts = selector;
7641 selector = '';
7642 }
7643
7644 opts = _selector_opts( opts );
7645
7646 var inst = this.iterator( 'table', function ( settings ) {
7647 return __row_selector( settings, selector, opts );
7648 }, 1 );
7649
7650 // Want argument shifting here and in __row_selector?
7651 inst.selector.rows = selector;
7652 inst.selector.opts = opts;
7653
7654 return inst;
7655 } );
7656
7657
7658 _api_register( 'rows().nodes()', function () {
7659 return this.iterator( 'row', function ( settings, row ) {
7660 return settings.aoData[ row ].nTr || undefined;
7661 }, 1 );
7662 } );
7663
7664 _api_register( 'rows().data()', function () {
7665 return this.iterator( true, 'rows', function ( settings, rows ) {
7666 return _pluck_order( settings.aoData, rows, '_aData' );
7667 }, 1 );
7668 } );
7669
7670 _api_registerPlural( 'rows().cache()', 'row().cache()', function ( type ) {
7671 return this.iterator( 'row', function ( settings, row ) {
7672 var r = settings.aoData[ row ];
7673 return type === 'search' ? r._aFilterData : r._aSortData;
7674 }, 1 );
7675 } );
7676
7677 _api_registerPlural( 'rows().invalidate()', 'row().invalidate()', function ( src ) {
7678 return this.iterator( 'row', function ( settings, row ) {
7679 _fnInvalidate( settings, row, src );
7680 } );
7681 } );
7682
7683 _api_registerPlural( 'rows().indexes()', 'row().index()', function () {
7684 return this.iterator( 'row', function ( settings, row ) {
7685 return row;
7686 }, 1 );
7687 } );
7688
7689 _api_registerPlural( 'rows().remove()', 'row().remove()', function () {
7690 var that = this;
7691
7692 return this.iterator( 'row', function ( settings, row, thatIdx ) {
7693 var data = settings.aoData;
7694
7695 data.splice( row, 1 );
7696
7697 // Update the _DT_RowIndex parameter on all rows in the table
7698 for ( var i=0, ien=data.length ; i<ien ; i++ ) {
7699 if ( data[i].nTr !== null ) {
7700 data[i].nTr._DT_RowIndex = i;
7701 }
7702 }
7703
7704 // Remove the target row from the search array
7705 var displayIndex = $.inArray( row, settings.aiDisplay );
7706
7707 // Delete from the display arrays
7708 _fnDeleteIndex( settings.aiDisplayMaster, row );
7709 _fnDeleteIndex( settings.aiDisplay, row );
7710 _fnDeleteIndex( that[ thatIdx ], row, false ); // maintain local indexes
7711
7712 // Check for an 'overflow' they case for displaying the table
7713 _fnLengthOverflow( settings );
7714 } );
7715 } );
7716
7717
7718 _api_register( 'rows.add()', function ( rows ) {
7719 var newRows = this.iterator( 'table', function ( settings ) {
7720 var row, i, ien;
7721 var out = [];
7722
7723 for ( i=0, ien=rows.length ; i<ien ; i++ ) {
7724 row = rows[i];
7725
7726 if ( row.nodeName && row.nodeName.toUpperCase() === 'TR' ) {
7727 out.push( _fnAddTr( settings, row )[0] );
7728 }
7729 else {
7730 out.push( _fnAddData( settings, row ) );
7731 }
7732 }
7733
7734 return out;
7735 }, 1 );
7736
7737 // Return an Api.rows() extended instance, so rows().nodes() etc can be used
7738 var modRows = this.rows( -1 );
7739 modRows.pop();
7740 modRows.push.apply( modRows, newRows.toArray() );
7741
7742 return modRows;
7743 } );
7744
7745
7746
7747
7748
7749 /**
7750 *
7751 */
7752 _api_register( 'row()', function ( selector, opts ) {
7753 return _selector_first( this.rows( selector, opts ) );
7754 } );
7755
7756
7757 _api_register( 'row().data()', function ( data ) {
7758 var ctx = this.context;
7759
7760 if ( data === undefined ) {
7761 // Get
7762 return ctx.length && this.length ?
7763 ctx[0].aoData[ this[0] ]._aData :
7764 undefined;
7765 }
7766
7767 // Set
7768 ctx[0].aoData[ this[0] ]._aData = data;
7769
7770 // Automatically invalidate
7771 _fnInvalidate( ctx[0], this[0], 'data' );
7772
7773 return this;
7774 } );
7775
7776
7777 _api_register( 'row().node()', function () {
7778 var ctx = this.context;
7779
7780 return ctx.length && this.length ?
7781 ctx[0].aoData[ this[0] ].nTr || null :
7782 null;
7783 } );
7784
7785
7786 _api_register( 'row.add()', function ( row ) {
7787 // Allow a jQuery object to be passed in - only a single row is added from
7788 // it though - the first element in the set
7789 if ( row instanceof $ && row.length ) {
7790 row = row[0];
7791 }
7792
7793 var rows = this.iterator( 'table', function ( settings ) {
7794 if ( row.nodeName && row.nodeName.toUpperCase() === 'TR' ) {
7795 return _fnAddTr( settings, row )[0];
7796 }
7797 return _fnAddData( settings, row );
7798 } );
7799
7800 // Return an Api.rows() extended instance, with the newly added row selected
7801 return this.row( rows[0] );
7802 } );
7803
7804
7805
7806 var __details_add = function ( ctx, row, data, klass )
7807 {
7808 // Convert to array of TR elements
7809 var rows = [];
7810 var addRow = function ( r, k ) {
7811 // If we get a TR element, then just add it directly - up to the dev
7812 // to add the correct number of columns etc
7813 if ( r.nodeName && r.nodeName.toLowerCase() === 'tr' ) {
7814 rows.push( r );
7815 }
7816 else {
7817 // Otherwise create a row with a wrapper
7818 var created = $('<tr><td/></tr>').addClass( k );
7819 $('td', created)
7820 .addClass( k )
7821 .html( r )
7822 [0].colSpan = _fnVisbleColumns( ctx );
7823
7824 rows.push( created[0] );
7825 }
7826 };
7827
7828 if ( $.isArray( data ) || data instanceof $ ) {
7829 for ( var i=0, ien=data.length ; i<ien ; i++ ) {
7830 addRow( data[i], klass );
7831 }
7832 }
7833 else {
7834 addRow( data, klass );
7835 }
7836
7837 if ( row._details ) {
7838 row._details.remove();
7839 }
7840
7841 row._details = $(rows);
7842
7843 // If the children were already shown, that state should be retained
7844 if ( row._detailsShow ) {
7845 row._details.insertAfter( row.nTr );
7846 }
7847 };
7848
7849
7850 var __details_remove = function ( api, idx )
7851 {
7852 var ctx = api.context;
7853
7854 if ( ctx.length ) {
7855 var row = ctx[0].aoData[ idx !== undefined ? idx : api[0] ];
7856
7857 if ( row._details ) {
7858 row._details.remove();
7859
7860 row._detailsShow = undefined;
7861 row._details = undefined;
7862 }
7863 }
7864 };
7865
7866
7867 var __details_display = function ( api, show ) {
7868 var ctx = api.context;
7869
7870 if ( ctx.length && api.length ) {
7871 var row = ctx[0].aoData[ api[0] ];
7872
7873 if ( row._details ) {
7874 row._detailsShow = show;
7875
7876 if ( show ) {
7877 row._details.insertAfter( row.nTr );
7878 }
7879 else {
7880 row._details.detach();
7881 }
7882
7883 __details_events( ctx[0] );
7884 }
7885 }
7886 };
7887
7888
7889 var __details_events = function ( settings )
7890 {
7891 var api = new _Api( settings );
7892 var namespace = '.dt.DT_details';
7893 var drawEvent = 'draw'+namespace;
7894 var colvisEvent = 'column-visibility'+namespace;
7895 var destroyEvent = 'destroy'+namespace;
7896 var data = settings.aoData;
7897
7898 api.off( drawEvent +' '+ colvisEvent +' '+ destroyEvent );
7899
7900 if ( _pluck( data, '_details' ).length > 0 ) {
7901 // On each draw, insert the required elements into the document
7902 api.on( drawEvent, function ( e, ctx ) {
7903 if ( settings !== ctx ) {
7904 return;
7905 }
7906
7907 api.rows( {page:'current'} ).eq(0).each( function (idx) {
7908 // Internal data grab
7909 var row = data[ idx ];
7910
7911 if ( row._detailsShow ) {
7912 row._details.insertAfter( row.nTr );
7913 }
7914 } );
7915 } );
7916
7917 // Column visibility change - update the colspan
7918 api.on( colvisEvent, function ( e, ctx, idx, vis ) {
7919 if ( settings !== ctx ) {
7920 return;
7921 }
7922
7923 // Update the colspan for the details rows (note, only if it already has
7924 // a colspan)
7925 var row, visible = _fnVisbleColumns( ctx );
7926
7927 for ( var i=0, ien=data.length ; i<ien ; i++ ) {
7928 row = data[i];
7929
7930 if ( row._details ) {
7931 row._details.children('td[colspan]').attr('colspan', visible );
7932 }
7933 }
7934 } );
7935
7936 // Table destroyed - nuke any child rows
7937 api.on( destroyEvent, function ( e, ctx ) {
7938 if ( settings !== ctx ) {
7939 return;
7940 }
7941
7942 for ( var i=0, ien=data.length ; i<ien ; i++ ) {
7943 if ( data[i]._details ) {
7944 __details_remove( api, i );
7945 }
7946 }
7947 } );
7948 }
7949 };
7950
7951 // Strings for the method names to help minification
7952 var _emp = '';
7953 var _child_obj = _emp+'row().child';
7954 var _child_mth = _child_obj+'()';
7955
7956 // data can be:
7957 // tr
7958 // string
7959 // jQuery or array of any of the above
7960 _api_register( _child_mth, function ( data, klass ) {
7961 var ctx = this.context;
7962
7963 if ( data === undefined ) {
7964 // get
7965 return ctx.length && this.length ?
7966 ctx[0].aoData[ this[0] ]._details :
7967 undefined;
7968 }
7969 else if ( data === true ) {
7970 // show
7971 this.child.show();
7972 }
7973 else if ( data === false ) {
7974 // remove
7975 __details_remove( this );
7976 }
7977 else if ( ctx.length && this.length ) {
7978 // set
7979 __details_add( ctx[0], ctx[0].aoData[ this[0] ], data, klass );
7980 }
7981
7982 return this;
7983 } );
7984
7985
7986 _api_register( [
7987 _child_obj+'.show()',
7988 _child_mth+'.show()' // only when `child()` was called with parameters (without
7989 ], function ( show ) { // it returns an object and this method is not executed)
7990 __details_display( this, true );
7991 return this;
7992 } );
7993
7994
7995 _api_register( [
7996 _child_obj+'.hide()',
7997 _child_mth+'.hide()' // only when `child()` was called with parameters (without
7998 ], function () { // it returns an object and this method is not executed)
7999 __details_display( this, false );
8000 return this;
8001 } );
8002
8003
8004 _api_register( [
8005 _child_obj+'.remove()',
8006 _child_mth+'.remove()' // only when `child()` was called with parameters (without
8007 ], function () { // it returns an object and this method is not executed)
8008 __details_remove( this );
8009 return this;
8010 } );
8011
8012
8013 _api_register( _child_obj+'.isShown()', function () {
8014 var ctx = this.context;
8015
8016 if ( ctx.length && this.length ) {
8017 // _detailsShown as false or undefined will fall through to return false
8018 return ctx[0].aoData[ this[0] ]._detailsShow || false;
8019 }
8020 return false;
8021 } );
8022
8023
8024
8025 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
8026 * Columns
8027 *
8028 * {integer} - column index (>=0 count from left, <0 count from right)
8029 * "{integer}:visIdx" - visible column index (i.e. translate to column index) (>=0 count from left, <0 count from right)
8030 * "{integer}:visible" - alias for {integer}:visIdx (>=0 count from left, <0 count from right)
8031 * "{string}:name" - column name
8032 * "{string}" - jQuery selector on column header nodes
8033 *
8034 */
8035
8036 // can be an array of these items, comma separated list, or an array of comma
8037 // separated lists
8038
8039 var __re_column_selector = /^(.+):(name|visIdx|visible)$/;
8040
8041
8042 // r1 and r2 are redundant - but it means that the parameters match for the
8043 // iterator callback in columns().data()
8044 var __columnData = function ( settings, column, r1, r2, rows ) {
8045 var a = [];
8046 for ( var row=0, ien=rows.length ; row<ien ; row++ ) {
8047 a.push( _fnGetCellData( settings, rows[row], column ) );
8048 }
8049 return a;
8050 };
8051
8052
8053 var __column_selector = function ( settings, selector, opts )
8054 {
8055 var
8056 columns = settings.aoColumns,
8057 names = _pluck( columns, 'sName' ),
8058 nodes = _pluck( columns, 'nTh' );
8059
8060 return _selector_run( selector, function ( s ) {
8061 var selInt = _intVal( s );
8062
8063 // Selector - all
8064 if ( s === '' ) {
8065 return _range( columns.length );
8066 }
8067
8068 // Selector - index
8069 if ( selInt !== null ) {
8070 return [ selInt >= 0 ?
8071 selInt : // Count from left
8072 columns.length + selInt // Count from right (+ because its a negative value)
8073 ];
8074 }
8075
8076 // Selector = function
8077 if ( typeof s === 'function' ) {
8078 var rows = _selector_row_indexes( settings, opts );
8079
8080 return $.map( columns, function (col, idx) {
8081 return s(
8082 idx,
8083 __columnData( settings, idx, 0, 0, rows ),
8084 nodes[ idx ]
8085 ) ? idx : null;
8086 } );
8087 }
8088
8089 // jQuery or string selector
8090 var match = typeof s === 'string' ?
8091 s.match( __re_column_selector ) :
8092 '';
8093
8094 if ( match ) {
8095 switch( match[2] ) {
8096 case 'visIdx':
8097 case 'visible':
8098 var idx = parseInt( match[1], 10 );
8099 // Visible index given, convert to column index
8100 if ( idx < 0 ) {
8101 // Counting from the right
8102 var visColumns = $.map( columns, function (col,i) {
8103 return col.bVisible ? i : null;
8104 } );
8105 return [ visColumns[ visColumns.length + idx ] ];
8106 }
8107 // Counting from the left
8108 return [ _fnVisibleToColumnIndex( settings, idx ) ];
8109
8110 case 'name':
8111 // match by name. `names` is column index complete and in order
8112 return $.map( names, function (name, i) {
8113 return name === match[1] ? i : null;
8114 } );
8115 }
8116 }
8117 else {
8118 // jQuery selector on the TH elements for the columns
8119 return $( nodes )
8120 .filter( s )
8121 .map( function () {
8122 return $.inArray( this, nodes ); // `nodes` is column index complete and in order
8123 } )
8124 .toArray();
8125 }
8126 } );
8127 };
8128
8129
8130 var __setColumnVis = function ( settings, column, vis, recalc ) {
8131 var
8132 cols = settings.aoColumns,
8133 col = cols[ column ],
8134 data = settings.aoData,
8135 row, cells, i, ien, tr;
8136
8137 // Get
8138 if ( vis === undefined ) {
8139 return col.bVisible;
8140 }
8141
8142 // Set
8143 // No change
8144 if ( col.bVisible === vis ) {
8145 return;
8146 }
8147
8148 if ( vis ) {
8149 // Insert column
8150 // Need to decide if we should use appendChild or insertBefore
8151 var insertBefore = $.inArray( true, _pluck(cols, 'bVisible'), column+1 );
8152
8153 for ( i=0, ien=data.length ; i<ien ; i++ ) {
8154 tr = data[i].nTr;
8155 cells = data[i].anCells;
8156
8157 if ( tr ) {
8158 // insertBefore can act like appendChild if 2nd arg is null
8159 tr.insertBefore( cells[ column ], cells[ insertBefore ] || null );
8160 }
8161 }
8162 }
8163 else {
8164 // Remove column
8165 $( _pluck( settings.aoData, 'anCells', column ) ).detach();
8166 }
8167
8168 // Common actions
8169 col.bVisible = vis;
8170 _fnDrawHead( settings, settings.aoHeader );
8171 _fnDrawHead( settings, settings.aoFooter );
8172
8173 if ( recalc === undefined || recalc ) {
8174 // Automatically adjust column sizing
8175 _fnAdjustColumnSizing( settings );
8176
8177 // Realign columns for scrolling
8178 if ( settings.oScroll.sX || settings.oScroll.sY ) {
8179 _fnScrollDraw( settings );
8180 }
8181 }
8182
8183 _fnCallbackFire( settings, null, 'column-visibility', [settings, column, vis] );
8184
8185 _fnSaveState( settings );
8186 };
8187
8188
8189 /**
8190 *
8191 */
8192 _api_register( 'columns()', function ( selector, opts ) {
8193 // argument shifting
8194 if ( selector === undefined ) {
8195 selector = '';
8196 }
8197 else if ( $.isPlainObject( selector ) ) {
8198 opts = selector;
8199 selector = '';
8200 }
8201
8202 opts = _selector_opts( opts );
8203
8204 var inst = this.iterator( 'table', function ( settings ) {
8205 return __column_selector( settings, selector, opts );
8206 }, 1 );
8207
8208 // Want argument shifting here and in _row_selector?
8209 inst.selector.cols = selector;
8210 inst.selector.opts = opts;
8211
8212 return inst;
8213 } );
8214
8215
8216 /**
8217 *
8218 */
8219 _api_registerPlural( 'columns().header()', 'column().header()', function ( selector, opts ) {
8220 return this.iterator( 'column', function ( settings, column ) {
8221 return settings.aoColumns[column].nTh;
8222 }, 1 );
8223 } );
8224
8225
8226 /**
8227 *
8228 */
8229 _api_registerPlural( 'columns().footer()', 'column().footer()', function ( selector, opts ) {
8230 return this.iterator( 'column', function ( settings, column ) {
8231 return settings.aoColumns[column].nTf;
8232 }, 1 );
8233 } );
8234
8235
8236 /**
8237 *
8238 */
8239 _api_registerPlural( 'columns().data()', 'column().data()', function () {
8240 return this.iterator( 'column-rows', __columnData, 1 );
8241 } );
8242
8243
8244 _api_registerPlural( 'columns().dataSrc()', 'column().dataSrc()', function () {
8245 return this.iterator( 'column', function ( settings, column ) {
8246 return settings.aoColumns[column].mData;
8247 }, 1 );
8248 } );
8249
8250
8251 _api_registerPlural( 'columns().cache()', 'column().cache()', function ( type ) {
8252 return this.iterator( 'column-rows', function ( settings, column, i, j, rows ) {
8253 return _pluck_order( settings.aoData, rows,
8254 type === 'search' ? '_aFilterData' : '_aSortData', column
8255 );
8256 }, 1 );
8257 } );
8258
8259
8260 _api_registerPlural( 'columns().nodes()', 'column().nodes()', function () {
8261 return this.iterator( 'column-rows', function ( settings, column, i, j, rows ) {
8262 return _pluck_order( settings.aoData, rows, 'anCells', column ) ;
8263 }, 1 );
8264 } );
8265
8266
8267
8268 _api_registerPlural( 'columns().visible()', 'column().visible()', function ( vis, calc ) {
8269 return this.iterator( 'column', function ( settings, column ) {
8270 if ( vis === undefined ) {
8271 return settings.aoColumns[ column ].bVisible;
8272 } // else
8273 __setColumnVis( settings, column, vis, calc );
8274 } );
8275 } );
8276
8277
8278
8279 _api_registerPlural( 'columns().indexes()', 'column().index()', function ( type ) {
8280 return this.iterator( 'column', function ( settings, column ) {
8281 return type === 'visible' ?
8282 _fnColumnIndexToVisible( settings, column ) :
8283 column;
8284 }, 1 );
8285 } );
8286
8287
8288 // _api_register( 'columns().show()', function () {
8289 // var selector = this.selector;
8290 // return this.columns( selector.cols, selector.opts ).visible( true );
8291 // } );
8292
8293
8294 // _api_register( 'columns().hide()', function () {
8295 // var selector = this.selector;
8296 // return this.columns( selector.cols, selector.opts ).visible( false );
8297 // } );
8298
8299
8300
8301 _api_register( 'columns.adjust()', function () {
8302 return this.iterator( 'table', function ( settings ) {
8303 _fnAdjustColumnSizing( settings );
8304 }, 1 );
8305 } );
8306
8307
8308 // Convert from one column index type, to another type
8309 _api_register( 'column.index()', function ( type, idx ) {
8310 if ( this.context.length !== 0 ) {
8311 var ctx = this.context[0];
8312
8313 if ( type === 'fromVisible' || type === 'toData' ) {
8314 return _fnVisibleToColumnIndex( ctx, idx );
8315 }
8316 else if ( type === 'fromData' || type === 'toVisible' ) {
8317 return _fnColumnIndexToVisible( ctx, idx );
8318 }
8319 }
8320 } );
8321
8322
8323 _api_register( 'column()', function ( selector, opts ) {
8324 return _selector_first( this.columns( selector, opts ) );
8325 } );
8326
8327
8328
8329
8330 var __cell_selector = function ( settings, selector, opts )
8331 {
8332 var data = settings.aoData;
8333 var rows = _selector_row_indexes( settings, opts );
8334 var cells = _removeEmpty( _pluck_order( data, rows, 'anCells' ) );
8335 var allCells = $( [].concat.apply([], cells) );
8336 var row;
8337 var columns = settings.aoColumns.length;
8338 var a, i, ien, j, o, host;
8339
8340 return _selector_run( selector, function ( s ) {
8341 var fnSelector = typeof s === 'function';
8342
8343 if ( s === null || s === undefined || fnSelector ) {
8344 // All cells and function selectors
8345 a = [];
8346
8347 for ( i=0, ien=rows.length ; i<ien ; i++ ) {
8348 row = rows[i];
8349
8350 for ( j=0 ; j<columns ; j++ ) {
8351 o = {
8352 row: row,
8353 column: j
8354 };
8355
8356 if ( fnSelector ) {
8357 // Selector - function
8358 host = settings.aoData[ row ];
8359
8360 if ( s( o, _fnGetCellData(settings, row, j), host.anCells[j] ) ) {
8361 a.push( o );
8362 }
8363 }
8364 else {
8365 // Selector - all
8366 a.push( o );
8367 }
8368 }
8369 }
8370
8371 return a;
8372 }
8373
8374 // Selector - index
8375 if ( $.isPlainObject( s ) ) {
8376 return [s];
8377 }
8378
8379 // Selector - jQuery filtered cells
8380 return allCells
8381 .filter( s )
8382 .map( function (i, el) {
8383 row = el.parentNode._DT_RowIndex;
8384
8385 return {
8386 row: row,
8387 column: $.inArray( el, data[ row ].anCells )
8388 };
8389 } )
8390 .toArray();
8391 } );
8392 };
8393
8394
8395
8396
8397 _api_register( 'cells()', function ( rowSelector, columnSelector, opts ) {
8398 // Argument shifting
8399 if ( $.isPlainObject( rowSelector ) ) {
8400 // Indexes
8401 if ( typeof rowSelector.row !== undefined ) {
8402 opts = columnSelector;
8403 columnSelector = null;
8404 }
8405 else {
8406 opts = rowSelector;
8407 rowSelector = null;
8408 }
8409 }
8410 if ( $.isPlainObject( columnSelector ) ) {
8411 opts = columnSelector;
8412 columnSelector = null;
8413 }
8414
8415 // Cell selector
8416 if ( columnSelector === null || columnSelector === undefined ) {
8417 return this.iterator( 'table', function ( settings ) {
8418 return __cell_selector( settings, rowSelector, _selector_opts( opts ) );
8419 } );
8420 }
8421
8422 // Row + column selector
8423 var columns = this.columns( columnSelector, opts );
8424 var rows = this.rows( rowSelector, opts );
8425 var a, i, ien, j, jen;
8426
8427 var cells = this.iterator( 'table', function ( settings, idx ) {
8428 a = [];
8429
8430 for ( i=0, ien=rows[idx].length ; i<ien ; i++ ) {
8431 for ( j=0, jen=columns[idx].length ; j<jen ; j++ ) {
8432 a.push( {
8433 row: rows[idx][i],
8434 column: columns[idx][j]
8435 } );
8436 }
8437 }
8438
8439 return a;
8440 }, 1 );
8441
8442 $.extend( cells.selector, {
8443 cols: columnSelector,
8444 rows: rowSelector,
8445 opts: opts
8446 } );
8447
8448 return cells;
8449 } );
8450
8451
8452 _api_registerPlural( 'cells().nodes()', 'cell().node()', function () {
8453 return this.iterator( 'cell', function ( settings, row, column ) {
8454 var cells = settings.aoData[ row ].anCells;
8455 return cells ?
8456 cells[ column ] :
8457 undefined;
8458 }, 1 );
8459 } );
8460
8461
8462 _api_register( 'cells().data()', function () {
8463 return this.iterator( 'cell', function ( settings, row, column ) {
8464 return _fnGetCellData( settings, row, column );
8465 }, 1 );
8466 } );
8467
8468
8469 _api_registerPlural( 'cells().cache()', 'cell().cache()', function ( type ) {
8470 type = type === 'search' ? '_aFilterData' : '_aSortData';
8471
8472 return this.iterator( 'cell', function ( settings, row, column ) {
8473 return settings.aoData[ row ][ type ][ column ];
8474 }, 1 );
8475 } );
8476
8477
8478 _api_registerPlural( 'cells().render()', 'cell().render()', function ( type ) {
8479 return this.iterator( 'cell', function ( settings, row, column ) {
8480 return _fnGetCellData( settings, row, column, type );
8481 }, 1 );
8482 } );
8483
8484
8485 _api_registerPlural( 'cells().indexes()', 'cell().index()', function () {
8486 return this.iterator( 'cell', function ( settings, row, column ) {
8487 return {
8488 row: row,
8489 column: column,
8490 columnVisible: _fnColumnIndexToVisible( settings, column )
8491 };
8492 }, 1 );
8493 } );
8494
8495
8496 _api_registerPlural( 'cells().invalidate()', 'cell().invalidate()', function ( src ) {
8497 return this.iterator( 'cell', function ( settings, row, column ) {
8498 _fnInvalidate( settings, row, src, column );
8499 } );
8500 } );
8501
8502
8503
8504 _api_register( 'cell()', function ( rowSelector, columnSelector, opts ) {
8505 return _selector_first( this.cells( rowSelector, columnSelector, opts ) );
8506 } );
8507
8508
8509 _api_register( 'cell().data()', function ( data ) {
8510 var ctx = this.context;
8511 var cell = this[0];
8512
8513 if ( data === undefined ) {
8514 // Get
8515 return ctx.length && cell.length ?
8516 _fnGetCellData( ctx[0], cell[0].row, cell[0].column ) :
8517 undefined;
8518 }
8519
8520 // Set
8521 _fnSetCellData( ctx[0], cell[0].row, cell[0].column, data );
8522 _fnInvalidate( ctx[0], cell[0].row, 'data', cell[0].column );
8523
8524 return this;
8525 } );
8526
8527
8528
8529 /**
8530 * Get current ordering (sorting) that has been applied to the table.
8531 *
8532 * @returns {array} 2D array containing the sorting information for the first
8533 * table in the current context. Each element in the parent array represents
8534 * a column being sorted upon (i.e. multi-sorting with two columns would have
8535 * 2 inner arrays). The inner arrays may have 2 or 3 elements. The first is
8536 * the column index that the sorting condition applies to, the second is the
8537 * direction of the sort (`desc` or `asc`) and, optionally, the third is the
8538 * index of the sorting order from the `column.sorting` initialisation array.
8539 *//**
8540 * Set the ordering for the table.
8541 *
8542 * @param {integer} order Column index to sort upon.
8543 * @param {string} direction Direction of the sort to be applied (`asc` or `desc`)
8544 * @returns {DataTables.Api} this
8545 *//**
8546 * Set the ordering for the table.
8547 *
8548 * @param {array} order 1D array of sorting information to be applied.
8549 * @param {array} [...] Optional additional sorting conditions
8550 * @returns {DataTables.Api} this
8551 *//**
8552 * Set the ordering for the table.
8553 *
8554 * @param {array} order 2D array of sorting information to be applied.
8555 * @returns {DataTables.Api} this
8556 */
8557 _api_register( 'order()', function ( order, dir ) {
8558 var ctx = this.context;
8559
8560 if ( order === undefined ) {
8561 // get
8562 return ctx.length !== 0 ?
8563 ctx[0].aaSorting :
8564 undefined;
8565 }
8566
8567 // set
8568 if ( typeof order === 'number' ) {
8569 // Simple column / direction passed in
8570 order = [ [ order, dir ] ];
8571 }
8572 else if ( ! $.isArray( order[0] ) ) {
8573 // Arguments passed in (list of 1D arrays)
8574 order = Array.prototype.slice.call( arguments );
8575 }
8576 // otherwise a 2D array was passed in
8577
8578 return this.iterator( 'table', function ( settings ) {
8579 settings.aaSorting = order.slice();
8580 } );
8581 } );
8582
8583
8584 /**
8585 * Attach a sort listener to an element for a given column
8586 *
8587 * @param {node|jQuery|string} node Identifier for the element(s) to attach the
8588 * listener to. This can take the form of a single DOM node, a jQuery
8589 * collection of nodes or a jQuery selector which will identify the node(s).
8590 * @param {integer} column the column that a click on this node will sort on
8591 * @param {function} [callback] callback function when sort is run
8592 * @returns {DataTables.Api} this
8593 */
8594 _api_register( 'order.listener()', function ( node, column, callback ) {
8595 return this.iterator( 'table', function ( settings ) {
8596 _fnSortAttachListener( settings, node, column, callback );
8597 } );
8598 } );
8599
8600
8601 // Order by the selected column(s)
8602 _api_register( [
8603 'columns().order()',
8604 'column().order()'
8605 ], function ( dir ) {
8606 var that = this;
8607
8608 return this.iterator( 'table', function ( settings, i ) {
8609 var sort = [];
8610
8611 $.each( that[i], function (j, col) {
8612 sort.push( [ col, dir ] );
8613 } );
8614
8615 settings.aaSorting = sort;
8616 } );
8617 } );
8618
8619
8620
8621 _api_register( 'search()', function ( input, regex, smart, caseInsen ) {
8622 var ctx = this.context;
8623
8624 if ( input === undefined ) {
8625 // get
8626 return ctx.length !== 0 ?
8627 ctx[0].oPreviousSearch.sSearch :
8628 undefined;
8629 }
8630
8631 // set
8632 return this.iterator( 'table', function ( settings ) {
8633 if ( ! settings.oFeatures.bFilter ) {
8634 return;
8635 }
8636
8637 _fnFilterComplete( settings, $.extend( {}, settings.oPreviousSearch, {
8638 "sSearch": input+"",
8639 "bRegex": regex === null ? false : regex,
8640 "bSmart": smart === null ? true : smart,
8641 "bCaseInsensitive": caseInsen === null ? true : caseInsen
8642 } ), 1 );
8643 } );
8644 } );
8645
8646
8647 _api_registerPlural(
8648 'columns().search()',
8649 'column().search()',
8650 function ( input, regex, smart, caseInsen ) {
8651 return this.iterator( 'column', function ( settings, column ) {
8652 var preSearch = settings.aoPreSearchCols;
8653
8654 if ( input === undefined ) {
8655 // get
8656 return preSearch[ column ].sSearch;
8657 }
8658
8659 // set
8660 if ( ! settings.oFeatures.bFilter ) {
8661 return;
8662 }
8663
8664 $.extend( preSearch[ column ], {
8665 "sSearch": input+"",
8666 "bRegex": regex === null ? false : regex,
8667 "bSmart": smart === null ? true : smart,
8668 "bCaseInsensitive": caseInsen === null ? true : caseInsen
8669 } );
8670
8671 _fnFilterComplete( settings, settings.oPreviousSearch, 1 );
8672 } );
8673 }
8674 );
8675
8676 /*
8677 * State API methods
8678 */
8679
8680 _api_register( 'state()', function () {
8681 return this.context.length ?
8682 this.context[0].oSavedState :
8683 null;
8684 } );
8685
8686
8687 _api_register( 'state.clear()', function () {
8688 return this.iterator( 'table', function ( settings ) {
8689 // Save an empty object
8690 settings.fnStateSaveCallback.call( settings.oInstance, settings, {} );
8691 } );
8692 } );
8693
8694
8695 _api_register( 'state.loaded()', function () {
8696 return this.context.length ?
8697 this.context[0].oLoadedState :
8698 null;
8699 } );
8700
8701
8702 _api_register( 'state.save()', function () {
8703 return this.iterator( 'table', function ( settings ) {
8704 _fnSaveState( settings );
8705 } );
8706 } );
8707
8708
8709
8710 /**
8711 * Provide a common method for plug-ins to check the version of DataTables being
8712 * used, in order to ensure compatibility.
8713 *
8714 * @param {string} version Version string to check for, in the format "X.Y.Z".
8715 * Note that the formats "X" and "X.Y" are also acceptable.
8716 * @returns {boolean} true if this version of DataTables is greater or equal to
8717 * the required version, or false if this version of DataTales is not
8718 * suitable
8719 * @static
8720 * @dtopt API-Static
8721 *
8722 * @example
8723 * alert( $.fn.dataTable.versionCheck( '1.9.0' ) );
8724 */
8725 DataTable.versionCheck = DataTable.fnVersionCheck = function( version )
8726 {
8727 var aThis = DataTable.version.split('.');
8728 var aThat = version.split('.');
8729 var iThis, iThat;
8730
8731 for ( var i=0, iLen=aThat.length ; i<iLen ; i++ ) {
8732 iThis = parseInt( aThis[i], 10 ) || 0;
8733 iThat = parseInt( aThat[i], 10 ) || 0;
8734
8735 // Parts are the same, keep comparing
8736 if (iThis === iThat) {
8737 continue;
8738 }
8739
8740 // Parts are different, return immediately
8741 return iThis > iThat;
8742 }
8743
8744 return true;
8745 };
8746
8747
8748 /**
8749 * Check if a `<table>` node is a DataTable table already or not.
8750 *
8751 * @param {node|jquery|string} table Table node, jQuery object or jQuery
8752 * selector for the table to test. Note that if more than more than one
8753 * table is passed on, only the first will be checked
8754 * @returns {boolean} true the table given is a DataTable, or false otherwise
8755 * @static
8756 * @dtopt API-Static
8757 *
8758 * @example
8759 * if ( ! $.fn.DataTable.isDataTable( '#example' ) ) {
8760 * $('#example').dataTable();
8761 * }
8762 */
8763 DataTable.isDataTable = DataTable.fnIsDataTable = function ( table )
8764 {
8765 var t = $(table).get(0);
8766 var is = false;
8767
8768 $.each( DataTable.settings, function (i, o) {
8769 if ( o.nTable === t || o.nScrollHead === t || o.nScrollFoot === t ) {
8770 is = true;
8771 }
8772 } );
8773
8774 return is;
8775 };
8776
8777
8778 /**
8779 * Get all DataTable tables that have been initialised - optionally you can
8780 * select to get only currently visible tables.
8781 *
8782 * @param {boolean} [visible=false] Flag to indicate if you want all (default)
8783 * or visible tables only.
8784 * @returns {array} Array of `table` nodes (not DataTable instances) which are
8785 * DataTables
8786 * @static
8787 * @dtopt API-Static
8788 *
8789 * @example
8790 * $.each( $.fn.dataTable.tables(true), function () {
8791 * $(table).DataTable().columns.adjust();
8792 * } );
8793 */
8794 DataTable.tables = DataTable.fnTables = function ( visible )
8795 {
8796 return $.map( DataTable.settings, function (o) {
8797 if ( !visible || (visible && $(o.nTable).is(':visible')) ) {
8798 return o.nTable;
8799 }
8800 } );
8801 };
8802
8803
8804 /**
8805 * DataTables utility methods
8806 *
8807 * This namespace provides helper methods that DataTables uses internally to
8808 * create a DataTable, but which are not exclusively used only for DataTables.
8809 * These methods can be used by extension authors to save the duplication of
8810 * code.
8811 *
8812 * @namespace
8813 */
8814 DataTable.util = {
8815 /**
8816 * Throttle the calls to a function. Arguments and context are maintained
8817 * for the throttled function.
8818 *
8819 * @param {function} fn Function to be called
8820 * @param {integer} freq Call frequency in mS
8821 * @return {function} Wrapped function
8822 */
8823 throttle: _fnThrottle,
8824
8825
8826 /**
8827 * Escape a string such that it can be used in a regular expression
8828 *
8829 * @param {string} sVal string to escape
8830 * @returns {string} escaped string
8831 */
8832 escapeRegex: _fnEscapeRegex
8833 };
8834
8835
8836 /**
8837 * Convert from camel case parameters to Hungarian notation. This is made public
8838 * for the extensions to provide the same ability as DataTables core to accept
8839 * either the 1.9 style Hungarian notation, or the 1.10+ style camelCase
8840 * parameters.
8841 *
8842 * @param {object} src The model object which holds all parameters that can be
8843 * mapped.
8844 * @param {object} user The object to convert from camel case to Hungarian.
8845 * @param {boolean} force When set to `true`, properties which already have a
8846 * Hungarian value in the `user` object will be overwritten. Otherwise they
8847 * won't be.
8848 */
8849 DataTable.camelToHungarian = _fnCamelToHungarian;
8850
8851
8852
8853 /**
8854 *
8855 */
8856 _api_register( '$()', function ( selector, opts ) {
8857 var
8858 rows = this.rows( opts ).nodes(), // Get all rows
8859 jqRows = $(rows);
8860
8861 return $( [].concat(
8862 jqRows.filter( selector ).toArray(),
8863 jqRows.find( selector ).toArray()
8864 ) );
8865 } );
8866
8867
8868 // jQuery functions to operate on the tables
8869 $.each( [ 'on', 'one', 'off' ], function (i, key) {
8870 _api_register( key+'()', function ( /* event, handler */ ) {
8871 var args = Array.prototype.slice.call(arguments);
8872
8873 // Add the `dt` namespace automatically if it isn't already present
8874 if ( ! args[0].match(/\.dt\b/) ) {
8875 args[0] += '.dt';
8876 }
8877
8878 var inst = $( this.tables().nodes() );
8879 inst[key].apply( inst, args );
8880 return this;
8881 } );
8882 } );
8883
8884
8885 _api_register( 'clear()', function () {
8886 return this.iterator( 'table', function ( settings ) {
8887 _fnClearTable( settings );
8888 } );
8889 } );
8890
8891
8892 _api_register( 'settings()', function () {
8893 return new _Api( this.context, this.context );
8894 } );
8895
8896
8897 _api_register( 'data()', function () {
8898 return this.iterator( 'table', function ( settings ) {
8899 return _pluck( settings.aoData, '_aData' );
8900 } ).flatten();
8901 } );
8902
8903
8904 _api_register( 'destroy()', function ( remove ) {
8905 remove = remove || false;
8906
8907 return this.iterator( 'table', function ( settings ) {
8908 var orig = settings.nTableWrapper.parentNode;
8909 var classes = settings.oClasses;
8910 var table = settings.nTable;
8911 var tbody = settings.nTBody;
8912 var thead = settings.nTHead;
8913 var tfoot = settings.nTFoot;
8914 var jqTable = $(table);
8915 var jqTbody = $(tbody);
8916 var jqWrapper = $(settings.nTableWrapper);
8917 var rows = $.map( settings.aoData, function (r) { return r.nTr; } );
8918 var i, ien;
8919
8920 // Flag to note that the table is currently being destroyed - no action
8921 // should be taken
8922 settings.bDestroying = true;
8923
8924 // Fire off the destroy callbacks for plug-ins etc
8925 _fnCallbackFire( settings, "aoDestroyCallback", "destroy", [settings] );
8926
8927 // If not being removed from the document, make all columns visible
8928 if ( ! remove ) {
8929 new _Api( settings ).columns().visible( true );
8930 }
8931
8932 // Blitz all `DT` namespaced events (these are internal events, the
8933 // lowercase, `dt` events are user subscribed and they are responsible
8934 // for removing them
8935 jqWrapper.unbind('.DT').find(':not(tbody *)').unbind('.DT');
8936 $(window).unbind('.DT-'+settings.sInstance);
8937
8938 // When scrolling we had to break the table up - restore it
8939 if ( table != thead.parentNode ) {
8940 jqTable.children('thead').detach();
8941 jqTable.append( thead );
8942 }
8943
8944 if ( tfoot && table != tfoot.parentNode ) {
8945 jqTable.children('tfoot').detach();
8946 jqTable.append( tfoot );
8947 }
8948
8949 // Remove the DataTables generated nodes, events and classes
8950 jqTable.detach();
8951 jqWrapper.detach();
8952
8953 settings.aaSorting = [];
8954 settings.aaSortingFixed = [];
8955 _fnSortingClasses( settings );
8956
8957 $( rows ).removeClass( settings.asStripeClasses.join(' ') );
8958
8959 $('th, td', thead).removeClass( classes.sSortable+' '+
8960 classes.sSortableAsc+' '+classes.sSortableDesc+' '+classes.sSortableNone
8961 );
8962
8963 if ( settings.bJUI ) {
8964 $('th span.'+classes.sSortIcon+ ', td span.'+classes.sSortIcon, thead).detach();
8965 $('th, td', thead).each( function () {
8966 var wrapper = $('div.'+classes.sSortJUIWrapper, this);
8967 $(this).append( wrapper.contents() );
8968 wrapper.detach();
8969 } );
8970 }
8971
8972 if ( ! remove && orig ) {
8973 // insertBefore acts like appendChild if !arg[1]
8974 orig.insertBefore( table, settings.nTableReinsertBefore );
8975 }
8976
8977 // Add the TR elements back into the table in their original order
8978 jqTbody.children().detach();
8979 jqTbody.append( rows );
8980
8981 // Restore the width of the original table - was read from the style property,
8982 // so we can restore directly to that
8983 jqTable
8984 .css( 'width', settings.sDestroyWidth )
8985 .removeClass( classes.sTable );
8986
8987 // If the were originally stripe classes - then we add them back here.
8988 // Note this is not fool proof (for example if not all rows had stripe
8989 // classes - but it's a good effort without getting carried away
8990 ien = settings.asDestroyStripes.length;
8991
8992 if ( ien ) {
8993 jqTbody.children().each( function (i) {
8994 $(this).addClass( settings.asDestroyStripes[i % ien] );
8995 } );
8996 }
8997
8998 /* Remove the settings object from the settings array */
8999 var idx = $.inArray( settings, DataTable.settings );
9000 if ( idx !== -1 ) {
9001 DataTable.settings.splice( idx, 1 );
9002 }
9003 } );
9004 } );
9005
9006
9007 /**
9008 * Version string for plug-ins to check compatibility. Allowed format is
9009 * `a.b.c-d` where: a:int, b:int, c:int, d:string(dev|beta|alpha). `d` is used
9010 * only for non-release builds. See http://semver.org/ for more information.
9011 * @member
9012 * @type string
9013 * @default Version number
9014 */
9015 DataTable.version = "1.10.4";
9016
9017 /**
9018 * Private data store, containing all of the settings objects that are
9019 * created for the tables on a given page.
9020 *
9021 * Note that the `DataTable.settings` object is aliased to
9022 * `jQuery.fn.dataTableExt` through which it may be accessed and
9023 * manipulated, or `jQuery.fn.dataTable.settings`.
9024 * @member
9025 * @type array
9026 * @default []
9027 * @private
9028 */
9029 DataTable.settings = [];
9030
9031 /**
9032 * Object models container, for the various models that DataTables has
9033 * available to it. These models define the objects that are used to hold
9034 * the active state and configuration of the table.
9035 * @namespace
9036 */
9037 DataTable.models = {};
9038
9039
9040
9041 /**
9042 * Template object for the way in which DataTables holds information about
9043 * search information for the global filter and individual column filters.
9044 * @namespace
9045 */
9046 DataTable.models.oSearch = {
9047 /**
9048 * Flag to indicate if the filtering should be case insensitive or not
9049 * @type boolean
9050 * @default true
9051 */
9052 "bCaseInsensitive": true,
9053
9054 /**
9055 * Applied search term
9056 * @type string
9057 * @default <i>Empty string</i>
9058 */
9059 "sSearch": "",
9060
9061 /**
9062 * Flag to indicate if the search term should be interpreted as a
9063 * regular expression (true) or not (false) and therefore and special
9064 * regex characters escaped.
9065 * @type boolean
9066 * @default false
9067 */
9068 "bRegex": false,
9069
9070 /**
9071 * Flag to indicate if DataTables is to use its smart filtering or not.
9072 * @type boolean
9073 * @default true
9074 */
9075 "bSmart": true
9076 };
9077
9078
9079
9080
9081 /**
9082 * Template object for the way in which DataTables holds information about
9083 * each individual row. This is the object format used for the settings
9084 * aoData array.
9085 * @namespace
9086 */
9087 DataTable.models.oRow = {
9088 /**
9089 * TR element for the row
9090 * @type node
9091 * @default null
9092 */
9093 "nTr": null,
9094
9095 /**
9096 * Array of TD elements for each row. This is null until the row has been
9097 * created.
9098 * @type array nodes
9099 * @default []
9100 */
9101 "anCells": null,
9102
9103 /**
9104 * Data object from the original data source for the row. This is either
9105 * an array if using the traditional form of DataTables, or an object if
9106 * using mData options. The exact type will depend on the passed in
9107 * data from the data source, or will be an array if using DOM a data
9108 * source.
9109 * @type array|object
9110 * @default []
9111 */
9112 "_aData": [],
9113
9114 /**
9115 * Sorting data cache - this array is ostensibly the same length as the
9116 * number of columns (although each index is generated only as it is
9117 * needed), and holds the data that is used for sorting each column in the
9118 * row. We do this cache generation at the start of the sort in order that
9119 * the formatting of the sort data need be done only once for each cell
9120 * per sort. This array should not be read from or written to by anything
9121 * other than the master sorting methods.
9122 * @type array
9123 * @default null
9124 * @private
9125 */
9126 "_aSortData": null,
9127
9128 /**
9129 * Per cell filtering data cache. As per the sort data cache, used to
9130 * increase the performance of the filtering in DataTables
9131 * @type array
9132 * @default null
9133 * @private
9134 */
9135 "_aFilterData": null,
9136
9137 /**
9138 * Filtering data cache. This is the same as the cell filtering cache, but
9139 * in this case a string rather than an array. This is easily computed with
9140 * a join on `_aFilterData`, but is provided as a cache so the join isn't
9141 * needed on every search (memory traded for performance)
9142 * @type array
9143 * @default null
9144 * @private
9145 */
9146 "_sFilterRow": null,
9147
9148 /**
9149 * Cache of the class name that DataTables has applied to the row, so we
9150 * can quickly look at this variable rather than needing to do a DOM check
9151 * on className for the nTr property.
9152 * @type string
9153 * @default <i>Empty string</i>
9154 * @private
9155 */
9156 "_sRowStripe": "",
9157
9158 /**
9159 * Denote if the original data source was from the DOM, or the data source
9160 * object. This is used for invalidating data, so DataTables can
9161 * automatically read data from the original source, unless uninstructed
9162 * otherwise.
9163 * @type string
9164 * @default null
9165 * @private
9166 */
9167 "src": null
9168 };
9169
9170
9171 /**
9172 * Template object for the column information object in DataTables. This object
9173 * is held in the settings aoColumns array and contains all the information that
9174 * DataTables needs about each individual column.
9175 *
9176 * Note that this object is related to {@link DataTable.defaults.column}
9177 * but this one is the internal data store for DataTables's cache of columns.
9178 * It should NOT be manipulated outside of DataTables. Any configuration should
9179 * be done through the initialisation options.
9180 * @namespace
9181 */
9182 DataTable.models.oColumn = {
9183 /**
9184 * Column index. This could be worked out on-the-fly with $.inArray, but it
9185 * is faster to just hold it as a variable
9186 * @type integer
9187 * @default null
9188 */
9189 "idx": null,
9190
9191 /**
9192 * A list of the columns that sorting should occur on when this column
9193 * is sorted. That this property is an array allows multi-column sorting
9194 * to be defined for a column (for example first name / last name columns
9195 * would benefit from this). The values are integers pointing to the
9196 * columns to be sorted on (typically it will be a single integer pointing
9197 * at itself, but that doesn't need to be the case).
9198 * @type array
9199 */
9200 "aDataSort": null,
9201
9202 /**
9203 * Define the sorting directions that are applied to the column, in sequence
9204 * as the column is repeatedly sorted upon - i.e. the first value is used
9205 * as the sorting direction when the column if first sorted (clicked on).
9206 * Sort it again (click again) and it will move on to the next index.
9207 * Repeat until loop.
9208 * @type array
9209 */
9210 "asSorting": null,
9211
9212 /**
9213 * Flag to indicate if the column is searchable, and thus should be included
9214 * in the filtering or not.
9215 * @type boolean
9216 */
9217 "bSearchable": null,
9218
9219 /**
9220 * Flag to indicate if the column is sortable or not.
9221 * @type boolean
9222 */
9223 "bSortable": null,
9224
9225 /**
9226 * Flag to indicate if the column is currently visible in the table or not
9227 * @type boolean
9228 */
9229 "bVisible": null,
9230
9231 /**
9232 * Store for manual type assignment using the `column.type` option. This
9233 * is held in store so we can manipulate the column's `sType` property.
9234 * @type string
9235 * @default null
9236 * @private
9237 */
9238 "_sManualType": null,
9239
9240 /**
9241 * Flag to indicate if HTML5 data attributes should be used as the data
9242 * source for filtering or sorting. True is either are.
9243 * @type boolean
9244 * @default false
9245 * @private
9246 */
9247 "_bAttrSrc": false,
9248
9249 /**
9250 * Developer definable function that is called whenever a cell is created (Ajax source,
9251 * etc) or processed for input (DOM source). This can be used as a compliment to mRender
9252 * allowing you to modify the DOM element (add background colour for example) when the
9253 * element is available.
9254 * @type function
9255 * @param {element} nTd The TD node that has been created
9256 * @param {*} sData The Data for the cell
9257 * @param {array|object} oData The data for the whole row
9258 * @param {int} iRow The row index for the aoData data store
9259 * @default null
9260 */
9261 "fnCreatedCell": null,
9262
9263 /**
9264 * Function to get data from a cell in a column. You should <b>never</b>
9265 * access data directly through _aData internally in DataTables - always use
9266 * the method attached to this property. It allows mData to function as
9267 * required. This function is automatically assigned by the column
9268 * initialisation method
9269 * @type function
9270 * @param {array|object} oData The data array/object for the array
9271 * (i.e. aoData[]._aData)
9272 * @param {string} sSpecific The specific data type you want to get -
9273 * 'display', 'type' 'filter' 'sort'
9274 * @returns {*} The data for the cell from the given row's data
9275 * @default null
9276 */
9277 "fnGetData": null,
9278
9279 /**
9280 * Function to set data for a cell in the column. You should <b>never</b>
9281 * set the data directly to _aData internally in DataTables - always use
9282 * this method. It allows mData to function as required. This function
9283 * is automatically assigned by the column initialisation method
9284 * @type function
9285 * @param {array|object} oData The data array/object for the array
9286 * (i.e. aoData[]._aData)
9287 * @param {*} sValue Value to set
9288 * @default null
9289 */
9290 "fnSetData": null,
9291
9292 /**
9293 * Property to read the value for the cells in the column from the data
9294 * source array / object. If null, then the default content is used, if a
9295 * function is given then the return from the function is used.
9296 * @type function|int|string|null
9297 * @default null
9298 */
9299 "mData": null,
9300
9301 /**
9302 * Partner property to mData which is used (only when defined) to get
9303 * the data - i.e. it is basically the same as mData, but without the
9304 * 'set' option, and also the data fed to it is the result from mData.
9305 * This is the rendering method to match the data method of mData.
9306 * @type function|int|string|null
9307 * @default null
9308 */
9309 "mRender": null,
9310
9311 /**
9312 * Unique header TH/TD element for this column - this is what the sorting
9313 * listener is attached to (if sorting is enabled.)
9314 * @type node
9315 * @default null
9316 */
9317 "nTh": null,
9318
9319 /**
9320 * Unique footer TH/TD element for this column (if there is one). Not used
9321 * in DataTables as such, but can be used for plug-ins to reference the
9322 * footer for each column.
9323 * @type node
9324 * @default null
9325 */
9326 "nTf": null,
9327
9328 /**
9329 * The class to apply to all TD elements in the table's TBODY for the column
9330 * @type string
9331 * @default null
9332 */
9333 "sClass": null,
9334
9335 /**
9336 * When DataTables calculates the column widths to assign to each column,
9337 * it finds the longest string in each column and then constructs a
9338 * temporary table and reads the widths from that. The problem with this
9339 * is that "mmm" is much wider then "iiii", but the latter is a longer
9340 * string - thus the calculation can go wrong (doing it properly and putting
9341 * it into an DOM object and measuring that is horribly(!) slow). Thus as
9342 * a "work around" we provide this option. It will append its value to the
9343 * text that is found to be the longest string for the column - i.e. padding.
9344 * @type string
9345 */
9346 "sContentPadding": null,
9347
9348 /**
9349 * Allows a default value to be given for a column's data, and will be used
9350 * whenever a null data source is encountered (this can be because mData
9351 * is set to null, or because the data source itself is null).
9352 * @type string
9353 * @default null
9354 */
9355 "sDefaultContent": null,
9356
9357 /**
9358 * Name for the column, allowing reference to the column by name as well as
9359 * by index (needs a lookup to work by name).
9360 * @type string
9361 */
9362 "sName": null,
9363
9364 /**
9365 * Custom sorting data type - defines which of the available plug-ins in
9366 * afnSortData the custom sorting will use - if any is defined.
9367 * @type string
9368 * @default std
9369 */
9370 "sSortDataType": 'std',
9371
9372 /**
9373 * Class to be applied to the header element when sorting on this column
9374 * @type string
9375 * @default null
9376 */
9377 "sSortingClass": null,
9378
9379 /**
9380 * Class to be applied to the header element when sorting on this column -
9381 * when jQuery UI theming is used.
9382 * @type string
9383 * @default null
9384 */
9385 "sSortingClassJUI": null,
9386
9387 /**
9388 * Title of the column - what is seen in the TH element (nTh).
9389 * @type string
9390 */
9391 "sTitle": null,
9392
9393 /**
9394 * Column sorting and filtering type
9395 * @type string
9396 * @default null
9397 */
9398 "sType": null,
9399
9400 /**
9401 * Width of the column
9402 * @type string
9403 * @default null
9404 */
9405 "sWidth": null,
9406
9407 /**
9408 * Width of the column when it was first "encountered"
9409 * @type string
9410 * @default null
9411 */
9412 "sWidthOrig": null
9413 };
9414
9415
9416 /*
9417 * Developer note: The properties of the object below are given in Hungarian
9418 * notation, that was used as the interface for DataTables prior to v1.10, however
9419 * from v1.10 onwards the primary interface is camel case. In order to avoid
9420 * breaking backwards compatibility utterly with this change, the Hungarian
9421 * version is still, internally the primary interface, but is is not documented
9422 * - hence the @name tags in each doc comment. This allows a Javascript function
9423 * to create a map from Hungarian notation to camel case (going the other direction
9424 * would require each property to be listed, which would at around 3K to the size
9425 * of DataTables, while this method is about a 0.5K hit.
9426 *
9427 * Ultimately this does pave the way for Hungarian notation to be dropped
9428 * completely, but that is a massive amount of work and will break current
9429 * installs (therefore is on-hold until v2).
9430 */
9431
9432 /**
9433 * Initialisation options that can be given to DataTables at initialisation
9434 * time.
9435 * @namespace
9436 */
9437 DataTable.defaults = {
9438 /**
9439 * An array of data to use for the table, passed in at initialisation which
9440 * will be used in preference to any data which is already in the DOM. This is
9441 * particularly useful for constructing tables purely in Javascript, for
9442 * example with a custom Ajax call.
9443 * @type array
9444 * @default null
9445 *
9446 * @dtopt Option
9447 * @name DataTable.defaults.data
9448 *
9449 * @example
9450 * // Using a 2D array data source
9451 * $(document).ready( function () {
9452 * $('#example').dataTable( {
9453 * "data": [
9454 * ['Trident', 'Internet Explorer 4.0', 'Win 95+', 4, 'X'],
9455 * ['Trident', 'Internet Explorer 5.0', 'Win 95+', 5, 'C'],
9456 * ],
9457 * "columns": [
9458 * { "title": "Engine" },
9459 * { "title": "Browser" },
9460 * { "title": "Platform" },
9461 * { "title": "Version" },
9462 * { "title": "Grade" }
9463 * ]
9464 * } );
9465 * } );
9466 *
9467 * @example
9468 * // Using an array of objects as a data source (`data`)
9469 * $(document).ready( function () {
9470 * $('#example').dataTable( {
9471 * "data": [
9472 * {
9473 * "engine": "Trident",
9474 * "browser": "Internet Explorer 4.0",
9475 * "platform": "Win 95+",
9476 * "version": 4,
9477 * "grade": "X"
9478 * },
9479 * {
9480 * "engine": "Trident",
9481 * "browser": "Internet Explorer 5.0",
9482 * "platform": "Win 95+",
9483 * "version": 5,
9484 * "grade": "C"
9485 * }
9486 * ],
9487 * "columns": [
9488 * { "title": "Engine", "data": "engine" },
9489 * { "title": "Browser", "data": "browser" },
9490 * { "title": "Platform", "data": "platform" },
9491 * { "title": "Version", "data": "version" },
9492 * { "title": "Grade", "data": "grade" }
9493 * ]
9494 * } );
9495 * } );
9496 */
9497 "aaData": null,
9498
9499
9500 /**
9501 * If ordering is enabled, then DataTables will perform a first pass sort on
9502 * initialisation. You can define which column(s) the sort is performed
9503 * upon, and the sorting direction, with this variable. The `sorting` array
9504 * should contain an array for each column to be sorted initially containing
9505 * the column's index and a direction string ('asc' or 'desc').
9506 * @type array
9507 * @default [[0,'asc']]
9508 *
9509 * @dtopt Option
9510 * @name DataTable.defaults.order
9511 *
9512 * @example
9513 * // Sort by 3rd column first, and then 4th column
9514 * $(document).ready( function() {
9515 * $('#example').dataTable( {
9516 * "order": [[2,'asc'], [3,'desc']]
9517 * } );
9518 * } );
9519 *
9520 * // No initial sorting
9521 * $(document).ready( function() {
9522 * $('#example').dataTable( {
9523 * "order": []
9524 * } );
9525 * } );
9526 */
9527 "aaSorting": [[0,'asc']],
9528
9529
9530 /**
9531 * This parameter is basically identical to the `sorting` parameter, but
9532 * cannot be overridden by user interaction with the table. What this means
9533 * is that you could have a column (visible or hidden) which the sorting
9534 * will always be forced on first - any sorting after that (from the user)
9535 * will then be performed as required. This can be useful for grouping rows
9536 * together.
9537 * @type array
9538 * @default null
9539 *
9540 * @dtopt Option
9541 * @name DataTable.defaults.orderFixed
9542 *
9543 * @example
9544 * $(document).ready( function() {
9545 * $('#example').dataTable( {
9546 * "orderFixed": [[0,'asc']]
9547 * } );
9548 * } )
9549 */
9550 "aaSortingFixed": [],
9551
9552
9553 /**
9554 * DataTables can be instructed to load data to display in the table from a
9555 * Ajax source. This option defines how that Ajax call is made and where to.
9556 *
9557 * The `ajax` property has three different modes of operation, depending on
9558 * how it is defined. These are:
9559 *
9560 * * `string` - Set the URL from where the data should be loaded from.
9561 * * `object` - Define properties for `jQuery.ajax`.
9562 * * `function` - Custom data get function
9563 *
9564 * `string`
9565 * --------
9566 *
9567 * As a string, the `ajax` property simply defines the URL from which
9568 * DataTables will load data.
9569 *
9570 * `object`
9571 * --------
9572 *
9573 * As an object, the parameters in the object are passed to
9574 * [jQuery.ajax](http://api.jquery.com/jQuery.ajax/) allowing fine control
9575 * of the Ajax request. DataTables has a number of default parameters which
9576 * you can override using this option. Please refer to the jQuery
9577 * documentation for a full description of the options available, although
9578 * the following parameters provide additional options in DataTables or
9579 * require special consideration:
9580 *
9581 * * `data` - As with jQuery, `data` can be provided as an object, but it
9582 * can also be used as a function to manipulate the data DataTables sends
9583 * to the server. The function takes a single parameter, an object of
9584 * parameters with the values that DataTables has readied for sending. An
9585 * object may be returned which will be merged into the DataTables
9586 * defaults, or you can add the items to the object that was passed in and
9587 * not return anything from the function. This supersedes `fnServerParams`
9588 * from DataTables 1.9-.
9589 *
9590 * * `dataSrc` - By default DataTables will look for the property `data` (or
9591 * `aaData` for compatibility with DataTables 1.9-) when obtaining data
9592 * from an Ajax source or for server-side processing - this parameter
9593 * allows that property to be changed. You can use Javascript dotted
9594 * object notation to get a data source for multiple levels of nesting, or
9595 * it my be used as a function. As a function it takes a single parameter,
9596 * the JSON returned from the server, which can be manipulated as
9597 * required, with the returned value being that used by DataTables as the
9598 * data source for the table. This supersedes `sAjaxDataProp` from
9599 * DataTables 1.9-.
9600 *
9601 * * `success` - Should not be overridden it is used internally in
9602 * DataTables. To manipulate / transform the data returned by the server
9603 * use `ajax.dataSrc`, or use `ajax` as a function (see below).
9604 *
9605 * `function`
9606 * ----------
9607 *
9608 * As a function, making the Ajax call is left up to yourself allowing
9609 * complete control of the Ajax request. Indeed, if desired, a method other
9610 * than Ajax could be used to obtain the required data, such as Web storage
9611 * or an AIR database.
9612 *
9613 * The function is given four parameters and no return is required. The
9614 * parameters are:
9615 *
9616 * 1. _object_ - Data to send to the server
9617 * 2. _function_ - Callback function that must be executed when the required
9618 * data has been obtained. That data should be passed into the callback
9619 * as the only parameter
9620 * 3. _object_ - DataTables settings object for the table
9621 *
9622 * Note that this supersedes `fnServerData` from DataTables 1.9-.
9623 *
9624 * @type string|object|function
9625 * @default null
9626 *
9627 * @dtopt Option
9628 * @name DataTable.defaults.ajax
9629 * @since 1.10.0
9630 *
9631 * @example
9632 * // Get JSON data from a file via Ajax.
9633 * // Note DataTables expects data in the form `{ data: [ ...data... ] }` by default).
9634 * $('#example').dataTable( {
9635 * "ajax": "data.json"
9636 * } );
9637 *
9638 * @example
9639 * // Get JSON data from a file via Ajax, using `dataSrc` to change
9640 * // `data` to `tableData` (i.e. `{ tableData: [ ...data... ] }`)
9641 * $('#example').dataTable( {
9642 * "ajax": {
9643 * "url": "data.json",
9644 * "dataSrc": "tableData"
9645 * }
9646 * } );
9647 *
9648 * @example
9649 * // Get JSON data from a file via Ajax, using `dataSrc` to read data
9650 * // from a plain array rather than an array in an object
9651 * $('#example').dataTable( {
9652 * "ajax": {
9653 * "url": "data.json",
9654 * "dataSrc": ""
9655 * }
9656 * } );
9657 *
9658 * @example
9659 * // Manipulate the data returned from the server - add a link to data
9660 * // (note this can, should, be done using `render` for the column - this
9661 * // is just a simple example of how the data can be manipulated).
9662 * $('#example').dataTable( {
9663 * "ajax": {
9664 * "url": "data.json",
9665 * "dataSrc": function ( json ) {
9666 * for ( var i=0, ien=json.length ; i<ien ; i++ ) {
9667 * json[i][0] = '<a href="/message/'+json[i][0]+'>View message</a>';
9668 * }
9669 * return json;
9670 * }
9671 * }
9672 * } );
9673 *
9674 * @example
9675 * // Add data to the request
9676 * $('#example').dataTable( {
9677 * "ajax": {
9678 * "url": "data.json",
9679 * "data": function ( d ) {
9680 * return {
9681 * "extra_search": $('#extra').val()
9682 * };
9683 * }
9684 * }
9685 * } );
9686 *
9687 * @example
9688 * // Send request as POST
9689 * $('#example').dataTable( {
9690 * "ajax": {
9691 * "url": "data.json",
9692 * "type": "POST"
9693 * }
9694 * } );
9695 *
9696 * @example
9697 * // Get the data from localStorage (could interface with a form for
9698 * // adding, editing and removing rows).
9699 * $('#example').dataTable( {
9700 * "ajax": function (data, callback, settings) {
9701 * callback(
9702 * JSON.parse( localStorage.getItem('dataTablesData') )
9703 * );
9704 * }
9705 * } );
9706 */
9707 "ajax": null,
9708
9709
9710 /**
9711 * This parameter allows you to readily specify the entries in the length drop
9712 * down menu that DataTables shows when pagination is enabled. It can be
9713 * either a 1D array of options which will be used for both the displayed
9714 * option and the value, or a 2D array which will use the array in the first
9715 * position as the value, and the array in the second position as the
9716 * displayed options (useful for language strings such as 'All').
9717 *
9718 * Note that the `pageLength` property will be automatically set to the
9719 * first value given in this array, unless `pageLength` is also provided.
9720 * @type array
9721 * @default [ 10, 25, 50, 100 ]
9722 *
9723 * @dtopt Option
9724 * @name DataTable.defaults.lengthMenu
9725 *
9726 * @example
9727 * $(document).ready( function() {
9728 * $('#example').dataTable( {
9729 * "lengthMenu": [[10, 25, 50, -1], [10, 25, 50, "All"]]
9730 * } );
9731 * } );
9732 */
9733 "aLengthMenu": [ 10, 25, 50, 100 ],
9734
9735
9736 /**
9737 * The `columns` option in the initialisation parameter allows you to define
9738 * details about the way individual columns behave. For a full list of
9739 * column options that can be set, please see
9740 * {@link DataTable.defaults.column}. Note that if you use `columns` to
9741 * define your columns, you must have an entry in the array for every single
9742 * column that you have in your table (these can be null if you don't which
9743 * to specify any options).
9744 * @member
9745 *
9746 * @name DataTable.defaults.column
9747 */
9748 "aoColumns": null,
9749
9750 /**
9751 * Very similar to `columns`, `columnDefs` allows you to target a specific
9752 * column, multiple columns, or all columns, using the `targets` property of
9753 * each object in the array. This allows great flexibility when creating
9754 * tables, as the `columnDefs` arrays can be of any length, targeting the
9755 * columns you specifically want. `columnDefs` may use any of the column
9756 * options available: {@link DataTable.defaults.column}, but it _must_
9757 * have `targets` defined in each object in the array. Values in the `targets`
9758 * array may be:
9759 * <ul>
9760 * <li>a string - class name will be matched on the TH for the column</li>
9761 * <li>0 or a positive integer - column index counting from the left</li>
9762 * <li>a negative integer - column index counting from the right</li>
9763 * <li>the string "_all" - all columns (i.e. assign a default)</li>
9764 * </ul>
9765 * @member
9766 *
9767 * @name DataTable.defaults.columnDefs
9768 */
9769 "aoColumnDefs": null,
9770
9771
9772 /**
9773 * Basically the same as `search`, this parameter defines the individual column
9774 * filtering state at initialisation time. The array must be of the same size
9775 * as the number of columns, and each element be an object with the parameters
9776 * `search` and `escapeRegex` (the latter is optional). 'null' is also
9777 * accepted and the default will be used.
9778 * @type array
9779 * @default []
9780 *
9781 * @dtopt Option
9782 * @name DataTable.defaults.searchCols
9783 *
9784 * @example
9785 * $(document).ready( function() {
9786 * $('#example').dataTable( {
9787 * "searchCols": [
9788 * null,
9789 * { "search": "My filter" },
9790 * null,
9791 * { "search": "^[0-9]", "escapeRegex": false }
9792 * ]
9793 * } );
9794 * } )
9795 */
9796 "aoSearchCols": [],
9797
9798
9799 /**
9800 * An array of CSS classes that should be applied to displayed rows. This
9801 * array may be of any length, and DataTables will apply each class
9802 * sequentially, looping when required.
9803 * @type array
9804 * @default null <i>Will take the values determined by the `oClasses.stripe*`
9805 * options</i>
9806 *
9807 * @dtopt Option
9808 * @name DataTable.defaults.stripeClasses
9809 *
9810 * @example
9811 * $(document).ready( function() {
9812 * $('#example').dataTable( {
9813 * "stripeClasses": [ 'strip1', 'strip2', 'strip3' ]
9814 * } );
9815 * } )
9816 */
9817 "asStripeClasses": null,
9818
9819
9820 /**
9821 * Enable or disable automatic column width calculation. This can be disabled
9822 * as an optimisation (it takes some time to calculate the widths) if the
9823 * tables widths are passed in using `columns`.
9824 * @type boolean
9825 * @default true
9826 *
9827 * @dtopt Features
9828 * @name DataTable.defaults.autoWidth
9829 *
9830 * @example
9831 * $(document).ready( function () {
9832 * $('#example').dataTable( {
9833 * "autoWidth": false
9834 * } );
9835 * } );
9836 */
9837 "bAutoWidth": true,
9838
9839
9840 /**
9841 * Deferred rendering can provide DataTables with a huge speed boost when you
9842 * are using an Ajax or JS data source for the table. This option, when set to
9843 * true, will cause DataTables to defer the creation of the table elements for
9844 * each row until they are needed for a draw - saving a significant amount of
9845 * time.
9846 * @type boolean
9847 * @default false
9848 *
9849 * @dtopt Features
9850 * @name DataTable.defaults.deferRender
9851 *
9852 * @example
9853 * $(document).ready( function() {
9854 * $('#example').dataTable( {
9855 * "ajax": "sources/arrays.txt",
9856 * "deferRender": true
9857 * } );
9858 * } );
9859 */
9860 "bDeferRender": false,
9861
9862
9863 /**
9864 * Replace a DataTable which matches the given selector and replace it with
9865 * one which has the properties of the new initialisation object passed. If no
9866 * table matches the selector, then the new DataTable will be constructed as
9867 * per normal.
9868 * @type boolean
9869 * @default false
9870 *
9871 * @dtopt Options
9872 * @name DataTable.defaults.destroy
9873 *
9874 * @example
9875 * $(document).ready( function() {
9876 * $('#example').dataTable( {
9877 * "srollY": "200px",
9878 * "paginate": false
9879 * } );
9880 *
9881 * // Some time later....
9882 * $('#example').dataTable( {
9883 * "filter": false,
9884 * "destroy": true
9885 * } );
9886 * } );
9887 */
9888 "bDestroy": false,
9889
9890
9891 /**
9892 * Enable or disable filtering of data. Filtering in DataTables is "smart" in
9893 * that it allows the end user to input multiple words (space separated) and
9894 * will match a row containing those words, even if not in the order that was
9895 * specified (this allow matching across multiple columns). Note that if you
9896 * wish to use filtering in DataTables this must remain 'true' - to remove the
9897 * default filtering input box and retain filtering abilities, please use
9898 * {@link DataTable.defaults.dom}.
9899 * @type boolean
9900 * @default true
9901 *
9902 * @dtopt Features
9903 * @name DataTable.defaults.searching
9904 *
9905 * @example
9906 * $(document).ready( function () {
9907 * $('#example').dataTable( {
9908 * "searching": false
9909 * } );
9910 * } );
9911 */
9912 "bFilter": true,
9913
9914
9915 /**
9916 * Enable or disable the table information display. This shows information
9917 * about the data that is currently visible on the page, including information
9918 * about filtered data if that action is being performed.
9919 * @type boolean
9920 * @default true
9921 *
9922 * @dtopt Features
9923 * @name DataTable.defaults.info
9924 *
9925 * @example
9926 * $(document).ready( function () {
9927 * $('#example').dataTable( {
9928 * "info": false
9929 * } );
9930 * } );
9931 */
9932 "bInfo": true,
9933
9934
9935 /**
9936 * Enable jQuery UI ThemeRoller support (required as ThemeRoller requires some
9937 * slightly different and additional mark-up from what DataTables has
9938 * traditionally used).
9939 * @type boolean
9940 * @default false
9941 *
9942 * @dtopt Features
9943 * @name DataTable.defaults.jQueryUI
9944 *
9945 * @example
9946 * $(document).ready( function() {
9947 * $('#example').dataTable( {
9948 * "jQueryUI": true
9949 * } );
9950 * } );
9951 */
9952 "bJQueryUI": false,
9953
9954
9955 /**
9956 * Allows the end user to select the size of a formatted page from a select
9957 * menu (sizes are 10, 25, 50 and 100). Requires pagination (`paginate`).
9958 * @type boolean
9959 * @default true
9960 *
9961 * @dtopt Features
9962 * @name DataTable.defaults.lengthChange
9963 *
9964 * @example
9965 * $(document).ready( function () {
9966 * $('#example').dataTable( {
9967 * "lengthChange": false
9968 * } );
9969 * } );
9970 */
9971 "bLengthChange": true,
9972
9973
9974 /**
9975 * Enable or disable pagination.
9976 * @type boolean
9977 * @default true
9978 *
9979 * @dtopt Features
9980 * @name DataTable.defaults.paging
9981 *
9982 * @example
9983 * $(document).ready( function () {
9984 * $('#example').dataTable( {
9985 * "paging": false
9986 * } );
9987 * } );
9988 */
9989 "bPaginate": true,
9990
9991
9992 /**
9993 * Enable or disable the display of a 'processing' indicator when the table is
9994 * being processed (e.g. a sort). This is particularly useful for tables with
9995 * large amounts of data where it can take a noticeable amount of time to sort
9996 * the entries.
9997 * @type boolean
9998 * @default false
9999 *
10000 * @dtopt Features
10001 * @name DataTable.defaults.processing
10002 *
10003 * @example
10004 * $(document).ready( function () {
10005 * $('#example').dataTable( {
10006 * "processing": true
10007 * } );
10008 * } );
10009 */
10010 "bProcessing": false,
10011
10012
10013 /**
10014 * Retrieve the DataTables object for the given selector. Note that if the
10015 * table has already been initialised, this parameter will cause DataTables
10016 * to simply return the object that has already been set up - it will not take
10017 * account of any changes you might have made to the initialisation object
10018 * passed to DataTables (setting this parameter to true is an acknowledgement
10019 * that you understand this). `destroy` can be used to reinitialise a table if
10020 * you need.
10021 * @type boolean
10022 * @default false
10023 *
10024 * @dtopt Options
10025 * @name DataTable.defaults.retrieve
10026 *
10027 * @example
10028 * $(document).ready( function() {
10029 * initTable();
10030 * tableActions();
10031 * } );
10032 *
10033 * function initTable ()
10034 * {
10035 * return $('#example').dataTable( {
10036 * "scrollY": "200px",
10037 * "paginate": false,
10038 * "retrieve": true
10039 * } );
10040 * }
10041 *
10042 * function tableActions ()
10043 * {
10044 * var table = initTable();
10045 * // perform API operations with oTable
10046 * }
10047 */
10048 "bRetrieve": false,
10049
10050
10051 /**
10052 * When vertical (y) scrolling is enabled, DataTables will force the height of
10053 * the table's viewport to the given height at all times (useful for layout).
10054 * However, this can look odd when filtering data down to a small data set,
10055 * and the footer is left "floating" further down. This parameter (when
10056 * enabled) will cause DataTables to collapse the table's viewport down when
10057 * the result set will fit within the given Y height.
10058 * @type boolean
10059 * @default false
10060 *
10061 * @dtopt Options
10062 * @name DataTable.defaults.scrollCollapse
10063 *
10064 * @example
10065 * $(document).ready( function() {
10066 * $('#example').dataTable( {
10067 * "scrollY": "200",
10068 * "scrollCollapse": true
10069 * } );
10070 * } );
10071 */
10072 "bScrollCollapse": false,
10073
10074
10075 /**
10076 * Configure DataTables to use server-side processing. Note that the
10077 * `ajax` parameter must also be given in order to give DataTables a
10078 * source to obtain the required data for each draw.
10079 * @type boolean
10080 * @default false
10081 *
10082 * @dtopt Features
10083 * @dtopt Server-side
10084 * @name DataTable.defaults.serverSide
10085 *
10086 * @example
10087 * $(document).ready( function () {
10088 * $('#example').dataTable( {
10089 * "serverSide": true,
10090 * "ajax": "xhr.php"
10091 * } );
10092 * } );
10093 */
10094 "bServerSide": false,
10095
10096
10097 /**
10098 * Enable or disable sorting of columns. Sorting of individual columns can be
10099 * disabled by the `sortable` option for each column.
10100 * @type boolean
10101 * @default true
10102 *
10103 * @dtopt Features
10104 * @name DataTable.defaults.ordering
10105 *
10106 * @example
10107 * $(document).ready( function () {
10108 * $('#example').dataTable( {
10109 * "ordering": false
10110 * } );
10111 * } );
10112 */
10113 "bSort": true,
10114
10115
10116 /**
10117 * Enable or display DataTables' ability to sort multiple columns at the
10118 * same time (activated by shift-click by the user).
10119 * @type boolean
10120 * @default true
10121 *
10122 * @dtopt Options
10123 * @name DataTable.defaults.orderMulti
10124 *
10125 * @example
10126 * // Disable multiple column sorting ability
10127 * $(document).ready( function () {
10128 * $('#example').dataTable( {
10129 * "orderMulti": false
10130 * } );
10131 * } );
10132 */
10133 "bSortMulti": true,
10134
10135
10136 /**
10137 * Allows control over whether DataTables should use the top (true) unique
10138 * cell that is found for a single column, or the bottom (false - default).
10139 * This is useful when using complex headers.
10140 * @type boolean
10141 * @default false
10142 *
10143 * @dtopt Options
10144 * @name DataTable.defaults.orderCellsTop
10145 *
10146 * @example
10147 * $(document).ready( function() {
10148 * $('#example').dataTable( {
10149 * "orderCellsTop": true
10150 * } );
10151 * } );
10152 */
10153 "bSortCellsTop": false,
10154
10155
10156 /**
10157 * Enable or disable the addition of the classes `sorting\_1`, `sorting\_2` and
10158 * `sorting\_3` to the columns which are currently being sorted on. This is
10159 * presented as a feature switch as it can increase processing time (while
10160 * classes are removed and added) so for large data sets you might want to
10161 * turn this off.
10162 * @type boolean
10163 * @default true
10164 *
10165 * @dtopt Features
10166 * @name DataTable.defaults.orderClasses
10167 *
10168 * @example
10169 * $(document).ready( function () {
10170 * $('#example').dataTable( {
10171 * "orderClasses": false
10172 * } );
10173 * } );
10174 */
10175 "bSortClasses": true,
10176
10177
10178 /**
10179 * Enable or disable state saving. When enabled HTML5 `localStorage` will be
10180 * used to save table display information such as pagination information,
10181 * display length, filtering and sorting. As such when the end user reloads
10182 * the page the display display will match what thy had previously set up.
10183 *
10184 * Due to the use of `localStorage` the default state saving is not supported
10185 * in IE6 or 7. If state saving is required in those browsers, use
10186 * `stateSaveCallback` to provide a storage solution such as cookies.
10187 * @type boolean
10188 * @default false
10189 *
10190 * @dtopt Features
10191 * @name DataTable.defaults.stateSave
10192 *
10193 * @example
10194 * $(document).ready( function () {
10195 * $('#example').dataTable( {
10196 * "stateSave": true
10197 * } );
10198 * } );
10199 */
10200 "bStateSave": false,
10201
10202
10203 /**
10204 * This function is called when a TR element is created (and all TD child
10205 * elements have been inserted), or registered if using a DOM source, allowing
10206 * manipulation of the TR element (adding classes etc).
10207 * @type function
10208 * @param {node} row "TR" element for the current row
10209 * @param {array} data Raw data array for this row
10210 * @param {int} dataIndex The index of this row in the internal aoData array
10211 *
10212 * @dtopt Callbacks
10213 * @name DataTable.defaults.createdRow
10214 *
10215 * @example
10216 * $(document).ready( function() {
10217 * $('#example').dataTable( {
10218 * "createdRow": function( row, data, dataIndex ) {
10219 * // Bold the grade for all 'A' grade browsers
10220 * if ( data[4] == "A" )
10221 * {
10222 * $('td:eq(4)', row).html( '<b>A</b>' );
10223 * }
10224 * }
10225 * } );
10226 * } );
10227 */
10228 "fnCreatedRow": null,
10229
10230
10231 /**
10232 * This function is called on every 'draw' event, and allows you to
10233 * dynamically modify any aspect you want about the created DOM.
10234 * @type function
10235 * @param {object} settings DataTables settings object
10236 *
10237 * @dtopt Callbacks
10238 * @name DataTable.defaults.drawCallback
10239 *
10240 * @example
10241 * $(document).ready( function() {
10242 * $('#example').dataTable( {
10243 * "drawCallback": function( settings ) {
10244 * alert( 'DataTables has redrawn the table' );
10245 * }
10246 * } );
10247 * } );
10248 */
10249 "fnDrawCallback": null,
10250
10251
10252 /**
10253 * Identical to fnHeaderCallback() but for the table footer this function
10254 * allows you to modify the table footer on every 'draw' event.
10255 * @type function
10256 * @param {node} foot "TR" element for the footer
10257 * @param {array} data Full table data (as derived from the original HTML)
10258 * @param {int} start Index for the current display starting point in the
10259 * display array
10260 * @param {int} end Index for the current display ending point in the
10261 * display array
10262 * @param {array int} display Index array to translate the visual position
10263 * to the full data array
10264 *
10265 * @dtopt Callbacks
10266 * @name DataTable.defaults.footerCallback
10267 *
10268 * @example
10269 * $(document).ready( function() {
10270 * $('#example').dataTable( {
10271 * "footerCallback": function( tfoot, data, start, end, display ) {
10272 * tfoot.getElementsByTagName('th')[0].innerHTML = "Starting index is "+start;
10273 * }
10274 * } );
10275 * } )
10276 */
10277 "fnFooterCallback": null,
10278
10279
10280 /**
10281 * When rendering large numbers in the information element for the table
10282 * (i.e. "Showing 1 to 10 of 57 entries") DataTables will render large numbers
10283 * to have a comma separator for the 'thousands' units (e.g. 1 million is
10284 * rendered as "1,000,000") to help readability for the end user. This
10285 * function will override the default method DataTables uses.
10286 * @type function
10287 * @member
10288 * @param {int} toFormat number to be formatted
10289 * @returns {string} formatted string for DataTables to show the number
10290 *
10291 * @dtopt Callbacks
10292 * @name DataTable.defaults.formatNumber
10293 *
10294 * @example
10295 * // Format a number using a single quote for the separator (note that
10296 * // this can also be done with the language.thousands option)
10297 * $(document).ready( function() {
10298 * $('#example').dataTable( {
10299 * "formatNumber": function ( toFormat ) {
10300 * return toFormat.toString().replace(
10301 * /\B(?=(\d{3})+(?!\d))/g, "'"
10302 * );
10303 * };
10304 * } );
10305 * } );
10306 */
10307 "fnFormatNumber": function ( toFormat ) {
10308 return toFormat.toString().replace(
10309 /\B(?=(\d{3})+(?!\d))/g,
10310 this.oLanguage.sThousands
10311 );
10312 },
10313
10314
10315 /**
10316 * This function is called on every 'draw' event, and allows you to
10317 * dynamically modify the header row. This can be used to calculate and
10318 * display useful information about the table.
10319 * @type function
10320 * @param {node} head "TR" element for the header
10321 * @param {array} data Full table data (as derived from the original HTML)
10322 * @param {int} start Index for the current display starting point in the
10323 * display array
10324 * @param {int} end Index for the current display ending point in the
10325 * display array
10326 * @param {array int} display Index array to translate the visual position
10327 * to the full data array
10328 *
10329 * @dtopt Callbacks
10330 * @name DataTable.defaults.headerCallback
10331 *
10332 * @example
10333 * $(document).ready( function() {
10334 * $('#example').dataTable( {
10335 * "fheaderCallback": function( head, data, start, end, display ) {
10336 * head.getElementsByTagName('th')[0].innerHTML = "Displaying "+(end-start)+" records";
10337 * }
10338 * } );
10339 * } )
10340 */
10341 "fnHeaderCallback": null,
10342
10343
10344 /**
10345 * The information element can be used to convey information about the current
10346 * state of the table. Although the internationalisation options presented by
10347 * DataTables are quite capable of dealing with most customisations, there may
10348 * be times where you wish to customise the string further. This callback
10349 * allows you to do exactly that.
10350 * @type function
10351 * @param {object} oSettings DataTables settings object
10352 * @param {int} start Starting position in data for the draw
10353 * @param {int} end End position in data for the draw
10354 * @param {int} max Total number of rows in the table (regardless of
10355 * filtering)
10356 * @param {int} total Total number of rows in the data set, after filtering
10357 * @param {string} pre The string that DataTables has formatted using it's
10358 * own rules
10359 * @returns {string} The string to be displayed in the information element.
10360 *
10361 * @dtopt Callbacks
10362 * @name DataTable.defaults.infoCallback
10363 *
10364 * @example
10365 * $('#example').dataTable( {
10366 * "infoCallback": function( settings, start, end, max, total, pre ) {
10367 * return start +" to "+ end;
10368 * }
10369 * } );
10370 */
10371 "fnInfoCallback": null,
10372
10373
10374 /**
10375 * Called when the table has been initialised. Normally DataTables will
10376 * initialise sequentially and there will be no need for this function,
10377 * however, this does not hold true when using external language information
10378 * since that is obtained using an async XHR call.
10379 * @type function
10380 * @param {object} settings DataTables settings object
10381 * @param {object} json The JSON object request from the server - only
10382 * present if client-side Ajax sourced data is used
10383 *
10384 * @dtopt Callbacks
10385 * @name DataTable.defaults.initComplete
10386 *
10387 * @example
10388 * $(document).ready( function() {
10389 * $('#example').dataTable( {
10390 * "initComplete": function(settings, json) {
10391 * alert( 'DataTables has finished its initialisation.' );
10392 * }
10393 * } );
10394 * } )
10395 */
10396 "fnInitComplete": null,
10397
10398
10399 /**
10400 * Called at the very start of each table draw and can be used to cancel the
10401 * draw by returning false, any other return (including undefined) results in
10402 * the full draw occurring).
10403 * @type function
10404 * @param {object} settings DataTables settings object
10405 * @returns {boolean} False will cancel the draw, anything else (including no
10406 * return) will allow it to complete.
10407 *
10408 * @dtopt Callbacks
10409 * @name DataTable.defaults.preDrawCallback
10410 *
10411 * @example
10412 * $(document).ready( function() {
10413 * $('#example').dataTable( {
10414 * "preDrawCallback": function( settings ) {
10415 * if ( $('#test').val() == 1 ) {
10416 * return false;
10417 * }
10418 * }
10419 * } );
10420 * } );
10421 */
10422 "fnPreDrawCallback": null,
10423
10424
10425 /**
10426 * This function allows you to 'post process' each row after it have been
10427 * generated for each table draw, but before it is rendered on screen. This
10428 * function might be used for setting the row class name etc.
10429 * @type function
10430 * @param {node} row "TR" element for the current row
10431 * @param {array} data Raw data array for this row
10432 * @param {int} displayIndex The display index for the current table draw
10433 * @param {int} displayIndexFull The index of the data in the full list of
10434 * rows (after filtering)
10435 *
10436 * @dtopt Callbacks
10437 * @name DataTable.defaults.rowCallback
10438 *
10439 * @example
10440 * $(document).ready( function() {
10441 * $('#example').dataTable( {
10442 * "rowCallback": function( row, data, displayIndex, displayIndexFull ) {
10443 * // Bold the grade for all 'A' grade browsers
10444 * if ( data[4] == "A" ) {
10445 * $('td:eq(4)', row).html( '<b>A</b>' );
10446 * }
10447 * }
10448 * } );
10449 * } );
10450 */
10451 "fnRowCallback": null,
10452
10453
10454 /**
10455 * __Deprecated__ The functionality provided by this parameter has now been
10456 * superseded by that provided through `ajax`, which should be used instead.
10457 *
10458 * This parameter allows you to override the default function which obtains
10459 * the data from the server so something more suitable for your application.
10460 * For example you could use POST data, or pull information from a Gears or
10461 * AIR database.
10462 * @type function
10463 * @member
10464 * @param {string} source HTTP source to obtain the data from (`ajax`)
10465 * @param {array} data A key/value pair object containing the data to send
10466 * to the server
10467 * @param {function} callback to be called on completion of the data get
10468 * process that will draw the data on the page.
10469 * @param {object} settings DataTables settings object
10470 *
10471 * @dtopt Callbacks
10472 * @dtopt Server-side
10473 * @name DataTable.defaults.serverData
10474 *
10475 * @deprecated 1.10. Please use `ajax` for this functionality now.
10476 */
10477 "fnServerData": null,
10478
10479
10480 /**
10481 * __Deprecated__ The functionality provided by this parameter has now been
10482 * superseded by that provided through `ajax`, which should be used instead.
10483 *
10484 * It is often useful to send extra data to the server when making an Ajax
10485 * request - for example custom filtering information, and this callback
10486 * function makes it trivial to send extra information to the server. The
10487 * passed in parameter is the data set that has been constructed by
10488 * DataTables, and you can add to this or modify it as you require.
10489 * @type function
10490 * @param {array} data Data array (array of objects which are name/value
10491 * pairs) that has been constructed by DataTables and will be sent to the
10492 * server. In the case of Ajax sourced data with server-side processing
10493 * this will be an empty array, for server-side processing there will be a
10494 * significant number of parameters!
10495 * @returns {undefined} Ensure that you modify the data array passed in,
10496 * as this is passed by reference.
10497 *
10498 * @dtopt Callbacks
10499 * @dtopt Server-side
10500 * @name DataTable.defaults.serverParams
10501 *
10502 * @deprecated 1.10. Please use `ajax` for this functionality now.
10503 */
10504 "fnServerParams": null,
10505
10506
10507 /**
10508 * Load the table state. With this function you can define from where, and how, the
10509 * state of a table is loaded. By default DataTables will load from `localStorage`
10510 * but you might wish to use a server-side database or cookies.
10511 * @type function
10512 * @member
10513 * @param {object} settings DataTables settings object
10514 * @return {object} The DataTables state object to be loaded
10515 *
10516 * @dtopt Callbacks
10517 * @name DataTable.defaults.stateLoadCallback
10518 *
10519 * @example
10520 * $(document).ready( function() {
10521 * $('#example').dataTable( {
10522 * "stateSave": true,
10523 * "stateLoadCallback": function (settings) {
10524 * var o;
10525 *
10526 * // Send an Ajax request to the server to get the data. Note that
10527 * // this is a synchronous request.
10528 * $.ajax( {
10529 * "url": "/state_load",
10530 * "async": false,
10531 * "dataType": "json",
10532 * "success": function (json) {
10533 * o = json;
10534 * }
10535 * } );
10536 *
10537 * return o;
10538 * }
10539 * } );
10540 * } );
10541 */
10542 "fnStateLoadCallback": function ( settings ) {
10543 try {
10544 return JSON.parse(
10545 (settings.iStateDuration === -1 ? sessionStorage : localStorage).getItem(
10546 'DataTables_'+settings.sInstance+'_'+location.pathname
10547 )
10548 );
10549 } catch (e) {}
10550 },
10551
10552
10553 /**
10554 * Callback which allows modification of the saved state prior to loading that state.
10555 * This callback is called when the table is loading state from the stored data, but
10556 * prior to the settings object being modified by the saved state. Note that for
10557 * plug-in authors, you should use the `stateLoadParams` event to load parameters for
10558 * a plug-in.
10559 * @type function
10560 * @param {object} settings DataTables settings object
10561 * @param {object} data The state object that is to be loaded
10562 *
10563 * @dtopt Callbacks
10564 * @name DataTable.defaults.stateLoadParams
10565 *
10566 * @example
10567 * // Remove a saved filter, so filtering is never loaded
10568 * $(document).ready( function() {
10569 * $('#example').dataTable( {
10570 * "stateSave": true,
10571 * "stateLoadParams": function (settings, data) {
10572 * data.oSearch.sSearch = "";
10573 * }
10574 * } );
10575 * } );
10576 *
10577 * @example
10578 * // Disallow state loading by returning false
10579 * $(document).ready( function() {
10580 * $('#example').dataTable( {
10581 * "stateSave": true,
10582 * "stateLoadParams": function (settings, data) {
10583 * return false;
10584 * }
10585 * } );
10586 * } );
10587 */
10588 "fnStateLoadParams": null,
10589
10590
10591 /**
10592 * Callback that is called when the state has been loaded from the state saving method
10593 * and the DataTables settings object has been modified as a result of the loaded state.
10594 * @type function
10595 * @param {object} settings DataTables settings object
10596 * @param {object} data The state object that was loaded
10597 *
10598 * @dtopt Callbacks
10599 * @name DataTable.defaults.stateLoaded
10600 *
10601 * @example
10602 * // Show an alert with the filtering value that was saved
10603 * $(document).ready( function() {
10604 * $('#example').dataTable( {
10605 * "stateSave": true,
10606 * "stateLoaded": function (settings, data) {
10607 * alert( 'Saved filter was: '+data.oSearch.sSearch );
10608 * }
10609 * } );
10610 * } );
10611 */
10612 "fnStateLoaded": null,
10613
10614
10615 /**
10616 * Save the table state. This function allows you to define where and how the state
10617 * information for the table is stored By default DataTables will use `localStorage`
10618 * but you might wish to use a server-side database or cookies.
10619 * @type function
10620 * @member
10621 * @param {object} settings DataTables settings object
10622 * @param {object} data The state object to be saved
10623 *
10624 * @dtopt Callbacks
10625 * @name DataTable.defaults.stateSaveCallback
10626 *
10627 * @example
10628 * $(document).ready( function() {
10629 * $('#example').dataTable( {
10630 * "stateSave": true,
10631 * "stateSaveCallback": function (settings, data) {
10632 * // Send an Ajax request to the server with the state object
10633 * $.ajax( {
10634 * "url": "/state_save",
10635 * "data": data,
10636 * "dataType": "json",
10637 * "method": "POST"
10638 * "success": function () {}
10639 * } );
10640 * }
10641 * } );
10642 * } );
10643 */
10644 "fnStateSaveCallback": function ( settings, data ) {
10645 try {
10646 (settings.iStateDuration === -1 ? sessionStorage : localStorage).setItem(
10647 'DataTables_'+settings.sInstance+'_'+location.pathname,
10648 JSON.stringify( data )
10649 );
10650 } catch (e) {}
10651 },
10652
10653
10654 /**
10655 * Callback which allows modification of the state to be saved. Called when the table
10656 * has changed state a new state save is required. This method allows modification of
10657 * the state saving object prior to actually doing the save, including addition or
10658 * other state properties or modification. Note that for plug-in authors, you should
10659 * use the `stateSaveParams` event to save parameters for a plug-in.
10660 * @type function
10661 * @param {object} settings DataTables settings object
10662 * @param {object} data The state object to be saved
10663 *
10664 * @dtopt Callbacks
10665 * @name DataTable.defaults.stateSaveParams
10666 *
10667 * @example
10668 * // Remove a saved filter, so filtering is never saved
10669 * $(document).ready( function() {
10670 * $('#example').dataTable( {
10671 * "stateSave": true,
10672 * "stateSaveParams": function (settings, data) {
10673 * data.oSearch.sSearch = "";
10674 * }
10675 * } );
10676 * } );
10677 */
10678 "fnStateSaveParams": null,
10679
10680
10681 /**
10682 * Duration for which the saved state information is considered valid. After this period
10683 * has elapsed the state will be returned to the default.
10684 * Value is given in seconds.
10685 * @type int
10686 * @default 7200 <i>(2 hours)</i>
10687 *
10688 * @dtopt Options
10689 * @name DataTable.defaults.stateDuration
10690 *
10691 * @example
10692 * $(document).ready( function() {
10693 * $('#example').dataTable( {
10694 * "stateDuration": 60*60*24; // 1 day
10695 * } );
10696 * } )
10697 */
10698 "iStateDuration": 7200,
10699
10700
10701 /**
10702 * When enabled DataTables will not make a request to the server for the first
10703 * page draw - rather it will use the data already on the page (no sorting etc
10704 * will be applied to it), thus saving on an XHR at load time. `deferLoading`
10705 * is used to indicate that deferred loading is required, but it is also used
10706 * to tell DataTables how many records there are in the full table (allowing
10707 * the information element and pagination to be displayed correctly). In the case
10708 * where a filtering is applied to the table on initial load, this can be
10709 * indicated by giving the parameter as an array, where the first element is
10710 * the number of records available after filtering and the second element is the
10711 * number of records without filtering (allowing the table information element
10712 * to be shown correctly).
10713 * @type int | array
10714 * @default null
10715 *
10716 * @dtopt Options
10717 * @name DataTable.defaults.deferLoading
10718 *
10719 * @example
10720 * // 57 records available in the table, no filtering applied
10721 * $(document).ready( function() {
10722 * $('#example').dataTable( {
10723 * "serverSide": true,
10724 * "ajax": "scripts/server_processing.php",
10725 * "deferLoading": 57
10726 * } );
10727 * } );
10728 *
10729 * @example
10730 * // 57 records after filtering, 100 without filtering (an initial filter applied)
10731 * $(document).ready( function() {
10732 * $('#example').dataTable( {
10733 * "serverSide": true,
10734 * "ajax": "scripts/server_processing.php",
10735 * "deferLoading": [ 57, 100 ],
10736 * "search": {
10737 * "search": "my_filter"
10738 * }
10739 * } );
10740 * } );
10741 */
10742 "iDeferLoading": null,
10743
10744
10745 /**
10746 * Number of rows to display on a single page when using pagination. If
10747 * feature enabled (`lengthChange`) then the end user will be able to override
10748 * this to a custom setting using a pop-up menu.
10749 * @type int
10750 * @default 10
10751 *
10752 * @dtopt Options
10753 * @name DataTable.defaults.pageLength
10754 *
10755 * @example
10756 * $(document).ready( function() {
10757 * $('#example').dataTable( {
10758 * "pageLength": 50
10759 * } );
10760 * } )
10761 */
10762 "iDisplayLength": 10,
10763
10764
10765 /**
10766 * Define the starting point for data display when using DataTables with
10767 * pagination. Note that this parameter is the number of records, rather than
10768 * the page number, so if you have 10 records per page and want to start on
10769 * the third page, it should be "20".
10770 * @type int
10771 * @default 0
10772 *
10773 * @dtopt Options
10774 * @name DataTable.defaults.displayStart
10775 *
10776 * @example
10777 * $(document).ready( function() {
10778 * $('#example').dataTable( {
10779 * "displayStart": 20
10780 * } );
10781 * } )
10782 */
10783 "iDisplayStart": 0,
10784
10785
10786 /**
10787 * By default DataTables allows keyboard navigation of the table (sorting, paging,
10788 * and filtering) by adding a `tabindex` attribute to the required elements. This
10789 * allows you to tab through the controls and press the enter key to activate them.
10790 * The tabindex is default 0, meaning that the tab follows the flow of the document.
10791 * You can overrule this using this parameter if you wish. Use a value of -1 to
10792 * disable built-in keyboard navigation.
10793 * @type int
10794 * @default 0
10795 *
10796 * @dtopt Options
10797 * @name DataTable.defaults.tabIndex
10798 *
10799 * @example
10800 * $(document).ready( function() {
10801 * $('#example').dataTable( {
10802 * "tabIndex": 1
10803 * } );
10804 * } );
10805 */
10806 "iTabIndex": 0,
10807
10808
10809 /**
10810 * Classes that DataTables assigns to the various components and features
10811 * that it adds to the HTML table. This allows classes to be configured
10812 * during initialisation in addition to through the static
10813 * {@link DataTable.ext.oStdClasses} object).
10814 * @namespace
10815 * @name DataTable.defaults.classes
10816 */
10817 "oClasses": {},
10818
10819
10820 /**
10821 * All strings that DataTables uses in the user interface that it creates
10822 * are defined in this object, allowing you to modified them individually or
10823 * completely replace them all as required.
10824 * @namespace
10825 * @name DataTable.defaults.language
10826 */
10827 "oLanguage": {
10828 /**
10829 * Strings that are used for WAI-ARIA labels and controls only (these are not
10830 * actually visible on the page, but will be read by screenreaders, and thus
10831 * must be internationalised as well).
10832 * @namespace
10833 * @name DataTable.defaults.language.aria
10834 */
10835 "oAria": {
10836 /**
10837 * ARIA label that is added to the table headers when the column may be
10838 * sorted ascending by activing the column (click or return when focused).
10839 * Note that the column header is prefixed to this string.
10840 * @type string
10841 * @default : activate to sort column ascending
10842 *
10843 * @dtopt Language
10844 * @name DataTable.defaults.language.aria.sortAscending
10845 *
10846 * @example
10847 * $(document).ready( function() {
10848 * $('#example').dataTable( {
10849 * "language": {
10850 * "aria": {
10851 * "sortAscending": " - click/return to sort ascending"
10852 * }
10853 * }
10854 * } );
10855 * } );
10856 */
10857 "sSortAscending": ": activate to sort column ascending",
10858
10859 /**
10860 * ARIA label that is added to the table headers when the column may be
10861 * sorted descending by activing the column (click or return when focused).
10862 * Note that the column header is prefixed to this string.
10863 * @type string
10864 * @default : activate to sort column ascending
10865 *
10866 * @dtopt Language
10867 * @name DataTable.defaults.language.aria.sortDescending
10868 *
10869 * @example
10870 * $(document).ready( function() {
10871 * $('#example').dataTable( {
10872 * "language": {
10873 * "aria": {
10874 * "sortDescending": " - click/return to sort descending"
10875 * }
10876 * }
10877 * } );
10878 * } );
10879 */
10880 "sSortDescending": ": activate to sort column descending"
10881 },
10882
10883 /**
10884 * Pagination string used by DataTables for the built-in pagination
10885 * control types.
10886 * @namespace
10887 * @name DataTable.defaults.language.paginate
10888 */
10889 "oPaginate": {
10890 /**
10891 * Text to use when using the 'full_numbers' type of pagination for the
10892 * button to take the user to the first page.
10893 * @type string
10894 * @default First
10895 *
10896 * @dtopt Language
10897 * @name DataTable.defaults.language.paginate.first
10898 *
10899 * @example
10900 * $(document).ready( function() {
10901 * $('#example').dataTable( {
10902 * "language": {
10903 * "paginate": {
10904 * "first": "First page"
10905 * }
10906 * }
10907 * } );
10908 * } );
10909 */
10910 "sFirst": "First",
10911
10912
10913 /**
10914 * Text to use when using the 'full_numbers' type of pagination for the
10915 * button to take the user to the last page.
10916 * @type string
10917 * @default Last
10918 *
10919 * @dtopt Language
10920 * @name DataTable.defaults.language.paginate.last
10921 *
10922 * @example
10923 * $(document).ready( function() {
10924 * $('#example').dataTable( {
10925 * "language": {
10926 * "paginate": {
10927 * "last": "Last page"
10928 * }
10929 * }
10930 * } );
10931 * } );
10932 */
10933 "sLast": "Last",
10934
10935
10936 /**
10937 * Text to use for the 'next' pagination button (to take the user to the
10938 * next page).
10939 * @type string
10940 * @default Next
10941 *
10942 * @dtopt Language
10943 * @name DataTable.defaults.language.paginate.next
10944 *
10945 * @example
10946 * $(document).ready( function() {
10947 * $('#example').dataTable( {
10948 * "language": {
10949 * "paginate": {
10950 * "next": "Next page"
10951 * }
10952 * }
10953 * } );
10954 * } );
10955 */
10956 "sNext": "Next",
10957
10958
10959 /**
10960 * Text to use for the 'previous' pagination button (to take the user to
10961 * the previous page).
10962 * @type string
10963 * @default Previous
10964 *
10965 * @dtopt Language
10966 * @name DataTable.defaults.language.paginate.previous
10967 *
10968 * @example
10969 * $(document).ready( function() {
10970 * $('#example').dataTable( {
10971 * "language": {
10972 * "paginate": {
10973 * "previous": "Previous page"
10974 * }
10975 * }
10976 * } );
10977 * } );
10978 */
10979 "sPrevious": "Previous"
10980 },
10981
10982 /**
10983 * This string is shown in preference to `zeroRecords` when the table is
10984 * empty of data (regardless of filtering). Note that this is an optional
10985 * parameter - if it is not given, the value of `zeroRecords` will be used
10986 * instead (either the default or given value).
10987 * @type string
10988 * @default No data available in table
10989 *
10990 * @dtopt Language
10991 * @name DataTable.defaults.language.emptyTable
10992 *
10993 * @example
10994 * $(document).ready( function() {
10995 * $('#example').dataTable( {
10996 * "language": {
10997 * "emptyTable": "No data available in table"
10998 * }
10999 * } );
11000 * } );
11001 */
11002 "sEmptyTable": "No data available in table",
11003
11004
11005 /**
11006 * This string gives information to the end user about the information
11007 * that is current on display on the page. The following tokens can be
11008 * used in the string and will be dynamically replaced as the table
11009 * display updates. This tokens can be placed anywhere in the string, or
11010 * removed as needed by the language requires:
11011 *
11012 * * `\_START\_` - Display index of the first record on the current page
11013 * * `\_END\_` - Display index of the last record on the current page
11014 * * `\_TOTAL\_` - Number of records in the table after filtering
11015 * * `\_MAX\_` - Number of records in the table without filtering
11016 * * `\_PAGE\_` - Current page number
11017 * * `\_PAGES\_` - Total number of pages of data in the table
11018 *
11019 * @type string
11020 * @default Showing _START_ to _END_ of _TOTAL_ entries
11021 *
11022 * @dtopt Language
11023 * @name DataTable.defaults.language.info
11024 *
11025 * @example
11026 * $(document).ready( function() {
11027 * $('#example').dataTable( {
11028 * "language": {
11029 * "info": "Showing page _PAGE_ of _PAGES_"
11030 * }
11031 * } );
11032 * } );
11033 */
11034 "sInfo": "Ostatnia aktualizacja:",
11035
11036
11037 /**
11038 * Display information string for when the table is empty. Typically the
11039 * format of this string should match `info`.
11040 * @type string
11041 * @default Showing 0 to 0 of 0 entries
11042 *
11043 * @dtopt Language
11044 * @name DataTable.defaults.language.infoEmpty
11045 *
11046 * @example
11047 * $(document).ready( function() {
11048 * $('#example').dataTable( {
11049 * "language": {
11050 * "infoEmpty": "No entries to show"
11051 * }
11052 * } );
11053 * } );
11054 */
11055 "sInfoEmpty": "Showing 0 to 0 of 0 entries",
11056
11057
11058 /**
11059 * When a user filters the information in a table, this string is appended
11060 * to the information (`info`) to give an idea of how strong the filtering
11061 * is. The variable _MAX_ is dynamically updated.
11062 * @type string
11063 * @default (filtered from _MAX_ total entries)
11064 *
11065 * @dtopt Language
11066 * @name DataTable.defaults.language.infoFiltered
11067 *
11068 * @example
11069 * $(document).ready( function() {
11070 * $('#example').dataTable( {
11071 * "language": {
11072 * "infoFiltered": " - filtering from _MAX_ records"
11073 * }
11074 * } );
11075 * } );
11076 */
11077 "sInfoFiltered": "(filtered from _MAX_ total entries)",
11078
11079
11080 /**
11081 * If can be useful to append extra information to the info string at times,
11082 * and this variable does exactly that. This information will be appended to
11083 * the `info` (`infoEmpty` and `infoFiltered` in whatever combination they are
11084 * being used) at all times.
11085 * @type string
11086 * @default <i>Empty string</i>
11087 *
11088 * @dtopt Language
11089 * @name DataTable.defaults.language.infoPostFix
11090 *
11091 * @example
11092 * $(document).ready( function() {
11093 * $('#example').dataTable( {
11094 * "language": {
11095 * "infoPostFix": "All records shown are derived from real information."
11096 * }
11097 * } );
11098 * } );
11099 */
11100 "sInfoPostFix": "",
11101
11102
11103 /**
11104 * This decimal place operator is a little different from the other
11105 * language options since DataTables doesn't output floating point
11106 * numbers, so it won't ever use this for display of a number. Rather,
11107 * what this parameter does is modify the sort methods of the table so
11108 * that numbers which are in a format which has a character other than
11109 * a period (`.`) as a decimal place will be sorted numerically.
11110 *
11111 * Note that numbers with different decimal places cannot be shown in
11112 * the same table and still be sortable, the table must be consistent.
11113 * However, multiple different tables on the page can use different
11114 * decimal place characters.
11115 * @type string
11116 * @default
11117 *
11118 * @dtopt Language
11119 * @name DataTable.defaults.language.decimal
11120 *
11121 * @example
11122 * $(document).ready( function() {
11123 * $('#example').dataTable( {
11124 * "language": {
11125 * "decimal": ","
11126 * "thousands": "."
11127 * }
11128 * } );
11129 * } );
11130 */
11131 "sDecimal": "",
11132
11133
11134 /**
11135 * DataTables has a build in number formatter (`formatNumber`) which is
11136 * used to format large numbers that are used in the table information.
11137 * By default a comma is used, but this can be trivially changed to any
11138 * character you wish with this parameter.
11139 * @type string
11140 * @default ,
11141 *
11142 * @dtopt Language
11143 * @name DataTable.defaults.language.thousands
11144 *
11145 * @example
11146 * $(document).ready( function() {
11147 * $('#example').dataTable( {
11148 * "language": {
11149 * "thousands": "'"
11150 * }
11151 * } );
11152 * } );
11153 */
11154 "sThousands": ",",
11155
11156
11157 /**
11158 * Detail the action that will be taken when the drop down menu for the
11159 * pagination length option is changed. The '_MENU_' variable is replaced
11160 * with a default select list of 10, 25, 50 and 100, and can be replaced
11161 * with a custom select box if required.
11162 * @type string
11163 * @default Show _MENU_ entries
11164 *
11165 * @dtopt Language
11166 * @name DataTable.defaults.language.lengthMenu
11167 *
11168 * @example
11169 * // Language change only
11170 * $(document).ready( function() {
11171 * $('#example').dataTable( {
11172 * "language": {
11173 * "lengthMenu": "Display _MENU_ records"
11174 * }
11175 * } );
11176 * } );
11177 *
11178 * @example
11179 * // Language and options change
11180 * $(document).ready( function() {
11181 * $('#example').dataTable( {
11182 * "language": {
11183 * "lengthMenu": 'Display <select>'+
11184 * '<option value="10">10</option>'+
11185 * '<option value="20">20</option>'+
11186 * '<option value="30">30</option>'+
11187 * '<option value="40">40</option>'+
11188 * '<option value="50">50</option>'+
11189 * '<option value="-1">All</option>'+
11190 * '</select> records'
11191 * }
11192 * } );
11193 * } );
11194 */
11195 "sLengthMenu": "Show _MENU_ entries",
11196
11197
11198 /**
11199 * When using Ajax sourced data and during the first draw when DataTables is
11200 * gathering the data, this message is shown in an empty row in the table to
11201 * indicate to the end user the the data is being loaded. Note that this
11202 * parameter is not used when loading data by server-side processing, just
11203 * Ajax sourced data with client-side processing.
11204 * @type string
11205 * @default Loading...
11206 *
11207 * @dtopt Language
11208 * @name DataTable.defaults.language.loadingRecords
11209 *
11210 * @example
11211 * $(document).ready( function() {
11212 * $('#example').dataTable( {
11213 * "language": {
11214 * "loadingRecords": "Please wait - loading..."
11215 * }
11216 * } );
11217 * } );
11218 */
11219 "sLoadingRecords": "Loading...",
11220
11221
11222 /**
11223 * Text which is displayed when the table is processing a user action
11224 * (usually a sort command or similar).
11225 * @type string
11226 * @default Processing...
11227 *
11228 * @dtopt Language
11229 * @name DataTable.defaults.language.processing
11230 *
11231 * @example
11232 * $(document).ready( function() {
11233 * $('#example').dataTable( {
11234 * "language": {
11235 * "processing": "DataTables is currently busy"
11236 * }
11237 * } );
11238 * } );
11239 */
11240 "sProcessing": "Processing...",
11241
11242
11243 /**
11244 * Details the actions that will be taken when the user types into the
11245 * filtering input text box. The variable "_INPUT_", if used in the string,
11246 * is replaced with the HTML text box for the filtering input allowing
11247 * control over where it appears in the string. If "_INPUT_" is not given
11248 * then the input box is appended to the string automatically.
11249 * @type string
11250 * @default Search:
11251 *
11252 * @dtopt Language
11253 * @name DataTable.defaults.language.search
11254 *
11255 * @example
11256 * // Input text box will be appended at the end automatically
11257 * $(document).ready( function() {
11258 * $('#example').dataTable( {
11259 * "language": {
11260 * "search": "Filter records:"
11261 * }
11262 * } );
11263 * } );
11264 *
11265 * @example
11266 * // Specify where the filter should appear
11267 * $(document).ready( function() {
11268 * $('#example').dataTable( {
11269 * "language": {
11270 * "search": "Apply filter _INPUT_ to table"
11271 * }
11272 * } );
11273 * } );
11274 */
11275 "sSearch": "",
11276
11277
11278 /**
11279 * Assign a `placeholder` attribute to the search `input` element
11280 * @type string
11281 * @default
11282 *
11283 * @dtopt Language
11284 * @name DataTable.defaults.language.searchPlaceholder
11285 */
11286 "sSearchPlaceholder": "",
11287
11288
11289 /**
11290 * All of the language information can be stored in a file on the
11291 * server-side, which DataTables will look up if this parameter is passed.
11292 * It must store the URL of the language file, which is in a JSON format,
11293 * and the object has the same properties as the oLanguage object in the
11294 * initialiser object (i.e. the above parameters). Please refer to one of
11295 * the example language files to see how this works in action.
11296 * @type string
11297 * @default <i>Empty string - i.e. disabled</i>
11298 *
11299 * @dtopt Language
11300 * @name DataTable.defaults.language.url
11301 *
11302 * @example
11303 * $(document).ready( function() {
11304 * $('#example').dataTable( {
11305 * "language": {
11306 * "url": "http://www.sprymedia.co.uk/dataTables/lang.txt"
11307 * }
11308 * } );
11309 * } );
11310 */
11311 "sUrl": "",
11312
11313
11314 /**
11315 * Text shown inside the table records when the is no information to be
11316 * displayed after filtering. `emptyTable` is shown when there is simply no
11317 * information in the table at all (regardless of filtering).
11318 * @type string
11319 * @default No matching records found
11320 *
11321 * @dtopt Language
11322 * @name DataTable.defaults.language.zeroRecords
11323 *
11324 * @example
11325 * $(document).ready( function() {
11326 * $('#example').dataTable( {
11327 * "language": {
11328 * "zeroRecords": "No records to display"
11329 * }
11330 * } );
11331 * } );
11332 */
11333 "sZeroRecords": "No matching records found"
11334 },
11335
11336
11337 /**
11338 * This parameter allows you to have define the global filtering state at
11339 * initialisation time. As an object the `search` parameter must be
11340 * defined, but all other parameters are optional. When `regex` is true,
11341 * the search string will be treated as a regular expression, when false
11342 * (default) it will be treated as a straight string. When `smart`
11343 * DataTables will use it's smart filtering methods (to word match at
11344 * any point in the data), when false this will not be done.
11345 * @namespace
11346 * @extends DataTable.models.oSearch
11347 *
11348 * @dtopt Options
11349 * @name DataTable.defaults.search
11350 *
11351 * @example
11352 * $(document).ready( function() {
11353 * $('#example').dataTable( {
11354 * "search": {"search": "Initial search"}
11355 * } );
11356 * } )
11357 */
11358 "oSearch": $.extend( {}, DataTable.models.oSearch ),
11359
11360
11361 /**
11362 * __Deprecated__ The functionality provided by this parameter has now been
11363 * superseded by that provided through `ajax`, which should be used instead.
11364 *
11365 * By default DataTables will look for the property `data` (or `aaData` for
11366 * compatibility with DataTables 1.9-) when obtaining data from an Ajax
11367 * source or for server-side processing - this parameter allows that
11368 * property to be changed. You can use Javascript dotted object notation to
11369 * get a data source for multiple levels of nesting.
11370 * @type string
11371 * @default data
11372 *
11373 * @dtopt Options
11374 * @dtopt Server-side
11375 * @name DataTable.defaults.ajaxDataProp
11376 *
11377 * @deprecated 1.10. Please use `ajax` for this functionality now.
11378 */
11379 "sAjaxDataProp": "data",
11380
11381
11382 /**
11383 * __Deprecated__ The functionality provided by this parameter has now been
11384 * superseded by that provided through `ajax`, which should be used instead.
11385 *
11386 * You can instruct DataTables to load data from an external
11387 * source using this parameter (use aData if you want to pass data in you
11388 * already have). Simply provide a url a JSON object can be obtained from.
11389 * @type string
11390 * @default null
11391 *
11392 * @dtopt Options
11393 * @dtopt Server-side
11394 * @name DataTable.defaults.ajaxSource
11395 *
11396 * @deprecated 1.10. Please use `ajax` for this functionality now.
11397 */
11398 "sAjaxSource": null,
11399
11400
11401 /**
11402 * This initialisation variable allows you to specify exactly where in the
11403 * DOM you want DataTables to inject the various controls it adds to the page
11404 * (for example you might want the pagination controls at the top of the
11405 * table). DIV elements (with or without a custom class) can also be added to
11406 * aid styling. The follow syntax is used:
11407 * <ul>
11408 * <li>The following options are allowed:
11409 * <ul>
11410 * <li>'l' - Length changing</li>
11411 * <li>'f' - Filtering input</li>
11412 * <li>'t' - The table!</li>
11413 * <li>'i' - Information</li>
11414 * <li>'p' - Pagination</li>
11415 * <li>'r' - pRocessing</li>
11416 * </ul>
11417 * </li>
11418 * <li>The following constants are allowed:
11419 * <ul>
11420 * <li>'H' - jQueryUI theme "header" classes ('fg-toolbar ui-widget-header ui-corner-tl ui-corner-tr ui-helper-clearfix')</li>
11421 * <li>'F' - jQueryUI theme "footer" classes ('fg-toolbar ui-widget-header ui-corner-bl ui-corner-br ui-helper-clearfix')</li>
11422 * </ul>
11423 * </li>
11424 * <li>The following syntax is expected:
11425 * <ul>
11426 * <li>'<' and '>' - div elements</li>
11427 * <li>'<"class" and '>' - div with a class</li>
11428 * <li>'<"#id" and '>' - div with an ID</li>
11429 * </ul>
11430 * </li>
11431 * <li>Examples:
11432 * <ul>
11433 * <li>'<"wrapper"flipt>'</li>
11434 * <li>'<lf<t>ip>'</li>
11435 * </ul>
11436 * </li>
11437 * </ul>
11438 * @type string
11439 * @default lfrtip <i>(when `jQueryUI` is false)</i> <b>or</b>
11440 * <"H"lfr>t<"F"ip> <i>(when `jQueryUI` is true)</i>
11441 *
11442 * @dtopt Options
11443 * @name DataTable.defaults.dom
11444 *
11445 * @example
11446 * $(document).ready( function() {
11447 * $('#example').dataTable( {
11448 * "dom": '<"top"i>rt<"bottom"flp><"clear">'
11449 * } );
11450 * } );
11451 */
11452 "sDom": "lfrtip",
11453
11454
11455 /**
11456 * Search delay option. This will throttle full table searches that use the
11457 * DataTables provided search input element (it does not effect calls to
11458 * `dt-api search()`, providing a delay before the search is made.
11459 * @type integer
11460 * @default 0
11461 *
11462 * @dtopt Options
11463 * @name DataTable.defaults.searchDelay
11464 *
11465 * @example
11466 * $(document).ready( function() {
11467 * $('#example').dataTable( {
11468 * "searchDelay": 200
11469 * } );
11470 * } )
11471 */
11472 "searchDelay": null,
11473
11474
11475 /**
11476 * DataTables features four different built-in options for the buttons to
11477 * display for pagination control:
11478 *
11479 * * `simple` - 'Previous' and 'Next' buttons only
11480 * * 'simple_numbers` - 'Previous' and 'Next' buttons, plus page numbers
11481 * * `full` - 'First', 'Previous', 'Next' and 'Last' buttons
11482 * * `full_numbers` - 'First', 'Previous', 'Next' and 'Last' buttons, plus
11483 * page numbers
11484 *
11485 * Further methods can be added using {@link DataTable.ext.oPagination}.
11486 * @type string
11487 * @default simple_numbers
11488 *
11489 * @dtopt Options
11490 * @name DataTable.defaults.pagingType
11491 *
11492 * @example
11493 * $(document).ready( function() {
11494 * $('#example').dataTable( {
11495 * "pagingType": "full_numbers"
11496 * } );
11497 * } )
11498 */
11499 "sPaginationType": "simple_numbers",
11500
11501
11502 /**
11503 * Enable horizontal scrolling. When a table is too wide to fit into a
11504 * certain layout, or you have a large number of columns in the table, you
11505 * can enable x-scrolling to show the table in a viewport, which can be
11506 * scrolled. This property can be `true` which will allow the table to
11507 * scroll horizontally when needed, or any CSS unit, or a number (in which
11508 * case it will be treated as a pixel measurement). Setting as simply `true`
11509 * is recommended.
11510 * @type boolean|string
11511 * @default <i>blank string - i.e. disabled</i>
11512 *
11513 * @dtopt Features
11514 * @name DataTable.defaults.scrollX
11515 *
11516 * @example
11517 * $(document).ready( function() {
11518 * $('#example').dataTable( {
11519 * "scrollX": true,
11520 * "scrollCollapse": true
11521 * } );
11522 * } );
11523 */
11524 "sScrollX": "",
11525
11526
11527 /**
11528 * This property can be used to force a DataTable to use more width than it
11529 * might otherwise do when x-scrolling is enabled. For example if you have a
11530 * table which requires to be well spaced, this parameter is useful for
11531 * "over-sizing" the table, and thus forcing scrolling. This property can by
11532 * any CSS unit, or a number (in which case it will be treated as a pixel
11533 * measurement).
11534 * @type string
11535 * @default <i>blank string - i.e. disabled</i>
11536 *
11537 * @dtopt Options
11538 * @name DataTable.defaults.scrollXInner
11539 *
11540 * @example
11541 * $(document).ready( function() {
11542 * $('#example').dataTable( {
11543 * "scrollX": "100%",
11544 * "scrollXInner": "110%"
11545 * } );
11546 * } );
11547 */
11548 "sScrollXInner": "",
11549
11550
11551 /**
11552 * Enable vertical scrolling. Vertical scrolling will constrain the DataTable
11553 * to the given height, and enable scrolling for any data which overflows the
11554 * current viewport. This can be used as an alternative to paging to display
11555 * a lot of data in a small area (although paging and scrolling can both be
11556 * enabled at the same time). This property can be any CSS unit, or a number
11557 * (in which case it will be treated as a pixel measurement).
11558 * @type string
11559 * @default <i>blank string - i.e. disabled</i>
11560 *
11561 * @dtopt Features
11562 * @name DataTable.defaults.scrollY
11563 *
11564 * @example
11565 * $(document).ready( function() {
11566 * $('#example').dataTable( {
11567 * "scrollY": "200px",
11568 * "paginate": false
11569 * } );
11570 * } );
11571 */
11572 "sScrollY": "",
11573
11574
11575 /**
11576 * __Deprecated__ The functionality provided by this parameter has now been
11577 * superseded by that provided through `ajax`, which should be used instead.
11578 *
11579 * Set the HTTP method that is used to make the Ajax call for server-side
11580 * processing or Ajax sourced data.
11581 * @type string
11582 * @default GET
11583 *
11584 * @dtopt Options
11585 * @dtopt Server-side
11586 * @name DataTable.defaults.serverMethod
11587 *
11588 * @deprecated 1.10. Please use `ajax` for this functionality now.
11589 */
11590 "sServerMethod": "GET",
11591
11592
11593 /**
11594 * DataTables makes use of renderers when displaying HTML elements for
11595 * a table. These renderers can be added or modified by plug-ins to
11596 * generate suitable mark-up for a site. For example the Bootstrap
11597 * integration plug-in for DataTables uses a paging button renderer to
11598 * display pagination buttons in the mark-up required by Bootstrap.
11599 *
11600 * For further information about the renderers available see
11601 * DataTable.ext.renderer
11602 * @type string|object
11603 * @default null
11604 *
11605 * @name DataTable.defaults.renderer
11606 *
11607 */
11608 "renderer": null
11609 };
11610
11611 _fnHungarianMap( DataTable.defaults );
11612
11613
11614
11615 /*
11616 * Developer note - See note in model.defaults.js about the use of Hungarian
11617 * notation and camel case.
11618 */
11619
11620 /**
11621 * Column options that can be given to DataTables at initialisation time.
11622 * @namespace
11623 */
11624 DataTable.defaults.column = {
11625 /**
11626 * Define which column(s) an order will occur on for this column. This
11627 * allows a column's ordering to take multiple columns into account when
11628 * doing a sort or use the data from a different column. For example first
11629 * name / last name columns make sense to do a multi-column sort over the
11630 * two columns.
11631 * @type array|int
11632 * @default null <i>Takes the value of the column index automatically</i>
11633 *
11634 * @name DataTable.defaults.column.orderData
11635 * @dtopt Columns
11636 *
11637 * @example
11638 * // Using `columnDefs`
11639 * $(document).ready( function() {
11640 * $('#example').dataTable( {
11641 * "columnDefs": [
11642 * { "orderData": [ 0, 1 ], "targets": [ 0 ] },
11643 * { "orderData": [ 1, 0 ], "targets": [ 1 ] },
11644 * { "orderData": 2, "targets": [ 2 ] }
11645 * ]
11646 * } );
11647 * } );
11648 *
11649 * @example
11650 * // Using `columns`
11651 * $(document).ready( function() {
11652 * $('#example').dataTable( {
11653 * "columns": [
11654 * { "orderData": [ 0, 1 ] },
11655 * { "orderData": [ 1, 0 ] },
11656 * { "orderData": 2 },
11657 * null,
11658 * null
11659 * ]
11660 * } );
11661 * } );
11662 */
11663 "aDataSort": null,
11664 "iDataSort": -1,
11665
11666
11667 /**
11668 * You can control the default ordering direction, and even alter the
11669 * behaviour of the sort handler (i.e. only allow ascending ordering etc)
11670 * using this parameter.
11671 * @type array
11672 * @default [ 'asc', 'desc' ]
11673 *
11674 * @name DataTable.defaults.column.orderSequence
11675 * @dtopt Columns
11676 *
11677 * @example
11678 * // Using `columnDefs`
11679 * $(document).ready( function() {
11680 * $('#example').dataTable( {
11681 * "columnDefs": [
11682 * { "orderSequence": [ "asc" ], "targets": [ 1 ] },
11683 * { "orderSequence": [ "desc", "asc", "asc" ], "targets": [ 2 ] },
11684 * { "orderSequence": [ "desc" ], "targets": [ 3 ] }
11685 * ]
11686 * } );
11687 * } );
11688 *
11689 * @example
11690 * // Using `columns`
11691 * $(document).ready( function() {
11692 * $('#example').dataTable( {
11693 * "columns": [
11694 * null,
11695 * { "orderSequence": [ "asc" ] },
11696 * { "orderSequence": [ "desc", "asc", "asc" ] },
11697 * { "orderSequence": [ "desc" ] },
11698 * null
11699 * ]
11700 * } );
11701 * } );
11702 */
11703 "asSorting": [ 'asc', 'desc' ],
11704
11705
11706 /**
11707 * Enable or disable filtering on the data in this column.
11708 * @type boolean
11709 * @default true
11710 *
11711 * @name DataTable.defaults.column.searchable
11712 * @dtopt Columns
11713 *
11714 * @example
11715 * // Using `columnDefs`
11716 * $(document).ready( function() {
11717 * $('#example').dataTable( {
11718 * "columnDefs": [
11719 * { "searchable": false, "targets": [ 0 ] }
11720 * ] } );
11721 * } );
11722 *
11723 * @example
11724 * // Using `columns`
11725 * $(document).ready( function() {
11726 * $('#example').dataTable( {
11727 * "columns": [
11728 * { "searchable": false },
11729 * null,
11730 * null,
11731 * null,
11732 * null
11733 * ] } );
11734 * } );
11735 */
11736 "bSearchable": true,
11737
11738
11739 /**
11740 * Enable or disable ordering on this column.
11741 * @type boolean
11742 * @default true
11743 *
11744 * @name DataTable.defaults.column.orderable
11745 * @dtopt Columns
11746 *
11747 * @example
11748 * // Using `columnDefs`
11749 * $(document).ready( function() {
11750 * $('#example').dataTable( {
11751 * "columnDefs": [
11752 * { "orderable": false, "targets": [ 0 ] }
11753 * ] } );
11754 * } );
11755 *
11756 * @example
11757 * // Using `columns`
11758 * $(document).ready( function() {
11759 * $('#example').dataTable( {
11760 * "columns": [
11761 * { "orderable": false },
11762 * null,
11763 * null,
11764 * null,
11765 * null
11766 * ] } );
11767 * } );
11768 */
11769 "bSortable": true,
11770
11771
11772 /**
11773 * Enable or disable the display of this column.
11774 * @type boolean
11775 * @default true
11776 *
11777 * @name DataTable.defaults.column.visible
11778 * @dtopt Columns
11779 *
11780 * @example
11781 * // Using `columnDefs`
11782 * $(document).ready( function() {
11783 * $('#example').dataTable( {
11784 * "columnDefs": [
11785 * { "visible": false, "targets": [ 0 ] }
11786 * ] } );
11787 * } );
11788 *
11789 * @example
11790 * // Using `columns`
11791 * $(document).ready( function() {
11792 * $('#example').dataTable( {
11793 * "columns": [
11794 * { "visible": false },
11795 * null,
11796 * null,
11797 * null,
11798 * null
11799 * ] } );
11800 * } );
11801 */
11802 "bVisible": true,
11803
11804
11805 /**
11806 * Developer definable function that is called whenever a cell is created (Ajax source,
11807 * etc) or processed for input (DOM source). This can be used as a compliment to mRender
11808 * allowing you to modify the DOM element (add background colour for example) when the
11809 * element is available.
11810 * @type function
11811 * @param {element} td The TD node that has been created
11812 * @param {*} cellData The Data for the cell
11813 * @param {array|object} rowData The data for the whole row
11814 * @param {int} row The row index for the aoData data store
11815 * @param {int} col The column index for aoColumns
11816 *
11817 * @name DataTable.defaults.column.createdCell
11818 * @dtopt Columns
11819 *
11820 * @example
11821 * $(document).ready( function() {
11822 * $('#example').dataTable( {
11823 * "columnDefs": [ {
11824 * "targets": [3],
11825 * "createdCell": function (td, cellData, rowData, row, col) {
11826 * if ( cellData == "1.7" ) {
11827 * $(td).css('color', 'blue')
11828 * }
11829 * }
11830 * } ]
11831 * });
11832 * } );
11833 */
11834 "fnCreatedCell": null,
11835
11836
11837 /**
11838 * This parameter has been replaced by `data` in DataTables to ensure naming
11839 * consistency. `dataProp` can still be used, as there is backwards
11840 * compatibility in DataTables for this option, but it is strongly
11841 * recommended that you use `data` in preference to `dataProp`.
11842 * @name DataTable.defaults.column.dataProp
11843 */
11844
11845
11846 /**
11847 * This property can be used to read data from any data source property,
11848 * including deeply nested objects / properties. `data` can be given in a
11849 * number of different ways which effect its behaviour:
11850 *
11851 * * `integer` - treated as an array index for the data source. This is the
11852 * default that DataTables uses (incrementally increased for each column).
11853 * * `string` - read an object property from the data source. There are
11854 * three 'special' options that can be used in the string to alter how
11855 * DataTables reads the data from the source object:
11856 * * `.` - Dotted Javascript notation. Just as you use a `.` in
11857 * Javascript to read from nested objects, so to can the options
11858 * specified in `data`. For example: `browser.version` or
11859 * `browser.name`. If your object parameter name contains a period, use
11860 * `\\` to escape it - i.e. `first\\.name`.
11861 * * `[]` - Array notation. DataTables can automatically combine data
11862 * from and array source, joining the data with the characters provided
11863 * between the two brackets. For example: `name[, ]` would provide a
11864 * comma-space separated list from the source array. If no characters
11865 * are provided between the brackets, the original array source is
11866 * returned.
11867 * * `()` - Function notation. Adding `()` to the end of a parameter will
11868 * execute a function of the name given. For example: `browser()` for a
11869 * simple function on the data source, `browser.version()` for a
11870 * function in a nested property or even `browser().version` to get an
11871 * object property if the function called returns an object. Note that
11872 * function notation is recommended for use in `render` rather than
11873 * `data` as it is much simpler to use as a renderer.
11874 * * `null` - use the original data source for the row rather than plucking
11875 * data directly from it. This action has effects on two other
11876 * initialisation options:
11877 * * `defaultContent` - When null is given as the `data` option and
11878 * `defaultContent` is specified for the column, the value defined by
11879 * `defaultContent` will be used for the cell.
11880 * * `render` - When null is used for the `data` option and the `render`
11881 * option is specified for the column, the whole data source for the
11882 * row is used for the renderer.
11883 * * `function` - the function given will be executed whenever DataTables
11884 * needs to set or get the data for a cell in the column. The function
11885 * takes three parameters:
11886 * * Parameters:
11887 * * `{array|object}` The data source for the row
11888 * * `{string}` The type call data requested - this will be 'set' when
11889 * setting data or 'filter', 'display', 'type', 'sort' or undefined
11890 * when gathering data. Note that when `undefined` is given for the
11891 * type DataTables expects to get the raw data for the object back<
11892 * * `{*}` Data to set when the second parameter is 'set'.
11893 * * Return:
11894 * * The return value from the function is not required when 'set' is
11895 * the type of call, but otherwise the return is what will be used
11896 * for the data requested.
11897 *
11898 * Note that `data` is a getter and setter option. If you just require
11899 * formatting of data for output, you will likely want to use `render` which
11900 * is simply a getter and thus simpler to use.
11901 *
11902 * Note that prior to DataTables 1.9.2 `data` was called `mDataProp`. The
11903 * name change reflects the flexibility of this property and is consistent
11904 * with the naming of mRender. If 'mDataProp' is given, then it will still
11905 * be used by DataTables, as it automatically maps the old name to the new
11906 * if required.
11907 *
11908 * @type string|int|function|null
11909 * @default null <i>Use automatically calculated column index</i>
11910 *
11911 * @name DataTable.defaults.column.data
11912 * @dtopt Columns
11913 *
11914 * @example
11915 * // Read table data from objects
11916 * // JSON structure for each row:
11917 * // {
11918 * // "engine": {value},
11919 * // "browser": {value},
11920 * // "platform": {value},
11921 * // "version": {value},
11922 * // "grade": {value}
11923 * // }
11924 * $(document).ready( function() {
11925 * $('#example').dataTable( {
11926 * "ajaxSource": "sources/objects.txt",
11927 * "columns": [
11928 * { "data": "engine" },
11929 * { "data": "browser" },
11930 * { "data": "platform" },
11931 * { "data": "version" },
11932 * { "data": "grade" }
11933 * ]
11934 * } );
11935 * } );
11936 *
11937 * @example
11938 * // Read information from deeply nested objects
11939 * // JSON structure for each row:
11940 * // {
11941 * // "engine": {value},
11942 * // "browser": {value},
11943 * // "platform": {
11944 * // "inner": {value}
11945 * // },
11946 * // "details": [
11947 * // {value}, {value}
11948 * // ]
11949 * // }
11950 * $(document).ready( function() {
11951 * $('#example').dataTable( {
11952 * "ajaxSource": "sources/deep.txt",
11953 * "columns": [
11954 * { "data": "engine" },
11955 * { "data": "browser" },
11956 * { "data": "platform.inner" },
11957 * { "data": "platform.details.0" },
11958 * { "data": "platform.details.1" }
11959 * ]
11960 * } );
11961 * } );
11962 *
11963 * @example
11964 * // Using `data` as a function to provide different information for
11965 * // sorting, filtering and display. In this case, currency (price)
11966 * $(document).ready( function() {
11967 * $('#example').dataTable( {
11968 * "columnDefs": [ {
11969 * "targets": [ 0 ],
11970 * "data": function ( source, type, val ) {
11971 * if (type === 'set') {
11972 * source.price = val;
11973 * // Store the computed dislay and filter values for efficiency
11974 * source.price_display = val=="" ? "" : "$"+numberFormat(val);
11975 * source.price_filter = val=="" ? "" : "$"+numberFormat(val)+" "+val;
11976 * return;
11977 * }
11978 * else if (type === 'display') {
11979 * return source.price_display;
11980 * }
11981 * else if (type === 'filter') {
11982 * return source.price_filter;
11983 * }
11984 * // 'sort', 'type' and undefined all just use the integer
11985 * return source.price;
11986 * }
11987 * } ]
11988 * } );
11989 * } );
11990 *
11991 * @example
11992 * // Using default content
11993 * $(document).ready( function() {
11994 * $('#example').dataTable( {
11995 * "columnDefs": [ {
11996 * "targets": [ 0 ],
11997 * "data": null,
11998 * "defaultContent": "Click to edit"
11999 * } ]
12000 * } );
12001 * } );
12002 *
12003 * @example
12004 * // Using array notation - outputting a list from an array
12005 * $(document).ready( function() {
12006 * $('#example').dataTable( {
12007 * "columnDefs": [ {
12008 * "targets": [ 0 ],
12009 * "data": "name[, ]"
12010 * } ]
12011 * } );
12012 * } );
12013 *
12014 */
12015 "mData": null,
12016
12017
12018 /**
12019 * This property is the rendering partner to `data` and it is suggested that
12020 * when you want to manipulate data for display (including filtering,
12021 * sorting etc) without altering the underlying data for the table, use this
12022 * property. `render` can be considered to be the the read only companion to
12023 * `data` which is read / write (then as such more complex). Like `data`
12024 * this option can be given in a number of different ways to effect its
12025 * behaviour:
12026 *
12027 * * `integer` - treated as an array index for the data source. This is the
12028 * default that DataTables uses (incrementally increased for each column).
12029 * * `string` - read an object property from the data source. There are
12030 * three 'special' options that can be used in the string to alter how
12031 * DataTables reads the data from the source object:
12032 * * `.` - Dotted Javascript notation. Just as you use a `.` in
12033 * Javascript to read from nested objects, so to can the options
12034 * specified in `data`. For example: `browser.version` or
12035 * `browser.name`. If your object parameter name contains a period, use
12036 * `\\` to escape it - i.e. `first\\.name`.
12037 * * `[]` - Array notation. DataTables can automatically combine data
12038 * from and array source, joining the data with the characters provided
12039 * between the two brackets. For example: `name[, ]` would provide a
12040 * comma-space separated list from the source array. If no characters
12041 * are provided between the brackets, the original array source is
12042 * returned.
12043 * * `()` - Function notation. Adding `()` to the end of a parameter will
12044 * execute a function of the name given. For example: `browser()` for a
12045 * simple function on the data source, `browser.version()` for a
12046 * function in a nested property or even `browser().version` to get an
12047 * object property if the function called returns an object.
12048 * * `object` - use different data for the different data types requested by
12049 * DataTables ('filter', 'display', 'type' or 'sort'). The property names
12050 * of the object is the data type the property refers to and the value can
12051 * defined using an integer, string or function using the same rules as
12052 * `render` normally does. Note that an `_` option _must_ be specified.
12053 * This is the default value to use if you haven't specified a value for
12054 * the data type requested by DataTables.
12055 * * `function` - the function given will be executed whenever DataTables
12056 * needs to set or get the data for a cell in the column. The function
12057 * takes three parameters:
12058 * * Parameters:
12059 * * {array|object} The data source for the row (based on `data`)
12060 * * {string} The type call data requested - this will be 'filter',
12061 * 'display', 'type' or 'sort'.
12062 * * {array|object} The full data source for the row (not based on
12063 * `data`)
12064 * * Return:
12065 * * The return value from the function is what will be used for the
12066 * data requested.
12067 *
12068 * @type string|int|function|object|null
12069 * @default null Use the data source value.
12070 *
12071 * @name DataTable.defaults.column.render
12072 * @dtopt Columns
12073 *
12074 * @example
12075 * // Create a comma separated list from an array of objects
12076 * $(document).ready( function() {
12077 * $('#example').dataTable( {
12078 * "ajaxSource": "sources/deep.txt",
12079 * "columns": [
12080 * { "data": "engine" },
12081 * { "data": "browser" },
12082 * {
12083 * "data": "platform",
12084 * "render": "[, ].name"
12085 * }
12086 * ]
12087 * } );
12088 * } );
12089 *
12090 * @example
12091 * // Execute a function to obtain data
12092 * $(document).ready( function() {
12093 * $('#example').dataTable( {
12094 * "columnDefs": [ {
12095 * "targets": [ 0 ],
12096 * "data": null, // Use the full data source object for the renderer's source
12097 * "render": "browserName()"
12098 * } ]
12099 * } );
12100 * } );
12101 *
12102 * @example
12103 * // As an object, extracting different data for the different types
12104 * // This would be used with a data source such as:
12105 * // { "phone": 5552368, "phone_filter": "5552368 555-2368", "phone_display": "555-2368" }
12106 * // Here the `phone` integer is used for sorting and type detection, while `phone_filter`
12107 * // (which has both forms) is used for filtering for if a user inputs either format, while
12108 * // the formatted phone number is the one that is shown in the table.
12109 * $(document).ready( function() {
12110 * $('#example').dataTable( {
12111 * "columnDefs": [ {
12112 * "targets": [ 0 ],
12113 * "data": null, // Use the full data source object for the renderer's source
12114 * "render": {
12115 * "_": "phone",
12116 * "filter": "phone_filter",
12117 * "display": "phone_display"
12118 * }
12119 * } ]
12120 * } );
12121 * } );
12122 *
12123 * @example
12124 * // Use as a function to create a link from the data source
12125 * $(document).ready( function() {
12126 * $('#example').dataTable( {
12127 * "columnDefs": [ {
12128 * "targets": [ 0 ],
12129 * "data": "download_link",
12130 * "render": function ( data, type, full ) {
12131 * return '<a href="'+data+'">Download</a>';
12132 * }
12133 * } ]
12134 * } );
12135 * } );
12136 */
12137 "mRender": null,
12138
12139
12140 /**
12141 * Change the cell type created for the column - either TD cells or TH cells. This
12142 * can be useful as TH cells have semantic meaning in the table body, allowing them
12143 * to act as a header for a row (you may wish to add scope='row' to the TH elements).
12144 * @type string
12145 * @default td
12146 *
12147 * @name DataTable.defaults.column.cellType
12148 * @dtopt Columns
12149 *
12150 * @example
12151 * // Make the first column use TH cells
12152 * $(document).ready( function() {
12153 * $('#example').dataTable( {
12154 * "columnDefs": [ {
12155 * "targets": [ 0 ],
12156 * "cellType": "th"
12157 * } ]
12158 * } );
12159 * } );
12160 */
12161 "sCellType": "td",
12162
12163
12164 /**
12165 * Class to give to each cell in this column.
12166 * @type string
12167 * @default <i>Empty string</i>
12168 *
12169 * @name DataTable.defaults.column.class
12170 * @dtopt Columns
12171 *
12172 * @example
12173 * // Using `columnDefs`
12174 * $(document).ready( function() {
12175 * $('#example').dataTable( {
12176 * "columnDefs": [
12177 * { "class": "my_class", "targets": [ 0 ] }
12178 * ]
12179 * } );
12180 * } );
12181 *
12182 * @example
12183 * // Using `columns`
12184 * $(document).ready( function() {
12185 * $('#example').dataTable( {
12186 * "columns": [
12187 * { "class": "my_class" },
12188 * null,
12189 * null,
12190 * null,
12191 * null
12192 * ]
12193 * } );
12194 * } );
12195 */
12196 "sClass": "",
12197
12198 /**
12199 * When DataTables calculates the column widths to assign to each column,
12200 * it finds the longest string in each column and then constructs a
12201 * temporary table and reads the widths from that. The problem with this
12202 * is that "mmm" is much wider then "iiii", but the latter is a longer
12203 * string - thus the calculation can go wrong (doing it properly and putting
12204 * it into an DOM object and measuring that is horribly(!) slow). Thus as
12205 * a "work around" we provide this option. It will append its value to the
12206 * text that is found to be the longest string for the column - i.e. padding.
12207 * Generally you shouldn't need this!
12208 * @type string
12209 * @default <i>Empty string<i>
12210 *
12211 * @name DataTable.defaults.column.contentPadding
12212 * @dtopt Columns
12213 *
12214 * @example
12215 * // Using `columns`
12216 * $(document).ready( function() {
12217 * $('#example').dataTable( {
12218 * "columns": [
12219 * null,
12220 * null,
12221 * null,
12222 * {
12223 * "contentPadding": "mmm"
12224 * }
12225 * ]
12226 * } );
12227 * } );
12228 */
12229 "sContentPadding": "",
12230
12231
12232 /**
12233 * Allows a default value to be given for a column's data, and will be used
12234 * whenever a null data source is encountered (this can be because `data`
12235 * is set to null, or because the data source itself is null).
12236 * @type string
12237 * @default null
12238 *
12239 * @name DataTable.defaults.column.defaultContent
12240 * @dtopt Columns
12241 *
12242 * @example
12243 * // Using `columnDefs`
12244 * $(document).ready( function() {
12245 * $('#example').dataTable( {
12246 * "columnDefs": [
12247 * {
12248 * "data": null,
12249 * "defaultContent": "Edit",
12250 * "targets": [ -1 ]
12251 * }
12252 * ]
12253 * } );
12254 * } );
12255 *
12256 * @example
12257 * // Using `columns`
12258 * $(document).ready( function() {
12259 * $('#example').dataTable( {
12260 * "columns": [
12261 * null,
12262 * null,
12263 * null,
12264 * {
12265 * "data": null,
12266 * "defaultContent": "Edit"
12267 * }
12268 * ]
12269 * } );
12270 * } );
12271 */
12272 "sDefaultContent": null,
12273
12274
12275 /**
12276 * This parameter is only used in DataTables' server-side processing. It can
12277 * be exceptionally useful to know what columns are being displayed on the
12278 * client side, and to map these to database fields. When defined, the names
12279 * also allow DataTables to reorder information from the server if it comes
12280 * back in an unexpected order (i.e. if you switch your columns around on the
12281 * client-side, your server-side code does not also need updating).
12282 * @type string
12283 * @default <i>Empty string</i>
12284 *
12285 * @name DataTable.defaults.column.name
12286 * @dtopt Columns
12287 *
12288 * @example
12289 * // Using `columnDefs`
12290 * $(document).ready( function() {
12291 * $('#example').dataTable( {
12292 * "columnDefs": [
12293 * { "name": "engine", "targets": [ 0 ] },
12294 * { "name": "browser", "targets": [ 1 ] },
12295 * { "name": "platform", "targets": [ 2 ] },
12296 * { "name": "version", "targets": [ 3 ] },
12297 * { "name": "grade", "targets": [ 4 ] }
12298 * ]
12299 * } );
12300 * } );
12301 *
12302 * @example
12303 * // Using `columns`
12304 * $(document).ready( function() {
12305 * $('#example').dataTable( {
12306 * "columns": [
12307 * { "name": "engine" },
12308 * { "name": "browser" },
12309 * { "name": "platform" },
12310 * { "name": "version" },
12311 * { "name": "grade" }
12312 * ]
12313 * } );
12314 * } );
12315 */
12316 "sName": "",
12317
12318
12319 /**
12320 * Defines a data source type for the ordering which can be used to read
12321 * real-time information from the table (updating the internally cached
12322 * version) prior to ordering. This allows ordering to occur on user
12323 * editable elements such as form inputs.
12324 * @type string
12325 * @default std
12326 *
12327 * @name DataTable.defaults.column.orderDataType
12328 * @dtopt Columns
12329 *
12330 * @example
12331 * // Using `columnDefs`
12332 * $(document).ready( function() {
12333 * $('#example').dataTable( {
12334 * "columnDefs": [
12335 * { "orderDataType": "dom-text", "targets": [ 2, 3 ] },
12336 * { "type": "numeric", "targets": [ 3 ] },
12337 * { "orderDataType": "dom-select", "targets": [ 4 ] },
12338 * { "orderDataType": "dom-checkbox", "targets": [ 5 ] }
12339 * ]
12340 * } );
12341 * } );
12342 *
12343 * @example
12344 * // Using `columns`
12345 * $(document).ready( function() {
12346 * $('#example').dataTable( {
12347 * "columns": [
12348 * null,
12349 * null,
12350 * { "orderDataType": "dom-text" },
12351 * { "orderDataType": "dom-text", "type": "numeric" },
12352 * { "orderDataType": "dom-select" },
12353 * { "orderDataType": "dom-checkbox" }
12354 * ]
12355 * } );
12356 * } );
12357 */
12358 "sSortDataType": "std",
12359
12360
12361 /**
12362 * The title of this column.
12363 * @type string
12364 * @default null <i>Derived from the 'TH' value for this column in the
12365 * original HTML table.</i>
12366 *
12367 * @name DataTable.defaults.column.title
12368 * @dtopt Columns
12369 *
12370 * @example
12371 * // Using `columnDefs`
12372 * $(document).ready( function() {
12373 * $('#example').dataTable( {
12374 * "columnDefs": [
12375 * { "title": "My column title", "targets": [ 0 ] }
12376 * ]
12377 * } );
12378 * } );
12379 *
12380 * @example
12381 * // Using `columns`
12382 * $(document).ready( function() {
12383 * $('#example').dataTable( {
12384 * "columns": [
12385 * { "title": "My column title" },
12386 * null,
12387 * null,
12388 * null,
12389 * null
12390 * ]
12391 * } );
12392 * } );
12393 */
12394 "sTitle": null,
12395
12396
12397 /**
12398 * The type allows you to specify how the data for this column will be
12399 * ordered. Four types (string, numeric, date and html (which will strip
12400 * HTML tags before ordering)) are currently available. Note that only date
12401 * formats understood by Javascript's Date() object will be accepted as type
12402 * date. For example: "Mar 26, 2008 5:03 PM". May take the values: 'string',
12403 * 'numeric', 'date' or 'html' (by default). Further types can be adding
12404 * through plug-ins.
12405 * @type string
12406 * @default null <i>Auto-detected from raw data</i>
12407 *
12408 * @name DataTable.defaults.column.type
12409 * @dtopt Columns
12410 *
12411 * @example
12412 * // Using `columnDefs`
12413 * $(document).ready( function() {
12414 * $('#example').dataTable( {
12415 * "columnDefs": [
12416 * { "type": "html", "targets": [ 0 ] }
12417 * ]
12418 * } );
12419 * } );
12420 *
12421 * @example
12422 * // Using `columns`
12423 * $(document).ready( function() {
12424 * $('#example').dataTable( {
12425 * "columns": [
12426 * { "type": "html" },
12427 * null,
12428 * null,
12429 * null,
12430 * null
12431 * ]
12432 * } );
12433 * } );
12434 */
12435 "sType": null,
12436
12437
12438 /**
12439 * Defining the width of the column, this parameter may take any CSS value
12440 * (3em, 20px etc). DataTables applies 'smart' widths to columns which have not
12441 * been given a specific width through this interface ensuring that the table
12442 * remains readable.
12443 * @type string
12444 * @default null <i>Automatic</i>
12445 *
12446 * @name DataTable.defaults.column.width
12447 * @dtopt Columns
12448 *
12449 * @example
12450 * // Using `columnDefs`
12451 * $(document).ready( function() {
12452 * $('#example').dataTable( {
12453 * "columnDefs": [
12454 * { "width": "20%", "targets": [ 0 ] }
12455 * ]
12456 * } );
12457 * } );
12458 *
12459 * @example
12460 * // Using `columns`
12461 * $(document).ready( function() {
12462 * $('#example').dataTable( {
12463 * "columns": [
12464 * { "width": "20%" },
12465 * null,
12466 * null,
12467 * null,
12468 * null
12469 * ]
12470 * } );
12471 * } );
12472 */
12473 "sWidth": null
12474 };
12475
12476 _fnHungarianMap( DataTable.defaults.column );
12477
12478
12479
12480 /**
12481 * DataTables settings object - this holds all the information needed for a
12482 * given table, including configuration, data and current application of the
12483 * table options. DataTables does not have a single instance for each DataTable
12484 * with the settings attached to that instance, but rather instances of the
12485 * DataTable "class" are created on-the-fly as needed (typically by a
12486 * $().dataTable() call) and the settings object is then applied to that
12487 * instance.
12488 *
12489 * Note that this object is related to {@link DataTable.defaults} but this
12490 * one is the internal data store for DataTables's cache of columns. It should
12491 * NOT be manipulated outside of DataTables. Any configuration should be done
12492 * through the initialisation options.
12493 * @namespace
12494 * @todo Really should attach the settings object to individual instances so we
12495 * don't need to create new instances on each $().dataTable() call (if the
12496 * table already exists). It would also save passing oSettings around and
12497 * into every single function. However, this is a very significant
12498 * architecture change for DataTables and will almost certainly break
12499 * backwards compatibility with older installations. This is something that
12500 * will be done in 2.0.
12501 */
12502 DataTable.models.oSettings = {
12503 /**
12504 * Primary features of DataTables and their enablement state.
12505 * @namespace
12506 */
12507 "oFeatures": {
12508
12509 /**
12510 * Flag to say if DataTables should automatically try to calculate the
12511 * optimum table and columns widths (true) or not (false).
12512 * Note that this parameter will be set by the initialisation routine. To
12513 * set a default use {@link DataTable.defaults}.
12514 * @type boolean
12515 */
12516 "bAutoWidth": null,
12517
12518 /**
12519 * Delay the creation of TR and TD elements until they are actually
12520 * needed by a driven page draw. This can give a significant speed
12521 * increase for Ajax source and Javascript source data, but makes no
12522 * difference at all fro DOM and server-side processing tables.
12523 * Note that this parameter will be set by the initialisation routine. To
12524 * set a default use {@link DataTable.defaults}.
12525 * @type boolean
12526 */
12527 "bDeferRender": null,
12528
12529 /**
12530 * Enable filtering on the table or not. Note that if this is disabled
12531 * then there is no filtering at all on the table, including fnFilter.
12532 * To just remove the filtering input use sDom and remove the 'f' option.
12533 * Note that this parameter will be set by the initialisation routine. To
12534 * set a default use {@link DataTable.defaults}.
12535 * @type boolean
12536 */
12537 "bFilter": null,
12538
12539 /**
12540 * Table information element (the 'Showing x of y records' div) enable
12541 * flag.
12542 * Note that this parameter will be set by the initialisation routine. To
12543 * set a default use {@link DataTable.defaults}.
12544 * @type boolean
12545 */
12546 "bInfo": null,
12547
12548 /**
12549 * Present a user control allowing the end user to change the page size
12550 * when pagination is enabled.
12551 * Note that this parameter will be set by the initialisation routine. To
12552 * set a default use {@link DataTable.defaults}.
12553 * @type boolean
12554 */
12555 "bLengthChange": null,
12556
12557 /**
12558 * Pagination enabled or not. Note that if this is disabled then length
12559 * changing must also be disabled.
12560 * Note that this parameter will be set by the initialisation routine. To
12561 * set a default use {@link DataTable.defaults}.
12562 * @type boolean
12563 */
12564 "bPaginate": null,
12565
12566 /**
12567 * Processing indicator enable flag whenever DataTables is enacting a
12568 * user request - typically an Ajax request for server-side processing.
12569 * Note that this parameter will be set by the initialisation routine. To
12570 * set a default use {@link DataTable.defaults}.
12571 * @type boolean
12572 */
12573 "bProcessing": null,
12574
12575 /**
12576 * Server-side processing enabled flag - when enabled DataTables will
12577 * get all data from the server for every draw - there is no filtering,
12578 * sorting or paging done on the client-side.
12579 * Note that this parameter will be set by the initialisation routine. To
12580 * set a default use {@link DataTable.defaults}.
12581 * @type boolean
12582 */
12583 "bServerSide": null,
12584
12585 /**
12586 * Sorting enablement flag.
12587 * Note that this parameter will be set by the initialisation routine. To
12588 * set a default use {@link DataTable.defaults}.
12589 * @type boolean
12590 */
12591 "bSort": null,
12592
12593 /**
12594 * Multi-column sorting
12595 * Note that this parameter will be set by the initialisation routine. To
12596 * set a default use {@link DataTable.defaults}.
12597 * @type boolean
12598 */
12599 "bSortMulti": null,
12600
12601 /**
12602 * Apply a class to the columns which are being sorted to provide a
12603 * visual highlight or not. This can slow things down when enabled since
12604 * there is a lot of DOM interaction.
12605 * Note that this parameter will be set by the initialisation routine. To
12606 * set a default use {@link DataTable.defaults}.
12607 * @type boolean
12608 */
12609 "bSortClasses": null,
12610
12611 /**
12612 * State saving enablement flag.
12613 * Note that this parameter will be set by the initialisation routine. To
12614 * set a default use {@link DataTable.defaults}.
12615 * @type boolean
12616 */
12617 "bStateSave": null
12618 },
12619
12620
12621 /**
12622 * Scrolling settings for a table.
12623 * @namespace
12624 */
12625 "oScroll": {
12626 /**
12627 * When the table is shorter in height than sScrollY, collapse the
12628 * table container down to the height of the table (when true).
12629 * Note that this parameter will be set by the initialisation routine. To
12630 * set a default use {@link DataTable.defaults}.
12631 * @type boolean
12632 */
12633 "bCollapse": null,
12634
12635 /**
12636 * Width of the scrollbar for the web-browser's platform. Calculated
12637 * during table initialisation.
12638 * @type int
12639 * @default 0
12640 */
12641 "iBarWidth": 0,
12642
12643 /**
12644 * Viewport width for horizontal scrolling. Horizontal scrolling is
12645 * disabled if an empty string.
12646 * Note that this parameter will be set by the initialisation routine. To
12647 * set a default use {@link DataTable.defaults}.
12648 * @type string
12649 */
12650 "sX": null,
12651
12652 /**
12653 * Width to expand the table to when using x-scrolling. Typically you
12654 * should not need to use this.
12655 * Note that this parameter will be set by the initialisation routine. To
12656 * set a default use {@link DataTable.defaults}.
12657 * @type string
12658 * @deprecated
12659 */
12660 "sXInner": null,
12661
12662 /**
12663 * Viewport height for vertical scrolling. Vertical scrolling is disabled
12664 * if an empty string.
12665 * Note that this parameter will be set by the initialisation routine. To
12666 * set a default use {@link DataTable.defaults}.
12667 * @type string
12668 */
12669 "sY": null
12670 },
12671
12672 /**
12673 * Language information for the table.
12674 * @namespace
12675 * @extends DataTable.defaults.oLanguage
12676 */
12677 "oLanguage": {
12678 /**
12679 * Information callback function. See
12680 * {@link DataTable.defaults.fnInfoCallback}
12681 * @type function
12682 * @default null
12683 */
12684 "fnInfoCallback": null
12685 },
12686
12687 /**
12688 * Browser support parameters
12689 * @namespace
12690 */
12691 "oBrowser": {
12692 /**
12693 * Indicate if the browser incorrectly calculates width:100% inside a
12694 * scrolling element (IE6/7)
12695 * @type boolean
12696 * @default false
12697 */
12698 "bScrollOversize": false,
12699
12700 /**
12701 * Determine if the vertical scrollbar is on the right or left of the
12702 * scrolling container - needed for rtl language layout, although not
12703 * all browsers move the scrollbar (Safari).
12704 * @type boolean
12705 * @default false
12706 */
12707 "bScrollbarLeft": false
12708 },
12709
12710
12711 "ajax": null,
12712
12713
12714 /**
12715 * Array referencing the nodes which are used for the features. The
12716 * parameters of this object match what is allowed by sDom - i.e.
12717 * <ul>
12718 * <li>'l' - Length changing</li>
12719 * <li>'f' - Filtering input</li>
12720 * <li>'t' - The table!</li>
12721 * <li>'i' - Information</li>
12722 * <li>'p' - Pagination</li>
12723 * <li>'r' - pRocessing</li>
12724 * </ul>
12725 * @type array
12726 * @default []
12727 */
12728 "aanFeatures": [],
12729
12730 /**
12731 * Store data information - see {@link DataTable.models.oRow} for detailed
12732 * information.
12733 * @type array
12734 * @default []
12735 */
12736 "aoData": [],
12737
12738 /**
12739 * Array of indexes which are in the current display (after filtering etc)
12740 * @type array
12741 * @default []
12742 */
12743 "aiDisplay": [],
12744
12745 /**
12746 * Array of indexes for display - no filtering
12747 * @type array
12748 * @default []
12749 */
12750 "aiDisplayMaster": [],
12751
12752 /**
12753 * Store information about each column that is in use
12754 * @type array
12755 * @default []
12756 */
12757 "aoColumns": [],
12758
12759 /**
12760 * Store information about the table's header
12761 * @type array
12762 * @default []
12763 */
12764 "aoHeader": [],
12765
12766 /**
12767 * Store information about the table's footer
12768 * @type array
12769 * @default []
12770 */
12771 "aoFooter": [],
12772
12773 /**
12774 * Store the applied global search information in case we want to force a
12775 * research or compare the old search to a new one.
12776 * Note that this parameter will be set by the initialisation routine. To
12777 * set a default use {@link DataTable.defaults}.
12778 * @namespace
12779 * @extends DataTable.models.oSearch
12780 */
12781 "oPreviousSearch": {},
12782
12783 /**
12784 * Store the applied search for each column - see
12785 * {@link DataTable.models.oSearch} for the format that is used for the
12786 * filtering information for each column.
12787 * @type array
12788 * @default []
12789 */
12790 "aoPreSearchCols": [],
12791
12792 /**
12793 * Sorting that is applied to the table. Note that the inner arrays are
12794 * used in the following manner:
12795 * <ul>
12796 * <li>Index 0 - column number</li>
12797 * <li>Index 1 - current sorting direction</li>
12798 * </ul>
12799 * Note that this parameter will be set by the initialisation routine. To
12800 * set a default use {@link DataTable.defaults}.
12801 * @type array
12802 * @todo These inner arrays should really be objects
12803 */
12804 "aaSorting": null,
12805
12806 /**
12807 * Sorting that is always applied to the table (i.e. prefixed in front of
12808 * aaSorting).
12809 * Note that this parameter will be set by the initialisation routine. To
12810 * set a default use {@link DataTable.defaults}.
12811 * @type array
12812 * @default []
12813 */
12814 "aaSortingFixed": [],
12815
12816 /**
12817 * Classes to use for the striping of a table.
12818 * Note that this parameter will be set by the initialisation routine. To
12819 * set a default use {@link DataTable.defaults}.
12820 * @type array
12821 * @default []
12822 */
12823 "asStripeClasses": null,
12824
12825 /**
12826 * If restoring a table - we should restore its striping classes as well
12827 * @type array
12828 * @default []
12829 */
12830 "asDestroyStripes": [],
12831
12832 /**
12833 * If restoring a table - we should restore its width
12834 * @type int
12835 * @default 0
12836 */
12837 "sDestroyWidth": 0,
12838
12839 /**
12840 * Callback functions array for every time a row is inserted (i.e. on a draw).
12841 * @type array
12842 * @default []
12843 */
12844 "aoRowCallback": [],
12845
12846 /**
12847 * Callback functions for the header on each draw.
12848 * @type array
12849 * @default []
12850 */
12851 "aoHeaderCallback": [],
12852
12853 /**
12854 * Callback function for the footer on each draw.
12855 * @type array
12856 * @default []
12857 */
12858 "aoFooterCallback": [],
12859
12860 /**
12861 * Array of callback functions for draw callback functions
12862 * @type array
12863 * @default []
12864 */
12865 "aoDrawCallback": [],
12866
12867 /**
12868 * Array of callback functions for row created function
12869 * @type array
12870 * @default []
12871 */
12872 "aoRowCreatedCallback": [],
12873
12874 /**
12875 * Callback functions for just before the table is redrawn. A return of
12876 * false will be used to cancel the draw.
12877 * @type array
12878 * @default []
12879 */
12880 "aoPreDrawCallback": [],
12881
12882 /**
12883 * Callback functions for when the table has been initialised.
12884 * @type array
12885 * @default []
12886 */
12887 "aoInitComplete": [],
12888
12889
12890 /**
12891 * Callbacks for modifying the settings to be stored for state saving, prior to
12892 * saving state.
12893 * @type array
12894 * @default []
12895 */
12896 "aoStateSaveParams": [],
12897
12898 /**
12899 * Callbacks for modifying the settings that have been stored for state saving
12900 * prior to using the stored values to restore the state.
12901 * @type array
12902 * @default []
12903 */
12904 "aoStateLoadParams": [],
12905
12906 /**
12907 * Callbacks for operating on the settings object once the saved state has been
12908 * loaded
12909 * @type array
12910 * @default []
12911 */
12912 "aoStateLoaded": [],
12913
12914 /**
12915 * Cache the table ID for quick access
12916 * @type string
12917 * @default <i>Empty string</i>
12918 */
12919 "sTableId": "",
12920
12921 /**
12922 * The TABLE node for the main table
12923 * @type node
12924 * @default null
12925 */
12926 "nTable": null,
12927
12928 /**
12929 * Permanent ref to the thead element
12930 * @type node
12931 * @default null
12932 */
12933 "nTHead": null,
12934
12935 /**
12936 * Permanent ref to the tfoot element - if it exists
12937 * @type node
12938 * @default null
12939 */
12940 "nTFoot": null,
12941
12942 /**
12943 * Permanent ref to the tbody element
12944 * @type node
12945 * @default null
12946 */
12947 "nTBody": null,
12948
12949 /**
12950 * Cache the wrapper node (contains all DataTables controlled elements)
12951 * @type node
12952 * @default null
12953 */
12954 "nTableWrapper": null,
12955
12956 /**
12957 * Indicate if when using server-side processing the loading of data
12958 * should be deferred until the second draw.
12959 * Note that this parameter will be set by the initialisation routine. To
12960 * set a default use {@link DataTable.defaults}.
12961 * @type boolean
12962 * @default false
12963 */
12964 "bDeferLoading": false,
12965
12966 /**
12967 * Indicate if all required information has been read in
12968 * @type boolean
12969 * @default false
12970 */
12971 "bInitialised": false,
12972
12973 /**
12974 * Information about open rows. Each object in the array has the parameters
12975 * 'nTr' and 'nParent'
12976 * @type array
12977 * @default []
12978 */
12979 "aoOpenRows": [],
12980
12981 /**
12982 * Dictate the positioning of DataTables' control elements - see
12983 * {@link DataTable.model.oInit.sDom}.
12984 * Note that this parameter will be set by the initialisation routine. To
12985 * set a default use {@link DataTable.defaults}.
12986 * @type string
12987 * @default null
12988 */
12989 "sDom": null,
12990
12991 /**
12992 * Search delay (in mS)
12993 * @type integer
12994 * @default null
12995 */
12996 "searchDelay": null,
12997
12998 /**
12999 * Which type of pagination should be used.
13000 * Note that this parameter will be set by the initialisation routine. To
13001 * set a default use {@link DataTable.defaults}.
13002 * @type string
13003 * @default two_button
13004 */
13005 "sPaginationType": "two_button",
13006
13007 /**
13008 * The state duration (for `stateSave`) in seconds.
13009 * Note that this parameter will be set by the initialisation routine. To
13010 * set a default use {@link DataTable.defaults}.
13011 * @type int
13012 * @default 0
13013 */
13014 "iStateDuration": 0,
13015
13016 /**
13017 * Array of callback functions for state saving. Each array element is an
13018 * object with the following parameters:
13019 * <ul>
13020 * <li>function:fn - function to call. Takes two parameters, oSettings
13021 * and the JSON string to save that has been thus far created. Returns
13022 * a JSON string to be inserted into a json object
13023 * (i.e. '"param": [ 0, 1, 2]')</li>
13024 * <li>string:sName - name of callback</li>
13025 * </ul>
13026 * @type array
13027 * @default []
13028 */
13029 "aoStateSave": [],
13030
13031 /**
13032 * Array of callback functions for state loading. Each array element is an
13033 * object with the following parameters:
13034 * <ul>
13035 * <li>function:fn - function to call. Takes two parameters, oSettings
13036 * and the object stored. May return false to cancel state loading</li>
13037 * <li>string:sName - name of callback</li>
13038 * </ul>
13039 * @type array
13040 * @default []
13041 */
13042 "aoStateLoad": [],
13043
13044 /**
13045 * State that was saved. Useful for back reference
13046 * @type object
13047 * @default null
13048 */
13049 "oSavedState": null,
13050
13051 /**
13052 * State that was loaded. Useful for back reference
13053 * @type object
13054 * @default null
13055 */
13056 "oLoadedState": null,
13057
13058 /**
13059 * Source url for AJAX data for the table.
13060 * Note that this parameter will be set by the initialisation routine. To
13061 * set a default use {@link DataTable.defaults}.
13062 * @type string
13063 * @default null
13064 */
13065 "sAjaxSource": null,
13066
13067 /**
13068 * Property from a given object from which to read the table data from. This
13069 * can be an empty string (when not server-side processing), in which case
13070 * it is assumed an an array is given directly.
13071 * Note that this parameter will be set by the initialisation routine. To
13072 * set a default use {@link DataTable.defaults}.
13073 * @type string
13074 */
13075 "sAjaxDataProp": null,
13076
13077 /**
13078 * Note if draw should be blocked while getting data
13079 * @type boolean
13080 * @default true
13081 */
13082 "bAjaxDataGet": true,
13083
13084 /**
13085 * The last jQuery XHR object that was used for server-side data gathering.
13086 * This can be used for working with the XHR information in one of the
13087 * callbacks
13088 * @type object
13089 * @default null
13090 */
13091 "jqXHR": null,
13092
13093 /**
13094 * JSON returned from the server in the last Ajax request
13095 * @type object
13096 * @default undefined
13097 */
13098 "json": undefined,
13099
13100 /**
13101 * Data submitted as part of the last Ajax request
13102 * @type object
13103 * @default undefined
13104 */
13105 "oAjaxData": undefined,
13106
13107 /**
13108 * Function to get the server-side data.
13109 * Note that this parameter will be set by the initialisation routine. To
13110 * set a default use {@link DataTable.defaults}.
13111 * @type function
13112 */
13113 "fnServerData": null,
13114
13115 /**
13116 * Functions which are called prior to sending an Ajax request so extra
13117 * parameters can easily be sent to the server
13118 * @type array
13119 * @default []
13120 */
13121 "aoServerParams": [],
13122
13123 /**
13124 * Send the XHR HTTP method - GET or POST (could be PUT or DELETE if
13125 * required).
13126 * Note that this parameter will be set by the initialisation routine. To
13127 * set a default use {@link DataTable.defaults}.
13128 * @type string
13129 */
13130 "sServerMethod": null,
13131
13132 /**
13133 * Format numbers for display.
13134 * Note that this parameter will be set by the initialisation routine. To
13135 * set a default use {@link DataTable.defaults}.
13136 * @type function
13137 */
13138 "fnFormatNumber": null,
13139
13140 /**
13141 * List of options that can be used for the user selectable length menu.
13142 * Note that this parameter will be set by the initialisation routine. To
13143 * set a default use {@link DataTable.defaults}.
13144 * @type array
13145 * @default []
13146 */
13147 "aLengthMenu": null,
13148
13149 /**
13150 * Counter for the draws that the table does. Also used as a tracker for
13151 * server-side processing
13152 * @type int
13153 * @default 0
13154 */
13155 "iDraw": 0,
13156
13157 /**
13158 * Indicate if a redraw is being done - useful for Ajax
13159 * @type boolean
13160 * @default false
13161 */
13162 "bDrawing": false,
13163
13164 /**
13165 * Draw index (iDraw) of the last error when parsing the returned data
13166 * @type int
13167 * @default -1
13168 */
13169 "iDrawError": -1,
13170
13171 /**
13172 * Paging display length
13173 * @type int
13174 * @default 10
13175 */
13176 "_iDisplayLength": 10,
13177
13178 /**
13179 * Paging start point - aiDisplay index
13180 * @type int
13181 * @default 0
13182 */
13183 "_iDisplayStart": 0,
13184
13185 /**
13186 * Server-side processing - number of records in the result set
13187 * (i.e. before filtering), Use fnRecordsTotal rather than
13188 * this property to get the value of the number of records, regardless of
13189 * the server-side processing setting.
13190 * @type int
13191 * @default 0
13192 * @private
13193 */
13194 "_iRecordsTotal": 0,
13195
13196 /**
13197 * Server-side processing - number of records in the current display set
13198 * (i.e. after filtering). Use fnRecordsDisplay rather than
13199 * this property to get the value of the number of records, regardless of
13200 * the server-side processing setting.
13201 * @type boolean
13202 * @default 0
13203 * @private
13204 */
13205 "_iRecordsDisplay": 0,
13206
13207 /**
13208 * Flag to indicate if jQuery UI marking and classes should be used.
13209 * Note that this parameter will be set by the initialisation routine. To
13210 * set a default use {@link DataTable.defaults}.
13211 * @type boolean
13212 */
13213 "bJUI": null,
13214
13215 /**
13216 * The classes to use for the table
13217 * @type object
13218 * @default {}
13219 */
13220 "oClasses": {},
13221
13222 /**
13223 * Flag attached to the settings object so you can check in the draw
13224 * callback if filtering has been done in the draw. Deprecated in favour of
13225 * events.
13226 * @type boolean
13227 * @default false
13228 * @deprecated
13229 */
13230 "bFiltered": false,
13231
13232 /**
13233 * Flag attached to the settings object so you can check in the draw
13234 * callback if sorting has been done in the draw. Deprecated in favour of
13235 * events.
13236 * @type boolean
13237 * @default false
13238 * @deprecated
13239 */
13240 "bSorted": false,
13241
13242 /**
13243 * Indicate that if multiple rows are in the header and there is more than
13244 * one unique cell per column, if the top one (true) or bottom one (false)
13245 * should be used for sorting / title by DataTables.
13246 * Note that this parameter will be set by the initialisation routine. To
13247 * set a default use {@link DataTable.defaults}.
13248 * @type boolean
13249 */
13250 "bSortCellsTop": null,
13251
13252 /**
13253 * Initialisation object that is used for the table
13254 * @type object
13255 * @default null
13256 */
13257 "oInit": null,
13258
13259 /**
13260 * Destroy callback functions - for plug-ins to attach themselves to the
13261 * destroy so they can clean up markup and events.
13262 * @type array
13263 * @default []
13264 */
13265 "aoDestroyCallback": [],
13266
13267
13268 /**
13269 * Get the number of records in the current record set, before filtering
13270 * @type function
13271 */
13272 "fnRecordsTotal": function ()
13273 {
13274 return _fnDataSource( this ) == 'ssp' ?
13275 this._iRecordsTotal * 1 :
13276 this.aiDisplayMaster.length;
13277 },
13278
13279 /**
13280 * Get the number of records in the current record set, after filtering
13281 * @type function
13282 */
13283 "fnRecordsDisplay": function ()
13284 {
13285 return _fnDataSource( this ) == 'ssp' ?
13286 this._iRecordsDisplay * 1 :
13287 this.aiDisplay.length;
13288 },
13289
13290 /**
13291 * Get the display end point - aiDisplay index
13292 * @type function
13293 */
13294 "fnDisplayEnd": function ()
13295 {
13296 var
13297 len = this._iDisplayLength,
13298 start = this._iDisplayStart,
13299 calc = start + len,
13300 records = this.aiDisplay.length,
13301 features = this.oFeatures,
13302 paginate = features.bPaginate;
13303
13304 if ( features.bServerSide ) {
13305 return paginate === false || len === -1 ?
13306 start + records :
13307 Math.min( start+len, this._iRecordsDisplay );
13308 }
13309 else {
13310 return ! paginate || calc>records || len===-1 ?
13311 records :
13312 calc;
13313 }
13314 },
13315
13316 /**
13317 * The DataTables object for this table
13318 * @type object
13319 * @default null
13320 */
13321 "oInstance": null,
13322
13323 /**
13324 * Unique identifier for each instance of the DataTables object. If there
13325 * is an ID on the table node, then it takes that value, otherwise an
13326 * incrementing internal counter is used.
13327 * @type string
13328 * @default null
13329 */
13330 "sInstance": null,
13331
13332 /**
13333 * tabindex attribute value that is added to DataTables control elements, allowing
13334 * keyboard navigation of the table and its controls.
13335 */
13336 "iTabIndex": 0,
13337
13338 /**
13339 * DIV container for the footer scrolling table if scrolling
13340 */
13341 "nScrollHead": null,
13342
13343 /**
13344 * DIV container for the footer scrolling table if scrolling
13345 */
13346 "nScrollFoot": null,
13347
13348 /**
13349 * Last applied sort
13350 * @type array
13351 * @default []
13352 */
13353 "aLastSort": [],
13354
13355 /**
13356 * Stored plug-in instances
13357 * @type object
13358 * @default {}
13359 */
13360 "oPlugins": {}
13361 };
13362
13363 /**
13364 * Extension object for DataTables that is used to provide all extension
13365 * options.
13366 *
13367 * Note that the `DataTable.ext` object is available through
13368 * `jQuery.fn.dataTable.ext` where it may be accessed and manipulated. It is
13369 * also aliased to `jQuery.fn.dataTableExt` for historic reasons.
13370 * @namespace
13371 * @extends DataTable.models.ext
13372 */
13373
13374
13375 /**
13376 * DataTables extensions
13377 *
13378 * This namespace acts as a collection area for plug-ins that can be used to
13379 * extend DataTables capabilities. Indeed many of the build in methods
13380 * use this method to provide their own capabilities (sorting methods for
13381 * example).
13382 *
13383 * Note that this namespace is aliased to `jQuery.fn.dataTableExt` for legacy
13384 * reasons
13385 *
13386 * @namespace
13387 */
13388 DataTable.ext = _ext = {
13389 /**
13390 * Element class names
13391 *
13392 * @type object
13393 * @default {}
13394 */
13395 classes: {},
13396
13397
13398 /**
13399 * Error reporting.
13400 *
13401 * How should DataTables report an error. Can take the value 'alert' or
13402 * 'throw'
13403 *
13404 * @type string
13405 * @default alert
13406 */
13407 errMode: "alert",
13408
13409
13410 /**
13411 * Feature plug-ins.
13412 *
13413 * This is an array of objects which describe the feature plug-ins that are
13414 * available to DataTables. These feature plug-ins are then available for
13415 * use through the `dom` initialisation option.
13416 *
13417 * Each feature plug-in is described by an object which must have the
13418 * following properties:
13419 *
13420 * * `fnInit` - function that is used to initialise the plug-in,
13421 * * `cFeature` - a character so the feature can be enabled by the `dom`
13422 * instillation option. This is case sensitive.
13423 *
13424 * The `fnInit` function has the following input parameters:
13425 *
13426 * 1. `{object}` DataTables settings object: see
13427 * {@link DataTable.models.oSettings}
13428 *
13429 * And the following return is expected:
13430 *
13431 * * {node|null} The element which contains your feature. Note that the
13432 * return may also be void if your plug-in does not require to inject any
13433 * DOM elements into DataTables control (`dom`) - for example this might
13434 * be useful when developing a plug-in which allows table control via
13435 * keyboard entry
13436 *
13437 * @type array
13438 *
13439 * @example
13440 * $.fn.dataTable.ext.features.push( {
13441 * "fnInit": function( oSettings ) {
13442 * return new TableTools( { "oDTSettings": oSettings } );
13443 * },
13444 * "cFeature": "T"
13445 * } );
13446 */
13447 feature: [],
13448
13449
13450 /**
13451 * Row searching.
13452 *
13453 * This method of searching is complimentary to the default type based
13454 * searching, and a lot more comprehensive as it allows you complete control
13455 * over the searching logic. Each element in this array is a function
13456 * (parameters described below) that is called for every row in the table,
13457 * and your logic decides if it should be included in the searching data set
13458 * or not.
13459 *
13460 * Searching functions have the following input parameters:
13461 *
13462 * 1. `{object}` DataTables settings object: see
13463 * {@link DataTable.models.oSettings}
13464 * 2. `{array|object}` Data for the row to be processed (same as the
13465 * original format that was passed in as the data source, or an array
13466 * from a DOM data source
13467 * 3. `{int}` Row index ({@link DataTable.models.oSettings.aoData}), which
13468 * can be useful to retrieve the `TR` element if you need DOM interaction.
13469 *
13470 * And the following return is expected:
13471 *
13472 * * {boolean} Include the row in the searched result set (true) or not
13473 * (false)
13474 *
13475 * Note that as with the main search ability in DataTables, technically this
13476 * is "filtering", since it is subtractive. However, for consistency in
13477 * naming we call it searching here.
13478 *
13479 * @type array
13480 * @default []
13481 *
13482 * @example
13483 * // The following example shows custom search being applied to the
13484 * // fourth column (i.e. the data[3] index) based on two input values
13485 * // from the end-user, matching the data in a certain range.
13486 * $.fn.dataTable.ext.search.push(
13487 * function( settings, data, dataIndex ) {
13488 * var min = document.getElementById('min').value * 1;
13489 * var max = document.getElementById('max').value * 1;
13490 * var version = data[3] == "-" ? 0 : data[3]*1;
13491 *
13492 * if ( min == "" && max == "" ) {
13493 * return true;
13494 * }
13495 * else if ( min == "" && version < max ) {
13496 * return true;
13497 * }
13498 * else if ( min < version && "" == max ) {
13499 * return true;
13500 * }
13501 * else if ( min < version && version < max ) {
13502 * return true;
13503 * }
13504 * return false;
13505 * }
13506 * );
13507 */
13508 search: [],
13509
13510
13511 /**
13512 * Internal functions, exposed for used in plug-ins.
13513 *
13514 * Please note that you should not need to use the internal methods for
13515 * anything other than a plug-in (and even then, try to avoid if possible).
13516 * The internal function may change between releases.
13517 *
13518 * @type object
13519 * @default {}
13520 */
13521 internal: {},
13522
13523
13524 /**
13525 * Legacy configuration options. Enable and disable legacy options that
13526 * are available in DataTables.
13527 *
13528 * @type object
13529 */
13530 legacy: {
13531 /**
13532 * Enable / disable DataTables 1.9 compatible server-side processing
13533 * requests
13534 *
13535 * @type boolean
13536 * @default null
13537 */
13538 ajax: null
13539 },
13540
13541
13542 /**
13543 * Pagination plug-in methods.
13544 *
13545 * Each entry in this object is a function and defines which buttons should
13546 * be shown by the pagination rendering method that is used for the table:
13547 * {@link DataTable.ext.renderer.pageButton}. The renderer addresses how the
13548 * buttons are displayed in the document, while the functions here tell it
13549 * what buttons to display. This is done by returning an array of button
13550 * descriptions (what each button will do).
13551 *
13552 * Pagination types (the four built in options and any additional plug-in
13553 * options defined here) can be used through the `paginationType`
13554 * initialisation parameter.
13555 *
13556 * The functions defined take two parameters:
13557 *
13558 * 1. `{int} page` The current page index
13559 * 2. `{int} pages` The number of pages in the table
13560 *
13561 * Each function is expected to return an array where each element of the
13562 * array can be one of:
13563 *
13564 * * `first` - Jump to first page when activated
13565 * * `last` - Jump to last page when activated
13566 * * `previous` - Show previous page when activated
13567 * * `next` - Show next page when activated
13568 * * `{int}` - Show page of the index given
13569 * * `{array}` - A nested array containing the above elements to add a
13570 * containing 'DIV' element (might be useful for styling).
13571 *
13572 * Note that DataTables v1.9- used this object slightly differently whereby
13573 * an object with two functions would be defined for each plug-in. That
13574 * ability is still supported by DataTables 1.10+ to provide backwards
13575 * compatibility, but this option of use is now decremented and no longer
13576 * documented in DataTables 1.10+.
13577 *
13578 * @type object
13579 * @default {}
13580 *
13581 * @example
13582 * // Show previous, next and current page buttons only
13583 * $.fn.dataTableExt.oPagination.current = function ( page, pages ) {
13584 * return [ 'previous', page, 'next' ];
13585 * };
13586 */
13587 pager: {},
13588
13589
13590 renderer: {
13591 pageButton: {},
13592 header: {}
13593 },
13594
13595
13596 /**
13597 * Ordering plug-ins - custom data source
13598 *
13599 * The extension options for ordering of data available here is complimentary
13600 * to the default type based ordering that DataTables typically uses. It
13601 * allows much greater control over the the data that is being used to
13602 * order a column, but is necessarily therefore more complex.
13603 *
13604 * This type of ordering is useful if you want to do ordering based on data
13605 * live from the DOM (for example the contents of an 'input' element) rather
13606 * than just the static string that DataTables knows of.
13607 *
13608 * The way these plug-ins work is that you create an array of the values you
13609 * wish to be ordering for the column in question and then return that
13610 * array. The data in the array much be in the index order of the rows in
13611 * the table (not the currently ordering order!). Which order data gathering
13612 * function is run here depends on the `dt-init columns.orderDataType`
13613 * parameter that is used for the column (if any).
13614 *
13615 * The functions defined take two parameters:
13616 *
13617 * 1. `{object}` DataTables settings object: see
13618 * {@link DataTable.models.oSettings}
13619 * 2. `{int}` Target column index
13620 *
13621 * Each function is expected to return an array:
13622 *
13623 * * `{array}` Data for the column to be ordering upon
13624 *
13625 * @type array
13626 *
13627 * @example
13628 * // Ordering using `input` node values
13629 * $.fn.dataTable.ext.order['dom-text'] = function ( settings, col )
13630 * {
13631 * return this.api().column( col, {order:'index'} ).nodes().map( function ( td, i ) {
13632 * return $('input', td).val();
13633 * } );
13634 * }
13635 */
13636 order: {},
13637
13638
13639 /**
13640 * Type based plug-ins.
13641 *
13642 * Each column in DataTables has a type assigned to it, either by automatic
13643 * detection or by direct assignment using the `type` option for the column.
13644 * The type of a column will effect how it is ordering and search (plug-ins
13645 * can also make use of the column type if required).
13646 *
13647 * @namespace
13648 */
13649 type: {
13650 /**
13651 * Type detection functions.
13652 *
13653 * The functions defined in this object are used to automatically detect
13654 * a column's type, making initialisation of DataTables super easy, even
13655 * when complex data is in the table.
13656 *
13657 * The functions defined take two parameters:
13658 *
13659 * 1. `{*}` Data from the column cell to be analysed
13660 * 2. `{settings}` DataTables settings object. This can be used to
13661 * perform context specific type detection - for example detection
13662 * based on language settings such as using a comma for a decimal
13663 * place. Generally speaking the options from the settings will not
13664 * be required
13665 *
13666 * Each function is expected to return:
13667 *
13668 * * `{string|null}` Data type detected, or null if unknown (and thus
13669 * pass it on to the other type detection functions.
13670 *
13671 * @type array
13672 *
13673 * @example
13674 * // Currency type detection plug-in:
13675 * $.fn.dataTable.ext.type.detect.push(
13676 * function ( data, settings ) {
13677 * // Check the numeric part
13678 * if ( ! $.isNumeric( data.substring(1) ) ) {
13679 * return null;
13680 * }
13681 *
13682 * // Check prefixed by currency
13683 * if ( data.charAt(0) == '$' || data.charAt(0) == '£' ) {
13684 * return 'currency';
13685 * }
13686 * return null;
13687 * }
13688 * );
13689 */
13690 detect: [],
13691
13692
13693 /**
13694 * Type based search formatting.
13695 *
13696 * The type based searching functions can be used to pre-format the
13697 * data to be search on. For example, it can be used to strip HTML
13698 * tags or to de-format telephone numbers for numeric only searching.
13699 *
13700 * Note that is a search is not defined for a column of a given type,
13701 * no search formatting will be performed.
13702 *
13703 * Pre-processing of searching data plug-ins - When you assign the sType
13704 * for a column (or have it automatically detected for you by DataTables
13705 * or a type detection plug-in), you will typically be using this for
13706 * custom sorting, but it can also be used to provide custom searching
13707 * by allowing you to pre-processing the data and returning the data in
13708 * the format that should be searched upon. This is done by adding
13709 * functions this object with a parameter name which matches the sType
13710 * for that target column. This is the corollary of <i>afnSortData</i>
13711 * for searching data.
13712 *
13713 * The functions defined take a single parameter:
13714 *
13715 * 1. `{*}` Data from the column cell to be prepared for searching
13716 *
13717 * Each function is expected to return:
13718 *
13719 * * `{string|null}` Formatted string that will be used for the searching.
13720 *
13721 * @type object
13722 * @default {}
13723 *
13724 * @example
13725 * $.fn.dataTable.ext.type.search['title-numeric'] = function ( d ) {
13726 * return d.replace(/\n/g," ").replace( /<.*?>/g, "" );
13727 * }
13728 */
13729 search: {},
13730
13731
13732 /**
13733 * Type based ordering.
13734 *
13735 * The column type tells DataTables what ordering to apply to the table
13736 * when a column is sorted upon. The order for each type that is defined,
13737 * is defined by the functions available in this object.
13738 *
13739 * Each ordering option can be described by three properties added to
13740 * this object:
13741 *
13742 * * `{type}-pre` - Pre-formatting function
13743 * * `{type}-asc` - Ascending order function
13744 * * `{type}-desc` - Descending order function
13745 *
13746 * All three can be used together, only `{type}-pre` or only
13747 * `{type}-asc` and `{type}-desc` together. It is generally recommended
13748 * that only `{type}-pre` is used, as this provides the optimal
13749 * implementation in terms of speed, although the others are provided
13750 * for compatibility with existing Javascript sort functions.
13751 *
13752 * `{type}-pre`: Functions defined take a single parameter:
13753 *
13754 * 1. `{*}` Data from the column cell to be prepared for ordering
13755 *
13756 * And return:
13757 *
13758 * * `{*}` Data to be sorted upon
13759 *
13760 * `{type}-asc` and `{type}-desc`: Functions are typical Javascript sort
13761 * functions, taking two parameters:
13762 *
13763 * 1. `{*}` Data to compare to the second parameter
13764 * 2. `{*}` Data to compare to the first parameter
13765 *
13766 * And returning:
13767 *
13768 * * `{*}` Ordering match: <0 if first parameter should be sorted lower
13769 * than the second parameter, ===0 if the two parameters are equal and
13770 * >0 if the first parameter should be sorted height than the second
13771 * parameter.
13772 *
13773 * @type object
13774 * @default {}
13775 *
13776 * @example
13777 * // Numeric ordering of formatted numbers with a pre-formatter
13778 * $.extend( $.fn.dataTable.ext.type.order, {
13779 * "string-pre": function(x) {
13780 * a = (a === "-" || a === "") ? 0 : a.replace( /[^\d\-\.]/g, "" );
13781 * return parseFloat( a );
13782 * }
13783 * } );
13784 *
13785 * @example
13786 * // Case-sensitive string ordering, with no pre-formatting method
13787 * $.extend( $.fn.dataTable.ext.order, {
13788 * "string-case-asc": function(x,y) {
13789 * return ((x < y) ? -1 : ((x > y) ? 1 : 0));
13790 * },
13791 * "string-case-desc": function(x,y) {
13792 * return ((x < y) ? 1 : ((x > y) ? -1 : 0));
13793 * }
13794 * } );
13795 */
13796 order: {}
13797 },
13798
13799 /**
13800 * Unique DataTables instance counter
13801 *
13802 * @type int
13803 * @private
13804 */
13805 _unique: 0,
13806
13807
13808 //
13809 // Depreciated
13810 // The following properties are retained for backwards compatiblity only.
13811 // The should not be used in new projects and will be removed in a future
13812 // version
13813 //
13814
13815 /**
13816 * Version check function.
13817 * @type function
13818 * @depreciated Since 1.10
13819 */
13820 fnVersionCheck: DataTable.fnVersionCheck,
13821
13822
13823 /**
13824 * Index for what 'this' index API functions should use
13825 * @type int
13826 * @deprecated Since v1.10
13827 */
13828 iApiIndex: 0,
13829
13830
13831 /**
13832 * jQuery UI class container
13833 * @type object
13834 * @deprecated Since v1.10
13835 */
13836 oJUIClasses: {},
13837
13838
13839 /**
13840 * Software version
13841 * @type string
13842 * @deprecated Since v1.10
13843 */
13844 sVersion: DataTable.version
13845 };
13846
13847
13848 //
13849 // Backwards compatibility. Alias to pre 1.10 Hungarian notation counter parts
13850 //
13851 $.extend( _ext, {
13852 afnFiltering: _ext.search,
13853 aTypes: _ext.type.detect,
13854 ofnSearch: _ext.type.search,
13855 oSort: _ext.type.order,
13856 afnSortData: _ext.order,
13857 aoFeatures: _ext.feature,
13858 oApi: _ext.internal,
13859 oStdClasses: _ext.classes,
13860 oPagination: _ext.pager
13861 } );
13862
13863
13864 $.extend( DataTable.ext.classes, {
13865 "sTable": "dataTable",
13866 "sNoFooter": "no-footer",
13867
13868 /* Paging buttons */
13869 "sPageButton": "paginate_button",
13870 "sPageButtonActive": "current",
13871 "sPageButtonDisabled": "disabled",
13872
13873 /* Striping classes */
13874 "sStripeOdd": "odd",
13875 "sStripeEven": "even",
13876
13877 /* Empty row */
13878 "sRowEmpty": "dataTables_empty",
13879
13880 /* Features */
13881 "sWrapper": "dataTables_wrapper",
13882 "sFilter": "dataTables_filter",
13883 "sInfo": "dataTables_info",
13884 "sPaging": "dataTables_paginate paging_", /* Note that the type is postfixed */
13885 "sLength": "dataTables_length",
13886 "sProcessing": "dataTables_processing",
13887
13888 /* Sorting */
13889 "sSortAsc": "sorting_asc",
13890 "sSortDesc": "sorting_desc",
13891 "sSortable": "sorting", /* Sortable in both directions */
13892 "sSortableAsc": "sorting_asc_disabled",
13893 "sSortableDesc": "sorting_desc_disabled",
13894 "sSortableNone": "sorting_disabled",
13895 "sSortColumn": "sorting_", /* Note that an int is postfixed for the sorting order */
13896
13897 /* Filtering */
13898 "sFilterInput": "",
13899
13900 /* Page length */
13901 "sLengthSelect": "",
13902
13903 /* Scrolling */
13904 "sScrollWrapper": "dataTables_scroll",
13905 "sScrollHead": "dataTables_scrollHead",
13906 "sScrollHeadInner": "dataTables_scrollHeadInner",
13907 "sScrollBody": "dataTables_scrollBody",
13908 "sScrollFoot": "dataTables_scrollFoot",
13909 "sScrollFootInner": "dataTables_scrollFootInner",
13910
13911 /* Misc */
13912 "sHeaderTH": "",
13913 "sFooterTH": "",
13914
13915 // Deprecated
13916 "sSortJUIAsc": "",
13917 "sSortJUIDesc": "",
13918 "sSortJUI": "",
13919 "sSortJUIAscAllowed": "",
13920 "sSortJUIDescAllowed": "",
13921 "sSortJUIWrapper": "",
13922 "sSortIcon": "",
13923 "sJUIHeader": "",
13924 "sJUIFooter": ""
13925 } );
13926
13927
13928 (function() {
13929
13930 // Reused strings for better compression. Closure compiler appears to have a
13931 // weird edge case where it is trying to expand strings rather than use the
13932 // variable version. This results in about 200 bytes being added, for very
13933 // little preference benefit since it this run on script load only.
13934 var _empty = '';
13935 _empty = '';
13936
13937 var _stateDefault = _empty + 'ui-state-default';
13938 var _sortIcon = _empty + 'css_right ui-icon ui-icon-';
13939 var _headerFooter = _empty + 'fg-toolbar ui-toolbar ui-widget-header ui-helper-clearfix';
13940
13941 $.extend( DataTable.ext.oJUIClasses, DataTable.ext.classes, {
13942 /* Full numbers paging buttons */
13943 "sPageButton": "fg-button ui-button "+_stateDefault,
13944 "sPageButtonActive": "ui-state-disabled",
13945 "sPageButtonDisabled": "ui-state-disabled",
13946
13947 /* Features */
13948 "sPaging": "dataTables_paginate fg-buttonset ui-buttonset fg-buttonset-multi "+
13949 "ui-buttonset-multi paging_", /* Note that the type is postfixed */
13950
13951 /* Sorting */
13952 "sSortAsc": _stateDefault+" sorting_asc",
13953 "sSortDesc": _stateDefault+" sorting_desc",
13954 "sSortable": _stateDefault+" sorting",
13955 "sSortableAsc": _stateDefault+" sorting_asc_disabled",
13956 "sSortableDesc": _stateDefault+" sorting_desc_disabled",
13957 "sSortableNone": _stateDefault+" sorting_disabled",
13958 "sSortJUIAsc": _sortIcon+"triangle-1-n",
13959 "sSortJUIDesc": _sortIcon+"triangle-1-s",
13960 "sSortJUI": _sortIcon+"carat-2-n-s",
13961 "sSortJUIAscAllowed": _sortIcon+"carat-1-n",
13962 "sSortJUIDescAllowed": _sortIcon+"carat-1-s",
13963 "sSortJUIWrapper": "DataTables_sort_wrapper",
13964 "sSortIcon": "DataTables_sort_icon",
13965
13966 /* Scrolling */
13967 "sScrollHead": "dataTables_scrollHead "+_stateDefault,
13968 "sScrollFoot": "dataTables_scrollFoot "+_stateDefault,
13969
13970 /* Misc */
13971 "sHeaderTH": _stateDefault,
13972 "sFooterTH": _stateDefault,
13973 "sJUIHeader": _headerFooter+" ui-corner-tl ui-corner-tr",
13974 "sJUIFooter": _headerFooter+" ui-corner-bl ui-corner-br"
13975 } );
13976
13977 }());
13978
13979
13980
13981 var extPagination = DataTable.ext.pager;
13982
13983 function _numbers ( page, pages ) {
13984 var
13985 numbers = [],
13986 buttons = extPagination.numbers_length,
13987 half = Math.floor( buttons / 2 ),
13988 i = 1;
13989
13990 if ( pages <= buttons ) {
13991 numbers = _range( 0, pages );
13992 }
13993 else if ( page <= half ) {
13994 numbers = _range( 0, buttons-2 );
13995 numbers.push( 'ellipsis' );
13996 numbers.push( pages-1 );
13997 }
13998 else if ( page >= pages - 1 - half ) {
13999 numbers = _range( pages-(buttons-2), pages );
14000 numbers.splice( 0, 0, 'ellipsis' ); // no unshift in ie6
14001 numbers.splice( 0, 0, 0 );
14002 }
14003 else {
14004 numbers = _range( page-1, page+2 );
14005 numbers.push( 'ellipsis' );
14006 numbers.push( pages-1 );
14007 numbers.splice( 0, 0, 'ellipsis' );
14008 numbers.splice( 0, 0, 0 );
14009 }
14010
14011 numbers.DT_el = 'span';
14012 return numbers;
14013 }
14014
14015
14016 $.extend( extPagination, {
14017 simple: function ( page, pages ) {
14018 return [ 'previous', 'next' ];
14019 },
14020
14021 full: function ( page, pages ) {
14022 return [ 'first', 'previous', 'next', 'last' ];
14023 },
14024
14025 simple_numbers: function ( page, pages ) {
14026 return [ 'previous', _numbers(page, pages), 'next' ];
14027 },
14028
14029 full_numbers: function ( page, pages ) {
14030 return [ 'first', 'previous', _numbers(page, pages), 'next', 'last' ];
14031 },
14032
14033 // For testing and plug-ins to use
14034 _numbers: _numbers,
14035 numbers_length: 7
14036 } );
14037
14038
14039 $.extend( true, DataTable.ext.renderer, {
14040 pageButton: {
14041 _: function ( settings, host, idx, buttons, page, pages ) {
14042 var classes = settings.oClasses;
14043 var lang = settings.oLanguage.oPaginate;
14044 var btnDisplay, btnClass, counter=0;
14045
14046 var attach = function( container, buttons ) {
14047 var i, ien, node, button;
14048 var clickHandler = function ( e ) {
14049 _fnPageChange( settings, e.data.action, true );
14050 };
14051
14052 for ( i=0, ien=buttons.length ; i<ien ; i++ ) {
14053 button = buttons[i];
14054
14055 if ( $.isArray( button ) ) {
14056 var inner = $( '<'+(button.DT_el || 'div')+'/>' )
14057 .appendTo( container );
14058 attach( inner, button );
14059 }
14060 else {
14061 btnDisplay = '';
14062 btnClass = '';
14063
14064 switch ( button ) {
14065 case 'ellipsis':
14066 container.append('<span>…</span>');
14067 break;
14068
14069 case 'first':
14070 btnDisplay = lang.sFirst;
14071 btnClass = button + (page > 0 ?
14072 '' : ' '+classes.sPageButtonDisabled);
14073 break;
14074
14075 case 'previous':
14076 btnDisplay = lang.sPrevious;
14077 btnClass = button + (page > 0 ?
14078 '' : ' '+classes.sPageButtonDisabled);
14079 break;
14080
14081 case 'next':
14082 btnDisplay = lang.sNext;
14083 btnClass = button + (page < pages-1 ?
14084 '' : ' '+classes.sPageButtonDisabled);
14085 break;
14086
14087 case 'last':
14088 btnDisplay = lang.sLast;
14089 btnClass = button + (page < pages-1 ?
14090 '' : ' '+classes.sPageButtonDisabled);
14091 break;
14092
14093 default:
14094 btnDisplay = button + 1;
14095 btnClass = page === button ?
14096 classes.sPageButtonActive : '';
14097 break;
14098 }
14099
14100 if ( btnDisplay ) {
14101 node = $('<a>', {
14102 'class': classes.sPageButton+' '+btnClass,
14103 'aria-controls': settings.sTableId,
14104 'data-dt-idx': counter,
14105 'tabindex': settings.iTabIndex,
14106 'id': idx === 0 && typeof button === 'string' ?
14107 settings.sTableId +'_'+ button :
14108 null
14109 } )
14110 .html( btnDisplay )
14111 .appendTo( container );
14112
14113 _fnBindAction(
14114 node, {action: button}, clickHandler
14115 );
14116
14117 counter++;
14118 }
14119 }
14120 }
14121 };
14122
14123 // IE9 throws an 'unknown error' if document.activeElement is used
14124 // inside an iframe or frame. Try / catch the error. Not good for
14125 // accessibility, but neither are frames.
14126 try {
14127 // Because this approach is destroying and recreating the paging
14128 // elements, focus is lost on the select button which is bad for
14129 // accessibility. So we want to restore focus once the draw has
14130 // completed
14131 var activeEl = $(document.activeElement).data('dt-idx');
14132
14133 attach( $(host).empty(), buttons );
14134
14135 if ( activeEl !== null ) {
14136 $(host).find( '[data-dt-idx='+activeEl+']' ).focus();
14137 }
14138 }
14139 catch (e) {}
14140 }
14141 }
14142 } );
14143
14144
14145
14146 // Built in type detection. See model.ext.aTypes for information about
14147 // what is required from this methods.
14148 $.extend( DataTable.ext.type.detect, [
14149 // Plain numbers - first since V8 detects some plain numbers as dates
14150 // e.g. Date.parse('55') (but not all, e.g. Date.parse('22')...).
14151 function ( d, settings )
14152 {
14153 var decimal = settings.oLanguage.sDecimal;
14154 return _isNumber( d, decimal ) ? 'num'+decimal : null;
14155 },
14156
14157 // Dates (only those recognised by the browser's Date.parse)
14158 function ( d, settings )
14159 {
14160 // V8 will remove any unknown characters at the start and end of the
14161 // expression, leading to false matches such as `$245.12` or `10%` being
14162 // a valid date. See forum thread 18941 for detail.
14163 if ( d && !(d instanceof Date) && ( ! _re_date_start.test(d) || ! _re_date_end.test(d) ) ) {
14164 return null;
14165 }
14166 var parsed = Date.parse(d);
14167 return (parsed !== null && !isNaN(parsed)) || _empty(d) ? 'date' : null;
14168 },
14169
14170 // Formatted numbers
14171 function ( d, settings )
14172 {
14173 var decimal = settings.oLanguage.sDecimal;
14174 return _isNumber( d, decimal, true ) ? 'num-fmt'+decimal : null;
14175 },
14176
14177 // HTML numeric
14178 function ( d, settings )
14179 {
14180 var decimal = settings.oLanguage.sDecimal;
14181 return _htmlNumeric( d, decimal ) ? 'html-num'+decimal : null;
14182 },
14183
14184 // HTML numeric, formatted
14185 function ( d, settings )
14186 {
14187 var decimal = settings.oLanguage.sDecimal;
14188 return _htmlNumeric( d, decimal, true ) ? 'html-num-fmt'+decimal : null;
14189 },
14190
14191 // HTML (this is strict checking - there must be html)
14192 function ( d, settings )
14193 {
14194 return _empty( d ) || (typeof d === 'string' && d.indexOf('<') !== -1) ?
14195 'html' : null;
14196 }
14197 ] );
14198
14199
14200
14201 // Filter formatting functions. See model.ext.ofnSearch for information about
14202 // what is required from these methods.
14203 //
14204 // Note that additional search methods are added for the html numbers and
14205 // html formatted numbers by `_addNumericSort()` when we know what the decimal
14206 // place is
14207
14208
14209 $.extend( DataTable.ext.type.search, {
14210 html: function ( data ) {
14211 return _empty(data) ?
14212 data :
14213 typeof data === 'string' ?
14214 data
14215 .replace( _re_new_lines, " " )
14216 .replace( _re_html, "" ) :
14217 '';
14218 },
14219
14220 string: function ( data ) {
14221 return _empty(data) ?
14222 data :
14223 typeof data === 'string' ?
14224 data.replace( _re_new_lines, " " ) :
14225 data;
14226 }
14227 } );
14228
14229
14230
14231 var __numericReplace = function ( d, decimalPlace, re1, re2 ) {
14232 if ( d !== 0 && (!d || d === '-') ) {
14233 return -Infinity;
14234 }
14235
14236 // If a decimal place other than `.` is used, it needs to be given to the
14237 // function so we can detect it and replace with a `.` which is the only
14238 // decimal place Javascript recognises - it is not locale aware.
14239 if ( decimalPlace ) {
14240 d = _numToDecimal( d, decimalPlace );
14241 }
14242
14243 if ( d.replace ) {
14244 if ( re1 ) {
14245 d = d.replace( re1, '' );
14246 }
14247
14248 if ( re2 ) {
14249 d = d.replace( re2, '' );
14250 }
14251 }
14252
14253 return d * 1;
14254 };
14255
14256
14257 // Add the numeric 'deformatting' functions for sorting and search. This is done
14258 // in a function to provide an easy ability for the language options to add
14259 // additional methods if a non-period decimal place is used.
14260 function _addNumericSort ( decimalPlace ) {
14261 $.each(
14262 {
14263 // Plain numbers
14264 "num": function ( d ) {
14265 return __numericReplace( d, decimalPlace );
14266 },
14267
14268 // Formatted numbers
14269 "num-fmt": function ( d ) {
14270 return __numericReplace( d, decimalPlace, _re_formatted_numeric );
14271 },
14272
14273 // HTML numeric
14274 "html-num": function ( d ) {
14275 return __numericReplace( d, decimalPlace, _re_html );
14276 },
14277
14278 // HTML numeric, formatted
14279 "html-num-fmt": function ( d ) {
14280 return __numericReplace( d, decimalPlace, _re_html, _re_formatted_numeric );
14281 }
14282 },
14283 function ( key, fn ) {
14284 // Add the ordering method
14285 _ext.type.order[ key+decimalPlace+'-pre' ] = fn;
14286
14287 // For HTML types add a search formatter that will strip the HTML
14288 if ( key.match(/^html\-/) ) {
14289 _ext.type.search[ key+decimalPlace ] = _ext.type.search.html;
14290 }
14291 }
14292 );
14293 }
14294
14295
14296 // Default sort methods
14297 $.extend( _ext.type.order, {
14298 // Dates
14299 "date-pre": function ( d ) {
14300 return Date.parse( d ) || 0;
14301 },
14302
14303 // html
14304 "html-pre": function ( a ) {
14305 return _empty(a) ?
14306 '' :
14307 a.replace ?
14308 a.replace( /<.*?>/g, "" ).toLowerCase() :
14309 a+'';
14310 },
14311
14312 // string
14313 "string-pre": function ( a ) {
14314 // This is a little complex, but faster than always calling toString,
14315 // http://jsperf.com/tostring-v-check
14316 return _empty(a) ?
14317 '' :
14318 typeof a === 'string' ?
14319 a.toLowerCase() :
14320 ! a.toString ?
14321 '' :
14322 a.toString();
14323 },
14324
14325 // string-asc and -desc are retained only for compatibility with the old
14326 // sort methods
14327 "string-asc": function ( x, y ) {
14328 return ((x < y) ? -1 : ((x > y) ? 1 : 0));
14329 },
14330
14331 "string-desc": function ( x, y ) {
14332 return ((x < y) ? 1 : ((x > y) ? -1 : 0));
14333 }
14334 } );
14335
14336
14337 // Numeric sorting types - order doesn't matter here
14338 _addNumericSort( '' );
14339
14340
14341 $.extend( true, DataTable.ext.renderer, {
14342 header: {
14343 _: function ( settings, cell, column, classes ) {
14344 // No additional mark-up required
14345 // Attach a sort listener to update on sort - note that using the
14346 // `DT` namespace will allow the event to be removed automatically
14347 // on destroy, while the `dt` namespaced event is the one we are
14348 // listening for
14349 $(settings.nTable).on( 'order.dt.DT', function ( e, ctx, sorting, columns ) {
14350 if ( settings !== ctx ) { // need to check this this is the host
14351 return; // table, not a nested one
14352 }
14353
14354 var colIdx = column.idx;
14355
14356 cell
14357 .removeClass(
14358 column.sSortingClass +' '+
14359 classes.sSortAsc +' '+
14360 classes.sSortDesc
14361 )
14362 .addClass( columns[ colIdx ] == 'asc' ?
14363 classes.sSortAsc : columns[ colIdx ] == 'desc' ?
14364 classes.sSortDesc :
14365 column.sSortingClass
14366 );
14367 } );
14368 },
14369
14370 jqueryui: function ( settings, cell, column, classes ) {
14371 $('<div/>')
14372 .addClass( classes.sSortJUIWrapper )
14373 .append( cell.contents() )
14374 .append( $('<span/>')
14375 .addClass( classes.sSortIcon+' '+column.sSortingClassJUI )
14376 )
14377 .appendTo( cell );
14378
14379 // Attach a sort listener to update on sort
14380 $(settings.nTable).on( 'order.dt.DT', function ( e, ctx, sorting, columns ) {
14381 if ( settings !== ctx ) {
14382 return;
14383 }
14384
14385 var colIdx = column.idx;
14386
14387 cell
14388 .removeClass( classes.sSortAsc +" "+classes.sSortDesc )
14389 .addClass( columns[ colIdx ] == 'asc' ?
14390 classes.sSortAsc : columns[ colIdx ] == 'desc' ?
14391 classes.sSortDesc :
14392 column.sSortingClass
14393 );
14394
14395 cell
14396 .find( 'span.'+classes.sSortIcon )
14397 .removeClass(
14398 classes.sSortJUIAsc +" "+
14399 classes.sSortJUIDesc +" "+
14400 classes.sSortJUI +" "+
14401 classes.sSortJUIAscAllowed +" "+
14402 classes.sSortJUIDescAllowed
14403 )
14404 .addClass( columns[ colIdx ] == 'asc' ?
14405 classes.sSortJUIAsc : columns[ colIdx ] == 'desc' ?
14406 classes.sSortJUIDesc :
14407 column.sSortingClassJUI
14408 );
14409 } );
14410 }
14411 }
14412 } );
14413
14414 /*
14415 * Public helper functions. These aren't used internally by DataTables, or
14416 * called by any of the options passed into DataTables, but they can be used
14417 * externally by developers working with DataTables. They are helper functions
14418 * to make working with DataTables a little bit easier.
14419 */
14420
14421 /**
14422 * Helpers for `columns.render`.
14423 *
14424 * The options defined here can be used with the `columns.render` initialisation
14425 * option to provide a display renderer. The following functions are defined:
14426 *
14427 * * `number` - Will format numeric data (defined by `columns.data`) for
14428 * display, retaining the original unformatted data for sorting and filtering.
14429 * It takes 4 parameters:
14430 * * `string` - Thousands grouping separator
14431 * * `string` - Decimal point indicator
14432 * * `integer` - Number of decimal points to show
14433 * * `string` (optional) - Prefix.
14434 *
14435 * @example
14436 * // Column definition using the number renderer
14437 * {
14438 * data: "salary",
14439 * render: $.fn.dataTable.render.number( '\'', '.', 0, '$' )
14440 * }
14441 *
14442 * @namespace
14443 */
14444 DataTable.render = {
14445 number: function ( thousands, decimal, precision, prefix ) {
14446 return {
14447 display: function ( d ) {
14448 var negative = d < 0 ? '-' : '';
14449 d = Math.abs( parseFloat( d ) );
14450
14451 var intPart = parseInt( d, 10 );
14452 var floatPart = precision ?
14453 decimal+(d - intPart).toFixed( precision ).substring( 2 ):
14454 '';
14455
14456 return negative + (prefix||'') +
14457 intPart.toString().replace(
14458 /\B(?=(\d{3})+(?!\d))/g, thousands
14459 ) +
14460 floatPart;
14461 }
14462 };
14463 }
14464 };
14465
14466
14467 /*
14468 * This is really a good bit rubbish this method of exposing the internal methods
14469 * publicly... - To be fixed in 2.0 using methods on the prototype
14470 */
14471
14472
14473 /**
14474 * Create a wrapper function for exporting an internal functions to an external API.
14475 * @param {string} fn API function name
14476 * @returns {function} wrapped function
14477 * @memberof DataTable#internal
14478 */
14479 function _fnExternApiFunc (fn)
14480 {
14481 return function() {
14482 var args = [_fnSettingsFromNode( this[DataTable.ext.iApiIndex] )].concat(
14483 Array.prototype.slice.call(arguments)
14484 );
14485 return DataTable.ext.internal[fn].apply( this, args );
14486 };
14487 }
14488
14489
14490 /**
14491 * Reference to internal functions for use by plug-in developers. Note that
14492 * these methods are references to internal functions and are considered to be
14493 * private. If you use these methods, be aware that they are liable to change
14494 * between versions.
14495 * @namespace
14496 */
14497 $.extend( DataTable.ext.internal, {
14498 _fnExternApiFunc: _fnExternApiFunc,
14499 _fnBuildAjax: _fnBuildAjax,
14500 _fnAjaxUpdate: _fnAjaxUpdate,
14501 _fnAjaxParameters: _fnAjaxParameters,
14502 _fnAjaxUpdateDraw: _fnAjaxUpdateDraw,
14503 _fnAjaxDataSrc: _fnAjaxDataSrc,
14504 _fnAddColumn: _fnAddColumn,
14505 _fnColumnOptions: _fnColumnOptions,
14506 _fnAdjustColumnSizing: _fnAdjustColumnSizing,
14507 _fnVisibleToColumnIndex: _fnVisibleToColumnIndex,
14508 _fnColumnIndexToVisible: _fnColumnIndexToVisible,
14509 _fnVisbleColumns: _fnVisbleColumns,
14510 _fnGetColumns: _fnGetColumns,
14511 _fnColumnTypes: _fnColumnTypes,
14512 _fnApplyColumnDefs: _fnApplyColumnDefs,
14513 _fnHungarianMap: _fnHungarianMap,
14514 _fnCamelToHungarian: _fnCamelToHungarian,
14515 _fnLanguageCompat: _fnLanguageCompat,
14516 _fnBrowserDetect: _fnBrowserDetect,
14517 _fnAddData: _fnAddData,
14518 _fnAddTr: _fnAddTr,
14519 _fnNodeToDataIndex: _fnNodeToDataIndex,
14520 _fnNodeToColumnIndex: _fnNodeToColumnIndex,
14521 _fnGetCellData: _fnGetCellData,
14522 _fnSetCellData: _fnSetCellData,
14523 _fnSplitObjNotation: _fnSplitObjNotation,
14524 _fnGetObjectDataFn: _fnGetObjectDataFn,
14525 _fnSetObjectDataFn: _fnSetObjectDataFn,
14526 _fnGetDataMaster: _fnGetDataMaster,
14527 _fnClearTable: _fnClearTable,
14528 _fnDeleteIndex: _fnDeleteIndex,
14529 _fnInvalidate: _fnInvalidate,
14530 _fnGetRowElements: _fnGetRowElements,
14531 _fnCreateTr: _fnCreateTr,
14532 _fnBuildHead: _fnBuildHead,
14533 _fnDrawHead: _fnDrawHead,
14534 _fnDraw: _fnDraw,
14535 _fnReDraw: _fnReDraw,
14536 _fnAddOptionsHtml: _fnAddOptionsHtml,
14537 _fnDetectHeader: _fnDetectHeader,
14538 _fnGetUniqueThs: _fnGetUniqueThs,
14539 _fnFeatureHtmlFilter: _fnFeatureHtmlFilter,
14540 _fnFilterComplete: _fnFilterComplete,
14541 _fnFilterCustom: _fnFilterCustom,
14542 _fnFilterColumn: _fnFilterColumn,
14543 _fnFilter: _fnFilter,
14544 _fnFilterCreateSearch: _fnFilterCreateSearch,
14545 _fnEscapeRegex: _fnEscapeRegex,
14546 _fnFilterData: _fnFilterData,
14547 _fnFeatureHtmlInfo: _fnFeatureHtmlInfo,
14548 _fnUpdateInfo: _fnUpdateInfo,
14549 _fnInfoMacros: _fnInfoMacros,
14550 _fnInitialise: _fnInitialise,
14551 _fnInitComplete: _fnInitComplete,
14552 _fnLengthChange: _fnLengthChange,
14553 _fnFeatureHtmlLength: _fnFeatureHtmlLength,
14554 _fnFeatureHtmlPaginate: _fnFeatureHtmlPaginate,
14555 _fnPageChange: _fnPageChange,
14556 _fnFeatureHtmlProcessing: _fnFeatureHtmlProcessing,
14557 _fnProcessingDisplay: _fnProcessingDisplay,
14558 _fnFeatureHtmlTable: _fnFeatureHtmlTable,
14559 _fnScrollDraw: _fnScrollDraw,
14560 _fnApplyToChildren: _fnApplyToChildren,
14561 _fnCalculateColumnWidths: _fnCalculateColumnWidths,
14562 _fnThrottle: _fnThrottle,
14563 _fnConvertToWidth: _fnConvertToWidth,
14564 _fnScrollingWidthAdjust: _fnScrollingWidthAdjust,
14565 _fnGetWidestNode: _fnGetWidestNode,
14566 _fnGetMaxLenString: _fnGetMaxLenString,
14567 _fnStringToCss: _fnStringToCss,
14568 _fnScrollBarWidth: _fnScrollBarWidth,
14569 _fnSortFlatten: _fnSortFlatten,
14570 _fnSort: _fnSort,
14571 _fnSortAria: _fnSortAria,
14572 _fnSortListener: _fnSortListener,
14573 _fnSortAttachListener: _fnSortAttachListener,
14574 _fnSortingClasses: _fnSortingClasses,
14575 _fnSortData: _fnSortData,
14576 _fnSaveState: _fnSaveState,
14577 _fnLoadState: _fnLoadState,
14578 _fnSettingsFromNode: _fnSettingsFromNode,
14579 _fnLog: _fnLog,
14580 _fnMap: _fnMap,
14581 _fnBindAction: _fnBindAction,
14582 _fnCallbackReg: _fnCallbackReg,
14583 _fnCallbackFire: _fnCallbackFire,
14584 _fnLengthOverflow: _fnLengthOverflow,
14585 _fnRenderer: _fnRenderer,
14586 _fnDataSource: _fnDataSource,
14587 _fnRowAttributes: _fnRowAttributes,
14588 _fnCalculateEnd: function () {} // Used by a lot of plug-ins, but redundant
14589 // in 1.10, so this dead-end function is
14590 // added to prevent errors
14591 } );
14592
14593
14594 // jQuery access
14595 $.fn.dataTable = DataTable;
14596
14597 // Legacy aliases
14598 $.fn.dataTableSettings = DataTable.settings;
14599 $.fn.dataTableExt = DataTable.ext;
14600
14601 // With a capital `D` we return a DataTables API instance rather than a
14602 // jQuery object
14603 $.fn.DataTable = function ( opts ) {
14604 return $(this).dataTable( opts ).api();
14605 };
14606
14607 // All properties that are available to $.fn.dataTable should also be
14608 // available on $.fn.DataTable
14609 $.each( DataTable, function ( prop, val ) {
14610 $.fn.DataTable[ prop ] = val;
14611 } );
14612
14613
14614 // Information about events fired by DataTables - for documentation.
14615 /**
14616 * Draw event, fired whenever the table is redrawn on the page, at the same
14617 * point as fnDrawCallback. This may be useful for binding events or
14618 * performing calculations when the table is altered at all.
14619 * @name DataTable#draw.dt
14620 * @event
14621 * @param {event} e jQuery event object
14622 * @param {object} o DataTables settings object {@link DataTable.models.oSettings}
14623 */
14624
14625 /**
14626 * Search event, fired when the searching applied to the table (using the
14627 * built-in global search, or column filters) is altered.
14628 * @name DataTable#search.dt
14629 * @event
14630 * @param {event} e jQuery event object
14631 * @param {object} o DataTables settings object {@link DataTable.models.oSettings}
14632 */
14633
14634 /**
14635 * Page change event, fired when the paging of the table is altered.
14636 * @name DataTable#page.dt
14637 * @event
14638 * @param {event} e jQuery event object
14639 * @param {object} o DataTables settings object {@link DataTable.models.oSettings}
14640 */
14641
14642 /**
14643 * Order event, fired when the ordering applied to the table is altered.
14644 * @name DataTable#order.dt
14645 * @event
14646 * @param {event} e jQuery event object
14647 * @param {object} o DataTables settings object {@link DataTable.models.oSettings}
14648 */
14649
14650 /**
14651 * DataTables initialisation complete event, fired when the table is fully
14652 * drawn, including Ajax data loaded, if Ajax data is required.
14653 * @name DataTable#init.dt
14654 * @event
14655 * @param {event} e jQuery event object
14656 * @param {object} oSettings DataTables settings object
14657 * @param {object} json The JSON object request from the server - only
14658 * present if client-side Ajax sourced data is used</li></ol>
14659 */
14660
14661 /**
14662 * State save event, fired when the table has changed state a new state save
14663 * is required. This event allows modification of the state saving object
14664 * prior to actually doing the save, including addition or other state
14665 * properties (for plug-ins) or modification of a DataTables core property.
14666 * @name DataTable#stateSaveParams.dt
14667 * @event
14668 * @param {event} e jQuery event object
14669 * @param {object} oSettings DataTables settings object
14670 * @param {object} json The state information to be saved
14671 */
14672
14673 /**
14674 * State load event, fired when the table is loading state from the stored
14675 * data, but prior to the settings object being modified by the saved state
14676 * - allowing modification of the saved state is required or loading of
14677 * state for a plug-in.
14678 * @name DataTable#stateLoadParams.dt
14679 * @event
14680 * @param {event} e jQuery event object
14681 * @param {object} oSettings DataTables settings object
14682 * @param {object} json The saved state information
14683 */
14684
14685 /**
14686 * State loaded event, fired when state has been loaded from stored data and
14687 * the settings object has been modified by the loaded data.
14688 * @name DataTable#stateLoaded.dt
14689 * @event
14690 * @param {event} e jQuery event object
14691 * @param {object} oSettings DataTables settings object
14692 * @param {object} json The saved state information
14693 */
14694
14695 /**
14696 * Processing event, fired when DataTables is doing some kind of processing
14697 * (be it, order, searcg or anything else). It can be used to indicate to
14698 * the end user that there is something happening, or that something has
14699 * finished.
14700 * @name DataTable#processing.dt
14701 * @event
14702 * @param {event} e jQuery event object
14703 * @param {object} oSettings DataTables settings object
14704 * @param {boolean} bShow Flag for if DataTables is doing processing or not
14705 */
14706
14707 /**
14708 * Ajax (XHR) event, fired whenever an Ajax request is completed from a
14709 * request to made to the server for new data. This event is called before
14710 * DataTables processed the returned data, so it can also be used to pre-
14711 * process the data returned from the server, if needed.
14712 *
14713 * Note that this trigger is called in `fnServerData`, if you override
14714 * `fnServerData` and which to use this event, you need to trigger it in you
14715 * success function.
14716 * @name DataTable#xhr.dt
14717 * @event
14718 * @param {event} e jQuery event object
14719 * @param {object} o DataTables settings object {@link DataTable.models.oSettings}
14720 * @param {object} json JSON returned from the server
14721 *
14722 * @example
14723 * // Use a custom property returned from the server in another DOM element
14724 * $('#table').dataTable().on('xhr.dt', function (e, settings, json) {
14725 * $('#status').html( json.status );
14726 * } );
14727 *
14728 * @example
14729 * // Pre-process the data returned from the server
14730 * $('#table').dataTable().on('xhr.dt', function (e, settings, json) {
14731 * for ( var i=0, ien=json.aaData.length ; i<ien ; i++ ) {
14732 * json.aaData[i].sum = json.aaData[i].one + json.aaData[i].two;
14733 * }
14734 * // Note no return - manipulate the data directly in the JSON object.
14735 * } );
14736 */
14737
14738 /**
14739 * Destroy event, fired when the DataTable is destroyed by calling fnDestroy
14740 * or passing the bDestroy:true parameter in the initialisation object. This
14741 * can be used to remove bound events, added DOM nodes, etc.
14742 * @name DataTable#destroy.dt
14743 * @event
14744 * @param {event} e jQuery event object
14745 * @param {object} o DataTables settings object {@link DataTable.models.oSettings}
14746 */
14747
14748 /**
14749 * Page length change event, fired when number of records to show on each
14750 * page (the length) is changed.
14751 * @name DataTable#length.dt
14752 * @event
14753 * @param {event} e jQuery event object
14754 * @param {object} o DataTables settings object {@link DataTable.models.oSettings}
14755 * @param {integer} len New length
14756 */
14757
14758 /**
14759 * Column sizing has changed.
14760 * @name DataTable#column-sizing.dt
14761 * @event
14762 * @param {event} e jQuery event object
14763 * @param {object} o DataTables settings object {@link DataTable.models.oSettings}
14764 */
14765
14766 /**
14767 * Column visibility has changed.
14768 * @name DataTable#column-visibility.dt
14769 * @event
14770 * @param {event} e jQuery event object
14771 * @param {object} o DataTables settings object {@link DataTable.models.oSettings}
14772 * @param {int} column Column index
14773 * @param {bool} vis `false` if column now hidden, or `true` if visible
14774 */
14775
14776 return $.fn.dataTable;
14777}));
14778
14779}(window, document));