comparison templates/lib/jquery.dataTables.js @ 0:cce6989ed423

new NIST wrapper demo tools
author pieter.lukasse@wur.nl
date Thu, 22 Jan 2015 16:14:57 +0100
parents
children
comparison
equal deleted inserted replaced
-1:000000000000 0:cce6989ed423
1 /*! DataTables 1.10.4
2 * ©2008-2014 SpryMedia Ltd - datatables.net/license
3 */
4
5 /**
6 * @summary DataTables
7 * @description Paginate, search and order HTML tables
8 * @version 1.10.4
9 * @file jquery.dataTables.js
10 * @author SpryMedia Ltd (www.sprymedia.co.uk)
11 * @contact www.sprymedia.co.uk/contact
12 * @copyright Copyright 2008-2014 SpryMedia Ltd.
13 *
14 * This source file is free software, available under the following license:
15 * MIT license - http://datatables.net/license
16 *
17 * This source file is distributed in the hope that it will be useful, but
18 * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
19 * or FITNESS FOR A PARTICULAR PURPOSE. See the license files for details.
20 *
21 * For details please refer to: http://www.datatables.net
22 */
23
24 /*jslint evil: true, undef: true, browser: true */
25 /*globals $,require,jQuery,define,_selector_run,_selector_opts,_selector_first,_selector_row_indexes,_ext,_Api,_api_register,_api_registerPlural,_re_new_lines,_re_html,_re_formatted_numeric,_re_escape_regex,_empty,_intVal,_numToDecimal,_isNumber,_isHtml,_htmlNumeric,_pluck,_pluck_order,_range,_stripHtml,_unique,_fnBuildAjax,_fnAjaxUpdate,_fnAjaxParameters,_fnAjaxUpdateDraw,_fnAjaxDataSrc,_fnAddColumn,_fnColumnOptions,_fnAdjustColumnSizing,_fnVisibleToColumnIndex,_fnColumnIndexToVisible,_fnVisbleColumns,_fnGetColumns,_fnColumnTypes,_fnApplyColumnDefs,_fnHungarianMap,_fnCamelToHungarian,_fnLanguageCompat,_fnBrowserDetect,_fnAddData,_fnAddTr,_fnNodeToDataIndex,_fnNodeToColumnIndex,_fnGetCellData,_fnSetCellData,_fnSplitObjNotation,_fnGetObjectDataFn,_fnSetObjectDataFn,_fnGetDataMaster,_fnClearTable,_fnDeleteIndex,_fnInvalidate,_fnGetRowElements,_fnCreateTr,_fnBuildHead,_fnDrawHead,_fnDraw,_fnReDraw,_fnAddOptionsHtml,_fnDetectHeader,_fnGetUniqueThs,_fnFeatureHtmlFilter,_fnFilterComplete,_fnFilterCustom,_fnFilterColumn,_fnFilter,_fnFilterCreateSearch,_fnEscapeRegex,_fnFilterData,_fnFeatureHtmlInfo,_fnUpdateInfo,_fnInfoMacros,_fnInitialise,_fnInitComplete,_fnLengthChange,_fnFeatureHtmlLength,_fnFeatureHtmlPaginate,_fnPageChange,_fnFeatureHtmlProcessing,_fnProcessingDisplay,_fnFeatureHtmlTable,_fnScrollDraw,_fnApplyToChildren,_fnCalculateColumnWidths,_fnThrottle,_fnConvertToWidth,_fnScrollingWidthAdjust,_fnGetWidestNode,_fnGetMaxLenString,_fnStringToCss,_fnScrollBarWidth,_fnSortFlatten,_fnSort,_fnSortAria,_fnSortListener,_fnSortAttachListener,_fnSortingClasses,_fnSortData,_fnSaveState,_fnLoadState,_fnSettingsFromNode,_fnLog,_fnMap,_fnBindAction,_fnCallbackReg,_fnCallbackFire,_fnLengthOverflow,_fnRenderer,_fnDataSource,_fnRowAttributes*/
26
27 (/** @lends <global> */function( window, document, undefined ) {
28
29 (function( factory ) {
30 "use strict";
31
32 if ( typeof define === 'function' && define.amd ) {
33 // Define as an AMD module if possible
34 define( 'datatables', ['jquery'], factory );
35 }
36 else if ( typeof exports === 'object' ) {
37 // Node/CommonJS
38 factory( require( 'jquery' ) );
39 }
40 else if ( jQuery && !jQuery.fn.dataTable ) {
41 // Define using browser globals otherwise
42 // Prevent multiple instantiations if the script is loaded twice
43 factory( jQuery );
44 }
45 }
46 (/** @lends <global> */function( $ ) {
47 "use strict";
48
49 /**
50 * DataTables is a plug-in for the jQuery Javascript library. It is a highly
51 * flexible tool, based upon the foundations of progressive enhancement,
52 * which will add advanced interaction controls to any HTML table. For a
53 * full list of features please refer to
54 * [DataTables.net](href="http://datatables.net).
55 *
56 * Note that the `DataTable` object is not a global variable but is aliased
57 * to `jQuery.fn.DataTable` and `jQuery.fn.dataTable` through which it may
58 * be accessed.
59 *
60 * @class
61 * @param {object} [init={}] Configuration object for DataTables. Options
62 * are defined by {@link DataTable.defaults}
63 * @requires jQuery 1.7+
64 *
65 * @example
66 * // Basic initialisation
67 * $(document).ready( function {
68 * $('#example').dataTable();
69 * } );
70 *
71 * @example
72 * // Initialisation with configuration options - in this case, disable
73 * // pagination and sorting.
74 * $(document).ready( function {
75 * $('#example').dataTable( {
76 * "paginate": false,
77 * "sort": false
78 * } );
79 * } );
80 */
81 var DataTable;
82
83
84 /*
85 * It is useful to have variables which are scoped locally so only the
86 * DataTables functions can access them and they don't leak into global space.
87 * At the same time these functions are often useful over multiple files in the
88 * core and API, so we list, or at least document, all variables which are used
89 * by DataTables as private variables here. This also ensures that there is no
90 * clashing of variable names and that they can easily referenced for reuse.
91 */
92
93
94 // Defined else where
95 // _selector_run
96 // _selector_opts
97 // _selector_first
98 // _selector_row_indexes
99
100 var _ext; // DataTable.ext
101 var _Api; // DataTable.Api
102 var _api_register; // DataTable.Api.register
103 var _api_registerPlural; // DataTable.Api.registerPlural
104
105 var _re_dic = {};
106 var _re_new_lines = /[\r\n]/g;
107 var _re_html = /<.*?>/g;
108 var _re_date_start = /^[\w\+\-]/;
109 var _re_date_end = /[\w\+\-]$/;
110
111 // Escape regular expression special characters
112 var _re_escape_regex = new RegExp( '(\\' + [ '/', '.', '*', '+', '?', '|', '(', ')', '[', ']', '{', '}', '\\', '$', '^', '-' ].join('|\\') + ')', 'g' );
113
114 // U+2009 is thin space and U+202F is narrow no-break space, both used in many
115 // standards as thousands separators
116 var _re_formatted_numeric = /[',$£€¥%\u2009\u202F]/g;
117
118
119 var _empty = function ( d ) {
120 return !d || d === true || d === '-' ? true : false;
121 };
122
123
124 var _intVal = function ( s ) {
125 var integer = parseInt( s, 10 );
126 return !isNaN(integer) && isFinite(s) ? integer : null;
127 };
128
129 // Convert from a formatted number with characters other than `.` as the
130 // decimal place, to a Javascript number
131 var _numToDecimal = function ( num, decimalPoint ) {
132 // Cache created regular expressions for speed as this function is called often
133 if ( ! _re_dic[ decimalPoint ] ) {
134 _re_dic[ decimalPoint ] = new RegExp( _fnEscapeRegex( decimalPoint ), 'g' );
135 }
136 return typeof num === 'string' && decimalPoint !== '.' ?
137 num.replace( /\./g, '' ).replace( _re_dic[ decimalPoint ], '.' ) :
138 num;
139 };
140
141
142 var _isNumber = function ( d, decimalPoint, formatted ) {
143 var strType = typeof d === 'string';
144
145 if ( decimalPoint && strType ) {
146 d = _numToDecimal( d, decimalPoint );
147 }
148
149 if ( formatted && strType ) {
150 d = d.replace( _re_formatted_numeric, '' );
151 }
152
153 return _empty( d ) || (!isNaN( parseFloat(d) ) && isFinite( d ));
154 };
155
156
157 // A string without HTML in it can be considered to be HTML still
158 var _isHtml = function ( d ) {
159 return _empty( d ) || typeof d === 'string';
160 };
161
162
163 var _htmlNumeric = function ( d, decimalPoint, formatted ) {
164 if ( _empty( d ) ) {
165 return true;
166 }
167
168 var html = _isHtml( d );
169 return ! html ?
170 null :
171 _isNumber( _stripHtml( d ), decimalPoint, formatted ) ?
172 true :
173 null;
174 };
175
176
177 var _pluck = function ( a, prop, prop2 ) {
178 var out = [];
179 var i=0, ien=a.length;
180
181 // Could have the test in the loop for slightly smaller code, but speed
182 // is essential here
183 if ( prop2 !== undefined ) {
184 for ( ; i<ien ; i++ ) {
185 if ( a[i] && a[i][ prop ] ) {
186 out.push( a[i][ prop ][ prop2 ] );
187 }
188 }
189 }
190 else {
191 for ( ; i<ien ; i++ ) {
192 if ( a[i] ) {
193 out.push( a[i][ prop ] );
194 }
195 }
196 }
197
198 return out;
199 };
200
201
202 // Basically the same as _pluck, but rather than looping over `a` we use `order`
203 // as the indexes to pick from `a`
204 var _pluck_order = function ( a, order, prop, prop2 )
205 {
206 var out = [];
207 var i=0, ien=order.length;
208
209 // Could have the test in the loop for slightly smaller code, but speed
210 // is essential here
211 if ( prop2 !== undefined ) {
212 for ( ; i<ien ; i++ ) {
213 if ( a[ order[i] ][ prop ] ) {
214 out.push( a[ order[i] ][ prop ][ prop2 ] );
215 }
216 }
217 }
218 else {
219 for ( ; i<ien ; i++ ) {
220 out.push( a[ order[i] ][ prop ] );
221 }
222 }
223
224 return out;
225 };
226
227
228 var _range = function ( len, start )
229 {
230 var out = [];
231 var end;
232
233 if ( start === undefined ) {
234 start = 0;
235 end = len;
236 }
237 else {
238 end = start;
239 start = len;
240 }
241
242 for ( var i=start ; i<end ; i++ ) {
243 out.push( i );
244 }
245
246 return out;
247 };
248
249
250 var _removeEmpty = function ( a )
251 {
252 var out = [];
253
254 for ( var i=0, ien=a.length ; i<ien ; i++ ) {
255 if ( a[i] ) { // careful - will remove all falsy values!
256 out.push( a[i] );
257 }
258 }
259
260 return out;
261 };
262
263
264 var _stripHtml = function ( d ) {
265 return d.replace( _re_html, '' );
266 };
267
268
269 /**
270 * Find the unique elements in a source array.
271 *
272 * @param {array} src Source array
273 * @return {array} Array of unique items
274 * @ignore
275 */
276 var _unique = function ( src )
277 {
278 // A faster unique method is to use object keys to identify used values,
279 // but this doesn't work with arrays or objects, which we must also
280 // consider. See jsperf.com/compare-array-unique-versions/4 for more
281 // information.
282 var
283 out = [],
284 val,
285 i, ien=src.length,
286 j, k=0;
287
288 again: for ( i=0 ; i<ien ; i++ ) {
289 val = src[i];
290
291 for ( j=0 ; j<k ; j++ ) {
292 if ( out[j] === val ) {
293 continue again;
294 }
295 }
296
297 out.push( val );
298 k++;
299 }
300
301 return out;
302 };
303
304
305
306 /**
307 * Create a mapping object that allows camel case parameters to be looked up
308 * for their Hungarian counterparts. The mapping is stored in a private
309 * parameter called `_hungarianMap` which can be accessed on the source object.
310 * @param {object} o
311 * @memberof DataTable#oApi
312 */
313 function _fnHungarianMap ( o )
314 {
315 var
316 hungarian = 'a aa ai ao as b fn i m o s ',
317 match,
318 newKey,
319 map = {};
320
321 $.each( o, function (key, val) {
322 match = key.match(/^([^A-Z]+?)([A-Z])/);
323
324 if ( match && hungarian.indexOf(match[1]+' ') !== -1 )
325 {
326 newKey = key.replace( match[0], match[2].toLowerCase() );
327 map[ newKey ] = key;
328
329 if ( match[1] === 'o' )
330 {
331 _fnHungarianMap( o[key] );
332 }
333 }
334 } );
335
336 o._hungarianMap = map;
337 }
338
339
340 /**
341 * Convert from camel case parameters to Hungarian, based on a Hungarian map
342 * created by _fnHungarianMap.
343 * @param {object} src The model object which holds all parameters that can be
344 * mapped.
345 * @param {object} user The object to convert from camel case to Hungarian.
346 * @param {boolean} force When set to `true`, properties which already have a
347 * Hungarian value in the `user` object will be overwritten. Otherwise they
348 * won't be.
349 * @memberof DataTable#oApi
350 */
351 function _fnCamelToHungarian ( src, user, force )
352 {
353 if ( ! src._hungarianMap ) {
354 _fnHungarianMap( src );
355 }
356
357 var hungarianKey;
358
359 $.each( user, function (key, val) {
360 hungarianKey = src._hungarianMap[ key ];
361
362 if ( hungarianKey !== undefined && (force || user[hungarianKey] === undefined) )
363 {
364 // For objects, we need to buzz down into the object to copy parameters
365 if ( hungarianKey.charAt(0) === 'o' )
366 {
367 // Copy the camelCase options over to the hungarian
368 if ( ! user[ hungarianKey ] ) {
369 user[ hungarianKey ] = {};
370 }
371 $.extend( true, user[hungarianKey], user[key] );
372
373 _fnCamelToHungarian( src[hungarianKey], user[hungarianKey], force );
374 }
375 else {
376 user[hungarianKey] = user[ key ];
377 }
378 }
379 } );
380 }
381
382
383 /**
384 * Language compatibility - when certain options are given, and others aren't, we
385 * need to duplicate the values over, in order to provide backwards compatibility
386 * with older language files.
387 * @param {object} oSettings dataTables settings object
388 * @memberof DataTable#oApi
389 */
390 function _fnLanguageCompat( lang )
391 {
392 var defaults = DataTable.defaults.oLanguage;
393 var zeroRecords = lang.sZeroRecords;
394
395 /* Backwards compatibility - if there is no sEmptyTable given, then use the same as
396 * sZeroRecords - assuming that is given.
397 */
398 if ( ! lang.sEmptyTable && zeroRecords &&
399 defaults.sEmptyTable === "No data available in table" )
400 {
401 _fnMap( lang, lang, 'sZeroRecords', 'sEmptyTable' );
402 }
403
404 /* Likewise with loading records */
405 if ( ! lang.sLoadingRecords && zeroRecords &&
406 defaults.sLoadingRecords === "Loading..." )
407 {
408 _fnMap( lang, lang, 'sZeroRecords', 'sLoadingRecords' );
409 }
410
411 // Old parameter name of the thousands separator mapped onto the new
412 if ( lang.sInfoThousands ) {
413 lang.sThousands = lang.sInfoThousands;
414 }
415
416 var decimal = lang.sDecimal;
417 if ( decimal ) {
418 _addNumericSort( decimal );
419 }
420 }
421
422
423 /**
424 * Map one parameter onto another
425 * @param {object} o Object to map
426 * @param {*} knew The new parameter name
427 * @param {*} old The old parameter name
428 */
429 var _fnCompatMap = function ( o, knew, old ) {
430 if ( o[ knew ] !== undefined ) {
431 o[ old ] = o[ knew ];
432 }
433 };
434
435
436 /**
437 * Provide backwards compatibility for the main DT options. Note that the new
438 * options are mapped onto the old parameters, so this is an external interface
439 * change only.
440 * @param {object} init Object to map
441 */
442 function _fnCompatOpts ( init )
443 {
444 _fnCompatMap( init, 'ordering', 'bSort' );
445 _fnCompatMap( init, 'orderMulti', 'bSortMulti' );
446 _fnCompatMap( init, 'orderClasses', 'bSortClasses' );
447 _fnCompatMap( init, 'orderCellsTop', 'bSortCellsTop' );
448 _fnCompatMap( init, 'order', 'aaSorting' );
449 _fnCompatMap( init, 'orderFixed', 'aaSortingFixed' );
450 _fnCompatMap( init, 'paging', 'bPaginate' );
451 _fnCompatMap( init, 'pagingType', 'sPaginationType' );
452 _fnCompatMap( init, 'pageLength', 'iDisplayLength' );
453 _fnCompatMap( init, 'searching', 'bFilter' );
454
455 // Column search objects are in an array, so it needs to be converted
456 // element by element
457 var searchCols = init.aoSearchCols;
458
459 if ( searchCols ) {
460 for ( var i=0, ien=searchCols.length ; i<ien ; i++ ) {
461 if ( searchCols[i] ) {
462 _fnCamelToHungarian( DataTable.models.oSearch, searchCols[i] );
463 }
464 }
465 }
466 }
467
468
469 /**
470 * Provide backwards compatibility for column options. Note that the new options
471 * are mapped onto the old parameters, so this is an external interface change
472 * only.
473 * @param {object} init Object to map
474 */
475 function _fnCompatCols ( init )
476 {
477 _fnCompatMap( init, 'orderable', 'bSortable' );
478 _fnCompatMap( init, 'orderData', 'aDataSort' );
479 _fnCompatMap( init, 'orderSequence', 'asSorting' );
480 _fnCompatMap( init, 'orderDataType', 'sortDataType' );
481 }
482
483
484 /**
485 * Browser feature detection for capabilities, quirks
486 * @param {object} settings dataTables settings object
487 * @memberof DataTable#oApi
488 */
489 function _fnBrowserDetect( settings )
490 {
491 var browser = settings.oBrowser;
492
493 // Scrolling feature / quirks detection
494 var n = $('<div/>')
495 .css( {
496 position: 'absolute',
497 top: 0,
498 left: 0,
499 height: 1,
500 width: 1,
501 overflow: 'hidden'
502 } )
503 .append(
504 $('<div/>')
505 .css( {
506 position: 'absolute',
507 top: 1,
508 left: 1,
509 width: 100,
510 overflow: 'scroll'
511 } )
512 .append(
513 $('<div class="test"/>')
514 .css( {
515 width: '100%',
516 height: 10
517 } )
518 )
519 )
520 .appendTo( 'body' );
521
522 var test = n.find('.test');
523
524 // IE6/7 will oversize a width 100% element inside a scrolling element, to
525 // include the width of the scrollbar, while other browsers ensure the inner
526 // element is contained without forcing scrolling
527 browser.bScrollOversize = test[0].offsetWidth === 100;
528
529 // In rtl text layout, some browsers (most, but not all) will place the
530 // scrollbar on the left, rather than the right.
531 browser.bScrollbarLeft = test.offset().left !== 1;
532
533 n.remove();
534 }
535
536
537 /**
538 * Array.prototype reduce[Right] method, used for browsers which don't support
539 * JS 1.6. Done this way to reduce code size, since we iterate either way
540 * @param {object} settings dataTables settings object
541 * @memberof DataTable#oApi
542 */
543 function _fnReduce ( that, fn, init, start, end, inc )
544 {
545 var
546 i = start,
547 value,
548 isSet = false;
549
550 if ( init !== undefined ) {
551 value = init;
552 isSet = true;
553 }
554
555 while ( i !== end ) {
556 if ( ! that.hasOwnProperty(i) ) {
557 continue;
558 }
559
560 value = isSet ?
561 fn( value, that[i], i, that ) :
562 that[i];
563
564 isSet = true;
565 i += inc;
566 }
567
568 return value;
569 }
570
571 /**
572 * Add a column to the list used for the table with default values
573 * @param {object} oSettings dataTables settings object
574 * @param {node} nTh The th element for this column
575 * @memberof DataTable#oApi
576 */
577 function _fnAddColumn( oSettings, nTh )
578 {
579 // Add column to aoColumns array
580 var oDefaults = DataTable.defaults.column;
581 var iCol = oSettings.aoColumns.length;
582 var oCol = $.extend( {}, DataTable.models.oColumn, oDefaults, {
583 "nTh": nTh ? nTh : document.createElement('th'),
584 "sTitle": oDefaults.sTitle ? oDefaults.sTitle : nTh ? nTh.innerHTML : '',
585 "aDataSort": oDefaults.aDataSort ? oDefaults.aDataSort : [iCol],
586 "mData": oDefaults.mData ? oDefaults.mData : iCol,
587 idx: iCol
588 } );
589 oSettings.aoColumns.push( oCol );
590
591 // Add search object for column specific search. Note that the `searchCols[ iCol ]`
592 // passed into extend can be undefined. This allows the user to give a default
593 // with only some of the parameters defined, and also not give a default
594 var searchCols = oSettings.aoPreSearchCols;
595 searchCols[ iCol ] = $.extend( {}, DataTable.models.oSearch, searchCols[ iCol ] );
596
597 // Use the default column options function to initialise classes etc
598 _fnColumnOptions( oSettings, iCol, null );
599 }
600
601
602 /**
603 * Apply options for a column
604 * @param {object} oSettings dataTables settings object
605 * @param {int} iCol column index to consider
606 * @param {object} oOptions object with sType, bVisible and bSearchable etc
607 * @memberof DataTable#oApi
608 */
609 function _fnColumnOptions( oSettings, iCol, oOptions )
610 {
611 var oCol = oSettings.aoColumns[ iCol ];
612 var oClasses = oSettings.oClasses;
613 var th = $(oCol.nTh);
614
615 // Try to get width information from the DOM. We can't get it from CSS
616 // as we'd need to parse the CSS stylesheet. `width` option can override
617 if ( ! oCol.sWidthOrig ) {
618 // Width attribute
619 oCol.sWidthOrig = th.attr('width') || null;
620
621 // Style attribute
622 var t = (th.attr('style') || '').match(/width:\s*(\d+[pxem%]+)/);
623 if ( t ) {
624 oCol.sWidthOrig = t[1];
625 }
626 }
627
628 /* User specified column options */
629 if ( oOptions !== undefined && oOptions !== null )
630 {
631 // Backwards compatibility
632 _fnCompatCols( oOptions );
633
634 // Map camel case parameters to their Hungarian counterparts
635 _fnCamelToHungarian( DataTable.defaults.column, oOptions );
636
637 /* Backwards compatibility for mDataProp */
638 if ( oOptions.mDataProp !== undefined && !oOptions.mData )
639 {
640 oOptions.mData = oOptions.mDataProp;
641 }
642
643 if ( oOptions.sType )
644 {
645 oCol._sManualType = oOptions.sType;
646 }
647
648 // `class` is a reserved word in Javascript, so we need to provide
649 // the ability to use a valid name for the camel case input
650 if ( oOptions.className && ! oOptions.sClass )
651 {
652 oOptions.sClass = oOptions.className;
653 }
654
655 $.extend( oCol, oOptions );
656 _fnMap( oCol, oOptions, "sWidth", "sWidthOrig" );
657
658 /* iDataSort to be applied (backwards compatibility), but aDataSort will take
659 * priority if defined
660 */
661 if ( typeof oOptions.iDataSort === 'number' )
662 {
663 oCol.aDataSort = [ oOptions.iDataSort ];
664 }
665 _fnMap( oCol, oOptions, "aDataSort" );
666 }
667
668 /* Cache the data get and set functions for speed */
669 var mDataSrc = oCol.mData;
670 var mData = _fnGetObjectDataFn( mDataSrc );
671 var mRender = oCol.mRender ? _fnGetObjectDataFn( oCol.mRender ) : null;
672
673 var attrTest = function( src ) {
674 return typeof src === 'string' && src.indexOf('@') !== -1;
675 };
676 oCol._bAttrSrc = $.isPlainObject( mDataSrc ) && (
677 attrTest(mDataSrc.sort) || attrTest(mDataSrc.type) || attrTest(mDataSrc.filter)
678 );
679
680 oCol.fnGetData = function (rowData, type, meta) {
681 var innerData = mData( rowData, type, undefined, meta );
682
683 return mRender && type ?
684 mRender( innerData, type, rowData, meta ) :
685 innerData;
686 };
687 oCol.fnSetData = function ( rowData, val, meta ) {
688 return _fnSetObjectDataFn( mDataSrc )( rowData, val, meta );
689 };
690
691 // Indicate if DataTables should read DOM data as an object or array
692 // Used in _fnGetRowElements
693 if ( typeof mDataSrc !== 'number' ) {
694 oSettings._rowReadObject = true;
695 }
696
697 /* Feature sorting overrides column specific when off */
698 if ( !oSettings.oFeatures.bSort )
699 {
700 oCol.bSortable = false;
701 th.addClass( oClasses.sSortableNone ); // Have to add class here as order event isn't called
702 }
703
704 /* Check that the class assignment is correct for sorting */
705 var bAsc = $.inArray('asc', oCol.asSorting) !== -1;
706 var bDesc = $.inArray('desc', oCol.asSorting) !== -1;
707 if ( !oCol.bSortable || (!bAsc && !bDesc) )
708 {
709 oCol.sSortingClass = oClasses.sSortableNone;
710 oCol.sSortingClassJUI = "";
711 }
712 else if ( bAsc && !bDesc )
713 {
714 oCol.sSortingClass = oClasses.sSortableAsc;
715 oCol.sSortingClassJUI = oClasses.sSortJUIAscAllowed;
716 }
717 else if ( !bAsc && bDesc )
718 {
719 oCol.sSortingClass = oClasses.sSortableDesc;
720 oCol.sSortingClassJUI = oClasses.sSortJUIDescAllowed;
721 }
722 else
723 {
724 oCol.sSortingClass = oClasses.sSortable;
725 oCol.sSortingClassJUI = oClasses.sSortJUI;
726 }
727 }
728
729
730 /**
731 * Adjust the table column widths for new data. Note: you would probably want to
732 * do a redraw after calling this function!
733 * @param {object} settings dataTables settings object
734 * @memberof DataTable#oApi
735 */
736 function _fnAdjustColumnSizing ( settings )
737 {
738 /* Not interested in doing column width calculation if auto-width is disabled */
739 if ( settings.oFeatures.bAutoWidth !== false )
740 {
741 var columns = settings.aoColumns;
742
743 _fnCalculateColumnWidths( settings );
744 for ( var i=0 , iLen=columns.length ; i<iLen ; i++ )
745 {
746 columns[i].nTh.style.width = columns[i].sWidth;
747 }
748 }
749
750 var scroll = settings.oScroll;
751 if ( scroll.sY !== '' || scroll.sX !== '')
752 {
753 _fnScrollDraw( settings );
754 }
755
756 _fnCallbackFire( settings, null, 'column-sizing', [settings] );
757 }
758
759
760 /**
761 * Covert the index of a visible column to the index in the data array (take account
762 * of hidden columns)
763 * @param {object} oSettings dataTables settings object
764 * @param {int} iMatch Visible column index to lookup
765 * @returns {int} i the data index
766 * @memberof DataTable#oApi
767 */
768 function _fnVisibleToColumnIndex( oSettings, iMatch )
769 {
770 var aiVis = _fnGetColumns( oSettings, 'bVisible' );
771
772 return typeof aiVis[iMatch] === 'number' ?
773 aiVis[iMatch] :
774 null;
775 }
776
777
778 /**
779 * Covert the index of an index in the data array and convert it to the visible
780 * column index (take account of hidden columns)
781 * @param {int} iMatch Column index to lookup
782 * @param {object} oSettings dataTables settings object
783 * @returns {int} i the data index
784 * @memberof DataTable#oApi
785 */
786 function _fnColumnIndexToVisible( oSettings, iMatch )
787 {
788 var aiVis = _fnGetColumns( oSettings, 'bVisible' );
789 var iPos = $.inArray( iMatch, aiVis );
790
791 return iPos !== -1 ? iPos : null;
792 }
793
794
795 /**
796 * Get the number of visible columns
797 * @param {object} oSettings dataTables settings object
798 * @returns {int} i the number of visible columns
799 * @memberof DataTable#oApi
800 */
801 function _fnVisbleColumns( oSettings )
802 {
803 return _fnGetColumns( oSettings, 'bVisible' ).length;
804 }
805
806
807 /**
808 * Get an array of column indexes that match a given property
809 * @param {object} oSettings dataTables settings object
810 * @param {string} sParam Parameter in aoColumns to look for - typically
811 * bVisible or bSearchable
812 * @returns {array} Array of indexes with matched properties
813 * @memberof DataTable#oApi
814 */
815 function _fnGetColumns( oSettings, sParam )
816 {
817 var a = [];
818
819 $.map( oSettings.aoColumns, function(val, i) {
820 if ( val[sParam] ) {
821 a.push( i );
822 }
823 } );
824
825 return a;
826 }
827
828
829 /**
830 * Calculate the 'type' of a column
831 * @param {object} settings dataTables settings object
832 * @memberof DataTable#oApi
833 */
834 function _fnColumnTypes ( settings )
835 {
836 var columns = settings.aoColumns;
837 var data = settings.aoData;
838 var types = DataTable.ext.type.detect;
839 var i, ien, j, jen, k, ken;
840 var col, cell, detectedType, cache;
841
842 // For each column, spin over the
843 for ( i=0, ien=columns.length ; i<ien ; i++ ) {
844 col = columns[i];
845 cache = [];
846
847 if ( ! col.sType && col._sManualType ) {
848 col.sType = col._sManualType;
849 }
850 else if ( ! col.sType ) {
851 for ( j=0, jen=types.length ; j<jen ; j++ ) {
852 for ( k=0, ken=data.length ; k<ken ; k++ ) {
853 // Use a cache array so we only need to get the type data
854 // from the formatter once (when using multiple detectors)
855 if ( cache[k] === undefined ) {
856 cache[k] = _fnGetCellData( settings, k, i, 'type' );
857 }
858
859 detectedType = types[j]( cache[k], settings );
860
861 // If null, then this type can't apply to this column, so
862 // rather than testing all cells, break out. There is an
863 // exception for the last type which is `html`. We need to
864 // scan all rows since it is possible to mix string and HTML
865 // types
866 if ( ! detectedType && j !== types.length-1 ) {
867 break;
868 }
869
870 // Only a single match is needed for html type since it is
871 // bottom of the pile and very similar to string
872 if ( detectedType === 'html' ) {
873 break;
874 }
875 }
876
877 // Type is valid for all data points in the column - use this
878 // type
879 if ( detectedType ) {
880 col.sType = detectedType;
881 break;
882 }
883 }
884
885 // Fall back - if no type was detected, always use string
886 if ( ! col.sType ) {
887 col.sType = 'string';
888 }
889 }
890 }
891 }
892
893
894 /**
895 * Take the column definitions and static columns arrays and calculate how
896 * they relate to column indexes. The callback function will then apply the
897 * definition found for a column to a suitable configuration object.
898 * @param {object} oSettings dataTables settings object
899 * @param {array} aoColDefs The aoColumnDefs array that is to be applied
900 * @param {array} aoCols The aoColumns array that defines columns individually
901 * @param {function} fn Callback function - takes two parameters, the calculated
902 * column index and the definition for that column.
903 * @memberof DataTable#oApi
904 */
905 function _fnApplyColumnDefs( oSettings, aoColDefs, aoCols, fn )
906 {
907 var i, iLen, j, jLen, k, kLen, def;
908 var columns = oSettings.aoColumns;
909
910 // Column definitions with aTargets
911 if ( aoColDefs )
912 {
913 /* Loop over the definitions array - loop in reverse so first instance has priority */
914 for ( i=aoColDefs.length-1 ; i>=0 ; i-- )
915 {
916 def = aoColDefs[i];
917
918 /* Each definition can target multiple columns, as it is an array */
919 var aTargets = def.targets !== undefined ?
920 def.targets :
921 def.aTargets;
922
923 if ( ! $.isArray( aTargets ) )
924 {
925 aTargets = [ aTargets ];
926 }
927
928 for ( j=0, jLen=aTargets.length ; j<jLen ; j++ )
929 {
930 if ( typeof aTargets[j] === 'number' && aTargets[j] >= 0 )
931 {
932 /* Add columns that we don't yet know about */
933 while( columns.length <= aTargets[j] )
934 {
935 _fnAddColumn( oSettings );
936 }
937
938 /* Integer, basic index */
939 fn( aTargets[j], def );
940 }
941 else if ( typeof aTargets[j] === 'number' && aTargets[j] < 0 )
942 {
943 /* Negative integer, right to left column counting */
944 fn( columns.length+aTargets[j], def );
945 }
946 else if ( typeof aTargets[j] === 'string' )
947 {
948 /* Class name matching on TH element */
949 for ( k=0, kLen=columns.length ; k<kLen ; k++ )
950 {
951 if ( aTargets[j] == "_all" ||
952 $(columns[k].nTh).hasClass( aTargets[j] ) )
953 {
954 fn( k, def );
955 }
956 }
957 }
958 }
959 }
960 }
961
962 // Statically defined columns array
963 if ( aoCols )
964 {
965 for ( i=0, iLen=aoCols.length ; i<iLen ; i++ )
966 {
967 fn( i, aoCols[i] );
968 }
969 }
970 }
971
972 /**
973 * Add a data array to the table, creating DOM node etc. This is the parallel to
974 * _fnGatherData, but for adding rows from a Javascript source, rather than a
975 * DOM source.
976 * @param {object} oSettings dataTables settings object
977 * @param {array} aData data array to be added
978 * @param {node} [nTr] TR element to add to the table - optional. If not given,
979 * DataTables will create a row automatically
980 * @param {array} [anTds] Array of TD|TH elements for the row - must be given
981 * if nTr is.
982 * @returns {int} >=0 if successful (index of new aoData entry), -1 if failed
983 * @memberof DataTable#oApi
984 */
985 function _fnAddData ( oSettings, aDataIn, nTr, anTds )
986 {
987 /* Create the object for storing information about this new row */
988 var iRow = oSettings.aoData.length;
989 var oData = $.extend( true, {}, DataTable.models.oRow, {
990 src: nTr ? 'dom' : 'data'
991 } );
992
993 oData._aData = aDataIn;
994 oSettings.aoData.push( oData );
995
996 /* Create the cells */
997 var nTd, sThisType;
998 var columns = oSettings.aoColumns;
999 for ( var i=0, iLen=columns.length ; i<iLen ; i++ )
1000 {
1001 // When working with a row, the data source object must be populated. In
1002 // all other cases, the data source object is already populated, so we
1003 // don't overwrite it, which might break bindings etc
1004 if ( nTr ) {
1005 _fnSetCellData( oSettings, iRow, i, _fnGetCellData( oSettings, iRow, i ) );
1006 }
1007 columns[i].sType = null;
1008 }
1009
1010 /* Add to the display array */
1011 oSettings.aiDisplayMaster.push( iRow );
1012
1013 /* Create the DOM information, or register it if already present */
1014 if ( nTr || ! oSettings.oFeatures.bDeferRender )
1015 {
1016 _fnCreateTr( oSettings, iRow, nTr, anTds );
1017 }
1018
1019 return iRow;
1020 }
1021
1022
1023 /**
1024 * Add one or more TR elements to the table. Generally we'd expect to
1025 * use this for reading data from a DOM sourced table, but it could be
1026 * used for an TR element. Note that if a TR is given, it is used (i.e.
1027 * it is not cloned).
1028 * @param {object} settings dataTables settings object
1029 * @param {array|node|jQuery} trs The TR element(s) to add to the table
1030 * @returns {array} Array of indexes for the added rows
1031 * @memberof DataTable#oApi
1032 */
1033 function _fnAddTr( settings, trs )
1034 {
1035 var row;
1036
1037 // Allow an individual node to be passed in
1038 if ( ! (trs instanceof $) ) {
1039 trs = $(trs);
1040 }
1041
1042 return trs.map( function (i, el) {
1043 row = _fnGetRowElements( settings, el );
1044 return _fnAddData( settings, row.data, el, row.cells );
1045 } );
1046 }
1047
1048
1049 /**
1050 * Take a TR element and convert it to an index in aoData
1051 * @param {object} oSettings dataTables settings object
1052 * @param {node} n the TR element to find
1053 * @returns {int} index if the node is found, null if not
1054 * @memberof DataTable#oApi
1055 */
1056 function _fnNodeToDataIndex( oSettings, n )
1057 {
1058 return (n._DT_RowIndex!==undefined) ? n._DT_RowIndex : null;
1059 }
1060
1061
1062 /**
1063 * Take a TD element and convert it into a column data index (not the visible index)
1064 * @param {object} oSettings dataTables settings object
1065 * @param {int} iRow The row number the TD/TH can be found in
1066 * @param {node} n The TD/TH element to find
1067 * @returns {int} index if the node is found, -1 if not
1068 * @memberof DataTable#oApi
1069 */
1070 function _fnNodeToColumnIndex( oSettings, iRow, n )
1071 {
1072 return $.inArray( n, oSettings.aoData[ iRow ].anCells );
1073 }
1074
1075
1076 /**
1077 * Get the data for a given cell from the internal cache, taking into account data mapping
1078 * @param {object} settings dataTables settings object
1079 * @param {int} rowIdx aoData row id
1080 * @param {int} colIdx Column index
1081 * @param {string} type data get type ('display', 'type' 'filter' 'sort')
1082 * @returns {*} Cell data
1083 * @memberof DataTable#oApi
1084 */
1085 function _fnGetCellData( settings, rowIdx, colIdx, type )
1086 {
1087 var draw = settings.iDraw;
1088 var col = settings.aoColumns[colIdx];
1089 var rowData = settings.aoData[rowIdx]._aData;
1090 var defaultContent = col.sDefaultContent;
1091 var cellData = col.fnGetData( rowData, type, {
1092 settings: settings,
1093 row: rowIdx,
1094 col: colIdx
1095 } );
1096
1097 if ( cellData === undefined ) {
1098 if ( settings.iDrawError != draw && defaultContent === null ) {
1099 _fnLog( settings, 0, "Requested unknown parameter "+
1100 (typeof col.mData=='function' ? '{function}' : "'"+col.mData+"'")+
1101 " for row "+rowIdx, 4 );
1102 settings.iDrawError = draw;
1103 }
1104 return defaultContent;
1105 }
1106
1107 /* When the data source is null, we can use default column data */
1108 if ( (cellData === rowData || cellData === null) && defaultContent !== null ) {
1109 cellData = defaultContent;
1110 }
1111 else if ( typeof cellData === 'function' ) {
1112 // If the data source is a function, then we run it and use the return,
1113 // executing in the scope of the data object (for instances)
1114 return cellData.call( rowData );
1115 }
1116
1117 if ( cellData === null && type == 'display' ) {
1118 return '';
1119 }
1120 return cellData;
1121 }
1122
1123
1124 /**
1125 * Set the value for a specific cell, into the internal data cache
1126 * @param {object} settings dataTables settings object
1127 * @param {int} rowIdx aoData row id
1128 * @param {int} colIdx Column index
1129 * @param {*} val Value to set
1130 * @memberof DataTable#oApi
1131 */
1132 function _fnSetCellData( settings, rowIdx, colIdx, val )
1133 {
1134 var col = settings.aoColumns[colIdx];
1135 var rowData = settings.aoData[rowIdx]._aData;
1136
1137 col.fnSetData( rowData, val, {
1138 settings: settings,
1139 row: rowIdx,
1140 col: colIdx
1141 } );
1142 }
1143
1144
1145 // Private variable that is used to match action syntax in the data property object
1146 var __reArray = /\[.*?\]$/;
1147 var __reFn = /\(\)$/;
1148
1149 /**
1150 * Split string on periods, taking into account escaped periods
1151 * @param {string} str String to split
1152 * @return {array} Split string
1153 */
1154 function _fnSplitObjNotation( str )
1155 {
1156 return $.map( str.match(/(\\.|[^\.])+/g), function ( s ) {
1157 return s.replace(/\\./g, '.');
1158 } );
1159 }
1160
1161
1162 /**
1163 * Return a function that can be used to get data from a source object, taking
1164 * into account the ability to use nested objects as a source
1165 * @param {string|int|function} mSource The data source for the object
1166 * @returns {function} Data get function
1167 * @memberof DataTable#oApi
1168 */
1169 function _fnGetObjectDataFn( mSource )
1170 {
1171 if ( $.isPlainObject( mSource ) )
1172 {
1173 /* Build an object of get functions, and wrap them in a single call */
1174 var o = {};
1175 $.each( mSource, function (key, val) {
1176 if ( val ) {
1177 o[key] = _fnGetObjectDataFn( val );
1178 }
1179 } );
1180
1181 return function (data, type, row, meta) {
1182 var t = o[type] || o._;
1183 return t !== undefined ?
1184 t(data, type, row, meta) :
1185 data;
1186 };
1187 }
1188 else if ( mSource === null )
1189 {
1190 /* Give an empty string for rendering / sorting etc */
1191 return function (data) { // type, row and meta also passed, but not used
1192 return data;
1193 };
1194 }
1195 else if ( typeof mSource === 'function' )
1196 {
1197 return function (data, type, row, meta) {
1198 return mSource( data, type, row, meta );
1199 };
1200 }
1201 else if ( typeof mSource === 'string' && (mSource.indexOf('.') !== -1 ||
1202 mSource.indexOf('[') !== -1 || mSource.indexOf('(') !== -1) )
1203 {
1204 /* If there is a . in the source string then the data source is in a
1205 * nested object so we loop over the data for each level to get the next
1206 * level down. On each loop we test for undefined, and if found immediately
1207 * return. This allows entire objects to be missing and sDefaultContent to
1208 * be used if defined, rather than throwing an error
1209 */
1210 var fetchData = function (data, type, src) {
1211 var arrayNotation, funcNotation, out, innerSrc;
1212
1213 if ( src !== "" )
1214 {
1215 var a = _fnSplitObjNotation( src );
1216
1217 for ( var i=0, iLen=a.length ; i<iLen ; i++ )
1218 {
1219 // Check if we are dealing with special notation
1220 arrayNotation = a[i].match(__reArray);
1221 funcNotation = a[i].match(__reFn);
1222
1223 if ( arrayNotation )
1224 {
1225 // Array notation
1226 a[i] = a[i].replace(__reArray, '');
1227
1228 // Condition allows simply [] to be passed in
1229 if ( a[i] !== "" ) {
1230 data = data[ a[i] ];
1231 }
1232 out = [];
1233
1234 // Get the remainder of the nested object to get
1235 a.splice( 0, i+1 );
1236 innerSrc = a.join('.');
1237
1238 // Traverse each entry in the array getting the properties requested
1239 for ( var j=0, jLen=data.length ; j<jLen ; j++ ) {
1240 out.push( fetchData( data[j], type, innerSrc ) );
1241 }
1242
1243 // If a string is given in between the array notation indicators, that
1244 // is used to join the strings together, otherwise an array is returned
1245 var join = arrayNotation[0].substring(1, arrayNotation[0].length-1);
1246 data = (join==="") ? out : out.join(join);
1247
1248 // The inner call to fetchData has already traversed through the remainder
1249 // of the source requested, so we exit from the loop
1250 break;
1251 }
1252 else if ( funcNotation )
1253 {
1254 // Function call
1255 a[i] = a[i].replace(__reFn, '');
1256 data = data[ a[i] ]();
1257 continue;
1258 }
1259
1260 if ( data === null || data[ a[i] ] === undefined )
1261 {
1262 return undefined;
1263 }
1264 data = data[ a[i] ];
1265 }
1266 }
1267
1268 return data;
1269 };
1270
1271 return function (data, type) { // row and meta also passed, but not used
1272 return fetchData( data, type, mSource );
1273 };
1274 }
1275 else
1276 {
1277 /* Array or flat object mapping */
1278 return function (data, type) { // row and meta also passed, but not used
1279 return data[mSource];
1280 };
1281 }
1282 }
1283
1284
1285 /**
1286 * Return a function that can be used to set data from a source object, taking
1287 * into account the ability to use nested objects as a source
1288 * @param {string|int|function} mSource The data source for the object
1289 * @returns {function} Data set function
1290 * @memberof DataTable#oApi
1291 */
1292 function _fnSetObjectDataFn( mSource )
1293 {
1294 if ( $.isPlainObject( mSource ) )
1295 {
1296 /* Unlike get, only the underscore (global) option is used for for
1297 * setting data since we don't know the type here. This is why an object
1298 * option is not documented for `mData` (which is read/write), but it is
1299 * for `mRender` which is read only.
1300 */
1301 return _fnSetObjectDataFn( mSource._ );
1302 }
1303 else if ( mSource === null )
1304 {
1305 /* Nothing to do when the data source is null */
1306 return function () {};
1307 }
1308 else if ( typeof mSource === 'function' )
1309 {
1310 return function (data, val, meta) {
1311 mSource( data, 'set', val, meta );
1312 };
1313 }
1314 else if ( typeof mSource === 'string' && (mSource.indexOf('.') !== -1 ||
1315 mSource.indexOf('[') !== -1 || mSource.indexOf('(') !== -1) )
1316 {
1317 /* Like the get, we need to get data from a nested object */
1318 var setData = function (data, val, src) {
1319 var a = _fnSplitObjNotation( src ), b;
1320 var aLast = a[a.length-1];
1321 var arrayNotation, funcNotation, o, innerSrc;
1322
1323 for ( var i=0, iLen=a.length-1 ; i<iLen ; i++ )
1324 {
1325 // Check if we are dealing with an array notation request
1326 arrayNotation = a[i].match(__reArray);
1327 funcNotation = a[i].match(__reFn);
1328
1329 if ( arrayNotation )
1330 {
1331 a[i] = a[i].replace(__reArray, '');
1332 data[ a[i] ] = [];
1333
1334 // Get the remainder of the nested object to set so we can recurse
1335 b = a.slice();
1336 b.splice( 0, i+1 );
1337 innerSrc = b.join('.');
1338
1339 // Traverse each entry in the array setting the properties requested
1340 for ( var j=0, jLen=val.length ; j<jLen ; j++ )
1341 {
1342 o = {};
1343 setData( o, val[j], innerSrc );
1344 data[ a[i] ].push( o );
1345 }
1346
1347 // The inner call to setData has already traversed through the remainder
1348 // of the source and has set the data, thus we can exit here
1349 return;
1350 }
1351 else if ( funcNotation )
1352 {
1353 // Function call
1354 a[i] = a[i].replace(__reFn, '');
1355 data = data[ a[i] ]( val );
1356 }
1357
1358 // If the nested object doesn't currently exist - since we are
1359 // trying to set the value - create it
1360 if ( data[ a[i] ] === null || data[ a[i] ] === undefined )
1361 {
1362 data[ a[i] ] = {};
1363 }
1364 data = data[ a[i] ];
1365 }
1366
1367 // Last item in the input - i.e, the actual set
1368 if ( aLast.match(__reFn ) )
1369 {
1370 // Function call
1371 data = data[ aLast.replace(__reFn, '') ]( val );
1372 }
1373 else
1374 {
1375 // If array notation is used, we just want to strip it and use the property name
1376 // and assign the value. If it isn't used, then we get the result we want anyway
1377 data[ aLast.replace(__reArray, '') ] = val;
1378 }
1379 };
1380
1381 return function (data, val) { // meta is also passed in, but not used
1382 return setData( data, val, mSource );
1383 };
1384 }
1385 else
1386 {
1387 /* Array or flat object mapping */
1388 return function (data, val) { // meta is also passed in, but not used
1389 data[mSource] = val;
1390 };
1391 }
1392 }
1393
1394
1395 /**
1396 * Return an array with the full table data
1397 * @param {object} oSettings dataTables settings object
1398 * @returns array {array} aData Master data array
1399 * @memberof DataTable#oApi
1400 */
1401 function _fnGetDataMaster ( settings )
1402 {
1403 return _pluck( settings.aoData, '_aData' );
1404 }
1405
1406
1407 /**
1408 * Nuke the table
1409 * @param {object} oSettings dataTables settings object
1410 * @memberof DataTable#oApi
1411 */
1412 function _fnClearTable( settings )
1413 {
1414 settings.aoData.length = 0;
1415 settings.aiDisplayMaster.length = 0;
1416 settings.aiDisplay.length = 0;
1417 }
1418
1419
1420 /**
1421 * Take an array of integers (index array) and remove a target integer (value - not
1422 * the key!)
1423 * @param {array} a Index array to target
1424 * @param {int} iTarget value to find
1425 * @memberof DataTable#oApi
1426 */
1427 function _fnDeleteIndex( a, iTarget, splice )
1428 {
1429 var iTargetIndex = -1;
1430
1431 for ( var i=0, iLen=a.length ; i<iLen ; i++ )
1432 {
1433 if ( a[i] == iTarget )
1434 {
1435 iTargetIndex = i;
1436 }
1437 else if ( a[i] > iTarget )
1438 {
1439 a[i]--;
1440 }
1441 }
1442
1443 if ( iTargetIndex != -1 && splice === undefined )
1444 {
1445 a.splice( iTargetIndex, 1 );
1446 }
1447 }
1448
1449
1450 /**
1451 * Mark cached data as invalid such that a re-read of the data will occur when
1452 * the cached data is next requested. Also update from the data source object.
1453 *
1454 * @param {object} settings DataTables settings object
1455 * @param {int} rowIdx Row index to invalidate
1456 * @param {string} [src] Source to invalidate from: undefined, 'auto', 'dom'
1457 * or 'data'
1458 * @param {int} [colIdx] Column index to invalidate. If undefined the whole
1459 * row will be invalidated
1460 * @memberof DataTable#oApi
1461 *
1462 * @todo For the modularisation of v1.11 this will need to become a callback, so
1463 * the sort and filter methods can subscribe to it. That will required
1464 * initialisation options for sorting, which is why it is not already baked in
1465 */
1466 function _fnInvalidate( settings, rowIdx, src, colIdx )
1467 {
1468 var row = settings.aoData[ rowIdx ];
1469 var i, ien;
1470 var cellWrite = function ( cell, col ) {
1471 // This is very frustrating, but in IE if you just write directly
1472 // to innerHTML, and elements that are overwritten are GC'ed,
1473 // even if there is a reference to them elsewhere
1474 while ( cell.childNodes.length ) {
1475 cell.removeChild( cell.firstChild );
1476 }
1477
1478 cell.innerHTML = _fnGetCellData( settings, rowIdx, col, 'display' );
1479 };
1480
1481 // Are we reading last data from DOM or the data object?
1482 if ( src === 'dom' || ((! src || src === 'auto') && row.src === 'dom') ) {
1483 // Read the data from the DOM
1484 row._aData = _fnGetRowElements(
1485 settings, row, colIdx, colIdx === undefined ? undefined : row._aData
1486 )
1487 .data;
1488 }
1489 else {
1490 // Reading from data object, update the DOM
1491 var cells = row.anCells;
1492
1493 if ( cells ) {
1494 if ( colIdx !== undefined ) {
1495 cellWrite( cells[colIdx], colIdx );
1496 }
1497 else {
1498 for ( i=0, ien=cells.length ; i<ien ; i++ ) {
1499 cellWrite( cells[i], i );
1500 }
1501 }
1502 }
1503 }
1504
1505 // For both row and cell invalidation, the cached data for sorting and
1506 // filtering is nulled out
1507 row._aSortData = null;
1508 row._aFilterData = null;
1509
1510 // Invalidate the type for a specific column (if given) or all columns since
1511 // the data might have changed
1512 var cols = settings.aoColumns;
1513 if ( colIdx !== undefined ) {
1514 cols[ colIdx ].sType = null;
1515 }
1516 else {
1517 for ( i=0, ien=cols.length ; i<ien ; i++ ) {
1518 cols[i].sType = null;
1519 }
1520
1521 // Update DataTables special `DT_*` attributes for the row
1522 _fnRowAttributes( row );
1523 }
1524 }
1525
1526
1527 /**
1528 * Build a data source object from an HTML row, reading the contents of the
1529 * cells that are in the row.
1530 *
1531 * @param {object} settings DataTables settings object
1532 * @param {node|object} TR element from which to read data or existing row
1533 * object from which to re-read the data from the cells
1534 * @param {int} [colIdx] Optional column index
1535 * @param {array|object} [d] Data source object. If `colIdx` is given then this
1536 * parameter should also be given and will be used to write the data into.
1537 * Only the column in question will be written
1538 * @returns {object} Object with two parameters: `data` the data read, in
1539 * document order, and `cells` and array of nodes (they can be useful to the
1540 * caller, so rather than needing a second traversal to get them, just return
1541 * them from here).
1542 * @memberof DataTable#oApi
1543 */
1544 function _fnGetRowElements( settings, row, colIdx, d )
1545 {
1546 var
1547 tds = [],
1548 td = row.firstChild,
1549 name, col, o, i=0, contents,
1550 columns = settings.aoColumns,
1551 objectRead = settings._rowReadObject;
1552
1553 // Allow the data object to be passed in, or construct
1554 d = d || objectRead ? {} : [];
1555
1556 var attr = function ( str, td ) {
1557 if ( typeof str === 'string' ) {
1558 var idx = str.indexOf('@');
1559
1560 if ( idx !== -1 ) {
1561 var attr = str.substring( idx+1 );
1562 var setter = _fnSetObjectDataFn( str );
1563 setter( d, td.getAttribute( attr ) );
1564 }
1565 }
1566 };
1567
1568 // Read data from a cell and store into the data object
1569 var cellProcess = function ( cell ) {
1570 if ( colIdx === undefined || colIdx === i ) {
1571 col = columns[i];
1572 contents = $.trim(cell.innerHTML);
1573
1574 if ( col && col._bAttrSrc ) {
1575 var setter = _fnSetObjectDataFn( col.mData._ );
1576 setter( d, contents );
1577
1578 attr( col.mData.sort, cell );
1579 attr( col.mData.type, cell );
1580 attr( col.mData.filter, cell );
1581 }
1582 else {
1583 // Depending on the `data` option for the columns the data can
1584 // be read to either an object or an array.
1585 if ( objectRead ) {
1586 if ( ! col._setter ) {
1587 // Cache the setter function
1588 col._setter = _fnSetObjectDataFn( col.mData );
1589 }
1590 col._setter( d, contents );
1591 }
1592 else {
1593 d[i] = contents;
1594 }
1595 }
1596 }
1597
1598 i++;
1599 };
1600
1601 if ( td ) {
1602 // `tr` element was passed in
1603 while ( td ) {
1604 name = td.nodeName.toUpperCase();
1605
1606 if ( name == "TD" || name == "TH" ) {
1607 cellProcess( td );
1608 tds.push( td );
1609 }
1610
1611 td = td.nextSibling;
1612 }
1613 }
1614 else {
1615 // Existing row object passed in
1616 tds = row.anCells;
1617
1618 for ( var j=0, jen=tds.length ; j<jen ; j++ ) {
1619 cellProcess( tds[j] );
1620 }
1621 }
1622
1623 return {
1624 data: d,
1625 cells: tds
1626 };
1627 }
1628 /**
1629 * Create a new TR element (and it's TD children) for a row
1630 * @param {object} oSettings dataTables settings object
1631 * @param {int} iRow Row to consider
1632 * @param {node} [nTrIn] TR element to add to the table - optional. If not given,
1633 * DataTables will create a row automatically
1634 * @param {array} [anTds] Array of TD|TH elements for the row - must be given
1635 * if nTr is.
1636 * @memberof DataTable#oApi
1637 */
1638 function _fnCreateTr ( oSettings, iRow, nTrIn, anTds )
1639 {
1640 var
1641 row = oSettings.aoData[iRow],
1642 rowData = row._aData,
1643 cells = [],
1644 nTr, nTd, oCol,
1645 i, iLen;
1646
1647 if ( row.nTr === null )
1648 {
1649 nTr = nTrIn || document.createElement('tr');
1650
1651 row.nTr = nTr;
1652 row.anCells = cells;
1653
1654 /* Use a private property on the node to allow reserve mapping from the node
1655 * to the aoData array for fast look up
1656 */
1657 nTr._DT_RowIndex = iRow;
1658
1659 /* Special parameters can be given by the data source to be used on the row */
1660 _fnRowAttributes( row );
1661
1662 /* Process each column */
1663 for ( i=0, iLen=oSettings.aoColumns.length ; i<iLen ; i++ )
1664 {
1665 oCol = oSettings.aoColumns[i];
1666
1667 nTd = nTrIn ? anTds[i] : document.createElement( oCol.sCellType );
1668 cells.push( nTd );
1669
1670 // Need to create the HTML if new, or if a rendering function is defined
1671 if ( !nTrIn || oCol.mRender || oCol.mData !== i )
1672 {
1673 nTd.innerHTML = _fnGetCellData( oSettings, iRow, i, 'display' );
1674 }
1675
1676 /* Add user defined class */
1677 if ( oCol.sClass )
1678 {
1679 nTd.className += ' '+oCol.sClass;
1680 }
1681
1682 // Visibility - add or remove as required
1683 if ( oCol.bVisible && ! nTrIn )
1684 {
1685 nTr.appendChild( nTd );
1686 }
1687 else if ( ! oCol.bVisible && nTrIn )
1688 {
1689 nTd.parentNode.removeChild( nTd );
1690 }
1691
1692 if ( oCol.fnCreatedCell )
1693 {
1694 oCol.fnCreatedCell.call( oSettings.oInstance,
1695 nTd, _fnGetCellData( oSettings, iRow, i ), rowData, iRow, i
1696 );
1697 }
1698 }
1699
1700 _fnCallbackFire( oSettings, 'aoRowCreatedCallback', null, [nTr, rowData, iRow] );
1701 }
1702
1703 // Remove once webkit bug 131819 and Chromium bug 365619 have been resolved
1704 // and deployed
1705 row.nTr.setAttribute( 'role', 'row' );
1706 }
1707
1708
1709 /**
1710 * Add attributes to a row based on the special `DT_*` parameters in a data
1711 * source object.
1712 * @param {object} DataTables row object for the row to be modified
1713 * @memberof DataTable#oApi
1714 */
1715 function _fnRowAttributes( row )
1716 {
1717 var tr = row.nTr;
1718 var data = row._aData;
1719
1720 if ( tr ) {
1721 if ( data.DT_RowId ) {
1722 tr.id = data.DT_RowId;
1723 }
1724
1725 if ( data.DT_RowClass ) {
1726 // Remove any classes added by DT_RowClass before
1727 var a = data.DT_RowClass.split(' ');
1728 row.__rowc = row.__rowc ?
1729 _unique( row.__rowc.concat( a ) ) :
1730 a;
1731
1732 $(tr)
1733 .removeClass( row.__rowc.join(' ') )
1734 .addClass( data.DT_RowClass );
1735 }
1736
1737 if ( data.DT_RowData ) {
1738 $(tr).data( data.DT_RowData );
1739 }
1740 }
1741 }
1742
1743
1744 /**
1745 * Create the HTML header for the table
1746 * @param {object} oSettings dataTables settings object
1747 * @memberof DataTable#oApi
1748 */
1749 function _fnBuildHead( oSettings )
1750 {
1751 var i, ien, cell, row, column;
1752 var thead = oSettings.nTHead;
1753 var tfoot = oSettings.nTFoot;
1754 var createHeader = $('th, td', thead).length === 0;
1755 var classes = oSettings.oClasses;
1756 var columns = oSettings.aoColumns;
1757
1758 if ( createHeader ) {
1759 row = $('<tr/>').appendTo( thead );
1760 }
1761
1762 for ( i=0, ien=columns.length ; i<ien ; i++ ) {
1763 column = columns[i];
1764 cell = $( column.nTh ).addClass( column.sClass );
1765
1766 if ( createHeader ) {
1767 cell.appendTo( row );
1768 }
1769
1770 // 1.11 move into sorting
1771 if ( oSettings.oFeatures.bSort ) {
1772 cell.addClass( column.sSortingClass );
1773
1774 if ( column.bSortable !== false ) {
1775 cell
1776 .attr( 'tabindex', oSettings.iTabIndex )
1777 .attr( 'aria-controls', oSettings.sTableId );
1778
1779 _fnSortAttachListener( oSettings, column.nTh, i );
1780 }
1781 }
1782
1783 if ( column.sTitle != cell.html() ) {
1784 cell.html( column.sTitle );
1785 }
1786
1787 _fnRenderer( oSettings, 'header' )(
1788 oSettings, cell, column, classes
1789 );
1790 }
1791
1792 if ( createHeader ) {
1793 _fnDetectHeader( oSettings.aoHeader, thead );
1794 }
1795
1796 /* ARIA role for the rows */
1797 $(thead).find('>tr').attr('role', 'row');
1798
1799 /* Deal with the footer - add classes if required */
1800 $(thead).find('>tr>th, >tr>td').addClass( classes.sHeaderTH );
1801 $(tfoot).find('>tr>th, >tr>td').addClass( classes.sFooterTH );
1802
1803 // Cache the footer cells. Note that we only take the cells from the first
1804 // row in the footer. If there is more than one row the user wants to
1805 // interact with, they need to use the table().foot() method. Note also this
1806 // allows cells to be used for multiple columns using colspan
1807 if ( tfoot !== null ) {
1808 var cells = oSettings.aoFooter[0];
1809
1810 for ( i=0, ien=cells.length ; i<ien ; i++ ) {
1811 column = columns[i];
1812 column.nTf = cells[i].cell;
1813
1814 if ( column.sClass ) {
1815 $(column.nTf).addClass( column.sClass );
1816 }
1817 }
1818 }
1819 }
1820
1821
1822 /**
1823 * Draw the header (or footer) element based on the column visibility states. The
1824 * methodology here is to use the layout array from _fnDetectHeader, modified for
1825 * the instantaneous column visibility, to construct the new layout. The grid is
1826 * traversed over cell at a time in a rows x columns grid fashion, although each
1827 * cell insert can cover multiple elements in the grid - which is tracks using the
1828 * aApplied array. Cell inserts in the grid will only occur where there isn't
1829 * already a cell in that position.
1830 * @param {object} oSettings dataTables settings object
1831 * @param array {objects} aoSource Layout array from _fnDetectHeader
1832 * @param {boolean} [bIncludeHidden=false] If true then include the hidden columns in the calc,
1833 * @memberof DataTable#oApi
1834 */
1835 function _fnDrawHead( oSettings, aoSource, bIncludeHidden )
1836 {
1837 var i, iLen, j, jLen, k, kLen, n, nLocalTr;
1838 var aoLocal = [];
1839 var aApplied = [];
1840 var iColumns = oSettings.aoColumns.length;
1841 var iRowspan, iColspan;
1842
1843 if ( ! aoSource )
1844 {
1845 return;
1846 }
1847
1848 if ( bIncludeHidden === undefined )
1849 {
1850 bIncludeHidden = false;
1851 }
1852
1853 /* Make a copy of the master layout array, but without the visible columns in it */
1854 for ( i=0, iLen=aoSource.length ; i<iLen ; i++ )
1855 {
1856 aoLocal[i] = aoSource[i].slice();
1857 aoLocal[i].nTr = aoSource[i].nTr;
1858
1859 /* Remove any columns which are currently hidden */
1860 for ( j=iColumns-1 ; j>=0 ; j-- )
1861 {
1862 if ( !oSettings.aoColumns[j].bVisible && !bIncludeHidden )
1863 {
1864 aoLocal[i].splice( j, 1 );
1865 }
1866 }
1867
1868 /* Prep the applied array - it needs an element for each row */
1869 aApplied.push( [] );
1870 }
1871
1872 for ( i=0, iLen=aoLocal.length ; i<iLen ; i++ )
1873 {
1874 nLocalTr = aoLocal[i].nTr;
1875
1876 /* All cells are going to be replaced, so empty out the row */
1877 if ( nLocalTr )
1878 {
1879 while( (n = nLocalTr.firstChild) )
1880 {
1881 nLocalTr.removeChild( n );
1882 }
1883 }
1884
1885 for ( j=0, jLen=aoLocal[i].length ; j<jLen ; j++ )
1886 {
1887 iRowspan = 1;
1888 iColspan = 1;
1889
1890 /* Check to see if there is already a cell (row/colspan) covering our target
1891 * insert point. If there is, then there is nothing to do.
1892 */
1893 if ( aApplied[i][j] === undefined )
1894 {
1895 nLocalTr.appendChild( aoLocal[i][j].cell );
1896 aApplied[i][j] = 1;
1897
1898 /* Expand the cell to cover as many rows as needed */
1899 while ( aoLocal[i+iRowspan] !== undefined &&
1900 aoLocal[i][j].cell == aoLocal[i+iRowspan][j].cell )
1901 {
1902 aApplied[i+iRowspan][j] = 1;
1903 iRowspan++;
1904 }
1905
1906 /* Expand the cell to cover as many columns as needed */
1907 while ( aoLocal[i][j+iColspan] !== undefined &&
1908 aoLocal[i][j].cell == aoLocal[i][j+iColspan].cell )
1909 {
1910 /* Must update the applied array over the rows for the columns */
1911 for ( k=0 ; k<iRowspan ; k++ )
1912 {
1913 aApplied[i+k][j+iColspan] = 1;
1914 }
1915 iColspan++;
1916 }
1917
1918 /* Do the actual expansion in the DOM */
1919 $(aoLocal[i][j].cell)
1920 .attr('rowspan', iRowspan)
1921 .attr('colspan', iColspan);
1922 }
1923 }
1924 }
1925 }
1926
1927
1928 /**
1929 * Insert the required TR nodes into the table for display
1930 * @param {object} oSettings dataTables settings object
1931 * @memberof DataTable#oApi
1932 */
1933 function _fnDraw( oSettings )
1934 {
1935 /* Provide a pre-callback function which can be used to cancel the draw is false is returned */
1936 var aPreDraw = _fnCallbackFire( oSettings, 'aoPreDrawCallback', 'preDraw', [oSettings] );
1937 if ( $.inArray( false, aPreDraw ) !== -1 )
1938 {
1939 _fnProcessingDisplay( oSettings, false );
1940 return;
1941 }
1942
1943 var i, iLen, n;
1944 var anRows = [];
1945 var iRowCount = 0;
1946 var asStripeClasses = oSettings.asStripeClasses;
1947 var iStripes = asStripeClasses.length;
1948 var iOpenRows = oSettings.aoOpenRows.length;
1949 var oLang = oSettings.oLanguage;
1950 var iInitDisplayStart = oSettings.iInitDisplayStart;
1951 var bServerSide = _fnDataSource( oSettings ) == 'ssp';
1952 var aiDisplay = oSettings.aiDisplay;
1953
1954 oSettings.bDrawing = true;
1955
1956 /* Check and see if we have an initial draw position from state saving */
1957 if ( iInitDisplayStart !== undefined && iInitDisplayStart !== -1 )
1958 {
1959 oSettings._iDisplayStart = bServerSide ?
1960 iInitDisplayStart :
1961 iInitDisplayStart >= oSettings.fnRecordsDisplay() ?
1962 0 :
1963 iInitDisplayStart;
1964
1965 oSettings.iInitDisplayStart = -1;
1966 }
1967
1968 var iDisplayStart = oSettings._iDisplayStart;
1969 var iDisplayEnd = oSettings.fnDisplayEnd();
1970
1971 /* Server-side processing draw intercept */
1972 if ( oSettings.bDeferLoading )
1973 {
1974 oSettings.bDeferLoading = false;
1975 oSettings.iDraw++;
1976 _fnProcessingDisplay( oSettings, false );
1977 }
1978 else if ( !bServerSide )
1979 {
1980 oSettings.iDraw++;
1981 }
1982 else if ( !oSettings.bDestroying && !_fnAjaxUpdate( oSettings ) )
1983 {
1984 return;
1985 }
1986
1987 if ( aiDisplay.length !== 0 )
1988 {
1989 var iStart = bServerSide ? 0 : iDisplayStart;
1990 var iEnd = bServerSide ? oSettings.aoData.length : iDisplayEnd;
1991
1992 for ( var j=iStart ; j<iEnd ; j++ )
1993 {
1994 var iDataIndex = aiDisplay[j];
1995 var aoData = oSettings.aoData[ iDataIndex ];
1996 if ( aoData.nTr === null )
1997 {
1998 _fnCreateTr( oSettings, iDataIndex );
1999 }
2000
2001 var nRow = aoData.nTr;
2002
2003 /* Remove the old striping classes and then add the new one */
2004 if ( iStripes !== 0 )
2005 {
2006 var sStripe = asStripeClasses[ iRowCount % iStripes ];
2007 if ( aoData._sRowStripe != sStripe )
2008 {
2009 $(nRow).removeClass( aoData._sRowStripe ).addClass( sStripe );
2010 aoData._sRowStripe = sStripe;
2011 }
2012 }
2013
2014 // Row callback functions - might want to manipulate the row
2015 // iRowCount and j are not currently documented. Are they at all
2016 // useful?
2017 _fnCallbackFire( oSettings, 'aoRowCallback', null,
2018 [nRow, aoData._aData, iRowCount, j] );
2019
2020 anRows.push( nRow );
2021 iRowCount++;
2022 }
2023 }
2024 else
2025 {
2026 /* Table is empty - create a row with an empty message in it */
2027 var sZero = oLang.sZeroRecords;
2028 if ( oSettings.iDraw == 1 && _fnDataSource( oSettings ) == 'ajax' )
2029 {
2030 sZero = oLang.sLoadingRecords;
2031 }
2032 else if ( oLang.sEmptyTable && oSettings.fnRecordsTotal() === 0 )
2033 {
2034 sZero = oLang.sEmptyTable;
2035 }
2036
2037 anRows[ 0 ] = $( '<tr/>', { 'class': iStripes ? asStripeClasses[0] : '' } )
2038 .append( $('<td />', {
2039 'valign': 'top',
2040 'colSpan': _fnVisbleColumns( oSettings ),
2041 'class': oSettings.oClasses.sRowEmpty
2042 } ).html( sZero ) )[0];
2043 }
2044
2045 /* Header and footer callbacks */
2046 _fnCallbackFire( oSettings, 'aoHeaderCallback', 'header', [ $(oSettings.nTHead).children('tr')[0],
2047 _fnGetDataMaster( oSettings ), iDisplayStart, iDisplayEnd, aiDisplay ] );
2048
2049 _fnCallbackFire( oSettings, 'aoFooterCallback', 'footer', [ $(oSettings.nTFoot).children('tr')[0],
2050 _fnGetDataMaster( oSettings ), iDisplayStart, iDisplayEnd, aiDisplay ] );
2051
2052 var body = $(oSettings.nTBody);
2053
2054 body.children().detach();
2055 body.append( $(anRows) );
2056
2057 /* Call all required callback functions for the end of a draw */
2058 _fnCallbackFire( oSettings, 'aoDrawCallback', 'draw', [oSettings] );
2059
2060 /* Draw is complete, sorting and filtering must be as well */
2061 oSettings.bSorted = false;
2062 oSettings.bFiltered = false;
2063 oSettings.bDrawing = false;
2064 }
2065
2066
2067 /**
2068 * Redraw the table - taking account of the various features which are enabled
2069 * @param {object} oSettings dataTables settings object
2070 * @param {boolean} [holdPosition] Keep the current paging position. By default
2071 * the paging is reset to the first page
2072 * @memberof DataTable#oApi
2073 */
2074 function _fnReDraw( settings, holdPosition )
2075 {
2076 var
2077 features = settings.oFeatures,
2078 sort = features.bSort,
2079 filter = features.bFilter;
2080
2081 if ( sort ) {
2082 _fnSort( settings );
2083 }
2084
2085 if ( filter ) {
2086 _fnFilterComplete( settings, settings.oPreviousSearch );
2087 }
2088 else {
2089 // No filtering, so we want to just use the display master
2090 settings.aiDisplay = settings.aiDisplayMaster.slice();
2091 }
2092
2093 if ( holdPosition !== true ) {
2094 settings._iDisplayStart = 0;
2095 }
2096
2097 // Let any modules know about the draw hold position state (used by
2098 // scrolling internally)
2099 settings._drawHold = holdPosition;
2100
2101 _fnDraw( settings );
2102
2103 settings._drawHold = false;
2104 }
2105
2106
2107 /**
2108 * Add the options to the page HTML for the table
2109 * @param {object} oSettings dataTables settings object
2110 * @memberof DataTable#oApi
2111 */
2112 function _fnAddOptionsHtml ( oSettings )
2113 {
2114 var classes = oSettings.oClasses;
2115 var table = $(oSettings.nTable);
2116 var holding = $('<div/>').insertBefore( table ); // Holding element for speed
2117 var features = oSettings.oFeatures;
2118
2119 // All DataTables are wrapped in a div
2120 var insert = $('<div/>', {
2121 id: oSettings.sTableId+'_wrapper',
2122 'class': classes.sWrapper + (oSettings.nTFoot ? '' : ' '+classes.sNoFooter)
2123 } );
2124
2125 oSettings.nHolding = holding[0];
2126 oSettings.nTableWrapper = insert[0];
2127 oSettings.nTableReinsertBefore = oSettings.nTable.nextSibling;
2128
2129 /* Loop over the user set positioning and place the elements as needed */
2130 var aDom = oSettings.sDom.split('');
2131 var featureNode, cOption, nNewNode, cNext, sAttr, j;
2132 for ( var i=0 ; i<aDom.length ; i++ )
2133 {
2134 featureNode = null;
2135 cOption = aDom[i];
2136
2137 if ( cOption == '<' )
2138 {
2139 /* New container div */
2140 nNewNode = $('<div/>')[0];
2141
2142 /* Check to see if we should append an id and/or a class name to the container */
2143 cNext = aDom[i+1];
2144 if ( cNext == "'" || cNext == '"' )
2145 {
2146 sAttr = "";
2147 j = 2;
2148 while ( aDom[i+j] != cNext )
2149 {
2150 sAttr += aDom[i+j];
2151 j++;
2152 }
2153
2154 /* Replace jQuery UI constants @todo depreciated */
2155 if ( sAttr == "H" )
2156 {
2157 sAttr = classes.sJUIHeader;
2158 }
2159 else if ( sAttr == "F" )
2160 {
2161 sAttr = classes.sJUIFooter;
2162 }
2163
2164 /* The attribute can be in the format of "#id.class", "#id" or "class" This logic
2165 * breaks the string into parts and applies them as needed
2166 */
2167 if ( sAttr.indexOf('.') != -1 )
2168 {
2169 var aSplit = sAttr.split('.');
2170 nNewNode.id = aSplit[0].substr(1, aSplit[0].length-1);
2171 nNewNode.className = aSplit[1];
2172 }
2173 else if ( sAttr.charAt(0) == "#" )
2174 {
2175 nNewNode.id = sAttr.substr(1, sAttr.length-1);
2176 }
2177 else
2178 {
2179 nNewNode.className = sAttr;
2180 }
2181
2182 i += j; /* Move along the position array */
2183 }
2184
2185 insert.append( nNewNode );
2186 insert = $(nNewNode);
2187 }
2188 else if ( cOption == '>' )
2189 {
2190 /* End container div */
2191 insert = insert.parent();
2192 }
2193 // @todo Move options into their own plugins?
2194 else if ( cOption == 'l' && features.bPaginate && features.bLengthChange )
2195 {
2196 /* Length */
2197 featureNode = _fnFeatureHtmlLength( oSettings );
2198 }
2199 else if ( cOption == 'f' && features.bFilter )
2200 {
2201 /* Filter */
2202 featureNode = _fnFeatureHtmlFilter( oSettings );
2203 }
2204 else if ( cOption == 'r' && features.bProcessing )
2205 {
2206 /* pRocessing */
2207 featureNode = _fnFeatureHtmlProcessing( oSettings );
2208 }
2209 else if ( cOption == 't' )
2210 {
2211 /* Table */
2212 featureNode = _fnFeatureHtmlTable( oSettings );
2213 }
2214 else if ( cOption == 'i' && features.bInfo )
2215 {
2216 /* Info */
2217 featureNode = _fnFeatureHtmlInfo( oSettings );
2218 }
2219 else if ( cOption == 'p' && features.bPaginate )
2220 {
2221 /* Pagination */
2222 featureNode = _fnFeatureHtmlPaginate( oSettings );
2223 }
2224 else if ( DataTable.ext.feature.length !== 0 )
2225 {
2226 /* Plug-in features */
2227 var aoFeatures = DataTable.ext.feature;
2228 for ( var k=0, kLen=aoFeatures.length ; k<kLen ; k++ )
2229 {
2230 if ( cOption == aoFeatures[k].cFeature )
2231 {
2232 featureNode = aoFeatures[k].fnInit( oSettings );
2233 break;
2234 }
2235 }
2236 }
2237
2238 /* Add to the 2D features array */
2239 if ( featureNode )
2240 {
2241 var aanFeatures = oSettings.aanFeatures;
2242
2243 if ( ! aanFeatures[cOption] )
2244 {
2245 aanFeatures[cOption] = [];
2246 }
2247
2248 aanFeatures[cOption].push( featureNode );
2249 insert.append( featureNode );
2250 }
2251 }
2252
2253 /* Built our DOM structure - replace the holding div with what we want */
2254 holding.replaceWith( insert );
2255 }
2256
2257
2258 /**
2259 * Use the DOM source to create up an array of header cells. The idea here is to
2260 * create a layout grid (array) of rows x columns, which contains a reference
2261 * to the cell that that point in the grid (regardless of col/rowspan), such that
2262 * any column / row could be removed and the new grid constructed
2263 * @param array {object} aLayout Array to store the calculated layout in
2264 * @param {node} nThead The header/footer element for the table
2265 * @memberof DataTable#oApi
2266 */
2267 function _fnDetectHeader ( aLayout, nThead )
2268 {
2269 var nTrs = $(nThead).children('tr');
2270 var nTr, nCell;
2271 var i, k, l, iLen, jLen, iColShifted, iColumn, iColspan, iRowspan;
2272 var bUnique;
2273 var fnShiftCol = function ( a, i, j ) {
2274 var k = a[i];
2275 while ( k[j] ) {
2276 j++;
2277 }
2278 return j;
2279 };
2280
2281 aLayout.splice( 0, aLayout.length );
2282
2283 /* We know how many rows there are in the layout - so prep it */
2284 for ( i=0, iLen=nTrs.length ; i<iLen ; i++ )
2285 {
2286 aLayout.push( [] );
2287 }
2288
2289 /* Calculate a layout array */
2290 for ( i=0, iLen=nTrs.length ; i<iLen ; i++ )
2291 {
2292 nTr = nTrs[i];
2293 iColumn = 0;
2294
2295 /* For every cell in the row... */
2296 nCell = nTr.firstChild;
2297 while ( nCell ) {
2298 if ( nCell.nodeName.toUpperCase() == "TD" ||
2299 nCell.nodeName.toUpperCase() == "TH" )
2300 {
2301 /* Get the col and rowspan attributes from the DOM and sanitise them */
2302 iColspan = nCell.getAttribute('colspan') * 1;
2303 iRowspan = nCell.getAttribute('rowspan') * 1;
2304 iColspan = (!iColspan || iColspan===0 || iColspan===1) ? 1 : iColspan;
2305 iRowspan = (!iRowspan || iRowspan===0 || iRowspan===1) ? 1 : iRowspan;
2306
2307 /* There might be colspan cells already in this row, so shift our target
2308 * accordingly
2309 */
2310 iColShifted = fnShiftCol( aLayout, i, iColumn );
2311
2312 /* Cache calculation for unique columns */
2313 bUnique = iColspan === 1 ? true : false;
2314
2315 /* If there is col / rowspan, copy the information into the layout grid */
2316 for ( l=0 ; l<iColspan ; l++ )
2317 {
2318 for ( k=0 ; k<iRowspan ; k++ )
2319 {
2320 aLayout[i+k][iColShifted+l] = {
2321 "cell": nCell,
2322 "unique": bUnique
2323 };
2324 aLayout[i+k].nTr = nTr;
2325 }
2326 }
2327 }
2328 nCell = nCell.nextSibling;
2329 }
2330 }
2331 }
2332
2333
2334 /**
2335 * Get an array of unique th elements, one for each column
2336 * @param {object} oSettings dataTables settings object
2337 * @param {node} nHeader automatically detect the layout from this node - optional
2338 * @param {array} aLayout thead/tfoot layout from _fnDetectHeader - optional
2339 * @returns array {node} aReturn list of unique th's
2340 * @memberof DataTable#oApi
2341 */
2342 function _fnGetUniqueThs ( oSettings, nHeader, aLayout )
2343 {
2344 var aReturn = [];
2345 if ( !aLayout )
2346 {
2347 aLayout = oSettings.aoHeader;
2348 if ( nHeader )
2349 {
2350 aLayout = [];
2351 _fnDetectHeader( aLayout, nHeader );
2352 }
2353 }
2354
2355 for ( var i=0, iLen=aLayout.length ; i<iLen ; i++ )
2356 {
2357 for ( var j=0, jLen=aLayout[i].length ; j<jLen ; j++ )
2358 {
2359 if ( aLayout[i][j].unique &&
2360 (!aReturn[j] || !oSettings.bSortCellsTop) )
2361 {
2362 aReturn[j] = aLayout[i][j].cell;
2363 }
2364 }
2365 }
2366
2367 return aReturn;
2368 }
2369
2370
2371
2372 /**
2373 * Create an Ajax call based on the table's settings, taking into account that
2374 * parameters can have multiple forms, and backwards compatibility.
2375 *
2376 * @param {object} oSettings dataTables settings object
2377 * @param {array} data Data to send to the server, required by
2378 * DataTables - may be augmented by developer callbacks
2379 * @param {function} fn Callback function to run when data is obtained
2380 */
2381 function _fnBuildAjax( oSettings, data, fn )
2382 {
2383 // Compatibility with 1.9-, allow fnServerData and event to manipulate
2384 _fnCallbackFire( oSettings, 'aoServerParams', 'serverParams', [data] );
2385
2386 // Convert to object based for 1.10+ if using the old array scheme which can
2387 // come from server-side processing or serverParams
2388 if ( data && $.isArray(data) ) {
2389 var tmp = {};
2390 var rbracket = /(.*?)\[\]$/;
2391
2392 $.each( data, function (key, val) {
2393 var match = val.name.match(rbracket);
2394
2395 if ( match ) {
2396 // Support for arrays
2397 var name = match[0];
2398
2399 if ( ! tmp[ name ] ) {
2400 tmp[ name ] = [];
2401 }
2402 tmp[ name ].push( val.value );
2403 }
2404 else {
2405 tmp[val.name] = val.value;
2406 }
2407 } );
2408 data = tmp;
2409 }
2410
2411 var ajaxData;
2412 var ajax = oSettings.ajax;
2413 var instance = oSettings.oInstance;
2414
2415 if ( $.isPlainObject( ajax ) && ajax.data )
2416 {
2417 ajaxData = ajax.data;
2418
2419 var newData = $.isFunction( ajaxData ) ?
2420 ajaxData( data ) : // fn can manipulate data or return an object
2421 ajaxData; // object or array to merge
2422
2423 // If the function returned an object, use that alone
2424 data = $.isFunction( ajaxData ) && newData ?
2425 newData :
2426 $.extend( true, data, newData );
2427
2428 // Remove the data property as we've resolved it already and don't want
2429 // jQuery to do it again (it is restored at the end of the function)
2430 delete ajax.data;
2431 }
2432
2433 var baseAjax = {
2434 "data": data,
2435 "success": function (json) {
2436 var error = json.error || json.sError;
2437 if ( error ) {
2438 oSettings.oApi._fnLog( oSettings, 0, error );
2439 }
2440
2441 oSettings.json = json;
2442 _fnCallbackFire( oSettings, null, 'xhr', [oSettings, json] );
2443 fn( json );
2444 },
2445 "dataType": "json",
2446 "cache": false,
2447 "type": oSettings.sServerMethod,
2448 "error": function (xhr, error, thrown) {
2449 var log = oSettings.oApi._fnLog;
2450
2451 if ( error == "parsererror" ) {
2452 log( oSettings, 0, 'Invalid JSON response', 1 );
2453 }
2454 else if ( xhr.readyState === 4 ) {
2455 log( oSettings, 0, 'Ajax error', 7 );
2456 }
2457
2458 _fnProcessingDisplay( oSettings, false );
2459 }
2460 };
2461
2462 // Store the data submitted for the API
2463 oSettings.oAjaxData = data;
2464
2465 // Allow plug-ins and external processes to modify the data
2466 _fnCallbackFire( oSettings, null, 'preXhr', [oSettings, data] );
2467
2468 if ( oSettings.fnServerData )
2469 {
2470 // DataTables 1.9- compatibility
2471 oSettings.fnServerData.call( instance,
2472 oSettings.sAjaxSource,
2473 $.map( data, function (val, key) { // Need to convert back to 1.9 trad format
2474 return { name: key, value: val };
2475 } ),
2476 fn,
2477 oSettings
2478 );
2479 }
2480 else if ( oSettings.sAjaxSource || typeof ajax === 'string' )
2481 {
2482 // DataTables 1.9- compatibility
2483 oSettings.jqXHR = $.ajax( $.extend( baseAjax, {
2484 url: ajax || oSettings.sAjaxSource
2485 } ) );
2486 }
2487 else if ( $.isFunction( ajax ) )
2488 {
2489 // Is a function - let the caller define what needs to be done
2490 oSettings.jqXHR = ajax.call( instance, data, fn, oSettings );
2491 }
2492 else
2493 {
2494 // Object to extend the base settings
2495 oSettings.jqXHR = $.ajax( $.extend( baseAjax, ajax ) );
2496
2497 // Restore for next time around
2498 ajax.data = ajaxData;
2499 }
2500 }
2501
2502
2503 /**
2504 * Update the table using an Ajax call
2505 * @param {object} settings dataTables settings object
2506 * @returns {boolean} Block the table drawing or not
2507 * @memberof DataTable#oApi
2508 */
2509 function _fnAjaxUpdate( settings )
2510 {
2511 if ( settings.bAjaxDataGet ) {
2512 settings.iDraw++;
2513 _fnProcessingDisplay( settings, true );
2514
2515 _fnBuildAjax(
2516 settings,
2517 _fnAjaxParameters( settings ),
2518 function(json) {
2519 _fnAjaxUpdateDraw( settings, json );
2520 }
2521 );
2522
2523 return false;
2524 }
2525 return true;
2526 }
2527
2528
2529 /**
2530 * Build up the parameters in an object needed for a server-side processing
2531 * request. Note that this is basically done twice, is different ways - a modern
2532 * method which is used by default in DataTables 1.10 which uses objects and
2533 * arrays, or the 1.9- method with is name / value pairs. 1.9 method is used if
2534 * the sAjaxSource option is used in the initialisation, or the legacyAjax
2535 * option is set.
2536 * @param {object} oSettings dataTables settings object
2537 * @returns {bool} block the table drawing or not
2538 * @memberof DataTable#oApi
2539 */
2540 function _fnAjaxParameters( settings )
2541 {
2542 var
2543 columns = settings.aoColumns,
2544 columnCount = columns.length,
2545 features = settings.oFeatures,
2546 preSearch = settings.oPreviousSearch,
2547 preColSearch = settings.aoPreSearchCols,
2548 i, data = [], dataProp, column, columnSearch,
2549 sort = _fnSortFlatten( settings ),
2550 displayStart = settings._iDisplayStart,
2551 displayLength = features.bPaginate !== false ?
2552 settings._iDisplayLength :
2553 -1;
2554
2555 var param = function ( name, value ) {
2556 data.push( { 'name': name, 'value': value } );
2557 };
2558
2559 // DataTables 1.9- compatible method
2560 param( 'sEcho', settings.iDraw );
2561 param( 'iColumns', columnCount );
2562 param( 'sColumns', _pluck( columns, 'sName' ).join(',') );
2563 param( 'iDisplayStart', displayStart );
2564 param( 'iDisplayLength', displayLength );
2565
2566 // DataTables 1.10+ method
2567 var d = {
2568 draw: settings.iDraw,
2569 columns: [],
2570 order: [],
2571 start: displayStart,
2572 length: displayLength,
2573 search: {
2574 value: preSearch.sSearch,
2575 regex: preSearch.bRegex
2576 }
2577 };
2578
2579 for ( i=0 ; i<columnCount ; i++ ) {
2580 column = columns[i];
2581 columnSearch = preColSearch[i];
2582 dataProp = typeof column.mData=="function" ? 'function' : column.mData ;
2583
2584 d.columns.push( {
2585 data: dataProp,
2586 name: column.sName,
2587 searchable: column.bSearchable,
2588 orderable: column.bSortable,
2589 search: {
2590 value: columnSearch.sSearch,
2591 regex: columnSearch.bRegex
2592 }
2593 } );
2594
2595 param( "mDataProp_"+i, dataProp );
2596
2597 if ( features.bFilter ) {
2598 param( 'sSearch_'+i, columnSearch.sSearch );
2599 param( 'bRegex_'+i, columnSearch.bRegex );
2600 param( 'bSearchable_'+i, column.bSearchable );
2601 }
2602
2603 if ( features.bSort ) {
2604 param( 'bSortable_'+i, column.bSortable );
2605 }
2606 }
2607
2608 if ( features.bFilter ) {
2609 param( 'sSearch', preSearch.sSearch );
2610 param( 'bRegex', preSearch.bRegex );
2611 }
2612
2613 if ( features.bSort ) {
2614 $.each( sort, function ( i, val ) {
2615 d.order.push( { column: val.col, dir: val.dir } );
2616
2617 param( 'iSortCol_'+i, val.col );
2618 param( 'sSortDir_'+i, val.dir );
2619 } );
2620
2621 param( 'iSortingCols', sort.length );
2622 }
2623
2624 // If the legacy.ajax parameter is null, then we automatically decide which
2625 // form to use, based on sAjaxSource
2626 var legacy = DataTable.ext.legacy.ajax;
2627 if ( legacy === null ) {
2628 return settings.sAjaxSource ? data : d;
2629 }
2630
2631 // Otherwise, if legacy has been specified then we use that to decide on the
2632 // form
2633 return legacy ? data : d;
2634 }
2635
2636
2637 /**
2638 * Data the data from the server (nuking the old) and redraw the table
2639 * @param {object} oSettings dataTables settings object
2640 * @param {object} json json data return from the server.
2641 * @param {string} json.sEcho Tracking flag for DataTables to match requests
2642 * @param {int} json.iTotalRecords Number of records in the data set, not accounting for filtering
2643 * @param {int} json.iTotalDisplayRecords Number of records in the data set, accounting for filtering
2644 * @param {array} json.aaData The data to display on this page
2645 * @param {string} [json.sColumns] Column ordering (sName, comma separated)
2646 * @memberof DataTable#oApi
2647 */
2648 function _fnAjaxUpdateDraw ( settings, json )
2649 {
2650 // v1.10 uses camelCase variables, while 1.9 uses Hungarian notation.
2651 // Support both
2652 var compat = function ( old, modern ) {
2653 return json[old] !== undefined ? json[old] : json[modern];
2654 };
2655
2656 var draw = compat( 'sEcho', 'draw' );
2657 var recordsTotal = compat( 'iTotalRecords', 'recordsTotal' );
2658 var recordsFiltered = compat( 'iTotalDisplayRecords', 'recordsFiltered' );
2659
2660 if ( draw ) {
2661 // Protect against out of sequence returns
2662 if ( draw*1 < settings.iDraw ) {
2663 return;
2664 }
2665 settings.iDraw = draw * 1;
2666 }
2667
2668 _fnClearTable( settings );
2669 settings._iRecordsTotal = parseInt(recordsTotal, 10);
2670 settings._iRecordsDisplay = parseInt(recordsFiltered, 10);
2671
2672 var data = _fnAjaxDataSrc( settings, json );
2673 for ( var i=0, ien=data.length ; i<ien ; i++ ) {
2674 _fnAddData( settings, data[i] );
2675 }
2676 settings.aiDisplay = settings.aiDisplayMaster.slice();
2677
2678 settings.bAjaxDataGet = false;
2679 _fnDraw( settings );
2680
2681 if ( ! settings._bInitComplete ) {
2682 _fnInitComplete( settings, json );
2683 }
2684
2685 settings.bAjaxDataGet = true;
2686 _fnProcessingDisplay( settings, false );
2687 }
2688
2689
2690 /**
2691 * Get the data from the JSON data source to use for drawing a table. Using
2692 * `_fnGetObjectDataFn` allows the data to be sourced from a property of the
2693 * source object, or from a processing function.
2694 * @param {object} oSettings dataTables settings object
2695 * @param {object} json Data source object / array from the server
2696 * @return {array} Array of data to use
2697 */
2698 function _fnAjaxDataSrc ( oSettings, json )
2699 {
2700 var dataSrc = $.isPlainObject( oSettings.ajax ) && oSettings.ajax.dataSrc !== undefined ?
2701 oSettings.ajax.dataSrc :
2702 oSettings.sAjaxDataProp; // Compatibility with 1.9-.
2703
2704 // Compatibility with 1.9-. In order to read from aaData, check if the
2705 // default has been changed, if not, check for aaData
2706 if ( dataSrc === 'data' ) {
2707 return json.aaData || json[dataSrc];
2708 }
2709
2710 return dataSrc !== "" ?
2711 _fnGetObjectDataFn( dataSrc )( json ) :
2712 json;
2713 }
2714
2715
2716 /**
2717 * Generate the node required for filtering text
2718 * @returns {node} Filter control element
2719 * @param {object} oSettings dataTables settings object
2720 * @memberof DataTable#oApi
2721 */
2722 function _fnFeatureHtmlFilter ( settings )
2723 {
2724 var classes = settings.oClasses;
2725 var tableId = settings.sTableId;
2726 var language = settings.oLanguage;
2727 var previousSearch = settings.oPreviousSearch;
2728 var features = settings.aanFeatures;
2729 var input = '<input type="search" class="'+classes.sFilterInput+'"/>';
2730
2731 var str = language.sSearch;
2732 str = str.match(/_INPUT_/) ?
2733 str.replace('_INPUT_', input) :
2734 str+input;
2735
2736 var filter = $('<div/>', {
2737 'id': ! features.f ? tableId+'_filter' : null,
2738 'class': classes.sFilter
2739 } )
2740 .append( $('<label/>' ).append( str ) );
2741
2742 var searchFn = function() {
2743 /* Update all other filter input elements for the new display */
2744 var n = features.f;
2745 var val = !this.value ? "" : this.value; // mental IE8 fix :-(
2746
2747 /* Now do the filter */
2748 if ( val != previousSearch.sSearch ) {
2749 _fnFilterComplete( settings, {
2750 "sSearch": val,
2751 "bRegex": previousSearch.bRegex,
2752 "bSmart": previousSearch.bSmart ,
2753 "bCaseInsensitive": previousSearch.bCaseInsensitive
2754 } );
2755
2756 // Need to redraw, without resorting
2757 settings._iDisplayStart = 0;
2758 _fnDraw( settings );
2759 }
2760 };
2761
2762 var searchDelay = settings.searchDelay !== null ?
2763 settings.searchDelay :
2764 _fnDataSource( settings ) === 'ssp' ?
2765 400 :
2766 0;
2767
2768 var jqFilter = $('input', filter)
2769 .val( previousSearch.sSearch )
2770 .attr( 'placeholder', language.sSearchPlaceholder )
2771 .bind(
2772 'keyup.DT search.DT input.DT paste.DT cut.DT',
2773 searchDelay ?
2774 _fnThrottle( searchFn, searchDelay ) :
2775 searchFn
2776 )
2777 .bind( 'keypress.DT', function(e) {
2778 /* Prevent form submission */
2779 if ( e.keyCode == 13 ) {
2780 return false;
2781 }
2782 } )
2783 .attr('aria-controls', tableId);
2784
2785 // Update the input elements whenever the table is filtered
2786 $(settings.nTable).on( 'search.dt.DT', function ( ev, s ) {
2787 if ( settings === s ) {
2788 // IE9 throws an 'unknown error' if document.activeElement is used
2789 // inside an iframe or frame...
2790 try {
2791 if ( jqFilter[0] !== document.activeElement ) {
2792 jqFilter.val( previousSearch.sSearch );
2793 }
2794 }
2795 catch ( e ) {}
2796 }
2797 } );
2798
2799 return filter[0];
2800 }
2801
2802
2803 /**
2804 * Filter the table using both the global filter and column based filtering
2805 * @param {object} oSettings dataTables settings object
2806 * @param {object} oSearch search information
2807 * @param {int} [iForce] force a research of the master array (1) or not (undefined or 0)
2808 * @memberof DataTable#oApi
2809 */
2810 function _fnFilterComplete ( oSettings, oInput, iForce )
2811 {
2812 var oPrevSearch = oSettings.oPreviousSearch;
2813 var aoPrevSearch = oSettings.aoPreSearchCols;
2814 var fnSaveFilter = function ( oFilter ) {
2815 /* Save the filtering values */
2816 oPrevSearch.sSearch = oFilter.sSearch;
2817 oPrevSearch.bRegex = oFilter.bRegex;
2818 oPrevSearch.bSmart = oFilter.bSmart;
2819 oPrevSearch.bCaseInsensitive = oFilter.bCaseInsensitive;
2820 };
2821 var fnRegex = function ( o ) {
2822 // Backwards compatibility with the bEscapeRegex option
2823 return o.bEscapeRegex !== undefined ? !o.bEscapeRegex : o.bRegex;
2824 };
2825
2826 // Resolve any column types that are unknown due to addition or invalidation
2827 // @todo As per sort - can this be moved into an event handler?
2828 _fnColumnTypes( oSettings );
2829
2830 /* In server-side processing all filtering is done by the server, so no point hanging around here */
2831 if ( _fnDataSource( oSettings ) != 'ssp' )
2832 {
2833 /* Global filter */
2834 _fnFilter( oSettings, oInput.sSearch, iForce, fnRegex(oInput), oInput.bSmart, oInput.bCaseInsensitive );
2835 fnSaveFilter( oInput );
2836
2837 /* Now do the individual column filter */
2838 for ( var i=0 ; i<aoPrevSearch.length ; i++ )
2839 {
2840 _fnFilterColumn( oSettings, aoPrevSearch[i].sSearch, i, fnRegex(aoPrevSearch[i]),
2841 aoPrevSearch[i].bSmart, aoPrevSearch[i].bCaseInsensitive );
2842 }
2843
2844 /* Custom filtering */
2845 _fnFilterCustom( oSettings );
2846 }
2847 else
2848 {
2849 fnSaveFilter( oInput );
2850 }
2851
2852 /* Tell the draw function we have been filtering */
2853 oSettings.bFiltered = true;
2854 _fnCallbackFire( oSettings, null, 'search', [oSettings] );
2855 }
2856
2857
2858 /**
2859 * Apply custom filtering functions
2860 * @param {object} oSettings dataTables settings object
2861 * @memberof DataTable#oApi
2862 */
2863 function _fnFilterCustom( settings )
2864 {
2865 var filters = DataTable.ext.search;
2866 var displayRows = settings.aiDisplay;
2867 var row, rowIdx;
2868
2869 for ( var i=0, ien=filters.length ; i<ien ; i++ ) {
2870 var rows = [];
2871
2872 // Loop over each row and see if it should be included
2873 for ( var j=0, jen=displayRows.length ; j<jen ; j++ ) {
2874 rowIdx = displayRows[ j ];
2875 row = settings.aoData[ rowIdx ];
2876
2877 if ( filters[i]( settings, row._aFilterData, rowIdx, row._aData, j ) ) {
2878 rows.push( rowIdx );
2879 }
2880 }
2881
2882 // So the array reference doesn't break set the results into the
2883 // existing array
2884 displayRows.length = 0;
2885 displayRows.push.apply( displayRows, rows );
2886 }
2887 }
2888
2889
2890 /**
2891 * Filter the table on a per-column basis
2892 * @param {object} oSettings dataTables settings object
2893 * @param {string} sInput string to filter on
2894 * @param {int} iColumn column to filter
2895 * @param {bool} bRegex treat search string as a regular expression or not
2896 * @param {bool} bSmart use smart filtering or not
2897 * @param {bool} bCaseInsensitive Do case insenstive matching or not
2898 * @memberof DataTable#oApi
2899 */
2900 function _fnFilterColumn ( settings, searchStr, colIdx, regex, smart, caseInsensitive )
2901 {
2902 if ( searchStr === '' ) {
2903 return;
2904 }
2905
2906 var data;
2907 var display = settings.aiDisplay;
2908 var rpSearch = _fnFilterCreateSearch( searchStr, regex, smart, caseInsensitive );
2909
2910 for ( var i=display.length-1 ; i>=0 ; i-- ) {
2911 data = settings.aoData[ display[i] ]._aFilterData[ colIdx ];
2912
2913 if ( ! rpSearch.test( data ) ) {
2914 display.splice( i, 1 );
2915 }
2916 }
2917 }
2918
2919
2920 /**
2921 * Filter the data table based on user input and draw the table
2922 * @param {object} settings dataTables settings object
2923 * @param {string} input string to filter on
2924 * @param {int} force optional - force a research of the master array (1) or not (undefined or 0)
2925 * @param {bool} regex treat as a regular expression or not
2926 * @param {bool} smart perform smart filtering or not
2927 * @param {bool} caseInsensitive Do case insenstive matching or not
2928 * @memberof DataTable#oApi
2929 */
2930 function _fnFilter( settings, input, force, regex, smart, caseInsensitive )
2931 {
2932 var rpSearch = _fnFilterCreateSearch( input, regex, smart, caseInsensitive );
2933 var prevSearch = settings.oPreviousSearch.sSearch;
2934 var displayMaster = settings.aiDisplayMaster;
2935 var display, invalidated, i;
2936
2937 // Need to take account of custom filtering functions - always filter
2938 if ( DataTable.ext.search.length !== 0 ) {
2939 force = true;
2940 }
2941
2942 // Check if any of the rows were invalidated
2943 invalidated = _fnFilterData( settings );
2944
2945 // If the input is blank - we just want the full data set
2946 if ( input.length <= 0 ) {
2947 settings.aiDisplay = displayMaster.slice();
2948 }
2949 else {
2950 // New search - start from the master array
2951 if ( invalidated ||
2952 force ||
2953 prevSearch.length > input.length ||
2954 input.indexOf(prevSearch) !== 0 ||
2955 settings.bSorted // On resort, the display master needs to be
2956 // re-filtered since indexes will have changed
2957 ) {
2958 settings.aiDisplay = displayMaster.slice();
2959 }
2960
2961 // Search the display array
2962 display = settings.aiDisplay;
2963
2964 for ( i=display.length-1 ; i>=0 ; i-- ) {
2965 if ( ! rpSearch.test( settings.aoData[ display[i] ]._sFilterRow ) ) {
2966 display.splice( i, 1 );
2967 }
2968 }
2969 }
2970 }
2971
2972
2973 /**
2974 * Build a regular expression object suitable for searching a table
2975 * @param {string} sSearch string to search for
2976 * @param {bool} bRegex treat as a regular expression or not
2977 * @param {bool} bSmart perform smart filtering or not
2978 * @param {bool} bCaseInsensitive Do case insensitive matching or not
2979 * @returns {RegExp} constructed object
2980 * @memberof DataTable#oApi
2981 */
2982 function _fnFilterCreateSearch( search, regex, smart, caseInsensitive )
2983 {
2984 search = regex ?
2985 search :
2986 _fnEscapeRegex( search );
2987
2988 if ( smart ) {
2989 /* For smart filtering we want to allow the search to work regardless of
2990 * word order. We also want double quoted text to be preserved, so word
2991 * order is important - a la google. So this is what we want to
2992 * generate:
2993 *
2994 * ^(?=.*?\bone\b)(?=.*?\btwo three\b)(?=.*?\bfour\b).*$
2995 */
2996 var a = $.map( search.match( /"[^"]+"|[^ ]+/g ) || '', function ( word ) {
2997 if ( word.charAt(0) === '"' ) {
2998 var m = word.match( /^"(.*)"$/ );
2999 word = m ? m[1] : word;
3000 }
3001
3002 return word.replace('"', '');
3003 } );
3004
3005 search = '^(?=.*?'+a.join( ')(?=.*?' )+').*$';
3006 }
3007
3008 return new RegExp( search, caseInsensitive ? 'i' : '' );
3009 }
3010
3011
3012 /**
3013 * Escape a string such that it can be used in a regular expression
3014 * @param {string} sVal string to escape
3015 * @returns {string} escaped string
3016 * @memberof DataTable#oApi
3017 */
3018 function _fnEscapeRegex ( sVal )
3019 {
3020 return sVal.replace( _re_escape_regex, '\\$1' );
3021 }
3022
3023
3024
3025 var __filter_div = $('<div>')[0];
3026 var __filter_div_textContent = __filter_div.textContent !== undefined;
3027
3028 // Update the filtering data for each row if needed (by invalidation or first run)
3029 function _fnFilterData ( settings )
3030 {
3031 var columns = settings.aoColumns;
3032 var column;
3033 var i, j, ien, jen, filterData, cellData, row;
3034 var fomatters = DataTable.ext.type.search;
3035 var wasInvalidated = false;
3036
3037 for ( i=0, ien=settings.aoData.length ; i<ien ; i++ ) {
3038 row = settings.aoData[i];
3039
3040 if ( ! row._aFilterData ) {
3041 filterData = [];
3042
3043 for ( j=0, jen=columns.length ; j<jen ; j++ ) {
3044 column = columns[j];
3045
3046 if ( column.bSearchable ) {
3047 cellData = _fnGetCellData( settings, i, j, 'filter' );
3048
3049 if ( fomatters[ column.sType ] ) {
3050 cellData = fomatters[ column.sType ]( cellData );
3051 }
3052
3053 // Search in DataTables 1.10 is string based. In 1.11 this
3054 // should be altered to also allow strict type checking.
3055 if ( cellData === null ) {
3056 cellData = '';
3057 }
3058
3059 if ( typeof cellData !== 'string' && cellData.toString ) {
3060 cellData = cellData.toString();
3061 }
3062 }
3063 else {
3064 cellData = '';
3065 }
3066
3067 // If it looks like there is an HTML entity in the string,
3068 // attempt to decode it so sorting works as expected. Note that
3069 // we could use a single line of jQuery to do this, but the DOM
3070 // method used here is much faster http://jsperf.com/html-decode
3071 if ( cellData.indexOf && cellData.indexOf('&') !== -1 ) {
3072 __filter_div.innerHTML = cellData;
3073 cellData = __filter_div_textContent ?
3074 __filter_div.textContent :
3075 __filter_div.innerText;
3076 }
3077
3078 if ( cellData.replace ) {
3079 cellData = cellData.replace(/[\r\n]/g, '');
3080 }
3081
3082 filterData.push( cellData );
3083 }
3084
3085 row._aFilterData = filterData;
3086 row._sFilterRow = filterData.join(' ');
3087 wasInvalidated = true;
3088 }
3089 }
3090
3091 return wasInvalidated;
3092 }
3093
3094
3095 /**
3096 * Convert from the internal Hungarian notation to camelCase for external
3097 * interaction
3098 * @param {object} obj Object to convert
3099 * @returns {object} Inverted object
3100 * @memberof DataTable#oApi
3101 */
3102 function _fnSearchToCamel ( obj )
3103 {
3104 return {
3105 search: obj.sSearch,
3106 smart: obj.bSmart,
3107 regex: obj.bRegex,
3108 caseInsensitive: obj.bCaseInsensitive
3109 };
3110 }
3111
3112
3113
3114 /**
3115 * Convert from camelCase notation to the internal Hungarian. We could use the
3116 * Hungarian convert function here, but this is cleaner
3117 * @param {object} obj Object to convert
3118 * @returns {object} Inverted object
3119 * @memberof DataTable#oApi
3120 */
3121 function _fnSearchToHung ( obj )
3122 {
3123 return {
3124 sSearch: obj.search,
3125 bSmart: obj.smart,
3126 bRegex: obj.regex,
3127 bCaseInsensitive: obj.caseInsensitive
3128 };
3129 }
3130
3131 /**
3132 * Generate the node required for the info display
3133 * @param {object} oSettings dataTables settings object
3134 * @returns {node} Information element
3135 * @memberof DataTable#oApi
3136 */
3137 function _fnFeatureHtmlInfo ( settings )
3138 {
3139 var
3140 tid = settings.sTableId,
3141 nodes = settings.aanFeatures.i,
3142 n = $('<div/>', {
3143 'class': settings.oClasses.sInfo,
3144 'id': ! nodes ? tid+'_info' : null
3145 } );
3146
3147 if ( ! nodes ) {
3148 // Update display on each draw
3149 settings.aoDrawCallback.push( {
3150 "fn": _fnUpdateInfo,
3151 "sName": "information"
3152 } );
3153
3154 n
3155 .attr( 'role', 'status' )
3156 .attr( 'aria-live', 'polite' );
3157
3158 // Table is described by our info div
3159 $(settings.nTable).attr( 'aria-describedby', tid+'_info' );
3160 }
3161
3162 return n[0];
3163 }
3164
3165
3166 /**
3167 * Update the information elements in the display
3168 * @param {object} settings dataTables settings object
3169 * @memberof DataTable#oApi
3170 */
3171 function _fnUpdateInfo ( settings )
3172 {
3173 /* Show information about the table */
3174 var nodes = settings.aanFeatures.i;
3175 if ( nodes.length === 0 ) {
3176 return;
3177 }
3178
3179 var
3180 lang = settings.oLanguage,
3181 start = settings._iDisplayStart+1,
3182 end = settings.fnDisplayEnd(),
3183 max = settings.fnRecordsTotal(),
3184 total = settings.fnRecordsDisplay(),
3185 out = total ?
3186 lang.sInfo :
3187 lang.sInfoEmpty;
3188
3189 if ( total !== max ) {
3190 /* Record set after filtering */
3191 out += ' ' + lang.sInfoFiltered;
3192 }
3193
3194 // Convert the macros
3195 out += lang.sInfoPostFix;
3196 out = _fnInfoMacros( settings, out );
3197
3198 var callback = lang.fnInfoCallback;
3199 if ( callback !== null ) {
3200 out = callback.call( settings.oInstance,
3201 settings, start, end, max, total, out
3202 );
3203 }
3204
3205 $(nodes).html( out );
3206 }
3207
3208
3209 function _fnInfoMacros ( settings, str )
3210 {
3211 // When infinite scrolling, we are always starting at 1. _iDisplayStart is used only
3212 // internally
3213 var
3214 formatter = settings.fnFormatNumber,
3215 start = settings._iDisplayStart+1,
3216 len = settings._iDisplayLength,
3217 vis = settings.fnRecordsDisplay(),
3218 all = len === -1;
3219
3220 return str.
3221 replace(/_START_/g, formatter.call( settings, start ) ).
3222 replace(/_END_/g, formatter.call( settings, settings.fnDisplayEnd() ) ).
3223 replace(/_MAX_/g, formatter.call( settings, settings.fnRecordsTotal() ) ).
3224 replace(/_TOTAL_/g, formatter.call( settings, vis ) ).
3225 replace(/_PAGE_/g, formatter.call( settings, all ? 1 : Math.ceil( start / len ) ) ).
3226 replace(/_PAGES_/g, formatter.call( settings, all ? 1 : Math.ceil( vis / len ) ) );
3227 }
3228
3229
3230
3231 /**
3232 * Draw the table for the first time, adding all required features
3233 * @param {object} settings dataTables settings object
3234 * @memberof DataTable#oApi
3235 */
3236 function _fnInitialise ( settings )
3237 {
3238 var i, iLen, iAjaxStart=settings.iInitDisplayStart;
3239 var columns = settings.aoColumns, column;
3240 var features = settings.oFeatures;
3241
3242 /* Ensure that the table data is fully initialised */
3243 if ( ! settings.bInitialised ) {
3244 setTimeout( function(){ _fnInitialise( settings ); }, 200 );
3245 return;
3246 }
3247
3248 /* Show the display HTML options */
3249 _fnAddOptionsHtml( settings );
3250
3251 /* Build and draw the header / footer for the table */
3252 _fnBuildHead( settings );
3253 _fnDrawHead( settings, settings.aoHeader );
3254 _fnDrawHead( settings, settings.aoFooter );
3255
3256 /* Okay to show that something is going on now */
3257 _fnProcessingDisplay( settings, true );
3258
3259 /* Calculate sizes for columns */
3260 if ( features.bAutoWidth ) {
3261 _fnCalculateColumnWidths( settings );
3262 }
3263
3264 for ( i=0, iLen=columns.length ; i<iLen ; i++ ) {
3265 column = columns[i];
3266
3267 if ( column.sWidth ) {
3268 column.nTh.style.width = _fnStringToCss( column.sWidth );
3269 }
3270 }
3271
3272 // If there is default sorting required - let's do it. The sort function
3273 // will do the drawing for us. Otherwise we draw the table regardless of the
3274 // Ajax source - this allows the table to look initialised for Ajax sourcing
3275 // data (show 'loading' message possibly)
3276 _fnReDraw( settings );
3277
3278 // Server-side processing init complete is done by _fnAjaxUpdateDraw
3279 var dataSrc = _fnDataSource( settings );
3280 if ( dataSrc != 'ssp' ) {
3281 // if there is an ajax source load the data
3282 if ( dataSrc == 'ajax' ) {
3283 _fnBuildAjax( settings, [], function(json) {
3284 var aData = _fnAjaxDataSrc( settings, json );
3285
3286 // Got the data - add it to the table
3287 for ( i=0 ; i<aData.length ; i++ ) {
3288 _fnAddData( settings, aData[i] );
3289 }
3290
3291 // Reset the init display for cookie saving. We've already done
3292 // a filter, and therefore cleared it before. So we need to make
3293 // it appear 'fresh'
3294 settings.iInitDisplayStart = iAjaxStart;
3295
3296 _fnReDraw( settings );
3297
3298 _fnProcessingDisplay( settings, false );
3299 _fnInitComplete( settings, json );
3300 }, settings );
3301 }
3302 else {
3303 _fnProcessingDisplay( settings, false );
3304 _fnInitComplete( settings );
3305 }
3306 }
3307 }
3308
3309
3310 /**
3311 * Draw the table for the first time, adding all required features
3312 * @param {object} oSettings dataTables settings object
3313 * @param {object} [json] JSON from the server that completed the table, if using Ajax source
3314 * with client-side processing (optional)
3315 * @memberof DataTable#oApi
3316 */
3317 function _fnInitComplete ( settings, json )
3318 {
3319 settings._bInitComplete = true;
3320
3321 // On an Ajax load we now have data and therefore want to apply the column
3322 // sizing
3323 if ( json ) {
3324 _fnAdjustColumnSizing( settings );
3325 }
3326
3327 _fnCallbackFire( settings, 'aoInitComplete', 'init', [settings, json] );
3328 }
3329
3330
3331 function _fnLengthChange ( settings, val )
3332 {
3333 var len = parseInt( val, 10 );
3334 settings._iDisplayLength = len;
3335
3336 _fnLengthOverflow( settings );
3337
3338 // Fire length change event
3339 _fnCallbackFire( settings, null, 'length', [settings, len] );
3340 }
3341
3342
3343 /**
3344 * Generate the node required for user display length changing
3345 * @param {object} settings dataTables settings object
3346 * @returns {node} Display length feature node
3347 * @memberof DataTable#oApi
3348 */
3349 function _fnFeatureHtmlLength ( settings )
3350 {
3351 var
3352 classes = settings.oClasses,
3353 tableId = settings.sTableId,
3354 menu = settings.aLengthMenu,
3355 d2 = $.isArray( menu[0] ),
3356 lengths = d2 ? menu[0] : menu,
3357 language = d2 ? menu[1] : menu;
3358
3359 var select = $('<select/>', {
3360 'name': tableId+'_length',
3361 'aria-controls': tableId,
3362 'class': classes.sLengthSelect
3363 } );
3364
3365 for ( var i=0, ien=lengths.length ; i<ien ; i++ ) {
3366 select[0][ i ] = new Option( language[i], lengths[i] );
3367 }
3368
3369 var div = $('<div><label/></div>').addClass( classes.sLength );
3370 if ( ! settings.aanFeatures.l ) {
3371 div[0].id = tableId+'_length';
3372 }
3373
3374 div.children().append(
3375 settings.oLanguage.sLengthMenu.replace( '_MENU_', select[0].outerHTML )
3376 );
3377
3378 // Can't use `select` variable as user might provide their own and the
3379 // reference is broken by the use of outerHTML
3380 $('select', div)
3381 .val( settings._iDisplayLength )
3382 .bind( 'change.DT', function(e) {
3383 _fnLengthChange( settings, $(this).val() );
3384 _fnDraw( settings );
3385 } );
3386
3387 // Update node value whenever anything changes the table's length
3388 $(settings.nTable).bind( 'length.dt.DT', function (e, s, len) {
3389 if ( settings === s ) {
3390 $('select', div).val( len );
3391 }
3392 } );
3393
3394 return div[0];
3395 }
3396
3397
3398
3399 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
3400 * Note that most of the paging logic is done in
3401 * DataTable.ext.pager
3402 */
3403
3404 /**
3405 * Generate the node required for default pagination
3406 * @param {object} oSettings dataTables settings object
3407 * @returns {node} Pagination feature node
3408 * @memberof DataTable#oApi
3409 */
3410 function _fnFeatureHtmlPaginate ( settings )
3411 {
3412 var
3413 type = settings.sPaginationType,
3414 plugin = DataTable.ext.pager[ type ],
3415 modern = typeof plugin === 'function',
3416 redraw = function( settings ) {
3417 _fnDraw( settings );
3418 },
3419 node = $('<div/>').addClass( settings.oClasses.sPaging + type )[0],
3420 features = settings.aanFeatures;
3421
3422 if ( ! modern ) {
3423 plugin.fnInit( settings, node, redraw );
3424 }
3425
3426 /* Add a draw callback for the pagination on first instance, to update the paging display */
3427 if ( ! features.p )
3428 {
3429 node.id = settings.sTableId+'_paginate';
3430
3431 settings.aoDrawCallback.push( {
3432 "fn": function( settings ) {
3433 if ( modern ) {
3434 var
3435 start = settings._iDisplayStart,
3436 len = settings._iDisplayLength,
3437 visRecords = settings.fnRecordsDisplay(),
3438 all = len === -1,
3439 page = all ? 0 : Math.ceil( start / len ),
3440 pages = all ? 1 : Math.ceil( visRecords / len ),
3441 buttons = plugin(page, pages),
3442 i, ien;
3443
3444 for ( i=0, ien=features.p.length ; i<ien ; i++ ) {
3445 _fnRenderer( settings, 'pageButton' )(
3446 settings, features.p[i], i, buttons, page, pages
3447 );
3448 }
3449 }
3450 else {
3451 plugin.fnUpdate( settings, redraw );
3452 }
3453 },
3454 "sName": "pagination"
3455 } );
3456 }
3457
3458 return node;
3459 }
3460
3461
3462 /**
3463 * Alter the display settings to change the page
3464 * @param {object} settings DataTables settings object
3465 * @param {string|int} action Paging action to take: "first", "previous",
3466 * "next" or "last" or page number to jump to (integer)
3467 * @param [bool] redraw Automatically draw the update or not
3468 * @returns {bool} true page has changed, false - no change
3469 * @memberof DataTable#oApi
3470 */
3471 function _fnPageChange ( settings, action, redraw )
3472 {
3473 var
3474 start = settings._iDisplayStart,
3475 len = settings._iDisplayLength,
3476 records = settings.fnRecordsDisplay();
3477
3478 if ( records === 0 || len === -1 )
3479 {
3480 start = 0;
3481 }
3482 else if ( typeof action === "number" )
3483 {
3484 start = action * len;
3485
3486 if ( start > records )
3487 {
3488 start = 0;
3489 }
3490 }
3491 else if ( action == "first" )
3492 {
3493 start = 0;
3494 }
3495 else if ( action == "previous" )
3496 {
3497 start = len >= 0 ?
3498 start - len :
3499 0;
3500
3501 if ( start < 0 )
3502 {
3503 start = 0;
3504 }
3505 }
3506 else if ( action == "next" )
3507 {
3508 if ( start + len < records )
3509 {
3510 start += len;
3511 }
3512 }
3513 else if ( action == "last" )
3514 {
3515 start = Math.floor( (records-1) / len) * len;
3516 }
3517 else
3518 {
3519 _fnLog( settings, 0, "Unknown paging action: "+action, 5 );
3520 }
3521
3522 var changed = settings._iDisplayStart !== start;
3523 settings._iDisplayStart = start;
3524
3525 if ( changed ) {
3526 _fnCallbackFire( settings, null, 'page', [settings] );
3527
3528 if ( redraw ) {
3529 _fnDraw( settings );
3530 }
3531 }
3532
3533 return changed;
3534 }
3535
3536
3537
3538 /**
3539 * Generate the node required for the processing node
3540 * @param {object} settings dataTables settings object
3541 * @returns {node} Processing element
3542 * @memberof DataTable#oApi
3543 */
3544 function _fnFeatureHtmlProcessing ( settings )
3545 {
3546 return $('<div/>', {
3547 'id': ! settings.aanFeatures.r ? settings.sTableId+'_processing' : null,
3548 'class': settings.oClasses.sProcessing
3549 } )
3550 .html( settings.oLanguage.sProcessing )
3551 .insertBefore( settings.nTable )[0];
3552 }
3553
3554
3555 /**
3556 * Display or hide the processing indicator
3557 * @param {object} settings dataTables settings object
3558 * @param {bool} show Show the processing indicator (true) or not (false)
3559 * @memberof DataTable#oApi
3560 */
3561 function _fnProcessingDisplay ( settings, show )
3562 {
3563 if ( settings.oFeatures.bProcessing ) {
3564 $(settings.aanFeatures.r).css( 'display', show ? 'block' : 'none' );
3565 }
3566
3567 _fnCallbackFire( settings, null, 'processing', [settings, show] );
3568 }
3569
3570 /**
3571 * Add any control elements for the table - specifically scrolling
3572 * @param {object} settings dataTables settings object
3573 * @returns {node} Node to add to the DOM
3574 * @memberof DataTable#oApi
3575 */
3576 function _fnFeatureHtmlTable ( settings )
3577 {
3578 var table = $(settings.nTable);
3579
3580 // Add the ARIA grid role to the table
3581 table.attr( 'role', 'grid' );
3582
3583 // Scrolling from here on in
3584 var scroll = settings.oScroll;
3585
3586 if ( scroll.sX === '' && scroll.sY === '' ) {
3587 return settings.nTable;
3588 }
3589
3590 var scrollX = scroll.sX;
3591 var scrollY = scroll.sY;
3592 var classes = settings.oClasses;
3593 var caption = table.children('caption');
3594 var captionSide = caption.length ? caption[0]._captionSide : null;
3595 var headerClone = $( table[0].cloneNode(false) );
3596 var footerClone = $( table[0].cloneNode(false) );
3597 var footer = table.children('tfoot');
3598 var _div = '<div/>';
3599 var size = function ( s ) {
3600 return !s ? null : _fnStringToCss( s );
3601 };
3602
3603 // This is fairly messy, but with x scrolling enabled, if the table has a
3604 // width attribute, regardless of any width applied using the column width
3605 // options, the browser will shrink or grow the table as needed to fit into
3606 // that 100%. That would make the width options useless. So we remove it.
3607 // This is okay, under the assumption that width:100% is applied to the
3608 // table in CSS (it is in the default stylesheet) which will set the table
3609 // width as appropriate (the attribute and css behave differently...)
3610 if ( scroll.sX && table.attr('width') === '100%' ) {
3611 table.removeAttr('width');
3612 }
3613
3614 if ( ! footer.length ) {
3615 footer = null;
3616 }
3617
3618 /*
3619 * The HTML structure that we want to generate in this function is:
3620 * div - scroller
3621 * div - scroll head
3622 * div - scroll head inner
3623 * table - scroll head table
3624 * thead - thead
3625 * div - scroll body
3626 * table - table (master table)
3627 * thead - thead clone for sizing
3628 * tbody - tbody
3629 * div - scroll foot
3630 * div - scroll foot inner
3631 * table - scroll foot table
3632 * tfoot - tfoot
3633 */
3634 var scroller = $( _div, { 'class': classes.sScrollWrapper } )
3635 .append(
3636 $(_div, { 'class': classes.sScrollHead } )
3637 .css( {
3638 overflow: 'hidden',
3639 position: 'relative',
3640 border: 0,
3641 width: scrollX ? size(scrollX) : '100%'
3642 } )
3643 .append(
3644 $(_div, { 'class': classes.sScrollHeadInner } )
3645 .css( {
3646 'box-sizing': 'content-box',
3647 width: scroll.sXInner || '100%'
3648 } )
3649 .append(
3650 headerClone
3651 .removeAttr('id')
3652 .css( 'margin-left', 0 )
3653 .append( captionSide === 'top' ? caption : null )
3654 .append(
3655 table.children('thead')
3656 )
3657 )
3658 )
3659 )
3660 .append(
3661 $(_div, { 'class': classes.sScrollBody } )
3662 .css( {
3663 overflow: 'auto',
3664 height: size( scrollY ),
3665 width: size( scrollX )
3666 } )
3667 .append( table )
3668 );
3669
3670 if ( footer ) {
3671 scroller.append(
3672 $(_div, { 'class': classes.sScrollFoot } )
3673 .css( {
3674 overflow: 'hidden',
3675 border: 0,
3676 width: scrollX ? size(scrollX) : '100%'
3677 } )
3678 .append(
3679 $(_div, { 'class': classes.sScrollFootInner } )
3680 .append(
3681 footerClone
3682 .removeAttr('id')
3683 .css( 'margin-left', 0 )
3684 .append( captionSide === 'bottom' ? caption : null )
3685 .append(
3686 table.children('tfoot')
3687 )
3688 )
3689 )
3690 );
3691 }
3692
3693 var children = scroller.children();
3694 var scrollHead = children[0];
3695 var scrollBody = children[1];
3696 var scrollFoot = footer ? children[2] : null;
3697
3698 // When the body is scrolled, then we also want to scroll the headers
3699 if ( scrollX ) {
3700 $(scrollBody).scroll( function (e) {
3701 var scrollLeft = this.scrollLeft;
3702
3703 scrollHead.scrollLeft = scrollLeft;
3704
3705 if ( footer ) {
3706 scrollFoot.scrollLeft = scrollLeft;
3707 }
3708 } );
3709 }
3710
3711 settings.nScrollHead = scrollHead;
3712 settings.nScrollBody = scrollBody;
3713 settings.nScrollFoot = scrollFoot;
3714
3715 // On redraw - align columns
3716 settings.aoDrawCallback.push( {
3717 "fn": _fnScrollDraw,
3718 "sName": "scrolling"
3719 } );
3720
3721 return scroller[0];
3722 }
3723
3724
3725
3726 /**
3727 * Update the header, footer and body tables for resizing - i.e. column
3728 * alignment.
3729 *
3730 * Welcome to the most horrible function DataTables. The process that this
3731 * function follows is basically:
3732 * 1. Re-create the table inside the scrolling div
3733 * 2. Take live measurements from the DOM
3734 * 3. Apply the measurements to align the columns
3735 * 4. Clean up
3736 *
3737 * @param {object} settings dataTables settings object
3738 * @memberof DataTable#oApi
3739 */
3740 function _fnScrollDraw ( settings )
3741 {
3742 // Given that this is such a monster function, a lot of variables are use
3743 // to try and keep the minimised size as small as possible
3744 var
3745 scroll = settings.oScroll,
3746 scrollX = scroll.sX,
3747 scrollXInner = scroll.sXInner,
3748 scrollY = scroll.sY,
3749 barWidth = scroll.iBarWidth,
3750 divHeader = $(settings.nScrollHead),
3751 divHeaderStyle = divHeader[0].style,
3752 divHeaderInner = divHeader.children('div'),
3753 divHeaderInnerStyle = divHeaderInner[0].style,
3754 divHeaderTable = divHeaderInner.children('table'),
3755 divBodyEl = settings.nScrollBody,
3756 divBody = $(divBodyEl),
3757 divBodyStyle = divBodyEl.style,
3758 divFooter = $(settings.nScrollFoot),
3759 divFooterInner = divFooter.children('div'),
3760 divFooterTable = divFooterInner.children('table'),
3761 header = $(settings.nTHead),
3762 table = $(settings.nTable),
3763 tableEl = table[0],
3764 tableStyle = tableEl.style,
3765 footer = settings.nTFoot ? $(settings.nTFoot) : null,
3766 browser = settings.oBrowser,
3767 ie67 = browser.bScrollOversize,
3768 headerTrgEls, footerTrgEls,
3769 headerSrcEls, footerSrcEls,
3770 headerCopy, footerCopy,
3771 headerWidths=[], footerWidths=[],
3772 headerContent=[],
3773 idx, correction, sanityWidth,
3774 zeroOut = function(nSizer) {
3775 var style = nSizer.style;
3776 style.paddingTop = "0";
3777 style.paddingBottom = "0";
3778 style.borderTopWidth = "0";
3779 style.borderBottomWidth = "0";
3780 style.height = 0;
3781 };
3782
3783 /*
3784 * 1. Re-create the table inside the scrolling div
3785 */
3786
3787 // Remove the old minimised thead and tfoot elements in the inner table
3788 table.children('thead, tfoot').remove();
3789
3790 // Clone the current header and footer elements and then place it into the inner table
3791 headerCopy = header.clone().prependTo( table );
3792 headerTrgEls = header.find('tr'); // original header is in its own table
3793 headerSrcEls = headerCopy.find('tr');
3794 headerCopy.find('th, td').removeAttr('tabindex');
3795
3796 if ( footer ) {
3797 footerCopy = footer.clone().prependTo( table );
3798 footerTrgEls = footer.find('tr'); // the original tfoot is in its own table and must be sized
3799 footerSrcEls = footerCopy.find('tr');
3800 }
3801
3802
3803 /*
3804 * 2. Take live measurements from the DOM - do not alter the DOM itself!
3805 */
3806
3807 // Remove old sizing and apply the calculated column widths
3808 // Get the unique column headers in the newly created (cloned) header. We want to apply the
3809 // calculated sizes to this header
3810 if ( ! scrollX )
3811 {
3812 divBodyStyle.width = '100%';
3813 divHeader[0].style.width = '100%';
3814 }
3815
3816 $.each( _fnGetUniqueThs( settings, headerCopy ), function ( i, el ) {
3817 idx = _fnVisibleToColumnIndex( settings, i );
3818 el.style.width = settings.aoColumns[idx].sWidth;
3819 } );
3820
3821 if ( footer ) {
3822 _fnApplyToChildren( function(n) {
3823 n.style.width = "";
3824 }, footerSrcEls );
3825 }
3826
3827 // If scroll collapse is enabled, when we put the headers back into the body for sizing, we
3828 // will end up forcing the scrollbar to appear, making our measurements wrong for when we
3829 // then hide it (end of this function), so add the header height to the body scroller.
3830 if ( scroll.bCollapse && scrollY !== "" ) {
3831 divBodyStyle.height = (divBody[0].offsetHeight + header[0].offsetHeight)+"px";
3832 }
3833
3834 // Size the table as a whole
3835 sanityWidth = table.outerWidth();
3836 if ( scrollX === "" ) {
3837 // No x scrolling
3838 tableStyle.width = "100%";
3839
3840 // IE7 will make the width of the table when 100% include the scrollbar
3841 // - which is shouldn't. When there is a scrollbar we need to take this
3842 // into account.
3843 if ( ie67 && (table.find('tbody').height() > divBodyEl.offsetHeight ||
3844 divBody.css('overflow-y') == "scroll")
3845 ) {
3846 tableStyle.width = _fnStringToCss( table.outerWidth() - barWidth);
3847 }
3848 }
3849 else
3850 {
3851 // x scrolling
3852 if ( scrollXInner !== "" ) {
3853 // x scroll inner has been given - use it
3854 tableStyle.width = _fnStringToCss(scrollXInner);
3855 }
3856 else if ( sanityWidth == divBody.width() && divBody.height() < table.height() ) {
3857 // There is y-scrolling - try to take account of the y scroll bar
3858 tableStyle.width = _fnStringToCss( sanityWidth-barWidth );
3859 if ( table.outerWidth() > sanityWidth-barWidth ) {
3860 // Not possible to take account of it
3861 tableStyle.width = _fnStringToCss( sanityWidth );
3862 }
3863 }
3864 else {
3865 // When all else fails
3866 tableStyle.width = _fnStringToCss( sanityWidth );
3867 }
3868 }
3869
3870 // Recalculate the sanity width - now that we've applied the required width,
3871 // before it was a temporary variable. This is required because the column
3872 // width calculation is done before this table DOM is created.
3873 sanityWidth = table.outerWidth();
3874
3875 // Hidden header should have zero height, so remove padding and borders. Then
3876 // set the width based on the real headers
3877
3878 // Apply all styles in one pass
3879 _fnApplyToChildren( zeroOut, headerSrcEls );
3880
3881 // Read all widths in next pass
3882 _fnApplyToChildren( function(nSizer) {
3883 headerContent.push( nSizer.innerHTML );
3884 headerWidths.push( _fnStringToCss( $(nSizer).css('width') ) );
3885 }, headerSrcEls );
3886
3887 // Apply all widths in final pass
3888 _fnApplyToChildren( function(nToSize, i) {
3889 nToSize.style.width = headerWidths[i];
3890 }, headerTrgEls );
3891
3892 $(headerSrcEls).height(0);
3893
3894 /* Same again with the footer if we have one */
3895 if ( footer )
3896 {
3897 _fnApplyToChildren( zeroOut, footerSrcEls );
3898
3899 _fnApplyToChildren( function(nSizer) {
3900 footerWidths.push( _fnStringToCss( $(nSizer).css('width') ) );
3901 }, footerSrcEls );
3902
3903 _fnApplyToChildren( function(nToSize, i) {
3904 nToSize.style.width = footerWidths[i];
3905 }, footerTrgEls );
3906
3907 $(footerSrcEls).height(0);
3908 }
3909
3910
3911 /*
3912 * 3. Apply the measurements
3913 */
3914
3915 // "Hide" the header and footer that we used for the sizing. We need to keep
3916 // the content of the cell so that the width applied to the header and body
3917 // both match, but we want to hide it completely. We want to also fix their
3918 // width to what they currently are
3919 _fnApplyToChildren( function(nSizer, i) {
3920 nSizer.innerHTML = '<div class="dataTables_sizing" style="height:0;overflow:hidden;">'+headerContent[i]+'</div>';
3921 nSizer.style.width = headerWidths[i];
3922 }, headerSrcEls );
3923
3924 if ( footer )
3925 {
3926 _fnApplyToChildren( function(nSizer, i) {
3927 nSizer.innerHTML = "";
3928 nSizer.style.width = footerWidths[i];
3929 }, footerSrcEls );
3930 }
3931
3932 // Sanity check that the table is of a sensible width. If not then we are going to get
3933 // misalignment - try to prevent this by not allowing the table to shrink below its min width
3934 if ( table.outerWidth() < sanityWidth )
3935 {
3936 // The min width depends upon if we have a vertical scrollbar visible or not */
3937 correction = ((divBodyEl.scrollHeight > divBodyEl.offsetHeight ||
3938 divBody.css('overflow-y') == "scroll")) ?
3939 sanityWidth+barWidth :
3940 sanityWidth;
3941
3942 // IE6/7 are a law unto themselves...
3943 if ( ie67 && (divBodyEl.scrollHeight >
3944 divBodyEl.offsetHeight || divBody.css('overflow-y') == "scroll")
3945 ) {
3946 tableStyle.width = _fnStringToCss( correction-barWidth );
3947 }
3948
3949 // And give the user a warning that we've stopped the table getting too small
3950 if ( scrollX === "" || scrollXInner !== "" ) {
3951 _fnLog( settings, 1, 'Possible column misalignment', 6 );
3952 }
3953 }
3954 else
3955 {
3956 correction = '100%';
3957 }
3958
3959 // Apply to the container elements
3960 divBodyStyle.width = _fnStringToCss( correction );
3961 divHeaderStyle.width = _fnStringToCss( correction );
3962
3963 if ( footer ) {
3964 settings.nScrollFoot.style.width = _fnStringToCss( correction );
3965 }
3966
3967
3968 /*
3969 * 4. Clean up
3970 */
3971 if ( ! scrollY ) {
3972 /* IE7< puts a vertical scrollbar in place (when it shouldn't be) due to subtracting
3973 * the scrollbar height from the visible display, rather than adding it on. We need to
3974 * set the height in order to sort this. Don't want to do it in any other browsers.
3975 */
3976 if ( ie67 ) {
3977 divBodyStyle.height = _fnStringToCss( tableEl.offsetHeight+barWidth );
3978 }
3979 }
3980
3981 if ( scrollY && scroll.bCollapse ) {
3982 divBodyStyle.height = _fnStringToCss( scrollY );
3983
3984 var iExtra = (scrollX && tableEl.offsetWidth > divBodyEl.offsetWidth) ?
3985 barWidth :
3986 0;
3987
3988 if ( tableEl.offsetHeight < divBodyEl.offsetHeight ) {
3989 divBodyStyle.height = _fnStringToCss( tableEl.offsetHeight+iExtra );
3990 }
3991 }
3992
3993 /* Finally set the width's of the header and footer tables */
3994 var iOuterWidth = table.outerWidth();
3995 divHeaderTable[0].style.width = _fnStringToCss( iOuterWidth );
3996 divHeaderInnerStyle.width = _fnStringToCss( iOuterWidth );
3997
3998 // Figure out if there are scrollbar present - if so then we need a the header and footer to
3999 // provide a bit more space to allow "overflow" scrolling (i.e. past the scrollbar)
4000 var bScrolling = table.height() > divBodyEl.clientHeight || divBody.css('overflow-y') == "scroll";
4001 var padding = 'padding' + (browser.bScrollbarLeft ? 'Left' : 'Right' );
4002 divHeaderInnerStyle[ padding ] = bScrolling ? barWidth+"px" : "0px";
4003
4004 if ( footer ) {
4005 divFooterTable[0].style.width = _fnStringToCss( iOuterWidth );
4006 divFooterInner[0].style.width = _fnStringToCss( iOuterWidth );
4007 divFooterInner[0].style[padding] = bScrolling ? barWidth+"px" : "0px";
4008 }
4009
4010 /* Adjust the position of the header in case we loose the y-scrollbar */
4011 divBody.scroll();
4012
4013 // If sorting or filtering has occurred, jump the scrolling back to the top
4014 // only if we aren't holding the position
4015 if ( (settings.bSorted || settings.bFiltered) && ! settings._drawHold ) {
4016 divBodyEl.scrollTop = 0;
4017 }
4018 }
4019
4020
4021
4022 /**
4023 * Apply a given function to the display child nodes of an element array (typically
4024 * TD children of TR rows
4025 * @param {function} fn Method to apply to the objects
4026 * @param array {nodes} an1 List of elements to look through for display children
4027 * @param array {nodes} an2 Another list (identical structure to the first) - optional
4028 * @memberof DataTable#oApi
4029 */
4030 function _fnApplyToChildren( fn, an1, an2 )
4031 {
4032 var index=0, i=0, iLen=an1.length;
4033 var nNode1, nNode2;
4034
4035 while ( i < iLen ) {
4036 nNode1 = an1[i].firstChild;
4037 nNode2 = an2 ? an2[i].firstChild : null;
4038
4039 while ( nNode1 ) {
4040 if ( nNode1.nodeType === 1 ) {
4041 if ( an2 ) {
4042 fn( nNode1, nNode2, index );
4043 }
4044 else {
4045 fn( nNode1, index );
4046 }
4047
4048 index++;
4049 }
4050
4051 nNode1 = nNode1.nextSibling;
4052 nNode2 = an2 ? nNode2.nextSibling : null;
4053 }
4054
4055 i++;
4056 }
4057 }
4058
4059
4060
4061 var __re_html_remove = /<.*?>/g;
4062
4063
4064 /**
4065 * Calculate the width of columns for the table
4066 * @param {object} oSettings dataTables settings object
4067 * @memberof DataTable#oApi
4068 */
4069 function _fnCalculateColumnWidths ( oSettings )
4070 {
4071 var
4072 table = oSettings.nTable,
4073 columns = oSettings.aoColumns,
4074 scroll = oSettings.oScroll,
4075 scrollY = scroll.sY,
4076 scrollX = scroll.sX,
4077 scrollXInner = scroll.sXInner,
4078 columnCount = columns.length,
4079 visibleColumns = _fnGetColumns( oSettings, 'bVisible' ),
4080 headerCells = $('th', oSettings.nTHead),
4081 tableWidthAttr = table.getAttribute('width'),
4082 tableContainer = table.parentNode,
4083 userInputs = false,
4084 i, column, columnIdx, width, outerWidth;
4085
4086 /* Convert any user input sizes into pixel sizes */
4087 for ( i=0 ; i<visibleColumns.length ; i++ ) {
4088 column = columns[ visibleColumns[i] ];
4089
4090 if ( column.sWidth !== null ) {
4091 column.sWidth = _fnConvertToWidth( column.sWidthOrig, tableContainer );
4092
4093 userInputs = true;
4094 }
4095 }
4096
4097 /* If the number of columns in the DOM equals the number that we have to
4098 * process in DataTables, then we can use the offsets that are created by
4099 * the web- browser. No custom sizes can be set in order for this to happen,
4100 * nor scrolling used
4101 */
4102 if ( ! userInputs && ! scrollX && ! scrollY &&
4103 columnCount == _fnVisbleColumns( oSettings ) &&
4104 columnCount == headerCells.length
4105 ) {
4106 for ( i=0 ; i<columnCount ; i++ ) {
4107 columns[i].sWidth = _fnStringToCss( headerCells.eq(i).width() );
4108 }
4109 }
4110 else
4111 {
4112 // Otherwise construct a single row table with the widest node in the
4113 // data, assign any user defined widths, then insert it into the DOM and
4114 // allow the browser to do all the hard work of calculating table widths
4115 var tmpTable = $(table).clone() // don't use cloneNode - IE8 will remove events on the main table
4116 .empty()
4117 .css( 'visibility', 'hidden' )
4118 .removeAttr( 'id' )
4119 .append( $(oSettings.nTHead).clone( false ) )
4120 .append( $(oSettings.nTFoot).clone( false ) )
4121 .append( $('<tbody><tr/></tbody>') );
4122
4123 // Remove any assigned widths from the footer (from scrolling)
4124 tmpTable.find('tfoot th, tfoot td').css('width', '');
4125
4126 var tr = tmpTable.find( 'tbody tr' );
4127
4128 // Apply custom sizing to the cloned header
4129 headerCells = _fnGetUniqueThs( oSettings, tmpTable.find('thead')[0] );
4130
4131 for ( i=0 ; i<visibleColumns.length ; i++ ) {
4132 column = columns[ visibleColumns[i] ];
4133
4134 headerCells[i].style.width = column.sWidthOrig !== null && column.sWidthOrig !== '' ?
4135 _fnStringToCss( column.sWidthOrig ) :
4136 '';
4137 }
4138
4139 // Find the widest cell for each column and put it into the table
4140 if ( oSettings.aoData.length ) {
4141 for ( i=0 ; i<visibleColumns.length ; i++ ) {
4142 columnIdx = visibleColumns[i];
4143 column = columns[ columnIdx ];
4144
4145 $( _fnGetWidestNode( oSettings, columnIdx ) )
4146 .clone( false )
4147 .append( column.sContentPadding )
4148 .appendTo( tr );
4149 }
4150 }
4151
4152 // Table has been built, attach to the document so we can work with it
4153 tmpTable.appendTo( tableContainer );
4154
4155 // When scrolling (X or Y) we want to set the width of the table as
4156 // appropriate. However, when not scrolling leave the table width as it
4157 // is. This results in slightly different, but I think correct behaviour
4158 if ( scrollX && scrollXInner ) {
4159 tmpTable.width( scrollXInner );
4160 }
4161 else if ( scrollX ) {
4162 tmpTable.css( 'width', 'auto' );
4163
4164 if ( tmpTable.width() < tableContainer.offsetWidth ) {
4165 tmpTable.width( tableContainer.offsetWidth );
4166 }
4167 }
4168 else if ( scrollY ) {
4169 tmpTable.width( tableContainer.offsetWidth );
4170 }
4171 else if ( tableWidthAttr ) {
4172 tmpTable.width( tableWidthAttr );
4173 }
4174
4175 // Take into account the y scrollbar
4176 _fnScrollingWidthAdjust( oSettings, tmpTable[0] );
4177
4178 // Browsers need a bit of a hand when a width is assigned to any columns
4179 // when x-scrolling as they tend to collapse the table to the min-width,
4180 // even if we sent the column widths. So we need to keep track of what
4181 // the table width should be by summing the user given values, and the
4182 // automatic values
4183 if ( scrollX )
4184 {
4185 var total = 0;
4186
4187 for ( i=0 ; i<visibleColumns.length ; i++ ) {
4188 column = columns[ visibleColumns[i] ];
4189 outerWidth = $(headerCells[i]).outerWidth();
4190
4191 total += column.sWidthOrig === null ?
4192 outerWidth :
4193 parseInt( column.sWidth, 10 ) + outerWidth - $(headerCells[i]).width();
4194 }
4195
4196 tmpTable.width( _fnStringToCss( total ) );
4197 table.style.width = _fnStringToCss( total );
4198 }
4199
4200 // Get the width of each column in the constructed table
4201 for ( i=0 ; i<visibleColumns.length ; i++ ) {
4202 column = columns[ visibleColumns[i] ];
4203 width = $(headerCells[i]).width();
4204
4205 if ( width ) {
4206 column.sWidth = _fnStringToCss( width );
4207 }
4208 }
4209
4210 table.style.width = _fnStringToCss( tmpTable.css('width') );
4211
4212 // Finished with the table - ditch it
4213 tmpTable.remove();
4214 }
4215
4216 // If there is a width attr, we want to attach an event listener which
4217 // allows the table sizing to automatically adjust when the window is
4218 // resized. Use the width attr rather than CSS, since we can't know if the
4219 // CSS is a relative value or absolute - DOM read is always px.
4220 if ( tableWidthAttr ) {
4221 table.style.width = _fnStringToCss( tableWidthAttr );
4222 }
4223
4224 if ( (tableWidthAttr || scrollX) && ! oSettings._reszEvt ) {
4225 $(window).bind('resize.DT-'+oSettings.sInstance, _fnThrottle( function () {
4226 _fnAdjustColumnSizing( oSettings );
4227 } ) );
4228
4229 oSettings._reszEvt = true;
4230 }
4231 }
4232
4233
4234 /**
4235 * Throttle the calls to a function. Arguments and context are maintained for
4236 * the throttled function
4237 * @param {function} fn Function to be called
4238 * @param {int} [freq=200] call frequency in mS
4239 * @returns {function} wrapped function
4240 * @memberof DataTable#oApi
4241 */
4242 function _fnThrottle( fn, freq ) {
4243 var
4244 frequency = freq !== undefined ? freq : 200,
4245 last,
4246 timer;
4247
4248 return function () {
4249 var
4250 that = this,
4251 now = +new Date(),
4252 args = arguments;
4253
4254 if ( last && now < last + frequency ) {
4255 clearTimeout( timer );
4256
4257 timer = setTimeout( function () {
4258 last = undefined;
4259 fn.apply( that, args );
4260 }, frequency );
4261 }
4262 else if ( last ) {
4263 last = now;
4264 fn.apply( that, args );
4265 }
4266 else {
4267 last = now;
4268 }
4269 };
4270 }
4271
4272
4273 /**
4274 * Convert a CSS unit width to pixels (e.g. 2em)
4275 * @param {string} width width to be converted
4276 * @param {node} parent parent to get the with for (required for relative widths) - optional
4277 * @returns {int} width in pixels
4278 * @memberof DataTable#oApi
4279 */
4280 function _fnConvertToWidth ( width, parent )
4281 {
4282 if ( ! width ) {
4283 return 0;
4284 }
4285
4286 var n = $('<div/>')
4287 .css( 'width', _fnStringToCss( width ) )
4288 .appendTo( parent || document.body );
4289
4290 var val = n[0].offsetWidth;
4291 n.remove();
4292
4293 return val;
4294 }
4295
4296
4297 /**
4298 * Adjust a table's width to take account of vertical scroll bar
4299 * @param {object} oSettings dataTables settings object
4300 * @param {node} n table node
4301 * @memberof DataTable#oApi
4302 */
4303
4304 function _fnScrollingWidthAdjust ( settings, n )
4305 {
4306 var scroll = settings.oScroll;
4307
4308 if ( scroll.sX || scroll.sY ) {
4309 // When y-scrolling only, we want to remove the width of the scroll bar
4310 // so the table + scroll bar will fit into the area available, otherwise
4311 // we fix the table at its current size with no adjustment
4312 var correction = ! scroll.sX ? scroll.iBarWidth : 0;
4313 n.style.width = _fnStringToCss( $(n).outerWidth() - correction );
4314 }
4315 }
4316
4317
4318 /**
4319 * Get the widest node
4320 * @param {object} settings dataTables settings object
4321 * @param {int} colIdx column of interest
4322 * @returns {node} widest table node
4323 * @memberof DataTable#oApi
4324 */
4325 function _fnGetWidestNode( settings, colIdx )
4326 {
4327 var idx = _fnGetMaxLenString( settings, colIdx );
4328 if ( idx < 0 ) {
4329 return null;
4330 }
4331
4332 var data = settings.aoData[ idx ];
4333 return ! data.nTr ? // Might not have been created when deferred rendering
4334 $('<td/>').html( _fnGetCellData( settings, idx, colIdx, 'display' ) )[0] :
4335 data.anCells[ colIdx ];
4336 }
4337
4338
4339 /**
4340 * Get the maximum strlen for each data column
4341 * @param {object} settings dataTables settings object
4342 * @param {int} colIdx column of interest
4343 * @returns {string} max string length for each column
4344 * @memberof DataTable#oApi
4345 */
4346 function _fnGetMaxLenString( settings, colIdx )
4347 {
4348 var s, max=-1, maxIdx = -1;
4349
4350 for ( var i=0, ien=settings.aoData.length ; i<ien ; i++ ) {
4351 s = _fnGetCellData( settings, i, colIdx, 'display' )+'';
4352 s = s.replace( __re_html_remove, '' );
4353
4354 if ( s.length > max ) {
4355 max = s.length;
4356 maxIdx = i;
4357 }
4358 }
4359
4360 return maxIdx;
4361 }
4362
4363
4364 /**
4365 * Append a CSS unit (only if required) to a string
4366 * @param {string} value to css-ify
4367 * @returns {string} value with css unit
4368 * @memberof DataTable#oApi
4369 */
4370 function _fnStringToCss( s )
4371 {
4372 if ( s === null ) {
4373 return '0px';
4374 }
4375
4376 if ( typeof s == 'number' ) {
4377 return s < 0 ?
4378 '0px' :
4379 s+'px';
4380 }
4381
4382 // Check it has a unit character already
4383 return s.match(/\d$/) ?
4384 s+'px' :
4385 s;
4386 }
4387
4388
4389 /**
4390 * Get the width of a scroll bar in this browser being used
4391 * @returns {int} width in pixels
4392 * @memberof DataTable#oApi
4393 */
4394 function _fnScrollBarWidth ()
4395 {
4396 // On first run a static variable is set, since this is only needed once.
4397 // Subsequent runs will just use the previously calculated value
4398 if ( ! DataTable.__scrollbarWidth ) {
4399 var inner = $('<p/>').css( {
4400 width: '100%',
4401 height: 200,
4402 padding: 0
4403 } )[0];
4404
4405 var outer = $('<div/>')
4406 .css( {
4407 position: 'absolute',
4408 top: 0,
4409 left: 0,
4410 width: 200,
4411 height: 150,
4412 padding: 0,
4413 overflow: 'hidden',
4414 visibility: 'hidden'
4415 } )
4416 .append( inner )
4417 .appendTo( 'body' );
4418
4419 var w1 = inner.offsetWidth;
4420 outer.css( 'overflow', 'scroll' );
4421 var w2 = inner.offsetWidth;
4422
4423 if ( w1 === w2 ) {
4424 w2 = outer[0].clientWidth;
4425 }
4426
4427 outer.remove();
4428
4429 DataTable.__scrollbarWidth = w1 - w2;
4430 }
4431
4432 return DataTable.__scrollbarWidth;
4433 }
4434
4435
4436
4437 function _fnSortFlatten ( settings )
4438 {
4439 var
4440 i, iLen, k, kLen,
4441 aSort = [],
4442 aiOrig = [],
4443 aoColumns = settings.aoColumns,
4444 aDataSort, iCol, sType, srcCol,
4445 fixed = settings.aaSortingFixed,
4446 fixedObj = $.isPlainObject( fixed ),
4447 nestedSort = [],
4448 add = function ( a ) {
4449 if ( a.length && ! $.isArray( a[0] ) ) {
4450 // 1D array
4451 nestedSort.push( a );
4452 }
4453 else {
4454 // 2D array
4455 nestedSort.push.apply( nestedSort, a );
4456 }
4457 };
4458
4459 // Build the sort array, with pre-fix and post-fix options if they have been
4460 // specified
4461 if ( $.isArray( fixed ) ) {
4462 add( fixed );
4463 }
4464
4465 if ( fixedObj && fixed.pre ) {
4466 add( fixed.pre );
4467 }
4468
4469 add( settings.aaSorting );
4470
4471 if (fixedObj && fixed.post ) {
4472 add( fixed.post );
4473 }
4474
4475 for ( i=0 ; i<nestedSort.length ; i++ )
4476 {
4477 srcCol = nestedSort[i][0];
4478 aDataSort = aoColumns[ srcCol ].aDataSort;
4479
4480 for ( k=0, kLen=aDataSort.length ; k<kLen ; k++ )
4481 {
4482 iCol = aDataSort[k];
4483 sType = aoColumns[ iCol ].sType || 'string';
4484
4485 if ( nestedSort[i]._idx === undefined ) {
4486 nestedSort[i]._idx = $.inArray( nestedSort[i][1], aoColumns[iCol].asSorting );
4487 }
4488
4489 aSort.push( {
4490 src: srcCol,
4491 col: iCol,
4492 dir: nestedSort[i][1],
4493 index: nestedSort[i]._idx,
4494 type: sType,
4495 formatter: DataTable.ext.type.order[ sType+"-pre" ]
4496 } );
4497 }
4498 }
4499
4500 return aSort;
4501 }
4502
4503 /**
4504 * Change the order of the table
4505 * @param {object} oSettings dataTables settings object
4506 * @memberof DataTable#oApi
4507 * @todo This really needs split up!
4508 */
4509 function _fnSort ( oSettings )
4510 {
4511 var
4512 i, ien, iLen, j, jLen, k, kLen,
4513 sDataType, nTh,
4514 aiOrig = [],
4515 oExtSort = DataTable.ext.type.order,
4516 aoData = oSettings.aoData,
4517 aoColumns = oSettings.aoColumns,
4518 aDataSort, data, iCol, sType, oSort,
4519 formatters = 0,
4520 sortCol,
4521 displayMaster = oSettings.aiDisplayMaster,
4522 aSort;
4523
4524 // Resolve any column types that are unknown due to addition or invalidation
4525 // @todo Can this be moved into a 'data-ready' handler which is called when
4526 // data is going to be used in the table?
4527 _fnColumnTypes( oSettings );
4528
4529 aSort = _fnSortFlatten( oSettings );
4530
4531 for ( i=0, ien=aSort.length ; i<ien ; i++ ) {
4532 sortCol = aSort[i];
4533
4534 // Track if we can use the fast sort algorithm
4535 if ( sortCol.formatter ) {
4536 formatters++;
4537 }
4538
4539 // Load the data needed for the sort, for each cell
4540 _fnSortData( oSettings, sortCol.col );
4541 }
4542
4543 /* No sorting required if server-side or no sorting array */
4544 if ( _fnDataSource( oSettings ) != 'ssp' && aSort.length !== 0 )
4545 {
4546 // Create a value - key array of the current row positions such that we can use their
4547 // current position during the sort, if values match, in order to perform stable sorting
4548 for ( i=0, iLen=displayMaster.length ; i<iLen ; i++ ) {
4549 aiOrig[ displayMaster[i] ] = i;
4550 }
4551
4552 /* Do the sort - here we want multi-column sorting based on a given data source (column)
4553 * and sorting function (from oSort) in a certain direction. It's reasonably complex to
4554 * follow on it's own, but this is what we want (example two column sorting):
4555 * fnLocalSorting = function(a,b){
4556 * var iTest;
4557 * iTest = oSort['string-asc']('data11', 'data12');
4558 * if (iTest !== 0)
4559 * return iTest;
4560 * iTest = oSort['numeric-desc']('data21', 'data22');
4561 * if (iTest !== 0)
4562 * return iTest;
4563 * return oSort['numeric-asc']( aiOrig[a], aiOrig[b] );
4564 * }
4565 * Basically we have a test for each sorting column, if the data in that column is equal,
4566 * test the next column. If all columns match, then we use a numeric sort on the row
4567 * positions in the original data array to provide a stable sort.
4568 *
4569 * Note - I know it seems excessive to have two sorting methods, but the first is around
4570 * 15% faster, so the second is only maintained for backwards compatibility with sorting
4571 * methods which do not have a pre-sort formatting function.
4572 */
4573 if ( formatters === aSort.length ) {
4574 // All sort types have formatting functions
4575 displayMaster.sort( function ( a, b ) {
4576 var
4577 x, y, k, test, sort,
4578 len=aSort.length,
4579 dataA = aoData[a]._aSortData,
4580 dataB = aoData[b]._aSortData;
4581
4582 for ( k=0 ; k<len ; k++ ) {
4583 sort = aSort[k];
4584
4585 x = dataA[ sort.col ];
4586 y = dataB[ sort.col ];
4587
4588 test = x<y ? -1 : x>y ? 1 : 0;
4589 if ( test !== 0 ) {
4590 return sort.dir === 'asc' ? test : -test;
4591 }
4592 }
4593
4594 x = aiOrig[a];
4595 y = aiOrig[b];
4596 return x<y ? -1 : x>y ? 1 : 0;
4597 } );
4598 }
4599 else {
4600 // Depreciated - remove in 1.11 (providing a plug-in option)
4601 // Not all sort types have formatting methods, so we have to call their sorting
4602 // methods.
4603 displayMaster.sort( function ( a, b ) {
4604 var
4605 x, y, k, l, test, sort, fn,
4606 len=aSort.length,
4607 dataA = aoData[a]._aSortData,
4608 dataB = aoData[b]._aSortData;
4609
4610 for ( k=0 ; k<len ; k++ ) {
4611 sort = aSort[k];
4612
4613 x = dataA[ sort.col ];
4614 y = dataB[ sort.col ];
4615
4616 fn = oExtSort[ sort.type+"-"+sort.dir ] || oExtSort[ "string-"+sort.dir ];
4617 test = fn( x, y );
4618 if ( test !== 0 ) {
4619 return test;
4620 }
4621 }
4622
4623 x = aiOrig[a];
4624 y = aiOrig[b];
4625 return x<y ? -1 : x>y ? 1 : 0;
4626 } );
4627 }
4628 }
4629
4630 /* Tell the draw function that we have sorted the data */
4631 oSettings.bSorted = true;
4632 }
4633
4634
4635 function _fnSortAria ( settings )
4636 {
4637 var label;
4638 var nextSort;
4639 var columns = settings.aoColumns;
4640 var aSort = _fnSortFlatten( settings );
4641 var oAria = settings.oLanguage.oAria;
4642
4643 // ARIA attributes - need to loop all columns, to update all (removing old
4644 // attributes as needed)
4645 for ( var i=0, iLen=columns.length ; i<iLen ; i++ )
4646 {
4647 var col = columns[i];
4648 var asSorting = col.asSorting;
4649 var sTitle = col.sTitle.replace( /<.*?>/g, "" );
4650 var th = col.nTh;
4651
4652 // IE7 is throwing an error when setting these properties with jQuery's
4653 // attr() and removeAttr() methods...
4654 th.removeAttribute('aria-sort');
4655
4656 /* In ARIA only the first sorting column can be marked as sorting - no multi-sort option */
4657 if ( col.bSortable ) {
4658 if ( aSort.length > 0 && aSort[0].col == i ) {
4659 th.setAttribute('aria-sort', aSort[0].dir=="asc" ? "ascending" : "descending" );
4660 nextSort = asSorting[ aSort[0].index+1 ] || asSorting[0];
4661 }
4662 else {
4663 nextSort = asSorting[0];
4664 }
4665
4666 label = sTitle + ( nextSort === "asc" ?
4667 oAria.sSortAscending :
4668 oAria.sSortDescending
4669 );
4670 }
4671 else {
4672 label = sTitle;
4673 }
4674
4675 th.setAttribute('aria-label', label);
4676 }
4677 }
4678
4679
4680 /**
4681 * Function to run on user sort request
4682 * @param {object} settings dataTables settings object
4683 * @param {node} attachTo node to attach the handler to
4684 * @param {int} colIdx column sorting index
4685 * @param {boolean} [append=false] Append the requested sort to the existing
4686 * sort if true (i.e. multi-column sort)
4687 * @param {function} [callback] callback function
4688 * @memberof DataTable#oApi
4689 */
4690 function _fnSortListener ( settings, colIdx, append, callback )
4691 {
4692 var col = settings.aoColumns[ colIdx ];
4693 var sorting = settings.aaSorting;
4694 var asSorting = col.asSorting;
4695 var nextSortIdx;
4696 var next = function ( a, overflow ) {
4697 var idx = a._idx;
4698 if ( idx === undefined ) {
4699 idx = $.inArray( a[1], asSorting );
4700 }
4701
4702 return idx+1 < asSorting.length ?
4703 idx+1 :
4704 overflow ?
4705 null :
4706 0;
4707 };
4708
4709 // Convert to 2D array if needed
4710 if ( typeof sorting[0] === 'number' ) {
4711 sorting = settings.aaSorting = [ sorting ];
4712 }
4713
4714 // If appending the sort then we are multi-column sorting
4715 if ( append && settings.oFeatures.bSortMulti ) {
4716 // Are we already doing some kind of sort on this column?
4717 var sortIdx = $.inArray( colIdx, _pluck(sorting, '0') );
4718
4719 if ( sortIdx !== -1 ) {
4720 // Yes, modify the sort
4721 nextSortIdx = next( sorting[sortIdx], true );
4722
4723 if ( nextSortIdx === null ) {
4724 sorting.splice( sortIdx, 1 );
4725 }
4726 else {
4727 sorting[sortIdx][1] = asSorting[ nextSortIdx ];
4728 sorting[sortIdx]._idx = nextSortIdx;
4729 }
4730 }
4731 else {
4732 // No sort on this column yet
4733 sorting.push( [ colIdx, asSorting[0], 0 ] );
4734 sorting[sorting.length-1]._idx = 0;
4735 }
4736 }
4737 else if ( sorting.length && sorting[0][0] == colIdx ) {
4738 // Single column - already sorting on this column, modify the sort
4739 nextSortIdx = next( sorting[0] );
4740
4741 sorting.length = 1;
4742 sorting[0][1] = asSorting[ nextSortIdx ];
4743 sorting[0]._idx = nextSortIdx;
4744 }
4745 else {
4746 // Single column - sort only on this column
4747 sorting.length = 0;
4748 sorting.push( [ colIdx, asSorting[0] ] );
4749 sorting[0]._idx = 0;
4750 }
4751
4752 // Run the sort by calling a full redraw
4753 _fnReDraw( settings );
4754
4755 // callback used for async user interaction
4756 if ( typeof callback == 'function' ) {
4757 callback( settings );
4758 }
4759 }
4760
4761
4762 /**
4763 * Attach a sort handler (click) to a node
4764 * @param {object} settings dataTables settings object
4765 * @param {node} attachTo node to attach the handler to
4766 * @param {int} colIdx column sorting index
4767 * @param {function} [callback] callback function
4768 * @memberof DataTable#oApi
4769 */
4770 function _fnSortAttachListener ( settings, attachTo, colIdx, callback )
4771 {
4772 var col = settings.aoColumns[ colIdx ];
4773
4774 _fnBindAction( attachTo, {}, function (e) {
4775 /* If the column is not sortable - don't to anything */
4776 if ( col.bSortable === false ) {
4777 return;
4778 }
4779
4780 // If processing is enabled use a timeout to allow the processing
4781 // display to be shown - otherwise to it synchronously
4782 if ( settings.oFeatures.bProcessing ) {
4783 _fnProcessingDisplay( settings, true );
4784
4785 setTimeout( function() {
4786 _fnSortListener( settings, colIdx, e.shiftKey, callback );
4787
4788 // In server-side processing, the draw callback will remove the
4789 // processing display
4790 if ( _fnDataSource( settings ) !== 'ssp' ) {
4791 _fnProcessingDisplay( settings, false );
4792 }
4793 }, 0 );
4794 }
4795 else {
4796 _fnSortListener( settings, colIdx, e.shiftKey, callback );
4797 }
4798 } );
4799 }
4800
4801
4802 /**
4803 * Set the sorting classes on table's body, Note: it is safe to call this function
4804 * when bSort and bSortClasses are false
4805 * @param {object} oSettings dataTables settings object
4806 * @memberof DataTable#oApi
4807 */
4808 function _fnSortingClasses( settings )
4809 {
4810 var oldSort = settings.aLastSort;
4811 var sortClass = settings.oClasses.sSortColumn;
4812 var sort = _fnSortFlatten( settings );
4813 var features = settings.oFeatures;
4814 var i, ien, colIdx;
4815
4816 if ( features.bSort && features.bSortClasses ) {
4817 // Remove old sorting classes
4818 for ( i=0, ien=oldSort.length ; i<ien ; i++ ) {
4819 colIdx = oldSort[i].src;
4820
4821 // Remove column sorting
4822 $( _pluck( settings.aoData, 'anCells', colIdx ) )
4823 .removeClass( sortClass + (i<2 ? i+1 : 3) );
4824 }
4825
4826 // Add new column sorting
4827 for ( i=0, ien=sort.length ; i<ien ; i++ ) {
4828 colIdx = sort[i].src;
4829
4830 $( _pluck( settings.aoData, 'anCells', colIdx ) )
4831 .addClass( sortClass + (i<2 ? i+1 : 3) );
4832 }
4833 }
4834
4835 settings.aLastSort = sort;
4836 }
4837
4838
4839 // Get the data to sort a column, be it from cache, fresh (populating the
4840 // cache), or from a sort formatter
4841 function _fnSortData( settings, idx )
4842 {
4843 // Custom sorting function - provided by the sort data type
4844 var column = settings.aoColumns[ idx ];
4845 var customSort = DataTable.ext.order[ column.sSortDataType ];
4846 var customData;
4847
4848 if ( customSort ) {
4849 customData = customSort.call( settings.oInstance, settings, idx,
4850 _fnColumnIndexToVisible( settings, idx )
4851 );
4852 }
4853
4854 // Use / populate cache
4855 var row, cellData;
4856 var formatter = DataTable.ext.type.order[ column.sType+"-pre" ];
4857
4858 for ( var i=0, ien=settings.aoData.length ; i<ien ; i++ ) {
4859 row = settings.aoData[i];
4860
4861 if ( ! row._aSortData ) {
4862 row._aSortData = [];
4863 }
4864
4865 if ( ! row._aSortData[idx] || customSort ) {
4866 cellData = customSort ?
4867 customData[i] : // If there was a custom sort function, use data from there
4868 _fnGetCellData( settings, i, idx, 'sort' );
4869
4870 row._aSortData[ idx ] = formatter ?
4871 formatter( cellData ) :
4872 cellData;
4873 }
4874 }
4875 }
4876
4877
4878
4879 /**
4880 * Save the state of a table
4881 * @param {object} oSettings dataTables settings object
4882 * @memberof DataTable#oApi
4883 */
4884 function _fnSaveState ( settings )
4885 {
4886 if ( !settings.oFeatures.bStateSave || settings.bDestroying )
4887 {
4888 return;
4889 }
4890
4891 /* Store the interesting variables */
4892 var state = {
4893 time: +new Date(),
4894 start: settings._iDisplayStart,
4895 length: settings._iDisplayLength,
4896 order: $.extend( true, [], settings.aaSorting ),
4897 search: _fnSearchToCamel( settings.oPreviousSearch ),
4898 columns: $.map( settings.aoColumns, function ( col, i ) {
4899 return {
4900 visible: col.bVisible,
4901 search: _fnSearchToCamel( settings.aoPreSearchCols[i] )
4902 };
4903 } )
4904 };
4905
4906 _fnCallbackFire( settings, "aoStateSaveParams", 'stateSaveParams', [settings, state] );
4907
4908 settings.oSavedState = state;
4909 settings.fnStateSaveCallback.call( settings.oInstance, settings, state );
4910 }
4911
4912
4913 /**
4914 * Attempt to load a saved table state
4915 * @param {object} oSettings dataTables settings object
4916 * @param {object} oInit DataTables init object so we can override settings
4917 * @memberof DataTable#oApi
4918 */
4919 function _fnLoadState ( settings, oInit )
4920 {
4921 var i, ien;
4922 var columns = settings.aoColumns;
4923
4924 if ( ! settings.oFeatures.bStateSave ) {
4925 return;
4926 }
4927
4928 var state = settings.fnStateLoadCallback.call( settings.oInstance, settings );
4929 if ( ! state || ! state.time ) {
4930 return;
4931 }
4932
4933 /* Allow custom and plug-in manipulation functions to alter the saved data set and
4934 * cancelling of loading by returning false
4935 */
4936 var abStateLoad = _fnCallbackFire( settings, 'aoStateLoadParams', 'stateLoadParams', [settings, state] );
4937 if ( $.inArray( false, abStateLoad ) !== -1 ) {
4938 return;
4939 }
4940
4941 /* Reject old data */
4942 var duration = settings.iStateDuration;
4943 if ( duration > 0 && state.time < +new Date() - (duration*1000) ) {
4944 return;
4945 }
4946
4947 // Number of columns have changed - all bets are off, no restore of settings
4948 if ( columns.length !== state.columns.length ) {
4949 return;
4950 }
4951
4952 // Store the saved state so it might be accessed at any time
4953 settings.oLoadedState = $.extend( true, {}, state );
4954
4955 // Restore key features - todo - for 1.11 this needs to be done by
4956 // subscribed events
4957 settings._iDisplayStart = state.start;
4958 settings.iInitDisplayStart = state.start;
4959 settings._iDisplayLength = state.length;
4960 settings.aaSorting = [];
4961
4962 // Order
4963 $.each( state.order, function ( i, col ) {
4964 settings.aaSorting.push( col[0] >= columns.length ?
4965 [ 0, col[1] ] :
4966 col
4967 );
4968 } );
4969
4970 // Search
4971 $.extend( settings.oPreviousSearch, _fnSearchToHung( state.search ) );
4972
4973 // Columns
4974 for ( i=0, ien=state.columns.length ; i<ien ; i++ ) {
4975 var col = state.columns[i];
4976
4977 // Visibility
4978 columns[i].bVisible = col.visible;
4979
4980 // Search
4981 $.extend( settings.aoPreSearchCols[i], _fnSearchToHung( col.search ) );
4982 }
4983
4984 _fnCallbackFire( settings, 'aoStateLoaded', 'stateLoaded', [settings, state] );
4985 }
4986
4987
4988 /**
4989 * Return the settings object for a particular table
4990 * @param {node} table table we are using as a dataTable
4991 * @returns {object} Settings object - or null if not found
4992 * @memberof DataTable#oApi
4993 */
4994 function _fnSettingsFromNode ( table )
4995 {
4996 var settings = DataTable.settings;
4997 var idx = $.inArray( table, _pluck( settings, 'nTable' ) );
4998
4999 return idx !== -1 ?
5000 settings[ idx ] :
5001 null;
5002 }
5003
5004
5005 /**
5006 * Log an error message
5007 * @param {object} settings dataTables settings object
5008 * @param {int} level log error messages, or display them to the user
5009 * @param {string} msg error message
5010 * @param {int} tn Technical note id to get more information about the error.
5011 * @memberof DataTable#oApi
5012 */
5013 function _fnLog( settings, level, msg, tn )
5014 {
5015 msg = 'DataTables warning: '+
5016 (settings!==null ? 'table id='+settings.sTableId+' - ' : '')+msg;
5017
5018 if ( tn ) {
5019 msg += '. For more information about this error, please see '+
5020 'http://datatables.net/tn/'+tn;
5021 }
5022
5023 if ( ! level ) {
5024 // Backwards compatibility pre 1.10
5025 var ext = DataTable.ext;
5026 var type = ext.sErrMode || ext.errMode;
5027
5028 if ( type == 'alert' ) {
5029 alert( msg );
5030 }
5031 else {
5032 throw new Error(msg);
5033 }
5034 }
5035 else if ( window.console && console.log ) {
5036 console.log( msg );
5037 }
5038 }
5039
5040
5041 /**
5042 * See if a property is defined on one object, if so assign it to the other object
5043 * @param {object} ret target object
5044 * @param {object} src source object
5045 * @param {string} name property
5046 * @param {string} [mappedName] name to map too - optional, name used if not given
5047 * @memberof DataTable#oApi
5048 */
5049 function _fnMap( ret, src, name, mappedName )
5050 {
5051 if ( $.isArray( name ) ) {
5052 $.each( name, function (i, val) {
5053 if ( $.isArray( val ) ) {
5054 _fnMap( ret, src, val[0], val[1] );
5055 }
5056 else {
5057 _fnMap( ret, src, val );
5058 }
5059 } );
5060
5061 return;
5062 }
5063
5064 if ( mappedName === undefined ) {
5065 mappedName = name;
5066 }
5067
5068 if ( src[name] !== undefined ) {
5069 ret[mappedName] = src[name];
5070 }
5071 }
5072
5073
5074 /**
5075 * Extend objects - very similar to jQuery.extend, but deep copy objects, and
5076 * shallow copy arrays. The reason we need to do this, is that we don't want to
5077 * deep copy array init values (such as aaSorting) since the dev wouldn't be
5078 * able to override them, but we do want to deep copy arrays.
5079 * @param {object} out Object to extend
5080 * @param {object} extender Object from which the properties will be applied to
5081 * out
5082 * @param {boolean} breakRefs If true, then arrays will be sliced to take an
5083 * independent copy with the exception of the `data` or `aaData` parameters
5084 * if they are present. This is so you can pass in a collection to
5085 * DataTables and have that used as your data source without breaking the
5086 * references
5087 * @returns {object} out Reference, just for convenience - out === the return.
5088 * @memberof DataTable#oApi
5089 * @todo This doesn't take account of arrays inside the deep copied objects.
5090 */
5091 function _fnExtend( out, extender, breakRefs )
5092 {
5093 var val;
5094
5095 for ( var prop in extender ) {
5096 if ( extender.hasOwnProperty(prop) ) {
5097 val = extender[prop];
5098
5099 if ( $.isPlainObject( val ) ) {
5100 if ( ! $.isPlainObject( out[prop] ) ) {
5101 out[prop] = {};
5102 }
5103 $.extend( true, out[prop], val );
5104 }
5105 else if ( breakRefs && prop !== 'data' && prop !== 'aaData' && $.isArray(val) ) {
5106 out[prop] = val.slice();
5107 }
5108 else {
5109 out[prop] = val;
5110 }
5111 }
5112 }
5113
5114 return out;
5115 }
5116
5117
5118 /**
5119 * Bind an event handers to allow a click or return key to activate the callback.
5120 * This is good for accessibility since a return on the keyboard will have the
5121 * same effect as a click, if the element has focus.
5122 * @param {element} n Element to bind the action to
5123 * @param {object} oData Data object to pass to the triggered function
5124 * @param {function} fn Callback function for when the event is triggered
5125 * @memberof DataTable#oApi
5126 */
5127 function _fnBindAction( n, oData, fn )
5128 {
5129 $(n)
5130 .bind( 'click.DT', oData, function (e) {
5131 n.blur(); // Remove focus outline for mouse users
5132 fn(e);
5133 } )
5134 .bind( 'keypress.DT', oData, function (e){
5135 if ( e.which === 13 ) {
5136 e.preventDefault();
5137 fn(e);
5138 }
5139 } )
5140 .bind( 'selectstart.DT', function () {
5141 /* Take the brutal approach to cancelling text selection */
5142 return false;
5143 } );
5144 }
5145
5146
5147 /**
5148 * Register a callback function. Easily allows a callback function to be added to
5149 * an array store of callback functions that can then all be called together.
5150 * @param {object} oSettings dataTables settings object
5151 * @param {string} sStore Name of the array storage for the callbacks in oSettings
5152 * @param {function} fn Function to be called back
5153 * @param {string} sName Identifying name for the callback (i.e. a label)
5154 * @memberof DataTable#oApi
5155 */
5156 function _fnCallbackReg( oSettings, sStore, fn, sName )
5157 {
5158 if ( fn )
5159 {
5160 oSettings[sStore].push( {
5161 "fn": fn,
5162 "sName": sName
5163 } );
5164 }
5165 }
5166
5167
5168 /**
5169 * Fire callback functions and trigger events. Note that the loop over the
5170 * callback array store is done backwards! Further note that you do not want to
5171 * fire off triggers in time sensitive applications (for example cell creation)
5172 * as its slow.
5173 * @param {object} settings dataTables settings object
5174 * @param {string} callbackArr Name of the array storage for the callbacks in
5175 * oSettings
5176 * @param {string} event Name of the jQuery custom event to trigger. If null no
5177 * trigger is fired
5178 * @param {array} args Array of arguments to pass to the callback function /
5179 * trigger
5180 * @memberof DataTable#oApi
5181 */
5182 function _fnCallbackFire( settings, callbackArr, e, args )
5183 {
5184 var ret = [];
5185
5186 if ( callbackArr ) {
5187 ret = $.map( settings[callbackArr].slice().reverse(), function (val, i) {
5188 return val.fn.apply( settings.oInstance, args );
5189 } );
5190 }
5191
5192 if ( e !== null ) {
5193 $(settings.nTable).trigger( e+'.dt', args );
5194 }
5195
5196 return ret;
5197 }
5198
5199
5200 function _fnLengthOverflow ( settings )
5201 {
5202 var
5203 start = settings._iDisplayStart,
5204 end = settings.fnDisplayEnd(),
5205 len = settings._iDisplayLength;
5206
5207 /* If we have space to show extra rows (backing up from the end point - then do so */
5208 if ( start >= end )
5209 {
5210 start = end - len;
5211 }
5212
5213 // Keep the start record on the current page
5214 start -= (start % len);
5215
5216 if ( len === -1 || start < 0 )
5217 {
5218 start = 0;
5219 }
5220
5221 settings._iDisplayStart = start;
5222 }
5223
5224
5225 function _fnRenderer( settings, type )
5226 {
5227 var renderer = settings.renderer;
5228 var host = DataTable.ext.renderer[type];
5229
5230 if ( $.isPlainObject( renderer ) && renderer[type] ) {
5231 // Specific renderer for this type. If available use it, otherwise use
5232 // the default.
5233 return host[renderer[type]] || host._;
5234 }
5235 else if ( typeof renderer === 'string' ) {
5236 // Common renderer - if there is one available for this type use it,
5237 // otherwise use the default
5238 return host[renderer] || host._;
5239 }
5240
5241 // Use the default
5242 return host._;
5243 }
5244
5245
5246 /**
5247 * Detect the data source being used for the table. Used to simplify the code
5248 * a little (ajax) and to make it compress a little smaller.
5249 *
5250 * @param {object} settings dataTables settings object
5251 * @returns {string} Data source
5252 * @memberof DataTable#oApi
5253 */
5254 function _fnDataSource ( settings )
5255 {
5256 if ( settings.oFeatures.bServerSide ) {
5257 return 'ssp';
5258 }
5259 else if ( settings.ajax || settings.sAjaxSource ) {
5260 return 'ajax';
5261 }
5262 return 'dom';
5263 }
5264
5265
5266 DataTable = function( options )
5267 {
5268 /**
5269 * Perform a jQuery selector action on the table's TR elements (from the tbody) and
5270 * return the resulting jQuery object.
5271 * @param {string|node|jQuery} sSelector jQuery selector or node collection to act on
5272 * @param {object} [oOpts] Optional parameters for modifying the rows to be included
5273 * @param {string} [oOpts.filter=none] Select TR elements that meet the current filter
5274 * criterion ("applied") or all TR elements (i.e. no filter).
5275 * @param {string} [oOpts.order=current] Order of the TR elements in the processed array.
5276 * Can be either 'current', whereby the current sorting of the table is used, or
5277 * 'original' whereby the original order the data was read into the table is used.
5278 * @param {string} [oOpts.page=all] Limit the selection to the currently displayed page
5279 * ("current") or not ("all"). If 'current' is given, then order is assumed to be
5280 * 'current' and filter is 'applied', regardless of what they might be given as.
5281 * @returns {object} jQuery object, filtered by the given selector.
5282 * @dtopt API
5283 * @deprecated Since v1.10
5284 *
5285 * @example
5286 * $(document).ready(function() {
5287 * var oTable = $('#example').dataTable();
5288 *
5289 * // Highlight every second row
5290 * oTable.$('tr:odd').css('backgroundColor', 'blue');
5291 * } );
5292 *
5293 * @example
5294 * $(document).ready(function() {
5295 * var oTable = $('#example').dataTable();
5296 *
5297 * // Filter to rows with 'Webkit' in them, add a background colour and then
5298 * // remove the filter, thus highlighting the 'Webkit' rows only.
5299 * oTable.fnFilter('Webkit');
5300 * oTable.$('tr', {"search": "applied"}).css('backgroundColor', 'blue');
5301 * oTable.fnFilter('');
5302 * } );
5303 */
5304 this.$ = function ( sSelector, oOpts )
5305 {
5306 return this.api(true).$( sSelector, oOpts );
5307 };
5308
5309
5310 /**
5311 * Almost identical to $ in operation, but in this case returns the data for the matched
5312 * rows - as such, the jQuery selector used should match TR row nodes or TD/TH cell nodes
5313 * rather than any descendants, so the data can be obtained for the row/cell. If matching
5314 * rows are found, the data returned is the original data array/object that was used to
5315 * create the row (or a generated array if from a DOM source).
5316 *
5317 * This method is often useful in-combination with $ where both functions are given the
5318 * same parameters and the array indexes will match identically.
5319 * @param {string|node|jQuery} sSelector jQuery selector or node collection to act on
5320 * @param {object} [oOpts] Optional parameters for modifying the rows to be included
5321 * @param {string} [oOpts.filter=none] Select elements that meet the current filter
5322 * criterion ("applied") or all elements (i.e. no filter).
5323 * @param {string} [oOpts.order=current] Order of the data in the processed array.
5324 * Can be either 'current', whereby the current sorting of the table is used, or
5325 * 'original' whereby the original order the data was read into the table is used.
5326 * @param {string} [oOpts.page=all] Limit the selection to the currently displayed page
5327 * ("current") or not ("all"). If 'current' is given, then order is assumed to be
5328 * 'current' and filter is 'applied', regardless of what they might be given as.
5329 * @returns {array} Data for the matched elements. If any elements, as a result of the
5330 * selector, were not TR, TD or TH elements in the DataTable, they will have a null
5331 * entry in the array.
5332 * @dtopt API
5333 * @deprecated Since v1.10
5334 *
5335 * @example
5336 * $(document).ready(function() {
5337 * var oTable = $('#example').dataTable();
5338 *
5339 * // Get the data from the first row in the table
5340 * var data = oTable._('tr:first');
5341 *
5342 * // Do something useful with the data
5343 * alert( "First cell is: "+data[0] );
5344 * } );
5345 *
5346 * @example
5347 * $(document).ready(function() {
5348 * var oTable = $('#example').dataTable();
5349 *
5350 * // Filter to 'Webkit' and get all data for
5351 * oTable.fnFilter('Webkit');
5352 * var data = oTable._('tr', {"search": "applied"});
5353 *
5354 * // Do something with the data
5355 * alert( data.length+" rows matched the search" );
5356 * } );
5357 */
5358 this._ = function ( sSelector, oOpts )
5359 {
5360 return this.api(true).rows( sSelector, oOpts ).data();
5361 };
5362
5363
5364 /**
5365 * Create a DataTables Api instance, with the currently selected tables for
5366 * the Api's context.
5367 * @param {boolean} [traditional=false] Set the API instance's context to be
5368 * only the table referred to by the `DataTable.ext.iApiIndex` option, as was
5369 * used in the API presented by DataTables 1.9- (i.e. the traditional mode),
5370 * or if all tables captured in the jQuery object should be used.
5371 * @return {DataTables.Api}
5372 */
5373 this.api = function ( traditional )
5374 {
5375 return traditional ?
5376 new _Api(
5377 _fnSettingsFromNode( this[ _ext.iApiIndex ] )
5378 ) :
5379 new _Api( this );
5380 };
5381
5382
5383 /**
5384 * Add a single new row or multiple rows of data to the table. Please note
5385 * that this is suitable for client-side processing only - if you are using
5386 * server-side processing (i.e. "bServerSide": true), then to add data, you
5387 * must add it to the data source, i.e. the server-side, through an Ajax call.
5388 * @param {array|object} data The data to be added to the table. This can be:
5389 * <ul>
5390 * <li>1D array of data - add a single row with the data provided</li>
5391 * <li>2D array of arrays - add multiple rows in a single call</li>
5392 * <li>object - data object when using <i>mData</i></li>
5393 * <li>array of objects - multiple data objects when using <i>mData</i></li>
5394 * </ul>
5395 * @param {bool} [redraw=true] redraw the table or not
5396 * @returns {array} An array of integers, representing the list of indexes in
5397 * <i>aoData</i> ({@link DataTable.models.oSettings}) that have been added to
5398 * the table.
5399 * @dtopt API
5400 * @deprecated Since v1.10
5401 *
5402 * @example
5403 * // Global var for counter
5404 * var giCount = 2;
5405 *
5406 * $(document).ready(function() {
5407 * $('#example').dataTable();
5408 * } );
5409 *
5410 * function fnClickAddRow() {
5411 * $('#example').dataTable().fnAddData( [
5412 * giCount+".1",
5413 * giCount+".2",
5414 * giCount+".3",
5415 * giCount+".4" ]
5416 * );
5417 *
5418 * giCount++;
5419 * }
5420 */
5421 this.fnAddData = function( data, redraw )
5422 {
5423 var api = this.api( true );
5424
5425 /* Check if we want to add multiple rows or not */
5426 var rows = $.isArray(data) && ( $.isArray(data[0]) || $.isPlainObject(data[0]) ) ?
5427 api.rows.add( data ) :
5428 api.row.add( data );
5429
5430 if ( redraw === undefined || redraw ) {
5431 api.draw();
5432 }
5433
5434 return rows.flatten().toArray();
5435 };
5436
5437
5438 /**
5439 * This function will make DataTables recalculate the column sizes, based on the data
5440 * contained in the table and the sizes applied to the columns (in the DOM, CSS or
5441 * through the sWidth parameter). This can be useful when the width of the table's
5442 * parent element changes (for example a window resize).
5443 * @param {boolean} [bRedraw=true] Redraw the table or not, you will typically want to
5444 * @dtopt API
5445 * @deprecated Since v1.10
5446 *
5447 * @example
5448 * $(document).ready(function() {
5449 * var oTable = $('#example').dataTable( {
5450 * "sScrollY": "200px",
5451 * "bPaginate": false
5452 * } );
5453 *
5454 * $(window).bind('resize', function () {
5455 * oTable.fnAdjustColumnSizing();
5456 * } );
5457 * } );
5458 */
5459 this.fnAdjustColumnSizing = function ( bRedraw )
5460 {
5461 var api = this.api( true ).columns.adjust();
5462 var settings = api.settings()[0];
5463 var scroll = settings.oScroll;
5464
5465 if ( bRedraw === undefined || bRedraw ) {
5466 api.draw( false );
5467 }
5468 else if ( scroll.sX !== "" || scroll.sY !== "" ) {
5469 /* If not redrawing, but scrolling, we want to apply the new column sizes anyway */
5470 _fnScrollDraw( settings );
5471 }
5472 };
5473
5474
5475 /**
5476 * Quickly and simply clear a table
5477 * @param {bool} [bRedraw=true] redraw the table or not
5478 * @dtopt API
5479 * @deprecated Since v1.10
5480 *
5481 * @example
5482 * $(document).ready(function() {
5483 * var oTable = $('#example').dataTable();
5484 *
5485 * // Immediately 'nuke' the current rows (perhaps waiting for an Ajax callback...)
5486 * oTable.fnClearTable();
5487 * } );
5488 */
5489 this.fnClearTable = function( bRedraw )
5490 {
5491 var api = this.api( true ).clear();
5492
5493 if ( bRedraw === undefined || bRedraw ) {
5494 api.draw();
5495 }
5496 };
5497
5498
5499 /**
5500 * The exact opposite of 'opening' a row, this function will close any rows which
5501 * are currently 'open'.
5502 * @param {node} nTr the table row to 'close'
5503 * @returns {int} 0 on success, or 1 if failed (can't find the row)
5504 * @dtopt API
5505 * @deprecated Since v1.10
5506 *
5507 * @example
5508 * $(document).ready(function() {
5509 * var oTable;
5510 *
5511 * // 'open' an information row when a row is clicked on
5512 * $('#example tbody tr').click( function () {
5513 * if ( oTable.fnIsOpen(this) ) {
5514 * oTable.fnClose( this );
5515 * } else {
5516 * oTable.fnOpen( this, "Temporary row opened", "info_row" );
5517 * }
5518 * } );
5519 *
5520 * oTable = $('#example').dataTable();
5521 * } );
5522 */
5523 this.fnClose = function( nTr )
5524 {
5525 this.api( true ).row( nTr ).child.hide();
5526 };
5527
5528
5529 /**
5530 * Remove a row for the table
5531 * @param {mixed} target The index of the row from aoData to be deleted, or
5532 * the TR element you want to delete
5533 * @param {function|null} [callBack] Callback function
5534 * @param {bool} [redraw=true] Redraw the table or not
5535 * @returns {array} The row that was deleted
5536 * @dtopt API
5537 * @deprecated Since v1.10
5538 *
5539 * @example
5540 * $(document).ready(function() {
5541 * var oTable = $('#example').dataTable();
5542 *
5543 * // Immediately remove the first row
5544 * oTable.fnDeleteRow( 0 );
5545 * } );
5546 */
5547 this.fnDeleteRow = function( target, callback, redraw )
5548 {
5549 var api = this.api( true );
5550 var rows = api.rows( target );
5551 var settings = rows.settings()[0];
5552 var data = settings.aoData[ rows[0][0] ];
5553
5554 rows.remove();
5555
5556 if ( callback ) {
5557 callback.call( this, settings, data );
5558 }
5559
5560 if ( redraw === undefined || redraw ) {
5561 api.draw();
5562 }
5563
5564 return data;
5565 };
5566
5567
5568 /**
5569 * Restore the table to it's original state in the DOM by removing all of DataTables
5570 * enhancements, alterations to the DOM structure of the table and event listeners.
5571 * @param {boolean} [remove=false] Completely remove the table from the DOM
5572 * @dtopt API
5573 * @deprecated Since v1.10
5574 *
5575 * @example
5576 * $(document).ready(function() {
5577 * // This example is fairly pointless in reality, but shows how fnDestroy can be used
5578 * var oTable = $('#example').dataTable();
5579 * oTable.fnDestroy();
5580 * } );
5581 */
5582 this.fnDestroy = function ( remove )
5583 {
5584 this.api( true ).destroy( remove );
5585 };
5586
5587
5588 /**
5589 * Redraw the table
5590 * @param {bool} [complete=true] Re-filter and resort (if enabled) the table before the draw.
5591 * @dtopt API
5592 * @deprecated Since v1.10
5593 *
5594 * @example
5595 * $(document).ready(function() {
5596 * var oTable = $('#example').dataTable();
5597 *
5598 * // Re-draw the table - you wouldn't want to do it here, but it's an example :-)
5599 * oTable.fnDraw();
5600 * } );
5601 */
5602 this.fnDraw = function( complete )
5603 {
5604 // Note that this isn't an exact match to the old call to _fnDraw - it takes
5605 // into account the new data, but can old position.
5606 this.api( true ).draw( ! complete );
5607 };
5608
5609
5610 /**
5611 * Filter the input based on data
5612 * @param {string} sInput String to filter the table on
5613 * @param {int|null} [iColumn] Column to limit filtering to
5614 * @param {bool} [bRegex=false] Treat as regular expression or not
5615 * @param {bool} [bSmart=true] Perform smart filtering or not
5616 * @param {bool} [bShowGlobal=true] Show the input global filter in it's input box(es)
5617 * @param {bool} [bCaseInsensitive=true] Do case-insensitive matching (true) or not (false)
5618 * @dtopt API
5619 * @deprecated Since v1.10
5620 *
5621 * @example
5622 * $(document).ready(function() {
5623 * var oTable = $('#example').dataTable();
5624 *
5625 * // Sometime later - filter...
5626 * oTable.fnFilter( 'test string' );
5627 * } );
5628 */
5629 this.fnFilter = function( sInput, iColumn, bRegex, bSmart, bShowGlobal, bCaseInsensitive )
5630 {
5631 var api = this.api( true );
5632
5633 if ( iColumn === null || iColumn === undefined ) {
5634 api.search( sInput, bRegex, bSmart, bCaseInsensitive );
5635 }
5636 else {
5637 api.column( iColumn ).search( sInput, bRegex, bSmart, bCaseInsensitive );
5638 }
5639
5640 api.draw();
5641 };
5642
5643
5644 /**
5645 * Get the data for the whole table, an individual row or an individual cell based on the
5646 * provided parameters.
5647 * @param {int|node} [src] A TR row node, TD/TH cell node or an integer. If given as
5648 * a TR node then the data source for the whole row will be returned. If given as a
5649 * TD/TH cell node then iCol will be automatically calculated and the data for the
5650 * cell returned. If given as an integer, then this is treated as the aoData internal
5651 * data index for the row (see fnGetPosition) and the data for that row used.
5652 * @param {int} [col] Optional column index that you want the data of.
5653 * @returns {array|object|string} If mRow is undefined, then the data for all rows is
5654 * returned. If mRow is defined, just data for that row, and is iCol is
5655 * defined, only data for the designated cell is returned.
5656 * @dtopt API
5657 * @deprecated Since v1.10
5658 *
5659 * @example
5660 * // Row data
5661 * $(document).ready(function() {
5662 * oTable = $('#example').dataTable();
5663 *
5664 * oTable.$('tr').click( function () {
5665 * var data = oTable.fnGetData( this );
5666 * // ... do something with the array / object of data for the row
5667 * } );
5668 * } );
5669 *
5670 * @example
5671 * // Individual cell data
5672 * $(document).ready(function() {
5673 * oTable = $('#example').dataTable();
5674 *
5675 * oTable.$('td').click( function () {
5676 * var sData = oTable.fnGetData( this );
5677 * alert( 'The cell clicked on had the value of '+sData );
5678 * } );
5679 * } );
5680 */
5681 this.fnGetData = function( src, col )
5682 {
5683 var api = this.api( true );
5684
5685 if ( src !== undefined ) {
5686 var type = src.nodeName ? src.nodeName.toLowerCase() : '';
5687
5688 return col !== undefined || type == 'td' || type == 'th' ?
5689 api.cell( src, col ).data() :
5690 api.row( src ).data() || null;
5691 }
5692
5693 return api.data().toArray();
5694 };
5695
5696
5697 /**
5698 * Get an array of the TR nodes that are used in the table's body. Note that you will
5699 * typically want to use the '$' API method in preference to this as it is more
5700 * flexible.
5701 * @param {int} [iRow] Optional row index for the TR element you want
5702 * @returns {array|node} If iRow is undefined, returns an array of all TR elements
5703 * in the table's body, or iRow is defined, just the TR element requested.
5704 * @dtopt API
5705 * @deprecated Since v1.10
5706 *
5707 * @example
5708 * $(document).ready(function() {
5709 * var oTable = $('#example').dataTable();
5710 *
5711 * // Get the nodes from the table
5712 * var nNodes = oTable.fnGetNodes( );
5713 * } );
5714 */
5715 this.fnGetNodes = function( iRow )
5716 {
5717 var api = this.api( true );
5718
5719 return iRow !== undefined ?
5720 api.row( iRow ).node() :
5721 api.rows().nodes().flatten().toArray();
5722 };
5723
5724
5725 /**
5726 * Get the array indexes of a particular cell from it's DOM element
5727 * and column index including hidden columns
5728 * @param {node} node this can either be a TR, TD or TH in the table's body
5729 * @returns {int} If nNode is given as a TR, then a single index is returned, or
5730 * if given as a cell, an array of [row index, column index (visible),
5731 * column index (all)] is given.
5732 * @dtopt API
5733 * @deprecated Since v1.10
5734 *
5735 * @example
5736 * $(document).ready(function() {
5737 * $('#example tbody td').click( function () {
5738 * // Get the position of the current data from the node
5739 * var aPos = oTable.fnGetPosition( this );
5740 *
5741 * // Get the data array for this row
5742 * var aData = oTable.fnGetData( aPos[0] );
5743 *
5744 * // Update the data array and return the value
5745 * aData[ aPos[1] ] = 'clicked';
5746 * this.innerHTML = 'clicked';
5747 * } );
5748 *
5749 * // Init DataTables
5750 * oTable = $('#example').dataTable();
5751 * } );
5752 */
5753 this.fnGetPosition = function( node )
5754 {
5755 var api = this.api( true );
5756 var nodeName = node.nodeName.toUpperCase();
5757
5758 if ( nodeName == 'TR' ) {
5759 return api.row( node ).index();
5760 }
5761 else if ( nodeName == 'TD' || nodeName == 'TH' ) {
5762 var cell = api.cell( node ).index();
5763
5764 return [
5765 cell.row,
5766 cell.columnVisible,
5767 cell.column
5768 ];
5769 }
5770 return null;
5771 };
5772
5773
5774 /**
5775 * Check to see if a row is 'open' or not.
5776 * @param {node} nTr the table row to check
5777 * @returns {boolean} true if the row is currently open, false otherwise
5778 * @dtopt API
5779 * @deprecated Since v1.10
5780 *
5781 * @example
5782 * $(document).ready(function() {
5783 * var oTable;
5784 *
5785 * // 'open' an information row when a row is clicked on
5786 * $('#example tbody tr').click( function () {
5787 * if ( oTable.fnIsOpen(this) ) {
5788 * oTable.fnClose( this );
5789 * } else {
5790 * oTable.fnOpen( this, "Temporary row opened", "info_row" );
5791 * }
5792 * } );
5793 *
5794 * oTable = $('#example').dataTable();
5795 * } );
5796 */
5797 this.fnIsOpen = function( nTr )
5798 {
5799 return this.api( true ).row( nTr ).child.isShown();
5800 };
5801
5802
5803 /**
5804 * This function will place a new row directly after a row which is currently
5805 * on display on the page, with the HTML contents that is passed into the
5806 * function. This can be used, for example, to ask for confirmation that a
5807 * particular record should be deleted.
5808 * @param {node} nTr The table row to 'open'
5809 * @param {string|node|jQuery} mHtml The HTML to put into the row
5810 * @param {string} sClass Class to give the new TD cell
5811 * @returns {node} The row opened. Note that if the table row passed in as the
5812 * first parameter, is not found in the table, this method will silently
5813 * return.
5814 * @dtopt API
5815 * @deprecated Since v1.10
5816 *
5817 * @example
5818 * $(document).ready(function() {
5819 * var oTable;
5820 *
5821 * // 'open' an information row when a row is clicked on
5822 * $('#example tbody tr').click( function () {
5823 * if ( oTable.fnIsOpen(this) ) {
5824 * oTable.fnClose( this );
5825 * } else {
5826 * oTable.fnOpen( this, "Temporary row opened", "info_row" );
5827 * }
5828 * } );
5829 *
5830 * oTable = $('#example').dataTable();
5831 * } );
5832 */
5833 this.fnOpen = function( nTr, mHtml, sClass )
5834 {
5835 return this.api( true )
5836 .row( nTr )
5837 .child( mHtml, sClass )
5838 .show()
5839 .child()[0];
5840 };
5841
5842
5843 /**
5844 * Change the pagination - provides the internal logic for pagination in a simple API
5845 * function. With this function you can have a DataTables table go to the next,
5846 * previous, first or last pages.
5847 * @param {string|int} mAction Paging action to take: "first", "previous", "next" or "last"
5848 * or page number to jump to (integer), note that page 0 is the first page.
5849 * @param {bool} [bRedraw=true] Redraw the table or not
5850 * @dtopt API
5851 * @deprecated Since v1.10
5852 *
5853 * @example
5854 * $(document).ready(function() {
5855 * var oTable = $('#example').dataTable();
5856 * oTable.fnPageChange( 'next' );
5857 * } );
5858 */
5859 this.fnPageChange = function ( mAction, bRedraw )
5860 {
5861 var api = this.api( true ).page( mAction );
5862
5863 if ( bRedraw === undefined || bRedraw ) {
5864 api.draw(false);
5865 }
5866 };
5867
5868
5869 /**
5870 * Show a particular column
5871 * @param {int} iCol The column whose display should be changed
5872 * @param {bool} bShow Show (true) or hide (false) the column
5873 * @param {bool} [bRedraw=true] Redraw the table or not
5874 * @dtopt API
5875 * @deprecated Since v1.10
5876 *
5877 * @example
5878 * $(document).ready(function() {
5879 * var oTable = $('#example').dataTable();
5880 *
5881 * // Hide the second column after initialisation
5882 * oTable.fnSetColumnVis( 1, false );
5883 * } );
5884 */
5885 this.fnSetColumnVis = function ( iCol, bShow, bRedraw )
5886 {
5887 var api = this.api( true ).column( iCol ).visible( bShow );
5888
5889 if ( bRedraw === undefined || bRedraw ) {
5890 api.columns.adjust().draw();
5891 }
5892 };
5893
5894
5895 /**
5896 * Get the settings for a particular table for external manipulation
5897 * @returns {object} DataTables settings object. See
5898 * {@link DataTable.models.oSettings}
5899 * @dtopt API
5900 * @deprecated Since v1.10
5901 *
5902 * @example
5903 * $(document).ready(function() {
5904 * var oTable = $('#example').dataTable();
5905 * var oSettings = oTable.fnSettings();
5906 *
5907 * // Show an example parameter from the settings
5908 * alert( oSettings._iDisplayStart );
5909 * } );
5910 */
5911 this.fnSettings = function()
5912 {
5913 return _fnSettingsFromNode( this[_ext.iApiIndex] );
5914 };
5915
5916
5917 /**
5918 * Sort the table by a particular column
5919 * @param {int} iCol the data index to sort on. Note that this will not match the
5920 * 'display index' if you have hidden data entries
5921 * @dtopt API
5922 * @deprecated Since v1.10
5923 *
5924 * @example
5925 * $(document).ready(function() {
5926 * var oTable = $('#example').dataTable();
5927 *
5928 * // Sort immediately with columns 0 and 1
5929 * oTable.fnSort( [ [0,'asc'], [1,'asc'] ] );
5930 * } );
5931 */
5932 this.fnSort = function( aaSort )
5933 {
5934 this.api( true ).order( aaSort ).draw();
5935 };
5936
5937
5938 /**
5939 * Attach a sort listener to an element for a given column
5940 * @param {node} nNode the element to attach the sort listener to
5941 * @param {int} iColumn the column that a click on this node will sort on
5942 * @param {function} [fnCallback] callback function when sort is run
5943 * @dtopt API
5944 * @deprecated Since v1.10
5945 *
5946 * @example
5947 * $(document).ready(function() {
5948 * var oTable = $('#example').dataTable();
5949 *
5950 * // Sort on column 1, when 'sorter' is clicked on
5951 * oTable.fnSortListener( document.getElementById('sorter'), 1 );
5952 * } );
5953 */
5954 this.fnSortListener = function( nNode, iColumn, fnCallback )
5955 {
5956 this.api( true ).order.listener( nNode, iColumn, fnCallback );
5957 };
5958
5959
5960 /**
5961 * Update a table cell or row - this method will accept either a single value to
5962 * update the cell with, an array of values with one element for each column or
5963 * an object in the same format as the original data source. The function is
5964 * self-referencing in order to make the multi column updates easier.
5965 * @param {object|array|string} mData Data to update the cell/row with
5966 * @param {node|int} mRow TR element you want to update or the aoData index
5967 * @param {int} [iColumn] The column to update, give as null or undefined to
5968 * update a whole row.
5969 * @param {bool} [bRedraw=true] Redraw the table or not
5970 * @param {bool} [bAction=true] Perform pre-draw actions or not
5971 * @returns {int} 0 on success, 1 on error
5972 * @dtopt API
5973 * @deprecated Since v1.10
5974 *
5975 * @example
5976 * $(document).ready(function() {
5977 * var oTable = $('#example').dataTable();
5978 * oTable.fnUpdate( 'Example update', 0, 0 ); // Single cell
5979 * oTable.fnUpdate( ['a', 'b', 'c', 'd', 'e'], $('tbody tr')[0] ); // Row
5980 * } );
5981 */
5982 this.fnUpdate = function( mData, mRow, iColumn, bRedraw, bAction )
5983 {
5984 var api = this.api( true );
5985
5986 if ( iColumn === undefined || iColumn === null ) {
5987 api.row( mRow ).data( mData );
5988 }
5989 else {
5990 api.cell( mRow, iColumn ).data( mData );
5991 }
5992
5993 if ( bAction === undefined || bAction ) {
5994 api.columns.adjust();
5995 }
5996
5997 if ( bRedraw === undefined || bRedraw ) {
5998 api.draw();
5999 }
6000 return 0;
6001 };
6002
6003
6004 /**
6005 * Provide a common method for plug-ins to check the version of DataTables being used, in order
6006 * to ensure compatibility.
6007 * @param {string} sVersion Version string to check for, in the format "X.Y.Z". Note that the
6008 * formats "X" and "X.Y" are also acceptable.
6009 * @returns {boolean} true if this version of DataTables is greater or equal to the required
6010 * version, or false if this version of DataTales is not suitable
6011 * @method
6012 * @dtopt API
6013 * @deprecated Since v1.10
6014 *
6015 * @example
6016 * $(document).ready(function() {
6017 * var oTable = $('#example').dataTable();
6018 * alert( oTable.fnVersionCheck( '1.9.0' ) );
6019 * } );
6020 */
6021 this.fnVersionCheck = _ext.fnVersionCheck;
6022
6023
6024 var _that = this;
6025 var emptyInit = options === undefined;
6026 var len = this.length;
6027
6028 if ( emptyInit ) {
6029 options = {};
6030 }
6031
6032 this.oApi = this.internal = _ext.internal;
6033
6034 // Extend with old style plug-in API methods
6035 for ( var fn in DataTable.ext.internal ) {
6036 if ( fn ) {
6037 this[fn] = _fnExternApiFunc(fn);
6038 }
6039 }
6040
6041 this.each(function() {
6042 // For each initialisation we want to give it a clean initialisation
6043 // object that can be bashed around
6044 var o = {};
6045 var oInit = len > 1 ? // optimisation for single table case
6046 _fnExtend( o, options, true ) :
6047 options;
6048
6049 /*global oInit,_that,emptyInit*/
6050 var i=0, iLen, j, jLen, k, kLen;
6051 var sId = this.getAttribute( 'id' );
6052 var bInitHandedOff = false;
6053 var defaults = DataTable.defaults;
6054
6055
6056 /* Sanity check */
6057 if ( this.nodeName.toLowerCase() != 'table' )
6058 {
6059 _fnLog( null, 0, 'Non-table node initialisation ('+this.nodeName+')', 2 );
6060 return;
6061 }
6062
6063 /* Backwards compatibility for the defaults */
6064 _fnCompatOpts( defaults );
6065 _fnCompatCols( defaults.column );
6066
6067 /* Convert the camel-case defaults to Hungarian */
6068 _fnCamelToHungarian( defaults, defaults, true );
6069 _fnCamelToHungarian( defaults.column, defaults.column, true );
6070
6071 /* Setting up the initialisation object */
6072 _fnCamelToHungarian( defaults, oInit );
6073
6074 /* Check to see if we are re-initialising a table */
6075 var allSettings = DataTable.settings;
6076 for ( i=0, iLen=allSettings.length ; i<iLen ; i++ )
6077 {
6078 /* Base check on table node */
6079 if ( allSettings[i].nTable == this )
6080 {
6081 var bRetrieve = oInit.bRetrieve !== undefined ? oInit.bRetrieve : defaults.bRetrieve;
6082 var bDestroy = oInit.bDestroy !== undefined ? oInit.bDestroy : defaults.bDestroy;
6083
6084 if ( emptyInit || bRetrieve )
6085 {
6086 return allSettings[i].oInstance;
6087 }
6088 else if ( bDestroy )
6089 {
6090 allSettings[i].oInstance.fnDestroy();
6091 break;
6092 }
6093 else
6094 {
6095 _fnLog( allSettings[i], 0, 'Cannot reinitialise DataTable', 3 );
6096 return;
6097 }
6098 }
6099
6100 /* If the element we are initialising has the same ID as a table which was previously
6101 * initialised, but the table nodes don't match (from before) then we destroy the old
6102 * instance by simply deleting it. This is under the assumption that the table has been
6103 * destroyed by other methods. Anyone using non-id selectors will need to do this manually
6104 */
6105 if ( allSettings[i].sTableId == this.id )
6106 {
6107 allSettings.splice( i, 1 );
6108 break;
6109 }
6110 }
6111
6112 /* Ensure the table has an ID - required for accessibility */
6113 if ( sId === null || sId === "" )
6114 {
6115 sId = "DataTables_Table_"+(DataTable.ext._unique++);
6116 this.id = sId;
6117 }
6118
6119 /* Create the settings object for this table and set some of the default parameters */
6120 var oSettings = $.extend( true, {}, DataTable.models.oSettings, {
6121 "nTable": this,
6122 "oApi": _that.internal,
6123 "oInit": oInit,
6124 "sDestroyWidth": $(this)[0].style.width,
6125 "sInstance": sId,
6126 "sTableId": sId
6127 } );
6128 allSettings.push( oSettings );
6129
6130 // Need to add the instance after the instance after the settings object has been added
6131 // to the settings array, so we can self reference the table instance if more than one
6132 oSettings.oInstance = (_that.length===1) ? _that : $(this).dataTable();
6133
6134 // Backwards compatibility, before we apply all the defaults
6135 _fnCompatOpts( oInit );
6136
6137 if ( oInit.oLanguage )
6138 {
6139 _fnLanguageCompat( oInit.oLanguage );
6140 }
6141
6142 // If the length menu is given, but the init display length is not, use the length menu
6143 if ( oInit.aLengthMenu && ! oInit.iDisplayLength )
6144 {
6145 oInit.iDisplayLength = $.isArray( oInit.aLengthMenu[0] ) ?
6146 oInit.aLengthMenu[0][0] : oInit.aLengthMenu[0];
6147 }
6148
6149 // Apply the defaults and init options to make a single init object will all
6150 // options defined from defaults and instance options.
6151 oInit = _fnExtend( $.extend( true, {}, defaults ), oInit );
6152
6153
6154 // Map the initialisation options onto the settings object
6155 _fnMap( oSettings.oFeatures, oInit, [
6156 "bPaginate",
6157 "bLengthChange",
6158 "bFilter",
6159 "bSort",
6160 "bSortMulti",
6161 "bInfo",
6162 "bProcessing",
6163 "bAutoWidth",
6164 "bSortClasses",
6165 "bServerSide",
6166 "bDeferRender"
6167 ] );
6168 _fnMap( oSettings, oInit, [
6169 "asStripeClasses",
6170 "ajax",
6171 "fnServerData",
6172 "fnFormatNumber",
6173 "sServerMethod",
6174 "aaSorting",
6175 "aaSortingFixed",
6176 "aLengthMenu",
6177 "sPaginationType",
6178 "sAjaxSource",
6179 "sAjaxDataProp",
6180 "iStateDuration",
6181 "sDom",
6182 "bSortCellsTop",
6183 "iTabIndex",
6184 "fnStateLoadCallback",
6185 "fnStateSaveCallback",
6186 "renderer",
6187 "searchDelay",
6188 [ "iCookieDuration", "iStateDuration" ], // backwards compat
6189 [ "oSearch", "oPreviousSearch" ],
6190 [ "aoSearchCols", "aoPreSearchCols" ],
6191 [ "iDisplayLength", "_iDisplayLength" ],
6192 [ "bJQueryUI", "bJUI" ]
6193 ] );
6194 _fnMap( oSettings.oScroll, oInit, [
6195 [ "sScrollX", "sX" ],
6196 [ "sScrollXInner", "sXInner" ],
6197 [ "sScrollY", "sY" ],
6198 [ "bScrollCollapse", "bCollapse" ]
6199 ] );
6200 _fnMap( oSettings.oLanguage, oInit, "fnInfoCallback" );
6201
6202 /* Callback functions which are array driven */
6203 _fnCallbackReg( oSettings, 'aoDrawCallback', oInit.fnDrawCallback, 'user' );
6204 _fnCallbackReg( oSettings, 'aoServerParams', oInit.fnServerParams, 'user' );
6205 _fnCallbackReg( oSettings, 'aoStateSaveParams', oInit.fnStateSaveParams, 'user' );
6206 _fnCallbackReg( oSettings, 'aoStateLoadParams', oInit.fnStateLoadParams, 'user' );
6207 _fnCallbackReg( oSettings, 'aoStateLoaded', oInit.fnStateLoaded, 'user' );
6208 _fnCallbackReg( oSettings, 'aoRowCallback', oInit.fnRowCallback, 'user' );
6209 _fnCallbackReg( oSettings, 'aoRowCreatedCallback', oInit.fnCreatedRow, 'user' );
6210 _fnCallbackReg( oSettings, 'aoHeaderCallback', oInit.fnHeaderCallback, 'user' );
6211 _fnCallbackReg( oSettings, 'aoFooterCallback', oInit.fnFooterCallback, 'user' );
6212 _fnCallbackReg( oSettings, 'aoInitComplete', oInit.fnInitComplete, 'user' );
6213 _fnCallbackReg( oSettings, 'aoPreDrawCallback', oInit.fnPreDrawCallback, 'user' );
6214
6215 var oClasses = oSettings.oClasses;
6216
6217 // @todo Remove in 1.11
6218 if ( oInit.bJQueryUI )
6219 {
6220 /* Use the JUI classes object for display. You could clone the oStdClasses object if
6221 * you want to have multiple tables with multiple independent classes
6222 */
6223 $.extend( oClasses, DataTable.ext.oJUIClasses, oInit.oClasses );
6224
6225 if ( oInit.sDom === defaults.sDom && defaults.sDom === "lfrtip" )
6226 {
6227 /* Set the DOM to use a layout suitable for jQuery UI's theming */
6228 oSettings.sDom = '<"H"lfr>t<"F"ip>';
6229 }
6230
6231 if ( ! oSettings.renderer ) {
6232 oSettings.renderer = 'jqueryui';
6233 }
6234 else if ( $.isPlainObject( oSettings.renderer ) && ! oSettings.renderer.header ) {
6235 oSettings.renderer.header = 'jqueryui';
6236 }
6237 }
6238 else
6239 {
6240 $.extend( oClasses, DataTable.ext.classes, oInit.oClasses );
6241 }
6242 $(this).addClass( oClasses.sTable );
6243
6244 /* Calculate the scroll bar width and cache it for use later on */
6245 if ( oSettings.oScroll.sX !== "" || oSettings.oScroll.sY !== "" )
6246 {
6247 oSettings.oScroll.iBarWidth = _fnScrollBarWidth();
6248 }
6249 if ( oSettings.oScroll.sX === true ) { // Easy initialisation of x-scrolling
6250 oSettings.oScroll.sX = '100%';
6251 }
6252
6253 if ( oSettings.iInitDisplayStart === undefined )
6254 {
6255 /* Display start point, taking into account the save saving */
6256 oSettings.iInitDisplayStart = oInit.iDisplayStart;
6257 oSettings._iDisplayStart = oInit.iDisplayStart;
6258 }
6259
6260 if ( oInit.iDeferLoading !== null )
6261 {
6262 oSettings.bDeferLoading = true;
6263 var tmp = $.isArray( oInit.iDeferLoading );
6264 oSettings._iRecordsDisplay = tmp ? oInit.iDeferLoading[0] : oInit.iDeferLoading;
6265 oSettings._iRecordsTotal = tmp ? oInit.iDeferLoading[1] : oInit.iDeferLoading;
6266 }
6267
6268 /* Language definitions */
6269 var oLanguage = oSettings.oLanguage;
6270 $.extend( true, oLanguage, oInit.oLanguage );
6271
6272 if ( oLanguage.sUrl !== "" )
6273 {
6274 /* Get the language definitions from a file - because this Ajax call makes the language
6275 * get async to the remainder of this function we use bInitHandedOff to indicate that
6276 * _fnInitialise will be fired by the returned Ajax handler, rather than the constructor
6277 */
6278 $.ajax( {
6279 dataType: 'json',
6280 url: oLanguage.sUrl,
6281 success: function ( json ) {
6282 _fnLanguageCompat( json );
6283 _fnCamelToHungarian( defaults.oLanguage, json );
6284 $.extend( true, oLanguage, json );
6285 _fnInitialise( oSettings );
6286 },
6287 error: function () {
6288 // Error occurred loading language file, continue on as best we can
6289 _fnInitialise( oSettings );
6290 }
6291 } );
6292 bInitHandedOff = true;
6293 }
6294
6295 /*
6296 * Stripes
6297 */
6298 if ( oInit.asStripeClasses === null )
6299 {
6300 oSettings.asStripeClasses =[
6301 oClasses.sStripeOdd,
6302 oClasses.sStripeEven
6303 ];
6304 }
6305
6306 /* Remove row stripe classes if they are already on the table row */
6307 var stripeClasses = oSettings.asStripeClasses;
6308 var rowOne = $('tbody tr:eq(0)', this);
6309 if ( $.inArray( true, $.map( stripeClasses, function(el, i) {
6310 return rowOne.hasClass(el);
6311 } ) ) !== -1 ) {
6312 $('tbody tr', this).removeClass( stripeClasses.join(' ') );
6313 oSettings.asDestroyStripes = stripeClasses.slice();
6314 }
6315
6316 /*
6317 * Columns
6318 * See if we should load columns automatically or use defined ones
6319 */
6320 var anThs = [];
6321 var aoColumnsInit;
6322 var nThead = this.getElementsByTagName('thead');
6323 if ( nThead.length !== 0 )
6324 {
6325 _fnDetectHeader( oSettings.aoHeader, nThead[0] );
6326 anThs = _fnGetUniqueThs( oSettings );
6327 }
6328
6329 /* If not given a column array, generate one with nulls */
6330 if ( oInit.aoColumns === null )
6331 {
6332 aoColumnsInit = [];
6333 for ( i=0, iLen=anThs.length ; i<iLen ; i++ )
6334 {
6335 aoColumnsInit.push( null );
6336 }
6337 }
6338 else
6339 {
6340 aoColumnsInit = oInit.aoColumns;
6341 }
6342
6343 /* Add the columns */
6344 for ( i=0, iLen=aoColumnsInit.length ; i<iLen ; i++ )
6345 {
6346 _fnAddColumn( oSettings, anThs ? anThs[i] : null );
6347 }
6348
6349 /* Apply the column definitions */
6350 _fnApplyColumnDefs( oSettings, oInit.aoColumnDefs, aoColumnsInit, function (iCol, oDef) {
6351 _fnColumnOptions( oSettings, iCol, oDef );
6352 } );
6353
6354 /* HTML5 attribute detection - build an mData object automatically if the
6355 * attributes are found
6356 */
6357 if ( rowOne.length ) {
6358 var a = function ( cell, name ) {
6359 return cell.getAttribute( 'data-'+name ) ? name : null;
6360 };
6361
6362 $.each( _fnGetRowElements( oSettings, rowOne[0] ).cells, function (i, cell) {
6363 var col = oSettings.aoColumns[i];
6364
6365 if ( col.mData === i ) {
6366 var sort = a( cell, 'sort' ) || a( cell, 'order' );
6367 var filter = a( cell, 'filter' ) || a( cell, 'search' );
6368
6369 if ( sort !== null || filter !== null ) {
6370 col.mData = {
6371 _: i+'.display',
6372 sort: sort !== null ? i+'.@data-'+sort : undefined,
6373 type: sort !== null ? i+'.@data-'+sort : undefined,
6374 filter: filter !== null ? i+'.@data-'+filter : undefined
6375 };
6376
6377 _fnColumnOptions( oSettings, i );
6378 }
6379 }
6380 } );
6381 }
6382
6383 var features = oSettings.oFeatures;
6384
6385 /* Must be done after everything which can be overridden by the state saving! */
6386 if ( oInit.bStateSave )
6387 {
6388 features.bStateSave = true;
6389 _fnLoadState( oSettings, oInit );
6390 _fnCallbackReg( oSettings, 'aoDrawCallback', _fnSaveState, 'state_save' );
6391 }
6392
6393
6394 /*
6395 * Sorting
6396 * @todo For modularisation (1.11) this needs to do into a sort start up handler
6397 */
6398
6399 // If aaSorting is not defined, then we use the first indicator in asSorting
6400 // in case that has been altered, so the default sort reflects that option
6401 if ( oInit.aaSorting === undefined )
6402 {
6403 var sorting = oSettings.aaSorting;
6404 for ( i=0, iLen=sorting.length ; i<iLen ; i++ )
6405 {
6406 sorting[i][1] = oSettings.aoColumns[ i ].asSorting[0];
6407 }
6408 }
6409
6410 /* Do a first pass on the sorting classes (allows any size changes to be taken into
6411 * account, and also will apply sorting disabled classes if disabled
6412 */
6413 _fnSortingClasses( oSettings );
6414
6415 if ( features.bSort )
6416 {
6417 _fnCallbackReg( oSettings, 'aoDrawCallback', function () {
6418 if ( oSettings.bSorted ) {
6419 var aSort = _fnSortFlatten( oSettings );
6420 var sortedColumns = {};
6421
6422 $.each( aSort, function (i, val) {
6423 sortedColumns[ val.src ] = val.dir;
6424 } );
6425
6426 _fnCallbackFire( oSettings, null, 'order', [oSettings, aSort, sortedColumns] );
6427 _fnSortAria( oSettings );
6428 }
6429 } );
6430 }
6431
6432 _fnCallbackReg( oSettings, 'aoDrawCallback', function () {
6433 if ( oSettings.bSorted || _fnDataSource( oSettings ) === 'ssp' || features.bDeferRender ) {
6434 _fnSortingClasses( oSettings );
6435 }
6436 }, 'sc' );
6437
6438
6439 /*
6440 * Final init
6441 * Cache the header, body and footer as required, creating them if needed
6442 */
6443
6444 /* Browser support detection */
6445 _fnBrowserDetect( oSettings );
6446
6447 // Work around for Webkit bug 83867 - store the caption-side before removing from doc
6448 var captions = $(this).children('caption').each( function () {
6449 this._captionSide = $(this).css('caption-side');
6450 } );
6451
6452 var thead = $(this).children('thead');
6453 if ( thead.length === 0 )
6454 {
6455 thead = $('<thead/>').appendTo(this);
6456 }
6457 oSettings.nTHead = thead[0];
6458
6459 var tbody = $(this).children('tbody');
6460 if ( tbody.length === 0 )
6461 {
6462 tbody = $('<tbody/>').appendTo(this);
6463 }
6464 oSettings.nTBody = tbody[0];
6465
6466 var tfoot = $(this).children('tfoot');
6467 if ( tfoot.length === 0 && captions.length > 0 && (oSettings.oScroll.sX !== "" || oSettings.oScroll.sY !== "") )
6468 {
6469 // If we are a scrolling table, and no footer has been given, then we need to create
6470 // a tfoot element for the caption element to be appended to
6471 tfoot = $('<tfoot/>').appendTo(this);
6472 }
6473
6474 if ( tfoot.length === 0 || tfoot.children().length === 0 ) {
6475 $(this).addClass( oClasses.sNoFooter );
6476 }
6477 else if ( tfoot.length > 0 ) {
6478 oSettings.nTFoot = tfoot[0];
6479 _fnDetectHeader( oSettings.aoFooter, oSettings.nTFoot );
6480 }
6481
6482 /* Check if there is data passing into the constructor */
6483 if ( oInit.aaData )
6484 {
6485 for ( i=0 ; i<oInit.aaData.length ; i++ )
6486 {
6487 _fnAddData( oSettings, oInit.aaData[ i ] );
6488 }
6489 }
6490 else if ( oSettings.bDeferLoading || _fnDataSource( oSettings ) == 'dom' )
6491 {
6492 /* Grab the data from the page - only do this when deferred loading or no Ajax
6493 * source since there is no point in reading the DOM data if we are then going
6494 * to replace it with Ajax data
6495 */
6496 _fnAddTr( oSettings, $(oSettings.nTBody).children('tr') );
6497 }
6498
6499 /* Copy the data index array */
6500 oSettings.aiDisplay = oSettings.aiDisplayMaster.slice();
6501
6502 /* Initialisation complete - table can be drawn */
6503 oSettings.bInitialised = true;
6504
6505 /* Check if we need to initialise the table (it might not have been handed off to the
6506 * language processor)
6507 */
6508 if ( bInitHandedOff === false )
6509 {
6510 _fnInitialise( oSettings );
6511 }
6512 } );
6513 _that = null;
6514 return this;
6515 };
6516
6517
6518
6519 /**
6520 * Computed structure of the DataTables API, defined by the options passed to
6521 * `DataTable.Api.register()` when building the API.
6522 *
6523 * The structure is built in order to speed creation and extension of the Api
6524 * objects since the extensions are effectively pre-parsed.
6525 *
6526 * The array is an array of objects with the following structure, where this
6527 * base array represents the Api prototype base:
6528 *
6529 * [
6530 * {
6531 * name: 'data' -- string - Property name
6532 * val: function () {}, -- function - Api method (or undefined if just an object
6533 * methodExt: [ ... ], -- array - Array of Api object definitions to extend the method result
6534 * propExt: [ ... ] -- array - Array of Api object definitions to extend the property
6535 * },
6536 * {
6537 * name: 'row'
6538 * val: {},
6539 * methodExt: [ ... ],
6540 * propExt: [
6541 * {
6542 * name: 'data'
6543 * val: function () {},
6544 * methodExt: [ ... ],
6545 * propExt: [ ... ]
6546 * },
6547 * ...
6548 * ]
6549 * }
6550 * ]
6551 *
6552 * @type {Array}
6553 * @ignore
6554 */
6555 var __apiStruct = [];
6556
6557
6558 /**
6559 * `Array.prototype` reference.
6560 *
6561 * @type object
6562 * @ignore
6563 */
6564 var __arrayProto = Array.prototype;
6565
6566
6567 /**
6568 * Abstraction for `context` parameter of the `Api` constructor to allow it to
6569 * take several different forms for ease of use.
6570 *
6571 * Each of the input parameter types will be converted to a DataTables settings
6572 * object where possible.
6573 *
6574 * @param {string|node|jQuery|object} mixed DataTable identifier. Can be one
6575 * of:
6576 *
6577 * * `string` - jQuery selector. Any DataTables' matching the given selector
6578 * with be found and used.
6579 * * `node` - `TABLE` node which has already been formed into a DataTable.
6580 * * `jQuery` - A jQuery object of `TABLE` nodes.
6581 * * `object` - DataTables settings object
6582 * * `DataTables.Api` - API instance
6583 * @return {array|null} Matching DataTables settings objects. `null` or
6584 * `undefined` is returned if no matching DataTable is found.
6585 * @ignore
6586 */
6587 var _toSettings = function ( mixed )
6588 {
6589 var idx, jq;
6590 var settings = DataTable.settings;
6591 var tables = $.map( settings, function (el, i) {
6592 return el.nTable;
6593 } );
6594
6595 if ( ! mixed ) {
6596 return [];
6597 }
6598 else if ( mixed.nTable && mixed.oApi ) {
6599 // DataTables settings object
6600 return [ mixed ];
6601 }
6602 else if ( mixed.nodeName && mixed.nodeName.toLowerCase() === 'table' ) {
6603 // Table node
6604 idx = $.inArray( mixed, tables );
6605 return idx !== -1 ? [ settings[idx] ] : null;
6606 }
6607 else if ( mixed && typeof mixed.settings === 'function' ) {
6608 return mixed.settings().toArray();
6609 }
6610 else if ( typeof mixed === 'string' ) {
6611 // jQuery selector
6612 jq = $(mixed);
6613 }
6614 else if ( mixed instanceof $ ) {
6615 // jQuery object (also DataTables instance)
6616 jq = mixed;
6617 }
6618
6619 if ( jq ) {
6620 return jq.map( function(i) {
6621 idx = $.inArray( this, tables );
6622 return idx !== -1 ? settings[idx] : null;
6623 } ).toArray();
6624 }
6625 };
6626
6627
6628 /**
6629 * DataTables API class - used to control and interface with one or more
6630 * DataTables enhanced tables.
6631 *
6632 * The API class is heavily based on jQuery, presenting a chainable interface
6633 * that you can use to interact with tables. Each instance of the API class has
6634 * a "context" - i.e. the tables that it will operate on. This could be a single
6635 * table, all tables on a page or a sub-set thereof.
6636 *
6637 * Additionally the API is designed to allow you to easily work with the data in
6638 * the tables, retrieving and manipulating it as required. This is done by
6639 * presenting the API class as an array like interface. The contents of the
6640 * array depend upon the actions requested by each method (for example
6641 * `rows().nodes()` will return an array of nodes, while `rows().data()` will
6642 * return an array of objects or arrays depending upon your table's
6643 * configuration). The API object has a number of array like methods (`push`,
6644 * `pop`, `reverse` etc) as well as additional helper methods (`each`, `pluck`,
6645 * `unique` etc) to assist your working with the data held in a table.
6646 *
6647 * Most methods (those which return an Api instance) are chainable, which means
6648 * the return from a method call also has all of the methods available that the
6649 * top level object had. For example, these two calls are equivalent:
6650 *
6651 * // Not chained
6652 * api.row.add( {...} );
6653 * api.draw();
6654 *
6655 * // Chained
6656 * api.row.add( {...} ).draw();
6657 *
6658 * @class DataTable.Api
6659 * @param {array|object|string|jQuery} context DataTable identifier. This is
6660 * used to define which DataTables enhanced tables this API will operate on.
6661 * Can be one of:
6662 *
6663 * * `string` - jQuery selector. Any DataTables' matching the given selector
6664 * with be found and used.
6665 * * `node` - `TABLE` node which has already been formed into a DataTable.
6666 * * `jQuery` - A jQuery object of `TABLE` nodes.
6667 * * `object` - DataTables settings object
6668 * @param {array} [data] Data to initialise the Api instance with.
6669 *
6670 * @example
6671 * // Direct initialisation during DataTables construction
6672 * var api = $('#example').DataTable();
6673 *
6674 * @example
6675 * // Initialisation using a DataTables jQuery object
6676 * var api = $('#example').dataTable().api();
6677 *
6678 * @example
6679 * // Initialisation as a constructor
6680 * var api = new $.fn.DataTable.Api( 'table.dataTable' );
6681 */
6682 _Api = function ( context, data )
6683 {
6684 if ( ! this instanceof _Api ) {
6685 throw 'DT API must be constructed as a new object';
6686 // or should it do the 'new' for the caller?
6687 // return new _Api.apply( this, arguments );
6688 }
6689
6690 var settings = [];
6691 var ctxSettings = function ( o ) {
6692 var a = _toSettings( o );
6693 if ( a ) {
6694 settings.push.apply( settings, a );
6695 }
6696 };
6697
6698 if ( $.isArray( context ) ) {
6699 for ( var i=0, ien=context.length ; i<ien ; i++ ) {
6700 ctxSettings( context[i] );
6701 }
6702 }
6703 else {
6704 ctxSettings( context );
6705 }
6706
6707 // Remove duplicates
6708 this.context = _unique( settings );
6709
6710 // Initial data
6711 if ( data ) {
6712 this.push.apply( this, data.toArray ? data.toArray() : data );
6713 }
6714
6715 // selector
6716 this.selector = {
6717 rows: null,
6718 cols: null,
6719 opts: null
6720 };
6721
6722 _Api.extend( this, this, __apiStruct );
6723 };
6724
6725 DataTable.Api = _Api;
6726
6727 _Api.prototype = /** @lends DataTables.Api */{
6728 /**
6729 * Return a new Api instance, comprised of the data held in the current
6730 * instance, join with the other array(s) and/or value(s).
6731 *
6732 * An alias for `Array.prototype.concat`.
6733 *
6734 * @type method
6735 * @param {*} value1 Arrays and/or values to concatenate.
6736 * @param {*} [...] Additional arrays and/or values to concatenate.
6737 * @returns {DataTables.Api} New API instance, comprising of the combined
6738 * array.
6739 */
6740 concat: __arrayProto.concat,
6741
6742
6743 context: [], // array of table settings objects
6744
6745
6746 each: function ( fn )
6747 {
6748 for ( var i=0, ien=this.length ; i<ien; i++ ) {
6749 fn.call( this, this[i], i, this );
6750 }
6751
6752 return this;
6753 },
6754
6755
6756 eq: function ( idx )
6757 {
6758 var ctx = this.context;
6759
6760 return ctx.length > idx ?
6761 new _Api( ctx[idx], this[idx] ) :
6762 null;
6763 },
6764
6765
6766 filter: function ( fn )
6767 {
6768 var a = [];
6769
6770 if ( __arrayProto.filter ) {
6771 a = __arrayProto.filter.call( this, fn, this );
6772 }
6773 else {
6774 // Compatibility for browsers without EMCA-252-5 (JS 1.6)
6775 for ( var i=0, ien=this.length ; i<ien ; i++ ) {
6776 if ( fn.call( this, this[i], i, this ) ) {
6777 a.push( this[i] );
6778 }
6779 }
6780 }
6781
6782 return new _Api( this.context, a );
6783 },
6784
6785
6786 flatten: function ()
6787 {
6788 var a = [];
6789 return new _Api( this.context, a.concat.apply( a, this.toArray() ) );
6790 },
6791
6792
6793 join: __arrayProto.join,
6794
6795
6796 indexOf: __arrayProto.indexOf || function (obj, start)
6797 {
6798 for ( var i=(start || 0), ien=this.length ; i<ien ; i++ ) {
6799 if ( this[i] === obj ) {
6800 return i;
6801 }
6802 }
6803 return -1;
6804 },
6805
6806 // Note that `alwaysNew` is internal - use iteratorNew externally
6807 iterator: function ( flatten, type, fn, alwaysNew ) {
6808 var
6809 a = [], ret,
6810 i, ien, j, jen,
6811 context = this.context,
6812 rows, items, item,
6813 selector = this.selector;
6814
6815 // Argument shifting
6816 if ( typeof flatten === 'string' ) {
6817 alwaysNew = fn;
6818 fn = type;
6819 type = flatten;
6820 flatten = false;
6821 }
6822
6823 for ( i=0, ien=context.length ; i<ien ; i++ ) {
6824 var apiInst = new _Api( context[i] );
6825
6826 if ( type === 'table' ) {
6827 ret = fn.call( apiInst, context[i], i );
6828
6829 if ( ret !== undefined ) {
6830 a.push( ret );
6831 }
6832 }
6833 else if ( type === 'columns' || type === 'rows' ) {
6834 // this has same length as context - one entry for each table
6835 ret = fn.call( apiInst, context[i], this[i], i );
6836
6837 if ( ret !== undefined ) {
6838 a.push( ret );
6839 }
6840 }
6841 else if ( type === 'column' || type === 'column-rows' || type === 'row' || type === 'cell' ) {
6842 // columns and rows share the same structure.
6843 // 'this' is an array of column indexes for each context
6844 items = this[i];
6845
6846 if ( type === 'column-rows' ) {
6847 rows = _selector_row_indexes( context[i], selector.opts );
6848 }
6849
6850 for ( j=0, jen=items.length ; j<jen ; j++ ) {
6851 item = items[j];
6852
6853 if ( type === 'cell' ) {
6854 ret = fn.call( apiInst, context[i], item.row, item.column, i, j );
6855 }
6856 else {
6857 ret = fn.call( apiInst, context[i], item, i, j, rows );
6858 }
6859
6860 if ( ret !== undefined ) {
6861 a.push( ret );
6862 }
6863 }
6864 }
6865 }
6866
6867 if ( a.length || alwaysNew ) {
6868 var api = new _Api( context, flatten ? a.concat.apply( [], a ) : a );
6869 var apiSelector = api.selector;
6870 apiSelector.rows = selector.rows;
6871 apiSelector.cols = selector.cols;
6872 apiSelector.opts = selector.opts;
6873 return api;
6874 }
6875 return this;
6876 },
6877
6878
6879 lastIndexOf: __arrayProto.lastIndexOf || function (obj, start)
6880 {
6881 // Bit cheeky...
6882 return this.indexOf.apply( this.toArray.reverse(), arguments );
6883 },
6884
6885
6886 length: 0,
6887
6888
6889 map: function ( fn )
6890 {
6891 var a = [];
6892
6893 if ( __arrayProto.map ) {
6894 a = __arrayProto.map.call( this, fn, this );
6895 }
6896 else {
6897 // Compatibility for browsers without EMCA-252-5 (JS 1.6)
6898 for ( var i=0, ien=this.length ; i<ien ; i++ ) {
6899 a.push( fn.call( this, this[i], i ) );
6900 }
6901 }
6902
6903 return new _Api( this.context, a );
6904 },
6905
6906
6907 pluck: function ( prop )
6908 {
6909 return this.map( function ( el ) {
6910 return el[ prop ];
6911 } );
6912 },
6913
6914 pop: __arrayProto.pop,
6915
6916
6917 push: __arrayProto.push,
6918
6919
6920 // Does not return an API instance
6921 reduce: __arrayProto.reduce || function ( fn, init )
6922 {
6923 return _fnReduce( this, fn, init, 0, this.length, 1 );
6924 },
6925
6926
6927 reduceRight: __arrayProto.reduceRight || function ( fn, init )
6928 {
6929 return _fnReduce( this, fn, init, this.length-1, -1, -1 );
6930 },
6931
6932
6933 reverse: __arrayProto.reverse,
6934
6935
6936 // Object with rows, columns and opts
6937 selector: null,
6938
6939
6940 shift: __arrayProto.shift,
6941
6942
6943 sort: __arrayProto.sort, // ? name - order?
6944
6945
6946 splice: __arrayProto.splice,
6947
6948
6949 toArray: function ()
6950 {
6951 return __arrayProto.slice.call( this );
6952 },
6953
6954
6955 to$: function ()
6956 {
6957 return $( this );
6958 },
6959
6960
6961 toJQuery: function ()
6962 {
6963 return $( this );
6964 },
6965
6966
6967 unique: function ()
6968 {
6969 return new _Api( this.context, _unique(this) );
6970 },
6971
6972
6973 unshift: __arrayProto.unshift
6974 };
6975
6976
6977 _Api.extend = function ( scope, obj, ext )
6978 {
6979 // Only extend API instances and static properties of the API
6980 if ( ! obj || ( ! (obj instanceof _Api) && ! obj.__dt_wrapper ) ) {
6981 return;
6982 }
6983
6984 var
6985 i, ien,
6986 j, jen,
6987 struct, inner,
6988 methodScoping = function ( scope, fn, struc ) {
6989 return function () {
6990 var ret = fn.apply( scope, arguments );
6991
6992 // Method extension
6993 _Api.extend( ret, ret, struc.methodExt );
6994 return ret;
6995 };
6996 };
6997
6998 for ( i=0, ien=ext.length ; i<ien ; i++ ) {
6999 struct = ext[i];
7000
7001 // Value
7002 obj[ struct.name ] = typeof struct.val === 'function' ?
7003 methodScoping( scope, struct.val, struct ) :
7004 $.isPlainObject( struct.val ) ?
7005 {} :
7006 struct.val;
7007
7008 obj[ struct.name ].__dt_wrapper = true;
7009
7010 // Property extension
7011 _Api.extend( scope, obj[ struct.name ], struct.propExt );
7012 }
7013 };
7014
7015
7016 // @todo - Is there need for an augment function?
7017 // _Api.augment = function ( inst, name )
7018 // {
7019 // // Find src object in the structure from the name
7020 // var parts = name.split('.');
7021
7022 // _Api.extend( inst, obj );
7023 // };
7024
7025
7026 // [
7027 // {
7028 // name: 'data' -- string - Property name
7029 // val: function () {}, -- function - Api method (or undefined if just an object
7030 // methodExt: [ ... ], -- array - Array of Api object definitions to extend the method result
7031 // propExt: [ ... ] -- array - Array of Api object definitions to extend the property
7032 // },
7033 // {
7034 // name: 'row'
7035 // val: {},
7036 // methodExt: [ ... ],
7037 // propExt: [
7038 // {
7039 // name: 'data'
7040 // val: function () {},
7041 // methodExt: [ ... ],
7042 // propExt: [ ... ]
7043 // },
7044 // ...
7045 // ]
7046 // }
7047 // ]
7048
7049 _Api.register = _api_register = function ( name, val )
7050 {
7051 if ( $.isArray( name ) ) {
7052 for ( var j=0, jen=name.length ; j<jen ; j++ ) {
7053 _Api.register( name[j], val );
7054 }
7055 return;
7056 }
7057
7058 var
7059 i, ien,
7060 heir = name.split('.'),
7061 struct = __apiStruct,
7062 key, method;
7063
7064 var find = function ( src, name ) {
7065 for ( var i=0, ien=src.length ; i<ien ; i++ ) {
7066 if ( src[i].name === name ) {
7067 return src[i];
7068 }
7069 }
7070 return null;
7071 };
7072
7073 for ( i=0, ien=heir.length ; i<ien ; i++ ) {
7074 method = heir[i].indexOf('()') !== -1;
7075 key = method ?
7076 heir[i].replace('()', '') :
7077 heir[i];
7078
7079 var src = find( struct, key );
7080 if ( ! src ) {
7081 src = {
7082 name: key,
7083 val: {},
7084 methodExt: [],
7085 propExt: []
7086 };
7087 struct.push( src );
7088 }
7089
7090 if ( i === ien-1 ) {
7091 src.val = val;
7092 }
7093 else {
7094 struct = method ?
7095 src.methodExt :
7096 src.propExt;
7097 }
7098 }
7099 };
7100
7101
7102 _Api.registerPlural = _api_registerPlural = function ( pluralName, singularName, val ) {
7103 _Api.register( pluralName, val );
7104
7105 _Api.register( singularName, function () {
7106 var ret = val.apply( this, arguments );
7107
7108 if ( ret === this ) {
7109 // Returned item is the API instance that was passed in, return it
7110 return this;
7111 }
7112 else if ( ret instanceof _Api ) {
7113 // New API instance returned, want the value from the first item
7114 // in the returned array for the singular result.
7115 return ret.length ?
7116 $.isArray( ret[0] ) ?
7117 new _Api( ret.context, ret[0] ) : // Array results are 'enhanced'
7118 ret[0] :
7119 undefined;
7120 }
7121
7122 // Non-API return - just fire it back
7123 return ret;
7124 } );
7125 };
7126
7127
7128 /**
7129 * Selector for HTML tables. Apply the given selector to the give array of
7130 * DataTables settings objects.
7131 *
7132 * @param {string|integer} [selector] jQuery selector string or integer
7133 * @param {array} Array of DataTables settings objects to be filtered
7134 * @return {array}
7135 * @ignore
7136 */
7137 var __table_selector = function ( selector, a )
7138 {
7139 // Integer is used to pick out a table by index
7140 if ( typeof selector === 'number' ) {
7141 return [ a[ selector ] ];
7142 }
7143
7144 // Perform a jQuery selector on the table nodes
7145 var nodes = $.map( a, function (el, i) {
7146 return el.nTable;
7147 } );
7148
7149 return $(nodes)
7150 .filter( selector )
7151 .map( function (i) {
7152 // Need to translate back from the table node to the settings
7153 var idx = $.inArray( this, nodes );
7154 return a[ idx ];
7155 } )
7156 .toArray();
7157 };
7158
7159
7160
7161 /**
7162 * Context selector for the API's context (i.e. the tables the API instance
7163 * refers to.
7164 *
7165 * @name DataTable.Api#tables
7166 * @param {string|integer} [selector] Selector to pick which tables the iterator
7167 * should operate on. If not given, all tables in the current context are
7168 * used. This can be given as a jQuery selector (for example `':gt(0)'`) to
7169 * select multiple tables or as an integer to select a single table.
7170 * @returns {DataTable.Api} Returns a new API instance if a selector is given.
7171 */
7172 _api_register( 'tables()', function ( selector ) {
7173 // A new instance is created if there was a selector specified
7174 return selector ?
7175 new _Api( __table_selector( selector, this.context ) ) :
7176 this;
7177 } );
7178
7179
7180 _api_register( 'table()', function ( selector ) {
7181 var tables = this.tables( selector );
7182 var ctx = tables.context;
7183
7184 // Truncate to the first matched table
7185 return ctx.length ?
7186 new _Api( ctx[0] ) :
7187 tables;
7188 } );
7189
7190
7191 _api_registerPlural( 'tables().nodes()', 'table().node()' , function () {
7192 return this.iterator( 'table', function ( ctx ) {
7193 return ctx.nTable;
7194 }, 1 );
7195 } );
7196
7197
7198 _api_registerPlural( 'tables().body()', 'table().body()' , function () {
7199 return this.iterator( 'table', function ( ctx ) {
7200 return ctx.nTBody;
7201 }, 1 );
7202 } );
7203
7204
7205 _api_registerPlural( 'tables().header()', 'table().header()' , function () {
7206 return this.iterator( 'table', function ( ctx ) {
7207 return ctx.nTHead;
7208 }, 1 );
7209 } );
7210
7211
7212 _api_registerPlural( 'tables().footer()', 'table().footer()' , function () {
7213 return this.iterator( 'table', function ( ctx ) {
7214 return ctx.nTFoot;
7215 }, 1 );
7216 } );
7217
7218
7219 _api_registerPlural( 'tables().containers()', 'table().container()' , function () {
7220 return this.iterator( 'table', function ( ctx ) {
7221 return ctx.nTableWrapper;
7222 }, 1 );
7223 } );
7224
7225
7226
7227 /**
7228 * Redraw the tables in the current context.
7229 *
7230 * @param {boolean} [reset=true] Reset (default) or hold the current paging
7231 * position. A full re-sort and re-filter is performed when this method is
7232 * called, which is why the pagination reset is the default action.
7233 * @returns {DataTables.Api} this
7234 */
7235 _api_register( 'draw()', function ( resetPaging ) {
7236 return this.iterator( 'table', function ( settings ) {
7237 _fnReDraw( settings, resetPaging===false );
7238 } );
7239 } );
7240
7241
7242
7243 /**
7244 * Get the current page index.
7245 *
7246 * @return {integer} Current page index (zero based)
7247 *//**
7248 * Set the current page.
7249 *
7250 * Note that if you attempt to show a page which does not exist, DataTables will
7251 * not throw an error, but rather reset the paging.
7252 *
7253 * @param {integer|string} action The paging action to take. This can be one of:
7254 * * `integer` - The page index to jump to
7255 * * `string` - An action to take:
7256 * * `first` - Jump to first page.
7257 * * `next` - Jump to the next page
7258 * * `previous` - Jump to previous page
7259 * * `last` - Jump to the last page.
7260 * @returns {DataTables.Api} this
7261 */
7262 _api_register( 'page()', function ( action ) {
7263 if ( action === undefined ) {
7264 return this.page.info().page; // not an expensive call
7265 }
7266
7267 // else, have an action to take on all tables
7268 return this.iterator( 'table', function ( settings ) {
7269 _fnPageChange( settings, action );
7270 } );
7271 } );
7272
7273
7274 /**
7275 * Paging information for the first table in the current context.
7276 *
7277 * If you require paging information for another table, use the `table()` method
7278 * with a suitable selector.
7279 *
7280 * @return {object} Object with the following properties set:
7281 * * `page` - Current page index (zero based - i.e. the first page is `0`)
7282 * * `pages` - Total number of pages
7283 * * `start` - Display index for the first record shown on the current page
7284 * * `end` - Display index for the last record shown on the current page
7285 * * `length` - Display length (number of records). Note that generally `start
7286 * + length = end`, but this is not always true, for example if there are
7287 * only 2 records to show on the final page, with a length of 10.
7288 * * `recordsTotal` - Full data set length
7289 * * `recordsDisplay` - Data set length once the current filtering criterion
7290 * are applied.
7291 */
7292 _api_register( 'page.info()', function ( action ) {
7293 if ( this.context.length === 0 ) {
7294 return undefined;
7295 }
7296
7297 var
7298 settings = this.context[0],
7299 start = settings._iDisplayStart,
7300 len = settings._iDisplayLength,
7301 visRecords = settings.fnRecordsDisplay(),
7302 all = len === -1;
7303
7304 return {
7305 "page": all ? 0 : Math.floor( start / len ),
7306 "pages": all ? 1 : Math.ceil( visRecords / len ),
7307 "start": start,
7308 "end": settings.fnDisplayEnd(),
7309 "length": len,
7310 "recordsTotal": settings.fnRecordsTotal(),
7311 "recordsDisplay": visRecords
7312 };
7313 } );
7314
7315
7316 /**
7317 * Get the current page length.
7318 *
7319 * @return {integer} Current page length. Note `-1` indicates that all records
7320 * are to be shown.
7321 *//**
7322 * Set the current page length.
7323 *
7324 * @param {integer} Page length to set. Use `-1` to show all records.
7325 * @returns {DataTables.Api} this
7326 */
7327 _api_register( 'page.len()', function ( len ) {
7328 // Note that we can't call this function 'length()' because `length`
7329 // is a Javascript property of functions which defines how many arguments
7330 // the function expects.
7331 if ( len === undefined ) {
7332 return this.context.length !== 0 ?
7333 this.context[0]._iDisplayLength :
7334 undefined;
7335 }
7336
7337 // else, set the page length
7338 return this.iterator( 'table', function ( settings ) {
7339 _fnLengthChange( settings, len );
7340 } );
7341 } );
7342
7343
7344
7345 var __reload = function ( settings, holdPosition, callback ) {
7346 if ( _fnDataSource( settings ) == 'ssp' ) {
7347 _fnReDraw( settings, holdPosition );
7348 }
7349 else {
7350 // Trigger xhr
7351 _fnProcessingDisplay( settings, true );
7352
7353 _fnBuildAjax( settings, [], function( json ) {
7354 _fnClearTable( settings );
7355
7356 var data = _fnAjaxDataSrc( settings, json );
7357 for ( var i=0, ien=data.length ; i<ien ; i++ ) {
7358 _fnAddData( settings, data[i] );
7359 }
7360
7361 _fnReDraw( settings, holdPosition );
7362 _fnProcessingDisplay( settings, false );
7363 } );
7364 }
7365
7366 // Use the draw event to trigger a callback, regardless of if it is an async
7367 // or sync draw
7368 if ( callback ) {
7369 var api = new _Api( settings );
7370
7371 api.one( 'draw', function () {
7372 callback( api.ajax.json() );
7373 } );
7374 }
7375 };
7376
7377
7378 /**
7379 * Get the JSON response from the last Ajax request that DataTables made to the
7380 * server. Note that this returns the JSON from the first table in the current
7381 * context.
7382 *
7383 * @return {object} JSON received from the server.
7384 */
7385 _api_register( 'ajax.json()', function () {
7386 var ctx = this.context;
7387
7388 if ( ctx.length > 0 ) {
7389 return ctx[0].json;
7390 }
7391
7392 // else return undefined;
7393 } );
7394
7395
7396 /**
7397 * Get the data submitted in the last Ajax request
7398 */
7399 _api_register( 'ajax.params()', function () {
7400 var ctx = this.context;
7401
7402 if ( ctx.length > 0 ) {
7403 return ctx[0].oAjaxData;
7404 }
7405
7406 // else return undefined;
7407 } );
7408
7409
7410 /**
7411 * Reload tables from the Ajax data source. Note that this function will
7412 * automatically re-draw the table when the remote data has been loaded.
7413 *
7414 * @param {boolean} [reset=true] Reset (default) or hold the current paging
7415 * position. A full re-sort and re-filter is performed when this method is
7416 * called, which is why the pagination reset is the default action.
7417 * @returns {DataTables.Api} this
7418 */
7419 _api_register( 'ajax.reload()', function ( callback, resetPaging ) {
7420 return this.iterator( 'table', function (settings) {
7421 __reload( settings, resetPaging===false, callback );
7422 } );
7423 } );
7424
7425
7426 /**
7427 * Get the current Ajax URL. Note that this returns the URL from the first
7428 * table in the current context.
7429 *
7430 * @return {string} Current Ajax source URL
7431 *//**
7432 * Set the Ajax URL. Note that this will set the URL for all tables in the
7433 * current context.
7434 *
7435 * @param {string} url URL to set.
7436 * @returns {DataTables.Api} this
7437 */
7438 _api_register( 'ajax.url()', function ( url ) {
7439 var ctx = this.context;
7440
7441 if ( url === undefined ) {
7442 // get
7443 if ( ctx.length === 0 ) {
7444 return undefined;
7445 }
7446 ctx = ctx[0];
7447
7448 return ctx.ajax ?
7449 $.isPlainObject( ctx.ajax ) ?
7450 ctx.ajax.url :
7451 ctx.ajax :
7452 ctx.sAjaxSource;
7453 }
7454
7455 // set
7456 return this.iterator( 'table', function ( settings ) {
7457 if ( $.isPlainObject( settings.ajax ) ) {
7458 settings.ajax.url = url;
7459 }
7460 else {
7461 settings.ajax = url;
7462 }
7463 // No need to consider sAjaxSource here since DataTables gives priority
7464 // to `ajax` over `sAjaxSource`. So setting `ajax` here, renders any
7465 // value of `sAjaxSource` redundant.
7466 } );
7467 } );
7468
7469
7470 /**
7471 * Load data from the newly set Ajax URL. Note that this method is only
7472 * available when `ajax.url()` is used to set a URL. Additionally, this method
7473 * has the same effect as calling `ajax.reload()` but is provided for
7474 * convenience when setting a new URL. Like `ajax.reload()` it will
7475 * automatically redraw the table once the remote data has been loaded.
7476 *
7477 * @returns {DataTables.Api} this
7478 */
7479 _api_register( 'ajax.url().load()', function ( callback, resetPaging ) {
7480 // Same as a reload, but makes sense to present it for easy access after a
7481 // url change
7482 return this.iterator( 'table', function ( ctx ) {
7483 __reload( ctx, resetPaging===false, callback );
7484 } );
7485 } );
7486
7487
7488
7489
7490 var _selector_run = function ( selector, select )
7491 {
7492 var
7493 out = [], res,
7494 a, i, ien, j, jen,
7495 selectorType = typeof selector;
7496
7497 // Can't just check for isArray here, as an API or jQuery instance might be
7498 // given with their array like look
7499 if ( ! selector || selectorType === 'string' || selectorType === 'function' || selector.length === undefined ) {
7500 selector = [ selector ];
7501 }
7502
7503 for ( i=0, ien=selector.length ; i<ien ; i++ ) {
7504 a = selector[i] && selector[i].split ?
7505 selector[i].split(',') :
7506 [ selector[i] ];
7507
7508 for ( j=0, jen=a.length ; j<jen ; j++ ) {
7509 res = select( typeof a[j] === 'string' ? $.trim(a[j]) : a[j] );
7510
7511 if ( res && res.length ) {
7512 out.push.apply( out, res );
7513 }
7514 }
7515 }
7516
7517 return out;
7518 };
7519
7520
7521 var _selector_opts = function ( opts )
7522 {
7523 if ( ! opts ) {
7524 opts = {};
7525 }
7526
7527 // Backwards compatibility for 1.9- which used the terminology filter rather
7528 // than search
7529 if ( opts.filter && ! opts.search ) {
7530 opts.search = opts.filter;
7531 }
7532
7533 return {
7534 search: opts.search || 'none',
7535 order: opts.order || 'current',
7536 page: opts.page || 'all'
7537 };
7538 };
7539
7540
7541 var _selector_first = function ( inst )
7542 {
7543 // Reduce the API instance to the first item found
7544 for ( var i=0, ien=inst.length ; i<ien ; i++ ) {
7545 if ( inst[i].length > 0 ) {
7546 // Assign the first element to the first item in the instance
7547 // and truncate the instance and context
7548 inst[0] = inst[i];
7549 inst.length = 1;
7550 inst.context = [ inst.context[i] ];
7551
7552 return inst;
7553 }
7554 }
7555
7556 // Not found - return an empty instance
7557 inst.length = 0;
7558 return inst;
7559 };
7560
7561
7562 var _selector_row_indexes = function ( settings, opts )
7563 {
7564 var
7565 i, ien, tmp, a=[],
7566 displayFiltered = settings.aiDisplay,
7567 displayMaster = settings.aiDisplayMaster;
7568
7569 var
7570 search = opts.search, // none, applied, removed
7571 order = opts.order, // applied, current, index (original - compatibility with 1.9)
7572 page = opts.page; // all, current
7573
7574 if ( _fnDataSource( settings ) == 'ssp' ) {
7575 // In server-side processing mode, most options are irrelevant since
7576 // rows not shown don't exist and the index order is the applied order
7577 // Removed is a special case - for consistency just return an empty
7578 // array
7579 return search === 'removed' ?
7580 [] :
7581 _range( 0, displayMaster.length );
7582 }
7583 else if ( page == 'current' ) {
7584 // Current page implies that order=current and fitler=applied, since it is
7585 // fairly senseless otherwise, regardless of what order and search actually
7586 // are
7587 for ( i=settings._iDisplayStart, ien=settings.fnDisplayEnd() ; i<ien ; i++ ) {
7588 a.push( displayFiltered[i] );
7589 }
7590 }
7591 else if ( order == 'current' || order == 'applied' ) {
7592 a = search == 'none' ?
7593 displayMaster.slice() : // no search
7594 search == 'applied' ?
7595 displayFiltered.slice() : // applied search
7596 $.map( displayMaster, function (el, i) { // removed search
7597 return $.inArray( el, displayFiltered ) === -1 ? el : null;
7598 } );
7599 }
7600 else if ( order == 'index' || order == 'original' ) {
7601 for ( i=0, ien=settings.aoData.length ; i<ien ; i++ ) {
7602 if ( search == 'none' ) {
7603 a.push( i );
7604 }
7605 else { // applied | removed
7606 tmp = $.inArray( i, displayFiltered );
7607
7608 if ((tmp === -1 && search == 'removed') ||
7609 (tmp >= 0 && search == 'applied') )
7610 {
7611 a.push( i );
7612 }
7613 }
7614 }
7615 }
7616
7617 return a;
7618 };
7619
7620
7621 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
7622 * Rows
7623 *
7624 * {} - no selector - use all available rows
7625 * {integer} - row aoData index
7626 * {node} - TR node
7627 * {string} - jQuery selector to apply to the TR elements
7628 * {array} - jQuery array of nodes, or simply an array of TR nodes
7629 *
7630 */
7631
7632
7633 var __row_selector = function ( settings, selector, opts )
7634 {
7635 return _selector_run( selector, function ( sel ) {
7636 var selInt = _intVal( sel );
7637 var i, ien;
7638
7639 // Short cut - selector is a number and no options provided (default is
7640 // all records, so no need to check if the index is in there, since it
7641 // must be - dev error if the index doesn't exist).
7642 if ( selInt !== null && ! opts ) {
7643 return [ selInt ];
7644 }
7645
7646 var rows = _selector_row_indexes( settings, opts );
7647
7648 if ( selInt !== null && $.inArray( selInt, rows ) !== -1 ) {
7649 // Selector - integer
7650 return [ selInt ];
7651 }
7652 else if ( ! sel ) {
7653 // Selector - none
7654 return rows;
7655 }
7656
7657 // Selector - function
7658 if ( typeof sel === 'function' ) {
7659 return $.map( rows, function (idx) {
7660 var row = settings.aoData[ idx ];
7661 return sel( idx, row._aData, row.nTr ) ? idx : null;
7662 } );
7663 }
7664
7665 // Get nodes in the order from the `rows` array with null values removed
7666 var nodes = _removeEmpty(
7667 _pluck_order( settings.aoData, rows, 'nTr' )
7668 );
7669
7670 // Selector - node
7671 if ( sel.nodeName ) {
7672 if ( $.inArray( sel, nodes ) !== -1 ) {
7673 return [ sel._DT_RowIndex ]; // sel is a TR node that is in the table
7674 // and DataTables adds a prop for fast lookup
7675 }
7676 }
7677
7678 // Selector - jQuery selector string, array of nodes or jQuery object/
7679 // As jQuery's .filter() allows jQuery objects to be passed in filter,
7680 // it also allows arrays, so this will cope with all three options
7681 return $(nodes)
7682 .filter( sel )
7683 .map( function () {
7684 return this._DT_RowIndex;
7685 } )
7686 .toArray();
7687 } );
7688 };
7689
7690
7691 /**
7692 *
7693 */
7694 _api_register( 'rows()', function ( selector, opts ) {
7695 // argument shifting
7696 if ( selector === undefined ) {
7697 selector = '';
7698 }
7699 else if ( $.isPlainObject( selector ) ) {
7700 opts = selector;
7701 selector = '';
7702 }
7703
7704 opts = _selector_opts( opts );
7705
7706 var inst = this.iterator( 'table', function ( settings ) {
7707 return __row_selector( settings, selector, opts );
7708 }, 1 );
7709
7710 // Want argument shifting here and in __row_selector?
7711 inst.selector.rows = selector;
7712 inst.selector.opts = opts;
7713
7714 return inst;
7715 } );
7716
7717
7718 _api_register( 'rows().nodes()', function () {
7719 return this.iterator( 'row', function ( settings, row ) {
7720 return settings.aoData[ row ].nTr || undefined;
7721 }, 1 );
7722 } );
7723
7724 _api_register( 'rows().data()', function () {
7725 return this.iterator( true, 'rows', function ( settings, rows ) {
7726 return _pluck_order( settings.aoData, rows, '_aData' );
7727 }, 1 );
7728 } );
7729
7730 _api_registerPlural( 'rows().cache()', 'row().cache()', function ( type ) {
7731 return this.iterator( 'row', function ( settings, row ) {
7732 var r = settings.aoData[ row ];
7733 return type === 'search' ? r._aFilterData : r._aSortData;
7734 }, 1 );
7735 } );
7736
7737 _api_registerPlural( 'rows().invalidate()', 'row().invalidate()', function ( src ) {
7738 return this.iterator( 'row', function ( settings, row ) {
7739 _fnInvalidate( settings, row, src );
7740 } );
7741 } );
7742
7743 _api_registerPlural( 'rows().indexes()', 'row().index()', function () {
7744 return this.iterator( 'row', function ( settings, row ) {
7745 return row;
7746 }, 1 );
7747 } );
7748
7749 _api_registerPlural( 'rows().remove()', 'row().remove()', function () {
7750 var that = this;
7751
7752 return this.iterator( 'row', function ( settings, row, thatIdx ) {
7753 var data = settings.aoData;
7754
7755 data.splice( row, 1 );
7756
7757 // Update the _DT_RowIndex parameter on all rows in the table
7758 for ( var i=0, ien=data.length ; i<ien ; i++ ) {
7759 if ( data[i].nTr !== null ) {
7760 data[i].nTr._DT_RowIndex = i;
7761 }
7762 }
7763
7764 // Remove the target row from the search array
7765 var displayIndex = $.inArray( row, settings.aiDisplay );
7766
7767 // Delete from the display arrays
7768 _fnDeleteIndex( settings.aiDisplayMaster, row );
7769 _fnDeleteIndex( settings.aiDisplay, row );
7770 _fnDeleteIndex( that[ thatIdx ], row, false ); // maintain local indexes
7771
7772 // Check for an 'overflow' they case for displaying the table
7773 _fnLengthOverflow( settings );
7774 } );
7775 } );
7776
7777
7778 _api_register( 'rows.add()', function ( rows ) {
7779 var newRows = this.iterator( 'table', function ( settings ) {
7780 var row, i, ien;
7781 var out = [];
7782
7783 for ( i=0, ien=rows.length ; i<ien ; i++ ) {
7784 row = rows[i];
7785
7786 if ( row.nodeName && row.nodeName.toUpperCase() === 'TR' ) {
7787 out.push( _fnAddTr( settings, row )[0] );
7788 }
7789 else {
7790 out.push( _fnAddData( settings, row ) );
7791 }
7792 }
7793
7794 return out;
7795 }, 1 );
7796
7797 // Return an Api.rows() extended instance, so rows().nodes() etc can be used
7798 var modRows = this.rows( -1 );
7799 modRows.pop();
7800 modRows.push.apply( modRows, newRows.toArray() );
7801
7802 return modRows;
7803 } );
7804
7805
7806
7807
7808
7809 /**
7810 *
7811 */
7812 _api_register( 'row()', function ( selector, opts ) {
7813 return _selector_first( this.rows( selector, opts ) );
7814 } );
7815
7816
7817 _api_register( 'row().data()', function ( data ) {
7818 var ctx = this.context;
7819
7820 if ( data === undefined ) {
7821 // Get
7822 return ctx.length && this.length ?
7823 ctx[0].aoData[ this[0] ]._aData :
7824 undefined;
7825 }
7826
7827 // Set
7828 ctx[0].aoData[ this[0] ]._aData = data;
7829
7830 // Automatically invalidate
7831 _fnInvalidate( ctx[0], this[0], 'data' );
7832
7833 return this;
7834 } );
7835
7836
7837 _api_register( 'row().node()', function () {
7838 var ctx = this.context;
7839
7840 return ctx.length && this.length ?
7841 ctx[0].aoData[ this[0] ].nTr || null :
7842 null;
7843 } );
7844
7845
7846 _api_register( 'row.add()', function ( row ) {
7847 // Allow a jQuery object to be passed in - only a single row is added from
7848 // it though - the first element in the set
7849 if ( row instanceof $ && row.length ) {
7850 row = row[0];
7851 }
7852
7853 var rows = this.iterator( 'table', function ( settings ) {
7854 if ( row.nodeName && row.nodeName.toUpperCase() === 'TR' ) {
7855 return _fnAddTr( settings, row )[0];
7856 }
7857 return _fnAddData( settings, row );
7858 } );
7859
7860 // Return an Api.rows() extended instance, with the newly added row selected
7861 return this.row( rows[0] );
7862 } );
7863
7864
7865
7866 var __details_add = function ( ctx, row, data, klass )
7867 {
7868 // Convert to array of TR elements
7869 var rows = [];
7870 var addRow = function ( r, k ) {
7871 // If we get a TR element, then just add it directly - up to the dev
7872 // to add the correct number of columns etc
7873 if ( r.nodeName && r.nodeName.toLowerCase() === 'tr' ) {
7874 rows.push( r );
7875 }
7876 else {
7877 // Otherwise create a row with a wrapper
7878 var created = $('<tr><td/></tr>').addClass( k );
7879 $('td', created)
7880 .addClass( k )
7881 .html( r )
7882 [0].colSpan = _fnVisbleColumns( ctx );
7883
7884 rows.push( created[0] );
7885 }
7886 };
7887
7888 if ( $.isArray( data ) || data instanceof $ ) {
7889 for ( var i=0, ien=data.length ; i<ien ; i++ ) {
7890 addRow( data[i], klass );
7891 }
7892 }
7893 else {
7894 addRow( data, klass );
7895 }
7896
7897 if ( row._details ) {
7898 row._details.remove();
7899 }
7900
7901 row._details = $(rows);
7902
7903 // If the children were already shown, that state should be retained
7904 if ( row._detailsShow ) {
7905 row._details.insertAfter( row.nTr );
7906 }
7907 };
7908
7909
7910 var __details_remove = function ( api, idx )
7911 {
7912 var ctx = api.context;
7913
7914 if ( ctx.length ) {
7915 var row = ctx[0].aoData[ idx !== undefined ? idx : api[0] ];
7916
7917 if ( row._details ) {
7918 row._details.remove();
7919
7920 row._detailsShow = undefined;
7921 row._details = undefined;
7922 }
7923 }
7924 };
7925
7926
7927 var __details_display = function ( api, show ) {
7928 var ctx = api.context;
7929
7930 if ( ctx.length && api.length ) {
7931 var row = ctx[0].aoData[ api[0] ];
7932
7933 if ( row._details ) {
7934 row._detailsShow = show;
7935
7936 if ( show ) {
7937 row._details.insertAfter( row.nTr );
7938 }
7939 else {
7940 row._details.detach();
7941 }
7942
7943 __details_events( ctx[0] );
7944 }
7945 }
7946 };
7947
7948
7949 var __details_events = function ( settings )
7950 {
7951 var api = new _Api( settings );
7952 var namespace = '.dt.DT_details';
7953 var drawEvent = 'draw'+namespace;
7954 var colvisEvent = 'column-visibility'+namespace;
7955 var destroyEvent = 'destroy'+namespace;
7956 var data = settings.aoData;
7957
7958 api.off( drawEvent +' '+ colvisEvent +' '+ destroyEvent );
7959
7960 if ( _pluck( data, '_details' ).length > 0 ) {
7961 // On each draw, insert the required elements into the document
7962 api.on( drawEvent, function ( e, ctx ) {
7963 if ( settings !== ctx ) {
7964 return;
7965 }
7966
7967 api.rows( {page:'current'} ).eq(0).each( function (idx) {
7968 // Internal data grab
7969 var row = data[ idx ];
7970
7971 if ( row._detailsShow ) {
7972 row._details.insertAfter( row.nTr );
7973 }
7974 } );
7975 } );
7976
7977 // Column visibility change - update the colspan
7978 api.on( colvisEvent, function ( e, ctx, idx, vis ) {
7979 if ( settings !== ctx ) {
7980 return;
7981 }
7982
7983 // Update the colspan for the details rows (note, only if it already has
7984 // a colspan)
7985 var row, visible = _fnVisbleColumns( ctx );
7986
7987 for ( var i=0, ien=data.length ; i<ien ; i++ ) {
7988 row = data[i];
7989
7990 if ( row._details ) {
7991 row._details.children('td[colspan]').attr('colspan', visible );
7992 }
7993 }
7994 } );
7995
7996 // Table destroyed - nuke any child rows
7997 api.on( destroyEvent, function ( e, ctx ) {
7998 if ( settings !== ctx ) {
7999 return;
8000 }
8001
8002 for ( var i=0, ien=data.length ; i<ien ; i++ ) {
8003 if ( data[i]._details ) {
8004 __details_remove( api, i );
8005 }
8006 }
8007 } );
8008 }
8009 };
8010
8011 // Strings for the method names to help minification
8012 var _emp = '';
8013 var _child_obj = _emp+'row().child';
8014 var _child_mth = _child_obj+'()';
8015
8016 // data can be:
8017 // tr
8018 // string
8019 // jQuery or array of any of the above
8020 _api_register( _child_mth, function ( data, klass ) {
8021 var ctx = this.context;
8022
8023 if ( data === undefined ) {
8024 // get
8025 return ctx.length && this.length ?
8026 ctx[0].aoData[ this[0] ]._details :
8027 undefined;
8028 }
8029 else if ( data === true ) {
8030 // show
8031 this.child.show();
8032 }
8033 else if ( data === false ) {
8034 // remove
8035 __details_remove( this );
8036 }
8037 else if ( ctx.length && this.length ) {
8038 // set
8039 __details_add( ctx[0], ctx[0].aoData[ this[0] ], data, klass );
8040 }
8041
8042 return this;
8043 } );
8044
8045
8046 _api_register( [
8047 _child_obj+'.show()',
8048 _child_mth+'.show()' // only when `child()` was called with parameters (without
8049 ], function ( show ) { // it returns an object and this method is not executed)
8050 __details_display( this, true );
8051 return this;
8052 } );
8053
8054
8055 _api_register( [
8056 _child_obj+'.hide()',
8057 _child_mth+'.hide()' // only when `child()` was called with parameters (without
8058 ], function () { // it returns an object and this method is not executed)
8059 __details_display( this, false );
8060 return this;
8061 } );
8062
8063
8064 _api_register( [
8065 _child_obj+'.remove()',
8066 _child_mth+'.remove()' // only when `child()` was called with parameters (without
8067 ], function () { // it returns an object and this method is not executed)
8068 __details_remove( this );
8069 return this;
8070 } );
8071
8072
8073 _api_register( _child_obj+'.isShown()', function () {
8074 var ctx = this.context;
8075
8076 if ( ctx.length && this.length ) {
8077 // _detailsShown as false or undefined will fall through to return false
8078 return ctx[0].aoData[ this[0] ]._detailsShow || false;
8079 }
8080 return false;
8081 } );
8082
8083
8084
8085 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
8086 * Columns
8087 *
8088 * {integer} - column index (>=0 count from left, <0 count from right)
8089 * "{integer}:visIdx" - visible column index (i.e. translate to column index) (>=0 count from left, <0 count from right)
8090 * "{integer}:visible" - alias for {integer}:visIdx (>=0 count from left, <0 count from right)
8091 * "{string}:name" - column name
8092 * "{string}" - jQuery selector on column header nodes
8093 *
8094 */
8095
8096 // can be an array of these items, comma separated list, or an array of comma
8097 // separated lists
8098
8099 var __re_column_selector = /^(.+):(name|visIdx|visible)$/;
8100
8101
8102 // r1 and r2 are redundant - but it means that the parameters match for the
8103 // iterator callback in columns().data()
8104 var __columnData = function ( settings, column, r1, r2, rows ) {
8105 var a = [];
8106 for ( var row=0, ien=rows.length ; row<ien ; row++ ) {
8107 a.push( _fnGetCellData( settings, rows[row], column ) );
8108 }
8109 return a;
8110 };
8111
8112
8113 var __column_selector = function ( settings, selector, opts )
8114 {
8115 var
8116 columns = settings.aoColumns,
8117 names = _pluck( columns, 'sName' ),
8118 nodes = _pluck( columns, 'nTh' );
8119
8120 return _selector_run( selector, function ( s ) {
8121 var selInt = _intVal( s );
8122
8123 // Selector - all
8124 if ( s === '' ) {
8125 return _range( columns.length );
8126 }
8127
8128 // Selector - index
8129 if ( selInt !== null ) {
8130 return [ selInt >= 0 ?
8131 selInt : // Count from left
8132 columns.length + selInt // Count from right (+ because its a negative value)
8133 ];
8134 }
8135
8136 // Selector = function
8137 if ( typeof s === 'function' ) {
8138 var rows = _selector_row_indexes( settings, opts );
8139
8140 return $.map( columns, function (col, idx) {
8141 return s(
8142 idx,
8143 __columnData( settings, idx, 0, 0, rows ),
8144 nodes[ idx ]
8145 ) ? idx : null;
8146 } );
8147 }
8148
8149 // jQuery or string selector
8150 var match = typeof s === 'string' ?
8151 s.match( __re_column_selector ) :
8152 '';
8153
8154 if ( match ) {
8155 switch( match[2] ) {
8156 case 'visIdx':
8157 case 'visible':
8158 var idx = parseInt( match[1], 10 );
8159 // Visible index given, convert to column index
8160 if ( idx < 0 ) {
8161 // Counting from the right
8162 var visColumns = $.map( columns, function (col,i) {
8163 return col.bVisible ? i : null;
8164 } );
8165 return [ visColumns[ visColumns.length + idx ] ];
8166 }
8167 // Counting from the left
8168 return [ _fnVisibleToColumnIndex( settings, idx ) ];
8169
8170 case 'name':
8171 // match by name. `names` is column index complete and in order
8172 return $.map( names, function (name, i) {
8173 return name === match[1] ? i : null;
8174 } );
8175 }
8176 }
8177 else {
8178 // jQuery selector on the TH elements for the columns
8179 return $( nodes )
8180 .filter( s )
8181 .map( function () {
8182 return $.inArray( this, nodes ); // `nodes` is column index complete and in order
8183 } )
8184 .toArray();
8185 }
8186 } );
8187 };
8188
8189
8190 var __setColumnVis = function ( settings, column, vis, recalc ) {
8191 var
8192 cols = settings.aoColumns,
8193 col = cols[ column ],
8194 data = settings.aoData,
8195 row, cells, i, ien, tr;
8196
8197 // Get
8198 if ( vis === undefined ) {
8199 return col.bVisible;
8200 }
8201
8202 // Set
8203 // No change
8204 if ( col.bVisible === vis ) {
8205 return;
8206 }
8207
8208 if ( vis ) {
8209 // Insert column
8210 // Need to decide if we should use appendChild or insertBefore
8211 var insertBefore = $.inArray( true, _pluck(cols, 'bVisible'), column+1 );
8212
8213 for ( i=0, ien=data.length ; i<ien ; i++ ) {
8214 tr = data[i].nTr;
8215 cells = data[i].anCells;
8216
8217 if ( tr ) {
8218 // insertBefore can act like appendChild if 2nd arg is null
8219 tr.insertBefore( cells[ column ], cells[ insertBefore ] || null );
8220 }
8221 }
8222 }
8223 else {
8224 // Remove column
8225 $( _pluck( settings.aoData, 'anCells', column ) ).detach();
8226 }
8227
8228 // Common actions
8229 col.bVisible = vis;
8230 _fnDrawHead( settings, settings.aoHeader );
8231 _fnDrawHead( settings, settings.aoFooter );
8232
8233 if ( recalc === undefined || recalc ) {
8234 // Automatically adjust column sizing
8235 _fnAdjustColumnSizing( settings );
8236
8237 // Realign columns for scrolling
8238 if ( settings.oScroll.sX || settings.oScroll.sY ) {
8239 _fnScrollDraw( settings );
8240 }
8241 }
8242
8243 _fnCallbackFire( settings, null, 'column-visibility', [settings, column, vis] );
8244
8245 _fnSaveState( settings );
8246 };
8247
8248
8249 /**
8250 *
8251 */
8252 _api_register( 'columns()', function ( selector, opts ) {
8253 // argument shifting
8254 if ( selector === undefined ) {
8255 selector = '';
8256 }
8257 else if ( $.isPlainObject( selector ) ) {
8258 opts = selector;
8259 selector = '';
8260 }
8261
8262 opts = _selector_opts( opts );
8263
8264 var inst = this.iterator( 'table', function ( settings ) {
8265 return __column_selector( settings, selector, opts );
8266 }, 1 );
8267
8268 // Want argument shifting here and in _row_selector?
8269 inst.selector.cols = selector;
8270 inst.selector.opts = opts;
8271
8272 return inst;
8273 } );
8274
8275
8276 /**
8277 *
8278 */
8279 _api_registerPlural( 'columns().header()', 'column().header()', function ( selector, opts ) {
8280 return this.iterator( 'column', function ( settings, column ) {
8281 return settings.aoColumns[column].nTh;
8282 }, 1 );
8283 } );
8284
8285
8286 /**
8287 *
8288 */
8289 _api_registerPlural( 'columns().footer()', 'column().footer()', function ( selector, opts ) {
8290 return this.iterator( 'column', function ( settings, column ) {
8291 return settings.aoColumns[column].nTf;
8292 }, 1 );
8293 } );
8294
8295
8296 /**
8297 *
8298 */
8299 _api_registerPlural( 'columns().data()', 'column().data()', function () {
8300 return this.iterator( 'column-rows', __columnData, 1 );
8301 } );
8302
8303
8304 _api_registerPlural( 'columns().dataSrc()', 'column().dataSrc()', function () {
8305 return this.iterator( 'column', function ( settings, column ) {
8306 return settings.aoColumns[column].mData;
8307 }, 1 );
8308 } );
8309
8310
8311 _api_registerPlural( 'columns().cache()', 'column().cache()', function ( type ) {
8312 return this.iterator( 'column-rows', function ( settings, column, i, j, rows ) {
8313 return _pluck_order( settings.aoData, rows,
8314 type === 'search' ? '_aFilterData' : '_aSortData', column
8315 );
8316 }, 1 );
8317 } );
8318
8319
8320 _api_registerPlural( 'columns().nodes()', 'column().nodes()', function () {
8321 return this.iterator( 'column-rows', function ( settings, column, i, j, rows ) {
8322 return _pluck_order( settings.aoData, rows, 'anCells', column ) ;
8323 }, 1 );
8324 } );
8325
8326
8327
8328 _api_registerPlural( 'columns().visible()', 'column().visible()', function ( vis, calc ) {
8329 return this.iterator( 'column', function ( settings, column ) {
8330 if ( vis === undefined ) {
8331 return settings.aoColumns[ column ].bVisible;
8332 } // else
8333 __setColumnVis( settings, column, vis, calc );
8334 } );
8335 } );
8336
8337
8338
8339 _api_registerPlural( 'columns().indexes()', 'column().index()', function ( type ) {
8340 return this.iterator( 'column', function ( settings, column ) {
8341 return type === 'visible' ?
8342 _fnColumnIndexToVisible( settings, column ) :
8343 column;
8344 }, 1 );
8345 } );
8346
8347
8348 // _api_register( 'columns().show()', function () {
8349 // var selector = this.selector;
8350 // return this.columns( selector.cols, selector.opts ).visible( true );
8351 // } );
8352
8353
8354 // _api_register( 'columns().hide()', function () {
8355 // var selector = this.selector;
8356 // return this.columns( selector.cols, selector.opts ).visible( false );
8357 // } );
8358
8359
8360
8361 _api_register( 'columns.adjust()', function () {
8362 return this.iterator( 'table', function ( settings ) {
8363 _fnAdjustColumnSizing( settings );
8364 }, 1 );
8365 } );
8366
8367
8368 // Convert from one column index type, to another type
8369 _api_register( 'column.index()', function ( type, idx ) {
8370 if ( this.context.length !== 0 ) {
8371 var ctx = this.context[0];
8372
8373 if ( type === 'fromVisible' || type === 'toData' ) {
8374 return _fnVisibleToColumnIndex( ctx, idx );
8375 }
8376 else if ( type === 'fromData' || type === 'toVisible' ) {
8377 return _fnColumnIndexToVisible( ctx, idx );
8378 }
8379 }
8380 } );
8381
8382
8383 _api_register( 'column()', function ( selector, opts ) {
8384 return _selector_first( this.columns( selector, opts ) );
8385 } );
8386
8387
8388
8389
8390 var __cell_selector = function ( settings, selector, opts )
8391 {
8392 var data = settings.aoData;
8393 var rows = _selector_row_indexes( settings, opts );
8394 var cells = _removeEmpty( _pluck_order( data, rows, 'anCells' ) );
8395 var allCells = $( [].concat.apply([], cells) );
8396 var row;
8397 var columns = settings.aoColumns.length;
8398 var a, i, ien, j, o, host;
8399
8400 return _selector_run( selector, function ( s ) {
8401 var fnSelector = typeof s === 'function';
8402
8403 if ( s === null || s === undefined || fnSelector ) {
8404 // All cells and function selectors
8405 a = [];
8406
8407 for ( i=0, ien=rows.length ; i<ien ; i++ ) {
8408 row = rows[i];
8409
8410 for ( j=0 ; j<columns ; j++ ) {
8411 o = {
8412 row: row,
8413 column: j
8414 };
8415
8416 if ( fnSelector ) {
8417 // Selector - function
8418 host = settings.aoData[ row ];
8419
8420 if ( s( o, _fnGetCellData(settings, row, j), host.anCells[j] ) ) {
8421 a.push( o );
8422 }
8423 }
8424 else {
8425 // Selector - all
8426 a.push( o );
8427 }
8428 }
8429 }
8430
8431 return a;
8432 }
8433
8434 // Selector - index
8435 if ( $.isPlainObject( s ) ) {
8436 return [s];
8437 }
8438
8439 // Selector - jQuery filtered cells
8440 return allCells
8441 .filter( s )
8442 .map( function (i, el) {
8443 row = el.parentNode._DT_RowIndex;
8444
8445 return {
8446 row: row,
8447 column: $.inArray( el, data[ row ].anCells )
8448 };
8449 } )
8450 .toArray();
8451 } );
8452 };
8453
8454
8455
8456
8457 _api_register( 'cells()', function ( rowSelector, columnSelector, opts ) {
8458 // Argument shifting
8459 if ( $.isPlainObject( rowSelector ) ) {
8460 // Indexes
8461 if ( typeof rowSelector.row !== undefined ) {
8462 opts = columnSelector;
8463 columnSelector = null;
8464 }
8465 else {
8466 opts = rowSelector;
8467 rowSelector = null;
8468 }
8469 }
8470 if ( $.isPlainObject( columnSelector ) ) {
8471 opts = columnSelector;
8472 columnSelector = null;
8473 }
8474
8475 // Cell selector
8476 if ( columnSelector === null || columnSelector === undefined ) {
8477 return this.iterator( 'table', function ( settings ) {
8478 return __cell_selector( settings, rowSelector, _selector_opts( opts ) );
8479 } );
8480 }
8481
8482 // Row + column selector
8483 var columns = this.columns( columnSelector, opts );
8484 var rows = this.rows( rowSelector, opts );
8485 var a, i, ien, j, jen;
8486
8487 var cells = this.iterator( 'table', function ( settings, idx ) {
8488 a = [];
8489
8490 for ( i=0, ien=rows[idx].length ; i<ien ; i++ ) {
8491 for ( j=0, jen=columns[idx].length ; j<jen ; j++ ) {
8492 a.push( {
8493 row: rows[idx][i],
8494 column: columns[idx][j]
8495 } );
8496 }
8497 }
8498
8499 return a;
8500 }, 1 );
8501
8502 $.extend( cells.selector, {
8503 cols: columnSelector,
8504 rows: rowSelector,
8505 opts: opts
8506 } );
8507
8508 return cells;
8509 } );
8510
8511
8512 _api_registerPlural( 'cells().nodes()', 'cell().node()', function () {
8513 return this.iterator( 'cell', function ( settings, row, column ) {
8514 var cells = settings.aoData[ row ].anCells;
8515 return cells ?
8516 cells[ column ] :
8517 undefined;
8518 }, 1 );
8519 } );
8520
8521
8522 _api_register( 'cells().data()', function () {
8523 return this.iterator( 'cell', function ( settings, row, column ) {
8524 return _fnGetCellData( settings, row, column );
8525 }, 1 );
8526 } );
8527
8528
8529 _api_registerPlural( 'cells().cache()', 'cell().cache()', function ( type ) {
8530 type = type === 'search' ? '_aFilterData' : '_aSortData';
8531
8532 return this.iterator( 'cell', function ( settings, row, column ) {
8533 return settings.aoData[ row ][ type ][ column ];
8534 }, 1 );
8535 } );
8536
8537
8538 _api_registerPlural( 'cells().render()', 'cell().render()', function ( type ) {
8539 return this.iterator( 'cell', function ( settings, row, column ) {
8540 return _fnGetCellData( settings, row, column, type );
8541 }, 1 );
8542 } );
8543
8544
8545 _api_registerPlural( 'cells().indexes()', 'cell().index()', function () {
8546 return this.iterator( 'cell', function ( settings, row, column ) {
8547 return {
8548 row: row,
8549 column: column,
8550 columnVisible: _fnColumnIndexToVisible( settings, column )
8551 };
8552 }, 1 );
8553 } );
8554
8555
8556 _api_registerPlural( 'cells().invalidate()', 'cell().invalidate()', function ( src ) {
8557 return this.iterator( 'cell', function ( settings, row, column ) {
8558 _fnInvalidate( settings, row, src, column );
8559 } );
8560 } );
8561
8562
8563
8564 _api_register( 'cell()', function ( rowSelector, columnSelector, opts ) {
8565 return _selector_first( this.cells( rowSelector, columnSelector, opts ) );
8566 } );
8567
8568
8569 _api_register( 'cell().data()', function ( data ) {
8570 var ctx = this.context;
8571 var cell = this[0];
8572
8573 if ( data === undefined ) {
8574 // Get
8575 return ctx.length && cell.length ?
8576 _fnGetCellData( ctx[0], cell[0].row, cell[0].column ) :
8577 undefined;
8578 }
8579
8580 // Set
8581 _fnSetCellData( ctx[0], cell[0].row, cell[0].column, data );
8582 _fnInvalidate( ctx[0], cell[0].row, 'data', cell[0].column );
8583
8584 return this;
8585 } );
8586
8587
8588
8589 /**
8590 * Get current ordering (sorting) that has been applied to the table.
8591 *
8592 * @returns {array} 2D array containing the sorting information for the first
8593 * table in the current context. Each element in the parent array represents
8594 * a column being sorted upon (i.e. multi-sorting with two columns would have
8595 * 2 inner arrays). The inner arrays may have 2 or 3 elements. The first is
8596 * the column index that the sorting condition applies to, the second is the
8597 * direction of the sort (`desc` or `asc`) and, optionally, the third is the
8598 * index of the sorting order from the `column.sorting` initialisation array.
8599 *//**
8600 * Set the ordering for the table.
8601 *
8602 * @param {integer} order Column index to sort upon.
8603 * @param {string} direction Direction of the sort to be applied (`asc` or `desc`)
8604 * @returns {DataTables.Api} this
8605 *//**
8606 * Set the ordering for the table.
8607 *
8608 * @param {array} order 1D array of sorting information to be applied.
8609 * @param {array} [...] Optional additional sorting conditions
8610 * @returns {DataTables.Api} this
8611 *//**
8612 * Set the ordering for the table.
8613 *
8614 * @param {array} order 2D array of sorting information to be applied.
8615 * @returns {DataTables.Api} this
8616 */
8617 _api_register( 'order()', function ( order, dir ) {
8618 var ctx = this.context;
8619
8620 if ( order === undefined ) {
8621 // get
8622 return ctx.length !== 0 ?
8623 ctx[0].aaSorting :
8624 undefined;
8625 }
8626
8627 // set
8628 if ( typeof order === 'number' ) {
8629 // Simple column / direction passed in
8630 order = [ [ order, dir ] ];
8631 }
8632 else if ( ! $.isArray( order[0] ) ) {
8633 // Arguments passed in (list of 1D arrays)
8634 order = Array.prototype.slice.call( arguments );
8635 }
8636 // otherwise a 2D array was passed in
8637
8638 return this.iterator( 'table', function ( settings ) {
8639 settings.aaSorting = order.slice();
8640 } );
8641 } );
8642
8643
8644 /**
8645 * Attach a sort listener to an element for a given column
8646 *
8647 * @param {node|jQuery|string} node Identifier for the element(s) to attach the
8648 * listener to. This can take the form of a single DOM node, a jQuery
8649 * collection of nodes or a jQuery selector which will identify the node(s).
8650 * @param {integer} column the column that a click on this node will sort on
8651 * @param {function} [callback] callback function when sort is run
8652 * @returns {DataTables.Api} this
8653 */
8654 _api_register( 'order.listener()', function ( node, column, callback ) {
8655 return this.iterator( 'table', function ( settings ) {
8656 _fnSortAttachListener( settings, node, column, callback );
8657 } );
8658 } );
8659
8660
8661 // Order by the selected column(s)
8662 _api_register( [
8663 'columns().order()',
8664 'column().order()'
8665 ], function ( dir ) {
8666 var that = this;
8667
8668 return this.iterator( 'table', function ( settings, i ) {
8669 var sort = [];
8670
8671 $.each( that[i], function (j, col) {
8672 sort.push( [ col, dir ] );
8673 } );
8674
8675 settings.aaSorting = sort;
8676 } );
8677 } );
8678
8679
8680
8681 _api_register( 'search()', function ( input, regex, smart, caseInsen ) {
8682 var ctx = this.context;
8683
8684 if ( input === undefined ) {
8685 // get
8686 return ctx.length !== 0 ?
8687 ctx[0].oPreviousSearch.sSearch :
8688 undefined;
8689 }
8690
8691 // set
8692 return this.iterator( 'table', function ( settings ) {
8693 if ( ! settings.oFeatures.bFilter ) {
8694 return;
8695 }
8696
8697 _fnFilterComplete( settings, $.extend( {}, settings.oPreviousSearch, {
8698 "sSearch": input+"",
8699 "bRegex": regex === null ? false : regex,
8700 "bSmart": smart === null ? true : smart,
8701 "bCaseInsensitive": caseInsen === null ? true : caseInsen
8702 } ), 1 );
8703 } );
8704 } );
8705
8706
8707 _api_registerPlural(
8708 'columns().search()',
8709 'column().search()',
8710 function ( input, regex, smart, caseInsen ) {
8711 return this.iterator( 'column', function ( settings, column ) {
8712 var preSearch = settings.aoPreSearchCols;
8713
8714 if ( input === undefined ) {
8715 // get
8716 return preSearch[ column ].sSearch;
8717 }
8718
8719 // set
8720 if ( ! settings.oFeatures.bFilter ) {
8721 return;
8722 }
8723
8724 $.extend( preSearch[ column ], {
8725 "sSearch": input+"",
8726 "bRegex": regex === null ? false : regex,
8727 "bSmart": smart === null ? true : smart,
8728 "bCaseInsensitive": caseInsen === null ? true : caseInsen
8729 } );
8730
8731 _fnFilterComplete( settings, settings.oPreviousSearch, 1 );
8732 } );
8733 }
8734 );
8735
8736 /*
8737 * State API methods
8738 */
8739
8740 _api_register( 'state()', function () {
8741 return this.context.length ?
8742 this.context[0].oSavedState :
8743 null;
8744 } );
8745
8746
8747 _api_register( 'state.clear()', function () {
8748 return this.iterator( 'table', function ( settings ) {
8749 // Save an empty object
8750 settings.fnStateSaveCallback.call( settings.oInstance, settings, {} );
8751 } );
8752 } );
8753
8754
8755 _api_register( 'state.loaded()', function () {
8756 return this.context.length ?
8757 this.context[0].oLoadedState :
8758 null;
8759 } );
8760
8761
8762 _api_register( 'state.save()', function () {
8763 return this.iterator( 'table', function ( settings ) {
8764 _fnSaveState( settings );
8765 } );
8766 } );
8767
8768
8769
8770 /**
8771 * Provide a common method for plug-ins to check the version of DataTables being
8772 * used, in order to ensure compatibility.
8773 *
8774 * @param {string} version Version string to check for, in the format "X.Y.Z".
8775 * Note that the formats "X" and "X.Y" are also acceptable.
8776 * @returns {boolean} true if this version of DataTables is greater or equal to
8777 * the required version, or false if this version of DataTales is not
8778 * suitable
8779 * @static
8780 * @dtopt API-Static
8781 *
8782 * @example
8783 * alert( $.fn.dataTable.versionCheck( '1.9.0' ) );
8784 */
8785 DataTable.versionCheck = DataTable.fnVersionCheck = function( version )
8786 {
8787 var aThis = DataTable.version.split('.');
8788 var aThat = version.split('.');
8789 var iThis, iThat;
8790
8791 for ( var i=0, iLen=aThat.length ; i<iLen ; i++ ) {
8792 iThis = parseInt( aThis[i], 10 ) || 0;
8793 iThat = parseInt( aThat[i], 10 ) || 0;
8794
8795 // Parts are the same, keep comparing
8796 if (iThis === iThat) {
8797 continue;
8798 }
8799
8800 // Parts are different, return immediately
8801 return iThis > iThat;
8802 }
8803
8804 return true;
8805 };
8806
8807
8808 /**
8809 * Check if a `<table>` node is a DataTable table already or not.
8810 *
8811 * @param {node|jquery|string} table Table node, jQuery object or jQuery
8812 * selector for the table to test. Note that if more than more than one
8813 * table is passed on, only the first will be checked
8814 * @returns {boolean} true the table given is a DataTable, or false otherwise
8815 * @static
8816 * @dtopt API-Static
8817 *
8818 * @example
8819 * if ( ! $.fn.DataTable.isDataTable( '#example' ) ) {
8820 * $('#example').dataTable();
8821 * }
8822 */
8823 DataTable.isDataTable = DataTable.fnIsDataTable = function ( table )
8824 {
8825 var t = $(table).get(0);
8826 var is = false;
8827
8828 $.each( DataTable.settings, function (i, o) {
8829 if ( o.nTable === t || o.nScrollHead === t || o.nScrollFoot === t ) {
8830 is = true;
8831 }
8832 } );
8833
8834 return is;
8835 };
8836
8837
8838 /**
8839 * Get all DataTable tables that have been initialised - optionally you can
8840 * select to get only currently visible tables.
8841 *
8842 * @param {boolean} [visible=false] Flag to indicate if you want all (default)
8843 * or visible tables only.
8844 * @returns {array} Array of `table` nodes (not DataTable instances) which are
8845 * DataTables
8846 * @static
8847 * @dtopt API-Static
8848 *
8849 * @example
8850 * $.each( $.fn.dataTable.tables(true), function () {
8851 * $(table).DataTable().columns.adjust();
8852 * } );
8853 */
8854 DataTable.tables = DataTable.fnTables = function ( visible )
8855 {
8856 return $.map( DataTable.settings, function (o) {
8857 if ( !visible || (visible && $(o.nTable).is(':visible')) ) {
8858 return o.nTable;
8859 }
8860 } );
8861 };
8862
8863
8864 /**
8865 * DataTables utility methods
8866 *
8867 * This namespace provides helper methods that DataTables uses internally to
8868 * create a DataTable, but which are not exclusively used only for DataTables.
8869 * These methods can be used by extension authors to save the duplication of
8870 * code.
8871 *
8872 * @namespace
8873 */
8874 DataTable.util = {
8875 /**
8876 * Throttle the calls to a function. Arguments and context are maintained
8877 * for the throttled function.
8878 *
8879 * @param {function} fn Function to be called
8880 * @param {integer} freq Call frequency in mS
8881 * @return {function} Wrapped function
8882 */
8883 throttle: _fnThrottle,
8884
8885
8886 /**
8887 * Escape a string such that it can be used in a regular expression
8888 *
8889 * @param {string} sVal string to escape
8890 * @returns {string} escaped string
8891 */
8892 escapeRegex: _fnEscapeRegex
8893 };
8894
8895
8896 /**
8897 * Convert from camel case parameters to Hungarian notation. This is made public
8898 * for the extensions to provide the same ability as DataTables core to accept
8899 * either the 1.9 style Hungarian notation, or the 1.10+ style camelCase
8900 * parameters.
8901 *
8902 * @param {object} src The model object which holds all parameters that can be
8903 * mapped.
8904 * @param {object} user The object to convert from camel case to Hungarian.
8905 * @param {boolean} force When set to `true`, properties which already have a
8906 * Hungarian value in the `user` object will be overwritten. Otherwise they
8907 * won't be.
8908 */
8909 DataTable.camelToHungarian = _fnCamelToHungarian;
8910
8911
8912
8913 /**
8914 *
8915 */
8916 _api_register( '$()', function ( selector, opts ) {
8917 var
8918 rows = this.rows( opts ).nodes(), // Get all rows
8919 jqRows = $(rows);
8920
8921 return $( [].concat(
8922 jqRows.filter( selector ).toArray(),
8923 jqRows.find( selector ).toArray()
8924 ) );
8925 } );
8926
8927
8928 // jQuery functions to operate on the tables
8929 $.each( [ 'on', 'one', 'off' ], function (i, key) {
8930 _api_register( key+'()', function ( /* event, handler */ ) {
8931 var args = Array.prototype.slice.call(arguments);
8932
8933 // Add the `dt` namespace automatically if it isn't already present
8934 if ( ! args[0].match(/\.dt\b/) ) {
8935 args[0] += '.dt';
8936 }
8937
8938 var inst = $( this.tables().nodes() );
8939 inst[key].apply( inst, args );
8940 return this;
8941 } );
8942 } );
8943
8944
8945 _api_register( 'clear()', function () {
8946 return this.iterator( 'table', function ( settings ) {
8947 _fnClearTable( settings );
8948 } );
8949 } );
8950
8951
8952 _api_register( 'settings()', function () {
8953 return new _Api( this.context, this.context );
8954 } );
8955
8956
8957 _api_register( 'data()', function () {
8958 return this.iterator( 'table', function ( settings ) {
8959 return _pluck( settings.aoData, '_aData' );
8960 } ).flatten();
8961 } );
8962
8963
8964 _api_register( 'destroy()', function ( remove ) {
8965 remove = remove || false;
8966
8967 return this.iterator( 'table', function ( settings ) {
8968 var orig = settings.nTableWrapper.parentNode;
8969 var classes = settings.oClasses;
8970 var table = settings.nTable;
8971 var tbody = settings.nTBody;
8972 var thead = settings.nTHead;
8973 var tfoot = settings.nTFoot;
8974 var jqTable = $(table);
8975 var jqTbody = $(tbody);
8976 var jqWrapper = $(settings.nTableWrapper);
8977 var rows = $.map( settings.aoData, function (r) { return r.nTr; } );
8978 var i, ien;
8979
8980 // Flag to note that the table is currently being destroyed - no action
8981 // should be taken
8982 settings.bDestroying = true;
8983
8984 // Fire off the destroy callbacks for plug-ins etc
8985 _fnCallbackFire( settings, "aoDestroyCallback", "destroy", [settings] );
8986
8987 // If not being removed from the document, make all columns visible
8988 if ( ! remove ) {
8989 new _Api( settings ).columns().visible( true );
8990 }
8991
8992 // Blitz all `DT` namespaced events (these are internal events, the
8993 // lowercase, `dt` events are user subscribed and they are responsible
8994 // for removing them
8995 jqWrapper.unbind('.DT').find(':not(tbody *)').unbind('.DT');
8996 $(window).unbind('.DT-'+settings.sInstance);
8997
8998 // When scrolling we had to break the table up - restore it
8999 if ( table != thead.parentNode ) {
9000 jqTable.children('thead').detach();
9001 jqTable.append( thead );
9002 }
9003
9004 if ( tfoot && table != tfoot.parentNode ) {
9005 jqTable.children('tfoot').detach();
9006 jqTable.append( tfoot );
9007 }
9008
9009 // Remove the DataTables generated nodes, events and classes
9010 jqTable.detach();
9011 jqWrapper.detach();
9012
9013 settings.aaSorting = [];
9014 settings.aaSortingFixed = [];
9015 _fnSortingClasses( settings );
9016
9017 $( rows ).removeClass( settings.asStripeClasses.join(' ') );
9018
9019 $('th, td', thead).removeClass( classes.sSortable+' '+
9020 classes.sSortableAsc+' '+classes.sSortableDesc+' '+classes.sSortableNone
9021 );
9022
9023 if ( settings.bJUI ) {
9024 $('th span.'+classes.sSortIcon+ ', td span.'+classes.sSortIcon, thead).detach();
9025 $('th, td', thead).each( function () {
9026 var wrapper = $('div.'+classes.sSortJUIWrapper, this);
9027 $(this).append( wrapper.contents() );
9028 wrapper.detach();
9029 } );
9030 }
9031
9032 if ( ! remove && orig ) {
9033 // insertBefore acts like appendChild if !arg[1]
9034 orig.insertBefore( table, settings.nTableReinsertBefore );
9035 }
9036
9037 // Add the TR elements back into the table in their original order
9038 jqTbody.children().detach();
9039 jqTbody.append( rows );
9040
9041 // Restore the width of the original table - was read from the style property,
9042 // so we can restore directly to that
9043 jqTable
9044 .css( 'width', settings.sDestroyWidth )
9045 .removeClass( classes.sTable );
9046
9047 // If the were originally stripe classes - then we add them back here.
9048 // Note this is not fool proof (for example if not all rows had stripe
9049 // classes - but it's a good effort without getting carried away
9050 ien = settings.asDestroyStripes.length;
9051
9052 if ( ien ) {
9053 jqTbody.children().each( function (i) {
9054 $(this).addClass( settings.asDestroyStripes[i % ien] );
9055 } );
9056 }
9057
9058 /* Remove the settings object from the settings array */
9059 var idx = $.inArray( settings, DataTable.settings );
9060 if ( idx !== -1 ) {
9061 DataTable.settings.splice( idx, 1 );
9062 }
9063 } );
9064 } );
9065
9066
9067 /**
9068 * Version string for plug-ins to check compatibility. Allowed format is
9069 * `a.b.c-d` where: a:int, b:int, c:int, d:string(dev|beta|alpha). `d` is used
9070 * only for non-release builds. See http://semver.org/ for more information.
9071 * @member
9072 * @type string
9073 * @default Version number
9074 */
9075 DataTable.version = "1.10.4";
9076
9077 /**
9078 * Private data store, containing all of the settings objects that are
9079 * created for the tables on a given page.
9080 *
9081 * Note that the `DataTable.settings` object is aliased to
9082 * `jQuery.fn.dataTableExt` through which it may be accessed and
9083 * manipulated, or `jQuery.fn.dataTable.settings`.
9084 * @member
9085 * @type array
9086 * @default []
9087 * @private
9088 */
9089 DataTable.settings = [];
9090
9091 /**
9092 * Object models container, for the various models that DataTables has
9093 * available to it. These models define the objects that are used to hold
9094 * the active state and configuration of the table.
9095 * @namespace
9096 */
9097 DataTable.models = {};
9098
9099
9100
9101 /**
9102 * Template object for the way in which DataTables holds information about
9103 * search information for the global filter and individual column filters.
9104 * @namespace
9105 */
9106 DataTable.models.oSearch = {
9107 /**
9108 * Flag to indicate if the filtering should be case insensitive or not
9109 * @type boolean
9110 * @default true
9111 */
9112 "bCaseInsensitive": true,
9113
9114 /**
9115 * Applied search term
9116 * @type string
9117 * @default <i>Empty string</i>
9118 */
9119 "sSearch": "",
9120
9121 /**
9122 * Flag to indicate if the search term should be interpreted as a
9123 * regular expression (true) or not (false) and therefore and special
9124 * regex characters escaped.
9125 * @type boolean
9126 * @default false
9127 */
9128 "bRegex": false,
9129
9130 /**
9131 * Flag to indicate if DataTables is to use its smart filtering or not.
9132 * @type boolean
9133 * @default true
9134 */
9135 "bSmart": true
9136 };
9137
9138
9139
9140
9141 /**
9142 * Template object for the way in which DataTables holds information about
9143 * each individual row. This is the object format used for the settings
9144 * aoData array.
9145 * @namespace
9146 */
9147 DataTable.models.oRow = {
9148 /**
9149 * TR element for the row
9150 * @type node
9151 * @default null
9152 */
9153 "nTr": null,
9154
9155 /**
9156 * Array of TD elements for each row. This is null until the row has been
9157 * created.
9158 * @type array nodes
9159 * @default []
9160 */
9161 "anCells": null,
9162
9163 /**
9164 * Data object from the original data source for the row. This is either
9165 * an array if using the traditional form of DataTables, or an object if
9166 * using mData options. The exact type will depend on the passed in
9167 * data from the data source, or will be an array if using DOM a data
9168 * source.
9169 * @type array|object
9170 * @default []
9171 */
9172 "_aData": [],
9173
9174 /**
9175 * Sorting data cache - this array is ostensibly the same length as the
9176 * number of columns (although each index is generated only as it is
9177 * needed), and holds the data that is used for sorting each column in the
9178 * row. We do this cache generation at the start of the sort in order that
9179 * the formatting of the sort data need be done only once for each cell
9180 * per sort. This array should not be read from or written to by anything
9181 * other than the master sorting methods.
9182 * @type array
9183 * @default null
9184 * @private
9185 */
9186 "_aSortData": null,
9187
9188 /**
9189 * Per cell filtering data cache. As per the sort data cache, used to
9190 * increase the performance of the filtering in DataTables
9191 * @type array
9192 * @default null
9193 * @private
9194 */
9195 "_aFilterData": null,
9196
9197 /**
9198 * Filtering data cache. This is the same as the cell filtering cache, but
9199 * in this case a string rather than an array. This is easily computed with
9200 * a join on `_aFilterData`, but is provided as a cache so the join isn't
9201 * needed on every search (memory traded for performance)
9202 * @type array
9203 * @default null
9204 * @private
9205 */
9206 "_sFilterRow": null,
9207
9208 /**
9209 * Cache of the class name that DataTables has applied to the row, so we
9210 * can quickly look at this variable rather than needing to do a DOM check
9211 * on className for the nTr property.
9212 * @type string
9213 * @default <i>Empty string</i>
9214 * @private
9215 */
9216 "_sRowStripe": "",
9217
9218 /**
9219 * Denote if the original data source was from the DOM, or the data source
9220 * object. This is used for invalidating data, so DataTables can
9221 * automatically read data from the original source, unless uninstructed
9222 * otherwise.
9223 * @type string
9224 * @default null
9225 * @private
9226 */
9227 "src": null
9228 };
9229
9230
9231 /**
9232 * Template object for the column information object in DataTables. This object
9233 * is held in the settings aoColumns array and contains all the information that
9234 * DataTables needs about each individual column.
9235 *
9236 * Note that this object is related to {@link DataTable.defaults.column}
9237 * but this one is the internal data store for DataTables's cache of columns.
9238 * It should NOT be manipulated outside of DataTables. Any configuration should
9239 * be done through the initialisation options.
9240 * @namespace
9241 */
9242 DataTable.models.oColumn = {
9243 /**
9244 * Column index. This could be worked out on-the-fly with $.inArray, but it
9245 * is faster to just hold it as a variable
9246 * @type integer
9247 * @default null
9248 */
9249 "idx": null,
9250
9251 /**
9252 * A list of the columns that sorting should occur on when this column
9253 * is sorted. That this property is an array allows multi-column sorting
9254 * to be defined for a column (for example first name / last name columns
9255 * would benefit from this). The values are integers pointing to the
9256 * columns to be sorted on (typically it will be a single integer pointing
9257 * at itself, but that doesn't need to be the case).
9258 * @type array
9259 */
9260 "aDataSort": null,
9261
9262 /**
9263 * Define the sorting directions that are applied to the column, in sequence
9264 * as the column is repeatedly sorted upon - i.e. the first value is used
9265 * as the sorting direction when the column if first sorted (clicked on).
9266 * Sort it again (click again) and it will move on to the next index.
9267 * Repeat until loop.
9268 * @type array
9269 */
9270 "asSorting": null,
9271
9272 /**
9273 * Flag to indicate if the column is searchable, and thus should be included
9274 * in the filtering or not.
9275 * @type boolean
9276 */
9277 "bSearchable": null,
9278
9279 /**
9280 * Flag to indicate if the column is sortable or not.
9281 * @type boolean
9282 */
9283 "bSortable": null,
9284
9285 /**
9286 * Flag to indicate if the column is currently visible in the table or not
9287 * @type boolean
9288 */
9289 "bVisible": null,
9290
9291 /**
9292 * Store for manual type assignment using the `column.type` option. This
9293 * is held in store so we can manipulate the column's `sType` property.
9294 * @type string
9295 * @default null
9296 * @private
9297 */
9298 "_sManualType": null,
9299
9300 /**
9301 * Flag to indicate if HTML5 data attributes should be used as the data
9302 * source for filtering or sorting. True is either are.
9303 * @type boolean
9304 * @default false
9305 * @private
9306 */
9307 "_bAttrSrc": false,
9308
9309 /**
9310 * Developer definable function that is called whenever a cell is created (Ajax source,
9311 * etc) or processed for input (DOM source). This can be used as a compliment to mRender
9312 * allowing you to modify the DOM element (add background colour for example) when the
9313 * element is available.
9314 * @type function
9315 * @param {element} nTd The TD node that has been created
9316 * @param {*} sData The Data for the cell
9317 * @param {array|object} oData The data for the whole row
9318 * @param {int} iRow The row index for the aoData data store
9319 * @default null
9320 */
9321 "fnCreatedCell": null,
9322
9323 /**
9324 * Function to get data from a cell in a column. You should <b>never</b>
9325 * access data directly through _aData internally in DataTables - always use
9326 * the method attached to this property. It allows mData to function as
9327 * required. This function is automatically assigned by the column
9328 * initialisation method
9329 * @type function
9330 * @param {array|object} oData The data array/object for the array
9331 * (i.e. aoData[]._aData)
9332 * @param {string} sSpecific The specific data type you want to get -
9333 * 'display', 'type' 'filter' 'sort'
9334 * @returns {*} The data for the cell from the given row's data
9335 * @default null
9336 */
9337 "fnGetData": null,
9338
9339 /**
9340 * Function to set data for a cell in the column. You should <b>never</b>
9341 * set the data directly to _aData internally in DataTables - always use
9342 * this method. It allows mData to function as required. This function
9343 * is automatically assigned by the column initialisation method
9344 * @type function
9345 * @param {array|object} oData The data array/object for the array
9346 * (i.e. aoData[]._aData)
9347 * @param {*} sValue Value to set
9348 * @default null
9349 */
9350 "fnSetData": null,
9351
9352 /**
9353 * Property to read the value for the cells in the column from the data
9354 * source array / object. If null, then the default content is used, if a
9355 * function is given then the return from the function is used.
9356 * @type function|int|string|null
9357 * @default null
9358 */
9359 "mData": null,
9360
9361 /**
9362 * Partner property to mData which is used (only when defined) to get
9363 * the data - i.e. it is basically the same as mData, but without the
9364 * 'set' option, and also the data fed to it is the result from mData.
9365 * This is the rendering method to match the data method of mData.
9366 * @type function|int|string|null
9367 * @default null
9368 */
9369 "mRender": null,
9370
9371 /**
9372 * Unique header TH/TD element for this column - this is what the sorting
9373 * listener is attached to (if sorting is enabled.)
9374 * @type node
9375 * @default null
9376 */
9377 "nTh": null,
9378
9379 /**
9380 * Unique footer TH/TD element for this column (if there is one). Not used
9381 * in DataTables as such, but can be used for plug-ins to reference the
9382 * footer for each column.
9383 * @type node
9384 * @default null
9385 */
9386 "nTf": null,
9387
9388 /**
9389 * The class to apply to all TD elements in the table's TBODY for the column
9390 * @type string
9391 * @default null
9392 */
9393 "sClass": null,
9394
9395 /**
9396 * When DataTables calculates the column widths to assign to each column,
9397 * it finds the longest string in each column and then constructs a
9398 * temporary table and reads the widths from that. The problem with this
9399 * is that "mmm" is much wider then "iiii", but the latter is a longer
9400 * string - thus the calculation can go wrong (doing it properly and putting
9401 * it into an DOM object and measuring that is horribly(!) slow). Thus as
9402 * a "work around" we provide this option. It will append its value to the
9403 * text that is found to be the longest string for the column - i.e. padding.
9404 * @type string
9405 */
9406 "sContentPadding": null,
9407
9408 /**
9409 * Allows a default value to be given for a column's data, and will be used
9410 * whenever a null data source is encountered (this can be because mData
9411 * is set to null, or because the data source itself is null).
9412 * @type string
9413 * @default null
9414 */
9415 "sDefaultContent": null,
9416
9417 /**
9418 * Name for the column, allowing reference to the column by name as well as
9419 * by index (needs a lookup to work by name).
9420 * @type string
9421 */
9422 "sName": null,
9423
9424 /**
9425 * Custom sorting data type - defines which of the available plug-ins in
9426 * afnSortData the custom sorting will use - if any is defined.
9427 * @type string
9428 * @default std
9429 */
9430 "sSortDataType": 'std',
9431
9432 /**
9433 * Class to be applied to the header element when sorting on this column
9434 * @type string
9435 * @default null
9436 */
9437 "sSortingClass": null,
9438
9439 /**
9440 * Class to be applied to the header element when sorting on this column -
9441 * when jQuery UI theming is used.
9442 * @type string
9443 * @default null
9444 */
9445 "sSortingClassJUI": null,
9446
9447 /**
9448 * Title of the column - what is seen in the TH element (nTh).
9449 * @type string
9450 */
9451 "sTitle": null,
9452
9453 /**
9454 * Column sorting and filtering type
9455 * @type string
9456 * @default null
9457 */
9458 "sType": null,
9459
9460 /**
9461 * Width of the column
9462 * @type string
9463 * @default null
9464 */
9465 "sWidth": null,
9466
9467 /**
9468 * Width of the column when it was first "encountered"
9469 * @type string
9470 * @default null
9471 */
9472 "sWidthOrig": null
9473 };
9474
9475
9476 /*
9477 * Developer note: The properties of the object below are given in Hungarian
9478 * notation, that was used as the interface for DataTables prior to v1.10, however
9479 * from v1.10 onwards the primary interface is camel case. In order to avoid
9480 * breaking backwards compatibility utterly with this change, the Hungarian
9481 * version is still, internally the primary interface, but is is not documented
9482 * - hence the @name tags in each doc comment. This allows a Javascript function
9483 * to create a map from Hungarian notation to camel case (going the other direction
9484 * would require each property to be listed, which would at around 3K to the size
9485 * of DataTables, while this method is about a 0.5K hit.
9486 *
9487 * Ultimately this does pave the way for Hungarian notation to be dropped
9488 * completely, but that is a massive amount of work and will break current
9489 * installs (therefore is on-hold until v2).
9490 */
9491
9492 /**
9493 * Initialisation options that can be given to DataTables at initialisation
9494 * time.
9495 * @namespace
9496 */
9497 DataTable.defaults = {
9498 /**
9499 * An array of data to use for the table, passed in at initialisation which
9500 * will be used in preference to any data which is already in the DOM. This is
9501 * particularly useful for constructing tables purely in Javascript, for
9502 * example with a custom Ajax call.
9503 * @type array
9504 * @default null
9505 *
9506 * @dtopt Option
9507 * @name DataTable.defaults.data
9508 *
9509 * @example
9510 * // Using a 2D array data source
9511 * $(document).ready( function () {
9512 * $('#example').dataTable( {
9513 * "data": [
9514 * ['Trident', 'Internet Explorer 4.0', 'Win 95+', 4, 'X'],
9515 * ['Trident', 'Internet Explorer 5.0', 'Win 95+', 5, 'C'],
9516 * ],
9517 * "columns": [
9518 * { "title": "Engine" },
9519 * { "title": "Browser" },
9520 * { "title": "Platform" },
9521 * { "title": "Version" },
9522 * { "title": "Grade" }
9523 * ]
9524 * } );
9525 * } );
9526 *
9527 * @example
9528 * // Using an array of objects as a data source (`data`)
9529 * $(document).ready( function () {
9530 * $('#example').dataTable( {
9531 * "data": [
9532 * {
9533 * "engine": "Trident",
9534 * "browser": "Internet Explorer 4.0",
9535 * "platform": "Win 95+",
9536 * "version": 4,
9537 * "grade": "X"
9538 * },
9539 * {
9540 * "engine": "Trident",
9541 * "browser": "Internet Explorer 5.0",
9542 * "platform": "Win 95+",
9543 * "version": 5,
9544 * "grade": "C"
9545 * }
9546 * ],
9547 * "columns": [
9548 * { "title": "Engine", "data": "engine" },
9549 * { "title": "Browser", "data": "browser" },
9550 * { "title": "Platform", "data": "platform" },
9551 * { "title": "Version", "data": "version" },
9552 * { "title": "Grade", "data": "grade" }
9553 * ]
9554 * } );
9555 * } );
9556 */
9557 "aaData": null,
9558
9559
9560 /**
9561 * If ordering is enabled, then DataTables will perform a first pass sort on
9562 * initialisation. You can define which column(s) the sort is performed
9563 * upon, and the sorting direction, with this variable. The `sorting` array
9564 * should contain an array for each column to be sorted initially containing
9565 * the column's index and a direction string ('asc' or 'desc').
9566 * @type array
9567 * @default [[0,'asc']]
9568 *
9569 * @dtopt Option
9570 * @name DataTable.defaults.order
9571 *
9572 * @example
9573 * // Sort by 3rd column first, and then 4th column
9574 * $(document).ready( function() {
9575 * $('#example').dataTable( {
9576 * "order": [[2,'asc'], [3,'desc']]
9577 * } );
9578 * } );
9579 *
9580 * // No initial sorting
9581 * $(document).ready( function() {
9582 * $('#example').dataTable( {
9583 * "order": []
9584 * } );
9585 * } );
9586 */
9587 "aaSorting": [[0,'asc']],
9588
9589
9590 /**
9591 * This parameter is basically identical to the `sorting` parameter, but
9592 * cannot be overridden by user interaction with the table. What this means
9593 * is that you could have a column (visible or hidden) which the sorting
9594 * will always be forced on first - any sorting after that (from the user)
9595 * will then be performed as required. This can be useful for grouping rows
9596 * together.
9597 * @type array
9598 * @default null
9599 *
9600 * @dtopt Option
9601 * @name DataTable.defaults.orderFixed
9602 *
9603 * @example
9604 * $(document).ready( function() {
9605 * $('#example').dataTable( {
9606 * "orderFixed": [[0,'asc']]
9607 * } );
9608 * } )
9609 */
9610 "aaSortingFixed": [],
9611
9612
9613 /**
9614 * DataTables can be instructed to load data to display in the table from a
9615 * Ajax source. This option defines how that Ajax call is made and where to.
9616 *
9617 * The `ajax` property has three different modes of operation, depending on
9618 * how it is defined. These are:
9619 *
9620 * * `string` - Set the URL from where the data should be loaded from.
9621 * * `object` - Define properties for `jQuery.ajax`.
9622 * * `function` - Custom data get function
9623 *
9624 * `string`
9625 * --------
9626 *
9627 * As a string, the `ajax` property simply defines the URL from which
9628 * DataTables will load data.
9629 *
9630 * `object`
9631 * --------
9632 *
9633 * As an object, the parameters in the object are passed to
9634 * [jQuery.ajax](http://api.jquery.com/jQuery.ajax/) allowing fine control
9635 * of the Ajax request. DataTables has a number of default parameters which
9636 * you can override using this option. Please refer to the jQuery
9637 * documentation for a full description of the options available, although
9638 * the following parameters provide additional options in DataTables or
9639 * require special consideration:
9640 *
9641 * * `data` - As with jQuery, `data` can be provided as an object, but it
9642 * can also be used as a function to manipulate the data DataTables sends
9643 * to the server. The function takes a single parameter, an object of
9644 * parameters with the values that DataTables has readied for sending. An
9645 * object may be returned which will be merged into the DataTables
9646 * defaults, or you can add the items to the object that was passed in and
9647 * not return anything from the function. This supersedes `fnServerParams`
9648 * from DataTables 1.9-.
9649 *
9650 * * `dataSrc` - By default DataTables will look for the property `data` (or
9651 * `aaData` for compatibility with DataTables 1.9-) when obtaining data
9652 * from an Ajax source or for server-side processing - this parameter
9653 * allows that property to be changed. You can use Javascript dotted
9654 * object notation to get a data source for multiple levels of nesting, or
9655 * it my be used as a function. As a function it takes a single parameter,
9656 * the JSON returned from the server, which can be manipulated as
9657 * required, with the returned value being that used by DataTables as the
9658 * data source for the table. This supersedes `sAjaxDataProp` from
9659 * DataTables 1.9-.
9660 *
9661 * * `success` - Should not be overridden it is used internally in
9662 * DataTables. To manipulate / transform the data returned by the server
9663 * use `ajax.dataSrc`, or use `ajax` as a function (see below).
9664 *
9665 * `function`
9666 * ----------
9667 *
9668 * As a function, making the Ajax call is left up to yourself allowing
9669 * complete control of the Ajax request. Indeed, if desired, a method other
9670 * than Ajax could be used to obtain the required data, such as Web storage
9671 * or an AIR database.
9672 *
9673 * The function is given four parameters and no return is required. The
9674 * parameters are:
9675 *
9676 * 1. _object_ - Data to send to the server
9677 * 2. _function_ - Callback function that must be executed when the required
9678 * data has been obtained. That data should be passed into the callback
9679 * as the only parameter
9680 * 3. _object_ - DataTables settings object for the table
9681 *
9682 * Note that this supersedes `fnServerData` from DataTables 1.9-.
9683 *
9684 * @type string|object|function
9685 * @default null
9686 *
9687 * @dtopt Option
9688 * @name DataTable.defaults.ajax
9689 * @since 1.10.0
9690 *
9691 * @example
9692 * // Get JSON data from a file via Ajax.
9693 * // Note DataTables expects data in the form `{ data: [ ...data... ] }` by default).
9694 * $('#example').dataTable( {
9695 * "ajax": "data.json"
9696 * } );
9697 *
9698 * @example
9699 * // Get JSON data from a file via Ajax, using `dataSrc` to change
9700 * // `data` to `tableData` (i.e. `{ tableData: [ ...data... ] }`)
9701 * $('#example').dataTable( {
9702 * "ajax": {
9703 * "url": "data.json",
9704 * "dataSrc": "tableData"
9705 * }
9706 * } );
9707 *
9708 * @example
9709 * // Get JSON data from a file via Ajax, using `dataSrc` to read data
9710 * // from a plain array rather than an array in an object
9711 * $('#example').dataTable( {
9712 * "ajax": {
9713 * "url": "data.json",
9714 * "dataSrc": ""
9715 * }
9716 * } );
9717 *
9718 * @example
9719 * // Manipulate the data returned from the server - add a link to data
9720 * // (note this can, should, be done using `render` for the column - this
9721 * // is just a simple example of how the data can be manipulated).
9722 * $('#example').dataTable( {
9723 * "ajax": {
9724 * "url": "data.json",
9725 * "dataSrc": function ( json ) {
9726 * for ( var i=0, ien=json.length ; i<ien ; i++ ) {
9727 * json[i][0] = '<a href="/message/'+json[i][0]+'>View message</a>';
9728 * }
9729 * return json;
9730 * }
9731 * }
9732 * } );
9733 *
9734 * @example
9735 * // Add data to the request
9736 * $('#example').dataTable( {
9737 * "ajax": {
9738 * "url": "data.json",
9739 * "data": function ( d ) {
9740 * return {
9741 * "extra_search": $('#extra').val()
9742 * };
9743 * }
9744 * }
9745 * } );
9746 *
9747 * @example
9748 * // Send request as POST
9749 * $('#example').dataTable( {
9750 * "ajax": {
9751 * "url": "data.json",
9752 * "type": "POST"
9753 * }
9754 * } );
9755 *
9756 * @example
9757 * // Get the data from localStorage (could interface with a form for
9758 * // adding, editing and removing rows).
9759 * $('#example').dataTable( {
9760 * "ajax": function (data, callback, settings) {
9761 * callback(
9762 * JSON.parse( localStorage.getItem('dataTablesData') )
9763 * );
9764 * }
9765 * } );
9766 */
9767 "ajax": null,
9768
9769
9770 /**
9771 * This parameter allows you to readily specify the entries in the length drop
9772 * down menu that DataTables shows when pagination is enabled. It can be
9773 * either a 1D array of options which will be used for both the displayed
9774 * option and the value, or a 2D array which will use the array in the first
9775 * position as the value, and the array in the second position as the
9776 * displayed options (useful for language strings such as 'All').
9777 *
9778 * Note that the `pageLength` property will be automatically set to the
9779 * first value given in this array, unless `pageLength` is also provided.
9780 * @type array
9781 * @default [ 10, 25, 50, 100 ]
9782 *
9783 * @dtopt Option
9784 * @name DataTable.defaults.lengthMenu
9785 *
9786 * @example
9787 * $(document).ready( function() {
9788 * $('#example').dataTable( {
9789 * "lengthMenu": [[10, 25, 50, -1], [10, 25, 50, "All"]]
9790 * } );
9791 * } );
9792 */
9793 "aLengthMenu": [ 10, 25, 50, 100 ],
9794
9795
9796 /**
9797 * The `columns` option in the initialisation parameter allows you to define
9798 * details about the way individual columns behave. For a full list of
9799 * column options that can be set, please see
9800 * {@link DataTable.defaults.column}. Note that if you use `columns` to
9801 * define your columns, you must have an entry in the array for every single
9802 * column that you have in your table (these can be null if you don't which
9803 * to specify any options).
9804 * @member
9805 *
9806 * @name DataTable.defaults.column
9807 */
9808 "aoColumns": null,
9809
9810 /**
9811 * Very similar to `columns`, `columnDefs` allows you to target a specific
9812 * column, multiple columns, or all columns, using the `targets` property of
9813 * each object in the array. This allows great flexibility when creating
9814 * tables, as the `columnDefs` arrays can be of any length, targeting the
9815 * columns you specifically want. `columnDefs` may use any of the column
9816 * options available: {@link DataTable.defaults.column}, but it _must_
9817 * have `targets` defined in each object in the array. Values in the `targets`
9818 * array may be:
9819 * <ul>
9820 * <li>a string - class name will be matched on the TH for the column</li>
9821 * <li>0 or a positive integer - column index counting from the left</li>
9822 * <li>a negative integer - column index counting from the right</li>
9823 * <li>the string "_all" - all columns (i.e. assign a default)</li>
9824 * </ul>
9825 * @member
9826 *
9827 * @name DataTable.defaults.columnDefs
9828 */
9829 "aoColumnDefs": null,
9830
9831
9832 /**
9833 * Basically the same as `search`, this parameter defines the individual column
9834 * filtering state at initialisation time. The array must be of the same size
9835 * as the number of columns, and each element be an object with the parameters
9836 * `search` and `escapeRegex` (the latter is optional). 'null' is also
9837 * accepted and the default will be used.
9838 * @type array
9839 * @default []
9840 *
9841 * @dtopt Option
9842 * @name DataTable.defaults.searchCols
9843 *
9844 * @example
9845 * $(document).ready( function() {
9846 * $('#example').dataTable( {
9847 * "searchCols": [
9848 * null,
9849 * { "search": "My filter" },
9850 * null,
9851 * { "search": "^[0-9]", "escapeRegex": false }
9852 * ]
9853 * } );
9854 * } )
9855 */
9856 "aoSearchCols": [],
9857
9858
9859 /**
9860 * An array of CSS classes that should be applied to displayed rows. This
9861 * array may be of any length, and DataTables will apply each class
9862 * sequentially, looping when required.
9863 * @type array
9864 * @default null <i>Will take the values determined by the `oClasses.stripe*`
9865 * options</i>
9866 *
9867 * @dtopt Option
9868 * @name DataTable.defaults.stripeClasses
9869 *
9870 * @example
9871 * $(document).ready( function() {
9872 * $('#example').dataTable( {
9873 * "stripeClasses": [ 'strip1', 'strip2', 'strip3' ]
9874 * } );
9875 * } )
9876 */
9877 "asStripeClasses": null,
9878
9879
9880 /**
9881 * Enable or disable automatic column width calculation. This can be disabled
9882 * as an optimisation (it takes some time to calculate the widths) if the
9883 * tables widths are passed in using `columns`.
9884 * @type boolean
9885 * @default true
9886 *
9887 * @dtopt Features
9888 * @name DataTable.defaults.autoWidth
9889 *
9890 * @example
9891 * $(document).ready( function () {
9892 * $('#example').dataTable( {
9893 * "autoWidth": false
9894 * } );
9895 * } );
9896 */
9897 "bAutoWidth": true,
9898
9899
9900 /**
9901 * Deferred rendering can provide DataTables with a huge speed boost when you
9902 * are using an Ajax or JS data source for the table. This option, when set to
9903 * true, will cause DataTables to defer the creation of the table elements for
9904 * each row until they are needed for a draw - saving a significant amount of
9905 * time.
9906 * @type boolean
9907 * @default false
9908 *
9909 * @dtopt Features
9910 * @name DataTable.defaults.deferRender
9911 *
9912 * @example
9913 * $(document).ready( function() {
9914 * $('#example').dataTable( {
9915 * "ajax": "sources/arrays.txt",
9916 * "deferRender": true
9917 * } );
9918 * } );
9919 */
9920 "bDeferRender": false,
9921
9922
9923 /**
9924 * Replace a DataTable which matches the given selector and replace it with
9925 * one which has the properties of the new initialisation object passed. If no
9926 * table matches the selector, then the new DataTable will be constructed as
9927 * per normal.
9928 * @type boolean
9929 * @default false
9930 *
9931 * @dtopt Options
9932 * @name DataTable.defaults.destroy
9933 *
9934 * @example
9935 * $(document).ready( function() {
9936 * $('#example').dataTable( {
9937 * "srollY": "200px",
9938 * "paginate": false
9939 * } );
9940 *
9941 * // Some time later....
9942 * $('#example').dataTable( {
9943 * "filter": false,
9944 * "destroy": true
9945 * } );
9946 * } );
9947 */
9948 "bDestroy": false,
9949
9950
9951 /**
9952 * Enable or disable filtering of data. Filtering in DataTables is "smart" in
9953 * that it allows the end user to input multiple words (space separated) and
9954 * will match a row containing those words, even if not in the order that was
9955 * specified (this allow matching across multiple columns). Note that if you
9956 * wish to use filtering in DataTables this must remain 'true' - to remove the
9957 * default filtering input box and retain filtering abilities, please use
9958 * {@link DataTable.defaults.dom}.
9959 * @type boolean
9960 * @default true
9961 *
9962 * @dtopt Features
9963 * @name DataTable.defaults.searching
9964 *
9965 * @example
9966 * $(document).ready( function () {
9967 * $('#example').dataTable( {
9968 * "searching": false
9969 * } );
9970 * } );
9971 */
9972 "bFilter": true,
9973
9974
9975 /**
9976 * Enable or disable the table information display. This shows information
9977 * about the data that is currently visible on the page, including information
9978 * about filtered data if that action is being performed.
9979 * @type boolean
9980 * @default true
9981 *
9982 * @dtopt Features
9983 * @name DataTable.defaults.info
9984 *
9985 * @example
9986 * $(document).ready( function () {
9987 * $('#example').dataTable( {
9988 * "info": false
9989 * } );
9990 * } );
9991 */
9992 "bInfo": true,
9993
9994
9995 /**
9996 * Enable jQuery UI ThemeRoller support (required as ThemeRoller requires some
9997 * slightly different and additional mark-up from what DataTables has
9998 * traditionally used).
9999 * @type boolean
10000 * @default false
10001 *
10002 * @dtopt Features
10003 * @name DataTable.defaults.jQueryUI
10004 *
10005 * @example
10006 * $(document).ready( function() {
10007 * $('#example').dataTable( {
10008 * "jQueryUI": true
10009 * } );
10010 * } );
10011 */
10012 "bJQueryUI": false,
10013
10014
10015 /**
10016 * Allows the end user to select the size of a formatted page from a select
10017 * menu (sizes are 10, 25, 50 and 100). Requires pagination (`paginate`).
10018 * @type boolean
10019 * @default true
10020 *
10021 * @dtopt Features
10022 * @name DataTable.defaults.lengthChange
10023 *
10024 * @example
10025 * $(document).ready( function () {
10026 * $('#example').dataTable( {
10027 * "lengthChange": false
10028 * } );
10029 * } );
10030 */
10031 "bLengthChange": true,
10032
10033
10034 /**
10035 * Enable or disable pagination.
10036 * @type boolean
10037 * @default true
10038 *
10039 * @dtopt Features
10040 * @name DataTable.defaults.paging
10041 *
10042 * @example
10043 * $(document).ready( function () {
10044 * $('#example').dataTable( {
10045 * "paging": false
10046 * } );
10047 * } );
10048 */
10049 "bPaginate": true,
10050
10051
10052 /**
10053 * Enable or disable the display of a 'processing' indicator when the table is
10054 * being processed (e.g. a sort). This is particularly useful for tables with
10055 * large amounts of data where it can take a noticeable amount of time to sort
10056 * the entries.
10057 * @type boolean
10058 * @default false
10059 *
10060 * @dtopt Features
10061 * @name DataTable.defaults.processing
10062 *
10063 * @example
10064 * $(document).ready( function () {
10065 * $('#example').dataTable( {
10066 * "processing": true
10067 * } );
10068 * } );
10069 */
10070 "bProcessing": false,
10071
10072
10073 /**
10074 * Retrieve the DataTables object for the given selector. Note that if the
10075 * table has already been initialised, this parameter will cause DataTables
10076 * to simply return the object that has already been set up - it will not take
10077 * account of any changes you might have made to the initialisation object
10078 * passed to DataTables (setting this parameter to true is an acknowledgement
10079 * that you understand this). `destroy` can be used to reinitialise a table if
10080 * you need.
10081 * @type boolean
10082 * @default false
10083 *
10084 * @dtopt Options
10085 * @name DataTable.defaults.retrieve
10086 *
10087 * @example
10088 * $(document).ready( function() {
10089 * initTable();
10090 * tableActions();
10091 * } );
10092 *
10093 * function initTable ()
10094 * {
10095 * return $('#example').dataTable( {
10096 * "scrollY": "200px",
10097 * "paginate": false,
10098 * "retrieve": true
10099 * } );
10100 * }
10101 *
10102 * function tableActions ()
10103 * {
10104 * var table = initTable();
10105 * // perform API operations with oTable
10106 * }
10107 */
10108 "bRetrieve": false,
10109
10110
10111 /**
10112 * When vertical (y) scrolling is enabled, DataTables will force the height of
10113 * the table's viewport to the given height at all times (useful for layout).
10114 * However, this can look odd when filtering data down to a small data set,
10115 * and the footer is left "floating" further down. This parameter (when
10116 * enabled) will cause DataTables to collapse the table's viewport down when
10117 * the result set will fit within the given Y height.
10118 * @type boolean
10119 * @default false
10120 *
10121 * @dtopt Options
10122 * @name DataTable.defaults.scrollCollapse
10123 *
10124 * @example
10125 * $(document).ready( function() {
10126 * $('#example').dataTable( {
10127 * "scrollY": "200",
10128 * "scrollCollapse": true
10129 * } );
10130 * } );
10131 */
10132 "bScrollCollapse": false,
10133
10134
10135 /**
10136 * Configure DataTables to use server-side processing. Note that the
10137 * `ajax` parameter must also be given in order to give DataTables a
10138 * source to obtain the required data for each draw.
10139 * @type boolean
10140 * @default false
10141 *
10142 * @dtopt Features
10143 * @dtopt Server-side
10144 * @name DataTable.defaults.serverSide
10145 *
10146 * @example
10147 * $(document).ready( function () {
10148 * $('#example').dataTable( {
10149 * "serverSide": true,
10150 * "ajax": "xhr.php"
10151 * } );
10152 * } );
10153 */
10154 "bServerSide": false,
10155
10156
10157 /**
10158 * Enable or disable sorting of columns. Sorting of individual columns can be
10159 * disabled by the `sortable` option for each column.
10160 * @type boolean
10161 * @default true
10162 *
10163 * @dtopt Features
10164 * @name DataTable.defaults.ordering
10165 *
10166 * @example
10167 * $(document).ready( function () {
10168 * $('#example').dataTable( {
10169 * "ordering": false
10170 * } );
10171 * } );
10172 */
10173 "bSort": true,
10174
10175
10176 /**
10177 * Enable or display DataTables' ability to sort multiple columns at the
10178 * same time (activated by shift-click by the user).
10179 * @type boolean
10180 * @default true
10181 *
10182 * @dtopt Options
10183 * @name DataTable.defaults.orderMulti
10184 *
10185 * @example
10186 * // Disable multiple column sorting ability
10187 * $(document).ready( function () {
10188 * $('#example').dataTable( {
10189 * "orderMulti": false
10190 * } );
10191 * } );
10192 */
10193 "bSortMulti": true,
10194
10195
10196 /**
10197 * Allows control over whether DataTables should use the top (true) unique
10198 * cell that is found for a single column, or the bottom (false - default).
10199 * This is useful when using complex headers.
10200 * @type boolean
10201 * @default false
10202 *
10203 * @dtopt Options
10204 * @name DataTable.defaults.orderCellsTop
10205 *
10206 * @example
10207 * $(document).ready( function() {
10208 * $('#example').dataTable( {
10209 * "orderCellsTop": true
10210 * } );
10211 * } );
10212 */
10213 "bSortCellsTop": false,
10214
10215
10216 /**
10217 * Enable or disable the addition of the classes `sorting\_1`, `sorting\_2` and
10218 * `sorting\_3` to the columns which are currently being sorted on. This is
10219 * presented as a feature switch as it can increase processing time (while
10220 * classes are removed and added) so for large data sets you might want to
10221 * turn this off.
10222 * @type boolean
10223 * @default true
10224 *
10225 * @dtopt Features
10226 * @name DataTable.defaults.orderClasses
10227 *
10228 * @example
10229 * $(document).ready( function () {
10230 * $('#example').dataTable( {
10231 * "orderClasses": false
10232 * } );
10233 * } );
10234 */
10235 "bSortClasses": true,
10236
10237
10238 /**
10239 * Enable or disable state saving. When enabled HTML5 `localStorage` will be
10240 * used to save table display information such as pagination information,
10241 * display length, filtering and sorting. As such when the end user reloads
10242 * the page the display display will match what thy had previously set up.
10243 *
10244 * Due to the use of `localStorage` the default state saving is not supported
10245 * in IE6 or 7. If state saving is required in those browsers, use
10246 * `stateSaveCallback` to provide a storage solution such as cookies.
10247 * @type boolean
10248 * @default false
10249 *
10250 * @dtopt Features
10251 * @name DataTable.defaults.stateSave
10252 *
10253 * @example
10254 * $(document).ready( function () {
10255 * $('#example').dataTable( {
10256 * "stateSave": true
10257 * } );
10258 * } );
10259 */
10260 "bStateSave": false,
10261
10262
10263 /**
10264 * This function is called when a TR element is created (and all TD child
10265 * elements have been inserted), or registered if using a DOM source, allowing
10266 * manipulation of the TR element (adding classes etc).
10267 * @type function
10268 * @param {node} row "TR" element for the current row
10269 * @param {array} data Raw data array for this row
10270 * @param {int} dataIndex The index of this row in the internal aoData array
10271 *
10272 * @dtopt Callbacks
10273 * @name DataTable.defaults.createdRow
10274 *
10275 * @example
10276 * $(document).ready( function() {
10277 * $('#example').dataTable( {
10278 * "createdRow": function( row, data, dataIndex ) {
10279 * // Bold the grade for all 'A' grade browsers
10280 * if ( data[4] == "A" )
10281 * {
10282 * $('td:eq(4)', row).html( '<b>A</b>' );
10283 * }
10284 * }
10285 * } );
10286 * } );
10287 */
10288 "fnCreatedRow": null,
10289
10290
10291 /**
10292 * This function is called on every 'draw' event, and allows you to
10293 * dynamically modify any aspect you want about the created DOM.
10294 * @type function
10295 * @param {object} settings DataTables settings object
10296 *
10297 * @dtopt Callbacks
10298 * @name DataTable.defaults.drawCallback
10299 *
10300 * @example
10301 * $(document).ready( function() {
10302 * $('#example').dataTable( {
10303 * "drawCallback": function( settings ) {
10304 * alert( 'DataTables has redrawn the table' );
10305 * }
10306 * } );
10307 * } );
10308 */
10309 "fnDrawCallback": null,
10310
10311
10312 /**
10313 * Identical to fnHeaderCallback() but for the table footer this function
10314 * allows you to modify the table footer on every 'draw' event.
10315 * @type function
10316 * @param {node} foot "TR" element for the footer
10317 * @param {array} data Full table data (as derived from the original HTML)
10318 * @param {int} start Index for the current display starting point in the
10319 * display array
10320 * @param {int} end Index for the current display ending point in the
10321 * display array
10322 * @param {array int} display Index array to translate the visual position
10323 * to the full data array
10324 *
10325 * @dtopt Callbacks
10326 * @name DataTable.defaults.footerCallback
10327 *
10328 * @example
10329 * $(document).ready( function() {
10330 * $('#example').dataTable( {
10331 * "footerCallback": function( tfoot, data, start, end, display ) {
10332 * tfoot.getElementsByTagName('th')[0].innerHTML = "Starting index is "+start;
10333 * }
10334 * } );
10335 * } )
10336 */
10337 "fnFooterCallback": null,
10338
10339
10340 /**
10341 * When rendering large numbers in the information element for the table
10342 * (i.e. "Showing 1 to 10 of 57 entries") DataTables will render large numbers
10343 * to have a comma separator for the 'thousands' units (e.g. 1 million is
10344 * rendered as "1,000,000") to help readability for the end user. This
10345 * function will override the default method DataTables uses.
10346 * @type function
10347 * @member
10348 * @param {int} toFormat number to be formatted
10349 * @returns {string} formatted string for DataTables to show the number
10350 *
10351 * @dtopt Callbacks
10352 * @name DataTable.defaults.formatNumber
10353 *
10354 * @example
10355 * // Format a number using a single quote for the separator (note that
10356 * // this can also be done with the language.thousands option)
10357 * $(document).ready( function() {
10358 * $('#example').dataTable( {
10359 * "formatNumber": function ( toFormat ) {
10360 * return toFormat.toString().replace(
10361 * /\B(?=(\d{3})+(?!\d))/g, "'"
10362 * );
10363 * };
10364 * } );
10365 * } );
10366 */
10367 "fnFormatNumber": function ( toFormat ) {
10368 return toFormat.toString().replace(
10369 /\B(?=(\d{3})+(?!\d))/g,
10370 this.oLanguage.sThousands
10371 );
10372 },
10373
10374
10375 /**
10376 * This function is called on every 'draw' event, and allows you to
10377 * dynamically modify the header row. This can be used to calculate and
10378 * display useful information about the table.
10379 * @type function
10380 * @param {node} head "TR" element for the header
10381 * @param {array} data Full table data (as derived from the original HTML)
10382 * @param {int} start Index for the current display starting point in the
10383 * display array
10384 * @param {int} end Index for the current display ending point in the
10385 * display array
10386 * @param {array int} display Index array to translate the visual position
10387 * to the full data array
10388 *
10389 * @dtopt Callbacks
10390 * @name DataTable.defaults.headerCallback
10391 *
10392 * @example
10393 * $(document).ready( function() {
10394 * $('#example').dataTable( {
10395 * "fheaderCallback": function( head, data, start, end, display ) {
10396 * head.getElementsByTagName('th')[0].innerHTML = "Displaying "+(end-start)+" records";
10397 * }
10398 * } );
10399 * } )
10400 */
10401 "fnHeaderCallback": null,
10402
10403
10404 /**
10405 * The information element can be used to convey information about the current
10406 * state of the table. Although the internationalisation options presented by
10407 * DataTables are quite capable of dealing with most customisations, there may
10408 * be times where you wish to customise the string further. This callback
10409 * allows you to do exactly that.
10410 * @type function
10411 * @param {object} oSettings DataTables settings object
10412 * @param {int} start Starting position in data for the draw
10413 * @param {int} end End position in data for the draw
10414 * @param {int} max Total number of rows in the table (regardless of
10415 * filtering)
10416 * @param {int} total Total number of rows in the data set, after filtering
10417 * @param {string} pre The string that DataTables has formatted using it's
10418 * own rules
10419 * @returns {string} The string to be displayed in the information element.
10420 *
10421 * @dtopt Callbacks
10422 * @name DataTable.defaults.infoCallback
10423 *
10424 * @example
10425 * $('#example').dataTable( {
10426 * "infoCallback": function( settings, start, end, max, total, pre ) {
10427 * return start +" to "+ end;
10428 * }
10429 * } );
10430 */
10431 "fnInfoCallback": null,
10432
10433
10434 /**
10435 * Called when the table has been initialised. Normally DataTables will
10436 * initialise sequentially and there will be no need for this function,
10437 * however, this does not hold true when using external language information
10438 * since that is obtained using an async XHR call.
10439 * @type function
10440 * @param {object} settings DataTables settings object
10441 * @param {object} json The JSON object request from the server - only
10442 * present if client-side Ajax sourced data is used
10443 *
10444 * @dtopt Callbacks
10445 * @name DataTable.defaults.initComplete
10446 *
10447 * @example
10448 * $(document).ready( function() {
10449 * $('#example').dataTable( {
10450 * "initComplete": function(settings, json) {
10451 * alert( 'DataTables has finished its initialisation.' );
10452 * }
10453 * } );
10454 * } )
10455 */
10456 "fnInitComplete": null,
10457
10458
10459 /**
10460 * Called at the very start of each table draw and can be used to cancel the
10461 * draw by returning false, any other return (including undefined) results in
10462 * the full draw occurring).
10463 * @type function
10464 * @param {object} settings DataTables settings object
10465 * @returns {boolean} False will cancel the draw, anything else (including no
10466 * return) will allow it to complete.
10467 *
10468 * @dtopt Callbacks
10469 * @name DataTable.defaults.preDrawCallback
10470 *
10471 * @example
10472 * $(document).ready( function() {
10473 * $('#example').dataTable( {
10474 * "preDrawCallback": function( settings ) {
10475 * if ( $('#test').val() == 1 ) {
10476 * return false;
10477 * }
10478 * }
10479 * } );
10480 * } );
10481 */
10482 "fnPreDrawCallback": null,
10483
10484
10485 /**
10486 * This function allows you to 'post process' each row after it have been
10487 * generated for each table draw, but before it is rendered on screen. This
10488 * function might be used for setting the row class name etc.
10489 * @type function
10490 * @param {node} row "TR" element for the current row
10491 * @param {array} data Raw data array for this row
10492 * @param {int} displayIndex The display index for the current table draw
10493 * @param {int} displayIndexFull The index of the data in the full list of
10494 * rows (after filtering)
10495 *
10496 * @dtopt Callbacks
10497 * @name DataTable.defaults.rowCallback
10498 *
10499 * @example
10500 * $(document).ready( function() {
10501 * $('#example').dataTable( {
10502 * "rowCallback": function( row, data, displayIndex, displayIndexFull ) {
10503 * // Bold the grade for all 'A' grade browsers
10504 * if ( data[4] == "A" ) {
10505 * $('td:eq(4)', row).html( '<b>A</b>' );
10506 * }
10507 * }
10508 * } );
10509 * } );
10510 */
10511 "fnRowCallback": null,
10512
10513
10514 /**
10515 * __Deprecated__ The functionality provided by this parameter has now been
10516 * superseded by that provided through `ajax`, which should be used instead.
10517 *
10518 * This parameter allows you to override the default function which obtains
10519 * the data from the server so something more suitable for your application.
10520 * For example you could use POST data, or pull information from a Gears or
10521 * AIR database.
10522 * @type function
10523 * @member
10524 * @param {string} source HTTP source to obtain the data from (`ajax`)
10525 * @param {array} data A key/value pair object containing the data to send
10526 * to the server
10527 * @param {function} callback to be called on completion of the data get
10528 * process that will draw the data on the page.
10529 * @param {object} settings DataTables settings object
10530 *
10531 * @dtopt Callbacks
10532 * @dtopt Server-side
10533 * @name DataTable.defaults.serverData
10534 *
10535 * @deprecated 1.10. Please use `ajax` for this functionality now.
10536 */
10537 "fnServerData": null,
10538
10539
10540 /**
10541 * __Deprecated__ The functionality provided by this parameter has now been
10542 * superseded by that provided through `ajax`, which should be used instead.
10543 *
10544 * It is often useful to send extra data to the server when making an Ajax
10545 * request - for example custom filtering information, and this callback
10546 * function makes it trivial to send extra information to the server. The
10547 * passed in parameter is the data set that has been constructed by
10548 * DataTables, and you can add to this or modify it as you require.
10549 * @type function
10550 * @param {array} data Data array (array of objects which are name/value
10551 * pairs) that has been constructed by DataTables and will be sent to the
10552 * server. In the case of Ajax sourced data with server-side processing
10553 * this will be an empty array, for server-side processing there will be a
10554 * significant number of parameters!
10555 * @returns {undefined} Ensure that you modify the data array passed in,
10556 * as this is passed by reference.
10557 *
10558 * @dtopt Callbacks
10559 * @dtopt Server-side
10560 * @name DataTable.defaults.serverParams
10561 *
10562 * @deprecated 1.10. Please use `ajax` for this functionality now.
10563 */
10564 "fnServerParams": null,
10565
10566
10567 /**
10568 * Load the table state. With this function you can define from where, and how, the
10569 * state of a table is loaded. By default DataTables will load from `localStorage`
10570 * but you might wish to use a server-side database or cookies.
10571 * @type function
10572 * @member
10573 * @param {object} settings DataTables settings object
10574 * @return {object} The DataTables state object to be loaded
10575 *
10576 * @dtopt Callbacks
10577 * @name DataTable.defaults.stateLoadCallback
10578 *
10579 * @example
10580 * $(document).ready( function() {
10581 * $('#example').dataTable( {
10582 * "stateSave": true,
10583 * "stateLoadCallback": function (settings) {
10584 * var o;
10585 *
10586 * // Send an Ajax request to the server to get the data. Note that
10587 * // this is a synchronous request.
10588 * $.ajax( {
10589 * "url": "/state_load",
10590 * "async": false,
10591 * "dataType": "json",
10592 * "success": function (json) {
10593 * o = json;
10594 * }
10595 * } );
10596 *
10597 * return o;
10598 * }
10599 * } );
10600 * } );
10601 */
10602 "fnStateLoadCallback": function ( settings ) {
10603 try {
10604 return JSON.parse(
10605 (settings.iStateDuration === -1 ? sessionStorage : localStorage).getItem(
10606 'DataTables_'+settings.sInstance+'_'+location.pathname
10607 )
10608 );
10609 } catch (e) {}
10610 },
10611
10612
10613 /**
10614 * Callback which allows modification of the saved state prior to loading that state.
10615 * This callback is called when the table is loading state from the stored data, but
10616 * prior to the settings object being modified by the saved state. Note that for
10617 * plug-in authors, you should use the `stateLoadParams` event to load parameters for
10618 * a plug-in.
10619 * @type function
10620 * @param {object} settings DataTables settings object
10621 * @param {object} data The state object that is to be loaded
10622 *
10623 * @dtopt Callbacks
10624 * @name DataTable.defaults.stateLoadParams
10625 *
10626 * @example
10627 * // Remove a saved filter, so filtering is never loaded
10628 * $(document).ready( function() {
10629 * $('#example').dataTable( {
10630 * "stateSave": true,
10631 * "stateLoadParams": function (settings, data) {
10632 * data.oSearch.sSearch = "";
10633 * }
10634 * } );
10635 * } );
10636 *
10637 * @example
10638 * // Disallow state loading by returning false
10639 * $(document).ready( function() {
10640 * $('#example').dataTable( {
10641 * "stateSave": true,
10642 * "stateLoadParams": function (settings, data) {
10643 * return false;
10644 * }
10645 * } );
10646 * } );
10647 */
10648 "fnStateLoadParams": null,
10649
10650
10651 /**
10652 * Callback that is called when the state has been loaded from the state saving method
10653 * and the DataTables settings object has been modified as a result of the loaded state.
10654 * @type function
10655 * @param {object} settings DataTables settings object
10656 * @param {object} data The state object that was loaded
10657 *
10658 * @dtopt Callbacks
10659 * @name DataTable.defaults.stateLoaded
10660 *
10661 * @example
10662 * // Show an alert with the filtering value that was saved
10663 * $(document).ready( function() {
10664 * $('#example').dataTable( {
10665 * "stateSave": true,
10666 * "stateLoaded": function (settings, data) {
10667 * alert( 'Saved filter was: '+data.oSearch.sSearch );
10668 * }
10669 * } );
10670 * } );
10671 */
10672 "fnStateLoaded": null,
10673
10674
10675 /**
10676 * Save the table state. This function allows you to define where and how the state
10677 * information for the table is stored By default DataTables will use `localStorage`
10678 * but you might wish to use a server-side database or cookies.
10679 * @type function
10680 * @member
10681 * @param {object} settings DataTables settings object
10682 * @param {object} data The state object to be saved
10683 *
10684 * @dtopt Callbacks
10685 * @name DataTable.defaults.stateSaveCallback
10686 *
10687 * @example
10688 * $(document).ready( function() {
10689 * $('#example').dataTable( {
10690 * "stateSave": true,
10691 * "stateSaveCallback": function (settings, data) {
10692 * // Send an Ajax request to the server with the state object
10693 * $.ajax( {
10694 * "url": "/state_save",
10695 * "data": data,
10696 * "dataType": "json",
10697 * "method": "POST"
10698 * "success": function () {}
10699 * } );
10700 * }
10701 * } );
10702 * } );
10703 */
10704 "fnStateSaveCallback": function ( settings, data ) {
10705 try {
10706 (settings.iStateDuration === -1 ? sessionStorage : localStorage).setItem(
10707 'DataTables_'+settings.sInstance+'_'+location.pathname,
10708 JSON.stringify( data )
10709 );
10710 } catch (e) {}
10711 },
10712
10713
10714 /**
10715 * Callback which allows modification of the state to be saved. Called when the table
10716 * has changed state a new state save is required. This method allows modification of
10717 * the state saving object prior to actually doing the save, including addition or
10718 * other state properties or modification. Note that for plug-in authors, you should
10719 * use the `stateSaveParams` event to save parameters for a plug-in.
10720 * @type function
10721 * @param {object} settings DataTables settings object
10722 * @param {object} data The state object to be saved
10723 *
10724 * @dtopt Callbacks
10725 * @name DataTable.defaults.stateSaveParams
10726 *
10727 * @example
10728 * // Remove a saved filter, so filtering is never saved
10729 * $(document).ready( function() {
10730 * $('#example').dataTable( {
10731 * "stateSave": true,
10732 * "stateSaveParams": function (settings, data) {
10733 * data.oSearch.sSearch = "";
10734 * }
10735 * } );
10736 * } );
10737 */
10738 "fnStateSaveParams": null,
10739
10740
10741 /**
10742 * Duration for which the saved state information is considered valid. After this period
10743 * has elapsed the state will be returned to the default.
10744 * Value is given in seconds.
10745 * @type int
10746 * @default 7200 <i>(2 hours)</i>
10747 *
10748 * @dtopt Options
10749 * @name DataTable.defaults.stateDuration
10750 *
10751 * @example
10752 * $(document).ready( function() {
10753 * $('#example').dataTable( {
10754 * "stateDuration": 60*60*24; // 1 day
10755 * } );
10756 * } )
10757 */
10758 "iStateDuration": 7200,
10759
10760
10761 /**
10762 * When enabled DataTables will not make a request to the server for the first
10763 * page draw - rather it will use the data already on the page (no sorting etc
10764 * will be applied to it), thus saving on an XHR at load time. `deferLoading`
10765 * is used to indicate that deferred loading is required, but it is also used
10766 * to tell DataTables how many records there are in the full table (allowing
10767 * the information element and pagination to be displayed correctly). In the case
10768 * where a filtering is applied to the table on initial load, this can be
10769 * indicated by giving the parameter as an array, where the first element is
10770 * the number of records available after filtering and the second element is the
10771 * number of records without filtering (allowing the table information element
10772 * to be shown correctly).
10773 * @type int | array
10774 * @default null
10775 *
10776 * @dtopt Options
10777 * @name DataTable.defaults.deferLoading
10778 *
10779 * @example
10780 * // 57 records available in the table, no filtering applied
10781 * $(document).ready( function() {
10782 * $('#example').dataTable( {
10783 * "serverSide": true,
10784 * "ajax": "scripts/server_processing.php",
10785 * "deferLoading": 57
10786 * } );
10787 * } );
10788 *
10789 * @example
10790 * // 57 records after filtering, 100 without filtering (an initial filter applied)
10791 * $(document).ready( function() {
10792 * $('#example').dataTable( {
10793 * "serverSide": true,
10794 * "ajax": "scripts/server_processing.php",
10795 * "deferLoading": [ 57, 100 ],
10796 * "search": {
10797 * "search": "my_filter"
10798 * }
10799 * } );
10800 * } );
10801 */
10802 "iDeferLoading": null,
10803
10804
10805 /**
10806 * Number of rows to display on a single page when using pagination. If
10807 * feature enabled (`lengthChange`) then the end user will be able to override
10808 * this to a custom setting using a pop-up menu.
10809 * @type int
10810 * @default 10
10811 *
10812 * @dtopt Options
10813 * @name DataTable.defaults.pageLength
10814 *
10815 * @example
10816 * $(document).ready( function() {
10817 * $('#example').dataTable( {
10818 * "pageLength": 50
10819 * } );
10820 * } )
10821 */
10822 "iDisplayLength": 10,
10823
10824
10825 /**
10826 * Define the starting point for data display when using DataTables with
10827 * pagination. Note that this parameter is the number of records, rather than
10828 * the page number, so if you have 10 records per page and want to start on
10829 * the third page, it should be "20".
10830 * @type int
10831 * @default 0
10832 *
10833 * @dtopt Options
10834 * @name DataTable.defaults.displayStart
10835 *
10836 * @example
10837 * $(document).ready( function() {
10838 * $('#example').dataTable( {
10839 * "displayStart": 20
10840 * } );
10841 * } )
10842 */
10843 "iDisplayStart": 0,
10844
10845
10846 /**
10847 * By default DataTables allows keyboard navigation of the table (sorting, paging,
10848 * and filtering) by adding a `tabindex` attribute to the required elements. This
10849 * allows you to tab through the controls and press the enter key to activate them.
10850 * The tabindex is default 0, meaning that the tab follows the flow of the document.
10851 * You can overrule this using this parameter if you wish. Use a value of -1 to
10852 * disable built-in keyboard navigation.
10853 * @type int
10854 * @default 0
10855 *
10856 * @dtopt Options
10857 * @name DataTable.defaults.tabIndex
10858 *
10859 * @example
10860 * $(document).ready( function() {
10861 * $('#example').dataTable( {
10862 * "tabIndex": 1
10863 * } );
10864 * } );
10865 */
10866 "iTabIndex": 0,
10867
10868
10869 /**
10870 * Classes that DataTables assigns to the various components and features
10871 * that it adds to the HTML table. This allows classes to be configured
10872 * during initialisation in addition to through the static
10873 * {@link DataTable.ext.oStdClasses} object).
10874 * @namespace
10875 * @name DataTable.defaults.classes
10876 */
10877 "oClasses": {},
10878
10879
10880 /**
10881 * All strings that DataTables uses in the user interface that it creates
10882 * are defined in this object, allowing you to modified them individually or
10883 * completely replace them all as required.
10884 * @namespace
10885 * @name DataTable.defaults.language
10886 */
10887 "oLanguage": {
10888 /**
10889 * Strings that are used for WAI-ARIA labels and controls only (these are not
10890 * actually visible on the page, but will be read by screenreaders, and thus
10891 * must be internationalised as well).
10892 * @namespace
10893 * @name DataTable.defaults.language.aria
10894 */
10895 "oAria": {
10896 /**
10897 * ARIA label that is added to the table headers when the column may be
10898 * sorted ascending by activing the column (click or return when focused).
10899 * Note that the column header is prefixed to this string.
10900 * @type string
10901 * @default : activate to sort column ascending
10902 *
10903 * @dtopt Language
10904 * @name DataTable.defaults.language.aria.sortAscending
10905 *
10906 * @example
10907 * $(document).ready( function() {
10908 * $('#example').dataTable( {
10909 * "language": {
10910 * "aria": {
10911 * "sortAscending": " - click/return to sort ascending"
10912 * }
10913 * }
10914 * } );
10915 * } );
10916 */
10917 "sSortAscending": ": activate to sort column ascending",
10918
10919 /**
10920 * ARIA label that is added to the table headers when the column may be
10921 * sorted descending by activing the column (click or return when focused).
10922 * Note that the column header is prefixed to this string.
10923 * @type string
10924 * @default : activate to sort column ascending
10925 *
10926 * @dtopt Language
10927 * @name DataTable.defaults.language.aria.sortDescending
10928 *
10929 * @example
10930 * $(document).ready( function() {
10931 * $('#example').dataTable( {
10932 * "language": {
10933 * "aria": {
10934 * "sortDescending": " - click/return to sort descending"
10935 * }
10936 * }
10937 * } );
10938 * } );
10939 */
10940 "sSortDescending": ": activate to sort column descending"
10941 },
10942
10943 /**
10944 * Pagination string used by DataTables for the built-in pagination
10945 * control types.
10946 * @namespace
10947 * @name DataTable.defaults.language.paginate
10948 */
10949 "oPaginate": {
10950 /**
10951 * Text to use when using the 'full_numbers' type of pagination for the
10952 * button to take the user to the first page.
10953 * @type string
10954 * @default First
10955 *
10956 * @dtopt Language
10957 * @name DataTable.defaults.language.paginate.first
10958 *
10959 * @example
10960 * $(document).ready( function() {
10961 * $('#example').dataTable( {
10962 * "language": {
10963 * "paginate": {
10964 * "first": "First page"
10965 * }
10966 * }
10967 * } );
10968 * } );
10969 */
10970 "sFirst": "First",
10971
10972
10973 /**
10974 * Text to use when using the 'full_numbers' type of pagination for the
10975 * button to take the user to the last page.
10976 * @type string
10977 * @default Last
10978 *
10979 * @dtopt Language
10980 * @name DataTable.defaults.language.paginate.last
10981 *
10982 * @example
10983 * $(document).ready( function() {
10984 * $('#example').dataTable( {
10985 * "language": {
10986 * "paginate": {
10987 * "last": "Last page"
10988 * }
10989 * }
10990 * } );
10991 * } );
10992 */
10993 "sLast": "Last",
10994
10995
10996 /**
10997 * Text to use for the 'next' pagination button (to take the user to the
10998 * next page).
10999 * @type string
11000 * @default Next
11001 *
11002 * @dtopt Language
11003 * @name DataTable.defaults.language.paginate.next
11004 *
11005 * @example
11006 * $(document).ready( function() {
11007 * $('#example').dataTable( {
11008 * "language": {
11009 * "paginate": {
11010 * "next": "Next page"
11011 * }
11012 * }
11013 * } );
11014 * } );
11015 */
11016 "sNext": "Next",
11017
11018
11019 /**
11020 * Text to use for the 'previous' pagination button (to take the user to
11021 * the previous page).
11022 * @type string
11023 * @default Previous
11024 *
11025 * @dtopt Language
11026 * @name DataTable.defaults.language.paginate.previous
11027 *
11028 * @example
11029 * $(document).ready( function() {
11030 * $('#example').dataTable( {
11031 * "language": {
11032 * "paginate": {
11033 * "previous": "Previous page"
11034 * }
11035 * }
11036 * } );
11037 * } );
11038 */
11039 "sPrevious": "Previous"
11040 },
11041
11042 /**
11043 * This string is shown in preference to `zeroRecords` when the table is
11044 * empty of data (regardless of filtering). Note that this is an optional
11045 * parameter - if it is not given, the value of `zeroRecords` will be used
11046 * instead (either the default or given value).
11047 * @type string
11048 * @default No data available in table
11049 *
11050 * @dtopt Language
11051 * @name DataTable.defaults.language.emptyTable
11052 *
11053 * @example
11054 * $(document).ready( function() {
11055 * $('#example').dataTable( {
11056 * "language": {
11057 * "emptyTable": "No data available in table"
11058 * }
11059 * } );
11060 * } );
11061 */
11062 "sEmptyTable": "No data available in table",
11063
11064
11065 /**
11066 * This string gives information to the end user about the information
11067 * that is current on display on the page. The following tokens can be
11068 * used in the string and will be dynamically replaced as the table
11069 * display updates. This tokens can be placed anywhere in the string, or
11070 * removed as needed by the language requires:
11071 *
11072 * * `\_START\_` - Display index of the first record on the current page
11073 * * `\_END\_` - Display index of the last record on the current page
11074 * * `\_TOTAL\_` - Number of records in the table after filtering
11075 * * `\_MAX\_` - Number of records in the table without filtering
11076 * * `\_PAGE\_` - Current page number
11077 * * `\_PAGES\_` - Total number of pages of data in the table
11078 *
11079 * @type string
11080 * @default Showing _START_ to _END_ of _TOTAL_ entries
11081 *
11082 * @dtopt Language
11083 * @name DataTable.defaults.language.info
11084 *
11085 * @example
11086 * $(document).ready( function() {
11087 * $('#example').dataTable( {
11088 * "language": {
11089 * "info": "Showing page _PAGE_ of _PAGES_"
11090 * }
11091 * } );
11092 * } );
11093 */
11094 "sInfo": "Showing _START_ to _END_ of _TOTAL_ entries",
11095
11096
11097 /**
11098 * Display information string for when the table is empty. Typically the
11099 * format of this string should match `info`.
11100 * @type string
11101 * @default Showing 0 to 0 of 0 entries
11102 *
11103 * @dtopt Language
11104 * @name DataTable.defaults.language.infoEmpty
11105 *
11106 * @example
11107 * $(document).ready( function() {
11108 * $('#example').dataTable( {
11109 * "language": {
11110 * "infoEmpty": "No entries to show"
11111 * }
11112 * } );
11113 * } );
11114 */
11115 "sInfoEmpty": "Showing 0 to 0 of 0 entries",
11116
11117
11118 /**
11119 * When a user filters the information in a table, this string is appended
11120 * to the information (`info`) to give an idea of how strong the filtering
11121 * is. The variable _MAX_ is dynamically updated.
11122 * @type string
11123 * @default (filtered from _MAX_ total entries)
11124 *
11125 * @dtopt Language
11126 * @name DataTable.defaults.language.infoFiltered
11127 *
11128 * @example
11129 * $(document).ready( function() {
11130 * $('#example').dataTable( {
11131 * "language": {
11132 * "infoFiltered": " - filtering from _MAX_ records"
11133 * }
11134 * } );
11135 * } );
11136 */
11137 "sInfoFiltered": "(filtered from _MAX_ total entries)",
11138
11139
11140 /**
11141 * If can be useful to append extra information to the info string at times,
11142 * and this variable does exactly that. This information will be appended to
11143 * the `info` (`infoEmpty` and `infoFiltered` in whatever combination they are
11144 * being used) at all times.
11145 * @type string
11146 * @default <i>Empty string</i>
11147 *
11148 * @dtopt Language
11149 * @name DataTable.defaults.language.infoPostFix
11150 *
11151 * @example
11152 * $(document).ready( function() {
11153 * $('#example').dataTable( {
11154 * "language": {
11155 * "infoPostFix": "All records shown are derived from real information."
11156 * }
11157 * } );
11158 * } );
11159 */
11160 "sInfoPostFix": "",
11161
11162
11163 /**
11164 * This decimal place operator is a little different from the other
11165 * language options since DataTables doesn't output floating point
11166 * numbers, so it won't ever use this for display of a number. Rather,
11167 * what this parameter does is modify the sort methods of the table so
11168 * that numbers which are in a format which has a character other than
11169 * a period (`.`) as a decimal place will be sorted numerically.
11170 *
11171 * Note that numbers with different decimal places cannot be shown in
11172 * the same table and still be sortable, the table must be consistent.
11173 * However, multiple different tables on the page can use different
11174 * decimal place characters.
11175 * @type string
11176 * @default
11177 *
11178 * @dtopt Language
11179 * @name DataTable.defaults.language.decimal
11180 *
11181 * @example
11182 * $(document).ready( function() {
11183 * $('#example').dataTable( {
11184 * "language": {
11185 * "decimal": ","
11186 * "thousands": "."
11187 * }
11188 * } );
11189 * } );
11190 */
11191 "sDecimal": "",
11192
11193
11194 /**
11195 * DataTables has a build in number formatter (`formatNumber`) which is
11196 * used to format large numbers that are used in the table information.
11197 * By default a comma is used, but this can be trivially changed to any
11198 * character you wish with this parameter.
11199 * @type string
11200 * @default ,
11201 *
11202 * @dtopt Language
11203 * @name DataTable.defaults.language.thousands
11204 *
11205 * @example
11206 * $(document).ready( function() {
11207 * $('#example').dataTable( {
11208 * "language": {
11209 * "thousands": "'"
11210 * }
11211 * } );
11212 * } );
11213 */
11214 "sThousands": ",",
11215
11216
11217 /**
11218 * Detail the action that will be taken when the drop down menu for the
11219 * pagination length option is changed. The '_MENU_' variable is replaced
11220 * with a default select list of 10, 25, 50 and 100, and can be replaced
11221 * with a custom select box if required.
11222 * @type string
11223 * @default Show _MENU_ entries
11224 *
11225 * @dtopt Language
11226 * @name DataTable.defaults.language.lengthMenu
11227 *
11228 * @example
11229 * // Language change only
11230 * $(document).ready( function() {
11231 * $('#example').dataTable( {
11232 * "language": {
11233 * "lengthMenu": "Display _MENU_ records"
11234 * }
11235 * } );
11236 * } );
11237 *
11238 * @example
11239 * // Language and options change
11240 * $(document).ready( function() {
11241 * $('#example').dataTable( {
11242 * "language": {
11243 * "lengthMenu": 'Display <select>'+
11244 * '<option value="10">10</option>'+
11245 * '<option value="20">20</option>'+
11246 * '<option value="30">30</option>'+
11247 * '<option value="40">40</option>'+
11248 * '<option value="50">50</option>'+
11249 * '<option value="-1">All</option>'+
11250 * '</select> records'
11251 * }
11252 * } );
11253 * } );
11254 */
11255 "sLengthMenu": "Show _MENU_ entries",
11256
11257
11258 /**
11259 * When using Ajax sourced data and during the first draw when DataTables is
11260 * gathering the data, this message is shown in an empty row in the table to
11261 * indicate to the end user the the data is being loaded. Note that this
11262 * parameter is not used when loading data by server-side processing, just
11263 * Ajax sourced data with client-side processing.
11264 * @type string
11265 * @default Loading...
11266 *
11267 * @dtopt Language
11268 * @name DataTable.defaults.language.loadingRecords
11269 *
11270 * @example
11271 * $(document).ready( function() {
11272 * $('#example').dataTable( {
11273 * "language": {
11274 * "loadingRecords": "Please wait - loading..."
11275 * }
11276 * } );
11277 * } );
11278 */
11279 "sLoadingRecords": "Loading...",
11280
11281
11282 /**
11283 * Text which is displayed when the table is processing a user action
11284 * (usually a sort command or similar).
11285 * @type string
11286 * @default Processing...
11287 *
11288 * @dtopt Language
11289 * @name DataTable.defaults.language.processing
11290 *
11291 * @example
11292 * $(document).ready( function() {
11293 * $('#example').dataTable( {
11294 * "language": {
11295 * "processing": "DataTables is currently busy"
11296 * }
11297 * } );
11298 * } );
11299 */
11300 "sProcessing": "Processing...",
11301
11302
11303 /**
11304 * Details the actions that will be taken when the user types into the
11305 * filtering input text box. The variable "_INPUT_", if used in the string,
11306 * is replaced with the HTML text box for the filtering input allowing
11307 * control over where it appears in the string. If "_INPUT_" is not given
11308 * then the input box is appended to the string automatically.
11309 * @type string
11310 * @default Search:
11311 *
11312 * @dtopt Language
11313 * @name DataTable.defaults.language.search
11314 *
11315 * @example
11316 * // Input text box will be appended at the end automatically
11317 * $(document).ready( function() {
11318 * $('#example').dataTable( {
11319 * "language": {
11320 * "search": "Filter records:"
11321 * }
11322 * } );
11323 * } );
11324 *
11325 * @example
11326 * // Specify where the filter should appear
11327 * $(document).ready( function() {
11328 * $('#example').dataTable( {
11329 * "language": {
11330 * "search": "Apply filter _INPUT_ to table"
11331 * }
11332 * } );
11333 * } );
11334 */
11335 "sSearch": "Search:",
11336
11337
11338 /**
11339 * Assign a `placeholder` attribute to the search `input` element
11340 * @type string
11341 * @default
11342 *
11343 * @dtopt Language
11344 * @name DataTable.defaults.language.searchPlaceholder
11345 */
11346 "sSearchPlaceholder": "",
11347
11348
11349 /**
11350 * All of the language information can be stored in a file on the
11351 * server-side, which DataTables will look up if this parameter is passed.
11352 * It must store the URL of the language file, which is in a JSON format,
11353 * and the object has the same properties as the oLanguage object in the
11354 * initialiser object (i.e. the above parameters). Please refer to one of
11355 * the example language files to see how this works in action.
11356 * @type string
11357 * @default <i>Empty string - i.e. disabled</i>
11358 *
11359 * @dtopt Language
11360 * @name DataTable.defaults.language.url
11361 *
11362 * @example
11363 * $(document).ready( function() {
11364 * $('#example').dataTable( {
11365 * "language": {
11366 * "url": "http://www.sprymedia.co.uk/dataTables/lang.txt"
11367 * }
11368 * } );
11369 * } );
11370 */
11371 "sUrl": "",
11372
11373
11374 /**
11375 * Text shown inside the table records when the is no information to be
11376 * displayed after filtering. `emptyTable` is shown when there is simply no
11377 * information in the table at all (regardless of filtering).
11378 * @type string
11379 * @default No matching records found
11380 *
11381 * @dtopt Language
11382 * @name DataTable.defaults.language.zeroRecords
11383 *
11384 * @example
11385 * $(document).ready( function() {
11386 * $('#example').dataTable( {
11387 * "language": {
11388 * "zeroRecords": "No records to display"
11389 * }
11390 * } );
11391 * } );
11392 */
11393 "sZeroRecords": "No matching records found"
11394 },
11395
11396
11397 /**
11398 * This parameter allows you to have define the global filtering state at
11399 * initialisation time. As an object the `search` parameter must be
11400 * defined, but all other parameters are optional. When `regex` is true,
11401 * the search string will be treated as a regular expression, when false
11402 * (default) it will be treated as a straight string. When `smart`
11403 * DataTables will use it's smart filtering methods (to word match at
11404 * any point in the data), when false this will not be done.
11405 * @namespace
11406 * @extends DataTable.models.oSearch
11407 *
11408 * @dtopt Options
11409 * @name DataTable.defaults.search
11410 *
11411 * @example
11412 * $(document).ready( function() {
11413 * $('#example').dataTable( {
11414 * "search": {"search": "Initial search"}
11415 * } );
11416 * } )
11417 */
11418 "oSearch": $.extend( {}, DataTable.models.oSearch ),
11419
11420
11421 /**
11422 * __Deprecated__ The functionality provided by this parameter has now been
11423 * superseded by that provided through `ajax`, which should be used instead.
11424 *
11425 * By default DataTables will look for the property `data` (or `aaData` for
11426 * compatibility with DataTables 1.9-) when obtaining data from an Ajax
11427 * source or for server-side processing - this parameter allows that
11428 * property to be changed. You can use Javascript dotted object notation to
11429 * get a data source for multiple levels of nesting.
11430 * @type string
11431 * @default data
11432 *
11433 * @dtopt Options
11434 * @dtopt Server-side
11435 * @name DataTable.defaults.ajaxDataProp
11436 *
11437 * @deprecated 1.10. Please use `ajax` for this functionality now.
11438 */
11439 "sAjaxDataProp": "data",
11440
11441
11442 /**
11443 * __Deprecated__ The functionality provided by this parameter has now been
11444 * superseded by that provided through `ajax`, which should be used instead.
11445 *
11446 * You can instruct DataTables to load data from an external
11447 * source using this parameter (use aData if you want to pass data in you
11448 * already have). Simply provide a url a JSON object can be obtained from.
11449 * @type string
11450 * @default null
11451 *
11452 * @dtopt Options
11453 * @dtopt Server-side
11454 * @name DataTable.defaults.ajaxSource
11455 *
11456 * @deprecated 1.10. Please use `ajax` for this functionality now.
11457 */
11458 "sAjaxSource": null,
11459
11460
11461 /**
11462 * This initialisation variable allows you to specify exactly where in the
11463 * DOM you want DataTables to inject the various controls it adds to the page
11464 * (for example you might want the pagination controls at the top of the
11465 * table). DIV elements (with or without a custom class) can also be added to
11466 * aid styling. The follow syntax is used:
11467 * <ul>
11468 * <li>The following options are allowed:
11469 * <ul>
11470 * <li>'l' - Length changing</li>
11471 * <li>'f' - Filtering input</li>
11472 * <li>'t' - The table!</li>
11473 * <li>'i' - Information</li>
11474 * <li>'p' - Pagination</li>
11475 * <li>'r' - pRocessing</li>
11476 * </ul>
11477 * </li>
11478 * <li>The following constants are allowed:
11479 * <ul>
11480 * <li>'H' - jQueryUI theme "header" classes ('fg-toolbar ui-widget-header ui-corner-tl ui-corner-tr ui-helper-clearfix')</li>
11481 * <li>'F' - jQueryUI theme "footer" classes ('fg-toolbar ui-widget-header ui-corner-bl ui-corner-br ui-helper-clearfix')</li>
11482 * </ul>
11483 * </li>
11484 * <li>The following syntax is expected:
11485 * <ul>
11486 * <li>'&lt;' and '&gt;' - div elements</li>
11487 * <li>'&lt;"class" and '&gt;' - div with a class</li>
11488 * <li>'&lt;"#id" and '&gt;' - div with an ID</li>
11489 * </ul>
11490 * </li>
11491 * <li>Examples:
11492 * <ul>
11493 * <li>'&lt;"wrapper"flipt&gt;'</li>
11494 * <li>'&lt;lf&lt;t&gt;ip&gt;'</li>
11495 * </ul>
11496 * </li>
11497 * </ul>
11498 * @type string
11499 * @default lfrtip <i>(when `jQueryUI` is false)</i> <b>or</b>
11500 * <"H"lfr>t<"F"ip> <i>(when `jQueryUI` is true)</i>
11501 *
11502 * @dtopt Options
11503 * @name DataTable.defaults.dom
11504 *
11505 * @example
11506 * $(document).ready( function() {
11507 * $('#example').dataTable( {
11508 * "dom": '&lt;"top"i&gt;rt&lt;"bottom"flp&gt;&lt;"clear"&gt;'
11509 * } );
11510 * } );
11511 */
11512 "sDom": "lfrtip",
11513
11514
11515 /**
11516 * Search delay option. This will throttle full table searches that use the
11517 * DataTables provided search input element (it does not effect calls to
11518 * `dt-api search()`, providing a delay before the search is made.
11519 * @type integer
11520 * @default 0
11521 *
11522 * @dtopt Options
11523 * @name DataTable.defaults.searchDelay
11524 *
11525 * @example
11526 * $(document).ready( function() {
11527 * $('#example').dataTable( {
11528 * "searchDelay": 200
11529 * } );
11530 * } )
11531 */
11532 "searchDelay": null,
11533
11534
11535 /**
11536 * DataTables features four different built-in options for the buttons to
11537 * display for pagination control:
11538 *
11539 * * `simple` - 'Previous' and 'Next' buttons only
11540 * * 'simple_numbers` - 'Previous' and 'Next' buttons, plus page numbers
11541 * * `full` - 'First', 'Previous', 'Next' and 'Last' buttons
11542 * * `full_numbers` - 'First', 'Previous', 'Next' and 'Last' buttons, plus
11543 * page numbers
11544 *
11545 * Further methods can be added using {@link DataTable.ext.oPagination}.
11546 * @type string
11547 * @default simple_numbers
11548 *
11549 * @dtopt Options
11550 * @name DataTable.defaults.pagingType
11551 *
11552 * @example
11553 * $(document).ready( function() {
11554 * $('#example').dataTable( {
11555 * "pagingType": "full_numbers"
11556 * } );
11557 * } )
11558 */
11559 "sPaginationType": "simple_numbers",
11560
11561
11562 /**
11563 * Enable horizontal scrolling. When a table is too wide to fit into a
11564 * certain layout, or you have a large number of columns in the table, you
11565 * can enable x-scrolling to show the table in a viewport, which can be
11566 * scrolled. This property can be `true` which will allow the table to
11567 * scroll horizontally when needed, or any CSS unit, or a number (in which
11568 * case it will be treated as a pixel measurement). Setting as simply `true`
11569 * is recommended.
11570 * @type boolean|string
11571 * @default <i>blank string - i.e. disabled</i>
11572 *
11573 * @dtopt Features
11574 * @name DataTable.defaults.scrollX
11575 *
11576 * @example
11577 * $(document).ready( function() {
11578 * $('#example').dataTable( {
11579 * "scrollX": true,
11580 * "scrollCollapse": true
11581 * } );
11582 * } );
11583 */
11584 "sScrollX": "",
11585
11586
11587 /**
11588 * This property can be used to force a DataTable to use more width than it
11589 * might otherwise do when x-scrolling is enabled. For example if you have a
11590 * table which requires to be well spaced, this parameter is useful for
11591 * "over-sizing" the table, and thus forcing scrolling. This property can by
11592 * any CSS unit, or a number (in which case it will be treated as a pixel
11593 * measurement).
11594 * @type string
11595 * @default <i>blank string - i.e. disabled</i>
11596 *
11597 * @dtopt Options
11598 * @name DataTable.defaults.scrollXInner
11599 *
11600 * @example
11601 * $(document).ready( function() {
11602 * $('#example').dataTable( {
11603 * "scrollX": "100%",
11604 * "scrollXInner": "110%"
11605 * } );
11606 * } );
11607 */
11608 "sScrollXInner": "",
11609
11610
11611 /**
11612 * Enable vertical scrolling. Vertical scrolling will constrain the DataTable
11613 * to the given height, and enable scrolling for any data which overflows the
11614 * current viewport. This can be used as an alternative to paging to display
11615 * a lot of data in a small area (although paging and scrolling can both be
11616 * enabled at the same time). This property can be any CSS unit, or a number
11617 * (in which case it will be treated as a pixel measurement).
11618 * @type string
11619 * @default <i>blank string - i.e. disabled</i>
11620 *
11621 * @dtopt Features
11622 * @name DataTable.defaults.scrollY
11623 *
11624 * @example
11625 * $(document).ready( function() {
11626 * $('#example').dataTable( {
11627 * "scrollY": "200px",
11628 * "paginate": false
11629 * } );
11630 * } );
11631 */
11632 "sScrollY": "",
11633
11634
11635 /**
11636 * __Deprecated__ The functionality provided by this parameter has now been
11637 * superseded by that provided through `ajax`, which should be used instead.
11638 *
11639 * Set the HTTP method that is used to make the Ajax call for server-side
11640 * processing or Ajax sourced data.
11641 * @type string
11642 * @default GET
11643 *
11644 * @dtopt Options
11645 * @dtopt Server-side
11646 * @name DataTable.defaults.serverMethod
11647 *
11648 * @deprecated 1.10. Please use `ajax` for this functionality now.
11649 */
11650 "sServerMethod": "GET",
11651
11652
11653 /**
11654 * DataTables makes use of renderers when displaying HTML elements for
11655 * a table. These renderers can be added or modified by plug-ins to
11656 * generate suitable mark-up for a site. For example the Bootstrap
11657 * integration plug-in for DataTables uses a paging button renderer to
11658 * display pagination buttons in the mark-up required by Bootstrap.
11659 *
11660 * For further information about the renderers available see
11661 * DataTable.ext.renderer
11662 * @type string|object
11663 * @default null
11664 *
11665 * @name DataTable.defaults.renderer
11666 *
11667 */
11668 "renderer": null
11669 };
11670
11671 _fnHungarianMap( DataTable.defaults );
11672
11673
11674
11675 /*
11676 * Developer note - See note in model.defaults.js about the use of Hungarian
11677 * notation and camel case.
11678 */
11679
11680 /**
11681 * Column options that can be given to DataTables at initialisation time.
11682 * @namespace
11683 */
11684 DataTable.defaults.column = {
11685 /**
11686 * Define which column(s) an order will occur on for this column. This
11687 * allows a column's ordering to take multiple columns into account when
11688 * doing a sort or use the data from a different column. For example first
11689 * name / last name columns make sense to do a multi-column sort over the
11690 * two columns.
11691 * @type array|int
11692 * @default null <i>Takes the value of the column index automatically</i>
11693 *
11694 * @name DataTable.defaults.column.orderData
11695 * @dtopt Columns
11696 *
11697 * @example
11698 * // Using `columnDefs`
11699 * $(document).ready( function() {
11700 * $('#example').dataTable( {
11701 * "columnDefs": [
11702 * { "orderData": [ 0, 1 ], "targets": [ 0 ] },
11703 * { "orderData": [ 1, 0 ], "targets": [ 1 ] },
11704 * { "orderData": 2, "targets": [ 2 ] }
11705 * ]
11706 * } );
11707 * } );
11708 *
11709 * @example
11710 * // Using `columns`
11711 * $(document).ready( function() {
11712 * $('#example').dataTable( {
11713 * "columns": [
11714 * { "orderData": [ 0, 1 ] },
11715 * { "orderData": [ 1, 0 ] },
11716 * { "orderData": 2 },
11717 * null,
11718 * null
11719 * ]
11720 * } );
11721 * } );
11722 */
11723 "aDataSort": null,
11724 "iDataSort": -1,
11725
11726
11727 /**
11728 * You can control the default ordering direction, and even alter the
11729 * behaviour of the sort handler (i.e. only allow ascending ordering etc)
11730 * using this parameter.
11731 * @type array
11732 * @default [ 'asc', 'desc' ]
11733 *
11734 * @name DataTable.defaults.column.orderSequence
11735 * @dtopt Columns
11736 *
11737 * @example
11738 * // Using `columnDefs`
11739 * $(document).ready( function() {
11740 * $('#example').dataTable( {
11741 * "columnDefs": [
11742 * { "orderSequence": [ "asc" ], "targets": [ 1 ] },
11743 * { "orderSequence": [ "desc", "asc", "asc" ], "targets": [ 2 ] },
11744 * { "orderSequence": [ "desc" ], "targets": [ 3 ] }
11745 * ]
11746 * } );
11747 * } );
11748 *
11749 * @example
11750 * // Using `columns`
11751 * $(document).ready( function() {
11752 * $('#example').dataTable( {
11753 * "columns": [
11754 * null,
11755 * { "orderSequence": [ "asc" ] },
11756 * { "orderSequence": [ "desc", "asc", "asc" ] },
11757 * { "orderSequence": [ "desc" ] },
11758 * null
11759 * ]
11760 * } );
11761 * } );
11762 */
11763 "asSorting": [ 'asc', 'desc' ],
11764
11765
11766 /**
11767 * Enable or disable filtering on the data in this column.
11768 * @type boolean
11769 * @default true
11770 *
11771 * @name DataTable.defaults.column.searchable
11772 * @dtopt Columns
11773 *
11774 * @example
11775 * // Using `columnDefs`
11776 * $(document).ready( function() {
11777 * $('#example').dataTable( {
11778 * "columnDefs": [
11779 * { "searchable": false, "targets": [ 0 ] }
11780 * ] } );
11781 * } );
11782 *
11783 * @example
11784 * // Using `columns`
11785 * $(document).ready( function() {
11786 * $('#example').dataTable( {
11787 * "columns": [
11788 * { "searchable": false },
11789 * null,
11790 * null,
11791 * null,
11792 * null
11793 * ] } );
11794 * } );
11795 */
11796 "bSearchable": true,
11797
11798
11799 /**
11800 * Enable or disable ordering on this column.
11801 * @type boolean
11802 * @default true
11803 *
11804 * @name DataTable.defaults.column.orderable
11805 * @dtopt Columns
11806 *
11807 * @example
11808 * // Using `columnDefs`
11809 * $(document).ready( function() {
11810 * $('#example').dataTable( {
11811 * "columnDefs": [
11812 * { "orderable": false, "targets": [ 0 ] }
11813 * ] } );
11814 * } );
11815 *
11816 * @example
11817 * // Using `columns`
11818 * $(document).ready( function() {
11819 * $('#example').dataTable( {
11820 * "columns": [
11821 * { "orderable": false },
11822 * null,
11823 * null,
11824 * null,
11825 * null
11826 * ] } );
11827 * } );
11828 */
11829 "bSortable": true,
11830
11831
11832 /**
11833 * Enable or disable the display of this column.
11834 * @type boolean
11835 * @default true
11836 *
11837 * @name DataTable.defaults.column.visible
11838 * @dtopt Columns
11839 *
11840 * @example
11841 * // Using `columnDefs`
11842 * $(document).ready( function() {
11843 * $('#example').dataTable( {
11844 * "columnDefs": [
11845 * { "visible": false, "targets": [ 0 ] }
11846 * ] } );
11847 * } );
11848 *
11849 * @example
11850 * // Using `columns`
11851 * $(document).ready( function() {
11852 * $('#example').dataTable( {
11853 * "columns": [
11854 * { "visible": false },
11855 * null,
11856 * null,
11857 * null,
11858 * null
11859 * ] } );
11860 * } );
11861 */
11862 "bVisible": true,
11863
11864
11865 /**
11866 * Developer definable function that is called whenever a cell is created (Ajax source,
11867 * etc) or processed for input (DOM source). This can be used as a compliment to mRender
11868 * allowing you to modify the DOM element (add background colour for example) when the
11869 * element is available.
11870 * @type function
11871 * @param {element} td The TD node that has been created
11872 * @param {*} cellData The Data for the cell
11873 * @param {array|object} rowData The data for the whole row
11874 * @param {int} row The row index for the aoData data store
11875 * @param {int} col The column index for aoColumns
11876 *
11877 * @name DataTable.defaults.column.createdCell
11878 * @dtopt Columns
11879 *
11880 * @example
11881 * $(document).ready( function() {
11882 * $('#example').dataTable( {
11883 * "columnDefs": [ {
11884 * "targets": [3],
11885 * "createdCell": function (td, cellData, rowData, row, col) {
11886 * if ( cellData == "1.7" ) {
11887 * $(td).css('color', 'blue')
11888 * }
11889 * }
11890 * } ]
11891 * });
11892 * } );
11893 */
11894 "fnCreatedCell": null,
11895
11896
11897 /**
11898 * This parameter has been replaced by `data` in DataTables to ensure naming
11899 * consistency. `dataProp` can still be used, as there is backwards
11900 * compatibility in DataTables for this option, but it is strongly
11901 * recommended that you use `data` in preference to `dataProp`.
11902 * @name DataTable.defaults.column.dataProp
11903 */
11904
11905
11906 /**
11907 * This property can be used to read data from any data source property,
11908 * including deeply nested objects / properties. `data` can be given in a
11909 * number of different ways which effect its behaviour:
11910 *
11911 * * `integer` - treated as an array index for the data source. This is the
11912 * default that DataTables uses (incrementally increased for each column).
11913 * * `string` - read an object property from the data source. There are
11914 * three 'special' options that can be used in the string to alter how
11915 * DataTables reads the data from the source object:
11916 * * `.` - Dotted Javascript notation. Just as you use a `.` in
11917 * Javascript to read from nested objects, so to can the options
11918 * specified in `data`. For example: `browser.version` or
11919 * `browser.name`. If your object parameter name contains a period, use
11920 * `\\` to escape it - i.e. `first\\.name`.
11921 * * `[]` - Array notation. DataTables can automatically combine data
11922 * from and array source, joining the data with the characters provided
11923 * between the two brackets. For example: `name[, ]` would provide a
11924 * comma-space separated list from the source array. If no characters
11925 * are provided between the brackets, the original array source is
11926 * returned.
11927 * * `()` - Function notation. Adding `()` to the end of a parameter will
11928 * execute a function of the name given. For example: `browser()` for a
11929 * simple function on the data source, `browser.version()` for a
11930 * function in a nested property or even `browser().version` to get an
11931 * object property if the function called returns an object. Note that
11932 * function notation is recommended for use in `render` rather than
11933 * `data` as it is much simpler to use as a renderer.
11934 * * `null` - use the original data source for the row rather than plucking
11935 * data directly from it. This action has effects on two other
11936 * initialisation options:
11937 * * `defaultContent` - When null is given as the `data` option and
11938 * `defaultContent` is specified for the column, the value defined by
11939 * `defaultContent` will be used for the cell.
11940 * * `render` - When null is used for the `data` option and the `render`
11941 * option is specified for the column, the whole data source for the
11942 * row is used for the renderer.
11943 * * `function` - the function given will be executed whenever DataTables
11944 * needs to set or get the data for a cell in the column. The function
11945 * takes three parameters:
11946 * * Parameters:
11947 * * `{array|object}` The data source for the row
11948 * * `{string}` The type call data requested - this will be 'set' when
11949 * setting data or 'filter', 'display', 'type', 'sort' or undefined
11950 * when gathering data. Note that when `undefined` is given for the
11951 * type DataTables expects to get the raw data for the object back<
11952 * * `{*}` Data to set when the second parameter is 'set'.
11953 * * Return:
11954 * * The return value from the function is not required when 'set' is
11955 * the type of call, but otherwise the return is what will be used
11956 * for the data requested.
11957 *
11958 * Note that `data` is a getter and setter option. If you just require
11959 * formatting of data for output, you will likely want to use `render` which
11960 * is simply a getter and thus simpler to use.
11961 *
11962 * Note that prior to DataTables 1.9.2 `data` was called `mDataProp`. The
11963 * name change reflects the flexibility of this property and is consistent
11964 * with the naming of mRender. If 'mDataProp' is given, then it will still
11965 * be used by DataTables, as it automatically maps the old name to the new
11966 * if required.
11967 *
11968 * @type string|int|function|null
11969 * @default null <i>Use automatically calculated column index</i>
11970 *
11971 * @name DataTable.defaults.column.data
11972 * @dtopt Columns
11973 *
11974 * @example
11975 * // Read table data from objects
11976 * // JSON structure for each row:
11977 * // {
11978 * // "engine": {value},
11979 * // "browser": {value},
11980 * // "platform": {value},
11981 * // "version": {value},
11982 * // "grade": {value}
11983 * // }
11984 * $(document).ready( function() {
11985 * $('#example').dataTable( {
11986 * "ajaxSource": "sources/objects.txt",
11987 * "columns": [
11988 * { "data": "engine" },
11989 * { "data": "browser" },
11990 * { "data": "platform" },
11991 * { "data": "version" },
11992 * { "data": "grade" }
11993 * ]
11994 * } );
11995 * } );
11996 *
11997 * @example
11998 * // Read information from deeply nested objects
11999 * // JSON structure for each row:
12000 * // {
12001 * // "engine": {value},
12002 * // "browser": {value},
12003 * // "platform": {
12004 * // "inner": {value}
12005 * // },
12006 * // "details": [
12007 * // {value}, {value}
12008 * // ]
12009 * // }
12010 * $(document).ready( function() {
12011 * $('#example').dataTable( {
12012 * "ajaxSource": "sources/deep.txt",
12013 * "columns": [
12014 * { "data": "engine" },
12015 * { "data": "browser" },
12016 * { "data": "platform.inner" },
12017 * { "data": "platform.details.0" },
12018 * { "data": "platform.details.1" }
12019 * ]
12020 * } );
12021 * } );
12022 *
12023 * @example
12024 * // Using `data` as a function to provide different information for
12025 * // sorting, filtering and display. In this case, currency (price)
12026 * $(document).ready( function() {
12027 * $('#example').dataTable( {
12028 * "columnDefs": [ {
12029 * "targets": [ 0 ],
12030 * "data": function ( source, type, val ) {
12031 * if (type === 'set') {
12032 * source.price = val;
12033 * // Store the computed dislay and filter values for efficiency
12034 * source.price_display = val=="" ? "" : "$"+numberFormat(val);
12035 * source.price_filter = val=="" ? "" : "$"+numberFormat(val)+" "+val;
12036 * return;
12037 * }
12038 * else if (type === 'display') {
12039 * return source.price_display;
12040 * }
12041 * else if (type === 'filter') {
12042 * return source.price_filter;
12043 * }
12044 * // 'sort', 'type' and undefined all just use the integer
12045 * return source.price;
12046 * }
12047 * } ]
12048 * } );
12049 * } );
12050 *
12051 * @example
12052 * // Using default content
12053 * $(document).ready( function() {
12054 * $('#example').dataTable( {
12055 * "columnDefs": [ {
12056 * "targets": [ 0 ],
12057 * "data": null,
12058 * "defaultContent": "Click to edit"
12059 * } ]
12060 * } );
12061 * } );
12062 *
12063 * @example
12064 * // Using array notation - outputting a list from an array
12065 * $(document).ready( function() {
12066 * $('#example').dataTable( {
12067 * "columnDefs": [ {
12068 * "targets": [ 0 ],
12069 * "data": "name[, ]"
12070 * } ]
12071 * } );
12072 * } );
12073 *
12074 */
12075 "mData": null,
12076
12077
12078 /**
12079 * This property is the rendering partner to `data` and it is suggested that
12080 * when you want to manipulate data for display (including filtering,
12081 * sorting etc) without altering the underlying data for the table, use this
12082 * property. `render` can be considered to be the the read only companion to
12083 * `data` which is read / write (then as such more complex). Like `data`
12084 * this option can be given in a number of different ways to effect its
12085 * behaviour:
12086 *
12087 * * `integer` - treated as an array index for the data source. This is the
12088 * default that DataTables uses (incrementally increased for each column).
12089 * * `string` - read an object property from the data source. There are
12090 * three 'special' options that can be used in the string to alter how
12091 * DataTables reads the data from the source object:
12092 * * `.` - Dotted Javascript notation. Just as you use a `.` in
12093 * Javascript to read from nested objects, so to can the options
12094 * specified in `data`. For example: `browser.version` or
12095 * `browser.name`. If your object parameter name contains a period, use
12096 * `\\` to escape it - i.e. `first\\.name`.
12097 * * `[]` - Array notation. DataTables can automatically combine data
12098 * from and array source, joining the data with the characters provided
12099 * between the two brackets. For example: `name[, ]` would provide a
12100 * comma-space separated list from the source array. If no characters
12101 * are provided between the brackets, the original array source is
12102 * returned.
12103 * * `()` - Function notation. Adding `()` to the end of a parameter will
12104 * execute a function of the name given. For example: `browser()` for a
12105 * simple function on the data source, `browser.version()` for a
12106 * function in a nested property or even `browser().version` to get an
12107 * object property if the function called returns an object.
12108 * * `object` - use different data for the different data types requested by
12109 * DataTables ('filter', 'display', 'type' or 'sort'). The property names
12110 * of the object is the data type the property refers to and the value can
12111 * defined using an integer, string or function using the same rules as
12112 * `render` normally does. Note that an `_` option _must_ be specified.
12113 * This is the default value to use if you haven't specified a value for
12114 * the data type requested by DataTables.
12115 * * `function` - the function given will be executed whenever DataTables
12116 * needs to set or get the data for a cell in the column. The function
12117 * takes three parameters:
12118 * * Parameters:
12119 * * {array|object} The data source for the row (based on `data`)
12120 * * {string} The type call data requested - this will be 'filter',
12121 * 'display', 'type' or 'sort'.
12122 * * {array|object} The full data source for the row (not based on
12123 * `data`)
12124 * * Return:
12125 * * The return value from the function is what will be used for the
12126 * data requested.
12127 *
12128 * @type string|int|function|object|null
12129 * @default null Use the data source value.
12130 *
12131 * @name DataTable.defaults.column.render
12132 * @dtopt Columns
12133 *
12134 * @example
12135 * // Create a comma separated list from an array of objects
12136 * $(document).ready( function() {
12137 * $('#example').dataTable( {
12138 * "ajaxSource": "sources/deep.txt",
12139 * "columns": [
12140 * { "data": "engine" },
12141 * { "data": "browser" },
12142 * {
12143 * "data": "platform",
12144 * "render": "[, ].name"
12145 * }
12146 * ]
12147 * } );
12148 * } );
12149 *
12150 * @example
12151 * // Execute a function to obtain data
12152 * $(document).ready( function() {
12153 * $('#example').dataTable( {
12154 * "columnDefs": [ {
12155 * "targets": [ 0 ],
12156 * "data": null, // Use the full data source object for the renderer's source
12157 * "render": "browserName()"
12158 * } ]
12159 * } );
12160 * } );
12161 *
12162 * @example
12163 * // As an object, extracting different data for the different types
12164 * // This would be used with a data source such as:
12165 * // { "phone": 5552368, "phone_filter": "5552368 555-2368", "phone_display": "555-2368" }
12166 * // Here the `phone` integer is used for sorting and type detection, while `phone_filter`
12167 * // (which has both forms) is used for filtering for if a user inputs either format, while
12168 * // the formatted phone number is the one that is shown in the table.
12169 * $(document).ready( function() {
12170 * $('#example').dataTable( {
12171 * "columnDefs": [ {
12172 * "targets": [ 0 ],
12173 * "data": null, // Use the full data source object for the renderer's source
12174 * "render": {
12175 * "_": "phone",
12176 * "filter": "phone_filter",
12177 * "display": "phone_display"
12178 * }
12179 * } ]
12180 * } );
12181 * } );
12182 *
12183 * @example
12184 * // Use as a function to create a link from the data source
12185 * $(document).ready( function() {
12186 * $('#example').dataTable( {
12187 * "columnDefs": [ {
12188 * "targets": [ 0 ],
12189 * "data": "download_link",
12190 * "render": function ( data, type, full ) {
12191 * return '<a href="'+data+'">Download</a>';
12192 * }
12193 * } ]
12194 * } );
12195 * } );
12196 */
12197 "mRender": null,
12198
12199
12200 /**
12201 * Change the cell type created for the column - either TD cells or TH cells. This
12202 * can be useful as TH cells have semantic meaning in the table body, allowing them
12203 * to act as a header for a row (you may wish to add scope='row' to the TH elements).
12204 * @type string
12205 * @default td
12206 *
12207 * @name DataTable.defaults.column.cellType
12208 * @dtopt Columns
12209 *
12210 * @example
12211 * // Make the first column use TH cells
12212 * $(document).ready( function() {
12213 * $('#example').dataTable( {
12214 * "columnDefs": [ {
12215 * "targets": [ 0 ],
12216 * "cellType": "th"
12217 * } ]
12218 * } );
12219 * } );
12220 */
12221 "sCellType": "td",
12222
12223
12224 /**
12225 * Class to give to each cell in this column.
12226 * @type string
12227 * @default <i>Empty string</i>
12228 *
12229 * @name DataTable.defaults.column.class
12230 * @dtopt Columns
12231 *
12232 * @example
12233 * // Using `columnDefs`
12234 * $(document).ready( function() {
12235 * $('#example').dataTable( {
12236 * "columnDefs": [
12237 * { "class": "my_class", "targets": [ 0 ] }
12238 * ]
12239 * } );
12240 * } );
12241 *
12242 * @example
12243 * // Using `columns`
12244 * $(document).ready( function() {
12245 * $('#example').dataTable( {
12246 * "columns": [
12247 * { "class": "my_class" },
12248 * null,
12249 * null,
12250 * null,
12251 * null
12252 * ]
12253 * } );
12254 * } );
12255 */
12256 "sClass": "",
12257
12258 /**
12259 * When DataTables calculates the column widths to assign to each column,
12260 * it finds the longest string in each column and then constructs a
12261 * temporary table and reads the widths from that. The problem with this
12262 * is that "mmm" is much wider then "iiii", but the latter is a longer
12263 * string - thus the calculation can go wrong (doing it properly and putting
12264 * it into an DOM object and measuring that is horribly(!) slow). Thus as
12265 * a "work around" we provide this option. It will append its value to the
12266 * text that is found to be the longest string for the column - i.e. padding.
12267 * Generally you shouldn't need this!
12268 * @type string
12269 * @default <i>Empty string<i>
12270 *
12271 * @name DataTable.defaults.column.contentPadding
12272 * @dtopt Columns
12273 *
12274 * @example
12275 * // Using `columns`
12276 * $(document).ready( function() {
12277 * $('#example').dataTable( {
12278 * "columns": [
12279 * null,
12280 * null,
12281 * null,
12282 * {
12283 * "contentPadding": "mmm"
12284 * }
12285 * ]
12286 * } );
12287 * } );
12288 */
12289 "sContentPadding": "",
12290
12291
12292 /**
12293 * Allows a default value to be given for a column's data, and will be used
12294 * whenever a null data source is encountered (this can be because `data`
12295 * is set to null, or because the data source itself is null).
12296 * @type string
12297 * @default null
12298 *
12299 * @name DataTable.defaults.column.defaultContent
12300 * @dtopt Columns
12301 *
12302 * @example
12303 * // Using `columnDefs`
12304 * $(document).ready( function() {
12305 * $('#example').dataTable( {
12306 * "columnDefs": [
12307 * {
12308 * "data": null,
12309 * "defaultContent": "Edit",
12310 * "targets": [ -1 ]
12311 * }
12312 * ]
12313 * } );
12314 * } );
12315 *
12316 * @example
12317 * // Using `columns`
12318 * $(document).ready( function() {
12319 * $('#example').dataTable( {
12320 * "columns": [
12321 * null,
12322 * null,
12323 * null,
12324 * {
12325 * "data": null,
12326 * "defaultContent": "Edit"
12327 * }
12328 * ]
12329 * } );
12330 * } );
12331 */
12332 "sDefaultContent": null,
12333
12334
12335 /**
12336 * This parameter is only used in DataTables' server-side processing. It can
12337 * be exceptionally useful to know what columns are being displayed on the
12338 * client side, and to map these to database fields. When defined, the names
12339 * also allow DataTables to reorder information from the server if it comes
12340 * back in an unexpected order (i.e. if you switch your columns around on the
12341 * client-side, your server-side code does not also need updating).
12342 * @type string
12343 * @default <i>Empty string</i>
12344 *
12345 * @name DataTable.defaults.column.name
12346 * @dtopt Columns
12347 *
12348 * @example
12349 * // Using `columnDefs`
12350 * $(document).ready( function() {
12351 * $('#example').dataTable( {
12352 * "columnDefs": [
12353 * { "name": "engine", "targets": [ 0 ] },
12354 * { "name": "browser", "targets": [ 1 ] },
12355 * { "name": "platform", "targets": [ 2 ] },
12356 * { "name": "version", "targets": [ 3 ] },
12357 * { "name": "grade", "targets": [ 4 ] }
12358 * ]
12359 * } );
12360 * } );
12361 *
12362 * @example
12363 * // Using `columns`
12364 * $(document).ready( function() {
12365 * $('#example').dataTable( {
12366 * "columns": [
12367 * { "name": "engine" },
12368 * { "name": "browser" },
12369 * { "name": "platform" },
12370 * { "name": "version" },
12371 * { "name": "grade" }
12372 * ]
12373 * } );
12374 * } );
12375 */
12376 "sName": "",
12377
12378
12379 /**
12380 * Defines a data source type for the ordering which can be used to read
12381 * real-time information from the table (updating the internally cached
12382 * version) prior to ordering. This allows ordering to occur on user
12383 * editable elements such as form inputs.
12384 * @type string
12385 * @default std
12386 *
12387 * @name DataTable.defaults.column.orderDataType
12388 * @dtopt Columns
12389 *
12390 * @example
12391 * // Using `columnDefs`
12392 * $(document).ready( function() {
12393 * $('#example').dataTable( {
12394 * "columnDefs": [
12395 * { "orderDataType": "dom-text", "targets": [ 2, 3 ] },
12396 * { "type": "numeric", "targets": [ 3 ] },
12397 * { "orderDataType": "dom-select", "targets": [ 4 ] },
12398 * { "orderDataType": "dom-checkbox", "targets": [ 5 ] }
12399 * ]
12400 * } );
12401 * } );
12402 *
12403 * @example
12404 * // Using `columns`
12405 * $(document).ready( function() {
12406 * $('#example').dataTable( {
12407 * "columns": [
12408 * null,
12409 * null,
12410 * { "orderDataType": "dom-text" },
12411 * { "orderDataType": "dom-text", "type": "numeric" },
12412 * { "orderDataType": "dom-select" },
12413 * { "orderDataType": "dom-checkbox" }
12414 * ]
12415 * } );
12416 * } );
12417 */
12418 "sSortDataType": "std",
12419
12420
12421 /**
12422 * The title of this column.
12423 * @type string
12424 * @default null <i>Derived from the 'TH' value for this column in the
12425 * original HTML table.</i>
12426 *
12427 * @name DataTable.defaults.column.title
12428 * @dtopt Columns
12429 *
12430 * @example
12431 * // Using `columnDefs`
12432 * $(document).ready( function() {
12433 * $('#example').dataTable( {
12434 * "columnDefs": [
12435 * { "title": "My column title", "targets": [ 0 ] }
12436 * ]
12437 * } );
12438 * } );
12439 *
12440 * @example
12441 * // Using `columns`
12442 * $(document).ready( function() {
12443 * $('#example').dataTable( {
12444 * "columns": [
12445 * { "title": "My column title" },
12446 * null,
12447 * null,
12448 * null,
12449 * null
12450 * ]
12451 * } );
12452 * } );
12453 */
12454 "sTitle": null,
12455
12456
12457 /**
12458 * The type allows you to specify how the data for this column will be
12459 * ordered. Four types (string, numeric, date and html (which will strip
12460 * HTML tags before ordering)) are currently available. Note that only date
12461 * formats understood by Javascript's Date() object will be accepted as type
12462 * date. For example: "Mar 26, 2008 5:03 PM". May take the values: 'string',
12463 * 'numeric', 'date' or 'html' (by default). Further types can be adding
12464 * through plug-ins.
12465 * @type string
12466 * @default null <i>Auto-detected from raw data</i>
12467 *
12468 * @name DataTable.defaults.column.type
12469 * @dtopt Columns
12470 *
12471 * @example
12472 * // Using `columnDefs`
12473 * $(document).ready( function() {
12474 * $('#example').dataTable( {
12475 * "columnDefs": [
12476 * { "type": "html", "targets": [ 0 ] }
12477 * ]
12478 * } );
12479 * } );
12480 *
12481 * @example
12482 * // Using `columns`
12483 * $(document).ready( function() {
12484 * $('#example').dataTable( {
12485 * "columns": [
12486 * { "type": "html" },
12487 * null,
12488 * null,
12489 * null,
12490 * null
12491 * ]
12492 * } );
12493 * } );
12494 */
12495 "sType": null,
12496
12497
12498 /**
12499 * Defining the width of the column, this parameter may take any CSS value
12500 * (3em, 20px etc). DataTables applies 'smart' widths to columns which have not
12501 * been given a specific width through this interface ensuring that the table
12502 * remains readable.
12503 * @type string
12504 * @default null <i>Automatic</i>
12505 *
12506 * @name DataTable.defaults.column.width
12507 * @dtopt Columns
12508 *
12509 * @example
12510 * // Using `columnDefs`
12511 * $(document).ready( function() {
12512 * $('#example').dataTable( {
12513 * "columnDefs": [
12514 * { "width": "20%", "targets": [ 0 ] }
12515 * ]
12516 * } );
12517 * } );
12518 *
12519 * @example
12520 * // Using `columns`
12521 * $(document).ready( function() {
12522 * $('#example').dataTable( {
12523 * "columns": [
12524 * { "width": "20%" },
12525 * null,
12526 * null,
12527 * null,
12528 * null
12529 * ]
12530 * } );
12531 * } );
12532 */
12533 "sWidth": null
12534 };
12535
12536 _fnHungarianMap( DataTable.defaults.column );
12537
12538
12539
12540 /**
12541 * DataTables settings object - this holds all the information needed for a
12542 * given table, including configuration, data and current application of the
12543 * table options. DataTables does not have a single instance for each DataTable
12544 * with the settings attached to that instance, but rather instances of the
12545 * DataTable "class" are created on-the-fly as needed (typically by a
12546 * $().dataTable() call) and the settings object is then applied to that
12547 * instance.
12548 *
12549 * Note that this object is related to {@link DataTable.defaults} but this
12550 * one is the internal data store for DataTables's cache of columns. It should
12551 * NOT be manipulated outside of DataTables. Any configuration should be done
12552 * through the initialisation options.
12553 * @namespace
12554 * @todo Really should attach the settings object to individual instances so we
12555 * don't need to create new instances on each $().dataTable() call (if the
12556 * table already exists). It would also save passing oSettings around and
12557 * into every single function. However, this is a very significant
12558 * architecture change for DataTables and will almost certainly break
12559 * backwards compatibility with older installations. This is something that
12560 * will be done in 2.0.
12561 */
12562 DataTable.models.oSettings = {
12563 /**
12564 * Primary features of DataTables and their enablement state.
12565 * @namespace
12566 */
12567 "oFeatures": {
12568
12569 /**
12570 * Flag to say if DataTables should automatically try to calculate the
12571 * optimum table and columns widths (true) or not (false).
12572 * Note that this parameter will be set by the initialisation routine. To
12573 * set a default use {@link DataTable.defaults}.
12574 * @type boolean
12575 */
12576 "bAutoWidth": null,
12577
12578 /**
12579 * Delay the creation of TR and TD elements until they are actually
12580 * needed by a driven page draw. This can give a significant speed
12581 * increase for Ajax source and Javascript source data, but makes no
12582 * difference at all fro DOM and server-side processing tables.
12583 * Note that this parameter will be set by the initialisation routine. To
12584 * set a default use {@link DataTable.defaults}.
12585 * @type boolean
12586 */
12587 "bDeferRender": null,
12588
12589 /**
12590 * Enable filtering on the table or not. Note that if this is disabled
12591 * then there is no filtering at all on the table, including fnFilter.
12592 * To just remove the filtering input use sDom and remove the 'f' option.
12593 * Note that this parameter will be set by the initialisation routine. To
12594 * set a default use {@link DataTable.defaults}.
12595 * @type boolean
12596 */
12597 "bFilter": null,
12598
12599 /**
12600 * Table information element (the 'Showing x of y records' div) enable
12601 * flag.
12602 * Note that this parameter will be set by the initialisation routine. To
12603 * set a default use {@link DataTable.defaults}.
12604 * @type boolean
12605 */
12606 "bInfo": null,
12607
12608 /**
12609 * Present a user control allowing the end user to change the page size
12610 * when pagination is enabled.
12611 * Note that this parameter will be set by the initialisation routine. To
12612 * set a default use {@link DataTable.defaults}.
12613 * @type boolean
12614 */
12615 "bLengthChange": null,
12616
12617 /**
12618 * Pagination enabled or not. Note that if this is disabled then length
12619 * changing must also be disabled.
12620 * Note that this parameter will be set by the initialisation routine. To
12621 * set a default use {@link DataTable.defaults}.
12622 * @type boolean
12623 */
12624 "bPaginate": null,
12625
12626 /**
12627 * Processing indicator enable flag whenever DataTables is enacting a
12628 * user request - typically an Ajax request for server-side processing.
12629 * Note that this parameter will be set by the initialisation routine. To
12630 * set a default use {@link DataTable.defaults}.
12631 * @type boolean
12632 */
12633 "bProcessing": null,
12634
12635 /**
12636 * Server-side processing enabled flag - when enabled DataTables will
12637 * get all data from the server for every draw - there is no filtering,
12638 * sorting or paging done on the client-side.
12639 * Note that this parameter will be set by the initialisation routine. To
12640 * set a default use {@link DataTable.defaults}.
12641 * @type boolean
12642 */
12643 "bServerSide": null,
12644
12645 /**
12646 * Sorting enablement flag.
12647 * Note that this parameter will be set by the initialisation routine. To
12648 * set a default use {@link DataTable.defaults}.
12649 * @type boolean
12650 */
12651 "bSort": null,
12652
12653 /**
12654 * Multi-column sorting
12655 * Note that this parameter will be set by the initialisation routine. To
12656 * set a default use {@link DataTable.defaults}.
12657 * @type boolean
12658 */
12659 "bSortMulti": null,
12660
12661 /**
12662 * Apply a class to the columns which are being sorted to provide a
12663 * visual highlight or not. This can slow things down when enabled since
12664 * there is a lot of DOM interaction.
12665 * Note that this parameter will be set by the initialisation routine. To
12666 * set a default use {@link DataTable.defaults}.
12667 * @type boolean
12668 */
12669 "bSortClasses": null,
12670
12671 /**
12672 * State saving enablement flag.
12673 * Note that this parameter will be set by the initialisation routine. To
12674 * set a default use {@link DataTable.defaults}.
12675 * @type boolean
12676 */
12677 "bStateSave": null
12678 },
12679
12680
12681 /**
12682 * Scrolling settings for a table.
12683 * @namespace
12684 */
12685 "oScroll": {
12686 /**
12687 * When the table is shorter in height than sScrollY, collapse the
12688 * table container down to the height of the table (when true).
12689 * Note that this parameter will be set by the initialisation routine. To
12690 * set a default use {@link DataTable.defaults}.
12691 * @type boolean
12692 */
12693 "bCollapse": null,
12694
12695 /**
12696 * Width of the scrollbar for the web-browser's platform. Calculated
12697 * during table initialisation.
12698 * @type int
12699 * @default 0
12700 */
12701 "iBarWidth": 0,
12702
12703 /**
12704 * Viewport width for horizontal scrolling. Horizontal scrolling is
12705 * disabled if an empty string.
12706 * Note that this parameter will be set by the initialisation routine. To
12707 * set a default use {@link DataTable.defaults}.
12708 * @type string
12709 */
12710 "sX": null,
12711
12712 /**
12713 * Width to expand the table to when using x-scrolling. Typically you
12714 * should not need to use this.
12715 * Note that this parameter will be set by the initialisation routine. To
12716 * set a default use {@link DataTable.defaults}.
12717 * @type string
12718 * @deprecated
12719 */
12720 "sXInner": null,
12721
12722 /**
12723 * Viewport height for vertical scrolling. Vertical scrolling is disabled
12724 * if an empty string.
12725 * Note that this parameter will be set by the initialisation routine. To
12726 * set a default use {@link DataTable.defaults}.
12727 * @type string
12728 */
12729 "sY": null
12730 },
12731
12732 /**
12733 * Language information for the table.
12734 * @namespace
12735 * @extends DataTable.defaults.oLanguage
12736 */
12737 "oLanguage": {
12738 /**
12739 * Information callback function. See
12740 * {@link DataTable.defaults.fnInfoCallback}
12741 * @type function
12742 * @default null
12743 */
12744 "fnInfoCallback": null
12745 },
12746
12747 /**
12748 * Browser support parameters
12749 * @namespace
12750 */
12751 "oBrowser": {
12752 /**
12753 * Indicate if the browser incorrectly calculates width:100% inside a
12754 * scrolling element (IE6/7)
12755 * @type boolean
12756 * @default false
12757 */
12758 "bScrollOversize": false,
12759
12760 /**
12761 * Determine if the vertical scrollbar is on the right or left of the
12762 * scrolling container - needed for rtl language layout, although not
12763 * all browsers move the scrollbar (Safari).
12764 * @type boolean
12765 * @default false
12766 */
12767 "bScrollbarLeft": false
12768 },
12769
12770
12771 "ajax": null,
12772
12773
12774 /**
12775 * Array referencing the nodes which are used for the features. The
12776 * parameters of this object match what is allowed by sDom - i.e.
12777 * <ul>
12778 * <li>'l' - Length changing</li>
12779 * <li>'f' - Filtering input</li>
12780 * <li>'t' - The table!</li>
12781 * <li>'i' - Information</li>
12782 * <li>'p' - Pagination</li>
12783 * <li>'r' - pRocessing</li>
12784 * </ul>
12785 * @type array
12786 * @default []
12787 */
12788 "aanFeatures": [],
12789
12790 /**
12791 * Store data information - see {@link DataTable.models.oRow} for detailed
12792 * information.
12793 * @type array
12794 * @default []
12795 */
12796 "aoData": [],
12797
12798 /**
12799 * Array of indexes which are in the current display (after filtering etc)
12800 * @type array
12801 * @default []
12802 */
12803 "aiDisplay": [],
12804
12805 /**
12806 * Array of indexes for display - no filtering
12807 * @type array
12808 * @default []
12809 */
12810 "aiDisplayMaster": [],
12811
12812 /**
12813 * Store information about each column that is in use
12814 * @type array
12815 * @default []
12816 */
12817 "aoColumns": [],
12818
12819 /**
12820 * Store information about the table's header
12821 * @type array
12822 * @default []
12823 */
12824 "aoHeader": [],
12825
12826 /**
12827 * Store information about the table's footer
12828 * @type array
12829 * @default []
12830 */
12831 "aoFooter": [],
12832
12833 /**
12834 * Store the applied global search information in case we want to force a
12835 * research or compare the old search to a new one.
12836 * Note that this parameter will be set by the initialisation routine. To
12837 * set a default use {@link DataTable.defaults}.
12838 * @namespace
12839 * @extends DataTable.models.oSearch
12840 */
12841 "oPreviousSearch": {},
12842
12843 /**
12844 * Store the applied search for each column - see
12845 * {@link DataTable.models.oSearch} for the format that is used for the
12846 * filtering information for each column.
12847 * @type array
12848 * @default []
12849 */
12850 "aoPreSearchCols": [],
12851
12852 /**
12853 * Sorting that is applied to the table. Note that the inner arrays are
12854 * used in the following manner:
12855 * <ul>
12856 * <li>Index 0 - column number</li>
12857 * <li>Index 1 - current sorting direction</li>
12858 * </ul>
12859 * Note that this parameter will be set by the initialisation routine. To
12860 * set a default use {@link DataTable.defaults}.
12861 * @type array
12862 * @todo These inner arrays should really be objects
12863 */
12864 "aaSorting": null,
12865
12866 /**
12867 * Sorting that is always applied to the table (i.e. prefixed in front of
12868 * aaSorting).
12869 * Note that this parameter will be set by the initialisation routine. To
12870 * set a default use {@link DataTable.defaults}.
12871 * @type array
12872 * @default []
12873 */
12874 "aaSortingFixed": [],
12875
12876 /**
12877 * Classes to use for the striping of a table.
12878 * Note that this parameter will be set by the initialisation routine. To
12879 * set a default use {@link DataTable.defaults}.
12880 * @type array
12881 * @default []
12882 */
12883 "asStripeClasses": null,
12884
12885 /**
12886 * If restoring a table - we should restore its striping classes as well
12887 * @type array
12888 * @default []
12889 */
12890 "asDestroyStripes": [],
12891
12892 /**
12893 * If restoring a table - we should restore its width
12894 * @type int
12895 * @default 0
12896 */
12897 "sDestroyWidth": 0,
12898
12899 /**
12900 * Callback functions array for every time a row is inserted (i.e. on a draw).
12901 * @type array
12902 * @default []
12903 */
12904 "aoRowCallback": [],
12905
12906 /**
12907 * Callback functions for the header on each draw.
12908 * @type array
12909 * @default []
12910 */
12911 "aoHeaderCallback": [],
12912
12913 /**
12914 * Callback function for the footer on each draw.
12915 * @type array
12916 * @default []
12917 */
12918 "aoFooterCallback": [],
12919
12920 /**
12921 * Array of callback functions for draw callback functions
12922 * @type array
12923 * @default []
12924 */
12925 "aoDrawCallback": [],
12926
12927 /**
12928 * Array of callback functions for row created function
12929 * @type array
12930 * @default []
12931 */
12932 "aoRowCreatedCallback": [],
12933
12934 /**
12935 * Callback functions for just before the table is redrawn. A return of
12936 * false will be used to cancel the draw.
12937 * @type array
12938 * @default []
12939 */
12940 "aoPreDrawCallback": [],
12941
12942 /**
12943 * Callback functions for when the table has been initialised.
12944 * @type array
12945 * @default []
12946 */
12947 "aoInitComplete": [],
12948
12949
12950 /**
12951 * Callbacks for modifying the settings to be stored for state saving, prior to
12952 * saving state.
12953 * @type array
12954 * @default []
12955 */
12956 "aoStateSaveParams": [],
12957
12958 /**
12959 * Callbacks for modifying the settings that have been stored for state saving
12960 * prior to using the stored values to restore the state.
12961 * @type array
12962 * @default []
12963 */
12964 "aoStateLoadParams": [],
12965
12966 /**
12967 * Callbacks for operating on the settings object once the saved state has been
12968 * loaded
12969 * @type array
12970 * @default []
12971 */
12972 "aoStateLoaded": [],
12973
12974 /**
12975 * Cache the table ID for quick access
12976 * @type string
12977 * @default <i>Empty string</i>
12978 */
12979 "sTableId": "",
12980
12981 /**
12982 * The TABLE node for the main table
12983 * @type node
12984 * @default null
12985 */
12986 "nTable": null,
12987
12988 /**
12989 * Permanent ref to the thead element
12990 * @type node
12991 * @default null
12992 */
12993 "nTHead": null,
12994
12995 /**
12996 * Permanent ref to the tfoot element - if it exists
12997 * @type node
12998 * @default null
12999 */
13000 "nTFoot": null,
13001
13002 /**
13003 * Permanent ref to the tbody element
13004 * @type node
13005 * @default null
13006 */
13007 "nTBody": null,
13008
13009 /**
13010 * Cache the wrapper node (contains all DataTables controlled elements)
13011 * @type node
13012 * @default null
13013 */
13014 "nTableWrapper": null,
13015
13016 /**
13017 * Indicate if when using server-side processing the loading of data
13018 * should be deferred until the second draw.
13019 * Note that this parameter will be set by the initialisation routine. To
13020 * set a default use {@link DataTable.defaults}.
13021 * @type boolean
13022 * @default false
13023 */
13024 "bDeferLoading": false,
13025
13026 /**
13027 * Indicate if all required information has been read in
13028 * @type boolean
13029 * @default false
13030 */
13031 "bInitialised": false,
13032
13033 /**
13034 * Information about open rows. Each object in the array has the parameters
13035 * 'nTr' and 'nParent'
13036 * @type array
13037 * @default []
13038 */
13039 "aoOpenRows": [],
13040
13041 /**
13042 * Dictate the positioning of DataTables' control elements - see
13043 * {@link DataTable.model.oInit.sDom}.
13044 * Note that this parameter will be set by the initialisation routine. To
13045 * set a default use {@link DataTable.defaults}.
13046 * @type string
13047 * @default null
13048 */
13049 "sDom": null,
13050
13051 /**
13052 * Search delay (in mS)
13053 * @type integer
13054 * @default null
13055 */
13056 "searchDelay": null,
13057
13058 /**
13059 * Which type of pagination should be used.
13060 * Note that this parameter will be set by the initialisation routine. To
13061 * set a default use {@link DataTable.defaults}.
13062 * @type string
13063 * @default two_button
13064 */
13065 "sPaginationType": "two_button",
13066
13067 /**
13068 * The state duration (for `stateSave`) in seconds.
13069 * Note that this parameter will be set by the initialisation routine. To
13070 * set a default use {@link DataTable.defaults}.
13071 * @type int
13072 * @default 0
13073 */
13074 "iStateDuration": 0,
13075
13076 /**
13077 * Array of callback functions for state saving. Each array element is an
13078 * object with the following parameters:
13079 * <ul>
13080 * <li>function:fn - function to call. Takes two parameters, oSettings
13081 * and the JSON string to save that has been thus far created. Returns
13082 * a JSON string to be inserted into a json object
13083 * (i.e. '"param": [ 0, 1, 2]')</li>
13084 * <li>string:sName - name of callback</li>
13085 * </ul>
13086 * @type array
13087 * @default []
13088 */
13089 "aoStateSave": [],
13090
13091 /**
13092 * Array of callback functions for state loading. Each array element is an
13093 * object with the following parameters:
13094 * <ul>
13095 * <li>function:fn - function to call. Takes two parameters, oSettings
13096 * and the object stored. May return false to cancel state loading</li>
13097 * <li>string:sName - name of callback</li>
13098 * </ul>
13099 * @type array
13100 * @default []
13101 */
13102 "aoStateLoad": [],
13103
13104 /**
13105 * State that was saved. Useful for back reference
13106 * @type object
13107 * @default null
13108 */
13109 "oSavedState": null,
13110
13111 /**
13112 * State that was loaded. Useful for back reference
13113 * @type object
13114 * @default null
13115 */
13116 "oLoadedState": null,
13117
13118 /**
13119 * Source url for AJAX data for the table.
13120 * Note that this parameter will be set by the initialisation routine. To
13121 * set a default use {@link DataTable.defaults}.
13122 * @type string
13123 * @default null
13124 */
13125 "sAjaxSource": null,
13126
13127 /**
13128 * Property from a given object from which to read the table data from. This
13129 * can be an empty string (when not server-side processing), in which case
13130 * it is assumed an an array is given directly.
13131 * Note that this parameter will be set by the initialisation routine. To
13132 * set a default use {@link DataTable.defaults}.
13133 * @type string
13134 */
13135 "sAjaxDataProp": null,
13136
13137 /**
13138 * Note if draw should be blocked while getting data
13139 * @type boolean
13140 * @default true
13141 */
13142 "bAjaxDataGet": true,
13143
13144 /**
13145 * The last jQuery XHR object that was used for server-side data gathering.
13146 * This can be used for working with the XHR information in one of the
13147 * callbacks
13148 * @type object
13149 * @default null
13150 */
13151 "jqXHR": null,
13152
13153 /**
13154 * JSON returned from the server in the last Ajax request
13155 * @type object
13156 * @default undefined
13157 */
13158 "json": undefined,
13159
13160 /**
13161 * Data submitted as part of the last Ajax request
13162 * @type object
13163 * @default undefined
13164 */
13165 "oAjaxData": undefined,
13166
13167 /**
13168 * Function to get the server-side data.
13169 * Note that this parameter will be set by the initialisation routine. To
13170 * set a default use {@link DataTable.defaults}.
13171 * @type function
13172 */
13173 "fnServerData": null,
13174
13175 /**
13176 * Functions which are called prior to sending an Ajax request so extra
13177 * parameters can easily be sent to the server
13178 * @type array
13179 * @default []
13180 */
13181 "aoServerParams": [],
13182
13183 /**
13184 * Send the XHR HTTP method - GET or POST (could be PUT or DELETE if
13185 * required).
13186 * Note that this parameter will be set by the initialisation routine. To
13187 * set a default use {@link DataTable.defaults}.
13188 * @type string
13189 */
13190 "sServerMethod": null,
13191
13192 /**
13193 * Format numbers for display.
13194 * Note that this parameter will be set by the initialisation routine. To
13195 * set a default use {@link DataTable.defaults}.
13196 * @type function
13197 */
13198 "fnFormatNumber": null,
13199
13200 /**
13201 * List of options that can be used for the user selectable length menu.
13202 * Note that this parameter will be set by the initialisation routine. To
13203 * set a default use {@link DataTable.defaults}.
13204 * @type array
13205 * @default []
13206 */
13207 "aLengthMenu": null,
13208
13209 /**
13210 * Counter for the draws that the table does. Also used as a tracker for
13211 * server-side processing
13212 * @type int
13213 * @default 0
13214 */
13215 "iDraw": 0,
13216
13217 /**
13218 * Indicate if a redraw is being done - useful for Ajax
13219 * @type boolean
13220 * @default false
13221 */
13222 "bDrawing": false,
13223
13224 /**
13225 * Draw index (iDraw) of the last error when parsing the returned data
13226 * @type int
13227 * @default -1
13228 */
13229 "iDrawError": -1,
13230
13231 /**
13232 * Paging display length
13233 * @type int
13234 * @default 10
13235 */
13236 "_iDisplayLength": 10,
13237
13238 /**
13239 * Paging start point - aiDisplay index
13240 * @type int
13241 * @default 0
13242 */
13243 "_iDisplayStart": 0,
13244
13245 /**
13246 * Server-side processing - number of records in the result set
13247 * (i.e. before filtering), Use fnRecordsTotal rather than
13248 * this property to get the value of the number of records, regardless of
13249 * the server-side processing setting.
13250 * @type int
13251 * @default 0
13252 * @private
13253 */
13254 "_iRecordsTotal": 0,
13255
13256 /**
13257 * Server-side processing - number of records in the current display set
13258 * (i.e. after filtering). Use fnRecordsDisplay rather than
13259 * this property to get the value of the number of records, regardless of
13260 * the server-side processing setting.
13261 * @type boolean
13262 * @default 0
13263 * @private
13264 */
13265 "_iRecordsDisplay": 0,
13266
13267 /**
13268 * Flag to indicate if jQuery UI marking and classes should be used.
13269 * Note that this parameter will be set by the initialisation routine. To
13270 * set a default use {@link DataTable.defaults}.
13271 * @type boolean
13272 */
13273 "bJUI": null,
13274
13275 /**
13276 * The classes to use for the table
13277 * @type object
13278 * @default {}
13279 */
13280 "oClasses": {},
13281
13282 /**
13283 * Flag attached to the settings object so you can check in the draw
13284 * callback if filtering has been done in the draw. Deprecated in favour of
13285 * events.
13286 * @type boolean
13287 * @default false
13288 * @deprecated
13289 */
13290 "bFiltered": false,
13291
13292 /**
13293 * Flag attached to the settings object so you can check in the draw
13294 * callback if sorting has been done in the draw. Deprecated in favour of
13295 * events.
13296 * @type boolean
13297 * @default false
13298 * @deprecated
13299 */
13300 "bSorted": false,
13301
13302 /**
13303 * Indicate that if multiple rows are in the header and there is more than
13304 * one unique cell per column, if the top one (true) or bottom one (false)
13305 * should be used for sorting / title by DataTables.
13306 * Note that this parameter will be set by the initialisation routine. To
13307 * set a default use {@link DataTable.defaults}.
13308 * @type boolean
13309 */
13310 "bSortCellsTop": null,
13311
13312 /**
13313 * Initialisation object that is used for the table
13314 * @type object
13315 * @default null
13316 */
13317 "oInit": null,
13318
13319 /**
13320 * Destroy callback functions - for plug-ins to attach themselves to the
13321 * destroy so they can clean up markup and events.
13322 * @type array
13323 * @default []
13324 */
13325 "aoDestroyCallback": [],
13326
13327
13328 /**
13329 * Get the number of records in the current record set, before filtering
13330 * @type function
13331 */
13332 "fnRecordsTotal": function ()
13333 {
13334 return _fnDataSource( this ) == 'ssp' ?
13335 this._iRecordsTotal * 1 :
13336 this.aiDisplayMaster.length;
13337 },
13338
13339 /**
13340 * Get the number of records in the current record set, after filtering
13341 * @type function
13342 */
13343 "fnRecordsDisplay": function ()
13344 {
13345 return _fnDataSource( this ) == 'ssp' ?
13346 this._iRecordsDisplay * 1 :
13347 this.aiDisplay.length;
13348 },
13349
13350 /**
13351 * Get the display end point - aiDisplay index
13352 * @type function
13353 */
13354 "fnDisplayEnd": function ()
13355 {
13356 var
13357 len = this._iDisplayLength,
13358 start = this._iDisplayStart,
13359 calc = start + len,
13360 records = this.aiDisplay.length,
13361 features = this.oFeatures,
13362 paginate = features.bPaginate;
13363
13364 if ( features.bServerSide ) {
13365 return paginate === false || len === -1 ?
13366 start + records :
13367 Math.min( start+len, this._iRecordsDisplay );
13368 }
13369 else {
13370 return ! paginate || calc>records || len===-1 ?
13371 records :
13372 calc;
13373 }
13374 },
13375
13376 /**
13377 * The DataTables object for this table
13378 * @type object
13379 * @default null
13380 */
13381 "oInstance": null,
13382
13383 /**
13384 * Unique identifier for each instance of the DataTables object. If there
13385 * is an ID on the table node, then it takes that value, otherwise an
13386 * incrementing internal counter is used.
13387 * @type string
13388 * @default null
13389 */
13390 "sInstance": null,
13391
13392 /**
13393 * tabindex attribute value that is added to DataTables control elements, allowing
13394 * keyboard navigation of the table and its controls.
13395 */
13396 "iTabIndex": 0,
13397
13398 /**
13399 * DIV container for the footer scrolling table if scrolling
13400 */
13401 "nScrollHead": null,
13402
13403 /**
13404 * DIV container for the footer scrolling table if scrolling
13405 */
13406 "nScrollFoot": null,
13407
13408 /**
13409 * Last applied sort
13410 * @type array
13411 * @default []
13412 */
13413 "aLastSort": [],
13414
13415 /**
13416 * Stored plug-in instances
13417 * @type object
13418 * @default {}
13419 */
13420 "oPlugins": {}
13421 };
13422
13423 /**
13424 * Extension object for DataTables that is used to provide all extension
13425 * options.
13426 *
13427 * Note that the `DataTable.ext` object is available through
13428 * `jQuery.fn.dataTable.ext` where it may be accessed and manipulated. It is
13429 * also aliased to `jQuery.fn.dataTableExt` for historic reasons.
13430 * @namespace
13431 * @extends DataTable.models.ext
13432 */
13433
13434
13435 /**
13436 * DataTables extensions
13437 *
13438 * This namespace acts as a collection area for plug-ins that can be used to
13439 * extend DataTables capabilities. Indeed many of the build in methods
13440 * use this method to provide their own capabilities (sorting methods for
13441 * example).
13442 *
13443 * Note that this namespace is aliased to `jQuery.fn.dataTableExt` for legacy
13444 * reasons
13445 *
13446 * @namespace
13447 */
13448 DataTable.ext = _ext = {
13449 /**
13450 * Element class names
13451 *
13452 * @type object
13453 * @default {}
13454 */
13455 classes: {},
13456
13457
13458 /**
13459 * Error reporting.
13460 *
13461 * How should DataTables report an error. Can take the value 'alert' or
13462 * 'throw'
13463 *
13464 * @type string
13465 * @default alert
13466 */
13467 errMode: "alert",
13468
13469
13470 /**
13471 * Feature plug-ins.
13472 *
13473 * This is an array of objects which describe the feature plug-ins that are
13474 * available to DataTables. These feature plug-ins are then available for
13475 * use through the `dom` initialisation option.
13476 *
13477 * Each feature plug-in is described by an object which must have the
13478 * following properties:
13479 *
13480 * * `fnInit` - function that is used to initialise the plug-in,
13481 * * `cFeature` - a character so the feature can be enabled by the `dom`
13482 * instillation option. This is case sensitive.
13483 *
13484 * The `fnInit` function has the following input parameters:
13485 *
13486 * 1. `{object}` DataTables settings object: see
13487 * {@link DataTable.models.oSettings}
13488 *
13489 * And the following return is expected:
13490 *
13491 * * {node|null} The element which contains your feature. Note that the
13492 * return may also be void if your plug-in does not require to inject any
13493 * DOM elements into DataTables control (`dom`) - for example this might
13494 * be useful when developing a plug-in which allows table control via
13495 * keyboard entry
13496 *
13497 * @type array
13498 *
13499 * @example
13500 * $.fn.dataTable.ext.features.push( {
13501 * "fnInit": function( oSettings ) {
13502 * return new TableTools( { "oDTSettings": oSettings } );
13503 * },
13504 * "cFeature": "T"
13505 * } );
13506 */
13507 feature: [],
13508
13509
13510 /**
13511 * Row searching.
13512 *
13513 * This method of searching is complimentary to the default type based
13514 * searching, and a lot more comprehensive as it allows you complete control
13515 * over the searching logic. Each element in this array is a function
13516 * (parameters described below) that is called for every row in the table,
13517 * and your logic decides if it should be included in the searching data set
13518 * or not.
13519 *
13520 * Searching functions have the following input parameters:
13521 *
13522 * 1. `{object}` DataTables settings object: see
13523 * {@link DataTable.models.oSettings}
13524 * 2. `{array|object}` Data for the row to be processed (same as the
13525 * original format that was passed in as the data source, or an array
13526 * from a DOM data source
13527 * 3. `{int}` Row index ({@link DataTable.models.oSettings.aoData}), which
13528 * can be useful to retrieve the `TR` element if you need DOM interaction.
13529 *
13530 * And the following return is expected:
13531 *
13532 * * {boolean} Include the row in the searched result set (true) or not
13533 * (false)
13534 *
13535 * Note that as with the main search ability in DataTables, technically this
13536 * is "filtering", since it is subtractive. However, for consistency in
13537 * naming we call it searching here.
13538 *
13539 * @type array
13540 * @default []
13541 *
13542 * @example
13543 * // The following example shows custom search being applied to the
13544 * // fourth column (i.e. the data[3] index) based on two input values
13545 * // from the end-user, matching the data in a certain range.
13546 * $.fn.dataTable.ext.search.push(
13547 * function( settings, data, dataIndex ) {
13548 * var min = document.getElementById('min').value * 1;
13549 * var max = document.getElementById('max').value * 1;
13550 * var version = data[3] == "-" ? 0 : data[3]*1;
13551 *
13552 * if ( min == "" && max == "" ) {
13553 * return true;
13554 * }
13555 * else if ( min == "" && version < max ) {
13556 * return true;
13557 * }
13558 * else if ( min < version && "" == max ) {
13559 * return true;
13560 * }
13561 * else if ( min < version && version < max ) {
13562 * return true;
13563 * }
13564 * return false;
13565 * }
13566 * );
13567 */
13568 search: [],
13569
13570
13571 /**
13572 * Internal functions, exposed for used in plug-ins.
13573 *
13574 * Please note that you should not need to use the internal methods for
13575 * anything other than a plug-in (and even then, try to avoid if possible).
13576 * The internal function may change between releases.
13577 *
13578 * @type object
13579 * @default {}
13580 */
13581 internal: {},
13582
13583
13584 /**
13585 * Legacy configuration options. Enable and disable legacy options that
13586 * are available in DataTables.
13587 *
13588 * @type object
13589 */
13590 legacy: {
13591 /**
13592 * Enable / disable DataTables 1.9 compatible server-side processing
13593 * requests
13594 *
13595 * @type boolean
13596 * @default null
13597 */
13598 ajax: null
13599 },
13600
13601
13602 /**
13603 * Pagination plug-in methods.
13604 *
13605 * Each entry in this object is a function and defines which buttons should
13606 * be shown by the pagination rendering method that is used for the table:
13607 * {@link DataTable.ext.renderer.pageButton}. The renderer addresses how the
13608 * buttons are displayed in the document, while the functions here tell it
13609 * what buttons to display. This is done by returning an array of button
13610 * descriptions (what each button will do).
13611 *
13612 * Pagination types (the four built in options and any additional plug-in
13613 * options defined here) can be used through the `paginationType`
13614 * initialisation parameter.
13615 *
13616 * The functions defined take two parameters:
13617 *
13618 * 1. `{int} page` The current page index
13619 * 2. `{int} pages` The number of pages in the table
13620 *
13621 * Each function is expected to return an array where each element of the
13622 * array can be one of:
13623 *
13624 * * `first` - Jump to first page when activated
13625 * * `last` - Jump to last page when activated
13626 * * `previous` - Show previous page when activated
13627 * * `next` - Show next page when activated
13628 * * `{int}` - Show page of the index given
13629 * * `{array}` - A nested array containing the above elements to add a
13630 * containing 'DIV' element (might be useful for styling).
13631 *
13632 * Note that DataTables v1.9- used this object slightly differently whereby
13633 * an object with two functions would be defined for each plug-in. That
13634 * ability is still supported by DataTables 1.10+ to provide backwards
13635 * compatibility, but this option of use is now decremented and no longer
13636 * documented in DataTables 1.10+.
13637 *
13638 * @type object
13639 * @default {}
13640 *
13641 * @example
13642 * // Show previous, next and current page buttons only
13643 * $.fn.dataTableExt.oPagination.current = function ( page, pages ) {
13644 * return [ 'previous', page, 'next' ];
13645 * };
13646 */
13647 pager: {},
13648
13649
13650 renderer: {
13651 pageButton: {},
13652 header: {}
13653 },
13654
13655
13656 /**
13657 * Ordering plug-ins - custom data source
13658 *
13659 * The extension options for ordering of data available here is complimentary
13660 * to the default type based ordering that DataTables typically uses. It
13661 * allows much greater control over the the data that is being used to
13662 * order a column, but is necessarily therefore more complex.
13663 *
13664 * This type of ordering is useful if you want to do ordering based on data
13665 * live from the DOM (for example the contents of an 'input' element) rather
13666 * than just the static string that DataTables knows of.
13667 *
13668 * The way these plug-ins work is that you create an array of the values you
13669 * wish to be ordering for the column in question and then return that
13670 * array. The data in the array much be in the index order of the rows in
13671 * the table (not the currently ordering order!). Which order data gathering
13672 * function is run here depends on the `dt-init columns.orderDataType`
13673 * parameter that is used for the column (if any).
13674 *
13675 * The functions defined take two parameters:
13676 *
13677 * 1. `{object}` DataTables settings object: see
13678 * {@link DataTable.models.oSettings}
13679 * 2. `{int}` Target column index
13680 *
13681 * Each function is expected to return an array:
13682 *
13683 * * `{array}` Data for the column to be ordering upon
13684 *
13685 * @type array
13686 *
13687 * @example
13688 * // Ordering using `input` node values
13689 * $.fn.dataTable.ext.order['dom-text'] = function ( settings, col )
13690 * {
13691 * return this.api().column( col, {order:'index'} ).nodes().map( function ( td, i ) {
13692 * return $('input', td).val();
13693 * } );
13694 * }
13695 */
13696 order: {},
13697
13698
13699 /**
13700 * Type based plug-ins.
13701 *
13702 * Each column in DataTables has a type assigned to it, either by automatic
13703 * detection or by direct assignment using the `type` option for the column.
13704 * The type of a column will effect how it is ordering and search (plug-ins
13705 * can also make use of the column type if required).
13706 *
13707 * @namespace
13708 */
13709 type: {
13710 /**
13711 * Type detection functions.
13712 *
13713 * The functions defined in this object are used to automatically detect
13714 * a column's type, making initialisation of DataTables super easy, even
13715 * when complex data is in the table.
13716 *
13717 * The functions defined take two parameters:
13718 *
13719 * 1. `{*}` Data from the column cell to be analysed
13720 * 2. `{settings}` DataTables settings object. This can be used to
13721 * perform context specific type detection - for example detection
13722 * based on language settings such as using a comma for a decimal
13723 * place. Generally speaking the options from the settings will not
13724 * be required
13725 *
13726 * Each function is expected to return:
13727 *
13728 * * `{string|null}` Data type detected, or null if unknown (and thus
13729 * pass it on to the other type detection functions.
13730 *
13731 * @type array
13732 *
13733 * @example
13734 * // Currency type detection plug-in:
13735 * $.fn.dataTable.ext.type.detect.push(
13736 * function ( data, settings ) {
13737 * // Check the numeric part
13738 * if ( ! $.isNumeric( data.substring(1) ) ) {
13739 * return null;
13740 * }
13741 *
13742 * // Check prefixed by currency
13743 * if ( data.charAt(0) == '$' || data.charAt(0) == '&pound;' ) {
13744 * return 'currency';
13745 * }
13746 * return null;
13747 * }
13748 * );
13749 */
13750 detect: [],
13751
13752
13753 /**
13754 * Type based search formatting.
13755 *
13756 * The type based searching functions can be used to pre-format the
13757 * data to be search on. For example, it can be used to strip HTML
13758 * tags or to de-format telephone numbers for numeric only searching.
13759 *
13760 * Note that is a search is not defined for a column of a given type,
13761 * no search formatting will be performed.
13762 *
13763 * Pre-processing of searching data plug-ins - When you assign the sType
13764 * for a column (or have it automatically detected for you by DataTables
13765 * or a type detection plug-in), you will typically be using this for
13766 * custom sorting, but it can also be used to provide custom searching
13767 * by allowing you to pre-processing the data and returning the data in
13768 * the format that should be searched upon. This is done by adding
13769 * functions this object with a parameter name which matches the sType
13770 * for that target column. This is the corollary of <i>afnSortData</i>
13771 * for searching data.
13772 *
13773 * The functions defined take a single parameter:
13774 *
13775 * 1. `{*}` Data from the column cell to be prepared for searching
13776 *
13777 * Each function is expected to return:
13778 *
13779 * * `{string|null}` Formatted string that will be used for the searching.
13780 *
13781 * @type object
13782 * @default {}
13783 *
13784 * @example
13785 * $.fn.dataTable.ext.type.search['title-numeric'] = function ( d ) {
13786 * return d.replace(/\n/g," ").replace( /<.*?>/g, "" );
13787 * }
13788 */
13789 search: {},
13790
13791
13792 /**
13793 * Type based ordering.
13794 *
13795 * The column type tells DataTables what ordering to apply to the table
13796 * when a column is sorted upon. The order for each type that is defined,
13797 * is defined by the functions available in this object.
13798 *
13799 * Each ordering option can be described by three properties added to
13800 * this object:
13801 *
13802 * * `{type}-pre` - Pre-formatting function
13803 * * `{type}-asc` - Ascending order function
13804 * * `{type}-desc` - Descending order function
13805 *
13806 * All three can be used together, only `{type}-pre` or only
13807 * `{type}-asc` and `{type}-desc` together. It is generally recommended
13808 * that only `{type}-pre` is used, as this provides the optimal
13809 * implementation in terms of speed, although the others are provided
13810 * for compatibility with existing Javascript sort functions.
13811 *
13812 * `{type}-pre`: Functions defined take a single parameter:
13813 *
13814 * 1. `{*}` Data from the column cell to be prepared for ordering
13815 *
13816 * And return:
13817 *
13818 * * `{*}` Data to be sorted upon
13819 *
13820 * `{type}-asc` and `{type}-desc`: Functions are typical Javascript sort
13821 * functions, taking two parameters:
13822 *
13823 * 1. `{*}` Data to compare to the second parameter
13824 * 2. `{*}` Data to compare to the first parameter
13825 *
13826 * And returning:
13827 *
13828 * * `{*}` Ordering match: <0 if first parameter should be sorted lower
13829 * than the second parameter, ===0 if the two parameters are equal and
13830 * >0 if the first parameter should be sorted height than the second
13831 * parameter.
13832 *
13833 * @type object
13834 * @default {}
13835 *
13836 * @example
13837 * // Numeric ordering of formatted numbers with a pre-formatter
13838 * $.extend( $.fn.dataTable.ext.type.order, {
13839 * "string-pre": function(x) {
13840 * a = (a === "-" || a === "") ? 0 : a.replace( /[^\d\-\.]/g, "" );
13841 * return parseFloat( a );
13842 * }
13843 * } );
13844 *
13845 * @example
13846 * // Case-sensitive string ordering, with no pre-formatting method
13847 * $.extend( $.fn.dataTable.ext.order, {
13848 * "string-case-asc": function(x,y) {
13849 * return ((x < y) ? -1 : ((x > y) ? 1 : 0));
13850 * },
13851 * "string-case-desc": function(x,y) {
13852 * return ((x < y) ? 1 : ((x > y) ? -1 : 0));
13853 * }
13854 * } );
13855 */
13856 order: {}
13857 },
13858
13859 /**
13860 * Unique DataTables instance counter
13861 *
13862 * @type int
13863 * @private
13864 */
13865 _unique: 0,
13866
13867
13868 //
13869 // Depreciated
13870 // The following properties are retained for backwards compatiblity only.
13871 // The should not be used in new projects and will be removed in a future
13872 // version
13873 //
13874
13875 /**
13876 * Version check function.
13877 * @type function
13878 * @depreciated Since 1.10
13879 */
13880 fnVersionCheck: DataTable.fnVersionCheck,
13881
13882
13883 /**
13884 * Index for what 'this' index API functions should use
13885 * @type int
13886 * @deprecated Since v1.10
13887 */
13888 iApiIndex: 0,
13889
13890
13891 /**
13892 * jQuery UI class container
13893 * @type object
13894 * @deprecated Since v1.10
13895 */
13896 oJUIClasses: {},
13897
13898
13899 /**
13900 * Software version
13901 * @type string
13902 * @deprecated Since v1.10
13903 */
13904 sVersion: DataTable.version
13905 };
13906
13907
13908 //
13909 // Backwards compatibility. Alias to pre 1.10 Hungarian notation counter parts
13910 //
13911 $.extend( _ext, {
13912 afnFiltering: _ext.search,
13913 aTypes: _ext.type.detect,
13914 ofnSearch: _ext.type.search,
13915 oSort: _ext.type.order,
13916 afnSortData: _ext.order,
13917 aoFeatures: _ext.feature,
13918 oApi: _ext.internal,
13919 oStdClasses: _ext.classes,
13920 oPagination: _ext.pager
13921 } );
13922
13923
13924 $.extend( DataTable.ext.classes, {
13925 "sTable": "dataTable",
13926 "sNoFooter": "no-footer",
13927
13928 /* Paging buttons */
13929 "sPageButton": "paginate_button",
13930 "sPageButtonActive": "current",
13931 "sPageButtonDisabled": "disabled",
13932
13933 /* Striping classes */
13934 "sStripeOdd": "odd",
13935 "sStripeEven": "even",
13936
13937 /* Empty row */
13938 "sRowEmpty": "dataTables_empty",
13939
13940 /* Features */
13941 "sWrapper": "dataTables_wrapper",
13942 "sFilter": "dataTables_filter",
13943 "sInfo": "dataTables_info",
13944 "sPaging": "dataTables_paginate paging_", /* Note that the type is postfixed */
13945 "sLength": "dataTables_length",
13946 "sProcessing": "dataTables_processing",
13947
13948 /* Sorting */
13949 "sSortAsc": "sorting_asc",
13950 "sSortDesc": "sorting_desc",
13951 "sSortable": "sorting", /* Sortable in both directions */
13952 "sSortableAsc": "sorting_asc_disabled",
13953 "sSortableDesc": "sorting_desc_disabled",
13954 "sSortableNone": "sorting_disabled",
13955 "sSortColumn": "sorting_", /* Note that an int is postfixed for the sorting order */
13956
13957 /* Filtering */
13958 "sFilterInput": "",
13959
13960 /* Page length */
13961 "sLengthSelect": "",
13962
13963 /* Scrolling */
13964 "sScrollWrapper": "dataTables_scroll",
13965 "sScrollHead": "dataTables_scrollHead",
13966 "sScrollHeadInner": "dataTables_scrollHeadInner",
13967 "sScrollBody": "dataTables_scrollBody",
13968 "sScrollFoot": "dataTables_scrollFoot",
13969 "sScrollFootInner": "dataTables_scrollFootInner",
13970
13971 /* Misc */
13972 "sHeaderTH": "",
13973 "sFooterTH": "",
13974
13975 // Deprecated
13976 "sSortJUIAsc": "",
13977 "sSortJUIDesc": "",
13978 "sSortJUI": "",
13979 "sSortJUIAscAllowed": "",
13980 "sSortJUIDescAllowed": "",
13981 "sSortJUIWrapper": "",
13982 "sSortIcon": "",
13983 "sJUIHeader": "",
13984 "sJUIFooter": ""
13985 } );
13986
13987
13988 (function() {
13989
13990 // Reused strings for better compression. Closure compiler appears to have a
13991 // weird edge case where it is trying to expand strings rather than use the
13992 // variable version. This results in about 200 bytes being added, for very
13993 // little preference benefit since it this run on script load only.
13994 var _empty = '';
13995 _empty = '';
13996
13997 var _stateDefault = _empty + 'ui-state-default';
13998 var _sortIcon = _empty + 'css_right ui-icon ui-icon-';
13999 var _headerFooter = _empty + 'fg-toolbar ui-toolbar ui-widget-header ui-helper-clearfix';
14000
14001 $.extend( DataTable.ext.oJUIClasses, DataTable.ext.classes, {
14002 /* Full numbers paging buttons */
14003 "sPageButton": "fg-button ui-button "+_stateDefault,
14004 "sPageButtonActive": "ui-state-disabled",
14005 "sPageButtonDisabled": "ui-state-disabled",
14006
14007 /* Features */
14008 "sPaging": "dataTables_paginate fg-buttonset ui-buttonset fg-buttonset-multi "+
14009 "ui-buttonset-multi paging_", /* Note that the type is postfixed */
14010
14011 /* Sorting */
14012 "sSortAsc": _stateDefault+" sorting_asc",
14013 "sSortDesc": _stateDefault+" sorting_desc",
14014 "sSortable": _stateDefault+" sorting",
14015 "sSortableAsc": _stateDefault+" sorting_asc_disabled",
14016 "sSortableDesc": _stateDefault+" sorting_desc_disabled",
14017 "sSortableNone": _stateDefault+" sorting_disabled",
14018 "sSortJUIAsc": _sortIcon+"triangle-1-n",
14019 "sSortJUIDesc": _sortIcon+"triangle-1-s",
14020 "sSortJUI": _sortIcon+"carat-2-n-s",
14021 "sSortJUIAscAllowed": _sortIcon+"carat-1-n",
14022 "sSortJUIDescAllowed": _sortIcon+"carat-1-s",
14023 "sSortJUIWrapper": "DataTables_sort_wrapper",
14024 "sSortIcon": "DataTables_sort_icon",
14025
14026 /* Scrolling */
14027 "sScrollHead": "dataTables_scrollHead "+_stateDefault,
14028 "sScrollFoot": "dataTables_scrollFoot "+_stateDefault,
14029
14030 /* Misc */
14031 "sHeaderTH": _stateDefault,
14032 "sFooterTH": _stateDefault,
14033 "sJUIHeader": _headerFooter+" ui-corner-tl ui-corner-tr",
14034 "sJUIFooter": _headerFooter+" ui-corner-bl ui-corner-br"
14035 } );
14036
14037 }());
14038
14039
14040
14041 var extPagination = DataTable.ext.pager;
14042
14043 function _numbers ( page, pages ) {
14044 var
14045 numbers = [],
14046 buttons = extPagination.numbers_length,
14047 half = Math.floor( buttons / 2 ),
14048 i = 1;
14049
14050 if ( pages <= buttons ) {
14051 numbers = _range( 0, pages );
14052 }
14053 else if ( page <= half ) {
14054 numbers = _range( 0, buttons-2 );
14055 numbers.push( 'ellipsis' );
14056 numbers.push( pages-1 );
14057 }
14058 else if ( page >= pages - 1 - half ) {
14059 numbers = _range( pages-(buttons-2), pages );
14060 numbers.splice( 0, 0, 'ellipsis' ); // no unshift in ie6
14061 numbers.splice( 0, 0, 0 );
14062 }
14063 else {
14064 numbers = _range( page-1, page+2 );
14065 numbers.push( 'ellipsis' );
14066 numbers.push( pages-1 );
14067 numbers.splice( 0, 0, 'ellipsis' );
14068 numbers.splice( 0, 0, 0 );
14069 }
14070
14071 numbers.DT_el = 'span';
14072 return numbers;
14073 }
14074
14075
14076 $.extend( extPagination, {
14077 simple: function ( page, pages ) {
14078 return [ 'previous', 'next' ];
14079 },
14080
14081 full: function ( page, pages ) {
14082 return [ 'first', 'previous', 'next', 'last' ];
14083 },
14084
14085 simple_numbers: function ( page, pages ) {
14086 return [ 'previous', _numbers(page, pages), 'next' ];
14087 },
14088
14089 full_numbers: function ( page, pages ) {
14090 return [ 'first', 'previous', _numbers(page, pages), 'next', 'last' ];
14091 },
14092
14093 // For testing and plug-ins to use
14094 _numbers: _numbers,
14095 numbers_length: 7
14096 } );
14097
14098
14099 $.extend( true, DataTable.ext.renderer, {
14100 pageButton: {
14101 _: function ( settings, host, idx, buttons, page, pages ) {
14102 var classes = settings.oClasses;
14103 var lang = settings.oLanguage.oPaginate;
14104 var btnDisplay, btnClass, counter=0;
14105
14106 var attach = function( container, buttons ) {
14107 var i, ien, node, button;
14108 var clickHandler = function ( e ) {
14109 _fnPageChange( settings, e.data.action, true );
14110 };
14111
14112 for ( i=0, ien=buttons.length ; i<ien ; i++ ) {
14113 button = buttons[i];
14114
14115 if ( $.isArray( button ) ) {
14116 var inner = $( '<'+(button.DT_el || 'div')+'/>' )
14117 .appendTo( container );
14118 attach( inner, button );
14119 }
14120 else {
14121 btnDisplay = '';
14122 btnClass = '';
14123
14124 switch ( button ) {
14125 case 'ellipsis':
14126 container.append('<span>&hellip;</span>');
14127 break;
14128
14129 case 'first':
14130 btnDisplay = lang.sFirst;
14131 btnClass = button + (page > 0 ?
14132 '' : ' '+classes.sPageButtonDisabled);
14133 break;
14134
14135 case 'previous':
14136 btnDisplay = lang.sPrevious;
14137 btnClass = button + (page > 0 ?
14138 '' : ' '+classes.sPageButtonDisabled);
14139 break;
14140
14141 case 'next':
14142 btnDisplay = lang.sNext;
14143 btnClass = button + (page < pages-1 ?
14144 '' : ' '+classes.sPageButtonDisabled);
14145 break;
14146
14147 case 'last':
14148 btnDisplay = lang.sLast;
14149 btnClass = button + (page < pages-1 ?
14150 '' : ' '+classes.sPageButtonDisabled);
14151 break;
14152
14153 default:
14154 btnDisplay = button + 1;
14155 btnClass = page === button ?
14156 classes.sPageButtonActive : '';
14157 break;
14158 }
14159
14160 if ( btnDisplay ) {
14161 node = $('<a>', {
14162 'class': classes.sPageButton+' '+btnClass,
14163 'aria-controls': settings.sTableId,
14164 'data-dt-idx': counter,
14165 'tabindex': settings.iTabIndex,
14166 'id': idx === 0 && typeof button === 'string' ?
14167 settings.sTableId +'_'+ button :
14168 null
14169 } )
14170 .html( btnDisplay )
14171 .appendTo( container );
14172
14173 _fnBindAction(
14174 node, {action: button}, clickHandler
14175 );
14176
14177 counter++;
14178 }
14179 }
14180 }
14181 };
14182
14183 // IE9 throws an 'unknown error' if document.activeElement is used
14184 // inside an iframe or frame. Try / catch the error. Not good for
14185 // accessibility, but neither are frames.
14186 try {
14187 // Because this approach is destroying and recreating the paging
14188 // elements, focus is lost on the select button which is bad for
14189 // accessibility. So we want to restore focus once the draw has
14190 // completed
14191 var activeEl = $(document.activeElement).data('dt-idx');
14192
14193 attach( $(host).empty(), buttons );
14194
14195 if ( activeEl !== null ) {
14196 $(host).find( '[data-dt-idx='+activeEl+']' ).focus();
14197 }
14198 }
14199 catch (e) {}
14200 }
14201 }
14202 } );
14203
14204
14205
14206 // Built in type detection. See model.ext.aTypes for information about
14207 // what is required from this methods.
14208 $.extend( DataTable.ext.type.detect, [
14209 // Plain numbers - first since V8 detects some plain numbers as dates
14210 // e.g. Date.parse('55') (but not all, e.g. Date.parse('22')...).
14211 function ( d, settings )
14212 {
14213 var decimal = settings.oLanguage.sDecimal;
14214 return _isNumber( d, decimal ) ? 'num'+decimal : null;
14215 },
14216
14217 // Dates (only those recognised by the browser's Date.parse)
14218 function ( d, settings )
14219 {
14220 // V8 will remove any unknown characters at the start and end of the
14221 // expression, leading to false matches such as `$245.12` or `10%` being
14222 // a valid date. See forum thread 18941 for detail.
14223 if ( d && !(d instanceof Date) && ( ! _re_date_start.test(d) || ! _re_date_end.test(d) ) ) {
14224 return null;
14225 }
14226 var parsed = Date.parse(d);
14227 return (parsed !== null && !isNaN(parsed)) || _empty(d) ? 'date' : null;
14228 },
14229
14230 // Formatted numbers
14231 function ( d, settings )
14232 {
14233 var decimal = settings.oLanguage.sDecimal;
14234 return _isNumber( d, decimal, true ) ? 'num-fmt'+decimal : null;
14235 },
14236
14237 // HTML numeric
14238 function ( d, settings )
14239 {
14240 var decimal = settings.oLanguage.sDecimal;
14241 return _htmlNumeric( d, decimal ) ? 'html-num'+decimal : null;
14242 },
14243
14244 // HTML numeric, formatted
14245 function ( d, settings )
14246 {
14247 var decimal = settings.oLanguage.sDecimal;
14248 return _htmlNumeric( d, decimal, true ) ? 'html-num-fmt'+decimal : null;
14249 },
14250
14251 // HTML (this is strict checking - there must be html)
14252 function ( d, settings )
14253 {
14254 return _empty( d ) || (typeof d === 'string' && d.indexOf('<') !== -1) ?
14255 'html' : null;
14256 }
14257 ] );
14258
14259
14260
14261 // Filter formatting functions. See model.ext.ofnSearch for information about
14262 // what is required from these methods.
14263 //
14264 // Note that additional search methods are added for the html numbers and
14265 // html formatted numbers by `_addNumericSort()` when we know what the decimal
14266 // place is
14267
14268
14269 $.extend( DataTable.ext.type.search, {
14270 html: function ( data ) {
14271 return _empty(data) ?
14272 data :
14273 typeof data === 'string' ?
14274 data
14275 .replace( _re_new_lines, " " )
14276 .replace( _re_html, "" ) :
14277 '';
14278 },
14279
14280 string: function ( data ) {
14281 return _empty(data) ?
14282 data :
14283 typeof data === 'string' ?
14284 data.replace( _re_new_lines, " " ) :
14285 data;
14286 }
14287 } );
14288
14289
14290
14291 var __numericReplace = function ( d, decimalPlace, re1, re2 ) {
14292 if ( d !== 0 && (!d || d === '-') ) {
14293 return -Infinity;
14294 }
14295
14296 // If a decimal place other than `.` is used, it needs to be given to the
14297 // function so we can detect it and replace with a `.` which is the only
14298 // decimal place Javascript recognises - it is not locale aware.
14299 if ( decimalPlace ) {
14300 d = _numToDecimal( d, decimalPlace );
14301 }
14302
14303 if ( d.replace ) {
14304 if ( re1 ) {
14305 d = d.replace( re1, '' );
14306 }
14307
14308 if ( re2 ) {
14309 d = d.replace( re2, '' );
14310 }
14311 }
14312
14313 return d * 1;
14314 };
14315
14316
14317 // Add the numeric 'deformatting' functions for sorting and search. This is done
14318 // in a function to provide an easy ability for the language options to add
14319 // additional methods if a non-period decimal place is used.
14320 function _addNumericSort ( decimalPlace ) {
14321 $.each(
14322 {
14323 // Plain numbers
14324 "num": function ( d ) {
14325 return __numericReplace( d, decimalPlace );
14326 },
14327
14328 // Formatted numbers
14329 "num-fmt": function ( d ) {
14330 return __numericReplace( d, decimalPlace, _re_formatted_numeric );
14331 },
14332
14333 // HTML numeric
14334 "html-num": function ( d ) {
14335 return __numericReplace( d, decimalPlace, _re_html );
14336 },
14337
14338 // HTML numeric, formatted
14339 "html-num-fmt": function ( d ) {
14340 return __numericReplace( d, decimalPlace, _re_html, _re_formatted_numeric );
14341 }
14342 },
14343 function ( key, fn ) {
14344 // Add the ordering method
14345 _ext.type.order[ key+decimalPlace+'-pre' ] = fn;
14346
14347 // For HTML types add a search formatter that will strip the HTML
14348 if ( key.match(/^html\-/) ) {
14349 _ext.type.search[ key+decimalPlace ] = _ext.type.search.html;
14350 }
14351 }
14352 );
14353 }
14354
14355
14356 // Default sort methods
14357 $.extend( _ext.type.order, {
14358 // Dates
14359 "date-pre": function ( d ) {
14360 return Date.parse( d ) || 0;
14361 },
14362
14363 // html
14364 "html-pre": function ( a ) {
14365 return _empty(a) ?
14366 '' :
14367 a.replace ?
14368 a.replace( /<.*?>/g, "" ).toLowerCase() :
14369 a+'';
14370 },
14371
14372 // string
14373 "string-pre": function ( a ) {
14374 // This is a little complex, but faster than always calling toString,
14375 // http://jsperf.com/tostring-v-check
14376 return _empty(a) ?
14377 '' :
14378 typeof a === 'string' ?
14379 a.toLowerCase() :
14380 ! a.toString ?
14381 '' :
14382 a.toString();
14383 },
14384
14385 // string-asc and -desc are retained only for compatibility with the old
14386 // sort methods
14387 "string-asc": function ( x, y ) {
14388 return ((x < y) ? -1 : ((x > y) ? 1 : 0));
14389 },
14390
14391 "string-desc": function ( x, y ) {
14392 return ((x < y) ? 1 : ((x > y) ? -1 : 0));
14393 }
14394 } );
14395
14396
14397 // Numeric sorting types - order doesn't matter here
14398 _addNumericSort( '' );
14399
14400
14401 $.extend( true, DataTable.ext.renderer, {
14402 header: {
14403 _: function ( settings, cell, column, classes ) {
14404 // No additional mark-up required
14405 // Attach a sort listener to update on sort - note that using the
14406 // `DT` namespace will allow the event to be removed automatically
14407 // on destroy, while the `dt` namespaced event is the one we are
14408 // listening for
14409 $(settings.nTable).on( 'order.dt.DT', function ( e, ctx, sorting, columns ) {
14410 if ( settings !== ctx ) { // need to check this this is the host
14411 return; // table, not a nested one
14412 }
14413
14414 var colIdx = column.idx;
14415
14416 cell
14417 .removeClass(
14418 column.sSortingClass +' '+
14419 classes.sSortAsc +' '+
14420 classes.sSortDesc
14421 )
14422 .addClass( columns[ colIdx ] == 'asc' ?
14423 classes.sSortAsc : columns[ colIdx ] == 'desc' ?
14424 classes.sSortDesc :
14425 column.sSortingClass
14426 );
14427 } );
14428 },
14429
14430 jqueryui: function ( settings, cell, column, classes ) {
14431 $('<div/>')
14432 .addClass( classes.sSortJUIWrapper )
14433 .append( cell.contents() )
14434 .append( $('<span/>')
14435 .addClass( classes.sSortIcon+' '+column.sSortingClassJUI )
14436 )
14437 .appendTo( cell );
14438
14439 // Attach a sort listener to update on sort
14440 $(settings.nTable).on( 'order.dt.DT', function ( e, ctx, sorting, columns ) {
14441 if ( settings !== ctx ) {
14442 return;
14443 }
14444
14445 var colIdx = column.idx;
14446
14447 cell
14448 .removeClass( classes.sSortAsc +" "+classes.sSortDesc )
14449 .addClass( columns[ colIdx ] == 'asc' ?
14450 classes.sSortAsc : columns[ colIdx ] == 'desc' ?
14451 classes.sSortDesc :
14452 column.sSortingClass
14453 );
14454
14455 cell
14456 .find( 'span.'+classes.sSortIcon )
14457 .removeClass(
14458 classes.sSortJUIAsc +" "+
14459 classes.sSortJUIDesc +" "+
14460 classes.sSortJUI +" "+
14461 classes.sSortJUIAscAllowed +" "+
14462 classes.sSortJUIDescAllowed
14463 )
14464 .addClass( columns[ colIdx ] == 'asc' ?
14465 classes.sSortJUIAsc : columns[ colIdx ] == 'desc' ?
14466 classes.sSortJUIDesc :
14467 column.sSortingClassJUI
14468 );
14469 } );
14470 }
14471 }
14472 } );
14473
14474 /*
14475 * Public helper functions. These aren't used internally by DataTables, or
14476 * called by any of the options passed into DataTables, but they can be used
14477 * externally by developers working with DataTables. They are helper functions
14478 * to make working with DataTables a little bit easier.
14479 */
14480
14481 /**
14482 * Helpers for `columns.render`.
14483 *
14484 * The options defined here can be used with the `columns.render` initialisation
14485 * option to provide a display renderer. The following functions are defined:
14486 *
14487 * * `number` - Will format numeric data (defined by `columns.data`) for
14488 * display, retaining the original unformatted data for sorting and filtering.
14489 * It takes 4 parameters:
14490 * * `string` - Thousands grouping separator
14491 * * `string` - Decimal point indicator
14492 * * `integer` - Number of decimal points to show
14493 * * `string` (optional) - Prefix.
14494 *
14495 * @example
14496 * // Column definition using the number renderer
14497 * {
14498 * data: "salary",
14499 * render: $.fn.dataTable.render.number( '\'', '.', 0, '$' )
14500 * }
14501 *
14502 * @namespace
14503 */
14504 DataTable.render = {
14505 number: function ( thousands, decimal, precision, prefix ) {
14506 return {
14507 display: function ( d ) {
14508 var negative = d < 0 ? '-' : '';
14509 d = Math.abs( parseFloat( d ) );
14510
14511 var intPart = parseInt( d, 10 );
14512 var floatPart = precision ?
14513 decimal+(d - intPart).toFixed( precision ).substring( 2 ):
14514 '';
14515
14516 return negative + (prefix||'') +
14517 intPart.toString().replace(
14518 /\B(?=(\d{3})+(?!\d))/g, thousands
14519 ) +
14520 floatPart;
14521 }
14522 };
14523 }
14524 };
14525
14526
14527 /*
14528 * This is really a good bit rubbish this method of exposing the internal methods
14529 * publicly... - To be fixed in 2.0 using methods on the prototype
14530 */
14531
14532
14533 /**
14534 * Create a wrapper function for exporting an internal functions to an external API.
14535 * @param {string} fn API function name
14536 * @returns {function} wrapped function
14537 * @memberof DataTable#internal
14538 */
14539 function _fnExternApiFunc (fn)
14540 {
14541 return function() {
14542 var args = [_fnSettingsFromNode( this[DataTable.ext.iApiIndex] )].concat(
14543 Array.prototype.slice.call(arguments)
14544 );
14545 return DataTable.ext.internal[fn].apply( this, args );
14546 };
14547 }
14548
14549
14550 /**
14551 * Reference to internal functions for use by plug-in developers. Note that
14552 * these methods are references to internal functions and are considered to be
14553 * private. If you use these methods, be aware that they are liable to change
14554 * between versions.
14555 * @namespace
14556 */
14557 $.extend( DataTable.ext.internal, {
14558 _fnExternApiFunc: _fnExternApiFunc,
14559 _fnBuildAjax: _fnBuildAjax,
14560 _fnAjaxUpdate: _fnAjaxUpdate,
14561 _fnAjaxParameters: _fnAjaxParameters,
14562 _fnAjaxUpdateDraw: _fnAjaxUpdateDraw,
14563 _fnAjaxDataSrc: _fnAjaxDataSrc,
14564 _fnAddColumn: _fnAddColumn,
14565 _fnColumnOptions: _fnColumnOptions,
14566 _fnAdjustColumnSizing: _fnAdjustColumnSizing,
14567 _fnVisibleToColumnIndex: _fnVisibleToColumnIndex,
14568 _fnColumnIndexToVisible: _fnColumnIndexToVisible,
14569 _fnVisbleColumns: _fnVisbleColumns,
14570 _fnGetColumns: _fnGetColumns,
14571 _fnColumnTypes: _fnColumnTypes,
14572 _fnApplyColumnDefs: _fnApplyColumnDefs,
14573 _fnHungarianMap: _fnHungarianMap,
14574 _fnCamelToHungarian: _fnCamelToHungarian,
14575 _fnLanguageCompat: _fnLanguageCompat,
14576 _fnBrowserDetect: _fnBrowserDetect,
14577 _fnAddData: _fnAddData,
14578 _fnAddTr: _fnAddTr,
14579 _fnNodeToDataIndex: _fnNodeToDataIndex,
14580 _fnNodeToColumnIndex: _fnNodeToColumnIndex,
14581 _fnGetCellData: _fnGetCellData,
14582 _fnSetCellData: _fnSetCellData,
14583 _fnSplitObjNotation: _fnSplitObjNotation,
14584 _fnGetObjectDataFn: _fnGetObjectDataFn,
14585 _fnSetObjectDataFn: _fnSetObjectDataFn,
14586 _fnGetDataMaster: _fnGetDataMaster,
14587 _fnClearTable: _fnClearTable,
14588 _fnDeleteIndex: _fnDeleteIndex,
14589 _fnInvalidate: _fnInvalidate,
14590 _fnGetRowElements: _fnGetRowElements,
14591 _fnCreateTr: _fnCreateTr,
14592 _fnBuildHead: _fnBuildHead,
14593 _fnDrawHead: _fnDrawHead,
14594 _fnDraw: _fnDraw,
14595 _fnReDraw: _fnReDraw,
14596 _fnAddOptionsHtml: _fnAddOptionsHtml,
14597 _fnDetectHeader: _fnDetectHeader,
14598 _fnGetUniqueThs: _fnGetUniqueThs,
14599 _fnFeatureHtmlFilter: _fnFeatureHtmlFilter,
14600 _fnFilterComplete: _fnFilterComplete,
14601 _fnFilterCustom: _fnFilterCustom,
14602 _fnFilterColumn: _fnFilterColumn,
14603 _fnFilter: _fnFilter,
14604 _fnFilterCreateSearch: _fnFilterCreateSearch,
14605 _fnEscapeRegex: _fnEscapeRegex,
14606 _fnFilterData: _fnFilterData,
14607 _fnFeatureHtmlInfo: _fnFeatureHtmlInfo,
14608 _fnUpdateInfo: _fnUpdateInfo,
14609 _fnInfoMacros: _fnInfoMacros,
14610 _fnInitialise: _fnInitialise,
14611 _fnInitComplete: _fnInitComplete,
14612 _fnLengthChange: _fnLengthChange,
14613 _fnFeatureHtmlLength: _fnFeatureHtmlLength,
14614 _fnFeatureHtmlPaginate: _fnFeatureHtmlPaginate,
14615 _fnPageChange: _fnPageChange,
14616 _fnFeatureHtmlProcessing: _fnFeatureHtmlProcessing,
14617 _fnProcessingDisplay: _fnProcessingDisplay,
14618 _fnFeatureHtmlTable: _fnFeatureHtmlTable,
14619 _fnScrollDraw: _fnScrollDraw,
14620 _fnApplyToChildren: _fnApplyToChildren,
14621 _fnCalculateColumnWidths: _fnCalculateColumnWidths,
14622 _fnThrottle: _fnThrottle,
14623 _fnConvertToWidth: _fnConvertToWidth,
14624 _fnScrollingWidthAdjust: _fnScrollingWidthAdjust,
14625 _fnGetWidestNode: _fnGetWidestNode,
14626 _fnGetMaxLenString: _fnGetMaxLenString,
14627 _fnStringToCss: _fnStringToCss,
14628 _fnScrollBarWidth: _fnScrollBarWidth,
14629 _fnSortFlatten: _fnSortFlatten,
14630 _fnSort: _fnSort,
14631 _fnSortAria: _fnSortAria,
14632 _fnSortListener: _fnSortListener,
14633 _fnSortAttachListener: _fnSortAttachListener,
14634 _fnSortingClasses: _fnSortingClasses,
14635 _fnSortData: _fnSortData,
14636 _fnSaveState: _fnSaveState,
14637 _fnLoadState: _fnLoadState,
14638 _fnSettingsFromNode: _fnSettingsFromNode,
14639 _fnLog: _fnLog,
14640 _fnMap: _fnMap,
14641 _fnBindAction: _fnBindAction,
14642 _fnCallbackReg: _fnCallbackReg,
14643 _fnCallbackFire: _fnCallbackFire,
14644 _fnLengthOverflow: _fnLengthOverflow,
14645 _fnRenderer: _fnRenderer,
14646 _fnDataSource: _fnDataSource,
14647 _fnRowAttributes: _fnRowAttributes,
14648 _fnCalculateEnd: function () {} // Used by a lot of plug-ins, but redundant
14649 // in 1.10, so this dead-end function is
14650 // added to prevent errors
14651 } );
14652
14653
14654 // jQuery access
14655 $.fn.dataTable = DataTable;
14656
14657 // Legacy aliases
14658 $.fn.dataTableSettings = DataTable.settings;
14659 $.fn.dataTableExt = DataTable.ext;
14660
14661 // With a capital `D` we return a DataTables API instance rather than a
14662 // jQuery object
14663 $.fn.DataTable = function ( opts ) {
14664 return $(this).dataTable( opts ).api();
14665 };
14666
14667 // All properties that are available to $.fn.dataTable should also be
14668 // available on $.fn.DataTable
14669 $.each( DataTable, function ( prop, val ) {
14670 $.fn.DataTable[ prop ] = val;
14671 } );
14672
14673
14674 // Information about events fired by DataTables - for documentation.
14675 /**
14676 * Draw event, fired whenever the table is redrawn on the page, at the same
14677 * point as fnDrawCallback. This may be useful for binding events or
14678 * performing calculations when the table is altered at all.
14679 * @name DataTable#draw.dt
14680 * @event
14681 * @param {event} e jQuery event object
14682 * @param {object} o DataTables settings object {@link DataTable.models.oSettings}
14683 */
14684
14685 /**
14686 * Search event, fired when the searching applied to the table (using the
14687 * built-in global search, or column filters) is altered.
14688 * @name DataTable#search.dt
14689 * @event
14690 * @param {event} e jQuery event object
14691 * @param {object} o DataTables settings object {@link DataTable.models.oSettings}
14692 */
14693
14694 /**
14695 * Page change event, fired when the paging of the table is altered.
14696 * @name DataTable#page.dt
14697 * @event
14698 * @param {event} e jQuery event object
14699 * @param {object} o DataTables settings object {@link DataTable.models.oSettings}
14700 */
14701
14702 /**
14703 * Order event, fired when the ordering applied to the table is altered.
14704 * @name DataTable#order.dt
14705 * @event
14706 * @param {event} e jQuery event object
14707 * @param {object} o DataTables settings object {@link DataTable.models.oSettings}
14708 */
14709
14710 /**
14711 * DataTables initialisation complete event, fired when the table is fully
14712 * drawn, including Ajax data loaded, if Ajax data is required.
14713 * @name DataTable#init.dt
14714 * @event
14715 * @param {event} e jQuery event object
14716 * @param {object} oSettings DataTables settings object
14717 * @param {object} json The JSON object request from the server - only
14718 * present if client-side Ajax sourced data is used</li></ol>
14719 */
14720
14721 /**
14722 * State save event, fired when the table has changed state a new state save
14723 * is required. This event allows modification of the state saving object
14724 * prior to actually doing the save, including addition or other state
14725 * properties (for plug-ins) or modification of a DataTables core property.
14726 * @name DataTable#stateSaveParams.dt
14727 * @event
14728 * @param {event} e jQuery event object
14729 * @param {object} oSettings DataTables settings object
14730 * @param {object} json The state information to be saved
14731 */
14732
14733 /**
14734 * State load event, fired when the table is loading state from the stored
14735 * data, but prior to the settings object being modified by the saved state
14736 * - allowing modification of the saved state is required or loading of
14737 * state for a plug-in.
14738 * @name DataTable#stateLoadParams.dt
14739 * @event
14740 * @param {event} e jQuery event object
14741 * @param {object} oSettings DataTables settings object
14742 * @param {object} json The saved state information
14743 */
14744
14745 /**
14746 * State loaded event, fired when state has been loaded from stored data and
14747 * the settings object has been modified by the loaded data.
14748 * @name DataTable#stateLoaded.dt
14749 * @event
14750 * @param {event} e jQuery event object
14751 * @param {object} oSettings DataTables settings object
14752 * @param {object} json The saved state information
14753 */
14754
14755 /**
14756 * Processing event, fired when DataTables is doing some kind of processing
14757 * (be it, order, searcg or anything else). It can be used to indicate to
14758 * the end user that there is something happening, or that something has
14759 * finished.
14760 * @name DataTable#processing.dt
14761 * @event
14762 * @param {event} e jQuery event object
14763 * @param {object} oSettings DataTables settings object
14764 * @param {boolean} bShow Flag for if DataTables is doing processing or not
14765 */
14766
14767 /**
14768 * Ajax (XHR) event, fired whenever an Ajax request is completed from a
14769 * request to made to the server for new data. This event is called before
14770 * DataTables processed the returned data, so it can also be used to pre-
14771 * process the data returned from the server, if needed.
14772 *
14773 * Note that this trigger is called in `fnServerData`, if you override
14774 * `fnServerData` and which to use this event, you need to trigger it in you
14775 * success function.
14776 * @name DataTable#xhr.dt
14777 * @event
14778 * @param {event} e jQuery event object
14779 * @param {object} o DataTables settings object {@link DataTable.models.oSettings}
14780 * @param {object} json JSON returned from the server
14781 *
14782 * @example
14783 * // Use a custom property returned from the server in another DOM element
14784 * $('#table').dataTable().on('xhr.dt', function (e, settings, json) {
14785 * $('#status').html( json.status );
14786 * } );
14787 *
14788 * @example
14789 * // Pre-process the data returned from the server
14790 * $('#table').dataTable().on('xhr.dt', function (e, settings, json) {
14791 * for ( var i=0, ien=json.aaData.length ; i<ien ; i++ ) {
14792 * json.aaData[i].sum = json.aaData[i].one + json.aaData[i].two;
14793 * }
14794 * // Note no return - manipulate the data directly in the JSON object.
14795 * } );
14796 */
14797
14798 /**
14799 * Destroy event, fired when the DataTable is destroyed by calling fnDestroy
14800 * or passing the bDestroy:true parameter in the initialisation object. This
14801 * can be used to remove bound events, added DOM nodes, etc.
14802 * @name DataTable#destroy.dt
14803 * @event
14804 * @param {event} e jQuery event object
14805 * @param {object} o DataTables settings object {@link DataTable.models.oSettings}
14806 */
14807
14808 /**
14809 * Page length change event, fired when number of records to show on each
14810 * page (the length) is changed.
14811 * @name DataTable#length.dt
14812 * @event
14813 * @param {event} e jQuery event object
14814 * @param {object} o DataTables settings object {@link DataTable.models.oSettings}
14815 * @param {integer} len New length
14816 */
14817
14818 /**
14819 * Column sizing has changed.
14820 * @name DataTable#column-sizing.dt
14821 * @event
14822 * @param {event} e jQuery event object
14823 * @param {object} o DataTables settings object {@link DataTable.models.oSettings}
14824 */
14825
14826 /**
14827 * Column visibility has changed.
14828 * @name DataTable#column-visibility.dt
14829 * @event
14830 * @param {event} e jQuery event object
14831 * @param {object} o DataTables settings object {@link DataTable.models.oSettings}
14832 * @param {int} column Column index
14833 * @param {bool} vis `false` if column now hidden, or `true` if visible
14834 */
14835
14836 return $.fn.dataTable;
14837 }));
14838
14839 }(window, document));
14840