commiting uncommited changes on live site
[weblabels.fsf.org.git] / crm.fsf.org / 20131203 / files / sites / all / modules-old / civicrm / packages / jquery / plugins / DataTables / media / js / jquery.dataTables.js
1 /*! DataTables 1.10.3
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.3
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,_fnInvalidateRow,_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 out.push( a[ order[i] ][ prop ][ prop2 ] );
214 }
215 }
216 else {
217 for ( ; i<ien ; i++ ) {
218 out.push( a[ order[i] ][ prop ] );
219 }
220 }
221
222 return out;
223 };
224
225
226 var _range = function ( len, start )
227 {
228 var out = [];
229 var end;
230
231 if ( start === undefined ) {
232 start = 0;
233 end = len;
234 }
235 else {
236 end = start;
237 start = len;
238 }
239
240 for ( var i=start ; i<end ; i++ ) {
241 out.push( i );
242 }
243
244 return out;
245 };
246
247
248 var _stripHtml = function ( d ) {
249 return d.replace( _re_html, '' );
250 };
251
252
253 /**
254 * Find the unique elements in a source array.
255 *
256 * @param {array} src Source array
257 * @return {array} Array of unique items
258 * @ignore
259 */
260 var _unique = function ( src )
261 {
262 // A faster unique method is to use object keys to identify used values,
263 // but this doesn't work with arrays or objects, which we must also
264 // consider. See jsperf.com/compare-array-unique-versions/4 for more
265 // information.
266 var
267 out = [],
268 val,
269 i, ien=src.length,
270 j, k=0;
271
272 again: for ( i=0 ; i<ien ; i++ ) {
273 val = src[i];
274
275 for ( j=0 ; j<k ; j++ ) {
276 if ( out[j] === val ) {
277 continue again;
278 }
279 }
280
281 out.push( val );
282 k++;
283 }
284
285 return out;
286 };
287
288
289
290 /**
291 * Create a mapping object that allows camel case parameters to be looked up
292 * for their Hungarian counterparts. The mapping is stored in a private
293 * parameter called `_hungarianMap` which can be accessed on the source object.
294 * @param {object} o
295 * @memberof DataTable#oApi
296 */
297 function _fnHungarianMap ( o )
298 {
299 var
300 hungarian = 'a aa ai ao as b fn i m o s ',
301 match,
302 newKey,
303 map = {};
304
305 $.each( o, function (key, val) {
306 match = key.match(/^([^A-Z]+?)([A-Z])/);
307
308 if ( match && hungarian.indexOf(match[1]+' ') !== -1 )
309 {
310 newKey = key.replace( match[0], match[2].toLowerCase() );
311 map[ newKey ] = key;
312
313 if ( match[1] === 'o' )
314 {
315 _fnHungarianMap( o[key] );
316 }
317 }
318 } );
319
320 o._hungarianMap = map;
321 }
322
323
324 /**
325 * Convert from camel case parameters to Hungarian, based on a Hungarian map
326 * created by _fnHungarianMap.
327 * @param {object} src The model object which holds all parameters that can be
328 * mapped.
329 * @param {object} user The object to convert from camel case to Hungarian.
330 * @param {boolean} force When set to `true`, properties which already have a
331 * Hungarian value in the `user` object will be overwritten. Otherwise they
332 * won't be.
333 * @memberof DataTable#oApi
334 */
335 function _fnCamelToHungarian ( src, user, force )
336 {
337 if ( ! src._hungarianMap ) {
338 _fnHungarianMap( src );
339 }
340
341 var hungarianKey;
342
343 $.each( user, function (key, val) {
344 hungarianKey = src._hungarianMap[ key ];
345
346 if ( hungarianKey !== undefined && (force || user[hungarianKey] === undefined) )
347 {
348 // For objects, we need to buzz down into the object to copy parameters
349 if ( hungarianKey.charAt(0) === 'o' )
350 {
351 // Copy the camelCase options over to the hungarian
352 if ( ! user[ hungarianKey ] ) {
353 user[ hungarianKey ] = {};
354 }
355 $.extend( true, user[hungarianKey], user[key] );
356
357 _fnCamelToHungarian( src[hungarianKey], user[hungarianKey], force );
358 }
359 else {
360 user[hungarianKey] = user[ key ];
361 }
362 }
363 } );
364 }
365
366
367 /**
368 * Language compatibility - when certain options are given, and others aren't, we
369 * need to duplicate the values over, in order to provide backwards compatibility
370 * with older language files.
371 * @param {object} oSettings dataTables settings object
372 * @memberof DataTable#oApi
373 */
374 function _fnLanguageCompat( lang )
375 {
376 var defaults = DataTable.defaults.oLanguage;
377 var zeroRecords = lang.sZeroRecords;
378
379 /* Backwards compatibility - if there is no sEmptyTable given, then use the same as
380 * sZeroRecords - assuming that is given.
381 */
382 if ( ! lang.sEmptyTable && zeroRecords &&
383 defaults.sEmptyTable === "No data available in table" )
384 {
385 _fnMap( lang, lang, 'sZeroRecords', 'sEmptyTable' );
386 }
387
388 /* Likewise with loading records */
389 if ( ! lang.sLoadingRecords && zeroRecords &&
390 defaults.sLoadingRecords === "Loading..." )
391 {
392 _fnMap( lang, lang, 'sZeroRecords', 'sLoadingRecords' );
393 }
394
395 // Old parameter name of the thousands separator mapped onto the new
396 if ( lang.sInfoThousands ) {
397 lang.sThousands = lang.sInfoThousands;
398 }
399
400 var decimal = lang.sDecimal;
401 if ( decimal ) {
402 _addNumericSort( decimal );
403 }
404 }
405
406
407 /**
408 * Map one parameter onto another
409 * @param {object} o Object to map
410 * @param {*} knew The new parameter name
411 * @param {*} old The old parameter name
412 */
413 var _fnCompatMap = function ( o, knew, old ) {
414 if ( o[ knew ] !== undefined ) {
415 o[ old ] = o[ knew ];
416 }
417 };
418
419
420 /**
421 * Provide backwards compatibility for the main DT options. Note that the new
422 * options are mapped onto the old parameters, so this is an external interface
423 * change only.
424 * @param {object} init Object to map
425 */
426 function _fnCompatOpts ( init )
427 {
428 _fnCompatMap( init, 'ordering', 'bSort' );
429 _fnCompatMap( init, 'orderMulti', 'bSortMulti' );
430 _fnCompatMap( init, 'orderClasses', 'bSortClasses' );
431 _fnCompatMap( init, 'orderCellsTop', 'bSortCellsTop' );
432 _fnCompatMap( init, 'order', 'aaSorting' );
433 _fnCompatMap( init, 'orderFixed', 'aaSortingFixed' );
434 _fnCompatMap( init, 'paging', 'bPaginate' );
435 _fnCompatMap( init, 'pagingType', 'sPaginationType' );
436 _fnCompatMap( init, 'pageLength', 'iDisplayLength' );
437 _fnCompatMap( init, 'searching', 'bFilter' );
438
439 // Column search objects are in an array, so it needs to be converted
440 // element by element
441 var searchCols = init.aoSearchCols;
442
443 if ( searchCols ) {
444 for ( var i=0, ien=searchCols.length ; i<ien ; i++ ) {
445 if ( searchCols[i] ) {
446 _fnCamelToHungarian( DataTable.models.oSearch, searchCols[i] );
447 }
448 }
449 }
450 }
451
452
453 /**
454 * Provide backwards compatibility for column options. Note that the new options
455 * are mapped onto the old parameters, so this is an external interface change
456 * only.
457 * @param {object} init Object to map
458 */
459 function _fnCompatCols ( init )
460 {
461 _fnCompatMap( init, 'orderable', 'bSortable' );
462 _fnCompatMap( init, 'orderData', 'aDataSort' );
463 _fnCompatMap( init, 'orderSequence', 'asSorting' );
464 _fnCompatMap( init, 'orderDataType', 'sortDataType' );
465 }
466
467
468 /**
469 * Browser feature detection for capabilities, quirks
470 * @param {object} settings dataTables settings object
471 * @memberof DataTable#oApi
472 */
473 function _fnBrowserDetect( settings )
474 {
475 var browser = settings.oBrowser;
476
477 // Scrolling feature / quirks detection
478 var n = $('<div/>')
479 .css( {
480 position: 'absolute',
481 top: 0,
482 left: 0,
483 height: 1,
484 width: 1,
485 overflow: 'hidden'
486 } )
487 .append(
488 $('<div/>')
489 .css( {
490 position: 'absolute',
491 top: 1,
492 left: 1,
493 width: 100,
494 overflow: 'scroll'
495 } )
496 .append(
497 $('<div class="test"/>')
498 .css( {
499 width: '100%',
500 height: 10
501 } )
502 )
503 )
504 .appendTo( 'body' );
505
506 var test = n.find('.test');
507
508 // IE6/7 will oversize a width 100% element inside a scrolling element, to
509 // include the width of the scrollbar, while other browsers ensure the inner
510 // element is contained without forcing scrolling
511 browser.bScrollOversize = test[0].offsetWidth === 100;
512
513 // In rtl text layout, some browsers (most, but not all) will place the
514 // scrollbar on the left, rather than the right.
515 browser.bScrollbarLeft = test.offset().left !== 1;
516
517 n.remove();
518 }
519
520
521 /**
522 * Array.prototype reduce[Right] method, used for browsers which don't support
523 * JS 1.6. Done this way to reduce code size, since we iterate either way
524 * @param {object} settings dataTables settings object
525 * @memberof DataTable#oApi
526 */
527 function _fnReduce ( that, fn, init, start, end, inc )
528 {
529 var
530 i = start,
531 value,
532 isSet = false;
533
534 if ( init !== undefined ) {
535 value = init;
536 isSet = true;
537 }
538
539 while ( i !== end ) {
540 if ( ! that.hasOwnProperty(i) ) {
541 continue;
542 }
543
544 value = isSet ?
545 fn( value, that[i], i, that ) :
546 that[i];
547
548 isSet = true;
549 i += inc;
550 }
551
552 return value;
553 }
554
555 /**
556 * Add a column to the list used for the table with default values
557 * @param {object} oSettings dataTables settings object
558 * @param {node} nTh The th element for this column
559 * @memberof DataTable#oApi
560 */
561 function _fnAddColumn( oSettings, nTh )
562 {
563 // Add column to aoColumns array
564 var oDefaults = DataTable.defaults.column;
565 var iCol = oSettings.aoColumns.length;
566 var oCol = $.extend( {}, DataTable.models.oColumn, oDefaults, {
567 "nTh": nTh ? nTh : document.createElement('th'),
568 "sTitle": oDefaults.sTitle ? oDefaults.sTitle : nTh ? nTh.innerHTML : '',
569 "aDataSort": oDefaults.aDataSort ? oDefaults.aDataSort : [iCol],
570 "mData": oDefaults.mData ? oDefaults.mData : iCol,
571 idx: iCol
572 } );
573 oSettings.aoColumns.push( oCol );
574
575 // Add search object for column specific search. Note that the `searchCols[ iCol ]`
576 // passed into extend can be undefined. This allows the user to give a default
577 // with only some of the parameters defined, and also not give a default
578 var searchCols = oSettings.aoPreSearchCols;
579 searchCols[ iCol ] = $.extend( {}, DataTable.models.oSearch, searchCols[ iCol ] );
580
581 // Use the default column options function to initialise classes etc
582 _fnColumnOptions( oSettings, iCol, null );
583 }
584
585
586 /**
587 * Apply options for a column
588 * @param {object} oSettings dataTables settings object
589 * @param {int} iCol column index to consider
590 * @param {object} oOptions object with sType, bVisible and bSearchable etc
591 * @memberof DataTable#oApi
592 */
593 function _fnColumnOptions( oSettings, iCol, oOptions )
594 {
595 var oCol = oSettings.aoColumns[ iCol ];
596 var oClasses = oSettings.oClasses;
597 var th = $(oCol.nTh);
598
599 // Try to get width information from the DOM. We can't get it from CSS
600 // as we'd need to parse the CSS stylesheet. `width` option can override
601 if ( ! oCol.sWidthOrig ) {
602 // Width attribute
603 oCol.sWidthOrig = th.attr('width') || null;
604
605 // Style attribute
606 var t = (th.attr('style') || '').match(/width:\s*(\d+[pxem%]+)/);
607 if ( t ) {
608 oCol.sWidthOrig = t[1];
609 }
610 }
611
612 /* User specified column options */
613 if ( oOptions !== undefined && oOptions !== null )
614 {
615 // Backwards compatibility
616 _fnCompatCols( oOptions );
617
618 // Map camel case parameters to their Hungarian counterparts
619 _fnCamelToHungarian( DataTable.defaults.column, oOptions );
620
621 /* Backwards compatibility for mDataProp */
622 if ( oOptions.mDataProp !== undefined && !oOptions.mData )
623 {
624 oOptions.mData = oOptions.mDataProp;
625 }
626
627 if ( oOptions.sType )
628 {
629 oCol._sManualType = oOptions.sType;
630 }
631
632 // `class` is a reserved word in Javascript, so we need to provide
633 // the ability to use a valid name for the camel case input
634 if ( oOptions.className && ! oOptions.sClass )
635 {
636 oOptions.sClass = oOptions.className;
637 }
638
639 $.extend( oCol, oOptions );
640 _fnMap( oCol, oOptions, "sWidth", "sWidthOrig" );
641
642 /* iDataSort to be applied (backwards compatibility), but aDataSort will take
643 * priority if defined
644 */
645 if ( typeof oOptions.iDataSort === 'number' )
646 {
647 oCol.aDataSort = [ oOptions.iDataSort ];
648 }
649 _fnMap( oCol, oOptions, "aDataSort" );
650 }
651
652 /* Cache the data get and set functions for speed */
653 var mDataSrc = oCol.mData;
654 var mData = _fnGetObjectDataFn( mDataSrc );
655 var mRender = oCol.mRender ? _fnGetObjectDataFn( oCol.mRender ) : null;
656
657 var attrTest = function( src ) {
658 return typeof src === 'string' && src.indexOf('@') !== -1;
659 };
660 oCol._bAttrSrc = $.isPlainObject( mDataSrc ) && (
661 attrTest(mDataSrc.sort) || attrTest(mDataSrc.type) || attrTest(mDataSrc.filter)
662 );
663
664 oCol.fnGetData = function (rowData, type, meta) {
665 var innerData = mData( rowData, type, undefined, meta );
666
667 return mRender && type ?
668 mRender( innerData, type, rowData, meta ) :
669 innerData;
670 };
671 oCol.fnSetData = function ( rowData, val, meta ) {
672 return _fnSetObjectDataFn( mDataSrc )( rowData, val, meta );
673 };
674
675 // Indicate if DataTables should read DOM data as an object or array
676 // Used in _fnGetRowElements
677 if ( typeof mDataSrc !== 'number' ) {
678 oSettings._rowReadObject = true;
679 }
680
681 /* Feature sorting overrides column specific when off */
682 if ( !oSettings.oFeatures.bSort )
683 {
684 oCol.bSortable = false;
685 th.addClass( oClasses.sSortableNone ); // Have to add class here as order event isn't called
686 }
687
688 /* Check that the class assignment is correct for sorting */
689 var bAsc = $.inArray('asc', oCol.asSorting) !== -1;
690 var bDesc = $.inArray('desc', oCol.asSorting) !== -1;
691 if ( !oCol.bSortable || (!bAsc && !bDesc) )
692 {
693 oCol.sSortingClass = oClasses.sSortableNone;
694 oCol.sSortingClassJUI = "";
695 }
696 else if ( bAsc && !bDesc )
697 {
698 oCol.sSortingClass = oClasses.sSortableAsc;
699 oCol.sSortingClassJUI = oClasses.sSortJUIAscAllowed;
700 }
701 else if ( !bAsc && bDesc )
702 {
703 oCol.sSortingClass = oClasses.sSortableDesc;
704 oCol.sSortingClassJUI = oClasses.sSortJUIDescAllowed;
705 }
706 else
707 {
708 oCol.sSortingClass = oClasses.sSortable;
709 oCol.sSortingClassJUI = oClasses.sSortJUI;
710 }
711 }
712
713
714 /**
715 * Adjust the table column widths for new data. Note: you would probably want to
716 * do a redraw after calling this function!
717 * @param {object} settings dataTables settings object
718 * @memberof DataTable#oApi
719 */
720 function _fnAdjustColumnSizing ( settings )
721 {
722 /* Not interested in doing column width calculation if auto-width is disabled */
723 if ( settings.oFeatures.bAutoWidth !== false )
724 {
725 var columns = settings.aoColumns;
726
727 _fnCalculateColumnWidths( settings );
728 for ( var i=0 , iLen=columns.length ; i<iLen ; i++ )
729 {
730 columns[i].nTh.style.width = columns[i].sWidth;
731 }
732 }
733
734 var scroll = settings.oScroll;
735 if ( scroll.sY !== '' || scroll.sX !== '')
736 {
737 _fnScrollDraw( settings );
738 }
739
740 _fnCallbackFire( settings, null, 'column-sizing', [settings] );
741 }
742
743
744 /**
745 * Covert the index of a visible column to the index in the data array (take account
746 * of hidden columns)
747 * @param {object} oSettings dataTables settings object
748 * @param {int} iMatch Visible column index to lookup
749 * @returns {int} i the data index
750 * @memberof DataTable#oApi
751 */
752 function _fnVisibleToColumnIndex( oSettings, iMatch )
753 {
754 var aiVis = _fnGetColumns( oSettings, 'bVisible' );
755
756 return typeof aiVis[iMatch] === 'number' ?
757 aiVis[iMatch] :
758 null;
759 }
760
761
762 /**
763 * Covert the index of an index in the data array and convert it to the visible
764 * column index (take account of hidden columns)
765 * @param {int} iMatch Column index to lookup
766 * @param {object} oSettings dataTables settings object
767 * @returns {int} i the data index
768 * @memberof DataTable#oApi
769 */
770 function _fnColumnIndexToVisible( oSettings, iMatch )
771 {
772 var aiVis = _fnGetColumns( oSettings, 'bVisible' );
773 var iPos = $.inArray( iMatch, aiVis );
774
775 return iPos !== -1 ? iPos : null;
776 }
777
778
779 /**
780 * Get the number of visible columns
781 * @param {object} oSettings dataTables settings object
782 * @returns {int} i the number of visible columns
783 * @memberof DataTable#oApi
784 */
785 function _fnVisbleColumns( oSettings )
786 {
787 return _fnGetColumns( oSettings, 'bVisible' ).length;
788 }
789
790
791 /**
792 * Get an array of column indexes that match a given property
793 * @param {object} oSettings dataTables settings object
794 * @param {string} sParam Parameter in aoColumns to look for - typically
795 * bVisible or bSearchable
796 * @returns {array} Array of indexes with matched properties
797 * @memberof DataTable#oApi
798 */
799 function _fnGetColumns( oSettings, sParam )
800 {
801 var a = [];
802
803 $.map( oSettings.aoColumns, function(val, i) {
804 if ( val[sParam] ) {
805 a.push( i );
806 }
807 } );
808
809 return a;
810 }
811
812
813 /**
814 * Calculate the 'type' of a column
815 * @param {object} settings dataTables settings object
816 * @memberof DataTable#oApi
817 */
818 function _fnColumnTypes ( settings )
819 {
820 var columns = settings.aoColumns;
821 var data = settings.aoData;
822 var types = DataTable.ext.type.detect;
823 var i, ien, j, jen, k, ken;
824 var col, cell, detectedType, cache;
825
826 // For each column, spin over the
827 for ( i=0, ien=columns.length ; i<ien ; i++ ) {
828 col = columns[i];
829 cache = [];
830
831 if ( ! col.sType && col._sManualType ) {
832 col.sType = col._sManualType;
833 }
834 else if ( ! col.sType ) {
835 for ( j=0, jen=types.length ; j<jen ; j++ ) {
836 for ( k=0, ken=data.length ; k<ken ; k++ ) {
837 // Use a cache array so we only need to get the type data
838 // from the formatter once (when using multiple detectors)
839 if ( cache[k] === undefined ) {
840 cache[k] = _fnGetCellData( settings, k, i, 'type' );
841 }
842
843 detectedType = types[j]( cache[k], settings );
844
845 // Doesn't match, so break early, since this type can't
846 // apply to this column. Also, HTML is a special case since
847 // it is so similar to `string`. Just a single match is
848 // needed for a column to be html type
849 if ( ! detectedType || detectedType === 'html' ) {
850 break;
851 }
852 }
853
854 // Type is valid for all data points in the column - use this
855 // type
856 if ( detectedType ) {
857 col.sType = detectedType;
858 break;
859 }
860 }
861
862 // Fall back - if no type was detected, always use string
863 if ( ! col.sType ) {
864 col.sType = 'string';
865 }
866 }
867 }
868 }
869
870
871 /**
872 * Take the column definitions and static columns arrays and calculate how
873 * they relate to column indexes. The callback function will then apply the
874 * definition found for a column to a suitable configuration object.
875 * @param {object} oSettings dataTables settings object
876 * @param {array} aoColDefs The aoColumnDefs array that is to be applied
877 * @param {array} aoCols The aoColumns array that defines columns individually
878 * @param {function} fn Callback function - takes two parameters, the calculated
879 * column index and the definition for that column.
880 * @memberof DataTable#oApi
881 */
882 function _fnApplyColumnDefs( oSettings, aoColDefs, aoCols, fn )
883 {
884 var i, iLen, j, jLen, k, kLen, def;
885 var columns = oSettings.aoColumns;
886
887 // Column definitions with aTargets
888 if ( aoColDefs )
889 {
890 /* Loop over the definitions array - loop in reverse so first instance has priority */
891 for ( i=aoColDefs.length-1 ; i>=0 ; i-- )
892 {
893 def = aoColDefs[i];
894
895 /* Each definition can target multiple columns, as it is an array */
896 var aTargets = def.targets !== undefined ?
897 def.targets :
898 def.aTargets;
899
900 if ( ! $.isArray( aTargets ) )
901 {
902 aTargets = [ aTargets ];
903 }
904
905 for ( j=0, jLen=aTargets.length ; j<jLen ; j++ )
906 {
907 if ( typeof aTargets[j] === 'number' && aTargets[j] >= 0 )
908 {
909 /* Add columns that we don't yet know about */
910 while( columns.length <= aTargets[j] )
911 {
912 _fnAddColumn( oSettings );
913 }
914
915 /* Integer, basic index */
916 fn( aTargets[j], def );
917 }
918 else if ( typeof aTargets[j] === 'number' && aTargets[j] < 0 )
919 {
920 /* Negative integer, right to left column counting */
921 fn( columns.length+aTargets[j], def );
922 }
923 else if ( typeof aTargets[j] === 'string' )
924 {
925 /* Class name matching on TH element */
926 for ( k=0, kLen=columns.length ; k<kLen ; k++ )
927 {
928 if ( aTargets[j] == "_all" ||
929 $(columns[k].nTh).hasClass( aTargets[j] ) )
930 {
931 fn( k, def );
932 }
933 }
934 }
935 }
936 }
937 }
938
939 // Statically defined columns array
940 if ( aoCols )
941 {
942 for ( i=0, iLen=aoCols.length ; i<iLen ; i++ )
943 {
944 fn( i, aoCols[i] );
945 }
946 }
947 }
948
949 /**
950 * Add a data array to the table, creating DOM node etc. This is the parallel to
951 * _fnGatherData, but for adding rows from a Javascript source, rather than a
952 * DOM source.
953 * @param {object} oSettings dataTables settings object
954 * @param {array} aData data array to be added
955 * @param {node} [nTr] TR element to add to the table - optional. If not given,
956 * DataTables will create a row automatically
957 * @param {array} [anTds] Array of TD|TH elements for the row - must be given
958 * if nTr is.
959 * @returns {int} >=0 if successful (index of new aoData entry), -1 if failed
960 * @memberof DataTable#oApi
961 */
962 function _fnAddData ( oSettings, aDataIn, nTr, anTds )
963 {
964 /* Create the object for storing information about this new row */
965 var iRow = oSettings.aoData.length;
966 var oData = $.extend( true, {}, DataTable.models.oRow, {
967 src: nTr ? 'dom' : 'data'
968 } );
969
970 oData._aData = aDataIn;
971 oSettings.aoData.push( oData );
972
973 /* Create the cells */
974 var nTd, sThisType;
975 var columns = oSettings.aoColumns;
976 for ( var i=0, iLen=columns.length ; i<iLen ; i++ )
977 {
978 // When working with a row, the data source object must be populated. In
979 // all other cases, the data source object is already populated, so we
980 // don't overwrite it, which might break bindings etc
981 if ( nTr ) {
982 _fnSetCellData( oSettings, iRow, i, _fnGetCellData( oSettings, iRow, i ) );
983 }
984 columns[i].sType = null;
985 }
986
987 /* Add to the display array */
988 oSettings.aiDisplayMaster.push( iRow );
989
990 /* Create the DOM information, or register it if already present */
991 if ( nTr || ! oSettings.oFeatures.bDeferRender )
992 {
993 _fnCreateTr( oSettings, iRow, nTr, anTds );
994 }
995
996 return iRow;
997 }
998
999
1000 /**
1001 * Add one or more TR elements to the table. Generally we'd expect to
1002 * use this for reading data from a DOM sourced table, but it could be
1003 * used for an TR element. Note that if a TR is given, it is used (i.e.
1004 * it is not cloned).
1005 * @param {object} settings dataTables settings object
1006 * @param {array|node|jQuery} trs The TR element(s) to add to the table
1007 * @returns {array} Array of indexes for the added rows
1008 * @memberof DataTable#oApi
1009 */
1010 function _fnAddTr( settings, trs )
1011 {
1012 var row;
1013
1014 // Allow an individual node to be passed in
1015 if ( ! (trs instanceof $) ) {
1016 trs = $(trs);
1017 }
1018
1019 return trs.map( function (i, el) {
1020 row = _fnGetRowElements( settings, el );
1021 return _fnAddData( settings, row.data, el, row.cells );
1022 } );
1023 }
1024
1025
1026 /**
1027 * Take a TR element and convert it to an index in aoData
1028 * @param {object} oSettings dataTables settings object
1029 * @param {node} n the TR element to find
1030 * @returns {int} index if the node is found, null if not
1031 * @memberof DataTable#oApi
1032 */
1033 function _fnNodeToDataIndex( oSettings, n )
1034 {
1035 return (n._DT_RowIndex!==undefined) ? n._DT_RowIndex : null;
1036 }
1037
1038
1039 /**
1040 * Take a TD element and convert it into a column data index (not the visible index)
1041 * @param {object} oSettings dataTables settings object
1042 * @param {int} iRow The row number the TD/TH can be found in
1043 * @param {node} n The TD/TH element to find
1044 * @returns {int} index if the node is found, -1 if not
1045 * @memberof DataTable#oApi
1046 */
1047 function _fnNodeToColumnIndex( oSettings, iRow, n )
1048 {
1049 return $.inArray( n, oSettings.aoData[ iRow ].anCells );
1050 }
1051
1052
1053 /**
1054 * Get the data for a given cell from the internal cache, taking into account data mapping
1055 * @param {object} settings dataTables settings object
1056 * @param {int} rowIdx aoData row id
1057 * @param {int} colIdx Column index
1058 * @param {string} type data get type ('display', 'type' 'filter' 'sort')
1059 * @returns {*} Cell data
1060 * @memberof DataTable#oApi
1061 */
1062 function _fnGetCellData( settings, rowIdx, colIdx, type )
1063 {
1064 var draw = settings.iDraw;
1065 var col = settings.aoColumns[colIdx];
1066 var rowData = settings.aoData[rowIdx]._aData;
1067 var defaultContent = col.sDefaultContent;
1068 var cellData = col.fnGetData( rowData, type, {
1069 settings: settings,
1070 row: rowIdx,
1071 col: colIdx
1072 } );
1073
1074 if ( cellData === undefined ) {
1075 if ( settings.iDrawError != draw && defaultContent === null ) {
1076 _fnLog( settings, 0, "Requested unknown parameter "+
1077 (typeof col.mData=='function' ? '{function}' : "'"+col.mData+"'")+
1078 " for row "+rowIdx, 4 );
1079 settings.iDrawError = draw;
1080 }
1081 return defaultContent;
1082 }
1083
1084 /* When the data source is null, we can use default column data */
1085 if ( (cellData === rowData || cellData === null) && defaultContent !== null ) {
1086 cellData = defaultContent;
1087 }
1088 else if ( typeof cellData === 'function' ) {
1089 // If the data source is a function, then we run it and use the return,
1090 // executing in the scope of the data object (for instances)
1091 return cellData.call( rowData );
1092 }
1093
1094 if ( cellData === null && type == 'display' ) {
1095 return '';
1096 }
1097 return cellData;
1098 }
1099
1100
1101 /**
1102 * Set the value for a specific cell, into the internal data cache
1103 * @param {object} settings dataTables settings object
1104 * @param {int} rowIdx aoData row id
1105 * @param {int} colIdx Column index
1106 * @param {*} val Value to set
1107 * @memberof DataTable#oApi
1108 */
1109 function _fnSetCellData( settings, rowIdx, colIdx, val )
1110 {
1111 var col = settings.aoColumns[colIdx];
1112 var rowData = settings.aoData[rowIdx]._aData;
1113
1114 col.fnSetData( rowData, val, {
1115 settings: settings,
1116 row: rowIdx,
1117 col: colIdx
1118 } );
1119 }
1120
1121
1122 // Private variable that is used to match action syntax in the data property object
1123 var __reArray = /\[.*?\]$/;
1124 var __reFn = /\(\)$/;
1125
1126 /**
1127 * Split string on periods, taking into account escaped periods
1128 * @param {string} str String to split
1129 * @return {array} Split string
1130 */
1131 function _fnSplitObjNotation( str )
1132 {
1133 return $.map( str.match(/(\\.|[^\.])+/g), function ( s ) {
1134 return s.replace(/\\./g, '.');
1135 } );
1136 }
1137
1138
1139 /**
1140 * Return a function that can be used to get data from a source object, taking
1141 * into account the ability to use nested objects as a source
1142 * @param {string|int|function} mSource The data source for the object
1143 * @returns {function} Data get function
1144 * @memberof DataTable#oApi
1145 */
1146 function _fnGetObjectDataFn( mSource )
1147 {
1148 if ( $.isPlainObject( mSource ) )
1149 {
1150 /* Build an object of get functions, and wrap them in a single call */
1151 var o = {};
1152 $.each( mSource, function (key, val) {
1153 if ( val ) {
1154 o[key] = _fnGetObjectDataFn( val );
1155 }
1156 } );
1157
1158 return function (data, type, row, meta) {
1159 var t = o[type] || o._;
1160 return t !== undefined ?
1161 t(data, type, row, meta) :
1162 data;
1163 };
1164 }
1165 else if ( mSource === null )
1166 {
1167 /* Give an empty string for rendering / sorting etc */
1168 return function (data) { // type, row and meta also passed, but not used
1169 return data;
1170 };
1171 }
1172 else if ( typeof mSource === 'function' )
1173 {
1174 return function (data, type, row, meta) {
1175 return mSource( data, type, row, meta );
1176 };
1177 }
1178 else if ( typeof mSource === 'string' && (mSource.indexOf('.') !== -1 ||
1179 mSource.indexOf('[') !== -1 || mSource.indexOf('(') !== -1) )
1180 {
1181 /* If there is a . in the source string then the data source is in a
1182 * nested object so we loop over the data for each level to get the next
1183 * level down. On each loop we test for undefined, and if found immediately
1184 * return. This allows entire objects to be missing and sDefaultContent to
1185 * be used if defined, rather than throwing an error
1186 */
1187 var fetchData = function (data, type, src) {
1188 var arrayNotation, funcNotation, out, innerSrc;
1189
1190 if ( src !== "" )
1191 {
1192 var a = _fnSplitObjNotation( src );
1193
1194 for ( var i=0, iLen=a.length ; i<iLen ; i++ )
1195 {
1196 // Check if we are dealing with special notation
1197 arrayNotation = a[i].match(__reArray);
1198 funcNotation = a[i].match(__reFn);
1199
1200 if ( arrayNotation )
1201 {
1202 // Array notation
1203 a[i] = a[i].replace(__reArray, '');
1204
1205 // Condition allows simply [] to be passed in
1206 if ( a[i] !== "" ) {
1207 data = data[ a[i] ];
1208 }
1209 out = [];
1210
1211 // Get the remainder of the nested object to get
1212 a.splice( 0, i+1 );
1213 innerSrc = a.join('.');
1214
1215 // Traverse each entry in the array getting the properties requested
1216 for ( var j=0, jLen=data.length ; j<jLen ; j++ ) {
1217 out.push( fetchData( data[j], type, innerSrc ) );
1218 }
1219
1220 // If a string is given in between the array notation indicators, that
1221 // is used to join the strings together, otherwise an array is returned
1222 var join = arrayNotation[0].substring(1, arrayNotation[0].length-1);
1223 data = (join==="") ? out : out.join(join);
1224
1225 // The inner call to fetchData has already traversed through the remainder
1226 // of the source requested, so we exit from the loop
1227 break;
1228 }
1229 else if ( funcNotation )
1230 {
1231 // Function call
1232 a[i] = a[i].replace(__reFn, '');
1233 data = data[ a[i] ]();
1234 continue;
1235 }
1236
1237 if ( data === null || data[ a[i] ] === undefined )
1238 {
1239 return undefined;
1240 }
1241 data = data[ a[i] ];
1242 }
1243 }
1244
1245 return data;
1246 };
1247
1248 return function (data, type) { // row and meta also passed, but not used
1249 return fetchData( data, type, mSource );
1250 };
1251 }
1252 else
1253 {
1254 /* Array or flat object mapping */
1255 return function (data, type) { // row and meta also passed, but not used
1256 return data[mSource];
1257 };
1258 }
1259 }
1260
1261
1262 /**
1263 * Return a function that can be used to set data from a source object, taking
1264 * into account the ability to use nested objects as a source
1265 * @param {string|int|function} mSource The data source for the object
1266 * @returns {function} Data set function
1267 * @memberof DataTable#oApi
1268 */
1269 function _fnSetObjectDataFn( mSource )
1270 {
1271 if ( $.isPlainObject( mSource ) )
1272 {
1273 /* Unlike get, only the underscore (global) option is used for for
1274 * setting data since we don't know the type here. This is why an object
1275 * option is not documented for `mData` (which is read/write), but it is
1276 * for `mRender` which is read only.
1277 */
1278 return _fnSetObjectDataFn( mSource._ );
1279 }
1280 else if ( mSource === null )
1281 {
1282 /* Nothing to do when the data source is null */
1283 return function () {};
1284 }
1285 else if ( typeof mSource === 'function' )
1286 {
1287 return function (data, val, meta) {
1288 mSource( data, 'set', val, meta );
1289 };
1290 }
1291 else if ( typeof mSource === 'string' && (mSource.indexOf('.') !== -1 ||
1292 mSource.indexOf('[') !== -1 || mSource.indexOf('(') !== -1) )
1293 {
1294 /* Like the get, we need to get data from a nested object */
1295 var setData = function (data, val, src) {
1296 var a = _fnSplitObjNotation( src ), b;
1297 var aLast = a[a.length-1];
1298 var arrayNotation, funcNotation, o, innerSrc;
1299
1300 for ( var i=0, iLen=a.length-1 ; i<iLen ; i++ )
1301 {
1302 // Check if we are dealing with an array notation request
1303 arrayNotation = a[i].match(__reArray);
1304 funcNotation = a[i].match(__reFn);
1305
1306 if ( arrayNotation )
1307 {
1308 a[i] = a[i].replace(__reArray, '');
1309 data[ a[i] ] = [];
1310
1311 // Get the remainder of the nested object to set so we can recurse
1312 b = a.slice();
1313 b.splice( 0, i+1 );
1314 innerSrc = b.join('.');
1315
1316 // Traverse each entry in the array setting the properties requested
1317 for ( var j=0, jLen=val.length ; j<jLen ; j++ )
1318 {
1319 o = {};
1320 setData( o, val[j], innerSrc );
1321 data[ a[i] ].push( o );
1322 }
1323
1324 // The inner call to setData has already traversed through the remainder
1325 // of the source and has set the data, thus we can exit here
1326 return;
1327 }
1328 else if ( funcNotation )
1329 {
1330 // Function call
1331 a[i] = a[i].replace(__reFn, '');
1332 data = data[ a[i] ]( val );
1333 }
1334
1335 // If the nested object doesn't currently exist - since we are
1336 // trying to set the value - create it
1337 if ( data[ a[i] ] === null || data[ a[i] ] === undefined )
1338 {
1339 data[ a[i] ] = {};
1340 }
1341 data = data[ a[i] ];
1342 }
1343
1344 // Last item in the input - i.e, the actual set
1345 if ( aLast.match(__reFn ) )
1346 {
1347 // Function call
1348 data = data[ aLast.replace(__reFn, '') ]( val );
1349 }
1350 else
1351 {
1352 // If array notation is used, we just want to strip it and use the property name
1353 // and assign the value. If it isn't used, then we get the result we want anyway
1354 data[ aLast.replace(__reArray, '') ] = val;
1355 }
1356 };
1357
1358 return function (data, val) { // meta is also passed in, but not used
1359 return setData( data, val, mSource );
1360 };
1361 }
1362 else
1363 {
1364 /* Array or flat object mapping */
1365 return function (data, val) { // meta is also passed in, but not used
1366 data[mSource] = val;
1367 };
1368 }
1369 }
1370
1371
1372 /**
1373 * Return an array with the full table data
1374 * @param {object} oSettings dataTables settings object
1375 * @returns array {array} aData Master data array
1376 * @memberof DataTable#oApi
1377 */
1378 function _fnGetDataMaster ( settings )
1379 {
1380 return _pluck( settings.aoData, '_aData' );
1381 }
1382
1383
1384 /**
1385 * Nuke the table
1386 * @param {object} oSettings dataTables settings object
1387 * @memberof DataTable#oApi
1388 */
1389 function _fnClearTable( settings )
1390 {
1391 settings.aoData.length = 0;
1392 settings.aiDisplayMaster.length = 0;
1393 settings.aiDisplay.length = 0;
1394 }
1395
1396
1397 /**
1398 * Take an array of integers (index array) and remove a target integer (value - not
1399 * the key!)
1400 * @param {array} a Index array to target
1401 * @param {int} iTarget value to find
1402 * @memberof DataTable#oApi
1403 */
1404 function _fnDeleteIndex( a, iTarget, splice )
1405 {
1406 var iTargetIndex = -1;
1407
1408 for ( var i=0, iLen=a.length ; i<iLen ; i++ )
1409 {
1410 if ( a[i] == iTarget )
1411 {
1412 iTargetIndex = i;
1413 }
1414 else if ( a[i] > iTarget )
1415 {
1416 a[i]--;
1417 }
1418 }
1419
1420 if ( iTargetIndex != -1 && splice === undefined )
1421 {
1422 a.splice( iTargetIndex, 1 );
1423 }
1424 }
1425
1426
1427 /**
1428 * Mark cached data as invalid such that a re-read of the data will occur when
1429 * the cached data is next requested. Also update from the data source object.
1430 *
1431 * @param {object} settings DataTables settings object
1432 * @param {int} rowIdx Row index to invalidate
1433 * @memberof DataTable#oApi
1434 *
1435 * @todo For the modularisation of v1.11 this will need to become a callback, so
1436 * the sort and filter methods can subscribe to it. That will required
1437 * initialisation options for sorting, which is why it is not already baked in
1438 */
1439 function _fnInvalidateRow( settings, rowIdx, src, column )
1440 {
1441 var row = settings.aoData[ rowIdx ];
1442 var i, ien;
1443
1444 // Are we reading last data from DOM or the data object?
1445 if ( src === 'dom' || ((! src || src === 'auto') && row.src === 'dom') ) {
1446 // Read the data from the DOM
1447 row._aData = _fnGetRowElements( settings, row ).data;
1448 }
1449 else {
1450 // Reading from data object, update the DOM
1451 var cells = row.anCells;
1452 var cell;
1453
1454 if ( cells ) {
1455 for ( i=0, ien=cells.length ; i<ien ; i++ ) {
1456 cell = cells[i];
1457
1458 // This is very frustrating, but in IE if you just write directly
1459 // to innerHTML, and elements that are overwritten are GC'ed,
1460 // even if there is a reference to them elsewhere
1461 while ( cell.childNodes.length ) {
1462 cell.removeChild( cell.firstChild );
1463 }
1464
1465 cells[i].innerHTML = _fnGetCellData( settings, rowIdx, i, 'display' );
1466 }
1467 }
1468 }
1469
1470 row._aSortData = null;
1471 row._aFilterData = null;
1472
1473 // Invalidate the type for a specific column (if given) or all columns since
1474 // the data might have changed
1475 var cols = settings.aoColumns;
1476 if ( column !== undefined ) {
1477 cols[ column ].sType = null;
1478 }
1479 else {
1480 for ( i=0, ien=cols.length ; i<ien ; i++ ) {
1481 cols[i].sType = null;
1482 }
1483 }
1484
1485 // Update DataTables special `DT_*` attributes for the row
1486 _fnRowAttributes( row );
1487 }
1488
1489
1490 /**
1491 * Build a data source object from an HTML row, reading the contents of the
1492 * cells that are in the row.
1493 *
1494 * @param {object} settings DataTables settings object
1495 * @param {node|object} TR element from which to read data or existing row
1496 * object from which to re-read the data from the cells
1497 * @returns {object} Object with two parameters: `data` the data read, in
1498 * document order, and `cells` and array of nodes (they can be useful to the
1499 * caller, so rather than needing a second traversal to get them, just return
1500 * them from here).
1501 * @memberof DataTable#oApi
1502 */
1503 function _fnGetRowElements( settings, row )
1504 {
1505 var
1506 tds = [],
1507 td = row.firstChild,
1508 name, col, o, i=0, contents,
1509 columns = settings.aoColumns,
1510 objectRead = settings._rowReadObject;
1511
1512 var d = objectRead ? {} : [];
1513
1514 var attr = function ( str, td ) {
1515 if ( typeof str === 'string' ) {
1516 var idx = str.indexOf('@');
1517
1518 if ( idx !== -1 ) {
1519 var attr = str.substring( idx+1 );
1520 var setter = _fnSetObjectDataFn( str );
1521 setter( d, td.getAttribute( attr ) );
1522 }
1523 }
1524 };
1525
1526 var cellProcess = function ( cell ) {
1527 col = columns[i];
1528 contents = $.trim(cell.innerHTML);
1529
1530 if ( col && col._bAttrSrc ) {
1531 var setter = _fnSetObjectDataFn( col.mData._ );
1532 setter( d, contents );
1533
1534 attr( col.mData.sort, cell );
1535 attr( col.mData.type, cell );
1536 attr( col.mData.filter, cell );
1537 }
1538 else {
1539 // Depending on the `data` option for the columns the data can be
1540 // read to either an object or an array.
1541 if ( objectRead ) {
1542 if ( ! col._setter ) {
1543 // Cache the setter function
1544 col._setter = _fnSetObjectDataFn( col.mData );
1545 }
1546 col._setter( d, contents );
1547 }
1548 else {
1549 d.push( contents );
1550 }
1551 }
1552
1553 i++;
1554 };
1555
1556 if ( td ) {
1557 // `tr` element passed in
1558 while ( td ) {
1559 name = td.nodeName.toUpperCase();
1560
1561 if ( name == "TD" || name == "TH" ) {
1562 cellProcess( td );
1563 tds.push( td );
1564 }
1565
1566 td = td.nextSibling;
1567 }
1568 }
1569 else {
1570 // Existing row object passed in
1571 tds = row.anCells;
1572
1573 for ( var j=0, jen=tds.length ; j<jen ; j++ ) {
1574 cellProcess( tds[j] );
1575 }
1576 }
1577
1578 return {
1579 data: d,
1580 cells: tds
1581 };
1582 }
1583 /**
1584 * Create a new TR element (and it's TD children) for a row
1585 * @param {object} oSettings dataTables settings object
1586 * @param {int} iRow Row to consider
1587 * @param {node} [nTrIn] TR element to add to the table - optional. If not given,
1588 * DataTables will create a row automatically
1589 * @param {array} [anTds] Array of TD|TH elements for the row - must be given
1590 * if nTr is.
1591 * @memberof DataTable#oApi
1592 */
1593 function _fnCreateTr ( oSettings, iRow, nTrIn, anTds )
1594 {
1595 var
1596 row = oSettings.aoData[iRow],
1597 rowData = row._aData,
1598 cells = [],
1599 nTr, nTd, oCol,
1600 i, iLen;
1601
1602 if ( row.nTr === null )
1603 {
1604 nTr = nTrIn || document.createElement('tr');
1605
1606 row.nTr = nTr;
1607 row.anCells = cells;
1608
1609 /* Use a private property on the node to allow reserve mapping from the node
1610 * to the aoData array for fast look up
1611 */
1612 nTr._DT_RowIndex = iRow;
1613
1614 /* Special parameters can be given by the data source to be used on the row */
1615 _fnRowAttributes( row );
1616
1617 /* Process each column */
1618 for ( i=0, iLen=oSettings.aoColumns.length ; i<iLen ; i++ )
1619 {
1620 oCol = oSettings.aoColumns[i];
1621
1622 nTd = nTrIn ? anTds[i] : document.createElement( oCol.sCellType );
1623 cells.push( nTd );
1624
1625 // Need to create the HTML if new, or if a rendering function is defined
1626 if ( !nTrIn || oCol.mRender || oCol.mData !== i )
1627 {
1628 nTd.innerHTML = _fnGetCellData( oSettings, iRow, i, 'display' );
1629 }
1630
1631 /* Add user defined class */
1632 if ( oCol.sClass )
1633 {
1634 nTd.className += ' '+oCol.sClass;
1635 }
1636
1637 // Visibility - add or remove as required
1638 if ( oCol.bVisible && ! nTrIn )
1639 {
1640 nTr.appendChild( nTd );
1641 }
1642 else if ( ! oCol.bVisible && nTrIn )
1643 {
1644 nTd.parentNode.removeChild( nTd );
1645 }
1646
1647 if ( oCol.fnCreatedCell )
1648 {
1649 oCol.fnCreatedCell.call( oSettings.oInstance,
1650 nTd, _fnGetCellData( oSettings, iRow, i ), rowData, iRow, i
1651 );
1652 }
1653 }
1654
1655 _fnCallbackFire( oSettings, 'aoRowCreatedCallback', null, [nTr, rowData, iRow] );
1656 }
1657
1658 // Remove once webkit bug 131819 and Chromium bug 365619 have been resolved
1659 // and deployed
1660 row.nTr.setAttribute( 'role', 'row' );
1661 }
1662
1663
1664 /**
1665 * Add attributes to a row based on the special `DT_*` parameters in a data
1666 * source object.
1667 * @param {object} DataTables row object for the row to be modified
1668 * @memberof DataTable#oApi
1669 */
1670 function _fnRowAttributes( row )
1671 {
1672 var tr = row.nTr;
1673 var data = row._aData;
1674
1675 if ( tr ) {
1676 if ( data.DT_RowId ) {
1677 tr.id = data.DT_RowId;
1678 }
1679
1680 if ( data.DT_RowClass ) {
1681 // Remove any classes added by DT_RowClass before
1682 var a = data.DT_RowClass.split(' ');
1683 row.__rowc = row.__rowc ?
1684 _unique( row.__rowc.concat( a ) ) :
1685 a;
1686
1687 $(tr)
1688 .removeClass( row.__rowc.join(' ') )
1689 .addClass( data.DT_RowClass );
1690 }
1691
1692 if ( data.DT_RowData ) {
1693 $(tr).data( data.DT_RowData );
1694 }
1695 }
1696 }
1697
1698
1699 /**
1700 * Create the HTML header for the table
1701 * @param {object} oSettings dataTables settings object
1702 * @memberof DataTable#oApi
1703 */
1704 function _fnBuildHead( oSettings )
1705 {
1706 var i, ien, cell, row, column;
1707 var thead = oSettings.nTHead;
1708 var tfoot = oSettings.nTFoot;
1709 var createHeader = $('th, td', thead).length === 0;
1710 var classes = oSettings.oClasses;
1711 var columns = oSettings.aoColumns;
1712
1713 if ( createHeader ) {
1714 row = $('<tr/>').appendTo( thead );
1715 }
1716
1717 for ( i=0, ien=columns.length ; i<ien ; i++ ) {
1718 column = columns[i];
1719 cell = $( column.nTh ).addClass( column.sClass );
1720
1721 if ( createHeader ) {
1722 cell.appendTo( row );
1723 }
1724
1725 // 1.11 move into sorting
1726 if ( oSettings.oFeatures.bSort ) {
1727 cell.addClass( column.sSortingClass );
1728
1729 if ( column.bSortable !== false ) {
1730 cell
1731 .attr( 'tabindex', oSettings.iTabIndex )
1732 .attr( 'aria-controls', oSettings.sTableId );
1733
1734 _fnSortAttachListener( oSettings, column.nTh, i );
1735 }
1736 }
1737
1738 if ( column.sTitle != cell.html() ) {
1739 cell.html( column.sTitle );
1740 }
1741
1742 _fnRenderer( oSettings, 'header' )(
1743 oSettings, cell, column, classes
1744 );
1745 }
1746
1747 if ( createHeader ) {
1748 _fnDetectHeader( oSettings.aoHeader, thead );
1749 }
1750
1751 /* ARIA role for the rows */
1752 $(thead).find('>tr').attr('role', 'row');
1753
1754 /* Deal with the footer - add classes if required */
1755 $(thead).find('>tr>th, >tr>td').addClass( classes.sHeaderTH );
1756 $(tfoot).find('>tr>th, >tr>td').addClass( classes.sFooterTH );
1757
1758 // Cache the footer cells. Note that we only take the cells from the first
1759 // row in the footer. If there is more than one row the user wants to
1760 // interact with, they need to use the table().foot() method. Note also this
1761 // allows cells to be used for multiple columns using colspan
1762 if ( tfoot !== null ) {
1763 var cells = oSettings.aoFooter[0];
1764
1765 for ( i=0, ien=cells.length ; i<ien ; i++ ) {
1766 column = columns[i];
1767 column.nTf = cells[i].cell;
1768
1769 if ( column.sClass ) {
1770 $(column.nTf).addClass( column.sClass );
1771 }
1772 }
1773 }
1774 }
1775
1776
1777 /**
1778 * Draw the header (or footer) element based on the column visibility states. The
1779 * methodology here is to use the layout array from _fnDetectHeader, modified for
1780 * the instantaneous column visibility, to construct the new layout. The grid is
1781 * traversed over cell at a time in a rows x columns grid fashion, although each
1782 * cell insert can cover multiple elements in the grid - which is tracks using the
1783 * aApplied array. Cell inserts in the grid will only occur where there isn't
1784 * already a cell in that position.
1785 * @param {object} oSettings dataTables settings object
1786 * @param array {objects} aoSource Layout array from _fnDetectHeader
1787 * @param {boolean} [bIncludeHidden=false] If true then include the hidden columns in the calc,
1788 * @memberof DataTable#oApi
1789 */
1790 function _fnDrawHead( oSettings, aoSource, bIncludeHidden )
1791 {
1792 var i, iLen, j, jLen, k, kLen, n, nLocalTr;
1793 var aoLocal = [];
1794 var aApplied = [];
1795 var iColumns = oSettings.aoColumns.length;
1796 var iRowspan, iColspan;
1797
1798 if ( ! aoSource )
1799 {
1800 return;
1801 }
1802
1803 if ( bIncludeHidden === undefined )
1804 {
1805 bIncludeHidden = false;
1806 }
1807
1808 /* Make a copy of the master layout array, but without the visible columns in it */
1809 for ( i=0, iLen=aoSource.length ; i<iLen ; i++ )
1810 {
1811 aoLocal[i] = aoSource[i].slice();
1812 aoLocal[i].nTr = aoSource[i].nTr;
1813
1814 /* Remove any columns which are currently hidden */
1815 for ( j=iColumns-1 ; j>=0 ; j-- )
1816 {
1817 if ( !oSettings.aoColumns[j].bVisible && !bIncludeHidden )
1818 {
1819 aoLocal[i].splice( j, 1 );
1820 }
1821 }
1822
1823 /* Prep the applied array - it needs an element for each row */
1824 aApplied.push( [] );
1825 }
1826
1827 for ( i=0, iLen=aoLocal.length ; i<iLen ; i++ )
1828 {
1829 nLocalTr = aoLocal[i].nTr;
1830
1831 /* All cells are going to be replaced, so empty out the row */
1832 if ( nLocalTr )
1833 {
1834 while( (n = nLocalTr.firstChild) )
1835 {
1836 nLocalTr.removeChild( n );
1837 }
1838 }
1839
1840 for ( j=0, jLen=aoLocal[i].length ; j<jLen ; j++ )
1841 {
1842 iRowspan = 1;
1843 iColspan = 1;
1844
1845 /* Check to see if there is already a cell (row/colspan) covering our target
1846 * insert point. If there is, then there is nothing to do.
1847 */
1848 if ( aApplied[i][j] === undefined )
1849 {
1850 nLocalTr.appendChild( aoLocal[i][j].cell );
1851 aApplied[i][j] = 1;
1852
1853 /* Expand the cell to cover as many rows as needed */
1854 while ( aoLocal[i+iRowspan] !== undefined &&
1855 aoLocal[i][j].cell == aoLocal[i+iRowspan][j].cell )
1856 {
1857 aApplied[i+iRowspan][j] = 1;
1858 iRowspan++;
1859 }
1860
1861 /* Expand the cell to cover as many columns as needed */
1862 while ( aoLocal[i][j+iColspan] !== undefined &&
1863 aoLocal[i][j].cell == aoLocal[i][j+iColspan].cell )
1864 {
1865 /* Must update the applied array over the rows for the columns */
1866 for ( k=0 ; k<iRowspan ; k++ )
1867 {
1868 aApplied[i+k][j+iColspan] = 1;
1869 }
1870 iColspan++;
1871 }
1872
1873 /* Do the actual expansion in the DOM */
1874 $(aoLocal[i][j].cell)
1875 .attr('rowspan', iRowspan)
1876 .attr('colspan', iColspan);
1877 }
1878 }
1879 }
1880 }
1881
1882
1883 /**
1884 * Insert the required TR nodes into the table for display
1885 * @param {object} oSettings dataTables settings object
1886 * @memberof DataTable#oApi
1887 */
1888 function _fnDraw( oSettings )
1889 {
1890 /* Provide a pre-callback function which can be used to cancel the draw is false is returned */
1891 var aPreDraw = _fnCallbackFire( oSettings, 'aoPreDrawCallback', 'preDraw', [oSettings] );
1892 if ( $.inArray( false, aPreDraw ) !== -1 )
1893 {
1894 _fnProcessingDisplay( oSettings, false );
1895 return;
1896 }
1897
1898 var i, iLen, n;
1899 var anRows = [];
1900 var iRowCount = 0;
1901 var asStripeClasses = oSettings.asStripeClasses;
1902 var iStripes = asStripeClasses.length;
1903 var iOpenRows = oSettings.aoOpenRows.length;
1904 var oLang = oSettings.oLanguage;
1905 var iInitDisplayStart = oSettings.iInitDisplayStart;
1906 var bServerSide = _fnDataSource( oSettings ) == 'ssp';
1907 var aiDisplay = oSettings.aiDisplay;
1908
1909 oSettings.bDrawing = true;
1910
1911 /* Check and see if we have an initial draw position from state saving */
1912 if ( iInitDisplayStart !== undefined && iInitDisplayStart !== -1 )
1913 {
1914 oSettings._iDisplayStart = bServerSide ?
1915 iInitDisplayStart :
1916 iInitDisplayStart >= oSettings.fnRecordsDisplay() ?
1917 0 :
1918 iInitDisplayStart;
1919
1920 oSettings.iInitDisplayStart = -1;
1921 }
1922
1923 var iDisplayStart = oSettings._iDisplayStart;
1924 var iDisplayEnd = oSettings.fnDisplayEnd();
1925
1926 /* Server-side processing draw intercept */
1927 if ( oSettings.bDeferLoading )
1928 {
1929 oSettings.bDeferLoading = false;
1930 oSettings.iDraw++;
1931 _fnProcessingDisplay( oSettings, false );
1932 }
1933 else if ( !bServerSide )
1934 {
1935 oSettings.iDraw++;
1936 }
1937 else if ( !oSettings.bDestroying && !_fnAjaxUpdate( oSettings ) )
1938 {
1939 return;
1940 }
1941
1942 if ( aiDisplay.length !== 0 )
1943 {
1944 var iStart = bServerSide ? 0 : iDisplayStart;
1945 var iEnd = bServerSide ? oSettings.aoData.length : iDisplayEnd;
1946
1947 for ( var j=iStart ; j<iEnd ; j++ )
1948 {
1949 var iDataIndex = aiDisplay[j];
1950 var aoData = oSettings.aoData[ iDataIndex ];
1951 if ( aoData.nTr === null )
1952 {
1953 _fnCreateTr( oSettings, iDataIndex );
1954 }
1955
1956 var nRow = aoData.nTr;
1957
1958 /* Remove the old striping classes and then add the new one */
1959 if ( iStripes !== 0 )
1960 {
1961 var sStripe = asStripeClasses[ iRowCount % iStripes ];
1962 if ( aoData._sRowStripe != sStripe )
1963 {
1964 $(nRow).removeClass( aoData._sRowStripe ).addClass( sStripe );
1965 aoData._sRowStripe = sStripe;
1966 }
1967 }
1968
1969 // Row callback functions - might want to manipulate the row
1970 // iRowCount and j are not currently documented. Are they at all
1971 // useful?
1972 _fnCallbackFire( oSettings, 'aoRowCallback', null,
1973 [nRow, aoData._aData, iRowCount, j] );
1974
1975 anRows.push( nRow );
1976 iRowCount++;
1977 }
1978 }
1979 else
1980 {
1981 /* Table is empty - create a row with an empty message in it */
1982 var sZero = oLang.sZeroRecords;
1983 if ( oSettings.iDraw == 1 && _fnDataSource( oSettings ) == 'ajax' )
1984 {
1985 sZero = oLang.sLoadingRecords;
1986 }
1987 else if ( oLang.sEmptyTable && oSettings.fnRecordsTotal() === 0 )
1988 {
1989 sZero = oLang.sEmptyTable;
1990 }
1991
1992 anRows[ 0 ] = $( '<tr/>', { 'class': iStripes ? asStripeClasses[0] : '' } )
1993 .append( $('<td />', {
1994 'valign': 'top',
1995 'colSpan': _fnVisbleColumns( oSettings ),
1996 'class': oSettings.oClasses.sRowEmpty
1997 } ).html( sZero ) )[0];
1998 }
1999
2000 /* Header and footer callbacks */
2001 _fnCallbackFire( oSettings, 'aoHeaderCallback', 'header', [ $(oSettings.nTHead).children('tr')[0],
2002 _fnGetDataMaster( oSettings ), iDisplayStart, iDisplayEnd, aiDisplay ] );
2003
2004 _fnCallbackFire( oSettings, 'aoFooterCallback', 'footer', [ $(oSettings.nTFoot).children('tr')[0],
2005 _fnGetDataMaster( oSettings ), iDisplayStart, iDisplayEnd, aiDisplay ] );
2006
2007 var body = $(oSettings.nTBody);
2008
2009 body.children().detach();
2010 body.append( $(anRows) );
2011
2012 /* Call all required callback functions for the end of a draw */
2013 _fnCallbackFire( oSettings, 'aoDrawCallback', 'draw', [oSettings] );
2014
2015 /* Draw is complete, sorting and filtering must be as well */
2016 oSettings.bSorted = false;
2017 oSettings.bFiltered = false;
2018 oSettings.bDrawing = false;
2019 }
2020
2021
2022 /**
2023 * Redraw the table - taking account of the various features which are enabled
2024 * @param {object} oSettings dataTables settings object
2025 * @param {boolean} [holdPosition] Keep the current paging position. By default
2026 * the paging is reset to the first page
2027 * @memberof DataTable#oApi
2028 */
2029 function _fnReDraw( settings, holdPosition )
2030 {
2031 var
2032 features = settings.oFeatures,
2033 sort = features.bSort,
2034 filter = features.bFilter;
2035
2036 if ( sort ) {
2037 _fnSort( settings );
2038 }
2039
2040 if ( filter ) {
2041 _fnFilterComplete( settings, settings.oPreviousSearch );
2042 }
2043 else {
2044 // No filtering, so we want to just use the display master
2045 settings.aiDisplay = settings.aiDisplayMaster.slice();
2046 }
2047
2048 if ( holdPosition !== true ) {
2049 settings._iDisplayStart = 0;
2050 }
2051
2052 // Let any modules know about the draw hold position state (used by
2053 // scrolling internally)
2054 settings._drawHold = holdPosition;
2055
2056 _fnDraw( settings );
2057
2058 settings._drawHold = false;
2059 }
2060
2061
2062 /**
2063 * Add the options to the page HTML for the table
2064 * @param {object} oSettings dataTables settings object
2065 * @memberof DataTable#oApi
2066 */
2067 function _fnAddOptionsHtml ( oSettings )
2068 {
2069 var classes = oSettings.oClasses;
2070 var table = $(oSettings.nTable);
2071 var holding = $('<div/>').insertBefore( table ); // Holding element for speed
2072 var features = oSettings.oFeatures;
2073
2074 // All DataTables are wrapped in a div
2075 var insert = $('<div/>', {
2076 id: oSettings.sTableId+'_wrapper',
2077 'class': classes.sWrapper + (oSettings.nTFoot ? '' : ' '+classes.sNoFooter)
2078 } );
2079
2080 oSettings.nHolding = holding[0];
2081 oSettings.nTableWrapper = insert[0];
2082 oSettings.nTableReinsertBefore = oSettings.nTable.nextSibling;
2083
2084 /* Loop over the user set positioning and place the elements as needed */
2085 var aDom = oSettings.sDom.split('');
2086 var featureNode, cOption, nNewNode, cNext, sAttr, j;
2087 for ( var i=0 ; i<aDom.length ; i++ )
2088 {
2089 featureNode = null;
2090 cOption = aDom[i];
2091
2092 if ( cOption == '<' )
2093 {
2094 /* New container div */
2095 nNewNode = $('<div/>')[0];
2096
2097 /* Check to see if we should append an id and/or a class name to the container */
2098 cNext = aDom[i+1];
2099 if ( cNext == "'" || cNext == '"' )
2100 {
2101 sAttr = "";
2102 j = 2;
2103 while ( aDom[i+j] != cNext )
2104 {
2105 sAttr += aDom[i+j];
2106 j++;
2107 }
2108
2109 /* Replace jQuery UI constants @todo depreciated */
2110 if ( sAttr == "H" )
2111 {
2112 sAttr = classes.sJUIHeader;
2113 }
2114 else if ( sAttr == "F" )
2115 {
2116 sAttr = classes.sJUIFooter;
2117 }
2118
2119 /* The attribute can be in the format of "#id.class", "#id" or "class" This logic
2120 * breaks the string into parts and applies them as needed
2121 */
2122 if ( sAttr.indexOf('.') != -1 )
2123 {
2124 var aSplit = sAttr.split('.');
2125 nNewNode.id = aSplit[0].substr(1, aSplit[0].length-1);
2126 nNewNode.className = aSplit[1];
2127 }
2128 else if ( sAttr.charAt(0) == "#" )
2129 {
2130 nNewNode.id = sAttr.substr(1, sAttr.length-1);
2131 }
2132 else
2133 {
2134 nNewNode.className = sAttr;
2135 }
2136
2137 i += j; /* Move along the position array */
2138 }
2139
2140 insert.append( nNewNode );
2141 insert = $(nNewNode);
2142 }
2143 else if ( cOption == '>' )
2144 {
2145 /* End container div */
2146 insert = insert.parent();
2147 }
2148 // @todo Move options into their own plugins?
2149 else if ( cOption == 'l' && features.bPaginate && features.bLengthChange )
2150 {
2151 /* Length */
2152 featureNode = _fnFeatureHtmlLength( oSettings );
2153 }
2154 else if ( cOption == 'f' && features.bFilter )
2155 {
2156 /* Filter */
2157 featureNode = _fnFeatureHtmlFilter( oSettings );
2158 }
2159 else if ( cOption == 'r' && features.bProcessing )
2160 {
2161 /* pRocessing */
2162 featureNode = _fnFeatureHtmlProcessing( oSettings );
2163 }
2164 else if ( cOption == 't' )
2165 {
2166 /* Table */
2167 featureNode = _fnFeatureHtmlTable( oSettings );
2168 }
2169 else if ( cOption == 'i' && features.bInfo )
2170 {
2171 /* Info */
2172 featureNode = _fnFeatureHtmlInfo( oSettings );
2173 }
2174 else if ( cOption == 'p' && features.bPaginate )
2175 {
2176 /* Pagination */
2177 featureNode = _fnFeatureHtmlPaginate( oSettings );
2178 }
2179 else if ( DataTable.ext.feature.length !== 0 )
2180 {
2181 /* Plug-in features */
2182 var aoFeatures = DataTable.ext.feature;
2183 for ( var k=0, kLen=aoFeatures.length ; k<kLen ; k++ )
2184 {
2185 if ( cOption == aoFeatures[k].cFeature )
2186 {
2187 featureNode = aoFeatures[k].fnInit( oSettings );
2188 break;
2189 }
2190 }
2191 }
2192
2193 /* Add to the 2D features array */
2194 if ( featureNode )
2195 {
2196 var aanFeatures = oSettings.aanFeatures;
2197
2198 if ( ! aanFeatures[cOption] )
2199 {
2200 aanFeatures[cOption] = [];
2201 }
2202
2203 aanFeatures[cOption].push( featureNode );
2204 insert.append( featureNode );
2205 }
2206 }
2207
2208 /* Built our DOM structure - replace the holding div with what we want */
2209 holding.replaceWith( insert );
2210 }
2211
2212
2213 /**
2214 * Use the DOM source to create up an array of header cells. The idea here is to
2215 * create a layout grid (array) of rows x columns, which contains a reference
2216 * to the cell that that point in the grid (regardless of col/rowspan), such that
2217 * any column / row could be removed and the new grid constructed
2218 * @param array {object} aLayout Array to store the calculated layout in
2219 * @param {node} nThead The header/footer element for the table
2220 * @memberof DataTable#oApi
2221 */
2222 function _fnDetectHeader ( aLayout, nThead )
2223 {
2224 var nTrs = $(nThead).children('tr');
2225 var nTr, nCell;
2226 var i, k, l, iLen, jLen, iColShifted, iColumn, iColspan, iRowspan;
2227 var bUnique;
2228 var fnShiftCol = function ( a, i, j ) {
2229 var k = a[i];
2230 while ( k[j] ) {
2231 j++;
2232 }
2233 return j;
2234 };
2235
2236 aLayout.splice( 0, aLayout.length );
2237
2238 /* We know how many rows there are in the layout - so prep it */
2239 for ( i=0, iLen=nTrs.length ; i<iLen ; i++ )
2240 {
2241 aLayout.push( [] );
2242 }
2243
2244 /* Calculate a layout array */
2245 for ( i=0, iLen=nTrs.length ; i<iLen ; i++ )
2246 {
2247 nTr = nTrs[i];
2248 iColumn = 0;
2249
2250 /* For every cell in the row... */
2251 nCell = nTr.firstChild;
2252 while ( nCell ) {
2253 if ( nCell.nodeName.toUpperCase() == "TD" ||
2254 nCell.nodeName.toUpperCase() == "TH" )
2255 {
2256 /* Get the col and rowspan attributes from the DOM and sanitise them */
2257 iColspan = nCell.getAttribute('colspan') * 1;
2258 iRowspan = nCell.getAttribute('rowspan') * 1;
2259 iColspan = (!iColspan || iColspan===0 || iColspan===1) ? 1 : iColspan;
2260 iRowspan = (!iRowspan || iRowspan===0 || iRowspan===1) ? 1 : iRowspan;
2261
2262 /* There might be colspan cells already in this row, so shift our target
2263 * accordingly
2264 */
2265 iColShifted = fnShiftCol( aLayout, i, iColumn );
2266
2267 /* Cache calculation for unique columns */
2268 bUnique = iColspan === 1 ? true : false;
2269
2270 /* If there is col / rowspan, copy the information into the layout grid */
2271 for ( l=0 ; l<iColspan ; l++ )
2272 {
2273 for ( k=0 ; k<iRowspan ; k++ )
2274 {
2275 aLayout[i+k][iColShifted+l] = {
2276 "cell": nCell,
2277 "unique": bUnique
2278 };
2279 aLayout[i+k].nTr = nTr;
2280 }
2281 }
2282 }
2283 nCell = nCell.nextSibling;
2284 }
2285 }
2286 }
2287
2288
2289 /**
2290 * Get an array of unique th elements, one for each column
2291 * @param {object} oSettings dataTables settings object
2292 * @param {node} nHeader automatically detect the layout from this node - optional
2293 * @param {array} aLayout thead/tfoot layout from _fnDetectHeader - optional
2294 * @returns array {node} aReturn list of unique th's
2295 * @memberof DataTable#oApi
2296 */
2297 function _fnGetUniqueThs ( oSettings, nHeader, aLayout )
2298 {
2299 var aReturn = [];
2300 if ( !aLayout )
2301 {
2302 aLayout = oSettings.aoHeader;
2303 if ( nHeader )
2304 {
2305 aLayout = [];
2306 _fnDetectHeader( aLayout, nHeader );
2307 }
2308 }
2309
2310 for ( var i=0, iLen=aLayout.length ; i<iLen ; i++ )
2311 {
2312 for ( var j=0, jLen=aLayout[i].length ; j<jLen ; j++ )
2313 {
2314 if ( aLayout[i][j].unique &&
2315 (!aReturn[j] || !oSettings.bSortCellsTop) )
2316 {
2317 aReturn[j] = aLayout[i][j].cell;
2318 }
2319 }
2320 }
2321
2322 return aReturn;
2323 }
2324
2325
2326
2327 /**
2328 * Create an Ajax call based on the table's settings, taking into account that
2329 * parameters can have multiple forms, and backwards compatibility.
2330 *
2331 * @param {object} oSettings dataTables settings object
2332 * @param {array} data Data to send to the server, required by
2333 * DataTables - may be augmented by developer callbacks
2334 * @param {function} fn Callback function to run when data is obtained
2335 */
2336 function _fnBuildAjax( oSettings, data, fn )
2337 {
2338 // Compatibility with 1.9-, allow fnServerData and event to manipulate
2339 _fnCallbackFire( oSettings, 'aoServerParams', 'serverParams', [data] );
2340
2341 // Convert to object based for 1.10+ if using the old array scheme which can
2342 // come from server-side processing or serverParams
2343 if ( data && $.isArray(data) ) {
2344 var tmp = {};
2345 var rbracket = /(.*?)\[\]$/;
2346
2347 $.each( data, function (key, val) {
2348 var match = val.name.match(rbracket);
2349
2350 if ( match ) {
2351 // Support for arrays
2352 var name = match[0];
2353
2354 if ( ! tmp[ name ] ) {
2355 tmp[ name ] = [];
2356 }
2357 tmp[ name ].push( val.value );
2358 }
2359 else {
2360 tmp[val.name] = val.value;
2361 }
2362 } );
2363 data = tmp;
2364 }
2365
2366 var ajaxData;
2367 var ajax = oSettings.ajax;
2368 var instance = oSettings.oInstance;
2369
2370 if ( $.isPlainObject( ajax ) && ajax.data )
2371 {
2372 ajaxData = ajax.data;
2373
2374 var newData = $.isFunction( ajaxData ) ?
2375 ajaxData( data ) : // fn can manipulate data or return an object
2376 ajaxData; // object or array to merge
2377
2378 // If the function returned an object, use that alone
2379 data = $.isFunction( ajaxData ) && newData ?
2380 newData :
2381 $.extend( true, data, newData );
2382
2383 // Remove the data property as we've resolved it already and don't want
2384 // jQuery to do it again (it is restored at the end of the function)
2385 delete ajax.data;
2386 }
2387
2388 var baseAjax = {
2389 "data": data,
2390 "success": function (json) {
2391 var error = json.error || json.sError;
2392 if ( error ) {
2393 oSettings.oApi._fnLog( oSettings, 0, error );
2394 }
2395
2396 oSettings.json = json;
2397 _fnCallbackFire( oSettings, null, 'xhr', [oSettings, json] );
2398 fn( json );
2399 },
2400 "dataType": "json",
2401 "cache": false,
2402 "type": oSettings.sServerMethod,
2403 "error": function (xhr, error, thrown) {
2404 var log = oSettings.oApi._fnLog;
2405
2406 if ( error == "parsererror" ) {
2407 log( oSettings, 0, 'Invalid JSON response', 1 );
2408 }
2409 else if ( xhr.readyState === 4 ) {
2410 log( oSettings, 0, 'Ajax error', 7 );
2411 }
2412
2413 _fnProcessingDisplay( oSettings, false );
2414 }
2415 };
2416
2417 // Store the data submitted for the API
2418 oSettings.oAjaxData = data;
2419
2420 // Allow plug-ins and external processes to modify the data
2421 _fnCallbackFire( oSettings, null, 'preXhr', [oSettings, data] );
2422
2423 if ( oSettings.fnServerData )
2424 {
2425 // DataTables 1.9- compatibility
2426 oSettings.fnServerData.call( instance,
2427 oSettings.sAjaxSource,
2428 $.map( data, function (val, key) { // Need to convert back to 1.9 trad format
2429 return { name: key, value: val };
2430 } ),
2431 fn,
2432 oSettings
2433 );
2434 }
2435 else if ( oSettings.sAjaxSource || typeof ajax === 'string' )
2436 {
2437 // DataTables 1.9- compatibility
2438 oSettings.jqXHR = $.ajax( $.extend( baseAjax, {
2439 url: ajax || oSettings.sAjaxSource
2440 } ) );
2441 }
2442 else if ( $.isFunction( ajax ) )
2443 {
2444 // Is a function - let the caller define what needs to be done
2445 oSettings.jqXHR = ajax.call( instance, data, fn, oSettings );
2446 }
2447 else
2448 {
2449 // Object to extend the base settings
2450 oSettings.jqXHR = $.ajax( $.extend( baseAjax, ajax ) );
2451
2452 // Restore for next time around
2453 ajax.data = ajaxData;
2454 }
2455 }
2456
2457
2458 /**
2459 * Update the table using an Ajax call
2460 * @param {object} settings dataTables settings object
2461 * @returns {boolean} Block the table drawing or not
2462 * @memberof DataTable#oApi
2463 */
2464 function _fnAjaxUpdate( settings )
2465 {
2466 if ( settings.bAjaxDataGet ) {
2467 settings.iDraw++;
2468 _fnProcessingDisplay( settings, true );
2469
2470 _fnBuildAjax(
2471 settings,
2472 _fnAjaxParameters( settings ),
2473 function(json) {
2474 _fnAjaxUpdateDraw( settings, json );
2475 }
2476 );
2477
2478 return false;
2479 }
2480 return true;
2481 }
2482
2483
2484 /**
2485 * Build up the parameters in an object needed for a server-side processing
2486 * request. Note that this is basically done twice, is different ways - a modern
2487 * method which is used by default in DataTables 1.10 which uses objects and
2488 * arrays, or the 1.9- method with is name / value pairs. 1.9 method is used if
2489 * the sAjaxSource option is used in the initialisation, or the legacyAjax
2490 * option is set.
2491 * @param {object} oSettings dataTables settings object
2492 * @returns {bool} block the table drawing or not
2493 * @memberof DataTable#oApi
2494 */
2495 function _fnAjaxParameters( settings )
2496 {
2497 var
2498 columns = settings.aoColumns,
2499 columnCount = columns.length,
2500 features = settings.oFeatures,
2501 preSearch = settings.oPreviousSearch,
2502 preColSearch = settings.aoPreSearchCols,
2503 i, data = [], dataProp, column, columnSearch,
2504 sort = _fnSortFlatten( settings ),
2505 displayStart = settings._iDisplayStart,
2506 displayLength = features.bPaginate !== false ?
2507 settings._iDisplayLength :
2508 -1;
2509
2510 var param = function ( name, value ) {
2511 data.push( { 'name': name, 'value': value } );
2512 };
2513
2514 // DataTables 1.9- compatible method
2515 param( 'sEcho', settings.iDraw );
2516 param( 'iColumns', columnCount );
2517 param( 'sColumns', _pluck( columns, 'sName' ).join(',') );
2518 param( 'iDisplayStart', displayStart );
2519 param( 'iDisplayLength', displayLength );
2520
2521 // DataTables 1.10+ method
2522 var d = {
2523 draw: settings.iDraw,
2524 columns: [],
2525 order: [],
2526 start: displayStart,
2527 length: displayLength,
2528 search: {
2529 value: preSearch.sSearch,
2530 regex: preSearch.bRegex
2531 }
2532 };
2533
2534 for ( i=0 ; i<columnCount ; i++ ) {
2535 column = columns[i];
2536 columnSearch = preColSearch[i];
2537 dataProp = typeof column.mData=="function" ? 'function' : column.mData ;
2538
2539 d.columns.push( {
2540 data: dataProp,
2541 name: column.sName,
2542 searchable: column.bSearchable,
2543 orderable: column.bSortable,
2544 search: {
2545 value: columnSearch.sSearch,
2546 regex: columnSearch.bRegex
2547 }
2548 } );
2549
2550 param( "mDataProp_"+i, dataProp );
2551
2552 if ( features.bFilter ) {
2553 param( 'sSearch_'+i, columnSearch.sSearch );
2554 param( 'bRegex_'+i, columnSearch.bRegex );
2555 param( 'bSearchable_'+i, column.bSearchable );
2556 }
2557
2558 if ( features.bSort ) {
2559 param( 'bSortable_'+i, column.bSortable );
2560 }
2561 }
2562
2563 if ( features.bFilter ) {
2564 param( 'sSearch', preSearch.sSearch );
2565 param( 'bRegex', preSearch.bRegex );
2566 }
2567
2568 if ( features.bSort ) {
2569 $.each( sort, function ( i, val ) {
2570 d.order.push( { column: val.col, dir: val.dir } );
2571
2572 param( 'iSortCol_'+i, val.col );
2573 param( 'sSortDir_'+i, val.dir );
2574 } );
2575
2576 param( 'iSortingCols', sort.length );
2577 }
2578
2579 // If the legacy.ajax parameter is null, then we automatically decide which
2580 // form to use, based on sAjaxSource
2581 var legacy = DataTable.ext.legacy.ajax;
2582 if ( legacy === null ) {
2583 return settings.sAjaxSource ? data : d;
2584 }
2585
2586 // Otherwise, if legacy has been specified then we use that to decide on the
2587 // form
2588 return legacy ? data : d;
2589 }
2590
2591
2592 /**
2593 * Data the data from the server (nuking the old) and redraw the table
2594 * @param {object} oSettings dataTables settings object
2595 * @param {object} json json data return from the server.
2596 * @param {string} json.sEcho Tracking flag for DataTables to match requests
2597 * @param {int} json.iTotalRecords Number of records in the data set, not accounting for filtering
2598 * @param {int} json.iTotalDisplayRecords Number of records in the data set, accounting for filtering
2599 * @param {array} json.aaData The data to display on this page
2600 * @param {string} [json.sColumns] Column ordering (sName, comma separated)
2601 * @memberof DataTable#oApi
2602 */
2603 function _fnAjaxUpdateDraw ( settings, json )
2604 {
2605 // v1.10 uses camelCase variables, while 1.9 uses Hungarian notation.
2606 // Support both
2607 var compat = function ( old, modern ) {
2608 return json[old] !== undefined ? json[old] : json[modern];
2609 };
2610
2611 var draw = compat( 'sEcho', 'draw' );
2612 var recordsTotal = compat( 'iTotalRecords', 'recordsTotal' );
2613 var rocordsFiltered = compat( 'iTotalDisplayRecords', 'recordsFiltered' );
2614
2615 if ( draw ) {
2616 // Protect against out of sequence returns
2617 if ( draw*1 < settings.iDraw ) {
2618 return;
2619 }
2620 settings.iDraw = draw * 1;
2621 }
2622
2623 _fnClearTable( settings );
2624 settings._iRecordsTotal = parseInt(recordsTotal, 10);
2625 settings._iRecordsDisplay = parseInt(rocordsFiltered, 10);
2626
2627 var data = _fnAjaxDataSrc( settings, json );
2628 for ( var i=0, ien=data.length ; i<ien ; i++ ) {
2629 _fnAddData( settings, data[i] );
2630 }
2631 settings.aiDisplay = settings.aiDisplayMaster.slice();
2632
2633 settings.bAjaxDataGet = false;
2634 _fnDraw( settings );
2635
2636 if ( ! settings._bInitComplete ) {
2637 _fnInitComplete( settings, json );
2638 }
2639
2640 settings.bAjaxDataGet = true;
2641 _fnProcessingDisplay( settings, false );
2642 }
2643
2644
2645 /**
2646 * Get the data from the JSON data source to use for drawing a table. Using
2647 * `_fnGetObjectDataFn` allows the data to be sourced from a property of the
2648 * source object, or from a processing function.
2649 * @param {object} oSettings dataTables settings object
2650 * @param {object} json Data source object / array from the server
2651 * @return {array} Array of data to use
2652 */
2653 function _fnAjaxDataSrc ( oSettings, json )
2654 {
2655 var dataSrc = $.isPlainObject( oSettings.ajax ) && oSettings.ajax.dataSrc !== undefined ?
2656 oSettings.ajax.dataSrc :
2657 oSettings.sAjaxDataProp; // Compatibility with 1.9-.
2658
2659 // Compatibility with 1.9-. In order to read from aaData, check if the
2660 // default has been changed, if not, check for aaData
2661 if ( dataSrc === 'data' ) {
2662 return json.aaData || json[dataSrc];
2663 }
2664
2665 return dataSrc !== "" ?
2666 _fnGetObjectDataFn( dataSrc )( json ) :
2667 json;
2668 }
2669
2670
2671 /**
2672 * Generate the node required for filtering text
2673 * @returns {node} Filter control element
2674 * @param {object} oSettings dataTables settings object
2675 * @memberof DataTable#oApi
2676 */
2677 function _fnFeatureHtmlFilter ( settings )
2678 {
2679 var classes = settings.oClasses;
2680 var tableId = settings.sTableId;
2681 var language = settings.oLanguage;
2682 var previousSearch = settings.oPreviousSearch;
2683 var features = settings.aanFeatures;
2684 var input = '<input type="search" class="'+classes.sFilterInput+'"/>';
2685
2686 var str = language.sSearch;
2687 str = str.match(/_INPUT_/) ?
2688 str.replace('_INPUT_', input) :
2689 str+input;
2690
2691 var filter = $('<div/>', {
2692 'id': ! features.f ? tableId+'_filter' : null,
2693 'class': classes.sFilter
2694 } )
2695 .append( $('<label/>' ).append( str ) );
2696
2697 var searchFn = function() {
2698 /* Update all other filter input elements for the new display */
2699 var n = features.f;
2700 var val = !this.value ? "" : this.value; // mental IE8 fix :-(
2701
2702 /* Now do the filter */
2703 if ( val != previousSearch.sSearch ) {
2704 _fnFilterComplete( settings, {
2705 "sSearch": val,
2706 "bRegex": previousSearch.bRegex,
2707 "bSmart": previousSearch.bSmart ,
2708 "bCaseInsensitive": previousSearch.bCaseInsensitive
2709 } );
2710
2711 // Need to redraw, without resorting
2712 settings._iDisplayStart = 0;
2713 _fnDraw( settings );
2714 }
2715 };
2716
2717 var searchDelay = settings.searchDelay !== null ?
2718 settings.searchDelay :
2719 _fnDataSource( settings ) === 'ssp' ?
2720 400 :
2721 0;
2722
2723 var jqFilter = $('input', filter)
2724 .val( previousSearch.sSearch )
2725 .attr( 'placeholder', language.sSearchPlaceholder )
2726 .bind(
2727 'keyup.DT search.DT input.DT paste.DT cut.DT',
2728 searchDelay ?
2729 _fnThrottle( searchFn, searchDelay ) :
2730 searchFn
2731 )
2732 .bind( 'keypress.DT', function(e) {
2733 /* Prevent form submission */
2734 if ( e.keyCode == 13 ) {
2735 return false;
2736 }
2737 } )
2738 .attr('aria-controls', tableId);
2739
2740 // Update the input elements whenever the table is filtered
2741 $(settings.nTable).on( 'search.dt.DT', function ( ev, s ) {
2742 if ( settings === s ) {
2743 // IE9 throws an 'unknown error' if document.activeElement is used
2744 // inside an iframe or frame...
2745 try {
2746 if ( jqFilter[0] !== document.activeElement ) {
2747 jqFilter.val( previousSearch.sSearch );
2748 }
2749 }
2750 catch ( e ) {}
2751 }
2752 } );
2753
2754 return filter[0];
2755 }
2756
2757
2758 /**
2759 * Filter the table using both the global filter and column based filtering
2760 * @param {object} oSettings dataTables settings object
2761 * @param {object} oSearch search information
2762 * @param {int} [iForce] force a research of the master array (1) or not (undefined or 0)
2763 * @memberof DataTable#oApi
2764 */
2765 function _fnFilterComplete ( oSettings, oInput, iForce )
2766 {
2767 var oPrevSearch = oSettings.oPreviousSearch;
2768 var aoPrevSearch = oSettings.aoPreSearchCols;
2769 var fnSaveFilter = function ( oFilter ) {
2770 /* Save the filtering values */
2771 oPrevSearch.sSearch = oFilter.sSearch;
2772 oPrevSearch.bRegex = oFilter.bRegex;
2773 oPrevSearch.bSmart = oFilter.bSmart;
2774 oPrevSearch.bCaseInsensitive = oFilter.bCaseInsensitive;
2775 };
2776 var fnRegex = function ( o ) {
2777 // Backwards compatibility with the bEscapeRegex option
2778 return o.bEscapeRegex !== undefined ? !o.bEscapeRegex : o.bRegex;
2779 };
2780
2781 // Resolve any column types that are unknown due to addition or invalidation
2782 // @todo As per sort - can this be moved into an event handler?
2783 _fnColumnTypes( oSettings );
2784
2785 /* In server-side processing all filtering is done by the server, so no point hanging around here */
2786 if ( _fnDataSource( oSettings ) != 'ssp' )
2787 {
2788 /* Global filter */
2789 _fnFilter( oSettings, oInput.sSearch, iForce, fnRegex(oInput), oInput.bSmart, oInput.bCaseInsensitive );
2790 fnSaveFilter( oInput );
2791
2792 /* Now do the individual column filter */
2793 for ( var i=0 ; i<aoPrevSearch.length ; i++ )
2794 {
2795 _fnFilterColumn( oSettings, aoPrevSearch[i].sSearch, i, fnRegex(aoPrevSearch[i]),
2796 aoPrevSearch[i].bSmart, aoPrevSearch[i].bCaseInsensitive );
2797 }
2798
2799 /* Custom filtering */
2800 _fnFilterCustom( oSettings );
2801 }
2802 else
2803 {
2804 fnSaveFilter( oInput );
2805 }
2806
2807 /* Tell the draw function we have been filtering */
2808 oSettings.bFiltered = true;
2809 _fnCallbackFire( oSettings, null, 'search', [oSettings] );
2810 }
2811
2812
2813 /**
2814 * Apply custom filtering functions
2815 * @param {object} oSettings dataTables settings object
2816 * @memberof DataTable#oApi
2817 */
2818 function _fnFilterCustom( settings )
2819 {
2820 var filters = DataTable.ext.search;
2821 var displayRows = settings.aiDisplay;
2822 var row, rowIdx;
2823
2824 for ( var i=0, ien=filters.length ; i<ien ; i++ ) {
2825 var rows = [];
2826
2827 // Loop over each row and see if it should be included
2828 for ( var j=0, jen=displayRows.length ; j<jen ; j++ ) {
2829 rowIdx = displayRows[ j ];
2830 row = settings.aoData[ rowIdx ];
2831
2832 if ( filters[i]( settings, row._aFilterData, rowIdx, row._aData, j ) ) {
2833 rows.push( rowIdx );
2834 }
2835 }
2836
2837 // So the array reference doesn't break set the results into the
2838 // existing array
2839 displayRows.length = 0;
2840 displayRows.push.apply( displayRows, rows );
2841 }
2842 }
2843
2844
2845 /**
2846 * Filter the table on a per-column basis
2847 * @param {object} oSettings dataTables settings object
2848 * @param {string} sInput string to filter on
2849 * @param {int} iColumn column to filter
2850 * @param {bool} bRegex treat search string as a regular expression or not
2851 * @param {bool} bSmart use smart filtering or not
2852 * @param {bool} bCaseInsensitive Do case insenstive matching or not
2853 * @memberof DataTable#oApi
2854 */
2855 function _fnFilterColumn ( settings, searchStr, colIdx, regex, smart, caseInsensitive )
2856 {
2857 if ( searchStr === '' ) {
2858 return;
2859 }
2860
2861 var data;
2862 var display = settings.aiDisplay;
2863 var rpSearch = _fnFilterCreateSearch( searchStr, regex, smart, caseInsensitive );
2864
2865 for ( var i=display.length-1 ; i>=0 ; i-- ) {
2866 data = settings.aoData[ display[i] ]._aFilterData[ colIdx ];
2867
2868 if ( ! rpSearch.test( data ) ) {
2869 display.splice( i, 1 );
2870 }
2871 }
2872 }
2873
2874
2875 /**
2876 * Filter the data table based on user input and draw the table
2877 * @param {object} settings dataTables settings object
2878 * @param {string} input string to filter on
2879 * @param {int} force optional - force a research of the master array (1) or not (undefined or 0)
2880 * @param {bool} regex treat as a regular expression or not
2881 * @param {bool} smart perform smart filtering or not
2882 * @param {bool} caseInsensitive Do case insenstive matching or not
2883 * @memberof DataTable#oApi
2884 */
2885 function _fnFilter( settings, input, force, regex, smart, caseInsensitive )
2886 {
2887 var rpSearch = _fnFilterCreateSearch( input, regex, smart, caseInsensitive );
2888 var prevSearch = settings.oPreviousSearch.sSearch;
2889 var displayMaster = settings.aiDisplayMaster;
2890 var display, invalidated, i;
2891
2892 // Need to take account of custom filtering functions - always filter
2893 if ( DataTable.ext.search.length !== 0 ) {
2894 force = true;
2895 }
2896
2897 // Check if any of the rows were invalidated
2898 invalidated = _fnFilterData( settings );
2899
2900 // If the input is blank - we just want the full data set
2901 if ( input.length <= 0 ) {
2902 settings.aiDisplay = displayMaster.slice();
2903 }
2904 else {
2905 // New search - start from the master array
2906 if ( invalidated ||
2907 force ||
2908 prevSearch.length > input.length ||
2909 input.indexOf(prevSearch) !== 0 ||
2910 settings.bSorted // On resort, the display master needs to be
2911 // re-filtered since indexes will have changed
2912 ) {
2913 settings.aiDisplay = displayMaster.slice();
2914 }
2915
2916 // Search the display array
2917 display = settings.aiDisplay;
2918
2919 for ( i=display.length-1 ; i>=0 ; i-- ) {
2920 if ( ! rpSearch.test( settings.aoData[ display[i] ]._sFilterRow ) ) {
2921 display.splice( i, 1 );
2922 }
2923 }
2924 }
2925 }
2926
2927
2928 /**
2929 * Build a regular expression object suitable for searching a table
2930 * @param {string} sSearch string to search for
2931 * @param {bool} bRegex treat as a regular expression or not
2932 * @param {bool} bSmart perform smart filtering or not
2933 * @param {bool} bCaseInsensitive Do case insensitive matching or not
2934 * @returns {RegExp} constructed object
2935 * @memberof DataTable#oApi
2936 */
2937 function _fnFilterCreateSearch( search, regex, smart, caseInsensitive )
2938 {
2939 search = regex ?
2940 search :
2941 _fnEscapeRegex( search );
2942
2943 if ( smart ) {
2944 /* For smart filtering we want to allow the search to work regardless of
2945 * word order. We also want double quoted text to be preserved, so word
2946 * order is important - a la google. So this is what we want to
2947 * generate:
2948 *
2949 * ^(?=.*?\bone\b)(?=.*?\btwo three\b)(?=.*?\bfour\b).*$
2950 */
2951 var a = $.map( search.match( /"[^"]+"|[^ ]+/g ) || '', function ( word ) {
2952 if ( word.charAt(0) === '"' ) {
2953 var m = word.match( /^"(.*)"$/ );
2954 word = m ? m[1] : word;
2955 }
2956
2957 return word.replace('"', '');
2958 } );
2959
2960 search = '^(?=.*?'+a.join( ')(?=.*?' )+').*$';
2961 }
2962
2963 return new RegExp( search, caseInsensitive ? 'i' : '' );
2964 }
2965
2966
2967 /**
2968 * scape a string such that it can be used in a regular expression
2969 * @param {string} sVal string to escape
2970 * @returns {string} escaped string
2971 * @memberof DataTable#oApi
2972 */
2973 function _fnEscapeRegex ( sVal )
2974 {
2975 return sVal.replace( _re_escape_regex, '\\$1' );
2976 }
2977
2978
2979
2980 var __filter_div = $('<div>')[0];
2981 var __filter_div_textContent = __filter_div.textContent !== undefined;
2982
2983 // Update the filtering data for each row if needed (by invalidation or first run)
2984 function _fnFilterData ( settings )
2985 {
2986 var columns = settings.aoColumns;
2987 var column;
2988 var i, j, ien, jen, filterData, cellData, row;
2989 var fomatters = DataTable.ext.type.search;
2990 var wasInvalidated = false;
2991
2992 for ( i=0, ien=settings.aoData.length ; i<ien ; i++ ) {
2993 row = settings.aoData[i];
2994
2995 if ( ! row._aFilterData ) {
2996 filterData = [];
2997
2998 for ( j=0, jen=columns.length ; j<jen ; j++ ) {
2999 column = columns[j];
3000
3001 if ( column.bSearchable ) {
3002 cellData = _fnGetCellData( settings, i, j, 'filter' );
3003
3004 if ( fomatters[ column.sType ] ) {
3005 cellData = fomatters[ column.sType ]( cellData );
3006 }
3007
3008 // Search in DataTables 1.10 is string based. In 1.11 this
3009 // should be altered to also allow strict type checking.
3010 if ( cellData === null ) {
3011 cellData = '';
3012 }
3013
3014 if ( typeof cellData !== 'string' && cellData.toString ) {
3015 cellData = cellData.toString();
3016 }
3017 }
3018 else {
3019 cellData = '';
3020 }
3021
3022 // If it looks like there is an HTML entity in the string,
3023 // attempt to decode it so sorting works as expected. Note that
3024 // we could use a single line of jQuery to do this, but the DOM
3025 // method used here is much faster http://jsperf.com/html-decode
3026 if ( cellData.indexOf && cellData.indexOf('&') !== -1 ) {
3027 __filter_div.innerHTML = cellData;
3028 cellData = __filter_div_textContent ?
3029 __filter_div.textContent :
3030 __filter_div.innerText;
3031 }
3032
3033 if ( cellData.replace ) {
3034 cellData = cellData.replace(/[\r\n]/g, '');
3035 }
3036
3037 filterData.push( cellData );
3038 }
3039
3040 row._aFilterData = filterData;
3041 row._sFilterRow = filterData.join(' ');
3042 wasInvalidated = true;
3043 }
3044 }
3045
3046 return wasInvalidated;
3047 }
3048
3049
3050 /**
3051 * Convert from the internal Hungarian notation to camelCase for external
3052 * interaction
3053 * @param {object} obj Object to convert
3054 * @returns {object} Inverted object
3055 * @memberof DataTable#oApi
3056 */
3057 function _fnSearchToCamel ( obj )
3058 {
3059 return {
3060 search: obj.sSearch,
3061 smart: obj.bSmart,
3062 regex: obj.bRegex,
3063 caseInsensitive: obj.bCaseInsensitive
3064 };
3065 }
3066
3067
3068
3069 /**
3070 * Convert from camelCase notation to the internal Hungarian. We could use the
3071 * Hungarian convert function here, but this is cleaner
3072 * @param {object} obj Object to convert
3073 * @returns {object} Inverted object
3074 * @memberof DataTable#oApi
3075 */
3076 function _fnSearchToHung ( obj )
3077 {
3078 return {
3079 sSearch: obj.search,
3080 bSmart: obj.smart,
3081 bRegex: obj.regex,
3082 bCaseInsensitive: obj.caseInsensitive
3083 };
3084 }
3085
3086 /**
3087 * Generate the node required for the info display
3088 * @param {object} oSettings dataTables settings object
3089 * @returns {node} Information element
3090 * @memberof DataTable#oApi
3091 */
3092 function _fnFeatureHtmlInfo ( settings )
3093 {
3094 var
3095 tid = settings.sTableId,
3096 nodes = settings.aanFeatures.i,
3097 n = $('<div/>', {
3098 'class': settings.oClasses.sInfo,
3099 'id': ! nodes ? tid+'_info' : null
3100 } );
3101
3102 if ( ! nodes ) {
3103 // Update display on each draw
3104 settings.aoDrawCallback.push( {
3105 "fn": _fnUpdateInfo,
3106 "sName": "information"
3107 } );
3108
3109 n
3110 .attr( 'role', 'status' )
3111 .attr( 'aria-live', 'polite' );
3112
3113 // Table is described by our info div
3114 $(settings.nTable).attr( 'aria-describedby', tid+'_info' );
3115 }
3116
3117 return n[0];
3118 }
3119
3120
3121 /**
3122 * Update the information elements in the display
3123 * @param {object} settings dataTables settings object
3124 * @memberof DataTable#oApi
3125 */
3126 function _fnUpdateInfo ( settings )
3127 {
3128 /* Show information about the table */
3129 var nodes = settings.aanFeatures.i;
3130 if ( nodes.length === 0 ) {
3131 return;
3132 }
3133
3134 var
3135 lang = settings.oLanguage,
3136 start = settings._iDisplayStart+1,
3137 end = settings.fnDisplayEnd(),
3138 max = settings.fnRecordsTotal(),
3139 total = settings.fnRecordsDisplay(),
3140 out = total ?
3141 lang.sInfo :
3142 lang.sInfoEmpty;
3143
3144 if ( total !== max ) {
3145 /* Record set after filtering */
3146 out += ' ' + lang.sInfoFiltered;
3147 }
3148
3149 // Convert the macros
3150 out += lang.sInfoPostFix;
3151 out = _fnInfoMacros( settings, out );
3152
3153 var callback = lang.fnInfoCallback;
3154 if ( callback !== null ) {
3155 out = callback.call( settings.oInstance,
3156 settings, start, end, max, total, out
3157 );
3158 }
3159
3160 $(nodes).html( out );
3161 }
3162
3163
3164 function _fnInfoMacros ( settings, str )
3165 {
3166 // When infinite scrolling, we are always starting at 1. _iDisplayStart is used only
3167 // internally
3168 var
3169 formatter = settings.fnFormatNumber,
3170 start = settings._iDisplayStart+1,
3171 len = settings._iDisplayLength,
3172 vis = settings.fnRecordsDisplay(),
3173 all = len === -1;
3174
3175 return str.
3176 replace(/_START_/g, formatter.call( settings, start ) ).
3177 replace(/_END_/g, formatter.call( settings, settings.fnDisplayEnd() ) ).
3178 replace(/_MAX_/g, formatter.call( settings, settings.fnRecordsTotal() ) ).
3179 replace(/_TOTAL_/g, formatter.call( settings, vis ) ).
3180 replace(/_PAGE_/g, formatter.call( settings, all ? 1 : Math.ceil( start / len ) ) ).
3181 replace(/_PAGES_/g, formatter.call( settings, all ? 1 : Math.ceil( vis / len ) ) );
3182 }
3183
3184
3185
3186 /**
3187 * Draw the table for the first time, adding all required features
3188 * @param {object} settings dataTables settings object
3189 * @memberof DataTable#oApi
3190 */
3191 function _fnInitialise ( settings )
3192 {
3193 var i, iLen, iAjaxStart=settings.iInitDisplayStart;
3194 var columns = settings.aoColumns, column;
3195 var features = settings.oFeatures;
3196
3197 /* Ensure that the table data is fully initialised */
3198 if ( ! settings.bInitialised ) {
3199 setTimeout( function(){ _fnInitialise( settings ); }, 200 );
3200 return;
3201 }
3202
3203 /* Show the display HTML options */
3204 _fnAddOptionsHtml( settings );
3205
3206 /* Build and draw the header / footer for the table */
3207 _fnBuildHead( settings );
3208 _fnDrawHead( settings, settings.aoHeader );
3209 _fnDrawHead( settings, settings.aoFooter );
3210
3211 /* Okay to show that something is going on now */
3212 _fnProcessingDisplay( settings, true );
3213
3214 /* Calculate sizes for columns */
3215 if ( features.bAutoWidth ) {
3216 _fnCalculateColumnWidths( settings );
3217 }
3218
3219 for ( i=0, iLen=columns.length ; i<iLen ; i++ ) {
3220 column = columns[i];
3221
3222 if ( column.sWidth ) {
3223 column.nTh.style.width = _fnStringToCss( column.sWidth );
3224 }
3225 }
3226
3227 // If there is default sorting required - let's do it. The sort function
3228 // will do the drawing for us. Otherwise we draw the table regardless of the
3229 // Ajax source - this allows the table to look initialised for Ajax sourcing
3230 // data (show 'loading' message possibly)
3231 _fnReDraw( settings );
3232
3233 // Server-side processing init complete is done by _fnAjaxUpdateDraw
3234 var dataSrc = _fnDataSource( settings );
3235 if ( dataSrc != 'ssp' ) {
3236 // if there is an ajax source load the data
3237 if ( dataSrc == 'ajax' ) {
3238 _fnBuildAjax( settings, [], function(json) {
3239 var aData = _fnAjaxDataSrc( settings, json );
3240
3241 // Got the data - add it to the table
3242 for ( i=0 ; i<aData.length ; i++ ) {
3243 _fnAddData( settings, aData[i] );
3244 }
3245
3246 // Reset the init display for cookie saving. We've already done
3247 // a filter, and therefore cleared it before. So we need to make
3248 // it appear 'fresh'
3249 settings.iInitDisplayStart = iAjaxStart;
3250
3251 _fnReDraw( settings );
3252
3253 _fnProcessingDisplay( settings, false );
3254 _fnInitComplete( settings, json );
3255 }, settings );
3256 }
3257 else {
3258 _fnProcessingDisplay( settings, false );
3259 _fnInitComplete( settings );
3260 }
3261 }
3262 }
3263
3264
3265 /**
3266 * Draw the table for the first time, adding all required features
3267 * @param {object} oSettings dataTables settings object
3268 * @param {object} [json] JSON from the server that completed the table, if using Ajax source
3269 * with client-side processing (optional)
3270 * @memberof DataTable#oApi
3271 */
3272 function _fnInitComplete ( settings, json )
3273 {
3274 settings._bInitComplete = true;
3275
3276 // On an Ajax load we now have data and therefore want to apply the column
3277 // sizing
3278 if ( json ) {
3279 _fnAdjustColumnSizing( settings );
3280 }
3281
3282 _fnCallbackFire( settings, 'aoInitComplete', 'init', [settings, json] );
3283 }
3284
3285
3286 function _fnLengthChange ( settings, val )
3287 {
3288 var len = parseInt( val, 10 );
3289 settings._iDisplayLength = len;
3290
3291 _fnLengthOverflow( settings );
3292
3293 // Fire length change event
3294 _fnCallbackFire( settings, null, 'length', [settings, len] );
3295 }
3296
3297
3298 /**
3299 * Generate the node required for user display length changing
3300 * @param {object} settings dataTables settings object
3301 * @returns {node} Display length feature node
3302 * @memberof DataTable#oApi
3303 */
3304 function _fnFeatureHtmlLength ( settings )
3305 {
3306 var
3307 classes = settings.oClasses,
3308 tableId = settings.sTableId,
3309 menu = settings.aLengthMenu,
3310 d2 = $.isArray( menu[0] ),
3311 lengths = d2 ? menu[0] : menu,
3312 language = d2 ? menu[1] : menu;
3313
3314 var select = $('<select/>', {
3315 'name': tableId+'_length',
3316 'aria-controls': tableId,
3317 'class': classes.sLengthSelect
3318 } );
3319
3320 for ( var i=0, ien=lengths.length ; i<ien ; i++ ) {
3321 select[0][ i ] = new Option( language[i], lengths[i] );
3322 }
3323
3324 var div = $('<div><label/></div>').addClass( classes.sLength );
3325 if ( ! settings.aanFeatures.l ) {
3326 div[0].id = tableId+'_length';
3327 }
3328
3329 div.children().append(
3330 settings.oLanguage.sLengthMenu.replace( '_MENU_', select[0].outerHTML )
3331 );
3332
3333 // Can't use `select` variable as user might provide their own and the
3334 // reference is broken by the use of outerHTML
3335 $('select', div)
3336 .val( settings._iDisplayLength )
3337 .bind( 'change.DT', function(e) {
3338 _fnLengthChange( settings, $(this).val() );
3339 _fnDraw( settings );
3340 } );
3341
3342 // Update node value whenever anything changes the table's length
3343 $(settings.nTable).bind( 'length.dt.DT', function (e, s, len) {
3344 if ( settings === s ) {
3345 $('select', div).val( len );
3346 }
3347 } );
3348
3349 return div[0];
3350 }
3351
3352
3353
3354 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
3355 * Note that most of the paging logic is done in
3356 * DataTable.ext.pager
3357 */
3358
3359 /**
3360 * Generate the node required for default pagination
3361 * @param {object} oSettings dataTables settings object
3362 * @returns {node} Pagination feature node
3363 * @memberof DataTable#oApi
3364 */
3365 function _fnFeatureHtmlPaginate ( settings )
3366 {
3367 var
3368 type = settings.sPaginationType,
3369 plugin = DataTable.ext.pager[ type ],
3370 modern = typeof plugin === 'function',
3371 redraw = function( settings ) {
3372 _fnDraw( settings );
3373 },
3374 node = $('<div/>').addClass( settings.oClasses.sPaging + type )[0],
3375 features = settings.aanFeatures;
3376
3377 if ( ! modern ) {
3378 plugin.fnInit( settings, node, redraw );
3379 }
3380
3381 /* Add a draw callback for the pagination on first instance, to update the paging display */
3382 if ( ! features.p )
3383 {
3384 node.id = settings.sTableId+'_paginate';
3385
3386 settings.aoDrawCallback.push( {
3387 "fn": function( settings ) {
3388 if ( modern ) {
3389 var
3390 start = settings._iDisplayStart,
3391 len = settings._iDisplayLength,
3392 visRecords = settings.fnRecordsDisplay(),
3393 all = len === -1,
3394 page = all ? 0 : Math.ceil( start / len ),
3395 pages = all ? 1 : Math.ceil( visRecords / len ),
3396 buttons = plugin(page, pages),
3397 i, ien;
3398
3399 for ( i=0, ien=features.p.length ; i<ien ; i++ ) {
3400 _fnRenderer( settings, 'pageButton' )(
3401 settings, features.p[i], i, buttons, page, pages
3402 );
3403 }
3404 }
3405 else {
3406 plugin.fnUpdate( settings, redraw );
3407 }
3408 },
3409 "sName": "pagination"
3410 } );
3411 }
3412
3413 return node;
3414 }
3415
3416
3417 /**
3418 * Alter the display settings to change the page
3419 * @param {object} settings DataTables settings object
3420 * @param {string|int} action Paging action to take: "first", "previous",
3421 * "next" or "last" or page number to jump to (integer)
3422 * @param [bool] redraw Automatically draw the update or not
3423 * @returns {bool} true page has changed, false - no change
3424 * @memberof DataTable#oApi
3425 */
3426 function _fnPageChange ( settings, action, redraw )
3427 {
3428 var
3429 start = settings._iDisplayStart,
3430 len = settings._iDisplayLength,
3431 records = settings.fnRecordsDisplay();
3432
3433 if ( records === 0 || len === -1 )
3434 {
3435 start = 0;
3436 }
3437 else if ( typeof action === "number" )
3438 {
3439 start = action * len;
3440
3441 if ( start > records )
3442 {
3443 start = 0;
3444 }
3445 }
3446 else if ( action == "first" )
3447 {
3448 start = 0;
3449 }
3450 else if ( action == "previous" )
3451 {
3452 start = len >= 0 ?
3453 start - len :
3454 0;
3455
3456 if ( start < 0 )
3457 {
3458 start = 0;
3459 }
3460 }
3461 else if ( action == "next" )
3462 {
3463 if ( start + len < records )
3464 {
3465 start += len;
3466 }
3467 }
3468 else if ( action == "last" )
3469 {
3470 start = Math.floor( (records-1) / len) * len;
3471 }
3472 else
3473 {
3474 _fnLog( settings, 0, "Unknown paging action: "+action, 5 );
3475 }
3476
3477 var changed = settings._iDisplayStart !== start;
3478 settings._iDisplayStart = start;
3479
3480 if ( changed ) {
3481 _fnCallbackFire( settings, null, 'page', [settings] );
3482
3483 if ( redraw ) {
3484 _fnDraw( settings );
3485 }
3486 }
3487
3488 return changed;
3489 }
3490
3491
3492
3493 /**
3494 * Generate the node required for the processing node
3495 * @param {object} settings dataTables settings object
3496 * @returns {node} Processing element
3497 * @memberof DataTable#oApi
3498 */
3499 function _fnFeatureHtmlProcessing ( settings )
3500 {
3501 return $('<div/>', {
3502 'id': ! settings.aanFeatures.r ? settings.sTableId+'_processing' : null,
3503 'class': settings.oClasses.sProcessing
3504 } )
3505 .html( settings.oLanguage.sProcessing )
3506 .insertBefore( settings.nTable )[0];
3507 }
3508
3509
3510 /**
3511 * Display or hide the processing indicator
3512 * @param {object} settings dataTables settings object
3513 * @param {bool} show Show the processing indicator (true) or not (false)
3514 * @memberof DataTable#oApi
3515 */
3516 function _fnProcessingDisplay ( settings, show )
3517 {
3518 if ( settings.oFeatures.bProcessing ) {
3519 $(settings.aanFeatures.r).css( 'display', show ? 'block' : 'none' );
3520 }
3521
3522 _fnCallbackFire( settings, null, 'processing', [settings, show] );
3523 }
3524
3525 /**
3526 * Add any control elements for the table - specifically scrolling
3527 * @param {object} settings dataTables settings object
3528 * @returns {node} Node to add to the DOM
3529 * @memberof DataTable#oApi
3530 */
3531 function _fnFeatureHtmlTable ( settings )
3532 {
3533 var table = $(settings.nTable);
3534
3535 // Add the ARIA grid role to the table
3536 table.attr( 'role', 'grid' );
3537
3538 // Scrolling from here on in
3539 var scroll = settings.oScroll;
3540
3541 if ( scroll.sX === '' && scroll.sY === '' ) {
3542 return settings.nTable;
3543 }
3544
3545 var scrollX = scroll.sX;
3546 var scrollY = scroll.sY;
3547 var classes = settings.oClasses;
3548 var caption = table.children('caption');
3549 var captionSide = caption.length ? caption[0]._captionSide : null;
3550 var headerClone = $( table[0].cloneNode(false) );
3551 var footerClone = $( table[0].cloneNode(false) );
3552 var footer = table.children('tfoot');
3553 var _div = '<div/>';
3554 var size = function ( s ) {
3555 return !s ? null : _fnStringToCss( s );
3556 };
3557
3558 // This is fairly messy, but with x scrolling enabled, if the table has a
3559 // width attribute, regardless of any width applied using the column width
3560 // options, the browser will shrink or grow the table as needed to fit into
3561 // that 100%. That would make the width options useless. So we remove it.
3562 // This is okay, under the assumption that width:100% is applied to the
3563 // table in CSS (it is in the default stylesheet) which will set the table
3564 // width as appropriate (the attribute and css behave differently...)
3565 if ( scroll.sX && table.attr('width') === '100%' ) {
3566 table.removeAttr('width');
3567 }
3568
3569 if ( ! footer.length ) {
3570 footer = null;
3571 }
3572
3573 /*
3574 * The HTML structure that we want to generate in this function is:
3575 * div - scroller
3576 * div - scroll head
3577 * div - scroll head inner
3578 * table - scroll head table
3579 * thead - thead
3580 * div - scroll body
3581 * table - table (master table)
3582 * thead - thead clone for sizing
3583 * tbody - tbody
3584 * div - scroll foot
3585 * div - scroll foot inner
3586 * table - scroll foot table
3587 * tfoot - tfoot
3588 */
3589 var scroller = $( _div, { 'class': classes.sScrollWrapper } )
3590 .append(
3591 $(_div, { 'class': classes.sScrollHead } )
3592 .css( {
3593 overflow: 'hidden',
3594 position: 'relative',
3595 border: 0,
3596 width: scrollX ? size(scrollX) : '100%'
3597 } )
3598 .append(
3599 $(_div, { 'class': classes.sScrollHeadInner } )
3600 .css( {
3601 'box-sizing': 'content-box',
3602 width: scroll.sXInner || '100%'
3603 } )
3604 .append(
3605 headerClone
3606 .removeAttr('id')
3607 .css( 'margin-left', 0 )
3608 .append(
3609 table.children('thead')
3610 )
3611 )
3612 )
3613 .append( captionSide === 'top' ? caption : null )
3614 )
3615 .append(
3616 $(_div, { 'class': classes.sScrollBody } )
3617 .css( {
3618 overflow: 'auto',
3619 height: size( scrollY ),
3620 width: size( scrollX )
3621 } )
3622 .append( table )
3623 );
3624
3625 if ( footer ) {
3626 scroller.append(
3627 $(_div, { 'class': classes.sScrollFoot } )
3628 .css( {
3629 overflow: 'hidden',
3630 border: 0,
3631 width: scrollX ? size(scrollX) : '100%'
3632 } )
3633 .append(
3634 $(_div, { 'class': classes.sScrollFootInner } )
3635 .append(
3636 footerClone
3637 .removeAttr('id')
3638 .css( 'margin-left', 0 )
3639 .append(
3640 table.children('tfoot')
3641 )
3642 )
3643 )
3644 .append( captionSide === 'bottom' ? caption : null )
3645 );
3646 }
3647
3648 var children = scroller.children();
3649 var scrollHead = children[0];
3650 var scrollBody = children[1];
3651 var scrollFoot = footer ? children[2] : null;
3652
3653 // When the body is scrolled, then we also want to scroll the headers
3654 if ( scrollX ) {
3655 $(scrollBody).scroll( function (e) {
3656 var scrollLeft = this.scrollLeft;
3657
3658 scrollHead.scrollLeft = scrollLeft;
3659
3660 if ( footer ) {
3661 scrollFoot.scrollLeft = scrollLeft;
3662 }
3663 } );
3664 }
3665
3666 settings.nScrollHead = scrollHead;
3667 settings.nScrollBody = scrollBody;
3668 settings.nScrollFoot = scrollFoot;
3669
3670 // On redraw - align columns
3671 settings.aoDrawCallback.push( {
3672 "fn": _fnScrollDraw,
3673 "sName": "scrolling"
3674 } );
3675
3676 return scroller[0];
3677 }
3678
3679
3680
3681 /**
3682 * Update the header, footer and body tables for resizing - i.e. column
3683 * alignment.
3684 *
3685 * Welcome to the most horrible function DataTables. The process that this
3686 * function follows is basically:
3687 * 1. Re-create the table inside the scrolling div
3688 * 2. Take live measurements from the DOM
3689 * 3. Apply the measurements to align the columns
3690 * 4. Clean up
3691 *
3692 * @param {object} settings dataTables settings object
3693 * @memberof DataTable#oApi
3694 */
3695 function _fnScrollDraw ( settings )
3696 {
3697 // Given that this is such a monster function, a lot of variables are use
3698 // to try and keep the minimised size as small as possible
3699 var
3700 scroll = settings.oScroll,
3701 scrollX = scroll.sX,
3702 scrollXInner = scroll.sXInner,
3703 scrollY = scroll.sY,
3704 barWidth = scroll.iBarWidth,
3705 divHeader = $(settings.nScrollHead),
3706 divHeaderStyle = divHeader[0].style,
3707 divHeaderInner = divHeader.children('div'),
3708 divHeaderInnerStyle = divHeaderInner[0].style,
3709 divHeaderTable = divHeaderInner.children('table'),
3710 divBodyEl = settings.nScrollBody,
3711 divBody = $(divBodyEl),
3712 divBodyStyle = divBodyEl.style,
3713 divFooter = $(settings.nScrollFoot),
3714 divFooterInner = divFooter.children('div'),
3715 divFooterTable = divFooterInner.children('table'),
3716 header = $(settings.nTHead),
3717 table = $(settings.nTable),
3718 tableEl = table[0],
3719 tableStyle = tableEl.style,
3720 footer = settings.nTFoot ? $(settings.nTFoot) : null,
3721 browser = settings.oBrowser,
3722 ie67 = browser.bScrollOversize,
3723 headerTrgEls, footerTrgEls,
3724 headerSrcEls, footerSrcEls,
3725 headerCopy, footerCopy,
3726 headerWidths=[], footerWidths=[],
3727 headerContent=[],
3728 idx, correction, sanityWidth,
3729 zeroOut = function(nSizer) {
3730 var style = nSizer.style;
3731 style.paddingTop = "0";
3732 style.paddingBottom = "0";
3733 style.borderTopWidth = "0";
3734 style.borderBottomWidth = "0";
3735 style.height = 0;
3736 };
3737
3738 /*
3739 * 1. Re-create the table inside the scrolling div
3740 */
3741
3742 // Remove the old minimised thead and tfoot elements in the inner table
3743 table.children('thead, tfoot').remove();
3744
3745 // Clone the current header and footer elements and then place it into the inner table
3746 headerCopy = header.clone().prependTo( table );
3747 headerTrgEls = header.find('tr'); // original header is in its own table
3748 headerSrcEls = headerCopy.find('tr');
3749 headerCopy.find('th, td').removeAttr('tabindex');
3750
3751 if ( footer ) {
3752 footerCopy = footer.clone().prependTo( table );
3753 footerTrgEls = footer.find('tr'); // the original tfoot is in its own table and must be sized
3754 footerSrcEls = footerCopy.find('tr');
3755 }
3756
3757
3758 /*
3759 * 2. Take live measurements from the DOM - do not alter the DOM itself!
3760 */
3761
3762 // Remove old sizing and apply the calculated column widths
3763 // Get the unique column headers in the newly created (cloned) header. We want to apply the
3764 // calculated sizes to this header
3765 if ( ! scrollX )
3766 {
3767 divBodyStyle.width = '100%';
3768 divHeader[0].style.width = '100%';
3769 }
3770
3771 $.each( _fnGetUniqueThs( settings, headerCopy ), function ( i, el ) {
3772 idx = _fnVisibleToColumnIndex( settings, i );
3773 el.style.width = settings.aoColumns[idx].sWidth;
3774 } );
3775
3776 if ( footer ) {
3777 _fnApplyToChildren( function(n) {
3778 n.style.width = "";
3779 }, footerSrcEls );
3780 }
3781
3782 // If scroll collapse is enabled, when we put the headers back into the body for sizing, we
3783 // will end up forcing the scrollbar to appear, making our measurements wrong for when we
3784 // then hide it (end of this function), so add the header height to the body scroller.
3785 if ( scroll.bCollapse && scrollY !== "" ) {
3786 divBodyStyle.height = (divBody[0].offsetHeight + header[0].offsetHeight)+"px";
3787 }
3788
3789 // Size the table as a whole
3790 sanityWidth = table.outerWidth();
3791 if ( scrollX === "" ) {
3792 // No x scrolling
3793 tableStyle.width = "100%";
3794
3795 // IE7 will make the width of the table when 100% include the scrollbar
3796 // - which is shouldn't. When there is a scrollbar we need to take this
3797 // into account.
3798 if ( ie67 && (table.find('tbody').height() > divBodyEl.offsetHeight ||
3799 divBody.css('overflow-y') == "scroll")
3800 ) {
3801 tableStyle.width = _fnStringToCss( table.outerWidth() - barWidth);
3802 }
3803 }
3804 else
3805 {
3806 // x scrolling
3807 if ( scrollXInner !== "" ) {
3808 // x scroll inner has been given - use it
3809 tableStyle.width = _fnStringToCss(scrollXInner);
3810 }
3811 else if ( sanityWidth == divBody.width() && divBody.height() < table.height() ) {
3812 // There is y-scrolling - try to take account of the y scroll bar
3813 tableStyle.width = _fnStringToCss( sanityWidth-barWidth );
3814 if ( table.outerWidth() > sanityWidth-barWidth ) {
3815 // Not possible to take account of it
3816 tableStyle.width = _fnStringToCss( sanityWidth );
3817 }
3818 }
3819 else {
3820 // When all else fails
3821 tableStyle.width = _fnStringToCss( sanityWidth );
3822 }
3823 }
3824
3825 // Recalculate the sanity width - now that we've applied the required width,
3826 // before it was a temporary variable. This is required because the column
3827 // width calculation is done before this table DOM is created.
3828 sanityWidth = table.outerWidth();
3829
3830 // Hidden header should have zero height, so remove padding and borders. Then
3831 // set the width based on the real headers
3832
3833 // Apply all styles in one pass
3834 _fnApplyToChildren( zeroOut, headerSrcEls );
3835
3836 // Read all widths in next pass
3837 _fnApplyToChildren( function(nSizer) {
3838 headerContent.push( nSizer.innerHTML );
3839 headerWidths.push( _fnStringToCss( $(nSizer).css('width') ) );
3840 }, headerSrcEls );
3841
3842 // Apply all widths in final pass
3843 _fnApplyToChildren( function(nToSize, i) {
3844 nToSize.style.width = headerWidths[i];
3845 }, headerTrgEls );
3846
3847 $(headerSrcEls).height(0);
3848
3849 /* Same again with the footer if we have one */
3850 if ( footer )
3851 {
3852 _fnApplyToChildren( zeroOut, footerSrcEls );
3853
3854 _fnApplyToChildren( function(nSizer) {
3855 footerWidths.push( _fnStringToCss( $(nSizer).css('width') ) );
3856 }, footerSrcEls );
3857
3858 _fnApplyToChildren( function(nToSize, i) {
3859 nToSize.style.width = footerWidths[i];
3860 }, footerTrgEls );
3861
3862 $(footerSrcEls).height(0);
3863 }
3864
3865
3866 /*
3867 * 3. Apply the measurements
3868 */
3869
3870 // "Hide" the header and footer that we used for the sizing. We need to keep
3871 // the content of the cell so that the width applied to the header and body
3872 // both match, but we want to hide it completely. We want to also fix their
3873 // width to what they currently are
3874 _fnApplyToChildren( function(nSizer, i) {
3875 nSizer.innerHTML = '<div class="dataTables_sizing" style="height:0;overflow:hidden;">'+headerContent[i]+'</div>';
3876 nSizer.style.width = headerWidths[i];
3877 }, headerSrcEls );
3878
3879 if ( footer )
3880 {
3881 _fnApplyToChildren( function(nSizer, i) {
3882 nSizer.innerHTML = "";
3883 nSizer.style.width = footerWidths[i];
3884 }, footerSrcEls );
3885 }
3886
3887 // Sanity check that the table is of a sensible width. If not then we are going to get
3888 // misalignment - try to prevent this by not allowing the table to shrink below its min width
3889 if ( table.outerWidth() < sanityWidth )
3890 {
3891 // The min width depends upon if we have a vertical scrollbar visible or not */
3892 correction = ((divBodyEl.scrollHeight > divBodyEl.offsetHeight ||
3893 divBody.css('overflow-y') == "scroll")) ?
3894 sanityWidth+barWidth :
3895 sanityWidth;
3896
3897 // IE6/7 are a law unto themselves...
3898 if ( ie67 && (divBodyEl.scrollHeight >
3899 divBodyEl.offsetHeight || divBody.css('overflow-y') == "scroll")
3900 ) {
3901 tableStyle.width = _fnStringToCss( correction-barWidth );
3902 }
3903
3904 // And give the user a warning that we've stopped the table getting too small
3905 if ( scrollX === "" || scrollXInner !== "" ) {
3906 _fnLog( settings, 1, 'Possible column misalignment', 6 );
3907 }
3908 }
3909 else
3910 {
3911 correction = '100%';
3912 }
3913
3914 // Apply to the container elements
3915 divBodyStyle.width = _fnStringToCss( correction );
3916 divHeaderStyle.width = _fnStringToCss( correction );
3917
3918 if ( footer ) {
3919 settings.nScrollFoot.style.width = _fnStringToCss( correction );
3920 }
3921
3922
3923 /*
3924 * 4. Clean up
3925 */
3926 if ( ! scrollY ) {
3927 /* IE7< puts a vertical scrollbar in place (when it shouldn't be) due to subtracting
3928 * the scrollbar height from the visible display, rather than adding it on. We need to
3929 * set the height in order to sort this. Don't want to do it in any other browsers.
3930 */
3931 if ( ie67 ) {
3932 divBodyStyle.height = _fnStringToCss( tableEl.offsetHeight+barWidth );
3933 }
3934 }
3935
3936 if ( scrollY && scroll.bCollapse ) {
3937 divBodyStyle.height = _fnStringToCss( scrollY );
3938
3939 var iExtra = (scrollX && tableEl.offsetWidth > divBodyEl.offsetWidth) ?
3940 barWidth :
3941 0;
3942
3943 if ( tableEl.offsetHeight < divBodyEl.offsetHeight ) {
3944 divBodyStyle.height = _fnStringToCss( tableEl.offsetHeight+iExtra );
3945 }
3946 }
3947
3948 /* Finally set the width's of the header and footer tables */
3949 var iOuterWidth = table.outerWidth();
3950 divHeaderTable[0].style.width = _fnStringToCss( iOuterWidth );
3951 divHeaderInnerStyle.width = _fnStringToCss( iOuterWidth );
3952
3953 // Figure out if there are scrollbar present - if so then we need a the header and footer to
3954 // provide a bit more space to allow "overflow" scrolling (i.e. past the scrollbar)
3955 var bScrolling = table.height() > divBodyEl.clientHeight || divBody.css('overflow-y') == "scroll";
3956 var padding = 'padding' + (browser.bScrollbarLeft ? 'Left' : 'Right' );
3957 divHeaderInnerStyle[ padding ] = bScrolling ? barWidth+"px" : "0px";
3958
3959 if ( footer ) {
3960 divFooterTable[0].style.width = _fnStringToCss( iOuterWidth );
3961 divFooterInner[0].style.width = _fnStringToCss( iOuterWidth );
3962 divFooterInner[0].style[padding] = bScrolling ? barWidth+"px" : "0px";
3963 }
3964
3965 /* Adjust the position of the header in case we loose the y-scrollbar */
3966 divBody.scroll();
3967
3968 // If sorting or filtering has occurred, jump the scrolling back to the top
3969 // only if we aren't holding the position
3970 if ( (settings.bSorted || settings.bFiltered) && ! settings._drawHold ) {
3971 divBodyEl.scrollTop = 0;
3972 }
3973 }
3974
3975
3976
3977 /**
3978 * Apply a given function to the display child nodes of an element array (typically
3979 * TD children of TR rows
3980 * @param {function} fn Method to apply to the objects
3981 * @param array {nodes} an1 List of elements to look through for display children
3982 * @param array {nodes} an2 Another list (identical structure to the first) - optional
3983 * @memberof DataTable#oApi
3984 */
3985 function _fnApplyToChildren( fn, an1, an2 )
3986 {
3987 var index=0, i=0, iLen=an1.length;
3988 var nNode1, nNode2;
3989
3990 while ( i < iLen ) {
3991 nNode1 = an1[i].firstChild;
3992 nNode2 = an2 ? an2[i].firstChild : null;
3993
3994 while ( nNode1 ) {
3995 if ( nNode1.nodeType === 1 ) {
3996 if ( an2 ) {
3997 fn( nNode1, nNode2, index );
3998 }
3999 else {
4000 fn( nNode1, index );
4001 }
4002
4003 index++;
4004 }
4005
4006 nNode1 = nNode1.nextSibling;
4007 nNode2 = an2 ? nNode2.nextSibling : null;
4008 }
4009
4010 i++;
4011 }
4012 }
4013
4014
4015
4016 var __re_html_remove = /<.*?>/g;
4017
4018
4019 /**
4020 * Calculate the width of columns for the table
4021 * @param {object} oSettings dataTables settings object
4022 * @memberof DataTable#oApi
4023 */
4024 function _fnCalculateColumnWidths ( oSettings )
4025 {
4026 var
4027 table = oSettings.nTable,
4028 columns = oSettings.aoColumns,
4029 scroll = oSettings.oScroll,
4030 scrollY = scroll.sY,
4031 scrollX = scroll.sX,
4032 scrollXInner = scroll.sXInner,
4033 columnCount = columns.length,
4034 visibleColumns = _fnGetColumns( oSettings, 'bVisible' ),
4035 headerCells = $('th', oSettings.nTHead),
4036 tableWidthAttr = table.getAttribute('width'),
4037 tableContainer = table.parentNode,
4038 userInputs = false,
4039 i, column, columnIdx, width, outerWidth;
4040
4041 /* Convert any user input sizes into pixel sizes */
4042 for ( i=0 ; i<visibleColumns.length ; i++ ) {
4043 column = columns[ visibleColumns[i] ];
4044
4045 if ( column.sWidth !== null ) {
4046 column.sWidth = _fnConvertToWidth( column.sWidthOrig, tableContainer );
4047
4048 userInputs = true;
4049 }
4050 }
4051
4052 /* If the number of columns in the DOM equals the number that we have to
4053 * process in DataTables, then we can use the offsets that are created by
4054 * the web- browser. No custom sizes can be set in order for this to happen,
4055 * nor scrolling used
4056 */
4057 if ( ! userInputs && ! scrollX && ! scrollY &&
4058 columnCount == _fnVisbleColumns( oSettings ) &&
4059 columnCount == headerCells.length
4060 ) {
4061 for ( i=0 ; i<columnCount ; i++ ) {
4062 columns[i].sWidth = _fnStringToCss( headerCells.eq(i).width() );
4063 }
4064 }
4065 else
4066 {
4067 // Otherwise construct a single row table with the widest node in the
4068 // data, assign any user defined widths, then insert it into the DOM and
4069 // allow the browser to do all the hard work of calculating table widths
4070 var tmpTable = $(table).clone() // don't use cloneNode - IE8 will remove events on the main table
4071 .empty()
4072 .css( 'visibility', 'hidden' )
4073 .removeAttr( 'id' )
4074 .append( $(oSettings.nTHead).clone( false ) )
4075 .append( $(oSettings.nTFoot).clone( false ) )
4076 .append( $('<tbody><tr/></tbody>') );
4077
4078 // Remove any assigned widths from the footer (from scrolling)
4079 tmpTable.find('tfoot th, tfoot td').css('width', '');
4080
4081 var tr = tmpTable.find( 'tbody tr' );
4082
4083 // Apply custom sizing to the cloned header
4084 headerCells = _fnGetUniqueThs( oSettings, tmpTable.find('thead')[0] );
4085
4086 for ( i=0 ; i<visibleColumns.length ; i++ ) {
4087 column = columns[ visibleColumns[i] ];
4088
4089 headerCells[i].style.width = column.sWidthOrig !== null && column.sWidthOrig !== '' ?
4090 _fnStringToCss( column.sWidthOrig ) :
4091 '';
4092 }
4093
4094 // Find the widest cell for each column and put it into the table
4095 if ( oSettings.aoData.length ) {
4096 for ( i=0 ; i<visibleColumns.length ; i++ ) {
4097 columnIdx = visibleColumns[i];
4098 column = columns[ columnIdx ];
4099
4100 $( _fnGetWidestNode( oSettings, columnIdx ) )
4101 .clone( false )
4102 .append( column.sContentPadding )
4103 .appendTo( tr );
4104 }
4105 }
4106
4107 // Table has been built, attach to the document so we can work with it
4108 tmpTable.appendTo( tableContainer );
4109
4110 // When scrolling (X or Y) we want to set the width of the table as
4111 // appropriate. However, when not scrolling leave the table width as it
4112 // is. This results in slightly different, but I think correct behaviour
4113 if ( scrollX && scrollXInner ) {
4114 tmpTable.width( scrollXInner );
4115 }
4116 else if ( scrollX ) {
4117 tmpTable.css( 'width', 'auto' );
4118
4119 if ( tmpTable.width() < tableContainer.offsetWidth ) {
4120 tmpTable.width( tableContainer.offsetWidth );
4121 }
4122 }
4123 else if ( scrollY ) {
4124 tmpTable.width( tableContainer.offsetWidth );
4125 }
4126 else if ( tableWidthAttr ) {
4127 tmpTable.width( tableWidthAttr );
4128 }
4129
4130 // Take into account the y scrollbar
4131 _fnScrollingWidthAdjust( oSettings, tmpTable[0] );
4132
4133 // Browsers need a bit of a hand when a width is assigned to any columns
4134 // when x-scrolling as they tend to collapse the table to the min-width,
4135 // even if we sent the column widths. So we need to keep track of what
4136 // the table width should be by summing the user given values, and the
4137 // automatic values
4138 if ( scrollX )
4139 {
4140 var total = 0;
4141
4142 for ( i=0 ; i<visibleColumns.length ; i++ ) {
4143 column = columns[ visibleColumns[i] ];
4144 outerWidth = $(headerCells[i]).outerWidth();
4145
4146 total += column.sWidthOrig === null ?
4147 outerWidth :
4148 parseInt( column.sWidth, 10 ) + outerWidth - $(headerCells[i]).width();
4149 }
4150
4151 tmpTable.width( _fnStringToCss( total ) );
4152 table.style.width = _fnStringToCss( total );
4153 }
4154
4155 // Get the width of each column in the constructed table
4156 for ( i=0 ; i<visibleColumns.length ; i++ ) {
4157 column = columns[ visibleColumns[i] ];
4158 width = $(headerCells[i]).width();
4159
4160 if ( width ) {
4161 column.sWidth = _fnStringToCss( width );
4162 }
4163 }
4164
4165 table.style.width = _fnStringToCss( tmpTable.css('width') );
4166
4167 // Finished with the table - ditch it
4168 tmpTable.remove();
4169 }
4170
4171 // If there is a width attr, we want to attach an event listener which
4172 // allows the table sizing to automatically adjust when the window is
4173 // resized. Use the width attr rather than CSS, since we can't know if the
4174 // CSS is a relative value or absolute - DOM read is always px.
4175 if ( tableWidthAttr ) {
4176 table.style.width = _fnStringToCss( tableWidthAttr );
4177 }
4178
4179 if ( (tableWidthAttr || scrollX) && ! oSettings._reszEvt ) {
4180 $(window).bind('resize.DT-'+oSettings.sInstance, _fnThrottle( function () {
4181 _fnAdjustColumnSizing( oSettings );
4182 } ) );
4183
4184 oSettings._reszEvt = true;
4185 }
4186 }
4187
4188
4189 /**
4190 * Throttle the calls to a function. Arguments and context are maintained for
4191 * the throttled function
4192 * @param {function} fn Function to be called
4193 * @param {int} [freq=200] call frequency in mS
4194 * @returns {function} wrapped function
4195 * @memberof DataTable#oApi
4196 */
4197 function _fnThrottle( fn, freq ) {
4198 var
4199 frequency = freq !== undefined ? freq : 200,
4200 last,
4201 timer;
4202
4203 return function () {
4204 var
4205 that = this,
4206 now = +new Date(),
4207 args = arguments;
4208
4209 if ( last && now < last + frequency ) {
4210 clearTimeout( timer );
4211
4212 timer = setTimeout( function () {
4213 last = undefined;
4214 fn.apply( that, args );
4215 }, frequency );
4216 }
4217 else if ( last ) {
4218 last = now;
4219 fn.apply( that, args );
4220 }
4221 else {
4222 last = now;
4223 }
4224 };
4225 }
4226
4227
4228 /**
4229 * Convert a CSS unit width to pixels (e.g. 2em)
4230 * @param {string} width width to be converted
4231 * @param {node} parent parent to get the with for (required for relative widths) - optional
4232 * @returns {int} width in pixels
4233 * @memberof DataTable#oApi
4234 */
4235 function _fnConvertToWidth ( width, parent )
4236 {
4237 if ( ! width ) {
4238 return 0;
4239 }
4240
4241 var n = $('<div/>')
4242 .css( 'width', _fnStringToCss( width ) )
4243 .appendTo( parent || document.body );
4244
4245 var val = n[0].offsetWidth;
4246 n.remove();
4247
4248 return val;
4249 }
4250
4251
4252 /**
4253 * Adjust a table's width to take account of vertical scroll bar
4254 * @param {object} oSettings dataTables settings object
4255 * @param {node} n table node
4256 * @memberof DataTable#oApi
4257 */
4258
4259 function _fnScrollingWidthAdjust ( settings, n )
4260 {
4261 var scroll = settings.oScroll;
4262
4263 if ( scroll.sX || scroll.sY ) {
4264 // When y-scrolling only, we want to remove the width of the scroll bar
4265 // so the table + scroll bar will fit into the area available, otherwise
4266 // we fix the table at its current size with no adjustment
4267 var correction = ! scroll.sX ? scroll.iBarWidth : 0;
4268 n.style.width = _fnStringToCss( $(n).outerWidth() - correction );
4269 }
4270 }
4271
4272
4273 /**
4274 * Get the widest node
4275 * @param {object} settings dataTables settings object
4276 * @param {int} colIdx column of interest
4277 * @returns {node} widest table node
4278 * @memberof DataTable#oApi
4279 */
4280 function _fnGetWidestNode( settings, colIdx )
4281 {
4282 var idx = _fnGetMaxLenString( settings, colIdx );
4283 if ( idx < 0 ) {
4284 return null;
4285 }
4286
4287 var data = settings.aoData[ idx ];
4288 return ! data.nTr ? // Might not have been created when deferred rendering
4289 $('<td/>').html( _fnGetCellData( settings, idx, colIdx, 'display' ) )[0] :
4290 data.anCells[ colIdx ];
4291 }
4292
4293
4294 /**
4295 * Get the maximum strlen for each data column
4296 * @param {object} settings dataTables settings object
4297 * @param {int} colIdx column of interest
4298 * @returns {string} max string length for each column
4299 * @memberof DataTable#oApi
4300 */
4301 function _fnGetMaxLenString( settings, colIdx )
4302 {
4303 var s, max=-1, maxIdx = -1;
4304
4305 for ( var i=0, ien=settings.aoData.length ; i<ien ; i++ ) {
4306 s = _fnGetCellData( settings, i, colIdx, 'display' )+'';
4307 s = s.replace( __re_html_remove, '' );
4308
4309 if ( s.length > max ) {
4310 max = s.length;
4311 maxIdx = i;
4312 }
4313 }
4314
4315 return maxIdx;
4316 }
4317
4318
4319 /**
4320 * Append a CSS unit (only if required) to a string
4321 * @param {string} value to css-ify
4322 * @returns {string} value with css unit
4323 * @memberof DataTable#oApi
4324 */
4325 function _fnStringToCss( s )
4326 {
4327 if ( s === null ) {
4328 return '0px';
4329 }
4330
4331 if ( typeof s == 'number' ) {
4332 return s < 0 ?
4333 '0px' :
4334 s+'px';
4335 }
4336
4337 // Check it has a unit character already
4338 return s.match(/\d$/) ?
4339 s+'px' :
4340 s;
4341 }
4342
4343
4344 /**
4345 * Get the width of a scroll bar in this browser being used
4346 * @returns {int} width in pixels
4347 * @memberof DataTable#oApi
4348 */
4349 function _fnScrollBarWidth ()
4350 {
4351 // On first run a static variable is set, since this is only needed once.
4352 // Subsequent runs will just use the previously calculated value
4353 if ( ! DataTable.__scrollbarWidth ) {
4354 var inner = $('<p/>').css( {
4355 width: '100%',
4356 height: 200,
4357 padding: 0
4358 } )[0];
4359
4360 var outer = $('<div/>')
4361 .css( {
4362 position: 'absolute',
4363 top: 0,
4364 left: 0,
4365 width: 200,
4366 height: 150,
4367 padding: 0,
4368 overflow: 'hidden',
4369 visibility: 'hidden'
4370 } )
4371 .append( inner )
4372 .appendTo( 'body' );
4373
4374 var w1 = inner.offsetWidth;
4375 outer.css( 'overflow', 'scroll' );
4376 var w2 = inner.offsetWidth;
4377
4378 if ( w1 === w2 ) {
4379 w2 = outer[0].clientWidth;
4380 }
4381
4382 outer.remove();
4383
4384 DataTable.__scrollbarWidth = w1 - w2;
4385 }
4386
4387 return DataTable.__scrollbarWidth;
4388 }
4389
4390
4391
4392 function _fnSortFlatten ( settings )
4393 {
4394 var
4395 i, iLen, k, kLen,
4396 aSort = [],
4397 aiOrig = [],
4398 aoColumns = settings.aoColumns,
4399 aDataSort, iCol, sType, srcCol,
4400 fixed = settings.aaSortingFixed,
4401 fixedObj = $.isPlainObject( fixed ),
4402 nestedSort = [],
4403 add = function ( a ) {
4404 if ( a.length && ! $.isArray( a[0] ) ) {
4405 // 1D array
4406 nestedSort.push( a );
4407 }
4408 else {
4409 // 2D array
4410 nestedSort.push.apply( nestedSort, a );
4411 }
4412 };
4413
4414 // Build the sort array, with pre-fix and post-fix options if they have been
4415 // specified
4416 if ( $.isArray( fixed ) ) {
4417 add( fixed );
4418 }
4419
4420 if ( fixedObj && fixed.pre ) {
4421 add( fixed.pre );
4422 }
4423
4424 add( settings.aaSorting );
4425
4426 if (fixedObj && fixed.post ) {
4427 add( fixed.post );
4428 }
4429
4430 for ( i=0 ; i<nestedSort.length ; i++ )
4431 {
4432 srcCol = nestedSort[i][0];
4433 aDataSort = aoColumns[ srcCol ].aDataSort;
4434
4435 for ( k=0, kLen=aDataSort.length ; k<kLen ; k++ )
4436 {
4437 iCol = aDataSort[k];
4438 sType = aoColumns[ iCol ].sType || 'string';
4439
4440 if ( nestedSort[i]._idx === undefined ) {
4441 nestedSort[i]._idx = $.inArray( nestedSort[i][1], aoColumns[iCol].asSorting );
4442 }
4443
4444 aSort.push( {
4445 src: srcCol,
4446 col: iCol,
4447 dir: nestedSort[i][1],
4448 index: nestedSort[i]._idx,
4449 type: sType,
4450 formatter: DataTable.ext.type.order[ sType+"-pre" ]
4451 } );
4452 }
4453 }
4454
4455 return aSort;
4456 }
4457
4458 /**
4459 * Change the order of the table
4460 * @param {object} oSettings dataTables settings object
4461 * @memberof DataTable#oApi
4462 * @todo This really needs split up!
4463 */
4464 function _fnSort ( oSettings )
4465 {
4466 var
4467 i, ien, iLen, j, jLen, k, kLen,
4468 sDataType, nTh,
4469 aiOrig = [],
4470 oExtSort = DataTable.ext.type.order,
4471 aoData = oSettings.aoData,
4472 aoColumns = oSettings.aoColumns,
4473 aDataSort, data, iCol, sType, oSort,
4474 formatters = 0,
4475 sortCol,
4476 displayMaster = oSettings.aiDisplayMaster,
4477 aSort;
4478
4479 // Resolve any column types that are unknown due to addition or invalidation
4480 // @todo Can this be moved into a 'data-ready' handler which is called when
4481 // data is going to be used in the table?
4482 _fnColumnTypes( oSettings );
4483
4484 aSort = _fnSortFlatten( oSettings );
4485
4486 for ( i=0, ien=aSort.length ; i<ien ; i++ ) {
4487 sortCol = aSort[i];
4488
4489 // Track if we can use the fast sort algorithm
4490 if ( sortCol.formatter ) {
4491 formatters++;
4492 }
4493
4494 // Load the data needed for the sort, for each cell
4495 _fnSortData( oSettings, sortCol.col );
4496 }
4497
4498 /* No sorting required if server-side or no sorting array */
4499 if ( _fnDataSource( oSettings ) != 'ssp' && aSort.length !== 0 )
4500 {
4501 // Create a value - key array of the current row positions such that we can use their
4502 // current position during the sort, if values match, in order to perform stable sorting
4503 for ( i=0, iLen=displayMaster.length ; i<iLen ; i++ ) {
4504 aiOrig[ displayMaster[i] ] = i;
4505 }
4506
4507 /* Do the sort - here we want multi-column sorting based on a given data source (column)
4508 * and sorting function (from oSort) in a certain direction. It's reasonably complex to
4509 * follow on it's own, but this is what we want (example two column sorting):
4510 * fnLocalSorting = function(a,b){
4511 * var iTest;
4512 * iTest = oSort['string-asc']('data11', 'data12');
4513 * if (iTest !== 0)
4514 * return iTest;
4515 * iTest = oSort['numeric-desc']('data21', 'data22');
4516 * if (iTest !== 0)
4517 * return iTest;
4518 * return oSort['numeric-asc']( aiOrig[a], aiOrig[b] );
4519 * }
4520 * Basically we have a test for each sorting column, if the data in that column is equal,
4521 * test the next column. If all columns match, then we use a numeric sort on the row
4522 * positions in the original data array to provide a stable sort.
4523 *
4524 * Note - I know it seems excessive to have two sorting methods, but the first is around
4525 * 15% faster, so the second is only maintained for backwards compatibility with sorting
4526 * methods which do not have a pre-sort formatting function.
4527 */
4528 if ( formatters === aSort.length ) {
4529 // All sort types have formatting functions
4530 displayMaster.sort( function ( a, b ) {
4531 var
4532 x, y, k, test, sort,
4533 len=aSort.length,
4534 dataA = aoData[a]._aSortData,
4535 dataB = aoData[b]._aSortData;
4536
4537 for ( k=0 ; k<len ; k++ ) {
4538 sort = aSort[k];
4539
4540 x = dataA[ sort.col ];
4541 y = dataB[ sort.col ];
4542
4543 test = x<y ? -1 : x>y ? 1 : 0;
4544 if ( test !== 0 ) {
4545 return sort.dir === 'asc' ? test : -test;
4546 }
4547 }
4548
4549 x = aiOrig[a];
4550 y = aiOrig[b];
4551 return x<y ? -1 : x>y ? 1 : 0;
4552 } );
4553 }
4554 else {
4555 // Depreciated - remove in 1.11 (providing a plug-in option)
4556 // Not all sort types have formatting methods, so we have to call their sorting
4557 // methods.
4558 displayMaster.sort( function ( a, b ) {
4559 var
4560 x, y, k, l, test, sort, fn,
4561 len=aSort.length,
4562 dataA = aoData[a]._aSortData,
4563 dataB = aoData[b]._aSortData;
4564
4565 for ( k=0 ; k<len ; k++ ) {
4566 sort = aSort[k];
4567
4568 x = dataA[ sort.col ];
4569 y = dataB[ sort.col ];
4570
4571 fn = oExtSort[ sort.type+"-"+sort.dir ] || oExtSort[ "string-"+sort.dir ];
4572 test = fn( x, y );
4573 if ( test !== 0 ) {
4574 return test;
4575 }
4576 }
4577
4578 x = aiOrig[a];
4579 y = aiOrig[b];
4580 return x<y ? -1 : x>y ? 1 : 0;
4581 } );
4582 }
4583 }
4584
4585 /* Tell the draw function that we have sorted the data */
4586 oSettings.bSorted = true;
4587 }
4588
4589
4590 function _fnSortAria ( settings )
4591 {
4592 var label;
4593 var nextSort;
4594 var columns = settings.aoColumns;
4595 var aSort = _fnSortFlatten( settings );
4596 var oAria = settings.oLanguage.oAria;
4597
4598 // ARIA attributes - need to loop all columns, to update all (removing old
4599 // attributes as needed)
4600 for ( var i=0, iLen=columns.length ; i<iLen ; i++ )
4601 {
4602 var col = columns[i];
4603 var asSorting = col.asSorting;
4604 var sTitle = col.sTitle.replace( /<.*?>/g, "" );
4605 var th = col.nTh;
4606
4607 // IE7 is throwing an error when setting these properties with jQuery's
4608 // attr() and removeAttr() methods...
4609 th.removeAttribute('aria-sort');
4610
4611 /* In ARIA only the first sorting column can be marked as sorting - no multi-sort option */
4612 if ( col.bSortable ) {
4613 if ( aSort.length > 0 && aSort[0].col == i ) {
4614 th.setAttribute('aria-sort', aSort[0].dir=="asc" ? "ascending" : "descending" );
4615 nextSort = asSorting[ aSort[0].index+1 ] || asSorting[0];
4616 }
4617 else {
4618 nextSort = asSorting[0];
4619 }
4620
4621 label = sTitle + ( nextSort === "asc" ?
4622 oAria.sSortAscending :
4623 oAria.sSortDescending
4624 );
4625 }
4626 else {
4627 label = sTitle;
4628 }
4629
4630 th.setAttribute('aria-label', label);
4631 }
4632 }
4633
4634
4635 /**
4636 * Function to run on user sort request
4637 * @param {object} settings dataTables settings object
4638 * @param {node} attachTo node to attach the handler to
4639 * @param {int} colIdx column sorting index
4640 * @param {boolean} [append=false] Append the requested sort to the existing
4641 * sort if true (i.e. multi-column sort)
4642 * @param {function} [callback] callback function
4643 * @memberof DataTable#oApi
4644 */
4645 function _fnSortListener ( settings, colIdx, append, callback )
4646 {
4647 var col = settings.aoColumns[ colIdx ];
4648 var sorting = settings.aaSorting;
4649 var asSorting = col.asSorting;
4650 var nextSortIdx;
4651 var next = function ( a, overflow ) {
4652 var idx = a._idx;
4653 if ( idx === undefined ) {
4654 idx = $.inArray( a[1], asSorting );
4655 }
4656
4657 return idx+1 < asSorting.length ?
4658 idx+1 :
4659 overflow ?
4660 null :
4661 0;
4662 };
4663
4664 // Convert to 2D array if needed
4665 if ( typeof sorting[0] === 'number' ) {
4666 sorting = settings.aaSorting = [ sorting ];
4667 }
4668
4669 // If appending the sort then we are multi-column sorting
4670 if ( append && settings.oFeatures.bSortMulti ) {
4671 // Are we already doing some kind of sort on this column?
4672 var sortIdx = $.inArray( colIdx, _pluck(sorting, '0') );
4673
4674 if ( sortIdx !== -1 ) {
4675 // Yes, modify the sort
4676 nextSortIdx = next( sorting[sortIdx], true );
4677
4678 if ( nextSortIdx === null ) {
4679 sorting.splice( sortIdx, 1 );
4680 }
4681 else {
4682 sorting[sortIdx][1] = asSorting[ nextSortIdx ];
4683 sorting[sortIdx]._idx = nextSortIdx;
4684 }
4685 }
4686 else {
4687 // No sort on this column yet
4688 sorting.push( [ colIdx, asSorting[0], 0 ] );
4689 sorting[sorting.length-1]._idx = 0;
4690 }
4691 }
4692 else if ( sorting.length && sorting[0][0] == colIdx ) {
4693 // Single column - already sorting on this column, modify the sort
4694 nextSortIdx = next( sorting[0] );
4695
4696 sorting.length = 1;
4697 sorting[0][1] = asSorting[ nextSortIdx ];
4698 sorting[0]._idx = nextSortIdx;
4699 }
4700 else {
4701 // Single column - sort only on this column
4702 sorting.length = 0;
4703 sorting.push( [ colIdx, asSorting[0] ] );
4704 sorting[0]._idx = 0;
4705 }
4706
4707 // Run the sort by calling a full redraw
4708 _fnReDraw( settings );
4709
4710 // callback used for async user interaction
4711 if ( typeof callback == 'function' ) {
4712 callback( settings );
4713 }
4714 }
4715
4716
4717 /**
4718 * Attach a sort handler (click) to a node
4719 * @param {object} settings dataTables settings object
4720 * @param {node} attachTo node to attach the handler to
4721 * @param {int} colIdx column sorting index
4722 * @param {function} [callback] callback function
4723 * @memberof DataTable#oApi
4724 */
4725 function _fnSortAttachListener ( settings, attachTo, colIdx, callback )
4726 {
4727 var col = settings.aoColumns[ colIdx ];
4728
4729 _fnBindAction( attachTo, {}, function (e) {
4730 /* If the column is not sortable - don't to anything */
4731 if ( col.bSortable === false ) {
4732 return;
4733 }
4734
4735 // If processing is enabled use a timeout to allow the processing
4736 // display to be shown - otherwise to it synchronously
4737 if ( settings.oFeatures.bProcessing ) {
4738 _fnProcessingDisplay( settings, true );
4739
4740 setTimeout( function() {
4741 _fnSortListener( settings, colIdx, e.shiftKey, callback );
4742
4743 // In server-side processing, the draw callback will remove the
4744 // processing display
4745 if ( _fnDataSource( settings ) !== 'ssp' ) {
4746 _fnProcessingDisplay( settings, false );
4747 }
4748 }, 0 );
4749 }
4750 else {
4751 _fnSortListener( settings, colIdx, e.shiftKey, callback );
4752 }
4753 } );
4754 }
4755
4756
4757 /**
4758 * Set the sorting classes on table's body, Note: it is safe to call this function
4759 * when bSort and bSortClasses are false
4760 * @param {object} oSettings dataTables settings object
4761 * @memberof DataTable#oApi
4762 */
4763 function _fnSortingClasses( settings )
4764 {
4765 var oldSort = settings.aLastSort;
4766 var sortClass = settings.oClasses.sSortColumn;
4767 var sort = _fnSortFlatten( settings );
4768 var features = settings.oFeatures;
4769 var i, ien, colIdx;
4770
4771 if ( features.bSort && features.bSortClasses ) {
4772 // Remove old sorting classes
4773 for ( i=0, ien=oldSort.length ; i<ien ; i++ ) {
4774 colIdx = oldSort[i].src;
4775
4776 // Remove column sorting
4777 $( _pluck( settings.aoData, 'anCells', colIdx ) )
4778 .removeClass( sortClass + (i<2 ? i+1 : 3) );
4779 }
4780
4781 // Add new column sorting
4782 for ( i=0, ien=sort.length ; i<ien ; i++ ) {
4783 colIdx = sort[i].src;
4784
4785 $( _pluck( settings.aoData, 'anCells', colIdx ) )
4786 .addClass( sortClass + (i<2 ? i+1 : 3) );
4787 }
4788 }
4789
4790 settings.aLastSort = sort;
4791 }
4792
4793
4794 // Get the data to sort a column, be it from cache, fresh (populating the
4795 // cache), or from a sort formatter
4796 function _fnSortData( settings, idx )
4797 {
4798 // Custom sorting function - provided by the sort data type
4799 var column = settings.aoColumns[ idx ];
4800 var customSort = DataTable.ext.order[ column.sSortDataType ];
4801 var customData;
4802
4803 if ( customSort ) {
4804 customData = customSort.call( settings.oInstance, settings, idx,
4805 _fnColumnIndexToVisible( settings, idx )
4806 );
4807 }
4808
4809 // Use / populate cache
4810 var row, cellData;
4811 var formatter = DataTable.ext.type.order[ column.sType+"-pre" ];
4812
4813 for ( var i=0, ien=settings.aoData.length ; i<ien ; i++ ) {
4814 row = settings.aoData[i];
4815
4816 if ( ! row._aSortData ) {
4817 row._aSortData = [];
4818 }
4819
4820 if ( ! row._aSortData[idx] || customSort ) {
4821 cellData = customSort ?
4822 customData[i] : // If there was a custom sort function, use data from there
4823 _fnGetCellData( settings, i, idx, 'sort' );
4824
4825 row._aSortData[ idx ] = formatter ?
4826 formatter( cellData ) :
4827 cellData;
4828 }
4829 }
4830 }
4831
4832
4833
4834 /**
4835 * Save the state of a table
4836 * @param {object} oSettings dataTables settings object
4837 * @memberof DataTable#oApi
4838 */
4839 function _fnSaveState ( settings )
4840 {
4841 if ( !settings.oFeatures.bStateSave || settings.bDestroying )
4842 {
4843 return;
4844 }
4845
4846 /* Store the interesting variables */
4847 var state = {
4848 time: +new Date(),
4849 start: settings._iDisplayStart,
4850 length: settings._iDisplayLength,
4851 order: $.extend( true, [], settings.aaSorting ),
4852 search: _fnSearchToCamel( settings.oPreviousSearch ),
4853 columns: $.map( settings.aoColumns, function ( col, i ) {
4854 return {
4855 visible: col.bVisible,
4856 search: _fnSearchToCamel( settings.aoPreSearchCols[i] )
4857 };
4858 } )
4859 };
4860
4861 _fnCallbackFire( settings, "aoStateSaveParams", 'stateSaveParams', [settings, state] );
4862
4863 settings.oSavedState = state;
4864 settings.fnStateSaveCallback.call( settings.oInstance, settings, state );
4865 }
4866
4867
4868 /**
4869 * Attempt to load a saved table state
4870 * @param {object} oSettings dataTables settings object
4871 * @param {object} oInit DataTables init object so we can override settings
4872 * @memberof DataTable#oApi
4873 */
4874 function _fnLoadState ( settings, oInit )
4875 {
4876 var i, ien;
4877 var columns = settings.aoColumns;
4878
4879 if ( ! settings.oFeatures.bStateSave ) {
4880 return;
4881 }
4882
4883 var state = settings.fnStateLoadCallback.call( settings.oInstance, settings );
4884 if ( ! state || ! state.time ) {
4885 return;
4886 }
4887
4888 /* Allow custom and plug-in manipulation functions to alter the saved data set and
4889 * cancelling of loading by returning false
4890 */
4891 var abStateLoad = _fnCallbackFire( settings, 'aoStateLoadParams', 'stateLoadParams', [settings, state] );
4892 if ( $.inArray( false, abStateLoad ) !== -1 ) {
4893 return;
4894 }
4895
4896 /* Reject old data */
4897 var duration = settings.iStateDuration;
4898 if ( duration > 0 && state.time < +new Date() - (duration*1000) ) {
4899 return;
4900 }
4901
4902 // Number of columns have changed - all bets are off, no restore of settings
4903 if ( columns.length !== state.columns.length ) {
4904 return;
4905 }
4906
4907 // Store the saved state so it might be accessed at any time
4908 settings.oLoadedState = $.extend( true, {}, state );
4909
4910 // Restore key features - todo - for 1.11 this needs to be done by
4911 // subscribed events
4912 settings._iDisplayStart = state.start;
4913 settings.iInitDisplayStart = state.start;
4914 settings._iDisplayLength = state.length;
4915 settings.aaSorting = [];
4916
4917 // Order
4918 $.each( state.order, function ( i, col ) {
4919 settings.aaSorting.push( col[0] >= columns.length ?
4920 [ 0, col[1] ] :
4921 col
4922 );
4923 } );
4924
4925 // Search
4926 $.extend( settings.oPreviousSearch, _fnSearchToHung( state.search ) );
4927
4928 // Columns
4929 for ( i=0, ien=state.columns.length ; i<ien ; i++ ) {
4930 var col = state.columns[i];
4931
4932 // Visibility
4933 columns[i].bVisible = col.visible;
4934
4935 // Search
4936 $.extend( settings.aoPreSearchCols[i], _fnSearchToHung( col.search ) );
4937 }
4938
4939 _fnCallbackFire( settings, 'aoStateLoaded', 'stateLoaded', [settings, state] );
4940 }
4941
4942
4943 /**
4944 * Return the settings object for a particular table
4945 * @param {node} table table we are using as a dataTable
4946 * @returns {object} Settings object - or null if not found
4947 * @memberof DataTable#oApi
4948 */
4949 function _fnSettingsFromNode ( table )
4950 {
4951 var settings = DataTable.settings;
4952 var idx = $.inArray( table, _pluck( settings, 'nTable' ) );
4953
4954 return idx !== -1 ?
4955 settings[ idx ] :
4956 null;
4957 }
4958
4959
4960 /**
4961 * Log an error message
4962 * @param {object} settings dataTables settings object
4963 * @param {int} level log error messages, or display them to the user
4964 * @param {string} msg error message
4965 * @param {int} tn Technical note id to get more information about the error.
4966 * @memberof DataTable#oApi
4967 */
4968 function _fnLog( settings, level, msg, tn )
4969 {
4970 msg = 'DataTables warning: '+
4971 (settings!==null ? 'table id='+settings.sTableId+' - ' : '')+msg;
4972
4973 if ( tn ) {
4974 msg += '. For more information about this error, please see '+
4975 'http://datatables.net/tn/'+tn;
4976 }
4977
4978 if ( ! level ) {
4979 // Backwards compatibility pre 1.10
4980 var ext = DataTable.ext;
4981 var type = ext.sErrMode || ext.errMode;
4982
4983 if ( type == 'alert' ) {
4984 alert( msg );
4985 }
4986 else {
4987 throw new Error(msg);
4988 }
4989 }
4990 else if ( window.console && console.log ) {
4991 console.log( msg );
4992 }
4993 }
4994
4995
4996 /**
4997 * See if a property is defined on one object, if so assign it to the other object
4998 * @param {object} ret target object
4999 * @param {object} src source object
5000 * @param {string} name property
5001 * @param {string} [mappedName] name to map too - optional, name used if not given
5002 * @memberof DataTable#oApi
5003 */
5004 function _fnMap( ret, src, name, mappedName )
5005 {
5006 if ( $.isArray( name ) ) {
5007 $.each( name, function (i, val) {
5008 if ( $.isArray( val ) ) {
5009 _fnMap( ret, src, val[0], val[1] );
5010 }
5011 else {
5012 _fnMap( ret, src, val );
5013 }
5014 } );
5015
5016 return;
5017 }
5018
5019 if ( mappedName === undefined ) {
5020 mappedName = name;
5021 }
5022
5023 if ( src[name] !== undefined ) {
5024 ret[mappedName] = src[name];
5025 }
5026 }
5027
5028
5029 /**
5030 * Extend objects - very similar to jQuery.extend, but deep copy objects, and
5031 * shallow copy arrays. The reason we need to do this, is that we don't want to
5032 * deep copy array init values (such as aaSorting) since the dev wouldn't be
5033 * able to override them, but we do want to deep copy arrays.
5034 * @param {object} out Object to extend
5035 * @param {object} extender Object from which the properties will be applied to
5036 * out
5037 * @param {boolean} breakRefs If true, then arrays will be sliced to take an
5038 * independent copy with the exception of the `data` or `aaData` parameters
5039 * if they are present. This is so you can pass in a collection to
5040 * DataTables and have that used as your data source without breaking the
5041 * references
5042 * @returns {object} out Reference, just for convenience - out === the return.
5043 * @memberof DataTable#oApi
5044 * @todo This doesn't take account of arrays inside the deep copied objects.
5045 */
5046 function _fnExtend( out, extender, breakRefs )
5047 {
5048 var val;
5049
5050 for ( var prop in extender ) {
5051 if ( extender.hasOwnProperty(prop) ) {
5052 val = extender[prop];
5053
5054 if ( $.isPlainObject( val ) ) {
5055 if ( ! $.isPlainObject( out[prop] ) ) {
5056 out[prop] = {};
5057 }
5058 $.extend( true, out[prop], val );
5059 }
5060 else if ( breakRefs && prop !== 'data' && prop !== 'aaData' && $.isArray(val) ) {
5061 out[prop] = val.slice();
5062 }
5063 else {
5064 out[prop] = val;
5065 }
5066 }
5067 }
5068
5069 return out;
5070 }
5071
5072
5073 /**
5074 * Bind an event handers to allow a click or return key to activate the callback.
5075 * This is good for accessibility since a return on the keyboard will have the
5076 * same effect as a click, if the element has focus.
5077 * @param {element} n Element to bind the action to
5078 * @param {object} oData Data object to pass to the triggered function
5079 * @param {function} fn Callback function for when the event is triggered
5080 * @memberof DataTable#oApi
5081 */
5082 function _fnBindAction( n, oData, fn )
5083 {
5084 $(n)
5085 .bind( 'click.DT', oData, function (e) {
5086 n.blur(); // Remove focus outline for mouse users
5087 fn(e);
5088 } )
5089 .bind( 'keypress.DT', oData, function (e){
5090 if ( e.which === 13 ) {
5091 e.preventDefault();
5092 fn(e);
5093 }
5094 } )
5095 .bind( 'selectstart.DT', function () {
5096 /* Take the brutal approach to cancelling text selection */
5097 return false;
5098 } );
5099 }
5100
5101
5102 /**
5103 * Register a callback function. Easily allows a callback function to be added to
5104 * an array store of callback functions that can then all be called together.
5105 * @param {object} oSettings dataTables settings object
5106 * @param {string} sStore Name of the array storage for the callbacks in oSettings
5107 * @param {function} fn Function to be called back
5108 * @param {string} sName Identifying name for the callback (i.e. a label)
5109 * @memberof DataTable#oApi
5110 */
5111 function _fnCallbackReg( oSettings, sStore, fn, sName )
5112 {
5113 if ( fn )
5114 {
5115 oSettings[sStore].push( {
5116 "fn": fn,
5117 "sName": sName
5118 } );
5119 }
5120 }
5121
5122
5123 /**
5124 * Fire callback functions and trigger events. Note that the loop over the
5125 * callback array store is done backwards! Further note that you do not want to
5126 * fire off triggers in time sensitive applications (for example cell creation)
5127 * as its slow.
5128 * @param {object} settings dataTables settings object
5129 * @param {string} callbackArr Name of the array storage for the callbacks in
5130 * oSettings
5131 * @param {string} event Name of the jQuery custom event to trigger. If null no
5132 * trigger is fired
5133 * @param {array} args Array of arguments to pass to the callback function /
5134 * trigger
5135 * @memberof DataTable#oApi
5136 */
5137 function _fnCallbackFire( settings, callbackArr, e, args )
5138 {
5139 var ret = [];
5140
5141 if ( callbackArr ) {
5142 ret = $.map( settings[callbackArr].slice().reverse(), function (val, i) {
5143 return val.fn.apply( settings.oInstance, args );
5144 } );
5145 }
5146
5147 if ( e !== null ) {
5148 $(settings.nTable).trigger( e+'.dt', args );
5149 }
5150
5151 return ret;
5152 }
5153
5154
5155 function _fnLengthOverflow ( settings )
5156 {
5157 var
5158 start = settings._iDisplayStart,
5159 end = settings.fnDisplayEnd(),
5160 len = settings._iDisplayLength;
5161
5162 /* If we have space to show extra rows (backing up from the end point - then do so */
5163 if (start >= end)
5164 {
5165 start = end - len;
5166 }
5167
5168 if ( len === -1 || start < 0 )
5169 {
5170 start = 0;
5171 }
5172
5173 settings._iDisplayStart = start;
5174 }
5175
5176
5177 function _fnRenderer( settings, type )
5178 {
5179 var renderer = settings.renderer;
5180 var host = DataTable.ext.renderer[type];
5181
5182 if ( $.isPlainObject( renderer ) && renderer[type] ) {
5183 // Specific renderer for this type. If available use it, otherwise use
5184 // the default.
5185 return host[renderer[type]] || host._;
5186 }
5187 else if ( typeof renderer === 'string' ) {
5188 // Common renderer - if there is one available for this type use it,
5189 // otherwise use the default
5190 return host[renderer] || host._;
5191 }
5192
5193 // Use the default
5194 return host._;
5195 }
5196
5197
5198 /**
5199 * Detect the data source being used for the table. Used to simplify the code
5200 * a little (ajax) and to make it compress a little smaller.
5201 *
5202 * @param {object} settings dataTables settings object
5203 * @returns {string} Data source
5204 * @memberof DataTable#oApi
5205 */
5206 function _fnDataSource ( settings )
5207 {
5208 if ( settings.oFeatures.bServerSide ) {
5209 return 'ssp';
5210 }
5211 else if ( settings.ajax || settings.sAjaxSource ) {
5212 return 'ajax';
5213 }
5214 return 'dom';
5215 }
5216
5217
5218 DataTable = function( options )
5219 {
5220 /**
5221 * Perform a jQuery selector action on the table's TR elements (from the tbody) and
5222 * return the resulting jQuery object.
5223 * @param {string|node|jQuery} sSelector jQuery selector or node collection to act on
5224 * @param {object} [oOpts] Optional parameters for modifying the rows to be included
5225 * @param {string} [oOpts.filter=none] Select TR elements that meet the current filter
5226 * criterion ("applied") or all TR elements (i.e. no filter).
5227 * @param {string} [oOpts.order=current] Order of the TR elements in the processed array.
5228 * Can be either 'current', whereby the current sorting of the table is used, or
5229 * 'original' whereby the original order the data was read into the table is used.
5230 * @param {string} [oOpts.page=all] Limit the selection to the currently displayed page
5231 * ("current") or not ("all"). If 'current' is given, then order is assumed to be
5232 * 'current' and filter is 'applied', regardless of what they might be given as.
5233 * @returns {object} jQuery object, filtered by the given selector.
5234 * @dtopt API
5235 * @deprecated Since v1.10
5236 *
5237 * @example
5238 * $(document).ready(function() {
5239 * var oTable = $('#example').dataTable();
5240 *
5241 * // Highlight every second row
5242 * oTable.$('tr:odd').css('backgroundColor', 'blue');
5243 * } );
5244 *
5245 * @example
5246 * $(document).ready(function() {
5247 * var oTable = $('#example').dataTable();
5248 *
5249 * // Filter to rows with 'Webkit' in them, add a background colour and then
5250 * // remove the filter, thus highlighting the 'Webkit' rows only.
5251 * oTable.fnFilter('Webkit');
5252 * oTable.$('tr', {"search": "applied"}).css('backgroundColor', 'blue');
5253 * oTable.fnFilter('');
5254 * } );
5255 */
5256 this.$ = function ( sSelector, oOpts )
5257 {
5258 return this.api(true).$( sSelector, oOpts );
5259 };
5260
5261
5262 /**
5263 * Almost identical to $ in operation, but in this case returns the data for the matched
5264 * rows - as such, the jQuery selector used should match TR row nodes or TD/TH cell nodes
5265 * rather than any descendants, so the data can be obtained for the row/cell. If matching
5266 * rows are found, the data returned is the original data array/object that was used to
5267 * create the row (or a generated array if from a DOM source).
5268 *
5269 * This method is often useful in-combination with $ where both functions are given the
5270 * same parameters and the array indexes will match identically.
5271 * @param {string|node|jQuery} sSelector jQuery selector or node collection to act on
5272 * @param {object} [oOpts] Optional parameters for modifying the rows to be included
5273 * @param {string} [oOpts.filter=none] Select elements that meet the current filter
5274 * criterion ("applied") or all elements (i.e. no filter).
5275 * @param {string} [oOpts.order=current] Order of the data in the processed array.
5276 * Can be either 'current', whereby the current sorting of the table is used, or
5277 * 'original' whereby the original order the data was read into the table is used.
5278 * @param {string} [oOpts.page=all] Limit the selection to the currently displayed page
5279 * ("current") or not ("all"). If 'current' is given, then order is assumed to be
5280 * 'current' and filter is 'applied', regardless of what they might be given as.
5281 * @returns {array} Data for the matched elements. If any elements, as a result of the
5282 * selector, were not TR, TD or TH elements in the DataTable, they will have a null
5283 * entry in the array.
5284 * @dtopt API
5285 * @deprecated Since v1.10
5286 *
5287 * @example
5288 * $(document).ready(function() {
5289 * var oTable = $('#example').dataTable();
5290 *
5291 * // Get the data from the first row in the table
5292 * var data = oTable._('tr:first');
5293 *
5294 * // Do something useful with the data
5295 * alert( "First cell is: "+data[0] );
5296 * } );
5297 *
5298 * @example
5299 * $(document).ready(function() {
5300 * var oTable = $('#example').dataTable();
5301 *
5302 * // Filter to 'Webkit' and get all data for
5303 * oTable.fnFilter('Webkit');
5304 * var data = oTable._('tr', {"search": "applied"});
5305 *
5306 * // Do something with the data
5307 * alert( data.length+" rows matched the search" );
5308 * } );
5309 */
5310 this._ = function ( sSelector, oOpts )
5311 {
5312 return this.api(true).rows( sSelector, oOpts ).data();
5313 };
5314
5315
5316 /**
5317 * Create a DataTables Api instance, with the currently selected tables for
5318 * the Api's context.
5319 * @param {boolean} [traditional=false] Set the API instance's context to be
5320 * only the table referred to by the `DataTable.ext.iApiIndex` option, as was
5321 * used in the API presented by DataTables 1.9- (i.e. the traditional mode),
5322 * or if all tables captured in the jQuery object should be used.
5323 * @return {DataTables.Api}
5324 */
5325 this.api = function ( traditional )
5326 {
5327 return traditional ?
5328 new _Api(
5329 _fnSettingsFromNode( this[ _ext.iApiIndex ] )
5330 ) :
5331 new _Api( this );
5332 };
5333
5334
5335 /**
5336 * Add a single new row or multiple rows of data to the table. Please note
5337 * that this is suitable for client-side processing only - if you are using
5338 * server-side processing (i.e. "bServerSide": true), then to add data, you
5339 * must add it to the data source, i.e. the server-side, through an Ajax call.
5340 * @param {array|object} data The data to be added to the table. This can be:
5341 * <ul>
5342 * <li>1D array of data - add a single row with the data provided</li>
5343 * <li>2D array of arrays - add multiple rows in a single call</li>
5344 * <li>object - data object when using <i>mData</i></li>
5345 * <li>array of objects - multiple data objects when using <i>mData</i></li>
5346 * </ul>
5347 * @param {bool} [redraw=true] redraw the table or not
5348 * @returns {array} An array of integers, representing the list of indexes in
5349 * <i>aoData</i> ({@link DataTable.models.oSettings}) that have been added to
5350 * the table.
5351 * @dtopt API
5352 * @deprecated Since v1.10
5353 *
5354 * @example
5355 * // Global var for counter
5356 * var giCount = 2;
5357 *
5358 * $(document).ready(function() {
5359 * $('#example').dataTable();
5360 * } );
5361 *
5362 * function fnClickAddRow() {
5363 * $('#example').dataTable().fnAddData( [
5364 * giCount+".1",
5365 * giCount+".2",
5366 * giCount+".3",
5367 * giCount+".4" ]
5368 * );
5369 *
5370 * giCount++;
5371 * }
5372 */
5373 this.fnAddData = function( data, redraw )
5374 {
5375 var api = this.api( true );
5376
5377 /* Check if we want to add multiple rows or not */
5378 var rows = $.isArray(data) && ( $.isArray(data[0]) || $.isPlainObject(data[0]) ) ?
5379 api.rows.add( data ) :
5380 api.row.add( data );
5381
5382 if ( redraw === undefined || redraw ) {
5383 api.draw();
5384 }
5385
5386 return rows.flatten().toArray();
5387 };
5388
5389
5390 /**
5391 * This function will make DataTables recalculate the column sizes, based on the data
5392 * contained in the table and the sizes applied to the columns (in the DOM, CSS or
5393 * through the sWidth parameter). This can be useful when the width of the table's
5394 * parent element changes (for example a window resize).
5395 * @param {boolean} [bRedraw=true] Redraw the table or not, you will typically want to
5396 * @dtopt API
5397 * @deprecated Since v1.10
5398 *
5399 * @example
5400 * $(document).ready(function() {
5401 * var oTable = $('#example').dataTable( {
5402 * "sScrollY": "200px",
5403 * "bPaginate": false
5404 * } );
5405 *
5406 * $(window).bind('resize', function () {
5407 * oTable.fnAdjustColumnSizing();
5408 * } );
5409 * } );
5410 */
5411 this.fnAdjustColumnSizing = function ( bRedraw )
5412 {
5413 var api = this.api( true ).columns.adjust();
5414 var settings = api.settings()[0];
5415 var scroll = settings.oScroll;
5416
5417 if ( bRedraw === undefined || bRedraw ) {
5418 api.draw( false );
5419 }
5420 else if ( scroll.sX !== "" || scroll.sY !== "" ) {
5421 /* If not redrawing, but scrolling, we want to apply the new column sizes anyway */
5422 _fnScrollDraw( settings );
5423 }
5424 };
5425
5426
5427 /**
5428 * Quickly and simply clear a table
5429 * @param {bool} [bRedraw=true] redraw the table or not
5430 * @dtopt API
5431 * @deprecated Since v1.10
5432 *
5433 * @example
5434 * $(document).ready(function() {
5435 * var oTable = $('#example').dataTable();
5436 *
5437 * // Immediately 'nuke' the current rows (perhaps waiting for an Ajax callback...)
5438 * oTable.fnClearTable();
5439 * } );
5440 */
5441 this.fnClearTable = function( bRedraw )
5442 {
5443 var api = this.api( true ).clear();
5444
5445 if ( bRedraw === undefined || bRedraw ) {
5446 api.draw();
5447 }
5448 };
5449
5450
5451 /**
5452 * The exact opposite of 'opening' a row, this function will close any rows which
5453 * are currently 'open'.
5454 * @param {node} nTr the table row to 'close'
5455 * @returns {int} 0 on success, or 1 if failed (can't find the row)
5456 * @dtopt API
5457 * @deprecated Since v1.10
5458 *
5459 * @example
5460 * $(document).ready(function() {
5461 * var oTable;
5462 *
5463 * // 'open' an information row when a row is clicked on
5464 * $('#example tbody tr').click( function () {
5465 * if ( oTable.fnIsOpen(this) ) {
5466 * oTable.fnClose( this );
5467 * } else {
5468 * oTable.fnOpen( this, "Temporary row opened", "info_row" );
5469 * }
5470 * } );
5471 *
5472 * oTable = $('#example').dataTable();
5473 * } );
5474 */
5475 this.fnClose = function( nTr )
5476 {
5477 this.api( true ).row( nTr ).child.hide();
5478 };
5479
5480
5481 /**
5482 * Remove a row for the table
5483 * @param {mixed} target The index of the row from aoData to be deleted, or
5484 * the TR element you want to delete
5485 * @param {function|null} [callBack] Callback function
5486 * @param {bool} [redraw=true] Redraw the table or not
5487 * @returns {array} The row that was deleted
5488 * @dtopt API
5489 * @deprecated Since v1.10
5490 *
5491 * @example
5492 * $(document).ready(function() {
5493 * var oTable = $('#example').dataTable();
5494 *
5495 * // Immediately remove the first row
5496 * oTable.fnDeleteRow( 0 );
5497 * } );
5498 */
5499 this.fnDeleteRow = function( target, callback, redraw )
5500 {
5501 var api = this.api( true );
5502 var rows = api.rows( target );
5503 var settings = rows.settings()[0];
5504 var data = settings.aoData[ rows[0][0] ];
5505
5506 rows.remove();
5507
5508 if ( callback ) {
5509 callback.call( this, settings, data );
5510 }
5511
5512 if ( redraw === undefined || redraw ) {
5513 api.draw();
5514 }
5515
5516 return data;
5517 };
5518
5519
5520 /**
5521 * Restore the table to it's original state in the DOM by removing all of DataTables
5522 * enhancements, alterations to the DOM structure of the table and event listeners.
5523 * @param {boolean} [remove=false] Completely remove the table from the DOM
5524 * @dtopt API
5525 * @deprecated Since v1.10
5526 *
5527 * @example
5528 * $(document).ready(function() {
5529 * // This example is fairly pointless in reality, but shows how fnDestroy can be used
5530 * var oTable = $('#example').dataTable();
5531 * oTable.fnDestroy();
5532 * } );
5533 */
5534 this.fnDestroy = function ( remove )
5535 {
5536 this.api( true ).destroy( remove );
5537 };
5538
5539
5540 /**
5541 * Redraw the table
5542 * @param {bool} [complete=true] Re-filter and resort (if enabled) the table before the draw.
5543 * @dtopt API
5544 * @deprecated Since v1.10
5545 *
5546 * @example
5547 * $(document).ready(function() {
5548 * var oTable = $('#example').dataTable();
5549 *
5550 * // Re-draw the table - you wouldn't want to do it here, but it's an example :-)
5551 * oTable.fnDraw();
5552 * } );
5553 */
5554 this.fnDraw = function( complete )
5555 {
5556 // Note that this isn't an exact match to the old call to _fnDraw - it takes
5557 // into account the new data, but can old position.
5558 this.api( true ).draw( ! complete );
5559 };
5560
5561
5562 /**
5563 * Filter the input based on data
5564 * @param {string} sInput String to filter the table on
5565 * @param {int|null} [iColumn] Column to limit filtering to
5566 * @param {bool} [bRegex=false] Treat as regular expression or not
5567 * @param {bool} [bSmart=true] Perform smart filtering or not
5568 * @param {bool} [bShowGlobal=true] Show the input global filter in it's input box(es)
5569 * @param {bool} [bCaseInsensitive=true] Do case-insensitive matching (true) or not (false)
5570 * @dtopt API
5571 * @deprecated Since v1.10
5572 *
5573 * @example
5574 * $(document).ready(function() {
5575 * var oTable = $('#example').dataTable();
5576 *
5577 * // Sometime later - filter...
5578 * oTable.fnFilter( 'test string' );
5579 * } );
5580 */
5581 this.fnFilter = function( sInput, iColumn, bRegex, bSmart, bShowGlobal, bCaseInsensitive )
5582 {
5583 var api = this.api( true );
5584
5585 if ( iColumn === null || iColumn === undefined ) {
5586 api.search( sInput, bRegex, bSmart, bCaseInsensitive );
5587 }
5588 else {
5589 api.column( iColumn ).search( sInput, bRegex, bSmart, bCaseInsensitive );
5590 }
5591
5592 api.draw();
5593 };
5594
5595
5596 /**
5597 * Get the data for the whole table, an individual row or an individual cell based on the
5598 * provided parameters.
5599 * @param {int|node} [src] A TR row node, TD/TH cell node or an integer. If given as
5600 * a TR node then the data source for the whole row will be returned. If given as a
5601 * TD/TH cell node then iCol will be automatically calculated and the data for the
5602 * cell returned. If given as an integer, then this is treated as the aoData internal
5603 * data index for the row (see fnGetPosition) and the data for that row used.
5604 * @param {int} [col] Optional column index that you want the data of.
5605 * @returns {array|object|string} If mRow is undefined, then the data for all rows is
5606 * returned. If mRow is defined, just data for that row, and is iCol is
5607 * defined, only data for the designated cell is returned.
5608 * @dtopt API
5609 * @deprecated Since v1.10
5610 *
5611 * @example
5612 * // Row data
5613 * $(document).ready(function() {
5614 * oTable = $('#example').dataTable();
5615 *
5616 * oTable.$('tr').click( function () {
5617 * var data = oTable.fnGetData( this );
5618 * // ... do something with the array / object of data for the row
5619 * } );
5620 * } );
5621 *
5622 * @example
5623 * // Individual cell data
5624 * $(document).ready(function() {
5625 * oTable = $('#example').dataTable();
5626 *
5627 * oTable.$('td').click( function () {
5628 * var sData = oTable.fnGetData( this );
5629 * alert( 'The cell clicked on had the value of '+sData );
5630 * } );
5631 * } );
5632 */
5633 this.fnGetData = function( src, col )
5634 {
5635 var api = this.api( true );
5636
5637 if ( src !== undefined ) {
5638 var type = src.nodeName ? src.nodeName.toLowerCase() : '';
5639
5640 return col !== undefined || type == 'td' || type == 'th' ?
5641 api.cell( src, col ).data() :
5642 api.row( src ).data() || null;
5643 }
5644
5645 return api.data().toArray();
5646 };
5647
5648
5649 /**
5650 * Get an array of the TR nodes that are used in the table's body. Note that you will
5651 * typically want to use the '$' API method in preference to this as it is more
5652 * flexible.
5653 * @param {int} [iRow] Optional row index for the TR element you want
5654 * @returns {array|node} If iRow is undefined, returns an array of all TR elements
5655 * in the table's body, or iRow is defined, just the TR element requested.
5656 * @dtopt API
5657 * @deprecated Since v1.10
5658 *
5659 * @example
5660 * $(document).ready(function() {
5661 * var oTable = $('#example').dataTable();
5662 *
5663 * // Get the nodes from the table
5664 * var nNodes = oTable.fnGetNodes( );
5665 * } );
5666 */
5667 this.fnGetNodes = function( iRow )
5668 {
5669 var api = this.api( true );
5670
5671 return iRow !== undefined ?
5672 api.row( iRow ).node() :
5673 api.rows().nodes().flatten().toArray();
5674 };
5675
5676
5677 /**
5678 * Get the array indexes of a particular cell from it's DOM element
5679 * and column index including hidden columns
5680 * @param {node} node this can either be a TR, TD or TH in the table's body
5681 * @returns {int} If nNode is given as a TR, then a single index is returned, or
5682 * if given as a cell, an array of [row index, column index (visible),
5683 * column index (all)] is given.
5684 * @dtopt API
5685 * @deprecated Since v1.10
5686 *
5687 * @example
5688 * $(document).ready(function() {
5689 * $('#example tbody td').click( function () {
5690 * // Get the position of the current data from the node
5691 * var aPos = oTable.fnGetPosition( this );
5692 *
5693 * // Get the data array for this row
5694 * var aData = oTable.fnGetData( aPos[0] );
5695 *
5696 * // Update the data array and return the value
5697 * aData[ aPos[1] ] = 'clicked';
5698 * this.innerHTML = 'clicked';
5699 * } );
5700 *
5701 * // Init DataTables
5702 * oTable = $('#example').dataTable();
5703 * } );
5704 */
5705 this.fnGetPosition = function( node )
5706 {
5707 var api = this.api( true );
5708 var nodeName = node.nodeName.toUpperCase();
5709
5710 if ( nodeName == 'TR' ) {
5711 return api.row( node ).index();
5712 }
5713 else if ( nodeName == 'TD' || nodeName == 'TH' ) {
5714 var cell = api.cell( node ).index();
5715
5716 return [
5717 cell.row,
5718 cell.columnVisible,
5719 cell.column
5720 ];
5721 }
5722 return null;
5723 };
5724
5725
5726 /**
5727 * Check to see if a row is 'open' or not.
5728 * @param {node} nTr the table row to check
5729 * @returns {boolean} true if the row is currently open, false otherwise
5730 * @dtopt API
5731 * @deprecated Since v1.10
5732 *
5733 * @example
5734 * $(document).ready(function() {
5735 * var oTable;
5736 *
5737 * // 'open' an information row when a row is clicked on
5738 * $('#example tbody tr').click( function () {
5739 * if ( oTable.fnIsOpen(this) ) {
5740 * oTable.fnClose( this );
5741 * } else {
5742 * oTable.fnOpen( this, "Temporary row opened", "info_row" );
5743 * }
5744 * } );
5745 *
5746 * oTable = $('#example').dataTable();
5747 * } );
5748 */
5749 this.fnIsOpen = function( nTr )
5750 {
5751 return this.api( true ).row( nTr ).child.isShown();
5752 };
5753
5754
5755 /**
5756 * This function will place a new row directly after a row which is currently
5757 * on display on the page, with the HTML contents that is passed into the
5758 * function. This can be used, for example, to ask for confirmation that a
5759 * particular record should be deleted.
5760 * @param {node} nTr The table row to 'open'
5761 * @param {string|node|jQuery} mHtml The HTML to put into the row
5762 * @param {string} sClass Class to give the new TD cell
5763 * @returns {node} The row opened. Note that if the table row passed in as the
5764 * first parameter, is not found in the table, this method will silently
5765 * return.
5766 * @dtopt API
5767 * @deprecated Since v1.10
5768 *
5769 * @example
5770 * $(document).ready(function() {
5771 * var oTable;
5772 *
5773 * // 'open' an information row when a row is clicked on
5774 * $('#example tbody tr').click( function () {
5775 * if ( oTable.fnIsOpen(this) ) {
5776 * oTable.fnClose( this );
5777 * } else {
5778 * oTable.fnOpen( this, "Temporary row opened", "info_row" );
5779 * }
5780 * } );
5781 *
5782 * oTable = $('#example').dataTable();
5783 * } );
5784 */
5785 this.fnOpen = function( nTr, mHtml, sClass )
5786 {
5787 return this.api( true )
5788 .row( nTr )
5789 .child( mHtml, sClass )
5790 .show()
5791 .child()[0];
5792 };
5793
5794
5795 /**
5796 * Change the pagination - provides the internal logic for pagination in a simple API
5797 * function. With this function you can have a DataTables table go to the next,
5798 * previous, first or last pages.
5799 * @param {string|int} mAction Paging action to take: "first", "previous", "next" or "last"
5800 * or page number to jump to (integer), note that page 0 is the first page.
5801 * @param {bool} [bRedraw=true] Redraw the table or not
5802 * @dtopt API
5803 * @deprecated Since v1.10
5804 *
5805 * @example
5806 * $(document).ready(function() {
5807 * var oTable = $('#example').dataTable();
5808 * oTable.fnPageChange( 'next' );
5809 * } );
5810 */
5811 this.fnPageChange = function ( mAction, bRedraw )
5812 {
5813 var api = this.api( true ).page( mAction );
5814
5815 if ( bRedraw === undefined || bRedraw ) {
5816 api.draw(false);
5817 }
5818 };
5819
5820
5821 /**
5822 * Show a particular column
5823 * @param {int} iCol The column whose display should be changed
5824 * @param {bool} bShow Show (true) or hide (false) the column
5825 * @param {bool} [bRedraw=true] Redraw the table or not
5826 * @dtopt API
5827 * @deprecated Since v1.10
5828 *
5829 * @example
5830 * $(document).ready(function() {
5831 * var oTable = $('#example').dataTable();
5832 *
5833 * // Hide the second column after initialisation
5834 * oTable.fnSetColumnVis( 1, false );
5835 * } );
5836 */
5837 this.fnSetColumnVis = function ( iCol, bShow, bRedraw )
5838 {
5839 var api = this.api( true ).column( iCol ).visible( bShow );
5840
5841 if ( bRedraw === undefined || bRedraw ) {
5842 api.columns.adjust().draw();
5843 }
5844 };
5845
5846
5847 /**
5848 * Get the settings for a particular table for external manipulation
5849 * @returns {object} DataTables settings object. See
5850 * {@link DataTable.models.oSettings}
5851 * @dtopt API
5852 * @deprecated Since v1.10
5853 *
5854 * @example
5855 * $(document).ready(function() {
5856 * var oTable = $('#example').dataTable();
5857 * var oSettings = oTable.fnSettings();
5858 *
5859 * // Show an example parameter from the settings
5860 * alert( oSettings._iDisplayStart );
5861 * } );
5862 */
5863 this.fnSettings = function()
5864 {
5865 return _fnSettingsFromNode( this[_ext.iApiIndex] );
5866 };
5867
5868
5869 /**
5870 * Sort the table by a particular column
5871 * @param {int} iCol the data index to sort on. Note that this will not match the
5872 * 'display index' if you have hidden data entries
5873 * @dtopt API
5874 * @deprecated Since v1.10
5875 *
5876 * @example
5877 * $(document).ready(function() {
5878 * var oTable = $('#example').dataTable();
5879 *
5880 * // Sort immediately with columns 0 and 1
5881 * oTable.fnSort( [ [0,'asc'], [1,'asc'] ] );
5882 * } );
5883 */
5884 this.fnSort = function( aaSort )
5885 {
5886 this.api( true ).order( aaSort ).draw();
5887 };
5888
5889
5890 /**
5891 * Attach a sort listener to an element for a given column
5892 * @param {node} nNode the element to attach the sort listener to
5893 * @param {int} iColumn the column that a click on this node will sort on
5894 * @param {function} [fnCallback] callback function when sort is run
5895 * @dtopt API
5896 * @deprecated Since v1.10
5897 *
5898 * @example
5899 * $(document).ready(function() {
5900 * var oTable = $('#example').dataTable();
5901 *
5902 * // Sort on column 1, when 'sorter' is clicked on
5903 * oTable.fnSortListener( document.getElementById('sorter'), 1 );
5904 * } );
5905 */
5906 this.fnSortListener = function( nNode, iColumn, fnCallback )
5907 {
5908 this.api( true ).order.listener( nNode, iColumn, fnCallback );
5909 };
5910
5911
5912 /**
5913 * Update a table cell or row - this method will accept either a single value to
5914 * update the cell with, an array of values with one element for each column or
5915 * an object in the same format as the original data source. The function is
5916 * self-referencing in order to make the multi column updates easier.
5917 * @param {object|array|string} mData Data to update the cell/row with
5918 * @param {node|int} mRow TR element you want to update or the aoData index
5919 * @param {int} [iColumn] The column to update, give as null or undefined to
5920 * update a whole row.
5921 * @param {bool} [bRedraw=true] Redraw the table or not
5922 * @param {bool} [bAction=true] Perform pre-draw actions or not
5923 * @returns {int} 0 on success, 1 on error
5924 * @dtopt API
5925 * @deprecated Since v1.10
5926 *
5927 * @example
5928 * $(document).ready(function() {
5929 * var oTable = $('#example').dataTable();
5930 * oTable.fnUpdate( 'Example update', 0, 0 ); // Single cell
5931 * oTable.fnUpdate( ['a', 'b', 'c', 'd', 'e'], $('tbody tr')[0] ); // Row
5932 * } );
5933 */
5934 this.fnUpdate = function( mData, mRow, iColumn, bRedraw, bAction )
5935 {
5936 var api = this.api( true );
5937
5938 if ( iColumn === undefined || iColumn === null ) {
5939 api.row( mRow ).data( mData );
5940 }
5941 else {
5942 api.cell( mRow, iColumn ).data( mData );
5943 }
5944
5945 if ( bAction === undefined || bAction ) {
5946 api.columns.adjust();
5947 }
5948
5949 if ( bRedraw === undefined || bRedraw ) {
5950 api.draw();
5951 }
5952 return 0;
5953 };
5954
5955
5956 /**
5957 * Provide a common method for plug-ins to check the version of DataTables being used, in order
5958 * to ensure compatibility.
5959 * @param {string} sVersion Version string to check for, in the format "X.Y.Z". Note that the
5960 * formats "X" and "X.Y" are also acceptable.
5961 * @returns {boolean} true if this version of DataTables is greater or equal to the required
5962 * version, or false if this version of DataTales is not suitable
5963 * @method
5964 * @dtopt API
5965 * @deprecated Since v1.10
5966 *
5967 * @example
5968 * $(document).ready(function() {
5969 * var oTable = $('#example').dataTable();
5970 * alert( oTable.fnVersionCheck( '1.9.0' ) );
5971 * } );
5972 */
5973 this.fnVersionCheck = _ext.fnVersionCheck;
5974
5975
5976 var _that = this;
5977 var emptyInit = options === undefined;
5978 var len = this.length;
5979
5980 if ( emptyInit ) {
5981 options = {};
5982 }
5983
5984 this.oApi = this.internal = _ext.internal;
5985
5986 // Extend with old style plug-in API methods
5987 for ( var fn in DataTable.ext.internal ) {
5988 if ( fn ) {
5989 this[fn] = _fnExternApiFunc(fn);
5990 }
5991 }
5992
5993 this.each(function() {
5994 // For each initialisation we want to give it a clean initialisation
5995 // object that can be bashed around
5996 var o = {};
5997 var oInit = len > 1 ? // optimisation for single table case
5998 _fnExtend( o, options, true ) :
5999 options;
6000
6001 /*global oInit,_that,emptyInit*/
6002 var i=0, iLen, j, jLen, k, kLen;
6003 var sId = this.getAttribute( 'id' );
6004 var bInitHandedOff = false;
6005 var defaults = DataTable.defaults;
6006
6007
6008 /* Sanity check */
6009 if ( this.nodeName.toLowerCase() != 'table' )
6010 {
6011 _fnLog( null, 0, 'Non-table node initialisation ('+this.nodeName+')', 2 );
6012 return;
6013 }
6014
6015 /* Backwards compatibility for the defaults */
6016 _fnCompatOpts( defaults );
6017 _fnCompatCols( defaults.column );
6018
6019 /* Convert the camel-case defaults to Hungarian */
6020 _fnCamelToHungarian( defaults, defaults, true );
6021 _fnCamelToHungarian( defaults.column, defaults.column, true );
6022
6023 /* Setting up the initialisation object */
6024 _fnCamelToHungarian( defaults, oInit );
6025
6026 /* Check to see if we are re-initialising a table */
6027 var allSettings = DataTable.settings;
6028 for ( i=0, iLen=allSettings.length ; i<iLen ; i++ )
6029 {
6030 /* Base check on table node */
6031 if ( allSettings[i].nTable == this )
6032 {
6033 var bRetrieve = oInit.bRetrieve !== undefined ? oInit.bRetrieve : defaults.bRetrieve;
6034 var bDestroy = oInit.bDestroy !== undefined ? oInit.bDestroy : defaults.bDestroy;
6035
6036 if ( emptyInit || bRetrieve )
6037 {
6038 return allSettings[i].oInstance;
6039 }
6040 else if ( bDestroy )
6041 {
6042 allSettings[i].oInstance.fnDestroy();
6043 break;
6044 }
6045 else
6046 {
6047 _fnLog( allSettings[i], 0, 'Cannot reinitialise DataTable', 3 );
6048 return;
6049 }
6050 }
6051
6052 /* If the element we are initialising has the same ID as a table which was previously
6053 * initialised, but the table nodes don't match (from before) then we destroy the old
6054 * instance by simply deleting it. This is under the assumption that the table has been
6055 * destroyed by other methods. Anyone using non-id selectors will need to do this manually
6056 */
6057 if ( allSettings[i].sTableId == this.id )
6058 {
6059 allSettings.splice( i, 1 );
6060 break;
6061 }
6062 }
6063
6064 /* Ensure the table has an ID - required for accessibility */
6065 if ( sId === null || sId === "" )
6066 {
6067 sId = "DataTables_Table_"+(DataTable.ext._unique++);
6068 this.id = sId;
6069 }
6070
6071 /* Create the settings object for this table and set some of the default parameters */
6072 var oSettings = $.extend( true, {}, DataTable.models.oSettings, {
6073 "nTable": this,
6074 "oApi": _that.internal,
6075 "oInit": oInit,
6076 "sDestroyWidth": $(this)[0].style.width,
6077 "sInstance": sId,
6078 "sTableId": sId
6079 } );
6080 allSettings.push( oSettings );
6081
6082 // Need to add the instance after the instance after the settings object has been added
6083 // to the settings array, so we can self reference the table instance if more than one
6084 oSettings.oInstance = (_that.length===1) ? _that : $(this).dataTable();
6085
6086 // Backwards compatibility, before we apply all the defaults
6087 _fnCompatOpts( oInit );
6088
6089 if ( oInit.oLanguage )
6090 {
6091 _fnLanguageCompat( oInit.oLanguage );
6092 }
6093
6094 // If the length menu is given, but the init display length is not, use the length menu
6095 if ( oInit.aLengthMenu && ! oInit.iDisplayLength )
6096 {
6097 oInit.iDisplayLength = $.isArray( oInit.aLengthMenu[0] ) ?
6098 oInit.aLengthMenu[0][0] : oInit.aLengthMenu[0];
6099 }
6100
6101 // Apply the defaults and init options to make a single init object will all
6102 // options defined from defaults and instance options.
6103 oInit = _fnExtend( $.extend( true, {}, defaults ), oInit );
6104
6105
6106 // Map the initialisation options onto the settings object
6107 _fnMap( oSettings.oFeatures, oInit, [
6108 "bPaginate",
6109 "bLengthChange",
6110 "bFilter",
6111 "bSort",
6112 "bSortMulti",
6113 "bInfo",
6114 "bProcessing",
6115 "bAutoWidth",
6116 "bSortClasses",
6117 "bServerSide",
6118 "bDeferRender"
6119 ] );
6120 _fnMap( oSettings, oInit, [
6121 "asStripeClasses",
6122 "ajax",
6123 "fnServerData",
6124 "fnFormatNumber",
6125 "sServerMethod",
6126 "aaSorting",
6127 "aaSortingFixed",
6128 "aLengthMenu",
6129 "sPaginationType",
6130 "sAjaxSource",
6131 "sAjaxDataProp",
6132 "iStateDuration",
6133 "sDom",
6134 "bSortCellsTop",
6135 "iTabIndex",
6136 "fnStateLoadCallback",
6137 "fnStateSaveCallback",
6138 "renderer",
6139 "searchDelay",
6140 [ "iCookieDuration", "iStateDuration" ], // backwards compat
6141 [ "oSearch", "oPreviousSearch" ],
6142 [ "aoSearchCols", "aoPreSearchCols" ],
6143 [ "iDisplayLength", "_iDisplayLength" ],
6144 [ "bJQueryUI", "bJUI" ]
6145 ] );
6146 _fnMap( oSettings.oScroll, oInit, [
6147 [ "sScrollX", "sX" ],
6148 [ "sScrollXInner", "sXInner" ],
6149 [ "sScrollY", "sY" ],
6150 [ "bScrollCollapse", "bCollapse" ]
6151 ] );
6152 _fnMap( oSettings.oLanguage, oInit, "fnInfoCallback" );
6153
6154 /* Callback functions which are array driven */
6155 _fnCallbackReg( oSettings, 'aoDrawCallback', oInit.fnDrawCallback, 'user' );
6156 _fnCallbackReg( oSettings, 'aoServerParams', oInit.fnServerParams, 'user' );
6157 _fnCallbackReg( oSettings, 'aoStateSaveParams', oInit.fnStateSaveParams, 'user' );
6158 _fnCallbackReg( oSettings, 'aoStateLoadParams', oInit.fnStateLoadParams, 'user' );
6159 _fnCallbackReg( oSettings, 'aoStateLoaded', oInit.fnStateLoaded, 'user' );
6160 _fnCallbackReg( oSettings, 'aoRowCallback', oInit.fnRowCallback, 'user' );
6161 _fnCallbackReg( oSettings, 'aoRowCreatedCallback', oInit.fnCreatedRow, 'user' );
6162 _fnCallbackReg( oSettings, 'aoHeaderCallback', oInit.fnHeaderCallback, 'user' );
6163 _fnCallbackReg( oSettings, 'aoFooterCallback', oInit.fnFooterCallback, 'user' );
6164 _fnCallbackReg( oSettings, 'aoInitComplete', oInit.fnInitComplete, 'user' );
6165 _fnCallbackReg( oSettings, 'aoPreDrawCallback', oInit.fnPreDrawCallback, 'user' );
6166
6167 var oClasses = oSettings.oClasses;
6168
6169 // @todo Remove in 1.11
6170 if ( oInit.bJQueryUI )
6171 {
6172 /* Use the JUI classes object for display. You could clone the oStdClasses object if
6173 * you want to have multiple tables with multiple independent classes
6174 */
6175 $.extend( oClasses, DataTable.ext.oJUIClasses, oInit.oClasses );
6176
6177 if ( oInit.sDom === defaults.sDom && defaults.sDom === "lfrtip" )
6178 {
6179 /* Set the DOM to use a layout suitable for jQuery UI's theming */
6180 oSettings.sDom = '<"H"lfr>t<"F"ip>';
6181 }
6182
6183 if ( ! oSettings.renderer ) {
6184 oSettings.renderer = 'jqueryui';
6185 }
6186 else if ( $.isPlainObject( oSettings.renderer ) && ! oSettings.renderer.header ) {
6187 oSettings.renderer.header = 'jqueryui';
6188 }
6189 }
6190 else
6191 {
6192 $.extend( oClasses, DataTable.ext.classes, oInit.oClasses );
6193 }
6194 $(this).addClass( oClasses.sTable );
6195
6196 /* Calculate the scroll bar width and cache it for use later on */
6197 if ( oSettings.oScroll.sX !== "" || oSettings.oScroll.sY !== "" )
6198 {
6199 oSettings.oScroll.iBarWidth = _fnScrollBarWidth();
6200 }
6201 if ( oSettings.oScroll.sX === true ) { // Easy initialisation of x-scrolling
6202 oSettings.oScroll.sX = '100%';
6203 }
6204
6205 if ( oSettings.iInitDisplayStart === undefined )
6206 {
6207 /* Display start point, taking into account the save saving */
6208 oSettings.iInitDisplayStart = oInit.iDisplayStart;
6209 oSettings._iDisplayStart = oInit.iDisplayStart;
6210 }
6211
6212 if ( oInit.iDeferLoading !== null )
6213 {
6214 oSettings.bDeferLoading = true;
6215 var tmp = $.isArray( oInit.iDeferLoading );
6216 oSettings._iRecordsDisplay = tmp ? oInit.iDeferLoading[0] : oInit.iDeferLoading;
6217 oSettings._iRecordsTotal = tmp ? oInit.iDeferLoading[1] : oInit.iDeferLoading;
6218 }
6219
6220 /* Language definitions */
6221 if ( oInit.oLanguage.sUrl !== "" )
6222 {
6223 /* Get the language definitions from a file - because this Ajax call makes the language
6224 * get async to the remainder of this function we use bInitHandedOff to indicate that
6225 * _fnInitialise will be fired by the returned Ajax handler, rather than the constructor
6226 */
6227 oSettings.oLanguage.sUrl = oInit.oLanguage.sUrl;
6228 $.getJSON( oSettings.oLanguage.sUrl, null, function( json ) {
6229 _fnLanguageCompat( json );
6230 _fnCamelToHungarian( defaults.oLanguage, json );
6231 $.extend( true, oSettings.oLanguage, oInit.oLanguage, json );
6232 _fnInitialise( oSettings );
6233 } );
6234 bInitHandedOff = true;
6235 }
6236 else
6237 {
6238 $.extend( true, oSettings.oLanguage, oInit.oLanguage );
6239 }
6240
6241
6242 /*
6243 * Stripes
6244 */
6245 if ( oInit.asStripeClasses === null )
6246 {
6247 oSettings.asStripeClasses =[
6248 oClasses.sStripeOdd,
6249 oClasses.sStripeEven
6250 ];
6251 }
6252
6253 /* Remove row stripe classes if they are already on the table row */
6254 var stripeClasses = oSettings.asStripeClasses;
6255 var rowOne = $('tbody tr:eq(0)', this);
6256 if ( $.inArray( true, $.map( stripeClasses, function(el, i) {
6257 return rowOne.hasClass(el);
6258 } ) ) !== -1 ) {
6259 $('tbody tr', this).removeClass( stripeClasses.join(' ') );
6260 oSettings.asDestroyStripes = stripeClasses.slice();
6261 }
6262
6263 /*
6264 * Columns
6265 * See if we should load columns automatically or use defined ones
6266 */
6267 var anThs = [];
6268 var aoColumnsInit;
6269 var nThead = this.getElementsByTagName('thead');
6270 if ( nThead.length !== 0 )
6271 {
6272 _fnDetectHeader( oSettings.aoHeader, nThead[0] );
6273 anThs = _fnGetUniqueThs( oSettings );
6274 }
6275
6276 /* If not given a column array, generate one with nulls */
6277 if ( oInit.aoColumns === null )
6278 {
6279 aoColumnsInit = [];
6280 for ( i=0, iLen=anThs.length ; i<iLen ; i++ )
6281 {
6282 aoColumnsInit.push( null );
6283 }
6284 }
6285 else
6286 {
6287 aoColumnsInit = oInit.aoColumns;
6288 }
6289
6290 /* Add the columns */
6291 for ( i=0, iLen=aoColumnsInit.length ; i<iLen ; i++ )
6292 {
6293 _fnAddColumn( oSettings, anThs ? anThs[i] : null );
6294 }
6295
6296 /* Apply the column definitions */
6297 _fnApplyColumnDefs( oSettings, oInit.aoColumnDefs, aoColumnsInit, function (iCol, oDef) {
6298 _fnColumnOptions( oSettings, iCol, oDef );
6299 } );
6300
6301 /* HTML5 attribute detection - build an mData object automatically if the
6302 * attributes are found
6303 */
6304 if ( rowOne.length ) {
6305 var a = function ( cell, name ) {
6306 return cell.getAttribute( 'data-'+name ) ? name : null;
6307 };
6308
6309 $.each( _fnGetRowElements( oSettings, rowOne[0] ).cells, function (i, cell) {
6310 var col = oSettings.aoColumns[i];
6311
6312 if ( col.mData === i ) {
6313 var sort = a( cell, 'sort' ) || a( cell, 'order' );
6314 var filter = a( cell, 'filter' ) || a( cell, 'search' );
6315
6316 if ( sort !== null || filter !== null ) {
6317 col.mData = {
6318 _: i+'.display',
6319 sort: sort !== null ? i+'.@data-'+sort : undefined,
6320 type: sort !== null ? i+'.@data-'+sort : undefined,
6321 filter: filter !== null ? i+'.@data-'+filter : undefined
6322 };
6323
6324 _fnColumnOptions( oSettings, i );
6325 }
6326 }
6327 } );
6328 }
6329
6330 var features = oSettings.oFeatures;
6331
6332 /* Must be done after everything which can be overridden by the state saving! */
6333 if ( oInit.bStateSave )
6334 {
6335 features.bStateSave = true;
6336 _fnLoadState( oSettings, oInit );
6337 _fnCallbackReg( oSettings, 'aoDrawCallback', _fnSaveState, 'state_save' );
6338 }
6339
6340
6341 /*
6342 * Sorting
6343 * @todo For modularisation (1.11) this needs to do into a sort start up handler
6344 */
6345
6346 // If aaSorting is not defined, then we use the first indicator in asSorting
6347 // in case that has been altered, so the default sort reflects that option
6348 if ( oInit.aaSorting === undefined )
6349 {
6350 var sorting = oSettings.aaSorting;
6351 for ( i=0, iLen=sorting.length ; i<iLen ; i++ )
6352 {
6353 sorting[i][1] = oSettings.aoColumns[ i ].asSorting[0];
6354 }
6355 }
6356
6357 /* Do a first pass on the sorting classes (allows any size changes to be taken into
6358 * account, and also will apply sorting disabled classes if disabled
6359 */
6360 _fnSortingClasses( oSettings );
6361
6362 if ( features.bSort )
6363 {
6364 _fnCallbackReg( oSettings, 'aoDrawCallback', function () {
6365 if ( oSettings.bSorted ) {
6366 var aSort = _fnSortFlatten( oSettings );
6367 var sortedColumns = {};
6368
6369 $.each( aSort, function (i, val) {
6370 sortedColumns[ val.src ] = val.dir;
6371 } );
6372
6373 _fnCallbackFire( oSettings, null, 'order', [oSettings, aSort, sortedColumns] );
6374 _fnSortAria( oSettings );
6375 }
6376 } );
6377 }
6378
6379 _fnCallbackReg( oSettings, 'aoDrawCallback', function () {
6380 if ( oSettings.bSorted || _fnDataSource( oSettings ) === 'ssp' || features.bDeferRender ) {
6381 _fnSortingClasses( oSettings );
6382 }
6383 }, 'sc' );
6384
6385
6386 /*
6387 * Final init
6388 * Cache the header, body and footer as required, creating them if needed
6389 */
6390
6391 /* Browser support detection */
6392 _fnBrowserDetect( oSettings );
6393
6394 // Work around for Webkit bug 83867 - store the caption-side before removing from doc
6395 var captions = $(this).children('caption').each( function () {
6396 this._captionSide = $(this).css('caption-side');
6397 } );
6398
6399 var thead = $(this).children('thead');
6400 if ( thead.length === 0 )
6401 {
6402 thead = $('<thead/>').appendTo(this);
6403 }
6404 oSettings.nTHead = thead[0];
6405
6406 var tbody = $(this).children('tbody');
6407 if ( tbody.length === 0 )
6408 {
6409 tbody = $('<tbody/>').appendTo(this);
6410 }
6411 oSettings.nTBody = tbody[0];
6412
6413 var tfoot = $(this).children('tfoot');
6414 if ( tfoot.length === 0 && captions.length > 0 && (oSettings.oScroll.sX !== "" || oSettings.oScroll.sY !== "") )
6415 {
6416 // If we are a scrolling table, and no footer has been given, then we need to create
6417 // a tfoot element for the caption element to be appended to
6418 tfoot = $('<tfoot/>').appendTo(this);
6419 }
6420
6421 if ( tfoot.length === 0 || tfoot.children().length === 0 ) {
6422 $(this).addClass( oClasses.sNoFooter );
6423 }
6424 else if ( tfoot.length > 0 ) {
6425 oSettings.nTFoot = tfoot[0];
6426 _fnDetectHeader( oSettings.aoFooter, oSettings.nTFoot );
6427 }
6428
6429 /* Check if there is data passing into the constructor */
6430 if ( oInit.aaData )
6431 {
6432 for ( i=0 ; i<oInit.aaData.length ; i++ )
6433 {
6434 _fnAddData( oSettings, oInit.aaData[ i ] );
6435 }
6436 }
6437 else if ( oSettings.bDeferLoading || _fnDataSource( oSettings ) == 'dom' )
6438 {
6439 /* Grab the data from the page - only do this when deferred loading or no Ajax
6440 * source since there is no point in reading the DOM data if we are then going
6441 * to replace it with Ajax data
6442 */
6443 _fnAddTr( oSettings, $(oSettings.nTBody).children('tr') );
6444 }
6445
6446 /* Copy the data index array */
6447 oSettings.aiDisplay = oSettings.aiDisplayMaster.slice();
6448
6449 /* Initialisation complete - table can be drawn */
6450 oSettings.bInitialised = true;
6451
6452 /* Check if we need to initialise the table (it might not have been handed off to the
6453 * language processor)
6454 */
6455 if ( bInitHandedOff === false )
6456 {
6457 _fnInitialise( oSettings );
6458 }
6459 } );
6460 _that = null;
6461 return this;
6462 };
6463
6464
6465
6466 /**
6467 * Computed structure of the DataTables API, defined by the options passed to
6468 * `DataTable.Api.register()` when building the API.
6469 *
6470 * The structure is built in order to speed creation and extension of the Api
6471 * objects since the extensions are effectively pre-parsed.
6472 *
6473 * The array is an array of objects with the following structure, where this
6474 * base array represents the Api prototype base:
6475 *
6476 * [
6477 * {
6478 * name: 'data' -- string - Property name
6479 * val: function () {}, -- function - Api method (or undefined if just an object
6480 * methodExt: [ ... ], -- array - Array of Api object definitions to extend the method result
6481 * propExt: [ ... ] -- array - Array of Api object definitions to extend the property
6482 * },
6483 * {
6484 * name: 'row'
6485 * val: {},
6486 * methodExt: [ ... ],
6487 * propExt: [
6488 * {
6489 * name: 'data'
6490 * val: function () {},
6491 * methodExt: [ ... ],
6492 * propExt: [ ... ]
6493 * },
6494 * ...
6495 * ]
6496 * }
6497 * ]
6498 *
6499 * @type {Array}
6500 * @ignore
6501 */
6502 var __apiStruct = [];
6503
6504
6505 /**
6506 * `Array.prototype` reference.
6507 *
6508 * @type object
6509 * @ignore
6510 */
6511 var __arrayProto = Array.prototype;
6512
6513
6514 /**
6515 * Abstraction for `context` parameter of the `Api` constructor to allow it to
6516 * take several different forms for ease of use.
6517 *
6518 * Each of the input parameter types will be converted to a DataTables settings
6519 * object where possible.
6520 *
6521 * @param {string|node|jQuery|object} mixed DataTable identifier. Can be one
6522 * of:
6523 *
6524 * * `string` - jQuery selector. Any DataTables' matching the given selector
6525 * with be found and used.
6526 * * `node` - `TABLE` node which has already been formed into a DataTable.
6527 * * `jQuery` - A jQuery object of `TABLE` nodes.
6528 * * `object` - DataTables settings object
6529 * * `DataTables.Api` - API instance
6530 * @return {array|null} Matching DataTables settings objects. `null` or
6531 * `undefined` is returned if no matching DataTable is found.
6532 * @ignore
6533 */
6534 var _toSettings = function ( mixed )
6535 {
6536 var idx, jq;
6537 var settings = DataTable.settings;
6538 var tables = $.map( settings, function (el, i) {
6539 return el.nTable;
6540 } );
6541
6542 if ( ! mixed ) {
6543 return [];
6544 }
6545 else if ( mixed.nTable && mixed.oApi ) {
6546 // DataTables settings object
6547 return [ mixed ];
6548 }
6549 else if ( mixed.nodeName && mixed.nodeName.toLowerCase() === 'table' ) {
6550 // Table node
6551 idx = $.inArray( mixed, tables );
6552 return idx !== -1 ? [ settings[idx] ] : null;
6553 }
6554 else if ( mixed && typeof mixed.settings === 'function' ) {
6555 return mixed.settings().toArray();
6556 }
6557 else if ( typeof mixed === 'string' ) {
6558 // jQuery selector
6559 jq = $(mixed);
6560 }
6561 else if ( mixed instanceof $ ) {
6562 // jQuery object (also DataTables instance)
6563 jq = mixed;
6564 }
6565
6566 if ( jq ) {
6567 return jq.map( function(i) {
6568 idx = $.inArray( this, tables );
6569 return idx !== -1 ? settings[idx] : null;
6570 } ).toArray();
6571 }
6572 };
6573
6574
6575 /**
6576 * DataTables API class - used to control and interface with one or more
6577 * DataTables enhanced tables.
6578 *
6579 * The API class is heavily based on jQuery, presenting a chainable interface
6580 * that you can use to interact with tables. Each instance of the API class has
6581 * a "context" - i.e. the tables that it will operate on. This could be a single
6582 * table, all tables on a page or a sub-set thereof.
6583 *
6584 * Additionally the API is designed to allow you to easily work with the data in
6585 * the tables, retrieving and manipulating it as required. This is done by
6586 * presenting the API class as an array like interface. The contents of the
6587 * array depend upon the actions requested by each method (for example
6588 * `rows().nodes()` will return an array of nodes, while `rows().data()` will
6589 * return an array of objects or arrays depending upon your table's
6590 * configuration). The API object has a number of array like methods (`push`,
6591 * `pop`, `reverse` etc) as well as additional helper methods (`each`, `pluck`,
6592 * `unique` etc) to assist your working with the data held in a table.
6593 *
6594 * Most methods (those which return an Api instance) are chainable, which means
6595 * the return from a method call also has all of the methods available that the
6596 * top level object had. For example, these two calls are equivalent:
6597 *
6598 * // Not chained
6599 * api.row.add( {...} );
6600 * api.draw();
6601 *
6602 * // Chained
6603 * api.row.add( {...} ).draw();
6604 *
6605 * @class DataTable.Api
6606 * @param {array|object|string|jQuery} context DataTable identifier. This is
6607 * used to define which DataTables enhanced tables this API will operate on.
6608 * Can be one of:
6609 *
6610 * * `string` - jQuery selector. Any DataTables' matching the given selector
6611 * with be found and used.
6612 * * `node` - `TABLE` node which has already been formed into a DataTable.
6613 * * `jQuery` - A jQuery object of `TABLE` nodes.
6614 * * `object` - DataTables settings object
6615 * @param {array} [data] Data to initialise the Api instance with.
6616 *
6617 * @example
6618 * // Direct initialisation during DataTables construction
6619 * var api = $('#example').DataTable();
6620 *
6621 * @example
6622 * // Initialisation using a DataTables jQuery object
6623 * var api = $('#example').dataTable().api();
6624 *
6625 * @example
6626 * // Initialisation as a constructor
6627 * var api = new $.fn.DataTable.Api( 'table.dataTable' );
6628 */
6629 _Api = function ( context, data )
6630 {
6631 if ( ! this instanceof _Api ) {
6632 throw 'DT API must be constructed as a new object';
6633 // or should it do the 'new' for the caller?
6634 // return new _Api.apply( this, arguments );
6635 }
6636
6637 var settings = [];
6638 var ctxSettings = function ( o ) {
6639 var a = _toSettings( o );
6640 if ( a ) {
6641 settings.push.apply( settings, a );
6642 }
6643 };
6644
6645 if ( $.isArray( context ) ) {
6646 for ( var i=0, ien=context.length ; i<ien ; i++ ) {
6647 ctxSettings( context[i] );
6648 }
6649 }
6650 else {
6651 ctxSettings( context );
6652 }
6653
6654 // Remove duplicates
6655 this.context = _unique( settings );
6656
6657 // Initial data
6658 if ( data ) {
6659 this.push.apply( this, data.toArray ? data.toArray() : data );
6660 }
6661
6662 // selector
6663 this.selector = {
6664 rows: null,
6665 cols: null,
6666 opts: null
6667 };
6668
6669 _Api.extend( this, this, __apiStruct );
6670 };
6671
6672 DataTable.Api = _Api;
6673
6674 _Api.prototype = /** @lends DataTables.Api */{
6675 /**
6676 * Return a new Api instance, comprised of the data held in the current
6677 * instance, join with the other array(s) and/or value(s).
6678 *
6679 * An alias for `Array.prototype.concat`.
6680 *
6681 * @type method
6682 * @param {*} value1 Arrays and/or values to concatenate.
6683 * @param {*} [...] Additional arrays and/or values to concatenate.
6684 * @returns {DataTables.Api} New API instance, comprising of the combined
6685 * array.
6686 */
6687 concat: __arrayProto.concat,
6688
6689
6690 context: [], // array of table settings objects
6691
6692
6693 each: function ( fn )
6694 {
6695 for ( var i=0, ien=this.length ; i<ien; i++ ) {
6696 fn.call( this, this[i], i, this );
6697 }
6698
6699 return this;
6700 },
6701
6702
6703 eq: function ( idx )
6704 {
6705 var ctx = this.context;
6706
6707 return ctx.length > idx ?
6708 new _Api( ctx[idx], this[idx] ) :
6709 null;
6710 },
6711
6712
6713 filter: function ( fn )
6714 {
6715 var a = [];
6716
6717 if ( __arrayProto.filter ) {
6718 a = __arrayProto.filter.call( this, fn, this );
6719 }
6720 else {
6721 // Compatibility for browsers without EMCA-252-5 (JS 1.6)
6722 for ( var i=0, ien=this.length ; i<ien ; i++ ) {
6723 if ( fn.call( this, this[i], i, this ) ) {
6724 a.push( this[i] );
6725 }
6726 }
6727 }
6728
6729 return new _Api( this.context, a );
6730 },
6731
6732
6733 flatten: function ()
6734 {
6735 var a = [];
6736 return new _Api( this.context, a.concat.apply( a, this.toArray() ) );
6737 },
6738
6739
6740 join: __arrayProto.join,
6741
6742
6743 indexOf: __arrayProto.indexOf || function (obj, start)
6744 {
6745 for ( var i=(start || 0), ien=this.length ; i<ien ; i++ ) {
6746 if ( this[i] === obj ) {
6747 return i;
6748 }
6749 }
6750 return -1;
6751 },
6752
6753 // Internal only at the moment - relax?
6754 iterator: function ( flatten, type, fn ) {
6755 var
6756 a = [], ret,
6757 i, ien, j, jen,
6758 context = this.context,
6759 rows, items, item,
6760 selector = this.selector;
6761
6762 // Argument shifting
6763 if ( typeof flatten === 'string' ) {
6764 fn = type;
6765 type = flatten;
6766 flatten = false;
6767 }
6768
6769 for ( i=0, ien=context.length ; i<ien ; i++ ) {
6770 var apiInst = new _Api( context[i] );
6771
6772 if ( type === 'table' ) {
6773 ret = fn.call( apiInst, context[i], i );
6774
6775 if ( ret !== undefined ) {
6776 a.push( ret );
6777 }
6778 }
6779 else if ( type === 'columns' || type === 'rows' ) {
6780 // this has same length as context - one entry for each table
6781 ret = fn.call( apiInst, context[i], this[i], i );
6782
6783 if ( ret !== undefined ) {
6784 a.push( ret );
6785 }
6786 }
6787 else if ( type === 'column' || type === 'column-rows' || type === 'row' || type === 'cell' ) {
6788 // columns and rows share the same structure.
6789 // 'this' is an array of column indexes for each context
6790 items = this[i];
6791
6792 if ( type === 'column-rows' ) {
6793 rows = _selector_row_indexes( context[i], selector.opts );
6794 }
6795
6796 for ( j=0, jen=items.length ; j<jen ; j++ ) {
6797 item = items[j];
6798
6799 if ( type === 'cell' ) {
6800 ret = fn.call( apiInst, context[i], item.row, item.column, i, j );
6801 }
6802 else {
6803 ret = fn.call( apiInst, context[i], item, i, j, rows );
6804 }
6805
6806 if ( ret !== undefined ) {
6807 a.push( ret );
6808 }
6809 }
6810 }
6811 }
6812
6813 if ( a.length ) {
6814 var api = new _Api( context, flatten ? a.concat.apply( [], a ) : a );
6815 var apiSelector = api.selector;
6816 apiSelector.rows = selector.rows;
6817 apiSelector.cols = selector.cols;
6818 apiSelector.opts = selector.opts;
6819 return api;
6820 }
6821 return this;
6822 },
6823
6824
6825 lastIndexOf: __arrayProto.lastIndexOf || function (obj, start)
6826 {
6827 // Bit cheeky...
6828 return this.indexOf.apply( this.toArray.reverse(), arguments );
6829 },
6830
6831
6832 length: 0,
6833
6834
6835 map: function ( fn )
6836 {
6837 var a = [];
6838
6839 if ( __arrayProto.map ) {
6840 a = __arrayProto.map.call( this, fn, this );
6841 }
6842 else {
6843 // Compatibility for browsers without EMCA-252-5 (JS 1.6)
6844 for ( var i=0, ien=this.length ; i<ien ; i++ ) {
6845 a.push( fn.call( this, this[i], i ) );
6846 }
6847 }
6848
6849 return new _Api( this.context, a );
6850 },
6851
6852
6853 pluck: function ( prop )
6854 {
6855 return this.map( function ( el ) {
6856 return el[ prop ];
6857 } );
6858 },
6859
6860 pop: __arrayProto.pop,
6861
6862
6863 push: __arrayProto.push,
6864
6865
6866 // Does not return an API instance
6867 reduce: __arrayProto.reduce || function ( fn, init )
6868 {
6869 return _fnReduce( this, fn, init, 0, this.length, 1 );
6870 },
6871
6872
6873 reduceRight: __arrayProto.reduceRight || function ( fn, init )
6874 {
6875 return _fnReduce( this, fn, init, this.length-1, -1, -1 );
6876 },
6877
6878
6879 reverse: __arrayProto.reverse,
6880
6881
6882 // Object with rows, columns and opts
6883 selector: null,
6884
6885
6886 shift: __arrayProto.shift,
6887
6888
6889 sort: __arrayProto.sort, // ? name - order?
6890
6891
6892 splice: __arrayProto.splice,
6893
6894
6895 toArray: function ()
6896 {
6897 return __arrayProto.slice.call( this );
6898 },
6899
6900
6901 to$: function ()
6902 {
6903 return $( this );
6904 },
6905
6906
6907 toJQuery: function ()
6908 {
6909 return $( this );
6910 },
6911
6912
6913 unique: function ()
6914 {
6915 return new _Api( this.context, _unique(this) );
6916 },
6917
6918
6919 unshift: __arrayProto.unshift
6920 };
6921
6922
6923 _Api.extend = function ( scope, obj, ext )
6924 {
6925 // Only extend API instances and static properties of the API
6926 if ( ! obj || ( ! (obj instanceof _Api) && ! obj.__dt_wrapper ) ) {
6927 return;
6928 }
6929
6930 var
6931 i, ien,
6932 j, jen,
6933 struct, inner,
6934 methodScoping = function ( scope, fn, struc ) {
6935 return function () {
6936 var ret = fn.apply( scope, arguments );
6937
6938 // Method extension
6939 _Api.extend( ret, ret, struc.methodExt );
6940 return ret;
6941 };
6942 };
6943
6944 for ( i=0, ien=ext.length ; i<ien ; i++ ) {
6945 struct = ext[i];
6946
6947 // Value
6948 obj[ struct.name ] = typeof struct.val === 'function' ?
6949 methodScoping( scope, struct.val, struct ) :
6950 $.isPlainObject( struct.val ) ?
6951 {} :
6952 struct.val;
6953
6954 obj[ struct.name ].__dt_wrapper = true;
6955
6956 // Property extension
6957 _Api.extend( scope, obj[ struct.name ], struct.propExt );
6958 }
6959 };
6960
6961
6962 // @todo - Is there need for an augment function?
6963 // _Api.augment = function ( inst, name )
6964 // {
6965 // // Find src object in the structure from the name
6966 // var parts = name.split('.');
6967
6968 // _Api.extend( inst, obj );
6969 // };
6970
6971
6972 // [
6973 // {
6974 // name: 'data' -- string - Property name
6975 // val: function () {}, -- function - Api method (or undefined if just an object
6976 // methodExt: [ ... ], -- array - Array of Api object definitions to extend the method result
6977 // propExt: [ ... ] -- array - Array of Api object definitions to extend the property
6978 // },
6979 // {
6980 // name: 'row'
6981 // val: {},
6982 // methodExt: [ ... ],
6983 // propExt: [
6984 // {
6985 // name: 'data'
6986 // val: function () {},
6987 // methodExt: [ ... ],
6988 // propExt: [ ... ]
6989 // },
6990 // ...
6991 // ]
6992 // }
6993 // ]
6994
6995 _Api.register = _api_register = function ( name, val )
6996 {
6997 if ( $.isArray( name ) ) {
6998 for ( var j=0, jen=name.length ; j<jen ; j++ ) {
6999 _Api.register( name[j], val );
7000 }
7001 return;
7002 }
7003
7004 var
7005 i, ien,
7006 heir = name.split('.'),
7007 struct = __apiStruct,
7008 key, method;
7009
7010 var find = function ( src, name ) {
7011 for ( var i=0, ien=src.length ; i<ien ; i++ ) {
7012 if ( src[i].name === name ) {
7013 return src[i];
7014 }
7015 }
7016 return null;
7017 };
7018
7019 for ( i=0, ien=heir.length ; i<ien ; i++ ) {
7020 method = heir[i].indexOf('()') !== -1;
7021 key = method ?
7022 heir[i].replace('()', '') :
7023 heir[i];
7024
7025 var src = find( struct, key );
7026 if ( ! src ) {
7027 src = {
7028 name: key,
7029 val: {},
7030 methodExt: [],
7031 propExt: []
7032 };
7033 struct.push( src );
7034 }
7035
7036 if ( i === ien-1 ) {
7037 src.val = val;
7038 }
7039 else {
7040 struct = method ?
7041 src.methodExt :
7042 src.propExt;
7043 }
7044 }
7045 };
7046
7047
7048 _Api.registerPlural = _api_registerPlural = function ( pluralName, singularName, val ) {
7049 _Api.register( pluralName, val );
7050
7051 _Api.register( singularName, function () {
7052 var ret = val.apply( this, arguments );
7053
7054 if ( ret === this ) {
7055 // Returned item is the API instance that was passed in, return it
7056 return this;
7057 }
7058 else if ( ret instanceof _Api ) {
7059 // New API instance returned, want the value from the first item
7060 // in the returned array for the singular result.
7061 return ret.length ?
7062 $.isArray( ret[0] ) ?
7063 new _Api( ret.context, ret[0] ) : // Array results are 'enhanced'
7064 ret[0] :
7065 undefined;
7066 }
7067
7068 // Non-API return - just fire it back
7069 return ret;
7070 } );
7071 };
7072
7073
7074 /**
7075 * Selector for HTML tables. Apply the given selector to the give array of
7076 * DataTables settings objects.
7077 *
7078 * @param {string|integer} [selector] jQuery selector string or integer
7079 * @param {array} Array of DataTables settings objects to be filtered
7080 * @return {array}
7081 * @ignore
7082 */
7083 var __table_selector = function ( selector, a )
7084 {
7085 // Integer is used to pick out a table by index
7086 if ( typeof selector === 'number' ) {
7087 return [ a[ selector ] ];
7088 }
7089
7090 // Perform a jQuery selector on the table nodes
7091 var nodes = $.map( a, function (el, i) {
7092 return el.nTable;
7093 } );
7094
7095 return $(nodes)
7096 .filter( selector )
7097 .map( function (i) {
7098 // Need to translate back from the table node to the settings
7099 var idx = $.inArray( this, nodes );
7100 return a[ idx ];
7101 } )
7102 .toArray();
7103 };
7104
7105
7106
7107 /**
7108 * Context selector for the API's context (i.e. the tables the API instance
7109 * refers to.
7110 *
7111 * @name DataTable.Api#tables
7112 * @param {string|integer} [selector] Selector to pick which tables the iterator
7113 * should operate on. If not given, all tables in the current context are
7114 * used. This can be given as a jQuery selector (for example `':gt(0)'`) to
7115 * select multiple tables or as an integer to select a single table.
7116 * @returns {DataTable.Api} Returns a new API instance if a selector is given.
7117 */
7118 _api_register( 'tables()', function ( selector ) {
7119 // A new instance is created if there was a selector specified
7120 return selector ?
7121 new _Api( __table_selector( selector, this.context ) ) :
7122 this;
7123 } );
7124
7125
7126 _api_register( 'table()', function ( selector ) {
7127 var tables = this.tables( selector );
7128 var ctx = tables.context;
7129
7130 // Truncate to the first matched table
7131 return ctx.length ?
7132 new _Api( ctx[0] ) :
7133 tables;
7134 } );
7135
7136
7137 _api_registerPlural( 'tables().nodes()', 'table().node()' , function () {
7138 return this.iterator( 'table', function ( ctx ) {
7139 return ctx.nTable;
7140 } );
7141 } );
7142
7143
7144 _api_registerPlural( 'tables().body()', 'table().body()' , function () {
7145 return this.iterator( 'table', function ( ctx ) {
7146 return ctx.nTBody;
7147 } );
7148 } );
7149
7150
7151 _api_registerPlural( 'tables().header()', 'table().header()' , function () {
7152 return this.iterator( 'table', function ( ctx ) {
7153 return ctx.nTHead;
7154 } );
7155 } );
7156
7157
7158 _api_registerPlural( 'tables().footer()', 'table().footer()' , function () {
7159 return this.iterator( 'table', function ( ctx ) {
7160 return ctx.nTFoot;
7161 } );
7162 } );
7163
7164
7165 _api_registerPlural( 'tables().containers()', 'table().container()' , function () {
7166 return this.iterator( 'table', function ( ctx ) {
7167 return ctx.nTableWrapper;
7168 } );
7169 } );
7170
7171
7172
7173 /**
7174 * Redraw the tables in the current context.
7175 *
7176 * @param {boolean} [reset=true] Reset (default) or hold the current paging
7177 * position. A full re-sort and re-filter is performed when this method is
7178 * called, which is why the pagination reset is the default action.
7179 * @returns {DataTables.Api} this
7180 */
7181 _api_register( 'draw()', function ( resetPaging ) {
7182 return this.iterator( 'table', function ( settings ) {
7183 _fnReDraw( settings, resetPaging===false );
7184 } );
7185 } );
7186
7187
7188
7189 /**
7190 * Get the current page index.
7191 *
7192 * @return {integer} Current page index (zero based)
7193 *//**
7194 * Set the current page.
7195 *
7196 * Note that if you attempt to show a page which does not exist, DataTables will
7197 * not throw an error, but rather reset the paging.
7198 *
7199 * @param {integer|string} action The paging action to take. This can be one of:
7200 * * `integer` - The page index to jump to
7201 * * `string` - An action to take:
7202 * * `first` - Jump to first page.
7203 * * `next` - Jump to the next page
7204 * * `previous` - Jump to previous page
7205 * * `last` - Jump to the last page.
7206 * @returns {DataTables.Api} this
7207 */
7208 _api_register( 'page()', function ( action ) {
7209 if ( action === undefined ) {
7210 return this.page.info().page; // not an expensive call
7211 }
7212
7213 // else, have an action to take on all tables
7214 return this.iterator( 'table', function ( settings ) {
7215 _fnPageChange( settings, action );
7216 } );
7217 } );
7218
7219
7220 /**
7221 * Paging information for the first table in the current context.
7222 *
7223 * If you require paging information for another table, use the `table()` method
7224 * with a suitable selector.
7225 *
7226 * @return {object} Object with the following properties set:
7227 * * `page` - Current page index (zero based - i.e. the first page is `0`)
7228 * * `pages` - Total number of pages
7229 * * `start` - Display index for the first record shown on the current page
7230 * * `end` - Display index for the last record shown on the current page
7231 * * `length` - Display length (number of records). Note that generally `start
7232 * + length = end`, but this is not always true, for example if there are
7233 * only 2 records to show on the final page, with a length of 10.
7234 * * `recordsTotal` - Full data set length
7235 * * `recordsDisplay` - Data set length once the current filtering criterion
7236 * are applied.
7237 */
7238 _api_register( 'page.info()', function ( action ) {
7239 if ( this.context.length === 0 ) {
7240 return undefined;
7241 }
7242
7243 var
7244 settings = this.context[0],
7245 start = settings._iDisplayStart,
7246 len = settings._iDisplayLength,
7247 visRecords = settings.fnRecordsDisplay(),
7248 all = len === -1;
7249
7250 return {
7251 "page": all ? 0 : Math.floor( start / len ),
7252 "pages": all ? 1 : Math.ceil( visRecords / len ),
7253 "start": start,
7254 "end": settings.fnDisplayEnd(),
7255 "length": len,
7256 "recordsTotal": settings.fnRecordsTotal(),
7257 "recordsDisplay": visRecords
7258 };
7259 } );
7260
7261
7262 /**
7263 * Get the current page length.
7264 *
7265 * @return {integer} Current page length. Note `-1` indicates that all records
7266 * are to be shown.
7267 *//**
7268 * Set the current page length.
7269 *
7270 * @param {integer} Page length to set. Use `-1` to show all records.
7271 * @returns {DataTables.Api} this
7272 */
7273 _api_register( 'page.len()', function ( len ) {
7274 // Note that we can't call this function 'length()' because `length`
7275 // is a Javascript property of functions which defines how many arguments
7276 // the function expects.
7277 if ( len === undefined ) {
7278 return this.context.length !== 0 ?
7279 this.context[0]._iDisplayLength :
7280 undefined;
7281 }
7282
7283 // else, set the page length
7284 return this.iterator( 'table', function ( settings ) {
7285 _fnLengthChange( settings, len );
7286 } );
7287 } );
7288
7289
7290
7291 var __reload = function ( settings, holdPosition, callback ) {
7292 if ( _fnDataSource( settings ) == 'ssp' ) {
7293 _fnReDraw( settings, holdPosition );
7294 }
7295 else {
7296 // Trigger xhr
7297 _fnProcessingDisplay( settings, true );
7298
7299 _fnBuildAjax( settings, [], function( json ) {
7300 _fnClearTable( settings );
7301
7302 var data = _fnAjaxDataSrc( settings, json );
7303 for ( var i=0, ien=data.length ; i<ien ; i++ ) {
7304 _fnAddData( settings, data[i] );
7305 }
7306
7307 _fnReDraw( settings, holdPosition );
7308 _fnProcessingDisplay( settings, false );
7309 } );
7310 }
7311
7312 // Use the draw event to trigger a callback, regardless of if it is an async
7313 // or sync draw
7314 if ( callback ) {
7315 var api = new _Api( settings );
7316
7317 api.one( 'draw', function () {
7318 callback( api.ajax.json() );
7319 } );
7320 }
7321 };
7322
7323
7324 /**
7325 * Get the JSON response from the last Ajax request that DataTables made to the
7326 * server. Note that this returns the JSON from the first table in the current
7327 * context.
7328 *
7329 * @return {object} JSON received from the server.
7330 */
7331 _api_register( 'ajax.json()', function () {
7332 var ctx = this.context;
7333
7334 if ( ctx.length > 0 ) {
7335 return ctx[0].json;
7336 }
7337
7338 // else return undefined;
7339 } );
7340
7341
7342 /**
7343 * Get the data submitted in the last Ajax request
7344 */
7345 _api_register( 'ajax.params()', function () {
7346 var ctx = this.context;
7347
7348 if ( ctx.length > 0 ) {
7349 return ctx[0].oAjaxData;
7350 }
7351
7352 // else return undefined;
7353 } );
7354
7355
7356 /**
7357 * Reload tables from the Ajax data source. Note that this function will
7358 * automatically re-draw the table when the remote data has been loaded.
7359 *
7360 * @param {boolean} [reset=true] Reset (default) or hold the current paging
7361 * position. A full re-sort and re-filter is performed when this method is
7362 * called, which is why the pagination reset is the default action.
7363 * @returns {DataTables.Api} this
7364 */
7365 _api_register( 'ajax.reload()', function ( callback, resetPaging ) {
7366 return this.iterator( 'table', function (settings) {
7367 __reload( settings, resetPaging===false, callback );
7368 } );
7369 } );
7370
7371
7372 /**
7373 * Get the current Ajax URL. Note that this returns the URL from the first
7374 * table in the current context.
7375 *
7376 * @return {string} Current Ajax source URL
7377 *//**
7378 * Set the Ajax URL. Note that this will set the URL for all tables in the
7379 * current context.
7380 *
7381 * @param {string} url URL to set.
7382 * @returns {DataTables.Api} this
7383 */
7384 _api_register( 'ajax.url()', function ( url ) {
7385 var ctx = this.context;
7386
7387 if ( url === undefined ) {
7388 // get
7389 if ( ctx.length === 0 ) {
7390 return undefined;
7391 }
7392 ctx = ctx[0];
7393
7394 return ctx.ajax ?
7395 $.isPlainObject( ctx.ajax ) ?
7396 ctx.ajax.url :
7397 ctx.ajax :
7398 ctx.sAjaxSource;
7399 }
7400
7401 // set
7402 return this.iterator( 'table', function ( settings ) {
7403 if ( $.isPlainObject( settings.ajax ) ) {
7404 settings.ajax.url = url;
7405 }
7406 else {
7407 settings.ajax = url;
7408 }
7409 // No need to consider sAjaxSource here since DataTables gives priority
7410 // to `ajax` over `sAjaxSource`. So setting `ajax` here, renders any
7411 // value of `sAjaxSource` redundant.
7412 } );
7413 } );
7414
7415
7416 /**
7417 * Load data from the newly set Ajax URL. Note that this method is only
7418 * available when `ajax.url()` is used to set a URL. Additionally, this method
7419 * has the same effect as calling `ajax.reload()` but is provided for
7420 * convenience when setting a new URL. Like `ajax.reload()` it will
7421 * automatically redraw the table once the remote data has been loaded.
7422 *
7423 * @returns {DataTables.Api} this
7424 */
7425 _api_register( 'ajax.url().load()', function ( callback, resetPaging ) {
7426 // Same as a reload, but makes sense to present it for easy access after a
7427 // url change
7428 return this.iterator( 'table', function ( ctx ) {
7429 __reload( ctx, resetPaging===false, callback );
7430 } );
7431 } );
7432
7433
7434
7435
7436 var _selector_run = function ( selector, select )
7437 {
7438 var
7439 out = [], res,
7440 a, i, ien, j, jen,
7441 selectorType = typeof selector;
7442
7443 // Can't just check for isArray here, as an API or jQuery instance might be
7444 // given with their array like look
7445 if ( ! selector || selectorType === 'string' || selectorType === 'function' || selector.length === undefined ) {
7446 selector = [ selector ];
7447 }
7448
7449 for ( i=0, ien=selector.length ; i<ien ; i++ ) {
7450 a = selector[i] && selector[i].split ?
7451 selector[i].split(',') :
7452 [ selector[i] ];
7453
7454 for ( j=0, jen=a.length ; j<jen ; j++ ) {
7455 res = select( typeof a[j] === 'string' ? $.trim(a[j]) : a[j] );
7456
7457 if ( res && res.length ) {
7458 out.push.apply( out, res );
7459 }
7460 }
7461 }
7462
7463 return out;
7464 };
7465
7466
7467 var _selector_opts = function ( opts )
7468 {
7469 if ( ! opts ) {
7470 opts = {};
7471 }
7472
7473 // Backwards compatibility for 1.9- which used the terminology filter rather
7474 // than search
7475 if ( opts.filter && ! opts.search ) {
7476 opts.search = opts.filter;
7477 }
7478
7479 return {
7480 search: opts.search || 'none',
7481 order: opts.order || 'current',
7482 page: opts.page || 'all'
7483 };
7484 };
7485
7486
7487 var _selector_first = function ( inst )
7488 {
7489 // Reduce the API instance to the first item found
7490 for ( var i=0, ien=inst.length ; i<ien ; i++ ) {
7491 if ( inst[i].length > 0 ) {
7492 // Assign the first element to the first item in the instance
7493 // and truncate the instance and context
7494 inst[0] = inst[i];
7495 inst.length = 1;
7496 inst.context = [ inst.context[i] ];
7497
7498 return inst;
7499 }
7500 }
7501
7502 // Not found - return an empty instance
7503 inst.length = 0;
7504 return inst;
7505 };
7506
7507
7508 var _selector_row_indexes = function ( settings, opts )
7509 {
7510 var
7511 i, ien, tmp, a=[],
7512 displayFiltered = settings.aiDisplay,
7513 displayMaster = settings.aiDisplayMaster;
7514
7515 var
7516 search = opts.search, // none, applied, removed
7517 order = opts.order, // applied, current, index (original - compatibility with 1.9)
7518 page = opts.page; // all, current
7519
7520 if ( _fnDataSource( settings ) == 'ssp' ) {
7521 // In server-side processing mode, most options are irrelevant since
7522 // rows not shown don't exist and the index order is the applied order
7523 // Removed is a special case - for consistency just return an empty
7524 // array
7525 return search === 'removed' ?
7526 [] :
7527 _range( 0, displayMaster.length );
7528 }
7529 else if ( page == 'current' ) {
7530 // Current page implies that order=current and fitler=applied, since it is
7531 // fairly senseless otherwise, regardless of what order and search actually
7532 // are
7533 for ( i=settings._iDisplayStart, ien=settings.fnDisplayEnd() ; i<ien ; i++ ) {
7534 a.push( displayFiltered[i] );
7535 }
7536 }
7537 else if ( order == 'current' || order == 'applied' ) {
7538 a = search == 'none' ?
7539 displayMaster.slice() : // no search
7540 search == 'applied' ?
7541 displayFiltered.slice() : // applied search
7542 $.map( displayMaster, function (el, i) { // removed search
7543 return $.inArray( el, displayFiltered ) === -1 ? el : null;
7544 } );
7545 }
7546 else if ( order == 'index' || order == 'original' ) {
7547 for ( i=0, ien=settings.aoData.length ; i<ien ; i++ ) {
7548 if ( search == 'none' ) {
7549 a.push( i );
7550 }
7551 else { // applied | removed
7552 tmp = $.inArray( i, displayFiltered );
7553
7554 if ((tmp === -1 && search == 'removed') ||
7555 (tmp >= 0 && search == 'applied') )
7556 {
7557 a.push( i );
7558 }
7559 }
7560 }
7561 }
7562
7563 return a;
7564 };
7565
7566
7567 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
7568 * Rows
7569 *
7570 * {} - no selector - use all available rows
7571 * {integer} - row aoData index
7572 * {node} - TR node
7573 * {string} - jQuery selector to apply to the TR elements
7574 * {array} - jQuery array of nodes, or simply an array of TR nodes
7575 *
7576 */
7577
7578
7579 var __row_selector = function ( settings, selector, opts )
7580 {
7581 return _selector_run( selector, function ( sel ) {
7582 var selInt = _intVal( sel );
7583 var i, ien;
7584
7585 // Short cut - selector is a number and no options provided (default is
7586 // all records, so no need to check if the index is in there, since it
7587 // must be - dev error if the index doesn't exist).
7588 if ( selInt !== null && ! opts ) {
7589 return [ selInt ];
7590 }
7591
7592 var rows = _selector_row_indexes( settings, opts );
7593
7594 if ( selInt !== null && $.inArray( selInt, rows ) !== -1 ) {
7595 // Selector - integer
7596 return [ selInt ];
7597 }
7598 else if ( ! sel ) {
7599 // Selector - none
7600 return rows;
7601 }
7602
7603 // Get nodes in the order from the `rows` array
7604 var nodes = _pluck_order( settings.aoData, rows, 'nTr' );
7605
7606 // Selector - function
7607 if ( typeof sel === 'function' ) {
7608 return $.map( rows, function (idx) {
7609 var row = settings.aoData[ idx ];
7610 return sel( idx, row._aData, row.nTr ) ? idx : null;
7611 } );
7612 }
7613
7614 // Selector - node
7615 if ( sel.nodeName ) {
7616 if ( $.inArray( sel, nodes ) !== -1 ) {
7617 return [ sel._DT_RowIndex ];// sel is a TR node that is in the table
7618 // and DataTables adds a prop for fast lookup
7619 }
7620 }
7621
7622 // Selector - jQuery selector string, array of nodes or jQuery object/
7623 // As jQuery's .filter() allows jQuery objects to be passed in filter,
7624 // it also allows arrays, so this will cope with all three options
7625 return $(nodes)
7626 .filter( sel )
7627 .map( function () {
7628 return this._DT_RowIndex;
7629 } )
7630 .toArray();
7631 } );
7632 };
7633
7634
7635 /**
7636 *
7637 */
7638 _api_register( 'rows()', function ( selector, opts ) {
7639 // argument shifting
7640 if ( selector === undefined ) {
7641 selector = '';
7642 }
7643 else if ( $.isPlainObject( selector ) ) {
7644 opts = selector;
7645 selector = '';
7646 }
7647
7648 opts = _selector_opts( opts );
7649
7650 var inst = this.iterator( 'table', function ( settings ) {
7651 return __row_selector( settings, selector, opts );
7652 } );
7653
7654 // Want argument shifting here and in __row_selector?
7655 inst.selector.rows = selector;
7656 inst.selector.opts = opts;
7657
7658 return inst;
7659 } );
7660
7661
7662 _api_register( 'rows().nodes()', function () {
7663 return this.iterator( 'row', function ( settings, row ) {
7664 return settings.aoData[ row ].nTr || undefined;
7665 } );
7666 } );
7667
7668 _api_register( 'rows().data()', function () {
7669 return this.iterator( true, 'rows', function ( settings, rows ) {
7670 return _pluck_order( settings.aoData, rows, '_aData' );
7671 } );
7672 } );
7673
7674 _api_registerPlural( 'rows().cache()', 'row().cache()', function ( type ) {
7675 return this.iterator( 'row', function ( settings, row ) {
7676 var r = settings.aoData[ row ];
7677 return type === 'search' ? r._aFilterData : r._aSortData;
7678 } );
7679 } );
7680
7681 _api_registerPlural( 'rows().invalidate()', 'row().invalidate()', function ( src ) {
7682 return this.iterator( 'row', function ( settings, row ) {
7683 _fnInvalidateRow( settings, row, src );
7684 } );
7685 } );
7686
7687 _api_registerPlural( 'rows().indexes()', 'row().index()', function () {
7688 return this.iterator( 'row', function ( settings, row ) {
7689 return row;
7690 } );
7691 } );
7692
7693 _api_registerPlural( 'rows().remove()', 'row().remove()', function () {
7694 var that = this;
7695
7696 return this.iterator( 'row', function ( settings, row, thatIdx ) {
7697 var data = settings.aoData;
7698
7699 data.splice( row, 1 );
7700
7701 // Update the _DT_RowIndex parameter on all rows in the table
7702 for ( var i=0, ien=data.length ; i<ien ; i++ ) {
7703 if ( data[i].nTr !== null ) {
7704 data[i].nTr._DT_RowIndex = i;
7705 }
7706 }
7707
7708 // Remove the target row from the search array
7709 var displayIndex = $.inArray( row, settings.aiDisplay );
7710
7711 // Delete from the display arrays
7712 _fnDeleteIndex( settings.aiDisplayMaster, row );
7713 _fnDeleteIndex( settings.aiDisplay, row );
7714 _fnDeleteIndex( that[ thatIdx ], row, false ); // maintain local indexes
7715
7716 // Check for an 'overflow' they case for displaying the table
7717 _fnLengthOverflow( settings );
7718 } );
7719 } );
7720
7721
7722 _api_register( 'rows.add()', function ( rows ) {
7723 var newRows = this.iterator( 'table', function ( settings ) {
7724 var row, i, ien;
7725 var out = [];
7726
7727 for ( i=0, ien=rows.length ; i<ien ; i++ ) {
7728 row = rows[i];
7729
7730 if ( row.nodeName && row.nodeName.toUpperCase() === 'TR' ) {
7731 out.push( _fnAddTr( settings, row )[0] );
7732 }
7733 else {
7734 out.push( _fnAddData( settings, row ) );
7735 }
7736 }
7737
7738 return out;
7739 } );
7740
7741 // Return an Api.rows() extended instance, so rows().nodes() etc can be used
7742 var modRows = this.rows( -1 );
7743 modRows.pop();
7744 modRows.push.apply( modRows, newRows.toArray() );
7745
7746 return modRows;
7747 } );
7748
7749
7750
7751
7752
7753 /**
7754 *
7755 */
7756 _api_register( 'row()', function ( selector, opts ) {
7757 return _selector_first( this.rows( selector, opts ) );
7758 } );
7759
7760
7761 _api_register( 'row().data()', function ( data ) {
7762 var ctx = this.context;
7763
7764 if ( data === undefined ) {
7765 // Get
7766 return ctx.length && this.length ?
7767 ctx[0].aoData[ this[0] ]._aData :
7768 undefined;
7769 }
7770
7771 // Set
7772 ctx[0].aoData[ this[0] ]._aData = data;
7773
7774 // Automatically invalidate
7775 _fnInvalidateRow( ctx[0], this[0], 'data' );
7776
7777 return this;
7778 } );
7779
7780
7781 _api_register( 'row().node()', function () {
7782 var ctx = this.context;
7783
7784 return ctx.length && this.length ?
7785 ctx[0].aoData[ this[0] ].nTr || null :
7786 null;
7787 } );
7788
7789
7790 _api_register( 'row.add()', function ( row ) {
7791 // Allow a jQuery object to be passed in - only a single row is added from
7792 // it though - the first element in the set
7793 if ( row instanceof $ && row.length ) {
7794 row = row[0];
7795 }
7796
7797 var rows = this.iterator( 'table', function ( settings ) {
7798 if ( row.nodeName && row.nodeName.toUpperCase() === 'TR' ) {
7799 return _fnAddTr( settings, row )[0];
7800 }
7801 return _fnAddData( settings, row );
7802 } );
7803
7804 // Return an Api.rows() extended instance, with the newly added row selected
7805 return this.row( rows[0] );
7806 } );
7807
7808
7809
7810 var __details_add = function ( ctx, row, data, klass )
7811 {
7812 // Convert to array of TR elements
7813 var rows = [];
7814 var addRow = function ( r, k ) {
7815 // If we get a TR element, then just add it directly - up to the dev
7816 // to add the correct number of columns etc
7817 if ( r.nodeName && r.nodeName.toLowerCase() === 'tr' ) {
7818 rows.push( r );
7819 }
7820 else {
7821 // Otherwise create a row with a wrapper
7822 var created = $('<tr><td/></tr>').addClass( k );
7823 $('td', created)
7824 .addClass( k )
7825 .html( r )
7826 [0].colSpan = _fnVisbleColumns( ctx );
7827
7828 rows.push( created[0] );
7829 }
7830 };
7831
7832 if ( $.isArray( data ) || data instanceof $ ) {
7833 for ( var i=0, ien=data.length ; i<ien ; i++ ) {
7834 addRow( data[i], klass );
7835 }
7836 }
7837 else {
7838 addRow( data, klass );
7839 }
7840
7841 if ( row._details ) {
7842 row._details.remove();
7843 }
7844
7845 row._details = $(rows);
7846
7847 // If the children were already shown, that state should be retained
7848 if ( row._detailsShow ) {
7849 row._details.insertAfter( row.nTr );
7850 }
7851 };
7852
7853
7854 var __details_remove = function ( api, idx )
7855 {
7856 var ctx = api.context;
7857
7858 if ( ctx.length ) {
7859 var row = ctx[0].aoData[ idx !== undefined ? idx : api[0] ];
7860
7861 if ( row._details ) {
7862 row._details.remove();
7863
7864 row._detailsShow = undefined;
7865 row._details = undefined;
7866 }
7867 }
7868 };
7869
7870
7871 var __details_display = function ( api, show ) {
7872 var ctx = api.context;
7873
7874 if ( ctx.length && api.length ) {
7875 var row = ctx[0].aoData[ api[0] ];
7876
7877 if ( row._details ) {
7878 row._detailsShow = show;
7879
7880 if ( show ) {
7881 row._details.insertAfter( row.nTr );
7882 }
7883 else {
7884 row._details.detach();
7885 }
7886
7887 __details_events( ctx[0] );
7888 }
7889 }
7890 };
7891
7892
7893 var __details_events = function ( settings )
7894 {
7895 var api = new _Api( settings );
7896 var namespace = '.dt.DT_details';
7897 var drawEvent = 'draw'+namespace;
7898 var colvisEvent = 'column-visibility'+namespace;
7899 var destroyEvent = 'destroy'+namespace;
7900 var data = settings.aoData;
7901
7902 api.off( drawEvent +' '+ colvisEvent +' '+ destroyEvent );
7903
7904 if ( _pluck( data, '_details' ).length > 0 ) {
7905 // On each draw, insert the required elements into the document
7906 api.on( drawEvent, function ( e, ctx ) {
7907 if ( settings !== ctx ) {
7908 return;
7909 }
7910
7911 api.rows( {page:'current'} ).eq(0).each( function (idx) {
7912 // Internal data grab
7913 var row = data[ idx ];
7914
7915 if ( row._detailsShow ) {
7916 row._details.insertAfter( row.nTr );
7917 }
7918 } );
7919 } );
7920
7921 // Column visibility change - update the colspan
7922 api.on( colvisEvent, function ( e, ctx, idx, vis ) {
7923 if ( settings !== ctx ) {
7924 return;
7925 }
7926
7927 // Update the colspan for the details rows (note, only if it already has
7928 // a colspan)
7929 var row, visible = _fnVisbleColumns( ctx );
7930
7931 for ( var i=0, ien=data.length ; i<ien ; i++ ) {
7932 row = data[i];
7933
7934 if ( row._details ) {
7935 row._details.children('td[colspan]').attr('colspan', visible );
7936 }
7937 }
7938 } );
7939
7940 // Table destroyed - nuke any child rows
7941 api.on( destroyEvent, function ( e, ctx ) {
7942 if ( settings !== ctx ) {
7943 return;
7944 }
7945
7946 for ( var i=0, ien=data.length ; i<ien ; i++ ) {
7947 if ( data[i]._details ) {
7948 __details_remove( api, i );
7949 }
7950 }
7951 } );
7952 }
7953 };
7954
7955 // Strings for the method names to help minification
7956 var _emp = '';
7957 var _child_obj = _emp+'row().child';
7958 var _child_mth = _child_obj+'()';
7959
7960 // data can be:
7961 // tr
7962 // string
7963 // jQuery or array of any of the above
7964 _api_register( _child_mth, function ( data, klass ) {
7965 var ctx = this.context;
7966
7967 if ( data === undefined ) {
7968 // get
7969 return ctx.length && this.length ?
7970 ctx[0].aoData[ this[0] ]._details :
7971 undefined;
7972 }
7973 else if ( data === true ) {
7974 // show
7975 this.child.show();
7976 }
7977 else if ( data === false ) {
7978 // remove
7979 __details_remove( this );
7980 }
7981 else if ( ctx.length && this.length ) {
7982 // set
7983 __details_add( ctx[0], ctx[0].aoData[ this[0] ], data, klass );
7984 }
7985
7986 return this;
7987 } );
7988
7989
7990 _api_register( [
7991 _child_obj+'.show()',
7992 _child_mth+'.show()' // only when `child()` was called with parameters (without
7993 ], function ( show ) { // it returns an object and this method is not executed)
7994 __details_display( this, true );
7995 return this;
7996 } );
7997
7998
7999 _api_register( [
8000 _child_obj+'.hide()',
8001 _child_mth+'.hide()' // only when `child()` was called with parameters (without
8002 ], function () { // it returns an object and this method is not executed)
8003 __details_display( this, false );
8004 return this;
8005 } );
8006
8007
8008 _api_register( [
8009 _child_obj+'.remove()',
8010 _child_mth+'.remove()' // only when `child()` was called with parameters (without
8011 ], function () { // it returns an object and this method is not executed)
8012 __details_remove( this );
8013 return this;
8014 } );
8015
8016
8017 _api_register( _child_obj+'.isShown()', function () {
8018 var ctx = this.context;
8019
8020 if ( ctx.length && this.length ) {
8021 // _detailsShown as false or undefined will fall through to return false
8022 return ctx[0].aoData[ this[0] ]._detailsShow || false;
8023 }
8024 return false;
8025 } );
8026
8027
8028
8029 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
8030 * Columns
8031 *
8032 * {integer} - column index (>=0 count from left, <0 count from right)
8033 * "{integer}:visIdx" - visible column index (i.e. translate to column index) (>=0 count from left, <0 count from right)
8034 * "{integer}:visible" - alias for {integer}:visIdx (>=0 count from left, <0 count from right)
8035 * "{string}:name" - column name
8036 * "{string}" - jQuery selector on column header nodes
8037 *
8038 */
8039
8040 // can be an array of these items, comma separated list, or an array of comma
8041 // separated lists
8042
8043 var __re_column_selector = /^(.+):(name|visIdx|visible)$/;
8044
8045
8046 // r1 and r2 are redundant - but it means that the parameters match for the
8047 // iterator callback in columns().data()
8048 var __columnData = function ( settings, column, r1, r2, rows ) {
8049 var a = [];
8050 for ( var row=0, ien=rows.length ; row<ien ; row++ ) {
8051 a.push( _fnGetCellData( settings, rows[row], column ) );
8052 }
8053 return a;
8054 };
8055
8056
8057 var __column_selector = function ( settings, selector, opts )
8058 {
8059 var
8060 columns = settings.aoColumns,
8061 names = _pluck( columns, 'sName' ),
8062 nodes = _pluck( columns, 'nTh' );
8063
8064 return _selector_run( selector, function ( s ) {
8065 var selInt = _intVal( s );
8066
8067 // Selector - all
8068 if ( s === '' ) {
8069 return _range( columns.length );
8070 }
8071
8072 // Selector - index
8073 if ( selInt !== null ) {
8074 return [ selInt >= 0 ?
8075 selInt : // Count from left
8076 columns.length + selInt // Count from right (+ because its a negative value)
8077 ];
8078 }
8079
8080 // Selector = function
8081 if ( typeof s === 'function' ) {
8082 var rows = _selector_row_indexes( settings, opts );
8083
8084 return $.map( columns, function (col, idx) {
8085 return s(
8086 idx,
8087 __columnData( settings, idx, 0, 0, rows ),
8088 nodes[ idx ]
8089 ) ? idx : null;
8090 } );
8091 }
8092
8093 // jQuery or string selector
8094 var match = typeof s === 'string' ?
8095 s.match( __re_column_selector ) :
8096 '';
8097
8098 if ( match ) {
8099 switch( match[2] ) {
8100 case 'visIdx':
8101 case 'visible':
8102 var idx = parseInt( match[1], 10 );
8103 // Visible index given, convert to column index
8104 if ( idx < 0 ) {
8105 // Counting from the right
8106 var visColumns = $.map( columns, function (col,i) {
8107 return col.bVisible ? i : null;
8108 } );
8109 return [ visColumns[ visColumns.length + idx ] ];
8110 }
8111 // Counting from the left
8112 return [ _fnVisibleToColumnIndex( settings, idx ) ];
8113
8114 case 'name':
8115 // match by name. `names` is column index complete and in order
8116 return $.map( names, function (name, i) {
8117 return name === match[1] ? i : null;
8118 } );
8119 }
8120 }
8121 else {
8122 // jQuery selector on the TH elements for the columns
8123 return $( nodes )
8124 .filter( s )
8125 .map( function () {
8126 return $.inArray( this, nodes ); // `nodes` is column index complete and in order
8127 } )
8128 .toArray();
8129 }
8130 } );
8131 };
8132
8133
8134 var __setColumnVis = function ( settings, column, vis, recalc ) {
8135 var
8136 cols = settings.aoColumns,
8137 col = cols[ column ],
8138 data = settings.aoData,
8139 row, cells, i, ien, tr;
8140
8141 // Get
8142 if ( vis === undefined ) {
8143 return col.bVisible;
8144 }
8145
8146 // Set
8147 // No change
8148 if ( col.bVisible === vis ) {
8149 return;
8150 }
8151
8152 if ( vis ) {
8153 // Insert column
8154 // Need to decide if we should use appendChild or insertBefore
8155 var insertBefore = $.inArray( true, _pluck(cols, 'bVisible'), column+1 );
8156
8157 for ( i=0, ien=data.length ; i<ien ; i++ ) {
8158 tr = data[i].nTr;
8159 cells = data[i].anCells;
8160
8161 if ( tr ) {
8162 // insertBefore can act like appendChild if 2nd arg is null
8163 tr.insertBefore( cells[ column ], cells[ insertBefore ] || null );
8164 }
8165 }
8166 }
8167 else {
8168 // Remove column
8169 $( _pluck( settings.aoData, 'anCells', column ) ).detach();
8170 }
8171
8172 // Common actions
8173 col.bVisible = vis;
8174 _fnDrawHead( settings, settings.aoHeader );
8175 _fnDrawHead( settings, settings.aoFooter );
8176
8177 if ( recalc === undefined || recalc ) {
8178 // Automatically adjust column sizing
8179 _fnAdjustColumnSizing( settings );
8180
8181 // Realign columns for scrolling
8182 if ( settings.oScroll.sX || settings.oScroll.sY ) {
8183 _fnScrollDraw( settings );
8184 }
8185 }
8186
8187 _fnCallbackFire( settings, null, 'column-visibility', [settings, column, vis] );
8188
8189 _fnSaveState( settings );
8190 };
8191
8192
8193 /**
8194 *
8195 */
8196 _api_register( 'columns()', function ( selector, opts ) {
8197 // argument shifting
8198 if ( selector === undefined ) {
8199 selector = '';
8200 }
8201 else if ( $.isPlainObject( selector ) ) {
8202 opts = selector;
8203 selector = '';
8204 }
8205
8206 opts = _selector_opts( opts );
8207
8208 var inst = this.iterator( 'table', function ( settings ) {
8209 return __column_selector( settings, selector, opts );
8210 } );
8211
8212 // Want argument shifting here and in _row_selector?
8213 inst.selector.cols = selector;
8214 inst.selector.opts = opts;
8215
8216 return inst;
8217 } );
8218
8219
8220 /**
8221 *
8222 */
8223 _api_registerPlural( 'columns().header()', 'column().header()', function ( selector, opts ) {
8224 return this.iterator( 'column', function ( settings, column ) {
8225 return settings.aoColumns[column].nTh;
8226 } );
8227 } );
8228
8229
8230 /**
8231 *
8232 */
8233 _api_registerPlural( 'columns().footer()', 'column().footer()', function ( selector, opts ) {
8234 return this.iterator( 'column', function ( settings, column ) {
8235 return settings.aoColumns[column].nTf;
8236 } );
8237 } );
8238
8239
8240 /**
8241 *
8242 */
8243 _api_registerPlural( 'columns().data()', 'column().data()', function () {
8244 return this.iterator( 'column-rows', __columnData );
8245 } );
8246
8247
8248 _api_registerPlural( 'columns().dataSrc()', 'column().dataSrc()', function () {
8249 return this.iterator( 'column', function ( settings, column ) {
8250 return settings.aoColumns[column].mData;
8251 } );
8252 } );
8253
8254
8255 _api_registerPlural( 'columns().cache()', 'column().cache()', function ( type ) {
8256 return this.iterator( 'column-rows', function ( settings, column, i, j, rows ) {
8257 return _pluck_order( settings.aoData, rows,
8258 type === 'search' ? '_aFilterData' : '_aSortData', column
8259 );
8260 } );
8261 } );
8262
8263
8264 _api_registerPlural( 'columns().nodes()', 'column().nodes()', function () {
8265 return this.iterator( 'column-rows', function ( settings, column, i, j, rows ) {
8266 return _pluck_order( settings.aoData, rows, 'anCells', column ) ;
8267 } );
8268 } );
8269
8270
8271
8272 _api_registerPlural( 'columns().visible()', 'column().visible()', function ( vis, calc ) {
8273 return this.iterator( 'column', function ( settings, column ) {
8274 return vis === undefined ?
8275 settings.aoColumns[ column ].bVisible :
8276 __setColumnVis( settings, column, vis, calc );
8277 } );
8278 } );
8279
8280
8281
8282 _api_registerPlural( 'columns().indexes()', 'column().index()', function ( type ) {
8283 return this.iterator( 'column', function ( settings, column ) {
8284 return type === 'visible' ?
8285 _fnColumnIndexToVisible( settings, column ) :
8286 column;
8287 } );
8288 } );
8289
8290
8291 // _api_register( 'columns().show()', function () {
8292 // var selector = this.selector;
8293 // return this.columns( selector.cols, selector.opts ).visible( true );
8294 // } );
8295
8296
8297 // _api_register( 'columns().hide()', function () {
8298 // var selector = this.selector;
8299 // return this.columns( selector.cols, selector.opts ).visible( false );
8300 // } );
8301
8302
8303
8304 _api_register( 'columns.adjust()', function () {
8305 return this.iterator( 'table', function ( settings ) {
8306 _fnAdjustColumnSizing( settings );
8307 } );
8308 } );
8309
8310
8311 // Convert from one column index type, to another type
8312 _api_register( 'column.index()', function ( type, idx ) {
8313 if ( this.context.length !== 0 ) {
8314 var ctx = this.context[0];
8315
8316 if ( type === 'fromVisible' || type === 'toData' ) {
8317 return _fnVisibleToColumnIndex( ctx, idx );
8318 }
8319 else if ( type === 'fromData' || type === 'toVisible' ) {
8320 return _fnColumnIndexToVisible( ctx, idx );
8321 }
8322 }
8323 } );
8324
8325
8326 _api_register( 'column()', function ( selector, opts ) {
8327 return _selector_first( this.columns( selector, opts ) );
8328 } );
8329
8330
8331
8332
8333 var __cell_selector = function ( settings, selector, opts )
8334 {
8335 var data = settings.aoData;
8336 var rows = _selector_row_indexes( settings, opts );
8337 var cells = _pluck_order( data, rows, 'anCells' );
8338 var allCells = $( [].concat.apply([], cells) );
8339 var row;
8340 var columns = settings.aoColumns.length;
8341 var a, i, ien, j, o, host;
8342
8343 return _selector_run( selector, function ( s ) {
8344 var fnSelector = typeof s === 'function';
8345
8346 if ( s === null || s === undefined || fnSelector ) {
8347 // All cells and function selectors
8348 a = [];
8349
8350 for ( i=0, ien=rows.length ; i<ien ; i++ ) {
8351 row = rows[i];
8352
8353 for ( j=0 ; j<columns ; j++ ) {
8354 o = {
8355 row: row,
8356 column: j
8357 };
8358
8359 if ( fnSelector ) {
8360 // Selector - function
8361 host = settings.aoData[ row ];
8362
8363 if ( s( o, _fnGetCellData(settings, row, j), host.anCells[j] ) ) {
8364 a.push( o );
8365 }
8366 }
8367 else {
8368 // Selector - all
8369 a.push( o );
8370 }
8371 }
8372 }
8373
8374 return a;
8375 }
8376
8377 // Selector - index
8378 if ( $.isPlainObject( s ) ) {
8379 return [s];
8380 }
8381
8382 // Selector - jQuery filtered cells
8383 return allCells
8384 .filter( s )
8385 .map( function (i, el) {
8386 row = el.parentNode._DT_RowIndex;
8387
8388 return {
8389 row: row,
8390 column: $.inArray( el, data[ row ].anCells )
8391 };
8392 } )
8393 .toArray();
8394 } );
8395 };
8396
8397
8398
8399
8400 _api_register( 'cells()', function ( rowSelector, columnSelector, opts ) {
8401 // Argument shifting
8402 if ( $.isPlainObject( rowSelector ) ) {
8403 // Indexes
8404 if ( typeof rowSelector.row !== undefined ) {
8405 opts = columnSelector;
8406 columnSelector = null;
8407 }
8408 else {
8409 opts = rowSelector;
8410 rowSelector = null;
8411 }
8412 }
8413 if ( $.isPlainObject( columnSelector ) ) {
8414 opts = columnSelector;
8415 columnSelector = null;
8416 }
8417
8418 // Cell selector
8419 if ( columnSelector === null || columnSelector === undefined ) {
8420 return this.iterator( 'table', function ( settings ) {
8421 return __cell_selector( settings, rowSelector, _selector_opts( opts ) );
8422 } );
8423 }
8424
8425 // Row + column selector
8426 var columns = this.columns( columnSelector, opts );
8427 var rows = this.rows( rowSelector, opts );
8428 var a, i, ien, j, jen;
8429
8430 var cells = this.iterator( 'table', function ( settings, idx ) {
8431 a = [];
8432
8433 for ( i=0, ien=rows[idx].length ; i<ien ; i++ ) {
8434 for ( j=0, jen=columns[idx].length ; j<jen ; j++ ) {
8435 a.push( {
8436 row: rows[idx][i],
8437 column: columns[idx][j]
8438 } );
8439 }
8440 }
8441
8442 return a;
8443 } );
8444
8445 $.extend( cells.selector, {
8446 cols: columnSelector,
8447 rows: rowSelector,
8448 opts: opts
8449 } );
8450
8451 return cells;
8452 } );
8453
8454
8455 _api_registerPlural( 'cells().nodes()', 'cell().node()', function () {
8456 return this.iterator( 'cell', function ( settings, row, column ) {
8457 return settings.aoData[ row ].anCells[ column ];
8458 } );
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 } );
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 } );
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 } );
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 } );
8493 } );
8494
8495
8496 _api_register( [
8497 'cells().invalidate()',
8498 'cell().invalidate()'
8499 ], function ( src ) {
8500 var selector = this.selector;
8501
8502 // Use the rows method of the instance to perform the invalidation, rather
8503 // than doing it here. This avoids needing to handle duplicate rows from
8504 // the cells.
8505 this.rows( selector.rows, selector.opts ).invalidate( src );
8506
8507 return this;
8508 } );
8509
8510
8511
8512
8513 _api_register( 'cell()', function ( rowSelector, columnSelector, opts ) {
8514 return _selector_first( this.cells( rowSelector, columnSelector, opts ) );
8515 } );
8516
8517
8518
8519 _api_register( 'cell().data()', function ( data ) {
8520 var ctx = this.context;
8521 var cell = this[0];
8522
8523 if ( data === undefined ) {
8524 // Get
8525 return ctx.length && cell.length ?
8526 _fnGetCellData( ctx[0], cell[0].row, cell[0].column ) :
8527 undefined;
8528 }
8529
8530 // Set
8531 _fnSetCellData( ctx[0], cell[0].row, cell[0].column, data );
8532 _fnInvalidateRow( ctx[0], cell[0].row, 'data', cell[0].column );
8533
8534 return this;
8535 } );
8536
8537
8538
8539 /**
8540 * Get current ordering (sorting) that has been applied to the table.
8541 *
8542 * @returns {array} 2D array containing the sorting information for the first
8543 * table in the current context. Each element in the parent array represents
8544 * a column being sorted upon (i.e. multi-sorting with two columns would have
8545 * 2 inner arrays). The inner arrays may have 2 or 3 elements. The first is
8546 * the column index that the sorting condition applies to, the second is the
8547 * direction of the sort (`desc` or `asc`) and, optionally, the third is the
8548 * index of the sorting order from the `column.sorting` initialisation array.
8549 *//**
8550 * Set the ordering for the table.
8551 *
8552 * @param {integer} order Column index to sort upon.
8553 * @param {string} direction Direction of the sort to be applied (`asc` or `desc`)
8554 * @returns {DataTables.Api} this
8555 *//**
8556 * Set the ordering for the table.
8557 *
8558 * @param {array} order 1D array of sorting information to be applied.
8559 * @param {array} [...] Optional additional sorting conditions
8560 * @returns {DataTables.Api} this
8561 *//**
8562 * Set the ordering for the table.
8563 *
8564 * @param {array} order 2D array of sorting information to be applied.
8565 * @returns {DataTables.Api} this
8566 */
8567 _api_register( 'order()', function ( order, dir ) {
8568 var ctx = this.context;
8569
8570 if ( order === undefined ) {
8571 // get
8572 return ctx.length !== 0 ?
8573 ctx[0].aaSorting :
8574 undefined;
8575 }
8576
8577 // set
8578 if ( typeof order === 'number' ) {
8579 // Simple column / direction passed in
8580 order = [ [ order, dir ] ];
8581 }
8582 else if ( ! $.isArray( order[0] ) ) {
8583 // Arguments passed in (list of 1D arrays)
8584 order = Array.prototype.slice.call( arguments );
8585 }
8586 // otherwise a 2D array was passed in
8587
8588 return this.iterator( 'table', function ( settings ) {
8589 settings.aaSorting = order.slice();
8590 } );
8591 } );
8592
8593
8594 /**
8595 * Attach a sort listener to an element for a given column
8596 *
8597 * @param {node|jQuery|string} node Identifier for the element(s) to attach the
8598 * listener to. This can take the form of a single DOM node, a jQuery
8599 * collection of nodes or a jQuery selector which will identify the node(s).
8600 * @param {integer} column the column that a click on this node will sort on
8601 * @param {function} [callback] callback function when sort is run
8602 * @returns {DataTables.Api} this
8603 */
8604 _api_register( 'order.listener()', function ( node, column, callback ) {
8605 return this.iterator( 'table', function ( settings ) {
8606 _fnSortAttachListener( settings, node, column, callback );
8607 } );
8608 } );
8609
8610
8611 // Order by the selected column(s)
8612 _api_register( [
8613 'columns().order()',
8614 'column().order()'
8615 ], function ( dir ) {
8616 var that = this;
8617
8618 return this.iterator( 'table', function ( settings, i ) {
8619 var sort = [];
8620
8621 $.each( that[i], function (j, col) {
8622 sort.push( [ col, dir ] );
8623 } );
8624
8625 settings.aaSorting = sort;
8626 } );
8627 } );
8628
8629
8630
8631 _api_register( 'search()', function ( input, regex, smart, caseInsen ) {
8632 var ctx = this.context;
8633
8634 if ( input === undefined ) {
8635 // get
8636 return ctx.length !== 0 ?
8637 ctx[0].oPreviousSearch.sSearch :
8638 undefined;
8639 }
8640
8641 // set
8642 return this.iterator( 'table', function ( settings ) {
8643 if ( ! settings.oFeatures.bFilter ) {
8644 return;
8645 }
8646
8647 _fnFilterComplete( settings, $.extend( {}, settings.oPreviousSearch, {
8648 "sSearch": input+"",
8649 "bRegex": regex === null ? false : regex,
8650 "bSmart": smart === null ? true : smart,
8651 "bCaseInsensitive": caseInsen === null ? true : caseInsen
8652 } ), 1 );
8653 } );
8654 } );
8655
8656
8657 _api_registerPlural(
8658 'columns().search()',
8659 'column().search()',
8660 function ( input, regex, smart, caseInsen ) {
8661 return this.iterator( 'column', function ( settings, column ) {
8662 var preSearch = settings.aoPreSearchCols;
8663
8664 if ( input === undefined ) {
8665 // get
8666 return preSearch[ column ].sSearch;
8667 }
8668
8669 // set
8670 if ( ! settings.oFeatures.bFilter ) {
8671 return;
8672 }
8673
8674 $.extend( preSearch[ column ], {
8675 "sSearch": input+"",
8676 "bRegex": regex === null ? false : regex,
8677 "bSmart": smart === null ? true : smart,
8678 "bCaseInsensitive": caseInsen === null ? true : caseInsen
8679 } );
8680
8681 _fnFilterComplete( settings, settings.oPreviousSearch, 1 );
8682 } );
8683 }
8684 );
8685
8686 /*
8687 * State API methods
8688 */
8689
8690 _api_register( 'state()', function () {
8691 return this.context.length ?
8692 this.context[0].oSavedState :
8693 null;
8694 } );
8695
8696
8697 _api_register( 'state.clear()', function () {
8698 return this.iterator( 'table', function ( settings ) {
8699 // Save an empty object
8700 settings.fnStateSaveCallback.call( settings.oInstance, settings, {} );
8701 } );
8702 } );
8703
8704
8705 _api_register( 'state.loaded()', function () {
8706 return this.context.length ?
8707 this.context[0].oLoadedState :
8708 null;
8709 } );
8710
8711
8712 _api_register( 'state.save()', function () {
8713 return this.iterator( 'table', function ( settings ) {
8714 _fnSaveState( settings );
8715 } );
8716 } );
8717
8718
8719
8720 /**
8721 * Provide a common method for plug-ins to check the version of DataTables being
8722 * used, in order to ensure compatibility.
8723 *
8724 * @param {string} version Version string to check for, in the format "X.Y.Z".
8725 * Note that the formats "X" and "X.Y" are also acceptable.
8726 * @returns {boolean} true if this version of DataTables is greater or equal to
8727 * the required version, or false if this version of DataTales is not
8728 * suitable
8729 * @static
8730 * @dtopt API-Static
8731 *
8732 * @example
8733 * alert( $.fn.dataTable.versionCheck( '1.9.0' ) );
8734 */
8735 DataTable.versionCheck = DataTable.fnVersionCheck = function( version )
8736 {
8737 var aThis = DataTable.version.split('.');
8738 var aThat = version.split('.');
8739 var iThis, iThat;
8740
8741 for ( var i=0, iLen=aThat.length ; i<iLen ; i++ ) {
8742 iThis = parseInt( aThis[i], 10 ) || 0;
8743 iThat = parseInt( aThat[i], 10 ) || 0;
8744
8745 // Parts are the same, keep comparing
8746 if (iThis === iThat) {
8747 continue;
8748 }
8749
8750 // Parts are different, return immediately
8751 return iThis > iThat;
8752 }
8753
8754 return true;
8755 };
8756
8757
8758 /**
8759 * Check if a `<table>` node is a DataTable table already or not.
8760 *
8761 * @param {node|jquery|string} table Table node, jQuery object or jQuery
8762 * selector for the table to test. Note that if more than more than one
8763 * table is passed on, only the first will be checked
8764 * @returns {boolean} true the table given is a DataTable, or false otherwise
8765 * @static
8766 * @dtopt API-Static
8767 *
8768 * @example
8769 * if ( ! $.fn.DataTable.isDataTable( '#example' ) ) {
8770 * $('#example').dataTable();
8771 * }
8772 */
8773 DataTable.isDataTable = DataTable.fnIsDataTable = function ( table )
8774 {
8775 var t = $(table).get(0);
8776 var is = false;
8777
8778 $.each( DataTable.settings, function (i, o) {
8779 if ( o.nTable === t || o.nScrollHead === t || o.nScrollFoot === t ) {
8780 is = true;
8781 }
8782 } );
8783
8784 return is;
8785 };
8786
8787
8788 /**
8789 * Get all DataTable tables that have been initialised - optionally you can
8790 * select to get only currently visible tables.
8791 *
8792 * @param {boolean} [visible=false] Flag to indicate if you want all (default)
8793 * or visible tables only.
8794 * @returns {array} Array of `table` nodes (not DataTable instances) which are
8795 * DataTables
8796 * @static
8797 * @dtopt API-Static
8798 *
8799 * @example
8800 * $.each( $.fn.dataTable.tables(true), function () {
8801 * $(table).DataTable().columns.adjust();
8802 * } );
8803 */
8804 DataTable.tables = DataTable.fnTables = function ( visible )
8805 {
8806 return $.map( DataTable.settings, function (o) {
8807 if ( !visible || (visible && $(o.nTable).is(':visible')) ) {
8808 return o.nTable;
8809 }
8810 } );
8811 };
8812
8813
8814 /**
8815 * DataTables utility methods
8816 *
8817 * This namespace provides helper methods that DataTables uses internally to
8818 * create a DataTable, but which are not exclusively used only for DataTables.
8819 * These methods can be used by extension authors to save the duplication of
8820 * code.
8821 *
8822 * @namespace
8823 */
8824 DataTable.util = {
8825 /**
8826 * Throttle the calls to a function. Arguments and context are maintained
8827 * for the throttled function.
8828 *
8829 * @param {function} fn Function to be called
8830 * @param {integer} freq Call frequency in mS
8831 * @return {function} Wrapped function
8832 */
8833 throttle: _fnThrottle
8834 };
8835
8836
8837 /**
8838 * Convert from camel case parameters to Hungarian notation. This is made public
8839 * for the extensions to provide the same ability as DataTables core to accept
8840 * either the 1.9 style Hungarian notation, or the 1.10+ style camelCase
8841 * parameters.
8842 *
8843 * @param {object} src The model object which holds all parameters that can be
8844 * mapped.
8845 * @param {object} user The object to convert from camel case to Hungarian.
8846 * @param {boolean} force When set to `true`, properties which already have a
8847 * Hungarian value in the `user` object will be overwritten. Otherwise they
8848 * won't be.
8849 */
8850 DataTable.camelToHungarian = _fnCamelToHungarian;
8851
8852
8853
8854 /**
8855 *
8856 */
8857 _api_register( '$()', function ( selector, opts ) {
8858 var
8859 rows = this.rows( opts ).nodes(), // Get all rows
8860 jqRows = $(rows);
8861
8862 return $( [].concat(
8863 jqRows.filter( selector ).toArray(),
8864 jqRows.find( selector ).toArray()
8865 ) );
8866 } );
8867
8868
8869 // jQuery functions to operate on the tables
8870 $.each( [ 'on', 'one', 'off' ], function (i, key) {
8871 _api_register( key+'()', function ( /* event, handler */ ) {
8872 var args = Array.prototype.slice.call(arguments);
8873
8874 // Add the `dt` namespace automatically if it isn't already present
8875 if ( ! args[0].match(/\.dt\b/) ) {
8876 args[0] += '.dt';
8877 }
8878
8879 var inst = $( this.tables().nodes() );
8880 inst[key].apply( inst, args );
8881 return this;
8882 } );
8883 } );
8884
8885
8886 _api_register( 'clear()', function () {
8887 return this.iterator( 'table', function ( settings ) {
8888 _fnClearTable( settings );
8889 } );
8890 } );
8891
8892
8893 _api_register( 'settings()', function () {
8894 return new _Api( this.context, this.context );
8895 } );
8896
8897
8898 _api_register( 'data()', function () {
8899 return this.iterator( 'table', function ( settings ) {
8900 return _pluck( settings.aoData, '_aData' );
8901 } ).flatten();
8902 } );
8903
8904
8905 _api_register( 'destroy()', function ( remove ) {
8906 remove = remove || false;
8907
8908 return this.iterator( 'table', function ( settings ) {
8909 var orig = settings.nTableWrapper.parentNode;
8910 var classes = settings.oClasses;
8911 var table = settings.nTable;
8912 var tbody = settings.nTBody;
8913 var thead = settings.nTHead;
8914 var tfoot = settings.nTFoot;
8915 var jqTable = $(table);
8916 var jqTbody = $(tbody);
8917 var jqWrapper = $(settings.nTableWrapper);
8918 var rows = $.map( settings.aoData, function (r) { return r.nTr; } );
8919 var i, ien;
8920
8921 // Flag to note that the table is currently being destroyed - no action
8922 // should be taken
8923 settings.bDestroying = true;
8924
8925 // Fire off the destroy callbacks for plug-ins etc
8926 _fnCallbackFire( settings, "aoDestroyCallback", "destroy", [settings] );
8927
8928 // If not being removed from the document, make all columns visible
8929 if ( ! remove ) {
8930 new _Api( settings ).columns().visible( true );
8931 }
8932
8933 // Blitz all `DT` namespaced events (these are internal events, the
8934 // lowercase, `dt` events are user subscribed and they are responsible
8935 // for removing them
8936 jqWrapper.unbind('.DT').find(':not(tbody *)').unbind('.DT');
8937 $(window).unbind('.DT-'+settings.sInstance);
8938
8939 // When scrolling we had to break the table up - restore it
8940 if ( table != thead.parentNode ) {
8941 jqTable.children('thead').detach();
8942 jqTable.append( thead );
8943 }
8944
8945 if ( tfoot && table != tfoot.parentNode ) {
8946 jqTable.children('tfoot').detach();
8947 jqTable.append( tfoot );
8948 }
8949
8950 // Remove the DataTables generated nodes, events and classes
8951 jqTable.detach();
8952 jqWrapper.detach();
8953
8954 settings.aaSorting = [];
8955 settings.aaSortingFixed = [];
8956 _fnSortingClasses( settings );
8957
8958 $( rows ).removeClass( settings.asStripeClasses.join(' ') );
8959
8960 $('th, td', thead).removeClass( classes.sSortable+' '+
8961 classes.sSortableAsc+' '+classes.sSortableDesc+' '+classes.sSortableNone
8962 );
8963
8964 if ( settings.bJUI ) {
8965 $('th span.'+classes.sSortIcon+ ', td span.'+classes.sSortIcon, thead).detach();
8966 $('th, td', thead).each( function () {
8967 var wrapper = $('div.'+classes.sSortJUIWrapper, this);
8968 $(this).append( wrapper.contents() );
8969 wrapper.detach();
8970 } );
8971 }
8972
8973 if ( ! remove && orig ) {
8974 // insertBefore acts like appendChild if !arg[1]
8975 orig.insertBefore( table, settings.nTableReinsertBefore );
8976 }
8977
8978 // Add the TR elements back into the table in their original order
8979 jqTbody.children().detach();
8980 jqTbody.append( rows );
8981
8982 // Restore the width of the original table - was read from the style property,
8983 // so we can restore directly to that
8984 jqTable
8985 .css( 'width', settings.sDestroyWidth )
8986 .removeClass( classes.sTable );
8987
8988 // If the were originally stripe classes - then we add them back here.
8989 // Note this is not fool proof (for example if not all rows had stripe
8990 // classes - but it's a good effort without getting carried away
8991 ien = settings.asDestroyStripes.length;
8992
8993 if ( ien ) {
8994 jqTbody.children().each( function (i) {
8995 $(this).addClass( settings.asDestroyStripes[i % ien] );
8996 } );
8997 }
8998
8999 /* Remove the settings object from the settings array */
9000 var idx = $.inArray( settings, DataTable.settings );
9001 if ( idx !== -1 ) {
9002 DataTable.settings.splice( idx, 1 );
9003 }
9004 } );
9005 } );
9006
9007
9008 /**
9009 * Version string for plug-ins to check compatibility. Allowed format is
9010 * `a.b.c-d` where: a:int, b:int, c:int, d:string(dev|beta|alpha). `d` is used
9011 * only for non-release builds. See http://semver.org/ for more information.
9012 * @member
9013 * @type string
9014 * @default Version number
9015 */
9016 DataTable.version = "1.10.3";
9017
9018 /**
9019 * Private data store, containing all of the settings objects that are
9020 * created for the tables on a given page.
9021 *
9022 * Note that the `DataTable.settings` object is aliased to
9023 * `jQuery.fn.dataTableExt` through which it may be accessed and
9024 * manipulated, or `jQuery.fn.dataTable.settings`.
9025 * @member
9026 * @type array
9027 * @default []
9028 * @private
9029 */
9030 DataTable.settings = [];
9031
9032 /**
9033 * Object models container, for the various models that DataTables has
9034 * available to it. These models define the objects that are used to hold
9035 * the active state and configuration of the table.
9036 * @namespace
9037 */
9038 DataTable.models = {};
9039
9040
9041
9042 /**
9043 * Template object for the way in which DataTables holds information about
9044 * search information for the global filter and individual column filters.
9045 * @namespace
9046 */
9047 DataTable.models.oSearch = {
9048 /**
9049 * Flag to indicate if the filtering should be case insensitive or not
9050 * @type boolean
9051 * @default true
9052 */
9053 "bCaseInsensitive": true,
9054
9055 /**
9056 * Applied search term
9057 * @type string
9058 * @default <i>Empty string</i>
9059 */
9060 "sSearch": "",
9061
9062 /**
9063 * Flag to indicate if the search term should be interpreted as a
9064 * regular expression (true) or not (false) and therefore and special
9065 * regex characters escaped.
9066 * @type boolean
9067 * @default false
9068 */
9069 "bRegex": false,
9070
9071 /**
9072 * Flag to indicate if DataTables is to use its smart filtering or not.
9073 * @type boolean
9074 * @default true
9075 */
9076 "bSmart": true
9077 };
9078
9079
9080
9081
9082 /**
9083 * Template object for the way in which DataTables holds information about
9084 * each individual row. This is the object format used for the settings
9085 * aoData array.
9086 * @namespace
9087 */
9088 DataTable.models.oRow = {
9089 /**
9090 * TR element for the row
9091 * @type node
9092 * @default null
9093 */
9094 "nTr": null,
9095
9096 /**
9097 * Array of TD elements for each row. This is null until the row has been
9098 * created.
9099 * @type array nodes
9100 * @default []
9101 */
9102 "anCells": null,
9103
9104 /**
9105 * Data object from the original data source for the row. This is either
9106 * an array if using the traditional form of DataTables, or an object if
9107 * using mData options. The exact type will depend on the passed in
9108 * data from the data source, or will be an array if using DOM a data
9109 * source.
9110 * @type array|object
9111 * @default []
9112 */
9113 "_aData": [],
9114
9115 /**
9116 * Sorting data cache - this array is ostensibly the same length as the
9117 * number of columns (although each index is generated only as it is
9118 * needed), and holds the data that is used for sorting each column in the
9119 * row. We do this cache generation at the start of the sort in order that
9120 * the formatting of the sort data need be done only once for each cell
9121 * per sort. This array should not be read from or written to by anything
9122 * other than the master sorting methods.
9123 * @type array
9124 * @default null
9125 * @private
9126 */
9127 "_aSortData": null,
9128
9129 /**
9130 * Per cell filtering data cache. As per the sort data cache, used to
9131 * increase the performance of the filtering in DataTables
9132 * @type array
9133 * @default null
9134 * @private
9135 */
9136 "_aFilterData": null,
9137
9138 /**
9139 * Filtering data cache. This is the same as the cell filtering cache, but
9140 * in this case a string rather than an array. This is easily computed with
9141 * a join on `_aFilterData`, but is provided as a cache so the join isn't
9142 * needed on every search (memory traded for performance)
9143 * @type array
9144 * @default null
9145 * @private
9146 */
9147 "_sFilterRow": null,
9148
9149 /**
9150 * Cache of the class name that DataTables has applied to the row, so we
9151 * can quickly look at this variable rather than needing to do a DOM check
9152 * on className for the nTr property.
9153 * @type string
9154 * @default <i>Empty string</i>
9155 * @private
9156 */
9157 "_sRowStripe": "",
9158
9159 /**
9160 * Denote if the original data source was from the DOM, or the data source
9161 * object. This is used for invalidating data, so DataTables can
9162 * automatically read data from the original source, unless uninstructed
9163 * otherwise.
9164 * @type string
9165 * @default null
9166 * @private
9167 */
9168 "src": null
9169 };
9170
9171
9172 /**
9173 * Template object for the column information object in DataTables. This object
9174 * is held in the settings aoColumns array and contains all the information that
9175 * DataTables needs about each individual column.
9176 *
9177 * Note that this object is related to {@link DataTable.defaults.column}
9178 * but this one is the internal data store for DataTables's cache of columns.
9179 * It should NOT be manipulated outside of DataTables. Any configuration should
9180 * be done through the initialisation options.
9181 * @namespace
9182 */
9183 DataTable.models.oColumn = {
9184 /**
9185 * Column index. This could be worked out on-the-fly with $.inArray, but it
9186 * is faster to just hold it as a variable
9187 * @type integer
9188 * @default null
9189 */
9190 "idx": null,
9191
9192 /**
9193 * A list of the columns that sorting should occur on when this column
9194 * is sorted. That this property is an array allows multi-column sorting
9195 * to be defined for a column (for example first name / last name columns
9196 * would benefit from this). The values are integers pointing to the
9197 * columns to be sorted on (typically it will be a single integer pointing
9198 * at itself, but that doesn't need to be the case).
9199 * @type array
9200 */
9201 "aDataSort": null,
9202
9203 /**
9204 * Define the sorting directions that are applied to the column, in sequence
9205 * as the column is repeatedly sorted upon - i.e. the first value is used
9206 * as the sorting direction when the column if first sorted (clicked on).
9207 * Sort it again (click again) and it will move on to the next index.
9208 * Repeat until loop.
9209 * @type array
9210 */
9211 "asSorting": null,
9212
9213 /**
9214 * Flag to indicate if the column is searchable, and thus should be included
9215 * in the filtering or not.
9216 * @type boolean
9217 */
9218 "bSearchable": null,
9219
9220 /**
9221 * Flag to indicate if the column is sortable or not.
9222 * @type boolean
9223 */
9224 "bSortable": null,
9225
9226 /**
9227 * Flag to indicate if the column is currently visible in the table or not
9228 * @type boolean
9229 */
9230 "bVisible": null,
9231
9232 /**
9233 * Store for manual type assignment using the `column.type` option. This
9234 * is held in store so we can manipulate the column's `sType` property.
9235 * @type string
9236 * @default null
9237 * @private
9238 */
9239 "_sManualType": null,
9240
9241 /**
9242 * Flag to indicate if HTML5 data attributes should be used as the data
9243 * source for filtering or sorting. True is either are.
9244 * @type boolean
9245 * @default false
9246 * @private
9247 */
9248 "_bAttrSrc": false,
9249
9250 /**
9251 * Developer definable function that is called whenever a cell is created (Ajax source,
9252 * etc) or processed for input (DOM source). This can be used as a compliment to mRender
9253 * allowing you to modify the DOM element (add background colour for example) when the
9254 * element is available.
9255 * @type function
9256 * @param {element} nTd The TD node that has been created
9257 * @param {*} sData The Data for the cell
9258 * @param {array|object} oData The data for the whole row
9259 * @param {int} iRow The row index for the aoData data store
9260 * @default null
9261 */
9262 "fnCreatedCell": null,
9263
9264 /**
9265 * Function to get data from a cell in a column. You should <b>never</b>
9266 * access data directly through _aData internally in DataTables - always use
9267 * the method attached to this property. It allows mData to function as
9268 * required. This function is automatically assigned by the column
9269 * initialisation method
9270 * @type function
9271 * @param {array|object} oData The data array/object for the array
9272 * (i.e. aoData[]._aData)
9273 * @param {string} sSpecific The specific data type you want to get -
9274 * 'display', 'type' 'filter' 'sort'
9275 * @returns {*} The data for the cell from the given row's data
9276 * @default null
9277 */
9278 "fnGetData": null,
9279
9280 /**
9281 * Function to set data for a cell in the column. You should <b>never</b>
9282 * set the data directly to _aData internally in DataTables - always use
9283 * this method. It allows mData to function as required. This function
9284 * is automatically assigned by the column initialisation method
9285 * @type function
9286 * @param {array|object} oData The data array/object for the array
9287 * (i.e. aoData[]._aData)
9288 * @param {*} sValue Value to set
9289 * @default null
9290 */
9291 "fnSetData": null,
9292
9293 /**
9294 * Property to read the value for the cells in the column from the data
9295 * source array / object. If null, then the default content is used, if a
9296 * function is given then the return from the function is used.
9297 * @type function|int|string|null
9298 * @default null
9299 */
9300 "mData": null,
9301
9302 /**
9303 * Partner property to mData which is used (only when defined) to get
9304 * the data - i.e. it is basically the same as mData, but without the
9305 * 'set' option, and also the data fed to it is the result from mData.
9306 * This is the rendering method to match the data method of mData.
9307 * @type function|int|string|null
9308 * @default null
9309 */
9310 "mRender": null,
9311
9312 /**
9313 * Unique header TH/TD element for this column - this is what the sorting
9314 * listener is attached to (if sorting is enabled.)
9315 * @type node
9316 * @default null
9317 */
9318 "nTh": null,
9319
9320 /**
9321 * Unique footer TH/TD element for this column (if there is one). Not used
9322 * in DataTables as such, but can be used for plug-ins to reference the
9323 * footer for each column.
9324 * @type node
9325 * @default null
9326 */
9327 "nTf": null,
9328
9329 /**
9330 * The class to apply to all TD elements in the table's TBODY for the column
9331 * @type string
9332 * @default null
9333 */
9334 "sClass": null,
9335
9336 /**
9337 * When DataTables calculates the column widths to assign to each column,
9338 * it finds the longest string in each column and then constructs a
9339 * temporary table and reads the widths from that. The problem with this
9340 * is that "mmm" is much wider then "iiii", but the latter is a longer
9341 * string - thus the calculation can go wrong (doing it properly and putting
9342 * it into an DOM object and measuring that is horribly(!) slow). Thus as
9343 * a "work around" we provide this option. It will append its value to the
9344 * text that is found to be the longest string for the column - i.e. padding.
9345 * @type string
9346 */
9347 "sContentPadding": null,
9348
9349 /**
9350 * Allows a default value to be given for a column's data, and will be used
9351 * whenever a null data source is encountered (this can be because mData
9352 * is set to null, or because the data source itself is null).
9353 * @type string
9354 * @default null
9355 */
9356 "sDefaultContent": null,
9357
9358 /**
9359 * Name for the column, allowing reference to the column by name as well as
9360 * by index (needs a lookup to work by name).
9361 * @type string
9362 */
9363 "sName": null,
9364
9365 /**
9366 * Custom sorting data type - defines which of the available plug-ins in
9367 * afnSortData the custom sorting will use - if any is defined.
9368 * @type string
9369 * @default std
9370 */
9371 "sSortDataType": 'std',
9372
9373 /**
9374 * Class to be applied to the header element when sorting on this column
9375 * @type string
9376 * @default null
9377 */
9378 "sSortingClass": null,
9379
9380 /**
9381 * Class to be applied to the header element when sorting on this column -
9382 * when jQuery UI theming is used.
9383 * @type string
9384 * @default null
9385 */
9386 "sSortingClassJUI": null,
9387
9388 /**
9389 * Title of the column - what is seen in the TH element (nTh).
9390 * @type string
9391 */
9392 "sTitle": null,
9393
9394 /**
9395 * Column sorting and filtering type
9396 * @type string
9397 * @default null
9398 */
9399 "sType": null,
9400
9401 /**
9402 * Width of the column
9403 * @type string
9404 * @default null
9405 */
9406 "sWidth": null,
9407
9408 /**
9409 * Width of the column when it was first "encountered"
9410 * @type string
9411 * @default null
9412 */
9413 "sWidthOrig": null
9414 };
9415
9416
9417 /*
9418 * Developer note: The properties of the object below are given in Hungarian
9419 * notation, that was used as the interface for DataTables prior to v1.10, however
9420 * from v1.10 onwards the primary interface is camel case. In order to avoid
9421 * breaking backwards compatibility utterly with this change, the Hungarian
9422 * version is still, internally the primary interface, but is is not documented
9423 * - hence the @name tags in each doc comment. This allows a Javascript function
9424 * to create a map from Hungarian notation to camel case (going the other direction
9425 * would require each property to be listed, which would at around 3K to the size
9426 * of DataTables, while this method is about a 0.5K hit.
9427 *
9428 * Ultimately this does pave the way for Hungarian notation to be dropped
9429 * completely, but that is a massive amount of work and will break current
9430 * installs (therefore is on-hold until v2).
9431 */
9432
9433 /**
9434 * Initialisation options that can be given to DataTables at initialisation
9435 * time.
9436 * @namespace
9437 */
9438 DataTable.defaults = {
9439 /**
9440 * An array of data to use for the table, passed in at initialisation which
9441 * will be used in preference to any data which is already in the DOM. This is
9442 * particularly useful for constructing tables purely in Javascript, for
9443 * example with a custom Ajax call.
9444 * @type array
9445 * @default null
9446 *
9447 * @dtopt Option
9448 * @name DataTable.defaults.data
9449 *
9450 * @example
9451 * // Using a 2D array data source
9452 * $(document).ready( function () {
9453 * $('#example').dataTable( {
9454 * "data": [
9455 * ['Trident', 'Internet Explorer 4.0', 'Win 95+', 4, 'X'],
9456 * ['Trident', 'Internet Explorer 5.0', 'Win 95+', 5, 'C'],
9457 * ],
9458 * "columns": [
9459 * { "title": "Engine" },
9460 * { "title": "Browser" },
9461 * { "title": "Platform" },
9462 * { "title": "Version" },
9463 * { "title": "Grade" }
9464 * ]
9465 * } );
9466 * } );
9467 *
9468 * @example
9469 * // Using an array of objects as a data source (`data`)
9470 * $(document).ready( function () {
9471 * $('#example').dataTable( {
9472 * "data": [
9473 * {
9474 * "engine": "Trident",
9475 * "browser": "Internet Explorer 4.0",
9476 * "platform": "Win 95+",
9477 * "version": 4,
9478 * "grade": "X"
9479 * },
9480 * {
9481 * "engine": "Trident",
9482 * "browser": "Internet Explorer 5.0",
9483 * "platform": "Win 95+",
9484 * "version": 5,
9485 * "grade": "C"
9486 * }
9487 * ],
9488 * "columns": [
9489 * { "title": "Engine", "data": "engine" },
9490 * { "title": "Browser", "data": "browser" },
9491 * { "title": "Platform", "data": "platform" },
9492 * { "title": "Version", "data": "version" },
9493 * { "title": "Grade", "data": "grade" }
9494 * ]
9495 * } );
9496 * } );
9497 */
9498 "aaData": null,
9499
9500
9501 /**
9502 * If ordering is enabled, then DataTables will perform a first pass sort on
9503 * initialisation. You can define which column(s) the sort is performed
9504 * upon, and the sorting direction, with this variable. The `sorting` array
9505 * should contain an array for each column to be sorted initially containing
9506 * the column's index and a direction string ('asc' or 'desc').
9507 * @type array
9508 * @default [[0,'asc']]
9509 *
9510 * @dtopt Option
9511 * @name DataTable.defaults.order
9512 *
9513 * @example
9514 * // Sort by 3rd column first, and then 4th column
9515 * $(document).ready( function() {
9516 * $('#example').dataTable( {
9517 * "order": [[2,'asc'], [3,'desc']]
9518 * } );
9519 * } );
9520 *
9521 * // No initial sorting
9522 * $(document).ready( function() {
9523 * $('#example').dataTable( {
9524 * "order": []
9525 * } );
9526 * } );
9527 */
9528 "aaSorting": [[0,'asc']],
9529
9530
9531 /**
9532 * This parameter is basically identical to the `sorting` parameter, but
9533 * cannot be overridden by user interaction with the table. What this means
9534 * is that you could have a column (visible or hidden) which the sorting
9535 * will always be forced on first - any sorting after that (from the user)
9536 * will then be performed as required. This can be useful for grouping rows
9537 * together.
9538 * @type array
9539 * @default null
9540 *
9541 * @dtopt Option
9542 * @name DataTable.defaults.orderFixed
9543 *
9544 * @example
9545 * $(document).ready( function() {
9546 * $('#example').dataTable( {
9547 * "orderFixed": [[0,'asc']]
9548 * } );
9549 * } )
9550 */
9551 "aaSortingFixed": [],
9552
9553
9554 /**
9555 * DataTables can be instructed to load data to display in the table from a
9556 * Ajax source. This option defines how that Ajax call is made and where to.
9557 *
9558 * The `ajax` property has three different modes of operation, depending on
9559 * how it is defined. These are:
9560 *
9561 * * `string` - Set the URL from where the data should be loaded from.
9562 * * `object` - Define properties for `jQuery.ajax`.
9563 * * `function` - Custom data get function
9564 *
9565 * `string`
9566 * --------
9567 *
9568 * As a string, the `ajax` property simply defines the URL from which
9569 * DataTables will load data.
9570 *
9571 * `object`
9572 * --------
9573 *
9574 * As an object, the parameters in the object are passed to
9575 * [jQuery.ajax](http://api.jquery.com/jQuery.ajax/) allowing fine control
9576 * of the Ajax request. DataTables has a number of default parameters which
9577 * you can override using this option. Please refer to the jQuery
9578 * documentation for a full description of the options available, although
9579 * the following parameters provide additional options in DataTables or
9580 * require special consideration:
9581 *
9582 * * `data` - As with jQuery, `data` can be provided as an object, but it
9583 * can also be used as a function to manipulate the data DataTables sends
9584 * to the server. The function takes a single parameter, an object of
9585 * parameters with the values that DataTables has readied for sending. An
9586 * object may be returned which will be merged into the DataTables
9587 * defaults, or you can add the items to the object that was passed in and
9588 * not return anything from the function. This supersedes `fnServerParams`
9589 * from DataTables 1.9-.
9590 *
9591 * * `dataSrc` - By default DataTables will look for the property `data` (or
9592 * `aaData` for compatibility with DataTables 1.9-) when obtaining data
9593 * from an Ajax source or for server-side processing - this parameter
9594 * allows that property to be changed. You can use Javascript dotted
9595 * object notation to get a data source for multiple levels of nesting, or
9596 * it my be used as a function. As a function it takes a single parameter,
9597 * the JSON returned from the server, which can be manipulated as
9598 * required, with the returned value being that used by DataTables as the
9599 * data source for the table. This supersedes `sAjaxDataProp` from
9600 * DataTables 1.9-.
9601 *
9602 * * `success` - Should not be overridden it is used internally in
9603 * DataTables. To manipulate / transform the data returned by the server
9604 * use `ajax.dataSrc`, or use `ajax` as a function (see below).
9605 *
9606 * `function`
9607 * ----------
9608 *
9609 * As a function, making the Ajax call is left up to yourself allowing
9610 * complete control of the Ajax request. Indeed, if desired, a method other
9611 * than Ajax could be used to obtain the required data, such as Web storage
9612 * or an AIR database.
9613 *
9614 * The function is given four parameters and no return is required. The
9615 * parameters are:
9616 *
9617 * 1. _object_ - Data to send to the server
9618 * 2. _function_ - Callback function that must be executed when the required
9619 * data has been obtained. That data should be passed into the callback
9620 * as the only parameter
9621 * 3. _object_ - DataTables settings object for the table
9622 *
9623 * Note that this supersedes `fnServerData` from DataTables 1.9-.
9624 *
9625 * @type string|object|function
9626 * @default null
9627 *
9628 * @dtopt Option
9629 * @name DataTable.defaults.ajax
9630 * @since 1.10.0
9631 *
9632 * @example
9633 * // Get JSON data from a file via Ajax.
9634 * // Note DataTables expects data in the form `{ data: [ ...data... ] }` by default).
9635 * $('#example').dataTable( {
9636 * "ajax": "data.json"
9637 * } );
9638 *
9639 * @example
9640 * // Get JSON data from a file via Ajax, using `dataSrc` to change
9641 * // `data` to `tableData` (i.e. `{ tableData: [ ...data... ] }`)
9642 * $('#example').dataTable( {
9643 * "ajax": {
9644 * "url": "data.json",
9645 * "dataSrc": "tableData"
9646 * }
9647 * } );
9648 *
9649 * @example
9650 * // Get JSON data from a file via Ajax, using `dataSrc` to read data
9651 * // from a plain array rather than an array in an object
9652 * $('#example').dataTable( {
9653 * "ajax": {
9654 * "url": "data.json",
9655 * "dataSrc": ""
9656 * }
9657 * } );
9658 *
9659 * @example
9660 * // Manipulate the data returned from the server - add a link to data
9661 * // (note this can, should, be done using `render` for the column - this
9662 * // is just a simple example of how the data can be manipulated).
9663 * $('#example').dataTable( {
9664 * "ajax": {
9665 * "url": "data.json",
9666 * "dataSrc": function ( json ) {
9667 * for ( var i=0, ien=json.length ; i<ien ; i++ ) {
9668 * json[i][0] = '<a href="/message/'+json[i][0]+'>View message</a>';
9669 * }
9670 * return json;
9671 * }
9672 * }
9673 * } );
9674 *
9675 * @example
9676 * // Add data to the request
9677 * $('#example').dataTable( {
9678 * "ajax": {
9679 * "url": "data.json",
9680 * "data": function ( d ) {
9681 * return {
9682 * "extra_search": $('#extra').val()
9683 * };
9684 * }
9685 * }
9686 * } );
9687 *
9688 * @example
9689 * // Send request as POST
9690 * $('#example').dataTable( {
9691 * "ajax": {
9692 * "url": "data.json",
9693 * "type": "POST"
9694 * }
9695 * } );
9696 *
9697 * @example
9698 * // Get the data from localStorage (could interface with a form for
9699 * // adding, editing and removing rows).
9700 * $('#example').dataTable( {
9701 * "ajax": function (data, callback, settings) {
9702 * callback(
9703 * JSON.parse( localStorage.getItem('dataTablesData') )
9704 * );
9705 * }
9706 * } );
9707 */
9708 "ajax": null,
9709
9710
9711 /**
9712 * This parameter allows you to readily specify the entries in the length drop
9713 * down menu that DataTables shows when pagination is enabled. It can be
9714 * either a 1D array of options which will be used for both the displayed
9715 * option and the value, or a 2D array which will use the array in the first
9716 * position as the value, and the array in the second position as the
9717 * displayed options (useful for language strings such as 'All').
9718 *
9719 * Note that the `pageLength` property will be automatically set to the
9720 * first value given in this array, unless `pageLength` is also provided.
9721 * @type array
9722 * @default [ 10, 25, 50, 100 ]
9723 *
9724 * @dtopt Option
9725 * @name DataTable.defaults.lengthMenu
9726 *
9727 * @example
9728 * $(document).ready( function() {
9729 * $('#example').dataTable( {
9730 * "lengthMenu": [[10, 25, 50, -1], [10, 25, 50, "All"]]
9731 * } );
9732 * } );
9733 */
9734 "aLengthMenu": [ 10, 25, 50, 100 ],
9735
9736
9737 /**
9738 * The `columns` option in the initialisation parameter allows you to define
9739 * details about the way individual columns behave. For a full list of
9740 * column options that can be set, please see
9741 * {@link DataTable.defaults.column}. Note that if you use `columns` to
9742 * define your columns, you must have an entry in the array for every single
9743 * column that you have in your table (these can be null if you don't which
9744 * to specify any options).
9745 * @member
9746 *
9747 * @name DataTable.defaults.column
9748 */
9749 "aoColumns": null,
9750
9751 /**
9752 * Very similar to `columns`, `columnDefs` allows you to target a specific
9753 * column, multiple columns, or all columns, using the `targets` property of
9754 * each object in the array. This allows great flexibility when creating
9755 * tables, as the `columnDefs` arrays can be of any length, targeting the
9756 * columns you specifically want. `columnDefs` may use any of the column
9757 * options available: {@link DataTable.defaults.column}, but it _must_
9758 * have `targets` defined in each object in the array. Values in the `targets`
9759 * array may be:
9760 * <ul>
9761 * <li>a string - class name will be matched on the TH for the column</li>
9762 * <li>0 or a positive integer - column index counting from the left</li>
9763 * <li>a negative integer - column index counting from the right</li>
9764 * <li>the string "_all" - all columns (i.e. assign a default)</li>
9765 * </ul>
9766 * @member
9767 *
9768 * @name DataTable.defaults.columnDefs
9769 */
9770 "aoColumnDefs": null,
9771
9772
9773 /**
9774 * Basically the same as `search`, this parameter defines the individual column
9775 * filtering state at initialisation time. The array must be of the same size
9776 * as the number of columns, and each element be an object with the parameters
9777 * `search` and `escapeRegex` (the latter is optional). 'null' is also
9778 * accepted and the default will be used.
9779 * @type array
9780 * @default []
9781 *
9782 * @dtopt Option
9783 * @name DataTable.defaults.searchCols
9784 *
9785 * @example
9786 * $(document).ready( function() {
9787 * $('#example').dataTable( {
9788 * "searchCols": [
9789 * null,
9790 * { "search": "My filter" },
9791 * null,
9792 * { "search": "^[0-9]", "escapeRegex": false }
9793 * ]
9794 * } );
9795 * } )
9796 */
9797 "aoSearchCols": [],
9798
9799
9800 /**
9801 * An array of CSS classes that should be applied to displayed rows. This
9802 * array may be of any length, and DataTables will apply each class
9803 * sequentially, looping when required.
9804 * @type array
9805 * @default null <i>Will take the values determined by the `oClasses.stripe*`
9806 * options</i>
9807 *
9808 * @dtopt Option
9809 * @name DataTable.defaults.stripeClasses
9810 *
9811 * @example
9812 * $(document).ready( function() {
9813 * $('#example').dataTable( {
9814 * "stripeClasses": [ 'strip1', 'strip2', 'strip3' ]
9815 * } );
9816 * } )
9817 */
9818 "asStripeClasses": null,
9819
9820
9821 /**
9822 * Enable or disable automatic column width calculation. This can be disabled
9823 * as an optimisation (it takes some time to calculate the widths) if the
9824 * tables widths are passed in using `columns`.
9825 * @type boolean
9826 * @default true
9827 *
9828 * @dtopt Features
9829 * @name DataTable.defaults.autoWidth
9830 *
9831 * @example
9832 * $(document).ready( function () {
9833 * $('#example').dataTable( {
9834 * "autoWidth": false
9835 * } );
9836 * } );
9837 */
9838 "bAutoWidth": true,
9839
9840
9841 /**
9842 * Deferred rendering can provide DataTables with a huge speed boost when you
9843 * are using an Ajax or JS data source for the table. This option, when set to
9844 * true, will cause DataTables to defer the creation of the table elements for
9845 * each row until they are needed for a draw - saving a significant amount of
9846 * time.
9847 * @type boolean
9848 * @default false
9849 *
9850 * @dtopt Features
9851 * @name DataTable.defaults.deferRender
9852 *
9853 * @example
9854 * $(document).ready( function() {
9855 * $('#example').dataTable( {
9856 * "ajax": "sources/arrays.txt",
9857 * "deferRender": true
9858 * } );
9859 * } );
9860 */
9861 "bDeferRender": false,
9862
9863
9864 /**
9865 * Replace a DataTable which matches the given selector and replace it with
9866 * one which has the properties of the new initialisation object passed. If no
9867 * table matches the selector, then the new DataTable will be constructed as
9868 * per normal.
9869 * @type boolean
9870 * @default false
9871 *
9872 * @dtopt Options
9873 * @name DataTable.defaults.destroy
9874 *
9875 * @example
9876 * $(document).ready( function() {
9877 * $('#example').dataTable( {
9878 * "srollY": "200px",
9879 * "paginate": false
9880 * } );
9881 *
9882 * // Some time later....
9883 * $('#example').dataTable( {
9884 * "filter": false,
9885 * "destroy": true
9886 * } );
9887 * } );
9888 */
9889 "bDestroy": false,
9890
9891
9892 /**
9893 * Enable or disable filtering of data. Filtering in DataTables is "smart" in
9894 * that it allows the end user to input multiple words (space separated) and
9895 * will match a row containing those words, even if not in the order that was
9896 * specified (this allow matching across multiple columns). Note that if you
9897 * wish to use filtering in DataTables this must remain 'true' - to remove the
9898 * default filtering input box and retain filtering abilities, please use
9899 * {@link DataTable.defaults.dom}.
9900 * @type boolean
9901 * @default true
9902 *
9903 * @dtopt Features
9904 * @name DataTable.defaults.searching
9905 *
9906 * @example
9907 * $(document).ready( function () {
9908 * $('#example').dataTable( {
9909 * "searching": false
9910 * } );
9911 * } );
9912 */
9913 "bFilter": true,
9914
9915
9916 /**
9917 * Enable or disable the table information display. This shows information
9918 * about the data that is currently visible on the page, including information
9919 * about filtered data if that action is being performed.
9920 * @type boolean
9921 * @default true
9922 *
9923 * @dtopt Features
9924 * @name DataTable.defaults.info
9925 *
9926 * @example
9927 * $(document).ready( function () {
9928 * $('#example').dataTable( {
9929 * "info": false
9930 * } );
9931 * } );
9932 */
9933 "bInfo": true,
9934
9935
9936 /**
9937 * Enable jQuery UI ThemeRoller support (required as ThemeRoller requires some
9938 * slightly different and additional mark-up from what DataTables has
9939 * traditionally used).
9940 * @type boolean
9941 * @default false
9942 *
9943 * @dtopt Features
9944 * @name DataTable.defaults.jQueryUI
9945 *
9946 * @example
9947 * $(document).ready( function() {
9948 * $('#example').dataTable( {
9949 * "jQueryUI": true
9950 * } );
9951 * } );
9952 */
9953 "bJQueryUI": false,
9954
9955
9956 /**
9957 * Allows the end user to select the size of a formatted page from a select
9958 * menu (sizes are 10, 25, 50 and 100). Requires pagination (`paginate`).
9959 * @type boolean
9960 * @default true
9961 *
9962 * @dtopt Features
9963 * @name DataTable.defaults.lengthChange
9964 *
9965 * @example
9966 * $(document).ready( function () {
9967 * $('#example').dataTable( {
9968 * "lengthChange": false
9969 * } );
9970 * } );
9971 */
9972 "bLengthChange": true,
9973
9974
9975 /**
9976 * Enable or disable pagination.
9977 * @type boolean
9978 * @default true
9979 *
9980 * @dtopt Features
9981 * @name DataTable.defaults.paging
9982 *
9983 * @example
9984 * $(document).ready( function () {
9985 * $('#example').dataTable( {
9986 * "paging": false
9987 * } );
9988 * } );
9989 */
9990 "bPaginate": true,
9991
9992
9993 /**
9994 * Enable or disable the display of a 'processing' indicator when the table is
9995 * being processed (e.g. a sort). This is particularly useful for tables with
9996 * large amounts of data where it can take a noticeable amount of time to sort
9997 * the entries.
9998 * @type boolean
9999 * @default false
10000 *
10001 * @dtopt Features
10002 * @name DataTable.defaults.processing
10003 *
10004 * @example
10005 * $(document).ready( function () {
10006 * $('#example').dataTable( {
10007 * "processing": true
10008 * } );
10009 * } );
10010 */
10011 "bProcessing": false,
10012
10013
10014 /**
10015 * Retrieve the DataTables object for the given selector. Note that if the
10016 * table has already been initialised, this parameter will cause DataTables
10017 * to simply return the object that has already been set up - it will not take
10018 * account of any changes you might have made to the initialisation object
10019 * passed to DataTables (setting this parameter to true is an acknowledgement
10020 * that you understand this). `destroy` can be used to reinitialise a table if
10021 * you need.
10022 * @type boolean
10023 * @default false
10024 *
10025 * @dtopt Options
10026 * @name DataTable.defaults.retrieve
10027 *
10028 * @example
10029 * $(document).ready( function() {
10030 * initTable();
10031 * tableActions();
10032 * } );
10033 *
10034 * function initTable ()
10035 * {
10036 * return $('#example').dataTable( {
10037 * "scrollY": "200px",
10038 * "paginate": false,
10039 * "retrieve": true
10040 * } );
10041 * }
10042 *
10043 * function tableActions ()
10044 * {
10045 * var table = initTable();
10046 * // perform API operations with oTable
10047 * }
10048 */
10049 "bRetrieve": false,
10050
10051
10052 /**
10053 * When vertical (y) scrolling is enabled, DataTables will force the height of
10054 * the table's viewport to the given height at all times (useful for layout).
10055 * However, this can look odd when filtering data down to a small data set,
10056 * and the footer is left "floating" further down. This parameter (when
10057 * enabled) will cause DataTables to collapse the table's viewport down when
10058 * the result set will fit within the given Y height.
10059 * @type boolean
10060 * @default false
10061 *
10062 * @dtopt Options
10063 * @name DataTable.defaults.scrollCollapse
10064 *
10065 * @example
10066 * $(document).ready( function() {
10067 * $('#example').dataTable( {
10068 * "scrollY": "200",
10069 * "scrollCollapse": true
10070 * } );
10071 * } );
10072 */
10073 "bScrollCollapse": false,
10074
10075
10076 /**
10077 * Configure DataTables to use server-side processing. Note that the
10078 * `ajax` parameter must also be given in order to give DataTables a
10079 * source to obtain the required data for each draw.
10080 * @type boolean
10081 * @default false
10082 *
10083 * @dtopt Features
10084 * @dtopt Server-side
10085 * @name DataTable.defaults.serverSide
10086 *
10087 * @example
10088 * $(document).ready( function () {
10089 * $('#example').dataTable( {
10090 * "serverSide": true,
10091 * "ajax": "xhr.php"
10092 * } );
10093 * } );
10094 */
10095 "bServerSide": false,
10096
10097
10098 /**
10099 * Enable or disable sorting of columns. Sorting of individual columns can be
10100 * disabled by the `sortable` option for each column.
10101 * @type boolean
10102 * @default true
10103 *
10104 * @dtopt Features
10105 * @name DataTable.defaults.ordering
10106 *
10107 * @example
10108 * $(document).ready( function () {
10109 * $('#example').dataTable( {
10110 * "ordering": false
10111 * } );
10112 * } );
10113 */
10114 "bSort": true,
10115
10116
10117 /**
10118 * Enable or display DataTables' ability to sort multiple columns at the
10119 * same time (activated by shift-click by the user).
10120 * @type boolean
10121 * @default true
10122 *
10123 * @dtopt Options
10124 * @name DataTable.defaults.orderMulti
10125 *
10126 * @example
10127 * // Disable multiple column sorting ability
10128 * $(document).ready( function () {
10129 * $('#example').dataTable( {
10130 * "orderMulti": false
10131 * } );
10132 * } );
10133 */
10134 "bSortMulti": true,
10135
10136
10137 /**
10138 * Allows control over whether DataTables should use the top (true) unique
10139 * cell that is found for a single column, or the bottom (false - default).
10140 * This is useful when using complex headers.
10141 * @type boolean
10142 * @default false
10143 *
10144 * @dtopt Options
10145 * @name DataTable.defaults.orderCellsTop
10146 *
10147 * @example
10148 * $(document).ready( function() {
10149 * $('#example').dataTable( {
10150 * "orderCellsTop": true
10151 * } );
10152 * } );
10153 */
10154 "bSortCellsTop": false,
10155
10156
10157 /**
10158 * Enable or disable the addition of the classes `sorting\_1`, `sorting\_2` and
10159 * `sorting\_3` to the columns which are currently being sorted on. This is
10160 * presented as a feature switch as it can increase processing time (while
10161 * classes are removed and added) so for large data sets you might want to
10162 * turn this off.
10163 * @type boolean
10164 * @default true
10165 *
10166 * @dtopt Features
10167 * @name DataTable.defaults.orderClasses
10168 *
10169 * @example
10170 * $(document).ready( function () {
10171 * $('#example').dataTable( {
10172 * "orderClasses": false
10173 * } );
10174 * } );
10175 */
10176 "bSortClasses": true,
10177
10178
10179 /**
10180 * Enable or disable state saving. When enabled HTML5 `localStorage` will be
10181 * used to save table display information such as pagination information,
10182 * display length, filtering and sorting. As such when the end user reloads
10183 * the page the display display will match what thy had previously set up.
10184 *
10185 * Due to the use of `localStorage` the default state saving is not supported
10186 * in IE6 or 7. If state saving is required in those browsers, use
10187 * `stateSaveCallback` to provide a storage solution such as cookies.
10188 * @type boolean
10189 * @default false
10190 *
10191 * @dtopt Features
10192 * @name DataTable.defaults.stateSave
10193 *
10194 * @example
10195 * $(document).ready( function () {
10196 * $('#example').dataTable( {
10197 * "stateSave": true
10198 * } );
10199 * } );
10200 */
10201 "bStateSave": false,
10202
10203
10204 /**
10205 * This function is called when a TR element is created (and all TD child
10206 * elements have been inserted), or registered if using a DOM source, allowing
10207 * manipulation of the TR element (adding classes etc).
10208 * @type function
10209 * @param {node} row "TR" element for the current row
10210 * @param {array} data Raw data array for this row
10211 * @param {int} dataIndex The index of this row in the internal aoData array
10212 *
10213 * @dtopt Callbacks
10214 * @name DataTable.defaults.createdRow
10215 *
10216 * @example
10217 * $(document).ready( function() {
10218 * $('#example').dataTable( {
10219 * "createdRow": function( row, data, dataIndex ) {
10220 * // Bold the grade for all 'A' grade browsers
10221 * if ( data[4] == "A" )
10222 * {
10223 * $('td:eq(4)', row).html( '<b>A</b>' );
10224 * }
10225 * }
10226 * } );
10227 * } );
10228 */
10229 "fnCreatedRow": null,
10230
10231
10232 /**
10233 * This function is called on every 'draw' event, and allows you to
10234 * dynamically modify any aspect you want about the created DOM.
10235 * @type function
10236 * @param {object} settings DataTables settings object
10237 *
10238 * @dtopt Callbacks
10239 * @name DataTable.defaults.drawCallback
10240 *
10241 * @example
10242 * $(document).ready( function() {
10243 * $('#example').dataTable( {
10244 * "drawCallback": function( settings ) {
10245 * alert( 'DataTables has redrawn the table' );
10246 * }
10247 * } );
10248 * } );
10249 */
10250 "fnDrawCallback": null,
10251
10252
10253 /**
10254 * Identical to fnHeaderCallback() but for the table footer this function
10255 * allows you to modify the table footer on every 'draw' event.
10256 * @type function
10257 * @param {node} foot "TR" element for the footer
10258 * @param {array} data Full table data (as derived from the original HTML)
10259 * @param {int} start Index for the current display starting point in the
10260 * display array
10261 * @param {int} end Index for the current display ending point in the
10262 * display array
10263 * @param {array int} display Index array to translate the visual position
10264 * to the full data array
10265 *
10266 * @dtopt Callbacks
10267 * @name DataTable.defaults.footerCallback
10268 *
10269 * @example
10270 * $(document).ready( function() {
10271 * $('#example').dataTable( {
10272 * "footerCallback": function( tfoot, data, start, end, display ) {
10273 * tfoot.getElementsByTagName('th')[0].innerHTML = "Starting index is "+start;
10274 * }
10275 * } );
10276 * } )
10277 */
10278 "fnFooterCallback": null,
10279
10280
10281 /**
10282 * When rendering large numbers in the information element for the table
10283 * (i.e. "Showing 1 to 10 of 57 entries") DataTables will render large numbers
10284 * to have a comma separator for the 'thousands' units (e.g. 1 million is
10285 * rendered as "1,000,000") to help readability for the end user. This
10286 * function will override the default method DataTables uses.
10287 * @type function
10288 * @member
10289 * @param {int} toFormat number to be formatted
10290 * @returns {string} formatted string for DataTables to show the number
10291 *
10292 * @dtopt Callbacks
10293 * @name DataTable.defaults.formatNumber
10294 *
10295 * @example
10296 * // Format a number using a single quote for the separator (note that
10297 * // this can also be done with the language.thousands option)
10298 * $(document).ready( function() {
10299 * $('#example').dataTable( {
10300 * "formatNumber": function ( toFormat ) {
10301 * return toFormat.toString().replace(
10302 * /\B(?=(\d{3})+(?!\d))/g, "'"
10303 * );
10304 * };
10305 * } );
10306 * } );
10307 */
10308 "fnFormatNumber": function ( toFormat ) {
10309 return toFormat.toString().replace(
10310 /\B(?=(\d{3})+(?!\d))/g,
10311 this.oLanguage.sThousands
10312 );
10313 },
10314
10315
10316 /**
10317 * This function is called on every 'draw' event, and allows you to
10318 * dynamically modify the header row. This can be used to calculate and
10319 * display useful information about the table.
10320 * @type function
10321 * @param {node} head "TR" element for the header
10322 * @param {array} data Full table data (as derived from the original HTML)
10323 * @param {int} start Index for the current display starting point in the
10324 * display array
10325 * @param {int} end Index for the current display ending point in the
10326 * display array
10327 * @param {array int} display Index array to translate the visual position
10328 * to the full data array
10329 *
10330 * @dtopt Callbacks
10331 * @name DataTable.defaults.headerCallback
10332 *
10333 * @example
10334 * $(document).ready( function() {
10335 * $('#example').dataTable( {
10336 * "fheaderCallback": function( head, data, start, end, display ) {
10337 * head.getElementsByTagName('th')[0].innerHTML = "Displaying "+(end-start)+" records";
10338 * }
10339 * } );
10340 * } )
10341 */
10342 "fnHeaderCallback": null,
10343
10344
10345 /**
10346 * The information element can be used to convey information about the current
10347 * state of the table. Although the internationalisation options presented by
10348 * DataTables are quite capable of dealing with most customisations, there may
10349 * be times where you wish to customise the string further. This callback
10350 * allows you to do exactly that.
10351 * @type function
10352 * @param {object} oSettings DataTables settings object
10353 * @param {int} start Starting position in data for the draw
10354 * @param {int} end End position in data for the draw
10355 * @param {int} max Total number of rows in the table (regardless of
10356 * filtering)
10357 * @param {int} total Total number of rows in the data set, after filtering
10358 * @param {string} pre The string that DataTables has formatted using it's
10359 * own rules
10360 * @returns {string} The string to be displayed in the information element.
10361 *
10362 * @dtopt Callbacks
10363 * @name DataTable.defaults.infoCallback
10364 *
10365 * @example
10366 * $('#example').dataTable( {
10367 * "infoCallback": function( settings, start, end, max, total, pre ) {
10368 * return start +" to "+ end;
10369 * }
10370 * } );
10371 */
10372 "fnInfoCallback": null,
10373
10374
10375 /**
10376 * Called when the table has been initialised. Normally DataTables will
10377 * initialise sequentially and there will be no need for this function,
10378 * however, this does not hold true when using external language information
10379 * since that is obtained using an async XHR call.
10380 * @type function
10381 * @param {object} settings DataTables settings object
10382 * @param {object} json The JSON object request from the server - only
10383 * present if client-side Ajax sourced data is used
10384 *
10385 * @dtopt Callbacks
10386 * @name DataTable.defaults.initComplete
10387 *
10388 * @example
10389 * $(document).ready( function() {
10390 * $('#example').dataTable( {
10391 * "initComplete": function(settings, json) {
10392 * alert( 'DataTables has finished its initialisation.' );
10393 * }
10394 * } );
10395 * } )
10396 */
10397 "fnInitComplete": null,
10398
10399
10400 /**
10401 * Called at the very start of each table draw and can be used to cancel the
10402 * draw by returning false, any other return (including undefined) results in
10403 * the full draw occurring).
10404 * @type function
10405 * @param {object} settings DataTables settings object
10406 * @returns {boolean} False will cancel the draw, anything else (including no
10407 * return) will allow it to complete.
10408 *
10409 * @dtopt Callbacks
10410 * @name DataTable.defaults.preDrawCallback
10411 *
10412 * @example
10413 * $(document).ready( function() {
10414 * $('#example').dataTable( {
10415 * "preDrawCallback": function( settings ) {
10416 * if ( $('#test').val() == 1 ) {
10417 * return false;
10418 * }
10419 * }
10420 * } );
10421 * } );
10422 */
10423 "fnPreDrawCallback": null,
10424
10425
10426 /**
10427 * This function allows you to 'post process' each row after it have been
10428 * generated for each table draw, but before it is rendered on screen. This
10429 * function might be used for setting the row class name etc.
10430 * @type function
10431 * @param {node} row "TR" element for the current row
10432 * @param {array} data Raw data array for this row
10433 * @param {int} displayIndex The display index for the current table draw
10434 * @param {int} displayIndexFull The index of the data in the full list of
10435 * rows (after filtering)
10436 *
10437 * @dtopt Callbacks
10438 * @name DataTable.defaults.rowCallback
10439 *
10440 * @example
10441 * $(document).ready( function() {
10442 * $('#example').dataTable( {
10443 * "rowCallback": function( row, data, displayIndex, displayIndexFull ) {
10444 * // Bold the grade for all 'A' grade browsers
10445 * if ( data[4] == "A" ) {
10446 * $('td:eq(4)', row).html( '<b>A</b>' );
10447 * }
10448 * }
10449 * } );
10450 * } );
10451 */
10452 "fnRowCallback": null,
10453
10454
10455 /**
10456 * __Deprecated__ The functionality provided by this parameter has now been
10457 * superseded by that provided through `ajax`, which should be used instead.
10458 *
10459 * This parameter allows you to override the default function which obtains
10460 * the data from the server so something more suitable for your application.
10461 * For example you could use POST data, or pull information from a Gears or
10462 * AIR database.
10463 * @type function
10464 * @member
10465 * @param {string} source HTTP source to obtain the data from (`ajax`)
10466 * @param {array} data A key/value pair object containing the data to send
10467 * to the server
10468 * @param {function} callback to be called on completion of the data get
10469 * process that will draw the data on the page.
10470 * @param {object} settings DataTables settings object
10471 *
10472 * @dtopt Callbacks
10473 * @dtopt Server-side
10474 * @name DataTable.defaults.serverData
10475 *
10476 * @deprecated 1.10. Please use `ajax` for this functionality now.
10477 */
10478 "fnServerData": null,
10479
10480
10481 /**
10482 * __Deprecated__ The functionality provided by this parameter has now been
10483 * superseded by that provided through `ajax`, which should be used instead.
10484 *
10485 * It is often useful to send extra data to the server when making an Ajax
10486 * request - for example custom filtering information, and this callback
10487 * function makes it trivial to send extra information to the server. The
10488 * passed in parameter is the data set that has been constructed by
10489 * DataTables, and you can add to this or modify it as you require.
10490 * @type function
10491 * @param {array} data Data array (array of objects which are name/value
10492 * pairs) that has been constructed by DataTables and will be sent to the
10493 * server. In the case of Ajax sourced data with server-side processing
10494 * this will be an empty array, for server-side processing there will be a
10495 * significant number of parameters!
10496 * @returns {undefined} Ensure that you modify the data array passed in,
10497 * as this is passed by reference.
10498 *
10499 * @dtopt Callbacks
10500 * @dtopt Server-side
10501 * @name DataTable.defaults.serverParams
10502 *
10503 * @deprecated 1.10. Please use `ajax` for this functionality now.
10504 */
10505 "fnServerParams": null,
10506
10507
10508 /**
10509 * Load the table state. With this function you can define from where, and how, the
10510 * state of a table is loaded. By default DataTables will load from `localStorage`
10511 * but you might wish to use a server-side database or cookies.
10512 * @type function
10513 * @member
10514 * @param {object} settings DataTables settings object
10515 * @return {object} The DataTables state object to be loaded
10516 *
10517 * @dtopt Callbacks
10518 * @name DataTable.defaults.stateLoadCallback
10519 *
10520 * @example
10521 * $(document).ready( function() {
10522 * $('#example').dataTable( {
10523 * "stateSave": true,
10524 * "stateLoadCallback": function (settings) {
10525 * var o;
10526 *
10527 * // Send an Ajax request to the server to get the data. Note that
10528 * // this is a synchronous request.
10529 * $.ajax( {
10530 * "url": "/state_load",
10531 * "async": false,
10532 * "dataType": "json",
10533 * "success": function (json) {
10534 * o = json;
10535 * }
10536 * } );
10537 *
10538 * return o;
10539 * }
10540 * } );
10541 * } );
10542 */
10543 "fnStateLoadCallback": function ( settings ) {
10544 try {
10545 return JSON.parse(
10546 (settings.iStateDuration === -1 ? sessionStorage : localStorage).getItem(
10547 'DataTables_'+settings.sInstance+'_'+location.pathname
10548 )
10549 );
10550 } catch (e) {}
10551 },
10552
10553
10554 /**
10555 * Callback which allows modification of the saved state prior to loading that state.
10556 * This callback is called when the table is loading state from the stored data, but
10557 * prior to the settings object being modified by the saved state. Note that for
10558 * plug-in authors, you should use the `stateLoadParams` event to load parameters for
10559 * a plug-in.
10560 * @type function
10561 * @param {object} settings DataTables settings object
10562 * @param {object} data The state object that is to be loaded
10563 *
10564 * @dtopt Callbacks
10565 * @name DataTable.defaults.stateLoadParams
10566 *
10567 * @example
10568 * // Remove a saved filter, so filtering is never loaded
10569 * $(document).ready( function() {
10570 * $('#example').dataTable( {
10571 * "stateSave": true,
10572 * "stateLoadParams": function (settings, data) {
10573 * data.oSearch.sSearch = "";
10574 * }
10575 * } );
10576 * } );
10577 *
10578 * @example
10579 * // Disallow state loading by returning false
10580 * $(document).ready( function() {
10581 * $('#example').dataTable( {
10582 * "stateSave": true,
10583 * "stateLoadParams": function (settings, data) {
10584 * return false;
10585 * }
10586 * } );
10587 * } );
10588 */
10589 "fnStateLoadParams": null,
10590
10591
10592 /**
10593 * Callback that is called when the state has been loaded from the state saving method
10594 * and the DataTables settings object has been modified as a result of the loaded state.
10595 * @type function
10596 * @param {object} settings DataTables settings object
10597 * @param {object} data The state object that was loaded
10598 *
10599 * @dtopt Callbacks
10600 * @name DataTable.defaults.stateLoaded
10601 *
10602 * @example
10603 * // Show an alert with the filtering value that was saved
10604 * $(document).ready( function() {
10605 * $('#example').dataTable( {
10606 * "stateSave": true,
10607 * "stateLoaded": function (settings, data) {
10608 * alert( 'Saved filter was: '+data.oSearch.sSearch );
10609 * }
10610 * } );
10611 * } );
10612 */
10613 "fnStateLoaded": null,
10614
10615
10616 /**
10617 * Save the table state. This function allows you to define where and how the state
10618 * information for the table is stored By default DataTables will use `localStorage`
10619 * but you might wish to use a server-side database or cookies.
10620 * @type function
10621 * @member
10622 * @param {object} settings DataTables settings object
10623 * @param {object} data The state object to be saved
10624 *
10625 * @dtopt Callbacks
10626 * @name DataTable.defaults.stateSaveCallback
10627 *
10628 * @example
10629 * $(document).ready( function() {
10630 * $('#example').dataTable( {
10631 * "stateSave": true,
10632 * "stateSaveCallback": function (settings, data) {
10633 * // Send an Ajax request to the server with the state object
10634 * $.ajax( {
10635 * "url": "/state_save",
10636 * "data": data,
10637 * "dataType": "json",
10638 * "method": "POST"
10639 * "success": function () {}
10640 * } );
10641 * }
10642 * } );
10643 * } );
10644 */
10645 "fnStateSaveCallback": function ( settings, data ) {
10646 try {
10647 (settings.iStateDuration === -1 ? sessionStorage : localStorage).setItem(
10648 'DataTables_'+settings.sInstance+'_'+location.pathname,
10649 JSON.stringify( data )
10650 );
10651 } catch (e) {}
10652 },
10653
10654
10655 /**
10656 * Callback which allows modification of the state to be saved. Called when the table
10657 * has changed state a new state save is required. This method allows modification of
10658 * the state saving object prior to actually doing the save, including addition or
10659 * other state properties or modification. Note that for plug-in authors, you should
10660 * use the `stateSaveParams` event to save parameters for a plug-in.
10661 * @type function
10662 * @param {object} settings DataTables settings object
10663 * @param {object} data The state object to be saved
10664 *
10665 * @dtopt Callbacks
10666 * @name DataTable.defaults.stateSaveParams
10667 *
10668 * @example
10669 * // Remove a saved filter, so filtering is never saved
10670 * $(document).ready( function() {
10671 * $('#example').dataTable( {
10672 * "stateSave": true,
10673 * "stateSaveParams": function (settings, data) {
10674 * data.oSearch.sSearch = "";
10675 * }
10676 * } );
10677 * } );
10678 */
10679 "fnStateSaveParams": null,
10680
10681
10682 /**
10683 * Duration for which the saved state information is considered valid. After this period
10684 * has elapsed the state will be returned to the default.
10685 * Value is given in seconds.
10686 * @type int
10687 * @default 7200 <i>(2 hours)</i>
10688 *
10689 * @dtopt Options
10690 * @name DataTable.defaults.stateDuration
10691 *
10692 * @example
10693 * $(document).ready( function() {
10694 * $('#example').dataTable( {
10695 * "stateDuration": 60*60*24; // 1 day
10696 * } );
10697 * } )
10698 */
10699 "iStateDuration": 7200,
10700
10701
10702 /**
10703 * When enabled DataTables will not make a request to the server for the first
10704 * page draw - rather it will use the data already on the page (no sorting etc
10705 * will be applied to it), thus saving on an XHR at load time. `deferLoading`
10706 * is used to indicate that deferred loading is required, but it is also used
10707 * to tell DataTables how many records there are in the full table (allowing
10708 * the information element and pagination to be displayed correctly). In the case
10709 * where a filtering is applied to the table on initial load, this can be
10710 * indicated by giving the parameter as an array, where the first element is
10711 * the number of records available after filtering and the second element is the
10712 * number of records without filtering (allowing the table information element
10713 * to be shown correctly).
10714 * @type int | array
10715 * @default null
10716 *
10717 * @dtopt Options
10718 * @name DataTable.defaults.deferLoading
10719 *
10720 * @example
10721 * // 57 records available in the table, no filtering applied
10722 * $(document).ready( function() {
10723 * $('#example').dataTable( {
10724 * "serverSide": true,
10725 * "ajax": "scripts/server_processing.php",
10726 * "deferLoading": 57
10727 * } );
10728 * } );
10729 *
10730 * @example
10731 * // 57 records after filtering, 100 without filtering (an initial filter applied)
10732 * $(document).ready( function() {
10733 * $('#example').dataTable( {
10734 * "serverSide": true,
10735 * "ajax": "scripts/server_processing.php",
10736 * "deferLoading": [ 57, 100 ],
10737 * "search": {
10738 * "search": "my_filter"
10739 * }
10740 * } );
10741 * } );
10742 */
10743 "iDeferLoading": null,
10744
10745
10746 /**
10747 * Number of rows to display on a single page when using pagination. If
10748 * feature enabled (`lengthChange`) then the end user will be able to override
10749 * this to a custom setting using a pop-up menu.
10750 * @type int
10751 * @default 10
10752 *
10753 * @dtopt Options
10754 * @name DataTable.defaults.pageLength
10755 *
10756 * @example
10757 * $(document).ready( function() {
10758 * $('#example').dataTable( {
10759 * "pageLength": 50
10760 * } );
10761 * } )
10762 */
10763 "iDisplayLength": 10,
10764
10765
10766 /**
10767 * Define the starting point for data display when using DataTables with
10768 * pagination. Note that this parameter is the number of records, rather than
10769 * the page number, so if you have 10 records per page and want to start on
10770 * the third page, it should be "20".
10771 * @type int
10772 * @default 0
10773 *
10774 * @dtopt Options
10775 * @name DataTable.defaults.displayStart
10776 *
10777 * @example
10778 * $(document).ready( function() {
10779 * $('#example').dataTable( {
10780 * "displayStart": 20
10781 * } );
10782 * } )
10783 */
10784 "iDisplayStart": 0,
10785
10786
10787 /**
10788 * By default DataTables allows keyboard navigation of the table (sorting, paging,
10789 * and filtering) by adding a `tabindex` attribute to the required elements. This
10790 * allows you to tab through the controls and press the enter key to activate them.
10791 * The tabindex is default 0, meaning that the tab follows the flow of the document.
10792 * You can overrule this using this parameter if you wish. Use a value of -1 to
10793 * disable built-in keyboard navigation.
10794 * @type int
10795 * @default 0
10796 *
10797 * @dtopt Options
10798 * @name DataTable.defaults.tabIndex
10799 *
10800 * @example
10801 * $(document).ready( function() {
10802 * $('#example').dataTable( {
10803 * "tabIndex": 1
10804 * } );
10805 * } );
10806 */
10807 "iTabIndex": 0,
10808
10809
10810 /**
10811 * Classes that DataTables assigns to the various components and features
10812 * that it adds to the HTML table. This allows classes to be configured
10813 * during initialisation in addition to through the static
10814 * {@link DataTable.ext.oStdClasses} object).
10815 * @namespace
10816 * @name DataTable.defaults.classes
10817 */
10818 "oClasses": {},
10819
10820
10821 /**
10822 * All strings that DataTables uses in the user interface that it creates
10823 * are defined in this object, allowing you to modified them individually or
10824 * completely replace them all as required.
10825 * @namespace
10826 * @name DataTable.defaults.language
10827 */
10828 "oLanguage": {
10829 /**
10830 * Strings that are used for WAI-ARIA labels and controls only (these are not
10831 * actually visible on the page, but will be read by screenreaders, and thus
10832 * must be internationalised as well).
10833 * @namespace
10834 * @name DataTable.defaults.language.aria
10835 */
10836 "oAria": {
10837 /**
10838 * ARIA label that is added to the table headers when the column may be
10839 * sorted ascending by activing the column (click or return when focused).
10840 * Note that the column header is prefixed to this string.
10841 * @type string
10842 * @default : activate to sort column ascending
10843 *
10844 * @dtopt Language
10845 * @name DataTable.defaults.language.aria.sortAscending
10846 *
10847 * @example
10848 * $(document).ready( function() {
10849 * $('#example').dataTable( {
10850 * "language": {
10851 * "aria": {
10852 * "sortAscending": " - click/return to sort ascending"
10853 * }
10854 * }
10855 * } );
10856 * } );
10857 */
10858 "sSortAscending": ": activate to sort column ascending",
10859
10860 /**
10861 * ARIA label that is added to the table headers when the column may be
10862 * sorted descending by activing the column (click or return when focused).
10863 * Note that the column header is prefixed to this string.
10864 * @type string
10865 * @default : activate to sort column ascending
10866 *
10867 * @dtopt Language
10868 * @name DataTable.defaults.language.aria.sortDescending
10869 *
10870 * @example
10871 * $(document).ready( function() {
10872 * $('#example').dataTable( {
10873 * "language": {
10874 * "aria": {
10875 * "sortDescending": " - click/return to sort descending"
10876 * }
10877 * }
10878 * } );
10879 * } );
10880 */
10881 "sSortDescending": ": activate to sort column descending"
10882 },
10883
10884 /**
10885 * Pagination string used by DataTables for the built-in pagination
10886 * control types.
10887 * @namespace
10888 * @name DataTable.defaults.language.paginate
10889 */
10890 "oPaginate": {
10891 /**
10892 * Text to use when using the 'full_numbers' type of pagination for the
10893 * button to take the user to the first page.
10894 * @type string
10895 * @default First
10896 *
10897 * @dtopt Language
10898 * @name DataTable.defaults.language.paginate.first
10899 *
10900 * @example
10901 * $(document).ready( function() {
10902 * $('#example').dataTable( {
10903 * "language": {
10904 * "paginate": {
10905 * "first": "First page"
10906 * }
10907 * }
10908 * } );
10909 * } );
10910 */
10911 "sFirst": "First",
10912
10913
10914 /**
10915 * Text to use when using the 'full_numbers' type of pagination for the
10916 * button to take the user to the last page.
10917 * @type string
10918 * @default Last
10919 *
10920 * @dtopt Language
10921 * @name DataTable.defaults.language.paginate.last
10922 *
10923 * @example
10924 * $(document).ready( function() {
10925 * $('#example').dataTable( {
10926 * "language": {
10927 * "paginate": {
10928 * "last": "Last page"
10929 * }
10930 * }
10931 * } );
10932 * } );
10933 */
10934 "sLast": "Last",
10935
10936
10937 /**
10938 * Text to use for the 'next' pagination button (to take the user to the
10939 * next page).
10940 * @type string
10941 * @default Next
10942 *
10943 * @dtopt Language
10944 * @name DataTable.defaults.language.paginate.next
10945 *
10946 * @example
10947 * $(document).ready( function() {
10948 * $('#example').dataTable( {
10949 * "language": {
10950 * "paginate": {
10951 * "next": "Next page"
10952 * }
10953 * }
10954 * } );
10955 * } );
10956 */
10957 "sNext": "Next",
10958
10959
10960 /**
10961 * Text to use for the 'previous' pagination button (to take the user to
10962 * the previous page).
10963 * @type string
10964 * @default Previous
10965 *
10966 * @dtopt Language
10967 * @name DataTable.defaults.language.paginate.previous
10968 *
10969 * @example
10970 * $(document).ready( function() {
10971 * $('#example').dataTable( {
10972 * "language": {
10973 * "paginate": {
10974 * "previous": "Previous page"
10975 * }
10976 * }
10977 * } );
10978 * } );
10979 */
10980 "sPrevious": "Previous"
10981 },
10982
10983 /**
10984 * This string is shown in preference to `zeroRecords` when the table is
10985 * empty of data (regardless of filtering). Note that this is an optional
10986 * parameter - if it is not given, the value of `zeroRecords` will be used
10987 * instead (either the default or given value).
10988 * @type string
10989 * @default No data available in table
10990 *
10991 * @dtopt Language
10992 * @name DataTable.defaults.language.emptyTable
10993 *
10994 * @example
10995 * $(document).ready( function() {
10996 * $('#example').dataTable( {
10997 * "language": {
10998 * "emptyTable": "No data available in table"
10999 * }
11000 * } );
11001 * } );
11002 */
11003 "sEmptyTable": "No data available in table",
11004
11005
11006 /**
11007 * This string gives information to the end user about the information
11008 * that is current on display on the page. The following tokens can be
11009 * used in the string and will be dynamically replaced as the table
11010 * display updates. This tokens can be placed anywhere in the string, or
11011 * removed as needed by the language requires:
11012 *
11013 * * `\_START\_` - Display index of the first record on the current page
11014 * * `\_END\_` - Display index of the last record on the current page
11015 * * `\_TOTAL\_` - Number of records in the table after filtering
11016 * * `\_MAX\_` - Number of records in the table without filtering
11017 * * `\_PAGE\_` - Current page number
11018 * * `\_PAGES\_` - Total number of pages of data in the table
11019 *
11020 * @type string
11021 * @default Showing _START_ to _END_ of _TOTAL_ entries
11022 *
11023 * @dtopt Language
11024 * @name DataTable.defaults.language.info
11025 *
11026 * @example
11027 * $(document).ready( function() {
11028 * $('#example').dataTable( {
11029 * "language": {
11030 * "info": "Showing page _PAGE_ of _PAGES_"
11031 * }
11032 * } );
11033 * } );
11034 */
11035 "sInfo": "Showing _START_ to _END_ of _TOTAL_ entries",
11036
11037
11038 /**
11039 * Display information string for when the table is empty. Typically the
11040 * format of this string should match `info`.
11041 * @type string
11042 * @default Showing 0 to 0 of 0 entries
11043 *
11044 * @dtopt Language
11045 * @name DataTable.defaults.language.infoEmpty
11046 *
11047 * @example
11048 * $(document).ready( function() {
11049 * $('#example').dataTable( {
11050 * "language": {
11051 * "infoEmpty": "No entries to show"
11052 * }
11053 * } );
11054 * } );
11055 */
11056 "sInfoEmpty": "Showing 0 to 0 of 0 entries",
11057
11058
11059 /**
11060 * When a user filters the information in a table, this string is appended
11061 * to the information (`info`) to give an idea of how strong the filtering
11062 * is. The variable _MAX_ is dynamically updated.
11063 * @type string
11064 * @default (filtered from _MAX_ total entries)
11065 *
11066 * @dtopt Language
11067 * @name DataTable.defaults.language.infoFiltered
11068 *
11069 * @example
11070 * $(document).ready( function() {
11071 * $('#example').dataTable( {
11072 * "language": {
11073 * "infoFiltered": " - filtering from _MAX_ records"
11074 * }
11075 * } );
11076 * } );
11077 */
11078 "sInfoFiltered": "(filtered from _MAX_ total entries)",
11079
11080
11081 /**
11082 * If can be useful to append extra information to the info string at times,
11083 * and this variable does exactly that. This information will be appended to
11084 * the `info` (`infoEmpty` and `infoFiltered` in whatever combination they are
11085 * being used) at all times.
11086 * @type string
11087 * @default <i>Empty string</i>
11088 *
11089 * @dtopt Language
11090 * @name DataTable.defaults.language.infoPostFix
11091 *
11092 * @example
11093 * $(document).ready( function() {
11094 * $('#example').dataTable( {
11095 * "language": {
11096 * "infoPostFix": "All records shown are derived from real information."
11097 * }
11098 * } );
11099 * } );
11100 */
11101 "sInfoPostFix": "",
11102
11103
11104 /**
11105 * This decimal place operator is a little different from the other
11106 * language options since DataTables doesn't output floating point
11107 * numbers, so it won't ever use this for display of a number. Rather,
11108 * what this parameter does is modify the sort methods of the table so
11109 * that numbers which are in a format which has a character other than
11110 * a period (`.`) as a decimal place will be sorted numerically.
11111 *
11112 * Note that numbers with different decimal places cannot be shown in
11113 * the same table and still be sortable, the table must be consistent.
11114 * However, multiple different tables on the page can use different
11115 * decimal place characters.
11116 * @type string
11117 * @default
11118 *
11119 * @dtopt Language
11120 * @name DataTable.defaults.language.decimal
11121 *
11122 * @example
11123 * $(document).ready( function() {
11124 * $('#example').dataTable( {
11125 * "language": {
11126 * "decimal": ","
11127 * "thousands": "."
11128 * }
11129 * } );
11130 * } );
11131 */
11132 "sDecimal": "",
11133
11134
11135 /**
11136 * DataTables has a build in number formatter (`formatNumber`) which is
11137 * used to format large numbers that are used in the table information.
11138 * By default a comma is used, but this can be trivially changed to any
11139 * character you wish with this parameter.
11140 * @type string
11141 * @default ,
11142 *
11143 * @dtopt Language
11144 * @name DataTable.defaults.language.thousands
11145 *
11146 * @example
11147 * $(document).ready( function() {
11148 * $('#example').dataTable( {
11149 * "language": {
11150 * "thousands": "'"
11151 * }
11152 * } );
11153 * } );
11154 */
11155 "sThousands": ",",
11156
11157
11158 /**
11159 * Detail the action that will be taken when the drop down menu for the
11160 * pagination length option is changed. The '_MENU_' variable is replaced
11161 * with a default select list of 10, 25, 50 and 100, and can be replaced
11162 * with a custom select box if required.
11163 * @type string
11164 * @default Show _MENU_ entries
11165 *
11166 * @dtopt Language
11167 * @name DataTable.defaults.language.lengthMenu
11168 *
11169 * @example
11170 * // Language change only
11171 * $(document).ready( function() {
11172 * $('#example').dataTable( {
11173 * "language": {
11174 * "lengthMenu": "Display _MENU_ records"
11175 * }
11176 * } );
11177 * } );
11178 *
11179 * @example
11180 * // Language and options change
11181 * $(document).ready( function() {
11182 * $('#example').dataTable( {
11183 * "language": {
11184 * "lengthMenu": 'Display <select>'+
11185 * '<option value="10">10</option>'+
11186 * '<option value="20">20</option>'+
11187 * '<option value="30">30</option>'+
11188 * '<option value="40">40</option>'+
11189 * '<option value="50">50</option>'+
11190 * '<option value="-1">All</option>'+
11191 * '</select> records'
11192 * }
11193 * } );
11194 * } );
11195 */
11196 "sLengthMenu": "Show _MENU_ entries",
11197
11198
11199 /**
11200 * When using Ajax sourced data and during the first draw when DataTables is
11201 * gathering the data, this message is shown in an empty row in the table to
11202 * indicate to the end user the the data is being loaded. Note that this
11203 * parameter is not used when loading data by server-side processing, just
11204 * Ajax sourced data with client-side processing.
11205 * @type string
11206 * @default Loading...
11207 *
11208 * @dtopt Language
11209 * @name DataTable.defaults.language.loadingRecords
11210 *
11211 * @example
11212 * $(document).ready( function() {
11213 * $('#example').dataTable( {
11214 * "language": {
11215 * "loadingRecords": "Please wait - loading..."
11216 * }
11217 * } );
11218 * } );
11219 */
11220 "sLoadingRecords": "Loading...",
11221
11222
11223 /**
11224 * Text which is displayed when the table is processing a user action
11225 * (usually a sort command or similar).
11226 * @type string
11227 * @default Processing...
11228 *
11229 * @dtopt Language
11230 * @name DataTable.defaults.language.processing
11231 *
11232 * @example
11233 * $(document).ready( function() {
11234 * $('#example').dataTable( {
11235 * "language": {
11236 * "processing": "DataTables is currently busy"
11237 * }
11238 * } );
11239 * } );
11240 */
11241 "sProcessing": "Processing...",
11242
11243
11244 /**
11245 * Details the actions that will be taken when the user types into the
11246 * filtering input text box. The variable "_INPUT_", if used in the string,
11247 * is replaced with the HTML text box for the filtering input allowing
11248 * control over where it appears in the string. If "_INPUT_" is not given
11249 * then the input box is appended to the string automatically.
11250 * @type string
11251 * @default Search:
11252 *
11253 * @dtopt Language
11254 * @name DataTable.defaults.language.search
11255 *
11256 * @example
11257 * // Input text box will be appended at the end automatically
11258 * $(document).ready( function() {
11259 * $('#example').dataTable( {
11260 * "language": {
11261 * "search": "Filter records:"
11262 * }
11263 * } );
11264 * } );
11265 *
11266 * @example
11267 * // Specify where the filter should appear
11268 * $(document).ready( function() {
11269 * $('#example').dataTable( {
11270 * "language": {
11271 * "search": "Apply filter _INPUT_ to table"
11272 * }
11273 * } );
11274 * } );
11275 */
11276 "sSearch": "Search:",
11277
11278
11279 /**
11280 * Assign a `placeholder` attribute to the search `input` element
11281 * @type string
11282 * @default
11283 *
11284 * @dtopt Language
11285 * @name DataTable.defaults.language.searchPlaceholder
11286 */
11287 "sSearchPlaceholder": "",
11288
11289
11290 /**
11291 * All of the language information can be stored in a file on the
11292 * server-side, which DataTables will look up if this parameter is passed.
11293 * It must store the URL of the language file, which is in a JSON format,
11294 * and the object has the same properties as the oLanguage object in the
11295 * initialiser object (i.e. the above parameters). Please refer to one of
11296 * the example language files to see how this works in action.
11297 * @type string
11298 * @default <i>Empty string - i.e. disabled</i>
11299 *
11300 * @dtopt Language
11301 * @name DataTable.defaults.language.url
11302 *
11303 * @example
11304 * $(document).ready( function() {
11305 * $('#example').dataTable( {
11306 * "language": {
11307 * "url": "http://www.sprymedia.co.uk/dataTables/lang.txt"
11308 * }
11309 * } );
11310 * } );
11311 */
11312 "sUrl": "",
11313
11314
11315 /**
11316 * Text shown inside the table records when the is no information to be
11317 * displayed after filtering. `emptyTable` is shown when there is simply no
11318 * information in the table at all (regardless of filtering).
11319 * @type string
11320 * @default No matching records found
11321 *
11322 * @dtopt Language
11323 * @name DataTable.defaults.language.zeroRecords
11324 *
11325 * @example
11326 * $(document).ready( function() {
11327 * $('#example').dataTable( {
11328 * "language": {
11329 * "zeroRecords": "No records to display"
11330 * }
11331 * } );
11332 * } );
11333 */
11334 "sZeroRecords": "No matching records found"
11335 },
11336
11337
11338 /**
11339 * This parameter allows you to have define the global filtering state at
11340 * initialisation time. As an object the `search` parameter must be
11341 * defined, but all other parameters are optional. When `regex` is true,
11342 * the search string will be treated as a regular expression, when false
11343 * (default) it will be treated as a straight string. When `smart`
11344 * DataTables will use it's smart filtering methods (to word match at
11345 * any point in the data), when false this will not be done.
11346 * @namespace
11347 * @extends DataTable.models.oSearch
11348 *
11349 * @dtopt Options
11350 * @name DataTable.defaults.search
11351 *
11352 * @example
11353 * $(document).ready( function() {
11354 * $('#example').dataTable( {
11355 * "search": {"search": "Initial search"}
11356 * } );
11357 * } )
11358 */
11359 "oSearch": $.extend( {}, DataTable.models.oSearch ),
11360
11361
11362 /**
11363 * __Deprecated__ The functionality provided by this parameter has now been
11364 * superseded by that provided through `ajax`, which should be used instead.
11365 *
11366 * By default DataTables will look for the property `data` (or `aaData` for
11367 * compatibility with DataTables 1.9-) when obtaining data from an Ajax
11368 * source or for server-side processing - this parameter allows that
11369 * property to be changed. You can use Javascript dotted object notation to
11370 * get a data source for multiple levels of nesting.
11371 * @type string
11372 * @default data
11373 *
11374 * @dtopt Options
11375 * @dtopt Server-side
11376 * @name DataTable.defaults.ajaxDataProp
11377 *
11378 * @deprecated 1.10. Please use `ajax` for this functionality now.
11379 */
11380 "sAjaxDataProp": "data",
11381
11382
11383 /**
11384 * __Deprecated__ The functionality provided by this parameter has now been
11385 * superseded by that provided through `ajax`, which should be used instead.
11386 *
11387 * You can instruct DataTables to load data from an external
11388 * source using this parameter (use aData if you want to pass data in you
11389 * already have). Simply provide a url a JSON object can be obtained from.
11390 * @type string
11391 * @default null
11392 *
11393 * @dtopt Options
11394 * @dtopt Server-side
11395 * @name DataTable.defaults.ajaxSource
11396 *
11397 * @deprecated 1.10. Please use `ajax` for this functionality now.
11398 */
11399 "sAjaxSource": null,
11400
11401
11402 /**
11403 * This initialisation variable allows you to specify exactly where in the
11404 * DOM you want DataTables to inject the various controls it adds to the page
11405 * (for example you might want the pagination controls at the top of the
11406 * table). DIV elements (with or without a custom class) can also be added to
11407 * aid styling. The follow syntax is used:
11408 * <ul>
11409 * <li>The following options are allowed:
11410 * <ul>
11411 * <li>'l' - Length changing</li>
11412 * <li>'f' - Filtering input</li>
11413 * <li>'t' - The table!</li>
11414 * <li>'i' - Information</li>
11415 * <li>'p' - Pagination</li>
11416 * <li>'r' - pRocessing</li>
11417 * </ul>
11418 * </li>
11419 * <li>The following constants are allowed:
11420 * <ul>
11421 * <li>'H' - jQueryUI theme "header" classes ('fg-toolbar ui-widget-header ui-corner-tl ui-corner-tr ui-helper-clearfix')</li>
11422 * <li>'F' - jQueryUI theme "footer" classes ('fg-toolbar ui-widget-header ui-corner-bl ui-corner-br ui-helper-clearfix')</li>
11423 * </ul>
11424 * </li>
11425 * <li>The following syntax is expected:
11426 * <ul>
11427 * <li>'&lt;' and '&gt;' - div elements</li>
11428 * <li>'&lt;"class" and '&gt;' - div with a class</li>
11429 * <li>'&lt;"#id" and '&gt;' - div with an ID</li>
11430 * </ul>
11431 * </li>
11432 * <li>Examples:
11433 * <ul>
11434 * <li>'&lt;"wrapper"flipt&gt;'</li>
11435 * <li>'&lt;lf&lt;t&gt;ip&gt;'</li>
11436 * </ul>
11437 * </li>
11438 * </ul>
11439 * @type string
11440 * @default lfrtip <i>(when `jQueryUI` is false)</i> <b>or</b>
11441 * <"H"lfr>t<"F"ip> <i>(when `jQueryUI` is true)</i>
11442 *
11443 * @dtopt Options
11444 * @name DataTable.defaults.dom
11445 *
11446 * @example
11447 * $(document).ready( function() {
11448 * $('#example').dataTable( {
11449 * "dom": '&lt;"top"i&gt;rt&lt;"bottom"flp&gt;&lt;"clear"&gt;'
11450 * } );
11451 * } );
11452 */
11453 "sDom": "lfrtip",
11454
11455
11456 /**
11457 * Search delay option. This will throttle full table searches that use the
11458 * DataTables provided search input element (it does not effect calls to
11459 * `dt-api search()`, providing a delay before the search is made.
11460 * @type integer
11461 * @default 0
11462 *
11463 * @dtopt Options
11464 * @name DataTable.defaults.searchDelay
11465 *
11466 * @example
11467 * $(document).ready( function() {
11468 * $('#example').dataTable( {
11469 * "searchDelay": 200
11470 * } );
11471 * } )
11472 */
11473 "searchDelay": null,
11474
11475
11476 /**
11477 * DataTables features four different built-in options for the buttons to
11478 * display for pagination control:
11479 *
11480 * * `simple` - 'Previous' and 'Next' buttons only
11481 * * 'simple_numbers` - 'Previous' and 'Next' buttons, plus page numbers
11482 * * `full` - 'First', 'Previous', 'Next' and 'Last' buttons
11483 * * `full_numbers` - 'First', 'Previous', 'Next' and 'Last' buttons, plus
11484 * page numbers
11485 *
11486 * Further methods can be added using {@link DataTable.ext.oPagination}.
11487 * @type string
11488 * @default simple_numbers
11489 *
11490 * @dtopt Options
11491 * @name DataTable.defaults.pagingType
11492 *
11493 * @example
11494 * $(document).ready( function() {
11495 * $('#example').dataTable( {
11496 * "pagingType": "full_numbers"
11497 * } );
11498 * } )
11499 */
11500 "sPaginationType": "simple_numbers",
11501
11502
11503 /**
11504 * Enable horizontal scrolling. When a table is too wide to fit into a
11505 * certain layout, or you have a large number of columns in the table, you
11506 * can enable x-scrolling to show the table in a viewport, which can be
11507 * scrolled. This property can be `true` which will allow the table to
11508 * scroll horizontally when needed, or any CSS unit, or a number (in which
11509 * case it will be treated as a pixel measurement). Setting as simply `true`
11510 * is recommended.
11511 * @type boolean|string
11512 * @default <i>blank string - i.e. disabled</i>
11513 *
11514 * @dtopt Features
11515 * @name DataTable.defaults.scrollX
11516 *
11517 * @example
11518 * $(document).ready( function() {
11519 * $('#example').dataTable( {
11520 * "scrollX": true,
11521 * "scrollCollapse": true
11522 * } );
11523 * } );
11524 */
11525 "sScrollX": "",
11526
11527
11528 /**
11529 * This property can be used to force a DataTable to use more width than it
11530 * might otherwise do when x-scrolling is enabled. For example if you have a
11531 * table which requires to be well spaced, this parameter is useful for
11532 * "over-sizing" the table, and thus forcing scrolling. This property can by
11533 * any CSS unit, or a number (in which case it will be treated as a pixel
11534 * measurement).
11535 * @type string
11536 * @default <i>blank string - i.e. disabled</i>
11537 *
11538 * @dtopt Options
11539 * @name DataTable.defaults.scrollXInner
11540 *
11541 * @example
11542 * $(document).ready( function() {
11543 * $('#example').dataTable( {
11544 * "scrollX": "100%",
11545 * "scrollXInner": "110%"
11546 * } );
11547 * } );
11548 */
11549 "sScrollXInner": "",
11550
11551
11552 /**
11553 * Enable vertical scrolling. Vertical scrolling will constrain the DataTable
11554 * to the given height, and enable scrolling for any data which overflows the
11555 * current viewport. This can be used as an alternative to paging to display
11556 * a lot of data in a small area (although paging and scrolling can both be
11557 * enabled at the same time). This property can be any CSS unit, or a number
11558 * (in which case it will be treated as a pixel measurement).
11559 * @type string
11560 * @default <i>blank string - i.e. disabled</i>
11561 *
11562 * @dtopt Features
11563 * @name DataTable.defaults.scrollY
11564 *
11565 * @example
11566 * $(document).ready( function() {
11567 * $('#example').dataTable( {
11568 * "scrollY": "200px",
11569 * "paginate": false
11570 * } );
11571 * } );
11572 */
11573 "sScrollY": "",
11574
11575
11576 /**
11577 * __Deprecated__ The functionality provided by this parameter has now been
11578 * superseded by that provided through `ajax`, which should be used instead.
11579 *
11580 * Set the HTTP method that is used to make the Ajax call for server-side
11581 * processing or Ajax sourced data.
11582 * @type string
11583 * @default GET
11584 *
11585 * @dtopt Options
11586 * @dtopt Server-side
11587 * @name DataTable.defaults.serverMethod
11588 *
11589 * @deprecated 1.10. Please use `ajax` for this functionality now.
11590 */
11591 "sServerMethod": "GET",
11592
11593
11594 /**
11595 * DataTables makes use of renderers when displaying HTML elements for
11596 * a table. These renderers can be added or modified by plug-ins to
11597 * generate suitable mark-up for a site. For example the Bootstrap
11598 * integration plug-in for DataTables uses a paging button renderer to
11599 * display pagination buttons in the mark-up required by Bootstrap.
11600 *
11601 * For further information about the renderers available see
11602 * DataTable.ext.renderer
11603 * @type string|object
11604 * @default null
11605 *
11606 * @name DataTable.defaults.renderer
11607 *
11608 */
11609 "renderer": null
11610 };
11611
11612 _fnHungarianMap( DataTable.defaults );
11613
11614
11615
11616 /*
11617 * Developer note - See note in model.defaults.js about the use of Hungarian
11618 * notation and camel case.
11619 */
11620
11621 /**
11622 * Column options that can be given to DataTables at initialisation time.
11623 * @namespace
11624 */
11625 DataTable.defaults.column = {
11626 /**
11627 * Define which column(s) an order will occur on for this column. This
11628 * allows a column's ordering to take multiple columns into account when
11629 * doing a sort or use the data from a different column. For example first
11630 * name / last name columns make sense to do a multi-column sort over the
11631 * two columns.
11632 * @type array|int
11633 * @default null <i>Takes the value of the column index automatically</i>
11634 *
11635 * @name DataTable.defaults.column.orderData
11636 * @dtopt Columns
11637 *
11638 * @example
11639 * // Using `columnDefs`
11640 * $(document).ready( function() {
11641 * $('#example').dataTable( {
11642 * "columnDefs": [
11643 * { "orderData": [ 0, 1 ], "targets": [ 0 ] },
11644 * { "orderData": [ 1, 0 ], "targets": [ 1 ] },
11645 * { "orderData": 2, "targets": [ 2 ] }
11646 * ]
11647 * } );
11648 * } );
11649 *
11650 * @example
11651 * // Using `columns`
11652 * $(document).ready( function() {
11653 * $('#example').dataTable( {
11654 * "columns": [
11655 * { "orderData": [ 0, 1 ] },
11656 * { "orderData": [ 1, 0 ] },
11657 * { "orderData": 2 },
11658 * null,
11659 * null
11660 * ]
11661 * } );
11662 * } );
11663 */
11664 "aDataSort": null,
11665 "iDataSort": -1,
11666
11667
11668 /**
11669 * You can control the default ordering direction, and even alter the
11670 * behaviour of the sort handler (i.e. only allow ascending ordering etc)
11671 * using this parameter.
11672 * @type array
11673 * @default [ 'asc', 'desc' ]
11674 *
11675 * @name DataTable.defaults.column.orderSequence
11676 * @dtopt Columns
11677 *
11678 * @example
11679 * // Using `columnDefs`
11680 * $(document).ready( function() {
11681 * $('#example').dataTable( {
11682 * "columnDefs": [
11683 * { "orderSequence": [ "asc" ], "targets": [ 1 ] },
11684 * { "orderSequence": [ "desc", "asc", "asc" ], "targets": [ 2 ] },
11685 * { "orderSequence": [ "desc" ], "targets": [ 3 ] }
11686 * ]
11687 * } );
11688 * } );
11689 *
11690 * @example
11691 * // Using `columns`
11692 * $(document).ready( function() {
11693 * $('#example').dataTable( {
11694 * "columns": [
11695 * null,
11696 * { "orderSequence": [ "asc" ] },
11697 * { "orderSequence": [ "desc", "asc", "asc" ] },
11698 * { "orderSequence": [ "desc" ] },
11699 * null
11700 * ]
11701 * } );
11702 * } );
11703 */
11704 "asSorting": [ 'asc', 'desc' ],
11705
11706
11707 /**
11708 * Enable or disable filtering on the data in this column.
11709 * @type boolean
11710 * @default true
11711 *
11712 * @name DataTable.defaults.column.searchable
11713 * @dtopt Columns
11714 *
11715 * @example
11716 * // Using `columnDefs`
11717 * $(document).ready( function() {
11718 * $('#example').dataTable( {
11719 * "columnDefs": [
11720 * { "searchable": false, "targets": [ 0 ] }
11721 * ] } );
11722 * } );
11723 *
11724 * @example
11725 * // Using `columns`
11726 * $(document).ready( function() {
11727 * $('#example').dataTable( {
11728 * "columns": [
11729 * { "searchable": false },
11730 * null,
11731 * null,
11732 * null,
11733 * null
11734 * ] } );
11735 * } );
11736 */
11737 "bSearchable": true,
11738
11739
11740 /**
11741 * Enable or disable ordering on this column.
11742 * @type boolean
11743 * @default true
11744 *
11745 * @name DataTable.defaults.column.orderable
11746 * @dtopt Columns
11747 *
11748 * @example
11749 * // Using `columnDefs`
11750 * $(document).ready( function() {
11751 * $('#example').dataTable( {
11752 * "columnDefs": [
11753 * { "orderable": false, "targets": [ 0 ] }
11754 * ] } );
11755 * } );
11756 *
11757 * @example
11758 * // Using `columns`
11759 * $(document).ready( function() {
11760 * $('#example').dataTable( {
11761 * "columns": [
11762 * { "orderable": false },
11763 * null,
11764 * null,
11765 * null,
11766 * null
11767 * ] } );
11768 * } );
11769 */
11770 "bSortable": true,
11771
11772
11773 /**
11774 * Enable or disable the display of this column.
11775 * @type boolean
11776 * @default true
11777 *
11778 * @name DataTable.defaults.column.visible
11779 * @dtopt Columns
11780 *
11781 * @example
11782 * // Using `columnDefs`
11783 * $(document).ready( function() {
11784 * $('#example').dataTable( {
11785 * "columnDefs": [
11786 * { "visible": false, "targets": [ 0 ] }
11787 * ] } );
11788 * } );
11789 *
11790 * @example
11791 * // Using `columns`
11792 * $(document).ready( function() {
11793 * $('#example').dataTable( {
11794 * "columns": [
11795 * { "visible": false },
11796 * null,
11797 * null,
11798 * null,
11799 * null
11800 * ] } );
11801 * } );
11802 */
11803 "bVisible": true,
11804
11805
11806 /**
11807 * Developer definable function that is called whenever a cell is created (Ajax source,
11808 * etc) or processed for input (DOM source). This can be used as a compliment to mRender
11809 * allowing you to modify the DOM element (add background colour for example) when the
11810 * element is available.
11811 * @type function
11812 * @param {element} td The TD node that has been created
11813 * @param {*} cellData The Data for the cell
11814 * @param {array|object} rowData The data for the whole row
11815 * @param {int} row The row index for the aoData data store
11816 * @param {int} col The column index for aoColumns
11817 *
11818 * @name DataTable.defaults.column.createdCell
11819 * @dtopt Columns
11820 *
11821 * @example
11822 * $(document).ready( function() {
11823 * $('#example').dataTable( {
11824 * "columnDefs": [ {
11825 * "targets": [3],
11826 * "createdCell": function (td, cellData, rowData, row, col) {
11827 * if ( cellData == "1.7" ) {
11828 * $(td).css('color', 'blue')
11829 * }
11830 * }
11831 * } ]
11832 * });
11833 * } );
11834 */
11835 "fnCreatedCell": null,
11836
11837
11838 /**
11839 * This parameter has been replaced by `data` in DataTables to ensure naming
11840 * consistency. `dataProp` can still be used, as there is backwards
11841 * compatibility in DataTables for this option, but it is strongly
11842 * recommended that you use `data` in preference to `dataProp`.
11843 * @name DataTable.defaults.column.dataProp
11844 */
11845
11846
11847 /**
11848 * This property can be used to read data from any data source property,
11849 * including deeply nested objects / properties. `data` can be given in a
11850 * number of different ways which effect its behaviour:
11851 *
11852 * * `integer` - treated as an array index for the data source. This is the
11853 * default that DataTables uses (incrementally increased for each column).
11854 * * `string` - read an object property from the data source. There are
11855 * three 'special' options that can be used in the string to alter how
11856 * DataTables reads the data from the source object:
11857 * * `.` - Dotted Javascript notation. Just as you use a `.` in
11858 * Javascript to read from nested objects, so to can the options
11859 * specified in `data`. For example: `browser.version` or
11860 * `browser.name`. If your object parameter name contains a period, use
11861 * `\\` to escape it - i.e. `first\\.name`.
11862 * * `[]` - Array notation. DataTables can automatically combine data
11863 * from and array source, joining the data with the characters provided
11864 * between the two brackets. For example: `name[, ]` would provide a
11865 * comma-space separated list from the source array. If no characters
11866 * are provided between the brackets, the original array source is
11867 * returned.
11868 * * `()` - Function notation. Adding `()` to the end of a parameter will
11869 * execute a function of the name given. For example: `browser()` for a
11870 * simple function on the data source, `browser.version()` for a
11871 * function in a nested property or even `browser().version` to get an
11872 * object property if the function called returns an object. Note that
11873 * function notation is recommended for use in `render` rather than
11874 * `data` as it is much simpler to use as a renderer.
11875 * * `null` - use the original data source for the row rather than plucking
11876 * data directly from it. This action has effects on two other
11877 * initialisation options:
11878 * * `defaultContent` - When null is given as the `data` option and
11879 * `defaultContent` is specified for the column, the value defined by
11880 * `defaultContent` will be used for the cell.
11881 * * `render` - When null is used for the `data` option and the `render`
11882 * option is specified for the column, the whole data source for the
11883 * row is used for the renderer.
11884 * * `function` - the function given will be executed whenever DataTables
11885 * needs to set or get the data for a cell in the column. The function
11886 * takes three parameters:
11887 * * Parameters:
11888 * * `{array|object}` The data source for the row
11889 * * `{string}` The type call data requested - this will be 'set' when
11890 * setting data or 'filter', 'display', 'type', 'sort' or undefined
11891 * when gathering data. Note that when `undefined` is given for the
11892 * type DataTables expects to get the raw data for the object back<
11893 * * `{*}` Data to set when the second parameter is 'set'.
11894 * * Return:
11895 * * The return value from the function is not required when 'set' is
11896 * the type of call, but otherwise the return is what will be used
11897 * for the data requested.
11898 *
11899 * Note that `data` is a getter and setter option. If you just require
11900 * formatting of data for output, you will likely want to use `render` which
11901 * is simply a getter and thus simpler to use.
11902 *
11903 * Note that prior to DataTables 1.9.2 `data` was called `mDataProp`. The
11904 * name change reflects the flexibility of this property and is consistent
11905 * with the naming of mRender. If 'mDataProp' is given, then it will still
11906 * be used by DataTables, as it automatically maps the old name to the new
11907 * if required.
11908 *
11909 * @type string|int|function|null
11910 * @default null <i>Use automatically calculated column index</i>
11911 *
11912 * @name DataTable.defaults.column.data
11913 * @dtopt Columns
11914 *
11915 * @example
11916 * // Read table data from objects
11917 * // JSON structure for each row:
11918 * // {
11919 * // "engine": {value},
11920 * // "browser": {value},
11921 * // "platform": {value},
11922 * // "version": {value},
11923 * // "grade": {value}
11924 * // }
11925 * $(document).ready( function() {
11926 * $('#example').dataTable( {
11927 * "ajaxSource": "sources/objects.txt",
11928 * "columns": [
11929 * { "data": "engine" },
11930 * { "data": "browser" },
11931 * { "data": "platform" },
11932 * { "data": "version" },
11933 * { "data": "grade" }
11934 * ]
11935 * } );
11936 * } );
11937 *
11938 * @example
11939 * // Read information from deeply nested objects
11940 * // JSON structure for each row:
11941 * // {
11942 * // "engine": {value},
11943 * // "browser": {value},
11944 * // "platform": {
11945 * // "inner": {value}
11946 * // },
11947 * // "details": [
11948 * // {value}, {value}
11949 * // ]
11950 * // }
11951 * $(document).ready( function() {
11952 * $('#example').dataTable( {
11953 * "ajaxSource": "sources/deep.txt",
11954 * "columns": [
11955 * { "data": "engine" },
11956 * { "data": "browser" },
11957 * { "data": "platform.inner" },
11958 * { "data": "platform.details.0" },
11959 * { "data": "platform.details.1" }
11960 * ]
11961 * } );
11962 * } );
11963 *
11964 * @example
11965 * // Using `data` as a function to provide different information for
11966 * // sorting, filtering and display. In this case, currency (price)
11967 * $(document).ready( function() {
11968 * $('#example').dataTable( {
11969 * "columnDefs": [ {
11970 * "targets": [ 0 ],
11971 * "data": function ( source, type, val ) {
11972 * if (type === 'set') {
11973 * source.price = val;
11974 * // Store the computed dislay and filter values for efficiency
11975 * source.price_display = val=="" ? "" : "$"+numberFormat(val);
11976 * source.price_filter = val=="" ? "" : "$"+numberFormat(val)+" "+val;
11977 * return;
11978 * }
11979 * else if (type === 'display') {
11980 * return source.price_display;
11981 * }
11982 * else if (type === 'filter') {
11983 * return source.price_filter;
11984 * }
11985 * // 'sort', 'type' and undefined all just use the integer
11986 * return source.price;
11987 * }
11988 * } ]
11989 * } );
11990 * } );
11991 *
11992 * @example
11993 * // Using default content
11994 * $(document).ready( function() {
11995 * $('#example').dataTable( {
11996 * "columnDefs": [ {
11997 * "targets": [ 0 ],
11998 * "data": null,
11999 * "defaultContent": "Click to edit"
12000 * } ]
12001 * } );
12002 * } );
12003 *
12004 * @example
12005 * // Using array notation - outputting a list from an array
12006 * $(document).ready( function() {
12007 * $('#example').dataTable( {
12008 * "columnDefs": [ {
12009 * "targets": [ 0 ],
12010 * "data": "name[, ]"
12011 * } ]
12012 * } );
12013 * } );
12014 *
12015 */
12016 "mData": null,
12017
12018
12019 /**
12020 * This property is the rendering partner to `data` and it is suggested that
12021 * when you want to manipulate data for display (including filtering,
12022 * sorting etc) without altering the underlying data for the table, use this
12023 * property. `render` can be considered to be the the read only companion to
12024 * `data` which is read / write (then as such more complex). Like `data`
12025 * this option can be given in a number of different ways to effect its
12026 * behaviour:
12027 *
12028 * * `integer` - treated as an array index for the data source. This is the
12029 * default that DataTables uses (incrementally increased for each column).
12030 * * `string` - read an object property from the data source. There are
12031 * three 'special' options that can be used in the string to alter how
12032 * DataTables reads the data from the source object:
12033 * * `.` - Dotted Javascript notation. Just as you use a `.` in
12034 * Javascript to read from nested objects, so to can the options
12035 * specified in `data`. For example: `browser.version` or
12036 * `browser.name`. If your object parameter name contains a period, use
12037 * `\\` to escape it - i.e. `first\\.name`.
12038 * * `[]` - Array notation. DataTables can automatically combine data
12039 * from and array source, joining the data with the characters provided
12040 * between the two brackets. For example: `name[, ]` would provide a
12041 * comma-space separated list from the source array. If no characters
12042 * are provided between the brackets, the original array source is
12043 * returned.
12044 * * `()` - Function notation. Adding `()` to the end of a parameter will
12045 * execute a function of the name given. For example: `browser()` for a
12046 * simple function on the data source, `browser.version()` for a
12047 * function in a nested property or even `browser().version` to get an
12048 * object property if the function called returns an object.
12049 * * `object` - use different data for the different data types requested by
12050 * DataTables ('filter', 'display', 'type' or 'sort'). The property names
12051 * of the object is the data type the property refers to and the value can
12052 * defined using an integer, string or function using the same rules as
12053 * `render` normally does. Note that an `_` option _must_ be specified.
12054 * This is the default value to use if you haven't specified a value for
12055 * the data type requested by DataTables.
12056 * * `function` - the function given will be executed whenever DataTables
12057 * needs to set or get the data for a cell in the column. The function
12058 * takes three parameters:
12059 * * Parameters:
12060 * * {array|object} The data source for the row (based on `data`)
12061 * * {string} The type call data requested - this will be 'filter',
12062 * 'display', 'type' or 'sort'.
12063 * * {array|object} The full data source for the row (not based on
12064 * `data`)
12065 * * Return:
12066 * * The return value from the function is what will be used for the
12067 * data requested.
12068 *
12069 * @type string|int|function|object|null
12070 * @default null Use the data source value.
12071 *
12072 * @name DataTable.defaults.column.render
12073 * @dtopt Columns
12074 *
12075 * @example
12076 * // Create a comma separated list from an array of objects
12077 * $(document).ready( function() {
12078 * $('#example').dataTable( {
12079 * "ajaxSource": "sources/deep.txt",
12080 * "columns": [
12081 * { "data": "engine" },
12082 * { "data": "browser" },
12083 * {
12084 * "data": "platform",
12085 * "render": "[, ].name"
12086 * }
12087 * ]
12088 * } );
12089 * } );
12090 *
12091 * @example
12092 * // Execute a function to obtain data
12093 * $(document).ready( function() {
12094 * $('#example').dataTable( {
12095 * "columnDefs": [ {
12096 * "targets": [ 0 ],
12097 * "data": null, // Use the full data source object for the renderer's source
12098 * "render": "browserName()"
12099 * } ]
12100 * } );
12101 * } );
12102 *
12103 * @example
12104 * // As an object, extracting different data for the different types
12105 * // This would be used with a data source such as:
12106 * // { "phone": 5552368, "phone_filter": "5552368 555-2368", "phone_display": "555-2368" }
12107 * // Here the `phone` integer is used for sorting and type detection, while `phone_filter`
12108 * // (which has both forms) is used for filtering for if a user inputs either format, while
12109 * // the formatted phone number is the one that is shown in the table.
12110 * $(document).ready( function() {
12111 * $('#example').dataTable( {
12112 * "columnDefs": [ {
12113 * "targets": [ 0 ],
12114 * "data": null, // Use the full data source object for the renderer's source
12115 * "render": {
12116 * "_": "phone",
12117 * "filter": "phone_filter",
12118 * "display": "phone_display"
12119 * }
12120 * } ]
12121 * } );
12122 * } );
12123 *
12124 * @example
12125 * // Use as a function to create a link from the data source
12126 * $(document).ready( function() {
12127 * $('#example').dataTable( {
12128 * "columnDefs": [ {
12129 * "targets": [ 0 ],
12130 * "data": "download_link",
12131 * "render": function ( data, type, full ) {
12132 * return '<a href="'+data+'">Download</a>';
12133 * }
12134 * } ]
12135 * } );
12136 * } );
12137 */
12138 "mRender": null,
12139
12140
12141 /**
12142 * Change the cell type created for the column - either TD cells or TH cells. This
12143 * can be useful as TH cells have semantic meaning in the table body, allowing them
12144 * to act as a header for a row (you may wish to add scope='row' to the TH elements).
12145 * @type string
12146 * @default td
12147 *
12148 * @name DataTable.defaults.column.cellType
12149 * @dtopt Columns
12150 *
12151 * @example
12152 * // Make the first column use TH cells
12153 * $(document).ready( function() {
12154 * $('#example').dataTable( {
12155 * "columnDefs": [ {
12156 * "targets": [ 0 ],
12157 * "cellType": "th"
12158 * } ]
12159 * } );
12160 * } );
12161 */
12162 "sCellType": "td",
12163
12164
12165 /**
12166 * Class to give to each cell in this column.
12167 * @type string
12168 * @default <i>Empty string</i>
12169 *
12170 * @name DataTable.defaults.column.class
12171 * @dtopt Columns
12172 *
12173 * @example
12174 * // Using `columnDefs`
12175 * $(document).ready( function() {
12176 * $('#example').dataTable( {
12177 * "columnDefs": [
12178 * { "class": "my_class", "targets": [ 0 ] }
12179 * ]
12180 * } );
12181 * } );
12182 *
12183 * @example
12184 * // Using `columns`
12185 * $(document).ready( function() {
12186 * $('#example').dataTable( {
12187 * "columns": [
12188 * { "class": "my_class" },
12189 * null,
12190 * null,
12191 * null,
12192 * null
12193 * ]
12194 * } );
12195 * } );
12196 */
12197 "sClass": "",
12198
12199 /**
12200 * When DataTables calculates the column widths to assign to each column,
12201 * it finds the longest string in each column and then constructs a
12202 * temporary table and reads the widths from that. The problem with this
12203 * is that "mmm" is much wider then "iiii", but the latter is a longer
12204 * string - thus the calculation can go wrong (doing it properly and putting
12205 * it into an DOM object and measuring that is horribly(!) slow). Thus as
12206 * a "work around" we provide this option. It will append its value to the
12207 * text that is found to be the longest string for the column - i.e. padding.
12208 * Generally you shouldn't need this!
12209 * @type string
12210 * @default <i>Empty string<i>
12211 *
12212 * @name DataTable.defaults.column.contentPadding
12213 * @dtopt Columns
12214 *
12215 * @example
12216 * // Using `columns`
12217 * $(document).ready( function() {
12218 * $('#example').dataTable( {
12219 * "columns": [
12220 * null,
12221 * null,
12222 * null,
12223 * {
12224 * "contentPadding": "mmm"
12225 * }
12226 * ]
12227 * } );
12228 * } );
12229 */
12230 "sContentPadding": "",
12231
12232
12233 /**
12234 * Allows a default value to be given for a column's data, and will be used
12235 * whenever a null data source is encountered (this can be because `data`
12236 * is set to null, or because the data source itself is null).
12237 * @type string
12238 * @default null
12239 *
12240 * @name DataTable.defaults.column.defaultContent
12241 * @dtopt Columns
12242 *
12243 * @example
12244 * // Using `columnDefs`
12245 * $(document).ready( function() {
12246 * $('#example').dataTable( {
12247 * "columnDefs": [
12248 * {
12249 * "data": null,
12250 * "defaultContent": "Edit",
12251 * "targets": [ -1 ]
12252 * }
12253 * ]
12254 * } );
12255 * } );
12256 *
12257 * @example
12258 * // Using `columns`
12259 * $(document).ready( function() {
12260 * $('#example').dataTable( {
12261 * "columns": [
12262 * null,
12263 * null,
12264 * null,
12265 * {
12266 * "data": null,
12267 * "defaultContent": "Edit"
12268 * }
12269 * ]
12270 * } );
12271 * } );
12272 */
12273 "sDefaultContent": null,
12274
12275
12276 /**
12277 * This parameter is only used in DataTables' server-side processing. It can
12278 * be exceptionally useful to know what columns are being displayed on the
12279 * client side, and to map these to database fields. When defined, the names
12280 * also allow DataTables to reorder information from the server if it comes
12281 * back in an unexpected order (i.e. if you switch your columns around on the
12282 * client-side, your server-side code does not also need updating).
12283 * @type string
12284 * @default <i>Empty string</i>
12285 *
12286 * @name DataTable.defaults.column.name
12287 * @dtopt Columns
12288 *
12289 * @example
12290 * // Using `columnDefs`
12291 * $(document).ready( function() {
12292 * $('#example').dataTable( {
12293 * "columnDefs": [
12294 * { "name": "engine", "targets": [ 0 ] },
12295 * { "name": "browser", "targets": [ 1 ] },
12296 * { "name": "platform", "targets": [ 2 ] },
12297 * { "name": "version", "targets": [ 3 ] },
12298 * { "name": "grade", "targets": [ 4 ] }
12299 * ]
12300 * } );
12301 * } );
12302 *
12303 * @example
12304 * // Using `columns`
12305 * $(document).ready( function() {
12306 * $('#example').dataTable( {
12307 * "columns": [
12308 * { "name": "engine" },
12309 * { "name": "browser" },
12310 * { "name": "platform" },
12311 * { "name": "version" },
12312 * { "name": "grade" }
12313 * ]
12314 * } );
12315 * } );
12316 */
12317 "sName": "",
12318
12319
12320 /**
12321 * Defines a data source type for the ordering which can be used to read
12322 * real-time information from the table (updating the internally cached
12323 * version) prior to ordering. This allows ordering to occur on user
12324 * editable elements such as form inputs.
12325 * @type string
12326 * @default std
12327 *
12328 * @name DataTable.defaults.column.orderDataType
12329 * @dtopt Columns
12330 *
12331 * @example
12332 * // Using `columnDefs`
12333 * $(document).ready( function() {
12334 * $('#example').dataTable( {
12335 * "columnDefs": [
12336 * { "orderDataType": "dom-text", "targets": [ 2, 3 ] },
12337 * { "type": "numeric", "targets": [ 3 ] },
12338 * { "orderDataType": "dom-select", "targets": [ 4 ] },
12339 * { "orderDataType": "dom-checkbox", "targets": [ 5 ] }
12340 * ]
12341 * } );
12342 * } );
12343 *
12344 * @example
12345 * // Using `columns`
12346 * $(document).ready( function() {
12347 * $('#example').dataTable( {
12348 * "columns": [
12349 * null,
12350 * null,
12351 * { "orderDataType": "dom-text" },
12352 * { "orderDataType": "dom-text", "type": "numeric" },
12353 * { "orderDataType": "dom-select" },
12354 * { "orderDataType": "dom-checkbox" }
12355 * ]
12356 * } );
12357 * } );
12358 */
12359 "sSortDataType": "std",
12360
12361
12362 /**
12363 * The title of this column.
12364 * @type string
12365 * @default null <i>Derived from the 'TH' value for this column in the
12366 * original HTML table.</i>
12367 *
12368 * @name DataTable.defaults.column.title
12369 * @dtopt Columns
12370 *
12371 * @example
12372 * // Using `columnDefs`
12373 * $(document).ready( function() {
12374 * $('#example').dataTable( {
12375 * "columnDefs": [
12376 * { "title": "My column title", "targets": [ 0 ] }
12377 * ]
12378 * } );
12379 * } );
12380 *
12381 * @example
12382 * // Using `columns`
12383 * $(document).ready( function() {
12384 * $('#example').dataTable( {
12385 * "columns": [
12386 * { "title": "My column title" },
12387 * null,
12388 * null,
12389 * null,
12390 * null
12391 * ]
12392 * } );
12393 * } );
12394 */
12395 "sTitle": null,
12396
12397
12398 /**
12399 * The type allows you to specify how the data for this column will be
12400 * ordered. Four types (string, numeric, date and html (which will strip
12401 * HTML tags before ordering)) are currently available. Note that only date
12402 * formats understood by Javascript's Date() object will be accepted as type
12403 * date. For example: "Mar 26, 2008 5:03 PM". May take the values: 'string',
12404 * 'numeric', 'date' or 'html' (by default). Further types can be adding
12405 * through plug-ins.
12406 * @type string
12407 * @default null <i>Auto-detected from raw data</i>
12408 *
12409 * @name DataTable.defaults.column.type
12410 * @dtopt Columns
12411 *
12412 * @example
12413 * // Using `columnDefs`
12414 * $(document).ready( function() {
12415 * $('#example').dataTable( {
12416 * "columnDefs": [
12417 * { "type": "html", "targets": [ 0 ] }
12418 * ]
12419 * } );
12420 * } );
12421 *
12422 * @example
12423 * // Using `columns`
12424 * $(document).ready( function() {
12425 * $('#example').dataTable( {
12426 * "columns": [
12427 * { "type": "html" },
12428 * null,
12429 * null,
12430 * null,
12431 * null
12432 * ]
12433 * } );
12434 * } );
12435 */
12436 "sType": null,
12437
12438
12439 /**
12440 * Defining the width of the column, this parameter may take any CSS value
12441 * (3em, 20px etc). DataTables applies 'smart' widths to columns which have not
12442 * been given a specific width through this interface ensuring that the table
12443 * remains readable.
12444 * @type string
12445 * @default null <i>Automatic</i>
12446 *
12447 * @name DataTable.defaults.column.width
12448 * @dtopt Columns
12449 *
12450 * @example
12451 * // Using `columnDefs`
12452 * $(document).ready( function() {
12453 * $('#example').dataTable( {
12454 * "columnDefs": [
12455 * { "width": "20%", "targets": [ 0 ] }
12456 * ]
12457 * } );
12458 * } );
12459 *
12460 * @example
12461 * // Using `columns`
12462 * $(document).ready( function() {
12463 * $('#example').dataTable( {
12464 * "columns": [
12465 * { "width": "20%" },
12466 * null,
12467 * null,
12468 * null,
12469 * null
12470 * ]
12471 * } );
12472 * } );
12473 */
12474 "sWidth": null
12475 };
12476
12477 _fnHungarianMap( DataTable.defaults.column );
12478
12479
12480
12481 /**
12482 * DataTables settings object - this holds all the information needed for a
12483 * given table, including configuration, data and current application of the
12484 * table options. DataTables does not have a single instance for each DataTable
12485 * with the settings attached to that instance, but rather instances of the
12486 * DataTable "class" are created on-the-fly as needed (typically by a
12487 * $().dataTable() call) and the settings object is then applied to that
12488 * instance.
12489 *
12490 * Note that this object is related to {@link DataTable.defaults} but this
12491 * one is the internal data store for DataTables's cache of columns. It should
12492 * NOT be manipulated outside of DataTables. Any configuration should be done
12493 * through the initialisation options.
12494 * @namespace
12495 * @todo Really should attach the settings object to individual instances so we
12496 * don't need to create new instances on each $().dataTable() call (if the
12497 * table already exists). It would also save passing oSettings around and
12498 * into every single function. However, this is a very significant
12499 * architecture change for DataTables and will almost certainly break
12500 * backwards compatibility with older installations. This is something that
12501 * will be done in 2.0.
12502 */
12503 DataTable.models.oSettings = {
12504 /**
12505 * Primary features of DataTables and their enablement state.
12506 * @namespace
12507 */
12508 "oFeatures": {
12509
12510 /**
12511 * Flag to say if DataTables should automatically try to calculate the
12512 * optimum table and columns widths (true) or not (false).
12513 * Note that this parameter will be set by the initialisation routine. To
12514 * set a default use {@link DataTable.defaults}.
12515 * @type boolean
12516 */
12517 "bAutoWidth": null,
12518
12519 /**
12520 * Delay the creation of TR and TD elements until they are actually
12521 * needed by a driven page draw. This can give a significant speed
12522 * increase for Ajax source and Javascript source data, but makes no
12523 * difference at all fro DOM and server-side processing tables.
12524 * Note that this parameter will be set by the initialisation routine. To
12525 * set a default use {@link DataTable.defaults}.
12526 * @type boolean
12527 */
12528 "bDeferRender": null,
12529
12530 /**
12531 * Enable filtering on the table or not. Note that if this is disabled
12532 * then there is no filtering at all on the table, including fnFilter.
12533 * To just remove the filtering input use sDom and remove the 'f' option.
12534 * Note that this parameter will be set by the initialisation routine. To
12535 * set a default use {@link DataTable.defaults}.
12536 * @type boolean
12537 */
12538 "bFilter": null,
12539
12540 /**
12541 * Table information element (the 'Showing x of y records' div) enable
12542 * flag.
12543 * Note that this parameter will be set by the initialisation routine. To
12544 * set a default use {@link DataTable.defaults}.
12545 * @type boolean
12546 */
12547 "bInfo": null,
12548
12549 /**
12550 * Present a user control allowing the end user to change the page size
12551 * when pagination is enabled.
12552 * Note that this parameter will be set by the initialisation routine. To
12553 * set a default use {@link DataTable.defaults}.
12554 * @type boolean
12555 */
12556 "bLengthChange": null,
12557
12558 /**
12559 * Pagination enabled or not. Note that if this is disabled then length
12560 * changing must also be disabled.
12561 * Note that this parameter will be set by the initialisation routine. To
12562 * set a default use {@link DataTable.defaults}.
12563 * @type boolean
12564 */
12565 "bPaginate": null,
12566
12567 /**
12568 * Processing indicator enable flag whenever DataTables is enacting a
12569 * user request - typically an Ajax request for server-side processing.
12570 * Note that this parameter will be set by the initialisation routine. To
12571 * set a default use {@link DataTable.defaults}.
12572 * @type boolean
12573 */
12574 "bProcessing": null,
12575
12576 /**
12577 * Server-side processing enabled flag - when enabled DataTables will
12578 * get all data from the server for every draw - there is no filtering,
12579 * sorting or paging done on the client-side.
12580 * Note that this parameter will be set by the initialisation routine. To
12581 * set a default use {@link DataTable.defaults}.
12582 * @type boolean
12583 */
12584 "bServerSide": null,
12585
12586 /**
12587 * Sorting enablement flag.
12588 * Note that this parameter will be set by the initialisation routine. To
12589 * set a default use {@link DataTable.defaults}.
12590 * @type boolean
12591 */
12592 "bSort": null,
12593
12594 /**
12595 * Multi-column sorting
12596 * Note that this parameter will be set by the initialisation routine. To
12597 * set a default use {@link DataTable.defaults}.
12598 * @type boolean
12599 */
12600 "bSortMulti": null,
12601
12602 /**
12603 * Apply a class to the columns which are being sorted to provide a
12604 * visual highlight or not. This can slow things down when enabled since
12605 * there is a lot of DOM interaction.
12606 * Note that this parameter will be set by the initialisation routine. To
12607 * set a default use {@link DataTable.defaults}.
12608 * @type boolean
12609 */
12610 "bSortClasses": null,
12611
12612 /**
12613 * State saving enablement flag.
12614 * Note that this parameter will be set by the initialisation routine. To
12615 * set a default use {@link DataTable.defaults}.
12616 * @type boolean
12617 */
12618 "bStateSave": null
12619 },
12620
12621
12622 /**
12623 * Scrolling settings for a table.
12624 * @namespace
12625 */
12626 "oScroll": {
12627 /**
12628 * When the table is shorter in height than sScrollY, collapse the
12629 * table container down to the height of the table (when true).
12630 * Note that this parameter will be set by the initialisation routine. To
12631 * set a default use {@link DataTable.defaults}.
12632 * @type boolean
12633 */
12634 "bCollapse": null,
12635
12636 /**
12637 * Width of the scrollbar for the web-browser's platform. Calculated
12638 * during table initialisation.
12639 * @type int
12640 * @default 0
12641 */
12642 "iBarWidth": 0,
12643
12644 /**
12645 * Viewport width for horizontal scrolling. Horizontal scrolling is
12646 * disabled if an empty string.
12647 * Note that this parameter will be set by the initialisation routine. To
12648 * set a default use {@link DataTable.defaults}.
12649 * @type string
12650 */
12651 "sX": null,
12652
12653 /**
12654 * Width to expand the table to when using x-scrolling. Typically you
12655 * should not need to use this.
12656 * Note that this parameter will be set by the initialisation routine. To
12657 * set a default use {@link DataTable.defaults}.
12658 * @type string
12659 * @deprecated
12660 */
12661 "sXInner": null,
12662
12663 /**
12664 * Viewport height for vertical scrolling. Vertical scrolling is disabled
12665 * if an empty string.
12666 * Note that this parameter will be set by the initialisation routine. To
12667 * set a default use {@link DataTable.defaults}.
12668 * @type string
12669 */
12670 "sY": null
12671 },
12672
12673 /**
12674 * Language information for the table.
12675 * @namespace
12676 * @extends DataTable.defaults.oLanguage
12677 */
12678 "oLanguage": {
12679 /**
12680 * Information callback function. See
12681 * {@link DataTable.defaults.fnInfoCallback}
12682 * @type function
12683 * @default null
12684 */
12685 "fnInfoCallback": null
12686 },
12687
12688 /**
12689 * Browser support parameters
12690 * @namespace
12691 */
12692 "oBrowser": {
12693 /**
12694 * Indicate if the browser incorrectly calculates width:100% inside a
12695 * scrolling element (IE6/7)
12696 * @type boolean
12697 * @default false
12698 */
12699 "bScrollOversize": false,
12700
12701 /**
12702 * Determine if the vertical scrollbar is on the right or left of the
12703 * scrolling container - needed for rtl language layout, although not
12704 * all browsers move the scrollbar (Safari).
12705 * @type boolean
12706 * @default false
12707 */
12708 "bScrollbarLeft": false
12709 },
12710
12711
12712 "ajax": null,
12713
12714
12715 /**
12716 * Array referencing the nodes which are used for the features. The
12717 * parameters of this object match what is allowed by sDom - i.e.
12718 * <ul>
12719 * <li>'l' - Length changing</li>
12720 * <li>'f' - Filtering input</li>
12721 * <li>'t' - The table!</li>
12722 * <li>'i' - Information</li>
12723 * <li>'p' - Pagination</li>
12724 * <li>'r' - pRocessing</li>
12725 * </ul>
12726 * @type array
12727 * @default []
12728 */
12729 "aanFeatures": [],
12730
12731 /**
12732 * Store data information - see {@link DataTable.models.oRow} for detailed
12733 * information.
12734 * @type array
12735 * @default []
12736 */
12737 "aoData": [],
12738
12739 /**
12740 * Array of indexes which are in the current display (after filtering etc)
12741 * @type array
12742 * @default []
12743 */
12744 "aiDisplay": [],
12745
12746 /**
12747 * Array of indexes for display - no filtering
12748 * @type array
12749 * @default []
12750 */
12751 "aiDisplayMaster": [],
12752
12753 /**
12754 * Store information about each column that is in use
12755 * @type array
12756 * @default []
12757 */
12758 "aoColumns": [],
12759
12760 /**
12761 * Store information about the table's header
12762 * @type array
12763 * @default []
12764 */
12765 "aoHeader": [],
12766
12767 /**
12768 * Store information about the table's footer
12769 * @type array
12770 * @default []
12771 */
12772 "aoFooter": [],
12773
12774 /**
12775 * Store the applied global search information in case we want to force a
12776 * research or compare the old search to a new one.
12777 * Note that this parameter will be set by the initialisation routine. To
12778 * set a default use {@link DataTable.defaults}.
12779 * @namespace
12780 * @extends DataTable.models.oSearch
12781 */
12782 "oPreviousSearch": {},
12783
12784 /**
12785 * Store the applied search for each column - see
12786 * {@link DataTable.models.oSearch} for the format that is used for the
12787 * filtering information for each column.
12788 * @type array
12789 * @default []
12790 */
12791 "aoPreSearchCols": [],
12792
12793 /**
12794 * Sorting that is applied to the table. Note that the inner arrays are
12795 * used in the following manner:
12796 * <ul>
12797 * <li>Index 0 - column number</li>
12798 * <li>Index 1 - current sorting direction</li>
12799 * </ul>
12800 * Note that this parameter will be set by the initialisation routine. To
12801 * set a default use {@link DataTable.defaults}.
12802 * @type array
12803 * @todo These inner arrays should really be objects
12804 */
12805 "aaSorting": null,
12806
12807 /**
12808 * Sorting that is always applied to the table (i.e. prefixed in front of
12809 * aaSorting).
12810 * Note that this parameter will be set by the initialisation routine. To
12811 * set a default use {@link DataTable.defaults}.
12812 * @type array
12813 * @default []
12814 */
12815 "aaSortingFixed": [],
12816
12817 /**
12818 * Classes to use for the striping of a table.
12819 * Note that this parameter will be set by the initialisation routine. To
12820 * set a default use {@link DataTable.defaults}.
12821 * @type array
12822 * @default []
12823 */
12824 "asStripeClasses": null,
12825
12826 /**
12827 * If restoring a table - we should restore its striping classes as well
12828 * @type array
12829 * @default []
12830 */
12831 "asDestroyStripes": [],
12832
12833 /**
12834 * If restoring a table - we should restore its width
12835 * @type int
12836 * @default 0
12837 */
12838 "sDestroyWidth": 0,
12839
12840 /**
12841 * Callback functions array for every time a row is inserted (i.e. on a draw).
12842 * @type array
12843 * @default []
12844 */
12845 "aoRowCallback": [],
12846
12847 /**
12848 * Callback functions for the header on each draw.
12849 * @type array
12850 * @default []
12851 */
12852 "aoHeaderCallback": [],
12853
12854 /**
12855 * Callback function for the footer on each draw.
12856 * @type array
12857 * @default []
12858 */
12859 "aoFooterCallback": [],
12860
12861 /**
12862 * Array of callback functions for draw callback functions
12863 * @type array
12864 * @default []
12865 */
12866 "aoDrawCallback": [],
12867
12868 /**
12869 * Array of callback functions for row created function
12870 * @type array
12871 * @default []
12872 */
12873 "aoRowCreatedCallback": [],
12874
12875 /**
12876 * Callback functions for just before the table is redrawn. A return of
12877 * false will be used to cancel the draw.
12878 * @type array
12879 * @default []
12880 */
12881 "aoPreDrawCallback": [],
12882
12883 /**
12884 * Callback functions for when the table has been initialised.
12885 * @type array
12886 * @default []
12887 */
12888 "aoInitComplete": [],
12889
12890
12891 /**
12892 * Callbacks for modifying the settings to be stored for state saving, prior to
12893 * saving state.
12894 * @type array
12895 * @default []
12896 */
12897 "aoStateSaveParams": [],
12898
12899 /**
12900 * Callbacks for modifying the settings that have been stored for state saving
12901 * prior to using the stored values to restore the state.
12902 * @type array
12903 * @default []
12904 */
12905 "aoStateLoadParams": [],
12906
12907 /**
12908 * Callbacks for operating on the settings object once the saved state has been
12909 * loaded
12910 * @type array
12911 * @default []
12912 */
12913 "aoStateLoaded": [],
12914
12915 /**
12916 * Cache the table ID for quick access
12917 * @type string
12918 * @default <i>Empty string</i>
12919 */
12920 "sTableId": "",
12921
12922 /**
12923 * The TABLE node for the main table
12924 * @type node
12925 * @default null
12926 */
12927 "nTable": null,
12928
12929 /**
12930 * Permanent ref to the thead element
12931 * @type node
12932 * @default null
12933 */
12934 "nTHead": null,
12935
12936 /**
12937 * Permanent ref to the tfoot element - if it exists
12938 * @type node
12939 * @default null
12940 */
12941 "nTFoot": null,
12942
12943 /**
12944 * Permanent ref to the tbody element
12945 * @type node
12946 * @default null
12947 */
12948 "nTBody": null,
12949
12950 /**
12951 * Cache the wrapper node (contains all DataTables controlled elements)
12952 * @type node
12953 * @default null
12954 */
12955 "nTableWrapper": null,
12956
12957 /**
12958 * Indicate if when using server-side processing the loading of data
12959 * should be deferred until the second draw.
12960 * Note that this parameter will be set by the initialisation routine. To
12961 * set a default use {@link DataTable.defaults}.
12962 * @type boolean
12963 * @default false
12964 */
12965 "bDeferLoading": false,
12966
12967 /**
12968 * Indicate if all required information has been read in
12969 * @type boolean
12970 * @default false
12971 */
12972 "bInitialised": false,
12973
12974 /**
12975 * Information about open rows. Each object in the array has the parameters
12976 * 'nTr' and 'nParent'
12977 * @type array
12978 * @default []
12979 */
12980 "aoOpenRows": [],
12981
12982 /**
12983 * Dictate the positioning of DataTables' control elements - see
12984 * {@link DataTable.model.oInit.sDom}.
12985 * Note that this parameter will be set by the initialisation routine. To
12986 * set a default use {@link DataTable.defaults}.
12987 * @type string
12988 * @default null
12989 */
12990 "sDom": null,
12991
12992 /**
12993 * Search delay (in mS)
12994 * @type integer
12995 * @default null
12996 */
12997 "searchDelay": null,
12998
12999 /**
13000 * Which type of pagination should be used.
13001 * Note that this parameter will be set by the initialisation routine. To
13002 * set a default use {@link DataTable.defaults}.
13003 * @type string
13004 * @default two_button
13005 */
13006 "sPaginationType": "two_button",
13007
13008 /**
13009 * The state duration (for `stateSave`) in seconds.
13010 * Note that this parameter will be set by the initialisation routine. To
13011 * set a default use {@link DataTable.defaults}.
13012 * @type int
13013 * @default 0
13014 */
13015 "iStateDuration": 0,
13016
13017 /**
13018 * Array of callback functions for state saving. Each array element is an
13019 * object with the following parameters:
13020 * <ul>
13021 * <li>function:fn - function to call. Takes two parameters, oSettings
13022 * and the JSON string to save that has been thus far created. Returns
13023 * a JSON string to be inserted into a json object
13024 * (i.e. '"param": [ 0, 1, 2]')</li>
13025 * <li>string:sName - name of callback</li>
13026 * </ul>
13027 * @type array
13028 * @default []
13029 */
13030 "aoStateSave": [],
13031
13032 /**
13033 * Array of callback functions for state loading. Each array element is an
13034 * object with the following parameters:
13035 * <ul>
13036 * <li>function:fn - function to call. Takes two parameters, oSettings
13037 * and the object stored. May return false to cancel state loading</li>
13038 * <li>string:sName - name of callback</li>
13039 * </ul>
13040 * @type array
13041 * @default []
13042 */
13043 "aoStateLoad": [],
13044
13045 /**
13046 * State that was saved. Useful for back reference
13047 * @type object
13048 * @default null
13049 */
13050 "oSavedState": null,
13051
13052 /**
13053 * State that was loaded. Useful for back reference
13054 * @type object
13055 * @default null
13056 */
13057 "oLoadedState": null,
13058
13059 /**
13060 * Source url for AJAX data for the table.
13061 * Note that this parameter will be set by the initialisation routine. To
13062 * set a default use {@link DataTable.defaults}.
13063 * @type string
13064 * @default null
13065 */
13066 "sAjaxSource": null,
13067
13068 /**
13069 * Property from a given object from which to read the table data from. This
13070 * can be an empty string (when not server-side processing), in which case
13071 * it is assumed an an array is given directly.
13072 * Note that this parameter will be set by the initialisation routine. To
13073 * set a default use {@link DataTable.defaults}.
13074 * @type string
13075 */
13076 "sAjaxDataProp": null,
13077
13078 /**
13079 * Note if draw should be blocked while getting data
13080 * @type boolean
13081 * @default true
13082 */
13083 "bAjaxDataGet": true,
13084
13085 /**
13086 * The last jQuery XHR object that was used for server-side data gathering.
13087 * This can be used for working with the XHR information in one of the
13088 * callbacks
13089 * @type object
13090 * @default null
13091 */
13092 "jqXHR": null,
13093
13094 /**
13095 * JSON returned from the server in the last Ajax request
13096 * @type object
13097 * @default undefined
13098 */
13099 "json": undefined,
13100
13101 /**
13102 * Data submitted as part of the last Ajax request
13103 * @type object
13104 * @default undefined
13105 */
13106 "oAjaxData": undefined,
13107
13108 /**
13109 * Function to get the server-side data.
13110 * Note that this parameter will be set by the initialisation routine. To
13111 * set a default use {@link DataTable.defaults}.
13112 * @type function
13113 */
13114 "fnServerData": null,
13115
13116 /**
13117 * Functions which are called prior to sending an Ajax request so extra
13118 * parameters can easily be sent to the server
13119 * @type array
13120 * @default []
13121 */
13122 "aoServerParams": [],
13123
13124 /**
13125 * Send the XHR HTTP method - GET or POST (could be PUT or DELETE if
13126 * required).
13127 * Note that this parameter will be set by the initialisation routine. To
13128 * set a default use {@link DataTable.defaults}.
13129 * @type string
13130 */
13131 "sServerMethod": null,
13132
13133 /**
13134 * Format numbers for display.
13135 * Note that this parameter will be set by the initialisation routine. To
13136 * set a default use {@link DataTable.defaults}.
13137 * @type function
13138 */
13139 "fnFormatNumber": null,
13140
13141 /**
13142 * List of options that can be used for the user selectable length menu.
13143 * Note that this parameter will be set by the initialisation routine. To
13144 * set a default use {@link DataTable.defaults}.
13145 * @type array
13146 * @default []
13147 */
13148 "aLengthMenu": null,
13149
13150 /**
13151 * Counter for the draws that the table does. Also used as a tracker for
13152 * server-side processing
13153 * @type int
13154 * @default 0
13155 */
13156 "iDraw": 0,
13157
13158 /**
13159 * Indicate if a redraw is being done - useful for Ajax
13160 * @type boolean
13161 * @default false
13162 */
13163 "bDrawing": false,
13164
13165 /**
13166 * Draw index (iDraw) of the last error when parsing the returned data
13167 * @type int
13168 * @default -1
13169 */
13170 "iDrawError": -1,
13171
13172 /**
13173 * Paging display length
13174 * @type int
13175 * @default 10
13176 */
13177 "_iDisplayLength": 10,
13178
13179 /**
13180 * Paging start point - aiDisplay index
13181 * @type int
13182 * @default 0
13183 */
13184 "_iDisplayStart": 0,
13185
13186 /**
13187 * Server-side processing - number of records in the result set
13188 * (i.e. before filtering), Use fnRecordsTotal rather than
13189 * this property to get the value of the number of records, regardless of
13190 * the server-side processing setting.
13191 * @type int
13192 * @default 0
13193 * @private
13194 */
13195 "_iRecordsTotal": 0,
13196
13197 /**
13198 * Server-side processing - number of records in the current display set
13199 * (i.e. after filtering). Use fnRecordsDisplay rather than
13200 * this property to get the value of the number of records, regardless of
13201 * the server-side processing setting.
13202 * @type boolean
13203 * @default 0
13204 * @private
13205 */
13206 "_iRecordsDisplay": 0,
13207
13208 /**
13209 * Flag to indicate if jQuery UI marking and classes should be used.
13210 * Note that this parameter will be set by the initialisation routine. To
13211 * set a default use {@link DataTable.defaults}.
13212 * @type boolean
13213 */
13214 "bJUI": null,
13215
13216 /**
13217 * The classes to use for the table
13218 * @type object
13219 * @default {}
13220 */
13221 "oClasses": {},
13222
13223 /**
13224 * Flag attached to the settings object so you can check in the draw
13225 * callback if filtering has been done in the draw. Deprecated in favour of
13226 * events.
13227 * @type boolean
13228 * @default false
13229 * @deprecated
13230 */
13231 "bFiltered": false,
13232
13233 /**
13234 * Flag attached to the settings object so you can check in the draw
13235 * callback if sorting has been done in the draw. Deprecated in favour of
13236 * events.
13237 * @type boolean
13238 * @default false
13239 * @deprecated
13240 */
13241 "bSorted": false,
13242
13243 /**
13244 * Indicate that if multiple rows are in the header and there is more than
13245 * one unique cell per column, if the top one (true) or bottom one (false)
13246 * should be used for sorting / title by DataTables.
13247 * Note that this parameter will be set by the initialisation routine. To
13248 * set a default use {@link DataTable.defaults}.
13249 * @type boolean
13250 */
13251 "bSortCellsTop": null,
13252
13253 /**
13254 * Initialisation object that is used for the table
13255 * @type object
13256 * @default null
13257 */
13258 "oInit": null,
13259
13260 /**
13261 * Destroy callback functions - for plug-ins to attach themselves to the
13262 * destroy so they can clean up markup and events.
13263 * @type array
13264 * @default []
13265 */
13266 "aoDestroyCallback": [],
13267
13268
13269 /**
13270 * Get the number of records in the current record set, before filtering
13271 * @type function
13272 */
13273 "fnRecordsTotal": function ()
13274 {
13275 return _fnDataSource( this ) == 'ssp' ?
13276 this._iRecordsTotal * 1 :
13277 this.aiDisplayMaster.length;
13278 },
13279
13280 /**
13281 * Get the number of records in the current record set, after filtering
13282 * @type function
13283 */
13284 "fnRecordsDisplay": function ()
13285 {
13286 return _fnDataSource( this ) == 'ssp' ?
13287 this._iRecordsDisplay * 1 :
13288 this.aiDisplay.length;
13289 },
13290
13291 /**
13292 * Get the display end point - aiDisplay index
13293 * @type function
13294 */
13295 "fnDisplayEnd": function ()
13296 {
13297 var
13298 len = this._iDisplayLength,
13299 start = this._iDisplayStart,
13300 calc = start + len,
13301 records = this.aiDisplay.length,
13302 features = this.oFeatures,
13303 paginate = features.bPaginate;
13304
13305 if ( features.bServerSide ) {
13306 return paginate === false || len === -1 ?
13307 start + records :
13308 Math.min( start+len, this._iRecordsDisplay );
13309 }
13310 else {
13311 return ! paginate || calc>records || len===-1 ?
13312 records :
13313 calc;
13314 }
13315 },
13316
13317 /**
13318 * The DataTables object for this table
13319 * @type object
13320 * @default null
13321 */
13322 "oInstance": null,
13323
13324 /**
13325 * Unique identifier for each instance of the DataTables object. If there
13326 * is an ID on the table node, then it takes that value, otherwise an
13327 * incrementing internal counter is used.
13328 * @type string
13329 * @default null
13330 */
13331 "sInstance": null,
13332
13333 /**
13334 * tabindex attribute value that is added to DataTables control elements, allowing
13335 * keyboard navigation of the table and its controls.
13336 */
13337 "iTabIndex": 0,
13338
13339 /**
13340 * DIV container for the footer scrolling table if scrolling
13341 */
13342 "nScrollHead": null,
13343
13344 /**
13345 * DIV container for the footer scrolling table if scrolling
13346 */
13347 "nScrollFoot": null,
13348
13349 /**
13350 * Last applied sort
13351 * @type array
13352 * @default []
13353 */
13354 "aLastSort": [],
13355
13356 /**
13357 * Stored plug-in instances
13358 * @type object
13359 * @default {}
13360 */
13361 "oPlugins": {}
13362 };
13363
13364 /**
13365 * Extension object for DataTables that is used to provide all extension
13366 * options.
13367 *
13368 * Note that the `DataTable.ext` object is available through
13369 * `jQuery.fn.dataTable.ext` where it may be accessed and manipulated. It is
13370 * also aliased to `jQuery.fn.dataTableExt` for historic reasons.
13371 * @namespace
13372 * @extends DataTable.models.ext
13373 */
13374
13375
13376 /**
13377 * DataTables extensions
13378 *
13379 * This namespace acts as a collection area for plug-ins that can be used to
13380 * extend DataTables capabilities. Indeed many of the build in methods
13381 * use this method to provide their own capabilities (sorting methods for
13382 * example).
13383 *
13384 * Note that this namespace is aliased to `jQuery.fn.dataTableExt` for legacy
13385 * reasons
13386 *
13387 * @namespace
13388 */
13389 DataTable.ext = _ext = {
13390 /**
13391 * Element class names
13392 *
13393 * @type object
13394 * @default {}
13395 */
13396 classes: {},
13397
13398
13399 /**
13400 * Error reporting.
13401 *
13402 * How should DataTables report an error. Can take the value 'alert' or
13403 * 'throw'
13404 *
13405 * @type string
13406 * @default alert
13407 */
13408 errMode: "alert",
13409
13410
13411 /**
13412 * Feature plug-ins.
13413 *
13414 * This is an array of objects which describe the feature plug-ins that are
13415 * available to DataTables. These feature plug-ins are then available for
13416 * use through the `dom` initialisation option.
13417 *
13418 * Each feature plug-in is described by an object which must have the
13419 * following properties:
13420 *
13421 * * `fnInit` - function that is used to initialise the plug-in,
13422 * * `cFeature` - a character so the feature can be enabled by the `dom`
13423 * instillation option. This is case sensitive.
13424 *
13425 * The `fnInit` function has the following input parameters:
13426 *
13427 * 1. `{object}` DataTables settings object: see
13428 * {@link DataTable.models.oSettings}
13429 *
13430 * And the following return is expected:
13431 *
13432 * * {node|null} The element which contains your feature. Note that the
13433 * return may also be void if your plug-in does not require to inject any
13434 * DOM elements into DataTables control (`dom`) - for example this might
13435 * be useful when developing a plug-in which allows table control via
13436 * keyboard entry
13437 *
13438 * @type array
13439 *
13440 * @example
13441 * $.fn.dataTable.ext.features.push( {
13442 * "fnInit": function( oSettings ) {
13443 * return new TableTools( { "oDTSettings": oSettings } );
13444 * },
13445 * "cFeature": "T"
13446 * } );
13447 */
13448 feature: [],
13449
13450
13451 /**
13452 * Row searching.
13453 *
13454 * This method of searching is complimentary to the default type based
13455 * searching, and a lot more comprehensive as it allows you complete control
13456 * over the searching logic. Each element in this array is a function
13457 * (parameters described below) that is called for every row in the table,
13458 * and your logic decides if it should be included in the searching data set
13459 * or not.
13460 *
13461 * Searching functions have the following input parameters:
13462 *
13463 * 1. `{object}` DataTables settings object: see
13464 * {@link DataTable.models.oSettings}
13465 * 2. `{array|object}` Data for the row to be processed (same as the
13466 * original format that was passed in as the data source, or an array
13467 * from a DOM data source
13468 * 3. `{int}` Row index ({@link DataTable.models.oSettings.aoData}), which
13469 * can be useful to retrieve the `TR` element if you need DOM interaction.
13470 *
13471 * And the following return is expected:
13472 *
13473 * * {boolean} Include the row in the searched result set (true) or not
13474 * (false)
13475 *
13476 * Note that as with the main search ability in DataTables, technically this
13477 * is "filtering", since it is subtractive. However, for consistency in
13478 * naming we call it searching here.
13479 *
13480 * @type array
13481 * @default []
13482 *
13483 * @example
13484 * // The following example shows custom search being applied to the
13485 * // fourth column (i.e. the data[3] index) based on two input values
13486 * // from the end-user, matching the data in a certain range.
13487 * $.fn.dataTable.ext.search.push(
13488 * function( settings, data, dataIndex ) {
13489 * var min = document.getElementById('min').value * 1;
13490 * var max = document.getElementById('max').value * 1;
13491 * var version = data[3] == "-" ? 0 : data[3]*1;
13492 *
13493 * if ( min == "" && max == "" ) {
13494 * return true;
13495 * }
13496 * else if ( min == "" && version < max ) {
13497 * return true;
13498 * }
13499 * else if ( min < version && "" == max ) {
13500 * return true;
13501 * }
13502 * else if ( min < version && version < max ) {
13503 * return true;
13504 * }
13505 * return false;
13506 * }
13507 * );
13508 */
13509 search: [],
13510
13511
13512 /**
13513 * Internal functions, exposed for used in plug-ins.
13514 *
13515 * Please note that you should not need to use the internal methods for
13516 * anything other than a plug-in (and even then, try to avoid if possible).
13517 * The internal function may change between releases.
13518 *
13519 * @type object
13520 * @default {}
13521 */
13522 internal: {},
13523
13524
13525 /**
13526 * Legacy configuration options. Enable and disable legacy options that
13527 * are available in DataTables.
13528 *
13529 * @type object
13530 */
13531 legacy: {
13532 /**
13533 * Enable / disable DataTables 1.9 compatible server-side processing
13534 * requests
13535 *
13536 * @type boolean
13537 * @default null
13538 */
13539 ajax: null
13540 },
13541
13542
13543 /**
13544 * Pagination plug-in methods.
13545 *
13546 * Each entry in this object is a function and defines which buttons should
13547 * be shown by the pagination rendering method that is used for the table:
13548 * {@link DataTable.ext.renderer.pageButton}. The renderer addresses how the
13549 * buttons are displayed in the document, while the functions here tell it
13550 * what buttons to display. This is done by returning an array of button
13551 * descriptions (what each button will do).
13552 *
13553 * Pagination types (the four built in options and any additional plug-in
13554 * options defined here) can be used through the `paginationType`
13555 * initialisation parameter.
13556 *
13557 * The functions defined take two parameters:
13558 *
13559 * 1. `{int} page` The current page index
13560 * 2. `{int} pages` The number of pages in the table
13561 *
13562 * Each function is expected to return an array where each element of the
13563 * array can be one of:
13564 *
13565 * * `first` - Jump to first page when activated
13566 * * `last` - Jump to last page when activated
13567 * * `previous` - Show previous page when activated
13568 * * `next` - Show next page when activated
13569 * * `{int}` - Show page of the index given
13570 * * `{array}` - A nested array containing the above elements to add a
13571 * containing 'DIV' element (might be useful for styling).
13572 *
13573 * Note that DataTables v1.9- used this object slightly differently whereby
13574 * an object with two functions would be defined for each plug-in. That
13575 * ability is still supported by DataTables 1.10+ to provide backwards
13576 * compatibility, but this option of use is now decremented and no longer
13577 * documented in DataTables 1.10+.
13578 *
13579 * @type object
13580 * @default {}
13581 *
13582 * @example
13583 * // Show previous, next and current page buttons only
13584 * $.fn.dataTableExt.oPagination.current = function ( page, pages ) {
13585 * return [ 'previous', page, 'next' ];
13586 * };
13587 */
13588 pager: {},
13589
13590
13591 renderer: {
13592 pageButton: {},
13593 header: {}
13594 },
13595
13596
13597 /**
13598 * Ordering plug-ins - custom data source
13599 *
13600 * The extension options for ordering of data available here is complimentary
13601 * to the default type based ordering that DataTables typically uses. It
13602 * allows much greater control over the the data that is being used to
13603 * order a column, but is necessarily therefore more complex.
13604 *
13605 * This type of ordering is useful if you want to do ordering based on data
13606 * live from the DOM (for example the contents of an 'input' element) rather
13607 * than just the static string that DataTables knows of.
13608 *
13609 * The way these plug-ins work is that you create an array of the values you
13610 * wish to be ordering for the column in question and then return that
13611 * array. The data in the array much be in the index order of the rows in
13612 * the table (not the currently ordering order!). Which order data gathering
13613 * function is run here depends on the `dt-init columns.orderDataType`
13614 * parameter that is used for the column (if any).
13615 *
13616 * The functions defined take two parameters:
13617 *
13618 * 1. `{object}` DataTables settings object: see
13619 * {@link DataTable.models.oSettings}
13620 * 2. `{int}` Target column index
13621 *
13622 * Each function is expected to return an array:
13623 *
13624 * * `{array}` Data for the column to be ordering upon
13625 *
13626 * @type array
13627 *
13628 * @example
13629 * // Ordering using `input` node values
13630 * $.fn.dataTable.ext.order['dom-text'] = function ( settings, col )
13631 * {
13632 * return this.api().column( col, {order:'index'} ).nodes().map( function ( td, i ) {
13633 * return $('input', td).val();
13634 * } );
13635 * }
13636 */
13637 order: {},
13638
13639
13640 /**
13641 * Type based plug-ins.
13642 *
13643 * Each column in DataTables has a type assigned to it, either by automatic
13644 * detection or by direct assignment using the `type` option for the column.
13645 * The type of a column will effect how it is ordering and search (plug-ins
13646 * can also make use of the column type if required).
13647 *
13648 * @namespace
13649 */
13650 type: {
13651 /**
13652 * Type detection functions.
13653 *
13654 * The functions defined in this object are used to automatically detect
13655 * a column's type, making initialisation of DataTables super easy, even
13656 * when complex data is in the table.
13657 *
13658 * The functions defined take two parameters:
13659 *
13660 * 1. `{*}` Data from the column cell to be analysed
13661 * 2. `{settings}` DataTables settings object. This can be used to
13662 * perform context specific type detection - for example detection
13663 * based on language settings such as using a comma for a decimal
13664 * place. Generally speaking the options from the settings will not
13665 * be required
13666 *
13667 * Each function is expected to return:
13668 *
13669 * * `{string|null}` Data type detected, or null if unknown (and thus
13670 * pass it on to the other type detection functions.
13671 *
13672 * @type array
13673 *
13674 * @example
13675 * // Currency type detection plug-in:
13676 * $.fn.dataTable.ext.type.detect.push(
13677 * function ( data, settings ) {
13678 * // Check the numeric part
13679 * if ( ! $.isNumeric( data.substring(1) ) ) {
13680 * return null;
13681 * }
13682 *
13683 * // Check prefixed by currency
13684 * if ( data.charAt(0) == '$' || data.charAt(0) == '&pound;' ) {
13685 * return 'currency';
13686 * }
13687 * return null;
13688 * }
13689 * );
13690 */
13691 detect: [],
13692
13693
13694 /**
13695 * Type based search formatting.
13696 *
13697 * The type based searching functions can be used to pre-format the
13698 * data to be search on. For example, it can be used to strip HTML
13699 * tags or to de-format telephone numbers for numeric only searching.
13700 *
13701 * Note that is a search is not defined for a column of a given type,
13702 * no search formatting will be performed.
13703 *
13704 * Pre-processing of searching data plug-ins - When you assign the sType
13705 * for a column (or have it automatically detected for you by DataTables
13706 * or a type detection plug-in), you will typically be using this for
13707 * custom sorting, but it can also be used to provide custom searching
13708 * by allowing you to pre-processing the data and returning the data in
13709 * the format that should be searched upon. This is done by adding
13710 * functions this object with a parameter name which matches the sType
13711 * for that target column. This is the corollary of <i>afnSortData</i>
13712 * for searching data.
13713 *
13714 * The functions defined take a single parameter:
13715 *
13716 * 1. `{*}` Data from the column cell to be prepared for searching
13717 *
13718 * Each function is expected to return:
13719 *
13720 * * `{string|null}` Formatted string that will be used for the searching.
13721 *
13722 * @type object
13723 * @default {}
13724 *
13725 * @example
13726 * $.fn.dataTable.ext.type.search['title-numeric'] = function ( d ) {
13727 * return d.replace(/\n/g," ").replace( /<.*?>/g, "" );
13728 * }
13729 */
13730 search: {},
13731
13732
13733 /**
13734 * Type based ordering.
13735 *
13736 * The column type tells DataTables what ordering to apply to the table
13737 * when a column is sorted upon. The order for each type that is defined,
13738 * is defined by the functions available in this object.
13739 *
13740 * Each ordering option can be described by three properties added to
13741 * this object:
13742 *
13743 * * `{type}-pre` - Pre-formatting function
13744 * * `{type}-asc` - Ascending order function
13745 * * `{type}-desc` - Descending order function
13746 *
13747 * All three can be used together, only `{type}-pre` or only
13748 * `{type}-asc` and `{type}-desc` together. It is generally recommended
13749 * that only `{type}-pre` is used, as this provides the optimal
13750 * implementation in terms of speed, although the others are provided
13751 * for compatibility with existing Javascript sort functions.
13752 *
13753 * `{type}-pre`: Functions defined take a single parameter:
13754 *
13755 * 1. `{*}` Data from the column cell to be prepared for ordering
13756 *
13757 * And return:
13758 *
13759 * * `{*}` Data to be sorted upon
13760 *
13761 * `{type}-asc` and `{type}-desc`: Functions are typical Javascript sort
13762 * functions, taking two parameters:
13763 *
13764 * 1. `{*}` Data to compare to the second parameter
13765 * 2. `{*}` Data to compare to the first parameter
13766 *
13767 * And returning:
13768 *
13769 * * `{*}` Ordering match: <0 if first parameter should be sorted lower
13770 * than the second parameter, ===0 if the two parameters are equal and
13771 * >0 if the first parameter should be sorted height than the second
13772 * parameter.
13773 *
13774 * @type object
13775 * @default {}
13776 *
13777 * @example
13778 * // Numeric ordering of formatted numbers with a pre-formatter
13779 * $.extend( $.fn.dataTable.ext.type.order, {
13780 * "string-pre": function(x) {
13781 * a = (a === "-" || a === "") ? 0 : a.replace( /[^\d\-\.]/g, "" );
13782 * return parseFloat( a );
13783 * }
13784 * } );
13785 *
13786 * @example
13787 * // Case-sensitive string ordering, with no pre-formatting method
13788 * $.extend( $.fn.dataTable.ext.order, {
13789 * "string-case-asc": function(x,y) {
13790 * return ((x < y) ? -1 : ((x > y) ? 1 : 0));
13791 * },
13792 * "string-case-desc": function(x,y) {
13793 * return ((x < y) ? 1 : ((x > y) ? -1 : 0));
13794 * }
13795 * } );
13796 */
13797 order: {}
13798 },
13799
13800 /**
13801 * Unique DataTables instance counter
13802 *
13803 * @type int
13804 * @private
13805 */
13806 _unique: 0,
13807
13808
13809 //
13810 // Depreciated
13811 // The following properties are retained for backwards compatiblity only.
13812 // The should not be used in new projects and will be removed in a future
13813 // version
13814 //
13815
13816 /**
13817 * Version check function.
13818 * @type function
13819 * @depreciated Since 1.10
13820 */
13821 fnVersionCheck: DataTable.fnVersionCheck,
13822
13823
13824 /**
13825 * Index for what 'this' index API functions should use
13826 * @type int
13827 * @deprecated Since v1.10
13828 */
13829 iApiIndex: 0,
13830
13831
13832 /**
13833 * jQuery UI class container
13834 * @type object
13835 * @deprecated Since v1.10
13836 */
13837 oJUIClasses: {},
13838
13839
13840 /**
13841 * Software version
13842 * @type string
13843 * @deprecated Since v1.10
13844 */
13845 sVersion: DataTable.version
13846 };
13847
13848
13849 //
13850 // Backwards compatibility. Alias to pre 1.10 Hungarian notation counter parts
13851 //
13852 $.extend( _ext, {
13853 afnFiltering: _ext.search,
13854 aTypes: _ext.type.detect,
13855 ofnSearch: _ext.type.search,
13856 oSort: _ext.type.order,
13857 afnSortData: _ext.order,
13858 aoFeatures: _ext.feature,
13859 oApi: _ext.internal,
13860 oStdClasses: _ext.classes,
13861 oPagination: _ext.pager
13862 } );
13863
13864
13865 $.extend( DataTable.ext.classes, {
13866 "sTable": "dataTable",
13867 "sNoFooter": "no-footer",
13868
13869 /* Paging buttons */
13870 "sPageButton": "paginate_button",
13871 "sPageButtonActive": "current",
13872 "sPageButtonDisabled": "disabled",
13873
13874 /* Striping classes */
13875 "sStripeOdd": "odd",
13876 "sStripeEven": "even",
13877
13878 /* Empty row */
13879 "sRowEmpty": "dataTables_empty",
13880
13881 /* Features */
13882 "sWrapper": "dataTables_wrapper",
13883 "sFilter": "dataTables_filter",
13884 "sInfo": "dataTables_info",
13885 "sPaging": "dataTables_paginate paging_", /* Note that the type is postfixed */
13886 "sLength": "dataTables_length",
13887 "sProcessing": "dataTables_processing",
13888
13889 /* Sorting */
13890 "sSortAsc": "sorting_asc",
13891 "sSortDesc": "sorting_desc",
13892 "sSortable": "sorting", /* Sortable in both directions */
13893 "sSortableAsc": "sorting_asc_disabled",
13894 "sSortableDesc": "sorting_desc_disabled",
13895 "sSortableNone": "sorting_disabled",
13896 "sSortColumn": "sorting_", /* Note that an int is postfixed for the sorting order */
13897
13898 /* Filtering */
13899 "sFilterInput": "",
13900
13901 /* Page length */
13902 "sLengthSelect": "",
13903
13904 /* Scrolling */
13905 "sScrollWrapper": "dataTables_scroll",
13906 "sScrollHead": "dataTables_scrollHead",
13907 "sScrollHeadInner": "dataTables_scrollHeadInner",
13908 "sScrollBody": "dataTables_scrollBody",
13909 "sScrollFoot": "dataTables_scrollFoot",
13910 "sScrollFootInner": "dataTables_scrollFootInner",
13911
13912 /* Misc */
13913 "sHeaderTH": "",
13914 "sFooterTH": "",
13915
13916 // Deprecated
13917 "sSortJUIAsc": "",
13918 "sSortJUIDesc": "",
13919 "sSortJUI": "",
13920 "sSortJUIAscAllowed": "",
13921 "sSortJUIDescAllowed": "",
13922 "sSortJUIWrapper": "",
13923 "sSortIcon": "",
13924 "sJUIHeader": "",
13925 "sJUIFooter": ""
13926 } );
13927
13928
13929 (function() {
13930
13931 // Reused strings for better compression. Closure compiler appears to have a
13932 // weird edge case where it is trying to expand strings rather than use the
13933 // variable version. This results in about 200 bytes being added, for very
13934 // little preference benefit since it this run on script load only.
13935 var _empty = '';
13936 _empty = '';
13937
13938 var _stateDefault = _empty + 'ui-state-default';
13939 var _sortIcon = _empty + 'css_right ui-icon ui-icon-';
13940 var _headerFooter = _empty + 'fg-toolbar ui-toolbar ui-widget-header ui-helper-clearfix';
13941
13942 $.extend( DataTable.ext.oJUIClasses, DataTable.ext.classes, {
13943 /* Full numbers paging buttons */
13944 "sPageButton": "fg-button ui-button "+_stateDefault,
13945 "sPageButtonActive": "ui-state-disabled",
13946 "sPageButtonDisabled": "ui-state-disabled",
13947
13948 /* Features */
13949 "sPaging": "dataTables_paginate fg-buttonset ui-buttonset fg-buttonset-multi "+
13950 "ui-buttonset-multi paging_", /* Note that the type is postfixed */
13951
13952 /* Sorting */
13953 "sSortAsc": _stateDefault+" sorting_asc",
13954 "sSortDesc": _stateDefault+" sorting_desc",
13955 "sSortable": _stateDefault+" sorting",
13956 "sSortableAsc": _stateDefault+" sorting_asc_disabled",
13957 "sSortableDesc": _stateDefault+" sorting_desc_disabled",
13958 "sSortableNone": _stateDefault+" sorting_disabled",
13959 "sSortJUIAsc": _sortIcon+"triangle-1-n",
13960 "sSortJUIDesc": _sortIcon+"triangle-1-s",
13961 "sSortJUI": _sortIcon+"carat-2-n-s",
13962 "sSortJUIAscAllowed": _sortIcon+"carat-1-n",
13963 "sSortJUIDescAllowed": _sortIcon+"carat-1-s",
13964 "sSortJUIWrapper": "DataTables_sort_wrapper",
13965 "sSortIcon": "DataTables_sort_icon",
13966
13967 /* Scrolling */
13968 "sScrollHead": "dataTables_scrollHead "+_stateDefault,
13969 "sScrollFoot": "dataTables_scrollFoot "+_stateDefault,
13970
13971 /* Misc */
13972 "sHeaderTH": _stateDefault,
13973 "sFooterTH": _stateDefault,
13974 "sJUIHeader": _headerFooter+" ui-corner-tl ui-corner-tr",
13975 "sJUIFooter": _headerFooter+" ui-corner-bl ui-corner-br"
13976 } );
13977
13978 }());
13979
13980
13981
13982 var extPagination = DataTable.ext.pager;
13983
13984 function _numbers ( page, pages ) {
13985 var
13986 numbers = [],
13987 buttons = extPagination.numbers_length,
13988 half = Math.floor( buttons / 2 ),
13989 i = 1;
13990
13991 if ( pages <= buttons ) {
13992 numbers = _range( 0, pages );
13993 }
13994 else if ( page <= half ) {
13995 numbers = _range( 0, buttons-2 );
13996 numbers.push( 'ellipsis' );
13997 numbers.push( pages-1 );
13998 }
13999 else if ( page >= pages - 1 - half ) {
14000 numbers = _range( pages-(buttons-2), pages );
14001 numbers.splice( 0, 0, 'ellipsis' ); // no unshift in ie6
14002 numbers.splice( 0, 0, 0 );
14003 }
14004 else {
14005 numbers = _range( page-1, page+2 );
14006 numbers.push( 'ellipsis' );
14007 numbers.push( pages-1 );
14008 numbers.splice( 0, 0, 'ellipsis' );
14009 numbers.splice( 0, 0, 0 );
14010 }
14011
14012 numbers.DT_el = 'span';
14013 return numbers;
14014 }
14015
14016
14017 $.extend( extPagination, {
14018 simple: function ( page, pages ) {
14019 return [ 'previous', 'next' ];
14020 },
14021
14022 full: function ( page, pages ) {
14023 return [ 'first', 'previous', 'next', 'last' ];
14024 },
14025
14026 simple_numbers: function ( page, pages ) {
14027 return [ 'previous', _numbers(page, pages), 'next' ];
14028 },
14029
14030 full_numbers: function ( page, pages ) {
14031 return [ 'first', 'previous', _numbers(page, pages), 'next', 'last' ];
14032 },
14033
14034 // For testing and plug-ins to use
14035 _numbers: _numbers,
14036 numbers_length: 7
14037 } );
14038
14039
14040 $.extend( true, DataTable.ext.renderer, {
14041 pageButton: {
14042 _: function ( settings, host, idx, buttons, page, pages ) {
14043 var classes = settings.oClasses;
14044 var lang = settings.oLanguage.oPaginate;
14045 var btnDisplay, btnClass, counter=0;
14046
14047 var attach = function( container, buttons ) {
14048 var i, ien, node, button;
14049 var clickHandler = function ( e ) {
14050 _fnPageChange( settings, e.data.action, true );
14051 };
14052
14053 for ( i=0, ien=buttons.length ; i<ien ; i++ ) {
14054 button = buttons[i];
14055
14056 if ( $.isArray( button ) ) {
14057 var inner = $( '<'+(button.DT_el || 'div')+'/>' )
14058 .appendTo( container );
14059 attach( inner, button );
14060 }
14061 else {
14062 btnDisplay = '';
14063 btnClass = '';
14064
14065 switch ( button ) {
14066 case 'ellipsis':
14067 container.append('<span>&hellip;</span>');
14068 break;
14069
14070 case 'first':
14071 btnDisplay = lang.sFirst;
14072 btnClass = button + (page > 0 ?
14073 '' : ' '+classes.sPageButtonDisabled);
14074 break;
14075
14076 case 'previous':
14077 btnDisplay = lang.sPrevious;
14078 btnClass = button + (page > 0 ?
14079 '' : ' '+classes.sPageButtonDisabled);
14080 break;
14081
14082 case 'next':
14083 btnDisplay = lang.sNext;
14084 btnClass = button + (page < pages-1 ?
14085 '' : ' '+classes.sPageButtonDisabled);
14086 break;
14087
14088 case 'last':
14089 btnDisplay = lang.sLast;
14090 btnClass = button + (page < pages-1 ?
14091 '' : ' '+classes.sPageButtonDisabled);
14092 break;
14093
14094 default:
14095 btnDisplay = button + 1;
14096 btnClass = page === button ?
14097 classes.sPageButtonActive : '';
14098 break;
14099 }
14100
14101 if ( btnDisplay ) {
14102 node = $('<a>', {
14103 'class': classes.sPageButton+' '+btnClass,
14104 'aria-controls': settings.sTableId,
14105 'data-dt-idx': counter,
14106 'tabindex': settings.iTabIndex,
14107 'id': idx === 0 && typeof button === 'string' ?
14108 settings.sTableId +'_'+ button :
14109 null
14110 } )
14111 .html( btnDisplay )
14112 .appendTo( container );
14113
14114 _fnBindAction(
14115 node, {action: button}, clickHandler
14116 );
14117
14118 counter++;
14119 }
14120 }
14121 }
14122 };
14123
14124 // IE9 throws an 'unknown error' if document.activeElement is used
14125 // inside an iframe or frame. Try / catch the error. Not good for
14126 // accessibility, but neither are frames.
14127 try {
14128 // Because this approach is destroying and recreating the paging
14129 // elements, focus is lost on the select button which is bad for
14130 // accessibility. So we want to restore focus once the draw has
14131 // completed
14132 var activeEl = $(document.activeElement).data('dt-idx');
14133
14134 attach( $(host).empty(), buttons );
14135
14136 if ( activeEl !== null ) {
14137 $(host).find( '[data-dt-idx='+activeEl+']' ).focus();
14138 }
14139 }
14140 catch (e) {}
14141 }
14142 }
14143 } );
14144
14145
14146
14147 var __numericReplace = function ( d, decimalPlace, re1, re2 ) {
14148 if ( d !== 0 && (!d || d === '-') ) {
14149 return -Infinity;
14150 }
14151
14152 // If a decimal place other than `.` is used, it needs to be given to the
14153 // function so we can detect it and replace with a `.` which is the only
14154 // decimal place Javascript recognises - it is not locale aware.
14155 if ( decimalPlace ) {
14156 d = _numToDecimal( d, decimalPlace );
14157 }
14158
14159 if ( d.replace ) {
14160 if ( re1 ) {
14161 d = d.replace( re1, '' );
14162 }
14163
14164 if ( re2 ) {
14165 d = d.replace( re2, '' );
14166 }
14167 }
14168
14169 return d * 1;
14170 };
14171
14172
14173 // Add the numeric 'deformatting' functions for sorting. This is done in a
14174 // function to provide an easy ability for the language options to add
14175 // additional methods if a non-period decimal place is used.
14176 function _addNumericSort ( decimalPlace ) {
14177 $.each(
14178 {
14179 // Plain numbers
14180 "num": function ( d ) {
14181 return __numericReplace( d, decimalPlace );
14182 },
14183
14184 // Formatted numbers
14185 "num-fmt": function ( d ) {
14186 return __numericReplace( d, decimalPlace, _re_formatted_numeric );
14187 },
14188
14189 // HTML numeric
14190 "html-num": function ( d ) {
14191 return __numericReplace( d, decimalPlace, _re_html );
14192 },
14193
14194 // HTML numeric, formatted
14195 "html-num-fmt": function ( d ) {
14196 return __numericReplace( d, decimalPlace, _re_html, _re_formatted_numeric );
14197 }
14198 },
14199 function ( key, fn ) {
14200 _ext.type.order[ key+decimalPlace+'-pre' ] = fn;
14201 }
14202 );
14203 }
14204
14205
14206 // Default sort methods
14207 $.extend( _ext.type.order, {
14208 // Dates
14209 "date-pre": function ( d ) {
14210 return Date.parse( d ) || 0;
14211 },
14212
14213 // html
14214 "html-pre": function ( a ) {
14215 return _empty(a) ?
14216 '' :
14217 a.replace ?
14218 a.replace( /<.*?>/g, "" ).toLowerCase() :
14219 a+'';
14220 },
14221
14222 // string
14223 "string-pre": function ( a ) {
14224 // This is a little complex, but faster than always calling toString,
14225 // http://jsperf.com/tostring-v-check
14226 return _empty(a) ?
14227 '' :
14228 typeof a === 'string' ?
14229 a.toLowerCase() :
14230 ! a.toString ?
14231 '' :
14232 a.toString();
14233 },
14234
14235 // string-asc and -desc are retained only for compatibility with the old
14236 // sort methods
14237 "string-asc": function ( x, y ) {
14238 return ((x < y) ? -1 : ((x > y) ? 1 : 0));
14239 },
14240
14241 "string-desc": function ( x, y ) {
14242 return ((x < y) ? 1 : ((x > y) ? -1 : 0));
14243 }
14244 } );
14245
14246
14247 // Numeric sorting types - order doesn't matter here
14248 _addNumericSort( '' );
14249
14250
14251 // Built in type detection. See model.ext.aTypes for information about
14252 // what is required from this methods.
14253 $.extend( DataTable.ext.type.detect, [
14254 // Plain numbers - first since V8 detects some plain numbers as dates
14255 // e.g. Date.parse('55') (but not all, e.g. Date.parse('22')...).
14256 function ( d, settings )
14257 {
14258 var decimal = settings.oLanguage.sDecimal;
14259 return _isNumber( d, decimal ) ? 'num'+decimal : null;
14260 },
14261
14262 // Dates (only those recognised by the browser's Date.parse)
14263 function ( d, settings )
14264 {
14265 // V8 will remove any unknown characters at the start and end of the
14266 // expression, leading to false matches such as `$245.12` or `10%` being
14267 // a valid date. See forum thread 18941 for detail.
14268 if ( d && !(d instanceof Date) && ( ! _re_date_start.test(d) || ! _re_date_end.test(d) ) ) {
14269 return null;
14270 }
14271 var parsed = Date.parse(d);
14272 return (parsed !== null && !isNaN(parsed)) || _empty(d) ? 'date' : null;
14273 },
14274
14275 // Formatted numbers
14276 function ( d, settings )
14277 {
14278 var decimal = settings.oLanguage.sDecimal;
14279 return _isNumber( d, decimal, true ) ? 'num-fmt'+decimal : null;
14280 },
14281
14282 // HTML numeric
14283 function ( d, settings )
14284 {
14285 var decimal = settings.oLanguage.sDecimal;
14286 return _htmlNumeric( d, decimal ) ? 'html-num'+decimal : null;
14287 },
14288
14289 // HTML numeric, formatted
14290 function ( d, settings )
14291 {
14292 var decimal = settings.oLanguage.sDecimal;
14293 return _htmlNumeric( d, decimal, true ) ? 'html-num-fmt'+decimal : null;
14294 },
14295
14296 // HTML (this is strict checking - there must be html)
14297 function ( d, settings )
14298 {
14299 return _empty( d ) || (typeof d === 'string' && d.indexOf('<') !== -1) ?
14300 'html' : null;
14301 }
14302 ] );
14303
14304
14305
14306 // Filter formatting functions. See model.ext.ofnSearch for information about
14307 // what is required from these methods.
14308
14309
14310 $.extend( DataTable.ext.type.search, {
14311 html: function ( data ) {
14312 return _empty(data) ?
14313 data :
14314 typeof data === 'string' ?
14315 data
14316 .replace( _re_new_lines, " " )
14317 .replace( _re_html, "" ) :
14318 '';
14319 },
14320
14321 string: function ( data ) {
14322 return _empty(data) ?
14323 data :
14324 typeof data === 'string' ?
14325 data.replace( _re_new_lines, " " ) :
14326 data;
14327 }
14328 } );
14329
14330
14331
14332 $.extend( true, DataTable.ext.renderer, {
14333 header: {
14334 _: function ( settings, cell, column, classes ) {
14335 // No additional mark-up required
14336 // Attach a sort listener to update on sort - note that using the
14337 // `DT` namespace will allow the event to be removed automatically
14338 // on destroy, while the `dt` namespaced event is the one we are
14339 // listening for
14340 $(settings.nTable).on( 'order.dt.DT', function ( e, ctx, sorting, columns ) {
14341 if ( settings !== ctx ) { // need to check this this is the host
14342 return; // table, not a nested one
14343 }
14344
14345 var colIdx = column.idx;
14346
14347 cell
14348 .removeClass(
14349 column.sSortingClass +' '+
14350 classes.sSortAsc +' '+
14351 classes.sSortDesc
14352 )
14353 .addClass( columns[ colIdx ] == 'asc' ?
14354 classes.sSortAsc : columns[ colIdx ] == 'desc' ?
14355 classes.sSortDesc :
14356 column.sSortingClass
14357 );
14358 } );
14359 },
14360
14361 jqueryui: function ( settings, cell, column, classes ) {
14362 $('<div/>')
14363 .addClass( classes.sSortJUIWrapper )
14364 .append( cell.contents() )
14365 .append( $('<span/>')
14366 .addClass( classes.sSortIcon+' '+column.sSortingClassJUI )
14367 )
14368 .appendTo( cell );
14369
14370 // Attach a sort listener to update on sort
14371 $(settings.nTable).on( 'order.dt.DT', function ( e, ctx, sorting, columns ) {
14372 if ( settings !== ctx ) {
14373 return;
14374 }
14375
14376 var colIdx = column.idx;
14377
14378 cell
14379 .removeClass( classes.sSortAsc +" "+classes.sSortDesc )
14380 .addClass( columns[ colIdx ] == 'asc' ?
14381 classes.sSortAsc : columns[ colIdx ] == 'desc' ?
14382 classes.sSortDesc :
14383 column.sSortingClass
14384 );
14385
14386 cell
14387 .find( 'span.'+classes.sSortIcon )
14388 .removeClass(
14389 classes.sSortJUIAsc +" "+
14390 classes.sSortJUIDesc +" "+
14391 classes.sSortJUI +" "+
14392 classes.sSortJUIAscAllowed +" "+
14393 classes.sSortJUIDescAllowed
14394 )
14395 .addClass( columns[ colIdx ] == 'asc' ?
14396 classes.sSortJUIAsc : columns[ colIdx ] == 'desc' ?
14397 classes.sSortJUIDesc :
14398 column.sSortingClassJUI
14399 );
14400 } );
14401 }
14402 }
14403 } );
14404
14405 /*
14406 * Public helper functions. These aren't used internally by DataTables, or
14407 * called by any of the options passed into DataTables, but they can be used
14408 * externally by developers working with DataTables. They are helper functions
14409 * to make working with DataTables a little bit easier.
14410 */
14411
14412 /**
14413 * Helpers for `columns.render`.
14414 *
14415 * The options defined here can be used with the `columns.render` initialisation
14416 * option to provide a display renderer. The following functions are defined:
14417 *
14418 * * `number` - Will format numeric data (defined by `columns.data`) for
14419 * display, retaining the original unformatted data for sorting and filtering.
14420 * It takes 4 parameters:
14421 * * `string` - Thousands grouping separator
14422 * * `string` - Decimal point indicator
14423 * * `integer` - Number of decimal points to show
14424 * * `string` (optional) - Prefix.
14425 *
14426 * @example
14427 * // Column definition using the number renderer
14428 * {
14429 * data: "salary",
14430 * render: $.fn.dataTable.render.number( '\'', '.', 0, '$' )
14431 * }
14432 *
14433 * @namespace
14434 */
14435 DataTable.render = {
14436 number: function ( thousands, decimal, precision, prefix ) {
14437 return {
14438 display: function ( d ) {
14439 var negative = d < 0 ? '-' : '';
14440 d = Math.abs( parseFloat( d ) );
14441
14442 var intPart = parseInt( d, 10 );
14443 var floatPart = precision ?
14444 decimal+(d - intPart).toFixed( precision ).substring( 2 ):
14445 '';
14446
14447 return negative + (prefix||'') +
14448 intPart.toString().replace(
14449 /\B(?=(\d{3})+(?!\d))/g, thousands
14450 ) +
14451 floatPart;
14452 }
14453 };
14454 }
14455 };
14456
14457
14458 /*
14459 * This is really a good bit rubbish this method of exposing the internal methods
14460 * publicly... - To be fixed in 2.0 using methods on the prototype
14461 */
14462
14463
14464 /**
14465 * Create a wrapper function for exporting an internal functions to an external API.
14466 * @param {string} fn API function name
14467 * @returns {function} wrapped function
14468 * @memberof DataTable#internal
14469 */
14470 function _fnExternApiFunc (fn)
14471 {
14472 return function() {
14473 var args = [_fnSettingsFromNode( this[DataTable.ext.iApiIndex] )].concat(
14474 Array.prototype.slice.call(arguments)
14475 );
14476 return DataTable.ext.internal[fn].apply( this, args );
14477 };
14478 }
14479
14480
14481 /**
14482 * Reference to internal functions for use by plug-in developers. Note that
14483 * these methods are references to internal functions and are considered to be
14484 * private. If you use these methods, be aware that they are liable to change
14485 * between versions.
14486 * @namespace
14487 */
14488 $.extend( DataTable.ext.internal, {
14489 _fnExternApiFunc: _fnExternApiFunc,
14490 _fnBuildAjax: _fnBuildAjax,
14491 _fnAjaxUpdate: _fnAjaxUpdate,
14492 _fnAjaxParameters: _fnAjaxParameters,
14493 _fnAjaxUpdateDraw: _fnAjaxUpdateDraw,
14494 _fnAjaxDataSrc: _fnAjaxDataSrc,
14495 _fnAddColumn: _fnAddColumn,
14496 _fnColumnOptions: _fnColumnOptions,
14497 _fnAdjustColumnSizing: _fnAdjustColumnSizing,
14498 _fnVisibleToColumnIndex: _fnVisibleToColumnIndex,
14499 _fnColumnIndexToVisible: _fnColumnIndexToVisible,
14500 _fnVisbleColumns: _fnVisbleColumns,
14501 _fnGetColumns: _fnGetColumns,
14502 _fnColumnTypes: _fnColumnTypes,
14503 _fnApplyColumnDefs: _fnApplyColumnDefs,
14504 _fnHungarianMap: _fnHungarianMap,
14505 _fnCamelToHungarian: _fnCamelToHungarian,
14506 _fnLanguageCompat: _fnLanguageCompat,
14507 _fnBrowserDetect: _fnBrowserDetect,
14508 _fnAddData: _fnAddData,
14509 _fnAddTr: _fnAddTr,
14510 _fnNodeToDataIndex: _fnNodeToDataIndex,
14511 _fnNodeToColumnIndex: _fnNodeToColumnIndex,
14512 _fnGetCellData: _fnGetCellData,
14513 _fnSetCellData: _fnSetCellData,
14514 _fnSplitObjNotation: _fnSplitObjNotation,
14515 _fnGetObjectDataFn: _fnGetObjectDataFn,
14516 _fnSetObjectDataFn: _fnSetObjectDataFn,
14517 _fnGetDataMaster: _fnGetDataMaster,
14518 _fnClearTable: _fnClearTable,
14519 _fnDeleteIndex: _fnDeleteIndex,
14520 _fnInvalidateRow: _fnInvalidateRow,
14521 _fnGetRowElements: _fnGetRowElements,
14522 _fnCreateTr: _fnCreateTr,
14523 _fnBuildHead: _fnBuildHead,
14524 _fnDrawHead: _fnDrawHead,
14525 _fnDraw: _fnDraw,
14526 _fnReDraw: _fnReDraw,
14527 _fnAddOptionsHtml: _fnAddOptionsHtml,
14528 _fnDetectHeader: _fnDetectHeader,
14529 _fnGetUniqueThs: _fnGetUniqueThs,
14530 _fnFeatureHtmlFilter: _fnFeatureHtmlFilter,
14531 _fnFilterComplete: _fnFilterComplete,
14532 _fnFilterCustom: _fnFilterCustom,
14533 _fnFilterColumn: _fnFilterColumn,
14534 _fnFilter: _fnFilter,
14535 _fnFilterCreateSearch: _fnFilterCreateSearch,
14536 _fnEscapeRegex: _fnEscapeRegex,
14537 _fnFilterData: _fnFilterData,
14538 _fnFeatureHtmlInfo: _fnFeatureHtmlInfo,
14539 _fnUpdateInfo: _fnUpdateInfo,
14540 _fnInfoMacros: _fnInfoMacros,
14541 _fnInitialise: _fnInitialise,
14542 _fnInitComplete: _fnInitComplete,
14543 _fnLengthChange: _fnLengthChange,
14544 _fnFeatureHtmlLength: _fnFeatureHtmlLength,
14545 _fnFeatureHtmlPaginate: _fnFeatureHtmlPaginate,
14546 _fnPageChange: _fnPageChange,
14547 _fnFeatureHtmlProcessing: _fnFeatureHtmlProcessing,
14548 _fnProcessingDisplay: _fnProcessingDisplay,
14549 _fnFeatureHtmlTable: _fnFeatureHtmlTable,
14550 _fnScrollDraw: _fnScrollDraw,
14551 _fnApplyToChildren: _fnApplyToChildren,
14552 _fnCalculateColumnWidths: _fnCalculateColumnWidths,
14553 _fnThrottle: _fnThrottle,
14554 _fnConvertToWidth: _fnConvertToWidth,
14555 _fnScrollingWidthAdjust: _fnScrollingWidthAdjust,
14556 _fnGetWidestNode: _fnGetWidestNode,
14557 _fnGetMaxLenString: _fnGetMaxLenString,
14558 _fnStringToCss: _fnStringToCss,
14559 _fnScrollBarWidth: _fnScrollBarWidth,
14560 _fnSortFlatten: _fnSortFlatten,
14561 _fnSort: _fnSort,
14562 _fnSortAria: _fnSortAria,
14563 _fnSortListener: _fnSortListener,
14564 _fnSortAttachListener: _fnSortAttachListener,
14565 _fnSortingClasses: _fnSortingClasses,
14566 _fnSortData: _fnSortData,
14567 _fnSaveState: _fnSaveState,
14568 _fnLoadState: _fnLoadState,
14569 _fnSettingsFromNode: _fnSettingsFromNode,
14570 _fnLog: _fnLog,
14571 _fnMap: _fnMap,
14572 _fnBindAction: _fnBindAction,
14573 _fnCallbackReg: _fnCallbackReg,
14574 _fnCallbackFire: _fnCallbackFire,
14575 _fnLengthOverflow: _fnLengthOverflow,
14576 _fnRenderer: _fnRenderer,
14577 _fnDataSource: _fnDataSource,
14578 _fnRowAttributes: _fnRowAttributes,
14579 _fnCalculateEnd: function () {} // Used by a lot of plug-ins, but redundant
14580 // in 1.10, so this dead-end function is
14581 // added to prevent errors
14582 } );
14583
14584
14585 // jQuery access
14586 $.fn.dataTable = DataTable;
14587
14588 // Legacy aliases
14589 $.fn.dataTableSettings = DataTable.settings;
14590 $.fn.dataTableExt = DataTable.ext;
14591
14592 // With a capital `D` we return a DataTables API instance rather than a
14593 // jQuery object
14594 $.fn.DataTable = function ( opts ) {
14595 return $(this).dataTable( opts ).api();
14596 };
14597
14598 // All properties that are available to $.fn.dataTable should also be
14599 // available on $.fn.DataTable
14600 $.each( DataTable, function ( prop, val ) {
14601 $.fn.DataTable[ prop ] = val;
14602 } );
14603
14604
14605 // Information about events fired by DataTables - for documentation.
14606 /**
14607 * Draw event, fired whenever the table is redrawn on the page, at the same
14608 * point as fnDrawCallback. This may be useful for binding events or
14609 * performing calculations when the table is altered at all.
14610 * @name DataTable#draw.dt
14611 * @event
14612 * @param {event} e jQuery event object
14613 * @param {object} o DataTables settings object {@link DataTable.models.oSettings}
14614 */
14615
14616 /**
14617 * Search event, fired when the searching applied to the table (using the
14618 * built-in global search, or column filters) is altered.
14619 * @name DataTable#search.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 * Page change event, fired when the paging of the table is altered.
14627 * @name DataTable#page.dt
14628 * @event
14629 * @param {event} e jQuery event object
14630 * @param {object} o DataTables settings object {@link DataTable.models.oSettings}
14631 */
14632
14633 /**
14634 * Order event, fired when the ordering applied to the table is altered.
14635 * @name DataTable#order.dt
14636 * @event
14637 * @param {event} e jQuery event object
14638 * @param {object} o DataTables settings object {@link DataTable.models.oSettings}
14639 */
14640
14641 /**
14642 * DataTables initialisation complete event, fired when the table is fully
14643 * drawn, including Ajax data loaded, if Ajax data is required.
14644 * @name DataTable#init.dt
14645 * @event
14646 * @param {event} e jQuery event object
14647 * @param {object} oSettings DataTables settings object
14648 * @param {object} json The JSON object request from the server - only
14649 * present if client-side Ajax sourced data is used</li></ol>
14650 */
14651
14652 /**
14653 * State save event, fired when the table has changed state a new state save
14654 * is required. This event allows modification of the state saving object
14655 * prior to actually doing the save, including addition or other state
14656 * properties (for plug-ins) or modification of a DataTables core property.
14657 * @name DataTable#stateSaveParams.dt
14658 * @event
14659 * @param {event} e jQuery event object
14660 * @param {object} oSettings DataTables settings object
14661 * @param {object} json The state information to be saved
14662 */
14663
14664 /**
14665 * State load event, fired when the table is loading state from the stored
14666 * data, but prior to the settings object being modified by the saved state
14667 * - allowing modification of the saved state is required or loading of
14668 * state for a plug-in.
14669 * @name DataTable#stateLoadParams.dt
14670 * @event
14671 * @param {event} e jQuery event object
14672 * @param {object} oSettings DataTables settings object
14673 * @param {object} json The saved state information
14674 */
14675
14676 /**
14677 * State loaded event, fired when state has been loaded from stored data and
14678 * the settings object has been modified by the loaded data.
14679 * @name DataTable#stateLoaded.dt
14680 * @event
14681 * @param {event} e jQuery event object
14682 * @param {object} oSettings DataTables settings object
14683 * @param {object} json The saved state information
14684 */
14685
14686 /**
14687 * Processing event, fired when DataTables is doing some kind of processing
14688 * (be it, order, searcg or anything else). It can be used to indicate to
14689 * the end user that there is something happening, or that something has
14690 * finished.
14691 * @name DataTable#processing.dt
14692 * @event
14693 * @param {event} e jQuery event object
14694 * @param {object} oSettings DataTables settings object
14695 * @param {boolean} bShow Flag for if DataTables is doing processing or not
14696 */
14697
14698 /**
14699 * Ajax (XHR) event, fired whenever an Ajax request is completed from a
14700 * request to made to the server for new data. This event is called before
14701 * DataTables processed the returned data, so it can also be used to pre-
14702 * process the data returned from the server, if needed.
14703 *
14704 * Note that this trigger is called in `fnServerData`, if you override
14705 * `fnServerData` and which to use this event, you need to trigger it in you
14706 * success function.
14707 * @name DataTable#xhr.dt
14708 * @event
14709 * @param {event} e jQuery event object
14710 * @param {object} o DataTables settings object {@link DataTable.models.oSettings}
14711 * @param {object} json JSON returned from the server
14712 *
14713 * @example
14714 * // Use a custom property returned from the server in another DOM element
14715 * $('#table').dataTable().on('xhr.dt', function (e, settings, json) {
14716 * $('#status').html( json.status );
14717 * } );
14718 *
14719 * @example
14720 * // Pre-process the data returned from the server
14721 * $('#table').dataTable().on('xhr.dt', function (e, settings, json) {
14722 * for ( var i=0, ien=json.aaData.length ; i<ien ; i++ ) {
14723 * json.aaData[i].sum = json.aaData[i].one + json.aaData[i].two;
14724 * }
14725 * // Note no return - manipulate the data directly in the JSON object.
14726 * } );
14727 */
14728
14729 /**
14730 * Destroy event, fired when the DataTable is destroyed by calling fnDestroy
14731 * or passing the bDestroy:true parameter in the initialisation object. This
14732 * can be used to remove bound events, added DOM nodes, etc.
14733 * @name DataTable#destroy.dt
14734 * @event
14735 * @param {event} e jQuery event object
14736 * @param {object} o DataTables settings object {@link DataTable.models.oSettings}
14737 */
14738
14739 /**
14740 * Page length change event, fired when number of records to show on each
14741 * page (the length) is changed.
14742 * @name DataTable#length.dt
14743 * @event
14744 * @param {event} e jQuery event object
14745 * @param {object} o DataTables settings object {@link DataTable.models.oSettings}
14746 * @param {integer} len New length
14747 */
14748
14749 /**
14750 * Column sizing has changed.
14751 * @name DataTable#column-sizing.dt
14752 * @event
14753 * @param {event} e jQuery event object
14754 * @param {object} o DataTables settings object {@link DataTable.models.oSettings}
14755 */
14756
14757 /**
14758 * Column visibility has changed.
14759 * @name DataTable#column-visibility.dt
14760 * @event
14761 * @param {event} e jQuery event object
14762 * @param {object} o DataTables settings object {@link DataTable.models.oSettings}
14763 * @param {int} column Column index
14764 * @param {bool} vis `false` if column now hidden, or `true` if visible
14765 */
14766
14767 return $.fn.dataTable;
14768 }));
14769
14770 }(window, document));
14771