comparison jquery.dataTables.js.vew @ 6:42076db43d42 draft

Fixed auto resizing plus various other minor bugs
author saskia-hiltemann
date Mon, 16 Nov 2015 08:56:22 -0500
parents
children
comparison
equal deleted inserted replaced
5:4e21ce709269 6:42076db43d42
1 /*! DataTables 1.10.9
2 * ©2008-2015 SpryMedia Ltd - datatables.net/license
3 */
4
5 /**
6 * @summary DataTables
7 * @description Paginate, search and order HTML tables
8 * @version 1.10.9
9 * @file jquery.dataTables.js
10 * @author SpryMedia Ltd (www.sprymedia.co.uk)
11 * @contact www.sprymedia.co.uk/contact
12 * @copyright Copyright 2008-2015 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,_fnGetWidestNode,_fnGetMaxLenString,_fnStringToCss,_fnSortFlatten,_fnSort,_fnSortAria,_fnSortListener,_fnSortAttachListener,_fnSortingClasses,_fnSortData,_fnSaveState,_fnLoadState,_fnSettingsFromNode,_fnLog,_fnMap,_fnBindAction,_fnCallbackReg,_fnCallbackFire,_fnLengthOverflow,_fnRenderer,_fnDataSource,_fnRowAttributes*/
26
27 (/** @lends <global> */function( window, document, undefined ) {
28
29 (function( factory ) {
30 "use strict";
31
32 if ( typeof define === 'function' && define.amd ) {
33 // Define as an AMD module if possible
34 define( 'datatables', ['jquery'], factory );
35 }
36 else if ( typeof exports === 'object' ) {
37 // Node/CommonJS
38 module.exports = factory( require( 'jquery' ) );
39 }
40 else if ( jQuery && !jQuery.fn.dataTable ) {
41 // Define using browser globals otherwise
42 // Prevent multiple instantiations if the script is loaded twice
43 factory( jQuery );
44 }
45 }
46 (/** @lends <global> */function( $ ) {
47 "use strict";
48
49 /**
50 * DataTables is a plug-in for the jQuery Javascript library. It is a highly
51 * flexible tool, based upon the foundations of progressive enhancement,
52 * which will add advanced interaction controls to any HTML table. For a
53 * full list of features please refer to
54 * [DataTables.net](href="http://datatables.net).
55 *
56 * Note that the `DataTable` object is not a global variable but is aliased
57 * to `jQuery.fn.DataTable` and `jQuery.fn.dataTable` through which it may
58 * be accessed.
59 *
60 * @class
61 * @param {object} [init={}] Configuration object for DataTables. Options
62 * are defined by {@link DataTable.defaults}
63 * @requires jQuery 1.7+
64 *
65 * @example
66 * // Basic initialisation
67 * $(document).ready( function {
68 * $('#example').dataTable();
69 * } );
70 *
71 * @example
72 * // Initialisation with configuration options - in this case, disable
73 * // pagination and sorting.
74 * $(document).ready( function {
75 * $('#example').dataTable( {
76 * "paginate": false,
77 * "sort": false
78 * } );
79 * } );
80 */
81 var DataTable;
82
83
84 /*
85 * It is useful to have variables which are scoped locally so only the
86 * DataTables functions can access them and they don't leak into global space.
87 * At the same time these functions are often useful over multiple files in the
88 * core and API, so we list, or at least document, all variables which are used
89 * by DataTables as private variables here. This also ensures that there is no
90 * clashing of variable names and that they can easily referenced for reuse.
91 */
92
93
94 // Defined else where
95 // _selector_run
96 // _selector_opts
97 // _selector_first
98 // _selector_row_indexes
99
100 var _ext; // DataTable.ext
101 var _Api; // DataTable.Api
102 var _api_register; // DataTable.Api.register
103 var _api_registerPlural; // DataTable.Api.registerPlural
104
105 var _re_dic = {};
106 var _re_new_lines = /[\r\n]/g;
107 var _re_html = /<.*?>/g;
108 var _re_date_start = /^[\w\+\-]/;
109 var _re_date_end = /[\w\+\-]$/;
110
111 // Escape regular expression special characters
112 var _re_escape_regex = new RegExp( '(\\' + [ '/', '.', '*', '+', '?', '|', '(', ')', '[', ']', '{', '}', '\\', '$', '^', '-' ].join('|\\') + ')', 'g' );
113
114 // http://en.wikipedia.org/wiki/Foreign_exchange_market
115 // - \u20BD - Russian ruble.
116 // - \u20a9 - South Korean Won
117 // - \u20BA - Turkish Lira
118 // - \u20B9 - Indian Rupee
119 // - R - Brazil (R$) and South Africa
120 // - fr - Swiss Franc
121 // - kr - Swedish krona, Norwegian krone and Danish krone
122 // - \u2009 is thin space and \u202F is narrow no-break space, both used in many
123 // standards as thousands separators.
124 var _re_formatted_numeric = /[',$£€¥%\u2009\u202F\u20BD\u20a9\u20BArfk]/gi;
125
126
127 var _empty = function ( d ) {
128 return !d || d === true || d === '-' ? true : false;
129 };
130
131
132 var _intVal = function ( s ) {
133 var integer = parseInt( s, 10 );
134 return !isNaN(integer) && isFinite(s) ? integer : null;
135 };
136
137 // Convert from a formatted number with characters other than `.` as the
138 // decimal place, to a Javascript number
139 var _numToDecimal = function ( num, decimalPoint ) {
140 // Cache created regular expressions for speed as this function is called often
141 if ( ! _re_dic[ decimalPoint ] ) {
142 _re_dic[ decimalPoint ] = new RegExp( _fnEscapeRegex( decimalPoint ), 'g' );
143 }
144 return typeof num === 'string' && decimalPoint !== '.' ?
145 num.replace( /\./g, '' ).replace( _re_dic[ decimalPoint ], '.' ) :
146 num;
147 };
148
149
150 var _isNumber = function ( d, decimalPoint, formatted ) {
151 var strType = typeof d === 'string';
152
153 // If empty return immediately so there must be a number if it is a
154 // formatted string (this stops the string "k", or "kr", etc being detected
155 // as a formatted number for currency
156 if ( _empty( d ) ) {
157 return true;
158 }
159
160 if ( decimalPoint && strType ) {
161 d = _numToDecimal( d, decimalPoint );
162 }
163
164 if ( formatted && strType ) {
165 d = d.replace( _re_formatted_numeric, '' );
166 }
167
168 return !isNaN( parseFloat(d) ) && isFinite( d );
169 };
170
171
172 // A string without HTML in it can be considered to be HTML still
173 var _isHtml = function ( d ) {
174 return _empty( d ) || typeof d === 'string';
175 };
176
177
178 var _htmlNumeric = function ( d, decimalPoint, formatted ) {
179 if ( _empty( d ) ) {
180 return true;
181 }
182
183 var html = _isHtml( d );
184 return ! html ?
185 null :
186 _isNumber( _stripHtml( d ), decimalPoint, formatted ) ?
187 true :
188 null;
189 };
190
191
192 var _pluck = function ( a, prop, prop2 ) {
193 var out = [];
194 var i=0, ien=a.length;
195
196 // Could have the test in the loop for slightly smaller code, but speed
197 // is essential here
198 if ( prop2 !== undefined ) {
199 for ( ; i<ien ; i++ ) {
200 if ( a[i] && a[i][ prop ] ) {
201 out.push( a[i][ prop ][ prop2 ] );
202 }
203 }
204 }
205 else {
206 for ( ; i<ien ; i++ ) {
207 if ( a[i] ) {
208 out.push( a[i][ prop ] );
209 }
210 }
211 }
212
213 return out;
214 };
215
216
217 // Basically the same as _pluck, but rather than looping over `a` we use `order`
218 // as the indexes to pick from `a`
219 var _pluck_order = function ( a, order, prop, prop2 )
220 {
221 var out = [];
222 var i=0, ien=order.length;
223
224 // Could have the test in the loop for slightly smaller code, but speed
225 // is essential here
226 if ( prop2 !== undefined ) {
227 for ( ; i<ien ; i++ ) {
228 if ( a[ order[i] ][ prop ] ) {
229 out.push( a[ order[i] ][ prop ][ prop2 ] );
230 }
231 }
232 }
233 else {
234 for ( ; i<ien ; i++ ) {
235 out.push( a[ order[i] ][ prop ] );
236 }
237 }
238
239 return out;
240 };
241
242
243 var _range = function ( len, start )
244 {
245 var out = [];
246 var end;
247
248 if ( start === undefined ) {
249 start = 0;
250 end = len;
251 }
252 else {
253 end = start;
254 start = len;
255 }
256
257 for ( var i=start ; i<end ; i++ ) {
258 out.push( i );
259 }
260
261 return out;
262 };
263
264
265 var _removeEmpty = function ( a )
266 {
267 var out = [];
268
269 for ( var i=0, ien=a.length ; i<ien ; i++ ) {
270 if ( a[i] ) { // careful - will remove all falsy values!
271 out.push( a[i] );
272 }
273 }
274
275 return out;
276 };
277
278
279 var _stripHtml = function ( d ) {
280 return d.replace( _re_html, '' );
281 };
282
283
284 /**
285 * Find the unique elements in a source array.
286 *
287 * @param {array} src Source array
288 * @return {array} Array of unique items
289 * @ignore
290 */
291 var _unique = function ( src )
292 {
293 // A faster unique method is to use object keys to identify used values,
294 // but this doesn't work with arrays or objects, which we must also
295 // consider. See jsperf.com/compare-array-unique-versions/4 for more
296 // information.
297 var
298 out = [],
299 val,
300 i, ien=src.length,
301 j, k=0;
302
303 again: for ( i=0 ; i<ien ; i++ ) {
304 val = src[i];
305
306 for ( j=0 ; j<k ; j++ ) {
307 if ( out[j] === val ) {
308 continue again;
309 }
310 }
311
312 out.push( val );
313 k++;
314 }
315
316 return out;
317 };
318
319
320
321 /**
322 * Create a mapping object that allows camel case parameters to be looked up
323 * for their Hungarian counterparts. The mapping is stored in a private
324 * parameter called `_hungarianMap` which can be accessed on the source object.
325 * @param {object} o
326 * @memberof DataTable#oApi
327 */
328 function _fnHungarianMap ( o )
329 {
330 var
331 hungarian = 'a aa ai ao as b fn i m o s ',
332 match,
333 newKey,
334 map = {};
335
336 $.each( o, function (key, val) {
337 match = key.match(/^([^A-Z]+?)([A-Z])/);
338
339 if ( match && hungarian.indexOf(match[1]+' ') !== -1 )
340 {
341 newKey = key.replace( match[0], match[2].toLowerCase() );
342 map[ newKey ] = key;
343
344 if ( match[1] === 'o' )
345 {
346 _fnHungarianMap( o[key] );
347 }
348 }
349 } );
350
351 o._hungarianMap = map;
352 }
353
354
355 /**
356 * Convert from camel case parameters to Hungarian, based on a Hungarian map
357 * created by _fnHungarianMap.
358 * @param {object} src The model object which holds all parameters that can be
359 * mapped.
360 * @param {object} user The object to convert from camel case to Hungarian.
361 * @param {boolean} force When set to `true`, properties which already have a
362 * Hungarian value in the `user` object will be overwritten. Otherwise they
363 * won't be.
364 * @memberof DataTable#oApi
365 */
366 function _fnCamelToHungarian ( src, user, force )
367 {
368 if ( ! src._hungarianMap ) {
369 _fnHungarianMap( src );
370 }
371
372 var hungarianKey;
373
374 $.each( user, function (key, val) {
375 hungarianKey = src._hungarianMap[ key ];
376
377 if ( hungarianKey !== undefined && (force || user[hungarianKey] === undefined) )
378 {
379 // For objects, we need to buzz down into the object to copy parameters
380 if ( hungarianKey.charAt(0) === 'o' )
381 {
382 // Copy the camelCase options over to the hungarian
383 if ( ! user[ hungarianKey ] ) {
384 user[ hungarianKey ] = {};
385 }
386 $.extend( true, user[hungarianKey], user[key] );
387
388 _fnCamelToHungarian( src[hungarianKey], user[hungarianKey], force );
389 }
390 else {
391 user[hungarianKey] = user[ key ];
392 }
393 }
394 } );
395 }
396
397
398 /**
399 * Language compatibility - when certain options are given, and others aren't, we
400 * need to duplicate the values over, in order to provide backwards compatibility
401 * with older language files.
402 * @param {object} oSettings dataTables settings object
403 * @memberof DataTable#oApi
404 */
405 function _fnLanguageCompat( lang )
406 {
407 var defaults = DataTable.defaults.oLanguage;
408 var zeroRecords = lang.sZeroRecords;
409
410 /* Backwards compatibility - if there is no sEmptyTable given, then use the same as
411 * sZeroRecords - assuming that is given.
412 */
413 if ( ! lang.sEmptyTable && zeroRecords &&
414 defaults.sEmptyTable === "No data available in table" )
415 {
416 _fnMap( lang, lang, 'sZeroRecords', 'sEmptyTable' );
417 }
418
419 /* Likewise with loading records */
420 if ( ! lang.sLoadingRecords && zeroRecords &&
421 defaults.sLoadingRecords === "Loading..." )
422 {
423 _fnMap( lang, lang, 'sZeroRecords', 'sLoadingRecords' );
424 }
425
426 // Old parameter name of the thousands separator mapped onto the new
427 if ( lang.sInfoThousands ) {
428 lang.sThousands = lang.sInfoThousands;
429 }
430
431 var decimal = lang.sDecimal;
432 if ( decimal ) {
433 _addNumericSort( decimal );
434 }
435 }
436
437
438 /**
439 * Map one parameter onto another
440 * @param {object} o Object to map
441 * @param {*} knew The new parameter name
442 * @param {*} old The old parameter name
443 */
444 var _fnCompatMap = function ( o, knew, old ) {
445 if ( o[ knew ] !== undefined ) {
446 o[ old ] = o[ knew ];
447 }
448 };
449
450
451 /**
452 * Provide backwards compatibility for the main DT options. Note that the new
453 * options are mapped onto the old parameters, so this is an external interface
454 * change only.
455 * @param {object} init Object to map
456 */
457 function _fnCompatOpts ( init )
458 {
459 _fnCompatMap( init, 'ordering', 'bSort' );
460 _fnCompatMap( init, 'orderMulti', 'bSortMulti' );
461 _fnCompatMap( init, 'orderClasses', 'bSortClasses' );
462 _fnCompatMap( init, 'orderCellsTop', 'bSortCellsTop' );
463 _fnCompatMap( init, 'order', 'aaSorting' );
464 _fnCompatMap( init, 'orderFixed', 'aaSortingFixed' );
465 _fnCompatMap( init, 'paging', 'bPaginate' );
466 _fnCompatMap( init, 'pagingType', 'sPaginationType' );
467 _fnCompatMap( init, 'pageLength', 'iDisplayLength' );
468 _fnCompatMap( init, 'searching', 'bFilter' );
469
470 // Boolean initialisation of x-scrolling
471 if ( typeof init.sScrollX === 'boolean' ) {
472 init.sScrollX = init.sScrollX ? '100%' : '';
473 }
474
475 // Column search objects are in an array, so it needs to be converted
476 // element by element
477 var searchCols = init.aoSearchCols;
478
479 if ( searchCols ) {
480 for ( var i=0, ien=searchCols.length ; i<ien ; i++ ) {
481 if ( searchCols[i] ) {
482 _fnCamelToHungarian( DataTable.models.oSearch, searchCols[i] );
483 }
484 }
485 }
486 }
487
488
489 /**
490 * Provide backwards compatibility for column options. Note that the new options
491 * are mapped onto the old parameters, so this is an external interface change
492 * only.
493 * @param {object} init Object to map
494 */
495 function _fnCompatCols ( init )
496 {
497 _fnCompatMap( init, 'orderable', 'bSortable' );
498 _fnCompatMap( init, 'orderData', 'aDataSort' );
499 _fnCompatMap( init, 'orderSequence', 'asSorting' );
500 _fnCompatMap( init, 'orderDataType', 'sortDataType' );
501
502 // orderData can be given as an integer
503 var dataSort = init.aDataSort;
504 if ( dataSort && ! $.isArray( dataSort ) ) {
505 init.aDataSort = [ dataSort ];
506 }
507 }
508
509
510 /**
511 * Browser feature detection for capabilities, quirks
512 * @param {object} settings dataTables settings object
513 * @memberof DataTable#oApi
514 */
515 function _fnBrowserDetect( settings )
516 {
517 // We don't need to do this every time DataTables is constructed, the values
518 // calculated are specific to the browser and OS configuration which we
519 // don't expect to change between initialisations
520 if ( ! DataTable.__browser ) {
521 var browser = {};
522 DataTable.__browser = browser;
523
524 // Scrolling feature / quirks detection
525 var n = $('<div/>')
526 .css( {
527 position: 'fixed',
528 top: 0,
529 left: 0,
530 height: 1,
531 width: 1,
532 overflow: 'hidden'
533 } )
534 .append(
535 $('<div/>')
536 .css( {
537 position: 'absolute',
538 top: 1,
539 left: 1,
540 width: 100,
541 overflow: 'scroll'
542 } )
543 .append(
544 $('<div/>')
545 .css( {
546 width: '100%',
547 height: 10
548 } )
549 )
550 )
551 .appendTo( 'body' );
552
553 var outer = n.children();
554 var inner = outer.children();
555
556 // Numbers below, in order, are:
557 // inner.offsetWidth, inner.clientWidth, outer.offsetWidth, outer.clientWidth
558 //
559 // IE6 XP: 100 100 100 83
560 // IE7 Vista: 100 100 100 83
561 // IE 8+ Windows: 83 83 100 83
562 // Evergreen Windows: 83 83 100 83
563 // Evergreen Mac with scrollbars: 85 85 100 85
564 // Evergreen Mac without scrollbars: 100 100 100 100
565
566 // Get scrollbar width
567 browser.barWidth = outer[0].offsetWidth - outer[0].clientWidth;
568
569 // IE6/7 will oversize a width 100% element inside a scrolling element, to
570 // include the width of the scrollbar, while other browsers ensure the inner
571 // element is contained without forcing scrolling
572 //console.log( inner.offsetWidth );
573 browser.bScrollOversize = inner[0].offsetWidth === 100 && outer[0].clientWidth !== 100;
574
575 // In rtl text layout, some browsers (most, but not all) will place the
576 // scrollbar on the left, rather than the right.
577 browser.bScrollbarLeft = Math.round( inner.offset().left ) !== 1;
578
579 // IE8- don't provide height and width for getBoundingClientRect
580 browser.bBounding = n[0].getBoundingClientRect().width ? true : false;
581
582 n.remove();
583 }
584
585 $.extend( settings.oBrowser, DataTable.__browser );
586 settings.oScroll.iBarWidth = DataTable.__browser.barWidth;
587 }
588
589
590 /**
591 * Array.prototype reduce[Right] method, used for browsers which don't support
592 * JS 1.6. Done this way to reduce code size, since we iterate either way
593 * @param {object} settings dataTables settings object
594 * @memberof DataTable#oApi
595 */
596 function _fnReduce ( that, fn, init, start, end, inc )
597 {
598 var
599 i = start,
600 value,
601 isSet = false;
602
603 if ( init !== undefined ) {
604 value = init;
605 isSet = true;
606 }
607
608 while ( i !== end ) {
609 if ( ! that.hasOwnProperty(i) ) {
610 continue;
611 }
612
613 value = isSet ?
614 fn( value, that[i], i, that ) :
615 that[i];
616
617 isSet = true;
618 i += inc;
619 }
620
621 return value;
622 }
623
624 /**
625 * Add a column to the list used for the table with default values
626 * @param {object} oSettings dataTables settings object
627 * @param {node} nTh The th element for this column
628 * @memberof DataTable#oApi
629 */
630 function _fnAddColumn( oSettings, nTh )
631 {
632 // Add column to aoColumns array
633 var oDefaults = DataTable.defaults.column;
634 var iCol = oSettings.aoColumns.length;
635 var oCol = $.extend( {}, DataTable.models.oColumn, oDefaults, {
636 "nTh": nTh ? nTh : document.createElement('th'),
637 "sTitle": oDefaults.sTitle ? oDefaults.sTitle : nTh ? nTh.innerHTML : '',
638 "aDataSort": oDefaults.aDataSort ? oDefaults.aDataSort : [iCol],
639 "mData": oDefaults.mData ? oDefaults.mData : iCol,
640 idx: iCol
641 } );
642 oSettings.aoColumns.push( oCol );
643
644 // Add search object for column specific search. Note that the `searchCols[ iCol ]`
645 // passed into extend can be undefined. This allows the user to give a default
646 // with only some of the parameters defined, and also not give a default
647 var searchCols = oSettings.aoPreSearchCols;
648 searchCols[ iCol ] = $.extend( {}, DataTable.models.oSearch, searchCols[ iCol ] );
649
650 // Use the default column options function to initialise classes etc
651 _fnColumnOptions( oSettings, iCol, $(nTh).data() );
652 }
653
654
655 /**
656 * Apply options for a column
657 * @param {object} oSettings dataTables settings object
658 * @param {int} iCol column index to consider
659 * @param {object} oOptions object with sType, bVisible and bSearchable etc
660 * @memberof DataTable#oApi
661 */
662 function _fnColumnOptions( oSettings, iCol, oOptions )
663 {
664 var oCol = oSettings.aoColumns[ iCol ];
665 var oClasses = oSettings.oClasses;
666 var th = $(oCol.nTh);
667
668 // Try to get width information from the DOM. We can't get it from CSS
669 // as we'd need to parse the CSS stylesheet. `width` option can override
670 if ( ! oCol.sWidthOrig ) {
671 // Width attribute
672 oCol.sWidthOrig = th.attr('width') || null;
673
674 // Style attribute
675 var t = (th.attr('style') || '').match(/width:\s*(\d+[pxem%]+)/);
676 if ( t ) {
677 oCol.sWidthOrig = t[1];
678 }
679 }
680
681 /* User specified column options */
682 if ( oOptions !== undefined && oOptions !== null )
683 {
684 // Backwards compatibility
685 _fnCompatCols( oOptions );
686
687 // Map camel case parameters to their Hungarian counterparts
688 _fnCamelToHungarian( DataTable.defaults.column, oOptions );
689
690 /* Backwards compatibility for mDataProp */
691 if ( oOptions.mDataProp !== undefined && !oOptions.mData )
692 {
693 oOptions.mData = oOptions.mDataProp;
694 }
695
696 if ( oOptions.sType )
697 {
698 oCol._sManualType = oOptions.sType;
699 }
700
701 // `class` is a reserved word in Javascript, so we need to provide
702 // the ability to use a valid name for the camel case input
703 if ( oOptions.className && ! oOptions.sClass )
704 {
705 oOptions.sClass = oOptions.className;
706 }
707
708 $.extend( oCol, oOptions );
709 _fnMap( oCol, oOptions, "sWidth", "sWidthOrig" );
710
711 /* iDataSort to be applied (backwards compatibility), but aDataSort will take
712 * priority if defined
713 */
714 if ( oOptions.iDataSort !== undefined )
715 {
716 oCol.aDataSort = [ oOptions.iDataSort ];
717 }
718 _fnMap( oCol, oOptions, "aDataSort" );
719 }
720
721 /* Cache the data get and set functions for speed */
722 var mDataSrc = oCol.mData;
723 var mData = _fnGetObjectDataFn( mDataSrc );
724 var mRender = oCol.mRender ? _fnGetObjectDataFn( oCol.mRender ) : null;
725
726 var attrTest = function( src ) {
727 return typeof src === 'string' && src.indexOf('@') !== -1;
728 };
729 oCol._bAttrSrc = $.isPlainObject( mDataSrc ) && (
730 attrTest(mDataSrc.sort) || attrTest(mDataSrc.type) || attrTest(mDataSrc.filter)
731 );
732
733 oCol.fnGetData = function (rowData, type, meta) {
734 var innerData = mData( rowData, type, undefined, meta );
735
736 return mRender && type ?
737 mRender( innerData, type, rowData, meta ) :
738 innerData;
739 };
740 oCol.fnSetData = function ( rowData, val, meta ) {
741 return _fnSetObjectDataFn( mDataSrc )( rowData, val, meta );
742 };
743
744 // Indicate if DataTables should read DOM data as an object or array
745 // Used in _fnGetRowElements
746 if ( typeof mDataSrc !== 'number' ) {
747 oSettings._rowReadObject = true;
748 }
749
750 /* Feature sorting overrides column specific when off */
751 if ( !oSettings.oFeatures.bSort )
752 {
753 oCol.bSortable = false;
754 th.addClass( oClasses.sSortableNone ); // Have to add class here as order event isn't called
755 }
756
757 /* Check that the class assignment is correct for sorting */
758 var bAsc = $.inArray('asc', oCol.asSorting) !== -1;
759 var bDesc = $.inArray('desc', oCol.asSorting) !== -1;
760 if ( !oCol.bSortable || (!bAsc && !bDesc) )
761 {
762 oCol.sSortingClass = oClasses.sSortableNone;
763 oCol.sSortingClassJUI = "";
764 }
765 else if ( bAsc && !bDesc )
766 {
767 oCol.sSortingClass = oClasses.sSortableAsc;
768 oCol.sSortingClassJUI = oClasses.sSortJUIAscAllowed;
769 }
770 else if ( !bAsc && bDesc )
771 {
772 oCol.sSortingClass = oClasses.sSortableDesc;
773 oCol.sSortingClassJUI = oClasses.sSortJUIDescAllowed;
774 }
775 else
776 {
777 oCol.sSortingClass = oClasses.sSortable;
778 oCol.sSortingClassJUI = oClasses.sSortJUI;
779 }
780 }
781
782
783 /**
784 * Adjust the table column widths for new data. Note: you would probably want to
785 * do a redraw after calling this function!
786 * @param {object} settings dataTables settings object
787 * @memberof DataTable#oApi
788 */
789 function _fnAdjustColumnSizing ( settings )
790 {
791 /* Not interested in doing column width calculation if auto-width is disabled */
792 if ( settings.oFeatures.bAutoWidth !== false )
793 {
794 var columns = settings.aoColumns;
795
796 _fnCalculateColumnWidths( settings );
797 for ( var i=0 , iLen=columns.length ; i<iLen ; i++ )
798 {
799 columns[i].nTh.style.width = columns[i].sWidth;
800 }
801 }
802
803 var scroll = settings.oScroll;
804 if ( scroll.sY !== '' || scroll.sX !== '')
805 {
806 _fnScrollDraw( settings );
807 }
808
809 _fnCallbackFire( settings, null, 'column-sizing', [settings] );
810 }
811
812
813 /**
814 * Covert the index of a visible column to the index in the data array (take account
815 * of hidden columns)
816 * @param {object} oSettings dataTables settings object
817 * @param {int} iMatch Visible column index to lookup
818 * @returns {int} i the data index
819 * @memberof DataTable#oApi
820 */
821 function _fnVisibleToColumnIndex( oSettings, iMatch )
822 {
823 var aiVis = _fnGetColumns( oSettings, 'bVisible' );
824
825 return typeof aiVis[iMatch] === 'number' ?
826 aiVis[iMatch] :
827 null;
828 }
829
830
831 /**
832 * Covert the index of an index in the data array and convert it to the visible
833 * column index (take account of hidden columns)
834 * @param {int} iMatch Column index to lookup
835 * @param {object} oSettings dataTables settings object
836 * @returns {int} i the data index
837 * @memberof DataTable#oApi
838 */
839 function _fnColumnIndexToVisible( oSettings, iMatch )
840 {
841 var aiVis = _fnGetColumns( oSettings, 'bVisible' );
842 var iPos = $.inArray( iMatch, aiVis );
843
844 return iPos !== -1 ? iPos : null;
845 }
846
847
848 /**
849 * Get the number of visible columns
850 * @param {object} oSettings dataTables settings object
851 * @returns {int} i the number of visible columns
852 * @memberof DataTable#oApi
853 */
854 function _fnVisbleColumns( oSettings )
855 {
856 return _fnGetColumns( oSettings, 'bVisible' ).length;
857 }
858
859
860 /**
861 * Get an array of column indexes that match a given property
862 * @param {object} oSettings dataTables settings object
863 * @param {string} sParam Parameter in aoColumns to look for - typically
864 * bVisible or bSearchable
865 * @returns {array} Array of indexes with matched properties
866 * @memberof DataTable#oApi
867 */
868 function _fnGetColumns( oSettings, sParam )
869 {
870 var a = [];
871
872 $.map( oSettings.aoColumns, function(val, i) {
873 if ( val[sParam] ) {
874 a.push( i );
875 }
876 } );
877
878 return a;
879 }
880
881
882 /**
883 * Calculate the 'type' of a column
884 * @param {object} settings dataTables settings object
885 * @memberof DataTable#oApi
886 */
887 function _fnColumnTypes ( settings )
888 {
889 var columns = settings.aoColumns;
890 var data = settings.aoData;
891 var types = DataTable.ext.type.detect;
892 var i, ien, j, jen, k, ken;
893 var col, cell, detectedType, cache;
894
895 // For each column, spin over the
896 for ( i=0, ien=columns.length ; i<ien ; i++ ) {
897 col = columns[i];
898 cache = [];
899
900 if ( ! col.sType && col._sManualType ) {
901 col.sType = col._sManualType;
902 }
903 else if ( ! col.sType ) {
904 for ( j=0, jen=types.length ; j<jen ; j++ ) {
905 for ( k=0, ken=data.length ; k<ken ; k++ ) {
906 // Use a cache array so we only need to get the type data
907 // from the formatter once (when using multiple detectors)
908 if ( cache[k] === undefined ) {
909 cache[k] = _fnGetCellData( settings, k, i, 'type' );
910 }
911
912 detectedType = types[j]( cache[k], settings );
913
914 // If null, then this type can't apply to this column, so
915 // rather than testing all cells, break out. There is an
916 // exception for the last type which is `html`. We need to
917 // scan all rows since it is possible to mix string and HTML
918 // types
919 if ( ! detectedType && j !== types.length-1 ) {
920 break;
921 }
922
923 // Only a single match is needed for html type since it is
924 // bottom of the pile and very similar to string
925 if ( detectedType === 'html' ) {
926 break;
927 }
928 }
929
930 // Type is valid for all data points in the column - use this
931 // type
932 if ( detectedType ) {
933 col.sType = detectedType;
934 break;
935 }
936 }
937
938 // Fall back - if no type was detected, always use string
939 if ( ! col.sType ) {
940 col.sType = 'string';
941 }
942 }
943 }
944 }
945
946
947 /**
948 * Take the column definitions and static columns arrays and calculate how
949 * they relate to column indexes. The callback function will then apply the
950 * definition found for a column to a suitable configuration object.
951 * @param {object} oSettings dataTables settings object
952 * @param {array} aoColDefs The aoColumnDefs array that is to be applied
953 * @param {array} aoCols The aoColumns array that defines columns individually
954 * @param {function} fn Callback function - takes two parameters, the calculated
955 * column index and the definition for that column.
956 * @memberof DataTable#oApi
957 */
958 function _fnApplyColumnDefs( oSettings, aoColDefs, aoCols, fn )
959 {
960 var i, iLen, j, jLen, k, kLen, def;
961 var columns = oSettings.aoColumns;
962
963 // Column definitions with aTargets
964 if ( aoColDefs )
965 {
966 /* Loop over the definitions array - loop in reverse so first instance has priority */
967 for ( i=aoColDefs.length-1 ; i>=0 ; i-- )
968 {
969 def = aoColDefs[i];
970
971 /* Each definition can target multiple columns, as it is an array */
972 var aTargets = def.targets !== undefined ?
973 def.targets :
974 def.aTargets;
975
976 if ( ! $.isArray( aTargets ) )
977 {
978 aTargets = [ aTargets ];
979 }
980
981 for ( j=0, jLen=aTargets.length ; j<jLen ; j++ )
982 {
983 if ( typeof aTargets[j] === 'number' && aTargets[j] >= 0 )
984 {
985 /* Add columns that we don't yet know about */
986 while( columns.length <= aTargets[j] )
987 {
988 _fnAddColumn( oSettings );
989 }
990
991 /* Integer, basic index */
992 fn( aTargets[j], def );
993 }
994 else if ( typeof aTargets[j] === 'number' && aTargets[j] < 0 )
995 {
996 /* Negative integer, right to left column counting */
997 fn( columns.length+aTargets[j], def );
998 }
999 else if ( typeof aTargets[j] === 'string' )
1000 {
1001 /* Class name matching on TH element */
1002 for ( k=0, kLen=columns.length ; k<kLen ; k++ )
1003 {
1004 if ( aTargets[j] == "_all" ||
1005 $(columns[k].nTh).hasClass( aTargets[j] ) )
1006 {
1007 fn( k, def );
1008 }
1009 }
1010 }
1011 }
1012 }
1013 }
1014
1015 // Statically defined columns array
1016 if ( aoCols )
1017 {
1018 for ( i=0, iLen=aoCols.length ; i<iLen ; i++ )
1019 {
1020 fn( i, aoCols[i] );
1021 }
1022 }
1023 }
1024
1025 /**
1026 * Add a data array to the table, creating DOM node etc. This is the parallel to
1027 * _fnGatherData, but for adding rows from a Javascript source, rather than a
1028 * DOM source.
1029 * @param {object} oSettings dataTables settings object
1030 * @param {array} aData data array to be added
1031 * @param {node} [nTr] TR element to add to the table - optional. If not given,
1032 * DataTables will create a row automatically
1033 * @param {array} [anTds] Array of TD|TH elements for the row - must be given
1034 * if nTr is.
1035 * @returns {int} >=0 if successful (index of new aoData entry), -1 if failed
1036 * @memberof DataTable#oApi
1037 */
1038 function _fnAddData ( oSettings, aDataIn, nTr, anTds )
1039 {
1040 /* Create the object for storing information about this new row */
1041 var iRow = oSettings.aoData.length;
1042 var oData = $.extend( true, {}, DataTable.models.oRow, {
1043 src: nTr ? 'dom' : 'data',
1044 idx: iRow
1045 } );
1046
1047 oData._aData = aDataIn;
1048 oSettings.aoData.push( oData );
1049
1050 /* Create the cells */
1051 var nTd, sThisType;
1052 var columns = oSettings.aoColumns;
1053
1054 // Invalidate the column types as the new data needs to be revalidated
1055 for ( var i=0, iLen=columns.length ; i<iLen ; i++ )
1056 {
1057 columns[i].sType = null;
1058 }
1059
1060 /* Add to the display array */
1061 oSettings.aiDisplayMaster.push( iRow );
1062
1063 var id = oSettings.rowIdFn( aDataIn );
1064 if ( id !== undefined ) {
1065 oSettings.aIds[ id ] = oData;
1066 }
1067
1068 /* Create the DOM information, or register it if already present */
1069 if ( nTr || ! oSettings.oFeatures.bDeferRender )
1070 {
1071 _fnCreateTr( oSettings, iRow, nTr, anTds );
1072 }
1073
1074 return iRow;
1075 }
1076
1077
1078 /**
1079 * Add one or more TR elements to the table. Generally we'd expect to
1080 * use this for reading data from a DOM sourced table, but it could be
1081 * used for an TR element. Note that if a TR is given, it is used (i.e.
1082 * it is not cloned).
1083 * @param {object} settings dataTables settings object
1084 * @param {array|node|jQuery} trs The TR element(s) to add to the table
1085 * @returns {array} Array of indexes for the added rows
1086 * @memberof DataTable#oApi
1087 */
1088 function _fnAddTr( settings, trs )
1089 {
1090 var row;
1091
1092 // Allow an individual node to be passed in
1093 if ( ! (trs instanceof $) ) {
1094 trs = $(trs);
1095 }
1096
1097 return trs.map( function (i, el) {
1098 row = _fnGetRowElements( settings, el );
1099 return _fnAddData( settings, row.data, el, row.cells );
1100 } );
1101 }
1102
1103
1104 /**
1105 * Take a TR element and convert it to an index in aoData
1106 * @param {object} oSettings dataTables settings object
1107 * @param {node} n the TR element to find
1108 * @returns {int} index if the node is found, null if not
1109 * @memberof DataTable#oApi
1110 */
1111 function _fnNodeToDataIndex( oSettings, n )
1112 {
1113 return (n._DT_RowIndex!==undefined) ? n._DT_RowIndex : null;
1114 }
1115
1116
1117 /**
1118 * Take a TD element and convert it into a column data index (not the visible index)
1119 * @param {object} oSettings dataTables settings object
1120 * @param {int} iRow The row number the TD/TH can be found in
1121 * @param {node} n The TD/TH element to find
1122 * @returns {int} index if the node is found, -1 if not
1123 * @memberof DataTable#oApi
1124 */
1125 function _fnNodeToColumnIndex( oSettings, iRow, n )
1126 {
1127 return $.inArray( n, oSettings.aoData[ iRow ].anCells );
1128 }
1129
1130
1131 /**
1132 * Get the data for a given cell from the internal cache, taking into account data mapping
1133 * @param {object} settings dataTables settings object
1134 * @param {int} rowIdx aoData row id
1135 * @param {int} colIdx Column index
1136 * @param {string} type data get type ('display', 'type' 'filter' 'sort')
1137 * @returns {*} Cell data
1138 * @memberof DataTable#oApi
1139 */
1140 function _fnGetCellData( settings, rowIdx, colIdx, type )
1141 {
1142 var draw = settings.iDraw;
1143 var col = settings.aoColumns[colIdx];
1144 var rowData = settings.aoData[rowIdx]._aData;
1145 var defaultContent = col.sDefaultContent;
1146 var cellData = col.fnGetData( rowData, type, {
1147 settings: settings,
1148 row: rowIdx,
1149 col: colIdx
1150 } );
1151
1152 if ( cellData === undefined ) {
1153 if ( settings.iDrawError != draw && defaultContent === null ) {
1154 _fnLog( settings, 0, "Requested unknown parameter "+
1155 (typeof col.mData=='function' ? '{function}' : "'"+col.mData+"'")+
1156 " for row "+rowIdx, 4 );
1157 settings.iDrawError = draw;
1158 }
1159 return defaultContent;
1160 }
1161
1162 /* When the data source is null, we can use default column data */
1163 if ( (cellData === rowData || cellData === null) && defaultContent !== null ) {
1164 cellData = defaultContent;
1165 }
1166 else if ( typeof cellData === 'function' ) {
1167 // If the data source is a function, then we run it and use the return,
1168 // executing in the scope of the data object (for instances)
1169 return cellData.call( rowData );
1170 }
1171
1172 if ( cellData === null && type == 'display' ) {
1173 return '';
1174 }
1175 return cellData;
1176 }
1177
1178
1179 /**
1180 * Set the value for a specific cell, into the internal data cache
1181 * @param {object} settings dataTables settings object
1182 * @param {int} rowIdx aoData row id
1183 * @param {int} colIdx Column index
1184 * @param {*} val Value to set
1185 * @memberof DataTable#oApi
1186 */
1187 function _fnSetCellData( settings, rowIdx, colIdx, val )
1188 {
1189 var col = settings.aoColumns[colIdx];
1190 var rowData = settings.aoData[rowIdx]._aData;
1191
1192 col.fnSetData( rowData, val, {
1193 settings: settings,
1194 row: rowIdx,
1195 col: colIdx
1196 } );
1197 }
1198
1199
1200 // Private variable that is used to match action syntax in the data property object
1201 var __reArray = /\[.*?\]$/;
1202 var __reFn = /\(\)$/;
1203
1204 /**
1205 * Split string on periods, taking into account escaped periods
1206 * @param {string} str String to split
1207 * @return {array} Split string
1208 */
1209 function _fnSplitObjNotation( str )
1210 {
1211 return $.map( str.match(/(\\.|[^\.])+/g) || [''], function ( s ) {
1212 return s.replace(/\\./g, '.');
1213 } );
1214 }
1215
1216
1217 /**
1218 * Return a function that can be used to get data from a source object, taking
1219 * into account the ability to use nested objects as a source
1220 * @param {string|int|function} mSource The data source for the object
1221 * @returns {function} Data get function
1222 * @memberof DataTable#oApi
1223 */
1224 function _fnGetObjectDataFn( mSource )
1225 {
1226 if ( $.isPlainObject( mSource ) )
1227 {
1228 /* Build an object of get functions, and wrap them in a single call */
1229 var o = {};
1230 $.each( mSource, function (key, val) {
1231 if ( val ) {
1232 o[key] = _fnGetObjectDataFn( val );
1233 }
1234 } );
1235
1236 return function (data, type, row, meta) {
1237 var t = o[type] || o._;
1238 return t !== undefined ?
1239 t(data, type, row, meta) :
1240 data;
1241 };
1242 }
1243 else if ( mSource === null )
1244 {
1245 /* Give an empty string for rendering / sorting etc */
1246 return function (data) { // type, row and meta also passed, but not used
1247 return data;
1248 };
1249 }
1250 else if ( typeof mSource === 'function' )
1251 {
1252 return function (data, type, row, meta) {
1253 return mSource( data, type, row, meta );
1254 };
1255 }
1256 else if ( typeof mSource === 'string' && (mSource.indexOf('.') !== -1 ||
1257 mSource.indexOf('[') !== -1 || mSource.indexOf('(') !== -1) )
1258 {
1259 /* If there is a . in the source string then the data source is in a
1260 * nested object so we loop over the data for each level to get the next
1261 * level down. On each loop we test for undefined, and if found immediately
1262 * return. This allows entire objects to be missing and sDefaultContent to
1263 * be used if defined, rather than throwing an error
1264 */
1265 var fetchData = function (data, type, src) {
1266 var arrayNotation, funcNotation, out, innerSrc;
1267
1268 if ( src !== "" )
1269 {
1270 var a = _fnSplitObjNotation( src );
1271
1272 for ( var i=0, iLen=a.length ; i<iLen ; i++ )
1273 {
1274 // Check if we are dealing with special notation
1275 arrayNotation = a[i].match(__reArray);
1276 funcNotation = a[i].match(__reFn);
1277
1278 if ( arrayNotation )
1279 {
1280 // Array notation
1281 a[i] = a[i].replace(__reArray, '');
1282
1283 // Condition allows simply [] to be passed in
1284 if ( a[i] !== "" ) {
1285 data = data[ a[i] ];
1286 }
1287 out = [];
1288
1289 // Get the remainder of the nested object to get
1290 a.splice( 0, i+1 );
1291 innerSrc = a.join('.');
1292
1293 // Traverse each entry in the array getting the properties requested
1294 if ( $.isArray( data ) ) {
1295 for ( var j=0, jLen=data.length ; j<jLen ; j++ ) {
1296 out.push( fetchData( data[j], type, innerSrc ) );
1297 }
1298 }
1299
1300 // If a string is given in between the array notation indicators, that
1301 // is used to join the strings together, otherwise an array is returned
1302 var join = arrayNotation[0].substring(1, arrayNotation[0].length-1);
1303 data = (join==="") ? out : out.join(join);
1304
1305 // The inner call to fetchData has already traversed through the remainder
1306 // of the source requested, so we exit from the loop
1307 break;
1308 }
1309 else if ( funcNotation )
1310 {
1311 // Function call
1312 a[i] = a[i].replace(__reFn, '');
1313 data = data[ a[i] ]();
1314 continue;
1315 }
1316
1317 if ( data === null || data[ a[i] ] === undefined )
1318 {
1319 return undefined;
1320 }
1321 data = data[ a[i] ];
1322 }
1323 }
1324
1325 return data;
1326 };
1327
1328 return function (data, type) { // row and meta also passed, but not used
1329 return fetchData( data, type, mSource );
1330 };
1331 }
1332 else
1333 {
1334 /* Array or flat object mapping */
1335 return function (data, type) { // row and meta also passed, but not used
1336 return data[mSource];
1337 };
1338 }
1339 }
1340
1341
1342 /**
1343 * Return a function that can be used to set data from a source object, taking
1344 * into account the ability to use nested objects as a source
1345 * @param {string|int|function} mSource The data source for the object
1346 * @returns {function} Data set function
1347 * @memberof DataTable#oApi
1348 */
1349 function _fnSetObjectDataFn( mSource )
1350 {
1351 if ( $.isPlainObject( mSource ) )
1352 {
1353 /* Unlike get, only the underscore (global) option is used for for
1354 * setting data since we don't know the type here. This is why an object
1355 * option is not documented for `mData` (which is read/write), but it is
1356 * for `mRender` which is read only.
1357 */
1358 return _fnSetObjectDataFn( mSource._ );
1359 }
1360 else if ( mSource === null )
1361 {
1362 /* Nothing to do when the data source is null */
1363 return function () {};
1364 }
1365 else if ( typeof mSource === 'function' )
1366 {
1367 return function (data, val, meta) {
1368 mSource( data, 'set', val, meta );
1369 };
1370 }
1371 else if ( typeof mSource === 'string' && (mSource.indexOf('.') !== -1 ||
1372 mSource.indexOf('[') !== -1 || mSource.indexOf('(') !== -1) )
1373 {
1374 /* Like the get, we need to get data from a nested object */
1375 var setData = function (data, val, src) {
1376 var a = _fnSplitObjNotation( src ), b;
1377 var aLast = a[a.length-1];
1378 var arrayNotation, funcNotation, o, innerSrc;
1379
1380 for ( var i=0, iLen=a.length-1 ; i<iLen ; i++ )
1381 {
1382 // Check if we are dealing with an array notation request
1383 arrayNotation = a[i].match(__reArray);
1384 funcNotation = a[i].match(__reFn);
1385
1386 if ( arrayNotation )
1387 {
1388 a[i] = a[i].replace(__reArray, '');
1389 data[ a[i] ] = [];
1390
1391 // Get the remainder of the nested object to set so we can recurse
1392 b = a.slice();
1393 b.splice( 0, i+1 );
1394 innerSrc = b.join('.');
1395
1396 // Traverse each entry in the array setting the properties requested
1397 if ( $.isArray( val ) )
1398 {
1399 for ( var j=0, jLen=val.length ; j<jLen ; j++ )
1400 {
1401 o = {};
1402 setData( o, val[j], innerSrc );
1403 data[ a[i] ].push( o );
1404 }
1405 }
1406 else
1407 {
1408 // We've been asked to save data to an array, but it
1409 // isn't array data to be saved. Best that can be done
1410 // is to just save the value.
1411 data[ a[i] ] = val;
1412 }
1413
1414 // The inner call to setData has already traversed through the remainder
1415 // of the source and has set the data, thus we can exit here
1416 return;
1417 }
1418 else if ( funcNotation )
1419 {
1420 // Function call
1421 a[i] = a[i].replace(__reFn, '');
1422 data = data[ a[i] ]( val );
1423 }
1424
1425 // If the nested object doesn't currently exist - since we are
1426 // trying to set the value - create it
1427 if ( data[ a[i] ] === null || data[ a[i] ] === undefined )
1428 {
1429 data[ a[i] ] = {};
1430 }
1431 data = data[ a[i] ];
1432 }
1433
1434 // Last item in the input - i.e, the actual set
1435 if ( aLast.match(__reFn ) )
1436 {
1437 // Function call
1438 data = data[ aLast.replace(__reFn, '') ]( val );
1439 }
1440 else
1441 {
1442 // If array notation is used, we just want to strip it and use the property name
1443 // and assign the value. If it isn't used, then we get the result we want anyway
1444 data[ aLast.replace(__reArray, '') ] = val;
1445 }
1446 };
1447
1448 return function (data, val) { // meta is also passed in, but not used
1449 return setData( data, val, mSource );
1450 };
1451 }
1452 else
1453 {
1454 /* Array or flat object mapping */
1455 return function (data, val) { // meta is also passed in, but not used
1456 data[mSource] = val;
1457 };
1458 }
1459 }
1460
1461
1462 /**
1463 * Return an array with the full table data
1464 * @param {object} oSettings dataTables settings object
1465 * @returns array {array} aData Master data array
1466 * @memberof DataTable#oApi
1467 */
1468 function _fnGetDataMaster ( settings )
1469 {
1470 return _pluck( settings.aoData, '_aData' );
1471 }
1472
1473
1474 /**
1475 * Nuke the table
1476 * @param {object} oSettings dataTables settings object
1477 * @memberof DataTable#oApi
1478 */
1479 function _fnClearTable( settings )
1480 {
1481 settings.aoData.length = 0;
1482 settings.aiDisplayMaster.length = 0;
1483 settings.aiDisplay.length = 0;
1484 settings.aIds = {};
1485 }
1486
1487
1488 /**
1489 * Take an array of integers (index array) and remove a target integer (value - not
1490 * the key!)
1491 * @param {array} a Index array to target
1492 * @param {int} iTarget value to find
1493 * @memberof DataTable#oApi
1494 */
1495 function _fnDeleteIndex( a, iTarget, splice )
1496 {
1497 var iTargetIndex = -1;
1498
1499 for ( var i=0, iLen=a.length ; i<iLen ; i++ )
1500 {
1501 if ( a[i] == iTarget )
1502 {
1503 iTargetIndex = i;
1504 }
1505 else if ( a[i] > iTarget )
1506 {
1507 a[i]--;
1508 }
1509 }
1510
1511 if ( iTargetIndex != -1 && splice === undefined )
1512 {
1513 a.splice( iTargetIndex, 1 );
1514 }
1515 }
1516
1517
1518 /**
1519 * Mark cached data as invalid such that a re-read of the data will occur when
1520 * the cached data is next requested. Also update from the data source object.
1521 *
1522 * @param {object} settings DataTables settings object
1523 * @param {int} rowIdx Row index to invalidate
1524 * @param {string} [src] Source to invalidate from: undefined, 'auto', 'dom'
1525 * or 'data'
1526 * @param {int} [colIdx] Column index to invalidate. If undefined the whole
1527 * row will be invalidated
1528 * @memberof DataTable#oApi
1529 *
1530 * @todo For the modularisation of v1.11 this will need to become a callback, so
1531 * the sort and filter methods can subscribe to it. That will required
1532 * initialisation options for sorting, which is why it is not already baked in
1533 */
1534 function _fnInvalidate( settings, rowIdx, src, colIdx )
1535 {
1536 var row = settings.aoData[ rowIdx ];
1537 var i, ien;
1538 var cellWrite = function ( cell, col ) {
1539 // This is very frustrating, but in IE if you just write directly
1540 // to innerHTML, and elements that are overwritten are GC'ed,
1541 // even if there is a reference to them elsewhere
1542 while ( cell.childNodes.length ) {
1543 cell.removeChild( cell.firstChild );
1544 }
1545
1546 cell.innerHTML = _fnGetCellData( settings, rowIdx, col, 'display' );
1547 };
1548
1549 // Are we reading last data from DOM or the data object?
1550 if ( src === 'dom' || ((! src || src === 'auto') && row.src === 'dom') ) {
1551 // Read the data from the DOM
1552 row._aData = _fnGetRowElements(
1553 settings, row, colIdx, colIdx === undefined ? undefined : row._aData
1554 )
1555 .data;
1556 }
1557 else {
1558 // Reading from data object, update the DOM
1559 var cells = row.anCells;
1560
1561 if ( cells ) {
1562 if ( colIdx !== undefined ) {
1563 cellWrite( cells[colIdx], colIdx );
1564 }
1565 else {
1566 for ( i=0, ien=cells.length ; i<ien ; i++ ) {
1567 cellWrite( cells[i], i );
1568 }
1569 }
1570 }
1571 }
1572
1573 // For both row and cell invalidation, the cached data for sorting and
1574 // filtering is nulled out
1575 row._aSortData = null;
1576 row._aFilterData = null;
1577
1578 // Invalidate the type for a specific column (if given) or all columns since
1579 // the data might have changed
1580 var cols = settings.aoColumns;
1581 if ( colIdx !== undefined ) {
1582 cols[ colIdx ].sType = null;
1583 }
1584 else {
1585 for ( i=0, ien=cols.length ; i<ien ; i++ ) {
1586 cols[i].sType = null;
1587 }
1588
1589 // Update DataTables special `DT_*` attributes for the row
1590 _fnRowAttributes( settings, row );
1591 }
1592 }
1593
1594
1595 /**
1596 * Build a data source object from an HTML row, reading the contents of the
1597 * cells that are in the row.
1598 *
1599 * @param {object} settings DataTables settings object
1600 * @param {node|object} TR element from which to read data or existing row
1601 * object from which to re-read the data from the cells
1602 * @param {int} [colIdx] Optional column index
1603 * @param {array|object} [d] Data source object. If `colIdx` is given then this
1604 * parameter should also be given and will be used to write the data into.
1605 * Only the column in question will be written
1606 * @returns {object} Object with two parameters: `data` the data read, in
1607 * document order, and `cells` and array of nodes (they can be useful to the
1608 * caller, so rather than needing a second traversal to get them, just return
1609 * them from here).
1610 * @memberof DataTable#oApi
1611 */
1612 function _fnGetRowElements( settings, row, colIdx, d )
1613 {
1614 var
1615 tds = [],
1616 td = row.firstChild,
1617 name, col, o, i=0, contents,
1618 columns = settings.aoColumns,
1619 objectRead = settings._rowReadObject;
1620
1621 // Allow the data object to be passed in, or construct
1622 d = d !== undefined ?
1623 d :
1624 objectRead ?
1625 {} :
1626 [];
1627
1628 var attr = function ( str, td ) {
1629 if ( typeof str === 'string' ) {
1630 var idx = str.indexOf('@');
1631
1632 if ( idx !== -1 ) {
1633 var attr = str.substring( idx+1 );
1634 var setter = _fnSetObjectDataFn( str );
1635 setter( d, td.getAttribute( attr ) );
1636 }
1637 }
1638 };
1639
1640 // Read data from a cell and store into the data object
1641 var cellProcess = function ( cell ) {
1642 if ( colIdx === undefined || colIdx === i ) {
1643 col = columns[i];
1644 contents = $.trim(cell.innerHTML);
1645
1646 if ( col && col._bAttrSrc ) {
1647 var setter = _fnSetObjectDataFn( col.mData._ );
1648 setter( d, contents );
1649
1650 attr( col.mData.sort, cell );
1651 attr( col.mData.type, cell );
1652 attr( col.mData.filter, cell );
1653 }
1654 else {
1655 // Depending on the `data` option for the columns the data can
1656 // be read to either an object or an array.
1657 if ( objectRead ) {
1658 if ( ! col._setter ) {
1659 // Cache the setter function
1660 col._setter = _fnSetObjectDataFn( col.mData );
1661 }
1662 col._setter( d, contents );
1663 }
1664 else {
1665 d[i] = contents;
1666 }
1667 }
1668 }
1669
1670 i++;
1671 };
1672
1673 if ( td ) {
1674 // `tr` element was passed in
1675 while ( td ) {
1676 name = td.nodeName.toUpperCase();
1677
1678 if ( name == "TD" || name == "TH" ) {
1679 cellProcess( td );
1680 tds.push( td );
1681 }
1682
1683 td = td.nextSibling;
1684 }
1685 }
1686 else {
1687 // Existing row object passed in
1688 tds = row.anCells;
1689
1690 for ( var j=0, jen=tds.length ; j<jen ; j++ ) {
1691 cellProcess( tds[j] );
1692 }
1693 }
1694
1695 // Read the ID from the DOM if present
1696 var rowNode = td ? row : row.nTr;
1697
1698 if ( rowNode ) {
1699 var id = rowNode.getAttribute( 'id' );
1700
1701 if ( id ) {
1702 _fnSetObjectDataFn( settings.rowId )( d, id );
1703 }
1704 }
1705
1706 return {
1707 data: d,
1708 cells: tds
1709 };
1710 }
1711 /**
1712 * Create a new TR element (and it's TD children) for a row
1713 * @param {object} oSettings dataTables settings object
1714 * @param {int} iRow Row to consider
1715 * @param {node} [nTrIn] TR element to add to the table - optional. If not given,
1716 * DataTables will create a row automatically
1717 * @param {array} [anTds] Array of TD|TH elements for the row - must be given
1718 * if nTr is.
1719 * @memberof DataTable#oApi
1720 */
1721 function _fnCreateTr ( oSettings, iRow, nTrIn, anTds )
1722 {
1723 var
1724 row = oSettings.aoData[iRow],
1725 rowData = row._aData,
1726 cells = [],
1727 nTr, nTd, oCol,
1728 i, iLen;
1729
1730 if ( row.nTr === null )
1731 {
1732 nTr = nTrIn || document.createElement('tr');
1733
1734 row.nTr = nTr;
1735 row.anCells = cells;
1736
1737 /* Use a private property on the node to allow reserve mapping from the node
1738 * to the aoData array for fast look up
1739 */
1740 nTr._DT_RowIndex = iRow;
1741
1742 /* Special parameters can be given by the data source to be used on the row */
1743 _fnRowAttributes( oSettings, row );
1744
1745 /* Process each column */
1746 for ( i=0, iLen=oSettings.aoColumns.length ; i<iLen ; i++ )
1747 {
1748 oCol = oSettings.aoColumns[i];
1749
1750 nTd = nTrIn ? anTds[i] : document.createElement( oCol.sCellType );
1751 cells.push( nTd );
1752
1753 // Need to create the HTML if new, or if a rendering function is defined
1754 if ( !nTrIn || oCol.mRender || oCol.mData !== i )
1755 {
1756 nTd.innerHTML = _fnGetCellData( oSettings, iRow, i, 'display' );
1757 }
1758
1759 /* Add user defined class */
1760 if ( oCol.sClass )
1761 {
1762 nTd.className += ' '+oCol.sClass;
1763 }
1764
1765 // Visibility - add or remove as required
1766 if ( oCol.bVisible && ! nTrIn )
1767 {
1768 nTr.appendChild( nTd );
1769 }
1770 else if ( ! oCol.bVisible && nTrIn )
1771 {
1772 nTd.parentNode.removeChild( nTd );
1773 }
1774
1775 if ( oCol.fnCreatedCell )
1776 {
1777 oCol.fnCreatedCell.call( oSettings.oInstance,
1778 nTd, _fnGetCellData( oSettings, iRow, i ), rowData, iRow, i
1779 );
1780 }
1781 }
1782
1783 _fnCallbackFire( oSettings, 'aoRowCreatedCallback', null, [nTr, rowData, iRow] );
1784 }
1785
1786 // Remove once webkit bug 131819 and Chromium bug 365619 have been resolved
1787 // and deployed
1788 row.nTr.setAttribute( 'role', 'row' );
1789 }
1790
1791
1792 /**
1793 * Add attributes to a row based on the special `DT_*` parameters in a data
1794 * source object.
1795 * @param {object} settings DataTables settings object
1796 * @param {object} DataTables row object for the row to be modified
1797 * @memberof DataTable#oApi
1798 */
1799 function _fnRowAttributes( settings, row )
1800 {
1801 var tr = row.nTr;
1802 var data = row._aData;
1803
1804 if ( tr ) {
1805 var id = settings.rowIdFn( data );
1806
1807 if ( id ) {
1808 tr.id = id;
1809 }
1810
1811 if ( data.DT_RowClass ) {
1812 // Remove any classes added by DT_RowClass before
1813 var a = data.DT_RowClass.split(' ');
1814 row.__rowc = row.__rowc ?
1815 _unique( row.__rowc.concat( a ) ) :
1816 a;
1817
1818 $(tr)
1819 .removeClass( row.__rowc.join(' ') )
1820 .addClass( data.DT_RowClass );
1821 }
1822
1823 if ( data.DT_RowAttr ) {
1824 $(tr).attr( data.DT_RowAttr );
1825 }
1826
1827 if ( data.DT_RowData ) {
1828 $(tr).data( data.DT_RowData );
1829 }
1830 }
1831 }
1832
1833
1834 /**
1835 * Create the HTML header for the table
1836 * @param {object} oSettings dataTables settings object
1837 * @memberof DataTable#oApi
1838 */
1839 function _fnBuildHead( oSettings )
1840 {
1841 var i, ien, cell, row, column;
1842 var thead = oSettings.nTHead;
1843 var tfoot = oSettings.nTFoot;
1844 var createHeader = $('th, td', thead).length === 0;
1845 var classes = oSettings.oClasses;
1846 var columns = oSettings.aoColumns;
1847
1848 if ( createHeader ) {
1849 row = $('<tr/>').appendTo( thead );
1850 }
1851
1852 for ( i=0, ien=columns.length ; i<ien ; i++ ) {
1853 column = columns[i];
1854 cell = $( column.nTh ).addClass( column.sClass );
1855
1856 if ( createHeader ) {
1857 cell.appendTo( row );
1858 }
1859
1860 // 1.11 move into sorting
1861 if ( oSettings.oFeatures.bSort ) {
1862 cell.addClass( column.sSortingClass );
1863
1864 if ( column.bSortable !== false ) {
1865 cell
1866 .attr( 'tabindex', oSettings.iTabIndex )
1867 .attr( 'aria-controls', oSettings.sTableId );
1868
1869 _fnSortAttachListener( oSettings, column.nTh, i );
1870 }
1871 }
1872
1873 if ( column.sTitle != cell[0].innerHTML ) {
1874 cell.html( column.sTitle );
1875 }
1876
1877 _fnRenderer( oSettings, 'header' )(
1878 oSettings, cell, column, classes
1879 );
1880 }
1881
1882 if ( createHeader ) {
1883 _fnDetectHeader( oSettings.aoHeader, thead );
1884 }
1885
1886 /* ARIA role for the rows */
1887 $(thead).find('>tr').attr('role', 'row');
1888
1889 /* Deal with the footer - add classes if required */
1890 $(thead).find('>tr>th, >tr>td').addClass( classes.sHeaderTH );
1891 $(tfoot).find('>tr>th, >tr>td').addClass( classes.sFooterTH );
1892
1893 // Cache the footer cells. Note that we only take the cells from the first
1894 // row in the footer. If there is more than one row the user wants to
1895 // interact with, they need to use the table().foot() method. Note also this
1896 // allows cells to be used for multiple columns using colspan
1897 if ( tfoot !== null ) {
1898 var cells = oSettings.aoFooter[0];
1899
1900 for ( i=0, ien=cells.length ; i<ien ; i++ ) {
1901 column = columns[i];
1902 column.nTf = cells[i].cell;
1903
1904 if ( column.sClass ) {
1905 $(column.nTf).addClass( column.sClass );
1906 }
1907 }
1908 }
1909 }
1910
1911
1912 /**
1913 * Draw the header (or footer) element based on the column visibility states. The
1914 * methodology here is to use the layout array from _fnDetectHeader, modified for
1915 * the instantaneous column visibility, to construct the new layout. The grid is
1916 * traversed over cell at a time in a rows x columns grid fashion, although each
1917 * cell insert can cover multiple elements in the grid - which is tracks using the
1918 * aApplied array. Cell inserts in the grid will only occur where there isn't
1919 * already a cell in that position.
1920 * @param {object} oSettings dataTables settings object
1921 * @param array {objects} aoSource Layout array from _fnDetectHeader
1922 * @param {boolean} [bIncludeHidden=false] If true then include the hidden columns in the calc,
1923 * @memberof DataTable#oApi
1924 */
1925 function _fnDrawHead( oSettings, aoSource, bIncludeHidden )
1926 {
1927 var i, iLen, j, jLen, k, kLen, n, nLocalTr;
1928 var aoLocal = [];
1929 var aApplied = [];
1930 var iColumns = oSettings.aoColumns.length;
1931 var iRowspan, iColspan;
1932
1933 if ( ! aoSource )
1934 {
1935 return;
1936 }
1937
1938 if ( bIncludeHidden === undefined )
1939 {
1940 bIncludeHidden = false;
1941 }
1942
1943 /* Make a copy of the master layout array, but without the visible columns in it */
1944 for ( i=0, iLen=aoSource.length ; i<iLen ; i++ )
1945 {
1946 aoLocal[i] = aoSource[i].slice();
1947 aoLocal[i].nTr = aoSource[i].nTr;
1948
1949 /* Remove any columns which are currently hidden */
1950 for ( j=iColumns-1 ; j>=0 ; j-- )
1951 {
1952 if ( !oSettings.aoColumns[j].bVisible && !bIncludeHidden )
1953 {
1954 aoLocal[i].splice( j, 1 );
1955 }
1956 }
1957
1958 /* Prep the applied array - it needs an element for each row */
1959 aApplied.push( [] );
1960 }
1961
1962 for ( i=0, iLen=aoLocal.length ; i<iLen ; i++ )
1963 {
1964 nLocalTr = aoLocal[i].nTr;
1965
1966 /* All cells are going to be replaced, so empty out the row */
1967 if ( nLocalTr )
1968 {
1969 while( (n = nLocalTr.firstChild) )
1970 {
1971 nLocalTr.removeChild( n );
1972 }
1973 }
1974
1975 for ( j=0, jLen=aoLocal[i].length ; j<jLen ; j++ )
1976 {
1977 iRowspan = 1;
1978 iColspan = 1;
1979
1980 /* Check to see if there is already a cell (row/colspan) covering our target
1981 * insert point. If there is, then there is nothing to do.
1982 */
1983 if ( aApplied[i][j] === undefined )
1984 {
1985 nLocalTr.appendChild( aoLocal[i][j].cell );
1986 aApplied[i][j] = 1;
1987
1988 /* Expand the cell to cover as many rows as needed */
1989 while ( aoLocal[i+iRowspan] !== undefined &&
1990 aoLocal[i][j].cell == aoLocal[i+iRowspan][j].cell )
1991 {
1992 aApplied[i+iRowspan][j] = 1;
1993 iRowspan++;
1994 }
1995
1996 /* Expand the cell to cover as many columns as needed */
1997 while ( aoLocal[i][j+iColspan] !== undefined &&
1998 aoLocal[i][j].cell == aoLocal[i][j+iColspan].cell )
1999 {
2000 /* Must update the applied array over the rows for the columns */
2001 for ( k=0 ; k<iRowspan ; k++ )
2002 {
2003 aApplied[i+k][j+iColspan] = 1;
2004 }
2005 iColspan++;
2006 }
2007
2008 /* Do the actual expansion in the DOM */
2009 $(aoLocal[i][j].cell)
2010 .attr('rowspan', iRowspan)
2011 .attr('colspan', iColspan);
2012 }
2013 }
2014 }
2015 }
2016
2017
2018 /**
2019 * Insert the required TR nodes into the table for display
2020 * @param {object} oSettings dataTables settings object
2021 * @memberof DataTable#oApi
2022 */
2023 function _fnDraw( oSettings )
2024 {
2025 /* Provide a pre-callback function which can be used to cancel the draw is false is returned */
2026 var aPreDraw = _fnCallbackFire( oSettings, 'aoPreDrawCallback', 'preDraw', [oSettings] );
2027 if ( $.inArray( false, aPreDraw ) !== -1 )
2028 {
2029 _fnProcessingDisplay( oSettings, false );
2030 return;
2031 }
2032
2033 var i, iLen, n;
2034 var anRows = [];
2035 var iRowCount = 0;
2036 var asStripeClasses = oSettings.asStripeClasses;
2037 var iStripes = asStripeClasses.length;
2038 var iOpenRows = oSettings.aoOpenRows.length;
2039 var oLang = oSettings.oLanguage;
2040 var iInitDisplayStart = oSettings.iInitDisplayStart;
2041 var bServerSide = _fnDataSource( oSettings ) == 'ssp';
2042 var aiDisplay = oSettings.aiDisplay;
2043
2044 oSettings.bDrawing = true;
2045
2046 /* Check and see if we have an initial draw position from state saving */
2047 if ( iInitDisplayStart !== undefined && iInitDisplayStart !== -1 )
2048 {
2049 oSettings._iDisplayStart = bServerSide ?
2050 iInitDisplayStart :
2051 iInitDisplayStart >= oSettings.fnRecordsDisplay() ?
2052 0 :
2053 iInitDisplayStart;
2054
2055 oSettings.iInitDisplayStart = -1;
2056 }
2057
2058 var iDisplayStart = oSettings._iDisplayStart;
2059 var iDisplayEnd = oSettings.fnDisplayEnd();
2060
2061 /* Server-side processing draw intercept */
2062 if ( oSettings.bDeferLoading )
2063 {
2064 oSettings.bDeferLoading = false;
2065 oSettings.iDraw++;
2066 _fnProcessingDisplay( oSettings, false );
2067 }
2068 else if ( !bServerSide )
2069 {
2070 oSettings.iDraw++;
2071 }
2072 else if ( !oSettings.bDestroying && !_fnAjaxUpdate( oSettings ) )
2073 {
2074 return;
2075 }
2076
2077 if ( aiDisplay.length !== 0 )
2078 {
2079 var iStart = bServerSide ? 0 : iDisplayStart;
2080 var iEnd = bServerSide ? oSettings.aoData.length : iDisplayEnd;
2081
2082 for ( var j=iStart ; j<iEnd ; j++ )
2083 {
2084 var iDataIndex = aiDisplay[j];
2085 var aoData = oSettings.aoData[ iDataIndex ];
2086 if ( aoData.nTr === null )
2087 {
2088 _fnCreateTr( oSettings, iDataIndex );
2089 }
2090
2091 var nRow = aoData.nTr;
2092
2093 /* Remove the old striping classes and then add the new one */
2094 if ( iStripes !== 0 )
2095 {
2096 var sStripe = asStripeClasses[ iRowCount % iStripes ];
2097 if ( aoData._sRowStripe != sStripe )
2098 {
2099 $(nRow).removeClass( aoData._sRowStripe ).addClass( sStripe );
2100 aoData._sRowStripe = sStripe;
2101 }
2102 }
2103
2104 // Row callback functions - might want to manipulate the row
2105 // iRowCount and j are not currently documented. Are they at all
2106 // useful?
2107 _fnCallbackFire( oSettings, 'aoRowCallback', null,
2108 [nRow, aoData._aData, iRowCount, j] );
2109
2110 anRows.push( nRow );
2111 iRowCount++;
2112 }
2113 }
2114 else
2115 {
2116 /* Table is empty - create a row with an empty message in it */
2117 var sZero = oLang.sZeroRecords;
2118 if ( oSettings.iDraw == 1 && _fnDataSource( oSettings ) == 'ajax' )
2119 {
2120 sZero = oLang.sLoadingRecords;
2121 }
2122 else if ( oLang.sEmptyTable && oSettings.fnRecordsTotal() === 0 )
2123 {
2124 sZero = oLang.sEmptyTable;
2125 }
2126
2127 anRows[ 0 ] = $( '<tr/>', { 'class': iStripes ? asStripeClasses[0] : '' } )
2128 .append( $('<td />', {
2129 'valign': 'top',
2130 'colSpan': _fnVisbleColumns( oSettings ),
2131 'class': oSettings.oClasses.sRowEmpty
2132 } ).html( sZero ) )[0];
2133 }
2134
2135 /* Header and footer callbacks */
2136 _fnCallbackFire( oSettings, 'aoHeaderCallback', 'header', [ $(oSettings.nTHead).children('tr')[0],
2137 _fnGetDataMaster( oSettings ), iDisplayStart, iDisplayEnd, aiDisplay ] );
2138
2139 _fnCallbackFire( oSettings, 'aoFooterCallback', 'footer', [ $(oSettings.nTFoot).children('tr')[0],
2140 _fnGetDataMaster( oSettings ), iDisplayStart, iDisplayEnd, aiDisplay ] );
2141
2142 var body = $(oSettings.nTBody);
2143
2144 body.children().detach();
2145 body.append( $(anRows) );
2146
2147 /* Call all required callback functions for the end of a draw */
2148 _fnCallbackFire( oSettings, 'aoDrawCallback', 'draw', [oSettings] );
2149
2150 /* Draw is complete, sorting and filtering must be as well */
2151 oSettings.bSorted = false;
2152 oSettings.bFiltered = false;
2153 oSettings.bDrawing = false;
2154 }
2155
2156
2157 /**
2158 * Redraw the table - taking account of the various features which are enabled
2159 * @param {object} oSettings dataTables settings object
2160 * @param {boolean} [holdPosition] Keep the current paging position. By default
2161 * the paging is reset to the first page
2162 * @memberof DataTable#oApi
2163 */
2164 function _fnReDraw( settings, holdPosition )
2165 {
2166 var
2167 features = settings.oFeatures,
2168 sort = features.bSort,
2169 filter = features.bFilter;
2170
2171 if ( sort ) {
2172 _fnSort( settings );
2173 }
2174
2175 if ( filter ) {
2176 _fnFilterComplete( settings, settings.oPreviousSearch );
2177 }
2178 else {
2179 // No filtering, so we want to just use the display master
2180 settings.aiDisplay = settings.aiDisplayMaster.slice();
2181 }
2182
2183 if ( holdPosition !== true ) {
2184 settings._iDisplayStart = 0;
2185 }
2186
2187 // Let any modules know about the draw hold position state (used by
2188 // scrolling internally)
2189 settings._drawHold = holdPosition;
2190
2191 _fnDraw( settings );
2192
2193 settings._drawHold = false;
2194 }
2195
2196
2197 /**
2198 * Add the options to the page HTML for the table
2199 * @param {object} oSettings dataTables settings object
2200 * @memberof DataTable#oApi
2201 */
2202 function _fnAddOptionsHtml ( oSettings )
2203 {
2204 var classes = oSettings.oClasses;
2205 var table = $(oSettings.nTable);
2206 var holding = $('<div/>').insertBefore( table ); // Holding element for speed
2207 var features = oSettings.oFeatures;
2208
2209 // All DataTables are wrapped in a div
2210 var insert = $('<div/>', {
2211 id: oSettings.sTableId+'_wrapper',
2212 'class': classes.sWrapper + (oSettings.nTFoot ? '' : ' '+classes.sNoFooter)
2213 } );
2214
2215 oSettings.nHolding = holding[0];
2216 oSettings.nTableWrapper = insert[0];
2217 oSettings.nTableReinsertBefore = oSettings.nTable.nextSibling;
2218
2219 /* Loop over the user set positioning and place the elements as needed */
2220 var aDom = oSettings.sDom.split('');
2221 var featureNode, cOption, nNewNode, cNext, sAttr, j;
2222 for ( var i=0 ; i<aDom.length ; i++ )
2223 {
2224 featureNode = null;
2225 cOption = aDom[i];
2226
2227 if ( cOption == '<' )
2228 {
2229 /* New container div */
2230 nNewNode = $('<div/>')[0];
2231
2232 /* Check to see if we should append an id and/or a class name to the container */
2233 cNext = aDom[i+1];
2234 if ( cNext == "'" || cNext == '"' )
2235 {
2236 sAttr = "";
2237 j = 2;
2238 while ( aDom[i+j] != cNext )
2239 {
2240 sAttr += aDom[i+j];
2241 j++;
2242 }
2243
2244 /* Replace jQuery UI constants @todo depreciated */
2245 if ( sAttr == "H" )
2246 {
2247 sAttr = classes.sJUIHeader;
2248 }
2249 else if ( sAttr == "F" )
2250 {
2251 sAttr = classes.sJUIFooter;
2252 }
2253
2254 /* The attribute can be in the format of "#id.class", "#id" or "class" This logic
2255 * breaks the string into parts and applies them as needed
2256 */
2257 if ( sAttr.indexOf('.') != -1 )
2258 {
2259 var aSplit = sAttr.split('.');
2260 nNewNode.id = aSplit[0].substr(1, aSplit[0].length-1);
2261 nNewNode.className = aSplit[1];
2262 }
2263 else if ( sAttr.charAt(0) == "#" )
2264 {
2265 nNewNode.id = sAttr.substr(1, sAttr.length-1);
2266 }
2267 else
2268 {
2269 nNewNode.className = sAttr;
2270 }
2271
2272 i += j; /* Move along the position array */
2273 }
2274
2275 insert.append( nNewNode );
2276 insert = $(nNewNode);
2277 }
2278 else if ( cOption == '>' )
2279 {
2280 /* End container div */
2281 insert = insert.parent();
2282 }
2283 // @todo Move options into their own plugins?
2284 else if ( cOption == 'l' && features.bPaginate && features.bLengthChange )
2285 {
2286 /* Length */
2287 featureNode = _fnFeatureHtmlLength( oSettings );
2288 }
2289 else if ( cOption == 'f' && features.bFilter )
2290 {
2291 /* Filter */
2292 featureNode = _fnFeatureHtmlFilter( oSettings );
2293 }
2294 else if ( cOption == 'r' && features.bProcessing )
2295 {
2296 /* pRocessing */
2297 featureNode = _fnFeatureHtmlProcessing( oSettings );
2298 }
2299 else if ( cOption == 't' )
2300 {
2301 /* Table */
2302 featureNode = _fnFeatureHtmlTable( oSettings );
2303 }
2304 else if ( cOption == 'i' && features.bInfo )
2305 {
2306 /* Info */
2307 featureNode = _fnFeatureHtmlInfo( oSettings );
2308 }
2309 else if ( cOption == 'p' && features.bPaginate )
2310 {
2311 /* Pagination */
2312 featureNode = _fnFeatureHtmlPaginate( oSettings );
2313 }
2314 else if ( DataTable.ext.feature.length !== 0 )
2315 {
2316 /* Plug-in features */
2317 var aoFeatures = DataTable.ext.feature;
2318 for ( var k=0, kLen=aoFeatures.length ; k<kLen ; k++ )
2319 {
2320 if ( cOption == aoFeatures[k].cFeature )
2321 {
2322 featureNode = aoFeatures[k].fnInit( oSettings );
2323 break;
2324 }
2325 }
2326 }
2327
2328 /* Add to the 2D features array */
2329 if ( featureNode )
2330 {
2331 var aanFeatures = oSettings.aanFeatures;
2332
2333 if ( ! aanFeatures[cOption] )
2334 {
2335 aanFeatures[cOption] = [];
2336 }
2337
2338 aanFeatures[cOption].push( featureNode );
2339 insert.append( featureNode );
2340 }
2341 }
2342
2343 /* Built our DOM structure - replace the holding div with what we want */
2344 holding.replaceWith( insert );
2345 oSettings.nHolding = null;
2346 }
2347
2348
2349 /**
2350 * Use the DOM source to create up an array of header cells. The idea here is to
2351 * create a layout grid (array) of rows x columns, which contains a reference
2352 * to the cell that that point in the grid (regardless of col/rowspan), such that
2353 * any column / row could be removed and the new grid constructed
2354 * @param array {object} aLayout Array to store the calculated layout in
2355 * @param {node} nThead The header/footer element for the table
2356 * @memberof DataTable#oApi
2357 */
2358 function _fnDetectHeader ( aLayout, nThead )
2359 {
2360 var nTrs = $(nThead).children('tr');
2361 var nTr, nCell;
2362 var i, k, l, iLen, jLen, iColShifted, iColumn, iColspan, iRowspan;
2363 var bUnique;
2364 var fnShiftCol = function ( a, i, j ) {
2365 var k = a[i];
2366 while ( k[j] ) {
2367 j++;
2368 }
2369 return j;
2370 };
2371
2372 aLayout.splice( 0, aLayout.length );
2373
2374 /* We know how many rows there are in the layout - so prep it */
2375 for ( i=0, iLen=nTrs.length ; i<iLen ; i++ )
2376 {
2377 aLayout.push( [] );
2378 }
2379
2380 /* Calculate a layout array */
2381 for ( i=0, iLen=nTrs.length ; i<iLen ; i++ )
2382 {
2383 nTr = nTrs[i];
2384 iColumn = 0;
2385
2386 /* For every cell in the row... */
2387 nCell = nTr.firstChild;
2388 while ( nCell ) {
2389 if ( nCell.nodeName.toUpperCase() == "TD" ||
2390 nCell.nodeName.toUpperCase() == "TH" )
2391 {
2392 /* Get the col and rowspan attributes from the DOM and sanitise them */
2393 iColspan = nCell.getAttribute('colspan') * 1;
2394 iRowspan = nCell.getAttribute('rowspan') * 1;
2395 iColspan = (!iColspan || iColspan===0 || iColspan===1) ? 1 : iColspan;
2396 iRowspan = (!iRowspan || iRowspan===0 || iRowspan===1) ? 1 : iRowspan;
2397
2398 /* There might be colspan cells already in this row, so shift our target
2399 * accordingly
2400 */
2401 iColShifted = fnShiftCol( aLayout, i, iColumn );
2402
2403 /* Cache calculation for unique columns */
2404 bUnique = iColspan === 1 ? true : false;
2405
2406 /* If there is col / rowspan, copy the information into the layout grid */
2407 for ( l=0 ; l<iColspan ; l++ )
2408 {
2409 for ( k=0 ; k<iRowspan ; k++ )
2410 {
2411 aLayout[i+k][iColShifted+l] = {
2412 "cell": nCell,
2413 "unique": bUnique
2414 };
2415 aLayout[i+k].nTr = nTr;
2416 }
2417 }
2418 }
2419 nCell = nCell.nextSibling;
2420 }
2421 }
2422 }
2423
2424
2425 /**
2426 * Get an array of unique th elements, one for each column
2427 * @param {object} oSettings dataTables settings object
2428 * @param {node} nHeader automatically detect the layout from this node - optional
2429 * @param {array} aLayout thead/tfoot layout from _fnDetectHeader - optional
2430 * @returns array {node} aReturn list of unique th's
2431 * @memberof DataTable#oApi
2432 */
2433 function _fnGetUniqueThs ( oSettings, nHeader, aLayout )
2434 {
2435 var aReturn = [];
2436 if ( !aLayout )
2437 {
2438 aLayout = oSettings.aoHeader;
2439 if ( nHeader )
2440 {
2441 aLayout = [];
2442 _fnDetectHeader( aLayout, nHeader );
2443 }
2444 }
2445
2446 for ( var i=0, iLen=aLayout.length ; i<iLen ; i++ )
2447 {
2448 for ( var j=0, jLen=aLayout[i].length ; j<jLen ; j++ )
2449 {
2450 if ( aLayout[i][j].unique &&
2451 (!aReturn[j] || !oSettings.bSortCellsTop) )
2452 {
2453 aReturn[j] = aLayout[i][j].cell;
2454 }
2455 }
2456 }
2457
2458 return aReturn;
2459 }
2460
2461 /**
2462 * Create an Ajax call based on the table's settings, taking into account that
2463 * parameters can have multiple forms, and backwards compatibility.
2464 *
2465 * @param {object} oSettings dataTables settings object
2466 * @param {array} data Data to send to the server, required by
2467 * DataTables - may be augmented by developer callbacks
2468 * @param {function} fn Callback function to run when data is obtained
2469 */
2470 function _fnBuildAjax( oSettings, data, fn )
2471 {
2472 // Compatibility with 1.9-, allow fnServerData and event to manipulate
2473 _fnCallbackFire( oSettings, 'aoServerParams', 'serverParams', [data] );
2474
2475 // Convert to object based for 1.10+ if using the old array scheme which can
2476 // come from server-side processing or serverParams
2477 if ( data && $.isArray(data) ) {
2478 var tmp = {};
2479 var rbracket = /(.*?)\[\]$/;
2480
2481 $.each( data, function (key, val) {
2482 var match = val.name.match(rbracket);
2483
2484 if ( match ) {
2485 // Support for arrays
2486 var name = match[0];
2487
2488 if ( ! tmp[ name ] ) {
2489 tmp[ name ] = [];
2490 }
2491 tmp[ name ].push( val.value );
2492 }
2493 else {
2494 tmp[val.name] = val.value;
2495 }
2496 } );
2497 data = tmp;
2498 }
2499
2500 var ajaxData;
2501 var ajax = oSettings.ajax;
2502 var instance = oSettings.oInstance;
2503 var callback = function ( json ) {
2504 _fnCallbackFire( oSettings, null, 'xhr', [oSettings, json, oSettings.jqXHR] );
2505 fn( json );
2506 };
2507
2508 if ( $.isPlainObject( ajax ) && ajax.data )
2509 {
2510 ajaxData = ajax.data;
2511
2512 var newData = $.isFunction( ajaxData ) ?
2513 ajaxData( data, oSettings ) : // fn can manipulate data or return
2514 ajaxData; // an object object or array to merge
2515
2516 // If the function returned something, use that alone
2517 data = $.isFunction( ajaxData ) && newData ?
2518 newData :
2519 $.extend( true, data, newData );
2520
2521 // Remove the data property as we've resolved it already and don't want
2522 // jQuery to do it again (it is restored at the end of the function)
2523 delete ajax.data;
2524 }
2525
2526 var baseAjax = {
2527 "data": data,
2528 "success": function (json) {
2529 var error = json.error || json.sError;
2530 if ( error ) {
2531 _fnLog( oSettings, 0, error );
2532 }
2533
2534 oSettings.json = json;
2535 callback( json );
2536 },
2537 "dataType": "json",
2538 "cache": false,
2539 "type": oSettings.sServerMethod,
2540 "error": function (xhr, error, thrown) {
2541 var ret = _fnCallbackFire( oSettings, null, 'xhr', [oSettings, null, oSettings.jqXHR] );
2542
2543 if ( $.inArray( true, ret ) === -1 ) {
2544 if ( error == "parsererror" ) {
2545 _fnLog( oSettings, 0, 'Invalid JSON response', 1 );
2546 }
2547 else if ( xhr.readyState === 4 ) {
2548 _fnLog( oSettings, 0, 'Ajax error', 7 );
2549 }
2550 }
2551
2552 _fnProcessingDisplay( oSettings, false );
2553 }
2554 };
2555
2556 // Store the data submitted for the API
2557 oSettings.oAjaxData = data;
2558
2559 // Allow plug-ins and external processes to modify the data
2560 _fnCallbackFire( oSettings, null, 'preXhr', [oSettings, data] );
2561
2562 if ( oSettings.fnServerData )
2563 {
2564 // DataTables 1.9- compatibility
2565 oSettings.fnServerData.call( instance,
2566 oSettings.sAjaxSource,
2567 $.map( data, function (val, key) { // Need to convert back to 1.9 trad format
2568 return { name: key, value: val };
2569 } ),
2570 callback,
2571 oSettings
2572 );
2573 }
2574 else if ( oSettings.sAjaxSource || typeof ajax === 'string' )
2575 {
2576 // DataTables 1.9- compatibility
2577 oSettings.jqXHR = $.ajax( $.extend( baseAjax, {
2578 url: ajax || oSettings.sAjaxSource
2579 } ) );
2580 }
2581 else if ( $.isFunction( ajax ) )
2582 {
2583 // Is a function - let the caller define what needs to be done
2584 oSettings.jqXHR = ajax.call( instance, data, callback, oSettings );
2585 }
2586 else
2587 {
2588 // Object to extend the base settings
2589 oSettings.jqXHR = $.ajax( $.extend( baseAjax, ajax ) );
2590
2591 // Restore for next time around
2592 ajax.data = ajaxData;
2593 }
2594 }
2595
2596
2597 /**
2598 * Update the table using an Ajax call
2599 * @param {object} settings dataTables settings object
2600 * @returns {boolean} Block the table drawing or not
2601 * @memberof DataTable#oApi
2602 */
2603 function _fnAjaxUpdate( settings )
2604 {
2605 if ( settings.bAjaxDataGet ) {
2606 settings.iDraw++;
2607 _fnProcessingDisplay( settings, true );
2608
2609 _fnBuildAjax(
2610 settings,
2611 _fnAjaxParameters( settings ),
2612 function(json) {
2613 _fnAjaxUpdateDraw( settings, json );
2614 }
2615 );
2616
2617 return false;
2618 }
2619 return true;
2620 }
2621
2622
2623 /**
2624 * Build up the parameters in an object needed for a server-side processing
2625 * request. Note that this is basically done twice, is different ways - a modern
2626 * method which is used by default in DataTables 1.10 which uses objects and
2627 * arrays, or the 1.9- method with is name / value pairs. 1.9 method is used if
2628 * the sAjaxSource option is used in the initialisation, or the legacyAjax
2629 * option is set.
2630 * @param {object} oSettings dataTables settings object
2631 * @returns {bool} block the table drawing or not
2632 * @memberof DataTable#oApi
2633 */
2634 function _fnAjaxParameters( settings )
2635 {
2636 var
2637 columns = settings.aoColumns,
2638 columnCount = columns.length,
2639 features = settings.oFeatures,
2640 preSearch = settings.oPreviousSearch,
2641 preColSearch = settings.aoPreSearchCols,
2642 i, data = [], dataProp, column, columnSearch,
2643 sort = _fnSortFlatten( settings ),
2644 displayStart = settings._iDisplayStart,
2645 displayLength = features.bPaginate !== false ?
2646 settings._iDisplayLength :
2647 -1;
2648
2649 var param = function ( name, value ) {
2650 data.push( { 'name': name, 'value': value } );
2651 };
2652
2653 // DataTables 1.9- compatible method
2654 param( 'sEcho', settings.iDraw );
2655 param( 'iColumns', columnCount );
2656 param( 'sColumns', _pluck( columns, 'sName' ).join(',') );
2657 param( 'iDisplayStart', displayStart );
2658 param( 'iDisplayLength', displayLength );
2659
2660 // DataTables 1.10+ method
2661 var d = {
2662 draw: settings.iDraw,
2663 columns: [],
2664 order: [],
2665 start: displayStart,
2666 length: displayLength,
2667 search: {
2668 value: preSearch.sSearch,
2669 regex: preSearch.bRegex
2670 }
2671 };
2672
2673 for ( i=0 ; i<columnCount ; i++ ) {
2674 column = columns[i];
2675 columnSearch = preColSearch[i];
2676 dataProp = typeof column.mData=="function" ? 'function' : column.mData ;
2677
2678 d.columns.push( {
2679 data: dataProp,
2680 name: column.sName,
2681 searchable: column.bSearchable,
2682 orderable: column.bSortable,
2683 search: {
2684 value: columnSearch.sSearch,
2685 regex: columnSearch.bRegex
2686 }
2687 } );
2688
2689 param( "mDataProp_"+i, dataProp );
2690
2691 if ( features.bFilter ) {
2692 param( 'sSearch_'+i, columnSearch.sSearch );
2693 param( 'bRegex_'+i, columnSearch.bRegex );
2694 param( 'bSearchable_'+i, column.bSearchable );
2695 }
2696
2697 if ( features.bSort ) {
2698 param( 'bSortable_'+i, column.bSortable );
2699 }
2700 }
2701
2702 if ( features.bFilter ) {
2703 param( 'sSearch', preSearch.sSearch );
2704 param( 'bRegex', preSearch.bRegex );
2705 }
2706
2707 if ( features.bSort ) {
2708 $.each( sort, function ( i, val ) {
2709 d.order.push( { column: val.col, dir: val.dir } );
2710
2711 param( 'iSortCol_'+i, val.col );
2712 param( 'sSortDir_'+i, val.dir );
2713 } );
2714
2715 param( 'iSortingCols', sort.length );
2716 }
2717
2718 // If the legacy.ajax parameter is null, then we automatically decide which
2719 // form to use, based on sAjaxSource
2720 var legacy = DataTable.ext.legacy.ajax;
2721 if ( legacy === null ) {
2722 return settings.sAjaxSource ? data : d;
2723 }
2724
2725 // Otherwise, if legacy has been specified then we use that to decide on the
2726 // form
2727 return legacy ? data : d;
2728 }
2729
2730
2731 /**
2732 * Data the data from the server (nuking the old) and redraw the table
2733 * @param {object} oSettings dataTables settings object
2734 * @param {object} json json data return from the server.
2735 * @param {string} json.sEcho Tracking flag for DataTables to match requests
2736 * @param {int} json.iTotalRecords Number of records in the data set, not accounting for filtering
2737 * @param {int} json.iTotalDisplayRecords Number of records in the data set, accounting for filtering
2738 * @param {array} json.aaData The data to display on this page
2739 * @param {string} [json.sColumns] Column ordering (sName, comma separated)
2740 * @memberof DataTable#oApi
2741 */
2742 function _fnAjaxUpdateDraw ( settings, json )
2743 {
2744 // v1.10 uses camelCase variables, while 1.9 uses Hungarian notation.
2745 // Support both
2746 var compat = function ( old, modern ) {
2747 return json[old] !== undefined ? json[old] : json[modern];
2748 };
2749
2750 var data = _fnAjaxDataSrc( settings, json );
2751 var draw = compat( 'sEcho', 'draw' );
2752 var recordsTotal = compat( 'iTotalRecords', 'recordsTotal' );
2753 var recordsFiltered = compat( 'iTotalDisplayRecords', 'recordsFiltered' );
2754
2755 if ( draw ) {
2756 // Protect against out of sequence returns
2757 if ( draw*1 < settings.iDraw ) {
2758 return;
2759 }
2760 settings.iDraw = draw * 1;
2761 }
2762
2763 _fnClearTable( settings );
2764 settings._iRecordsTotal = parseInt(recordsTotal, 10);
2765 settings._iRecordsDisplay = parseInt(recordsFiltered, 10);
2766
2767 for ( var i=0, ien=data.length ; i<ien ; i++ ) {
2768 _fnAddData( settings, data[i] );
2769 }
2770 settings.aiDisplay = settings.aiDisplayMaster.slice();
2771
2772 settings.bAjaxDataGet = false;
2773 _fnDraw( settings );
2774
2775 if ( ! settings._bInitComplete ) {
2776 _fnInitComplete( settings, json );
2777 }
2778
2779 settings.bAjaxDataGet = true;
2780 _fnProcessingDisplay( settings, false );
2781 }
2782
2783
2784 /**
2785 * Get the data from the JSON data source to use for drawing a table. Using
2786 * `_fnGetObjectDataFn` allows the data to be sourced from a property of the
2787 * source object, or from a processing function.
2788 * @param {object} oSettings dataTables settings object
2789 * @param {object} json Data source object / array from the server
2790 * @return {array} Array of data to use
2791 */
2792 function _fnAjaxDataSrc ( oSettings, json )
2793 {
2794 var dataSrc = $.isPlainObject( oSettings.ajax ) && oSettings.ajax.dataSrc !== undefined ?
2795 oSettings.ajax.dataSrc :
2796 oSettings.sAjaxDataProp; // Compatibility with 1.9-.
2797
2798 // Compatibility with 1.9-. In order to read from aaData, check if the
2799 // default has been changed, if not, check for aaData
2800 if ( dataSrc === 'data' ) {
2801 return json.aaData || json[dataSrc];
2802 }
2803
2804 return dataSrc !== "" ?
2805 _fnGetObjectDataFn( dataSrc )( json ) :
2806 json;
2807 }
2808
2809 /**
2810 * Generate the node required for filtering text
2811 * @returns {node} Filter control element
2812 * @param {object} oSettings dataTables settings object
2813 * @memberof DataTable#oApi
2814 */
2815 function _fnFeatureHtmlFilter ( settings )
2816 {
2817 var classes = settings.oClasses;
2818 var tableId = settings.sTableId;
2819 var language = settings.oLanguage;
2820 var previousSearch = settings.oPreviousSearch;
2821 var features = settings.aanFeatures;
2822 var input = '<input type="search" class="'+classes.sFilterInput+'"/>';
2823
2824 var str = language.sSearch;
2825 str = str.match(/_INPUT_/) ?
2826 str.replace('_INPUT_', input) :
2827 str+input;
2828
2829 var filter = $('<div/>', {
2830 'id': ! features.f ? tableId+'_filter' : null,
2831 'class': classes.sFilter
2832 } )
2833 .append( $('<label/>' ).append( str ) );
2834
2835 var searchFn = function() {
2836 /* Update all other filter input elements for the new display */
2837 var n = features.f;
2838 var val = !this.value ? "" : this.value; // mental IE8 fix :-(
2839
2840 /* Now do the filter */
2841 if ( val != previousSearch.sSearch ) {
2842 _fnFilterComplete( settings, {
2843 "sSearch": val,
2844 "bRegex": previousSearch.bRegex,
2845 "bSmart": previousSearch.bSmart ,
2846 "bCaseInsensitive": previousSearch.bCaseInsensitive
2847 } );
2848
2849 // Need to redraw, without resorting
2850 settings._iDisplayStart = 0;
2851 _fnDraw( settings );
2852 }
2853 };
2854
2855 var searchDelay = settings.searchDelay !== null ?
2856 settings.searchDelay :
2857 _fnDataSource( settings ) === 'ssp' ?
2858 400 :
2859 0;
2860
2861 var jqFilter = $('input', filter)
2862 .val( previousSearch.sSearch )
2863 .attr( 'placeholder', language.sSearchPlaceholder )
2864 .bind(
2865 'keyup.DT search.DT input.DT paste.DT cut.DT',
2866 searchDelay ?
2867 _fnThrottle( searchFn, searchDelay ) :
2868 searchFn
2869 )
2870 .bind( 'keypress.DT', function(e) {
2871 /* Prevent form submission */
2872 if ( e.keyCode == 13 ) {
2873 return false;
2874 }
2875 } )
2876 .attr('aria-controls', tableId);
2877
2878 // Update the input elements whenever the table is filtered
2879 $(settings.nTable).on( 'search.dt.DT', function ( ev, s ) {
2880 if ( settings === s ) {
2881 // IE9 throws an 'unknown error' if document.activeElement is used
2882 // inside an iframe or frame...
2883 try {
2884 if ( jqFilter[0] !== document.activeElement ) {
2885 jqFilter.val( previousSearch.sSearch );
2886 }
2887 }
2888 catch ( e ) {}
2889 }
2890 } );
2891
2892 return filter[0];
2893 }
2894
2895
2896 /**
2897 * Filter the table using both the global filter and column based filtering
2898 * @param {object} oSettings dataTables settings object
2899 * @param {object} oSearch search information
2900 * @param {int} [iForce] force a research of the master array (1) or not (undefined or 0)
2901 * @memberof DataTable#oApi
2902 */
2903 function _fnFilterComplete ( oSettings, oInput, iForce )
2904 {
2905 var oPrevSearch = oSettings.oPreviousSearch;
2906 var aoPrevSearch = oSettings.aoPreSearchCols;
2907 var fnSaveFilter = function ( oFilter ) {
2908 /* Save the filtering values */
2909 oPrevSearch.sSearch = oFilter.sSearch;
2910 oPrevSearch.bRegex = oFilter.bRegex;
2911 oPrevSearch.bSmart = oFilter.bSmart;
2912 oPrevSearch.bCaseInsensitive = oFilter.bCaseInsensitive;
2913 };
2914 var fnRegex = function ( o ) {
2915 // Backwards compatibility with the bEscapeRegex option
2916 return o.bEscapeRegex !== undefined ? !o.bEscapeRegex : o.bRegex;
2917 };
2918
2919 // Resolve any column types that are unknown due to addition or invalidation
2920 // @todo As per sort - can this be moved into an event handler?
2921 _fnColumnTypes( oSettings );
2922
2923 /* In server-side processing all filtering is done by the server, so no point hanging around here */
2924 if ( _fnDataSource( oSettings ) != 'ssp' )
2925 {
2926 /* Global filter */
2927 _fnFilter( oSettings, oInput.sSearch, iForce, fnRegex(oInput), oInput.bSmart, oInput.bCaseInsensitive );
2928 fnSaveFilter( oInput );
2929
2930 /* Now do the individual column filter */
2931 for ( var i=0 ; i<aoPrevSearch.length ; i++ )
2932 {
2933 _fnFilterColumn( oSettings, aoPrevSearch[i].sSearch, i, fnRegex(aoPrevSearch[i]),
2934 aoPrevSearch[i].bSmart, aoPrevSearch[i].bCaseInsensitive );
2935 }
2936
2937 /* Custom filtering */
2938 _fnFilterCustom( oSettings );
2939 }
2940 else
2941 {
2942 fnSaveFilter( oInput );
2943 }
2944
2945 /* Tell the draw function we have been filtering */
2946 oSettings.bFiltered = true;
2947 _fnCallbackFire( oSettings, null, 'search', [oSettings] );
2948 }
2949
2950
2951 /**
2952 * Apply custom filtering functions
2953 * @param {object} oSettings dataTables settings object
2954 * @memberof DataTable#oApi
2955 */
2956 function _fnFilterCustom( settings )
2957 {
2958 var filters = DataTable.ext.search;
2959 var displayRows = settings.aiDisplay;
2960 var row, rowIdx;
2961
2962 for ( var i=0, ien=filters.length ; i<ien ; i++ ) {
2963 var rows = [];
2964
2965 // Loop over each row and see if it should be included
2966 for ( var j=0, jen=displayRows.length ; j<jen ; j++ ) {
2967 rowIdx = displayRows[ j ];
2968 row = settings.aoData[ rowIdx ];
2969
2970 if ( filters[i]( settings, row._aFilterData, rowIdx, row._aData, j ) ) {
2971 rows.push( rowIdx );
2972 }
2973 }
2974
2975 // So the array reference doesn't break set the results into the
2976 // existing array
2977 displayRows.length = 0;
2978 $.merge( displayRows, rows );
2979 }
2980 }
2981
2982
2983 /**
2984 * Filter the table on a per-column basis
2985 * @param {object} oSettings dataTables settings object
2986 * @param {string} sInput string to filter on
2987 * @param {int} iColumn column to filter
2988 * @param {bool} bRegex treat search string as a regular expression or not
2989 * @param {bool} bSmart use smart filtering or not
2990 * @param {bool} bCaseInsensitive Do case insenstive matching or not
2991 * @memberof DataTable#oApi
2992 */
2993 function _fnFilterColumn ( settings, searchStr, colIdx, regex, smart, caseInsensitive )
2994 {
2995 if ( searchStr === '' ) {
2996 return;
2997 }
2998
2999 var data;
3000 var display = settings.aiDisplay;
3001 var rpSearch = _fnFilterCreateSearch( searchStr, regex, smart, caseInsensitive );
3002
3003 for ( var i=display.length-1 ; i>=0 ; i-- ) {
3004 data = settings.aoData[ display[i] ]._aFilterData[ colIdx ];
3005
3006 if ( ! rpSearch.test( data ) ) {
3007 display.splice( i, 1 );
3008 }
3009 }
3010 }
3011
3012
3013 /**
3014 * Filter the data table based on user input and draw the table
3015 * @param {object} settings dataTables settings object
3016 * @param {string} input string to filter on
3017 * @param {int} force optional - force a research of the master array (1) or not (undefined or 0)
3018 * @param {bool} regex treat as a regular expression or not
3019 * @param {bool} smart perform smart filtering or not
3020 * @param {bool} caseInsensitive Do case insenstive matching or not
3021 * @memberof DataTable#oApi
3022 */
3023 function _fnFilter( settings, input, force, regex, smart, caseInsensitive )
3024 {
3025 var rpSearch = _fnFilterCreateSearch( input, regex, smart, caseInsensitive );
3026 var prevSearch = settings.oPreviousSearch.sSearch;
3027 var displayMaster = settings.aiDisplayMaster;
3028 var display, invalidated, i;
3029
3030 // Need to take account of custom filtering functions - always filter
3031 if ( DataTable.ext.search.length !== 0 ) {
3032 force = true;
3033 }
3034
3035 // Check if any of the rows were invalidated
3036 invalidated = _fnFilterData( settings );
3037
3038 // If the input is blank - we just want the full data set
3039 if ( input.length <= 0 ) {
3040 settings.aiDisplay = displayMaster.slice();
3041 }
3042 else {
3043 // New search - start from the master array
3044 if ( invalidated ||
3045 force ||
3046 prevSearch.length > input.length ||
3047 input.indexOf(prevSearch) !== 0 ||
3048 settings.bSorted // On resort, the display master needs to be
3049 // re-filtered since indexes will have changed
3050 ) {
3051 settings.aiDisplay = displayMaster.slice();
3052 }
3053
3054 // Search the display array
3055 display = settings.aiDisplay;
3056
3057 for ( i=display.length-1 ; i>=0 ; i-- ) {
3058 if ( ! rpSearch.test( settings.aoData[ display[i] ]._sFilterRow ) ) {
3059 display.splice( i, 1 );
3060 }
3061 }
3062 }
3063 }
3064
3065
3066 /**
3067 * Build a regular expression object suitable for searching a table
3068 * @param {string} sSearch string to search for
3069 * @param {bool} bRegex treat as a regular expression or not
3070 * @param {bool} bSmart perform smart filtering or not
3071 * @param {bool} bCaseInsensitive Do case insensitive matching or not
3072 * @returns {RegExp} constructed object
3073 * @memberof DataTable#oApi
3074 */
3075 function _fnFilterCreateSearch( search, regex, smart, caseInsensitive )
3076 {
3077 search = regex ?
3078 search :
3079 _fnEscapeRegex( search );
3080
3081 if ( smart ) {
3082 /* For smart filtering we want to allow the search to work regardless of
3083 * word order. We also want double quoted text to be preserved, so word
3084 * order is important - a la google. So this is what we want to
3085 * generate:
3086 *
3087 * ^(?=.*?\bone\b)(?=.*?\btwo three\b)(?=.*?\bfour\b).*$
3088 */
3089 var a = $.map( search.match( /"[^"]+"|[^ ]+/g ) || [''], function ( word ) {
3090 if ( word.charAt(0) === '"' ) {
3091 var m = word.match( /^"(.*)"$/ );
3092 word = m ? m[1] : word;
3093 }
3094
3095 return word.replace('"', '');
3096 } );
3097
3098 search = '^(?=.*?'+a.join( ')(?=.*?' )+').*$';
3099 }
3100
3101 return new RegExp( search, caseInsensitive ? 'i' : '' );
3102 }
3103
3104
3105 /**
3106 * Escape a string such that it can be used in a regular expression
3107 * @param {string} sVal string to escape
3108 * @returns {string} escaped string
3109 * @memberof DataTable#oApi
3110 */
3111 function _fnEscapeRegex ( sVal )
3112 {
3113 return sVal.replace( _re_escape_regex, '\\$1' );
3114 }
3115
3116
3117
3118 var __filter_div = $('<div>')[0];
3119 var __filter_div_textContent = __filter_div.textContent !== undefined;
3120
3121 // Update the filtering data for each row if needed (by invalidation or first run)
3122 function _fnFilterData ( settings )
3123 {
3124 var columns = settings.aoColumns;
3125 var column;
3126 var i, j, ien, jen, filterData, cellData, row;
3127 var fomatters = DataTable.ext.type.search;
3128 var wasInvalidated = false;
3129
3130 for ( i=0, ien=settings.aoData.length ; i<ien ; i++ ) {
3131 row = settings.aoData[i];
3132
3133 if ( ! row._aFilterData ) {
3134 filterData = [];
3135
3136 for ( j=0, jen=columns.length ; j<jen ; j++ ) {
3137 column = columns[j];
3138
3139 if ( column.bSearchable ) {
3140 cellData = _fnGetCellData( settings, i, j, 'filter' );
3141
3142 if ( fomatters[ column.sType ] ) {
3143 cellData = fomatters[ column.sType ]( cellData );
3144 }
3145
3146 // Search in DataTables 1.10 is string based. In 1.11 this
3147 // should be altered to also allow strict type checking.
3148 if ( cellData === null ) {
3149 cellData = '';
3150 }
3151
3152 if ( typeof cellData !== 'string' && cellData.toString ) {
3153 cellData = cellData.toString();
3154 }
3155 }
3156 else {
3157 cellData = '';
3158 }
3159
3160 // If it looks like there is an HTML entity in the string,
3161 // attempt to decode it so sorting works as expected. Note that
3162 // we could use a single line of jQuery to do this, but the DOM
3163 // method used here is much faster http://jsperf.com/html-decode
3164 if ( cellData.indexOf && cellData.indexOf('&') !== -1 ) {
3165 __filter_div.innerHTML = cellData;
3166 cellData = __filter_div_textContent ?
3167 __filter_div.textContent :
3168 __filter_div.innerText;
3169 }
3170
3171 if ( cellData.replace ) {
3172 cellData = cellData.replace(/[\r\n]/g, '');
3173 }
3174
3175 filterData.push( cellData );
3176 }
3177
3178 row._aFilterData = filterData;
3179 row._sFilterRow = filterData.join(' ');
3180 wasInvalidated = true;
3181 }
3182 }
3183
3184 return wasInvalidated;
3185 }
3186
3187
3188 /**
3189 * Convert from the internal Hungarian notation to camelCase for external
3190 * interaction
3191 * @param {object} obj Object to convert
3192 * @returns {object} Inverted object
3193 * @memberof DataTable#oApi
3194 */
3195 function _fnSearchToCamel ( obj )
3196 {
3197 return {
3198 search: obj.sSearch,
3199 smart: obj.bSmart,
3200 regex: obj.bRegex,
3201 caseInsensitive: obj.bCaseInsensitive
3202 };
3203 }
3204
3205
3206
3207 /**
3208 * Convert from camelCase notation to the internal Hungarian. We could use the
3209 * Hungarian convert function here, but this is cleaner
3210 * @param {object} obj Object to convert
3211 * @returns {object} Inverted object
3212 * @memberof DataTable#oApi
3213 */
3214 function _fnSearchToHung ( obj )
3215 {
3216 return {
3217 sSearch: obj.search,
3218 bSmart: obj.smart,
3219 bRegex: obj.regex,
3220 bCaseInsensitive: obj.caseInsensitive
3221 };
3222 }
3223
3224 /**
3225 * Generate the node required for the info display
3226 * @param {object} oSettings dataTables settings object
3227 * @returns {node} Information element
3228 * @memberof DataTable#oApi
3229 */
3230 function _fnFeatureHtmlInfo ( settings )
3231 {
3232 var
3233 tid = settings.sTableId,
3234 nodes = settings.aanFeatures.i,
3235 n = $('<div/>', {
3236 'class': settings.oClasses.sInfo,
3237 'id': ! nodes ? tid+'_info' : null
3238 } );
3239
3240 if ( ! nodes ) {
3241 // Update display on each draw
3242 settings.aoDrawCallback.push( {
3243 "fn": _fnUpdateInfo,
3244 "sName": "information"
3245 } );
3246
3247 n
3248 .attr( 'role', 'status' )
3249 .attr( 'aria-live', 'polite' );
3250
3251 // Table is described by our info div
3252 $(settings.nTable).attr( 'aria-describedby', tid+'_info' );
3253 }
3254
3255 return n[0];
3256 }
3257
3258
3259 /**
3260 * Update the information elements in the display
3261 * @param {object} settings dataTables settings object
3262 * @memberof DataTable#oApi
3263 */
3264 function _fnUpdateInfo ( settings )
3265 {
3266 /* Show information about the table */
3267 var nodes = settings.aanFeatures.i;
3268 if ( nodes.length === 0 ) {
3269 return;
3270 }
3271
3272 var
3273 lang = settings.oLanguage,
3274 start = settings._iDisplayStart+1,
3275 end = settings.fnDisplayEnd(),
3276 max = settings.fnRecordsTotal(),
3277 total = settings.fnRecordsDisplay(),
3278 out = total ?
3279 lang.sInfo :
3280 lang.sInfoEmpty;
3281
3282 if ( total !== max ) {
3283 /* Record set after filtering */
3284 out += ' ' + lang.sInfoFiltered;
3285 }
3286
3287 // Convert the macros
3288 out += lang.sInfoPostFix;
3289 out = _fnInfoMacros( settings, out );
3290
3291 var callback = lang.fnInfoCallback;
3292 if ( callback !== null ) {
3293 out = callback.call( settings.oInstance,
3294 settings, start, end, max, total, out
3295 );
3296 }
3297
3298 $(nodes).html( out );
3299 }
3300
3301
3302 function _fnInfoMacros ( settings, str )
3303 {
3304 // When infinite scrolling, we are always starting at 1. _iDisplayStart is used only
3305 // internally
3306 var
3307 formatter = settings.fnFormatNumber,
3308 start = settings._iDisplayStart+1,
3309 len = settings._iDisplayLength,
3310 vis = settings.fnRecordsDisplay(),
3311 all = len === -1;
3312
3313 return str.
3314 replace(/_START_/g, formatter.call( settings, start ) ).
3315 replace(/_END_/g, formatter.call( settings, settings.fnDisplayEnd() ) ).
3316 replace(/_MAX_/g, formatter.call( settings, settings.fnRecordsTotal() ) ).
3317 replace(/_TOTAL_/g, formatter.call( settings, vis ) ).
3318 replace(/_PAGE_/g, formatter.call( settings, all ? 1 : Math.ceil( start / len ) ) ).
3319 replace(/_PAGES_/g, formatter.call( settings, all ? 1 : Math.ceil( vis / len ) ) );
3320 }
3321
3322
3323
3324 /**
3325 * Draw the table for the first time, adding all required features
3326 * @param {object} settings dataTables settings object
3327 * @memberof DataTable#oApi
3328 */
3329 function _fnInitialise ( settings )
3330 {
3331 var i, iLen, iAjaxStart=settings.iInitDisplayStart;
3332 var columns = settings.aoColumns, column;
3333 var features = settings.oFeatures;
3334 var deferLoading = settings.bDeferLoading; // value modified by the draw
3335
3336 /* Ensure that the table data is fully initialised */
3337 if ( ! settings.bInitialised ) {
3338 setTimeout( function(){ _fnInitialise( settings ); }, 200 );
3339 return;
3340 }
3341
3342 /* Show the display HTML options */
3343 _fnAddOptionsHtml( settings );
3344
3345 /* Build and draw the header / footer for the table */
3346 _fnBuildHead( settings );
3347 _fnDrawHead( settings, settings.aoHeader );
3348 _fnDrawHead( settings, settings.aoFooter );
3349
3350 /* Okay to show that something is going on now */
3351 _fnProcessingDisplay( settings, true );
3352
3353 /* Calculate sizes for columns */
3354 if ( features.bAutoWidth ) {
3355 _fnCalculateColumnWidths( settings );
3356 }
3357
3358 for ( i=0, iLen=columns.length ; i<iLen ; i++ ) {
3359 column = columns[i];
3360
3361 if ( column.sWidth ) {
3362 column.nTh.style.width = _fnStringToCss( column.sWidth );
3363 }
3364 }
3365
3366 _fnCallbackFire( settings, null, 'preInit', [settings] );
3367
3368 // If there is default sorting required - let's do it. The sort function
3369 // will do the drawing for us. Otherwise we draw the table regardless of the
3370 // Ajax source - this allows the table to look initialised for Ajax sourcing
3371 // data (show 'loading' message possibly)
3372 _fnReDraw( settings );
3373
3374 // Server-side processing init complete is done by _fnAjaxUpdateDraw
3375 var dataSrc = _fnDataSource( settings );
3376 if ( dataSrc != 'ssp' || deferLoading ) {
3377 // if there is an ajax source load the data
3378 if ( dataSrc == 'ajax' ) {
3379 _fnBuildAjax( settings, [], function(json) {
3380 var aData = _fnAjaxDataSrc( settings, json );
3381
3382 // Got the data - add it to the table
3383 for ( i=0 ; i<aData.length ; i++ ) {
3384 _fnAddData( settings, aData[i] );
3385 }
3386
3387 // Reset the init display for cookie saving. We've already done
3388 // a filter, and therefore cleared it before. So we need to make
3389 // it appear 'fresh'
3390 settings.iInitDisplayStart = iAjaxStart;
3391
3392 _fnReDraw( settings );
3393
3394 _fnProcessingDisplay( settings, false );
3395 _fnInitComplete( settings, json );
3396 }, settings );
3397 }
3398 else {
3399 _fnProcessingDisplay( settings, false );
3400 _fnInitComplete( settings );
3401 }
3402 }
3403 }
3404
3405
3406 /**
3407 * Draw the table for the first time, adding all required features
3408 * @param {object} oSettings dataTables settings object
3409 * @param {object} [json] JSON from the server that completed the table, if using Ajax source
3410 * with client-side processing (optional)
3411 * @memberof DataTable#oApi
3412 */
3413 function _fnInitComplete ( settings, json )
3414 {
3415 settings._bInitComplete = true;
3416
3417 // When data was added after the initialisation (data or Ajax) we need to
3418 // calculate the column sizing
3419 if ( json || settings.oInit.aaData ) {
3420 _fnAdjustColumnSizing( settings );
3421 }
3422
3423 _fnCallbackFire( settings, 'aoInitComplete', 'init', [settings, json] );
3424 }
3425
3426
3427 function _fnLengthChange ( settings, val )
3428 {
3429 var len = parseInt( val, 10 );
3430 settings._iDisplayLength = len;
3431
3432 _fnLengthOverflow( settings );
3433
3434 // Fire length change event
3435 _fnCallbackFire( settings, null, 'length', [settings, len] );
3436 }
3437
3438
3439 /**
3440 * Generate the node required for user display length changing
3441 * @param {object} settings dataTables settings object
3442 * @returns {node} Display length feature node
3443 * @memberof DataTable#oApi
3444 */
3445 function _fnFeatureHtmlLength ( settings )
3446 {
3447 var
3448 classes = settings.oClasses,
3449 tableId = settings.sTableId,
3450 menu = settings.aLengthMenu,
3451 d2 = $.isArray( menu[0] ),
3452 lengths = d2 ? menu[0] : menu,
3453 language = d2 ? menu[1] : menu;
3454
3455 var select = $('<select/>', {
3456 'name': tableId+'_length',
3457 'aria-controls': tableId,
3458 'class': classes.sLengthSelect
3459 } );
3460
3461 for ( var i=0, ien=lengths.length ; i<ien ; i++ ) {
3462 select[0][ i ] = new Option( language[i], lengths[i] );
3463 }
3464
3465 var div = $('<div><label/></div>').addClass( classes.sLength );
3466 if ( ! settings.aanFeatures.l ) {
3467 div[0].id = tableId+'_length';
3468 }
3469
3470 div.children().append(
3471 settings.oLanguage.sLengthMenu.replace( '_MENU_', select[0].outerHTML )
3472 );
3473
3474 // Can't use `select` variable as user might provide their own and the
3475 // reference is broken by the use of outerHTML
3476 $('select', div)
3477 .val( settings._iDisplayLength )
3478 .bind( 'change.DT', function(e) {
3479 _fnLengthChange( settings, $(this).val() );
3480 _fnDraw( settings );
3481 } );
3482
3483 // Update node value whenever anything changes the table's length
3484 $(settings.nTable).bind( 'length.dt.DT', function (e, s, len) {
3485 if ( settings === s ) {
3486 $('select', div).val( len );
3487 }
3488 } );
3489
3490 return div[0];
3491 }
3492
3493
3494
3495 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
3496 * Note that most of the paging logic is done in
3497 * DataTable.ext.pager
3498 */
3499
3500 /**
3501 * Generate the node required for default pagination
3502 * @param {object} oSettings dataTables settings object
3503 * @returns {node} Pagination feature node
3504 * @memberof DataTable#oApi
3505 */
3506 function _fnFeatureHtmlPaginate ( settings )
3507 {
3508 var
3509 type = settings.sPaginationType,
3510 plugin = DataTable.ext.pager[ type ],
3511 modern = typeof plugin === 'function',
3512 redraw = function( settings ) {
3513 _fnDraw( settings );
3514 },
3515 node = $('<div/>').addClass( settings.oClasses.sPaging + type )[0],
3516 features = settings.aanFeatures;
3517
3518 if ( ! modern ) {
3519 plugin.fnInit( settings, node, redraw );
3520 }
3521
3522 /* Add a draw callback for the pagination on first instance, to update the paging display */
3523 if ( ! features.p )
3524 {
3525 node.id = settings.sTableId+'_paginate';
3526
3527 settings.aoDrawCallback.push( {
3528 "fn": function( settings ) {
3529 if ( modern ) {
3530 var
3531 start = settings._iDisplayStart,
3532 len = settings._iDisplayLength,
3533 visRecords = settings.fnRecordsDisplay(),
3534 all = len === -1,
3535 page = all ? 0 : Math.ceil( start / len ),
3536 pages = all ? 1 : Math.ceil( visRecords / len ),
3537 buttons = plugin(page, pages),
3538 i, ien;
3539
3540 for ( i=0, ien=features.p.length ; i<ien ; i++ ) {
3541 _fnRenderer( settings, 'pageButton' )(
3542 settings, features.p[i], i, buttons, page, pages
3543 );
3544 }
3545 }
3546 else {
3547 plugin.fnUpdate( settings, redraw );
3548 }
3549 },
3550 "sName": "pagination"
3551 } );
3552 }
3553
3554 return node;
3555 }
3556
3557
3558 /**
3559 * Alter the display settings to change the page
3560 * @param {object} settings DataTables settings object
3561 * @param {string|int} action Paging action to take: "first", "previous",
3562 * "next" or "last" or page number to jump to (integer)
3563 * @param [bool] redraw Automatically draw the update or not
3564 * @returns {bool} true page has changed, false - no change
3565 * @memberof DataTable#oApi
3566 */
3567 function _fnPageChange ( settings, action, redraw )
3568 {
3569 var
3570 start = settings._iDisplayStart,
3571 len = settings._iDisplayLength,
3572 records = settings.fnRecordsDisplay();
3573
3574 if ( records === 0 || len === -1 )
3575 {
3576 start = 0;
3577 }
3578 else if ( typeof action === "number" )
3579 {
3580 start = action * len;
3581
3582 if ( start > records )
3583 {
3584 start = 0;
3585 }
3586 }
3587 else if ( action == "first" )
3588 {
3589 start = 0;
3590 }
3591 else if ( action == "previous" )
3592 {
3593 start = len >= 0 ?
3594 start - len :
3595 0;
3596
3597 if ( start < 0 )
3598 {
3599 start = 0;
3600 }
3601 }
3602 else if ( action == "next" )
3603 {
3604 if ( start + len < records )
3605 {
3606 start += len;
3607 }
3608 }
3609 else if ( action == "last" )
3610 {
3611 start = Math.floor( (records-1) / len) * len;
3612 }
3613 else
3614 {
3615 _fnLog( settings, 0, "Unknown paging action: "+action, 5 );
3616 }
3617
3618 var changed = settings._iDisplayStart !== start;
3619 settings._iDisplayStart = start;
3620
3621 if ( changed ) {
3622 _fnCallbackFire( settings, null, 'page', [settings] );
3623
3624 if ( redraw ) {
3625 _fnDraw( settings );
3626 }
3627 }
3628
3629 return changed;
3630 }
3631
3632
3633
3634 /**
3635 * Generate the node required for the processing node
3636 * @param {object} settings dataTables settings object
3637 * @returns {node} Processing element
3638 * @memberof DataTable#oApi
3639 */
3640 function _fnFeatureHtmlProcessing ( settings )
3641 {
3642 return $('<div/>', {
3643 'id': ! settings.aanFeatures.r ? settings.sTableId+'_processing' : null,
3644 'class': settings.oClasses.sProcessing
3645 } )
3646 .html( settings.oLanguage.sProcessing )
3647 .insertBefore( settings.nTable )[0];
3648 }
3649
3650
3651 /**
3652 * Display or hide the processing indicator
3653 * @param {object} settings dataTables settings object
3654 * @param {bool} show Show the processing indicator (true) or not (false)
3655 * @memberof DataTable#oApi
3656 */
3657 function _fnProcessingDisplay ( settings, show )
3658 {
3659 if ( settings.oFeatures.bProcessing ) {
3660 $(settings.aanFeatures.r).css( 'display', show ? 'block' : 'none' );
3661 }
3662
3663 _fnCallbackFire( settings, null, 'processing', [settings, show] );
3664 }
3665
3666 /**
3667 * Add any control elements for the table - specifically scrolling
3668 * @param {object} settings dataTables settings object
3669 * @returns {node} Node to add to the DOM
3670 * @memberof DataTable#oApi
3671 */
3672 function _fnFeatureHtmlTable ( settings )
3673 {
3674 var table = $(settings.nTable);
3675
3676 // Add the ARIA grid role to the table
3677 table.attr( 'role', 'grid' );
3678
3679 // Scrolling from here on in
3680 var scroll = settings.oScroll;
3681
3682 if ( scroll.sX === '' && scroll.sY === '' ) {
3683 return settings.nTable;
3684 }
3685
3686 var scrollX = scroll.sX;
3687 var scrollY = scroll.sY;
3688 var classes = settings.oClasses;
3689 var caption = table.children('caption');
3690 var captionSide = caption.length ? caption[0]._captionSide : null;
3691 var headerClone = $( table[0].cloneNode(false) );
3692 var footerClone = $( table[0].cloneNode(false) );
3693 var footer = table.children('tfoot');
3694 var _div = '<div/>';
3695 var size = function ( s ) {
3696 return !s ? null : _fnStringToCss( s );
3697 };
3698
3699 // This is fairly messy, but with x scrolling enabled, if the table has a
3700 // width attribute, regardless of any width applied using the column width
3701 // options, the browser will shrink or grow the table as needed to fit into
3702 // that 100%. That would make the width options useless. So we remove it.
3703 // This is okay, under the assumption that width:100% is applied to the
3704 // table in CSS (it is in the default stylesheet) which will set the table
3705 // width as appropriate (the attribute and css behave differently...)
3706 if ( scroll.sX && table.attr('width') === '100%' ) {
3707 table.removeAttr('width');
3708 }
3709
3710 if ( ! footer.length ) {
3711 footer = null;
3712 }
3713
3714 /*
3715 * The HTML structure that we want to generate in this function is:
3716 * div - scroller
3717 * div - scroll head
3718 * div - scroll head inner
3719 * table - scroll head table
3720 * thead - thead
3721 * div - scroll body
3722 * table - table (master table)
3723 * thead - thead clone for sizing
3724 * tbody - tbody
3725 * div - scroll foot
3726 * div - scroll foot inner
3727 * table - scroll foot table
3728 * tfoot - tfoot
3729 */
3730 var scroller = $( _div, { 'class': classes.sScrollWrapper } )
3731 .append(
3732 $(_div, { 'class': classes.sScrollHead } )
3733 .css( {
3734 overflow: 'hidden',
3735 position: 'relative',
3736 border: 0,
3737 width: scrollX ? size(scrollX) : '100%'
3738 } )
3739 .append(
3740 $(_div, { 'class': classes.sScrollHeadInner } )
3741 .css( {
3742 'box-sizing': 'content-box',
3743 width: scroll.sXInner || '100%'
3744 } )
3745 .append(
3746 headerClone
3747 .removeAttr('id')
3748 .css( 'margin-left', 0 )
3749 .append( captionSide === 'top' ? caption : null )
3750 .append(
3751 table.children('thead')
3752 )
3753 )
3754 )
3755 )
3756 .append(
3757 $(_div, { 'class': classes.sScrollBody } )
3758 .css( {
3759 position: 'relative',
3760 overflow: 'auto',
3761 width: size( scrollX )
3762 } )
3763 .append( table )
3764 );
3765
3766 if ( footer ) {
3767 scroller.append(
3768 $(_div, { 'class': classes.sScrollFoot } )
3769 .css( {
3770 overflow: 'hidden',
3771 border: 0,
3772 width: scrollX ? size(scrollX) : '100%'
3773 } )
3774 .append(
3775 $(_div, { 'class': classes.sScrollFootInner } )
3776 .append(
3777 footerClone
3778 .removeAttr('id')
3779 .css( 'margin-left', 0 )
3780 .append( captionSide === 'bottom' ? caption : null )
3781 .append(
3782 table.children('tfoot')
3783 )
3784 )
3785 )
3786 );
3787 }
3788
3789 var children = scroller.children();
3790 var scrollHead = children[0];
3791 var scrollBody = children[1];
3792 var scrollFoot = footer ? children[2] : null;
3793
3794 // When the body is scrolled, then we also want to scroll the headers
3795 if ( scrollX ) {
3796 $(scrollBody).on( 'scroll.DT', function (e) {
3797 var scrollLeft = this.scrollLeft;
3798
3799 scrollHead.scrollLeft = scrollLeft;
3800
3801 if ( footer ) {
3802 scrollFoot.scrollLeft = scrollLeft;
3803 }
3804 } );
3805 }
3806
3807 $(scrollBody).css(
3808 scrollY && scroll.bCollapse ? 'max-height' : 'height',
3809 scrollY
3810 );
3811
3812 settings.nScrollHead = scrollHead;
3813 settings.nScrollBody = scrollBody;
3814 settings.nScrollFoot = scrollFoot;
3815
3816 // On redraw - align columns
3817 settings.aoDrawCallback.push( {
3818 "fn": _fnScrollDraw,
3819 "sName": "scrolling"
3820 } );
3821
3822 return scroller[0];
3823 }
3824
3825
3826
3827 /**
3828 * Update the header, footer and body tables for resizing - i.e. column
3829 * alignment.
3830 *
3831 * Welcome to the most horrible function DataTables. The process that this
3832 * function follows is basically:
3833 * 1. Re-create the table inside the scrolling div
3834 * 2. Take live measurements from the DOM
3835 * 3. Apply the measurements to align the columns
3836 * 4. Clean up
3837 *
3838 * @param {object} settings dataTables settings object
3839 * @memberof DataTable#oApi
3840 */
3841 function _fnScrollDraw ( settings )
3842 {
3843 // Given that this is such a monster function, a lot of variables are use
3844 // to try and keep the minimised size as small as possible
3845 var
3846 scroll = settings.oScroll,
3847 scrollX = scroll.sX,
3848 scrollXInner = scroll.sXInner,
3849 scrollY = scroll.sY,
3850 barWidth = scroll.iBarWidth,
3851 divHeader = $(settings.nScrollHead),
3852 divHeaderStyle = divHeader[0].style,
3853 divHeaderInner = divHeader.children('div'),
3854 divHeaderInnerStyle = divHeaderInner[0].style,
3855 divHeaderTable = divHeaderInner.children('table'),
3856 divBodyEl = settings.nScrollBody,
3857 divBody = $(divBodyEl),
3858 divBodyStyle = divBodyEl.style,
3859 divFooter = $(settings.nScrollFoot),
3860 divFooterInner = divFooter.children('div'),
3861 divFooterTable = divFooterInner.children('table'),
3862 header = $(settings.nTHead),
3863 table = $(settings.nTable),
3864 tableEl = table[0],
3865 tableStyle = tableEl.style,
3866 footer = settings.nTFoot ? $(settings.nTFoot) : null,
3867 browser = settings.oBrowser,
3868 ie67 = browser.bScrollOversize,
3869 headerTrgEls, footerTrgEls,
3870 headerSrcEls, footerSrcEls,
3871 headerCopy, footerCopy,
3872 headerWidths=[], footerWidths=[],
3873 headerContent=[],
3874 idx, correction, sanityWidth,
3875 zeroOut = function(nSizer) {
3876 var style = nSizer.style;
3877 style.paddingTop = "0";
3878 style.paddingBottom = "0";
3879 style.borderTopWidth = "0";
3880 style.borderBottomWidth = "0";
3881 style.height = 0;
3882 };
3883
3884 /*
3885 * 1. Re-create the table inside the scrolling div
3886 */
3887
3888 // Remove the old minimised thead and tfoot elements in the inner table
3889 table.children('thead, tfoot').remove();
3890
3891 // Clone the current header and footer elements and then place it into the inner table
3892 headerCopy = header.clone().prependTo( table );
3893 headerTrgEls = header.find('tr'); // original header is in its own table
3894 headerSrcEls = headerCopy.find('tr');
3895 headerCopy.find('th, td').removeAttr('tabindex');
3896
3897 if ( footer ) {
3898 footerCopy = footer.clone().prependTo( table );
3899 footerTrgEls = footer.find('tr'); // the original tfoot is in its own table and must be sized
3900 footerSrcEls = footerCopy.find('tr');
3901 }
3902
3903
3904 /*
3905 * 2. Take live measurements from the DOM - do not alter the DOM itself!
3906 */
3907
3908 // Remove old sizing and apply the calculated column widths
3909 // Get the unique column headers in the newly created (cloned) header. We want to apply the
3910 // calculated sizes to this header
3911 if ( ! scrollX )
3912 {
3913 divBodyStyle.width = '100%';
3914 divHeader[0].style.width = '100%';
3915 }
3916
3917 $.each( _fnGetUniqueThs( settings, headerCopy ), function ( i, el ) {
3918 idx = _fnVisibleToColumnIndex( settings, i );
3919 el.style.width = settings.aoColumns[idx].sWidth;
3920 } );
3921
3922 if ( footer ) {
3923 _fnApplyToChildren( function(n) {
3924 n.style.width = "";
3925 }, footerSrcEls );
3926 }
3927
3928 // Size the table as a whole
3929 sanityWidth = table.outerWidth();
3930 if ( scrollX === "" ) {
3931 // No x scrolling
3932 tableStyle.width = "100%";
3933
3934 // IE7 will make the width of the table when 100% include the scrollbar
3935 // - which is shouldn't. When there is a scrollbar we need to take this
3936 // into account.
3937 if ( ie67 && (table.find('tbody').height() > divBodyEl.offsetHeight ||
3938 divBody.css('overflow-y') == "scroll")
3939 ) {
3940 tableStyle.width = _fnStringToCss( table.outerWidth() - barWidth);
3941 }
3942
3943 // Recalculate the sanity width
3944 sanityWidth = table.outerWidth();
3945 }
3946 else if ( scrollXInner !== "" ) {
3947 // legacy x scroll inner has been given - use it
3948 tableStyle.width = _fnStringToCss(scrollXInner);
3949
3950 // Recalculate the sanity width
3951 sanityWidth = table.outerWidth();
3952 }
3953
3954 // Hidden header should have zero height, so remove padding and borders. Then
3955 // set the width based on the real headers
3956
3957 // Apply all styles in one pass
3958 _fnApplyToChildren( zeroOut, headerSrcEls );
3959
3960 // Read all widths in next pass
3961 _fnApplyToChildren( function(nSizer) {
3962 headerContent.push( nSizer.innerHTML );
3963 headerWidths.push( _fnStringToCss( $(nSizer).css('width') ) );
3964 }, headerSrcEls );
3965
3966 // Apply all widths in final pass
3967 _fnApplyToChildren( function(nToSize, i) {
3968 nToSize.style.width = headerWidths[i];
3969 }, headerTrgEls );
3970
3971 $(headerSrcEls).height(0);
3972
3973 /* Same again with the footer if we have one */
3974 if ( footer )
3975 {
3976 _fnApplyToChildren( zeroOut, footerSrcEls );
3977
3978 _fnApplyToChildren( function(nSizer) {
3979 footerWidths.push( _fnStringToCss( $(nSizer).css('width') ) );
3980 }, footerSrcEls );
3981
3982 _fnApplyToChildren( function(nToSize, i) {
3983 nToSize.style.width = footerWidths[i];
3984 }, footerTrgEls );
3985
3986 $(footerSrcEls).height(0);
3987 }
3988
3989
3990 /*
3991 * 3. Apply the measurements
3992 */
3993
3994 // "Hide" the header and footer that we used for the sizing. We need to keep
3995 // the content of the cell so that the width applied to the header and body
3996 // both match, but we want to hide it completely. We want to also fix their
3997 // width to what they currently are
3998 _fnApplyToChildren( function(nSizer, i) {
3999 nSizer.innerHTML = '<div class="dataTables_sizing" style="height:0;overflow:hidden;">'+headerContent[i]+'</div>';
4000 nSizer.style.width = headerWidths[i];
4001 }, headerSrcEls );
4002
4003 if ( footer )
4004 {
4005 _fnApplyToChildren( function(nSizer, i) {
4006 nSizer.innerHTML = "";
4007 nSizer.style.width = footerWidths[i];
4008 }, footerSrcEls );
4009 }
4010
4011 // Sanity check that the table is of a sensible width. If not then we are going to get
4012 // misalignment - try to prevent this by not allowing the table to shrink below its min width
4013 if ( table.outerWidth() < sanityWidth )
4014 {
4015 // The min width depends upon if we have a vertical scrollbar visible or not */
4016 correction = ((divBodyEl.scrollHeight > divBodyEl.offsetHeight ||
4017 divBody.css('overflow-y') == "scroll")) ?
4018 sanityWidth+barWidth :
4019 sanityWidth;
4020
4021 // IE6/7 are a law unto themselves...
4022 if ( ie67 && (divBodyEl.scrollHeight >
4023 divBodyEl.offsetHeight || divBody.css('overflow-y') == "scroll")
4024 ) {
4025 tableStyle.width = _fnStringToCss( correction-barWidth );
4026 }
4027
4028 // And give the user a warning that we've stopped the table getting too small
4029 if ( scrollX === "" || scrollXInner !== "" ) {
4030 _fnLog( settings, 1, 'Possible column misalignment', 6 );
4031 }
4032 }
4033 else
4034 {
4035 correction = '100%';
4036 }
4037
4038 // Apply to the container elements
4039 divBodyStyle.width = _fnStringToCss( correction );
4040 divHeaderStyle.width = _fnStringToCss( correction );
4041
4042 if ( footer ) {
4043 settings.nScrollFoot.style.width = _fnStringToCss( correction );
4044 }
4045
4046
4047 /*
4048 * 4. Clean up
4049 */
4050 if ( ! scrollY ) {
4051 /* IE7< puts a vertical scrollbar in place (when it shouldn't be) due to subtracting
4052 * the scrollbar height from the visible display, rather than adding it on. We need to
4053 * set the height in order to sort this. Don't want to do it in any other browsers.
4054 */
4055 if ( ie67 ) {
4056 divBodyStyle.height = _fnStringToCss( tableEl.offsetHeight+barWidth );
4057 }
4058 }
4059
4060 /* Finally set the width's of the header and footer tables */
4061 var iOuterWidth = table.outerWidth();
4062 divHeaderTable[0].style.width = _fnStringToCss( iOuterWidth );
4063 divHeaderInnerStyle.width = _fnStringToCss( iOuterWidth );
4064
4065 // Figure out if there are scrollbar present - if so then we need a the header and footer to
4066 // provide a bit more space to allow "overflow" scrolling (i.e. past the scrollbar)
4067 var bScrolling = table.height() > divBodyEl.clientHeight || divBody.css('overflow-y') == "scroll";
4068 var padding = 'padding' + (browser.bScrollbarLeft ? 'Left' : 'Right' );
4069 divHeaderInnerStyle[ padding ] = bScrolling ? barWidth+"px" : "0px";
4070
4071 if ( footer ) {
4072 divFooterTable[0].style.width = _fnStringToCss( iOuterWidth );
4073 divFooterInner[0].style.width = _fnStringToCss( iOuterWidth );
4074 divFooterInner[0].style[padding] = bScrolling ? barWidth+"px" : "0px";
4075 }
4076
4077 /* Adjust the position of the header in case we loose the y-scrollbar */
4078 divBody.scroll();
4079
4080 // If sorting or filtering has occurred, jump the scrolling back to the top
4081 // only if we aren't holding the position
4082 if ( (settings.bSorted || settings.bFiltered) && ! settings._drawHold ) {
4083 divBodyEl.scrollTop = 0;
4084 }
4085 }
4086
4087
4088
4089 /**
4090 * Apply a given function to the display child nodes of an element array (typically
4091 * TD children of TR rows
4092 * @param {function} fn Method to apply to the objects
4093 * @param array {nodes} an1 List of elements to look through for display children
4094 * @param array {nodes} an2 Another list (identical structure to the first) - optional
4095 * @memberof DataTable#oApi
4096 */
4097 function _fnApplyToChildren( fn, an1, an2 )
4098 {
4099 var index=0, i=0, iLen=an1.length;
4100 var nNode1, nNode2;
4101
4102 while ( i < iLen ) {
4103 nNode1 = an1[i].firstChild;
4104 nNode2 = an2 ? an2[i].firstChild : null;
4105
4106 while ( nNode1 ) {
4107 if ( nNode1.nodeType === 1 ) {
4108 if ( an2 ) {
4109 fn( nNode1, nNode2, index );
4110 }
4111 else {
4112 fn( nNode1, index );
4113 }
4114
4115 index++;
4116 }
4117
4118 nNode1 = nNode1.nextSibling;
4119 nNode2 = an2 ? nNode2.nextSibling : null;
4120 }
4121
4122 i++;
4123 }
4124 }
4125
4126
4127
4128 var __re_html_remove = /<.*?>/g;
4129
4130
4131 /**
4132 * Calculate the width of columns for the table
4133 * @param {object} oSettings dataTables settings object
4134 * @memberof DataTable#oApi
4135 */
4136 function _fnCalculateColumnWidths ( oSettings )
4137 {
4138 var
4139 table = oSettings.nTable,
4140 columns = oSettings.aoColumns,
4141 scroll = oSettings.oScroll,
4142 scrollY = scroll.sY,
4143 scrollX = scroll.sX,
4144 scrollXInner = scroll.sXInner,
4145 columnCount = columns.length,
4146 visibleColumns = _fnGetColumns( oSettings, 'bVisible' ),
4147 headerCells = $('th', oSettings.nTHead),
4148 tableWidthAttr = table.getAttribute('width'), // from DOM element
4149 tableContainer = table.parentNode,
4150 userInputs = false,
4151 i, column, columnIdx, width, outerWidth,
4152 browser = oSettings.oBrowser,
4153 ie67 = browser.bScrollOversize;
4154
4155 var styleWidth = table.style.width;
4156 if ( styleWidth && styleWidth.indexOf('%') !== -1 ) {
4157 tableWidthAttr = styleWidth;
4158 }
4159
4160 /* Convert any user input sizes into pixel sizes */
4161 for ( i=0 ; i<visibleColumns.length ; i++ ) {
4162 column = columns[ visibleColumns[i] ];
4163
4164 if ( column.sWidth !== null ) {
4165 column.sWidth = _fnConvertToWidth( column.sWidthOrig, tableContainer );
4166
4167 userInputs = true;
4168 }
4169 }
4170
4171 /* If the number of columns in the DOM equals the number that we have to
4172 * process in DataTables, then we can use the offsets that are created by
4173 * the web- browser. No custom sizes can be set in order for this to happen,
4174 * nor scrolling used
4175 */
4176 if ( ie67 || ! userInputs && ! scrollX && ! scrollY &&
4177 columnCount == _fnVisbleColumns( oSettings ) &&
4178 columnCount == headerCells.length
4179 ) {
4180 for ( i=0 ; i<columnCount ; i++ ) {
4181 var colIdx = _fnVisibleToColumnIndex( oSettings, i );
4182
4183 if ( colIdx ) {
4184 columns[ colIdx ].sWidth = _fnStringToCss( headerCells.eq(i).width() );
4185 }
4186 }
4187 }
4188 else
4189 {
4190 // Otherwise construct a single row, worst case, table with the widest
4191 // node in the data, assign any user defined widths, then insert it into
4192 // the DOM and allow the browser to do all the hard work of calculating
4193 // table widths
4194 var tmpTable = $(table).clone() // don't use cloneNode - IE8 will remove events on the main table
4195 .css( 'visibility', 'hidden' )
4196 .removeAttr( 'id' );
4197
4198 // Clean up the table body
4199 tmpTable.find('tbody tr').remove();
4200 var tr = $('<tr/>').appendTo( tmpTable.find('tbody') );
4201
4202 // Clone the table header and footer - we can't use the header / footer
4203 // from the cloned table, since if scrolling is active, the table's
4204 // real header and footer are contained in different table tags
4205 tmpTable.find('thead, tfoot').remove();
4206 tmpTable
4207 .append( $(oSettings.nTHead).clone() )
4208 .append( $(oSettings.nTFoot).clone() );
4209
4210 // Remove any assigned widths from the footer (from scrolling)
4211 tmpTable.find('tfoot th, tfoot td').css('width', '');
4212
4213 // Apply custom sizing to the cloned header
4214 headerCells = _fnGetUniqueThs( oSettings, tmpTable.find('thead')[0] );
4215
4216 for ( i=0 ; i<visibleColumns.length ; i++ ) {
4217 column = columns[ visibleColumns[i] ];
4218
4219 headerCells[i].style.width = column.sWidthOrig !== null && column.sWidthOrig !== '' ?
4220 _fnStringToCss( column.sWidthOrig ) :
4221 '';
4222 }
4223
4224 // Find the widest cell for each column and put it into the table
4225 if ( oSettings.aoData.length ) {
4226 for ( i=0 ; i<visibleColumns.length ; i++ ) {
4227 columnIdx = visibleColumns[i];
4228 column = columns[ columnIdx ];
4229
4230 $( _fnGetWidestNode( oSettings, columnIdx ) )
4231 .clone( false )
4232 .append( column.sContentPadding )
4233 .appendTo( tr );
4234 }
4235 }
4236
4237 // Table has been built, attach to the document so we can work with it.
4238 // A holding element is used, positioned at the top of the container
4239 // with minimal height, so it has no effect on if the container scrolls
4240 // or not. Otherwise it might trigger scrolling when it actually isn't
4241 // needed
4242 var holder = $('<div/>').css( scrollX || scrollY ?
4243 {
4244 position: 'absolute',
4245 top: 0,
4246 left: 0,
4247 height: 1,
4248 right: 0,
4249 overflow: 'hidden'
4250 } :
4251 {}
4252 )
4253 .append( tmpTable )
4254 .appendTo( tableContainer );
4255
4256 // When scrolling (X or Y) we want to set the width of the table as
4257 // appropriate. However, when not scrolling leave the table width as it
4258 // is. This results in slightly different, but I think correct behaviour
4259 if ( scrollX && scrollXInner ) {
4260 tmpTable.width( scrollXInner );
4261 }
4262 else if ( scrollX ) {
4263 tmpTable.css( 'width', 'auto' );
4264
4265 if ( tmpTable.width() < tableContainer.clientWidth ) {
4266 tmpTable.width( tableContainer.clientWidth );
4267 }
4268 }
4269 else if ( scrollY ) {
4270 tmpTable.width( tableContainer.clientWidth );
4271 }
4272 else if ( tableWidthAttr ) {
4273 tmpTable.width( tableWidthAttr );
4274 }
4275
4276 // Browsers need a bit of a hand when a width is assigned to any columns
4277 // when x-scrolling as they tend to collapse the table to the min-width,
4278 // even if we sent the column widths. So we need to keep track of what
4279 // the table width should be by summing the user given values, and the
4280 // automatic values
4281 if ( scrollX )
4282 {
4283 var total = 0;
4284
4285 for ( i=0 ; i<visibleColumns.length ; i++ ) {
4286 column = columns[ visibleColumns[i] ];
4287
4288 // Much prefer to use getBoundingClientRect due to its sub-pixel
4289 // resolution, but IE8- do not support the width property.
4290 outerWidth = browser.bBounding ?
4291 headerCells[i].getBoundingClientRect().width :
4292 $(headerCells[i]).outerWidth();
4293
4294 total += column.sWidthOrig === null ?
4295 outerWidth :
4296 parseInt( column.sWidth, 10 ) + outerWidth - $(headerCells[i]).width();
4297 }
4298
4299 tmpTable.width( _fnStringToCss( total ) );
4300 table.style.width = _fnStringToCss( total );
4301 }
4302
4303 // Get the width of each column in the constructed table
4304 for ( i=0 ; i<visibleColumns.length ; i++ ) {
4305 column = columns[ visibleColumns[i] ];
4306 width = $(headerCells[i]).width();
4307
4308 if ( width ) {
4309 column.sWidth = _fnStringToCss( width );
4310 }
4311 }
4312
4313 table.style.width = _fnStringToCss( tmpTable.css('width') );
4314
4315 // Finished with the table - ditch it
4316 holder.remove();
4317 }
4318
4319 // If there is a width attr, we want to attach an event listener which
4320 // allows the table sizing to automatically adjust when the window is
4321 // resized. Use the width attr rather than CSS, since we can't know if the
4322 // CSS is a relative value or absolute - DOM read is always px.
4323 if ( tableWidthAttr ) {
4324 table.style.width = _fnStringToCss( tableWidthAttr );
4325 }
4326
4327 if ( (tableWidthAttr || scrollX) && ! oSettings._reszEvt ) {
4328 var bindResize = function () {
4329 $(window).bind('resize.DT-'+oSettings.sInstance, _fnThrottle( function () {
4330 _fnAdjustColumnSizing( oSettings );
4331 } ) );
4332 };
4333
4334 // IE6/7 will crash if we bind a resize event handler on page load.
4335 // To be removed in 1.11 which drops IE6/7 support
4336 if ( ie67 ) {
4337 setTimeout( bindResize, 1000 );
4338 }
4339 else {
4340 bindResize();
4341 }
4342
4343 oSettings._reszEvt = true;
4344 }
4345 }
4346
4347
4348 /**
4349 * Throttle the calls to a function. Arguments and context are maintained for
4350 * the throttled function
4351 * @param {function} fn Function to be called
4352 * @param {int} [freq=200] call frequency in mS
4353 * @returns {function} wrapped function
4354 * @memberof DataTable#oApi
4355 */
4356 function _fnThrottle( fn, freq ) {
4357 var
4358 frequency = freq !== undefined ? freq : 200,
4359 last,
4360 timer;
4361
4362 return function () {
4363 var
4364 that = this,
4365 now = +new Date(),
4366 args = arguments;
4367
4368 if ( last && now < last + frequency ) {
4369 clearTimeout( timer );
4370
4371 timer = setTimeout( function () {
4372 last = undefined;
4373 fn.apply( that, args );
4374 }, frequency );
4375 }
4376 else {
4377 last = now;
4378 fn.apply( that, args );
4379 }
4380 };
4381 }
4382
4383
4384 /**
4385 * Convert a CSS unit width to pixels (e.g. 2em)
4386 * @param {string} width width to be converted
4387 * @param {node} parent parent to get the with for (required for relative widths) - optional
4388 * @returns {int} width in pixels
4389 * @memberof DataTable#oApi
4390 */
4391 function _fnConvertToWidth ( width, parent )
4392 {
4393 if ( ! width ) {
4394 return 0;
4395 }
4396
4397 var n = $('<div/>')
4398 .css( 'width', _fnStringToCss( width ) )
4399 .appendTo( parent || document.body );
4400
4401 var val = n[0].offsetWidth;
4402 n.remove();
4403
4404 return val;
4405 }
4406
4407
4408 /**
4409 * Get the widest node
4410 * @param {object} settings dataTables settings object
4411 * @param {int} colIdx column of interest
4412 * @returns {node} widest table node
4413 * @memberof DataTable#oApi
4414 */
4415 function _fnGetWidestNode( settings, colIdx )
4416 {
4417 var idx = _fnGetMaxLenString( settings, colIdx );
4418 if ( idx < 0 ) {
4419 return null;
4420 }
4421
4422 var data = settings.aoData[ idx ];
4423 return ! data.nTr ? // Might not have been created when deferred rendering
4424 $('<td/>').html( _fnGetCellData( settings, idx, colIdx, 'display' ) )[0] :
4425 data.anCells[ colIdx ];
4426 }
4427
4428
4429 /**
4430 * Get the maximum strlen for each data column
4431 * @param {object} settings dataTables settings object
4432 * @param {int} colIdx column of interest
4433 * @returns {string} max string length for each column
4434 * @memberof DataTable#oApi
4435 */
4436 function _fnGetMaxLenString( settings, colIdx )
4437 {
4438 var s, max=-1, maxIdx = -1;
4439
4440 for ( var i=0, ien=settings.aoData.length ; i<ien ; i++ ) {
4441 s = _fnGetCellData( settings, i, colIdx, 'display' )+'';
4442 s = s.replace( __re_html_remove, '' );
4443
4444 if ( s.length > max ) {
4445 max = s.length;
4446 maxIdx = i;
4447 }
4448 }
4449
4450 return maxIdx;
4451 }
4452
4453
4454 /**
4455 * Append a CSS unit (only if required) to a string
4456 * @param {string} value to css-ify
4457 * @returns {string} value with css unit
4458 * @memberof DataTable#oApi
4459 */
4460 function _fnStringToCss( s )
4461 {
4462 if ( s === null ) {
4463 return '0px';
4464 }
4465
4466 if ( typeof s == 'number' ) {
4467 return s < 0 ?
4468 '0px' :
4469 s+'px';
4470 }
4471
4472 // Check it has a unit character already
4473 return s.match(/\d$/) ?
4474 s+'px' :
4475 s;
4476 }
4477
4478
4479
4480 function _fnSortFlatten ( settings )
4481 {
4482 var
4483 i, iLen, k, kLen,
4484 aSort = [],
4485 aiOrig = [],
4486 aoColumns = settings.aoColumns,
4487 aDataSort, iCol, sType, srcCol,
4488 fixed = settings.aaSortingFixed,
4489 fixedObj = $.isPlainObject( fixed ),
4490 nestedSort = [],
4491 add = function ( a ) {
4492 if ( a.length && ! $.isArray( a[0] ) ) {
4493 // 1D array
4494 nestedSort.push( a );
4495 }
4496 else {
4497 // 2D array
4498 $.merge( nestedSort, a );
4499 }
4500 };
4501
4502 // Build the sort array, with pre-fix and post-fix options if they have been
4503 // specified
4504 if ( $.isArray( fixed ) ) {
4505 add( fixed );
4506 }
4507
4508 if ( fixedObj && fixed.pre ) {
4509 add( fixed.pre );
4510 }
4511
4512 add( settings.aaSorting );
4513
4514 if (fixedObj && fixed.post ) {
4515 add( fixed.post );
4516 }
4517
4518 for ( i=0 ; i<nestedSort.length ; i++ )
4519 {
4520 srcCol = nestedSort[i][0];
4521 aDataSort = aoColumns[ srcCol ].aDataSort;
4522
4523 for ( k=0, kLen=aDataSort.length ; k<kLen ; k++ )
4524 {
4525 iCol = aDataSort[k];
4526 sType = aoColumns[ iCol ].sType || 'string';
4527
4528 if ( nestedSort[i]._idx === undefined ) {
4529 nestedSort[i]._idx = $.inArray( nestedSort[i][1], aoColumns[iCol].asSorting );
4530 }
4531
4532 aSort.push( {
4533 src: srcCol,
4534 col: iCol,
4535 dir: nestedSort[i][1],
4536 index: nestedSort[i]._idx,
4537 type: sType,
4538 formatter: DataTable.ext.type.order[ sType+"-pre" ]
4539 } );
4540 }
4541 }
4542
4543 return aSort;
4544 }
4545
4546 /**
4547 * Change the order of the table
4548 * @param {object} oSettings dataTables settings object
4549 * @memberof DataTable#oApi
4550 * @todo This really needs split up!
4551 */
4552 function _fnSort ( oSettings )
4553 {
4554 var
4555 i, ien, iLen, j, jLen, k, kLen,
4556 sDataType, nTh,
4557 aiOrig = [],
4558 oExtSort = DataTable.ext.type.order,
4559 aoData = oSettings.aoData,
4560 aoColumns = oSettings.aoColumns,
4561 aDataSort, data, iCol, sType, oSort,
4562 formatters = 0,
4563 sortCol,
4564 displayMaster = oSettings.aiDisplayMaster,
4565 aSort;
4566
4567 // Resolve any column types that are unknown due to addition or invalidation
4568 // @todo Can this be moved into a 'data-ready' handler which is called when
4569 // data is going to be used in the table?
4570 _fnColumnTypes( oSettings );
4571
4572 aSort = _fnSortFlatten( oSettings );
4573
4574 for ( i=0, ien=aSort.length ; i<ien ; i++ ) {
4575 sortCol = aSort[i];
4576
4577 // Track if we can use the fast sort algorithm
4578 if ( sortCol.formatter ) {
4579 formatters++;
4580 }
4581
4582 // Load the data needed for the sort, for each cell
4583 _fnSortData( oSettings, sortCol.col );
4584 }
4585
4586 /* No sorting required if server-side or no sorting array */
4587 if ( _fnDataSource( oSettings ) != 'ssp' && aSort.length !== 0 )
4588 {
4589 // Create a value - key array of the current row positions such that we can use their
4590 // current position during the sort, if values match, in order to perform stable sorting
4591 for ( i=0, iLen=displayMaster.length ; i<iLen ; i++ ) {
4592 aiOrig[ displayMaster[i] ] = i;
4593 }
4594
4595 /* Do the sort - here we want multi-column sorting based on a given data source (column)
4596 * and sorting function (from oSort) in a certain direction. It's reasonably complex to
4597 * follow on it's own, but this is what we want (example two column sorting):
4598 * fnLocalSorting = function(a,b){
4599 * var iTest;
4600 * iTest = oSort['string-asc']('data11', 'data12');
4601 * if (iTest !== 0)
4602 * return iTest;
4603 * iTest = oSort['numeric-desc']('data21', 'data22');
4604 * if (iTest !== 0)
4605 * return iTest;
4606 * return oSort['numeric-asc']( aiOrig[a], aiOrig[b] );
4607 * }
4608 * Basically we have a test for each sorting column, if the data in that column is equal,
4609 * test the next column. If all columns match, then we use a numeric sort on the row
4610 * positions in the original data array to provide a stable sort.
4611 *
4612 * Note - I know it seems excessive to have two sorting methods, but the first is around
4613 * 15% faster, so the second is only maintained for backwards compatibility with sorting
4614 * methods which do not have a pre-sort formatting function.
4615 */
4616 if ( formatters === aSort.length ) {
4617 // All sort types have formatting functions
4618 displayMaster.sort( function ( a, b ) {
4619 var
4620 x, y, k, test, sort,
4621 len=aSort.length,
4622 dataA = aoData[a]._aSortData,
4623 dataB = aoData[b]._aSortData;
4624
4625 for ( k=0 ; k<len ; k++ ) {
4626 sort = aSort[k];
4627
4628 x = dataA[ sort.col ];
4629 y = dataB[ sort.col ];
4630
4631 test = x<y ? -1 : x>y ? 1 : 0;
4632 if ( test !== 0 ) {
4633 return sort.dir === 'asc' ? test : -test;
4634 }
4635 }
4636
4637 x = aiOrig[a];
4638 y = aiOrig[b];
4639 return x<y ? -1 : x>y ? 1 : 0;
4640 } );
4641 }
4642 else {
4643 // Depreciated - remove in 1.11 (providing a plug-in option)
4644 // Not all sort types have formatting methods, so we have to call their sorting
4645 // methods.
4646 displayMaster.sort( function ( a, b ) {
4647 var
4648 x, y, k, l, test, sort, fn,
4649 len=aSort.length,
4650 dataA = aoData[a]._aSortData,
4651 dataB = aoData[b]._aSortData;
4652
4653 for ( k=0 ; k<len ; k++ ) {
4654 sort = aSort[k];
4655
4656 x = dataA[ sort.col ];
4657 y = dataB[ sort.col ];
4658
4659 fn = oExtSort[ sort.type+"-"+sort.dir ] || oExtSort[ "string-"+sort.dir ];
4660 test = fn( x, y );
4661 if ( test !== 0 ) {
4662 return test;
4663 }
4664 }
4665
4666 x = aiOrig[a];
4667 y = aiOrig[b];
4668 return x<y ? -1 : x>y ? 1 : 0;
4669 } );
4670 }
4671 }
4672
4673 /* Tell the draw function that we have sorted the data */
4674 oSettings.bSorted = true;
4675 }
4676
4677
4678 function _fnSortAria ( settings )
4679 {
4680 var label;
4681 var nextSort;
4682 var columns = settings.aoColumns;
4683 var aSort = _fnSortFlatten( settings );
4684 var oAria = settings.oLanguage.oAria;
4685
4686 // ARIA attributes - need to loop all columns, to update all (removing old
4687 // attributes as needed)
4688 for ( var i=0, iLen=columns.length ; i<iLen ; i++ )
4689 {
4690 var col = columns[i];
4691 var asSorting = col.asSorting;
4692 var sTitle = col.sTitle.replace( /<.*?>/g, "" );
4693 var th = col.nTh;
4694
4695 // IE7 is throwing an error when setting these properties with jQuery's
4696 // attr() and removeAttr() methods...
4697 th.removeAttribute('aria-sort');
4698
4699 /* In ARIA only the first sorting column can be marked as sorting - no multi-sort option */
4700 if ( col.bSortable ) {
4701 if ( aSort.length > 0 && aSort[0].col == i ) {
4702 th.setAttribute('aria-sort', aSort[0].dir=="asc" ? "ascending" : "descending" );
4703 nextSort = asSorting[ aSort[0].index+1 ] || asSorting[0];
4704 }
4705 else {
4706 nextSort = asSorting[0];
4707 }
4708
4709 label = sTitle + ( nextSort === "asc" ?
4710 oAria.sSortAscending :
4711 oAria.sSortDescending
4712 );
4713 }
4714 else {
4715 label = sTitle;
4716 }
4717
4718 th.setAttribute('aria-label', label);
4719 }
4720 }
4721
4722
4723 /**
4724 * Function to run on user sort request
4725 * @param {object} settings dataTables settings object
4726 * @param {node} attachTo node to attach the handler to
4727 * @param {int} colIdx column sorting index
4728 * @param {boolean} [append=false] Append the requested sort to the existing
4729 * sort if true (i.e. multi-column sort)
4730 * @param {function} [callback] callback function
4731 * @memberof DataTable#oApi
4732 */
4733 function _fnSortListener ( settings, colIdx, append, callback )
4734 {
4735 var col = settings.aoColumns[ colIdx ];
4736 var sorting = settings.aaSorting;
4737 var asSorting = col.asSorting;
4738 var nextSortIdx;
4739 var next = function ( a, overflow ) {
4740 var idx = a._idx;
4741 if ( idx === undefined ) {
4742 idx = $.inArray( a[1], asSorting );
4743 }
4744
4745 return idx+1 < asSorting.length ?
4746 idx+1 :
4747 overflow ?
4748 null :
4749 0;
4750 };
4751
4752 // Convert to 2D array if needed
4753 if ( typeof sorting[0] === 'number' ) {
4754 sorting = settings.aaSorting = [ sorting ];
4755 }
4756
4757 // If appending the sort then we are multi-column sorting
4758 if ( append && settings.oFeatures.bSortMulti ) {
4759 // Are we already doing some kind of sort on this column?
4760 var sortIdx = $.inArray( colIdx, _pluck(sorting, '0') );
4761
4762 if ( sortIdx !== -1 ) {
4763 // Yes, modify the sort
4764 nextSortIdx = next( sorting[sortIdx], true );
4765
4766 if ( nextSortIdx === null && sorting.length === 1 ) {
4767 nextSortIdx = 0; // can't remove sorting completely
4768 }
4769
4770 if ( nextSortIdx === null ) {
4771 sorting.splice( sortIdx, 1 );
4772 }
4773 else {
4774 sorting[sortIdx][1] = asSorting[ nextSortIdx ];
4775 sorting[sortIdx]._idx = nextSortIdx;
4776 }
4777 }
4778 else {
4779 // No sort on this column yet
4780 sorting.push( [ colIdx, asSorting[0], 0 ] );
4781 sorting[sorting.length-1]._idx = 0;
4782 }
4783 }
4784 else if ( sorting.length && sorting[0][0] == colIdx ) {
4785 // Single column - already sorting on this column, modify the sort
4786 nextSortIdx = next( sorting[0] );
4787
4788 sorting.length = 1;
4789 sorting[0][1] = asSorting[ nextSortIdx ];
4790 sorting[0]._idx = nextSortIdx;
4791 }
4792 else {
4793 // Single column - sort only on this column
4794 sorting.length = 0;
4795 sorting.push( [ colIdx, asSorting[0] ] );
4796 sorting[0]._idx = 0;
4797 }
4798
4799 // Run the sort by calling a full redraw
4800 _fnReDraw( settings );
4801
4802 // callback used for async user interaction
4803 if ( typeof callback == 'function' ) {
4804 callback( settings );
4805 }
4806 }
4807
4808
4809 /**
4810 * Attach a sort handler (click) to a node
4811 * @param {object} settings dataTables settings object
4812 * @param {node} attachTo node to attach the handler to
4813 * @param {int} colIdx column sorting index
4814 * @param {function} [callback] callback function
4815 * @memberof DataTable#oApi
4816 */
4817 function _fnSortAttachListener ( settings, attachTo, colIdx, callback )
4818 {
4819 var col = settings.aoColumns[ colIdx ];
4820
4821 _fnBindAction( attachTo, {}, function (e) {
4822 /* If the column is not sortable - don't to anything */
4823 if ( col.bSortable === false ) {
4824 return;
4825 }
4826
4827 // If processing is enabled use a timeout to allow the processing
4828 // display to be shown - otherwise to it synchronously
4829 if ( settings.oFeatures.bProcessing ) {
4830 _fnProcessingDisplay( settings, true );
4831
4832 setTimeout( function() {
4833 _fnSortListener( settings, colIdx, e.shiftKey, callback );
4834
4835 // In server-side processing, the draw callback will remove the
4836 // processing display
4837 if ( _fnDataSource( settings ) !== 'ssp' ) {
4838 _fnProcessingDisplay( settings, false );
4839 }
4840 }, 0 );
4841 }
4842 else {
4843 _fnSortListener( settings, colIdx, e.shiftKey, callback );
4844 }
4845 } );
4846 }
4847
4848
4849 /**
4850 * Set the sorting classes on table's body, Note: it is safe to call this function
4851 * when bSort and bSortClasses are false
4852 * @param {object} oSettings dataTables settings object
4853 * @memberof DataTable#oApi
4854 */
4855 function _fnSortingClasses( settings )
4856 {
4857 var oldSort = settings.aLastSort;
4858 var sortClass = settings.oClasses.sSortColumn;
4859 var sort = _fnSortFlatten( settings );
4860 var features = settings.oFeatures;
4861 var i, ien, colIdx;
4862
4863 if ( features.bSort && features.bSortClasses ) {
4864 // Remove old sorting classes
4865 for ( i=0, ien=oldSort.length ; i<ien ; i++ ) {
4866 colIdx = oldSort[i].src;
4867
4868 // Remove column sorting
4869 $( _pluck( settings.aoData, 'anCells', colIdx ) )
4870 .removeClass( sortClass + (i<2 ? i+1 : 3) );
4871 }
4872
4873 // Add new column sorting
4874 for ( i=0, ien=sort.length ; i<ien ; i++ ) {
4875 colIdx = sort[i].src;
4876
4877 $( _pluck( settings.aoData, 'anCells', colIdx ) )
4878 .addClass( sortClass + (i<2 ? i+1 : 3) );
4879 }
4880 }
4881
4882 settings.aLastSort = sort;
4883 }
4884
4885
4886 // Get the data to sort a column, be it from cache, fresh (populating the
4887 // cache), or from a sort formatter
4888 function _fnSortData( settings, idx )
4889 {
4890 // Custom sorting function - provided by the sort data type
4891 var column = settings.aoColumns[ idx ];
4892 var customSort = DataTable.ext.order[ column.sSortDataType ];
4893 var customData;
4894
4895 if ( customSort ) {
4896 customData = customSort.call( settings.oInstance, settings, idx,
4897 _fnColumnIndexToVisible( settings, idx )
4898 );
4899 }
4900
4901 // Use / populate cache
4902 var row, cellData;
4903 var formatter = DataTable.ext.type.order[ column.sType+"-pre" ];
4904
4905 for ( var i=0, ien=settings.aoData.length ; i<ien ; i++ ) {
4906 row = settings.aoData[i];
4907
4908 if ( ! row._aSortData ) {
4909 row._aSortData = [];
4910 }
4911
4912 if ( ! row._aSortData[idx] || customSort ) {
4913 cellData = customSort ?
4914 customData[i] : // If there was a custom sort function, use data from there
4915 _fnGetCellData( settings, i, idx, 'sort' );
4916
4917 row._aSortData[ idx ] = formatter ?
4918 formatter( cellData ) :
4919 cellData;
4920 }
4921 }
4922 }
4923
4924
4925
4926 /**
4927 * Save the state of a table
4928 * @param {object} oSettings dataTables settings object
4929 * @memberof DataTable#oApi
4930 */
4931 function _fnSaveState ( settings )
4932 {
4933 if ( !settings.oFeatures.bStateSave || settings.bDestroying )
4934 {
4935 return;
4936 }
4937
4938 /* Store the interesting variables */
4939 var state = {
4940 time: +new Date(),
4941 start: settings._iDisplayStart,
4942 length: settings._iDisplayLength,
4943 order: $.extend( true, [], settings.aaSorting ),
4944 search: _fnSearchToCamel( settings.oPreviousSearch ),
4945 columns: $.map( settings.aoColumns, function ( col, i ) {
4946 return {
4947 visible: col.bVisible,
4948 search: _fnSearchToCamel( settings.aoPreSearchCols[i] )
4949 };
4950 } )
4951 };
4952
4953 _fnCallbackFire( settings, "aoStateSaveParams", 'stateSaveParams', [settings, state] );
4954
4955 settings.oSavedState = state;
4956 settings.fnStateSaveCallback.call( settings.oInstance, settings, state );
4957 }
4958
4959
4960 /**
4961 * Attempt to load a saved table state
4962 * @param {object} oSettings dataTables settings object
4963 * @param {object} oInit DataTables init object so we can override settings
4964 * @memberof DataTable#oApi
4965 */
4966 function _fnLoadState ( settings, oInit )
4967 {
4968 var i, ien;
4969 var columns = settings.aoColumns;
4970
4971 if ( ! settings.oFeatures.bStateSave ) {
4972 return;
4973 }
4974
4975 var state = settings.fnStateLoadCallback.call( settings.oInstance, settings );
4976 if ( ! state || ! state.time ) {
4977 return;
4978 }
4979
4980 /* Allow custom and plug-in manipulation functions to alter the saved data set and
4981 * cancelling of loading by returning false
4982 */
4983 var abStateLoad = _fnCallbackFire( settings, 'aoStateLoadParams', 'stateLoadParams', [settings, state] );
4984 if ( $.inArray( false, abStateLoad ) !== -1 ) {
4985 return;
4986 }
4987
4988 /* Reject old data */
4989 var duration = settings.iStateDuration;
4990 if ( duration > 0 && state.time < +new Date() - (duration*1000) ) {
4991 return;
4992 }
4993
4994 // Number of columns have changed - all bets are off, no restore of settings
4995 if ( columns.length !== state.columns.length ) {
4996 return;
4997 }
4998
4999 // Store the saved state so it might be accessed at any time
5000 settings.oLoadedState = $.extend( true, {}, state );
5001
5002 // Restore key features - todo - for 1.11 this needs to be done by
5003 // subscribed events
5004 if ( state.start !== undefined ) {
5005 settings._iDisplayStart = state.start;
5006 settings.iInitDisplayStart = state.start;
5007 }
5008 if ( state.length !== undefined ) {
5009 settings._iDisplayLength = state.length;
5010 }
5011
5012 // Order
5013 if ( state.order !== undefined ) {
5014 settings.aaSorting = [];
5015 $.each( state.order, function ( i, col ) {
5016 settings.aaSorting.push( col[0] >= columns.length ?
5017 [ 0, col[1] ] :
5018 col
5019 );
5020 } );
5021 }
5022
5023 // Search
5024 if ( state.search !== undefined ) {
5025 $.extend( settings.oPreviousSearch, _fnSearchToHung( state.search ) );
5026 }
5027
5028 // Columns
5029 for ( i=0, ien=state.columns.length ; i<ien ; i++ ) {
5030 var col = state.columns[i];
5031
5032 // Visibility
5033 if ( col.visible !== undefined ) {
5034 columns[i].bVisible = col.visible;
5035 }
5036
5037 // Search
5038 if ( col.search !== undefined ) {
5039 $.extend( settings.aoPreSearchCols[i], _fnSearchToHung( col.search ) );
5040 }
5041 }
5042
5043 _fnCallbackFire( settings, 'aoStateLoaded', 'stateLoaded', [settings, state] );
5044 }
5045
5046
5047 /**
5048 * Return the settings object for a particular table
5049 * @param {node} table table we are using as a dataTable
5050 * @returns {object} Settings object - or null if not found
5051 * @memberof DataTable#oApi
5052 */
5053 function _fnSettingsFromNode ( table )
5054 {
5055 var settings = DataTable.settings;
5056 var idx = $.inArray( table, _pluck( settings, 'nTable' ) );
5057
5058 return idx !== -1 ?
5059 settings[ idx ] :
5060 null;
5061 }
5062
5063
5064 /**
5065 * Log an error message
5066 * @param {object} settings dataTables settings object
5067 * @param {int} level log error messages, or display them to the user
5068 * @param {string} msg error message
5069 * @param {int} tn Technical note id to get more information about the error.
5070 * @memberof DataTable#oApi
5071 */
5072 function _fnLog( settings, level, msg, tn )
5073 {
5074 msg = 'DataTables warning: '+
5075 (settings ? 'table id='+settings.sTableId+' - ' : '')+msg;
5076
5077 if ( tn ) {
5078 msg += '. For more information about this error, please see '+
5079 'http://datatables.net/tn/'+tn;
5080 }
5081
5082 if ( ! level ) {
5083 // Backwards compatibility pre 1.10
5084 var ext = DataTable.ext;
5085 var type = ext.sErrMode || ext.errMode;
5086
5087 if ( settings ) {
5088 _fnCallbackFire( settings, null, 'error', [ settings, tn, msg ] );
5089 }
5090
5091 if ( type == 'alert' ) {
5092 alert( msg );
5093 }
5094 else if ( type == 'throw' ) {
5095 throw new Error(msg);
5096 }
5097 else if ( typeof type == 'function' ) {
5098 type( settings, tn, msg );
5099 }
5100 }
5101 else if ( window.console && console.log ) {
5102 console.log( msg );
5103 }
5104 }
5105
5106
5107 /**
5108 * See if a property is defined on one object, if so assign it to the other object
5109 * @param {object} ret target object
5110 * @param {object} src source object
5111 * @param {string} name property
5112 * @param {string} [mappedName] name to map too - optional, name used if not given
5113 * @memberof DataTable#oApi
5114 */
5115 function _fnMap( ret, src, name, mappedName )
5116 {
5117 if ( $.isArray( name ) ) {
5118 $.each( name, function (i, val) {
5119 if ( $.isArray( val ) ) {
5120 _fnMap( ret, src, val[0], val[1] );
5121 }
5122 else {
5123 _fnMap( ret, src, val );
5124 }
5125 } );
5126
5127 return;
5128 }
5129
5130 if ( mappedName === undefined ) {
5131 mappedName = name;
5132 }
5133
5134 if ( src[name] !== undefined ) {
5135 ret[mappedName] = src[name];
5136 }
5137 }
5138
5139
5140 /**
5141 * Extend objects - very similar to jQuery.extend, but deep copy objects, and
5142 * shallow copy arrays. The reason we need to do this, is that we don't want to
5143 * deep copy array init values (such as aaSorting) since the dev wouldn't be
5144 * able to override them, but we do want to deep copy arrays.
5145 * @param {object} out Object to extend
5146 * @param {object} extender Object from which the properties will be applied to
5147 * out
5148 * @param {boolean} breakRefs If true, then arrays will be sliced to take an
5149 * independent copy with the exception of the `data` or `aaData` parameters
5150 * if they are present. This is so you can pass in a collection to
5151 * DataTables and have that used as your data source without breaking the
5152 * references
5153 * @returns {object} out Reference, just for convenience - out === the return.
5154 * @memberof DataTable#oApi
5155 * @todo This doesn't take account of arrays inside the deep copied objects.
5156 */
5157 function _fnExtend( out, extender, breakRefs )
5158 {
5159 var val;
5160
5161 for ( var prop in extender ) {
5162 if ( extender.hasOwnProperty(prop) ) {
5163 val = extender[prop];
5164
5165 if ( $.isPlainObject( val ) ) {
5166 if ( ! $.isPlainObject( out[prop] ) ) {
5167 out[prop] = {};
5168 }
5169 $.extend( true, out[prop], val );
5170 }
5171 else if ( breakRefs && prop !== 'data' && prop !== 'aaData' && $.isArray(val) ) {
5172 out[prop] = val.slice();
5173 }
5174 else {
5175 out[prop] = val;
5176 }
5177 }
5178 }
5179
5180 return out;
5181 }
5182
5183
5184 /**
5185 * Bind an event handers to allow a click or return key to activate the callback.
5186 * This is good for accessibility since a return on the keyboard will have the
5187 * same effect as a click, if the element has focus.
5188 * @param {element} n Element to bind the action to
5189 * @param {object} oData Data object to pass to the triggered function
5190 * @param {function} fn Callback function for when the event is triggered
5191 * @memberof DataTable#oApi
5192 */
5193 function _fnBindAction( n, oData, fn )
5194 {
5195 $(n)
5196 .bind( 'click.DT', oData, function (e) {
5197 n.blur(); // Remove focus outline for mouse users
5198 fn(e);
5199 } )
5200 .bind( 'keypress.DT', oData, function (e){
5201 if ( e.which === 13 ) {
5202 e.preventDefault();
5203 fn(e);
5204 }
5205 } )
5206 .bind( 'selectstart.DT', function () {
5207 /* Take the brutal approach to cancelling text selection */
5208 return false;
5209 } );
5210 }
5211
5212
5213 /**
5214 * Register a callback function. Easily allows a callback function to be added to
5215 * an array store of callback functions that can then all be called together.
5216 * @param {object} oSettings dataTables settings object
5217 * @param {string} sStore Name of the array storage for the callbacks in oSettings
5218 * @param {function} fn Function to be called back
5219 * @param {string} sName Identifying name for the callback (i.e. a label)
5220 * @memberof DataTable#oApi
5221 */
5222 function _fnCallbackReg( oSettings, sStore, fn, sName )
5223 {
5224 if ( fn )
5225 {
5226 oSettings[sStore].push( {
5227 "fn": fn,
5228 "sName": sName
5229 } );
5230 }
5231 }
5232
5233
5234 /**
5235 * Fire callback functions and trigger events. Note that the loop over the
5236 * callback array store is done backwards! Further note that you do not want to
5237 * fire off triggers in time sensitive applications (for example cell creation)
5238 * as its slow.
5239 * @param {object} settings dataTables settings object
5240 * @param {string} callbackArr Name of the array storage for the callbacks in
5241 * oSettings
5242 * @param {string} eventName Name of the jQuery custom event to trigger. If
5243 * null no trigger is fired
5244 * @param {array} args Array of arguments to pass to the callback function /
5245 * trigger
5246 * @memberof DataTable#oApi
5247 */
5248 function _fnCallbackFire( settings, callbackArr, eventName, args )
5249 {
5250 var ret = [];
5251
5252 if ( callbackArr ) {
5253 ret = $.map( settings[callbackArr].slice().reverse(), function (val, i) {
5254 return val.fn.apply( settings.oInstance, args );
5255 } );
5256 }
5257
5258 if ( eventName !== null ) {
5259 var e = $.Event( eventName+'.dt' );
5260
5261 $(settings.nTable).trigger( e, args );
5262
5263 ret.push( e.result );
5264 }
5265
5266 return ret;
5267 }
5268
5269
5270 function _fnLengthOverflow ( settings )
5271 {
5272 var
5273 start = settings._iDisplayStart,
5274 end = settings.fnDisplayEnd(),
5275 len = settings._iDisplayLength;
5276
5277 /* If we have space to show extra rows (backing up from the end point - then do so */
5278 if ( start >= end )
5279 {
5280 start = end - len;
5281 }
5282
5283 // Keep the start record on the current page
5284 start -= (start % len);
5285
5286 if ( len === -1 || start < 0 )
5287 {
5288 start = 0;
5289 }
5290
5291 settings._iDisplayStart = start;
5292 }
5293
5294
5295 function _fnRenderer( settings, type )
5296 {
5297 var renderer = settings.renderer;
5298 var host = DataTable.ext.renderer[type];
5299
5300 if ( $.isPlainObject( renderer ) && renderer[type] ) {
5301 // Specific renderer for this type. If available use it, otherwise use
5302 // the default.
5303 return host[renderer[type]] || host._;
5304 }
5305 else if ( typeof renderer === 'string' ) {
5306 // Common renderer - if there is one available for this type use it,
5307 // otherwise use the default
5308 return host[renderer] || host._;
5309 }
5310
5311 // Use the default
5312 return host._;
5313 }
5314
5315
5316 /**
5317 * Detect the data source being used for the table. Used to simplify the code
5318 * a little (ajax) and to make it compress a little smaller.
5319 *
5320 * @param {object} settings dataTables settings object
5321 * @returns {string} Data source
5322 * @memberof DataTable#oApi
5323 */
5324 function _fnDataSource ( settings )
5325 {
5326 if ( settings.oFeatures.bServerSide ) {
5327 return 'ssp';
5328 }
5329 else if ( settings.ajax || settings.sAjaxSource ) {
5330 return 'ajax';
5331 }
5332 return 'dom';
5333 }
5334
5335
5336 DataTable = function( options )
5337 {
5338 /**
5339 * Perform a jQuery selector action on the table's TR elements (from the tbody) and
5340 * return the resulting jQuery object.
5341 * @param {string|node|jQuery} sSelector jQuery selector or node collection to act on
5342 * @param {object} [oOpts] Optional parameters for modifying the rows to be included
5343 * @param {string} [oOpts.filter=none] Select TR elements that meet the current filter
5344 * criterion ("applied") or all TR elements (i.e. no filter).
5345 * @param {string} [oOpts.order=current] Order of the TR elements in the processed array.
5346 * Can be either 'current', whereby the current sorting of the table is used, or
5347 * 'original' whereby the original order the data was read into the table is used.
5348 * @param {string} [oOpts.page=all] Limit the selection to the currently displayed page
5349 * ("current") or not ("all"). If 'current' is given, then order is assumed to be
5350 * 'current' and filter is 'applied', regardless of what they might be given as.
5351 * @returns {object} jQuery object, filtered by the given selector.
5352 * @dtopt API
5353 * @deprecated Since v1.10
5354 *
5355 * @example
5356 * $(document).ready(function() {
5357 * var oTable = $('#example').dataTable();
5358 *
5359 * // Highlight every second row
5360 * oTable.$('tr:odd').css('backgroundColor', 'blue');
5361 * } );
5362 *
5363 * @example
5364 * $(document).ready(function() {
5365 * var oTable = $('#example').dataTable();
5366 *
5367 * // Filter to rows with 'Webkit' in them, add a background colour and then
5368 * // remove the filter, thus highlighting the 'Webkit' rows only.
5369 * oTable.fnFilter('Webkit');
5370 * oTable.$('tr', {"search": "applied"}).css('backgroundColor', 'blue');
5371 * oTable.fnFilter('');
5372 * } );
5373 */
5374 this.$ = function ( sSelector, oOpts )
5375 {
5376 return this.api(true).$( sSelector, oOpts );
5377 };
5378
5379
5380 /**
5381 * Almost identical to $ in operation, but in this case returns the data for the matched
5382 * rows - as such, the jQuery selector used should match TR row nodes or TD/TH cell nodes
5383 * rather than any descendants, so the data can be obtained for the row/cell. If matching
5384 * rows are found, the data returned is the original data array/object that was used to
5385 * create the row (or a generated array if from a DOM source).
5386 *
5387 * This method is often useful in-combination with $ where both functions are given the
5388 * same parameters and the array indexes will match identically.
5389 * @param {string|node|jQuery} sSelector jQuery selector or node collection to act on
5390 * @param {object} [oOpts] Optional parameters for modifying the rows to be included
5391 * @param {string} [oOpts.filter=none] Select elements that meet the current filter
5392 * criterion ("applied") or all elements (i.e. no filter).
5393 * @param {string} [oOpts.order=current] Order of the data in the processed array.
5394 * Can be either 'current', whereby the current sorting of the table is used, or
5395 * 'original' whereby the original order the data was read into the table is used.
5396 * @param {string} [oOpts.page=all] Limit the selection to the currently displayed page
5397 * ("current") or not ("all"). If 'current' is given, then order is assumed to be
5398 * 'current' and filter is 'applied', regardless of what they might be given as.
5399 * @returns {array} Data for the matched elements. If any elements, as a result of the
5400 * selector, were not TR, TD or TH elements in the DataTable, they will have a null
5401 * entry in the array.
5402 * @dtopt API
5403 * @deprecated Since v1.10
5404 *
5405 * @example
5406 * $(document).ready(function() {
5407 * var oTable = $('#example').dataTable();
5408 *
5409 * // Get the data from the first row in the table
5410 * var data = oTable._('tr:first');
5411 *
5412 * // Do something useful with the data
5413 * alert( "First cell is: "+data[0] );
5414 * } );
5415 *
5416 * @example
5417 * $(document).ready(function() {
5418 * var oTable = $('#example').dataTable();
5419 *
5420 * // Filter to 'Webkit' and get all data for
5421 * oTable.fnFilter('Webkit');
5422 * var data = oTable._('tr', {"search": "applied"});
5423 *
5424 * // Do something with the data
5425 * alert( data.length+" rows matched the search" );
5426 * } );
5427 */
5428 this._ = function ( sSelector, oOpts )
5429 {
5430 return this.api(true).rows( sSelector, oOpts ).data();
5431 };
5432
5433
5434 /**
5435 * Create a DataTables Api instance, with the currently selected tables for
5436 * the Api's context.
5437 * @param {boolean} [traditional=false] Set the API instance's context to be
5438 * only the table referred to by the `DataTable.ext.iApiIndex` option, as was
5439 * used in the API presented by DataTables 1.9- (i.e. the traditional mode),
5440 * or if all tables captured in the jQuery object should be used.
5441 * @return {DataTables.Api}
5442 */
5443 this.api = function ( traditional )
5444 {
5445 return traditional ?
5446 new _Api(
5447 _fnSettingsFromNode( this[ _ext.iApiIndex ] )
5448 ) :
5449 new _Api( this );
5450 };
5451
5452
5453 /**
5454 * Add a single new row or multiple rows of data to the table. Please note
5455 * that this is suitable for client-side processing only - if you are using
5456 * server-side processing (i.e. "bServerSide": true), then to add data, you
5457 * must add it to the data source, i.e. the server-side, through an Ajax call.
5458 * @param {array|object} data The data to be added to the table. This can be:
5459 * <ul>
5460 * <li>1D array of data - add a single row with the data provided</li>
5461 * <li>2D array of arrays - add multiple rows in a single call</li>
5462 * <li>object - data object when using <i>mData</i></li>
5463 * <li>array of objects - multiple data objects when using <i>mData</i></li>
5464 * </ul>
5465 * @param {bool} [redraw=true] redraw the table or not
5466 * @returns {array} An array of integers, representing the list of indexes in
5467 * <i>aoData</i> ({@link DataTable.models.oSettings}) that have been added to
5468 * the table.
5469 * @dtopt API
5470 * @deprecated Since v1.10
5471 *
5472 * @example
5473 * // Global var for counter
5474 * var giCount = 2;
5475 *
5476 * $(document).ready(function() {
5477 * $('#example').dataTable();
5478 * } );
5479 *
5480 * function fnClickAddRow() {
5481 * $('#example').dataTable().fnAddData( [
5482 * giCount+".1",
5483 * giCount+".2",
5484 * giCount+".3",
5485 * giCount+".4" ]
5486 * );
5487 *
5488 * giCount++;
5489 * }
5490 */
5491 this.fnAddData = function( data, redraw )
5492 {
5493 var api = this.api( true );
5494
5495 /* Check if we want to add multiple rows or not */
5496 var rows = $.isArray(data) && ( $.isArray(data[0]) || $.isPlainObject(data[0]) ) ?
5497 api.rows.add( data ) :
5498 api.row.add( data );
5499
5500 if ( redraw === undefined || redraw ) {
5501 api.draw();
5502 }
5503
5504 return rows.flatten().toArray();
5505 };
5506
5507
5508 /**
5509 * This function will make DataTables recalculate the column sizes, based on the data
5510 * contained in the table and the sizes applied to the columns (in the DOM, CSS or
5511 * through the sWidth parameter). This can be useful when the width of the table's
5512 * parent element changes (for example a window resize).
5513 * @param {boolean} [bRedraw=true] Redraw the table or not, you will typically want to
5514 * @dtopt API
5515 * @deprecated Since v1.10
5516 *
5517 * @example
5518 * $(document).ready(function() {
5519 * var oTable = $('#example').dataTable( {
5520 * "sScrollY": "200px",
5521 * "bPaginate": false
5522 * } );
5523 *
5524 * $(window).bind('resize', function () {
5525 * oTable.fnAdjustColumnSizing();
5526 * } );
5527 * } );
5528 */
5529 this.fnAdjustColumnSizing = function ( bRedraw )
5530 {
5531 var api = this.api( true ).columns.adjust();
5532 var settings = api.settings()[0];
5533 var scroll = settings.oScroll;
5534
5535 if ( bRedraw === undefined || bRedraw ) {
5536 api.draw( false );
5537 }
5538 else if ( scroll.sX !== "" || scroll.sY !== "" ) {
5539 /* If not redrawing, but scrolling, we want to apply the new column sizes anyway */
5540 _fnScrollDraw( settings );
5541 }
5542 };
5543
5544
5545 /**
5546 * Quickly and simply clear a table
5547 * @param {bool} [bRedraw=true] redraw the table or not
5548 * @dtopt API
5549 * @deprecated Since v1.10
5550 *
5551 * @example
5552 * $(document).ready(function() {
5553 * var oTable = $('#example').dataTable();
5554 *
5555 * // Immediately 'nuke' the current rows (perhaps waiting for an Ajax callback...)
5556 * oTable.fnClearTable();
5557 * } );
5558 */
5559 this.fnClearTable = function( bRedraw )
5560 {
5561 var api = this.api( true ).clear();
5562
5563 if ( bRedraw === undefined || bRedraw ) {
5564 api.draw();
5565 }
5566 };
5567
5568
5569 /**
5570 * The exact opposite of 'opening' a row, this function will close any rows which
5571 * are currently 'open'.
5572 * @param {node} nTr the table row to 'close'
5573 * @returns {int} 0 on success, or 1 if failed (can't find the row)
5574 * @dtopt API
5575 * @deprecated Since v1.10
5576 *
5577 * @example
5578 * $(document).ready(function() {
5579 * var oTable;
5580 *
5581 * // 'open' an information row when a row is clicked on
5582 * $('#example tbody tr').click( function () {
5583 * if ( oTable.fnIsOpen(this) ) {
5584 * oTable.fnClose( this );
5585 * } else {
5586 * oTable.fnOpen( this, "Temporary row opened", "info_row" );
5587 * }
5588 * } );
5589 *
5590 * oTable = $('#example').dataTable();
5591 * } );
5592 */
5593 this.fnClose = function( nTr )
5594 {
5595 this.api( true ).row( nTr ).child.hide();
5596 };
5597
5598
5599 /**
5600 * Remove a row for the table
5601 * @param {mixed} target The index of the row from aoData to be deleted, or
5602 * the TR element you want to delete
5603 * @param {function|null} [callBack] Callback function
5604 * @param {bool} [redraw=true] Redraw the table or not
5605 * @returns {array} The row that was deleted
5606 * @dtopt API
5607 * @deprecated Since v1.10
5608 *
5609 * @example
5610 * $(document).ready(function() {
5611 * var oTable = $('#example').dataTable();
5612 *
5613 * // Immediately remove the first row
5614 * oTable.fnDeleteRow( 0 );
5615 * } );
5616 */
5617 this.fnDeleteRow = function( target, callback, redraw )
5618 {
5619 var api = this.api( true );
5620 var rows = api.rows( target );
5621 var settings = rows.settings()[0];
5622 var data = settings.aoData[ rows[0][0] ];
5623
5624 rows.remove();
5625
5626 if ( callback ) {
5627 callback.call( this, settings, data );
5628 }
5629
5630 if ( redraw === undefined || redraw ) {
5631 api.draw();
5632 }
5633
5634 return data;
5635 };
5636
5637
5638 /**
5639 * Restore the table to it's original state in the DOM by removing all of DataTables
5640 * enhancements, alterations to the DOM structure of the table and event listeners.
5641 * @param {boolean} [remove=false] Completely remove the table from the DOM
5642 * @dtopt API
5643 * @deprecated Since v1.10
5644 *
5645 * @example
5646 * $(document).ready(function() {
5647 * // This example is fairly pointless in reality, but shows how fnDestroy can be used
5648 * var oTable = $('#example').dataTable();
5649 * oTable.fnDestroy();
5650 * } );
5651 */
5652 this.fnDestroy = function ( remove )
5653 {
5654 this.api( true ).destroy( remove );
5655 };
5656
5657
5658 /**
5659 * Redraw the table
5660 * @param {bool} [complete=true] Re-filter and resort (if enabled) the table before the draw.
5661 * @dtopt API
5662 * @deprecated Since v1.10
5663 *
5664 * @example
5665 * $(document).ready(function() {
5666 * var oTable = $('#example').dataTable();
5667 *
5668 * // Re-draw the table - you wouldn't want to do it here, but it's an example :-)
5669 * oTable.fnDraw();
5670 * } );
5671 */
5672 this.fnDraw = function( complete )
5673 {
5674 // Note that this isn't an exact match to the old call to _fnDraw - it takes
5675 // into account the new data, but can hold position.
5676 this.api( true ).draw( complete );
5677 };
5678
5679
5680 /**
5681 * Filter the input based on data
5682 * @param {string} sInput String to filter the table on
5683 * @param {int|null} [iColumn] Column to limit filtering to
5684 * @param {bool} [bRegex=false] Treat as regular expression or not
5685 * @param {bool} [bSmart=true] Perform smart filtering or not
5686 * @param {bool} [bShowGlobal=true] Show the input global filter in it's input box(es)
5687 * @param {bool} [bCaseInsensitive=true] Do case-insensitive matching (true) or not (false)
5688 * @dtopt API
5689 * @deprecated Since v1.10
5690 *
5691 * @example
5692 * $(document).ready(function() {
5693 * var oTable = $('#example').dataTable();
5694 *
5695 * // Sometime later - filter...
5696 * oTable.fnFilter( 'test string' );
5697 * } );
5698 */
5699 this.fnFilter = function( sInput, iColumn, bRegex, bSmart, bShowGlobal, bCaseInsensitive )
5700 {
5701 var api = this.api( true );
5702
5703 if ( iColumn === null || iColumn === undefined ) {
5704 api.search( sInput, bRegex, bSmart, bCaseInsensitive );
5705 }
5706 else {
5707 api.column( iColumn ).search( sInput, bRegex, bSmart, bCaseInsensitive );
5708 }
5709
5710 api.draw();
5711 };
5712
5713
5714 /**
5715 * Get the data for the whole table, an individual row or an individual cell based on the
5716 * provided parameters.
5717 * @param {int|node} [src] A TR row node, TD/TH cell node or an integer. If given as
5718 * a TR node then the data source for the whole row will be returned. If given as a
5719 * TD/TH cell node then iCol will be automatically calculated and the data for the
5720 * cell returned. If given as an integer, then this is treated as the aoData internal
5721 * data index for the row (see fnGetPosition) and the data for that row used.
5722 * @param {int} [col] Optional column index that you want the data of.
5723 * @returns {array|object|string} If mRow is undefined, then the data for all rows is
5724 * returned. If mRow is defined, just data for that row, and is iCol is
5725 * defined, only data for the designated cell is returned.
5726 * @dtopt API
5727 * @deprecated Since v1.10
5728 *
5729 * @example
5730 * // Row data
5731 * $(document).ready(function() {
5732 * oTable = $('#example').dataTable();
5733 *
5734 * oTable.$('tr').click( function () {
5735 * var data = oTable.fnGetData( this );
5736 * // ... do something with the array / object of data for the row
5737 * } );
5738 * } );
5739 *
5740 * @example
5741 * // Individual cell data
5742 * $(document).ready(function() {
5743 * oTable = $('#example').dataTable();
5744 *
5745 * oTable.$('td').click( function () {
5746 * var sData = oTable.fnGetData( this );
5747 * alert( 'The cell clicked on had the value of '+sData );
5748 * } );
5749 * } );
5750 */
5751 this.fnGetData = function( src, col )
5752 {
5753 var api = this.api( true );
5754
5755 if ( src !== undefined ) {
5756 var type = src.nodeName ? src.nodeName.toLowerCase() : '';
5757
5758 return col !== undefined || type == 'td' || type == 'th' ?
5759 api.cell( src, col ).data() :
5760 api.row( src ).data() || null;
5761 }
5762
5763 return api.data().toArray();
5764 };
5765
5766
5767 /**
5768 * Get an array of the TR nodes that are used in the table's body. Note that you will
5769 * typically want to use the '$' API method in preference to this as it is more
5770 * flexible.
5771 * @param {int} [iRow] Optional row index for the TR element you want
5772 * @returns {array|node} If iRow is undefined, returns an array of all TR elements
5773 * in the table's body, or iRow is defined, just the TR element requested.
5774 * @dtopt API
5775 * @deprecated Since v1.10
5776 *
5777 * @example
5778 * $(document).ready(function() {
5779 * var oTable = $('#example').dataTable();
5780 *
5781 * // Get the nodes from the table
5782 * var nNodes = oTable.fnGetNodes( );
5783 * } );
5784 */
5785 this.fnGetNodes = function( iRow )
5786 {
5787 var api = this.api( true );
5788
5789 return iRow !== undefined ?
5790 api.row( iRow ).node() :
5791 api.rows().nodes().flatten().toArray();
5792 };
5793
5794
5795 /**
5796 * Get the array indexes of a particular cell from it's DOM element
5797 * and column index including hidden columns
5798 * @param {node} node this can either be a TR, TD or TH in the table's body
5799 * @returns {int} If nNode is given as a TR, then a single index is returned, or
5800 * if given as a cell, an array of [row index, column index (visible),
5801 * column index (all)] is given.
5802 * @dtopt API
5803 * @deprecated Since v1.10
5804 *
5805 * @example
5806 * $(document).ready(function() {
5807 * $('#example tbody td').click( function () {
5808 * // Get the position of the current data from the node
5809 * var aPos = oTable.fnGetPosition( this );
5810 *
5811 * // Get the data array for this row
5812 * var aData = oTable.fnGetData( aPos[0] );
5813 *
5814 * // Update the data array and return the value
5815 * aData[ aPos[1] ] = 'clicked';
5816 * this.innerHTML = 'clicked';
5817 * } );
5818 *
5819 * // Init DataTables
5820 * oTable = $('#example').dataTable();
5821 * } );
5822 */
5823 this.fnGetPosition = function( node )
5824 {
5825 var api = this.api( true );
5826 var nodeName = node.nodeName.toUpperCase();
5827
5828 if ( nodeName == 'TR' ) {
5829 return api.row( node ).index();
5830 }
5831 else if ( nodeName == 'TD' || nodeName == 'TH' ) {
5832 var cell = api.cell( node ).index();
5833
5834 return [
5835 cell.row,
5836 cell.columnVisible,
5837 cell.column
5838 ];
5839 }
5840 return null;
5841 };
5842
5843
5844 /**
5845 * Check to see if a row is 'open' or not.
5846 * @param {node} nTr the table row to check
5847 * @returns {boolean} true if the row is currently open, false otherwise
5848 * @dtopt API
5849 * @deprecated Since v1.10
5850 *
5851 * @example
5852 * $(document).ready(function() {
5853 * var oTable;
5854 *
5855 * // 'open' an information row when a row is clicked on
5856 * $('#example tbody tr').click( function () {
5857 * if ( oTable.fnIsOpen(this) ) {
5858 * oTable.fnClose( this );
5859 * } else {
5860 * oTable.fnOpen( this, "Temporary row opened", "info_row" );
5861 * }
5862 * } );
5863 *
5864 * oTable = $('#example').dataTable();
5865 * } );
5866 */
5867 this.fnIsOpen = function( nTr )
5868 {
5869 return this.api( true ).row( nTr ).child.isShown();
5870 };
5871
5872
5873 /**
5874 * This function will place a new row directly after a row which is currently
5875 * on display on the page, with the HTML contents that is passed into the
5876 * function. This can be used, for example, to ask for confirmation that a
5877 * particular record should be deleted.
5878 * @param {node} nTr The table row to 'open'
5879 * @param {string|node|jQuery} mHtml The HTML to put into the row
5880 * @param {string} sClass Class to give the new TD cell
5881 * @returns {node} The row opened. Note that if the table row passed in as the
5882 * first parameter, is not found in the table, this method will silently
5883 * return.
5884 * @dtopt API
5885 * @deprecated Since v1.10
5886 *
5887 * @example
5888 * $(document).ready(function() {
5889 * var oTable;
5890 *
5891 * // 'open' an information row when a row is clicked on
5892 * $('#example tbody tr').click( function () {
5893 * if ( oTable.fnIsOpen(this) ) {
5894 * oTable.fnClose( this );
5895 * } else {
5896 * oTable.fnOpen( this, "Temporary row opened", "info_row" );
5897 * }
5898 * } );
5899 *
5900 * oTable = $('#example').dataTable();
5901 * } );
5902 */
5903 this.fnOpen = function( nTr, mHtml, sClass )
5904 {
5905 return this.api( true )
5906 .row( nTr )
5907 .child( mHtml, sClass )
5908 .show()
5909 .child()[0];
5910 };
5911
5912
5913 /**
5914 * Change the pagination - provides the internal logic for pagination in a simple API
5915 * function. With this function you can have a DataTables table go to the next,
5916 * previous, first or last pages.
5917 * @param {string|int} mAction Paging action to take: "first", "previous", "next" or "last"
5918 * or page number to jump to (integer), note that page 0 is the first page.
5919 * @param {bool} [bRedraw=true] Redraw the table or not
5920 * @dtopt API
5921 * @deprecated Since v1.10
5922 *
5923 * @example
5924 * $(document).ready(function() {
5925 * var oTable = $('#example').dataTable();
5926 * oTable.fnPageChange( 'next' );
5927 * } );
5928 */
5929 this.fnPageChange = function ( mAction, bRedraw )
5930 {
5931 var api = this.api( true ).page( mAction );
5932
5933 if ( bRedraw === undefined || bRedraw ) {
5934 api.draw(false);
5935 }
5936 };
5937
5938
5939 /**
5940 * Show a particular column
5941 * @param {int} iCol The column whose display should be changed
5942 * @param {bool} bShow Show (true) or hide (false) the column
5943 * @param {bool} [bRedraw=true] Redraw the table or not
5944 * @dtopt API
5945 * @deprecated Since v1.10
5946 *
5947 * @example
5948 * $(document).ready(function() {
5949 * var oTable = $('#example').dataTable();
5950 *
5951 * // Hide the second column after initialisation
5952 * oTable.fnSetColumnVis( 1, false );
5953 * } );
5954 */
5955 this.fnSetColumnVis = function ( iCol, bShow, bRedraw )
5956 {
5957 var api = this.api( true ).column( iCol ).visible( bShow );
5958
5959 if ( bRedraw === undefined || bRedraw ) {
5960 api.columns.adjust().draw();
5961 }
5962 };
5963
5964
5965 /**
5966 * Get the settings for a particular table for external manipulation
5967 * @returns {object} DataTables settings object. See
5968 * {@link DataTable.models.oSettings}
5969 * @dtopt API
5970 * @deprecated Since v1.10
5971 *
5972 * @example
5973 * $(document).ready(function() {
5974 * var oTable = $('#example').dataTable();
5975 * var oSettings = oTable.fnSettings();
5976 *
5977 * // Show an example parameter from the settings
5978 * alert( oSettings._iDisplayStart );
5979 * } );
5980 */
5981 this.fnSettings = function()
5982 {
5983 return _fnSettingsFromNode( this[_ext.iApiIndex] );
5984 };
5985
5986
5987 /**
5988 * Sort the table by a particular column
5989 * @param {int} iCol the data index to sort on. Note that this will not match the
5990 * 'display index' if you have hidden data entries
5991 * @dtopt API
5992 * @deprecated Since v1.10
5993 *
5994 * @example
5995 * $(document).ready(function() {
5996 * var oTable = $('#example').dataTable();
5997 *
5998 * // Sort immediately with columns 0 and 1
5999 * oTable.fnSort( [ [0,'asc'], [1,'asc'] ] );
6000 * } );
6001 */
6002 this.fnSort = function( aaSort )
6003 {
6004 this.api( true ).order( aaSort ).draw();
6005 };
6006
6007
6008 /**
6009 * Attach a sort listener to an element for a given column
6010 * @param {node} nNode the element to attach the sort listener to
6011 * @param {int} iColumn the column that a click on this node will sort on
6012 * @param {function} [fnCallback] callback function when sort is run
6013 * @dtopt API
6014 * @deprecated Since v1.10
6015 *
6016 * @example
6017 * $(document).ready(function() {
6018 * var oTable = $('#example').dataTable();
6019 *
6020 * // Sort on column 1, when 'sorter' is clicked on
6021 * oTable.fnSortListener( document.getElementById('sorter'), 1 );
6022 * } );
6023 */
6024 this.fnSortListener = function( nNode, iColumn, fnCallback )
6025 {
6026 this.api( true ).order.listener( nNode, iColumn, fnCallback );
6027 };
6028
6029
6030 /**
6031 * Update a table cell or row - this method will accept either a single value to
6032 * update the cell with, an array of values with one element for each column or
6033 * an object in the same format as the original data source. The function is
6034 * self-referencing in order to make the multi column updates easier.
6035 * @param {object|array|string} mData Data to update the cell/row with
6036 * @param {node|int} mRow TR element you want to update or the aoData index
6037 * @param {int} [iColumn] The column to update, give as null or undefined to
6038 * update a whole row.
6039 * @param {bool} [bRedraw=true] Redraw the table or not
6040 * @param {bool} [bAction=true] Perform pre-draw actions or not
6041 * @returns {int} 0 on success, 1 on error
6042 * @dtopt API
6043 * @deprecated Since v1.10
6044 *
6045 * @example
6046 * $(document).ready(function() {
6047 * var oTable = $('#example').dataTable();
6048 * oTable.fnUpdate( 'Example update', 0, 0 ); // Single cell
6049 * oTable.fnUpdate( ['a', 'b', 'c', 'd', 'e'], $('tbody tr')[0] ); // Row
6050 * } );
6051 */
6052 this.fnUpdate = function( mData, mRow, iColumn, bRedraw, bAction )
6053 {
6054 var api = this.api( true );
6055
6056 if ( iColumn === undefined || iColumn === null ) {
6057 api.row( mRow ).data( mData );
6058 }
6059 else {
6060 api.cell( mRow, iColumn ).data( mData );
6061 }
6062
6063 if ( bAction === undefined || bAction ) {
6064 api.columns.adjust();
6065 }
6066
6067 if ( bRedraw === undefined || bRedraw ) {
6068 api.draw();
6069 }
6070 return 0;
6071 };
6072
6073
6074 /**
6075 * Provide a common method for plug-ins to check the version of DataTables being used, in order
6076 * to ensure compatibility.
6077 * @param {string} sVersion Version string to check for, in the format "X.Y.Z". Note that the
6078 * formats "X" and "X.Y" are also acceptable.
6079 * @returns {boolean} true if this version of DataTables is greater or equal to the required
6080 * version, or false if this version of DataTales is not suitable
6081 * @method
6082 * @dtopt API
6083 * @deprecated Since v1.10
6084 *
6085 * @example
6086 * $(document).ready(function() {
6087 * var oTable = $('#example').dataTable();
6088 * alert( oTable.fnVersionCheck( '1.9.0' ) );
6089 * } );
6090 */
6091 this.fnVersionCheck = _ext.fnVersionCheck;
6092
6093
6094 var _that = this;
6095 var emptyInit = options === undefined;
6096 var len = this.length;
6097
6098 if ( emptyInit ) {
6099 options = {};
6100 }
6101
6102 this.oApi = this.internal = _ext.internal;
6103
6104 // Extend with old style plug-in API methods
6105 for ( var fn in DataTable.ext.internal ) {
6106 if ( fn ) {
6107 this[fn] = _fnExternApiFunc(fn);
6108 }
6109 }
6110
6111 this.each(function() {
6112 // For each initialisation we want to give it a clean initialisation
6113 // object that can be bashed around
6114 var o = {};
6115 var oInit = len > 1 ? // optimisation for single table case
6116 _fnExtend( o, options, true ) :
6117 options;
6118
6119 /*global oInit,_that,emptyInit*/
6120 var i=0, iLen, j, jLen, k, kLen;
6121 var sId = this.getAttribute( 'id' );
6122 var bInitHandedOff = false;
6123 var defaults = DataTable.defaults;
6124 var $this = $(this);
6125
6126
6127 /* Sanity check */
6128 if ( this.nodeName.toLowerCase() != 'table' )
6129 {
6130 _fnLog( null, 0, 'Non-table node initialisation ('+this.nodeName+')', 2 );
6131 return;
6132 }
6133
6134 /* Backwards compatibility for the defaults */
6135 _fnCompatOpts( defaults );
6136 _fnCompatCols( defaults.column );
6137
6138 /* Convert the camel-case defaults to Hungarian */
6139 _fnCamelToHungarian( defaults, defaults, true );
6140 _fnCamelToHungarian( defaults.column, defaults.column, true );
6141
6142 /* Setting up the initialisation object */
6143 _fnCamelToHungarian( defaults, $.extend( oInit, $this.data() ) );
6144
6145
6146
6147 /* Check to see if we are re-initialising a table */
6148 var allSettings = DataTable.settings;
6149 for ( i=0, iLen=allSettings.length ; i<iLen ; i++ )
6150 {
6151 var s = allSettings[i];
6152
6153 /* Base check on table node */
6154 if ( s.nTable == this || s.nTHead.parentNode == this || (s.nTFoot && s.nTFoot.parentNode == this) )
6155 {
6156 var bRetrieve = oInit.bRetrieve !== undefined ? oInit.bRetrieve : defaults.bRetrieve;
6157 var bDestroy = oInit.bDestroy !== undefined ? oInit.bDestroy : defaults.bDestroy;
6158
6159 if ( emptyInit || bRetrieve )
6160 {
6161 return s.oInstance;
6162 }
6163 else if ( bDestroy )
6164 {
6165 s.oInstance.fnDestroy();
6166 break;
6167 }
6168 else
6169 {
6170 _fnLog( s, 0, 'Cannot reinitialise DataTable', 3 );
6171 return;
6172 }
6173 }
6174
6175 /* If the element we are initialising has the same ID as a table which was previously
6176 * initialised, but the table nodes don't match (from before) then we destroy the old
6177 * instance by simply deleting it. This is under the assumption that the table has been
6178 * destroyed by other methods. Anyone using non-id selectors will need to do this manually
6179 */
6180 if ( s.sTableId == this.id )
6181 {
6182 allSettings.splice( i, 1 );
6183 break;
6184 }
6185 }
6186
6187 /* Ensure the table has an ID - required for accessibility */
6188 if ( sId === null || sId === "" )
6189 {
6190 sId = "DataTables_Table_"+(DataTable.ext._unique++);
6191 this.id = sId;
6192 }
6193
6194 /* Create the settings object for this table and set some of the default parameters */
6195 var oSettings = $.extend( true, {}, DataTable.models.oSettings, {
6196 "sDestroyWidth": $this[0].style.width,
6197 "sInstance": sId,
6198 "sTableId": sId
6199 } );
6200 oSettings.nTable = this;
6201 oSettings.oApi = _that.internal;
6202 oSettings.oInit = oInit;
6203
6204 allSettings.push( oSettings );
6205
6206 // Need to add the instance after the instance after the settings object has been added
6207 // to the settings array, so we can self reference the table instance if more than one
6208 oSettings.oInstance = (_that.length===1) ? _that : $this.dataTable();
6209
6210 // Backwards compatibility, before we apply all the defaults
6211 _fnCompatOpts( oInit );
6212
6213 if ( oInit.oLanguage )
6214 {
6215 _fnLanguageCompat( oInit.oLanguage );
6216 }
6217
6218 // If the length menu is given, but the init display length is not, use the length menu
6219 if ( oInit.aLengthMenu && ! oInit.iDisplayLength )
6220 {
6221 oInit.iDisplayLength = $.isArray( oInit.aLengthMenu[0] ) ?
6222 oInit.aLengthMenu[0][0] : oInit.aLengthMenu[0];
6223 }
6224
6225 // Apply the defaults and init options to make a single init object will all
6226 // options defined from defaults and instance options.
6227 oInit = _fnExtend( $.extend( true, {}, defaults ), oInit );
6228
6229
6230 // Map the initialisation options onto the settings object
6231 _fnMap( oSettings.oFeatures, oInit, [
6232 "bPaginate",
6233 "bLengthChange",
6234 "bFilter",
6235 "bSort",
6236 "bSortMulti",
6237 "bInfo",
6238 "bProcessing",
6239 "bAutoWidth",
6240 "bSortClasses",
6241 "bServerSide",
6242 "bDeferRender"
6243 ] );
6244 _fnMap( oSettings, oInit, [
6245 "asStripeClasses",
6246 "ajax",
6247 "fnServerData",
6248 "fnFormatNumber",
6249 "sServerMethod",
6250 "aaSorting",
6251 "aaSortingFixed",
6252 "aLengthMenu",
6253 "sPaginationType",
6254 "sAjaxSource",
6255 "sAjaxDataProp",
6256 "iStateDuration",
6257 "sDom",
6258 "bSortCellsTop",
6259 "iTabIndex",
6260 "fnStateLoadCallback",
6261 "fnStateSaveCallback",
6262 "renderer",
6263 "searchDelay",
6264 "rowId",
6265 [ "iCookieDuration", "iStateDuration" ], // backwards compat
6266 [ "oSearch", "oPreviousSearch" ],
6267 [ "aoSearchCols", "aoPreSearchCols" ],
6268 [ "iDisplayLength", "_iDisplayLength" ],
6269 [ "bJQueryUI", "bJUI" ]
6270 ] );
6271 _fnMap( oSettings.oScroll, oInit, [
6272 [ "sScrollX", "sX" ],
6273 [ "sScrollXInner", "sXInner" ],
6274 [ "sScrollY", "sY" ],
6275 [ "bScrollCollapse", "bCollapse" ]
6276 ] );
6277 _fnMap( oSettings.oLanguage, oInit, "fnInfoCallback" );
6278
6279 /* Callback functions which are array driven */
6280 _fnCallbackReg( oSettings, 'aoDrawCallback', oInit.fnDrawCallback, 'user' );
6281 _fnCallbackReg( oSettings, 'aoServerParams', oInit.fnServerParams, 'user' );
6282 _fnCallbackReg( oSettings, 'aoStateSaveParams', oInit.fnStateSaveParams, 'user' );
6283 _fnCallbackReg( oSettings, 'aoStateLoadParams', oInit.fnStateLoadParams, 'user' );
6284 _fnCallbackReg( oSettings, 'aoStateLoaded', oInit.fnStateLoaded, 'user' );
6285 _fnCallbackReg( oSettings, 'aoRowCallback', oInit.fnRowCallback, 'user' );
6286 _fnCallbackReg( oSettings, 'aoRowCreatedCallback', oInit.fnCreatedRow, 'user' );
6287 _fnCallbackReg( oSettings, 'aoHeaderCallback', oInit.fnHeaderCallback, 'user' );
6288 _fnCallbackReg( oSettings, 'aoFooterCallback', oInit.fnFooterCallback, 'user' );
6289 _fnCallbackReg( oSettings, 'aoInitComplete', oInit.fnInitComplete, 'user' );
6290 _fnCallbackReg( oSettings, 'aoPreDrawCallback', oInit.fnPreDrawCallback, 'user' );
6291
6292 oSettings.rowIdFn = _fnGetObjectDataFn( oInit.rowId );
6293
6294 /* Browser support detection */
6295 _fnBrowserDetect( oSettings );
6296
6297 var oClasses = oSettings.oClasses;
6298
6299 // @todo Remove in 1.11
6300 if ( oInit.bJQueryUI )
6301 {
6302 /* Use the JUI classes object for display. You could clone the oStdClasses object if
6303 * you want to have multiple tables with multiple independent classes
6304 */
6305 $.extend( oClasses, DataTable.ext.oJUIClasses, oInit.oClasses );
6306
6307 if ( oInit.sDom === defaults.sDom && defaults.sDom === "lfrtip" )
6308 {
6309 /* Set the DOM to use a layout suitable for jQuery UI's theming */
6310 oSettings.sDom = '<"H"lfr>t<"F"ip>';
6311 }
6312
6313 if ( ! oSettings.renderer ) {
6314 oSettings.renderer = 'jqueryui';
6315 }
6316 else if ( $.isPlainObject( oSettings.renderer ) && ! oSettings.renderer.header ) {
6317 oSettings.renderer.header = 'jqueryui';
6318 }
6319 }
6320 else
6321 {
6322 $.extend( oClasses, DataTable.ext.classes, oInit.oClasses );
6323 }
6324 $this.addClass( oClasses.sTable );
6325
6326
6327 if ( oSettings.iInitDisplayStart === undefined )
6328 {
6329 /* Display start point, taking into account the save saving */
6330 oSettings.iInitDisplayStart = oInit.iDisplayStart;
6331 oSettings._iDisplayStart = oInit.iDisplayStart;
6332 }
6333
6334 if ( oInit.iDeferLoading !== null )
6335 {
6336 oSettings.bDeferLoading = true;
6337 var tmp = $.isArray( oInit.iDeferLoading );
6338 oSettings._iRecordsDisplay = tmp ? oInit.iDeferLoading[0] : oInit.iDeferLoading;
6339 oSettings._iRecordsTotal = tmp ? oInit.iDeferLoading[1] : oInit.iDeferLoading;
6340 }
6341
6342 /* Language definitions */
6343 var oLanguage = oSettings.oLanguage;
6344 $.extend( true, oLanguage, oInit.oLanguage );
6345
6346 if ( oLanguage.sUrl !== "" )
6347 {
6348 /* Get the language definitions from a file - because this Ajax call makes the language
6349 * get async to the remainder of this function we use bInitHandedOff to indicate that
6350 * _fnInitialise will be fired by the returned Ajax handler, rather than the constructor
6351 */
6352 $.ajax( {
6353 dataType: 'json',
6354 url: oLanguage.sUrl,
6355 success: function ( json ) {
6356 _fnLanguageCompat( json );
6357 _fnCamelToHungarian( defaults.oLanguage, json );
6358 $.extend( true, oLanguage, json );
6359 _fnInitialise( oSettings );
6360 },
6361 error: function () {
6362 // Error occurred loading language file, continue on as best we can
6363 _fnInitialise( oSettings );
6364 }
6365 } );
6366 bInitHandedOff = true;
6367 }
6368
6369 /*
6370 * Stripes
6371 */
6372 if ( oInit.asStripeClasses === null )
6373 {
6374 oSettings.asStripeClasses =[
6375 oClasses.sStripeOdd,
6376 oClasses.sStripeEven
6377 ];
6378 }
6379
6380 /* Remove row stripe classes if they are already on the table row */
6381 var stripeClasses = oSettings.asStripeClasses;
6382 var rowOne = $this.children('tbody').find('tr').eq(0);
6383 if ( $.inArray( true, $.map( stripeClasses, function(el, i) {
6384 return rowOne.hasClass(el);
6385 } ) ) !== -1 ) {
6386 $('tbody tr', this).removeClass( stripeClasses.join(' ') );
6387 oSettings.asDestroyStripes = stripeClasses.slice();
6388 }
6389
6390 /*
6391 * Columns
6392 * See if we should load columns automatically or use defined ones
6393 */
6394 var anThs = [];
6395 var aoColumnsInit;
6396 var nThead = this.getElementsByTagName('thead');
6397 if ( nThead.length !== 0 )
6398 {
6399 _fnDetectHeader( oSettings.aoHeader, nThead[0] );
6400 anThs = _fnGetUniqueThs( oSettings );
6401 }
6402
6403 /* If not given a column array, generate one with nulls */
6404 if ( oInit.aoColumns === null )
6405 {
6406 aoColumnsInit = [];
6407 for ( i=0, iLen=anThs.length ; i<iLen ; i++ )
6408 {
6409 aoColumnsInit.push( null );
6410 }
6411 }
6412 else
6413 {
6414 aoColumnsInit = oInit.aoColumns;
6415 }
6416
6417 /* Add the columns */
6418 for ( i=0, iLen=aoColumnsInit.length ; i<iLen ; i++ )
6419 {
6420 _fnAddColumn( oSettings, anThs ? anThs[i] : null );
6421 }
6422
6423 /* Apply the column definitions */
6424 _fnApplyColumnDefs( oSettings, oInit.aoColumnDefs, aoColumnsInit, function (iCol, oDef) {
6425 _fnColumnOptions( oSettings, iCol, oDef );
6426 } );
6427
6428 /* HTML5 attribute detection - build an mData object automatically if the
6429 * attributes are found
6430 */
6431 if ( rowOne.length ) {
6432 var a = function ( cell, name ) {
6433 return cell.getAttribute( 'data-'+name ) !== null ? name : null;
6434 };
6435
6436 $( rowOne[0] ).children('th, td').each( function (i, cell) {
6437 var col = oSettings.aoColumns[i];
6438
6439 if ( col.mData === i ) {
6440 var sort = a( cell, 'sort' ) || a( cell, 'order' );
6441 var filter = a( cell, 'filter' ) || a( cell, 'search' );
6442
6443 if ( sort !== null || filter !== null ) {
6444 col.mData = {
6445 _: i+'.display',
6446 sort: sort !== null ? i+'.@data-'+sort : undefined,
6447 type: sort !== null ? i+'.@data-'+sort : undefined,
6448 filter: filter !== null ? i+'.@data-'+filter : undefined
6449 };
6450
6451 _fnColumnOptions( oSettings, i );
6452 }
6453 }
6454 } );
6455 }
6456
6457 var features = oSettings.oFeatures;
6458
6459 /* Must be done after everything which can be overridden by the state saving! */
6460 if ( oInit.bStateSave )
6461 {
6462 features.bStateSave = true;
6463 _fnLoadState( oSettings, oInit );
6464 _fnCallbackReg( oSettings, 'aoDrawCallback', _fnSaveState, 'state_save' );
6465 }
6466
6467
6468 /*
6469 * Sorting
6470 * @todo For modularisation (1.11) this needs to do into a sort start up handler
6471 */
6472
6473 // If aaSorting is not defined, then we use the first indicator in asSorting
6474 // in case that has been altered, so the default sort reflects that option
6475 if ( oInit.aaSorting === undefined )
6476 {
6477 var sorting = oSettings.aaSorting;
6478 for ( i=0, iLen=sorting.length ; i<iLen ; i++ )
6479 {
6480 sorting[i][1] = oSettings.aoColumns[ i ].asSorting[0];
6481 }
6482 }
6483
6484 /* Do a first pass on the sorting classes (allows any size changes to be taken into
6485 * account, and also will apply sorting disabled classes if disabled
6486 */
6487 _fnSortingClasses( oSettings );
6488
6489 if ( features.bSort )
6490 {
6491 _fnCallbackReg( oSettings, 'aoDrawCallback', function () {
6492 if ( oSettings.bSorted ) {
6493 var aSort = _fnSortFlatten( oSettings );
6494 var sortedColumns = {};
6495
6496 $.each( aSort, function (i, val) {
6497 sortedColumns[ val.src ] = val.dir;
6498 } );
6499
6500 _fnCallbackFire( oSettings, null, 'order', [oSettings, aSort, sortedColumns] );
6501 _fnSortAria( oSettings );
6502 }
6503 } );
6504 }
6505
6506 _fnCallbackReg( oSettings, 'aoDrawCallback', function () {
6507 if ( oSettings.bSorted || _fnDataSource( oSettings ) === 'ssp' || features.bDeferRender ) {
6508 _fnSortingClasses( oSettings );
6509 }
6510 }, 'sc' );
6511
6512
6513 /*
6514 * Final init
6515 * Cache the header, body and footer as required, creating them if needed
6516 */
6517
6518 // Work around for Webkit bug 83867 - store the caption-side before removing from doc
6519 var captions = $this.children('caption').each( function () {
6520 this._captionSide = $this.css('caption-side');
6521 } );
6522
6523 var thead = $this.children('thead');
6524 if ( thead.length === 0 )
6525 {
6526 thead = $('<thead/>').appendTo(this);
6527 }
6528 oSettings.nTHead = thead[0];
6529
6530 var tbody = $this.children('tbody');
6531 if ( tbody.length === 0 )
6532 {
6533 tbody = $('<tbody/>').appendTo(this);
6534 }
6535 oSettings.nTBody = tbody[0];
6536
6537 var tfoot = $this.children('tfoot');
6538 if ( tfoot.length === 0 && captions.length > 0 && (oSettings.oScroll.sX !== "" || oSettings.oScroll.sY !== "") )
6539 {
6540 // If we are a scrolling table, and no footer has been given, then we need to create
6541 // a tfoot element for the caption element to be appended to
6542 tfoot = $('<tfoot/>').appendTo(this);
6543 }
6544
6545 if ( tfoot.length === 0 || tfoot.children().length === 0 ) {
6546 $this.addClass( oClasses.sNoFooter );
6547 }
6548 else if ( tfoot.length > 0 ) {
6549 oSettings.nTFoot = tfoot[0];
6550 _fnDetectHeader( oSettings.aoFooter, oSettings.nTFoot );
6551 }
6552
6553 /* Check if there is data passing into the constructor */
6554 if ( oInit.aaData )
6555 {
6556 for ( i=0 ; i<oInit.aaData.length ; i++ )
6557 {
6558 _fnAddData( oSettings, oInit.aaData[ i ] );
6559 }
6560 }
6561 else if ( oSettings.bDeferLoading || _fnDataSource( oSettings ) == 'dom' )
6562 {
6563 /* Grab the data from the page - only do this when deferred loading or no Ajax
6564 * source since there is no point in reading the DOM data if we are then going
6565 * to replace it with Ajax data
6566 */
6567 _fnAddTr( oSettings, $(oSettings.nTBody).children('tr') );
6568 }
6569
6570 /* Copy the data index array */
6571 oSettings.aiDisplay = oSettings.aiDisplayMaster.slice();
6572
6573 /* Initialisation complete - table can be drawn */
6574 oSettings.bInitialised = true;
6575
6576 /* Check if we need to initialise the table (it might not have been handed off to the
6577 * language processor)
6578 */
6579 if ( bInitHandedOff === false )
6580 {
6581 _fnInitialise( oSettings );
6582 }
6583 } );
6584 _that = null;
6585 return this;
6586 };
6587
6588
6589
6590 /**
6591 * Computed structure of the DataTables API, defined by the options passed to
6592 * `DataTable.Api.register()` when building the API.
6593 *
6594 * The structure is built in order to speed creation and extension of the Api
6595 * objects since the extensions are effectively pre-parsed.
6596 *
6597 * The array is an array of objects with the following structure, where this
6598 * base array represents the Api prototype base:
6599 *
6600 * [
6601 * {
6602 * name: 'data' -- string - Property name
6603 * val: function () {}, -- function - Api method (or undefined if just an object
6604 * methodExt: [ ... ], -- array - Array of Api object definitions to extend the method result
6605 * propExt: [ ... ] -- array - Array of Api object definitions to extend the property
6606 * },
6607 * {
6608 * name: 'row'
6609 * val: {},
6610 * methodExt: [ ... ],
6611 * propExt: [
6612 * {
6613 * name: 'data'
6614 * val: function () {},
6615 * methodExt: [ ... ],
6616 * propExt: [ ... ]
6617 * },
6618 * ...
6619 * ]
6620 * }
6621 * ]
6622 *
6623 * @type {Array}
6624 * @ignore
6625 */
6626 var __apiStruct = [];
6627
6628
6629 /**
6630 * `Array.prototype` reference.
6631 *
6632 * @type object
6633 * @ignore
6634 */
6635 var __arrayProto = Array.prototype;
6636
6637
6638 /**
6639 * Abstraction for `context` parameter of the `Api` constructor to allow it to
6640 * take several different forms for ease of use.
6641 *
6642 * Each of the input parameter types will be converted to a DataTables settings
6643 * object where possible.
6644 *
6645 * @param {string|node|jQuery|object} mixed DataTable identifier. Can be one
6646 * of:
6647 *
6648 * * `string` - jQuery selector. Any DataTables' matching the given selector
6649 * with be found and used.
6650 * * `node` - `TABLE` node which has already been formed into a DataTable.
6651 * * `jQuery` - A jQuery object of `TABLE` nodes.
6652 * * `object` - DataTables settings object
6653 * * `DataTables.Api` - API instance
6654 * @return {array|null} Matching DataTables settings objects. `null` or
6655 * `undefined` is returned if no matching DataTable is found.
6656 * @ignore
6657 */
6658 var _toSettings = function ( mixed )
6659 {
6660 var idx, jq;
6661 var settings = DataTable.settings;
6662 var tables = $.map( settings, function (el, i) {
6663 return el.nTable;
6664 } );
6665
6666 if ( ! mixed ) {
6667 return [];
6668 }
6669 else if ( mixed.nTable && mixed.oApi ) {
6670 // DataTables settings object
6671 return [ mixed ];
6672 }
6673 else if ( mixed.nodeName && mixed.nodeName.toLowerCase() === 'table' ) {
6674 // Table node
6675 idx = $.inArray( mixed, tables );
6676 return idx !== -1 ? [ settings[idx] ] : null;
6677 }
6678 else if ( mixed && typeof mixed.settings === 'function' ) {
6679 return mixed.settings().toArray();
6680 }
6681 else if ( typeof mixed === 'string' ) {
6682 // jQuery selector
6683 jq = $(mixed);
6684 }
6685 else if ( mixed instanceof $ ) {
6686 // jQuery object (also DataTables instance)
6687 jq = mixed;
6688 }
6689
6690 if ( jq ) {
6691 return jq.map( function(i) {
6692 idx = $.inArray( this, tables );
6693 return idx !== -1 ? settings[idx] : null;
6694 } ).toArray();
6695 }
6696 };
6697
6698
6699 /**
6700 * DataTables API class - used to control and interface with one or more
6701 * DataTables enhanced tables.
6702 *
6703 * The API class is heavily based on jQuery, presenting a chainable interface
6704 * that you can use to interact with tables. Each instance of the API class has
6705 * a "context" - i.e. the tables that it will operate on. This could be a single
6706 * table, all tables on a page or a sub-set thereof.
6707 *
6708 * Additionally the API is designed to allow you to easily work with the data in
6709 * the tables, retrieving and manipulating it as required. This is done by
6710 * presenting the API class as an array like interface. The contents of the
6711 * array depend upon the actions requested by each method (for example
6712 * `rows().nodes()` will return an array of nodes, while `rows().data()` will
6713 * return an array of objects or arrays depending upon your table's
6714 * configuration). The API object has a number of array like methods (`push`,
6715 * `pop`, `reverse` etc) as well as additional helper methods (`each`, `pluck`,
6716 * `unique` etc) to assist your working with the data held in a table.
6717 *
6718 * Most methods (those which return an Api instance) are chainable, which means
6719 * the return from a method call also has all of the methods available that the
6720 * top level object had. For example, these two calls are equivalent:
6721 *
6722 * // Not chained
6723 * api.row.add( {...} );
6724 * api.draw();
6725 *
6726 * // Chained
6727 * api.row.add( {...} ).draw();
6728 *
6729 * @class DataTable.Api
6730 * @param {array|object|string|jQuery} context DataTable identifier. This is
6731 * used to define which DataTables enhanced tables this API will operate on.
6732 * Can be one of:
6733 *
6734 * * `string` - jQuery selector. Any DataTables' matching the given selector
6735 * with be found and used.
6736 * * `node` - `TABLE` node which has already been formed into a DataTable.
6737 * * `jQuery` - A jQuery object of `TABLE` nodes.
6738 * * `object` - DataTables settings object
6739 * @param {array} [data] Data to initialise the Api instance with.
6740 *
6741 * @example
6742 * // Direct initialisation during DataTables construction
6743 * var api = $('#example').DataTable();
6744 *
6745 * @example
6746 * // Initialisation using a DataTables jQuery object
6747 * var api = $('#example').dataTable().api();
6748 *
6749 * @example
6750 * // Initialisation as a constructor
6751 * var api = new $.fn.DataTable.Api( 'table.dataTable' );
6752 */
6753 _Api = function ( context, data )
6754 {
6755 if ( ! (this instanceof _Api) ) {
6756 return new _Api( context, data );
6757 }
6758
6759 var settings = [];
6760 var ctxSettings = function ( o ) {
6761 var a = _toSettings( o );
6762 if ( a ) {
6763 settings = settings.concat( a );
6764 }
6765 };
6766
6767 if ( $.isArray( context ) ) {
6768 for ( var i=0, ien=context.length ; i<ien ; i++ ) {
6769 ctxSettings( context[i] );
6770 }
6771 }
6772 else {
6773 ctxSettings( context );
6774 }
6775
6776 // Remove duplicates
6777 this.context = _unique( settings );
6778
6779 // Initial data
6780 if ( data ) {
6781 $.merge( this, data );
6782 }
6783
6784 // selector
6785 this.selector = {
6786 rows: null,
6787 cols: null,
6788 opts: null
6789 };
6790
6791 _Api.extend( this, this, __apiStruct );
6792 };
6793
6794 DataTable.Api = _Api;
6795
6796 // Don't destroy the existing prototype, just extend it. Required for jQuery 2's
6797 // isPlainObject.
6798 $.extend( _Api.prototype, {
6799 any: function ()
6800 {
6801 return this.count() !== 0;
6802 },
6803
6804
6805 concat: __arrayProto.concat,
6806
6807
6808 context: [], // array of table settings objects
6809
6810
6811 count: function ()
6812 {
6813 return this.flatten().length;
6814 },
6815
6816
6817 each: function ( fn )
6818 {
6819 for ( var i=0, ien=this.length ; i<ien; i++ ) {
6820 fn.call( this, this[i], i, this );
6821 }
6822
6823 return this;
6824 },
6825
6826
6827 eq: function ( idx )
6828 {
6829 var ctx = this.context;
6830
6831 return ctx.length > idx ?
6832 new _Api( ctx[idx], this[idx] ) :
6833 null;
6834 },
6835
6836
6837 filter: function ( fn )
6838 {
6839 var a = [];
6840
6841 if ( __arrayProto.filter ) {
6842 a = __arrayProto.filter.call( this, fn, this );
6843 }
6844 else {
6845 // Compatibility for browsers without EMCA-252-5 (JS 1.6)
6846 for ( var i=0, ien=this.length ; i<ien ; i++ ) {
6847 if ( fn.call( this, this[i], i, this ) ) {
6848 a.push( this[i] );
6849 }
6850 }
6851 }
6852
6853 return new _Api( this.context, a );
6854 },
6855
6856
6857 flatten: function ()
6858 {
6859 var a = [];
6860 return new _Api( this.context, a.concat.apply( a, this.toArray() ) );
6861 },
6862
6863
6864 join: __arrayProto.join,
6865
6866
6867 indexOf: __arrayProto.indexOf || function (obj, start)
6868 {
6869 for ( var i=(start || 0), ien=this.length ; i<ien ; i++ ) {
6870 if ( this[i] === obj ) {
6871 return i;
6872 }
6873 }
6874 return -1;
6875 },
6876
6877 iterator: function ( flatten, type, fn, alwaysNew ) {
6878 var
6879 a = [], ret,
6880 i, ien, j, jen,
6881 context = this.context,
6882 rows, items, item,
6883 selector = this.selector;
6884
6885 // Argument shifting
6886 if ( typeof flatten === 'string' ) {
6887 alwaysNew = fn;
6888 fn = type;
6889 type = flatten;
6890 flatten = false;
6891 }
6892
6893 for ( i=0, ien=context.length ; i<ien ; i++ ) {
6894 var apiInst = new _Api( context[i] );
6895
6896 if ( type === 'table' ) {
6897 ret = fn.call( apiInst, context[i], i );
6898
6899 if ( ret !== undefined ) {
6900 a.push( ret );
6901 }
6902 }
6903 else if ( type === 'columns' || type === 'rows' ) {
6904 // this has same length as context - one entry for each table
6905 ret = fn.call( apiInst, context[i], this[i], i );
6906
6907 if ( ret !== undefined ) {
6908 a.push( ret );
6909 }
6910 }
6911 else if ( type === 'column' || type === 'column-rows' || type === 'row' || type === 'cell' ) {
6912 // columns and rows share the same structure.
6913 // 'this' is an array of column indexes for each context
6914 items = this[i];
6915
6916 if ( type === 'column-rows' ) {
6917 rows = _selector_row_indexes( context[i], selector.opts );
6918 }
6919
6920 for ( j=0, jen=items.length ; j<jen ; j++ ) {
6921 item = items[j];
6922
6923 if ( type === 'cell' ) {
6924 ret = fn.call( apiInst, context[i], item.row, item.column, i, j );
6925 }
6926 else {
6927 ret = fn.call( apiInst, context[i], item, i, j, rows );
6928 }
6929
6930 if ( ret !== undefined ) {
6931 a.push( ret );
6932 }
6933 }
6934 }
6935 }
6936
6937 if ( a.length || alwaysNew ) {
6938 var api = new _Api( context, flatten ? a.concat.apply( [], a ) : a );
6939 var apiSelector = api.selector;
6940 apiSelector.rows = selector.rows;
6941 apiSelector.cols = selector.cols;
6942 apiSelector.opts = selector.opts;
6943 return api;
6944 }
6945 return this;
6946 },
6947
6948
6949 lastIndexOf: __arrayProto.lastIndexOf || function (obj, start)
6950 {
6951 // Bit cheeky...
6952 return this.indexOf.apply( this.toArray.reverse(), arguments );
6953 },
6954
6955
6956 length: 0,
6957
6958
6959 map: function ( fn )
6960 {
6961 var a = [];
6962
6963 if ( __arrayProto.map ) {
6964 a = __arrayProto.map.call( this, fn, this );
6965 }
6966 else {
6967 // Compatibility for browsers without EMCA-252-5 (JS 1.6)
6968 for ( var i=0, ien=this.length ; i<ien ; i++ ) {
6969 a.push( fn.call( this, this[i], i ) );
6970 }
6971 }
6972
6973 return new _Api( this.context, a );
6974 },
6975
6976
6977 pluck: function ( prop )
6978 {
6979 return this.map( function ( el ) {
6980 return el[ prop ];
6981 } );
6982 },
6983
6984 pop: __arrayProto.pop,
6985
6986
6987 push: __arrayProto.push,
6988
6989
6990 // Does not return an API instance
6991 reduce: __arrayProto.reduce || function ( fn, init )
6992 {
6993 return _fnReduce( this, fn, init, 0, this.length, 1 );
6994 },
6995
6996
6997 reduceRight: __arrayProto.reduceRight || function ( fn, init )
6998 {
6999 return _fnReduce( this, fn, init, this.length-1, -1, -1 );
7000 },
7001
7002
7003 reverse: __arrayProto.reverse,
7004
7005
7006 // Object with rows, columns and opts
7007 selector: null,
7008
7009
7010 shift: __arrayProto.shift,
7011
7012
7013 sort: __arrayProto.sort, // ? name - order?
7014
7015
7016 splice: __arrayProto.splice,
7017
7018
7019 toArray: function ()
7020 {
7021 return __arrayProto.slice.call( this );
7022 },
7023
7024
7025 to$: function ()
7026 {
7027 return $( this );
7028 },
7029
7030
7031 toJQuery: function ()
7032 {
7033 return $( this );
7034 },
7035
7036
7037 unique: function ()
7038 {
7039 return new _Api( this.context, _unique(this) );
7040 },
7041
7042
7043 unshift: __arrayProto.unshift
7044 } );
7045
7046
7047 _Api.extend = function ( scope, obj, ext )
7048 {
7049 // Only extend API instances and static properties of the API
7050 if ( ! ext.length || ! obj || ( ! (obj instanceof _Api) && ! obj.__dt_wrapper ) ) {
7051 return;
7052 }
7053
7054 var
7055 i, ien,
7056 j, jen,
7057 struct, inner,
7058 methodScoping = function ( scope, fn, struc ) {
7059 return function () {
7060 var ret = fn.apply( scope, arguments );
7061
7062 // Method extension
7063 _Api.extend( ret, ret, struc.methodExt );
7064 return ret;
7065 };
7066 };
7067
7068 for ( i=0, ien=ext.length ; i<ien ; i++ ) {
7069 struct = ext[i];
7070
7071 // Value
7072 obj[ struct.name ] = typeof struct.val === 'function' ?
7073 methodScoping( scope, struct.val, struct ) :
7074 $.isPlainObject( struct.val ) ?
7075 {} :
7076 struct.val;
7077
7078 obj[ struct.name ].__dt_wrapper = true;
7079
7080 // Property extension
7081 _Api.extend( scope, obj[ struct.name ], struct.propExt );
7082 }
7083 };
7084
7085
7086 // @todo - Is there need for an augment function?
7087 // _Api.augment = function ( inst, name )
7088 // {
7089 // // Find src object in the structure from the name
7090 // var parts = name.split('.');
7091
7092 // _Api.extend( inst, obj );
7093 // };
7094
7095
7096 // [
7097 // {
7098 // name: 'data' -- string - Property name
7099 // val: function () {}, -- function - Api method (or undefined if just an object
7100 // methodExt: [ ... ], -- array - Array of Api object definitions to extend the method result
7101 // propExt: [ ... ] -- array - Array of Api object definitions to extend the property
7102 // },
7103 // {
7104 // name: 'row'
7105 // val: {},
7106 // methodExt: [ ... ],
7107 // propExt: [
7108 // {
7109 // name: 'data'
7110 // val: function () {},
7111 // methodExt: [ ... ],
7112 // propExt: [ ... ]
7113 // },
7114 // ...
7115 // ]
7116 // }
7117 // ]
7118
7119 _Api.register = _api_register = function ( name, val )
7120 {
7121 if ( $.isArray( name ) ) {
7122 for ( var j=0, jen=name.length ; j<jen ; j++ ) {
7123 _Api.register( name[j], val );
7124 }
7125 return;
7126 }
7127
7128 var
7129 i, ien,
7130 heir = name.split('.'),
7131 struct = __apiStruct,
7132 key, method;
7133
7134 var find = function ( src, name ) {
7135 for ( var i=0, ien=src.length ; i<ien ; i++ ) {
7136 if ( src[i].name === name ) {
7137 return src[i];
7138 }
7139 }
7140 return null;
7141 };
7142
7143 for ( i=0, ien=heir.length ; i<ien ; i++ ) {
7144 method = heir[i].indexOf('()') !== -1;
7145 key = method ?
7146 heir[i].replace('()', '') :
7147 heir[i];
7148
7149 var src = find( struct, key );
7150 if ( ! src ) {
7151 src = {
7152 name: key,
7153 val: {},
7154 methodExt: [],
7155 propExt: []
7156 };
7157 struct.push( src );
7158 }
7159
7160 if ( i === ien-1 ) {
7161 src.val = val;
7162 }
7163 else {
7164 struct = method ?
7165 src.methodExt :
7166 src.propExt;
7167 }
7168 }
7169 };
7170
7171
7172 _Api.registerPlural = _api_registerPlural = function ( pluralName, singularName, val ) {
7173 _Api.register( pluralName, val );
7174
7175 _Api.register( singularName, function () {
7176 var ret = val.apply( this, arguments );
7177
7178 if ( ret === this ) {
7179 // Returned item is the API instance that was passed in, return it
7180 return this;
7181 }
7182 else if ( ret instanceof _Api ) {
7183 // New API instance returned, want the value from the first item
7184 // in the returned array for the singular result.
7185 return ret.length ?
7186 $.isArray( ret[0] ) ?
7187 new _Api( ret.context, ret[0] ) : // Array results are 'enhanced'
7188 ret[0] :
7189 undefined;
7190 }
7191
7192 // Non-API return - just fire it back
7193 return ret;
7194 } );
7195 };
7196
7197
7198 /**
7199 * Selector for HTML tables. Apply the given selector to the give array of
7200 * DataTables settings objects.
7201 *
7202 * @param {string|integer} [selector] jQuery selector string or integer
7203 * @param {array} Array of DataTables settings objects to be filtered
7204 * @return {array}
7205 * @ignore
7206 */
7207 var __table_selector = function ( selector, a )
7208 {
7209 // Integer is used to pick out a table by index
7210 if ( typeof selector === 'number' ) {
7211 return [ a[ selector ] ];
7212 }
7213
7214 // Perform a jQuery selector on the table nodes
7215 var nodes = $.map( a, function (el, i) {
7216 return el.nTable;
7217 } );
7218
7219 return $(nodes)
7220 .filter( selector )
7221 .map( function (i) {
7222 // Need to translate back from the table node to the settings
7223 var idx = $.inArray( this, nodes );
7224 return a[ idx ];
7225 } )
7226 .toArray();
7227 };
7228
7229
7230
7231 /**
7232 * Context selector for the API's context (i.e. the tables the API instance
7233 * refers to.
7234 *
7235 * @name DataTable.Api#tables
7236 * @param {string|integer} [selector] Selector to pick which tables the iterator
7237 * should operate on. If not given, all tables in the current context are
7238 * used. This can be given as a jQuery selector (for example `':gt(0)'`) to
7239 * select multiple tables or as an integer to select a single table.
7240 * @returns {DataTable.Api} Returns a new API instance if a selector is given.
7241 */
7242 _api_register( 'tables()', function ( selector ) {
7243 // A new instance is created if there was a selector specified
7244 return selector ?
7245 new _Api( __table_selector( selector, this.context ) ) :
7246 this;
7247 } );
7248
7249
7250 _api_register( 'table()', function ( selector ) {
7251 var tables = this.tables( selector );
7252 var ctx = tables.context;
7253
7254 // Truncate to the first matched table
7255 return ctx.length ?
7256 new _Api( ctx[0] ) :
7257 tables;
7258 } );
7259
7260
7261 _api_registerPlural( 'tables().nodes()', 'table().node()' , function () {
7262 return this.iterator( 'table', function ( ctx ) {
7263 return ctx.nTable;
7264 }, 1 );
7265 } );
7266
7267
7268 _api_registerPlural( 'tables().body()', 'table().body()' , function () {
7269 return this.iterator( 'table', function ( ctx ) {
7270 return ctx.nTBody;
7271 }, 1 );
7272 } );
7273
7274
7275 _api_registerPlural( 'tables().header()', 'table().header()' , function () {
7276 return this.iterator( 'table', function ( ctx ) {
7277 return ctx.nTHead;
7278 }, 1 );
7279 } );
7280
7281
7282 _api_registerPlural( 'tables().footer()', 'table().footer()' , function () {
7283 return this.iterator( 'table', function ( ctx ) {
7284 return ctx.nTFoot;
7285 }, 1 );
7286 } );
7287
7288
7289 _api_registerPlural( 'tables().containers()', 'table().container()' , function () {
7290 return this.iterator( 'table', function ( ctx ) {
7291 return ctx.nTableWrapper;
7292 }, 1 );
7293 } );
7294
7295
7296
7297 /**
7298 * Redraw the tables in the current context.
7299 */
7300 _api_register( 'draw()', function ( paging ) {
7301 return this.iterator( 'table', function ( settings ) {
7302 if ( paging === 'page' ) {
7303 _fnDraw( settings );
7304 }
7305 else {
7306 if ( typeof paging === 'string' ) {
7307 paging = paging === 'full-hold' ?
7308 false :
7309 true;
7310 }
7311
7312 _fnReDraw( settings, paging===false );
7313 }
7314 } );
7315 } );
7316
7317
7318
7319 /**
7320 * Get the current page index.
7321 *
7322 * @return {integer} Current page index (zero based)
7323 *//**
7324 * Set the current page.
7325 *
7326 * Note that if you attempt to show a page which does not exist, DataTables will
7327 * not throw an error, but rather reset the paging.
7328 *
7329 * @param {integer|string} action The paging action to take. This can be one of:
7330 * * `integer` - The page index to jump to
7331 * * `string` - An action to take:
7332 * * `first` - Jump to first page.
7333 * * `next` - Jump to the next page
7334 * * `previous` - Jump to previous page
7335 * * `last` - Jump to the last page.
7336 * @returns {DataTables.Api} this
7337 */
7338 _api_register( 'page()', function ( action ) {
7339 if ( action === undefined ) {
7340 return this.page.info().page; // not an expensive call
7341 }
7342
7343 // else, have an action to take on all tables
7344 return this.iterator( 'table', function ( settings ) {
7345 _fnPageChange( settings, action );
7346 } );
7347 } );
7348
7349
7350 /**
7351 * Paging information for the first table in the current context.
7352 *
7353 * If you require paging information for another table, use the `table()` method
7354 * with a suitable selector.
7355 *
7356 * @return {object} Object with the following properties set:
7357 * * `page` - Current page index (zero based - i.e. the first page is `0`)
7358 * * `pages` - Total number of pages
7359 * * `start` - Display index for the first record shown on the current page
7360 * * `end` - Display index for the last record shown on the current page
7361 * * `length` - Display length (number of records). Note that generally `start
7362 * + length = end`, but this is not always true, for example if there are
7363 * only 2 records to show on the final page, with a length of 10.
7364 * * `recordsTotal` - Full data set length
7365 * * `recordsDisplay` - Data set length once the current filtering criterion
7366 * are applied.
7367 */
7368 _api_register( 'page.info()', function ( action ) {
7369 if ( this.context.length === 0 ) {
7370 return undefined;
7371 }
7372
7373 var
7374 settings = this.context[0],
7375 start = settings._iDisplayStart,
7376 len = settings._iDisplayLength,
7377 visRecords = settings.fnRecordsDisplay(),
7378 all = len === -1;
7379
7380 return {
7381 "page": all ? 0 : Math.floor( start / len ),
7382 "pages": all ? 1 : Math.ceil( visRecords / len ),
7383 "start": start,
7384 "end": settings.fnDisplayEnd(),
7385 "length": len,
7386 "recordsTotal": settings.fnRecordsTotal(),
7387 "recordsDisplay": visRecords,
7388 "serverSide": _fnDataSource( settings ) === 'ssp'
7389 };
7390 } );
7391
7392
7393 /**
7394 * Get the current page length.
7395 *
7396 * @return {integer} Current page length. Note `-1` indicates that all records
7397 * are to be shown.
7398 *//**
7399 * Set the current page length.
7400 *
7401 * @param {integer} Page length to set. Use `-1` to show all records.
7402 * @returns {DataTables.Api} this
7403 */
7404 _api_register( 'page.len()', function ( len ) {
7405 // Note that we can't call this function 'length()' because `length`
7406 // is a Javascript property of functions which defines how many arguments
7407 // the function expects.
7408 if ( len === undefined ) {
7409 return this.context.length !== 0 ?
7410 this.context[0]._iDisplayLength :
7411 undefined;
7412 }
7413
7414 // else, set the page length
7415 return this.iterator( 'table', function ( settings ) {
7416 _fnLengthChange( settings, len );
7417 } );
7418 } );
7419
7420
7421
7422 var __reload = function ( settings, holdPosition, callback ) {
7423 // Use the draw event to trigger a callback
7424 if ( callback ) {
7425 var api = new _Api( settings );
7426
7427 api.one( 'draw', function () {
7428 callback( api.ajax.json() );
7429 } );
7430 }
7431
7432 if ( _fnDataSource( settings ) == 'ssp' ) {
7433 _fnReDraw( settings, holdPosition );
7434 }
7435 else {
7436 _fnProcessingDisplay( settings, true );
7437
7438 // Cancel an existing request
7439 var xhr = settings.jqXHR;
7440 if ( xhr && xhr.readyState !== 4 ) {
7441 xhr.abort();
7442 }
7443
7444 // Trigger xhr
7445 _fnBuildAjax( settings, [], function( json ) {
7446 _fnClearTable( settings );
7447
7448 var data = _fnAjaxDataSrc( settings, json );
7449 for ( var i=0, ien=data.length ; i<ien ; i++ ) {
7450 _fnAddData( settings, data[i] );
7451 }
7452
7453 _fnReDraw( settings, holdPosition );
7454 _fnProcessingDisplay( settings, false );
7455 } );
7456 }
7457 };
7458
7459
7460 /**
7461 * Get the JSON response from the last Ajax request that DataTables made to the
7462 * server. Note that this returns the JSON from the first table in the current
7463 * context.
7464 *
7465 * @return {object} JSON received from the server.
7466 */
7467 _api_register( 'ajax.json()', function () {
7468 var ctx = this.context;
7469
7470 if ( ctx.length > 0 ) {
7471 return ctx[0].json;
7472 }
7473
7474 // else return undefined;
7475 } );
7476
7477
7478 /**
7479 * Get the data submitted in the last Ajax request
7480 */
7481 _api_register( 'ajax.params()', function () {
7482 var ctx = this.context;
7483
7484 if ( ctx.length > 0 ) {
7485 return ctx[0].oAjaxData;
7486 }
7487
7488 // else return undefined;
7489 } );
7490
7491
7492 /**
7493 * Reload tables from the Ajax data source. Note that this function will
7494 * automatically re-draw the table when the remote data has been loaded.
7495 *
7496 * @param {boolean} [reset=true] Reset (default) or hold the current paging
7497 * position. A full re-sort and re-filter is performed when this method is
7498 * called, which is why the pagination reset is the default action.
7499 * @returns {DataTables.Api} this
7500 */
7501 _api_register( 'ajax.reload()', function ( callback, resetPaging ) {
7502 return this.iterator( 'table', function (settings) {
7503 __reload( settings, resetPaging===false, callback );
7504 } );
7505 } );
7506
7507
7508 /**
7509 * Get the current Ajax URL. Note that this returns the URL from the first
7510 * table in the current context.
7511 *
7512 * @return {string} Current Ajax source URL
7513 *//**
7514 * Set the Ajax URL. Note that this will set the URL for all tables in the
7515 * current context.
7516 *
7517 * @param {string} url URL to set.
7518 * @returns {DataTables.Api} this
7519 */
7520 _api_register( 'ajax.url()', function ( url ) {
7521 var ctx = this.context;
7522
7523 if ( url === undefined ) {
7524 // get
7525 if ( ctx.length === 0 ) {
7526 return undefined;
7527 }
7528 ctx = ctx[0];
7529
7530 return ctx.ajax ?
7531 $.isPlainObject( ctx.ajax ) ?
7532 ctx.ajax.url :
7533 ctx.ajax :
7534 ctx.sAjaxSource;
7535 }
7536
7537 // set
7538 return this.iterator( 'table', function ( settings ) {
7539 if ( $.isPlainObject( settings.ajax ) ) {
7540 settings.ajax.url = url;
7541 }
7542 else {
7543 settings.ajax = url;
7544 }
7545 // No need to consider sAjaxSource here since DataTables gives priority
7546 // to `ajax` over `sAjaxSource`. So setting `ajax` here, renders any
7547 // value of `sAjaxSource` redundant.
7548 } );
7549 } );
7550
7551
7552 /**
7553 * Load data from the newly set Ajax URL. Note that this method is only
7554 * available when `ajax.url()` is used to set a URL. Additionally, this method
7555 * has the same effect as calling `ajax.reload()` but is provided for
7556 * convenience when setting a new URL. Like `ajax.reload()` it will
7557 * automatically redraw the table once the remote data has been loaded.
7558 *
7559 * @returns {DataTables.Api} this
7560 */
7561 _api_register( 'ajax.url().load()', function ( callback, resetPaging ) {
7562 // Same as a reload, but makes sense to present it for easy access after a
7563 // url change
7564 return this.iterator( 'table', function ( ctx ) {
7565 __reload( ctx, resetPaging===false, callback );
7566 } );
7567 } );
7568
7569
7570
7571
7572 var _selector_run = function ( type, selector, selectFn, settings, opts )
7573 {
7574 var
7575 out = [], res,
7576 a, i, ien, j, jen,
7577 selectorType = typeof selector;
7578
7579 // Can't just check for isArray here, as an API or jQuery instance might be
7580 // given with their array like look
7581 if ( ! selector || selectorType === 'string' || selectorType === 'function' || selector.length === undefined ) {
7582 selector = [ selector ];
7583 }
7584
7585 for ( i=0, ien=selector.length ; i<ien ; i++ ) {
7586 a = selector[i] && selector[i].split ?
7587 selector[i].split(',') :
7588 [ selector[i] ];
7589
7590 for ( j=0, jen=a.length ; j<jen ; j++ ) {
7591 res = selectFn( typeof a[j] === 'string' ? $.trim(a[j]) : a[j] );
7592
7593 if ( res && res.length ) {
7594 out = out.concat( res );
7595 }
7596 }
7597 }
7598
7599 // selector extensions
7600 var ext = _ext.selector[ type ];
7601 if ( ext.length ) {
7602 for ( i=0, ien=ext.length ; i<ien ; i++ ) {
7603 out = ext[i]( settings, opts, out );
7604 }
7605 }
7606
7607 return _unique( out );
7608 };
7609
7610
7611 var _selector_opts = function ( opts )
7612 {
7613 if ( ! opts ) {
7614 opts = {};
7615 }
7616
7617 // Backwards compatibility for 1.9- which used the terminology filter rather
7618 // than search
7619 if ( opts.filter && opts.search === undefined ) {
7620 opts.search = opts.filter;
7621 }
7622
7623 return $.extend( {
7624 search: 'none',
7625 order: 'current',
7626 page: 'all'
7627 }, opts );
7628 };
7629
7630
7631 var _selector_first = function ( inst )
7632 {
7633 // Reduce the API instance to the first item found
7634 for ( var i=0, ien=inst.length ; i<ien ; i++ ) {
7635 if ( inst[i].length > 0 ) {
7636 // Assign the first element to the first item in the instance
7637 // and truncate the instance and context
7638 inst[0] = inst[i];
7639 inst[0].length = 1;
7640 inst.length = 1;
7641 inst.context = [ inst.context[i] ];
7642
7643 return inst;
7644 }
7645 }
7646
7647 // Not found - return an empty instance
7648 inst.length = 0;
7649 return inst;
7650 };
7651
7652
7653 var _selector_row_indexes = function ( settings, opts )
7654 {
7655 var
7656 i, ien, tmp, a=[],
7657 displayFiltered = settings.aiDisplay,
7658 displayMaster = settings.aiDisplayMaster;
7659
7660 var
7661 search = opts.search, // none, applied, removed
7662 order = opts.order, // applied, current, index (original - compatibility with 1.9)
7663 page = opts.page; // all, current
7664
7665 if ( _fnDataSource( settings ) == 'ssp' ) {
7666 // In server-side processing mode, most options are irrelevant since
7667 // rows not shown don't exist and the index order is the applied order
7668 // Removed is a special case - for consistency just return an empty
7669 // array
7670 return search === 'removed' ?
7671 [] :
7672 _range( 0, displayMaster.length );
7673 }
7674 else if ( page == 'current' ) {
7675 // Current page implies that order=current and fitler=applied, since it is
7676 // fairly senseless otherwise, regardless of what order and search actually
7677 // are
7678 for ( i=settings._iDisplayStart, ien=settings.fnDisplayEnd() ; i<ien ; i++ ) {
7679 a.push( displayFiltered[i] );
7680 }
7681 }
7682 else if ( order == 'current' || order == 'applied' ) {
7683 a = search == 'none' ?
7684 displayMaster.slice() : // no search
7685 search == 'applied' ?
7686 displayFiltered.slice() : // applied search
7687 $.map( displayMaster, function (el, i) { // removed search
7688 return $.inArray( el, displayFiltered ) === -1 ? el : null;
7689 } );
7690 }
7691 else if ( order == 'index' || order == 'original' ) {
7692 for ( i=0, ien=settings.aoData.length ; i<ien ; i++ ) {
7693 if ( search == 'none' ) {
7694 a.push( i );
7695 }
7696 else { // applied | removed
7697 tmp = $.inArray( i, displayFiltered );
7698
7699 if ((tmp === -1 && search == 'removed') ||
7700 (tmp >= 0 && search == 'applied') )
7701 {
7702 a.push( i );
7703 }
7704 }
7705 }
7706 }
7707
7708 return a;
7709 };
7710
7711
7712 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
7713 * Rows
7714 *
7715 * {} - no selector - use all available rows
7716 * {integer} - row aoData index
7717 * {node} - TR node
7718 * {string} - jQuery selector to apply to the TR elements
7719 * {array} - jQuery array of nodes, or simply an array of TR nodes
7720 *
7721 */
7722
7723
7724 var __row_selector = function ( settings, selector, opts )
7725 {
7726 var run = function ( sel ) {
7727 var selInt = _intVal( sel );
7728 var i, ien;
7729
7730 // Short cut - selector is a number and no options provided (default is
7731 // all records, so no need to check if the index is in there, since it
7732 // must be - dev error if the index doesn't exist).
7733 if ( selInt !== null && ! opts ) {
7734 return [ selInt ];
7735 }
7736
7737 var rows = _selector_row_indexes( settings, opts );
7738
7739 if ( selInt !== null && $.inArray( selInt, rows ) !== -1 ) {
7740 // Selector - integer
7741 return [ selInt ];
7742 }
7743 else if ( ! sel ) {
7744 // Selector - none
7745 return rows;
7746 }
7747
7748 // Selector - function
7749 if ( typeof sel === 'function' ) {
7750 return $.map( rows, function (idx) {
7751 var row = settings.aoData[ idx ];
7752 return sel( idx, row._aData, row.nTr ) ? idx : null;
7753 } );
7754 }
7755
7756 // Get nodes in the order from the `rows` array with null values removed
7757 var nodes = _removeEmpty(
7758 _pluck_order( settings.aoData, rows, 'nTr' )
7759 );
7760
7761 // Selector - node
7762 if ( sel.nodeName ) {
7763 if ( $.inArray( sel, nodes ) !== -1 ) {
7764 return [ sel._DT_RowIndex ]; // sel is a TR node that is in the table
7765 // and DataTables adds a prop for fast lookup
7766 }
7767 }
7768
7769 // ID selector. Want to always be able to select rows by id, regardless
7770 // of if the tr element has been created or not, so can't rely upon
7771 // jQuery here - hence a custom implementation. This does not match
7772 // Sizzle's fast selector or HTML4 - in HTML5 the ID can be anything,
7773 // but to select it using a CSS selector engine (like Sizzle or
7774 // querySelect) it would need to need to be escaped for some characters.
7775 // DataTables simplifies this for row selectors since you can select
7776 // only a row. A # indicates an id any anything that follows is the id -
7777 // unescaped.
7778 if ( typeof sel === 'string' && sel.charAt(0) === '#' ) {
7779 // get row index from id
7780 var rowObj = settings.aIds[ sel.replace( /^#/, '' ) ];
7781 if ( rowObj !== undefined ) {
7782 return [ rowObj.idx ];
7783 }
7784
7785 // need to fall through to jQuery in case there is DOM id that
7786 // matches
7787 }
7788
7789 // Selector - jQuery selector string, array of nodes or jQuery object/
7790 // As jQuery's .filter() allows jQuery objects to be passed in filter,
7791 // it also allows arrays, so this will cope with all three options
7792 return $(nodes)
7793 .filter( sel )
7794 .map( function () {
7795 return this._DT_RowIndex;
7796 } )
7797 .toArray();
7798 };
7799
7800 return _selector_run( 'row', selector, run, settings, opts );
7801 };
7802
7803
7804 _api_register( 'rows()', function ( selector, opts ) {
7805 // argument shifting
7806 if ( selector === undefined ) {
7807 selector = '';
7808 }
7809 else if ( $.isPlainObject( selector ) ) {
7810 opts = selector;
7811 selector = '';
7812 }
7813
7814 opts = _selector_opts( opts );
7815
7816 var inst = this.iterator( 'table', function ( settings ) {
7817 return __row_selector( settings, selector, opts );
7818 }, 1 );
7819
7820 // Want argument shifting here and in __row_selector?
7821 inst.selector.rows = selector;
7822 inst.selector.opts = opts;
7823
7824 return inst;
7825 } );
7826
7827 _api_register( 'rows().nodes()', function () {
7828 return this.iterator( 'row', function ( settings, row ) {
7829 return settings.aoData[ row ].nTr || undefined;
7830 }, 1 );
7831 } );
7832
7833 _api_register( 'rows().data()', function () {
7834 return this.iterator( true, 'rows', function ( settings, rows ) {
7835 return _pluck_order( settings.aoData, rows, '_aData' );
7836 }, 1 );
7837 } );
7838
7839 _api_registerPlural( 'rows().cache()', 'row().cache()', function ( type ) {
7840 return this.iterator( 'row', function ( settings, row ) {
7841 var r = settings.aoData[ row ];
7842 return type === 'search' ? r._aFilterData : r._aSortData;
7843 }, 1 );
7844 } );
7845
7846 _api_registerPlural( 'rows().invalidate()', 'row().invalidate()', function ( src ) {
7847 return this.iterator( 'row', function ( settings, row ) {
7848 _fnInvalidate( settings, row, src );
7849 } );
7850 } );
7851
7852 _api_registerPlural( 'rows().indexes()', 'row().index()', function () {
7853 return this.iterator( 'row', function ( settings, row ) {
7854 return row;
7855 }, 1 );
7856 } );
7857
7858 _api_registerPlural( 'rows().ids()', 'row().id()', function ( hash ) {
7859 var a = [];
7860 var context = this.context;
7861
7862 // `iterator` will drop undefined values, but in this case we want them
7863 for ( var i=0, ien=context.length ; i<ien ; i++ ) {
7864 for ( var j=0, jen=this[i].length ; j<jen ; j++ ) {
7865 var id = context[i].rowIdFn( context[i].aoData[ this[i][j] ]._aData );
7866 a.push( (hash === true ? '#' : '' )+ id );
7867 }
7868 }
7869
7870 return new _Api( context, a );
7871 } );
7872
7873 _api_registerPlural( 'rows().remove()', 'row().remove()', function () {
7874 var that = this;
7875
7876 this.iterator( 'row', function ( settings, row, thatIdx ) {
7877 var data = settings.aoData;
7878 var rowData = data[ row ];
7879
7880 data.splice( row, 1 );
7881
7882 // Update the _DT_RowIndex parameter on all rows in the table
7883 for ( var i=0, ien=data.length ; i<ien ; i++ ) {
7884 if ( data[i].nTr !== null ) {
7885 data[i].nTr._DT_RowIndex = i;
7886 }
7887 }
7888
7889 // Delete from the display arrays
7890 _fnDeleteIndex( settings.aiDisplayMaster, row );
7891 _fnDeleteIndex( settings.aiDisplay, row );
7892 _fnDeleteIndex( that[ thatIdx ], row, false ); // maintain local indexes
7893
7894 // Check for an 'overflow' they case for displaying the table
7895 _fnLengthOverflow( settings );
7896
7897 // Remove the row's ID reference if there is one
7898 var id = settings.rowIdFn( rowData._aData );
7899 if ( id !== undefined ) {
7900 delete settings.aIds[ id ];
7901 }
7902 } );
7903
7904 this.iterator( 'table', function ( settings ) {
7905 for ( var i=0, ien=settings.aoData.length ; i<ien ; i++ ) {
7906 settings.aoData[i].idx = i;
7907 }
7908 } );
7909
7910 return this;
7911 } );
7912
7913
7914 _api_register( 'rows.add()', function ( rows ) {
7915 var newRows = this.iterator( 'table', function ( settings ) {
7916 var row, i, ien;
7917 var out = [];
7918
7919 for ( i=0, ien=rows.length ; i<ien ; i++ ) {
7920 row = rows[i];
7921
7922 if ( row.nodeName && row.nodeName.toUpperCase() === 'TR' ) {
7923 out.push( _fnAddTr( settings, row )[0] );
7924 }
7925 else {
7926 out.push( _fnAddData( settings, row ) );
7927 }
7928 }
7929
7930 return out;
7931 }, 1 );
7932
7933 // Return an Api.rows() extended instance, so rows().nodes() etc can be used
7934 var modRows = this.rows( -1 );
7935 modRows.pop();
7936 $.merge( modRows, newRows );
7937
7938 return modRows;
7939 } );
7940
7941
7942
7943
7944
7945 /**
7946 *
7947 */
7948 _api_register( 'row()', function ( selector, opts ) {
7949 return _selector_first( this.rows( selector, opts ) );
7950 } );
7951
7952
7953 _api_register( 'row().data()', function ( data ) {
7954 var ctx = this.context;
7955
7956 if ( data === undefined ) {
7957 // Get
7958 return ctx.length && this.length ?
7959 ctx[0].aoData[ this[0] ]._aData :
7960 undefined;
7961 }
7962
7963 // Set
7964 ctx[0].aoData[ this[0] ]._aData = data;
7965
7966 // Automatically invalidate
7967 _fnInvalidate( ctx[0], this[0], 'data' );
7968
7969 return this;
7970 } );
7971
7972
7973 _api_register( 'row().node()', function () {
7974 var ctx = this.context;
7975
7976 return ctx.length && this.length ?
7977 ctx[0].aoData[ this[0] ].nTr || null :
7978 null;
7979 } );
7980
7981
7982 _api_register( 'row.add()', function ( row ) {
7983 // Allow a jQuery object to be passed in - only a single row is added from
7984 // it though - the first element in the set
7985 if ( row instanceof $ && row.length ) {
7986 row = row[0];
7987 }
7988
7989 var rows = this.iterator( 'table', function ( settings ) {
7990 if ( row.nodeName && row.nodeName.toUpperCase() === 'TR' ) {
7991 return _fnAddTr( settings, row )[0];
7992 }
7993 return _fnAddData( settings, row );
7994 } );
7995
7996 // Return an Api.rows() extended instance, with the newly added row selected
7997 return this.row( rows[0] );
7998 } );
7999
8000
8001
8002 var __details_add = function ( ctx, row, data, klass )
8003 {
8004 // Convert to array of TR elements
8005 var rows = [];
8006 var addRow = function ( r, k ) {
8007 // Recursion to allow for arrays of jQuery objects
8008 if ( $.isArray( r ) || r instanceof $ ) {
8009 for ( var i=0, ien=r.length ; i<ien ; i++ ) {
8010 addRow( r[i], k );
8011 }
8012 return;
8013 }
8014
8015 // If we get a TR element, then just add it directly - up to the dev
8016 // to add the correct number of columns etc
8017 if ( r.nodeName && r.nodeName.toLowerCase() === 'tr' ) {
8018 rows.push( r );
8019 }
8020 else {
8021 // Otherwise create a row with a wrapper
8022 var created = $('<tr><td/></tr>').addClass( k );
8023 $('td', created)
8024 .addClass( k )
8025 .html( r )
8026 [0].colSpan = _fnVisbleColumns( ctx );
8027
8028 rows.push( created[0] );
8029 }
8030 };
8031
8032 addRow( data, klass );
8033
8034 if ( row._details ) {
8035 row._details.remove();
8036 }
8037
8038 row._details = $(rows);
8039
8040 // If the children were already shown, that state should be retained
8041 if ( row._detailsShow ) {
8042 row._details.insertAfter( row.nTr );
8043 }
8044 };
8045
8046
8047 var __details_remove = function ( api, idx )
8048 {
8049 var ctx = api.context;
8050
8051 if ( ctx.length ) {
8052 var row = ctx[0].aoData[ idx !== undefined ? idx : api[0] ];
8053
8054 if ( row && row._details ) {
8055 row._details.remove();
8056
8057 row._detailsShow = undefined;
8058 row._details = undefined;
8059 }
8060 }
8061 };
8062
8063
8064 var __details_display = function ( api, show ) {
8065 var ctx = api.context;
8066
8067 if ( ctx.length && api.length ) {
8068 var row = ctx[0].aoData[ api[0] ];
8069
8070 if ( row._details ) {
8071 row._detailsShow = show;
8072
8073 if ( show ) {
8074 row._details.insertAfter( row.nTr );
8075 }
8076 else {
8077 row._details.detach();
8078 }
8079
8080 __details_events( ctx[0] );
8081 }
8082 }
8083 };
8084
8085
8086 var __details_events = function ( settings )
8087 {
8088 var api = new _Api( settings );
8089 var namespace = '.dt.DT_details';
8090 var drawEvent = 'draw'+namespace;
8091 var colvisEvent = 'column-visibility'+namespace;
8092 var destroyEvent = 'destroy'+namespace;
8093 var data = settings.aoData;
8094
8095 api.off( drawEvent +' '+ colvisEvent +' '+ destroyEvent );
8096
8097 if ( _pluck( data, '_details' ).length > 0 ) {
8098 // On each draw, insert the required elements into the document
8099 api.on( drawEvent, function ( e, ctx ) {
8100 if ( settings !== ctx ) {
8101 return;
8102 }
8103
8104 api.rows( {page:'current'} ).eq(0).each( function (idx) {
8105 // Internal data grab
8106 var row = data[ idx ];
8107
8108 if ( row._detailsShow ) {
8109 row._details.insertAfter( row.nTr );
8110 }
8111 } );
8112 } );
8113
8114 // Column visibility change - update the colspan
8115 api.on( colvisEvent, function ( e, ctx, idx, vis ) {
8116 if ( settings !== ctx ) {
8117 return;
8118 }
8119
8120 // Update the colspan for the details rows (note, only if it already has
8121 // a colspan)
8122 var row, visible = _fnVisbleColumns( ctx );
8123
8124 for ( var i=0, ien=data.length ; i<ien ; i++ ) {
8125 row = data[i];
8126
8127 if ( row._details ) {
8128 row._details.children('td[colspan]').attr('colspan', visible );
8129 }
8130 }
8131 } );
8132
8133 // Table destroyed - nuke any child rows
8134 api.on( destroyEvent, function ( e, ctx ) {
8135 if ( settings !== ctx ) {
8136 return;
8137 }
8138
8139 for ( var i=0, ien=data.length ; i<ien ; i++ ) {
8140 if ( data[i]._details ) {
8141 __details_remove( api, i );
8142 }
8143 }
8144 } );
8145 }
8146 };
8147
8148 // Strings for the method names to help minification
8149 var _emp = '';
8150 var _child_obj = _emp+'row().child';
8151 var _child_mth = _child_obj+'()';
8152
8153 // data can be:
8154 // tr
8155 // string
8156 // jQuery or array of any of the above
8157 _api_register( _child_mth, function ( data, klass ) {
8158 var ctx = this.context;
8159
8160 if ( data === undefined ) {
8161 // get
8162 return ctx.length && this.length ?
8163 ctx[0].aoData[ this[0] ]._details :
8164 undefined;
8165 }
8166 else if ( data === true ) {
8167 // show
8168 this.child.show();
8169 }
8170 else if ( data === false ) {
8171 // remove
8172 __details_remove( this );
8173 }
8174 else if ( ctx.length && this.length ) {
8175 // set
8176 __details_add( ctx[0], ctx[0].aoData[ this[0] ], data, klass );
8177 }
8178
8179 return this;
8180 } );
8181
8182
8183 _api_register( [
8184 _child_obj+'.show()',
8185 _child_mth+'.show()' // only when `child()` was called with parameters (without
8186 ], function ( show ) { // it returns an object and this method is not executed)
8187 __details_display( this, true );
8188 return this;
8189 } );
8190
8191
8192 _api_register( [
8193 _child_obj+'.hide()',
8194 _child_mth+'.hide()' // only when `child()` was called with parameters (without
8195 ], function () { // it returns an object and this method is not executed)
8196 __details_display( this, false );
8197 return this;
8198 } );
8199
8200
8201 _api_register( [
8202 _child_obj+'.remove()',
8203 _child_mth+'.remove()' // only when `child()` was called with parameters (without
8204 ], function () { // it returns an object and this method is not executed)
8205 __details_remove( this );
8206 return this;
8207 } );
8208
8209
8210 _api_register( _child_obj+'.isShown()', function () {
8211 var ctx = this.context;
8212
8213 if ( ctx.length && this.length ) {
8214 // _detailsShown as false or undefined will fall through to return false
8215 return ctx[0].aoData[ this[0] ]._detailsShow || false;
8216 }
8217 return false;
8218 } );
8219
8220
8221
8222 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
8223 * Columns
8224 *
8225 * {integer} - column index (>=0 count from left, <0 count from right)
8226 * "{integer}:visIdx" - visible column index (i.e. translate to column index) (>=0 count from left, <0 count from right)
8227 * "{integer}:visible" - alias for {integer}:visIdx (>=0 count from left, <0 count from right)
8228 * "{string}:name" - column name
8229 * "{string}" - jQuery selector on column header nodes
8230 *
8231 */
8232
8233 // can be an array of these items, comma separated list, or an array of comma
8234 // separated lists
8235
8236 var __re_column_selector = /^(.+):(name|visIdx|visible)$/;
8237
8238
8239 // r1 and r2 are redundant - but it means that the parameters match for the
8240 // iterator callback in columns().data()
8241 var __columnData = function ( settings, column, r1, r2, rows ) {
8242 var a = [];
8243 for ( var row=0, ien=rows.length ; row<ien ; row++ ) {
8244 a.push( _fnGetCellData( settings, rows[row], column ) );
8245 }
8246 return a;
8247 };
8248
8249
8250 var __column_selector = function ( settings, selector, opts )
8251 {
8252 var
8253 columns = settings.aoColumns,
8254 names = _pluck( columns, 'sName' ),
8255 nodes = _pluck( columns, 'nTh' );
8256
8257 var run = function ( s ) {
8258 var selInt = _intVal( s );
8259
8260 // Selector - all
8261 if ( s === '' ) {
8262 return _range( columns.length );
8263 }
8264
8265 // Selector - index
8266 if ( selInt !== null ) {
8267 return [ selInt >= 0 ?
8268 selInt : // Count from left
8269 columns.length + selInt // Count from right (+ because its a negative value)
8270 ];
8271 }
8272
8273 // Selector = function
8274 if ( typeof s === 'function' ) {
8275 var rows = _selector_row_indexes( settings, opts );
8276
8277 return $.map( columns, function (col, idx) {
8278 return s(
8279 idx,
8280 __columnData( settings, idx, 0, 0, rows ),
8281 nodes[ idx ]
8282 ) ? idx : null;
8283 } );
8284 }
8285
8286 // jQuery or string selector
8287 var match = typeof s === 'string' ?
8288 s.match( __re_column_selector ) :
8289 '';
8290
8291 if ( match ) {
8292 switch( match[2] ) {
8293 case 'visIdx':
8294 case 'visible':
8295 var idx = parseInt( match[1], 10 );
8296 // Visible index given, convert to column index
8297 if ( idx < 0 ) {
8298 // Counting from the right
8299 var visColumns = $.map( columns, function (col,i) {
8300 return col.bVisible ? i : null;
8301 } );
8302 return [ visColumns[ visColumns.length + idx ] ];
8303 }
8304 // Counting from the left
8305 return [ _fnVisibleToColumnIndex( settings, idx ) ];
8306
8307 case 'name':
8308 // match by name. `names` is column index complete and in order
8309 return $.map( names, function (name, i) {
8310 return name === match[1] ? i : null;
8311 } );
8312 }
8313 }
8314 else {
8315 // jQuery selector on the TH elements for the columns
8316 return $( nodes )
8317 .filter( s )
8318 .map( function () {
8319 return $.inArray( this, nodes ); // `nodes` is column index complete and in order
8320 } )
8321 .toArray();
8322 }
8323 };
8324
8325 return _selector_run( 'column', selector, run, settings, opts );
8326 };
8327
8328
8329 var __setColumnVis = function ( settings, column, vis, recalc ) {
8330 var
8331 cols = settings.aoColumns,
8332 col = cols[ column ],
8333 data = settings.aoData,
8334 row, cells, i, ien, tr;
8335
8336 // Get
8337 if ( vis === undefined ) {
8338 return col.bVisible;
8339 }
8340
8341 // Set
8342 // No change
8343 if ( col.bVisible === vis ) {
8344 return;
8345 }
8346
8347 if ( vis ) {
8348 // Insert column
8349 // Need to decide if we should use appendChild or insertBefore
8350 var insertBefore = $.inArray( true, _pluck(cols, 'bVisible'), column+1 );
8351
8352 for ( i=0, ien=data.length ; i<ien ; i++ ) {
8353 tr = data[i].nTr;
8354 cells = data[i].anCells;
8355
8356 if ( tr ) {
8357 // insertBefore can act like appendChild if 2nd arg is null
8358 tr.insertBefore( cells[ column ], cells[ insertBefore ] || null );
8359 }
8360 }
8361 }
8362 else {
8363 // Remove column
8364 $( _pluck( settings.aoData, 'anCells', column ) ).detach();
8365 }
8366
8367 // Common actions
8368 col.bVisible = vis;
8369 _fnDrawHead( settings, settings.aoHeader );
8370 _fnDrawHead( settings, settings.aoFooter );
8371
8372 if ( recalc === undefined || recalc ) {
8373 // Automatically adjust column sizing
8374 _fnAdjustColumnSizing( settings );
8375
8376 // Realign columns for scrolling
8377 if ( settings.oScroll.sX || settings.oScroll.sY ) {
8378 _fnScrollDraw( settings );
8379 }
8380 }
8381
8382 _fnCallbackFire( settings, null, 'column-visibility', [settings, column, vis] );
8383
8384 _fnSaveState( settings );
8385 };
8386
8387
8388 _api_register( 'columns()', function ( selector, opts ) {
8389 // argument shifting
8390 if ( selector === undefined ) {
8391 selector = '';
8392 }
8393 else if ( $.isPlainObject( selector ) ) {
8394 opts = selector;
8395 selector = '';
8396 }
8397
8398 opts = _selector_opts( opts );
8399
8400 var inst = this.iterator( 'table', function ( settings ) {
8401 return __column_selector( settings, selector, opts );
8402 }, 1 );
8403
8404 // Want argument shifting here and in _row_selector?
8405 inst.selector.cols = selector;
8406 inst.selector.opts = opts;
8407
8408 return inst;
8409 } );
8410
8411 _api_registerPlural( 'columns().header()', 'column().header()', function ( selector, opts ) {
8412 return this.iterator( 'column', function ( settings, column ) {
8413 return settings.aoColumns[column].nTh;
8414 }, 1 );
8415 } );
8416
8417 _api_registerPlural( 'columns().footer()', 'column().footer()', function ( selector, opts ) {
8418 return this.iterator( 'column', function ( settings, column ) {
8419 return settings.aoColumns[column].nTf;
8420 }, 1 );
8421 } );
8422
8423 _api_registerPlural( 'columns().data()', 'column().data()', function () {
8424 return this.iterator( 'column-rows', __columnData, 1 );
8425 } );
8426
8427 _api_registerPlural( 'columns().dataSrc()', 'column().dataSrc()', function () {
8428 return this.iterator( 'column', function ( settings, column ) {
8429 return settings.aoColumns[column].mData;
8430 }, 1 );
8431 } );
8432
8433 _api_registerPlural( 'columns().cache()', 'column().cache()', function ( type ) {
8434 return this.iterator( 'column-rows', function ( settings, column, i, j, rows ) {
8435 return _pluck_order( settings.aoData, rows,
8436 type === 'search' ? '_aFilterData' : '_aSortData', column
8437 );
8438 }, 1 );
8439 } );
8440
8441 _api_registerPlural( 'columns().nodes()', 'column().nodes()', function () {
8442 return this.iterator( 'column-rows', function ( settings, column, i, j, rows ) {
8443 return _pluck_order( settings.aoData, rows, 'anCells', column ) ;
8444 }, 1 );
8445 } );
8446
8447 _api_registerPlural( 'columns().visible()', 'column().visible()', function ( vis, calc ) {
8448 return this.iterator( 'column', function ( settings, column ) {
8449 if ( vis === undefined ) {
8450 return settings.aoColumns[ column ].bVisible;
8451 } // else
8452 __setColumnVis( settings, column, vis, calc );
8453 } );
8454 } );
8455
8456 _api_registerPlural( 'columns().indexes()', 'column().index()', function ( type ) {
8457 return this.iterator( 'column', function ( settings, column ) {
8458 return type === 'visible' ?
8459 _fnColumnIndexToVisible( settings, column ) :
8460 column;
8461 }, 1 );
8462 } );
8463
8464 _api_register( 'columns.adjust()', function () {
8465 return this.iterator( 'table', function ( settings ) {
8466 _fnAdjustColumnSizing( settings );
8467 }, 1 );
8468 } );
8469
8470 _api_register( 'column.index()', function ( type, idx ) {
8471 if ( this.context.length !== 0 ) {
8472 var ctx = this.context[0];
8473
8474 if ( type === 'fromVisible' || type === 'toData' ) {
8475 return _fnVisibleToColumnIndex( ctx, idx );
8476 }
8477 else if ( type === 'fromData' || type === 'toVisible' ) {
8478 return _fnColumnIndexToVisible( ctx, idx );
8479 }
8480 }
8481 } );
8482
8483 _api_register( 'column()', function ( selector, opts ) {
8484 return _selector_first( this.columns( selector, opts ) );
8485 } );
8486
8487
8488
8489
8490 var __cell_selector = function ( settings, selector, opts )
8491 {
8492 var data = settings.aoData;
8493 var rows = _selector_row_indexes( settings, opts );
8494 var cells = _removeEmpty( _pluck_order( data, rows, 'anCells' ) );
8495 var allCells = $( [].concat.apply([], cells) );
8496 var row;
8497 var columns = settings.aoColumns.length;
8498 var a, i, ien, j, o, host;
8499
8500 var run = function ( s ) {
8501 var fnSelector = typeof s === 'function';
8502
8503 if ( s === null || s === undefined || fnSelector ) {
8504 // All cells and function selectors
8505 a = [];
8506
8507 for ( i=0, ien=rows.length ; i<ien ; i++ ) {
8508 row = rows[i];
8509
8510 for ( j=0 ; j<columns ; j++ ) {
8511 o = {
8512 row: row,
8513 column: j
8514 };
8515
8516 if ( fnSelector ) {
8517 // Selector - function
8518 host = data[ row ];
8519
8520 if ( s( o, _fnGetCellData(settings, row, j), host.anCells ? host.anCells[j] : null ) ) {
8521 a.push( o );
8522 }
8523 }
8524 else {
8525 // Selector - all
8526 a.push( o );
8527 }
8528 }
8529 }
8530
8531 return a;
8532 }
8533
8534 // Selector - index
8535 if ( $.isPlainObject( s ) ) {
8536 return [s];
8537 }
8538
8539 // Selector - jQuery filtered cells
8540 return allCells
8541 .filter( s )
8542 .map( function (i, el) {
8543 if ( el.parentNode ) {
8544 row = el.parentNode._DT_RowIndex;
8545 }
8546 else {
8547 // If no parent node, then the cell is hidden and we'll need
8548 // to traverse the array to find it
8549 for ( i=0, ien=data.length ; i<ien ; i++ ) {
8550 if ( $.inArray( el, data[i].anCells ) !== -1 ) {
8551 row = i;
8552 break;
8553 }
8554 }
8555 }
8556
8557 return {
8558 row: row,
8559 column: $.inArray( el, data[ row ].anCells )
8560 };
8561 } )
8562 .toArray();
8563 };
8564
8565 return _selector_run( 'cell', selector, run, settings, opts );
8566 };
8567
8568
8569
8570
8571 _api_register( 'cells()', function ( rowSelector, columnSelector, opts ) {
8572 // Argument shifting
8573 if ( $.isPlainObject( rowSelector ) ) {
8574 // Indexes
8575 if ( rowSelector.row === undefined ) {
8576 // Selector options in first parameter
8577 opts = rowSelector;
8578 rowSelector = null;
8579 }
8580 else {
8581 // Cell index objects in first parameter
8582 opts = columnSelector;
8583 columnSelector = null;
8584 }
8585 }
8586 if ( $.isPlainObject( columnSelector ) ) {
8587 opts = columnSelector;
8588 columnSelector = null;
8589 }
8590
8591 // Cell selector
8592 if ( columnSelector === null || columnSelector === undefined ) {
8593 return this.iterator( 'table', function ( settings ) {
8594 return __cell_selector( settings, rowSelector, _selector_opts( opts ) );
8595 } );
8596 }
8597
8598 // Row + column selector
8599 var columns = this.columns( columnSelector, opts );
8600 var rows = this.rows( rowSelector, opts );
8601 var a, i, ien, j, jen;
8602
8603 var cells = this.iterator( 'table', function ( settings, idx ) {
8604 a = [];
8605
8606 for ( i=0, ien=rows[idx].length ; i<ien ; i++ ) {
8607 for ( j=0, jen=columns[idx].length ; j<jen ; j++ ) {
8608 a.push( {
8609 row: rows[idx][i],
8610 column: columns[idx][j]
8611 } );
8612 }
8613 }
8614
8615 return a;
8616 }, 1 );
8617
8618 $.extend( cells.selector, {
8619 cols: columnSelector,
8620 rows: rowSelector,
8621 opts: opts
8622 } );
8623
8624 return cells;
8625 } );
8626
8627
8628 _api_registerPlural( 'cells().nodes()', 'cell().node()', function () {
8629 return this.iterator( 'cell', function ( settings, row, column ) {
8630 var cells = settings.aoData[ row ].anCells;
8631 return cells ?
8632 cells[ column ] :
8633 undefined;
8634 }, 1 );
8635 } );
8636
8637
8638 _api_register( 'cells().data()', function () {
8639 return this.iterator( 'cell', function ( settings, row, column ) {
8640 return _fnGetCellData( settings, row, column );
8641 }, 1 );
8642 } );
8643
8644
8645 _api_registerPlural( 'cells().cache()', 'cell().cache()', function ( type ) {
8646 type = type === 'search' ? '_aFilterData' : '_aSortData';
8647
8648 return this.iterator( 'cell', function ( settings, row, column ) {
8649 return settings.aoData[ row ][ type ][ column ];
8650 }, 1 );
8651 } );
8652
8653
8654 _api_registerPlural( 'cells().render()', 'cell().render()', function ( type ) {
8655 return this.iterator( 'cell', function ( settings, row, column ) {
8656 return _fnGetCellData( settings, row, column, type );
8657 }, 1 );
8658 } );
8659
8660
8661 _api_registerPlural( 'cells().indexes()', 'cell().index()', function () {
8662 return this.iterator( 'cell', function ( settings, row, column ) {
8663 return {
8664 row: row,
8665 column: column,
8666 columnVisible: _fnColumnIndexToVisible( settings, column )
8667 };
8668 }, 1 );
8669 } );
8670
8671
8672 _api_registerPlural( 'cells().invalidate()', 'cell().invalidate()', function ( src ) {
8673 return this.iterator( 'cell', function ( settings, row, column ) {
8674 _fnInvalidate( settings, row, src, column );
8675 } );
8676 } );
8677
8678
8679
8680 _api_register( 'cell()', function ( rowSelector, columnSelector, opts ) {
8681 return _selector_first( this.cells( rowSelector, columnSelector, opts ) );
8682 } );
8683
8684
8685 _api_register( 'cell().data()', function ( data ) {
8686 var ctx = this.context;
8687 var cell = this[0];
8688
8689 if ( data === undefined ) {
8690 // Get
8691 return ctx.length && cell.length ?
8692 _fnGetCellData( ctx[0], cell[0].row, cell[0].column ) :
8693 undefined;
8694 }
8695
8696 // Set
8697 _fnSetCellData( ctx[0], cell[0].row, cell[0].column, data );
8698 _fnInvalidate( ctx[0], cell[0].row, 'data', cell[0].column );
8699
8700 return this;
8701 } );
8702
8703
8704
8705 /**
8706 * Get current ordering (sorting) that has been applied to the table.
8707 *
8708 * @returns {array} 2D array containing the sorting information for the first
8709 * table in the current context. Each element in the parent array represents
8710 * a column being sorted upon (i.e. multi-sorting with two columns would have
8711 * 2 inner arrays). The inner arrays may have 2 or 3 elements. The first is
8712 * the column index that the sorting condition applies to, the second is the
8713 * direction of the sort (`desc` or `asc`) and, optionally, the third is the
8714 * index of the sorting order from the `column.sorting` initialisation array.
8715 *//**
8716 * Set the ordering for the table.
8717 *
8718 * @param {integer} order Column index to sort upon.
8719 * @param {string} direction Direction of the sort to be applied (`asc` or `desc`)
8720 * @returns {DataTables.Api} this
8721 *//**
8722 * Set the ordering for the table.
8723 *
8724 * @param {array} order 1D array of sorting information to be applied.
8725 * @param {array} [...] Optional additional sorting conditions
8726 * @returns {DataTables.Api} this
8727 *//**
8728 * Set the ordering for the table.
8729 *
8730 * @param {array} order 2D array of sorting information to be applied.
8731 * @returns {DataTables.Api} this
8732 */
8733 _api_register( 'order()', function ( order, dir ) {
8734 var ctx = this.context;
8735
8736 if ( order === undefined ) {
8737 // get
8738 return ctx.length !== 0 ?
8739 ctx[0].aaSorting :
8740 undefined;
8741 }
8742
8743 // set
8744 if ( typeof order === 'number' ) {
8745 // Simple column / direction passed in
8746 order = [ [ order, dir ] ];
8747 }
8748 else if ( ! $.isArray( order[0] ) ) {
8749 // Arguments passed in (list of 1D arrays)
8750 order = Array.prototype.slice.call( arguments );
8751 }
8752 // otherwise a 2D array was passed in
8753
8754 return this.iterator( 'table', function ( settings ) {
8755 settings.aaSorting = order.slice();
8756 } );
8757 } );
8758
8759
8760 /**
8761 * Attach a sort listener to an element for a given column
8762 *
8763 * @param {node|jQuery|string} node Identifier for the element(s) to attach the
8764 * listener to. This can take the form of a single DOM node, a jQuery
8765 * collection of nodes or a jQuery selector which will identify the node(s).
8766 * @param {integer} column the column that a click on this node will sort on
8767 * @param {function} [callback] callback function when sort is run
8768 * @returns {DataTables.Api} this
8769 */
8770 _api_register( 'order.listener()', function ( node, column, callback ) {
8771 return this.iterator( 'table', function ( settings ) {
8772 _fnSortAttachListener( settings, node, column, callback );
8773 } );
8774 } );
8775
8776
8777 // Order by the selected column(s)
8778 _api_register( [
8779 'columns().order()',
8780 'column().order()'
8781 ], function ( dir ) {
8782 var that = this;
8783
8784 return this.iterator( 'table', function ( settings, i ) {
8785 var sort = [];
8786
8787 $.each( that[i], function (j, col) {
8788 sort.push( [ col, dir ] );
8789 } );
8790
8791 settings.aaSorting = sort;
8792 } );
8793 } );
8794
8795
8796
8797 _api_register( 'search()', function ( input, regex, smart, caseInsen ) {
8798 var ctx = this.context;
8799
8800 if ( input === undefined ) {
8801 // get
8802 return ctx.length !== 0 ?
8803 ctx[0].oPreviousSearch.sSearch :
8804 undefined;
8805 }
8806
8807 // set
8808 return this.iterator( 'table', function ( settings ) {
8809 if ( ! settings.oFeatures.bFilter ) {
8810 return;
8811 }
8812
8813 _fnFilterComplete( settings, $.extend( {}, settings.oPreviousSearch, {
8814 "sSearch": input+"",
8815 "bRegex": regex === null ? false : regex,
8816 "bSmart": smart === null ? true : smart,
8817 "bCaseInsensitive": caseInsen === null ? true : caseInsen
8818 } ), 1 );
8819 } );
8820 } );
8821
8822
8823 _api_registerPlural(
8824 'columns().search()',
8825 'column().search()',
8826 function ( input, regex, smart, caseInsen ) {
8827 return this.iterator( 'column', function ( settings, column ) {
8828 var preSearch = settings.aoPreSearchCols;
8829
8830 if ( input === undefined ) {
8831 // get
8832 return preSearch[ column ].sSearch;
8833 }
8834
8835 // set
8836 if ( ! settings.oFeatures.bFilter ) {
8837 return;
8838 }
8839
8840 $.extend( preSearch[ column ], {
8841 "sSearch": input+"",
8842 "bRegex": regex === null ? false : regex,
8843 "bSmart": smart === null ? true : smart,
8844 "bCaseInsensitive": caseInsen === null ? true : caseInsen
8845 } );
8846
8847 _fnFilterComplete( settings, settings.oPreviousSearch, 1 );
8848 } );
8849 }
8850 );
8851
8852 /*
8853 * State API methods
8854 */
8855
8856 _api_register( 'state()', function () {
8857 return this.context.length ?
8858 this.context[0].oSavedState :
8859 null;
8860 } );
8861
8862
8863 _api_register( 'state.clear()', function () {
8864 return this.iterator( 'table', function ( settings ) {
8865 // Save an empty object
8866 settings.fnStateSaveCallback.call( settings.oInstance, settings, {} );
8867 } );
8868 } );
8869
8870
8871 _api_register( 'state.loaded()', function () {
8872 return this.context.length ?
8873 this.context[0].oLoadedState :
8874 null;
8875 } );
8876
8877
8878 _api_register( 'state.save()', function () {
8879 return this.iterator( 'table', function ( settings ) {
8880 _fnSaveState( settings );
8881 } );
8882 } );
8883
8884
8885
8886 /**
8887 * Provide a common method for plug-ins to check the version of DataTables being
8888 * used, in order to ensure compatibility.
8889 *
8890 * @param {string} version Version string to check for, in the format "X.Y.Z".
8891 * Note that the formats "X" and "X.Y" are also acceptable.
8892 * @returns {boolean} true if this version of DataTables is greater or equal to
8893 * the required version, or false if this version of DataTales is not
8894 * suitable
8895 * @static
8896 * @dtopt API-Static
8897 *
8898 * @example
8899 * alert( $.fn.dataTable.versionCheck( '1.9.0' ) );
8900 */
8901 DataTable.versionCheck = DataTable.fnVersionCheck = function( version )
8902 {
8903 var aThis = DataTable.version.split('.');
8904 var aThat = version.split('.');
8905 var iThis, iThat;
8906
8907 for ( var i=0, iLen=aThat.length ; i<iLen ; i++ ) {
8908 iThis = parseInt( aThis[i], 10 ) || 0;
8909 iThat = parseInt( aThat[i], 10 ) || 0;
8910
8911 // Parts are the same, keep comparing
8912 if (iThis === iThat) {
8913 continue;
8914 }
8915
8916 // Parts are different, return immediately
8917 return iThis > iThat;
8918 }
8919
8920 return true;
8921 };
8922
8923
8924 /**
8925 * Check if a `<table>` node is a DataTable table already or not.
8926 *
8927 * @param {node|jquery|string} table Table node, jQuery object or jQuery
8928 * selector for the table to test. Note that if more than more than one
8929 * table is passed on, only the first will be checked
8930 * @returns {boolean} true the table given is a DataTable, or false otherwise
8931 * @static
8932 * @dtopt API-Static
8933 *
8934 * @example
8935 * if ( ! $.fn.DataTable.isDataTable( '#example' ) ) {
8936 * $('#example').dataTable();
8937 * }
8938 */
8939 DataTable.isDataTable = DataTable.fnIsDataTable = function ( table )
8940 {
8941 var t = $(table).get(0);
8942 var is = false;
8943
8944 $.each( DataTable.settings, function (i, o) {
8945 var head = o.nScrollHead ? $('table', o.nScrollHead)[0] : null;
8946 var foot = o.nScrollFoot ? $('table', o.nScrollFoot)[0] : null;
8947
8948 if ( o.nTable === t || head === t || foot === t ) {
8949 is = true;
8950 }
8951 } );
8952
8953 return is;
8954 };
8955
8956
8957 /**
8958 * Get all DataTable tables that have been initialised - optionally you can
8959 * select to get only currently visible tables.
8960 *
8961 * @param {boolean} [visible=false] Flag to indicate if you want all (default)
8962 * or visible tables only.
8963 * @returns {array} Array of `table` nodes (not DataTable instances) which are
8964 * DataTables
8965 * @static
8966 * @dtopt API-Static
8967 *
8968 * @example
8969 * $.each( $.fn.dataTable.tables(true), function () {
8970 * $(table).DataTable().columns.adjust();
8971 * } );
8972 */
8973 DataTable.tables = DataTable.fnTables = function ( visible )
8974 {
8975 var api = false;
8976
8977 if ( $.isPlainObject( visible ) ) {
8978 api = visible.api;
8979 visible = visible.visible;
8980 }
8981
8982 var a = $.map( DataTable.settings, function (o) {
8983 if ( !visible || (visible && $(o.nTable).is(':visible')) ) {
8984 return o.nTable;
8985 }
8986 } );
8987
8988 return api ?
8989 new _Api( a ) :
8990 a;
8991 };
8992
8993
8994 /**
8995 * DataTables utility methods
8996 *
8997 * This namespace provides helper methods that DataTables uses internally to
8998 * create a DataTable, but which are not exclusively used only for DataTables.
8999 * These methods can be used by extension authors to save the duplication of
9000 * code.
9001 *
9002 * @namespace
9003 */
9004 DataTable.util = {
9005 /**
9006 * Throttle the calls to a function. Arguments and context are maintained
9007 * for the throttled function.
9008 *
9009 * @param {function} fn Function to be called
9010 * @param {integer} freq Call frequency in mS
9011 * @return {function} Wrapped function
9012 */
9013 throttle: _fnThrottle,
9014
9015
9016 /**
9017 * Escape a string such that it can be used in a regular expression
9018 *
9019 * @param {string} sVal string to escape
9020 * @returns {string} escaped string
9021 */
9022 escapeRegex: _fnEscapeRegex
9023 };
9024
9025
9026 /**
9027 * Convert from camel case parameters to Hungarian notation. This is made public
9028 * for the extensions to provide the same ability as DataTables core to accept
9029 * either the 1.9 style Hungarian notation, or the 1.10+ style camelCase
9030 * parameters.
9031 *
9032 * @param {object} src The model object which holds all parameters that can be
9033 * mapped.
9034 * @param {object} user The object to convert from camel case to Hungarian.
9035 * @param {boolean} force When set to `true`, properties which already have a
9036 * Hungarian value in the `user` object will be overwritten. Otherwise they
9037 * won't be.
9038 */
9039 DataTable.camelToHungarian = _fnCamelToHungarian;
9040
9041
9042
9043 /**
9044 *
9045 */
9046 _api_register( '$()', function ( selector, opts ) {
9047 var
9048 rows = this.rows( opts ).nodes(), // Get all rows
9049 jqRows = $(rows);
9050
9051 return $( [].concat(
9052 jqRows.filter( selector ).toArray(),
9053 jqRows.find( selector ).toArray()
9054 ) );
9055 } );
9056
9057
9058 // jQuery functions to operate on the tables
9059 $.each( [ 'on', 'one', 'off' ], function (i, key) {
9060 _api_register( key+'()', function ( /* event, handler */ ) {
9061 var args = Array.prototype.slice.call(arguments);
9062
9063 // Add the `dt` namespace automatically if it isn't already present
9064 if ( ! args[0].match(/\.dt\b/) ) {
9065 args[0] += '.dt';
9066 }
9067
9068 var inst = $( this.tables().nodes() );
9069 inst[key].apply( inst, args );
9070 return this;
9071 } );
9072 } );
9073
9074
9075 _api_register( 'clear()', function () {
9076 return this.iterator( 'table', function ( settings ) {
9077 _fnClearTable( settings );
9078 } );
9079 } );
9080
9081
9082 _api_register( 'settings()', function () {
9083 return new _Api( this.context, this.context );
9084 } );
9085
9086
9087 _api_register( 'init()', function () {
9088 var ctx = this.context;
9089 return ctx.length ? ctx[0].oInit : null;
9090 } );
9091
9092
9093 _api_register( 'data()', function () {
9094 return this.iterator( 'table', function ( settings ) {
9095 return _pluck( settings.aoData, '_aData' );
9096 } ).flatten();
9097 } );
9098
9099
9100 _api_register( 'destroy()', function ( remove ) {
9101 remove = remove || false;
9102
9103 return this.iterator( 'table', function ( settings ) {
9104 var orig = settings.nTableWrapper.parentNode;
9105 var classes = settings.oClasses;
9106 var table = settings.nTable;
9107 var tbody = settings.nTBody;
9108 var thead = settings.nTHead;
9109 var tfoot = settings.nTFoot;
9110 var jqTable = $(table);
9111 var jqTbody = $(tbody);
9112 var jqWrapper = $(settings.nTableWrapper);
9113 var rows = $.map( settings.aoData, function (r) { return r.nTr; } );
9114 var i, ien;
9115
9116 // Flag to note that the table is currently being destroyed - no action
9117 // should be taken
9118 settings.bDestroying = true;
9119
9120 // Fire off the destroy callbacks for plug-ins etc
9121 _fnCallbackFire( settings, "aoDestroyCallback", "destroy", [settings] );
9122
9123 // If not being removed from the document, make all columns visible
9124 if ( ! remove ) {
9125 new _Api( settings ).columns().visible( true );
9126 }
9127
9128 // Blitz all `DT` namespaced events (these are internal events, the
9129 // lowercase, `dt` events are user subscribed and they are responsible
9130 // for removing them
9131 jqWrapper.unbind('.DT').find(':not(tbody *)').unbind('.DT');
9132 $(window).unbind('.DT-'+settings.sInstance);
9133
9134 // When scrolling we had to break the table up - restore it
9135 if ( table != thead.parentNode ) {
9136 jqTable.children('thead').detach();
9137 jqTable.append( thead );
9138 }
9139
9140 if ( tfoot && table != tfoot.parentNode ) {
9141 jqTable.children('tfoot').detach();
9142 jqTable.append( tfoot );
9143 }
9144
9145 settings.aaSorting = [];
9146 settings.aaSortingFixed = [];
9147 _fnSortingClasses( settings );
9148
9149 $( rows ).removeClass( settings.asStripeClasses.join(' ') );
9150
9151 $('th, td', thead).removeClass( classes.sSortable+' '+
9152 classes.sSortableAsc+' '+classes.sSortableDesc+' '+classes.sSortableNone
9153 );
9154
9155 if ( settings.bJUI ) {
9156 $('th span.'+classes.sSortIcon+ ', td span.'+classes.sSortIcon, thead).detach();
9157 $('th, td', thead).each( function () {
9158 var wrapper = $('div.'+classes.sSortJUIWrapper, this);
9159 $(this).append( wrapper.contents() );
9160 wrapper.detach();
9161 } );
9162 }
9163
9164 // Add the TR elements back into the table in their original order
9165 jqTbody.children().detach();
9166 jqTbody.append( rows );
9167
9168 // Remove the DataTables generated nodes, events and classes
9169 var removedMethod = remove ? 'remove' : 'detach';
9170 jqTable[ removedMethod ]();
9171 jqWrapper[ removedMethod ]();
9172
9173 // If we need to reattach the table to the document
9174 if ( ! remove && orig ) {
9175 // insertBefore acts like appendChild if !arg[1]
9176 orig.insertBefore( table, settings.nTableReinsertBefore );
9177
9178 // Restore the width of the original table - was read from the style property,
9179 // so we can restore directly to that
9180 jqTable
9181 .css( 'width', settings.sDestroyWidth )
9182 .removeClass( classes.sTable );
9183
9184 // If the were originally stripe classes - then we add them back here.
9185 // Note this is not fool proof (for example if not all rows had stripe
9186 // classes - but it's a good effort without getting carried away
9187 ien = settings.asDestroyStripes.length;
9188
9189 if ( ien ) {
9190 jqTbody.children().each( function (i) {
9191 $(this).addClass( settings.asDestroyStripes[i % ien] );
9192 } );
9193 }
9194 }
9195
9196 /* Remove the settings object from the settings array */
9197 var idx = $.inArray( settings, DataTable.settings );
9198 if ( idx !== -1 ) {
9199 DataTable.settings.splice( idx, 1 );
9200 }
9201 } );
9202 } );
9203
9204
9205 // Add the `every()` method for rows, columns and cells in a compact form
9206 $.each( [ 'column', 'row', 'cell' ], function ( i, type ) {
9207 _api_register( type+'s().every()', function ( fn ) {
9208 return this.iterator( type, function ( settings, arg1, arg2, arg3, arg4 ) {
9209 // Rows and columns:
9210 // arg1 - index
9211 // arg2 - table counter
9212 // arg3 - loop counter
9213 // arg4 - undefined
9214 // Cells:
9215 // arg1 - row index
9216 // arg2 - column index
9217 // arg3 - table counter
9218 // arg4 - loop counter
9219 fn.call(
9220 new _Api( settings )[ type ]( arg1, type==='cell' ? arg2 : undefined ),
9221 arg1, arg2, arg3, arg4
9222 );
9223 } );
9224 } );
9225 } );
9226
9227
9228 // i18n method for extensions to be able to use the language object from the
9229 // DataTable
9230 _api_register( 'i18n()', function ( token, def, plural ) {
9231 var ctx = this.context[0];
9232 var resolved = _fnGetObjectDataFn( token )( ctx.oLanguage );
9233
9234 if ( resolved === undefined ) {
9235 resolved = def;
9236 }
9237
9238 if ( plural !== undefined && $.isPlainObject( resolved ) ) {
9239 resolved = resolved[ plural ] !== undefined ?
9240 resolved[ plural ] :
9241 resolved._;
9242 }
9243
9244 return resolved.replace( '%d', plural ); // nb: plural might be undefined,
9245 } );
9246
9247 /**
9248 * Version string for plug-ins to check compatibility. Allowed format is
9249 * `a.b.c-d` where: a:int, b:int, c:int, d:string(dev|beta|alpha). `d` is used
9250 * only for non-release builds. See http://semver.org/ for more information.
9251 * @member
9252 * @type string
9253 * @default Version number
9254 */
9255 DataTable.version = "1.10.9";
9256
9257 /**
9258 * Private data store, containing all of the settings objects that are
9259 * created for the tables on a given page.
9260 *
9261 * Note that the `DataTable.settings` object is aliased to
9262 * `jQuery.fn.dataTableExt` through which it may be accessed and
9263 * manipulated, or `jQuery.fn.dataTable.settings`.
9264 * @member
9265 * @type array
9266 * @default []
9267 * @private
9268 */
9269 DataTable.settings = [];
9270
9271 /**
9272 * Object models container, for the various models that DataTables has
9273 * available to it. These models define the objects that are used to hold
9274 * the active state and configuration of the table.
9275 * @namespace
9276 */
9277 DataTable.models = {};
9278
9279
9280
9281 /**
9282 * Template object for the way in which DataTables holds information about
9283 * search information for the global filter and individual column filters.
9284 * @namespace
9285 */
9286 DataTable.models.oSearch = {
9287 /**
9288 * Flag to indicate if the filtering should be case insensitive or not
9289 * @type boolean
9290 * @default true
9291 */
9292 "bCaseInsensitive": true,
9293
9294 /**
9295 * Applied search term
9296 * @type string
9297 * @default <i>Empty string</i>
9298 */
9299 "sSearch": "",
9300
9301 /**
9302 * Flag to indicate if the search term should be interpreted as a
9303 * regular expression (true) or not (false) and therefore and special
9304 * regex characters escaped.
9305 * @type boolean
9306 * @default false
9307 */
9308 "bRegex": false,
9309
9310 /**
9311 * Flag to indicate if DataTables is to use its smart filtering or not.
9312 * @type boolean
9313 * @default true
9314 */
9315 "bSmart": true
9316 };
9317
9318
9319
9320
9321 /**
9322 * Template object for the way in which DataTables holds information about
9323 * each individual row. This is the object format used for the settings
9324 * aoData array.
9325 * @namespace
9326 */
9327 DataTable.models.oRow = {
9328 /**
9329 * TR element for the row
9330 * @type node
9331 * @default null
9332 */
9333 "nTr": null,
9334
9335 /**
9336 * Array of TD elements for each row. This is null until the row has been
9337 * created.
9338 * @type array nodes
9339 * @default []
9340 */
9341 "anCells": null,
9342
9343 /**
9344 * Data object from the original data source for the row. This is either
9345 * an array if using the traditional form of DataTables, or an object if
9346 * using mData options. The exact type will depend on the passed in
9347 * data from the data source, or will be an array if using DOM a data
9348 * source.
9349 * @type array|object
9350 * @default []
9351 */
9352 "_aData": [],
9353
9354 /**
9355 * Sorting data cache - this array is ostensibly the same length as the
9356 * number of columns (although each index is generated only as it is
9357 * needed), and holds the data that is used for sorting each column in the
9358 * row. We do this cache generation at the start of the sort in order that
9359 * the formatting of the sort data need be done only once for each cell
9360 * per sort. This array should not be read from or written to by anything
9361 * other than the master sorting methods.
9362 * @type array
9363 * @default null
9364 * @private
9365 */
9366 "_aSortData": null,
9367
9368 /**
9369 * Per cell filtering data cache. As per the sort data cache, used to
9370 * increase the performance of the filtering in DataTables
9371 * @type array
9372 * @default null
9373 * @private
9374 */
9375 "_aFilterData": null,
9376
9377 /**
9378 * Filtering data cache. This is the same as the cell filtering cache, but
9379 * in this case a string rather than an array. This is easily computed with
9380 * a join on `_aFilterData`, but is provided as a cache so the join isn't
9381 * needed on every search (memory traded for performance)
9382 * @type array
9383 * @default null
9384 * @private
9385 */
9386 "_sFilterRow": null,
9387
9388 /**
9389 * Cache of the class name that DataTables has applied to the row, so we
9390 * can quickly look at this variable rather than needing to do a DOM check
9391 * on className for the nTr property.
9392 * @type string
9393 * @default <i>Empty string</i>
9394 * @private
9395 */
9396 "_sRowStripe": "",
9397
9398 /**
9399 * Denote if the original data source was from the DOM, or the data source
9400 * object. This is used for invalidating data, so DataTables can
9401 * automatically read data from the original source, unless uninstructed
9402 * otherwise.
9403 * @type string
9404 * @default null
9405 * @private
9406 */
9407 "src": null,
9408
9409 /**
9410 * Index in the aoData array. This saves an indexOf lookup when we have the
9411 * object, but want to know the index
9412 * @type integer
9413 * @default -1
9414 * @private
9415 */
9416 "idx": -1
9417 };
9418
9419
9420 /**
9421 * Template object for the column information object in DataTables. This object
9422 * is held in the settings aoColumns array and contains all the information that
9423 * DataTables needs about each individual column.
9424 *
9425 * Note that this object is related to {@link DataTable.defaults.column}
9426 * but this one is the internal data store for DataTables's cache of columns.
9427 * It should NOT be manipulated outside of DataTables. Any configuration should
9428 * be done through the initialisation options.
9429 * @namespace
9430 */
9431 DataTable.models.oColumn = {
9432 /**
9433 * Column index. This could be worked out on-the-fly with $.inArray, but it
9434 * is faster to just hold it as a variable
9435 * @type integer
9436 * @default null
9437 */
9438 "idx": null,
9439
9440 /**
9441 * A list of the columns that sorting should occur on when this column
9442 * is sorted. That this property is an array allows multi-column sorting
9443 * to be defined for a column (for example first name / last name columns
9444 * would benefit from this). The values are integers pointing to the
9445 * columns to be sorted on (typically it will be a single integer pointing
9446 * at itself, but that doesn't need to be the case).
9447 * @type array
9448 */
9449 "aDataSort": null,
9450
9451 /**
9452 * Define the sorting directions that are applied to the column, in sequence
9453 * as the column is repeatedly sorted upon - i.e. the first value is used
9454 * as the sorting direction when the column if first sorted (clicked on).
9455 * Sort it again (click again) and it will move on to the next index.
9456 * Repeat until loop.
9457 * @type array
9458 */
9459 "asSorting": null,
9460
9461 /**
9462 * Flag to indicate if the column is searchable, and thus should be included
9463 * in the filtering or not.
9464 * @type boolean
9465 */
9466 "bSearchable": null,
9467
9468 /**
9469 * Flag to indicate if the column is sortable or not.
9470 * @type boolean
9471 */
9472 "bSortable": null,
9473
9474 /**
9475 * Flag to indicate if the column is currently visible in the table or not
9476 * @type boolean
9477 */
9478 "bVisible": null,
9479
9480 /**
9481 * Store for manual type assignment using the `column.type` option. This
9482 * is held in store so we can manipulate the column's `sType` property.
9483 * @type string
9484 * @default null
9485 * @private
9486 */
9487 "_sManualType": null,
9488
9489 /**
9490 * Flag to indicate if HTML5 data attributes should be used as the data
9491 * source for filtering or sorting. True is either are.
9492 * @type boolean
9493 * @default false
9494 * @private
9495 */
9496 "_bAttrSrc": false,
9497
9498 /**
9499 * Developer definable function that is called whenever a cell is created (Ajax source,
9500 * etc) or processed for input (DOM source). This can be used as a compliment to mRender
9501 * allowing you to modify the DOM element (add background colour for example) when the
9502 * element is available.
9503 * @type function
9504 * @param {element} nTd The TD node that has been created
9505 * @param {*} sData The Data for the cell
9506 * @param {array|object} oData The data for the whole row
9507 * @param {int} iRow The row index for the aoData data store
9508 * @default null
9509 */
9510 "fnCreatedCell": null,
9511
9512 /**
9513 * Function to get data from a cell in a column. You should <b>never</b>
9514 * access data directly through _aData internally in DataTables - always use
9515 * the method attached to this property. It allows mData to function as
9516 * required. This function is automatically assigned by the column
9517 * initialisation method
9518 * @type function
9519 * @param {array|object} oData The data array/object for the array
9520 * (i.e. aoData[]._aData)
9521 * @param {string} sSpecific The specific data type you want to get -
9522 * 'display', 'type' 'filter' 'sort'
9523 * @returns {*} The data for the cell from the given row's data
9524 * @default null
9525 */
9526 "fnGetData": null,
9527
9528 /**
9529 * Function to set data for a cell in the column. You should <b>never</b>
9530 * set the data directly to _aData internally in DataTables - always use
9531 * this method. It allows mData to function as required. This function
9532 * is automatically assigned by the column initialisation method
9533 * @type function
9534 * @param {array|object} oData The data array/object for the array
9535 * (i.e. aoData[]._aData)
9536 * @param {*} sValue Value to set
9537 * @default null
9538 */
9539 "fnSetData": null,
9540
9541 /**
9542 * Property to read the value for the cells in the column from the data
9543 * source array / object. If null, then the default content is used, if a
9544 * function is given then the return from the function is used.
9545 * @type function|int|string|null
9546 * @default null
9547 */
9548 "mData": null,
9549
9550 /**
9551 * Partner property to mData which is used (only when defined) to get
9552 * the data - i.e. it is basically the same as mData, but without the
9553 * 'set' option, and also the data fed to it is the result from mData.
9554 * This is the rendering method to match the data method of mData.
9555 * @type function|int|string|null
9556 * @default null
9557 */
9558 "mRender": null,
9559
9560 /**
9561 * Unique header TH/TD element for this column - this is what the sorting
9562 * listener is attached to (if sorting is enabled.)
9563 * @type node
9564 * @default null
9565 */
9566 "nTh": null,
9567
9568 /**
9569 * Unique footer TH/TD element for this column (if there is one). Not used
9570 * in DataTables as such, but can be used for plug-ins to reference the
9571 * footer for each column.
9572 * @type node
9573 * @default null
9574 */
9575 "nTf": null,
9576
9577 /**
9578 * The class to apply to all TD elements in the table's TBODY for the column
9579 * @type string
9580 * @default null
9581 */
9582 "sClass": null,
9583
9584 /**
9585 * When DataTables calculates the column widths to assign to each column,
9586 * it finds the longest string in each column and then constructs a
9587 * temporary table and reads the widths from that. The problem with this
9588 * is that "mmm" is much wider then "iiii", but the latter is a longer
9589 * string - thus the calculation can go wrong (doing it properly and putting
9590 * it into an DOM object and measuring that is horribly(!) slow). Thus as
9591 * a "work around" we provide this option. It will append its value to the
9592 * text that is found to be the longest string for the column - i.e. padding.
9593 * @type string
9594 */
9595 "sContentPadding": null,
9596
9597 /**
9598 * Allows a default value to be given for a column's data, and will be used
9599 * whenever a null data source is encountered (this can be because mData
9600 * is set to null, or because the data source itself is null).
9601 * @type string
9602 * @default null
9603 */
9604 "sDefaultContent": null,
9605
9606 /**
9607 * Name for the column, allowing reference to the column by name as well as
9608 * by index (needs a lookup to work by name).
9609 * @type string
9610 */
9611 "sName": null,
9612
9613 /**
9614 * Custom sorting data type - defines which of the available plug-ins in
9615 * afnSortData the custom sorting will use - if any is defined.
9616 * @type string
9617 * @default std
9618 */
9619 "sSortDataType": 'std',
9620
9621 /**
9622 * Class to be applied to the header element when sorting on this column
9623 * @type string
9624 * @default null
9625 */
9626 "sSortingClass": null,
9627
9628 /**
9629 * Class to be applied to the header element when sorting on this column -
9630 * when jQuery UI theming is used.
9631 * @type string
9632 * @default null
9633 */
9634 "sSortingClassJUI": null,
9635
9636 /**
9637 * Title of the column - what is seen in the TH element (nTh).
9638 * @type string
9639 */
9640 "sTitle": null,
9641
9642 /**
9643 * Column sorting and filtering type
9644 * @type string
9645 * @default null
9646 */
9647 "sType": null,
9648
9649 /**
9650 * Width of the column
9651 * @type string
9652 * @default null
9653 */
9654 "sWidth": null,
9655
9656 /**
9657 * Width of the column when it was first "encountered"
9658 * @type string
9659 * @default null
9660 */
9661 "sWidthOrig": null
9662 };
9663
9664
9665 /*
9666 * Developer note: The properties of the object below are given in Hungarian
9667 * notation, that was used as the interface for DataTables prior to v1.10, however
9668 * from v1.10 onwards the primary interface is camel case. In order to avoid
9669 * breaking backwards compatibility utterly with this change, the Hungarian
9670 * version is still, internally the primary interface, but is is not documented
9671 * - hence the @name tags in each doc comment. This allows a Javascript function
9672 * to create a map from Hungarian notation to camel case (going the other direction
9673 * would require each property to be listed, which would at around 3K to the size
9674 * of DataTables, while this method is about a 0.5K hit.
9675 *
9676 * Ultimately this does pave the way for Hungarian notation to be dropped
9677 * completely, but that is a massive amount of work and will break current
9678 * installs (therefore is on-hold until v2).
9679 */
9680
9681 /**
9682 * Initialisation options that can be given to DataTables at initialisation
9683 * time.
9684 * @namespace
9685 */
9686 DataTable.defaults = {
9687 /**
9688 * An array of data to use for the table, passed in at initialisation which
9689 * will be used in preference to any data which is already in the DOM. This is
9690 * particularly useful for constructing tables purely in Javascript, for
9691 * example with a custom Ajax call.
9692 * @type array
9693 * @default null
9694 *
9695 * @dtopt Option
9696 * @name DataTable.defaults.data
9697 *
9698 * @example
9699 * // Using a 2D array data source
9700 * $(document).ready( function () {
9701 * $('#example').dataTable( {
9702 * "data": [
9703 * ['Trident', 'Internet Explorer 4.0', 'Win 95+', 4, 'X'],
9704 * ['Trident', 'Internet Explorer 5.0', 'Win 95+', 5, 'C'],
9705 * ],
9706 * "columns": [
9707 * { "title": "Engine" },
9708 * { "title": "Browser" },
9709 * { "title": "Platform" },
9710 * { "title": "Version" },
9711 * { "title": "Grade" }
9712 * ]
9713 * } );
9714 * } );
9715 *
9716 * @example
9717 * // Using an array of objects as a data source (`data`)
9718 * $(document).ready( function () {
9719 * $('#example').dataTable( {
9720 * "data": [
9721 * {
9722 * "engine": "Trident",
9723 * "browser": "Internet Explorer 4.0",
9724 * "platform": "Win 95+",
9725 * "version": 4,
9726 * "grade": "X"
9727 * },
9728 * {
9729 * "engine": "Trident",
9730 * "browser": "Internet Explorer 5.0",
9731 * "platform": "Win 95+",
9732 * "version": 5,
9733 * "grade": "C"
9734 * }
9735 * ],
9736 * "columns": [
9737 * { "title": "Engine", "data": "engine" },
9738 * { "title": "Browser", "data": "browser" },
9739 * { "title": "Platform", "data": "platform" },
9740 * { "title": "Version", "data": "version" },
9741 * { "title": "Grade", "data": "grade" }
9742 * ]
9743 * } );
9744 * } );
9745 */
9746 "aaData": null,
9747
9748
9749 /**
9750 * If ordering is enabled, then DataTables will perform a first pass sort on
9751 * initialisation. You can define which column(s) the sort is performed
9752 * upon, and the sorting direction, with this variable. The `sorting` array
9753 * should contain an array for each column to be sorted initially containing
9754 * the column's index and a direction string ('asc' or 'desc').
9755 * @type array
9756 * @default [[0,'asc']]
9757 *
9758 * @dtopt Option
9759 * @name DataTable.defaults.order
9760 *
9761 * @example
9762 * // Sort by 3rd column first, and then 4th column
9763 * $(document).ready( function() {
9764 * $('#example').dataTable( {
9765 * "order": [[2,'asc'], [3,'desc']]
9766 * } );
9767 * } );
9768 *
9769 * // No initial sorting
9770 * $(document).ready( function() {
9771 * $('#example').dataTable( {
9772 * "order": []
9773 * } );
9774 * } );
9775 */
9776 "aaSorting": [[0,'asc']],
9777
9778
9779 /**
9780 * This parameter is basically identical to the `sorting` parameter, but
9781 * cannot be overridden by user interaction with the table. What this means
9782 * is that you could have a column (visible or hidden) which the sorting
9783 * will always be forced on first - any sorting after that (from the user)
9784 * will then be performed as required. This can be useful for grouping rows
9785 * together.
9786 * @type array
9787 * @default null
9788 *
9789 * @dtopt Option
9790 * @name DataTable.defaults.orderFixed
9791 *
9792 * @example
9793 * $(document).ready( function() {
9794 * $('#example').dataTable( {
9795 * "orderFixed": [[0,'asc']]
9796 * } );
9797 * } )
9798 */
9799 "aaSortingFixed": [],
9800
9801
9802 /**
9803 * DataTables can be instructed to load data to display in the table from a
9804 * Ajax source. This option defines how that Ajax call is made and where to.
9805 *
9806 * The `ajax` property has three different modes of operation, depending on
9807 * how it is defined. These are:
9808 *
9809 * * `string` - Set the URL from where the data should be loaded from.
9810 * * `object` - Define properties for `jQuery.ajax`.
9811 * * `function` - Custom data get function
9812 *
9813 * `string`
9814 * --------
9815 *
9816 * As a string, the `ajax` property simply defines the URL from which
9817 * DataTables will load data.
9818 *
9819 * `object`
9820 * --------
9821 *
9822 * As an object, the parameters in the object are passed to
9823 * [jQuery.ajax](http://api.jquery.com/jQuery.ajax/) allowing fine control
9824 * of the Ajax request. DataTables has a number of default parameters which
9825 * you can override using this option. Please refer to the jQuery
9826 * documentation for a full description of the options available, although
9827 * the following parameters provide additional options in DataTables or
9828 * require special consideration:
9829 *
9830 * * `data` - As with jQuery, `data` can be provided as an object, but it
9831 * can also be used as a function to manipulate the data DataTables sends
9832 * to the server. The function takes a single parameter, an object of
9833 * parameters with the values that DataTables has readied for sending. An
9834 * object may be returned which will be merged into the DataTables
9835 * defaults, or you can add the items to the object that was passed in and
9836 * not return anything from the function. This supersedes `fnServerParams`
9837 * from DataTables 1.9-.
9838 *
9839 * * `dataSrc` - By default DataTables will look for the property `data` (or
9840 * `aaData` for compatibility with DataTables 1.9-) when obtaining data
9841 * from an Ajax source or for server-side processing - this parameter
9842 * allows that property to be changed. You can use Javascript dotted
9843 * object notation to get a data source for multiple levels of nesting, or
9844 * it my be used as a function. As a function it takes a single parameter,
9845 * the JSON returned from the server, which can be manipulated as
9846 * required, with the returned value being that used by DataTables as the
9847 * data source for the table. This supersedes `sAjaxDataProp` from
9848 * DataTables 1.9-.
9849 *
9850 * * `success` - Should not be overridden it is used internally in
9851 * DataTables. To manipulate / transform the data returned by the server
9852 * use `ajax.dataSrc`, or use `ajax` as a function (see below).
9853 *
9854 * `function`
9855 * ----------
9856 *
9857 * As a function, making the Ajax call is left up to yourself allowing
9858 * complete control of the Ajax request. Indeed, if desired, a method other
9859 * than Ajax could be used to obtain the required data, such as Web storage
9860 * or an AIR database.
9861 *
9862 * The function is given four parameters and no return is required. The
9863 * parameters are:
9864 *
9865 * 1. _object_ - Data to send to the server
9866 * 2. _function_ - Callback function that must be executed when the required
9867 * data has been obtained. That data should be passed into the callback
9868 * as the only parameter
9869 * 3. _object_ - DataTables settings object for the table
9870 *
9871 * Note that this supersedes `fnServerData` from DataTables 1.9-.
9872 *
9873 * @type string|object|function
9874 * @default null
9875 *
9876 * @dtopt Option
9877 * @name DataTable.defaults.ajax
9878 * @since 1.10.0
9879 *
9880 * @example
9881 * // Get JSON data from a file via Ajax.
9882 * // Note DataTables expects data in the form `{ data: [ ...data... ] }` by default).
9883 * $('#example').dataTable( {
9884 * "ajax": "data.json"
9885 * } );
9886 *
9887 * @example
9888 * // Get JSON data from a file via Ajax, using `dataSrc` to change
9889 * // `data` to `tableData` (i.e. `{ tableData: [ ...data... ] }`)
9890 * $('#example').dataTable( {
9891 * "ajax": {
9892 * "url": "data.json",
9893 * "dataSrc": "tableData"
9894 * }
9895 * } );
9896 *
9897 * @example
9898 * // Get JSON data from a file via Ajax, using `dataSrc` to read data
9899 * // from a plain array rather than an array in an object
9900 * $('#example').dataTable( {
9901 * "ajax": {
9902 * "url": "data.json",
9903 * "dataSrc": ""
9904 * }
9905 * } );
9906 *
9907 * @example
9908 * // Manipulate the data returned from the server - add a link to data
9909 * // (note this can, should, be done using `render` for the column - this
9910 * // is just a simple example of how the data can be manipulated).
9911 * $('#example').dataTable( {
9912 * "ajax": {
9913 * "url": "data.json",
9914 * "dataSrc": function ( json ) {
9915 * for ( var i=0, ien=json.length ; i<ien ; i++ ) {
9916 * json[i][0] = '<a href="/message/'+json[i][0]+'>View message</a>';
9917 * }
9918 * return json;
9919 * }
9920 * }
9921 * } );
9922 *
9923 * @example
9924 * // Add data to the request
9925 * $('#example').dataTable( {
9926 * "ajax": {
9927 * "url": "data.json",
9928 * "data": function ( d ) {
9929 * return {
9930 * "extra_search": $('#extra').val()
9931 * };
9932 * }
9933 * }
9934 * } );
9935 *
9936 * @example
9937 * // Send request as POST
9938 * $('#example').dataTable( {
9939 * "ajax": {
9940 * "url": "data.json",
9941 * "type": "POST"
9942 * }
9943 * } );
9944 *
9945 * @example
9946 * // Get the data from localStorage (could interface with a form for
9947 * // adding, editing and removing rows).
9948 * $('#example').dataTable( {
9949 * "ajax": function (data, callback, settings) {
9950 * callback(
9951 * JSON.parse( localStorage.getItem('dataTablesData') )
9952 * );
9953 * }
9954 * } );
9955 */
9956 "ajax": null,
9957
9958
9959 /**
9960 * This parameter allows you to readily specify the entries in the length drop
9961 * down menu that DataTables shows when pagination is enabled. It can be
9962 * either a 1D array of options which will be used for both the displayed
9963 * option and the value, or a 2D array which will use the array in the first
9964 * position as the value, and the array in the second position as the
9965 * displayed options (useful for language strings such as 'All').
9966 *
9967 * Note that the `pageLength` property will be automatically set to the
9968 * first value given in this array, unless `pageLength` is also provided.
9969 * @type array
9970 * @default [ 10, 25, 50, 100 ]
9971 *
9972 * @dtopt Option
9973 * @name DataTable.defaults.lengthMenu
9974 *
9975 * @example
9976 * $(document).ready( function() {
9977 * $('#example').dataTable( {
9978 * "lengthMenu": [[10, 25, 50, -1], [10, 25, 50, "All"]]
9979 * } );
9980 * } );
9981 */
9982 "aLengthMenu": [ 10, 25, 50, 100 ],
9983
9984
9985 /**
9986 * The `columns` option in the initialisation parameter allows you to define
9987 * details about the way individual columns behave. For a full list of
9988 * column options that can be set, please see
9989 * {@link DataTable.defaults.column}. Note that if you use `columns` to
9990 * define your columns, you must have an entry in the array for every single
9991 * column that you have in your table (these can be null if you don't which
9992 * to specify any options).
9993 * @member
9994 *
9995 * @name DataTable.defaults.column
9996 */
9997 "aoColumns": null,
9998
9999 /**
10000 * Very similar to `columns`, `columnDefs` allows you to target a specific
10001 * column, multiple columns, or all columns, using the `targets` property of
10002 * each object in the array. This allows great flexibility when creating
10003 * tables, as the `columnDefs` arrays can be of any length, targeting the
10004 * columns you specifically want. `columnDefs` may use any of the column
10005 * options available: {@link DataTable.defaults.column}, but it _must_
10006 * have `targets` defined in each object in the array. Values in the `targets`
10007 * array may be:
10008 * <ul>
10009 * <li>a string - class name will be matched on the TH for the column</li>
10010 * <li>0 or a positive integer - column index counting from the left</li>
10011 * <li>a negative integer - column index counting from the right</li>
10012 * <li>the string "_all" - all columns (i.e. assign a default)</li>
10013 * </ul>
10014 * @member
10015 *
10016 * @name DataTable.defaults.columnDefs
10017 */
10018 "aoColumnDefs": null,
10019
10020
10021 /**
10022 * Basically the same as `search`, this parameter defines the individual column
10023 * filtering state at initialisation time. The array must be of the same size
10024 * as the number of columns, and each element be an object with the parameters
10025 * `search` and `escapeRegex` (the latter is optional). 'null' is also
10026 * accepted and the default will be used.
10027 * @type array
10028 * @default []
10029 *
10030 * @dtopt Option
10031 * @name DataTable.defaults.searchCols
10032 *
10033 * @example
10034 * $(document).ready( function() {
10035 * $('#example').dataTable( {
10036 * "searchCols": [
10037 * null,
10038 * { "search": "My filter" },
10039 * null,
10040 * { "search": "^[0-9]", "escapeRegex": false }
10041 * ]
10042 * } );
10043 * } )
10044 */
10045 "aoSearchCols": [],
10046
10047
10048 /**
10049 * An array of CSS classes that should be applied to displayed rows. This
10050 * array may be of any length, and DataTables will apply each class
10051 * sequentially, looping when required.
10052 * @type array
10053 * @default null <i>Will take the values determined by the `oClasses.stripe*`
10054 * options</i>
10055 *
10056 * @dtopt Option
10057 * @name DataTable.defaults.stripeClasses
10058 *
10059 * @example
10060 * $(document).ready( function() {
10061 * $('#example').dataTable( {
10062 * "stripeClasses": [ 'strip1', 'strip2', 'strip3' ]
10063 * } );
10064 * } )
10065 */
10066 "asStripeClasses": null,
10067
10068
10069 /**
10070 * Enable or disable automatic column width calculation. This can be disabled
10071 * as an optimisation (it takes some time to calculate the widths) if the
10072 * tables widths are passed in using `columns`.
10073 * @type boolean
10074 * @default true
10075 *
10076 * @dtopt Features
10077 * @name DataTable.defaults.autoWidth
10078 *
10079 * @example
10080 * $(document).ready( function () {
10081 * $('#example').dataTable( {
10082 * "autoWidth": false
10083 * } );
10084 * } );
10085 */
10086 "bAutoWidth": true,
10087
10088
10089 /**
10090 * Deferred rendering can provide DataTables with a huge speed boost when you
10091 * are using an Ajax or JS data source for the table. This option, when set to
10092 * true, will cause DataTables to defer the creation of the table elements for
10093 * each row until they are needed for a draw - saving a significant amount of
10094 * time.
10095 * @type boolean
10096 * @default false
10097 *
10098 * @dtopt Features
10099 * @name DataTable.defaults.deferRender
10100 *
10101 * @example
10102 * $(document).ready( function() {
10103 * $('#example').dataTable( {
10104 * "ajax": "sources/arrays.txt",
10105 * "deferRender": true
10106 * } );
10107 * } );
10108 */
10109 "bDeferRender": false,
10110
10111
10112 /**
10113 * Replace a DataTable which matches the given selector and replace it with
10114 * one which has the properties of the new initialisation object passed. If no
10115 * table matches the selector, then the new DataTable will be constructed as
10116 * per normal.
10117 * @type boolean
10118 * @default false
10119 *
10120 * @dtopt Options
10121 * @name DataTable.defaults.destroy
10122 *
10123 * @example
10124 * $(document).ready( function() {
10125 * $('#example').dataTable( {
10126 * "srollY": "200px",
10127 * "paginate": false
10128 * } );
10129 *
10130 * // Some time later....
10131 * $('#example').dataTable( {
10132 * "filter": false,
10133 * "destroy": true
10134 * } );
10135 * } );
10136 */
10137 "bDestroy": false,
10138
10139
10140 /**
10141 * Enable or disable filtering of data. Filtering in DataTables is "smart" in
10142 * that it allows the end user to input multiple words (space separated) and
10143 * will match a row containing those words, even if not in the order that was
10144 * specified (this allow matching across multiple columns). Note that if you
10145 * wish to use filtering in DataTables this must remain 'true' - to remove the
10146 * default filtering input box and retain filtering abilities, please use
10147 * {@link DataTable.defaults.dom}.
10148 * @type boolean
10149 * @default true
10150 *
10151 * @dtopt Features
10152 * @name DataTable.defaults.searching
10153 *
10154 * @example
10155 * $(document).ready( function () {
10156 * $('#example').dataTable( {
10157 * "searching": false
10158 * } );
10159 * } );
10160 */
10161 "bFilter": true,
10162
10163
10164 /**
10165 * Enable or disable the table information display. This shows information
10166 * about the data that is currently visible on the page, including information
10167 * about filtered data if that action is being performed.
10168 * @type boolean
10169 * @default true
10170 *
10171 * @dtopt Features
10172 * @name DataTable.defaults.info
10173 *
10174 * @example
10175 * $(document).ready( function () {
10176 * $('#example').dataTable( {
10177 * "info": false
10178 * } );
10179 * } );
10180 */
10181 "bInfo": true,
10182
10183
10184 /**
10185 * Enable jQuery UI ThemeRoller support (required as ThemeRoller requires some
10186 * slightly different and additional mark-up from what DataTables has
10187 * traditionally used).
10188 * @type boolean
10189 * @default false
10190 *
10191 * @dtopt Features
10192 * @name DataTable.defaults.jQueryUI
10193 *
10194 * @example
10195 * $(document).ready( function() {
10196 * $('#example').dataTable( {
10197 * "jQueryUI": true
10198 * } );
10199 * } );
10200 */
10201 "bJQueryUI": false,
10202
10203
10204 /**
10205 * Allows the end user to select the size of a formatted page from a select
10206 * menu (sizes are 10, 25, 50 and 100). Requires pagination (`paginate`).
10207 * @type boolean
10208 * @default true
10209 *
10210 * @dtopt Features
10211 * @name DataTable.defaults.lengthChange
10212 *
10213 * @example
10214 * $(document).ready( function () {
10215 * $('#example').dataTable( {
10216 * "lengthChange": false
10217 * } );
10218 * } );
10219 */
10220 "bLengthChange": true,
10221
10222
10223 /**
10224 * Enable or disable pagination.
10225 * @type boolean
10226 * @default true
10227 *
10228 * @dtopt Features
10229 * @name DataTable.defaults.paging
10230 *
10231 * @example
10232 * $(document).ready( function () {
10233 * $('#example').dataTable( {
10234 * "paging": false
10235 * } );
10236 * } );
10237 */
10238 "bPaginate": true,
10239
10240
10241 /**
10242 * Enable or disable the display of a 'processing' indicator when the table is
10243 * being processed (e.g. a sort). This is particularly useful for tables with
10244 * large amounts of data where it can take a noticeable amount of time to sort
10245 * the entries.
10246 * @type boolean
10247 * @default false
10248 *
10249 * @dtopt Features
10250 * @name DataTable.defaults.processing
10251 *
10252 * @example
10253 * $(document).ready( function () {
10254 * $('#example').dataTable( {
10255 * "processing": true
10256 * } );
10257 * } );
10258 */
10259 "bProcessing": false,
10260
10261
10262 /**
10263 * Retrieve the DataTables object for the given selector. Note that if the
10264 * table has already been initialised, this parameter will cause DataTables
10265 * to simply return the object that has already been set up - it will not take
10266 * account of any changes you might have made to the initialisation object
10267 * passed to DataTables (setting this parameter to true is an acknowledgement
10268 * that you understand this). `destroy` can be used to reinitialise a table if
10269 * you need.
10270 * @type boolean
10271 * @default false
10272 *
10273 * @dtopt Options
10274 * @name DataTable.defaults.retrieve
10275 *
10276 * @example
10277 * $(document).ready( function() {
10278 * initTable();
10279 * tableActions();
10280 * } );
10281 *
10282 * function initTable ()
10283 * {
10284 * return $('#example').dataTable( {
10285 * "scrollY": "200px",
10286 * "paginate": false,
10287 * "retrieve": true
10288 * } );
10289 * }
10290 *
10291 * function tableActions ()
10292 * {
10293 * var table = initTable();
10294 * // perform API operations with oTable
10295 * }
10296 */
10297 "bRetrieve": false,
10298
10299
10300 /**
10301 * When vertical (y) scrolling is enabled, DataTables will force the height of
10302 * the table's viewport to the given height at all times (useful for layout).
10303 * However, this can look odd when filtering data down to a small data set,
10304 * and the footer is left "floating" further down. This parameter (when
10305 * enabled) will cause DataTables to collapse the table's viewport down when
10306 * the result set will fit within the given Y height.
10307 * @type boolean
10308 * @default false
10309 *
10310 * @dtopt Options
10311 * @name DataTable.defaults.scrollCollapse
10312 *
10313 * @example
10314 * $(document).ready( function() {
10315 * $('#example').dataTable( {
10316 * "scrollY": "200",
10317 * "scrollCollapse": true
10318 * } );
10319 * } );
10320 */
10321 "bScrollCollapse": false,
10322
10323
10324 /**
10325 * Configure DataTables to use server-side processing. Note that the
10326 * `ajax` parameter must also be given in order to give DataTables a
10327 * source to obtain the required data for each draw.
10328 * @type boolean
10329 * @default false
10330 *
10331 * @dtopt Features
10332 * @dtopt Server-side
10333 * @name DataTable.defaults.serverSide
10334 *
10335 * @example
10336 * $(document).ready( function () {
10337 * $('#example').dataTable( {
10338 * "serverSide": true,
10339 * "ajax": "xhr.php"
10340 * } );
10341 * } );
10342 */
10343 "bServerSide": false,
10344
10345
10346 /**
10347 * Enable or disable sorting of columns. Sorting of individual columns can be
10348 * disabled by the `sortable` option for each column.
10349 * @type boolean
10350 * @default true
10351 *
10352 * @dtopt Features
10353 * @name DataTable.defaults.ordering
10354 *
10355 * @example
10356 * $(document).ready( function () {
10357 * $('#example').dataTable( {
10358 * "ordering": false
10359 * } );
10360 * } );
10361 */
10362 "bSort": true,
10363
10364
10365 /**
10366 * Enable or display DataTables' ability to sort multiple columns at the
10367 * same time (activated by shift-click by the user).
10368 * @type boolean
10369 * @default true
10370 *
10371 * @dtopt Options
10372 * @name DataTable.defaults.orderMulti
10373 *
10374 * @example
10375 * // Disable multiple column sorting ability
10376 * $(document).ready( function () {
10377 * $('#example').dataTable( {
10378 * "orderMulti": false
10379 * } );
10380 * } );
10381 */
10382 "bSortMulti": true,
10383
10384
10385 /**
10386 * Allows control over whether DataTables should use the top (true) unique
10387 * cell that is found for a single column, or the bottom (false - default).
10388 * This is useful when using complex headers.
10389 * @type boolean
10390 * @default false
10391 *
10392 * @dtopt Options
10393 * @name DataTable.defaults.orderCellsTop
10394 *
10395 * @example
10396 * $(document).ready( function() {
10397 * $('#example').dataTable( {
10398 * "orderCellsTop": true
10399 * } );
10400 * } );
10401 */
10402 "bSortCellsTop": false,
10403
10404
10405 /**
10406 * Enable or disable the addition of the classes `sorting\_1`, `sorting\_2` and
10407 * `sorting\_3` to the columns which are currently being sorted on. This is
10408 * presented as a feature switch as it can increase processing time (while
10409 * classes are removed and added) so for large data sets you might want to
10410 * turn this off.
10411 * @type boolean
10412 * @default true
10413 *
10414 * @dtopt Features
10415 * @name DataTable.defaults.orderClasses
10416 *
10417 * @example
10418 * $(document).ready( function () {
10419 * $('#example').dataTable( {
10420 * "orderClasses": false
10421 * } );
10422 * } );
10423 */
10424 "bSortClasses": true,
10425
10426
10427 /**
10428 * Enable or disable state saving. When enabled HTML5 `localStorage` will be
10429 * used to save table display information such as pagination information,
10430 * display length, filtering and sorting. As such when the end user reloads
10431 * the page the display display will match what thy had previously set up.
10432 *
10433 * Due to the use of `localStorage` the default state saving is not supported
10434 * in IE6 or 7. If state saving is required in those browsers, use
10435 * `stateSaveCallback` to provide a storage solution such as cookies.
10436 * @type boolean
10437 * @default false
10438 *
10439 * @dtopt Features
10440 * @name DataTable.defaults.stateSave
10441 *
10442 * @example
10443 * $(document).ready( function () {
10444 * $('#example').dataTable( {
10445 * "stateSave": true
10446 * } );
10447 * } );
10448 */
10449 "bStateSave": false,
10450
10451
10452 /**
10453 * This function is called when a TR element is created (and all TD child
10454 * elements have been inserted), or registered if using a DOM source, allowing
10455 * manipulation of the TR element (adding classes etc).
10456 * @type function
10457 * @param {node} row "TR" element for the current row
10458 * @param {array} data Raw data array for this row
10459 * @param {int} dataIndex The index of this row in the internal aoData array
10460 *
10461 * @dtopt Callbacks
10462 * @name DataTable.defaults.createdRow
10463 *
10464 * @example
10465 * $(document).ready( function() {
10466 * $('#example').dataTable( {
10467 * "createdRow": function( row, data, dataIndex ) {
10468 * // Bold the grade for all 'A' grade browsers
10469 * if ( data[4] == "A" )
10470 * {
10471 * $('td:eq(4)', row).html( '<b>A</b>' );
10472 * }
10473 * }
10474 * } );
10475 * } );
10476 */
10477 "fnCreatedRow": null,
10478
10479
10480 /**
10481 * This function is called on every 'draw' event, and allows you to
10482 * dynamically modify any aspect you want about the created DOM.
10483 * @type function
10484 * @param {object} settings DataTables settings object
10485 *
10486 * @dtopt Callbacks
10487 * @name DataTable.defaults.drawCallback
10488 *
10489 * @example
10490 * $(document).ready( function() {
10491 * $('#example').dataTable( {
10492 * "drawCallback": function( settings ) {
10493 * alert( 'DataTables has redrawn the table' );
10494 * }
10495 * } );
10496 * } );
10497 */
10498 "fnDrawCallback": null,
10499
10500
10501 /**
10502 * Identical to fnHeaderCallback() but for the table footer this function
10503 * allows you to modify the table footer on every 'draw' event.
10504 * @type function
10505 * @param {node} foot "TR" element for the footer
10506 * @param {array} data Full table data (as derived from the original HTML)
10507 * @param {int} start Index for the current display starting point in the
10508 * display array
10509 * @param {int} end Index for the current display ending point in the
10510 * display array
10511 * @param {array int} display Index array to translate the visual position
10512 * to the full data array
10513 *
10514 * @dtopt Callbacks
10515 * @name DataTable.defaults.footerCallback
10516 *
10517 * @example
10518 * $(document).ready( function() {
10519 * $('#example').dataTable( {
10520 * "footerCallback": function( tfoot, data, start, end, display ) {
10521 * tfoot.getElementsByTagName('th')[0].innerHTML = "Starting index is "+start;
10522 * }
10523 * } );
10524 * } )
10525 */
10526 "fnFooterCallback": null,
10527
10528
10529 /**
10530 * When rendering large numbers in the information element for the table
10531 * (i.e. "Showing 1 to 10 of 57 entries") DataTables will render large numbers
10532 * to have a comma separator for the 'thousands' units (e.g. 1 million is
10533 * rendered as "1,000,000") to help readability for the end user. This
10534 * function will override the default method DataTables uses.
10535 * @type function
10536 * @member
10537 * @param {int} toFormat number to be formatted
10538 * @returns {string} formatted string for DataTables to show the number
10539 *
10540 * @dtopt Callbacks
10541 * @name DataTable.defaults.formatNumber
10542 *
10543 * @example
10544 * // Format a number using a single quote for the separator (note that
10545 * // this can also be done with the language.thousands option)
10546 * $(document).ready( function() {
10547 * $('#example').dataTable( {
10548 * "formatNumber": function ( toFormat ) {
10549 * return toFormat.toString().replace(
10550 * /\B(?=(\d{3})+(?!\d))/g, "'"
10551 * );
10552 * };
10553 * } );
10554 * } );
10555 */
10556 "fnFormatNumber": function ( toFormat ) {
10557 return toFormat.toString().replace(
10558 /\B(?=(\d{3})+(?!\d))/g,
10559 this.oLanguage.sThousands
10560 );
10561 },
10562
10563
10564 /**
10565 * This function is called on every 'draw' event, and allows you to
10566 * dynamically modify the header row. This can be used to calculate and
10567 * display useful information about the table.
10568 * @type function
10569 * @param {node} head "TR" element for the header
10570 * @param {array} data Full table data (as derived from the original HTML)
10571 * @param {int} start Index for the current display starting point in the
10572 * display array
10573 * @param {int} end Index for the current display ending point in the
10574 * display array
10575 * @param {array int} display Index array to translate the visual position
10576 * to the full data array
10577 *
10578 * @dtopt Callbacks
10579 * @name DataTable.defaults.headerCallback
10580 *
10581 * @example
10582 * $(document).ready( function() {
10583 * $('#example').dataTable( {
10584 * "fheaderCallback": function( head, data, start, end, display ) {
10585 * head.getElementsByTagName('th')[0].innerHTML = "Displaying "+(end-start)+" records";
10586 * }
10587 * } );
10588 * } )
10589 */
10590 "fnHeaderCallback": null,
10591
10592
10593 /**
10594 * The information element can be used to convey information about the current
10595 * state of the table. Although the internationalisation options presented by
10596 * DataTables are quite capable of dealing with most customisations, there may
10597 * be times where you wish to customise the string further. This callback
10598 * allows you to do exactly that.
10599 * @type function
10600 * @param {object} oSettings DataTables settings object
10601 * @param {int} start Starting position in data for the draw
10602 * @param {int} end End position in data for the draw
10603 * @param {int} max Total number of rows in the table (regardless of
10604 * filtering)
10605 * @param {int} total Total number of rows in the data set, after filtering
10606 * @param {string} pre The string that DataTables has formatted using it's
10607 * own rules
10608 * @returns {string} The string to be displayed in the information element.
10609 *
10610 * @dtopt Callbacks
10611 * @name DataTable.defaults.infoCallback
10612 *
10613 * @example
10614 * $('#example').dataTable( {
10615 * "infoCallback": function( settings, start, end, max, total, pre ) {
10616 * return start +" to "+ end;
10617 * }
10618 * } );
10619 */
10620 "fnInfoCallback": null,
10621
10622
10623 /**
10624 * Called when the table has been initialised. Normally DataTables will
10625 * initialise sequentially and there will be no need for this function,
10626 * however, this does not hold true when using external language information
10627 * since that is obtained using an async XHR call.
10628 * @type function
10629 * @param {object} settings DataTables settings object
10630 * @param {object} json The JSON object request from the server - only
10631 * present if client-side Ajax sourced data is used
10632 *
10633 * @dtopt Callbacks
10634 * @name DataTable.defaults.initComplete
10635 *
10636 * @example
10637 * $(document).ready( function() {
10638 * $('#example').dataTable( {
10639 * "initComplete": function(settings, json) {
10640 * alert( 'DataTables has finished its initialisation.' );
10641 * }
10642 * } );
10643 * } )
10644 */
10645 "fnInitComplete": null,
10646
10647
10648 /**
10649 * Called at the very start of each table draw and can be used to cancel the
10650 * draw by returning false, any other return (including undefined) results in
10651 * the full draw occurring).
10652 * @type function
10653 * @param {object} settings DataTables settings object
10654 * @returns {boolean} False will cancel the draw, anything else (including no
10655 * return) will allow it to complete.
10656 *
10657 * @dtopt Callbacks
10658 * @name DataTable.defaults.preDrawCallback
10659 *
10660 * @example
10661 * $(document).ready( function() {
10662 * $('#example').dataTable( {
10663 * "preDrawCallback": function( settings ) {
10664 * if ( $('#test').val() == 1 ) {
10665 * return false;
10666 * }
10667 * }
10668 * } );
10669 * } );
10670 */
10671 "fnPreDrawCallback": null,
10672
10673
10674 /**
10675 * This function allows you to 'post process' each row after it have been
10676 * generated for each table draw, but before it is rendered on screen. This
10677 * function might be used for setting the row class name etc.
10678 * @type function
10679 * @param {node} row "TR" element for the current row
10680 * @param {array} data Raw data array for this row
10681 * @param {int} displayIndex The display index for the current table draw
10682 * @param {int} displayIndexFull The index of the data in the full list of
10683 * rows (after filtering)
10684 *
10685 * @dtopt Callbacks
10686 * @name DataTable.defaults.rowCallback
10687 *
10688 * @example
10689 * $(document).ready( function() {
10690 * $('#example').dataTable( {
10691 * "rowCallback": function( row, data, displayIndex, displayIndexFull ) {
10692 * // Bold the grade for all 'A' grade browsers
10693 * if ( data[4] == "A" ) {
10694 * $('td:eq(4)', row).html( '<b>A</b>' );
10695 * }
10696 * }
10697 * } );
10698 * } );
10699 */
10700 "fnRowCallback": null,
10701
10702
10703 /**
10704 * __Deprecated__ The functionality provided by this parameter has now been
10705 * superseded by that provided through `ajax`, which should be used instead.
10706 *
10707 * This parameter allows you to override the default function which obtains
10708 * the data from the server so something more suitable for your application.
10709 * For example you could use POST data, or pull information from a Gears or
10710 * AIR database.
10711 * @type function
10712 * @member
10713 * @param {string} source HTTP source to obtain the data from (`ajax`)
10714 * @param {array} data A key/value pair object containing the data to send
10715 * to the server
10716 * @param {function} callback to be called on completion of the data get
10717 * process that will draw the data on the page.
10718 * @param {object} settings DataTables settings object
10719 *
10720 * @dtopt Callbacks
10721 * @dtopt Server-side
10722 * @name DataTable.defaults.serverData
10723 *
10724 * @deprecated 1.10. Please use `ajax` for this functionality now.
10725 */
10726 "fnServerData": null,
10727
10728
10729 /**
10730 * __Deprecated__ The functionality provided by this parameter has now been
10731 * superseded by that provided through `ajax`, which should be used instead.
10732 *
10733 * It is often useful to send extra data to the server when making an Ajax
10734 * request - for example custom filtering information, and this callback
10735 * function makes it trivial to send extra information to the server. The
10736 * passed in parameter is the data set that has been constructed by
10737 * DataTables, and you can add to this or modify it as you require.
10738 * @type function
10739 * @param {array} data Data array (array of objects which are name/value
10740 * pairs) that has been constructed by DataTables and will be sent to the
10741 * server. In the case of Ajax sourced data with server-side processing
10742 * this will be an empty array, for server-side processing there will be a
10743 * significant number of parameters!
10744 * @returns {undefined} Ensure that you modify the data array passed in,
10745 * as this is passed by reference.
10746 *
10747 * @dtopt Callbacks
10748 * @dtopt Server-side
10749 * @name DataTable.defaults.serverParams
10750 *
10751 * @deprecated 1.10. Please use `ajax` for this functionality now.
10752 */
10753 "fnServerParams": null,
10754
10755
10756 /**
10757 * Load the table state. With this function you can define from where, and how, the
10758 * state of a table is loaded. By default DataTables will load from `localStorage`
10759 * but you might wish to use a server-side database or cookies.
10760 * @type function
10761 * @member
10762 * @param {object} settings DataTables settings object
10763 * @return {object} The DataTables state object to be loaded
10764 *
10765 * @dtopt Callbacks
10766 * @name DataTable.defaults.stateLoadCallback
10767 *
10768 * @example
10769 * $(document).ready( function() {
10770 * $('#example').dataTable( {
10771 * "stateSave": true,
10772 * "stateLoadCallback": function (settings) {
10773 * var o;
10774 *
10775 * // Send an Ajax request to the server to get the data. Note that
10776 * // this is a synchronous request.
10777 * $.ajax( {
10778 * "url": "/state_load",
10779 * "async": false,
10780 * "dataType": "json",
10781 * "success": function (json) {
10782 * o = json;
10783 * }
10784 * } );
10785 *
10786 * return o;
10787 * }
10788 * } );
10789 * } );
10790 */
10791 "fnStateLoadCallback": function ( settings ) {
10792 try {
10793 return JSON.parse(
10794 (settings.iStateDuration === -1 ? sessionStorage : localStorage).getItem(
10795 'DataTables_'+settings.sInstance+'_'+location.pathname
10796 )
10797 );
10798 } catch (e) {}
10799 },
10800
10801
10802 /**
10803 * Callback which allows modification of the saved state prior to loading that state.
10804 * This callback is called when the table is loading state from the stored data, but
10805 * prior to the settings object being modified by the saved state. Note that for
10806 * plug-in authors, you should use the `stateLoadParams` event to load parameters for
10807 * a plug-in.
10808 * @type function
10809 * @param {object} settings DataTables settings object
10810 * @param {object} data The state object that is to be loaded
10811 *
10812 * @dtopt Callbacks
10813 * @name DataTable.defaults.stateLoadParams
10814 *
10815 * @example
10816 * // Remove a saved filter, so filtering is never loaded
10817 * $(document).ready( function() {
10818 * $('#example').dataTable( {
10819 * "stateSave": true,
10820 * "stateLoadParams": function (settings, data) {
10821 * data.oSearch.sSearch = "";
10822 * }
10823 * } );
10824 * } );
10825 *
10826 * @example
10827 * // Disallow state loading by returning false
10828 * $(document).ready( function() {
10829 * $('#example').dataTable( {
10830 * "stateSave": true,
10831 * "stateLoadParams": function (settings, data) {
10832 * return false;
10833 * }
10834 * } );
10835 * } );
10836 */
10837 "fnStateLoadParams": null,
10838
10839
10840 /**
10841 * Callback that is called when the state has been loaded from the state saving method
10842 * and the DataTables settings object has been modified as a result of the loaded state.
10843 * @type function
10844 * @param {object} settings DataTables settings object
10845 * @param {object} data The state object that was loaded
10846 *
10847 * @dtopt Callbacks
10848 * @name DataTable.defaults.stateLoaded
10849 *
10850 * @example
10851 * // Show an alert with the filtering value that was saved
10852 * $(document).ready( function() {
10853 * $('#example').dataTable( {
10854 * "stateSave": true,
10855 * "stateLoaded": function (settings, data) {
10856 * alert( 'Saved filter was: '+data.oSearch.sSearch );
10857 * }
10858 * } );
10859 * } );
10860 */
10861 "fnStateLoaded": null,
10862
10863
10864 /**
10865 * Save the table state. This function allows you to define where and how the state
10866 * information for the table is stored By default DataTables will use `localStorage`
10867 * but you might wish to use a server-side database or cookies.
10868 * @type function
10869 * @member
10870 * @param {object} settings DataTables settings object
10871 * @param {object} data The state object to be saved
10872 *
10873 * @dtopt Callbacks
10874 * @name DataTable.defaults.stateSaveCallback
10875 *
10876 * @example
10877 * $(document).ready( function() {
10878 * $('#example').dataTable( {
10879 * "stateSave": true,
10880 * "stateSaveCallback": function (settings, data) {
10881 * // Send an Ajax request to the server with the state object
10882 * $.ajax( {
10883 * "url": "/state_save",
10884 * "data": data,
10885 * "dataType": "json",
10886 * "method": "POST"
10887 * "success": function () {}
10888 * } );
10889 * }
10890 * } );
10891 * } );
10892 */
10893 "fnStateSaveCallback": function ( settings, data ) {
10894 try {
10895 (settings.iStateDuration === -1 ? sessionStorage : localStorage).setItem(
10896 'DataTables_'+settings.sInstance+'_'+location.pathname,
10897 JSON.stringify( data )
10898 );
10899 } catch (e) {}
10900 },
10901
10902
10903 /**
10904 * Callback which allows modification of the state to be saved. Called when the table
10905 * has changed state a new state save is required. This method allows modification of
10906 * the state saving object prior to actually doing the save, including addition or
10907 * other state properties or modification. Note that for plug-in authors, you should
10908 * use the `stateSaveParams` event to save parameters for a plug-in.
10909 * @type function
10910 * @param {object} settings DataTables settings object
10911 * @param {object} data The state object to be saved
10912 *
10913 * @dtopt Callbacks
10914 * @name DataTable.defaults.stateSaveParams
10915 *
10916 * @example
10917 * // Remove a saved filter, so filtering is never saved
10918 * $(document).ready( function() {
10919 * $('#example').dataTable( {
10920 * "stateSave": true,
10921 * "stateSaveParams": function (settings, data) {
10922 * data.oSearch.sSearch = "";
10923 * }
10924 * } );
10925 * } );
10926 */
10927 "fnStateSaveParams": null,
10928
10929
10930 /**
10931 * Duration for which the saved state information is considered valid. After this period
10932 * has elapsed the state will be returned to the default.
10933 * Value is given in seconds.
10934 * @type int
10935 * @default 7200 <i>(2 hours)</i>
10936 *
10937 * @dtopt Options
10938 * @name DataTable.defaults.stateDuration
10939 *
10940 * @example
10941 * $(document).ready( function() {
10942 * $('#example').dataTable( {
10943 * "stateDuration": 60*60*24; // 1 day
10944 * } );
10945 * } )
10946 */
10947 "iStateDuration": 7200,
10948
10949
10950 /**
10951 * When enabled DataTables will not make a request to the server for the first
10952 * page draw - rather it will use the data already on the page (no sorting etc
10953 * will be applied to it), thus saving on an XHR at load time. `deferLoading`
10954 * is used to indicate that deferred loading is required, but it is also used
10955 * to tell DataTables how many records there are in the full table (allowing
10956 * the information element and pagination to be displayed correctly). In the case
10957 * where a filtering is applied to the table on initial load, this can be
10958 * indicated by giving the parameter as an array, where the first element is
10959 * the number of records available after filtering and the second element is the
10960 * number of records without filtering (allowing the table information element
10961 * to be shown correctly).
10962 * @type int | array
10963 * @default null
10964 *
10965 * @dtopt Options
10966 * @name DataTable.defaults.deferLoading
10967 *
10968 * @example
10969 * // 57 records available in the table, no filtering applied
10970 * $(document).ready( function() {
10971 * $('#example').dataTable( {
10972 * "serverSide": true,
10973 * "ajax": "scripts/server_processing.php",
10974 * "deferLoading": 57
10975 * } );
10976 * } );
10977 *
10978 * @example
10979 * // 57 records after filtering, 100 without filtering (an initial filter applied)
10980 * $(document).ready( function() {
10981 * $('#example').dataTable( {
10982 * "serverSide": true,
10983 * "ajax": "scripts/server_processing.php",
10984 * "deferLoading": [ 57, 100 ],
10985 * "search": {
10986 * "search": "my_filter"
10987 * }
10988 * } );
10989 * } );
10990 */
10991 "iDeferLoading": null,
10992
10993
10994 /**
10995 * Number of rows to display on a single page when using pagination. If
10996 * feature enabled (`lengthChange`) then the end user will be able to override
10997 * this to a custom setting using a pop-up menu.
10998 * @type int
10999 * @default 10
11000 *
11001 * @dtopt Options
11002 * @name DataTable.defaults.pageLength
11003 *
11004 * @example
11005 * $(document).ready( function() {
11006 * $('#example').dataTable( {
11007 * "pageLength": 50
11008 * } );
11009 * } )
11010 */
11011 "iDisplayLength": 10,
11012
11013
11014 /**
11015 * Define the starting point for data display when using DataTables with
11016 * pagination. Note that this parameter is the number of records, rather than
11017 * the page number, so if you have 10 records per page and want to start on
11018 * the third page, it should be "20".
11019 * @type int
11020 * @default 0
11021 *
11022 * @dtopt Options
11023 * @name DataTable.defaults.displayStart
11024 *
11025 * @example
11026 * $(document).ready( function() {
11027 * $('#example').dataTable( {
11028 * "displayStart": 20
11029 * } );
11030 * } )
11031 */
11032 "iDisplayStart": 0,
11033
11034
11035 /**
11036 * By default DataTables allows keyboard navigation of the table (sorting, paging,
11037 * and filtering) by adding a `tabindex` attribute to the required elements. This
11038 * allows you to tab through the controls and press the enter key to activate them.
11039 * The tabindex is default 0, meaning that the tab follows the flow of the document.
11040 * You can overrule this using this parameter if you wish. Use a value of -1 to
11041 * disable built-in keyboard navigation.
11042 * @type int
11043 * @default 0
11044 *
11045 * @dtopt Options
11046 * @name DataTable.defaults.tabIndex
11047 *
11048 * @example
11049 * $(document).ready( function() {
11050 * $('#example').dataTable( {
11051 * "tabIndex": 1
11052 * } );
11053 * } );
11054 */
11055 "iTabIndex": 0,
11056
11057
11058 /**
11059 * Classes that DataTables assigns to the various components and features
11060 * that it adds to the HTML table. This allows classes to be configured
11061 * during initialisation in addition to through the static
11062 * {@link DataTable.ext.oStdClasses} object).
11063 * @namespace
11064 * @name DataTable.defaults.classes
11065 */
11066 "oClasses": {},
11067
11068
11069 /**
11070 * All strings that DataTables uses in the user interface that it creates
11071 * are defined in this object, allowing you to modified them individually or
11072 * completely replace them all as required.
11073 * @namespace
11074 * @name DataTable.defaults.language
11075 */
11076 "oLanguage": {
11077 /**
11078 * Strings that are used for WAI-ARIA labels and controls only (these are not
11079 * actually visible on the page, but will be read by screenreaders, and thus
11080 * must be internationalised as well).
11081 * @namespace
11082 * @name DataTable.defaults.language.aria
11083 */
11084 "oAria": {
11085 /**
11086 * ARIA label that is added to the table headers when the column may be
11087 * sorted ascending by activing the column (click or return when focused).
11088 * Note that the column header is prefixed to this string.
11089 * @type string
11090 * @default : activate to sort column ascending
11091 *
11092 * @dtopt Language
11093 * @name DataTable.defaults.language.aria.sortAscending
11094 *
11095 * @example
11096 * $(document).ready( function() {
11097 * $('#example').dataTable( {
11098 * "language": {
11099 * "aria": {
11100 * "sortAscending": " - click/return to sort ascending"
11101 * }
11102 * }
11103 * } );
11104 * } );
11105 */
11106 "sSortAscending": ": activate to sort column ascending",
11107
11108 /**
11109 * ARIA label that is added to the table headers when the column may be
11110 * sorted descending by activing the column (click or return when focused).
11111 * Note that the column header is prefixed to this string.
11112 * @type string
11113 * @default : activate to sort column ascending
11114 *
11115 * @dtopt Language
11116 * @name DataTable.defaults.language.aria.sortDescending
11117 *
11118 * @example
11119 * $(document).ready( function() {
11120 * $('#example').dataTable( {
11121 * "language": {
11122 * "aria": {
11123 * "sortDescending": " - click/return to sort descending"
11124 * }
11125 * }
11126 * } );
11127 * } );
11128 */
11129 "sSortDescending": ": activate to sort column descending"
11130 },
11131
11132 /**
11133 * Pagination string used by DataTables for the built-in pagination
11134 * control types.
11135 * @namespace
11136 * @name DataTable.defaults.language.paginate
11137 */
11138 "oPaginate": {
11139 /**
11140 * Text to use when using the 'full_numbers' type of pagination for the
11141 * button to take the user to the first page.
11142 * @type string
11143 * @default First
11144 *
11145 * @dtopt Language
11146 * @name DataTable.defaults.language.paginate.first
11147 *
11148 * @example
11149 * $(document).ready( function() {
11150 * $('#example').dataTable( {
11151 * "language": {
11152 * "paginate": {
11153 * "first": "First page"
11154 * }
11155 * }
11156 * } );
11157 * } );
11158 */
11159 "sFirst": "First",
11160
11161
11162 /**
11163 * Text to use when using the 'full_numbers' type of pagination for the
11164 * button to take the user to the last page.
11165 * @type string
11166 * @default Last
11167 *
11168 * @dtopt Language
11169 * @name DataTable.defaults.language.paginate.last
11170 *
11171 * @example
11172 * $(document).ready( function() {
11173 * $('#example').dataTable( {
11174 * "language": {
11175 * "paginate": {
11176 * "last": "Last page"
11177 * }
11178 * }
11179 * } );
11180 * } );
11181 */
11182 "sLast": "Last",
11183
11184
11185 /**
11186 * Text to use for the 'next' pagination button (to take the user to the
11187 * next page).
11188 * @type string
11189 * @default Next
11190 *
11191 * @dtopt Language
11192 * @name DataTable.defaults.language.paginate.next
11193 *
11194 * @example
11195 * $(document).ready( function() {
11196 * $('#example').dataTable( {
11197 * "language": {
11198 * "paginate": {
11199 * "next": "Next page"
11200 * }
11201 * }
11202 * } );
11203 * } );
11204 */
11205 "sNext": "Next",
11206
11207
11208 /**
11209 * Text to use for the 'previous' pagination button (to take the user to
11210 * the previous page).
11211 * @type string
11212 * @default Previous
11213 *
11214 * @dtopt Language
11215 * @name DataTable.defaults.language.paginate.previous
11216 *
11217 * @example
11218 * $(document).ready( function() {
11219 * $('#example').dataTable( {
11220 * "language": {
11221 * "paginate": {
11222 * "previous": "Previous page"
11223 * }
11224 * }
11225 * } );
11226 * } );
11227 */
11228 "sPrevious": "Previous"
11229 },
11230
11231 /**
11232 * This string is shown in preference to `zeroRecords` when the table is
11233 * empty of data (regardless of filtering). Note that this is an optional
11234 * parameter - if it is not given, the value of `zeroRecords` will be used
11235 * instead (either the default or given value).
11236 * @type string
11237 * @default No data available in table
11238 *
11239 * @dtopt Language
11240 * @name DataTable.defaults.language.emptyTable
11241 *
11242 * @example
11243 * $(document).ready( function() {
11244 * $('#example').dataTable( {
11245 * "language": {
11246 * "emptyTable": "No data available in table"
11247 * }
11248 * } );
11249 * } );
11250 */
11251 "sEmptyTable": "No data available in table",
11252
11253
11254 /**
11255 * This string gives information to the end user about the information
11256 * that is current on display on the page. The following tokens can be
11257 * used in the string and will be dynamically replaced as the table
11258 * display updates. This tokens can be placed anywhere in the string, or
11259 * removed as needed by the language requires:
11260 *
11261 * * `\_START\_` - Display index of the first record on the current page
11262 * * `\_END\_` - Display index of the last record on the current page
11263 * * `\_TOTAL\_` - Number of records in the table after filtering
11264 * * `\_MAX\_` - Number of records in the table without filtering
11265 * * `\_PAGE\_` - Current page number
11266 * * `\_PAGES\_` - Total number of pages of data in the table
11267 *
11268 * @type string
11269 * @default Showing _START_ to _END_ of _TOTAL_ entries
11270 *
11271 * @dtopt Language
11272 * @name DataTable.defaults.language.info
11273 *
11274 * @example
11275 * $(document).ready( function() {
11276 * $('#example').dataTable( {
11277 * "language": {
11278 * "info": "Showing page _PAGE_ of _PAGES_"
11279 * }
11280 * } );
11281 * } );
11282 */
11283 "sInfo": "Showing _START_ to _END_ of _TOTAL_ entries",
11284
11285
11286 /**
11287 * Display information string for when the table is empty. Typically the
11288 * format of this string should match `info`.
11289 * @type string
11290 * @default Showing 0 to 0 of 0 entries
11291 *
11292 * @dtopt Language
11293 * @name DataTable.defaults.language.infoEmpty
11294 *
11295 * @example
11296 * $(document).ready( function() {
11297 * $('#example').dataTable( {
11298 * "language": {
11299 * "infoEmpty": "No entries to show"
11300 * }
11301 * } );
11302 * } );
11303 */
11304 "sInfoEmpty": "Showing 0 to 0 of 0 entries",
11305
11306
11307 /**
11308 * When a user filters the information in a table, this string is appended
11309 * to the information (`info`) to give an idea of how strong the filtering
11310 * is. The variable _MAX_ is dynamically updated.
11311 * @type string
11312 * @default (filtered from _MAX_ total entries)
11313 *
11314 * @dtopt Language
11315 * @name DataTable.defaults.language.infoFiltered
11316 *
11317 * @example
11318 * $(document).ready( function() {
11319 * $('#example').dataTable( {
11320 * "language": {
11321 * "infoFiltered": " - filtering from _MAX_ records"
11322 * }
11323 * } );
11324 * } );
11325 */
11326 "sInfoFiltered": "(filtered from _MAX_ total entries)",
11327
11328
11329 /**
11330 * If can be useful to append extra information to the info string at times,
11331 * and this variable does exactly that. This information will be appended to
11332 * the `info` (`infoEmpty` and `infoFiltered` in whatever combination they are
11333 * being used) at all times.
11334 * @type string
11335 * @default <i>Empty string</i>
11336 *
11337 * @dtopt Language
11338 * @name DataTable.defaults.language.infoPostFix
11339 *
11340 * @example
11341 * $(document).ready( function() {
11342 * $('#example').dataTable( {
11343 * "language": {
11344 * "infoPostFix": "All records shown are derived from real information."
11345 * }
11346 * } );
11347 * } );
11348 */
11349 "sInfoPostFix": "",
11350
11351
11352 /**
11353 * This decimal place operator is a little different from the other
11354 * language options since DataTables doesn't output floating point
11355 * numbers, so it won't ever use this for display of a number. Rather,
11356 * what this parameter does is modify the sort methods of the table so
11357 * that numbers which are in a format which has a character other than
11358 * a period (`.`) as a decimal place will be sorted numerically.
11359 *
11360 * Note that numbers with different decimal places cannot be shown in
11361 * the same table and still be sortable, the table must be consistent.
11362 * However, multiple different tables on the page can use different
11363 * decimal place characters.
11364 * @type string
11365 * @default
11366 *
11367 * @dtopt Language
11368 * @name DataTable.defaults.language.decimal
11369 *
11370 * @example
11371 * $(document).ready( function() {
11372 * $('#example').dataTable( {
11373 * "language": {
11374 * "decimal": ","
11375 * "thousands": "."
11376 * }
11377 * } );
11378 * } );
11379 */
11380 "sDecimal": "",
11381
11382
11383 /**
11384 * DataTables has a build in number formatter (`formatNumber`) which is
11385 * used to format large numbers that are used in the table information.
11386 * By default a comma is used, but this can be trivially changed to any
11387 * character you wish with this parameter.
11388 * @type string
11389 * @default ,
11390 *
11391 * @dtopt Language
11392 * @name DataTable.defaults.language.thousands
11393 *
11394 * @example
11395 * $(document).ready( function() {
11396 * $('#example').dataTable( {
11397 * "language": {
11398 * "thousands": "'"
11399 * }
11400 * } );
11401 * } );
11402 */
11403 "sThousands": ",",
11404
11405
11406 /**
11407 * Detail the action that will be taken when the drop down menu for the
11408 * pagination length option is changed. The '_MENU_' variable is replaced
11409 * with a default select list of 10, 25, 50 and 100, and can be replaced
11410 * with a custom select box if required.
11411 * @type string
11412 * @default Show _MENU_ entries
11413 *
11414 * @dtopt Language
11415 * @name DataTable.defaults.language.lengthMenu
11416 *
11417 * @example
11418 * // Language change only
11419 * $(document).ready( function() {
11420 * $('#example').dataTable( {
11421 * "language": {
11422 * "lengthMenu": "Display _MENU_ records"
11423 * }
11424 * } );
11425 * } );
11426 *
11427 * @example
11428 * // Language and options change
11429 * $(document).ready( function() {
11430 * $('#example').dataTable( {
11431 * "language": {
11432 * "lengthMenu": 'Display <select>'+
11433 * '<option value="10">10</option>'+
11434 * '<option value="20">20</option>'+
11435 * '<option value="30">30</option>'+
11436 * '<option value="40">40</option>'+
11437 * '<option value="50">50</option>'+
11438 * '<option value="-1">All</option>'+
11439 * '</select> records'
11440 * }
11441 * } );
11442 * } );
11443 */
11444 "sLengthMenu": "Show _MENU_ entries",
11445
11446
11447 /**
11448 * When using Ajax sourced data and during the first draw when DataTables is
11449 * gathering the data, this message is shown in an empty row in the table to
11450 * indicate to the end user the the data is being loaded. Note that this
11451 * parameter is not used when loading data by server-side processing, just
11452 * Ajax sourced data with client-side processing.
11453 * @type string
11454 * @default Loading...
11455 *
11456 * @dtopt Language
11457 * @name DataTable.defaults.language.loadingRecords
11458 *
11459 * @example
11460 * $(document).ready( function() {
11461 * $('#example').dataTable( {
11462 * "language": {
11463 * "loadingRecords": "Please wait - loading..."
11464 * }
11465 * } );
11466 * } );
11467 */
11468 "sLoadingRecords": "Loading...",
11469
11470
11471 /**
11472 * Text which is displayed when the table is processing a user action
11473 * (usually a sort command or similar).
11474 * @type string
11475 * @default Processing...
11476 *
11477 * @dtopt Language
11478 * @name DataTable.defaults.language.processing
11479 *
11480 * @example
11481 * $(document).ready( function() {
11482 * $('#example').dataTable( {
11483 * "language": {
11484 * "processing": "DataTables is currently busy"
11485 * }
11486 * } );
11487 * } );
11488 */
11489 "sProcessing": "Processing...",
11490
11491
11492 /**
11493 * Details the actions that will be taken when the user types into the
11494 * filtering input text box. The variable "_INPUT_", if used in the string,
11495 * is replaced with the HTML text box for the filtering input allowing
11496 * control over where it appears in the string. If "_INPUT_" is not given
11497 * then the input box is appended to the string automatically.
11498 * @type string
11499 * @default Search:
11500 *
11501 * @dtopt Language
11502 * @name DataTable.defaults.language.search
11503 *
11504 * @example
11505 * // Input text box will be appended at the end automatically
11506 * $(document).ready( function() {
11507 * $('#example').dataTable( {
11508 * "language": {
11509 * "search": "Filter records:"
11510 * }
11511 * } );
11512 * } );
11513 *
11514 * @example
11515 * // Specify where the filter should appear
11516 * $(document).ready( function() {
11517 * $('#example').dataTable( {
11518 * "language": {
11519 * "search": "Apply filter _INPUT_ to table"
11520 * }
11521 * } );
11522 * } );
11523 */
11524 "sSearch": "Search:",
11525
11526
11527 /**
11528 * Assign a `placeholder` attribute to the search `input` element
11529 * @type string
11530 * @default
11531 *
11532 * @dtopt Language
11533 * @name DataTable.defaults.language.searchPlaceholder
11534 */
11535 "sSearchPlaceholder": "",
11536
11537
11538 /**
11539 * All of the language information can be stored in a file on the
11540 * server-side, which DataTables will look up if this parameter is passed.
11541 * It must store the URL of the language file, which is in a JSON format,
11542 * and the object has the same properties as the oLanguage object in the
11543 * initialiser object (i.e. the above parameters). Please refer to one of
11544 * the example language files to see how this works in action.
11545 * @type string
11546 * @default <i>Empty string - i.e. disabled</i>
11547 *
11548 * @dtopt Language
11549 * @name DataTable.defaults.language.url
11550 *
11551 * @example
11552 * $(document).ready( function() {
11553 * $('#example').dataTable( {
11554 * "language": {
11555 * "url": "http://www.sprymedia.co.uk/dataTables/lang.txt"
11556 * }
11557 * } );
11558 * } );
11559 */
11560 "sUrl": "",
11561
11562
11563 /**
11564 * Text shown inside the table records when the is no information to be
11565 * displayed after filtering. `emptyTable` is shown when there is simply no
11566 * information in the table at all (regardless of filtering).
11567 * @type string
11568 * @default No matching records found
11569 *
11570 * @dtopt Language
11571 * @name DataTable.defaults.language.zeroRecords
11572 *
11573 * @example
11574 * $(document).ready( function() {
11575 * $('#example').dataTable( {
11576 * "language": {
11577 * "zeroRecords": "No records to display"
11578 * }
11579 * } );
11580 * } );
11581 */
11582 "sZeroRecords": "No matching records found"
11583 },
11584
11585
11586 /**
11587 * This parameter allows you to have define the global filtering state at
11588 * initialisation time. As an object the `search` parameter must be
11589 * defined, but all other parameters are optional. When `regex` is true,
11590 * the search string will be treated as a regular expression, when false
11591 * (default) it will be treated as a straight string. When `smart`
11592 * DataTables will use it's smart filtering methods (to word match at
11593 * any point in the data), when false this will not be done.
11594 * @namespace
11595 * @extends DataTable.models.oSearch
11596 *
11597 * @dtopt Options
11598 * @name DataTable.defaults.search
11599 *
11600 * @example
11601 * $(document).ready( function() {
11602 * $('#example').dataTable( {
11603 * "search": {"search": "Initial search"}
11604 * } );
11605 * } )
11606 */
11607 "oSearch": $.extend( {}, DataTable.models.oSearch ),
11608
11609
11610 /**
11611 * __Deprecated__ The functionality provided by this parameter has now been
11612 * superseded by that provided through `ajax`, which should be used instead.
11613 *
11614 * By default DataTables will look for the property `data` (or `aaData` for
11615 * compatibility with DataTables 1.9-) when obtaining data from an Ajax
11616 * source or for server-side processing - this parameter allows that
11617 * property to be changed. You can use Javascript dotted object notation to
11618 * get a data source for multiple levels of nesting.
11619 * @type string
11620 * @default data
11621 *
11622 * @dtopt Options
11623 * @dtopt Server-side
11624 * @name DataTable.defaults.ajaxDataProp
11625 *
11626 * @deprecated 1.10. Please use `ajax` for this functionality now.
11627 */
11628 "sAjaxDataProp": "data",
11629
11630
11631 /**
11632 * __Deprecated__ The functionality provided by this parameter has now been
11633 * superseded by that provided through `ajax`, which should be used instead.
11634 *
11635 * You can instruct DataTables to load data from an external
11636 * source using this parameter (use aData if you want to pass data in you
11637 * already have). Simply provide a url a JSON object can be obtained from.
11638 * @type string
11639 * @default null
11640 *
11641 * @dtopt Options
11642 * @dtopt Server-side
11643 * @name DataTable.defaults.ajaxSource
11644 *
11645 * @deprecated 1.10. Please use `ajax` for this functionality now.
11646 */
11647 "sAjaxSource": null,
11648
11649
11650 /**
11651 * This initialisation variable allows you to specify exactly where in the
11652 * DOM you want DataTables to inject the various controls it adds to the page
11653 * (for example you might want the pagination controls at the top of the
11654 * table). DIV elements (with or without a custom class) can also be added to
11655 * aid styling. The follow syntax is used:
11656 * <ul>
11657 * <li>The following options are allowed:
11658 * <ul>
11659 * <li>'l' - Length changing</li>
11660 * <li>'f' - Filtering input</li>
11661 * <li>'t' - The table!</li>
11662 * <li>'i' - Information</li>
11663 * <li>'p' - Pagination</li>
11664 * <li>'r' - pRocessing</li>
11665 * </ul>
11666 * </li>
11667 * <li>The following constants are allowed:
11668 * <ul>
11669 * <li>'H' - jQueryUI theme "header" classes ('fg-toolbar ui-widget-header ui-corner-tl ui-corner-tr ui-helper-clearfix')</li>
11670 * <li>'F' - jQueryUI theme "footer" classes ('fg-toolbar ui-widget-header ui-corner-bl ui-corner-br ui-helper-clearfix')</li>
11671 * </ul>
11672 * </li>
11673 * <li>The following syntax is expected:
11674 * <ul>
11675 * <li>'&lt;' and '&gt;' - div elements</li>
11676 * <li>'&lt;"class" and '&gt;' - div with a class</li>
11677 * <li>'&lt;"#id" and '&gt;' - div with an ID</li>
11678 * </ul>
11679 * </li>
11680 * <li>Examples:
11681 * <ul>
11682 * <li>'&lt;"wrapper"flipt&gt;'</li>
11683 * <li>'&lt;lf&lt;t&gt;ip&gt;'</li>
11684 * </ul>
11685 * </li>
11686 * </ul>
11687 * @type string
11688 * @default lfrtip <i>(when `jQueryUI` is false)</i> <b>or</b>
11689 * <"H"lfr>t<"F"ip> <i>(when `jQueryUI` is true)</i>
11690 *
11691 * @dtopt Options
11692 * @name DataTable.defaults.dom
11693 *
11694 * @example
11695 * $(document).ready( function() {
11696 * $('#example').dataTable( {
11697 * "dom": '&lt;"top"i&gt;rt&lt;"bottom"flp&gt;&lt;"clear"&gt;'
11698 * } );
11699 * } );
11700 */
11701 "sDom": "lfrtip",
11702
11703
11704 /**
11705 * Search delay option. This will throttle full table searches that use the
11706 * DataTables provided search input element (it does not effect calls to
11707 * `dt-api search()`, providing a delay before the search is made.
11708 * @type integer
11709 * @default 0
11710 *
11711 * @dtopt Options
11712 * @name DataTable.defaults.searchDelay
11713 *
11714 * @example
11715 * $(document).ready( function() {
11716 * $('#example').dataTable( {
11717 * "searchDelay": 200
11718 * } );
11719 * } )
11720 */
11721 "searchDelay": null,
11722
11723
11724 /**
11725 * DataTables features four different built-in options for the buttons to
11726 * display for pagination control:
11727 *
11728 * * `simple` - 'Previous' and 'Next' buttons only
11729 * * 'simple_numbers` - 'Previous' and 'Next' buttons, plus page numbers
11730 * * `full` - 'First', 'Previous', 'Next' and 'Last' buttons
11731 * * `full_numbers` - 'First', 'Previous', 'Next' and 'Last' buttons, plus
11732 * page numbers
11733 *
11734 * Further methods can be added using {@link DataTable.ext.oPagination}.
11735 * @type string
11736 * @default simple_numbers
11737 *
11738 * @dtopt Options
11739 * @name DataTable.defaults.pagingType
11740 *
11741 * @example
11742 * $(document).ready( function() {
11743 * $('#example').dataTable( {
11744 * "pagingType": "full_numbers"
11745 * } );
11746 * } )
11747 */
11748 "sPaginationType": "simple_numbers",
11749
11750
11751 /**
11752 * Enable horizontal scrolling. When a table is too wide to fit into a
11753 * certain layout, or you have a large number of columns in the table, you
11754 * can enable x-scrolling to show the table in a viewport, which can be
11755 * scrolled. This property can be `true` which will allow the table to
11756 * scroll horizontally when needed, or any CSS unit, or a number (in which
11757 * case it will be treated as a pixel measurement). Setting as simply `true`
11758 * is recommended.
11759 * @type boolean|string
11760 * @default <i>blank string - i.e. disabled</i>
11761 *
11762 * @dtopt Features
11763 * @name DataTable.defaults.scrollX
11764 *
11765 * @example
11766 * $(document).ready( function() {
11767 * $('#example').dataTable( {
11768 * "scrollX": true,
11769 * "scrollCollapse": true
11770 * } );
11771 * } );
11772 */
11773 "sScrollX": "",
11774
11775
11776 /**
11777 * This property can be used to force a DataTable to use more width than it
11778 * might otherwise do when x-scrolling is enabled. For example if you have a
11779 * table which requires to be well spaced, this parameter is useful for
11780 * "over-sizing" the table, and thus forcing scrolling. This property can by
11781 * any CSS unit, or a number (in which case it will be treated as a pixel
11782 * measurement).
11783 * @type string
11784 * @default <i>blank string - i.e. disabled</i>
11785 *
11786 * @dtopt Options
11787 * @name DataTable.defaults.scrollXInner
11788 *
11789 * @example
11790 * $(document).ready( function() {
11791 * $('#example').dataTable( {
11792 * "scrollX": "100%",
11793 * "scrollXInner": "110%"
11794 * } );
11795 * } );
11796 */
11797 "sScrollXInner": "",
11798
11799
11800 /**
11801 * Enable vertical scrolling. Vertical scrolling will constrain the DataTable
11802 * to the given height, and enable scrolling for any data which overflows the
11803 * current viewport. This can be used as an alternative to paging to display
11804 * a lot of data in a small area (although paging and scrolling can both be
11805 * enabled at the same time). This property can be any CSS unit, or a number
11806 * (in which case it will be treated as a pixel measurement).
11807 * @type string
11808 * @default <i>blank string - i.e. disabled</i>
11809 *
11810 * @dtopt Features
11811 * @name DataTable.defaults.scrollY
11812 *
11813 * @example
11814 * $(document).ready( function() {
11815 * $('#example').dataTable( {
11816 * "scrollY": "200px",
11817 * "paginate": false
11818 * } );
11819 * } );
11820 */
11821 "sScrollY": "",
11822
11823
11824 /**
11825 * __Deprecated__ The functionality provided by this parameter has now been
11826 * superseded by that provided through `ajax`, which should be used instead.
11827 *
11828 * Set the HTTP method that is used to make the Ajax call for server-side
11829 * processing or Ajax sourced data.
11830 * @type string
11831 * @default GET
11832 *
11833 * @dtopt Options
11834 * @dtopt Server-side
11835 * @name DataTable.defaults.serverMethod
11836 *
11837 * @deprecated 1.10. Please use `ajax` for this functionality now.
11838 */
11839 "sServerMethod": "GET",
11840
11841
11842 /**
11843 * DataTables makes use of renderers when displaying HTML elements for
11844 * a table. These renderers can be added or modified by plug-ins to
11845 * generate suitable mark-up for a site. For example the Bootstrap
11846 * integration plug-in for DataTables uses a paging button renderer to
11847 * display pagination buttons in the mark-up required by Bootstrap.
11848 *
11849 * For further information about the renderers available see
11850 * DataTable.ext.renderer
11851 * @type string|object
11852 * @default null
11853 *
11854 * @name DataTable.defaults.renderer
11855 *
11856 */
11857 "renderer": null,
11858
11859
11860 /**
11861 * Set the data property name that DataTables should use to get a row's id
11862 * to set as the `id` property in the node.
11863 * @type string
11864 * @default DT_RowId
11865 *
11866 * @name DataTable.defaults.rowId
11867 */
11868 "rowId": "DT_RowId"
11869 };
11870
11871 _fnHungarianMap( DataTable.defaults );
11872
11873
11874
11875 /*
11876 * Developer note - See note in model.defaults.js about the use of Hungarian
11877 * notation and camel case.
11878 */
11879
11880 /**
11881 * Column options that can be given to DataTables at initialisation time.
11882 * @namespace
11883 */
11884 DataTable.defaults.column = {
11885 /**
11886 * Define which column(s) an order will occur on for this column. This
11887 * allows a column's ordering to take multiple columns into account when
11888 * doing a sort or use the data from a different column. For example first
11889 * name / last name columns make sense to do a multi-column sort over the
11890 * two columns.
11891 * @type array|int
11892 * @default null <i>Takes the value of the column index automatically</i>
11893 *
11894 * @name DataTable.defaults.column.orderData
11895 * @dtopt Columns
11896 *
11897 * @example
11898 * // Using `columnDefs`
11899 * $(document).ready( function() {
11900 * $('#example').dataTable( {
11901 * "columnDefs": [
11902 * { "orderData": [ 0, 1 ], "targets": [ 0 ] },
11903 * { "orderData": [ 1, 0 ], "targets": [ 1 ] },
11904 * { "orderData": 2, "targets": [ 2 ] }
11905 * ]
11906 * } );
11907 * } );
11908 *
11909 * @example
11910 * // Using `columns`
11911 * $(document).ready( function() {
11912 * $('#example').dataTable( {
11913 * "columns": [
11914 * { "orderData": [ 0, 1 ] },
11915 * { "orderData": [ 1, 0 ] },
11916 * { "orderData": 2 },
11917 * null,
11918 * null
11919 * ]
11920 * } );
11921 * } );
11922 */
11923 "aDataSort": null,
11924 "iDataSort": -1,
11925
11926
11927 /**
11928 * You can control the default ordering direction, and even alter the
11929 * behaviour of the sort handler (i.e. only allow ascending ordering etc)
11930 * using this parameter.
11931 * @type array
11932 * @default [ 'asc', 'desc' ]
11933 *
11934 * @name DataTable.defaults.column.orderSequence
11935 * @dtopt Columns
11936 *
11937 * @example
11938 * // Using `columnDefs`
11939 * $(document).ready( function() {
11940 * $('#example').dataTable( {
11941 * "columnDefs": [
11942 * { "orderSequence": [ "asc" ], "targets": [ 1 ] },
11943 * { "orderSequence": [ "desc", "asc", "asc" ], "targets": [ 2 ] },
11944 * { "orderSequence": [ "desc" ], "targets": [ 3 ] }
11945 * ]
11946 * } );
11947 * } );
11948 *
11949 * @example
11950 * // Using `columns`
11951 * $(document).ready( function() {
11952 * $('#example').dataTable( {
11953 * "columns": [
11954 * null,
11955 * { "orderSequence": [ "asc" ] },
11956 * { "orderSequence": [ "desc", "asc", "asc" ] },
11957 * { "orderSequence": [ "desc" ] },
11958 * null
11959 * ]
11960 * } );
11961 * } );
11962 */
11963 "asSorting": [ 'asc', 'desc' ],
11964
11965
11966 /**
11967 * Enable or disable filtering on the data in this column.
11968 * @type boolean
11969 * @default true
11970 *
11971 * @name DataTable.defaults.column.searchable
11972 * @dtopt Columns
11973 *
11974 * @example
11975 * // Using `columnDefs`
11976 * $(document).ready( function() {
11977 * $('#example').dataTable( {
11978 * "columnDefs": [
11979 * { "searchable": false, "targets": [ 0 ] }
11980 * ] } );
11981 * } );
11982 *
11983 * @example
11984 * // Using `columns`
11985 * $(document).ready( function() {
11986 * $('#example').dataTable( {
11987 * "columns": [
11988 * { "searchable": false },
11989 * null,
11990 * null,
11991 * null,
11992 * null
11993 * ] } );
11994 * } );
11995 */
11996 "bSearchable": true,
11997
11998
11999 /**
12000 * Enable or disable ordering on this column.
12001 * @type boolean
12002 * @default true
12003 *
12004 * @name DataTable.defaults.column.orderable
12005 * @dtopt Columns
12006 *
12007 * @example
12008 * // Using `columnDefs`
12009 * $(document).ready( function() {
12010 * $('#example').dataTable( {
12011 * "columnDefs": [
12012 * { "orderable": false, "targets": [ 0 ] }
12013 * ] } );
12014 * } );
12015 *
12016 * @example
12017 * // Using `columns`
12018 * $(document).ready( function() {
12019 * $('#example').dataTable( {
12020 * "columns": [
12021 * { "orderable": false },
12022 * null,
12023 * null,
12024 * null,
12025 * null
12026 * ] } );
12027 * } );
12028 */
12029 "bSortable": true,
12030
12031
12032 /**
12033 * Enable or disable the display of this column.
12034 * @type boolean
12035 * @default true
12036 *
12037 * @name DataTable.defaults.column.visible
12038 * @dtopt Columns
12039 *
12040 * @example
12041 * // Using `columnDefs`
12042 * $(document).ready( function() {
12043 * $('#example').dataTable( {
12044 * "columnDefs": [
12045 * { "visible": false, "targets": [ 0 ] }
12046 * ] } );
12047 * } );
12048 *
12049 * @example
12050 * // Using `columns`
12051 * $(document).ready( function() {
12052 * $('#example').dataTable( {
12053 * "columns": [
12054 * { "visible": false },
12055 * null,
12056 * null,
12057 * null,
12058 * null
12059 * ] } );
12060 * } );
12061 */
12062 "bVisible": true,
12063
12064
12065 /**
12066 * Developer definable function that is called whenever a cell is created (Ajax source,
12067 * etc) or processed for input (DOM source). This can be used as a compliment to mRender
12068 * allowing you to modify the DOM element (add background colour for example) when the
12069 * element is available.
12070 * @type function
12071 * @param {element} td The TD node that has been created
12072 * @param {*} cellData The Data for the cell
12073 * @param {array|object} rowData The data for the whole row
12074 * @param {int} row The row index for the aoData data store
12075 * @param {int} col The column index for aoColumns
12076 *
12077 * @name DataTable.defaults.column.createdCell
12078 * @dtopt Columns
12079 *
12080 * @example
12081 * $(document).ready( function() {
12082 * $('#example').dataTable( {
12083 * "columnDefs": [ {
12084 * "targets": [3],
12085 * "createdCell": function (td, cellData, rowData, row, col) {
12086 * if ( cellData == "1.7" ) {
12087 * $(td).css('color', 'blue')
12088 * }
12089 * }
12090 * } ]
12091 * });
12092 * } );
12093 */
12094 "fnCreatedCell": null,
12095
12096
12097 /**
12098 * This parameter has been replaced by `data` in DataTables to ensure naming
12099 * consistency. `dataProp` can still be used, as there is backwards
12100 * compatibility in DataTables for this option, but it is strongly
12101 * recommended that you use `data` in preference to `dataProp`.
12102 * @name DataTable.defaults.column.dataProp
12103 */
12104
12105
12106 /**
12107 * This property can be used to read data from any data source property,
12108 * including deeply nested objects / properties. `data` can be given in a
12109 * number of different ways which effect its behaviour:
12110 *
12111 * * `integer` - treated as an array index for the data source. This is the
12112 * default that DataTables uses (incrementally increased for each column).
12113 * * `string` - read an object property from the data source. There are
12114 * three 'special' options that can be used in the string to alter how
12115 * DataTables reads the data from the source object:
12116 * * `.` - Dotted Javascript notation. Just as you use a `.` in
12117 * Javascript to read from nested objects, so to can the options
12118 * specified in `data`. For example: `browser.version` or
12119 * `browser.name`. If your object parameter name contains a period, use
12120 * `\\` to escape it - i.e. `first\\.name`.
12121 * * `[]` - Array notation. DataTables can automatically combine data
12122 * from and array source, joining the data with the characters provided
12123 * between the two brackets. For example: `name[, ]` would provide a
12124 * comma-space separated list from the source array. If no characters
12125 * are provided between the brackets, the original array source is
12126 * returned.
12127 * * `()` - Function notation. Adding `()` to the end of a parameter will
12128 * execute a function of the name given. For example: `browser()` for a
12129 * simple function on the data source, `browser.version()` for a
12130 * function in a nested property or even `browser().version` to get an
12131 * object property if the function called returns an object. Note that
12132 * function notation is recommended for use in `render` rather than
12133 * `data` as it is much simpler to use as a renderer.
12134 * * `null` - use the original data source for the row rather than plucking
12135 * data directly from it. This action has effects on two other
12136 * initialisation options:
12137 * * `defaultContent` - When null is given as the `data` option and
12138 * `defaultContent` is specified for the column, the value defined by
12139 * `defaultContent` will be used for the cell.
12140 * * `render` - When null is used for the `data` option and the `render`
12141 * option is specified for the column, the whole data source for the
12142 * row is used for the renderer.
12143 * * `function` - the function given will be executed whenever DataTables
12144 * needs to set or get the data for a cell in the column. The function
12145 * takes three parameters:
12146 * * Parameters:
12147 * * `{array|object}` The data source for the row
12148 * * `{string}` The type call data requested - this will be 'set' when
12149 * setting data or 'filter', 'display', 'type', 'sort' or undefined
12150 * when gathering data. Note that when `undefined` is given for the
12151 * type DataTables expects to get the raw data for the object back<
12152 * * `{*}` Data to set when the second parameter is 'set'.
12153 * * Return:
12154 * * The return value from the function is not required when 'set' is
12155 * the type of call, but otherwise the return is what will be used
12156 * for the data requested.
12157 *
12158 * Note that `data` is a getter and setter option. If you just require
12159 * formatting of data for output, you will likely want to use `render` which
12160 * is simply a getter and thus simpler to use.
12161 *
12162 * Note that prior to DataTables 1.9.2 `data` was called `mDataProp`. The
12163 * name change reflects the flexibility of this property and is consistent
12164 * with the naming of mRender. If 'mDataProp' is given, then it will still
12165 * be used by DataTables, as it automatically maps the old name to the new
12166 * if required.
12167 *
12168 * @type string|int|function|null
12169 * @default null <i>Use automatically calculated column index</i>
12170 *
12171 * @name DataTable.defaults.column.data
12172 * @dtopt Columns
12173 *
12174 * @example
12175 * // Read table data from objects
12176 * // JSON structure for each row:
12177 * // {
12178 * // "engine": {value},
12179 * // "browser": {value},
12180 * // "platform": {value},
12181 * // "version": {value},
12182 * // "grade": {value}
12183 * // }
12184 * $(document).ready( function() {
12185 * $('#example').dataTable( {
12186 * "ajaxSource": "sources/objects.txt",
12187 * "columns": [
12188 * { "data": "engine" },
12189 * { "data": "browser" },
12190 * { "data": "platform" },
12191 * { "data": "version" },
12192 * { "data": "grade" }
12193 * ]
12194 * } );
12195 * } );
12196 *
12197 * @example
12198 * // Read information from deeply nested objects
12199 * // JSON structure for each row:
12200 * // {
12201 * // "engine": {value},
12202 * // "browser": {value},
12203 * // "platform": {
12204 * // "inner": {value}
12205 * // },
12206 * // "details": [
12207 * // {value}, {value}
12208 * // ]
12209 * // }
12210 * $(document).ready( function() {
12211 * $('#example').dataTable( {
12212 * "ajaxSource": "sources/deep.txt",
12213 * "columns": [
12214 * { "data": "engine" },
12215 * { "data": "browser" },
12216 * { "data": "platform.inner" },
12217 * { "data": "platform.details.0" },
12218 * { "data": "platform.details.1" }
12219 * ]
12220 * } );
12221 * } );
12222 *
12223 * @example
12224 * // Using `data` as a function to provide different information for
12225 * // sorting, filtering and display. In this case, currency (price)
12226 * $(document).ready( function() {
12227 * $('#example').dataTable( {
12228 * "columnDefs": [ {
12229 * "targets": [ 0 ],
12230 * "data": function ( source, type, val ) {
12231 * if (type === 'set') {
12232 * source.price = val;
12233 * // Store the computed dislay and filter values for efficiency
12234 * source.price_display = val=="" ? "" : "$"+numberFormat(val);
12235 * source.price_filter = val=="" ? "" : "$"+numberFormat(val)+" "+val;
12236 * return;
12237 * }
12238 * else if (type === 'display') {
12239 * return source.price_display;
12240 * }
12241 * else if (type === 'filter') {
12242 * return source.price_filter;
12243 * }
12244 * // 'sort', 'type' and undefined all just use the integer
12245 * return source.price;
12246 * }
12247 * } ]
12248 * } );
12249 * } );
12250 *
12251 * @example
12252 * // Using default content
12253 * $(document).ready( function() {
12254 * $('#example').dataTable( {
12255 * "columnDefs": [ {
12256 * "targets": [ 0 ],
12257 * "data": null,
12258 * "defaultContent": "Click to edit"
12259 * } ]
12260 * } );
12261 * } );
12262 *
12263 * @example
12264 * // Using array notation - outputting a list from an array
12265 * $(document).ready( function() {
12266 * $('#example').dataTable( {
12267 * "columnDefs": [ {
12268 * "targets": [ 0 ],
12269 * "data": "name[, ]"
12270 * } ]
12271 * } );
12272 * } );
12273 *
12274 */
12275 "mData": null,
12276
12277
12278 /**
12279 * This property is the rendering partner to `data` and it is suggested that
12280 * when you want to manipulate data for display (including filtering,
12281 * sorting etc) without altering the underlying data for the table, use this
12282 * property. `render` can be considered to be the the read only companion to
12283 * `data` which is read / write (then as such more complex). Like `data`
12284 * this option can be given in a number of different ways to effect its
12285 * behaviour:
12286 *
12287 * * `integer` - treated as an array index for the data source. This is the
12288 * default that DataTables uses (incrementally increased for each column).
12289 * * `string` - read an object property from the data source. There are
12290 * three 'special' options that can be used in the string to alter how
12291 * DataTables reads the data from the source object:
12292 * * `.` - Dotted Javascript notation. Just as you use a `.` in
12293 * Javascript to read from nested objects, so to can the options
12294 * specified in `data`. For example: `browser.version` or
12295 * `browser.name`. If your object parameter name contains a period, use
12296 * `\\` to escape it - i.e. `first\\.name`.
12297 * * `[]` - Array notation. DataTables can automatically combine data
12298 * from and array source, joining the data with the characters provided
12299 * between the two brackets. For example: `name[, ]` would provide a
12300 * comma-space separated list from the source array. If no characters
12301 * are provided between the brackets, the original array source is
12302 * returned.
12303 * * `()` - Function notation. Adding `()` to the end of a parameter will
12304 * execute a function of the name given. For example: `browser()` for a
12305 * simple function on the data source, `browser.version()` for a
12306 * function in a nested property or even `browser().version` to get an
12307 * object property if the function called returns an object.
12308 * * `object` - use different data for the different data types requested by
12309 * DataTables ('filter', 'display', 'type' or 'sort'). The property names
12310 * of the object is the data type the property refers to and the value can
12311 * defined using an integer, string or function using the same rules as
12312 * `render` normally does. Note that an `_` option _must_ be specified.
12313 * This is the default value to use if you haven't specified a value for
12314 * the data type requested by DataTables.
12315 * * `function` - the function given will be executed whenever DataTables
12316 * needs to set or get the data for a cell in the column. The function
12317 * takes three parameters:
12318 * * Parameters:
12319 * * {array|object} The data source for the row (based on `data`)
12320 * * {string} The type call data requested - this will be 'filter',
12321 * 'display', 'type' or 'sort'.
12322 * * {array|object} The full data source for the row (not based on
12323 * `data`)
12324 * * Return:
12325 * * The return value from the function is what will be used for the
12326 * data requested.
12327 *
12328 * @type string|int|function|object|null
12329 * @default null Use the data source value.
12330 *
12331 * @name DataTable.defaults.column.render
12332 * @dtopt Columns
12333 *
12334 * @example
12335 * // Create a comma separated list from an array of objects
12336 * $(document).ready( function() {
12337 * $('#example').dataTable( {
12338 * "ajaxSource": "sources/deep.txt",
12339 * "columns": [
12340 * { "data": "engine" },
12341 * { "data": "browser" },
12342 * {
12343 * "data": "platform",
12344 * "render": "[, ].name"
12345 * }
12346 * ]
12347 * } );
12348 * } );
12349 *
12350 * @example
12351 * // Execute a function to obtain data
12352 * $(document).ready( function() {
12353 * $('#example').dataTable( {
12354 * "columnDefs": [ {
12355 * "targets": [ 0 ],
12356 * "data": null, // Use the full data source object for the renderer's source
12357 * "render": "browserName()"
12358 * } ]
12359 * } );
12360 * } );
12361 *
12362 * @example
12363 * // As an object, extracting different data for the different types
12364 * // This would be used with a data source such as:
12365 * // { "phone": 5552368, "phone_filter": "5552368 555-2368", "phone_display": "555-2368" }
12366 * // Here the `phone` integer is used for sorting and type detection, while `phone_filter`
12367 * // (which has both forms) is used for filtering for if a user inputs either format, while
12368 * // the formatted phone number is the one that is shown in the table.
12369 * $(document).ready( function() {
12370 * $('#example').dataTable( {
12371 * "columnDefs": [ {
12372 * "targets": [ 0 ],
12373 * "data": null, // Use the full data source object for the renderer's source
12374 * "render": {
12375 * "_": "phone",
12376 * "filter": "phone_filter",
12377 * "display": "phone_display"
12378 * }
12379 * } ]
12380 * } );
12381 * } );
12382 *
12383 * @example
12384 * // Use as a function to create a link from the data source
12385 * $(document).ready( function() {
12386 * $('#example').dataTable( {
12387 * "columnDefs": [ {
12388 * "targets": [ 0 ],
12389 * "data": "download_link",
12390 * "render": function ( data, type, full ) {
12391 * return '<a href="'+data+'">Download</a>';
12392 * }
12393 * } ]
12394 * } );
12395 * } );
12396 */
12397 "mRender": null,
12398
12399
12400 /**
12401 * Change the cell type created for the column - either TD cells or TH cells. This
12402 * can be useful as TH cells have semantic meaning in the table body, allowing them
12403 * to act as a header for a row (you may wish to add scope='row' to the TH elements).
12404 * @type string
12405 * @default td
12406 *
12407 * @name DataTable.defaults.column.cellType
12408 * @dtopt Columns
12409 *
12410 * @example
12411 * // Make the first column use TH cells
12412 * $(document).ready( function() {
12413 * $('#example').dataTable( {
12414 * "columnDefs": [ {
12415 * "targets": [ 0 ],
12416 * "cellType": "th"
12417 * } ]
12418 * } );
12419 * } );
12420 */
12421 "sCellType": "td",
12422
12423
12424 /**
12425 * Class to give to each cell in this column.
12426 * @type string
12427 * @default <i>Empty string</i>
12428 *
12429 * @name DataTable.defaults.column.class
12430 * @dtopt Columns
12431 *
12432 * @example
12433 * // Using `columnDefs`
12434 * $(document).ready( function() {
12435 * $('#example').dataTable( {
12436 * "columnDefs": [
12437 * { "class": "my_class", "targets": [ 0 ] }
12438 * ]
12439 * } );
12440 * } );
12441 *
12442 * @example
12443 * // Using `columns`
12444 * $(document).ready( function() {
12445 * $('#example').dataTable( {
12446 * "columns": [
12447 * { "class": "my_class" },
12448 * null,
12449 * null,
12450 * null,
12451 * null
12452 * ]
12453 * } );
12454 * } );
12455 */
12456 "sClass": "",
12457
12458 /**
12459 * When DataTables calculates the column widths to assign to each column,
12460 * it finds the longest string in each column and then constructs a
12461 * temporary table and reads the widths from that. The problem with this
12462 * is that "mmm" is much wider then "iiii", but the latter is a longer
12463 * string - thus the calculation can go wrong (doing it properly and putting
12464 * it into an DOM object and measuring that is horribly(!) slow). Thus as
12465 * a "work around" we provide this option. It will append its value to the
12466 * text that is found to be the longest string for the column - i.e. padding.
12467 * Generally you shouldn't need this!
12468 * @type string
12469 * @default <i>Empty string<i>
12470 *
12471 * @name DataTable.defaults.column.contentPadding
12472 * @dtopt Columns
12473 *
12474 * @example
12475 * // Using `columns`
12476 * $(document).ready( function() {
12477 * $('#example').dataTable( {
12478 * "columns": [
12479 * null,
12480 * null,
12481 * null,
12482 * {
12483 * "contentPadding": "mmm"
12484 * }
12485 * ]
12486 * } );
12487 * } );
12488 */
12489 "sContentPadding": "",
12490
12491
12492 /**
12493 * Allows a default value to be given for a column's data, and will be used
12494 * whenever a null data source is encountered (this can be because `data`
12495 * is set to null, or because the data source itself is null).
12496 * @type string
12497 * @default null
12498 *
12499 * @name DataTable.defaults.column.defaultContent
12500 * @dtopt Columns
12501 *
12502 * @example
12503 * // Using `columnDefs`
12504 * $(document).ready( function() {
12505 * $('#example').dataTable( {
12506 * "columnDefs": [
12507 * {
12508 * "data": null,
12509 * "defaultContent": "Edit",
12510 * "targets": [ -1 ]
12511 * }
12512 * ]
12513 * } );
12514 * } );
12515 *
12516 * @example
12517 * // Using `columns`
12518 * $(document).ready( function() {
12519 * $('#example').dataTable( {
12520 * "columns": [
12521 * null,
12522 * null,
12523 * null,
12524 * {
12525 * "data": null,
12526 * "defaultContent": "Edit"
12527 * }
12528 * ]
12529 * } );
12530 * } );
12531 */
12532 "sDefaultContent": null,
12533
12534
12535 /**
12536 * This parameter is only used in DataTables' server-side processing. It can
12537 * be exceptionally useful to know what columns are being displayed on the
12538 * client side, and to map these to database fields. When defined, the names
12539 * also allow DataTables to reorder information from the server if it comes
12540 * back in an unexpected order (i.e. if you switch your columns around on the
12541 * client-side, your server-side code does not also need updating).
12542 * @type string
12543 * @default <i>Empty string</i>
12544 *
12545 * @name DataTable.defaults.column.name
12546 * @dtopt Columns
12547 *
12548 * @example
12549 * // Using `columnDefs`
12550 * $(document).ready( function() {
12551 * $('#example').dataTable( {
12552 * "columnDefs": [
12553 * { "name": "engine", "targets": [ 0 ] },
12554 * { "name": "browser", "targets": [ 1 ] },
12555 * { "name": "platform", "targets": [ 2 ] },
12556 * { "name": "version", "targets": [ 3 ] },
12557 * { "name": "grade", "targets": [ 4 ] }
12558 * ]
12559 * } );
12560 * } );
12561 *
12562 * @example
12563 * // Using `columns`
12564 * $(document).ready( function() {
12565 * $('#example').dataTable( {
12566 * "columns": [
12567 * { "name": "engine" },
12568 * { "name": "browser" },
12569 * { "name": "platform" },
12570 * { "name": "version" },
12571 * { "name": "grade" }
12572 * ]
12573 * } );
12574 * } );
12575 */
12576 "sName": "",
12577
12578
12579 /**
12580 * Defines a data source type for the ordering which can be used to read
12581 * real-time information from the table (updating the internally cached
12582 * version) prior to ordering. This allows ordering to occur on user
12583 * editable elements such as form inputs.
12584 * @type string
12585 * @default std
12586 *
12587 * @name DataTable.defaults.column.orderDataType
12588 * @dtopt Columns
12589 *
12590 * @example
12591 * // Using `columnDefs`
12592 * $(document).ready( function() {
12593 * $('#example').dataTable( {
12594 * "columnDefs": [
12595 * { "orderDataType": "dom-text", "targets": [ 2, 3 ] },
12596 * { "type": "numeric", "targets": [ 3 ] },
12597 * { "orderDataType": "dom-select", "targets": [ 4 ] },
12598 * { "orderDataType": "dom-checkbox", "targets": [ 5 ] }
12599 * ]
12600 * } );
12601 * } );
12602 *
12603 * @example
12604 * // Using `columns`
12605 * $(document).ready( function() {
12606 * $('#example').dataTable( {
12607 * "columns": [
12608 * null,
12609 * null,
12610 * { "orderDataType": "dom-text" },
12611 * { "orderDataType": "dom-text", "type": "numeric" },
12612 * { "orderDataType": "dom-select" },
12613 * { "orderDataType": "dom-checkbox" }
12614 * ]
12615 * } );
12616 * } );
12617 */
12618 "sSortDataType": "std",
12619
12620
12621 /**
12622 * The title of this column.
12623 * @type string
12624 * @default null <i>Derived from the 'TH' value for this column in the
12625 * original HTML table.</i>
12626 *
12627 * @name DataTable.defaults.column.title
12628 * @dtopt Columns
12629 *
12630 * @example
12631 * // Using `columnDefs`
12632 * $(document).ready( function() {
12633 * $('#example').dataTable( {
12634 * "columnDefs": [
12635 * { "title": "My column title", "targets": [ 0 ] }
12636 * ]
12637 * } );
12638 * } );
12639 *
12640 * @example
12641 * // Using `columns`
12642 * $(document).ready( function() {
12643 * $('#example').dataTable( {
12644 * "columns": [
12645 * { "title": "My column title" },
12646 * null,
12647 * null,
12648 * null,
12649 * null
12650 * ]
12651 * } );
12652 * } );
12653 */
12654 "sTitle": null,
12655
12656
12657 /**
12658 * The type allows you to specify how the data for this column will be
12659 * ordered. Four types (string, numeric, date and html (which will strip
12660 * HTML tags before ordering)) are currently available. Note that only date
12661 * formats understood by Javascript's Date() object will be accepted as type
12662 * date. For example: "Mar 26, 2008 5:03 PM". May take the values: 'string',
12663 * 'numeric', 'date' or 'html' (by default). Further types can be adding
12664 * through plug-ins.
12665 * @type string
12666 * @default null <i>Auto-detected from raw data</i>
12667 *
12668 * @name DataTable.defaults.column.type
12669 * @dtopt Columns
12670 *
12671 * @example
12672 * // Using `columnDefs`
12673 * $(document).ready( function() {
12674 * $('#example').dataTable( {
12675 * "columnDefs": [
12676 * { "type": "html", "targets": [ 0 ] }
12677 * ]
12678 * } );
12679 * } );
12680 *
12681 * @example
12682 * // Using `columns`
12683 * $(document).ready( function() {
12684 * $('#example').dataTable( {
12685 * "columns": [
12686 * { "type": "html" },
12687 * null,
12688 * null,
12689 * null,
12690 * null
12691 * ]
12692 * } );
12693 * } );
12694 */
12695 "sType": null,
12696
12697
12698 /**
12699 * Defining the width of the column, this parameter may take any CSS value
12700 * (3em, 20px etc). DataTables applies 'smart' widths to columns which have not
12701 * been given a specific width through this interface ensuring that the table
12702 * remains readable.
12703 * @type string
12704 * @default null <i>Automatic</i>
12705 *
12706 * @name DataTable.defaults.column.width
12707 * @dtopt Columns
12708 *
12709 * @example
12710 * // Using `columnDefs`
12711 * $(document).ready( function() {
12712 * $('#example').dataTable( {
12713 * "columnDefs": [
12714 * { "width": "20%", "targets": [ 0 ] }
12715 * ]
12716 * } );
12717 * } );
12718 *
12719 * @example
12720 * // Using `columns`
12721 * $(document).ready( function() {
12722 * $('#example').dataTable( {
12723 * "columns": [
12724 * { "width": "20%" },
12725 * null,
12726 * null,
12727 * null,
12728 * null
12729 * ]
12730 * } );
12731 * } );
12732 */
12733 "sWidth": null
12734 };
12735
12736 _fnHungarianMap( DataTable.defaults.column );
12737
12738
12739
12740 /**
12741 * DataTables settings object - this holds all the information needed for a
12742 * given table, including configuration, data and current application of the
12743 * table options. DataTables does not have a single instance for each DataTable
12744 * with the settings attached to that instance, but rather instances of the
12745 * DataTable "class" are created on-the-fly as needed (typically by a
12746 * $().dataTable() call) and the settings object is then applied to that
12747 * instance.
12748 *
12749 * Note that this object is related to {@link DataTable.defaults} but this
12750 * one is the internal data store for DataTables's cache of columns. It should
12751 * NOT be manipulated outside of DataTables. Any configuration should be done
12752 * through the initialisation options.
12753 * @namespace
12754 * @todo Really should attach the settings object to individual instances so we
12755 * don't need to create new instances on each $().dataTable() call (if the
12756 * table already exists). It would also save passing oSettings around and
12757 * into every single function. However, this is a very significant
12758 * architecture change for DataTables and will almost certainly break
12759 * backwards compatibility with older installations. This is something that
12760 * will be done in 2.0.
12761 */
12762 DataTable.models.oSettings = {
12763 /**
12764 * Primary features of DataTables and their enablement state.
12765 * @namespace
12766 */
12767 "oFeatures": {
12768
12769 /**
12770 * Flag to say if DataTables should automatically try to calculate the
12771 * optimum table and columns widths (true) or not (false).
12772 * Note that this parameter will be set by the initialisation routine. To
12773 * set a default use {@link DataTable.defaults}.
12774 * @type boolean
12775 */
12776 "bAutoWidth": null,
12777
12778 /**
12779 * Delay the creation of TR and TD elements until they are actually
12780 * needed by a driven page draw. This can give a significant speed
12781 * increase for Ajax source and Javascript source data, but makes no
12782 * difference at all fro DOM and server-side processing tables.
12783 * Note that this parameter will be set by the initialisation routine. To
12784 * set a default use {@link DataTable.defaults}.
12785 * @type boolean
12786 */
12787 "bDeferRender": null,
12788
12789 /**
12790 * Enable filtering on the table or not. Note that if this is disabled
12791 * then there is no filtering at all on the table, including fnFilter.
12792 * To just remove the filtering input use sDom and remove the 'f' option.
12793 * Note that this parameter will be set by the initialisation routine. To
12794 * set a default use {@link DataTable.defaults}.
12795 * @type boolean
12796 */
12797 "bFilter": null,
12798
12799 /**
12800 * Table information element (the 'Showing x of y records' div) enable
12801 * flag.
12802 * Note that this parameter will be set by the initialisation routine. To
12803 * set a default use {@link DataTable.defaults}.
12804 * @type boolean
12805 */
12806 "bInfo": null,
12807
12808 /**
12809 * Present a user control allowing the end user to change the page size
12810 * when pagination is enabled.
12811 * Note that this parameter will be set by the initialisation routine. To
12812 * set a default use {@link DataTable.defaults}.
12813 * @type boolean
12814 */
12815 "bLengthChange": null,
12816
12817 /**
12818 * Pagination enabled or not. Note that if this is disabled then length
12819 * changing must also be disabled.
12820 * Note that this parameter will be set by the initialisation routine. To
12821 * set a default use {@link DataTable.defaults}.
12822 * @type boolean
12823 */
12824 "bPaginate": null,
12825
12826 /**
12827 * Processing indicator enable flag whenever DataTables is enacting a
12828 * user request - typically an Ajax request for server-side processing.
12829 * Note that this parameter will be set by the initialisation routine. To
12830 * set a default use {@link DataTable.defaults}.
12831 * @type boolean
12832 */
12833 "bProcessing": null,
12834
12835 /**
12836 * Server-side processing enabled flag - when enabled DataTables will
12837 * get all data from the server for every draw - there is no filtering,
12838 * sorting or paging done on the client-side.
12839 * Note that this parameter will be set by the initialisation routine. To
12840 * set a default use {@link DataTable.defaults}.
12841 * @type boolean
12842 */
12843 "bServerSide": null,
12844
12845 /**
12846 * Sorting enablement flag.
12847 * Note that this parameter will be set by the initialisation routine. To
12848 * set a default use {@link DataTable.defaults}.
12849 * @type boolean
12850 */
12851 "bSort": null,
12852
12853 /**
12854 * Multi-column sorting
12855 * Note that this parameter will be set by the initialisation routine. To
12856 * set a default use {@link DataTable.defaults}.
12857 * @type boolean
12858 */
12859 "bSortMulti": null,
12860
12861 /**
12862 * Apply a class to the columns which are being sorted to provide a
12863 * visual highlight or not. This can slow things down when enabled since
12864 * there is a lot of DOM interaction.
12865 * Note that this parameter will be set by the initialisation routine. To
12866 * set a default use {@link DataTable.defaults}.
12867 * @type boolean
12868 */
12869 "bSortClasses": null,
12870
12871 /**
12872 * State saving enablement flag.
12873 * Note that this parameter will be set by the initialisation routine. To
12874 * set a default use {@link DataTable.defaults}.
12875 * @type boolean
12876 */
12877 "bStateSave": null
12878 },
12879
12880
12881 /**
12882 * Scrolling settings for a table.
12883 * @namespace
12884 */
12885 "oScroll": {
12886 /**
12887 * When the table is shorter in height than sScrollY, collapse the
12888 * table container down to the height of the table (when true).
12889 * Note that this parameter will be set by the initialisation routine. To
12890 * set a default use {@link DataTable.defaults}.
12891 * @type boolean
12892 */
12893 "bCollapse": null,
12894
12895 /**
12896 * Width of the scrollbar for the web-browser's platform. Calculated
12897 * during table initialisation.
12898 * @type int
12899 * @default 0
12900 */
12901 "iBarWidth": 0,
12902
12903 /**
12904 * Viewport width for horizontal scrolling. Horizontal scrolling is
12905 * disabled if an empty string.
12906 * Note that this parameter will be set by the initialisation routine. To
12907 * set a default use {@link DataTable.defaults}.
12908 * @type string
12909 */
12910 "sX": null,
12911
12912 /**
12913 * Width to expand the table to when using x-scrolling. Typically you
12914 * should not need to use this.
12915 * Note that this parameter will be set by the initialisation routine. To
12916 * set a default use {@link DataTable.defaults}.
12917 * @type string
12918 * @deprecated
12919 */
12920 "sXInner": null,
12921
12922 /**
12923 * Viewport height for vertical scrolling. Vertical scrolling is disabled
12924 * if an empty string.
12925 * Note that this parameter will be set by the initialisation routine. To
12926 * set a default use {@link DataTable.defaults}.
12927 * @type string
12928 */
12929 "sY": null
12930 },
12931
12932 /**
12933 * Language information for the table.
12934 * @namespace
12935 * @extends DataTable.defaults.oLanguage
12936 */
12937 "oLanguage": {
12938 /**
12939 * Information callback function. See
12940 * {@link DataTable.defaults.fnInfoCallback}
12941 * @type function
12942 * @default null
12943 */
12944 "fnInfoCallback": null
12945 },
12946
12947 /**
12948 * Browser support parameters
12949 * @namespace
12950 */
12951 "oBrowser": {
12952 /**
12953 * Indicate if the browser incorrectly calculates width:100% inside a
12954 * scrolling element (IE6/7)
12955 * @type boolean
12956 * @default false
12957 */
12958 "bScrollOversize": false,
12959
12960 /**
12961 * Determine if the vertical scrollbar is on the right or left of the
12962 * scrolling container - needed for rtl language layout, although not
12963 * all browsers move the scrollbar (Safari).
12964 * @type boolean
12965 * @default false
12966 */
12967 "bScrollbarLeft": false,
12968
12969 /**
12970 * Flag for if `getBoundingClientRect` is fully supported or not
12971 * @type boolean
12972 * @default false
12973 */
12974 "bBounding": false,
12975
12976 /**
12977 * Browser scrollbar width
12978 * @type integer
12979 * @default 0
12980 */
12981 "barWidth": 0
12982 },
12983
12984
12985 "ajax": null,
12986
12987
12988 /**
12989 * Array referencing the nodes which are used for the features. The
12990 * parameters of this object match what is allowed by sDom - i.e.
12991 * <ul>
12992 * <li>'l' - Length changing</li>
12993 * <li>'f' - Filtering input</li>
12994 * <li>'t' - The table!</li>
12995 * <li>'i' - Information</li>
12996 * <li>'p' - Pagination</li>
12997 * <li>'r' - pRocessing</li>
12998 * </ul>
12999 * @type array
13000 * @default []
13001 */
13002 "aanFeatures": [],
13003
13004 /**
13005 * Store data information - see {@link DataTable.models.oRow} for detailed
13006 * information.
13007 * @type array
13008 * @default []
13009 */
13010 "aoData": [],
13011
13012 /**
13013 * Array of indexes which are in the current display (after filtering etc)
13014 * @type array
13015 * @default []
13016 */
13017 "aiDisplay": [],
13018
13019 /**
13020 * Array of indexes for display - no filtering
13021 * @type array
13022 * @default []
13023 */
13024 "aiDisplayMaster": [],
13025
13026 /**
13027 * Map of row ids to data indexes
13028 * @type object
13029 * @default {}
13030 */
13031 "aIds": {},
13032
13033 /**
13034 * Store information about each column that is in use
13035 * @type array
13036 * @default []
13037 */
13038 "aoColumns": [],
13039
13040 /**
13041 * Store information about the table's header
13042 * @type array
13043 * @default []
13044 */
13045 "aoHeader": [],
13046
13047 /**
13048 * Store information about the table's footer
13049 * @type array
13050 * @default []
13051 */
13052 "aoFooter": [],
13053
13054 /**
13055 * Store the applied global search information in case we want to force a
13056 * research or compare the old search to a new one.
13057 * Note that this parameter will be set by the initialisation routine. To
13058 * set a default use {@link DataTable.defaults}.
13059 * @namespace
13060 * @extends DataTable.models.oSearch
13061 */
13062 "oPreviousSearch": {},
13063
13064 /**
13065 * Store the applied search for each column - see
13066 * {@link DataTable.models.oSearch} for the format that is used for the
13067 * filtering information for each column.
13068 * @type array
13069 * @default []
13070 */
13071 "aoPreSearchCols": [],
13072
13073 /**
13074 * Sorting that is applied to the table. Note that the inner arrays are
13075 * used in the following manner:
13076 * <ul>
13077 * <li>Index 0 - column number</li>
13078 * <li>Index 1 - current sorting direction</li>
13079 * </ul>
13080 * Note that this parameter will be set by the initialisation routine. To
13081 * set a default use {@link DataTable.defaults}.
13082 * @type array
13083 * @todo These inner arrays should really be objects
13084 */
13085 "aaSorting": null,
13086
13087 /**
13088 * Sorting that is always applied to the table (i.e. prefixed in front of
13089 * aaSorting).
13090 * Note that this parameter will be set by the initialisation routine. To
13091 * set a default use {@link DataTable.defaults}.
13092 * @type array
13093 * @default []
13094 */
13095 "aaSortingFixed": [],
13096
13097 /**
13098 * Classes to use for the striping of a table.
13099 * Note that this parameter will be set by the initialisation routine. To
13100 * set a default use {@link DataTable.defaults}.
13101 * @type array
13102 * @default []
13103 */
13104 "asStripeClasses": null,
13105
13106 /**
13107 * If restoring a table - we should restore its striping classes as well
13108 * @type array
13109 * @default []
13110 */
13111 "asDestroyStripes": [],
13112
13113 /**
13114 * If restoring a table - we should restore its width
13115 * @type int
13116 * @default 0
13117 */
13118 "sDestroyWidth": 0,
13119
13120 /**
13121 * Callback functions array for every time a row is inserted (i.e. on a draw).
13122 * @type array
13123 * @default []
13124 */
13125 "aoRowCallback": [],
13126
13127 /**
13128 * Callback functions for the header on each draw.
13129 * @type array
13130 * @default []
13131 */
13132 "aoHeaderCallback": [],
13133
13134 /**
13135 * Callback function for the footer on each draw.
13136 * @type array
13137 * @default []
13138 */
13139 "aoFooterCallback": [],
13140
13141 /**
13142 * Array of callback functions for draw callback functions
13143 * @type array
13144 * @default []
13145 */
13146 "aoDrawCallback": [],
13147
13148 /**
13149 * Array of callback functions for row created function
13150 * @type array
13151 * @default []
13152 */
13153 "aoRowCreatedCallback": [],
13154
13155 /**
13156 * Callback functions for just before the table is redrawn. A return of
13157 * false will be used to cancel the draw.
13158 * @type array
13159 * @default []
13160 */
13161 "aoPreDrawCallback": [],
13162
13163 /**
13164 * Callback functions for when the table has been initialised.
13165 * @type array
13166 * @default []
13167 */
13168 "aoInitComplete": [],
13169
13170
13171 /**
13172 * Callbacks for modifying the settings to be stored for state saving, prior to
13173 * saving state.
13174 * @type array
13175 * @default []
13176 */
13177 "aoStateSaveParams": [],
13178
13179 /**
13180 * Callbacks for modifying the settings that have been stored for state saving
13181 * prior to using the stored values to restore the state.
13182 * @type array
13183 * @default []
13184 */
13185 "aoStateLoadParams": [],
13186
13187 /**
13188 * Callbacks for operating on the settings object once the saved state has been
13189 * loaded
13190 * @type array
13191 * @default []
13192 */
13193 "aoStateLoaded": [],
13194
13195 /**
13196 * Cache the table ID for quick access
13197 * @type string
13198 * @default <i>Empty string</i>
13199 */
13200 "sTableId": "",
13201
13202 /**
13203 * The TABLE node for the main table
13204 * @type node
13205 * @default null
13206 */
13207 "nTable": null,
13208
13209 /**
13210 * Permanent ref to the thead element
13211 * @type node
13212 * @default null
13213 */
13214 "nTHead": null,
13215
13216 /**
13217 * Permanent ref to the tfoot element - if it exists
13218 * @type node
13219 * @default null
13220 */
13221 "nTFoot": null,
13222
13223 /**
13224 * Permanent ref to the tbody element
13225 * @type node
13226 * @default null
13227 */
13228 "nTBody": null,
13229
13230 /**
13231 * Cache the wrapper node (contains all DataTables controlled elements)
13232 * @type node
13233 * @default null
13234 */
13235 "nTableWrapper": null,
13236
13237 /**
13238 * Indicate if when using server-side processing the loading of data
13239 * should be deferred until the second draw.
13240 * Note that this parameter will be set by the initialisation routine. To
13241 * set a default use {@link DataTable.defaults}.
13242 * @type boolean
13243 * @default false
13244 */
13245 "bDeferLoading": false,
13246
13247 /**
13248 * Indicate if all required information has been read in
13249 * @type boolean
13250 * @default false
13251 */
13252 "bInitialised": false,
13253
13254 /**
13255 * Information about open rows. Each object in the array has the parameters
13256 * 'nTr' and 'nParent'
13257 * @type array
13258 * @default []
13259 */
13260 "aoOpenRows": [],
13261
13262 /**
13263 * Dictate the positioning of DataTables' control elements - see
13264 * {@link DataTable.model.oInit.sDom}.
13265 * Note that this parameter will be set by the initialisation routine. To
13266 * set a default use {@link DataTable.defaults}.
13267 * @type string
13268 * @default null
13269 */
13270 "sDom": null,
13271
13272 /**
13273 * Search delay (in mS)
13274 * @type integer
13275 * @default null
13276 */
13277 "searchDelay": null,
13278
13279 /**
13280 * Which type of pagination should be used.
13281 * Note that this parameter will be set by the initialisation routine. To
13282 * set a default use {@link DataTable.defaults}.
13283 * @type string
13284 * @default two_button
13285 */
13286 "sPaginationType": "two_button",
13287
13288 /**
13289 * The state duration (for `stateSave`) in seconds.
13290 * Note that this parameter will be set by the initialisation routine. To
13291 * set a default use {@link DataTable.defaults}.
13292 * @type int
13293 * @default 0
13294 */
13295 "iStateDuration": 0,
13296
13297 /**
13298 * Array of callback functions for state saving. Each array element is an
13299 * object with the following parameters:
13300 * <ul>
13301 * <li>function:fn - function to call. Takes two parameters, oSettings
13302 * and the JSON string to save that has been thus far created. Returns
13303 * a JSON string to be inserted into a json object
13304 * (i.e. '"param": [ 0, 1, 2]')</li>
13305 * <li>string:sName - name of callback</li>
13306 * </ul>
13307 * @type array
13308 * @default []
13309 */
13310 "aoStateSave": [],
13311
13312 /**
13313 * Array of callback functions for state loading. Each array element is an
13314 * object with the following parameters:
13315 * <ul>
13316 * <li>function:fn - function to call. Takes two parameters, oSettings
13317 * and the object stored. May return false to cancel state loading</li>
13318 * <li>string:sName - name of callback</li>
13319 * </ul>
13320 * @type array
13321 * @default []
13322 */
13323 "aoStateLoad": [],
13324
13325 /**
13326 * State that was saved. Useful for back reference
13327 * @type object
13328 * @default null
13329 */
13330 "oSavedState": null,
13331
13332 /**
13333 * State that was loaded. Useful for back reference
13334 * @type object
13335 * @default null
13336 */
13337 "oLoadedState": null,
13338
13339 /**
13340 * Source url for AJAX data for the table.
13341 * Note that this parameter will be set by the initialisation routine. To
13342 * set a default use {@link DataTable.defaults}.
13343 * @type string
13344 * @default null
13345 */
13346 "sAjaxSource": null,
13347
13348 /**
13349 * Property from a given object from which to read the table data from. This
13350 * can be an empty string (when not server-side processing), in which case
13351 * it is assumed an an array is given directly.
13352 * Note that this parameter will be set by the initialisation routine. To
13353 * set a default use {@link DataTable.defaults}.
13354 * @type string
13355 */
13356 "sAjaxDataProp": null,
13357
13358 /**
13359 * Note if draw should be blocked while getting data
13360 * @type boolean
13361 * @default true
13362 */
13363 "bAjaxDataGet": true,
13364
13365 /**
13366 * The last jQuery XHR object that was used for server-side data gathering.
13367 * This can be used for working with the XHR information in one of the
13368 * callbacks
13369 * @type object
13370 * @default null
13371 */
13372 "jqXHR": null,
13373
13374 /**
13375 * JSON returned from the server in the last Ajax request
13376 * @type object
13377 * @default undefined
13378 */
13379 "json": undefined,
13380
13381 /**
13382 * Data submitted as part of the last Ajax request
13383 * @type object
13384 * @default undefined
13385 */
13386 "oAjaxData": undefined,
13387
13388 /**
13389 * Function to get the server-side data.
13390 * Note that this parameter will be set by the initialisation routine. To
13391 * set a default use {@link DataTable.defaults}.
13392 * @type function
13393 */
13394 "fnServerData": null,
13395
13396 /**
13397 * Functions which are called prior to sending an Ajax request so extra
13398 * parameters can easily be sent to the server
13399 * @type array
13400 * @default []
13401 */
13402 "aoServerParams": [],
13403
13404 /**
13405 * Send the XHR HTTP method - GET or POST (could be PUT or DELETE if
13406 * required).
13407 * Note that this parameter will be set by the initialisation routine. To
13408 * set a default use {@link DataTable.defaults}.
13409 * @type string
13410 */
13411 "sServerMethod": null,
13412
13413 /**
13414 * Format numbers for display.
13415 * Note that this parameter will be set by the initialisation routine. To
13416 * set a default use {@link DataTable.defaults}.
13417 * @type function
13418 */
13419 "fnFormatNumber": null,
13420
13421 /**
13422 * List of options that can be used for the user selectable length menu.
13423 * Note that this parameter will be set by the initialisation routine. To
13424 * set a default use {@link DataTable.defaults}.
13425 * @type array
13426 * @default []
13427 */
13428 "aLengthMenu": null,
13429
13430 /**
13431 * Counter for the draws that the table does. Also used as a tracker for
13432 * server-side processing
13433 * @type int
13434 * @default 0
13435 */
13436 "iDraw": 0,
13437
13438 /**
13439 * Indicate if a redraw is being done - useful for Ajax
13440 * @type boolean
13441 * @default false
13442 */
13443 "bDrawing": false,
13444
13445 /**
13446 * Draw index (iDraw) of the last error when parsing the returned data
13447 * @type int
13448 * @default -1
13449 */
13450 "iDrawError": -1,
13451
13452 /**
13453 * Paging display length
13454 * @type int
13455 * @default 10
13456 */
13457 "_iDisplayLength": 10,
13458
13459 /**
13460 * Paging start point - aiDisplay index
13461 * @type int
13462 * @default 0
13463 */
13464 "_iDisplayStart": 0,
13465
13466 /**
13467 * Server-side processing - number of records in the result set
13468 * (i.e. before filtering), Use fnRecordsTotal rather than
13469 * this property to get the value of the number of records, regardless of
13470 * the server-side processing setting.
13471 * @type int
13472 * @default 0
13473 * @private
13474 */
13475 "_iRecordsTotal": 0,
13476
13477 /**
13478 * Server-side processing - number of records in the current display set
13479 * (i.e. after filtering). Use fnRecordsDisplay rather than
13480 * this property to get the value of the number of records, regardless of
13481 * the server-side processing setting.
13482 * @type boolean
13483 * @default 0
13484 * @private
13485 */
13486 "_iRecordsDisplay": 0,
13487
13488 /**
13489 * Flag to indicate if jQuery UI marking and classes should be used.
13490 * Note that this parameter will be set by the initialisation routine. To
13491 * set a default use {@link DataTable.defaults}.
13492 * @type boolean
13493 */
13494 "bJUI": null,
13495
13496 /**
13497 * The classes to use for the table
13498 * @type object
13499 * @default {}
13500 */
13501 "oClasses": {},
13502
13503 /**
13504 * Flag attached to the settings object so you can check in the draw
13505 * callback if filtering has been done in the draw. Deprecated in favour of
13506 * events.
13507 * @type boolean
13508 * @default false
13509 * @deprecated
13510 */
13511 "bFiltered": false,
13512
13513 /**
13514 * Flag attached to the settings object so you can check in the draw
13515 * callback if sorting has been done in the draw. Deprecated in favour of
13516 * events.
13517 * @type boolean
13518 * @default false
13519 * @deprecated
13520 */
13521 "bSorted": false,
13522
13523 /**
13524 * Indicate that if multiple rows are in the header and there is more than
13525 * one unique cell per column, if the top one (true) or bottom one (false)
13526 * should be used for sorting / title by DataTables.
13527 * Note that this parameter will be set by the initialisation routine. To
13528 * set a default use {@link DataTable.defaults}.
13529 * @type boolean
13530 */
13531 "bSortCellsTop": null,
13532
13533 /**
13534 * Initialisation object that is used for the table
13535 * @type object
13536 * @default null
13537 */
13538 "oInit": null,
13539
13540 /**
13541 * Destroy callback functions - for plug-ins to attach themselves to the
13542 * destroy so they can clean up markup and events.
13543 * @type array
13544 * @default []
13545 */
13546 "aoDestroyCallback": [],
13547
13548
13549 /**
13550 * Get the number of records in the current record set, before filtering
13551 * @type function
13552 */
13553 "fnRecordsTotal": function ()
13554 {
13555 return _fnDataSource( this ) == 'ssp' ?
13556 this._iRecordsTotal * 1 :
13557 this.aiDisplayMaster.length;
13558 },
13559
13560 /**
13561 * Get the number of records in the current record set, after filtering
13562 * @type function
13563 */
13564 "fnRecordsDisplay": function ()
13565 {
13566 return _fnDataSource( this ) == 'ssp' ?
13567 this._iRecordsDisplay * 1 :
13568 this.aiDisplay.length;
13569 },
13570
13571 /**
13572 * Get the display end point - aiDisplay index
13573 * @type function
13574 */
13575 "fnDisplayEnd": function ()
13576 {
13577 var
13578 len = this._iDisplayLength,
13579 start = this._iDisplayStart,
13580 calc = start + len,
13581 records = this.aiDisplay.length,
13582 features = this.oFeatures,
13583 paginate = features.bPaginate;
13584
13585 if ( features.bServerSide ) {
13586 return paginate === false || len === -1 ?
13587 start + records :
13588 Math.min( start+len, this._iRecordsDisplay );
13589 }
13590 else {
13591 return ! paginate || calc>records || len===-1 ?
13592 records :
13593 calc;
13594 }
13595 },
13596
13597 /**
13598 * The DataTables object for this table
13599 * @type object
13600 * @default null
13601 */
13602 "oInstance": null,
13603
13604 /**
13605 * Unique identifier for each instance of the DataTables object. If there
13606 * is an ID on the table node, then it takes that value, otherwise an
13607 * incrementing internal counter is used.
13608 * @type string
13609 * @default null
13610 */
13611 "sInstance": null,
13612
13613 /**
13614 * tabindex attribute value that is added to DataTables control elements, allowing
13615 * keyboard navigation of the table and its controls.
13616 */
13617 "iTabIndex": 0,
13618
13619 /**
13620 * DIV container for the footer scrolling table if scrolling
13621 */
13622 "nScrollHead": null,
13623
13624 /**
13625 * DIV container for the footer scrolling table if scrolling
13626 */
13627 "nScrollFoot": null,
13628
13629 /**
13630 * Last applied sort
13631 * @type array
13632 * @default []
13633 */
13634 "aLastSort": [],
13635
13636 /**
13637 * Stored plug-in instances
13638 * @type object
13639 * @default {}
13640 */
13641 "oPlugins": {},
13642
13643 /**
13644 * Function used to get a row's id from the row's data
13645 * @type function
13646 * @default null
13647 */
13648 "rowIdFn": null,
13649
13650 /**
13651 * Data location where to store a row's id
13652 * @type string
13653 * @default null
13654 */
13655 "rowId": null
13656 };
13657
13658 /**
13659 * Extension object for DataTables that is used to provide all extension
13660 * options.
13661 *
13662 * Note that the `DataTable.ext` object is available through
13663 * `jQuery.fn.dataTable.ext` where it may be accessed and manipulated. It is
13664 * also aliased to `jQuery.fn.dataTableExt` for historic reasons.
13665 * @namespace
13666 * @extends DataTable.models.ext
13667 */
13668
13669
13670 /**
13671 * DataTables extensions
13672 *
13673 * This namespace acts as a collection area for plug-ins that can be used to
13674 * extend DataTables capabilities. Indeed many of the build in methods
13675 * use this method to provide their own capabilities (sorting methods for
13676 * example).
13677 *
13678 * Note that this namespace is aliased to `jQuery.fn.dataTableExt` for legacy
13679 * reasons
13680 *
13681 * @namespace
13682 */
13683 DataTable.ext = _ext = {
13684 /**
13685 * Buttons. For use with the Buttons extension for DataTables. This is
13686 * defined here so other extensions can define buttons regardless of load
13687 * order. It is _not_ used by DataTables core.
13688 *
13689 * @type object
13690 * @default {}
13691 */
13692 buttons: {},
13693
13694
13695 /**
13696 * Element class names
13697 *
13698 * @type object
13699 * @default {}
13700 */
13701 classes: {},
13702
13703
13704 /**
13705 * Error reporting.
13706 *
13707 * How should DataTables report an error. Can take the value 'alert',
13708 * 'throw', 'none' or a function.
13709 *
13710 * @type string|function
13711 * @default alert
13712 */
13713 errMode: "alert",
13714
13715
13716 /**
13717 * Feature plug-ins.
13718 *
13719 * This is an array of objects which describe the feature plug-ins that are
13720 * available to DataTables. These feature plug-ins are then available for
13721 * use through the `dom` initialisation option.
13722 *
13723 * Each feature plug-in is described by an object which must have the
13724 * following properties:
13725 *
13726 * * `fnInit` - function that is used to initialise the plug-in,
13727 * * `cFeature` - a character so the feature can be enabled by the `dom`
13728 * instillation option. This is case sensitive.
13729 *
13730 * The `fnInit` function has the following input parameters:
13731 *
13732 * 1. `{object}` DataTables settings object: see
13733 * {@link DataTable.models.oSettings}
13734 *
13735 * And the following return is expected:
13736 *
13737 * * {node|null} The element which contains your feature. Note that the
13738 * return may also be void if your plug-in does not require to inject any
13739 * DOM elements into DataTables control (`dom`) - for example this might
13740 * be useful when developing a plug-in which allows table control via
13741 * keyboard entry
13742 *
13743 * @type array
13744 *
13745 * @example
13746 * $.fn.dataTable.ext.features.push( {
13747 * "fnInit": function( oSettings ) {
13748 * return new TableTools( { "oDTSettings": oSettings } );
13749 * },
13750 * "cFeature": "T"
13751 * } );
13752 */
13753 feature: [],
13754
13755
13756 /**
13757 * Row searching.
13758 *
13759 * This method of searching is complimentary to the default type based
13760 * searching, and a lot more comprehensive as it allows you complete control
13761 * over the searching logic. Each element in this array is a function
13762 * (parameters described below) that is called for every row in the table,
13763 * and your logic decides if it should be included in the searching data set
13764 * or not.
13765 *
13766 * Searching functions have the following input parameters:
13767 *
13768 * 1. `{object}` DataTables settings object: see
13769 * {@link DataTable.models.oSettings}
13770 * 2. `{array|object}` Data for the row to be processed (same as the
13771 * original format that was passed in as the data source, or an array
13772 * from a DOM data source
13773 * 3. `{int}` Row index ({@link DataTable.models.oSettings.aoData}), which
13774 * can be useful to retrieve the `TR` element if you need DOM interaction.
13775 *
13776 * And the following return is expected:
13777 *
13778 * * {boolean} Include the row in the searched result set (true) or not
13779 * (false)
13780 *
13781 * Note that as with the main search ability in DataTables, technically this
13782 * is "filtering", since it is subtractive. However, for consistency in
13783 * naming we call it searching here.
13784 *
13785 * @type array
13786 * @default []
13787 *
13788 * @example
13789 * // The following example shows custom search being applied to the
13790 * // fourth column (i.e. the data[3] index) based on two input values
13791 * // from the end-user, matching the data in a certain range.
13792 * $.fn.dataTable.ext.search.push(
13793 * function( settings, data, dataIndex ) {
13794 * var min = document.getElementById('min').value * 1;
13795 * var max = document.getElementById('max').value * 1;
13796 * var version = data[3] == "-" ? 0 : data[3]*1;
13797 *
13798 * if ( min == "" && max == "" ) {
13799 * return true;
13800 * }
13801 * else if ( min == "" && version < max ) {
13802 * return true;
13803 * }
13804 * else if ( min < version && "" == max ) {
13805 * return true;
13806 * }
13807 * else if ( min < version && version < max ) {
13808 * return true;
13809 * }
13810 * return false;
13811 * }
13812 * );
13813 */
13814 search: [],
13815
13816
13817 /**
13818 * Selector extensions
13819 *
13820 * The `selector` option can be used to extend the options available for the
13821 * selector modifier options (`selector-modifier` object data type) that
13822 * each of the three built in selector types offer (row, column and cell +
13823 * their plural counterparts). For example the Select extension uses this
13824 * mechanism to provide an option to select only rows, columns and cells
13825 * that have been marked as selected by the end user (`{selected: true}`),
13826 * which can be used in conjunction with the existing built in selector
13827 * options.
13828 *
13829 * Each property is an array to which functions can be pushed. The functions
13830 * take three attributes:
13831 *
13832 * * Settings object for the host table
13833 * * Options object (`selector-modifier` object type)
13834 * * Array of selected item indexes
13835 *
13836 * The return is an array of the resulting item indexes after the custom
13837 * selector has been applied.
13838 *
13839 * @type object
13840 */
13841 selector: {
13842 cell: [],
13843 column: [],
13844 row: []
13845 },
13846
13847
13848 /**
13849 * Internal functions, exposed for used in plug-ins.
13850 *
13851 * Please note that you should not need to use the internal methods for
13852 * anything other than a plug-in (and even then, try to avoid if possible).
13853 * The internal function may change between releases.
13854 *
13855 * @type object
13856 * @default {}
13857 */
13858 internal: {},
13859
13860
13861 /**
13862 * Legacy configuration options. Enable and disable legacy options that
13863 * are available in DataTables.
13864 *
13865 * @type object
13866 */
13867 legacy: {
13868 /**
13869 * Enable / disable DataTables 1.9 compatible server-side processing
13870 * requests
13871 *
13872 * @type boolean
13873 * @default null
13874 */
13875 ajax: null
13876 },
13877
13878
13879 /**
13880 * Pagination plug-in methods.
13881 *
13882 * Each entry in this object is a function and defines which buttons should
13883 * be shown by the pagination rendering method that is used for the table:
13884 * {@link DataTable.ext.renderer.pageButton}. The renderer addresses how the
13885 * buttons are displayed in the document, while the functions here tell it
13886 * what buttons to display. This is done by returning an array of button
13887 * descriptions (what each button will do).
13888 *
13889 * Pagination types (the four built in options and any additional plug-in
13890 * options defined here) can be used through the `paginationType`
13891 * initialisation parameter.
13892 *
13893 * The functions defined take two parameters:
13894 *
13895 * 1. `{int} page` The current page index
13896 * 2. `{int} pages` The number of pages in the table
13897 *
13898 * Each function is expected to return an array where each element of the
13899 * array can be one of:
13900 *
13901 * * `first` - Jump to first page when activated
13902 * * `last` - Jump to last page when activated
13903 * * `previous` - Show previous page when activated
13904 * * `next` - Show next page when activated
13905 * * `{int}` - Show page of the index given
13906 * * `{array}` - A nested array containing the above elements to add a
13907 * containing 'DIV' element (might be useful for styling).
13908 *
13909 * Note that DataTables v1.9- used this object slightly differently whereby
13910 * an object with two functions would be defined for each plug-in. That
13911 * ability is still supported by DataTables 1.10+ to provide backwards
13912 * compatibility, but this option of use is now decremented and no longer
13913 * documented in DataTables 1.10+.
13914 *
13915 * @type object
13916 * @default {}
13917 *
13918 * @example
13919 * // Show previous, next and current page buttons only
13920 * $.fn.dataTableExt.oPagination.current = function ( page, pages ) {
13921 * return [ 'previous', page, 'next' ];
13922 * };
13923 */
13924 pager: {},
13925
13926
13927 renderer: {
13928 pageButton: {},
13929 header: {}
13930 },
13931
13932
13933 /**
13934 * Ordering plug-ins - custom data source
13935 *
13936 * The extension options for ordering of data available here is complimentary
13937 * to the default type based ordering that DataTables typically uses. It
13938 * allows much greater control over the the data that is being used to
13939 * order a column, but is necessarily therefore more complex.
13940 *
13941 * This type of ordering is useful if you want to do ordering based on data
13942 * live from the DOM (for example the contents of an 'input' element) rather
13943 * than just the static string that DataTables knows of.
13944 *
13945 * The way these plug-ins work is that you create an array of the values you
13946 * wish to be ordering for the column in question and then return that
13947 * array. The data in the array much be in the index order of the rows in
13948 * the table (not the currently ordering order!). Which order data gathering
13949 * function is run here depends on the `dt-init columns.orderDataType`
13950 * parameter that is used for the column (if any).
13951 *
13952 * The functions defined take two parameters:
13953 *
13954 * 1. `{object}` DataTables settings object: see
13955 * {@link DataTable.models.oSettings}
13956 * 2. `{int}` Target column index
13957 *
13958 * Each function is expected to return an array:
13959 *
13960 * * `{array}` Data for the column to be ordering upon
13961 *
13962 * @type array
13963 *
13964 * @example
13965 * // Ordering using `input` node values
13966 * $.fn.dataTable.ext.order['dom-text'] = function ( settings, col )
13967 * {
13968 * return this.api().column( col, {order:'index'} ).nodes().map( function ( td, i ) {
13969 * return $('input', td).val();
13970 * } );
13971 * }
13972 */
13973 order: {},
13974
13975
13976 /**
13977 * Type based plug-ins.
13978 *
13979 * Each column in DataTables has a type assigned to it, either by automatic
13980 * detection or by direct assignment using the `type` option for the column.
13981 * The type of a column will effect how it is ordering and search (plug-ins
13982 * can also make use of the column type if required).
13983 *
13984 * @namespace
13985 */
13986 type: {
13987 /**
13988 * Type detection functions.
13989 *
13990 * The functions defined in this object are used to automatically detect
13991 * a column's type, making initialisation of DataTables super easy, even
13992 * when complex data is in the table.
13993 *
13994 * The functions defined take two parameters:
13995 *
13996 * 1. `{*}` Data from the column cell to be analysed
13997 * 2. `{settings}` DataTables settings object. This can be used to
13998 * perform context specific type detection - for example detection
13999 * based on language settings such as using a comma for a decimal
14000 * place. Generally speaking the options from the settings will not
14001 * be required
14002 *
14003 * Each function is expected to return:
14004 *
14005 * * `{string|null}` Data type detected, or null if unknown (and thus
14006 * pass it on to the other type detection functions.
14007 *
14008 * @type array
14009 *
14010 * @example
14011 * // Currency type detection plug-in:
14012 * $.fn.dataTable.ext.type.detect.push(
14013 * function ( data, settings ) {
14014 * // Check the numeric part
14015 * if ( ! $.isNumeric( data.substring(1) ) ) {
14016 * return null;
14017 * }
14018 *
14019 * // Check prefixed by currency
14020 * if ( data.charAt(0) == '$' || data.charAt(0) == '&pound;' ) {
14021 * return 'currency';
14022 * }
14023 * return null;
14024 * }
14025 * );
14026 */
14027 detect: [],
14028
14029
14030 /**
14031 * Type based search formatting.
14032 *
14033 * The type based searching functions can be used to pre-format the
14034 * data to be search on. For example, it can be used to strip HTML
14035 * tags or to de-format telephone numbers for numeric only searching.
14036 *
14037 * Note that is a search is not defined for a column of a given type,
14038 * no search formatting will be performed.
14039 *
14040 * Pre-processing of searching data plug-ins - When you assign the sType
14041 * for a column (or have it automatically detected for you by DataTables
14042 * or a type detection plug-in), you will typically be using this for
14043 * custom sorting, but it can also be used to provide custom searching
14044 * by allowing you to pre-processing the data and returning the data in
14045 * the format that should be searched upon. This is done by adding
14046 * functions this object with a parameter name which matches the sType
14047 * for that target column. This is the corollary of <i>afnSortData</i>
14048 * for searching data.
14049 *
14050 * The functions defined take a single parameter:
14051 *
14052 * 1. `{*}` Data from the column cell to be prepared for searching
14053 *
14054 * Each function is expected to return:
14055 *
14056 * * `{string|null}` Formatted string that will be used for the searching.
14057 *
14058 * @type object
14059 * @default {}
14060 *
14061 * @example
14062 * $.fn.dataTable.ext.type.search['title-numeric'] = function ( d ) {
14063 * return d.replace(/\n/g," ").replace( /<.*?>/g, "" );
14064 * }
14065 */
14066 search: {},
14067
14068
14069 /**
14070 * Type based ordering.
14071 *
14072 * The column type tells DataTables what ordering to apply to the table
14073 * when a column is sorted upon. The order for each type that is defined,
14074 * is defined by the functions available in this object.
14075 *
14076 * Each ordering option can be described by three properties added to
14077 * this object:
14078 *
14079 * * `{type}-pre` - Pre-formatting function
14080 * * `{type}-asc` - Ascending order function
14081 * * `{type}-desc` - Descending order function
14082 *
14083 * All three can be used together, only `{type}-pre` or only
14084 * `{type}-asc` and `{type}-desc` together. It is generally recommended
14085 * that only `{type}-pre` is used, as this provides the optimal
14086 * implementation in terms of speed, although the others are provided
14087 * for compatibility with existing Javascript sort functions.
14088 *
14089 * `{type}-pre`: Functions defined take a single parameter:
14090 *
14091 * 1. `{*}` Data from the column cell to be prepared for ordering
14092 *
14093 * And return:
14094 *
14095 * * `{*}` Data to be sorted upon
14096 *
14097 * `{type}-asc` and `{type}-desc`: Functions are typical Javascript sort
14098 * functions, taking two parameters:
14099 *
14100 * 1. `{*}` Data to compare to the second parameter
14101 * 2. `{*}` Data to compare to the first parameter
14102 *
14103 * And returning:
14104 *
14105 * * `{*}` Ordering match: <0 if first parameter should be sorted lower
14106 * than the second parameter, ===0 if the two parameters are equal and
14107 * >0 if the first parameter should be sorted height than the second
14108 * parameter.
14109 *
14110 * @type object
14111 * @default {}
14112 *
14113 * @example
14114 * // Numeric ordering of formatted numbers with a pre-formatter
14115 * $.extend( $.fn.dataTable.ext.type.order, {
14116 * "string-pre": function(x) {
14117 * a = (a === "-" || a === "") ? 0 : a.replace( /[^\d\-\.]/g, "" );
14118 * return parseFloat( a );
14119 * }
14120 * } );
14121 *
14122 * @example
14123 * // Case-sensitive string ordering, with no pre-formatting method
14124 * $.extend( $.fn.dataTable.ext.order, {
14125 * "string-case-asc": function(x,y) {
14126 * return ((x < y) ? -1 : ((x > y) ? 1 : 0));
14127 * },
14128 * "string-case-desc": function(x,y) {
14129 * return ((x < y) ? 1 : ((x > y) ? -1 : 0));
14130 * }
14131 * } );
14132 */
14133 order: {}
14134 },
14135
14136 /**
14137 * Unique DataTables instance counter
14138 *
14139 * @type int
14140 * @private
14141 */
14142 _unique: 0,
14143
14144
14145 //
14146 // Depreciated
14147 // The following properties are retained for backwards compatiblity only.
14148 // The should not be used in new projects and will be removed in a future
14149 // version
14150 //
14151
14152 /**
14153 * Version check function.
14154 * @type function
14155 * @depreciated Since 1.10
14156 */
14157 fnVersionCheck: DataTable.fnVersionCheck,
14158
14159
14160 /**
14161 * Index for what 'this' index API functions should use
14162 * @type int
14163 * @deprecated Since v1.10
14164 */
14165 iApiIndex: 0,
14166
14167
14168 /**
14169 * jQuery UI class container
14170 * @type object
14171 * @deprecated Since v1.10
14172 */
14173 oJUIClasses: {},
14174
14175
14176 /**
14177 * Software version
14178 * @type string
14179 * @deprecated Since v1.10
14180 */
14181 sVersion: DataTable.version
14182 };
14183
14184
14185 //
14186 // Backwards compatibility. Alias to pre 1.10 Hungarian notation counter parts
14187 //
14188 $.extend( _ext, {
14189 afnFiltering: _ext.search,
14190 aTypes: _ext.type.detect,
14191 ofnSearch: _ext.type.search,
14192 oSort: _ext.type.order,
14193 afnSortData: _ext.order,
14194 aoFeatures: _ext.feature,
14195 oApi: _ext.internal,
14196 oStdClasses: _ext.classes,
14197 oPagination: _ext.pager
14198 } );
14199
14200
14201 $.extend( DataTable.ext.classes, {
14202 "sTable": "dataTable",
14203 "sNoFooter": "no-footer",
14204
14205 /* Paging buttons */
14206 "sPageButton": "paginate_button",
14207 "sPageButtonActive": "current",
14208 "sPageButtonDisabled": "disabled",
14209
14210 /* Striping classes */
14211 "sStripeOdd": "odd",
14212 "sStripeEven": "even",
14213
14214 /* Empty row */
14215 "sRowEmpty": "dataTables_empty",
14216
14217 /* Features */
14218 "sWrapper": "dataTables_wrapper",
14219 "sFilter": "dataTables_filter",
14220 "sInfo": "dataTables_info",
14221 "sPaging": "dataTables_paginate paging_", /* Note that the type is postfixed */
14222 "sLength": "dataTables_length",
14223 "sProcessing": "dataTables_processing",
14224
14225 /* Sorting */
14226 "sSortAsc": "sorting_asc",
14227 "sSortDesc": "sorting_desc",
14228 "sSortable": "sorting", /* Sortable in both directions */
14229 "sSortableAsc": "sorting_asc_disabled",
14230 "sSortableDesc": "sorting_desc_disabled",
14231 "sSortableNone": "sorting_disabled",
14232 "sSortColumn": "sorting_", /* Note that an int is postfixed for the sorting order */
14233
14234 /* Filtering */
14235 "sFilterInput": "",
14236
14237 /* Page length */
14238 "sLengthSelect": "",
14239
14240 /* Scrolling */
14241 "sScrollWrapper": "dataTables_scroll",
14242 "sScrollHead": "dataTables_scrollHead",
14243 "sScrollHeadInner": "dataTables_scrollHeadInner",
14244 "sScrollBody": "dataTables_scrollBody",
14245 "sScrollFoot": "dataTables_scrollFoot",
14246 "sScrollFootInner": "dataTables_scrollFootInner",
14247
14248 /* Misc */
14249 "sHeaderTH": "",
14250 "sFooterTH": "",
14251
14252 // Deprecated
14253 "sSortJUIAsc": "",
14254 "sSortJUIDesc": "",
14255 "sSortJUI": "",
14256 "sSortJUIAscAllowed": "",
14257 "sSortJUIDescAllowed": "",
14258 "sSortJUIWrapper": "",
14259 "sSortIcon": "",
14260 "sJUIHeader": "",
14261 "sJUIFooter": ""
14262 } );
14263
14264
14265 (function() {
14266
14267 // Reused strings for better compression. Closure compiler appears to have a
14268 // weird edge case where it is trying to expand strings rather than use the
14269 // variable version. This results in about 200 bytes being added, for very
14270 // little preference benefit since it this run on script load only.
14271 var _empty = '';
14272 _empty = '';
14273
14274 var _stateDefault = _empty + 'ui-state-default';
14275 var _sortIcon = _empty + 'css_right ui-icon ui-icon-';
14276 var _headerFooter = _empty + 'fg-toolbar ui-toolbar ui-widget-header ui-helper-clearfix';
14277
14278 $.extend( DataTable.ext.oJUIClasses, DataTable.ext.classes, {
14279 /* Full numbers paging buttons */
14280 "sPageButton": "fg-button ui-button "+_stateDefault,
14281 "sPageButtonActive": "ui-state-disabled",
14282 "sPageButtonDisabled": "ui-state-disabled",
14283
14284 /* Features */
14285 "sPaging": "dataTables_paginate fg-buttonset ui-buttonset fg-buttonset-multi "+
14286 "ui-buttonset-multi paging_", /* Note that the type is postfixed */
14287
14288 /* Sorting */
14289 "sSortAsc": _stateDefault+" sorting_asc",
14290 "sSortDesc": _stateDefault+" sorting_desc",
14291 "sSortable": _stateDefault+" sorting",
14292 "sSortableAsc": _stateDefault+" sorting_asc_disabled",
14293 "sSortableDesc": _stateDefault+" sorting_desc_disabled",
14294 "sSortableNone": _stateDefault+" sorting_disabled",
14295 "sSortJUIAsc": _sortIcon+"triangle-1-n",
14296 "sSortJUIDesc": _sortIcon+"triangle-1-s",
14297 "sSortJUI": _sortIcon+"carat-2-n-s",
14298 "sSortJUIAscAllowed": _sortIcon+"carat-1-n",
14299 "sSortJUIDescAllowed": _sortIcon+"carat-1-s",
14300 "sSortJUIWrapper": "DataTables_sort_wrapper",
14301 "sSortIcon": "DataTables_sort_icon",
14302
14303 /* Scrolling */
14304 "sScrollHead": "dataTables_scrollHead "+_stateDefault,
14305 "sScrollFoot": "dataTables_scrollFoot "+_stateDefault,
14306
14307 /* Misc */
14308 "sHeaderTH": _stateDefault,
14309 "sFooterTH": _stateDefault,
14310 "sJUIHeader": _headerFooter+" ui-corner-tl ui-corner-tr",
14311 "sJUIFooter": _headerFooter+" ui-corner-bl ui-corner-br"
14312 } );
14313
14314 }());
14315
14316
14317
14318 var extPagination = DataTable.ext.pager;
14319
14320 function _numbers ( page, pages ) {
14321 var
14322 numbers = [],
14323 buttons = extPagination.numbers_length,
14324 half = Math.floor( buttons / 2 ),
14325 i = 1;
14326
14327 if ( pages <= buttons ) {
14328 numbers = _range( 0, pages );
14329 }
14330 else if ( page <= half ) {
14331 numbers = _range( 0, buttons-2 );
14332 numbers.push( 'ellipsis' );
14333 numbers.push( pages-1 );
14334 }
14335 else if ( page >= pages - 1 - half ) {
14336 numbers = _range( pages-(buttons-2), pages );
14337 numbers.splice( 0, 0, 'ellipsis' ); // no unshift in ie6
14338 numbers.splice( 0, 0, 0 );
14339 }
14340 else {
14341 numbers = _range( page-half+2, page+half-1 );
14342 numbers.push( 'ellipsis' );
14343 numbers.push( pages-1 );
14344 numbers.splice( 0, 0, 'ellipsis' );
14345 numbers.splice( 0, 0, 0 );
14346 }
14347
14348 numbers.DT_el = 'span';
14349 return numbers;
14350 }
14351
14352
14353 $.extend( extPagination, {
14354 simple: function ( page, pages ) {
14355 return [ 'previous', 'next' ];
14356 },
14357
14358 full: function ( page, pages ) {
14359 return [ 'first', 'previous', 'next', 'last' ];
14360 },
14361
14362 numbers: function ( page, pages ) {
14363 return [ _numbers(page, pages) ];
14364 },
14365
14366 simple_numbers: function ( page, pages ) {
14367 return [ 'previous', _numbers(page, pages), 'next' ];
14368 },
14369
14370 full_numbers: function ( page, pages ) {
14371 return [ 'first', 'previous', _numbers(page, pages), 'next', 'last' ];
14372 },
14373
14374 // For testing and plug-ins to use
14375 _numbers: _numbers,
14376
14377 // Number of number buttons (including ellipsis) to show. _Must be odd!_
14378 numbers_length: 7
14379 } );
14380
14381
14382 $.extend( true, DataTable.ext.renderer, {
14383 pageButton: {
14384 _: function ( settings, host, idx, buttons, page, pages ) {
14385 var classes = settings.oClasses;
14386 var lang = settings.oLanguage.oPaginate;
14387 var btnDisplay, btnClass, counter=0;
14388
14389 var attach = function( container, buttons ) {
14390 var i, ien, node, button;
14391 var clickHandler = function ( e ) {
14392 _fnPageChange( settings, e.data.action, true );
14393 };
14394
14395 for ( i=0, ien=buttons.length ; i<ien ; i++ ) {
14396 button = buttons[i];
14397
14398 if ( $.isArray( button ) ) {
14399 var inner = $( '<'+(button.DT_el || 'div')+'/>' )
14400 .appendTo( container );
14401 attach( inner, button );
14402 }
14403 else {
14404 btnDisplay = null;
14405 btnClass = '';
14406
14407 switch ( button ) {
14408 case 'ellipsis':
14409 container.append('<span class="ellipsis">&#x2026;</span>');
14410 break;
14411
14412 case 'first':
14413 btnDisplay = lang.sFirst;
14414 btnClass = button + (page > 0 ?
14415 '' : ' '+classes.sPageButtonDisabled);
14416 break;
14417
14418 case 'previous':
14419 btnDisplay = lang.sPrevious;
14420 btnClass = button + (page > 0 ?
14421 '' : ' '+classes.sPageButtonDisabled);
14422 break;
14423
14424 case 'next':
14425 btnDisplay = lang.sNext;
14426 btnClass = button + (page < pages-1 ?
14427 '' : ' '+classes.sPageButtonDisabled);
14428 break;
14429
14430 case 'last':
14431 btnDisplay = lang.sLast;
14432 btnClass = button + (page < pages-1 ?
14433 '' : ' '+classes.sPageButtonDisabled);
14434 break;
14435
14436 default:
14437 btnDisplay = button + 1;
14438 btnClass = page === button ?
14439 classes.sPageButtonActive : '';
14440 break;
14441 }
14442
14443 if ( btnDisplay !== null ) {
14444 node = $('<a>', {
14445 'class': classes.sPageButton+' '+btnClass,
14446 'aria-controls': settings.sTableId,
14447 'data-dt-idx': counter,
14448 'tabindex': settings.iTabIndex,
14449 'id': idx === 0 && typeof button === 'string' ?
14450 settings.sTableId +'_'+ button :
14451 null
14452 } )
14453 .html( btnDisplay )
14454 .appendTo( container );
14455
14456 _fnBindAction(
14457 node, {action: button}, clickHandler
14458 );
14459
14460 counter++;
14461 }
14462 }
14463 }
14464 };
14465
14466 // IE9 throws an 'unknown error' if document.activeElement is used
14467 // inside an iframe or frame. Try / catch the error. Not good for
14468 // accessibility, but neither are frames.
14469 var activeEl;
14470
14471 try {
14472 // Because this approach is destroying and recreating the paging
14473 // elements, focus is lost on the select button which is bad for
14474 // accessibility. So we want to restore focus once the draw has
14475 // completed
14476 activeEl = $(host).find(document.activeElement).data('dt-idx');
14477 }
14478 catch (e) {}
14479
14480 attach( $(host).empty(), buttons );
14481
14482 if ( activeEl ) {
14483 $(host).find( '[data-dt-idx='+activeEl+']' ).focus();
14484 }
14485 }
14486 }
14487 } );
14488
14489
14490
14491 // Built in type detection. See model.ext.aTypes for information about
14492 // what is required from this methods.
14493 $.extend( DataTable.ext.type.detect, [
14494 // Plain numbers - first since V8 detects some plain numbers as dates
14495 // e.g. Date.parse('55') (but not all, e.g. Date.parse('22')...).
14496 function ( d, settings )
14497 {
14498 var decimal = settings.oLanguage.sDecimal;
14499 return _isNumber( d, decimal ) ? 'num'+decimal : null;
14500 },
14501
14502 // Dates (only those recognised by the browser's Date.parse)
14503 function ( d, settings )
14504 {
14505 // V8 will remove any unknown characters at the start and end of the
14506 // expression, leading to false matches such as `$245.12` or `10%` being
14507 // a valid date. See forum thread 18941 for detail.
14508 if ( d && !(d instanceof Date) && ( ! _re_date_start.test(d) || ! _re_date_end.test(d) ) ) {
14509 return null;
14510 }
14511 var parsed = Date.parse(d);
14512 return (parsed !== null && !isNaN(parsed)) || _empty(d) ? 'date' : null;
14513 },
14514
14515 // Formatted numbers
14516 function ( d, settings )
14517 {
14518 var decimal = settings.oLanguage.sDecimal;
14519 return _isNumber( d, decimal, true ) ? 'num-fmt'+decimal : null;
14520 },
14521
14522 // HTML numeric
14523 function ( d, settings )
14524 {
14525 var decimal = settings.oLanguage.sDecimal;
14526 return _htmlNumeric( d, decimal ) ? 'html-num'+decimal : null;
14527 },
14528
14529 // HTML numeric, formatted
14530 function ( d, settings )
14531 {
14532 var decimal = settings.oLanguage.sDecimal;
14533 return _htmlNumeric( d, decimal, true ) ? 'html-num-fmt'+decimal : null;
14534 },
14535
14536 // HTML (this is strict checking - there must be html)
14537 function ( d, settings )
14538 {
14539 return _empty( d ) || (typeof d === 'string' && d.indexOf('<') !== -1) ?
14540 'html' : null;
14541 }
14542 ] );
14543
14544
14545
14546 // Filter formatting functions. See model.ext.ofnSearch for information about
14547 // what is required from these methods.
14548 //
14549 // Note that additional search methods are added for the html numbers and
14550 // html formatted numbers by `_addNumericSort()` when we know what the decimal
14551 // place is
14552
14553
14554 $.extend( DataTable.ext.type.search, {
14555 html: function ( data ) {
14556 return _empty(data) ?
14557 data :
14558 typeof data === 'string' ?
14559 data
14560 .replace( _re_new_lines, " " )
14561 .replace( _re_html, "" ) :
14562 '';
14563 },
14564
14565 string: function ( data ) {
14566 return _empty(data) ?
14567 data :
14568 typeof data === 'string' ?
14569 data.replace( _re_new_lines, " " ) :
14570 data;
14571 }
14572 } );
14573
14574
14575
14576 var __numericReplace = function ( d, decimalPlace, re1, re2 ) {
14577 if ( d !== 0 && (!d || d === '-') ) {
14578 return -Infinity;
14579 }
14580
14581 // If a decimal place other than `.` is used, it needs to be given to the
14582 // function so we can detect it and replace with a `.` which is the only
14583 // decimal place Javascript recognises - it is not locale aware.
14584 if ( decimalPlace ) {
14585 d = _numToDecimal( d, decimalPlace );
14586 }
14587
14588 if ( d.replace ) {
14589 if ( re1 ) {
14590 d = d.replace( re1, '' );
14591 }
14592
14593 if ( re2 ) {
14594 d = d.replace( re2, '' );
14595 }
14596 }
14597
14598 return d * 1;
14599 };
14600
14601
14602 // Add the numeric 'deformatting' functions for sorting and search. This is done
14603 // in a function to provide an easy ability for the language options to add
14604 // additional methods if a non-period decimal place is used.
14605 function _addNumericSort ( decimalPlace ) {
14606 $.each(
14607 {
14608 // Plain numbers
14609 "num": function ( d ) {
14610 return __numericReplace( d, decimalPlace );
14611 },
14612
14613 // Formatted numbers
14614 "num-fmt": function ( d ) {
14615 return __numericReplace( d, decimalPlace, _re_formatted_numeric );
14616 },
14617
14618 // HTML numeric
14619 "html-num": function ( d ) {
14620 return __numericReplace( d, decimalPlace, _re_html );
14621 },
14622
14623 // HTML numeric, formatted
14624 "html-num-fmt": function ( d ) {
14625 return __numericReplace( d, decimalPlace, _re_html, _re_formatted_numeric );
14626 }
14627 },
14628 function ( key, fn ) {
14629 // Add the ordering method
14630 _ext.type.order[ key+decimalPlace+'-pre' ] = fn;
14631
14632 // For HTML types add a search formatter that will strip the HTML
14633 if ( key.match(/^html\-/) ) {
14634 _ext.type.search[ key+decimalPlace ] = _ext.type.search.html;
14635 }
14636 }
14637 );
14638 }
14639
14640
14641 // Default sort methods
14642 $.extend( _ext.type.order, {
14643 // Dates
14644 "date-pre": function ( d ) {
14645 return Date.parse( d ) || 0;
14646 },
14647
14648 // html
14649 "html-pre": function ( a ) {
14650 return _empty(a) ?
14651 '' :
14652 a.replace ?
14653 a.replace( /<.*?>/g, "" ).toLowerCase() :
14654 a+'';
14655 },
14656
14657 // string
14658 "string-pre": function ( a ) {
14659 // This is a little complex, but faster than always calling toString,
14660 // http://jsperf.com/tostring-v-check
14661 return _empty(a) ?
14662 '' :
14663 typeof a === 'string' ?
14664 a.toLowerCase() :
14665 ! a.toString ?
14666 '' :
14667 a.toString();
14668 },
14669
14670 // string-asc and -desc are retained only for compatibility with the old
14671 // sort methods
14672 "string-asc": function ( x, y ) {
14673 return ((x < y) ? -1 : ((x > y) ? 1 : 0));
14674 },
14675
14676 "string-desc": function ( x, y ) {
14677 return ((x < y) ? 1 : ((x > y) ? -1 : 0));
14678 }
14679 } );
14680
14681
14682 // Numeric sorting types - order doesn't matter here
14683 _addNumericSort( '' );
14684
14685
14686 $.extend( true, DataTable.ext.renderer, {
14687 header: {
14688 _: function ( settings, cell, column, classes ) {
14689 // No additional mark-up required
14690 // Attach a sort listener to update on sort - note that using the
14691 // `DT` namespace will allow the event to be removed automatically
14692 // on destroy, while the `dt` namespaced event is the one we are
14693 // listening for
14694 $(settings.nTable).on( 'order.dt.DT', function ( e, ctx, sorting, columns ) {
14695 if ( settings !== ctx ) { // need to check this this is the host
14696 return; // table, not a nested one
14697 }
14698
14699 var colIdx = column.idx;
14700
14701 cell
14702 .removeClass(
14703 column.sSortingClass +' '+
14704 classes.sSortAsc +' '+
14705 classes.sSortDesc
14706 )
14707 .addClass( columns[ colIdx ] == 'asc' ?
14708 classes.sSortAsc : columns[ colIdx ] == 'desc' ?
14709 classes.sSortDesc :
14710 column.sSortingClass
14711 );
14712 } );
14713 },
14714
14715 jqueryui: function ( settings, cell, column, classes ) {
14716 $('<div/>')
14717 .addClass( classes.sSortJUIWrapper )
14718 .append( cell.contents() )
14719 .append( $('<span/>')
14720 .addClass( classes.sSortIcon+' '+column.sSortingClassJUI )
14721 )
14722 .appendTo( cell );
14723
14724 // Attach a sort listener to update on sort
14725 $(settings.nTable).on( 'order.dt.DT', function ( e, ctx, sorting, columns ) {
14726 if ( settings !== ctx ) {
14727 return;
14728 }
14729
14730 var colIdx = column.idx;
14731
14732 cell
14733 .removeClass( classes.sSortAsc +" "+classes.sSortDesc )
14734 .addClass( columns[ colIdx ] == 'asc' ?
14735 classes.sSortAsc : columns[ colIdx ] == 'desc' ?
14736 classes.sSortDesc :
14737 column.sSortingClass
14738 );
14739
14740 cell
14741 .find( 'span.'+classes.sSortIcon )
14742 .removeClass(
14743 classes.sSortJUIAsc +" "+
14744 classes.sSortJUIDesc +" "+
14745 classes.sSortJUI +" "+
14746 classes.sSortJUIAscAllowed +" "+
14747 classes.sSortJUIDescAllowed
14748 )
14749 .addClass( columns[ colIdx ] == 'asc' ?
14750 classes.sSortJUIAsc : columns[ colIdx ] == 'desc' ?
14751 classes.sSortJUIDesc :
14752 column.sSortingClassJUI
14753 );
14754 } );
14755 }
14756 }
14757 } );
14758
14759 /*
14760 * Public helper functions. These aren't used internally by DataTables, or
14761 * called by any of the options passed into DataTables, but they can be used
14762 * externally by developers working with DataTables. They are helper functions
14763 * to make working with DataTables a little bit easier.
14764 */
14765
14766 /**
14767 * Helpers for `columns.render`.
14768 *
14769 * The options defined here can be used with the `columns.render` initialisation
14770 * option to provide a display renderer. The following functions are defined:
14771 *
14772 * * `number` - Will format numeric data (defined by `columns.data`) for
14773 * display, retaining the original unformatted data for sorting and filtering.
14774 * It takes 5 parameters:
14775 * * `string` - Thousands grouping separator
14776 * * `string` - Decimal point indicator
14777 * * `integer` - Number of decimal points to show
14778 * * `string` (optional) - Prefix.
14779 * * `string` (optional) - Postfix (/suffix).
14780 *
14781 * @example
14782 * // Column definition using the number renderer
14783 * {
14784 * data: "salary",
14785 * render: $.fn.dataTable.render.number( '\'', '.', 0, '$' )
14786 * }
14787 *
14788 * @namespace
14789 */
14790 DataTable.render = {
14791 number: function ( thousands, decimal, precision, prefix, postfix ) {
14792 return {
14793 display: function ( d ) {
14794 if ( typeof d !== 'number' && typeof d !== 'string' ) {
14795 return d;
14796 }
14797
14798 var negative = d < 0 ? '-' : '';
14799 d = Math.abs( parseFloat( d ) );
14800
14801 var intPart = parseInt( d, 10 );
14802 var floatPart = precision ?
14803 decimal+(d - intPart).toFixed( precision ).substring( 2 ):
14804 '';
14805
14806 return negative + (prefix||'') +
14807 intPart.toString().replace(
14808 /\B(?=(\d{3})+(?!\d))/g, thousands
14809 ) +
14810 floatPart +
14811 (postfix||'');
14812 }
14813 };
14814 }
14815 };
14816
14817
14818 /*
14819 * This is really a good bit rubbish this method of exposing the internal methods
14820 * publicly... - To be fixed in 2.0 using methods on the prototype
14821 */
14822
14823
14824 /**
14825 * Create a wrapper function for exporting an internal functions to an external API.
14826 * @param {string} fn API function name
14827 * @returns {function} wrapped function
14828 * @memberof DataTable#internal
14829 */
14830 function _fnExternApiFunc (fn)
14831 {
14832 return function() {
14833 var args = [_fnSettingsFromNode( this[DataTable.ext.iApiIndex] )].concat(
14834 Array.prototype.slice.call(arguments)
14835 );
14836 return DataTable.ext.internal[fn].apply( this, args );
14837 };
14838 }
14839
14840
14841 /**
14842 * Reference to internal functions for use by plug-in developers. Note that
14843 * these methods are references to internal functions and are considered to be
14844 * private. If you use these methods, be aware that they are liable to change
14845 * between versions.
14846 * @namespace
14847 */
14848 $.extend( DataTable.ext.internal, {
14849 _fnExternApiFunc: _fnExternApiFunc,
14850 _fnBuildAjax: _fnBuildAjax,
14851 _fnAjaxUpdate: _fnAjaxUpdate,
14852 _fnAjaxParameters: _fnAjaxParameters,
14853 _fnAjaxUpdateDraw: _fnAjaxUpdateDraw,
14854 _fnAjaxDataSrc: _fnAjaxDataSrc,
14855 _fnAddColumn: _fnAddColumn,
14856 _fnColumnOptions: _fnColumnOptions,
14857 _fnAdjustColumnSizing: _fnAdjustColumnSizing,
14858 _fnVisibleToColumnIndex: _fnVisibleToColumnIndex,
14859 _fnColumnIndexToVisible: _fnColumnIndexToVisible,
14860 _fnVisbleColumns: _fnVisbleColumns,
14861 _fnGetColumns: _fnGetColumns,
14862 _fnColumnTypes: _fnColumnTypes,
14863 _fnApplyColumnDefs: _fnApplyColumnDefs,
14864 _fnHungarianMap: _fnHungarianMap,
14865 _fnCamelToHungarian: _fnCamelToHungarian,
14866 _fnLanguageCompat: _fnLanguageCompat,
14867 _fnBrowserDetect: _fnBrowserDetect,
14868 _fnAddData: _fnAddData,
14869 _fnAddTr: _fnAddTr,
14870 _fnNodeToDataIndex: _fnNodeToDataIndex,
14871 _fnNodeToColumnIndex: _fnNodeToColumnIndex,
14872 _fnGetCellData: _fnGetCellData,
14873 _fnSetCellData: _fnSetCellData,
14874 _fnSplitObjNotation: _fnSplitObjNotation,
14875 _fnGetObjectDataFn: _fnGetObjectDataFn,
14876 _fnSetObjectDataFn: _fnSetObjectDataFn,
14877 _fnGetDataMaster: _fnGetDataMaster,
14878 _fnClearTable: _fnClearTable,
14879 _fnDeleteIndex: _fnDeleteIndex,
14880 _fnInvalidate: _fnInvalidate,
14881 _fnGetRowElements: _fnGetRowElements,
14882 _fnCreateTr: _fnCreateTr,
14883 _fnBuildHead: _fnBuildHead,
14884 _fnDrawHead: _fnDrawHead,
14885 _fnDraw: _fnDraw,
14886 _fnReDraw: _fnReDraw,
14887 _fnAddOptionsHtml: _fnAddOptionsHtml,
14888 _fnDetectHeader: _fnDetectHeader,
14889 _fnGetUniqueThs: _fnGetUniqueThs,
14890 _fnFeatureHtmlFilter: _fnFeatureHtmlFilter,
14891 _fnFilterComplete: _fnFilterComplete,
14892 _fnFilterCustom: _fnFilterCustom,
14893 _fnFilterColumn: _fnFilterColumn,
14894 _fnFilter: _fnFilter,
14895 _fnFilterCreateSearch: _fnFilterCreateSearch,
14896 _fnEscapeRegex: _fnEscapeRegex,
14897 _fnFilterData: _fnFilterData,
14898 _fnFeatureHtmlInfo: _fnFeatureHtmlInfo,
14899 _fnUpdateInfo: _fnUpdateInfo,
14900 _fnInfoMacros: _fnInfoMacros,
14901 _fnInitialise: _fnInitialise,
14902 _fnInitComplete: _fnInitComplete,
14903 _fnLengthChange: _fnLengthChange,
14904 _fnFeatureHtmlLength: _fnFeatureHtmlLength,
14905 _fnFeatureHtmlPaginate: _fnFeatureHtmlPaginate,
14906 _fnPageChange: _fnPageChange,
14907 _fnFeatureHtmlProcessing: _fnFeatureHtmlProcessing,
14908 _fnProcessingDisplay: _fnProcessingDisplay,
14909 _fnFeatureHtmlTable: _fnFeatureHtmlTable,
14910 _fnScrollDraw: _fnScrollDraw,
14911 _fnApplyToChildren: _fnApplyToChildren,
14912 _fnCalculateColumnWidths: _fnCalculateColumnWidths,
14913 _fnThrottle: _fnThrottle,
14914 _fnConvertToWidth: _fnConvertToWidth,
14915 _fnGetWidestNode: _fnGetWidestNode,
14916 _fnGetMaxLenString: _fnGetMaxLenString,
14917 _fnStringToCss: _fnStringToCss,
14918 _fnSortFlatten: _fnSortFlatten,
14919 _fnSort: _fnSort,
14920 _fnSortAria: _fnSortAria,
14921 _fnSortListener: _fnSortListener,
14922 _fnSortAttachListener: _fnSortAttachListener,
14923 _fnSortingClasses: _fnSortingClasses,
14924 _fnSortData: _fnSortData,
14925 _fnSaveState: _fnSaveState,
14926 _fnLoadState: _fnLoadState,
14927 _fnSettingsFromNode: _fnSettingsFromNode,
14928 _fnLog: _fnLog,
14929 _fnMap: _fnMap,
14930 _fnBindAction: _fnBindAction,
14931 _fnCallbackReg: _fnCallbackReg,
14932 _fnCallbackFire: _fnCallbackFire,
14933 _fnLengthOverflow: _fnLengthOverflow,
14934 _fnRenderer: _fnRenderer,
14935 _fnDataSource: _fnDataSource,
14936 _fnRowAttributes: _fnRowAttributes,
14937 _fnCalculateEnd: function () {} // Used by a lot of plug-ins, but redundant
14938 // in 1.10, so this dead-end function is
14939 // added to prevent errors
14940 } );
14941
14942
14943 // jQuery access
14944 $.fn.dataTable = DataTable;
14945
14946 // Legacy aliases
14947 $.fn.dataTableSettings = DataTable.settings;
14948 $.fn.dataTableExt = DataTable.ext;
14949
14950 // With a capital `D` we return a DataTables API instance rather than a
14951 // jQuery object
14952 $.fn.DataTable = function ( opts ) {
14953 return $(this).dataTable( opts ).api();
14954 };
14955
14956 // All properties that are available to $.fn.dataTable should also be
14957 // available on $.fn.DataTable
14958 $.each( DataTable, function ( prop, val ) {
14959 $.fn.DataTable[ prop ] = val;
14960 } );
14961
14962
14963 // Information about events fired by DataTables - for documentation.
14964 /**
14965 * Draw event, fired whenever the table is redrawn on the page, at the same
14966 * point as fnDrawCallback. This may be useful for binding events or
14967 * performing calculations when the table is altered at all.
14968 * @name DataTable#draw.dt
14969 * @event
14970 * @param {event} e jQuery event object
14971 * @param {object} o DataTables settings object {@link DataTable.models.oSettings}
14972 */
14973
14974 /**
14975 * Search event, fired when the searching applied to the table (using the
14976 * built-in global search, or column filters) is altered.
14977 * @name DataTable#search.dt
14978 * @event
14979 * @param {event} e jQuery event object
14980 * @param {object} o DataTables settings object {@link DataTable.models.oSettings}
14981 */
14982
14983 /**
14984 * Page change event, fired when the paging of the table is altered.
14985 * @name DataTable#page.dt
14986 * @event
14987 * @param {event} e jQuery event object
14988 * @param {object} o DataTables settings object {@link DataTable.models.oSettings}
14989 */
14990
14991 /**
14992 * Order event, fired when the ordering applied to the table is altered.
14993 * @name DataTable#order.dt
14994 * @event
14995 * @param {event} e jQuery event object
14996 * @param {object} o DataTables settings object {@link DataTable.models.oSettings}
14997 */
14998
14999 /**
15000 * DataTables initialisation complete event, fired when the table is fully
15001 * drawn, including Ajax data loaded, if Ajax data is required.
15002 * @name DataTable#init.dt
15003 * @event
15004 * @param {event} e jQuery event object
15005 * @param {object} oSettings DataTables settings object
15006 * @param {object} json The JSON object request from the server - only
15007 * present if client-side Ajax sourced data is used</li></ol>
15008 */
15009
15010 /**
15011 * State save event, fired when the table has changed state a new state save
15012 * is required. This event allows modification of the state saving object
15013 * prior to actually doing the save, including addition or other state
15014 * properties (for plug-ins) or modification of a DataTables core property.
15015 * @name DataTable#stateSaveParams.dt
15016 * @event
15017 * @param {event} e jQuery event object
15018 * @param {object} oSettings DataTables settings object
15019 * @param {object} json The state information to be saved
15020 */
15021
15022 /**
15023 * State load event, fired when the table is loading state from the stored
15024 * data, but prior to the settings object being modified by the saved state
15025 * - allowing modification of the saved state is required or loading of
15026 * state for a plug-in.
15027 * @name DataTable#stateLoadParams.dt
15028 * @event
15029 * @param {event} e jQuery event object
15030 * @param {object} oSettings DataTables settings object
15031 * @param {object} json The saved state information
15032 */
15033
15034 /**
15035 * State loaded event, fired when state has been loaded from stored data and
15036 * the settings object has been modified by the loaded data.
15037 * @name DataTable#stateLoaded.dt
15038 * @event
15039 * @param {event} e jQuery event object
15040 * @param {object} oSettings DataTables settings object
15041 * @param {object} json The saved state information
15042 */
15043
15044 /**
15045 * Processing event, fired when DataTables is doing some kind of processing
15046 * (be it, order, searcg or anything else). It can be used to indicate to
15047 * the end user that there is something happening, or that something has
15048 * finished.
15049 * @name DataTable#processing.dt
15050 * @event
15051 * @param {event} e jQuery event object
15052 * @param {object} oSettings DataTables settings object
15053 * @param {boolean} bShow Flag for if DataTables is doing processing or not
15054 */
15055
15056 /**
15057 * Ajax (XHR) event, fired whenever an Ajax request is completed from a
15058 * request to made to the server for new data. This event is called before
15059 * DataTables processed the returned data, so it can also be used to pre-
15060 * process the data returned from the server, if needed.
15061 *
15062 * Note that this trigger is called in `fnServerData`, if you override
15063 * `fnServerData` and which to use this event, you need to trigger it in you
15064 * success function.
15065 * @name DataTable#xhr.dt
15066 * @event
15067 * @param {event} e jQuery event object
15068 * @param {object} o DataTables settings object {@link DataTable.models.oSettings}
15069 * @param {object} json JSON returned from the server
15070 *
15071 * @example
15072 * // Use a custom property returned from the server in another DOM element
15073 * $('#table').dataTable().on('xhr.dt', function (e, settings, json) {
15074 * $('#status').html( json.status );
15075 * } );
15076 *
15077 * @example
15078 * // Pre-process the data returned from the server
15079 * $('#table').dataTable().on('xhr.dt', function (e, settings, json) {
15080 * for ( var i=0, ien=json.aaData.length ; i<ien ; i++ ) {
15081 * json.aaData[i].sum = json.aaData[i].one + json.aaData[i].two;
15082 * }
15083 * // Note no return - manipulate the data directly in the JSON object.
15084 * } );
15085 */
15086
15087 /**
15088 * Destroy event, fired when the DataTable is destroyed by calling fnDestroy
15089 * or passing the bDestroy:true parameter in the initialisation object. This
15090 * can be used to remove bound events, added DOM nodes, etc.
15091 * @name DataTable#destroy.dt
15092 * @event
15093 * @param {event} e jQuery event object
15094 * @param {object} o DataTables settings object {@link DataTable.models.oSettings}
15095 */
15096
15097 /**
15098 * Page length change event, fired when number of records to show on each
15099 * page (the length) is changed.
15100 * @name DataTable#length.dt
15101 * @event
15102 * @param {event} e jQuery event object
15103 * @param {object} o DataTables settings object {@link DataTable.models.oSettings}
15104 * @param {integer} len New length
15105 */
15106
15107 /**
15108 * Column sizing has changed.
15109 * @name DataTable#column-sizing.dt
15110 * @event
15111 * @param {event} e jQuery event object
15112 * @param {object} o DataTables settings object {@link DataTable.models.oSettings}
15113 */
15114
15115 /**
15116 * Column visibility has changed.
15117 * @name DataTable#column-visibility.dt
15118 * @event
15119 * @param {event} e jQuery event object
15120 * @param {object} o DataTables settings object {@link DataTable.models.oSettings}
15121 * @param {int} column Column index
15122 * @param {bool} vis `false` if column now hidden, or `true` if visible
15123 */
15124
15125 return $.fn.dataTable;
15126 }));
15127
15128 }(window, document));
15129