PluginProbe
Posts Table with Search & Sort / 1.0.1
Posts Table with Search & Sort v1.0.1
1.4.13 trunk 1.0 1.0.1 1.0.2 1.0.3 1.0.4 1.0.5 1.0.6 1.1 1.1.1 1.1.2 1.1.3 1.1.4 1.1.5 1.2 1.3 1.3.1 1.3.1-v2 1.3.2 1.3.3 1.3.4 1.3.5 1.3.6 1.3.7 All 40 releases
posts-data-table / assets / js / datatables.js

datatables.js in Posts Table with Search & Sort 1.0.1, at assets/js/datatables.js

16,378 lines 466.0 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 /*
2 * This combined file was created by the DataTables downloader builder:
3 * https://datatables.net/download
4 *
5 * To rebuild or modify this file with the latest versions of the included
6 * software please visit:
7 * https://datatables.net/download/#dt/dt-1.10.10,r-2.0.0
8 *
9 * Included libraries:
10 * DataTables 1.10.10, Responsive 2.0.0
11 */
12
13 /*! DataTables 1.10.10
14 * ©2008-2015 SpryMedia Ltd - datatables.net/license
15 */
16
17 /**
18 * @summary DataTables
19 * @description Paginate, search and order HTML tables
20 * @version 1.10.10
21 * @file jquery.dataTables.js
22 * @author SpryMedia Ltd (www.sprymedia.co.uk)
23 * @contact www.sprymedia.co.uk/contact
24 * @copyright Copyright 2008-2015 SpryMedia Ltd.
25 *
26 * This source file is free software, available under the following license:
27 * MIT license - http://datatables.net/license
28 *
29 * This source file is distributed in the hope that it will be useful, but
30 * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
31 * or FITNESS FOR A PARTICULAR PURPOSE. See the license files for details.
32 *
33 * For details please refer to: http://www.datatables.net
34 */
35
36 /*jslint evil: true, undef: true, browser: true */
37 /*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*/
38
39 (function( factory ) {
40 "use strict";
41
42 if ( typeof define === 'function' && define.amd ) {
43 // AMD
44 define( ['jquery'], function ( $ ) {
45 return factory( $, window, document );
46 } );
47 }
48 else if ( typeof exports === 'object' ) {
49 // CommonJS
50 module.exports = function (root, $) {
51 if ( ! root ) {
52 // CommonJS environments without a window global must pass a
53 // root. This will give an error otherwise
54 root = window;
55 }
56
57 if ( ! $ ) {
58 $ = typeof window !== 'undefined' ? // jQuery's factory checks for a global window
59 require('jquery') :
60 require('jquery')( root );
61 }
62
63 return factory( $, root, root.document );
64 };
65 }
66 else {
67 // Browser
68 factory( jQuery, window, document );
69 }
70 }
71 (function( $, window, document, undefined ) {
72 "use strict";
73
74 /**
75 * DataTables is a plug-in for the jQuery Javascript library. It is a highly
76 * flexible tool, based upon the foundations of progressive enhancement,
77 * which will add advanced interaction controls to any HTML table. For a
78 * full list of features please refer to
79 * [DataTables.net](href="http://datatables.net).
80 *
81 * Note that the `DataTable` object is not a global variable but is aliased
82 * to `jQuery.fn.DataTable` and `jQuery.fn.dataTable` through which it may
83 * be accessed.
84 *
85 * @class
86 * @param {object} [init={}] Configuration object for DataTables. Options
87 * are defined by {@link DataTable.defaults}
88 * @requires jQuery 1.7+
89 *
90 * @example
91 * // Basic initialisation
92 * $(document).ready( function {
93 * $('#example').dataTable();
94 * } );
95 *
96 * @example
97 * // Initialisation with configuration options - in this case, disable
98 * // pagination and sorting.
99 * $(document).ready( function {
100 * $('#example').dataTable( {
101 * "paginate": false,
102 * "sort": false
103 * } );
104 * } );
105 */
106 var DataTable;
107
108
109 /*
110 * It is useful to have variables which are scoped locally so only the
111 * DataTables functions can access them and they don't leak into global space.
112 * At the same time these functions are often useful over multiple files in the
113 * core and API, so we list, or at least document, all variables which are used
114 * by DataTables as private variables here. This also ensures that there is no
115 * clashing of variable names and that they can easily referenced for reuse.
116 */
117
118
119 // Defined else where
120 // _selector_run
121 // _selector_opts
122 // _selector_first
123 // _selector_row_indexes
124
125 var _ext; // DataTable.ext
126 var _Api; // DataTable.Api
127 var _api_register; // DataTable.Api.register
128 var _api_registerPlural; // DataTable.Api.registerPlural
129
130 var _re_dic = {};
131 var _re_new_lines = /[\r\n]/g;
132 var _re_html = /<.*?>/g;
133 var _re_date_start = /^[\w\+\-]/;
134 var _re_date_end = /[\w\+\-]$/;
135
136 // Escape regular expression special characters
137 var _re_escape_regex = new RegExp( '(\\' + [ '/', '.', '*', '+', '?', '|', '(', ')', '[', ']', '{', '}', '\\', '$', '^', '-' ].join('|\\') + ')', 'g' );
138
139 // http://en.wikipedia.org/wiki/Foreign_exchange_market
140 // - \u20BD - Russian ruble.
141 // - \u20a9 - South Korean Won
142 // - \u20BA - Turkish Lira
143 // - \u20B9 - Indian Rupee
144 // - R - Brazil (R$) and South Africa
145 // - fr - Swiss Franc
146 // - kr - Swedish krona, Norwegian krone and Danish krone
147 // - \u2009 is thin space and \u202F is narrow no-break space, both used in many
148 // standards as thousands separators.
149 var _re_formatted_numeric = /[',$£€¥%\u2009\u202F\u20BD\u20a9\u20BArfk]/gi;
150
151
152 var _empty = function ( d ) {
153 return !d || d === true || d === '-' ? true : false;
154 };
155
156
157 var _intVal = function ( s ) {
158 var integer = parseInt( s, 10 );
159 return !isNaN(integer) && isFinite(s) ? integer : null;
160 };
161
162 // Convert from a formatted number with characters other than `.` as the
163 // decimal place, to a Javascript number
164 var _numToDecimal = function ( num, decimalPoint ) {
165 // Cache created regular expressions for speed as this function is called often
166 if ( ! _re_dic[ decimalPoint ] ) {
167 _re_dic[ decimalPoint ] = new RegExp( _fnEscapeRegex( decimalPoint ), 'g' );
168 }
169 return typeof num === 'string' && decimalPoint !== '.' ?
170 num.replace( /\./g, '' ).replace( _re_dic[ decimalPoint ], '.' ) :
171 num;
172 };
173
174
175 var _isNumber = function ( d, decimalPoint, formatted ) {
176 var strType = typeof d === 'string';
177
178 // If empty return immediately so there must be a number if it is a
179 // formatted string (this stops the string "k", or "kr", etc being detected
180 // as a formatted number for currency
181 if ( _empty( d ) ) {
182 return true;
183 }
184
185 if ( decimalPoint && strType ) {
186 d = _numToDecimal( d, decimalPoint );
187 }
188
189 if ( formatted && strType ) {
190 d = d.replace( _re_formatted_numeric, '' );
191 }
192
193 return !isNaN( parseFloat(d) ) && isFinite( d );
194 };
195
196
197 // A string without HTML in it can be considered to be HTML still
198 var _isHtml = function ( d ) {
199 return _empty( d ) || typeof d === 'string';
200 };
201
202
203 var _htmlNumeric = function ( d, decimalPoint, formatted ) {
204 if ( _empty( d ) ) {
205 return true;
206 }
207
208 var html = _isHtml( d );
209 return ! html ?
210 null :
211 _isNumber( _stripHtml( d ), decimalPoint, formatted ) ?
212 true :
213 null;
214 };
215
216
217 var _pluck = function ( a, prop, prop2 ) {
218 var out = [];
219 var i=0, ien=a.length;
220
221 // Could have the test in the loop for slightly smaller code, but speed
222 // is essential here
223 if ( prop2 !== undefined ) {
224 for ( ; i<ien ; i++ ) {
225 if ( a[i] && a[i][ prop ] ) {
226 out.push( a[i][ prop ][ prop2 ] );
227 }
228 }
229 }
230 else {
231 for ( ; i<ien ; i++ ) {
232 if ( a[i] ) {
233 out.push( a[i][ prop ] );
234 }
235 }
236 }
237
238 return out;
239 };
240
241
242 // Basically the same as _pluck, but rather than looping over `a` we use `order`
243 // as the indexes to pick from `a`
244 var _pluck_order = function ( a, order, prop, prop2 )
245 {
246 var out = [];
247 var i=0, ien=order.length;
248
249 // Could have the test in the loop for slightly smaller code, but speed
250 // is essential here
251 if ( prop2 !== undefined ) {
252 for ( ; i<ien ; i++ ) {
253 if ( a[ order[i] ][ prop ] ) {
254 out.push( a[ order[i] ][ prop ][ prop2 ] );
255 }
256 }
257 }
258 else {
259 for ( ; i<ien ; i++ ) {
260 out.push( a[ order[i] ][ prop ] );
261 }
262 }
263
264 return out;
265 };
266
267
268 var _range = function ( len, start )
269 {
270 var out = [];
271 var end;
272
273 if ( start === undefined ) {
274 start = 0;
275 end = len;
276 }
277 else {
278 end = start;
279 start = len;
280 }
281
282 for ( var i=start ; i<end ; i++ ) {
283 out.push( i );
284 }
285
286 return out;
287 };
288
289
290 var _removeEmpty = function ( a )
291 {
292 var out = [];
293
294 for ( var i=0, ien=a.length ; i<ien ; i++ ) {
295 if ( a[i] ) { // careful - will remove all falsy values!
296 out.push( a[i] );
297 }
298 }
299
300 return out;
301 };
302
303
304 var _stripHtml = function ( d ) {
305 return d.replace( _re_html, '' );
306 };
307
308
309 /**
310 * Find the unique elements in a source array.
311 *
312 * @param {array} src Source array
313 * @return {array} Array of unique items
314 * @ignore
315 */
316 var _unique = function ( src )
317 {
318 // A faster unique method is to use object keys to identify used values,
319 // but this doesn't work with arrays or objects, which we must also
320 // consider. See jsperf.com/compare-array-unique-versions/4 for more
321 // information.
322 var
323 out = [],
324 val,
325 i, ien=src.length,
326 j, k=0;
327
328 again: for ( i=0 ; i<ien ; i++ ) {
329 val = src[i];
330
331 for ( j=0 ; j<k ; j++ ) {
332 if ( out[j] === val ) {
333 continue again;
334 }
335 }
336
337 out.push( val );
338 k++;
339 }
340
341 return out;
342 };
343
344
345
346 /**
347 * Create a mapping object that allows camel case parameters to be looked up
348 * for their Hungarian counterparts. The mapping is stored in a private
349 * parameter called `_hungarianMap` which can be accessed on the source object.
350 * @param {object} o
351 * @memberof DataTable#oApi
352 */
353 function _fnHungarianMap ( o )
354 {
355 var
356 hungarian = 'a aa ai ao as b fn i m o s ',
357 match,
358 newKey,
359 map = {};
360
361 $.each( o, function (key, val) {
362 match = key.match(/^([^A-Z]+?)([A-Z])/);
363
364 if ( match && hungarian.indexOf(match[1]+' ') !== -1 )
365 {
366 newKey = key.replace( match[0], match[2].toLowerCase() );
367 map[ newKey ] = key;
368
369 if ( match[1] === 'o' )
370 {
371 _fnHungarianMap( o[key] );
372 }
373 }
374 } );
375
376 o._hungarianMap = map;
377 }
378
379
380 /**
381 * Convert from camel case parameters to Hungarian, based on a Hungarian map
382 * created by _fnHungarianMap.
383 * @param {object} src The model object which holds all parameters that can be
384 * mapped.
385 * @param {object} user The object to convert from camel case to Hungarian.
386 * @param {boolean} force When set to `true`, properties which already have a
387 * Hungarian value in the `user` object will be overwritten. Otherwise they
388 * won't be.
389 * @memberof DataTable#oApi
390 */
391 function _fnCamelToHungarian ( src, user, force )
392 {
393 if ( ! src._hungarianMap ) {
394 _fnHungarianMap( src );
395 }
396
397 var hungarianKey;
398
399 $.each( user, function (key, val) {
400 hungarianKey = src._hungarianMap[ key ];
401
402 if ( hungarianKey !== undefined && (force || user[hungarianKey] === undefined) )
403 {
404 // For objects, we need to buzz down into the object to copy parameters
405 if ( hungarianKey.charAt(0) === 'o' )
406 {
407 // Copy the camelCase options over to the hungarian
408 if ( ! user[ hungarianKey ] ) {
409 user[ hungarianKey ] = {};
410 }
411 $.extend( true, user[hungarianKey], user[key] );
412
413 _fnCamelToHungarian( src[hungarianKey], user[hungarianKey], force );
414 }
415 else {
416 user[hungarianKey] = user[ key ];
417 }
418 }
419 } );
420 }
421
422
423 /**
424 * Language compatibility - when certain options are given, and others aren't, we
425 * need to duplicate the values over, in order to provide backwards compatibility
426 * with older language files.
427 * @param {object} oSettings dataTables settings object
428 * @memberof DataTable#oApi
429 */
430 function _fnLanguageCompat( lang )
431 {
432 var defaults = DataTable.defaults.oLanguage;
433 var zeroRecords = lang.sZeroRecords;
434
435 /* Backwards compatibility - if there is no sEmptyTable given, then use the same as
436 * sZeroRecords - assuming that is given.
437 */
438 if ( ! lang.sEmptyTable && zeroRecords &&
439 defaults.sEmptyTable === "No data available in table" )
440 {
441 _fnMap( lang, lang, 'sZeroRecords', 'sEmptyTable' );
442 }
443
444 /* Likewise with loading records */
445 if ( ! lang.sLoadingRecords && zeroRecords &&
446 defaults.sLoadingRecords === "Loading..." )
447 {
448 _fnMap( lang, lang, 'sZeroRecords', 'sLoadingRecords' );
449 }
450
451 // Old parameter name of the thousands separator mapped onto the new
452 if ( lang.sInfoThousands ) {
453 lang.sThousands = lang.sInfoThousands;
454 }
455
456 var decimal = lang.sDecimal;
457 if ( decimal ) {
458 _addNumericSort( decimal );
459 }
460 }
461
462
463 /**
464 * Map one parameter onto another
465 * @param {object} o Object to map
466 * @param {*} knew The new parameter name
467 * @param {*} old The old parameter name
468 */
469 var _fnCompatMap = function ( o, knew, old ) {
470 if ( o[ knew ] !== undefined ) {
471 o[ old ] = o[ knew ];
472 }
473 };
474
475
476 /**
477 * Provide backwards compatibility for the main DT options. Note that the new
478 * options are mapped onto the old parameters, so this is an external interface
479 * change only.
480 * @param {object} init Object to map
481 */
482 function _fnCompatOpts ( init )
483 {
484 _fnCompatMap( init, 'ordering', 'bSort' );
485 _fnCompatMap( init, 'orderMulti', 'bSortMulti' );
486 _fnCompatMap( init, 'orderClasses', 'bSortClasses' );
487 _fnCompatMap( init, 'orderCellsTop', 'bSortCellsTop' );
488 _fnCompatMap( init, 'order', 'aaSorting' );
489 _fnCompatMap( init, 'orderFixed', 'aaSortingFixed' );
490 _fnCompatMap( init, 'paging', 'bPaginate' );
491 _fnCompatMap( init, 'pagingType', 'sPaginationType' );
492 _fnCompatMap( init, 'pageLength', 'iDisplayLength' );
493 _fnCompatMap( init, 'searching', 'bFilter' );
494
495 // Boolean initialisation of x-scrolling
496 if ( typeof init.sScrollX === 'boolean' ) {
497 init.sScrollX = init.sScrollX ? '100%' : '';
498 }
499 if ( typeof init.scrollX === 'boolean' ) {
500 init.scrollX = init.scrollX ? '100%' : '';
501 }
502
503 // Column search objects are in an array, so it needs to be converted
504 // element by element
505 var searchCols = init.aoSearchCols;
506
507 if ( searchCols ) {
508 for ( var i=0, ien=searchCols.length ; i<ien ; i++ ) {
509 if ( searchCols[i] ) {
510 _fnCamelToHungarian( DataTable.models.oSearch, searchCols[i] );
511 }
512 }
513 }
514 }
515
516
517 /**
518 * Provide backwards compatibility for column options. Note that the new options
519 * are mapped onto the old parameters, so this is an external interface change
520 * only.
521 * @param {object} init Object to map
522 */
523 function _fnCompatCols ( init )
524 {
525 _fnCompatMap( init, 'orderable', 'bSortable' );
526 _fnCompatMap( init, 'orderData', 'aDataSort' );
527 _fnCompatMap( init, 'orderSequence', 'asSorting' );
528 _fnCompatMap( init, 'orderDataType', 'sortDataType' );
529
530 // orderData can be given as an integer
531 var dataSort = init.aDataSort;
532 if ( dataSort && ! $.isArray( dataSort ) ) {
533 init.aDataSort = [ dataSort ];
534 }
535 }
536
537
538 /**
539 * Browser feature detection for capabilities, quirks
540 * @param {object} settings dataTables settings object
541 * @memberof DataTable#oApi
542 */
543 function _fnBrowserDetect( settings )
544 {
545 // We don't need to do this every time DataTables is constructed, the values
546 // calculated are specific to the browser and OS configuration which we
547 // don't expect to change between initialisations
548 if ( ! DataTable.__browser ) {
549 var browser = {};
550 DataTable.__browser = browser;
551
552 // Scrolling feature / quirks detection
553 var n = $('<div/>')
554 .css( {
555 position: 'fixed',
556 top: 0,
557 left: 0,
558 height: 1,
559 width: 1,
560 overflow: 'hidden'
561 } )
562 .append(
563 $('<div/>')
564 .css( {
565 position: 'absolute',
566 top: 1,
567 left: 1,
568 width: 100,
569 overflow: 'scroll'
570 } )
571 .append(
572 $('<div/>')
573 .css( {
574 width: '100%',
575 height: 10
576 } )
577 )
578 )
579 .appendTo( 'body' );
580
581 var outer = n.children();
582 var inner = outer.children();
583
584 // Numbers below, in order, are:
585 // inner.offsetWidth, inner.clientWidth, outer.offsetWidth, outer.clientWidth
586 //
587 // IE6 XP: 100 100 100 83
588 // IE7 Vista: 100 100 100 83
589 // IE 8+ Windows: 83 83 100 83
590 // Evergreen Windows: 83 83 100 83
591 // Evergreen Mac with scrollbars: 85 85 100 85
592 // Evergreen Mac without scrollbars: 100 100 100 100
593
594 // Get scrollbar width
595 browser.barWidth = outer[0].offsetWidth - outer[0].clientWidth;
596
597 // IE6/7 will oversize a width 100% element inside a scrolling element, to
598 // include the width of the scrollbar, while other browsers ensure the inner
599 // element is contained without forcing scrolling
600 browser.bScrollOversize = inner[0].offsetWidth === 100 && outer[0].clientWidth !== 100;
601
602 // In rtl text layout, some browsers (most, but not all) will place the
603 // scrollbar on the left, rather than the right.
604 browser.bScrollbarLeft = Math.round( inner.offset().left ) !== 1;
605
606 // IE8- don't provide height and width for getBoundingClientRect
607 browser.bBounding = n[0].getBoundingClientRect().width ? true : false;
608
609 n.remove();
610 }
611
612 $.extend( settings.oBrowser, DataTable.__browser );
613 settings.oScroll.iBarWidth = DataTable.__browser.barWidth;
614 }
615
616
617 /**
618 * Array.prototype reduce[Right] method, used for browsers which don't support
619 * JS 1.6. Done this way to reduce code size, since we iterate either way
620 * @param {object} settings dataTables settings object
621 * @memberof DataTable#oApi
622 */
623 function _fnReduce ( that, fn, init, start, end, inc )
624 {
625 var
626 i = start,
627 value,
628 isSet = false;
629
630 if ( init !== undefined ) {
631 value = init;
632 isSet = true;
633 }
634
635 while ( i !== end ) {
636 if ( ! that.hasOwnProperty(i) ) {
637 continue;
638 }
639
640 value = isSet ?
641 fn( value, that[i], i, that ) :
642 that[i];
643
644 isSet = true;
645 i += inc;
646 }
647
648 return value;
649 }
650
651 /**
652 * Add a column to the list used for the table with default values
653 * @param {object} oSettings dataTables settings object
654 * @param {node} nTh The th element for this column
655 * @memberof DataTable#oApi
656 */
657 function _fnAddColumn( oSettings, nTh )
658 {
659 // Add column to aoColumns array
660 var oDefaults = DataTable.defaults.column;
661 var iCol = oSettings.aoColumns.length;
662 var oCol = $.extend( {}, DataTable.models.oColumn, oDefaults, {
663 "nTh": nTh ? nTh : document.createElement('th'),
664 "sTitle": oDefaults.sTitle ? oDefaults.sTitle : nTh ? nTh.innerHTML : '',
665 "aDataSort": oDefaults.aDataSort ? oDefaults.aDataSort : [iCol],
666 "mData": oDefaults.mData ? oDefaults.mData : iCol,
667 idx: iCol
668 } );
669 oSettings.aoColumns.push( oCol );
670
671 // Add search object for column specific search. Note that the `searchCols[ iCol ]`
672 // passed into extend can be undefined. This allows the user to give a default
673 // with only some of the parameters defined, and also not give a default
674 var searchCols = oSettings.aoPreSearchCols;
675 searchCols[ iCol ] = $.extend( {}, DataTable.models.oSearch, searchCols[ iCol ] );
676
677 // Use the default column options function to initialise classes etc
678 _fnColumnOptions( oSettings, iCol, $(nTh).data() );
679 }
680
681
682 /**
683 * Apply options for a column
684 * @param {object} oSettings dataTables settings object
685 * @param {int} iCol column index to consider
686 * @param {object} oOptions object with sType, bVisible and bSearchable etc
687 * @memberof DataTable#oApi
688 */
689 function _fnColumnOptions( oSettings, iCol, oOptions )
690 {
691 var oCol = oSettings.aoColumns[ iCol ];
692 var oClasses = oSettings.oClasses;
693 var th = $(oCol.nTh);
694
695 // Try to get width information from the DOM. We can't get it from CSS
696 // as we'd need to parse the CSS stylesheet. `width` option can override
697 if ( ! oCol.sWidthOrig ) {
698 // Width attribute
699 oCol.sWidthOrig = th.attr('width') || null;
700
701 // Style attribute
702 var t = (th.attr('style') || '').match(/width:\s*(\d+[pxem%]+)/);
703 if ( t ) {
704 oCol.sWidthOrig = t[1];
705 }
706 }
707
708 /* User specified column options */
709 if ( oOptions !== undefined && oOptions !== null )
710 {
711 // Backwards compatibility
712 _fnCompatCols( oOptions );
713
714 // Map camel case parameters to their Hungarian counterparts
715 _fnCamelToHungarian( DataTable.defaults.column, oOptions );
716
717 /* Backwards compatibility for mDataProp */
718 if ( oOptions.mDataProp !== undefined && !oOptions.mData )
719 {
720 oOptions.mData = oOptions.mDataProp;
721 }
722
723 if ( oOptions.sType )
724 {
725 oCol._sManualType = oOptions.sType;
726 }
727
728 // `class` is a reserved word in Javascript, so we need to provide
729 // the ability to use a valid name for the camel case input
730 if ( oOptions.className && ! oOptions.sClass )
731 {
732 oOptions.sClass = oOptions.className;
733 }
734
735 $.extend( oCol, oOptions );
736 _fnMap( oCol, oOptions, "sWidth", "sWidthOrig" );
737
738 /* iDataSort to be applied (backwards compatibility), but aDataSort will take
739 * priority if defined
740 */
741 if ( oOptions.iDataSort !== undefined )
742 {
743 oCol.aDataSort = [ oOptions.iDataSort ];
744 }
745 _fnMap( oCol, oOptions, "aDataSort" );
746 }
747
748 /* Cache the data get and set functions for speed */
749 var mDataSrc = oCol.mData;
750 var mData = _fnGetObjectDataFn( mDataSrc );
751 var mRender = oCol.mRender ? _fnGetObjectDataFn( oCol.mRender ) : null;
752
753 var attrTest = function( src ) {
754 return typeof src === 'string' && src.indexOf('@') !== -1;
755 };
756 oCol._bAttrSrc = $.isPlainObject( mDataSrc ) && (
757 attrTest(mDataSrc.sort) || attrTest(mDataSrc.type) || attrTest(mDataSrc.filter)
758 );
759
760 oCol.fnGetData = function (rowData, type, meta) {
761 var innerData = mData( rowData, type, undefined, meta );
762
763 return mRender && type ?
764 mRender( innerData, type, rowData, meta ) :
765 innerData;
766 };
767 oCol.fnSetData = function ( rowData, val, meta ) {
768 return _fnSetObjectDataFn( mDataSrc )( rowData, val, meta );
769 };
770
771 // Indicate if DataTables should read DOM data as an object or array
772 // Used in _fnGetRowElements
773 if ( typeof mDataSrc !== 'number' ) {
774 oSettings._rowReadObject = true;
775 }
776
777 /* Feature sorting overrides column specific when off */
778 if ( !oSettings.oFeatures.bSort )
779 {
780 oCol.bSortable = false;
781 th.addClass( oClasses.sSortableNone ); // Have to add class here as order event isn't called
782 }
783
784 /* Check that the class assignment is correct for sorting */
785 var bAsc = $.inArray('asc', oCol.asSorting) !== -1;
786 var bDesc = $.inArray('desc', oCol.asSorting) !== -1;
787 if ( !oCol.bSortable || (!bAsc && !bDesc) )
788 {
789 oCol.sSortingClass = oClasses.sSortableNone;
790 oCol.sSortingClassJUI = "";
791 }
792 else if ( bAsc && !bDesc )
793 {
794 oCol.sSortingClass = oClasses.sSortableAsc;
795 oCol.sSortingClassJUI = oClasses.sSortJUIAscAllowed;
796 }
797 else if ( !bAsc && bDesc )
798 {
799 oCol.sSortingClass = oClasses.sSortableDesc;
800 oCol.sSortingClassJUI = oClasses.sSortJUIDescAllowed;
801 }
802 else
803 {
804 oCol.sSortingClass = oClasses.sSortable;
805 oCol.sSortingClassJUI = oClasses.sSortJUI;
806 }
807 }
808
809
810 /**
811 * Adjust the table column widths for new data. Note: you would probably want to
812 * do a redraw after calling this function!
813 * @param {object} settings dataTables settings object
814 * @memberof DataTable#oApi
815 */
816 function _fnAdjustColumnSizing ( settings )
817 {
818 /* Not interested in doing column width calculation if auto-width is disabled */
819 if ( settings.oFeatures.bAutoWidth !== false )
820 {
821 var columns = settings.aoColumns;
822
823 _fnCalculateColumnWidths( settings );
824 for ( var i=0 , iLen=columns.length ; i<iLen ; i++ )
825 {
826 columns[i].nTh.style.width = columns[i].sWidth;
827 }
828 }
829
830 var scroll = settings.oScroll;
831 if ( scroll.sY !== '' || scroll.sX !== '')
832 {
833 _fnScrollDraw( settings );
834 }
835
836 _fnCallbackFire( settings, null, 'column-sizing', [settings] );
837 }
838
839
840 /**
841 * Covert the index of a visible column to the index in the data array (take account
842 * of hidden columns)
843 * @param {object} oSettings dataTables settings object
844 * @param {int} iMatch Visible column index to lookup
845 * @returns {int} i the data index
846 * @memberof DataTable#oApi
847 */
848 function _fnVisibleToColumnIndex( oSettings, iMatch )
849 {
850 var aiVis = _fnGetColumns( oSettings, 'bVisible' );
851
852 return typeof aiVis[iMatch] === 'number' ?
853 aiVis[iMatch] :
854 null;
855 }
856
857
858 /**
859 * Covert the index of an index in the data array and convert it to the visible
860 * column index (take account of hidden columns)
861 * @param {int} iMatch Column index to lookup
862 * @param {object} oSettings dataTables settings object
863 * @returns {int} i the data index
864 * @memberof DataTable#oApi
865 */
866 function _fnColumnIndexToVisible( oSettings, iMatch )
867 {
868 var aiVis = _fnGetColumns( oSettings, 'bVisible' );
869 var iPos = $.inArray( iMatch, aiVis );
870
871 return iPos !== -1 ? iPos : null;
872 }
873
874
875 /**
876 * Get the number of visible columns
877 * @param {object} oSettings dataTables settings object
878 * @returns {int} i the number of visible columns
879 * @memberof DataTable#oApi
880 */
881 function _fnVisbleColumns( oSettings )
882 {
883 return _fnGetColumns( oSettings, 'bVisible' ).length;
884 }
885
886
887 /**
888 * Get an array of column indexes that match a given property
889 * @param {object} oSettings dataTables settings object
890 * @param {string} sParam Parameter in aoColumns to look for - typically
891 * bVisible or bSearchable
892 * @returns {array} Array of indexes with matched properties
893 * @memberof DataTable#oApi
894 */
895 function _fnGetColumns( oSettings, sParam )
896 {
897 var a = [];
898
899 $.map( oSettings.aoColumns, function(val, i) {
900 if ( val[sParam] ) {
901 a.push( i );
902 }
903 } );
904
905 return a;
906 }
907
908
909 /**
910 * Calculate the 'type' of a column
911 * @param {object} settings dataTables settings object
912 * @memberof DataTable#oApi
913 */
914 function _fnColumnTypes ( settings )
915 {
916 var columns = settings.aoColumns;
917 var data = settings.aoData;
918 var types = DataTable.ext.type.detect;
919 var i, ien, j, jen, k, ken;
920 var col, cell, detectedType, cache;
921
922 // For each column, spin over the
923 for ( i=0, ien=columns.length ; i<ien ; i++ ) {
924 col = columns[i];
925 cache = [];
926
927 if ( ! col.sType && col._sManualType ) {
928 col.sType = col._sManualType;
929 }
930 else if ( ! col.sType ) {
931 for ( j=0, jen=types.length ; j<jen ; j++ ) {
932 for ( k=0, ken=data.length ; k<ken ; k++ ) {
933 // Use a cache array so we only need to get the type data
934 // from the formatter once (when using multiple detectors)
935 if ( cache[k] === undefined ) {
936 cache[k] = _fnGetCellData( settings, k, i, 'type' );
937 }
938
939 detectedType = types[j]( cache[k], settings );
940
941 // If null, then this type can't apply to this column, so
942 // rather than testing all cells, break out. There is an
943 // exception for the last type which is `html`. We need to
944 // scan all rows since it is possible to mix string and HTML
945 // types
946 if ( ! detectedType && j !== types.length-1 ) {
947 break;
948 }
949
950 // Only a single match is needed for html type since it is
951 // bottom of the pile and very similar to string
952 if ( detectedType === 'html' ) {
953 break;
954 }
955 }
956
957 // Type is valid for all data points in the column - use this
958 // type
959 if ( detectedType ) {
960 col.sType = detectedType;
961 break;
962 }
963 }
964
965 // Fall back - if no type was detected, always use string
966 if ( ! col.sType ) {
967 col.sType = 'string';
968 }
969 }
970 }
971 }
972
973
974 /**
975 * Take the column definitions and static columns arrays and calculate how
976 * they relate to column indexes. The callback function will then apply the
977 * definition found for a column to a suitable configuration object.
978 * @param {object} oSettings dataTables settings object
979 * @param {array} aoColDefs The aoColumnDefs array that is to be applied
980 * @param {array} aoCols The aoColumns array that defines columns individually
981 * @param {function} fn Callback function - takes two parameters, the calculated
982 * column index and the definition for that column.
983 * @memberof DataTable#oApi
984 */
985 function _fnApplyColumnDefs( oSettings, aoColDefs, aoCols, fn )
986 {
987 var i, iLen, j, jLen, k, kLen, def;
988 var columns = oSettings.aoColumns;
989
990 // Column definitions with aTargets
991 if ( aoColDefs )
992 {
993 /* Loop over the definitions array - loop in reverse so first instance has priority */
994 for ( i=aoColDefs.length-1 ; i>=0 ; i-- )
995 {
996 def = aoColDefs[i];
997
998 /* Each definition can target multiple columns, as it is an array */
999 var aTargets = def.targets !== undefined ?
1000 def.targets :
1001 def.aTargets;
1002
1003 if ( ! $.isArray( aTargets ) )
1004 {
1005 aTargets = [ aTargets ];
1006 }
1007
1008 for ( j=0, jLen=aTargets.length ; j<jLen ; j++ )
1009 {
1010 if ( typeof aTargets[j] === 'number' && aTargets[j] >= 0 )
1011 {
1012 /* Add columns that we don't yet know about */
1013 while( columns.length <= aTargets[j] )
1014 {
1015 _fnAddColumn( oSettings );
1016 }
1017
1018 /* Integer, basic index */
1019 fn( aTargets[j], def );
1020 }
1021 else if ( typeof aTargets[j] === 'number' && aTargets[j] < 0 )
1022 {
1023 /* Negative integer, right to left column counting */
1024 fn( columns.length+aTargets[j], def );
1025 }
1026 else if ( typeof aTargets[j] === 'string' )
1027 {
1028 /* Class name matching on TH element */
1029 for ( k=0, kLen=columns.length ; k<kLen ; k++ )
1030 {
1031 if ( aTargets[j] == "_all" ||
1032 $(columns[k].nTh).hasClass( aTargets[j] ) )
1033 {
1034 fn( k, def );
1035 }
1036 }
1037 }
1038 }
1039 }
1040 }
1041
1042 // Statically defined columns array
1043 if ( aoCols )
1044 {
1045 for ( i=0, iLen=aoCols.length ; i<iLen ; i++ )
1046 {
1047 fn( i, aoCols[i] );
1048 }
1049 }
1050 }
1051
1052 /**
1053 * Add a data array to the table, creating DOM node etc. This is the parallel to
1054 * _fnGatherData, but for adding rows from a Javascript source, rather than a
1055 * DOM source.
1056 * @param {object} oSettings dataTables settings object
1057 * @param {array} aData data array to be added
1058 * @param {node} [nTr] TR element to add to the table - optional. If not given,
1059 * DataTables will create a row automatically
1060 * @param {array} [anTds] Array of TD|TH elements for the row - must be given
1061 * if nTr is.
1062 * @returns {int} >=0 if successful (index of new aoData entry), -1 if failed
1063 * @memberof DataTable#oApi
1064 */
1065 function _fnAddData ( oSettings, aDataIn, nTr, anTds )
1066 {
1067 /* Create the object for storing information about this new row */
1068 var iRow = oSettings.aoData.length;
1069 var oData = $.extend( true, {}, DataTable.models.oRow, {
1070 src: nTr ? 'dom' : 'data',
1071 idx: iRow
1072 } );
1073
1074 oData._aData = aDataIn;
1075 oSettings.aoData.push( oData );
1076
1077 /* Create the cells */
1078 var nTd, sThisType;
1079 var columns = oSettings.aoColumns;
1080
1081 // Invalidate the column types as the new data needs to be revalidated
1082 for ( var i=0, iLen=columns.length ; i<iLen ; i++ )
1083 {
1084 columns[i].sType = null;
1085 }
1086
1087 /* Add to the display array */
1088 oSettings.aiDisplayMaster.push( iRow );
1089
1090 var id = oSettings.rowIdFn( aDataIn );
1091 if ( id !== undefined ) {
1092 oSettings.aIds[ id ] = oData;
1093 }
1094
1095 /* Create the DOM information, or register it if already present */
1096 if ( nTr || ! oSettings.oFeatures.bDeferRender )
1097 {
1098 _fnCreateTr( oSettings, iRow, nTr, anTds );
1099 }
1100
1101 return iRow;
1102 }
1103
1104
1105 /**
1106 * Add one or more TR elements to the table. Generally we'd expect to
1107 * use this for reading data from a DOM sourced table, but it could be
1108 * used for an TR element. Note that if a TR is given, it is used (i.e.
1109 * it is not cloned).
1110 * @param {object} settings dataTables settings object
1111 * @param {array|node|jQuery} trs The TR element(s) to add to the table
1112 * @returns {array} Array of indexes for the added rows
1113 * @memberof DataTable#oApi
1114 */
1115 function _fnAddTr( settings, trs )
1116 {
1117 var row;
1118
1119 // Allow an individual node to be passed in
1120 if ( ! (trs instanceof $) ) {
1121 trs = $(trs);
1122 }
1123
1124 return trs.map( function (i, el) {
1125 row = _fnGetRowElements( settings, el );
1126 return _fnAddData( settings, row.data, el, row.cells );
1127 } );
1128 }
1129
1130
1131 /**
1132 * Take a TR element and convert it to an index in aoData
1133 * @param {object} oSettings dataTables settings object
1134 * @param {node} n the TR element to find
1135 * @returns {int} index if the node is found, null if not
1136 * @memberof DataTable#oApi
1137 */
1138 function _fnNodeToDataIndex( oSettings, n )
1139 {
1140 return (n._DT_RowIndex!==undefined) ? n._DT_RowIndex : null;
1141 }
1142
1143
1144 /**
1145 * Take a TD element and convert it into a column data index (not the visible index)
1146 * @param {object} oSettings dataTables settings object
1147 * @param {int} iRow The row number the TD/TH can be found in
1148 * @param {node} n The TD/TH element to find
1149 * @returns {int} index if the node is found, -1 if not
1150 * @memberof DataTable#oApi
1151 */
1152 function _fnNodeToColumnIndex( oSettings, iRow, n )
1153 {
1154 return $.inArray( n, oSettings.aoData[ iRow ].anCells );
1155 }
1156
1157
1158 /**
1159 * Get the data for a given cell from the internal cache, taking into account data mapping
1160 * @param {object} settings dataTables settings object
1161 * @param {int} rowIdx aoData row id
1162 * @param {int} colIdx Column index
1163 * @param {string} type data get type ('display', 'type' 'filter' 'sort')
1164 * @returns {*} Cell data
1165 * @memberof DataTable#oApi
1166 */
1167 function _fnGetCellData( settings, rowIdx, colIdx, type )
1168 {
1169 var draw = settings.iDraw;
1170 var col = settings.aoColumns[colIdx];
1171 var rowData = settings.aoData[rowIdx]._aData;
1172 var defaultContent = col.sDefaultContent;
1173 var cellData = col.fnGetData( rowData, type, {
1174 settings: settings,
1175 row: rowIdx,
1176 col: colIdx
1177 } );
1178
1179 if ( cellData === undefined ) {
1180 if ( settings.iDrawError != draw && defaultContent === null ) {
1181 _fnLog( settings, 0, "Requested unknown parameter "+
1182 (typeof col.mData=='function' ? '{function}' : "'"+col.mData+"'")+
1183 " for row "+rowIdx+", column "+colIdx, 4 );
1184 settings.iDrawError = draw;
1185 }
1186 return defaultContent;
1187 }
1188
1189 /* When the data source is null, we can use default column data */
1190 if ( (cellData === rowData || cellData === null) && defaultContent !== null ) {
1191 cellData = defaultContent;
1192 }
1193 else if ( typeof cellData === 'function' ) {
1194 // If the data source is a function, then we run it and use the return,
1195 // executing in the scope of the data object (for instances)
1196 return cellData.call( rowData );
1197 }
1198
1199 if ( cellData === null && type == 'display' ) {
1200 return '';
1201 }
1202 return cellData;
1203 }
1204
1205
1206 /**
1207 * Set the value for a specific cell, into the internal data cache
1208 * @param {object} settings dataTables settings object
1209 * @param {int} rowIdx aoData row id
1210 * @param {int} colIdx Column index
1211 * @param {*} val Value to set
1212 * @memberof DataTable#oApi
1213 */
1214 function _fnSetCellData( settings, rowIdx, colIdx, val )
1215 {
1216 var col = settings.aoColumns[colIdx];
1217 var rowData = settings.aoData[rowIdx]._aData;
1218
1219 col.fnSetData( rowData, val, {
1220 settings: settings,
1221 row: rowIdx,
1222 col: colIdx
1223 } );
1224 }
1225
1226
1227 // Private variable that is used to match action syntax in the data property object
1228 var __reArray = /\[.*?\]$/;
1229 var __reFn = /\(\)$/;
1230
1231 /**
1232 * Split string on periods, taking into account escaped periods
1233 * @param {string} str String to split
1234 * @return {array} Split string
1235 */
1236 function _fnSplitObjNotation( str )
1237 {
1238 return $.map( str.match(/(\\.|[^\.])+/g) || [''], function ( s ) {
1239 return s.replace(/\\./g, '.');
1240 } );
1241 }
1242
1243
1244 /**
1245 * Return a function that can be used to get data from a source object, taking
1246 * into account the ability to use nested objects as a source
1247 * @param {string|int|function} mSource The data source for the object
1248 * @returns {function} Data get function
1249 * @memberof DataTable#oApi
1250 */
1251 function _fnGetObjectDataFn( mSource )
1252 {
1253 if ( $.isPlainObject( mSource ) )
1254 {
1255 /* Build an object of get functions, and wrap them in a single call */
1256 var o = {};
1257 $.each( mSource, function (key, val) {
1258 if ( val ) {
1259 o[key] = _fnGetObjectDataFn( val );
1260 }
1261 } );
1262
1263 return function (data, type, row, meta) {
1264 var t = o[type] || o._;
1265 return t !== undefined ?
1266 t(data, type, row, meta) :
1267 data;
1268 };
1269 }
1270 else if ( mSource === null )
1271 {
1272 /* Give an empty string for rendering / sorting etc */
1273 return function (data) { // type, row and meta also passed, but not used
1274 return data;
1275 };
1276 }
1277 else if ( typeof mSource === 'function' )
1278 {
1279 return function (data, type, row, meta) {
1280 return mSource( data, type, row, meta );
1281 };
1282 }
1283 else if ( typeof mSource === 'string' && (mSource.indexOf('.') !== -1 ||
1284 mSource.indexOf('[') !== -1 || mSource.indexOf('(') !== -1) )
1285 {
1286 /* If there is a . in the source string then the data source is in a
1287 * nested object so we loop over the data for each level to get the next
1288 * level down. On each loop we test for undefined, and if found immediately
1289 * return. This allows entire objects to be missing and sDefaultContent to
1290 * be used if defined, rather than throwing an error
1291 */
1292 var fetchData = function (data, type, src) {
1293 var arrayNotation, funcNotation, out, innerSrc;
1294
1295 if ( src !== "" )
1296 {
1297 var a = _fnSplitObjNotation( src );
1298
1299 for ( var i=0, iLen=a.length ; i<iLen ; i++ )
1300 {
1301 // Check if we are dealing with special notation
1302 arrayNotation = a[i].match(__reArray);
1303 funcNotation = a[i].match(__reFn);
1304
1305 if ( arrayNotation )
1306 {
1307 // Array notation
1308 a[i] = a[i].replace(__reArray, '');
1309
1310 // Condition allows simply [] to be passed in
1311 if ( a[i] !== "" ) {
1312 data = data[ a[i] ];
1313 }
1314 out = [];
1315
1316 // Get the remainder of the nested object to get
1317 a.splice( 0, i+1 );
1318 innerSrc = a.join('.');
1319
1320 // Traverse each entry in the array getting the properties requested
1321 if ( $.isArray( data ) ) {
1322 for ( var j=0, jLen=data.length ; j<jLen ; j++ ) {
1323 out.push( fetchData( data[j], type, innerSrc ) );
1324 }
1325 }
1326
1327 // If a string is given in between the array notation indicators, that
1328 // is used to join the strings together, otherwise an array is returned
1329 var join = arrayNotation[0].substring(1, arrayNotation[0].length-1);
1330 data = (join==="") ? out : out.join(join);
1331
1332 // The inner call to fetchData has already traversed through the remainder
1333 // of the source requested, so we exit from the loop
1334 break;
1335 }
1336 else if ( funcNotation )
1337 {
1338 // Function call
1339 a[i] = a[i].replace(__reFn, '');
1340 data = data[ a[i] ]();
1341 continue;
1342 }
1343
1344 if ( data === null || data[ a[i] ] === undefined )
1345 {
1346 return undefined;
1347 }
1348 data = data[ a[i] ];
1349 }
1350 }
1351
1352 return data;
1353 };
1354
1355 return function (data, type) { // row and meta also passed, but not used
1356 return fetchData( data, type, mSource );
1357 };
1358 }
1359 else
1360 {
1361 /* Array or flat object mapping */
1362 return function (data, type) { // row and meta also passed, but not used
1363 return data[mSource];
1364 };
1365 }
1366 }
1367
1368
1369 /**
1370 * Return a function that can be used to set data from a source object, taking
1371 * into account the ability to use nested objects as a source
1372 * @param {string|int|function} mSource The data source for the object
1373 * @returns {function} Data set function
1374 * @memberof DataTable#oApi
1375 */
1376 function _fnSetObjectDataFn( mSource )
1377 {
1378 if ( $.isPlainObject( mSource ) )
1379 {
1380 /* Unlike get, only the underscore (global) option is used for for
1381 * setting data since we don't know the type here. This is why an object
1382 * option is not documented for `mData` (which is read/write), but it is
1383 * for `mRender` which is read only.
1384 */
1385 return _fnSetObjectDataFn( mSource._ );
1386 }
1387 else if ( mSource === null )
1388 {
1389 /* Nothing to do when the data source is null */
1390 return function () {};
1391 }
1392 else if ( typeof mSource === 'function' )
1393 {
1394 return function (data, val, meta) {
1395 mSource( data, 'set', val, meta );
1396 };
1397 }
1398 else if ( typeof mSource === 'string' && (mSource.indexOf('.') !== -1 ||
1399 mSource.indexOf('[') !== -1 || mSource.indexOf('(') !== -1) )
1400 {
1401 /* Like the get, we need to get data from a nested object */
1402 var setData = function (data, val, src) {
1403 var a = _fnSplitObjNotation( src ), b;
1404 var aLast = a[a.length-1];
1405 var arrayNotation, funcNotation, o, innerSrc;
1406
1407 for ( var i=0, iLen=a.length-1 ; i<iLen ; i++ )
1408 {
1409 // Check if we are dealing with an array notation request
1410 arrayNotation = a[i].match(__reArray);
1411 funcNotation = a[i].match(__reFn);
1412
1413 if ( arrayNotation )
1414 {
1415 a[i] = a[i].replace(__reArray, '');
1416 data[ a[i] ] = [];
1417
1418 // Get the remainder of the nested object to set so we can recurse
1419 b = a.slice();
1420 b.splice( 0, i+1 );
1421 innerSrc = b.join('.');
1422
1423 // Traverse each entry in the array setting the properties requested
1424 if ( $.isArray( val ) )
1425 {
1426 for ( var j=0, jLen=val.length ; j<jLen ; j++ )
1427 {
1428 o = {};
1429 setData( o, val[j], innerSrc );
1430 data[ a[i] ].push( o );
1431 }
1432 }
1433 else
1434 {
1435 // We've been asked to save data to an array, but it
1436 // isn't array data to be saved. Best that can be done
1437 // is to just save the value.
1438 data[ a[i] ] = val;
1439 }
1440
1441 // The inner call to setData has already traversed through the remainder
1442 // of the source and has set the data, thus we can exit here
1443 return;
1444 }
1445 else if ( funcNotation )
1446 {
1447 // Function call
1448 a[i] = a[i].replace(__reFn, '');
1449 data = data[ a[i] ]( val );
1450 }
1451
1452 // If the nested object doesn't currently exist - since we are
1453 // trying to set the value - create it
1454 if ( data[ a[i] ] === null || data[ a[i] ] === undefined )
1455 {
1456 data[ a[i] ] = {};
1457 }
1458 data = data[ a[i] ];
1459 }
1460
1461 // Last item in the input - i.e, the actual set
1462 if ( aLast.match(__reFn ) )
1463 {
1464 // Function call
1465 data = data[ aLast.replace(__reFn, '') ]( val );
1466 }
1467 else
1468 {
1469 // If array notation is used, we just want to strip it and use the property name
1470 // and assign the value. If it isn't used, then we get the result we want anyway
1471 data[ aLast.replace(__reArray, '') ] = val;
1472 }
1473 };
1474
1475 return function (data, val) { // meta is also passed in, but not used
1476 return setData( data, val, mSource );
1477 };
1478 }
1479 else
1480 {
1481 /* Array or flat object mapping */
1482 return function (data, val) { // meta is also passed in, but not used
1483 data[mSource] = val;
1484 };
1485 }
1486 }
1487
1488
1489 /**
1490 * Return an array with the full table data
1491 * @param {object} oSettings dataTables settings object
1492 * @returns array {array} aData Master data array
1493 * @memberof DataTable#oApi
1494 */
1495 function _fnGetDataMaster ( settings )
1496 {
1497 return _pluck( settings.aoData, '_aData' );
1498 }
1499
1500
1501 /**
1502 * Nuke the table
1503 * @param {object} oSettings dataTables settings object
1504 * @memberof DataTable#oApi
1505 */
1506 function _fnClearTable( settings )
1507 {
1508 settings.aoData.length = 0;
1509 settings.aiDisplayMaster.length = 0;
1510 settings.aiDisplay.length = 0;
1511 settings.aIds = {};
1512 }
1513
1514
1515 /**
1516 * Take an array of integers (index array) and remove a target integer (value - not
1517 * the key!)
1518 * @param {array} a Index array to target
1519 * @param {int} iTarget value to find
1520 * @memberof DataTable#oApi
1521 */
1522 function _fnDeleteIndex( a, iTarget, splice )
1523 {
1524 var iTargetIndex = -1;
1525
1526 for ( var i=0, iLen=a.length ; i<iLen ; i++ )
1527 {
1528 if ( a[i] == iTarget )
1529 {
1530 iTargetIndex = i;
1531 }
1532 else if ( a[i] > iTarget )
1533 {
1534 a[i]--;
1535 }
1536 }
1537
1538 if ( iTargetIndex != -1 && splice === undefined )
1539 {
1540 a.splice( iTargetIndex, 1 );
1541 }
1542 }
1543
1544
1545 /**
1546 * Mark cached data as invalid such that a re-read of the data will occur when
1547 * the cached data is next requested. Also update from the data source object.
1548 *
1549 * @param {object} settings DataTables settings object
1550 * @param {int} rowIdx Row index to invalidate
1551 * @param {string} [src] Source to invalidate from: undefined, 'auto', 'dom'
1552 * or 'data'
1553 * @param {int} [colIdx] Column index to invalidate. If undefined the whole
1554 * row will be invalidated
1555 * @memberof DataTable#oApi
1556 *
1557 * @todo For the modularisation of v1.11 this will need to become a callback, so
1558 * the sort and filter methods can subscribe to it. That will required
1559 * initialisation options for sorting, which is why it is not already baked in
1560 */
1561 function _fnInvalidate( settings, rowIdx, src, colIdx )
1562 {
1563 var row = settings.aoData[ rowIdx ];
1564 var i, ien;
1565 var cellWrite = function ( cell, col ) {
1566 // This is very frustrating, but in IE if you just write directly
1567 // to innerHTML, and elements that are overwritten are GC'ed,
1568 // even if there is a reference to them elsewhere
1569 while ( cell.childNodes.length ) {
1570 cell.removeChild( cell.firstChild );
1571 }
1572
1573 cell.innerHTML = _fnGetCellData( settings, rowIdx, col, 'display' );
1574 };
1575
1576 // Are we reading last data from DOM or the data object?
1577 if ( src === 'dom' || ((! src || src === 'auto') && row.src === 'dom') ) {
1578 // Read the data from the DOM
1579 row._aData = _fnGetRowElements(
1580 settings, row, colIdx, colIdx === undefined ? undefined : row._aData
1581 )
1582 .data;
1583 }
1584 else {
1585 // Reading from data object, update the DOM
1586 var cells = row.anCells;
1587
1588 if ( cells ) {
1589 if ( colIdx !== undefined ) {
1590 cellWrite( cells[colIdx], colIdx );
1591 }
1592 else {
1593 for ( i=0, ien=cells.length ; i<ien ; i++ ) {
1594 cellWrite( cells[i], i );
1595 }
1596 }
1597 }
1598 }
1599
1600 // For both row and cell invalidation, the cached data for sorting and
1601 // filtering is nulled out
1602 row._aSortData = null;
1603 row._aFilterData = null;
1604
1605 // Invalidate the type for a specific column (if given) or all columns since
1606 // the data might have changed
1607 var cols = settings.aoColumns;
1608 if ( colIdx !== undefined ) {
1609 cols[ colIdx ].sType = null;
1610 }
1611 else {
1612 for ( i=0, ien=cols.length ; i<ien ; i++ ) {
1613 cols[i].sType = null;
1614 }
1615
1616 // Update DataTables special `DT_*` attributes for the row
1617 _fnRowAttributes( settings, row );
1618 }
1619 }
1620
1621
1622 /**
1623 * Build a data source object from an HTML row, reading the contents of the
1624 * cells that are in the row.
1625 *
1626 * @param {object} settings DataTables settings object
1627 * @param {node|object} TR element from which to read data or existing row
1628 * object from which to re-read the data from the cells
1629 * @param {int} [colIdx] Optional column index
1630 * @param {array|object} [d] Data source object. If `colIdx` is given then this
1631 * parameter should also be given and will be used to write the data into.
1632 * Only the column in question will be written
1633 * @returns {object} Object with two parameters: `data` the data read, in
1634 * document order, and `cells` and array of nodes (they can be useful to the
1635 * caller, so rather than needing a second traversal to get them, just return
1636 * them from here).
1637 * @memberof DataTable#oApi
1638 */
1639 function _fnGetRowElements( settings, row, colIdx, d )
1640 {
1641 var
1642 tds = [],
1643 td = row.firstChild,
1644 name, col, o, i=0, contents,
1645 columns = settings.aoColumns,
1646 objectRead = settings._rowReadObject;
1647
1648 // Allow the data object to be passed in, or construct
1649 d = d !== undefined ?
1650 d :
1651 objectRead ?
1652 {} :
1653 [];
1654
1655 var attr = function ( str, td ) {
1656 if ( typeof str === 'string' ) {
1657 var idx = str.indexOf('@');
1658
1659 if ( idx !== -1 ) {
1660 var attr = str.substring( idx+1 );
1661 var setter = _fnSetObjectDataFn( str );
1662 setter( d, td.getAttribute( attr ) );
1663 }
1664 }
1665 };
1666
1667 // Read data from a cell and store into the data object
1668 var cellProcess = function ( cell ) {
1669 if ( colIdx === undefined || colIdx === i ) {
1670 col = columns[i];
1671 contents = $.trim(cell.innerHTML);
1672
1673 if ( col && col._bAttrSrc ) {
1674 var setter = _fnSetObjectDataFn( col.mData._ );
1675 setter( d, contents );
1676
1677 attr( col.mData.sort, cell );
1678 attr( col.mData.type, cell );
1679 attr( col.mData.filter, cell );
1680 }
1681 else {
1682 // Depending on the `data` option for the columns the data can
1683 // be read to either an object or an array.
1684 if ( objectRead ) {
1685 if ( ! col._setter ) {
1686 // Cache the setter function
1687 col._setter = _fnSetObjectDataFn( col.mData );
1688 }
1689 col._setter( d, contents );
1690 }
1691 else {
1692 d[i] = contents;
1693 }
1694 }
1695 }
1696
1697 i++;
1698 };
1699
1700 if ( td ) {
1701 // `tr` element was passed in
1702 while ( td ) {
1703 name = td.nodeName.toUpperCase();
1704
1705 if ( name == "TD" || name == "TH" ) {
1706 cellProcess( td );
1707 tds.push( td );
1708 }
1709
1710 td = td.nextSibling;
1711 }
1712 }
1713 else {
1714 // Existing row object passed in
1715 tds = row.anCells;
1716
1717 for ( var j=0, jen=tds.length ; j<jen ; j++ ) {
1718 cellProcess( tds[j] );
1719 }
1720 }
1721
1722 // Read the ID from the DOM if present
1723 var rowNode = row.firstChild ? row : row.nTr;
1724
1725 if ( rowNode ) {
1726 var id = rowNode.getAttribute( 'id' );
1727
1728 if ( id ) {
1729 _fnSetObjectDataFn( settings.rowId )( d, id );
1730 }
1731 }
1732
1733 return {
1734 data: d,
1735 cells: tds
1736 };
1737 }
1738 /**
1739 * Create a new TR element (and it's TD children) for a row
1740 * @param {object} oSettings dataTables settings object
1741 * @param {int} iRow Row to consider
1742 * @param {node} [nTrIn] TR element to add to the table - optional. If not given,
1743 * DataTables will create a row automatically
1744 * @param {array} [anTds] Array of TD|TH elements for the row - must be given
1745 * if nTr is.
1746 * @memberof DataTable#oApi
1747 */
1748 function _fnCreateTr ( oSettings, iRow, nTrIn, anTds )
1749 {
1750 var
1751 row = oSettings.aoData[iRow],
1752 rowData = row._aData,
1753 cells = [],
1754 nTr, nTd, oCol,
1755 i, iLen;
1756
1757 if ( row.nTr === null )
1758 {
1759 nTr = nTrIn || document.createElement('tr');
1760
1761 row.nTr = nTr;
1762 row.anCells = cells;
1763
1764 /* Use a private property on the node to allow reserve mapping from the node
1765 * to the aoData array for fast look up
1766 */
1767 nTr._DT_RowIndex = iRow;
1768
1769 /* Special parameters can be given by the data source to be used on the row */
1770 _fnRowAttributes( oSettings, row );
1771
1772 /* Process each column */
1773 for ( i=0, iLen=oSettings.aoColumns.length ; i<iLen ; i++ )
1774 {
1775 oCol = oSettings.aoColumns[i];
1776
1777 nTd = nTrIn ? anTds[i] : document.createElement( oCol.sCellType );
1778 nTd._DT_CellIndex = {
1779 row: iRow,
1780 column: i
1781 };
1782
1783 cells.push( nTd );
1784
1785 // Need to create the HTML if new, or if a rendering function is defined
1786 if ( !nTrIn || oCol.mRender || oCol.mData !== i )
1787 {
1788 nTd.innerHTML = _fnGetCellData( oSettings, iRow, i, 'display' );
1789 }
1790
1791 /* Add user defined class */
1792 if ( oCol.sClass )
1793 {
1794 nTd.className += ' '+oCol.sClass;
1795 }
1796
1797 // Visibility - add or remove as required
1798 if ( oCol.bVisible && ! nTrIn )
1799 {
1800 nTr.appendChild( nTd );
1801 }
1802 else if ( ! oCol.bVisible && nTrIn )
1803 {
1804 nTd.parentNode.removeChild( nTd );
1805 }
1806
1807 if ( oCol.fnCreatedCell )
1808 {
1809 oCol.fnCreatedCell.call( oSettings.oInstance,
1810 nTd, _fnGetCellData( oSettings, iRow, i ), rowData, iRow, i
1811 );
1812 }
1813 }
1814
1815 _fnCallbackFire( oSettings, 'aoRowCreatedCallback', null, [nTr, rowData, iRow] );
1816 }
1817
1818 // Remove once webkit bug 131819 and Chromium bug 365619 have been resolved
1819 // and deployed
1820 row.nTr.setAttribute( 'role', 'row' );
1821 }
1822
1823
1824 /**
1825 * Add attributes to a row based on the special `DT_*` parameters in a data
1826 * source object.
1827 * @param {object} settings DataTables settings object
1828 * @param {object} DataTables row object for the row to be modified
1829 * @memberof DataTable#oApi
1830 */
1831 function _fnRowAttributes( settings, row )
1832 {
1833 var tr = row.nTr;
1834 var data = row._aData;
1835
1836 if ( tr ) {
1837 var id = settings.rowIdFn( data );
1838
1839 if ( id ) {
1840 tr.id = id;
1841 }
1842
1843 if ( data.DT_RowClass ) {
1844 // Remove any classes added by DT_RowClass before
1845 var a = data.DT_RowClass.split(' ');
1846 row.__rowc = row.__rowc ?
1847 _unique( row.__rowc.concat( a ) ) :
1848 a;
1849
1850 $(tr)
1851 .removeClass( row.__rowc.join(' ') )
1852 .addClass( data.DT_RowClass );
1853 }
1854
1855 if ( data.DT_RowAttr ) {
1856 $(tr).attr( data.DT_RowAttr );
1857 }
1858
1859 if ( data.DT_RowData ) {
1860 $(tr).data( data.DT_RowData );
1861 }
1862 }
1863 }
1864
1865
1866 /**
1867 * Create the HTML header for the table
1868 * @param {object} oSettings dataTables settings object
1869 * @memberof DataTable#oApi
1870 */
1871 function _fnBuildHead( oSettings )
1872 {
1873 var i, ien, cell, row, column;
1874 var thead = oSettings.nTHead;
1875 var tfoot = oSettings.nTFoot;
1876 var createHeader = $('th, td', thead).length === 0;
1877 var classes = oSettings.oClasses;
1878 var columns = oSettings.aoColumns;
1879
1880 if ( createHeader ) {
1881 row = $('<tr/>').appendTo( thead );
1882 }
1883
1884 for ( i=0, ien=columns.length ; i<ien ; i++ ) {
1885 column = columns[i];
1886 cell = $( column.nTh ).addClass( column.sClass );
1887
1888 if ( createHeader ) {
1889 cell.appendTo( row );
1890 }
1891
1892 // 1.11 move into sorting
1893 if ( oSettings.oFeatures.bSort ) {
1894 cell.addClass( column.sSortingClass );
1895
1896 if ( column.bSortable !== false ) {
1897 cell
1898 .attr( 'tabindex', oSettings.iTabIndex )
1899 .attr( 'aria-controls', oSettings.sTableId );
1900
1901 _fnSortAttachListener( oSettings, column.nTh, i );
1902 }
1903 }
1904
1905 if ( column.sTitle != cell[0].innerHTML ) {
1906 cell.html( column.sTitle );
1907 }
1908
1909 _fnRenderer( oSettings, 'header' )(
1910 oSettings, cell, column, classes
1911 );
1912 }
1913
1914 if ( createHeader ) {
1915 _fnDetectHeader( oSettings.aoHeader, thead );
1916 }
1917
1918 /* ARIA role for the rows */
1919 $(thead).find('>tr').attr('role', 'row');
1920
1921 /* Deal with the footer - add classes if required */
1922 $(thead).find('>tr>th, >tr>td').addClass( classes.sHeaderTH );
1923 $(tfoot).find('>tr>th, >tr>td').addClass( classes.sFooterTH );
1924
1925 // Cache the footer cells. Note that we only take the cells from the first
1926 // row in the footer. If there is more than one row the user wants to
1927 // interact with, they need to use the table().foot() method. Note also this
1928 // allows cells to be used for multiple columns using colspan
1929 if ( tfoot !== null ) {
1930 var cells = oSettings.aoFooter[0];
1931
1932 for ( i=0, ien=cells.length ; i<ien ; i++ ) {
1933 column = columns[i];
1934 column.nTf = cells[i].cell;
1935
1936 if ( column.sClass ) {
1937 $(column.nTf).addClass( column.sClass );
1938 }
1939 }
1940 }
1941 }
1942
1943
1944 /**
1945 * Draw the header (or footer) element based on the column visibility states. The
1946 * methodology here is to use the layout array from _fnDetectHeader, modified for
1947 * the instantaneous column visibility, to construct the new layout. The grid is
1948 * traversed over cell at a time in a rows x columns grid fashion, although each
1949 * cell insert can cover multiple elements in the grid - which is tracks using the
1950 * aApplied array. Cell inserts in the grid will only occur where there isn't
1951 * already a cell in that position.
1952 * @param {object} oSettings dataTables settings object
1953 * @param array {objects} aoSource Layout array from _fnDetectHeader
1954 * @param {boolean} [bIncludeHidden=false] If true then include the hidden columns in the calc,
1955 * @memberof DataTable#oApi
1956 */
1957 function _fnDrawHead( oSettings, aoSource, bIncludeHidden )
1958 {
1959 var i, iLen, j, jLen, k, kLen, n, nLocalTr;
1960 var aoLocal = [];
1961 var aApplied = [];
1962 var iColumns = oSettings.aoColumns.length;
1963 var iRowspan, iColspan;
1964
1965 if ( ! aoSource )
1966 {
1967 return;
1968 }
1969
1970 if ( bIncludeHidden === undefined )
1971 {
1972 bIncludeHidden = false;
1973 }
1974
1975 /* Make a copy of the master layout array, but without the visible columns in it */
1976 for ( i=0, iLen=aoSource.length ; i<iLen ; i++ )
1977 {
1978 aoLocal[i] = aoSource[i].slice();
1979 aoLocal[i].nTr = aoSource[i].nTr;
1980
1981 /* Remove any columns which are currently hidden */
1982 for ( j=iColumns-1 ; j>=0 ; j-- )
1983 {
1984 if ( !oSettings.aoColumns[j].bVisible && !bIncludeHidden )
1985 {
1986 aoLocal[i].splice( j, 1 );
1987 }
1988 }
1989
1990 /* Prep the applied array - it needs an element for each row */
1991 aApplied.push( [] );
1992 }
1993
1994 for ( i=0, iLen=aoLocal.length ; i<iLen ; i++ )
1995 {
1996 nLocalTr = aoLocal[i].nTr;
1997
1998 /* All cells are going to be replaced, so empty out the row */
1999 if ( nLocalTr )
2000 {
2001 while( (n = nLocalTr.firstChild) )
2002 {
2003 nLocalTr.removeChild( n );
2004 }
2005 }
2006
2007 for ( j=0, jLen=aoLocal[i].length ; j<jLen ; j++ )
2008 {
2009 iRowspan = 1;
2010 iColspan = 1;
2011
2012 /* Check to see if there is already a cell (row/colspan) covering our target
2013 * insert point. If there is, then there is nothing to do.
2014 */
2015 if ( aApplied[i][j] === undefined )
2016 {
2017 nLocalTr.appendChild( aoLocal[i][j].cell );
2018 aApplied[i][j] = 1;
2019
2020 /* Expand the cell to cover as many rows as needed */
2021 while ( aoLocal[i+iRowspan] !== undefined &&
2022 aoLocal[i][j].cell == aoLocal[i+iRowspan][j].cell )
2023 {
2024 aApplied[i+iRowspan][j] = 1;
2025 iRowspan++;
2026 }
2027
2028 /* Expand the cell to cover as many columns as needed */
2029 while ( aoLocal[i][j+iColspan] !== undefined &&
2030 aoLocal[i][j].cell == aoLocal[i][j+iColspan].cell )
2031 {
2032 /* Must update the applied array over the rows for the columns */
2033 for ( k=0 ; k<iRowspan ; k++ )
2034 {
2035 aApplied[i+k][j+iColspan] = 1;
2036 }
2037 iColspan++;
2038 }
2039
2040 /* Do the actual expansion in the DOM */
2041 $(aoLocal[i][j].cell)
2042 .attr('rowspan', iRowspan)
2043 .attr('colspan', iColspan);
2044 }
2045 }
2046 }
2047 }
2048
2049
2050 /**
2051 * Insert the required TR nodes into the table for display
2052 * @param {object} oSettings dataTables settings object
2053 * @memberof DataTable#oApi
2054 */
2055 function _fnDraw( oSettings )
2056 {
2057 /* Provide a pre-callback function which can be used to cancel the draw is false is returned */
2058 var aPreDraw = _fnCallbackFire( oSettings, 'aoPreDrawCallback', 'preDraw', [oSettings] );
2059 if ( $.inArray( false, aPreDraw ) !== -1 )
2060 {
2061 _fnProcessingDisplay( oSettings, false );
2062 return;
2063 }
2064
2065 var i, iLen, n;
2066 var anRows = [];
2067 var iRowCount = 0;
2068 var asStripeClasses = oSettings.asStripeClasses;
2069 var iStripes = asStripeClasses.length;
2070 var iOpenRows = oSettings.aoOpenRows.length;
2071 var oLang = oSettings.oLanguage;
2072 var iInitDisplayStart = oSettings.iInitDisplayStart;
2073 var bServerSide = _fnDataSource( oSettings ) == 'ssp';
2074 var aiDisplay = oSettings.aiDisplay;
2075
2076 oSettings.bDrawing = true;
2077
2078 /* Check and see if we have an initial draw position from state saving */
2079 if ( iInitDisplayStart !== undefined && iInitDisplayStart !== -1 )
2080 {
2081 oSettings._iDisplayStart = bServerSide ?
2082 iInitDisplayStart :
2083 iInitDisplayStart >= oSettings.fnRecordsDisplay() ?
2084 0 :
2085 iInitDisplayStart;
2086
2087 oSettings.iInitDisplayStart = -1;
2088 }
2089
2090 var iDisplayStart = oSettings._iDisplayStart;
2091 var iDisplayEnd = oSettings.fnDisplayEnd();
2092
2093 /* Server-side processing draw intercept */
2094 if ( oSettings.bDeferLoading )
2095 {
2096 oSettings.bDeferLoading = false;
2097 oSettings.iDraw++;
2098 _fnProcessingDisplay( oSettings, false );
2099 }
2100 else if ( !bServerSide )
2101 {
2102 oSettings.iDraw++;
2103 }
2104 else if ( !oSettings.bDestroying && !_fnAjaxUpdate( oSettings ) )
2105 {
2106 return;
2107 }
2108
2109 if ( aiDisplay.length !== 0 )
2110 {
2111 var iStart = bServerSide ? 0 : iDisplayStart;
2112 var iEnd = bServerSide ? oSettings.aoData.length : iDisplayEnd;
2113
2114 for ( var j=iStart ; j<iEnd ; j++ )
2115 {
2116 var iDataIndex = aiDisplay[j];
2117 var aoData = oSettings.aoData[ iDataIndex ];
2118 if ( aoData.nTr === null )
2119 {
2120 _fnCreateTr( oSettings, iDataIndex );
2121 }
2122
2123 var nRow = aoData.nTr;
2124
2125 /* Remove the old striping classes and then add the new one */
2126 if ( iStripes !== 0 )
2127 {
2128 var sStripe = asStripeClasses[ iRowCount % iStripes ];
2129 if ( aoData._sRowStripe != sStripe )
2130 {
2131 $(nRow).removeClass( aoData._sRowStripe ).addClass( sStripe );
2132 aoData._sRowStripe = sStripe;
2133 }
2134 }
2135
2136 // Row callback functions - might want to manipulate the row
2137 // iRowCount and j are not currently documented. Are they at all
2138 // useful?
2139 _fnCallbackFire( oSettings, 'aoRowCallback', null,
2140 [nRow, aoData._aData, iRowCount, j] );
2141
2142 anRows.push( nRow );
2143 iRowCount++;
2144 }
2145 }
2146 else
2147 {
2148 /* Table is empty - create a row with an empty message in it */
2149 var sZero = oLang.sZeroRecords;
2150 if ( oSettings.iDraw == 1 && _fnDataSource( oSettings ) == 'ajax' )
2151 {
2152 sZero = oLang.sLoadingRecords;
2153 }
2154 else if ( oLang.sEmptyTable && oSettings.fnRecordsTotal() === 0 )
2155 {
2156 sZero = oLang.sEmptyTable;
2157 }
2158
2159 anRows[ 0 ] = $( '<tr/>', { 'class': iStripes ? asStripeClasses[0] : '' } )
2160 .append( $('<td />', {
2161 'valign': 'top',
2162 'colSpan': _fnVisbleColumns( oSettings ),
2163 'class': oSettings.oClasses.sRowEmpty
2164 } ).html( sZero ) )[0];
2165 }
2166
2167 /* Header and footer callbacks */
2168 _fnCallbackFire( oSettings, 'aoHeaderCallback', 'header', [ $(oSettings.nTHead).children('tr')[0],
2169 _fnGetDataMaster( oSettings ), iDisplayStart, iDisplayEnd, aiDisplay ] );
2170
2171 _fnCallbackFire( oSettings, 'aoFooterCallback', 'footer', [ $(oSettings.nTFoot).children('tr')[0],
2172 _fnGetDataMaster( oSettings ), iDisplayStart, iDisplayEnd, aiDisplay ] );
2173
2174 var body = $(oSettings.nTBody);
2175
2176 body.children().detach();
2177 body.append( $(anRows) );
2178
2179 /* Call all required callback functions for the end of a draw */
2180 _fnCallbackFire( oSettings, 'aoDrawCallback', 'draw', [oSettings] );
2181
2182 /* Draw is complete, sorting and filtering must be as well */
2183 oSettings.bSorted = false;
2184 oSettings.bFiltered = false;
2185 oSettings.bDrawing = false;
2186 }
2187
2188
2189 /**
2190 * Redraw the table - taking account of the various features which are enabled
2191 * @param {object} oSettings dataTables settings object
2192 * @param {boolean} [holdPosition] Keep the current paging position. By default
2193 * the paging is reset to the first page
2194 * @memberof DataTable#oApi
2195 */
2196 function _fnReDraw( settings, holdPosition )
2197 {
2198 var
2199 features = settings.oFeatures,
2200 sort = features.bSort,
2201 filter = features.bFilter;
2202
2203 if ( sort ) {
2204 _fnSort( settings );
2205 }
2206
2207 if ( filter ) {
2208 _fnFilterComplete( settings, settings.oPreviousSearch );
2209 }
2210 else {
2211 // No filtering, so we want to just use the display master
2212 settings.aiDisplay = settings.aiDisplayMaster.slice();
2213 }
2214
2215 if ( holdPosition !== true ) {
2216 settings._iDisplayStart = 0;
2217 }
2218
2219 // Let any modules know about the draw hold position state (used by
2220 // scrolling internally)
2221 settings._drawHold = holdPosition;
2222
2223 _fnDraw( settings );
2224
2225 settings._drawHold = false;
2226 }
2227
2228
2229 /**
2230 * Add the options to the page HTML for the table
2231 * @param {object} oSettings dataTables settings object
2232 * @memberof DataTable#oApi
2233 */
2234 function _fnAddOptionsHtml ( oSettings )
2235 {
2236 var classes = oSettings.oClasses;
2237 var table = $(oSettings.nTable);
2238 var holding = $('<div/>').insertBefore( table ); // Holding element for speed
2239 var features = oSettings.oFeatures;
2240
2241 // All DataTables are wrapped in a div
2242 var insert = $('<div/>', {
2243 id: oSettings.sTableId+'_wrapper',
2244 'class': classes.sWrapper + (oSettings.nTFoot ? '' : ' '+classes.sNoFooter)
2245 } );
2246
2247 oSettings.nHolding = holding[0];
2248 oSettings.nTableWrapper = insert[0];
2249 oSettings.nTableReinsertBefore = oSettings.nTable.nextSibling;
2250
2251 /* Loop over the user set positioning and place the elements as needed */
2252 var aDom = oSettings.sDom.split('');
2253 var featureNode, cOption, nNewNode, cNext, sAttr, j;
2254 for ( var i=0 ; i<aDom.length ; i++ )
2255 {
2256 featureNode = null;
2257 cOption = aDom[i];
2258
2259 if ( cOption == '<' )
2260 {
2261 /* New container div */
2262 nNewNode = $('<div/>')[0];
2263
2264 /* Check to see if we should append an id and/or a class name to the container */
2265 cNext = aDom[i+1];
2266 if ( cNext == "'" || cNext == '"' )
2267 {
2268 sAttr = "";
2269 j = 2;
2270 while ( aDom[i+j] != cNext )
2271 {
2272 sAttr += aDom[i+j];
2273 j++;
2274 }
2275
2276 /* Replace jQuery UI constants @todo depreciated */
2277 if ( sAttr == "H" )
2278 {
2279 sAttr = classes.sJUIHeader;
2280 }
2281 else if ( sAttr == "F" )
2282 {
2283 sAttr = classes.sJUIFooter;
2284 }
2285
2286 /* The attribute can be in the format of "#id.class", "#id" or "class" This logic
2287 * breaks the string into parts and applies them as needed
2288 */
2289 if ( sAttr.indexOf('.') != -1 )
2290 {
2291 var aSplit = sAttr.split('.');
2292 nNewNode.id = aSplit[0].substr(1, aSplit[0].length-1);
2293 nNewNode.className = aSplit[1];
2294 }
2295 else if ( sAttr.charAt(0) == "#" )
2296 {
2297 nNewNode.id = sAttr.substr(1, sAttr.length-1);
2298 }
2299 else
2300 {
2301 nNewNode.className = sAttr;
2302 }
2303
2304 i += j; /* Move along the position array */
2305 }
2306
2307 insert.append( nNewNode );
2308 insert = $(nNewNode);
2309 }
2310 else if ( cOption == '>' )
2311 {
2312 /* End container div */
2313 insert = insert.parent();
2314 }
2315 // @todo Move options into their own plugins?
2316 else if ( cOption == 'l' && features.bPaginate && features.bLengthChange )
2317 {
2318 /* Length */
2319 featureNode = _fnFeatureHtmlLength( oSettings );
2320 }
2321 else if ( cOption == 'f' && features.bFilter )
2322 {
2323 /* Filter */
2324 featureNode = _fnFeatureHtmlFilter( oSettings );
2325 }
2326 else if ( cOption == 'r' && features.bProcessing )
2327 {
2328 /* pRocessing */
2329 featureNode = _fnFeatureHtmlProcessing( oSettings );
2330 }
2331 else if ( cOption == 't' )
2332 {
2333 /* Table */
2334 featureNode = _fnFeatureHtmlTable( oSettings );
2335 }
2336 else if ( cOption == 'i' && features.bInfo )
2337 {
2338 /* Info */
2339 featureNode = _fnFeatureHtmlInfo( oSettings );
2340 }
2341 else if ( cOption == 'p' && features.bPaginate )
2342 {
2343 /* Pagination */
2344 featureNode = _fnFeatureHtmlPaginate( oSettings );
2345 }
2346 else if ( DataTable.ext.feature.length !== 0 )
2347 {
2348 /* Plug-in features */
2349 var aoFeatures = DataTable.ext.feature;
2350 for ( var k=0, kLen=aoFeatures.length ; k<kLen ; k++ )
2351 {
2352 if ( cOption == aoFeatures[k].cFeature )
2353 {
2354 featureNode = aoFeatures[k].fnInit( oSettings );
2355 break;
2356 }
2357 }
2358 }
2359
2360 /* Add to the 2D features array */
2361 if ( featureNode )
2362 {
2363 var aanFeatures = oSettings.aanFeatures;
2364
2365 if ( ! aanFeatures[cOption] )
2366 {
2367 aanFeatures[cOption] = [];
2368 }
2369
2370 aanFeatures[cOption].push( featureNode );
2371 insert.append( featureNode );
2372 }
2373 }
2374
2375 /* Built our DOM structure - replace the holding div with what we want */
2376 holding.replaceWith( insert );
2377 oSettings.nHolding = null;
2378 }
2379
2380
2381 /**
2382 * Use the DOM source to create up an array of header cells. The idea here is to
2383 * create a layout grid (array) of rows x columns, which contains a reference
2384 * to the cell that that point in the grid (regardless of col/rowspan), such that
2385 * any column / row could be removed and the new grid constructed
2386 * @param array {object} aLayout Array to store the calculated layout in
2387 * @param {node} nThead The header/footer element for the table
2388 * @memberof DataTable#oApi
2389 */
2390 function _fnDetectHeader ( aLayout, nThead )
2391 {
2392 var nTrs = $(nThead).children('tr');
2393 var nTr, nCell;
2394 var i, k, l, iLen, jLen, iColShifted, iColumn, iColspan, iRowspan;
2395 var bUnique;
2396 var fnShiftCol = function ( a, i, j ) {
2397 var k = a[i];
2398 while ( k[j] ) {
2399 j++;
2400 }
2401 return j;
2402 };
2403
2404 aLayout.splice( 0, aLayout.length );
2405
2406 /* We know how many rows there are in the layout - so prep it */
2407 for ( i=0, iLen=nTrs.length ; i<iLen ; i++ )
2408 {
2409 aLayout.push( [] );
2410 }
2411
2412 /* Calculate a layout array */
2413 for ( i=0, iLen=nTrs.length ; i<iLen ; i++ )
2414 {
2415 nTr = nTrs[i];
2416 iColumn = 0;
2417
2418 /* For every cell in the row... */
2419 nCell = nTr.firstChild;
2420 while ( nCell ) {
2421 if ( nCell.nodeName.toUpperCase() == "TD" ||
2422 nCell.nodeName.toUpperCase() == "TH" )
2423 {
2424 /* Get the col and rowspan attributes from the DOM and sanitise them */
2425 iColspan = nCell.getAttribute('colspan') * 1;
2426 iRowspan = nCell.getAttribute('rowspan') * 1;
2427 iColspan = (!iColspan || iColspan===0 || iColspan===1) ? 1 : iColspan;
2428 iRowspan = (!iRowspan || iRowspan===0 || iRowspan===1) ? 1 : iRowspan;
2429
2430 /* There might be colspan cells already in this row, so shift our target
2431 * accordingly
2432 */
2433 iColShifted = fnShiftCol( aLayout, i, iColumn );
2434
2435 /* Cache calculation for unique columns */
2436 bUnique = iColspan === 1 ? true : false;
2437
2438 /* If there is col / rowspan, copy the information into the layout grid */
2439 for ( l=0 ; l<iColspan ; l++ )
2440 {
2441 for ( k=0 ; k<iRowspan ; k++ )
2442 {
2443 aLayout[i+k][iColShifted+l] = {
2444 "cell": nCell,
2445 "unique": bUnique
2446 };
2447 aLayout[i+k].nTr = nTr;
2448 }
2449 }
2450 }
2451 nCell = nCell.nextSibling;
2452 }
2453 }
2454 }
2455
2456
2457 /**
2458 * Get an array of unique th elements, one for each column
2459 * @param {object} oSettings dataTables settings object
2460 * @param {node} nHeader automatically detect the layout from this node - optional
2461 * @param {array} aLayout thead/tfoot layout from _fnDetectHeader - optional
2462 * @returns array {node} aReturn list of unique th's
2463 * @memberof DataTable#oApi
2464 */
2465 function _fnGetUniqueThs ( oSettings, nHeader, aLayout )
2466 {
2467 var aReturn = [];
2468 if ( !aLayout )
2469 {
2470 aLayout = oSettings.aoHeader;
2471 if ( nHeader )
2472 {
2473 aLayout = [];
2474 _fnDetectHeader( aLayout, nHeader );
2475 }
2476 }
2477
2478 for ( var i=0, iLen=aLayout.length ; i<iLen ; i++ )
2479 {
2480 for ( var j=0, jLen=aLayout[i].length ; j<jLen ; j++ )
2481 {
2482 if ( aLayout[i][j].unique &&
2483 (!aReturn[j] || !oSettings.bSortCellsTop) )
2484 {
2485 aReturn[j] = aLayout[i][j].cell;
2486 }
2487 }
2488 }
2489
2490 return aReturn;
2491 }
2492
2493 /**
2494 * Create an Ajax call based on the table's settings, taking into account that
2495 * parameters can have multiple forms, and backwards compatibility.
2496 *
2497 * @param {object} oSettings dataTables settings object
2498 * @param {array} data Data to send to the server, required by
2499 * DataTables - may be augmented by developer callbacks
2500 * @param {function} fn Callback function to run when data is obtained
2501 */
2502 function _fnBuildAjax( oSettings, data, fn )
2503 {
2504 // Compatibility with 1.9-, allow fnServerData and event to manipulate
2505 _fnCallbackFire( oSettings, 'aoServerParams', 'serverParams', [data] );
2506
2507 // Convert to object based for 1.10+ if using the old array scheme which can
2508 // come from server-side processing or serverParams
2509 if ( data && $.isArray(data) ) {
2510 var tmp = {};
2511 var rbracket = /(.*?)\[\]$/;
2512
2513 $.each( data, function (key, val) {
2514 var match = val.name.match(rbracket);
2515
2516 if ( match ) {
2517 // Support for arrays
2518 var name = match[0];
2519
2520 if ( ! tmp[ name ] ) {
2521 tmp[ name ] = [];
2522 }
2523 tmp[ name ].push( val.value );
2524 }
2525 else {
2526 tmp[val.name] = val.value;
2527 }
2528 } );
2529 data = tmp;
2530 }
2531
2532 var ajaxData;
2533 var ajax = oSettings.ajax;
2534 var instance = oSettings.oInstance;
2535 var callback = function ( json ) {
2536 _fnCallbackFire( oSettings, null, 'xhr', [oSettings, json, oSettings.jqXHR] );
2537 fn( json );
2538 };
2539
2540 if ( $.isPlainObject( ajax ) && ajax.data )
2541 {
2542 ajaxData = ajax.data;
2543
2544 var newData = $.isFunction( ajaxData ) ?
2545 ajaxData( data, oSettings ) : // fn can manipulate data or return
2546 ajaxData; // an object object or array to merge
2547
2548 // If the function returned something, use that alone
2549 data = $.isFunction( ajaxData ) && newData ?
2550 newData :
2551 $.extend( true, data, newData );
2552
2553 // Remove the data property as we've resolved it already and don't want
2554 // jQuery to do it again (it is restored at the end of the function)
2555 delete ajax.data;
2556 }
2557
2558 var baseAjax = {
2559 "data": data,
2560 "success": function (json) {
2561 var error = json.error || json.sError;
2562 if ( error ) {
2563 _fnLog( oSettings, 0, error );
2564 }
2565
2566 oSettings.json = json;
2567 callback( json );
2568 },
2569 "dataType": "json",
2570 "cache": false,
2571 "type": oSettings.sServerMethod,
2572 "error": function (xhr, error, thrown) {
2573 var ret = _fnCallbackFire( oSettings, null, 'xhr', [oSettings, null, oSettings.jqXHR] );
2574
2575 if ( $.inArray( true, ret ) === -1 ) {
2576 if ( error == "parsererror" ) {
2577 _fnLog( oSettings, 0, 'Invalid JSON response', 1 );
2578 }
2579 else if ( xhr.readyState === 4 ) {
2580 _fnLog( oSettings, 0, 'Ajax error', 7 );
2581 }
2582 }
2583
2584 _fnProcessingDisplay( oSettings, false );
2585 }
2586 };
2587
2588 // Store the data submitted for the API
2589 oSettings.oAjaxData = data;
2590
2591 // Allow plug-ins and external processes to modify the data
2592 _fnCallbackFire( oSettings, null, 'preXhr', [oSettings, data] );
2593
2594 if ( oSettings.fnServerData )
2595 {
2596 // DataTables 1.9- compatibility
2597 oSettings.fnServerData.call( instance,
2598 oSettings.sAjaxSource,
2599 $.map( data, function (val, key) { // Need to convert back to 1.9 trad format
2600 return { name: key, value: val };
2601 } ),
2602 callback,
2603 oSettings
2604 );
2605 }
2606 else if ( oSettings.sAjaxSource || typeof ajax === 'string' )
2607 {
2608 // DataTables 1.9- compatibility
2609 oSettings.jqXHR = $.ajax( $.extend( baseAjax, {
2610 url: ajax || oSettings.sAjaxSource
2611 } ) );
2612 }
2613 else if ( $.isFunction( ajax ) )
2614 {
2615 // Is a function - let the caller define what needs to be done
2616 oSettings.jqXHR = ajax.call( instance, data, callback, oSettings );
2617 }
2618 else
2619 {
2620 // Object to extend the base settings
2621 oSettings.jqXHR = $.ajax( $.extend( baseAjax, ajax ) );
2622
2623 // Restore for next time around
2624 ajax.data = ajaxData;
2625 }
2626 }
2627
2628
2629 /**
2630 * Update the table using an Ajax call
2631 * @param {object} settings dataTables settings object
2632 * @returns {boolean} Block the table drawing or not
2633 * @memberof DataTable#oApi
2634 */
2635 function _fnAjaxUpdate( settings )
2636 {
2637 if ( settings.bAjaxDataGet ) {
2638 settings.iDraw++;
2639 _fnProcessingDisplay( settings, true );
2640
2641 _fnBuildAjax(
2642 settings,
2643 _fnAjaxParameters( settings ),
2644 function(json) {
2645 _fnAjaxUpdateDraw( settings, json );
2646 }
2647 );
2648
2649 return false;
2650 }
2651 return true;
2652 }
2653
2654
2655 /**
2656 * Build up the parameters in an object needed for a server-side processing
2657 * request. Note that this is basically done twice, is different ways - a modern
2658 * method which is used by default in DataTables 1.10 which uses objects and
2659 * arrays, or the 1.9- method with is name / value pairs. 1.9 method is used if
2660 * the sAjaxSource option is used in the initialisation, or the legacyAjax
2661 * option is set.
2662 * @param {object} oSettings dataTables settings object
2663 * @returns {bool} block the table drawing or not
2664 * @memberof DataTable#oApi
2665 */
2666 function _fnAjaxParameters( settings )
2667 {
2668 var
2669 columns = settings.aoColumns,
2670 columnCount = columns.length,
2671 features = settings.oFeatures,
2672 preSearch = settings.oPreviousSearch,
2673 preColSearch = settings.aoPreSearchCols,
2674 i, data = [], dataProp, column, columnSearch,
2675 sort = _fnSortFlatten( settings ),
2676 displayStart = settings._iDisplayStart,
2677 displayLength = features.bPaginate !== false ?
2678 settings._iDisplayLength :
2679 -1;
2680
2681 var param = function ( name, value ) {
2682 data.push( { 'name': name, 'value': value } );
2683 };
2684
2685 // DataTables 1.9- compatible method
2686 param( 'sEcho', settings.iDraw );
2687 param( 'iColumns', columnCount );
2688 param( 'sColumns', _pluck( columns, 'sName' ).join(',') );
2689 param( 'iDisplayStart', displayStart );
2690 param( 'iDisplayLength', displayLength );
2691
2692 // DataTables 1.10+ method
2693 var d = {
2694 draw: settings.iDraw,
2695 columns: [],
2696 order: [],
2697 start: displayStart,
2698 length: displayLength,
2699 search: {
2700 value: preSearch.sSearch,
2701 regex: preSearch.bRegex
2702 }
2703 };
2704
2705 for ( i=0 ; i<columnCount ; i++ ) {
2706 column = columns[i];
2707 columnSearch = preColSearch[i];
2708 dataProp = typeof column.mData=="function" ? 'function' : column.mData ;
2709
2710 d.columns.push( {
2711 data: dataProp,
2712 name: column.sName,
2713 searchable: column.bSearchable,
2714 orderable: column.bSortable,
2715 search: {
2716 value: columnSearch.sSearch,
2717 regex: columnSearch.bRegex
2718 }
2719 } );
2720
2721 param( "mDataProp_"+i, dataProp );
2722
2723 if ( features.bFilter ) {
2724 param( 'sSearch_'+i, columnSearch.sSearch );
2725 param( 'bRegex_'+i, columnSearch.bRegex );
2726 param( 'bSearchable_'+i, column.bSearchable );
2727 }
2728
2729 if ( features.bSort ) {
2730 param( 'bSortable_'+i, column.bSortable );
2731 }
2732 }
2733
2734 if ( features.bFilter ) {
2735 param( 'sSearch', preSearch.sSearch );
2736 param( 'bRegex', preSearch.bRegex );
2737 }
2738
2739 if ( features.bSort ) {
2740 $.each( sort, function ( i, val ) {
2741 d.order.push( { column: val.col, dir: val.dir } );
2742
2743 param( 'iSortCol_'+i, val.col );
2744 param( 'sSortDir_'+i, val.dir );
2745 } );
2746
2747 param( 'iSortingCols', sort.length );
2748 }
2749
2750 // If the legacy.ajax parameter is null, then we automatically decide which
2751 // form to use, based on sAjaxSource
2752 var legacy = DataTable.ext.legacy.ajax;
2753 if ( legacy === null ) {
2754 return settings.sAjaxSource ? data : d;
2755 }
2756
2757 // Otherwise, if legacy has been specified then we use that to decide on the
2758 // form
2759 return legacy ? data : d;
2760 }
2761
2762
2763 /**
2764 * Data the data from the server (nuking the old) and redraw the table
2765 * @param {object} oSettings dataTables settings object
2766 * @param {object} json json data return from the server.
2767 * @param {string} json.sEcho Tracking flag for DataTables to match requests
2768 * @param {int} json.iTotalRecords Number of records in the data set, not accounting for filtering
2769 * @param {int} json.iTotalDisplayRecords Number of records in the data set, accounting for filtering
2770 * @param {array} json.aaData The data to display on this page
2771 * @param {string} [json.sColumns] Column ordering (sName, comma separated)
2772 * @memberof DataTable#oApi
2773 */
2774 function _fnAjaxUpdateDraw ( settings, json )
2775 {
2776 // v1.10 uses camelCase variables, while 1.9 uses Hungarian notation.
2777 // Support both
2778 var compat = function ( old, modern ) {
2779 return json[old] !== undefined ? json[old] : json[modern];
2780 };
2781
2782 var data = _fnAjaxDataSrc( settings, json );
2783 var draw = compat( 'sEcho', 'draw' );
2784 var recordsTotal = compat( 'iTotalRecords', 'recordsTotal' );
2785 var recordsFiltered = compat( 'iTotalDisplayRecords', 'recordsFiltered' );
2786
2787 if ( draw ) {
2788 // Protect against out of sequence returns
2789 if ( draw*1 < settings.iDraw ) {
2790 return;
2791 }
2792 settings.iDraw = draw * 1;
2793 }
2794
2795 _fnClearTable( settings );
2796 settings._iRecordsTotal = parseInt(recordsTotal, 10);
2797 settings._iRecordsDisplay = parseInt(recordsFiltered, 10);
2798
2799 for ( var i=0, ien=data.length ; i<ien ; i++ ) {
2800 _fnAddData( settings, data[i] );
2801 }
2802 settings.aiDisplay = settings.aiDisplayMaster.slice();
2803
2804 settings.bAjaxDataGet = false;
2805 _fnDraw( settings );
2806
2807 if ( ! settings._bInitComplete ) {
2808 _fnInitComplete( settings, json );
2809 }
2810
2811 settings.bAjaxDataGet = true;
2812 _fnProcessingDisplay( settings, false );
2813 }
2814
2815
2816 /**
2817 * Get the data from the JSON data source to use for drawing a table. Using
2818 * `_fnGetObjectDataFn` allows the data to be sourced from a property of the
2819 * source object, or from a processing function.
2820 * @param {object} oSettings dataTables settings object
2821 * @param {object} json Data source object / array from the server
2822 * @return {array} Array of data to use
2823 */
2824 function _fnAjaxDataSrc ( oSettings, json )
2825 {
2826 var dataSrc = $.isPlainObject( oSettings.ajax ) && oSettings.ajax.dataSrc !== undefined ?
2827 oSettings.ajax.dataSrc :
2828 oSettings.sAjaxDataProp; // Compatibility with 1.9-.
2829
2830 // Compatibility with 1.9-. In order to read from aaData, check if the
2831 // default has been changed, if not, check for aaData
2832 if ( dataSrc === 'data' ) {
2833 return json.aaData || json[dataSrc];
2834 }
2835
2836 return dataSrc !== "" ?
2837 _fnGetObjectDataFn( dataSrc )( json ) :
2838 json;
2839 }
2840
2841 /**
2842 * Generate the node required for filtering text
2843 * @returns {node} Filter control element
2844 * @param {object} oSettings dataTables settings object
2845 * @memberof DataTable#oApi
2846 */
2847 function _fnFeatureHtmlFilter ( settings )
2848 {
2849 var classes = settings.oClasses;
2850 var tableId = settings.sTableId;
2851 var language = settings.oLanguage;
2852 var previousSearch = settings.oPreviousSearch;
2853 var features = settings.aanFeatures;
2854 var input = '<input type="search" class="'+classes.sFilterInput+'"/>';
2855
2856 var str = language.sSearch;
2857 str = str.match(/_INPUT_/) ?
2858 str.replace('_INPUT_', input) :
2859 str+input;
2860
2861 var filter = $('<div/>', {
2862 'id': ! features.f ? tableId+'_filter' : null,
2863 'class': classes.sFilter
2864 } )
2865 .append( $('<label/>' ).append( str ) );
2866
2867 var searchFn = function() {
2868 /* Update all other filter input elements for the new display */
2869 var n = features.f;
2870 var val = !this.value ? "" : this.value; // mental IE8 fix :-(
2871
2872 /* Now do the filter */
2873 if ( val != previousSearch.sSearch ) {
2874 _fnFilterComplete( settings, {
2875 "sSearch": val,
2876 "bRegex": previousSearch.bRegex,
2877 "bSmart": previousSearch.bSmart ,
2878 "bCaseInsensitive": previousSearch.bCaseInsensitive
2879 } );
2880
2881 // Need to redraw, without resorting
2882 settings._iDisplayStart = 0;
2883 _fnDraw( settings );
2884 }
2885 };
2886
2887 var searchDelay = settings.searchDelay !== null ?
2888 settings.searchDelay :
2889 _fnDataSource( settings ) === 'ssp' ?
2890 400 :
2891 0;
2892
2893 var jqFilter = $('input', filter)
2894 .val( previousSearch.sSearch )
2895 .attr( 'placeholder', language.sSearchPlaceholder )
2896 .bind(
2897 'keyup.DT search.DT input.DT paste.DT cut.DT',
2898 searchDelay ?
2899 _fnThrottle( searchFn, searchDelay ) :
2900 searchFn
2901 )
2902 .bind( 'keypress.DT', function(e) {
2903 /* Prevent form submission */
2904 if ( e.keyCode == 13 ) {
2905 return false;
2906 }
2907 } )
2908 .attr('aria-controls', tableId);
2909
2910 // Update the input elements whenever the table is filtered
2911 $(settings.nTable).on( 'search.dt.DT', function ( ev, s ) {
2912 if ( settings === s ) {
2913 // IE9 throws an 'unknown error' if document.activeElement is used
2914 // inside an iframe or frame...
2915 try {
2916 if ( jqFilter[0] !== document.activeElement ) {
2917 jqFilter.val( previousSearch.sSearch );
2918 }
2919 }
2920 catch ( e ) {}
2921 }
2922 } );
2923
2924 return filter[0];
2925 }
2926
2927
2928 /**
2929 * Filter the table using both the global filter and column based filtering
2930 * @param {object} oSettings dataTables settings object
2931 * @param {object} oSearch search information
2932 * @param {int} [iForce] force a research of the master array (1) or not (undefined or 0)
2933 * @memberof DataTable#oApi
2934 */
2935 function _fnFilterComplete ( oSettings, oInput, iForce )
2936 {
2937 var oPrevSearch = oSettings.oPreviousSearch;
2938 var aoPrevSearch = oSettings.aoPreSearchCols;
2939 var fnSaveFilter = function ( oFilter ) {
2940 /* Save the filtering values */
2941 oPrevSearch.sSearch = oFilter.sSearch;
2942 oPrevSearch.bRegex = oFilter.bRegex;
2943 oPrevSearch.bSmart = oFilter.bSmart;
2944 oPrevSearch.bCaseInsensitive = oFilter.bCaseInsensitive;
2945 };
2946 var fnRegex = function ( o ) {
2947 // Backwards compatibility with the bEscapeRegex option
2948 return o.bEscapeRegex !== undefined ? !o.bEscapeRegex : o.bRegex;
2949 };
2950
2951 // Resolve any column types that are unknown due to addition or invalidation
2952 // @todo As per sort - can this be moved into an event handler?
2953 _fnColumnTypes( oSettings );
2954
2955 /* In server-side processing all filtering is done by the server, so no point hanging around here */
2956 if ( _fnDataSource( oSettings ) != 'ssp' )
2957 {
2958 /* Global filter */
2959 _fnFilter( oSettings, oInput.sSearch, iForce, fnRegex(oInput), oInput.bSmart, oInput.bCaseInsensitive );
2960 fnSaveFilter( oInput );
2961
2962 /* Now do the individual column filter */
2963 for ( var i=0 ; i<aoPrevSearch.length ; i++ )
2964 {
2965 _fnFilterColumn( oSettings, aoPrevSearch[i].sSearch, i, fnRegex(aoPrevSearch[i]),
2966 aoPrevSearch[i].bSmart, aoPrevSearch[i].bCaseInsensitive );
2967 }
2968
2969 /* Custom filtering */
2970 _fnFilterCustom( oSettings );
2971 }
2972 else
2973 {
2974 fnSaveFilter( oInput );
2975 }
2976
2977 /* Tell the draw function we have been filtering */
2978 oSettings.bFiltered = true;
2979 _fnCallbackFire( oSettings, null, 'search', [oSettings] );
2980 }
2981
2982
2983 /**
2984 * Apply custom filtering functions
2985 * @param {object} oSettings dataTables settings object
2986 * @memberof DataTable#oApi
2987 */
2988 function _fnFilterCustom( settings )
2989 {
2990 var filters = DataTable.ext.search;
2991 var displayRows = settings.aiDisplay;
2992 var row, rowIdx;
2993
2994 for ( var i=0, ien=filters.length ; i<ien ; i++ ) {
2995 var rows = [];
2996
2997 // Loop over each row and see if it should be included
2998 for ( var j=0, jen=displayRows.length ; j<jen ; j++ ) {
2999 rowIdx = displayRows[ j ];
3000 row = settings.aoData[ rowIdx ];
3001
3002 if ( filters[i]( settings, row._aFilterData, rowIdx, row._aData, j ) ) {
3003 rows.push( rowIdx );
3004 }
3005 }
3006
3007 // So the array reference doesn't break set the results into the
3008 // existing array
3009 displayRows.length = 0;
3010 $.merge( displayRows, rows );
3011 }
3012 }
3013
3014
3015 /**
3016 * Filter the table on a per-column basis
3017 * @param {object} oSettings dataTables settings object
3018 * @param {string} sInput string to filter on
3019 * @param {int} iColumn column to filter
3020 * @param {bool} bRegex treat search string as a regular expression or not
3021 * @param {bool} bSmart use smart filtering or not
3022 * @param {bool} bCaseInsensitive Do case insenstive matching or not
3023 * @memberof DataTable#oApi
3024 */
3025 function _fnFilterColumn ( settings, searchStr, colIdx, regex, smart, caseInsensitive )
3026 {
3027 if ( searchStr === '' ) {
3028 return;
3029 }
3030
3031 var data;
3032 var display = settings.aiDisplay;
3033 var rpSearch = _fnFilterCreateSearch( searchStr, regex, smart, caseInsensitive );
3034
3035 for ( var i=display.length-1 ; i>=0 ; i-- ) {
3036 data = settings.aoData[ display[i] ]._aFilterData[ colIdx ];
3037
3038 if ( ! rpSearch.test( data ) ) {
3039 display.splice( i, 1 );
3040 }
3041 }
3042 }
3043
3044
3045 /**
3046 * Filter the data table based on user input and draw the table
3047 * @param {object} settings dataTables settings object
3048 * @param {string} input string to filter on
3049 * @param {int} force optional - force a research of the master array (1) or not (undefined or 0)
3050 * @param {bool} regex treat as a regular expression or not
3051 * @param {bool} smart perform smart filtering or not
3052 * @param {bool} caseInsensitive Do case insenstive matching or not
3053 * @memberof DataTable#oApi
3054 */
3055 function _fnFilter( settings, input, force, regex, smart, caseInsensitive )
3056 {
3057 var rpSearch = _fnFilterCreateSearch( input, regex, smart, caseInsensitive );
3058 var prevSearch = settings.oPreviousSearch.sSearch;
3059 var displayMaster = settings.aiDisplayMaster;
3060 var display, invalidated, i;
3061
3062 // Need to take account of custom filtering functions - always filter
3063 if ( DataTable.ext.search.length !== 0 ) {
3064 force = true;
3065 }
3066
3067 // Check if any of the rows were invalidated
3068 invalidated = _fnFilterData( settings );
3069
3070 // If the input is blank - we just want the full data set
3071 if ( input.length <= 0 ) {
3072 settings.aiDisplay = displayMaster.slice();
3073 }
3074 else {
3075 // New search - start from the master array
3076 if ( invalidated ||
3077 force ||
3078 prevSearch.length > input.length ||
3079 input.indexOf(prevSearch) !== 0 ||
3080 settings.bSorted // On resort, the display master needs to be
3081 // re-filtered since indexes will have changed
3082 ) {
3083 settings.aiDisplay = displayMaster.slice();
3084 }
3085
3086 // Search the display array
3087 display = settings.aiDisplay;
3088
3089 for ( i=display.length-1 ; i>=0 ; i-- ) {
3090 if ( ! rpSearch.test( settings.aoData[ display[i] ]._sFilterRow ) ) {
3091 display.splice( i, 1 );
3092 }
3093 }
3094 }
3095 }
3096
3097
3098 /**
3099 * Build a regular expression object suitable for searching a table
3100 * @param {string} sSearch string to search for
3101 * @param {bool} bRegex treat as a regular expression or not
3102 * @param {bool} bSmart perform smart filtering or not
3103 * @param {bool} bCaseInsensitive Do case insensitive matching or not
3104 * @returns {RegExp} constructed object
3105 * @memberof DataTable#oApi
3106 */
3107 function _fnFilterCreateSearch( search, regex, smart, caseInsensitive )
3108 {
3109 search = regex ?
3110 search :
3111 _fnEscapeRegex( search );
3112
3113 if ( smart ) {
3114 /* For smart filtering we want to allow the search to work regardless of
3115 * word order. We also want double quoted text to be preserved, so word
3116 * order is important - a la google. So this is what we want to
3117 * generate:
3118 *
3119 * ^(?=.*?\bone\b)(?=.*?\btwo three\b)(?=.*?\bfour\b).*$
3120 */
3121 var a = $.map( search.match( /"[^"]+"|[^ ]+/g ) || [''], function ( word ) {
3122 if ( word.charAt(0) === '"' ) {
3123 var m = word.match( /^"(.*)"$/ );
3124 word = m ? m[1] : word;
3125 }
3126
3127 return word.replace('"', '');
3128 } );
3129
3130 search = '^(?=.*?'+a.join( ')(?=.*?' )+').*$';
3131 }
3132
3133 return new RegExp( search, caseInsensitive ? 'i' : '' );
3134 }
3135
3136
3137 /**
3138 * Escape a string such that it can be used in a regular expression
3139 * @param {string} sVal string to escape
3140 * @returns {string} escaped string
3141 * @memberof DataTable#oApi
3142 */
3143 function _fnEscapeRegex ( sVal )
3144 {
3145 return sVal.replace( _re_escape_regex, '\\$1' );
3146 }
3147
3148
3149
3150 var __filter_div = $('<div>')[0];
3151 var __filter_div_textContent = __filter_div.textContent !== undefined;
3152
3153 // Update the filtering data for each row if needed (by invalidation or first run)
3154 function _fnFilterData ( settings )
3155 {
3156 var columns = settings.aoColumns;
3157 var column;
3158 var i, j, ien, jen, filterData, cellData, row;
3159 var fomatters = DataTable.ext.type.search;
3160 var wasInvalidated = false;
3161
3162 for ( i=0, ien=settings.aoData.length ; i<ien ; i++ ) {
3163 row = settings.aoData[i];
3164
3165 if ( ! row._aFilterData ) {
3166 filterData = [];
3167
3168 for ( j=0, jen=columns.length ; j<jen ; j++ ) {
3169 column = columns[j];
3170
3171 if ( column.bSearchable ) {
3172 cellData = _fnGetCellData( settings, i, j, 'filter' );
3173
3174 if ( fomatters[ column.sType ] ) {
3175 cellData = fomatters[ column.sType ]( cellData );
3176 }
3177
3178 // Search in DataTables 1.10 is string based. In 1.11 this
3179 // should be altered to also allow strict type checking.
3180 if ( cellData === null ) {
3181 cellData = '';
3182 }
3183
3184 if ( typeof cellData !== 'string' && cellData.toString ) {
3185 cellData = cellData.toString();
3186 }
3187 }
3188 else {
3189 cellData = '';
3190 }
3191
3192 // If it looks like there is an HTML entity in the string,
3193 // attempt to decode it so sorting works as expected. Note that
3194 // we could use a single line of jQuery to do this, but the DOM
3195 // method used here is much faster http://jsperf.com/html-decode
3196 if ( cellData.indexOf && cellData.indexOf('&') !== -1 ) {
3197 __filter_div.innerHTML = cellData;
3198 cellData = __filter_div_textContent ?
3199 __filter_div.textContent :
3200 __filter_div.innerText;
3201 }
3202
3203 if ( cellData.replace ) {
3204 cellData = cellData.replace(/[\r\n]/g, '');
3205 }
3206
3207 filterData.push( cellData );
3208 }
3209
3210 row._aFilterData = filterData;
3211 row._sFilterRow = filterData.join(' ');
3212 wasInvalidated = true;
3213 }
3214 }
3215
3216 return wasInvalidated;
3217 }
3218
3219
3220 /**
3221 * Convert from the internal Hungarian notation to camelCase for external
3222 * interaction
3223 * @param {object} obj Object to convert
3224 * @returns {object} Inverted object
3225 * @memberof DataTable#oApi
3226 */
3227 function _fnSearchToCamel ( obj )
3228 {
3229 return {
3230 search: obj.sSearch,
3231 smart: obj.bSmart,
3232 regex: obj.bRegex,
3233 caseInsensitive: obj.bCaseInsensitive
3234 };
3235 }
3236
3237
3238
3239 /**
3240 * Convert from camelCase notation to the internal Hungarian. We could use the
3241 * Hungarian convert function here, but this is cleaner
3242 * @param {object} obj Object to convert
3243 * @returns {object} Inverted object
3244 * @memberof DataTable#oApi
3245 */
3246 function _fnSearchToHung ( obj )
3247 {
3248 return {
3249 sSearch: obj.search,
3250 bSmart: obj.smart,
3251 bRegex: obj.regex,
3252 bCaseInsensitive: obj.caseInsensitive
3253 };
3254 }
3255
3256 /**
3257 * Generate the node required for the info display
3258 * @param {object} oSettings dataTables settings object
3259 * @returns {node} Information element
3260 * @memberof DataTable#oApi
3261 */
3262 function _fnFeatureHtmlInfo ( settings )
3263 {
3264 var
3265 tid = settings.sTableId,
3266 nodes = settings.aanFeatures.i,
3267 n = $('<div/>', {
3268 'class': settings.oClasses.sInfo,
3269 'id': ! nodes ? tid+'_info' : null
3270 } );
3271
3272 if ( ! nodes ) {
3273 // Update display on each draw
3274 settings.aoDrawCallback.push( {
3275 "fn": _fnUpdateInfo,
3276 "sName": "information"
3277 } );
3278
3279 n
3280 .attr( 'role', 'status' )
3281 .attr( 'aria-live', 'polite' );
3282
3283 // Table is described by our info div
3284 $(settings.nTable).attr( 'aria-describedby', tid+'_info' );
3285 }
3286
3287 return n[0];
3288 }
3289
3290
3291 /**
3292 * Update the information elements in the display
3293 * @param {object} settings dataTables settings object
3294 * @memberof DataTable#oApi
3295 */
3296 function _fnUpdateInfo ( settings )
3297 {
3298 /* Show information about the table */
3299 var nodes = settings.aanFeatures.i;
3300 if ( nodes.length === 0 ) {
3301 return;
3302 }
3303
3304 var
3305 lang = settings.oLanguage,
3306 start = settings._iDisplayStart+1,
3307 end = settings.fnDisplayEnd(),
3308 max = settings.fnRecordsTotal(),
3309 total = settings.fnRecordsDisplay(),
3310 out = total ?
3311 lang.sInfo :
3312 lang.sInfoEmpty;
3313
3314 if ( total !== max ) {
3315 /* Record set after filtering */
3316 out += ' ' + lang.sInfoFiltered;
3317 }
3318
3319 // Convert the macros
3320 out += lang.sInfoPostFix;
3321 out = _fnInfoMacros( settings, out );
3322
3323 var callback = lang.fnInfoCallback;
3324 if ( callback !== null ) {
3325 out = callback.call( settings.oInstance,
3326 settings, start, end, max, total, out
3327 );
3328 }
3329
3330 $(nodes).html( out );
3331 }
3332
3333
3334 function _fnInfoMacros ( settings, str )
3335 {
3336 // When infinite scrolling, we are always starting at 1. _iDisplayStart is used only
3337 // internally
3338 var
3339 formatter = settings.fnFormatNumber,
3340 start = settings._iDisplayStart+1,
3341 len = settings._iDisplayLength,
3342 vis = settings.fnRecordsDisplay(),
3343 all = len === -1;
3344
3345 return str.
3346 replace(/_START_/g, formatter.call( settings, start ) ).
3347 replace(/_END_/g, formatter.call( settings, settings.fnDisplayEnd() ) ).
3348 replace(/_MAX_/g, formatter.call( settings, settings.fnRecordsTotal() ) ).
3349 replace(/_TOTAL_/g, formatter.call( settings, vis ) ).
3350 replace(/_PAGE_/g, formatter.call( settings, all ? 1 : Math.ceil( start / len ) ) ).
3351 replace(/_PAGES_/g, formatter.call( settings, all ? 1 : Math.ceil( vis / len ) ) );
3352 }
3353
3354
3355
3356 /**
3357 * Draw the table for the first time, adding all required features
3358 * @param {object} settings dataTables settings object
3359 * @memberof DataTable#oApi
3360 */
3361 function _fnInitialise ( settings )
3362 {
3363 var i, iLen, iAjaxStart=settings.iInitDisplayStart;
3364 var columns = settings.aoColumns, column;
3365 var features = settings.oFeatures;
3366 var deferLoading = settings.bDeferLoading; // value modified by the draw
3367
3368 /* Ensure that the table data is fully initialised */
3369 if ( ! settings.bInitialised ) {
3370 setTimeout( function(){ _fnInitialise( settings ); }, 200 );
3371 return;
3372 }
3373
3374 /* Show the display HTML options */
3375 _fnAddOptionsHtml( settings );
3376
3377 /* Build and draw the header / footer for the table */
3378 _fnBuildHead( settings );
3379 _fnDrawHead( settings, settings.aoHeader );
3380 _fnDrawHead( settings, settings.aoFooter );
3381
3382 /* Okay to show that something is going on now */
3383 _fnProcessingDisplay( settings, true );
3384
3385 /* Calculate sizes for columns */
3386 if ( features.bAutoWidth ) {
3387 _fnCalculateColumnWidths( settings );
3388 }
3389
3390 for ( i=0, iLen=columns.length ; i<iLen ; i++ ) {
3391 column = columns[i];
3392
3393 if ( column.sWidth ) {
3394 column.nTh.style.width = _fnStringToCss( column.sWidth );
3395 }
3396 }
3397
3398 _fnCallbackFire( settings, null, 'preInit', [settings] );
3399
3400 // If there is default sorting required - let's do it. The sort function
3401 // will do the drawing for us. Otherwise we draw the table regardless of the
3402 // Ajax source - this allows the table to look initialised for Ajax sourcing
3403 // data (show 'loading' message possibly)
3404 _fnReDraw( settings );
3405
3406 // Server-side processing init complete is done by _fnAjaxUpdateDraw
3407 var dataSrc = _fnDataSource( settings );
3408 if ( dataSrc != 'ssp' || deferLoading ) {
3409 // if there is an ajax source load the data
3410 if ( dataSrc == 'ajax' ) {
3411 _fnBuildAjax( settings, [], function(json) {
3412 var aData = _fnAjaxDataSrc( settings, json );
3413
3414 // Got the data - add it to the table
3415 for ( i=0 ; i<aData.length ; i++ ) {
3416 _fnAddData( settings, aData[i] );
3417 }
3418
3419 // Reset the init display for cookie saving. We've already done
3420 // a filter, and therefore cleared it before. So we need to make
3421 // it appear 'fresh'
3422 settings.iInitDisplayStart = iAjaxStart;
3423
3424 _fnReDraw( settings );
3425
3426 _fnProcessingDisplay( settings, false );
3427 _fnInitComplete( settings, json );
3428 }, settings );
3429 }
3430 else {
3431 _fnProcessingDisplay( settings, false );
3432 _fnInitComplete( settings );
3433 }
3434 }
3435 }
3436
3437
3438 /**
3439 * Draw the table for the first time, adding all required features
3440 * @param {object} oSettings dataTables settings object
3441 * @param {object} [json] JSON from the server that completed the table, if using Ajax source
3442 * with client-side processing (optional)
3443 * @memberof DataTable#oApi
3444 */
3445 function _fnInitComplete ( settings, json )
3446 {
3447 settings._bInitComplete = true;
3448
3449 // When data was added after the initialisation (data or Ajax) we need to
3450 // calculate the column sizing
3451 if ( json || settings.oInit.aaData ) {
3452 _fnAdjustColumnSizing( settings );
3453 }
3454
3455 _fnCallbackFire( settings, null, 'plugin-init', [settings, json] );
3456 _fnCallbackFire( settings, 'aoInitComplete', 'init', [settings, json] );
3457 }
3458
3459
3460 function _fnLengthChange ( settings, val )
3461 {
3462 var len = parseInt( val, 10 );
3463 settings._iDisplayLength = len;
3464
3465 _fnLengthOverflow( settings );
3466
3467 // Fire length change event
3468 _fnCallbackFire( settings, null, 'length', [settings, len] );
3469 }
3470
3471
3472 /**
3473 * Generate the node required for user display length changing
3474 * @param {object} settings dataTables settings object
3475 * @returns {node} Display length feature node
3476 * @memberof DataTable#oApi
3477 */
3478 function _fnFeatureHtmlLength ( settings )
3479 {
3480 var
3481 classes = settings.oClasses,
3482 tableId = settings.sTableId,
3483 menu = settings.aLengthMenu,
3484 d2 = $.isArray( menu[0] ),
3485 lengths = d2 ? menu[0] : menu,
3486 language = d2 ? menu[1] : menu;
3487
3488 var select = $('<select/>', {
3489 'name': tableId+'_length',
3490 'aria-controls': tableId,
3491 'class': classes.sLengthSelect
3492 } );
3493
3494 for ( var i=0, ien=lengths.length ; i<ien ; i++ ) {
3495 select[0][ i ] = new Option( language[i], lengths[i] );
3496 }
3497
3498 var div = $('<div><label/></div>').addClass( classes.sLength );
3499 if ( ! settings.aanFeatures.l ) {
3500 div[0].id = tableId+'_length';
3501 }
3502
3503 div.children().append(
3504 settings.oLanguage.sLengthMenu.replace( '_MENU_', select[0].outerHTML )
3505 );
3506
3507 // Can't use `select` variable as user might provide their own and the
3508 // reference is broken by the use of outerHTML
3509 $('select', div)
3510 .val( settings._iDisplayLength )
3511 .bind( 'change.DT', function(e) {
3512 _fnLengthChange( settings, $(this).val() );
3513 _fnDraw( settings );
3514 } );
3515
3516 // Update node value whenever anything changes the table's length
3517 $(settings.nTable).bind( 'length.dt.DT', function (e, s, len) {
3518 if ( settings === s ) {
3519 $('select', div).val( len );
3520 }
3521 } );
3522
3523 return div[0];
3524 }
3525
3526
3527
3528 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
3529 * Note that most of the paging logic is done in
3530 * DataTable.ext.pager
3531 */
3532
3533 /**
3534 * Generate the node required for default pagination
3535 * @param {object} oSettings dataTables settings object
3536 * @returns {node} Pagination feature node
3537 * @memberof DataTable#oApi
3538 */
3539 function _fnFeatureHtmlPaginate ( settings )
3540 {
3541 var
3542 type = settings.sPaginationType,
3543 plugin = DataTable.ext.pager[ type ],
3544 modern = typeof plugin === 'function',
3545 redraw = function( settings ) {
3546 _fnDraw( settings );
3547 },
3548 node = $('<div/>').addClass( settings.oClasses.sPaging + type )[0],
3549 features = settings.aanFeatures;
3550
3551 if ( ! modern ) {
3552 plugin.fnInit( settings, node, redraw );
3553 }
3554
3555 /* Add a draw callback for the pagination on first instance, to update the paging display */
3556 if ( ! features.p )
3557 {
3558 node.id = settings.sTableId+'_paginate';
3559
3560 settings.aoDrawCallback.push( {
3561 "fn": function( settings ) {
3562 if ( modern ) {
3563 var
3564 start = settings._iDisplayStart,
3565 len = settings._iDisplayLength,
3566 visRecords = settings.fnRecordsDisplay(),
3567 all = len === -1,
3568 page = all ? 0 : Math.ceil( start / len ),
3569 pages = all ? 1 : Math.ceil( visRecords / len ),
3570 buttons = plugin(page, pages),
3571 i, ien;
3572
3573 for ( i=0, ien=features.p.length ; i<ien ; i++ ) {
3574 _fnRenderer( settings, 'pageButton' )(
3575 settings, features.p[i], i, buttons, page, pages
3576 );
3577 }
3578 }
3579 else {
3580 plugin.fnUpdate( settings, redraw );
3581 }
3582 },
3583 "sName": "pagination"
3584 } );
3585 }
3586
3587 return node;
3588 }
3589
3590
3591 /**
3592 * Alter the display settings to change the page
3593 * @param {object} settings DataTables settings object
3594 * @param {string|int} action Paging action to take: "first", "previous",
3595 * "next" or "last" or page number to jump to (integer)
3596 * @param [bool] redraw Automatically draw the update or not
3597 * @returns {bool} true page has changed, false - no change
3598 * @memberof DataTable#oApi
3599 */
3600 function _fnPageChange ( settings, action, redraw )
3601 {
3602 var
3603 start = settings._iDisplayStart,
3604 len = settings._iDisplayLength,
3605 records = settings.fnRecordsDisplay();
3606
3607 if ( records === 0 || len === -1 )
3608 {
3609 start = 0;
3610 }
3611 else if ( typeof action === "number" )
3612 {
3613 start = action * len;
3614
3615 if ( start > records )
3616 {
3617 start = 0;
3618 }
3619 }
3620 else if ( action == "first" )
3621 {
3622 start = 0;
3623 }
3624 else if ( action == "previous" )
3625 {
3626 start = len >= 0 ?
3627 start - len :
3628 0;
3629
3630 if ( start < 0 )
3631 {
3632 start = 0;
3633 }
3634 }
3635 else if ( action == "next" )
3636 {
3637 if ( start + len < records )
3638 {
3639 start += len;
3640 }
3641 }
3642 else if ( action == "last" )
3643 {
3644 start = Math.floor( (records-1) / len) * len;
3645 }
3646 else
3647 {
3648 _fnLog( settings, 0, "Unknown paging action: "+action, 5 );
3649 }
3650
3651 var changed = settings._iDisplayStart !== start;
3652 settings._iDisplayStart = start;
3653
3654 if ( changed ) {
3655 _fnCallbackFire( settings, null, 'page', [settings] );
3656
3657 if ( redraw ) {
3658 _fnDraw( settings );
3659 }
3660 }
3661
3662 return changed;
3663 }
3664
3665
3666
3667 /**
3668 * Generate the node required for the processing node
3669 * @param {object} settings dataTables settings object
3670 * @returns {node} Processing element
3671 * @memberof DataTable#oApi
3672 */
3673 function _fnFeatureHtmlProcessing ( settings )
3674 {
3675 return $('<div/>', {
3676 'id': ! settings.aanFeatures.r ? settings.sTableId+'_processing' : null,
3677 'class': settings.oClasses.sProcessing
3678 } )
3679 .html( settings.oLanguage.sProcessing )
3680 .insertBefore( settings.nTable )[0];
3681 }
3682
3683
3684 /**
3685 * Display or hide the processing indicator
3686 * @param {object} settings dataTables settings object
3687 * @param {bool} show Show the processing indicator (true) or not (false)
3688 * @memberof DataTable#oApi
3689 */
3690 function _fnProcessingDisplay ( settings, show )
3691 {
3692 if ( settings.oFeatures.bProcessing ) {
3693 $(settings.aanFeatures.r).css( 'display', show ? 'block' : 'none' );
3694 }
3695
3696 _fnCallbackFire( settings, null, 'processing', [settings, show] );
3697 }
3698
3699 /**
3700 * Add any control elements for the table - specifically scrolling
3701 * @param {object} settings dataTables settings object
3702 * @returns {node} Node to add to the DOM
3703 * @memberof DataTable#oApi
3704 */
3705 function _fnFeatureHtmlTable ( settings )
3706 {
3707 var table = $(settings.nTable);
3708
3709 // Add the ARIA grid role to the table
3710 table.attr( 'role', 'grid' );
3711
3712 // Scrolling from here on in
3713 var scroll = settings.oScroll;
3714
3715 if ( scroll.sX === '' && scroll.sY === '' ) {
3716 return settings.nTable;
3717 }
3718
3719 var scrollX = scroll.sX;
3720 var scrollY = scroll.sY;
3721 var classes = settings.oClasses;
3722 var caption = table.children('caption');
3723 var captionSide = caption.length ? caption[0]._captionSide : null;
3724 var headerClone = $( table[0].cloneNode(false) );
3725 var footerClone = $( table[0].cloneNode(false) );
3726 var footer = table.children('tfoot');
3727 var _div = '<div/>';
3728 var size = function ( s ) {
3729 return !s ? null : _fnStringToCss( s );
3730 };
3731
3732 if ( ! footer.length ) {
3733 footer = null;
3734 }
3735
3736 /*
3737 * The HTML structure that we want to generate in this function is:
3738 * div - scroller
3739 * div - scroll head
3740 * div - scroll head inner
3741 * table - scroll head table
3742 * thead - thead
3743 * div - scroll body
3744 * table - table (master table)
3745 * thead - thead clone for sizing
3746 * tbody - tbody
3747 * div - scroll foot
3748 * div - scroll foot inner
3749 * table - scroll foot table
3750 * tfoot - tfoot
3751 */
3752 var scroller = $( _div, { 'class': classes.sScrollWrapper } )
3753 .append(
3754 $(_div, { 'class': classes.sScrollHead } )
3755 .css( {
3756 overflow: 'hidden',
3757 position: 'relative',
3758 border: 0,
3759 width: scrollX ? size(scrollX) : '100%'
3760 } )
3761 .append(
3762 $(_div, { 'class': classes.sScrollHeadInner } )
3763 .css( {
3764 'box-sizing': 'content-box',
3765 width: scroll.sXInner || '100%'
3766 } )
3767 .append(
3768 headerClone
3769 .removeAttr('id')
3770 .css( 'margin-left', 0 )
3771 .append( captionSide === 'top' ? caption : null )
3772 .append(
3773 table.children('thead')
3774 )
3775 )
3776 )
3777 )
3778 .append(
3779 $(_div, { 'class': classes.sScrollBody } )
3780 .css( {
3781 position: 'relative',
3782 overflow: 'auto',
3783 width: size( scrollX )
3784 } )
3785 .append( table )
3786 );
3787
3788 if ( footer ) {
3789 scroller.append(
3790 $(_div, { 'class': classes.sScrollFoot } )
3791 .css( {
3792 overflow: 'hidden',
3793 border: 0,
3794 width: scrollX ? size(scrollX) : '100%'
3795 } )
3796 .append(
3797 $(_div, { 'class': classes.sScrollFootInner } )
3798 .append(
3799 footerClone
3800 .removeAttr('id')
3801 .css( 'margin-left', 0 )
3802 .append( captionSide === 'bottom' ? caption : null )
3803 .append(
3804 table.children('tfoot')
3805 )
3806 )
3807 )
3808 );
3809 }
3810
3811 var children = scroller.children();
3812 var scrollHead = children[0];
3813 var scrollBody = children[1];
3814 var scrollFoot = footer ? children[2] : null;
3815
3816 // When the body is scrolled, then we also want to scroll the headers
3817 if ( scrollX ) {
3818 $(scrollBody).on( 'scroll.DT', function (e) {
3819 var scrollLeft = this.scrollLeft;
3820
3821 scrollHead.scrollLeft = scrollLeft;
3822
3823 if ( footer ) {
3824 scrollFoot.scrollLeft = scrollLeft;
3825 }
3826 } );
3827 }
3828
3829 $(scrollBody).css(
3830 scrollY && scroll.bCollapse ? 'max-height' : 'height',
3831 scrollY
3832 );
3833
3834 settings.nScrollHead = scrollHead;
3835 settings.nScrollBody = scrollBody;
3836 settings.nScrollFoot = scrollFoot;
3837
3838 // On redraw - align columns
3839 settings.aoDrawCallback.push( {
3840 "fn": _fnScrollDraw,
3841 "sName": "scrolling"
3842 } );
3843
3844 return scroller[0];
3845 }
3846
3847
3848
3849 /**
3850 * Update the header, footer and body tables for resizing - i.e. column
3851 * alignment.
3852 *
3853 * Welcome to the most horrible function DataTables. The process that this
3854 * function follows is basically:
3855 * 1. Re-create the table inside the scrolling div
3856 * 2. Take live measurements from the DOM
3857 * 3. Apply the measurements to align the columns
3858 * 4. Clean up
3859 *
3860 * @param {object} settings dataTables settings object
3861 * @memberof DataTable#oApi
3862 */
3863 function _fnScrollDraw ( settings )
3864 {
3865 // Given that this is such a monster function, a lot of variables are use
3866 // to try and keep the minimised size as small as possible
3867 var
3868 scroll = settings.oScroll,
3869 scrollX = scroll.sX,
3870 scrollXInner = scroll.sXInner,
3871 scrollY = scroll.sY,
3872 barWidth = scroll.iBarWidth,
3873 divHeader = $(settings.nScrollHead),
3874 divHeaderStyle = divHeader[0].style,
3875 divHeaderInner = divHeader.children('div'),
3876 divHeaderInnerStyle = divHeaderInner[0].style,
3877 divHeaderTable = divHeaderInner.children('table'),
3878 divBodyEl = settings.nScrollBody,
3879 divBody = $(divBodyEl),
3880 divBodyStyle = divBodyEl.style,
3881 divFooter = $(settings.nScrollFoot),
3882 divFooterInner = divFooter.children('div'),
3883 divFooterTable = divFooterInner.children('table'),
3884 header = $(settings.nTHead),
3885 table = $(settings.nTable),
3886 tableEl = table[0],
3887 tableStyle = tableEl.style,
3888 footer = settings.nTFoot ? $(settings.nTFoot) : null,
3889 browser = settings.oBrowser,
3890 ie67 = browser.bScrollOversize,
3891 headerTrgEls, footerTrgEls,
3892 headerSrcEls, footerSrcEls,
3893 headerCopy, footerCopy,
3894 headerWidths=[], footerWidths=[],
3895 headerContent=[],
3896 idx, correction, sanityWidth,
3897 zeroOut = function(nSizer) {
3898 var style = nSizer.style;
3899 style.paddingTop = "0";
3900 style.paddingBottom = "0";
3901 style.borderTopWidth = "0";
3902 style.borderBottomWidth = "0";
3903 style.height = 0;
3904 };
3905
3906 // If the scrollbar visibility has changed from the last draw, we need to
3907 // adjust the column sizes as the table width will have changed to account
3908 // for the scrollbar
3909 var scrollBarVis = divBodyEl.scrollHeight > divBodyEl.clientHeight;
3910
3911 if ( settings.scrollBarVis !== scrollBarVis && settings.scrollBarVis !== undefined ) {
3912 settings.scrollBarVis = scrollBarVis;
3913 _fnAdjustColumnSizing( settings );
3914 return; // adjust column sizing will call this function again
3915 }
3916 else {
3917 settings.scrollBarVis = scrollBarVis;
3918 }
3919
3920 /*
3921 * 1. Re-create the table inside the scrolling div
3922 */
3923
3924 // Remove the old minimised thead and tfoot elements in the inner table
3925 table.children('thead, tfoot').remove();
3926
3927 // Clone the current header and footer elements and then place it into the inner table
3928 headerCopy = header.clone().prependTo( table );
3929 headerTrgEls = header.find('tr'); // original header is in its own table
3930 headerSrcEls = headerCopy.find('tr');
3931 headerCopy.find('th, td').removeAttr('tabindex');
3932
3933 if ( footer ) {
3934 footerCopy = footer.clone().prependTo( table );
3935 footerTrgEls = footer.find('tr'); // the original tfoot is in its own table and must be sized
3936 footerSrcEls = footerCopy.find('tr');
3937 }
3938
3939
3940 /*
3941 * 2. Take live measurements from the DOM - do not alter the DOM itself!
3942 */
3943
3944 // Remove old sizing and apply the calculated column widths
3945 // Get the unique column headers in the newly created (cloned) header. We want to apply the
3946 // calculated sizes to this header
3947 if ( ! scrollX )
3948 {
3949 divBodyStyle.width = '100%';
3950 divHeader[0].style.width = '100%';
3951 }
3952
3953 $.each( _fnGetUniqueThs( settings, headerCopy ), function ( i, el ) {
3954 idx = _fnVisibleToColumnIndex( settings, i );
3955 el.style.width = settings.aoColumns[idx].sWidth;
3956 } );
3957
3958 if ( footer ) {
3959 _fnApplyToChildren( function(n) {
3960 n.style.width = "";
3961 }, footerSrcEls );
3962 }
3963
3964 // Size the table as a whole
3965 sanityWidth = table.outerWidth();
3966 if ( scrollX === "" ) {
3967 // No x scrolling
3968 tableStyle.width = "100%";
3969
3970 // IE7 will make the width of the table when 100% include the scrollbar
3971 // - which is shouldn't. When there is a scrollbar we need to take this
3972 // into account.
3973 if ( ie67 && (table.find('tbody').height() > divBodyEl.offsetHeight ||
3974 divBody.css('overflow-y') == "scroll")
3975 ) {
3976 tableStyle.width = _fnStringToCss( table.outerWidth() - barWidth);
3977 }
3978
3979 // Recalculate the sanity width
3980 sanityWidth = table.outerWidth();
3981 }
3982 else if ( scrollXInner !== "" ) {
3983 // legacy x scroll inner has been given - use it
3984 tableStyle.width = _fnStringToCss(scrollXInner);
3985
3986 // Recalculate the sanity width
3987 sanityWidth = table.outerWidth();
3988 }
3989
3990 // Hidden header should have zero height, so remove padding and borders. Then
3991 // set the width based on the real headers
3992
3993 // Apply all styles in one pass
3994 _fnApplyToChildren( zeroOut, headerSrcEls );
3995
3996 // Read all widths in next pass
3997 _fnApplyToChildren( function(nSizer) {
3998 headerContent.push( nSizer.innerHTML );
3999 headerWidths.push( _fnStringToCss( $(nSizer).css('width') ) );
4000 }, headerSrcEls );
4001
4002 // Apply all widths in final pass
4003 _fnApplyToChildren( function(nToSize, i) {
4004 nToSize.style.width = headerWidths[i];
4005 }, headerTrgEls );
4006
4007 $(headerSrcEls).height(0);
4008
4009 /* Same again with the footer if we have one */
4010 if ( footer )
4011 {
4012 _fnApplyToChildren( zeroOut, footerSrcEls );
4013
4014 _fnApplyToChildren( function(nSizer) {
4015 footerWidths.push( _fnStringToCss( $(nSizer).css('width') ) );
4016 }, footerSrcEls );
4017
4018 _fnApplyToChildren( function(nToSize, i) {
4019 nToSize.style.width = footerWidths[i];
4020 }, footerTrgEls );
4021
4022 $(footerSrcEls).height(0);
4023 }
4024
4025
4026 /*
4027 * 3. Apply the measurements
4028 */
4029
4030 // "Hide" the header and footer that we used for the sizing. We need to keep
4031 // the content of the cell so that the width applied to the header and body
4032 // both match, but we want to hide it completely. We want to also fix their
4033 // width to what they currently are
4034 _fnApplyToChildren( function(nSizer, i) {
4035 nSizer.innerHTML = '<div class="dataTables_sizing" style="height:0;overflow:hidden;">'+headerContent[i]+'</div>';
4036 nSizer.style.width = headerWidths[i];
4037 }, headerSrcEls );
4038
4039 if ( footer )
4040 {
4041 _fnApplyToChildren( function(nSizer, i) {
4042 nSizer.innerHTML = "";
4043 nSizer.style.width = footerWidths[i];
4044 }, footerSrcEls );
4045 }
4046
4047 // Sanity check that the table is of a sensible width. If not then we are going to get
4048 // misalignment - try to prevent this by not allowing the table to shrink below its min width
4049 if ( table.outerWidth() < sanityWidth )
4050 {
4051 // The min width depends upon if we have a vertical scrollbar visible or not */
4052 correction = ((divBodyEl.scrollHeight > divBodyEl.offsetHeight ||
4053 divBody.css('overflow-y') == "scroll")) ?
4054 sanityWidth+barWidth :
4055 sanityWidth;
4056
4057 // IE6/7 are a law unto themselves...
4058 if ( ie67 && (divBodyEl.scrollHeight >
4059 divBodyEl.offsetHeight || divBody.css('overflow-y') == "scroll")
4060 ) {
4061 tableStyle.width = _fnStringToCss( correction-barWidth );
4062 }
4063
4064 // And give the user a warning that we've stopped the table getting too small
4065 if ( scrollX === "" || scrollXInner !== "" ) {
4066 _fnLog( settings, 1, 'Possible column misalignment', 6 );
4067 }
4068 }
4069 else
4070 {
4071 correction = '100%';
4072 }
4073
4074 // Apply to the container elements
4075 divBodyStyle.width = _fnStringToCss( correction );
4076 divHeaderStyle.width = _fnStringToCss( correction );
4077
4078 if ( footer ) {
4079 settings.nScrollFoot.style.width = _fnStringToCss( correction );
4080 }
4081
4082
4083 /*
4084 * 4. Clean up
4085 */
4086 if ( ! scrollY ) {
4087 /* IE7< puts a vertical scrollbar in place (when it shouldn't be) due to subtracting
4088 * the scrollbar height from the visible display, rather than adding it on. We need to
4089 * set the height in order to sort this. Don't want to do it in any other browsers.
4090 */
4091 if ( ie67 ) {
4092 divBodyStyle.height = _fnStringToCss( tableEl.offsetHeight+barWidth );
4093 }
4094 }
4095
4096 /* Finally set the width's of the header and footer tables */
4097 var iOuterWidth = table.outerWidth();
4098 divHeaderTable[0].style.width = _fnStringToCss( iOuterWidth );
4099 divHeaderInnerStyle.width = _fnStringToCss( iOuterWidth );
4100
4101 // Figure out if there are scrollbar present - if so then we need a the header and footer to
4102 // provide a bit more space to allow "overflow" scrolling (i.e. past the scrollbar)
4103 var bScrolling = table.height() > divBodyEl.clientHeight || divBody.css('overflow-y') == "scroll";
4104 var padding = 'padding' + (browser.bScrollbarLeft ? 'Left' : 'Right' );
4105 divHeaderInnerStyle[ padding ] = bScrolling ? barWidth+"px" : "0px";
4106
4107 if ( footer ) {
4108 divFooterTable[0].style.width = _fnStringToCss( iOuterWidth );
4109 divFooterInner[0].style.width = _fnStringToCss( iOuterWidth );
4110 divFooterInner[0].style[padding] = bScrolling ? barWidth+"px" : "0px";
4111 }
4112
4113 /* Adjust the position of the header in case we loose the y-scrollbar */
4114 divBody.scroll();
4115
4116 // If sorting or filtering has occurred, jump the scrolling back to the top
4117 // only if we aren't holding the position
4118 if ( (settings.bSorted || settings.bFiltered) && ! settings._drawHold ) {
4119 divBodyEl.scrollTop = 0;
4120 }
4121 }
4122
4123
4124
4125 /**
4126 * Apply a given function to the display child nodes of an element array (typically
4127 * TD children of TR rows
4128 * @param {function} fn Method to apply to the objects
4129 * @param array {nodes} an1 List of elements to look through for display children
4130 * @param array {nodes} an2 Another list (identical structure to the first) - optional
4131 * @memberof DataTable#oApi
4132 */
4133 function _fnApplyToChildren( fn, an1, an2 )
4134 {
4135 var index=0, i=0, iLen=an1.length;
4136 var nNode1, nNode2;
4137
4138 while ( i < iLen ) {
4139 nNode1 = an1[i].firstChild;
4140 nNode2 = an2 ? an2[i].firstChild : null;
4141
4142 while ( nNode1 ) {
4143 if ( nNode1.nodeType === 1 ) {
4144 if ( an2 ) {
4145 fn( nNode1, nNode2, index );
4146 }
4147 else {
4148 fn( nNode1, index );
4149 }
4150
4151 index++;
4152 }
4153
4154 nNode1 = nNode1.nextSibling;
4155 nNode2 = an2 ? nNode2.nextSibling : null;
4156 }
4157
4158 i++;
4159 }
4160 }
4161
4162
4163
4164 var __re_html_remove = /<.*?>/g;
4165
4166
4167 /**
4168 * Calculate the width of columns for the table
4169 * @param {object} oSettings dataTables settings object
4170 * @memberof DataTable#oApi
4171 */
4172 function _fnCalculateColumnWidths ( oSettings )
4173 {
4174 var
4175 table = oSettings.nTable,
4176 columns = oSettings.aoColumns,
4177 scroll = oSettings.oScroll,
4178 scrollY = scroll.sY,
4179 scrollX = scroll.sX,
4180 scrollXInner = scroll.sXInner,
4181 columnCount = columns.length,
4182 visibleColumns = _fnGetColumns( oSettings, 'bVisible' ),
4183 headerCells = $('th', oSettings.nTHead),
4184 tableWidthAttr = table.getAttribute('width'), // from DOM element
4185 tableContainer = table.parentNode,
4186 userInputs = false,
4187 i, column, columnIdx, width, outerWidth,
4188 browser = oSettings.oBrowser,
4189 ie67 = browser.bScrollOversize;
4190
4191 var styleWidth = table.style.width;
4192 if ( styleWidth && styleWidth.indexOf('%') !== -1 ) {
4193 tableWidthAttr = styleWidth;
4194 }
4195
4196 /* Convert any user input sizes into pixel sizes */
4197 for ( i=0 ; i<visibleColumns.length ; i++ ) {
4198 column = columns[ visibleColumns[i] ];
4199
4200 if ( column.sWidth !== null ) {
4201 column.sWidth = _fnConvertToWidth( column.sWidthOrig, tableContainer );
4202
4203 userInputs = true;
4204 }
4205 }
4206
4207 /* If the number of columns in the DOM equals the number that we have to
4208 * process in DataTables, then we can use the offsets that are created by
4209 * the web- browser. No custom sizes can be set in order for this to happen,
4210 * nor scrolling used
4211 */
4212 if ( ie67 || ! userInputs && ! scrollX && ! scrollY &&
4213 columnCount == _fnVisbleColumns( oSettings ) &&
4214 columnCount == headerCells.length
4215 ) {
4216 for ( i=0 ; i<columnCount ; i++ ) {
4217 var colIdx = _fnVisibleToColumnIndex( oSettings, i );
4218
4219 if ( colIdx !== null ) {
4220 columns[ colIdx ].sWidth = _fnStringToCss( headerCells.eq(i).width() );
4221 }
4222 }
4223 }
4224 else
4225 {
4226 // Otherwise construct a single row, worst case, table with the widest
4227 // node in the data, assign any user defined widths, then insert it into
4228 // the DOM and allow the browser to do all the hard work of calculating
4229 // table widths
4230 var tmpTable = $(table).clone() // don't use cloneNode - IE8 will remove events on the main table
4231 .css( 'visibility', 'hidden' )
4232 .removeAttr( 'id' );
4233
4234 // Clean up the table body
4235 tmpTable.find('tbody tr').remove();
4236 var tr = $('<tr/>').appendTo( tmpTable.find('tbody') );
4237
4238 // Clone the table header and footer - we can't use the header / footer
4239 // from the cloned table, since if scrolling is active, the table's
4240 // real header and footer are contained in different table tags
4241 tmpTable.find('thead, tfoot').remove();
4242 tmpTable
4243 .append( $(oSettings.nTHead).clone() )
4244 .append( $(oSettings.nTFoot).clone() );
4245
4246 // Remove any assigned widths from the footer (from scrolling)
4247 tmpTable.find('tfoot th, tfoot td').css('width', '');
4248
4249 // Apply custom sizing to the cloned header
4250 headerCells = _fnGetUniqueThs( oSettings, tmpTable.find('thead')[0] );
4251
4252 for ( i=0 ; i<visibleColumns.length ; i++ ) {
4253 column = columns[ visibleColumns[i] ];
4254
4255 headerCells[i].style.width = column.sWidthOrig !== null && column.sWidthOrig !== '' ?
4256 _fnStringToCss( column.sWidthOrig ) :
4257 '';
4258
4259 // For scrollX we need to force the column width otherwise the
4260 // browser will collapse it. If this width is smaller than the
4261 // width the column requires, then it will have no effect
4262 if ( column.sWidthOrig && scrollX ) {
4263 $( headerCells[i] ).append( $('<div/>').css( {
4264 width: column.sWidthOrig,
4265 margin: 0,
4266 padding: 0,
4267 border: 0,
4268 height: 1
4269 } ) );
4270 }
4271 }
4272
4273 // Find the widest cell for each column and put it into the table
4274 if ( oSettings.aoData.length ) {
4275 for ( i=0 ; i<visibleColumns.length ; i++ ) {
4276 columnIdx = visibleColumns[i];
4277 column = columns[ columnIdx ];
4278
4279 $( _fnGetWidestNode( oSettings, columnIdx ) )
4280 .clone( false )
4281 .append( column.sContentPadding )
4282 .appendTo( tr );
4283 }
4284 }
4285
4286 // Table has been built, attach to the document so we can work with it.
4287 // A holding element is used, positioned at the top of the container
4288 // with minimal height, so it has no effect on if the container scrolls
4289 // or not. Otherwise it might trigger scrolling when it actually isn't
4290 // needed
4291 var holder = $('<div/>').css( scrollX || scrollY ?
4292 {
4293 position: 'absolute',
4294 top: 0,
4295 left: 0,
4296 height: 1,
4297 right: 0,
4298 overflow: 'hidden'
4299 } :
4300 {}
4301 )
4302 .append( tmpTable )
4303 .appendTo( tableContainer );
4304
4305 // When scrolling (X or Y) we want to set the width of the table as
4306 // appropriate. However, when not scrolling leave the table width as it
4307 // is. This results in slightly different, but I think correct behaviour
4308 if ( scrollX && scrollXInner ) {
4309 tmpTable.width( scrollXInner );
4310 }
4311 else if ( scrollX ) {
4312 tmpTable.css( 'width', 'auto' );
4313 tmpTable.removeAttr('width');
4314
4315 // If there is no width attribute or style, then allow the table to
4316 // collapse
4317 if ( tmpTable.width() < tableContainer.clientWidth && tableWidthAttr ) {
4318 tmpTable.width( tableContainer.clientWidth );
4319 }
4320 }
4321 else if ( scrollY ) {
4322 tmpTable.width( tableContainer.clientWidth );
4323 }
4324 else if ( tableWidthAttr ) {
4325 tmpTable.width( tableWidthAttr );
4326 }
4327
4328 // Get the width of each column in the constructed table - we need to
4329 // know the inner width (so it can be assigned to the other table's
4330 // cells) and the outer width so we can calculate the full width of the
4331 // table. This is safe since DataTables requires a unique cell for each
4332 // column, but if ever a header can span multiple columns, this will
4333 // need to be modified.
4334 var total = 0;
4335 for ( i=0 ; i<visibleColumns.length ; i++ ) {
4336 var cell = $(headerCells[i]);
4337 var border = cell.outerWidth() - cell.width();
4338
4339 // Use getBounding... where possible (not IE8-) because it can give
4340 // sub-pixel accuracy, which we then want to round up!
4341 var bounding = browser.bBounding ?
4342 Math.ceil( headerCells[i].getBoundingClientRect().width ) :
4343 cell.outerWidth();
4344
4345 // Total is tracked to remove any sub-pixel errors as the outerWidth
4346 // of the table might not equal the total given here (IE!).
4347 total += bounding;
4348
4349 // Width for each column to use
4350 columns[ visibleColumns[i] ].sWidth = _fnStringToCss( bounding - border );
4351 }
4352
4353 table.style.width = _fnStringToCss( total );
4354
4355 // Finished with the table - ditch it
4356 holder.remove();
4357 }
4358
4359 // If there is a width attr, we want to attach an event listener which
4360 // allows the table sizing to automatically adjust when the window is
4361 // resized. Use the width attr rather than CSS, since we can't know if the
4362 // CSS is a relative value or absolute - DOM read is always px.
4363 if ( tableWidthAttr ) {
4364 table.style.width = _fnStringToCss( tableWidthAttr );
4365 }
4366
4367 if ( (tableWidthAttr || scrollX) && ! oSettings._reszEvt ) {
4368 var bindResize = function () {
4369 $(window).bind('resize.DT-'+oSettings.sInstance, _fnThrottle( function () {
4370 _fnAdjustColumnSizing( oSettings );
4371 } ) );
4372 };
4373
4374 // IE6/7 will crash if we bind a resize event handler on page load.
4375 // To be removed in 1.11 which drops IE6/7 support
4376 if ( ie67 ) {
4377 setTimeout( bindResize, 1000 );
4378 }
4379 else {
4380 bindResize();
4381 }
4382
4383 oSettings._reszEvt = true;
4384 }
4385 }
4386
4387
4388 /**
4389 * Throttle the calls to a function. Arguments and context are maintained for
4390 * the throttled function
4391 * @param {function} fn Function to be called
4392 * @param {int} [freq=200] call frequency in mS
4393 * @returns {function} wrapped function
4394 * @memberof DataTable#oApi
4395 */
4396 function _fnThrottle( fn, freq ) {
4397 var
4398 frequency = freq !== undefined ? freq : 200,
4399 last,
4400 timer;
4401
4402 return function () {
4403 var
4404 that = this,
4405 now = +new Date(),
4406 args = arguments;
4407
4408 if ( last && now < last + frequency ) {
4409 clearTimeout( timer );
4410
4411 timer = setTimeout( function () {
4412 last = undefined;
4413 fn.apply( that, args );
4414 }, frequency );
4415 }
4416 else {
4417 last = now;
4418 fn.apply( that, args );
4419 }
4420 };
4421 }
4422
4423
4424 /**
4425 * Convert a CSS unit width to pixels (e.g. 2em)
4426 * @param {string} width width to be converted
4427 * @param {node} parent parent to get the with for (required for relative widths) - optional
4428 * @returns {int} width in pixels
4429 * @memberof DataTable#oApi
4430 */
4431 function _fnConvertToWidth ( width, parent )
4432 {
4433 if ( ! width ) {
4434 return 0;
4435 }
4436
4437 var n = $('<div/>')
4438 .css( 'width', _fnStringToCss( width ) )
4439 .appendTo( parent || document.body );
4440
4441 var val = n[0].offsetWidth;
4442 n.remove();
4443
4444 return val;
4445 }
4446
4447
4448 /**
4449 * Get the widest node
4450 * @param {object} settings dataTables settings object
4451 * @param {int} colIdx column of interest
4452 * @returns {node} widest table node
4453 * @memberof DataTable#oApi
4454 */
4455 function _fnGetWidestNode( settings, colIdx )
4456 {
4457 var idx = _fnGetMaxLenString( settings, colIdx );
4458 if ( idx < 0 ) {
4459 return null;
4460 }
4461
4462 var data = settings.aoData[ idx ];
4463 return ! data.nTr ? // Might not have been created when deferred rendering
4464 $('<td/>').html( _fnGetCellData( settings, idx, colIdx, 'display' ) )[0] :
4465 data.anCells[ colIdx ];
4466 }
4467
4468
4469 /**
4470 * Get the maximum strlen for each data column
4471 * @param {object} settings dataTables settings object
4472 * @param {int} colIdx column of interest
4473 * @returns {string} max string length for each column
4474 * @memberof DataTable#oApi
4475 */
4476 function _fnGetMaxLenString( settings, colIdx )
4477 {
4478 var s, max=-1, maxIdx = -1;
4479
4480 for ( var i=0, ien=settings.aoData.length ; i<ien ; i++ ) {
4481 s = _fnGetCellData( settings, i, colIdx, 'display' )+'';
4482 s = s.replace( __re_html_remove, '' );
4483 s = s.replace( /&nbsp;/g, ' ' );
4484
4485 if ( s.length > max ) {
4486 max = s.length;
4487 maxIdx = i;
4488 }
4489 }
4490
4491 return maxIdx;
4492 }
4493
4494
4495 /**
4496 * Append a CSS unit (only if required) to a string
4497 * @param {string} value to css-ify
4498 * @returns {string} value with css unit
4499 * @memberof DataTable#oApi
4500 */
4501 function _fnStringToCss( s )
4502 {
4503 if ( s === null ) {
4504 return '0px';
4505 }
4506
4507 if ( typeof s == 'number' ) {
4508 return s < 0 ?
4509 '0px' :
4510 s+'px';
4511 }
4512
4513 // Check it has a unit character already
4514 return s.match(/\d$/) ?
4515 s+'px' :
4516 s;
4517 }
4518
4519
4520
4521 function _fnSortFlatten ( settings )
4522 {
4523 var
4524 i, iLen, k, kLen,
4525 aSort = [],
4526 aiOrig = [],
4527 aoColumns = settings.aoColumns,
4528 aDataSort, iCol, sType, srcCol,
4529 fixed = settings.aaSortingFixed,
4530 fixedObj = $.isPlainObject( fixed ),
4531 nestedSort = [],
4532 add = function ( a ) {
4533 if ( a.length && ! $.isArray( a[0] ) ) {
4534 // 1D array
4535 nestedSort.push( a );
4536 }
4537 else {
4538 // 2D array
4539 $.merge( nestedSort, a );
4540 }
4541 };
4542
4543 // Build the sort array, with pre-fix and post-fix options if they have been
4544 // specified
4545 if ( $.isArray( fixed ) ) {
4546 add( fixed );
4547 }
4548
4549 if ( fixedObj && fixed.pre ) {
4550 add( fixed.pre );
4551 }
4552
4553 add( settings.aaSorting );
4554
4555 if (fixedObj && fixed.post ) {
4556 add( fixed.post );
4557 }
4558
4559 for ( i=0 ; i<nestedSort.length ; i++ )
4560 {
4561 srcCol = nestedSort[i][0];
4562 aDataSort = aoColumns[ srcCol ].aDataSort;
4563
4564 for ( k=0, kLen=aDataSort.length ; k<kLen ; k++ )
4565 {
4566 iCol = aDataSort[k];
4567 sType = aoColumns[ iCol ].sType || 'string';
4568
4569 if ( nestedSort[i]._idx === undefined ) {
4570 nestedSort[i]._idx = $.inArray( nestedSort[i][1], aoColumns[iCol].asSorting );
4571 }
4572
4573 aSort.push( {
4574 src: srcCol,
4575 col: iCol,
4576 dir: nestedSort[i][1],
4577 index: nestedSort[i]._idx,
4578 type: sType,
4579 formatter: DataTable.ext.type.order[ sType+"-pre" ]
4580 } );
4581 }
4582 }
4583
4584 return aSort;
4585 }
4586
4587 /**
4588 * Change the order of the table
4589 * @param {object} oSettings dataTables settings object
4590 * @memberof DataTable#oApi
4591 * @todo This really needs split up!
4592 */
4593 function _fnSort ( oSettings )
4594 {
4595 var
4596 i, ien, iLen, j, jLen, k, kLen,
4597 sDataType, nTh,
4598 aiOrig = [],
4599 oExtSort = DataTable.ext.type.order,
4600 aoData = oSettings.aoData,
4601 aoColumns = oSettings.aoColumns,
4602 aDataSort, data, iCol, sType, oSort,
4603 formatters = 0,
4604 sortCol,
4605 displayMaster = oSettings.aiDisplayMaster,
4606 aSort;
4607
4608 // Resolve any column types that are unknown due to addition or invalidation
4609 // @todo Can this be moved into a 'data-ready' handler which is called when
4610 // data is going to be used in the table?
4611 _fnColumnTypes( oSettings );
4612
4613 aSort = _fnSortFlatten( oSettings );
4614
4615 for ( i=0, ien=aSort.length ; i<ien ; i++ ) {
4616 sortCol = aSort[i];
4617
4618 // Track if we can use the fast sort algorithm
4619 if ( sortCol.formatter ) {
4620 formatters++;
4621 }
4622
4623 // Load the data needed for the sort, for each cell
4624 _fnSortData( oSettings, sortCol.col );
4625 }
4626
4627 /* No sorting required if server-side or no sorting array */
4628 if ( _fnDataSource( oSettings ) != 'ssp' && aSort.length !== 0 )
4629 {
4630 // Create a value - key array of the current row positions such that we can use their
4631 // current position during the sort, if values match, in order to perform stable sorting
4632 for ( i=0, iLen=displayMaster.length ; i<iLen ; i++ ) {
4633 aiOrig[ displayMaster[i] ] = i;
4634 }
4635
4636 /* Do the sort - here we want multi-column sorting based on a given data source (column)
4637 * and sorting function (from oSort) in a certain direction. It's reasonably complex to
4638 * follow on it's own, but this is what we want (example two column sorting):
4639 * fnLocalSorting = function(a,b){
4640 * var iTest;
4641 * iTest = oSort['string-asc']('data11', 'data12');
4642 * if (iTest !== 0)
4643 * return iTest;
4644 * iTest = oSort['numeric-desc']('data21', 'data22');
4645 * if (iTest !== 0)
4646 * return iTest;
4647 * return oSort['numeric-asc']( aiOrig[a], aiOrig[b] );
4648 * }
4649 * Basically we have a test for each sorting column, if the data in that column is equal,
4650 * test the next column. If all columns match, then we use a numeric sort on the row
4651 * positions in the original data array to provide a stable sort.
4652 *
4653 * Note - I know it seems excessive to have two sorting methods, but the first is around
4654 * 15% faster, so the second is only maintained for backwards compatibility with sorting
4655 * methods which do not have a pre-sort formatting function.
4656 */
4657 if ( formatters === aSort.length ) {
4658 // All sort types have formatting functions
4659 displayMaster.sort( function ( a, b ) {
4660 var
4661 x, y, k, test, sort,
4662 len=aSort.length,
4663 dataA = aoData[a]._aSortData,
4664 dataB = aoData[b]._aSortData;
4665
4666 for ( k=0 ; k<len ; k++ ) {
4667 sort = aSort[k];
4668
4669 x = dataA[ sort.col ];
4670 y = dataB[ sort.col ];
4671
4672 test = x<y ? -1 : x>y ? 1 : 0;
4673 if ( test !== 0 ) {
4674 return sort.dir === 'asc' ? test : -test;
4675 }
4676 }
4677
4678 x = aiOrig[a];
4679 y = aiOrig[b];
4680 return x<y ? -1 : x>y ? 1 : 0;
4681 } );
4682 }
4683 else {
4684 // Depreciated - remove in 1.11 (providing a plug-in option)
4685 // Not all sort types have formatting methods, so we have to call their sorting
4686 // methods.
4687 displayMaster.sort( function ( a, b ) {
4688 var
4689 x, y, k, l, test, sort, fn,
4690 len=aSort.length,
4691 dataA = aoData[a]._aSortData,
4692 dataB = aoData[b]._aSortData;
4693
4694 for ( k=0 ; k<len ; k++ ) {
4695 sort = aSort[k];
4696
4697 x = dataA[ sort.col ];
4698 y = dataB[ sort.col ];
4699
4700 fn = oExtSort[ sort.type+"-"+sort.dir ] || oExtSort[ "string-"+sort.dir ];
4701 test = fn( x, y );
4702 if ( test !== 0 ) {
4703 return test;
4704 }
4705 }
4706
4707 x = aiOrig[a];
4708 y = aiOrig[b];
4709 return x<y ? -1 : x>y ? 1 : 0;
4710 } );
4711 }
4712 }
4713
4714 /* Tell the draw function that we have sorted the data */
4715 oSettings.bSorted = true;
4716 }
4717
4718
4719 function _fnSortAria ( settings )
4720 {
4721 var label;
4722 var nextSort;
4723 var columns = settings.aoColumns;
4724 var aSort = _fnSortFlatten( settings );
4725 var oAria = settings.oLanguage.oAria;
4726
4727 // ARIA attributes - need to loop all columns, to update all (removing old
4728 // attributes as needed)
4729 for ( var i=0, iLen=columns.length ; i<iLen ; i++ )
4730 {
4731 var col = columns[i];
4732 var asSorting = col.asSorting;
4733 var sTitle = col.sTitle.replace( /<.*?>/g, "" );
4734 var th = col.nTh;
4735
4736 // IE7 is throwing an error when setting these properties with jQuery's
4737 // attr() and removeAttr() methods...
4738 th.removeAttribute('aria-sort');
4739
4740 /* In ARIA only the first sorting column can be marked as sorting - no multi-sort option */
4741 if ( col.bSortable ) {
4742 if ( aSort.length > 0 && aSort[0].col == i ) {
4743 th.setAttribute('aria-sort', aSort[0].dir=="asc" ? "ascending" : "descending" );
4744 nextSort = asSorting[ aSort[0].index+1 ] || asSorting[0];
4745 }
4746 else {
4747 nextSort = asSorting[0];
4748 }
4749
4750 label = sTitle + ( nextSort === "asc" ?
4751 oAria.sSortAscending :
4752 oAria.sSortDescending
4753 );
4754 }
4755 else {
4756 label = sTitle;
4757 }
4758
4759 th.setAttribute('aria-label', label);
4760 }
4761 }
4762
4763
4764 /**
4765 * Function to run on user sort request
4766 * @param {object} settings dataTables settings object
4767 * @param {node} attachTo node to attach the handler to
4768 * @param {int} colIdx column sorting index
4769 * @param {boolean} [append=false] Append the requested sort to the existing
4770 * sort if true (i.e. multi-column sort)
4771 * @param {function} [callback] callback function
4772 * @memberof DataTable#oApi
4773 */
4774 function _fnSortListener ( settings, colIdx, append, callback )
4775 {
4776 var col = settings.aoColumns[ colIdx ];
4777 var sorting = settings.aaSorting;
4778 var asSorting = col.asSorting;
4779 var nextSortIdx;
4780 var next = function ( a, overflow ) {
4781 var idx = a._idx;
4782 if ( idx === undefined ) {
4783 idx = $.inArray( a[1], asSorting );
4784 }
4785
4786 return idx+1 < asSorting.length ?
4787 idx+1 :
4788 overflow ?
4789 null :
4790 0;
4791 };
4792
4793 // Convert to 2D array if needed
4794 if ( typeof sorting[0] === 'number' ) {
4795 sorting = settings.aaSorting = [ sorting ];
4796 }
4797
4798 // If appending the sort then we are multi-column sorting
4799 if ( append && settings.oFeatures.bSortMulti ) {
4800 // Are we already doing some kind of sort on this column?
4801 var sortIdx = $.inArray( colIdx, _pluck(sorting, '0') );
4802
4803 if ( sortIdx !== -1 ) {
4804 // Yes, modify the sort
4805 nextSortIdx = next( sorting[sortIdx], true );
4806
4807 if ( nextSortIdx === null && sorting.length === 1 ) {
4808 nextSortIdx = 0; // can't remove sorting completely
4809 }
4810
4811 if ( nextSortIdx === null ) {
4812 sorting.splice( sortIdx, 1 );
4813 }
4814 else {
4815 sorting[sortIdx][1] = asSorting[ nextSortIdx ];
4816 sorting[sortIdx]._idx = nextSortIdx;
4817 }
4818 }
4819 else {
4820 // No sort on this column yet
4821 sorting.push( [ colIdx, asSorting[0], 0 ] );
4822 sorting[sorting.length-1]._idx = 0;
4823 }
4824 }
4825 else if ( sorting.length && sorting[0][0] == colIdx ) {
4826 // Single column - already sorting on this column, modify the sort
4827 nextSortIdx = next( sorting[0] );
4828
4829 sorting.length = 1;
4830 sorting[0][1] = asSorting[ nextSortIdx ];
4831 sorting[0]._idx = nextSortIdx;
4832 }
4833 else {
4834 // Single column - sort only on this column
4835 sorting.length = 0;
4836 sorting.push( [ colIdx, asSorting[0] ] );
4837 sorting[0]._idx = 0;
4838 }
4839
4840 // Run the sort by calling a full redraw
4841 _fnReDraw( settings );
4842
4843 // callback used for async user interaction
4844 if ( typeof callback == 'function' ) {
4845 callback( settings );
4846 }
4847 }
4848
4849
4850 /**
4851 * Attach a sort handler (click) to a node
4852 * @param {object} settings dataTables settings object
4853 * @param {node} attachTo node to attach the handler to
4854 * @param {int} colIdx column sorting index
4855 * @param {function} [callback] callback function
4856 * @memberof DataTable#oApi
4857 */
4858 function _fnSortAttachListener ( settings, attachTo, colIdx, callback )
4859 {
4860 var col = settings.aoColumns[ colIdx ];
4861
4862 _fnBindAction( attachTo, {}, function (e) {
4863 /* If the column is not sortable - don't to anything */
4864 if ( col.bSortable === false ) {
4865 return;
4866 }
4867
4868 // If processing is enabled use a timeout to allow the processing
4869 // display to be shown - otherwise to it synchronously
4870 if ( settings.oFeatures.bProcessing ) {
4871 _fnProcessingDisplay( settings, true );
4872
4873 setTimeout( function() {
4874 _fnSortListener( settings, colIdx, e.shiftKey, callback );
4875
4876 // In server-side processing, the draw callback will remove the
4877 // processing display
4878 if ( _fnDataSource( settings ) !== 'ssp' ) {
4879 _fnProcessingDisplay( settings, false );
4880 }
4881 }, 0 );
4882 }
4883 else {
4884 _fnSortListener( settings, colIdx, e.shiftKey, callback );
4885 }
4886 } );
4887 }
4888
4889
4890 /**
4891 * Set the sorting classes on table's body, Note: it is safe to call this function
4892 * when bSort and bSortClasses are false
4893 * @param {object} oSettings dataTables settings object
4894 * @memberof DataTable#oApi
4895 */
4896 function _fnSortingClasses( settings )
4897 {
4898 var oldSort = settings.aLastSort;
4899 var sortClass = settings.oClasses.sSortColumn;
4900 var sort = _fnSortFlatten( settings );
4901 var features = settings.oFeatures;
4902 var i, ien, colIdx;
4903
4904 if ( features.bSort && features.bSortClasses ) {
4905 // Remove old sorting classes
4906 for ( i=0, ien=oldSort.length ; i<ien ; i++ ) {
4907 colIdx = oldSort[i].src;
4908
4909 // Remove column sorting
4910 $( _pluck( settings.aoData, 'anCells', colIdx ) )
4911 .removeClass( sortClass + (i<2 ? i+1 : 3) );
4912 }
4913
4914 // Add new column sorting
4915 for ( i=0, ien=sort.length ; i<ien ; i++ ) {
4916 colIdx = sort[i].src;
4917
4918 $( _pluck( settings.aoData, 'anCells', colIdx ) )
4919 .addClass( sortClass + (i<2 ? i+1 : 3) );
4920 }
4921 }
4922
4923 settings.aLastSort = sort;
4924 }
4925
4926
4927 // Get the data to sort a column, be it from cache, fresh (populating the
4928 // cache), or from a sort formatter
4929 function _fnSortData( settings, idx )
4930 {
4931 // Custom sorting function - provided by the sort data type
4932 var column = settings.aoColumns[ idx ];
4933 var customSort = DataTable.ext.order[ column.sSortDataType ];
4934 var customData;
4935
4936 if ( customSort ) {
4937 customData = customSort.call( settings.oInstance, settings, idx,
4938 _fnColumnIndexToVisible( settings, idx )
4939 );
4940 }
4941
4942 // Use / populate cache
4943 var row, cellData;
4944 var formatter = DataTable.ext.type.order[ column.sType+"-pre" ];
4945
4946 for ( var i=0, ien=settings.aoData.length ; i<ien ; i++ ) {
4947 row = settings.aoData[i];
4948
4949 if ( ! row._aSortData ) {
4950 row._aSortData = [];
4951 }
4952
4953 if ( ! row._aSortData[idx] || customSort ) {
4954 cellData = customSort ?
4955 customData[i] : // If there was a custom sort function, use data from there
4956 _fnGetCellData( settings, i, idx, 'sort' );
4957
4958 row._aSortData[ idx ] = formatter ?
4959 formatter( cellData ) :
4960 cellData;
4961 }
4962 }
4963 }
4964
4965
4966
4967 /**
4968 * Save the state of a table
4969 * @param {object} oSettings dataTables settings object
4970 * @memberof DataTable#oApi
4971 */
4972 function _fnSaveState ( settings )
4973 {
4974 if ( !settings.oFeatures.bStateSave || settings.bDestroying )
4975 {
4976 return;
4977 }
4978
4979 /* Store the interesting variables */
4980 var state = {
4981 time: +new Date(),
4982 start: settings._iDisplayStart,
4983 length: settings._iDisplayLength,
4984 order: $.extend( true, [], settings.aaSorting ),
4985 search: _fnSearchToCamel( settings.oPreviousSearch ),
4986 columns: $.map( settings.aoColumns, function ( col, i ) {
4987 return {
4988 visible: col.bVisible,
4989 search: _fnSearchToCamel( settings.aoPreSearchCols[i] )
4990 };
4991 } )
4992 };
4993
4994 _fnCallbackFire( settings, "aoStateSaveParams", 'stateSaveParams', [settings, state] );
4995
4996 settings.oSavedState = state;
4997 settings.fnStateSaveCallback.call( settings.oInstance, settings, state );
4998 }
4999
5000
5001 /**
5002 * Attempt to load a saved table state
5003 * @param {object} oSettings dataTables settings object
5004 * @param {object} oInit DataTables init object so we can override settings
5005 * @memberof DataTable#oApi
5006 */
5007 function _fnLoadState ( settings, oInit )
5008 {
5009 var i, ien;
5010 var columns = settings.aoColumns;
5011
5012 if ( ! settings.oFeatures.bStateSave ) {
5013 return;
5014 }
5015
5016 var state = settings.fnStateLoadCallback.call( settings.oInstance, settings );
5017 if ( ! state || ! state.time ) {
5018 return;
5019 }
5020
5021 /* Allow custom and plug-in manipulation functions to alter the saved data set and
5022 * cancelling of loading by returning false
5023 */
5024 var abStateLoad = _fnCallbackFire( settings, 'aoStateLoadParams', 'stateLoadParams', [settings, state] );
5025 if ( $.inArray( false, abStateLoad ) !== -1 ) {
5026 return;
5027 }
5028
5029 /* Reject old data */
5030 var duration = settings.iStateDuration;
5031 if ( duration > 0 && state.time < +new Date() - (duration*1000) ) {
5032 return;
5033 }
5034
5035 // Number of columns have changed - all bets are off, no restore of settings
5036 if ( columns.length !== state.columns.length ) {
5037 return;
5038 }
5039
5040 // Store the saved state so it might be accessed at any time
5041 settings.oLoadedState = $.extend( true, {}, state );
5042
5043 // Restore key features - todo - for 1.11 this needs to be done by
5044 // subscribed events
5045 if ( state.start !== undefined ) {
5046 settings._iDisplayStart = state.start;
5047 settings.iInitDisplayStart = state.start;
5048 }
5049 if ( state.length !== undefined ) {
5050 settings._iDisplayLength = state.length;
5051 }
5052
5053 // Order
5054 if ( state.order !== undefined ) {
5055 settings.aaSorting = [];
5056 $.each( state.order, function ( i, col ) {
5057 settings.aaSorting.push( col[0] >= columns.length ?
5058 [ 0, col[1] ] :
5059 col
5060 );
5061 } );
5062 }
5063
5064 // Search
5065 if ( state.search !== undefined ) {
5066 $.extend( settings.oPreviousSearch, _fnSearchToHung( state.search ) );
5067 }
5068
5069 // Columns
5070 for ( i=0, ien=state.columns.length ; i<ien ; i++ ) {
5071 var col = state.columns[i];
5072
5073 // Visibility
5074 if ( col.visible !== undefined ) {
5075 columns[i].bVisible = col.visible;
5076 }
5077
5078 // Search
5079 if ( col.search !== undefined ) {
5080 $.extend( settings.aoPreSearchCols[i], _fnSearchToHung( col.search ) );
5081 }
5082 }
5083
5084 _fnCallbackFire( settings, 'aoStateLoaded', 'stateLoaded', [settings, state] );
5085 }
5086
5087
5088 /**
5089 * Return the settings object for a particular table
5090 * @param {node} table table we are using as a dataTable
5091 * @returns {object} Settings object - or null if not found
5092 * @memberof DataTable#oApi
5093 */
5094 function _fnSettingsFromNode ( table )
5095 {
5096 var settings = DataTable.settings;
5097 var idx = $.inArray( table, _pluck( settings, 'nTable' ) );
5098
5099 return idx !== -1 ?
5100 settings[ idx ] :
5101 null;
5102 }
5103
5104
5105 /**
5106 * Log an error message
5107 * @param {object} settings dataTables settings object
5108 * @param {int} level log error messages, or display them to the user
5109 * @param {string} msg error message
5110 * @param {int} tn Technical note id to get more information about the error.
5111 * @memberof DataTable#oApi
5112 */
5113 function _fnLog( settings, level, msg, tn )
5114 {
5115 msg = 'DataTables warning: '+
5116 (settings ? 'table id='+settings.sTableId+' - ' : '')+msg;
5117
5118 if ( tn ) {
5119 msg += '. For more information about this error, please see '+
5120 'http://datatables.net/tn/'+tn;
5121 }
5122
5123 if ( ! level ) {
5124 // Backwards compatibility pre 1.10
5125 var ext = DataTable.ext;
5126 var type = ext.sErrMode || ext.errMode;
5127
5128 if ( settings ) {
5129 _fnCallbackFire( settings, null, 'error', [ settings, tn, msg ] );
5130 }
5131
5132 if ( type == 'alert' ) {
5133 alert( msg );
5134 }
5135 else if ( type == 'throw' ) {
5136 throw new Error(msg);
5137 }
5138 else if ( typeof type == 'function' ) {
5139 type( settings, tn, msg );
5140 }
5141 }
5142 else if ( window.console && console.log ) {
5143 console.log( msg );
5144 }
5145 }
5146
5147
5148 /**
5149 * See if a property is defined on one object, if so assign it to the other object
5150 * @param {object} ret target object
5151 * @param {object} src source object
5152 * @param {string} name property
5153 * @param {string} [mappedName] name to map too - optional, name used if not given
5154 * @memberof DataTable#oApi
5155 */
5156 function _fnMap( ret, src, name, mappedName )
5157 {
5158 if ( $.isArray( name ) ) {
5159 $.each( name, function (i, val) {
5160 if ( $.isArray( val ) ) {
5161 _fnMap( ret, src, val[0], val[1] );
5162 }
5163 else {
5164 _fnMap( ret, src, val );
5165 }
5166 } );
5167
5168 return;
5169 }
5170
5171 if ( mappedName === undefined ) {
5172 mappedName = name;
5173 }
5174
5175 if ( src[name] !== undefined ) {
5176 ret[mappedName] = src[name];
5177 }
5178 }
5179
5180
5181 /**
5182 * Extend objects - very similar to jQuery.extend, but deep copy objects, and
5183 * shallow copy arrays. The reason we need to do this, is that we don't want to
5184 * deep copy array init values (such as aaSorting) since the dev wouldn't be
5185 * able to override them, but we do want to deep copy arrays.
5186 * @param {object} out Object to extend
5187 * @param {object} extender Object from which the properties will be applied to
5188 * out
5189 * @param {boolean} breakRefs If true, then arrays will be sliced to take an
5190 * independent copy with the exception of the `data` or `aaData` parameters
5191 * if they are present. This is so you can pass in a collection to
5192 * DataTables and have that used as your data source without breaking the
5193 * references
5194 * @returns {object} out Reference, just for convenience - out === the return.
5195 * @memberof DataTable#oApi
5196 * @todo This doesn't take account of arrays inside the deep copied objects.
5197 */
5198 function _fnExtend( out, extender, breakRefs )
5199 {
5200 var val;
5201
5202 for ( var prop in extender ) {
5203 if ( extender.hasOwnProperty(prop) ) {
5204 val = extender[prop];
5205
5206 if ( $.isPlainObject( val ) ) {
5207 if ( ! $.isPlainObject( out[prop] ) ) {
5208 out[prop] = {};
5209 }
5210 $.extend( true, out[prop], val );
5211 }
5212 else if ( breakRefs && prop !== 'data' && prop !== 'aaData' && $.isArray(val) ) {
5213 out[prop] = val.slice();
5214 }
5215 else {
5216 out[prop] = val;
5217 }
5218 }
5219 }
5220
5221 return out;
5222 }
5223
5224
5225 /**
5226 * Bind an event handers to allow a click or return key to activate the callback.
5227 * This is good for accessibility since a return on the keyboard will have the
5228 * same effect as a click, if the element has focus.
5229 * @param {element} n Element to bind the action to
5230 * @param {object} oData Data object to pass to the triggered function
5231 * @param {function} fn Callback function for when the event is triggered
5232 * @memberof DataTable#oApi
5233 */
5234 function _fnBindAction( n, oData, fn )
5235 {
5236 $(n)
5237 .bind( 'click.DT', oData, function (e) {
5238 n.blur(); // Remove focus outline for mouse users
5239 fn(e);
5240 } )
5241 .bind( 'keypress.DT', oData, function (e){
5242 if ( e.which === 13 ) {
5243 e.preventDefault();
5244 fn(e);
5245 }
5246 } )
5247 .bind( 'selectstart.DT', function () {
5248 /* Take the brutal approach to cancelling text selection */
5249 return false;
5250 } );
5251 }
5252
5253
5254 /**
5255 * Register a callback function. Easily allows a callback function to be added to
5256 * an array store of callback functions that can then all be called together.
5257 * @param {object} oSettings dataTables settings object
5258 * @param {string} sStore Name of the array storage for the callbacks in oSettings
5259 * @param {function} fn Function to be called back
5260 * @param {string} sName Identifying name for the callback (i.e. a label)
5261 * @memberof DataTable#oApi
5262 */
5263 function _fnCallbackReg( oSettings, sStore, fn, sName )
5264 {
5265 if ( fn )
5266 {
5267 oSettings[sStore].push( {
5268 "fn": fn,
5269 "sName": sName
5270 } );
5271 }
5272 }
5273
5274
5275 /**
5276 * Fire callback functions and trigger events. Note that the loop over the
5277 * callback array store is done backwards! Further note that you do not want to
5278 * fire off triggers in time sensitive applications (for example cell creation)
5279 * as its slow.
5280 * @param {object} settings dataTables settings object
5281 * @param {string} callbackArr Name of the array storage for the callbacks in
5282 * oSettings
5283 * @param {string} eventName Name of the jQuery custom event to trigger. If
5284 * null no trigger is fired
5285 * @param {array} args Array of arguments to pass to the callback function /
5286 * trigger
5287 * @memberof DataTable#oApi
5288 */
5289 function _fnCallbackFire( settings, callbackArr, eventName, args )
5290 {
5291 var ret = [];
5292
5293 if ( callbackArr ) {
5294 ret = $.map( settings[callbackArr].slice().reverse(), function (val, i) {
5295 return val.fn.apply( settings.oInstance, args );
5296 } );
5297 }
5298
5299 if ( eventName !== null ) {
5300 var e = $.Event( eventName+'.dt' );
5301
5302 $(settings.nTable).trigger( e, args );
5303
5304 ret.push( e.result );
5305 }
5306
5307 return ret;
5308 }
5309
5310
5311 function _fnLengthOverflow ( settings )
5312 {
5313 var
5314 start = settings._iDisplayStart,
5315 end = settings.fnDisplayEnd(),
5316 len = settings._iDisplayLength;
5317
5318 /* If we have space to show extra rows (backing up from the end point - then do so */
5319 if ( start >= end )
5320 {
5321 start = end - len;
5322 }
5323
5324 // Keep the start record on the current page
5325 start -= (start % len);
5326
5327 if ( len === -1 || start < 0 )
5328 {
5329 start = 0;
5330 }
5331
5332 settings._iDisplayStart = start;
5333 }
5334
5335
5336 function _fnRenderer( settings, type )
5337 {
5338 var renderer = settings.renderer;
5339 var host = DataTable.ext.renderer[type];
5340
5341 if ( $.isPlainObject( renderer ) && renderer[type] ) {
5342 // Specific renderer for this type. If available use it, otherwise use
5343 // the default.
5344 return host[renderer[type]] || host._;
5345 }
5346 else if ( typeof renderer === 'string' ) {
5347 // Common renderer - if there is one available for this type use it,
5348 // otherwise use the default
5349 return host[renderer] || host._;
5350 }
5351
5352 // Use the default
5353 return host._;
5354 }
5355
5356
5357 /**
5358 * Detect the data source being used for the table. Used to simplify the code
5359 * a little (ajax) and to make it compress a little smaller.
5360 *
5361 * @param {object} settings dataTables settings object
5362 * @returns {string} Data source
5363 * @memberof DataTable#oApi
5364 */
5365 function _fnDataSource ( settings )
5366 {
5367 if ( settings.oFeatures.bServerSide ) {
5368 return 'ssp';
5369 }
5370 else if ( settings.ajax || settings.sAjaxSource ) {
5371 return 'ajax';
5372 }
5373 return 'dom';
5374 }
5375
5376
5377 DataTable = function( options )
5378 {
5379 /**
5380 * Perform a jQuery selector action on the table's TR elements (from the tbody) and
5381 * return the resulting jQuery object.
5382 * @param {string|node|jQuery} sSelector jQuery selector or node collection to act on
5383 * @param {object} [oOpts] Optional parameters for modifying the rows to be included
5384 * @param {string} [oOpts.filter=none] Select TR elements that meet the current filter
5385 * criterion ("applied") or all TR elements (i.e. no filter).
5386 * @param {string} [oOpts.order=current] Order of the TR elements in the processed array.
5387 * Can be either 'current', whereby the current sorting of the table is used, or
5388 * 'original' whereby the original order the data was read into the table is used.
5389 * @param {string} [oOpts.page=all] Limit the selection to the currently displayed page
5390 * ("current") or not ("all"). If 'current' is given, then order is assumed to be
5391 * 'current' and filter is 'applied', regardless of what they might be given as.
5392 * @returns {object} jQuery object, filtered by the given selector.
5393 * @dtopt API
5394 * @deprecated Since v1.10
5395 *
5396 * @example
5397 * $(document).ready(function() {
5398 * var oTable = $('#example').dataTable();
5399 *
5400 * // Highlight every second row
5401 * oTable.$('tr:odd').css('backgroundColor', 'blue');
5402 * } );
5403 *
5404 * @example
5405 * $(document).ready(function() {
5406 * var oTable = $('#example').dataTable();
5407 *
5408 * // Filter to rows with 'Webkit' in them, add a background colour and then
5409 * // remove the filter, thus highlighting the 'Webkit' rows only.
5410 * oTable.fnFilter('Webkit');
5411 * oTable.$('tr', {"search": "applied"}).css('backgroundColor', 'blue');
5412 * oTable.fnFilter('');
5413 * } );
5414 */
5415 this.$ = function ( sSelector, oOpts )
5416 {
5417 return this.api(true).$( sSelector, oOpts );
5418 };
5419
5420
5421 /**
5422 * Almost identical to $ in operation, but in this case returns the data for the matched
5423 * rows - as such, the jQuery selector used should match TR row nodes or TD/TH cell nodes
5424 * rather than any descendants, so the data can be obtained for the row/cell. If matching
5425 * rows are found, the data returned is the original data array/object that was used to
5426 * create the row (or a generated array if from a DOM source).
5427 *
5428 * This method is often useful in-combination with $ where both functions are given the
5429 * same parameters and the array indexes will match identically.
5430 * @param {string|node|jQuery} sSelector jQuery selector or node collection to act on
5431 * @param {object} [oOpts] Optional parameters for modifying the rows to be included
5432 * @param {string} [oOpts.filter=none] Select elements that meet the current filter
5433 * criterion ("applied") or all elements (i.e. no filter).
5434 * @param {string} [oOpts.order=current] Order of the data in the processed array.
5435 * Can be either 'current', whereby the current sorting of the table is used, or
5436 * 'original' whereby the original order the data was read into the table is used.
5437 * @param {string} [oOpts.page=all] Limit the selection to the currently displayed page
5438 * ("current") or not ("all"). If 'current' is given, then order is assumed to be
5439 * 'current' and filter is 'applied', regardless of what they might be given as.
5440 * @returns {array} Data for the matched elements. If any elements, as a result of the
5441 * selector, were not TR, TD or TH elements in the DataTable, they will have a null
5442 * entry in the array.
5443 * @dtopt API
5444 * @deprecated Since v1.10
5445 *
5446 * @example
5447 * $(document).ready(function() {
5448 * var oTable = $('#example').dataTable();
5449 *
5450 * // Get the data from the first row in the table
5451 * var data = oTable._('tr:first');
5452 *
5453 * // Do something useful with the data
5454 * alert( "First cell is: "+data[0] );
5455 * } );
5456 *
5457 * @example
5458 * $(document).ready(function() {
5459 * var oTable = $('#example').dataTable();
5460 *
5461 * // Filter to 'Webkit' and get all data for
5462 * oTable.fnFilter('Webkit');
5463 * var data = oTable._('tr', {"search": "applied"});
5464 *
5465 * // Do something with the data
5466 * alert( data.length+" rows matched the search" );
5467 * } );
5468 */
5469 this._ = function ( sSelector, oOpts )
5470 {
5471 return this.api(true).rows( sSelector, oOpts ).data();
5472 };
5473
5474
5475 /**
5476 * Create a DataTables Api instance, with the currently selected tables for
5477 * the Api's context.
5478 * @param {boolean} [traditional=false] Set the API instance's context to be
5479 * only the table referred to by the `DataTable.ext.iApiIndex` option, as was
5480 * used in the API presented by DataTables 1.9- (i.e. the traditional mode),
5481 * or if all tables captured in the jQuery object should be used.
5482 * @return {DataTables.Api}
5483 */
5484 this.api = function ( traditional )
5485 {
5486 return traditional ?
5487 new _Api(
5488 _fnSettingsFromNode( this[ _ext.iApiIndex ] )
5489 ) :
5490 new _Api( this );
5491 };
5492
5493
5494 /**
5495 * Add a single new row or multiple rows of data to the table. Please note
5496 * that this is suitable for client-side processing only - if you are using
5497 * server-side processing (i.e. "bServerSide": true), then to add data, you
5498 * must add it to the data source, i.e. the server-side, through an Ajax call.
5499 * @param {array|object} data The data to be added to the table. This can be:
5500 * <ul>
5501 * <li>1D array of data - add a single row with the data provided</li>
5502 * <li>2D array of arrays - add multiple rows in a single call</li>
5503 * <li>object - data object when using <i>mData</i></li>
5504 * <li>array of objects - multiple data objects when using <i>mData</i></li>
5505 * </ul>
5506 * @param {bool} [redraw=true] redraw the table or not
5507 * @returns {array} An array of integers, representing the list of indexes in
5508 * <i>aoData</i> ({@link DataTable.models.oSettings}) that have been added to
5509 * the table.
5510 * @dtopt API
5511 * @deprecated Since v1.10
5512 *
5513 * @example
5514 * // Global var for counter
5515 * var giCount = 2;
5516 *
5517 * $(document).ready(function() {
5518 * $('#example').dataTable();
5519 * } );
5520 *
5521 * function fnClickAddRow() {
5522 * $('#example').dataTable().fnAddData( [
5523 * giCount+".1",
5524 * giCount+".2",
5525 * giCount+".3",
5526 * giCount+".4" ]
5527 * );
5528 *
5529 * giCount++;
5530 * }
5531 */
5532 this.fnAddData = function( data, redraw )
5533 {
5534 var api = this.api( true );
5535
5536 /* Check if we want to add multiple rows or not */
5537 var rows = $.isArray(data) && ( $.isArray(data[0]) || $.isPlainObject(data[0]) ) ?
5538 api.rows.add( data ) :
5539 api.row.add( data );
5540
5541 if ( redraw === undefined || redraw ) {
5542 api.draw();
5543 }
5544
5545 return rows.flatten().toArray();
5546 };
5547
5548
5549 /**
5550 * This function will make DataTables recalculate the column sizes, based on the data
5551 * contained in the table and the sizes applied to the columns (in the DOM, CSS or
5552 * through the sWidth parameter). This can be useful when the width of the table's
5553 * parent element changes (for example a window resize).
5554 * @param {boolean} [bRedraw=true] Redraw the table or not, you will typically want to
5555 * @dtopt API
5556 * @deprecated Since v1.10
5557 *
5558 * @example
5559 * $(document).ready(function() {
5560 * var oTable = $('#example').dataTable( {
5561 * "sScrollY": "200px",
5562 * "bPaginate": false
5563 * } );
5564 *
5565 * $(window).bind('resize', function () {
5566 * oTable.fnAdjustColumnSizing();
5567 * } );
5568 * } );
5569 */
5570 this.fnAdjustColumnSizing = function ( bRedraw )
5571 {
5572 var api = this.api( true ).columns.adjust();
5573 var settings = api.settings()[0];
5574 var scroll = settings.oScroll;
5575
5576 if ( bRedraw === undefined || bRedraw ) {
5577 api.draw( false );
5578 }
5579 else if ( scroll.sX !== "" || scroll.sY !== "" ) {
5580 /* If not redrawing, but scrolling, we want to apply the new column sizes anyway */
5581 _fnScrollDraw( settings );
5582 }
5583 };
5584
5585
5586 /**
5587 * Quickly and simply clear a table
5588 * @param {bool} [bRedraw=true] redraw the table or not
5589 * @dtopt API
5590 * @deprecated Since v1.10
5591 *
5592 * @example
5593 * $(document).ready(function() {
5594 * var oTable = $('#example').dataTable();
5595 *
5596 * // Immediately 'nuke' the current rows (perhaps waiting for an Ajax callback...)
5597 * oTable.fnClearTable();
5598 * } );
5599 */
5600 this.fnClearTable = function( bRedraw )
5601 {
5602 var api = this.api( true ).clear();
5603
5604 if ( bRedraw === undefined || bRedraw ) {
5605 api.draw();
5606 }
5607 };
5608
5609
5610 /**
5611 * The exact opposite of 'opening' a row, this function will close any rows which
5612 * are currently 'open'.
5613 * @param {node} nTr the table row to 'close'
5614 * @returns {int} 0 on success, or 1 if failed (can't find the row)
5615 * @dtopt API
5616 * @deprecated Since v1.10
5617 *
5618 * @example
5619 * $(document).ready(function() {
5620 * var oTable;
5621 *
5622 * // 'open' an information row when a row is clicked on
5623 * $('#example tbody tr').click( function () {
5624 * if ( oTable.fnIsOpen(this) ) {
5625 * oTable.fnClose( this );
5626 * } else {
5627 * oTable.fnOpen( this, "Temporary row opened", "info_row" );
5628 * }
5629 * } );
5630 *
5631 * oTable = $('#example').dataTable();
5632 * } );
5633 */
5634 this.fnClose = function( nTr )
5635 {
5636 this.api( true ).row( nTr ).child.hide();
5637 };
5638
5639
5640 /**
5641 * Remove a row for the table
5642 * @param {mixed} target The index of the row from aoData to be deleted, or
5643 * the TR element you want to delete
5644 * @param {function|null} [callBack] Callback function
5645 * @param {bool} [redraw=true] Redraw the table or not
5646 * @returns {array} The row that was deleted
5647 * @dtopt API
5648 * @deprecated Since v1.10
5649 *
5650 * @example
5651 * $(document).ready(function() {
5652 * var oTable = $('#example').dataTable();
5653 *
5654 * // Immediately remove the first row
5655 * oTable.fnDeleteRow( 0 );
5656 * } );
5657 */
5658 this.fnDeleteRow = function( target, callback, redraw )
5659 {
5660 var api = this.api( true );
5661 var rows = api.rows( target );
5662 var settings = rows.settings()[0];
5663 var data = settings.aoData[ rows[0][0] ];
5664
5665 rows.remove();
5666
5667 if ( callback ) {
5668 callback.call( this, settings, data );
5669 }
5670
5671 if ( redraw === undefined || redraw ) {
5672 api.draw();
5673 }
5674
5675 return data;
5676 };
5677
5678
5679 /**
5680 * Restore the table to it's original state in the DOM by removing all of DataTables
5681 * enhancements, alterations to the DOM structure of the table and event listeners.
5682 * @param {boolean} [remove=false] Completely remove the table from the DOM
5683 * @dtopt API
5684 * @deprecated Since v1.10
5685 *
5686 * @example
5687 * $(document).ready(function() {
5688 * // This example is fairly pointless in reality, but shows how fnDestroy can be used
5689 * var oTable = $('#example').dataTable();
5690 * oTable.fnDestroy();
5691 * } );
5692 */
5693 this.fnDestroy = function ( remove )
5694 {
5695 this.api( true ).destroy( remove );
5696 };
5697
5698
5699 /**
5700 * Redraw the table
5701 * @param {bool} [complete=true] Re-filter and resort (if enabled) the table before the draw.
5702 * @dtopt API
5703 * @deprecated Since v1.10
5704 *
5705 * @example
5706 * $(document).ready(function() {
5707 * var oTable = $('#example').dataTable();
5708 *
5709 * // Re-draw the table - you wouldn't want to do it here, but it's an example :-)
5710 * oTable.fnDraw();
5711 * } );
5712 */
5713 this.fnDraw = function( complete )
5714 {
5715 // Note that this isn't an exact match to the old call to _fnDraw - it takes
5716 // into account the new data, but can hold position.
5717 this.api( true ).draw( complete );
5718 };
5719
5720
5721 /**
5722 * Filter the input based on data
5723 * @param {string} sInput String to filter the table on
5724 * @param {int|null} [iColumn] Column to limit filtering to
5725 * @param {bool} [bRegex=false] Treat as regular expression or not
5726 * @param {bool} [bSmart=true] Perform smart filtering or not
5727 * @param {bool} [bShowGlobal=true] Show the input global filter in it's input box(es)
5728 * @param {bool} [bCaseInsensitive=true] Do case-insensitive matching (true) or not (false)
5729 * @dtopt API
5730 * @deprecated Since v1.10
5731 *
5732 * @example
5733 * $(document).ready(function() {
5734 * var oTable = $('#example').dataTable();
5735 *
5736 * // Sometime later - filter...
5737 * oTable.fnFilter( 'test string' );
5738 * } );
5739 */
5740 this.fnFilter = function( sInput, iColumn, bRegex, bSmart, bShowGlobal, bCaseInsensitive )
5741 {
5742 var api = this.api( true );
5743
5744 if ( iColumn === null || iColumn === undefined ) {
5745 api.search( sInput, bRegex, bSmart, bCaseInsensitive );
5746 }
5747 else {
5748 api.column( iColumn ).search( sInput, bRegex, bSmart, bCaseInsensitive );
5749 }
5750
5751 api.draw();
5752 };
5753
5754
5755 /**
5756 * Get the data for the whole table, an individual row or an individual cell based on the
5757 * provided parameters.
5758 * @param {int|node} [src] A TR row node, TD/TH cell node or an integer. If given as
5759 * a TR node then the data source for the whole row will be returned. If given as a
5760 * TD/TH cell node then iCol will be automatically calculated and the data for the
5761 * cell returned. If given as an integer, then this is treated as the aoData internal
5762 * data index for the row (see fnGetPosition) and the data for that row used.
5763 * @param {int} [col] Optional column index that you want the data of.
5764 * @returns {array|object|string} If mRow is undefined, then the data for all rows is
5765 * returned. If mRow is defined, just data for that row, and is iCol is
5766 * defined, only data for the designated cell is returned.
5767 * @dtopt API
5768 * @deprecated Since v1.10
5769 *
5770 * @example
5771 * // Row data
5772 * $(document).ready(function() {
5773 * oTable = $('#example').dataTable();
5774 *
5775 * oTable.$('tr').click( function () {
5776 * var data = oTable.fnGetData( this );
5777 * // ... do something with the array / object of data for the row
5778 * } );
5779 * } );
5780 *
5781 * @example
5782 * // Individual cell data
5783 * $(document).ready(function() {
5784 * oTable = $('#example').dataTable();
5785 *
5786 * oTable.$('td').click( function () {
5787 * var sData = oTable.fnGetData( this );
5788 * alert( 'The cell clicked on had the value of '+sData );
5789 * } );
5790 * } );
5791 */
5792 this.fnGetData = function( src, col )
5793 {
5794 var api = this.api( true );
5795
5796 if ( src !== undefined ) {
5797 var type = src.nodeName ? src.nodeName.toLowerCase() : '';
5798
5799 return col !== undefined || type == 'td' || type == 'th' ?
5800 api.cell( src, col ).data() :
5801 api.row( src ).data() || null;
5802 }
5803
5804 return api.data().toArray();
5805 };
5806
5807
5808 /**
5809 * Get an array of the TR nodes that are used in the table's body. Note that you will
5810 * typically want to use the '$' API method in preference to this as it is more
5811 * flexible.
5812 * @param {int} [iRow] Optional row index for the TR element you want
5813 * @returns {array|node} If iRow is undefined, returns an array of all TR elements
5814 * in the table's body, or iRow is defined, just the TR element requested.
5815 * @dtopt API
5816 * @deprecated Since v1.10
5817 *
5818 * @example
5819 * $(document).ready(function() {
5820 * var oTable = $('#example').dataTable();
5821 *
5822 * // Get the nodes from the table
5823 * var nNodes = oTable.fnGetNodes( );
5824 * } );
5825 */
5826 this.fnGetNodes = function( iRow )
5827 {
5828 var api = this.api( true );
5829
5830 return iRow !== undefined ?
5831 api.row( iRow ).node() :
5832 api.rows().nodes().flatten().toArray();
5833 };
5834
5835
5836 /**
5837 * Get the array indexes of a particular cell from it's DOM element
5838 * and column index including hidden columns
5839 * @param {node} node this can either be a TR, TD or TH in the table's body
5840 * @returns {int} If nNode is given as a TR, then a single index is returned, or
5841 * if given as a cell, an array of [row index, column index (visible),
5842 * column index (all)] is given.
5843 * @dtopt API
5844 * @deprecated Since v1.10
5845 *
5846 * @example
5847 * $(document).ready(function() {
5848 * $('#example tbody td').click( function () {
5849 * // Get the position of the current data from the node
5850 * var aPos = oTable.fnGetPosition( this );
5851 *
5852 * // Get the data array for this row
5853 * var aData = oTable.fnGetData( aPos[0] );
5854 *
5855 * // Update the data array and return the value
5856 * aData[ aPos[1] ] = 'clicked';
5857 * this.innerHTML = 'clicked';
5858 * } );
5859 *
5860 * // Init DataTables
5861 * oTable = $('#example').dataTable();
5862 * } );
5863 */
5864 this.fnGetPosition = function( node )
5865 {
5866 var api = this.api( true );
5867 var nodeName = node.nodeName.toUpperCase();
5868
5869 if ( nodeName == 'TR' ) {
5870 return api.row( node ).index();
5871 }
5872 else if ( nodeName == 'TD' || nodeName == 'TH' ) {
5873 var cell = api.cell( node ).index();
5874
5875 return [
5876 cell.row,
5877 cell.columnVisible,
5878 cell.column
5879 ];
5880 }
5881 return null;
5882 };
5883
5884
5885 /**
5886 * Check to see if a row is 'open' or not.
5887 * @param {node} nTr the table row to check
5888 * @returns {boolean} true if the row is currently open, false otherwise
5889 * @dtopt API
5890 * @deprecated Since v1.10
5891 *
5892 * @example
5893 * $(document).ready(function() {
5894 * var oTable;
5895 *
5896 * // 'open' an information row when a row is clicked on
5897 * $('#example tbody tr').click( function () {
5898 * if ( oTable.fnIsOpen(this) ) {
5899 * oTable.fnClose( this );
5900 * } else {
5901 * oTable.fnOpen( this, "Temporary row opened", "info_row" );
5902 * }
5903 * } );
5904 *
5905 * oTable = $('#example').dataTable();
5906 * } );
5907 */
5908 this.fnIsOpen = function( nTr )
5909 {
5910 return this.api( true ).row( nTr ).child.isShown();
5911 };
5912
5913
5914 /**
5915 * This function will place a new row directly after a row which is currently
5916 * on display on the page, with the HTML contents that is passed into the
5917 * function. This can be used, for example, to ask for confirmation that a
5918 * particular record should be deleted.
5919 * @param {node} nTr The table row to 'open'
5920 * @param {string|node|jQuery} mHtml The HTML to put into the row
5921 * @param {string} sClass Class to give the new TD cell
5922 * @returns {node} The row opened. Note that if the table row passed in as the
5923 * first parameter, is not found in the table, this method will silently
5924 * return.
5925 * @dtopt API
5926 * @deprecated Since v1.10
5927 *
5928 * @example
5929 * $(document).ready(function() {
5930 * var oTable;
5931 *
5932 * // 'open' an information row when a row is clicked on
5933 * $('#example tbody tr').click( function () {
5934 * if ( oTable.fnIsOpen(this) ) {
5935 * oTable.fnClose( this );
5936 * } else {
5937 * oTable.fnOpen( this, "Temporary row opened", "info_row" );
5938 * }
5939 * } );
5940 *
5941 * oTable = $('#example').dataTable();
5942 * } );
5943 */
5944 this.fnOpen = function( nTr, mHtml, sClass )
5945 {
5946 return this.api( true )
5947 .row( nTr )
5948 .child( mHtml, sClass )
5949 .show()
5950 .child()[0];
5951 };
5952
5953
5954 /**
5955 * Change the pagination - provides the internal logic for pagination in a simple API
5956 * function. With this function you can have a DataTables table go to the next,
5957 * previous, first or last pages.
5958 * @param {string|int} mAction Paging action to take: "first", "previous", "next" or "last"
5959 * or page number to jump to (integer), note that page 0 is the first page.
5960 * @param {bool} [bRedraw=true] Redraw the table or not
5961 * @dtopt API
5962 * @deprecated Since v1.10
5963 *
5964 * @example
5965 * $(document).ready(function() {
5966 * var oTable = $('#example').dataTable();
5967 * oTable.fnPageChange( 'next' );
5968 * } );
5969 */
5970 this.fnPageChange = function ( mAction, bRedraw )
5971 {
5972 var api = this.api( true ).page( mAction );
5973
5974 if ( bRedraw === undefined || bRedraw ) {
5975 api.draw(false);
5976 }
5977 };
5978
5979
5980 /**
5981 * Show a particular column
5982 * @param {int} iCol The column whose display should be changed
5983 * @param {bool} bShow Show (true) or hide (false) the column
5984 * @param {bool} [bRedraw=true] Redraw the table or not
5985 * @dtopt API
5986 * @deprecated Since v1.10
5987 *
5988 * @example
5989 * $(document).ready(function() {
5990 * var oTable = $('#example').dataTable();
5991 *
5992 * // Hide the second column after initialisation
5993 * oTable.fnSetColumnVis( 1, false );
5994 * } );
5995 */
5996 this.fnSetColumnVis = function ( iCol, bShow, bRedraw )
5997 {
5998 var api = this.api( true ).column( iCol ).visible( bShow );
5999
6000 if ( bRedraw === undefined || bRedraw ) {
6001 api.columns.adjust().draw();
6002 }
6003 };
6004
6005
6006 /**
6007 * Get the settings for a particular table for external manipulation
6008 * @returns {object} DataTables settings object. See
6009 * {@link DataTable.models.oSettings}
6010 * @dtopt API
6011 * @deprecated Since v1.10
6012 *
6013 * @example
6014 * $(document).ready(function() {
6015 * var oTable = $('#example').dataTable();
6016 * var oSettings = oTable.fnSettings();
6017 *
6018 * // Show an example parameter from the settings
6019 * alert( oSettings._iDisplayStart );
6020 * } );
6021 */
6022 this.fnSettings = function()
6023 {
6024 return _fnSettingsFromNode( this[_ext.iApiIndex] );
6025 };
6026
6027
6028 /**
6029 * Sort the table by a particular column
6030 * @param {int} iCol the data index to sort on. Note that this will not match the
6031 * 'display index' if you have hidden data entries
6032 * @dtopt API
6033 * @deprecated Since v1.10
6034 *
6035 * @example
6036 * $(document).ready(function() {
6037 * var oTable = $('#example').dataTable();
6038 *
6039 * // Sort immediately with columns 0 and 1
6040 * oTable.fnSort( [ [0,'asc'], [1,'asc'] ] );
6041 * } );
6042 */
6043 this.fnSort = function( aaSort )
6044 {
6045 this.api( true ).order( aaSort ).draw();
6046 };
6047
6048
6049 /**
6050 * Attach a sort listener to an element for a given column
6051 * @param {node} nNode the element to attach the sort listener to
6052 * @param {int} iColumn the column that a click on this node will sort on
6053 * @param {function} [fnCallback] callback function when sort is run
6054 * @dtopt API
6055 * @deprecated Since v1.10
6056 *
6057 * @example
6058 * $(document).ready(function() {
6059 * var oTable = $('#example').dataTable();
6060 *
6061 * // Sort on column 1, when 'sorter' is clicked on
6062 * oTable.fnSortListener( document.getElementById('sorter'), 1 );
6063 * } );
6064 */
6065 this.fnSortListener = function( nNode, iColumn, fnCallback )
6066 {
6067 this.api( true ).order.listener( nNode, iColumn, fnCallback );
6068 };
6069
6070
6071 /**
6072 * Update a table cell or row - this method will accept either a single value to
6073 * update the cell with, an array of values with one element for each column or
6074 * an object in the same format as the original data source. The function is
6075 * self-referencing in order to make the multi column updates easier.
6076 * @param {object|array|string} mData Data to update the cell/row with
6077 * @param {node|int} mRow TR element you want to update or the aoData index
6078 * @param {int} [iColumn] The column to update, give as null or undefined to
6079 * update a whole row.
6080 * @param {bool} [bRedraw=true] Redraw the table or not
6081 * @param {bool} [bAction=true] Perform pre-draw actions or not
6082 * @returns {int} 0 on success, 1 on error
6083 * @dtopt API
6084 * @deprecated Since v1.10
6085 *
6086 * @example
6087 * $(document).ready(function() {
6088 * var oTable = $('#example').dataTable();
6089 * oTable.fnUpdate( 'Example update', 0, 0 ); // Single cell
6090 * oTable.fnUpdate( ['a', 'b', 'c', 'd', 'e'], $('tbody tr')[0] ); // Row
6091 * } );
6092 */
6093 this.fnUpdate = function( mData, mRow, iColumn, bRedraw, bAction )
6094 {
6095 var api = this.api( true );
6096
6097 if ( iColumn === undefined || iColumn === null ) {
6098 api.row( mRow ).data( mData );
6099 }
6100 else {
6101 api.cell( mRow, iColumn ).data( mData );
6102 }
6103
6104 if ( bAction === undefined || bAction ) {
6105 api.columns.adjust();
6106 }
6107
6108 if ( bRedraw === undefined || bRedraw ) {
6109 api.draw();
6110 }
6111 return 0;
6112 };
6113
6114
6115 /**
6116 * Provide a common method for plug-ins to check the version of DataTables being used, in order
6117 * to ensure compatibility.
6118 * @param {string} sVersion Version string to check for, in the format "X.Y.Z". Note that the
6119 * formats "X" and "X.Y" are also acceptable.
6120 * @returns {boolean} true if this version of DataTables is greater or equal to the required
6121 * version, or false if this version of DataTales is not suitable
6122 * @method
6123 * @dtopt API
6124 * @deprecated Since v1.10
6125 *
6126 * @example
6127 * $(document).ready(function() {
6128 * var oTable = $('#example').dataTable();
6129 * alert( oTable.fnVersionCheck( '1.9.0' ) );
6130 * } );
6131 */
6132 this.fnVersionCheck = _ext.fnVersionCheck;
6133
6134
6135 var _that = this;
6136 var emptyInit = options === undefined;
6137 var len = this.length;
6138
6139 if ( emptyInit ) {
6140 options = {};
6141 }
6142
6143 this.oApi = this.internal = _ext.internal;
6144
6145 // Extend with old style plug-in API methods
6146 for ( var fn in DataTable.ext.internal ) {
6147 if ( fn ) {
6148 this[fn] = _fnExternApiFunc(fn);
6149 }
6150 }
6151
6152 this.each(function() {
6153 // For each initialisation we want to give it a clean initialisation
6154 // object that can be bashed around
6155 var o = {};
6156 var oInit = len > 1 ? // optimisation for single table case
6157 _fnExtend( o, options, true ) :
6158 options;
6159
6160 /*global oInit,_that,emptyInit*/
6161 var i=0, iLen, j, jLen, k, kLen;
6162 var sId = this.getAttribute( 'id' );
6163 var bInitHandedOff = false;
6164 var defaults = DataTable.defaults;
6165 var $this = $(this);
6166
6167
6168 /* Sanity check */
6169 if ( this.nodeName.toLowerCase() != 'table' )
6170 {
6171 _fnLog( null, 0, 'Non-table node initialisation ('+this.nodeName+')', 2 );
6172 return;
6173 }
6174
6175 /* Backwards compatibility for the defaults */
6176 _fnCompatOpts( defaults );
6177 _fnCompatCols( defaults.column );
6178
6179 /* Convert the camel-case defaults to Hungarian */
6180 _fnCamelToHungarian( defaults, defaults, true );
6181 _fnCamelToHungarian( defaults.column, defaults.column, true );
6182
6183 /* Setting up the initialisation object */
6184 _fnCamelToHungarian( defaults, $.extend( oInit, $this.data() ) );
6185
6186
6187
6188 /* Check to see if we are re-initialising a table */
6189 var allSettings = DataTable.settings;
6190 for ( i=0, iLen=allSettings.length ; i<iLen ; i++ )
6191 {
6192 var s = allSettings[i];
6193
6194 /* Base check on table node */
6195 if ( s.nTable == this || s.nTHead.parentNode == this || (s.nTFoot && s.nTFoot.parentNode == this) )
6196 {
6197 var bRetrieve = oInit.bRetrieve !== undefined ? oInit.bRetrieve : defaults.bRetrieve;
6198 var bDestroy = oInit.bDestroy !== undefined ? oInit.bDestroy : defaults.bDestroy;
6199
6200 if ( emptyInit || bRetrieve )
6201 {
6202 return s.oInstance;
6203 }
6204 else if ( bDestroy )
6205 {
6206 s.oInstance.fnDestroy();
6207 break;
6208 }
6209 else
6210 {
6211 _fnLog( s, 0, 'Cannot reinitialise DataTable', 3 );
6212 return;
6213 }
6214 }
6215
6216 /* If the element we are initialising has the same ID as a table which was previously
6217 * initialised, but the table nodes don't match (from before) then we destroy the old
6218 * instance by simply deleting it. This is under the assumption that the table has been
6219 * destroyed by other methods. Anyone using non-id selectors will need to do this manually
6220 */
6221 if ( s.sTableId == this.id )
6222 {
6223 allSettings.splice( i, 1 );
6224 break;
6225 }
6226 }
6227
6228 /* Ensure the table has an ID - required for accessibility */
6229 if ( sId === null || sId === "" )
6230 {
6231 sId = "DataTables_Table_"+(DataTable.ext._unique++);
6232 this.id = sId;
6233 }
6234
6235 /* Create the settings object for this table and set some of the default parameters */
6236 var oSettings = $.extend( true, {}, DataTable.models.oSettings, {
6237 "sDestroyWidth": $this[0].style.width,
6238 "sInstance": sId,
6239 "sTableId": sId
6240 } );
6241 oSettings.nTable = this;
6242 oSettings.oApi = _that.internal;
6243 oSettings.oInit = oInit;
6244
6245 allSettings.push( oSettings );
6246
6247 // Need to add the instance after the instance after the settings object has been added
6248 // to the settings array, so we can self reference the table instance if more than one
6249 oSettings.oInstance = (_that.length===1) ? _that : $this.dataTable();
6250
6251 // Backwards compatibility, before we apply all the defaults
6252 _fnCompatOpts( oInit );
6253
6254 if ( oInit.oLanguage )
6255 {
6256 _fnLanguageCompat( oInit.oLanguage );
6257 }
6258
6259 // If the length menu is given, but the init display length is not, use the length menu
6260 if ( oInit.aLengthMenu && ! oInit.iDisplayLength )
6261 {
6262 oInit.iDisplayLength = $.isArray( oInit.aLengthMenu[0] ) ?
6263 oInit.aLengthMenu[0][0] : oInit.aLengthMenu[0];
6264 }
6265
6266 // Apply the defaults and init options to make a single init object will all
6267 // options defined from defaults and instance options.
6268 oInit = _fnExtend( $.extend( true, {}, defaults ), oInit );
6269
6270
6271 // Map the initialisation options onto the settings object
6272 _fnMap( oSettings.oFeatures, oInit, [
6273 "bPaginate",
6274 "bLengthChange",
6275 "bFilter",
6276 "bSort",
6277 "bSortMulti",
6278 "bInfo",
6279 "bProcessing",
6280 "bAutoWidth",
6281 "bSortClasses",
6282 "bServerSide",
6283 "bDeferRender"
6284 ] );
6285 _fnMap( oSettings, oInit, [
6286 "asStripeClasses",
6287 "ajax",
6288 "fnServerData",
6289 "fnFormatNumber",
6290 "sServerMethod",
6291 "aaSorting",
6292 "aaSortingFixed",
6293 "aLengthMenu",
6294 "sPaginationType",
6295 "sAjaxSource",
6296 "sAjaxDataProp",
6297 "iStateDuration",
6298 "sDom",
6299 "bSortCellsTop",
6300 "iTabIndex",
6301 "fnStateLoadCallback",
6302 "fnStateSaveCallback",
6303 "renderer",
6304 "searchDelay",
6305 "rowId",
6306 [ "iCookieDuration", "iStateDuration" ], // backwards compat
6307 [ "oSearch", "oPreviousSearch" ],
6308 [ "aoSearchCols", "aoPreSearchCols" ],
6309 [ "iDisplayLength", "_iDisplayLength" ],
6310 [ "bJQueryUI", "bJUI" ]
6311 ] );
6312 _fnMap( oSettings.oScroll, oInit, [
6313 [ "sScrollX", "sX" ],
6314 [ "sScrollXInner", "sXInner" ],
6315 [ "sScrollY", "sY" ],
6316 [ "bScrollCollapse", "bCollapse" ]
6317 ] );
6318 _fnMap( oSettings.oLanguage, oInit, "fnInfoCallback" );
6319
6320 /* Callback functions which are array driven */
6321 _fnCallbackReg( oSettings, 'aoDrawCallback', oInit.fnDrawCallback, 'user' );
6322 _fnCallbackReg( oSettings, 'aoServerParams', oInit.fnServerParams, 'user' );
6323 _fnCallbackReg( oSettings, 'aoStateSaveParams', oInit.fnStateSaveParams, 'user' );
6324 _fnCallbackReg( oSettings, 'aoStateLoadParams', oInit.fnStateLoadParams, 'user' );
6325 _fnCallbackReg( oSettings, 'aoStateLoaded', oInit.fnStateLoaded, 'user' );
6326 _fnCallbackReg( oSettings, 'aoRowCallback', oInit.fnRowCallback, 'user' );
6327 _fnCallbackReg( oSettings, 'aoRowCreatedCallback', oInit.fnCreatedRow, 'user' );
6328 _fnCallbackReg( oSettings, 'aoHeaderCallback', oInit.fnHeaderCallback, 'user' );
6329 _fnCallbackReg( oSettings, 'aoFooterCallback', oInit.fnFooterCallback, 'user' );
6330 _fnCallbackReg( oSettings, 'aoInitComplete', oInit.fnInitComplete, 'user' );
6331 _fnCallbackReg( oSettings, 'aoPreDrawCallback', oInit.fnPreDrawCallback, 'user' );
6332
6333 oSettings.rowIdFn = _fnGetObjectDataFn( oInit.rowId );
6334
6335 /* Browser support detection */
6336 _fnBrowserDetect( oSettings );
6337
6338 var oClasses = oSettings.oClasses;
6339
6340 // @todo Remove in 1.11
6341 if ( oInit.bJQueryUI )
6342 {
6343 /* Use the JUI classes object for display. You could clone the oStdClasses object if
6344 * you want to have multiple tables with multiple independent classes
6345 */
6346 $.extend( oClasses, DataTable.ext.oJUIClasses, oInit.oClasses );
6347
6348 if ( oInit.sDom === defaults.sDom && defaults.sDom === "lfrtip" )
6349 {
6350 /* Set the DOM to use a layout suitable for jQuery UI's theming */
6351 oSettings.sDom = '<"H"lfr>t<"F"ip>';
6352 }
6353
6354 if ( ! oSettings.renderer ) {
6355 oSettings.renderer = 'jqueryui';
6356 }
6357 else if ( $.isPlainObject( oSettings.renderer ) && ! oSettings.renderer.header ) {
6358 oSettings.renderer.header = 'jqueryui';
6359 }
6360 }
6361 else
6362 {
6363 $.extend( oClasses, DataTable.ext.classes, oInit.oClasses );
6364 }
6365 $this.addClass( oClasses.sTable );
6366
6367
6368 if ( oSettings.iInitDisplayStart === undefined )
6369 {
6370 /* Display start point, taking into account the save saving */
6371 oSettings.iInitDisplayStart = oInit.iDisplayStart;
6372 oSettings._iDisplayStart = oInit.iDisplayStart;
6373 }
6374
6375 if ( oInit.iDeferLoading !== null )
6376 {
6377 oSettings.bDeferLoading = true;
6378 var tmp = $.isArray( oInit.iDeferLoading );
6379 oSettings._iRecordsDisplay = tmp ? oInit.iDeferLoading[0] : oInit.iDeferLoading;
6380 oSettings._iRecordsTotal = tmp ? oInit.iDeferLoading[1] : oInit.iDeferLoading;
6381 }
6382
6383 /* Language definitions */
6384 var oLanguage = oSettings.oLanguage;
6385 $.extend( true, oLanguage, oInit.oLanguage );
6386
6387 if ( oLanguage.sUrl !== "" )
6388 {
6389 /* Get the language definitions from a file - because this Ajax call makes the language
6390 * get async to the remainder of this function we use bInitHandedOff to indicate that
6391 * _fnInitialise will be fired by the returned Ajax handler, rather than the constructor
6392 */
6393 $.ajax( {
6394 dataType: 'json',
6395 url: oLanguage.sUrl,
6396 success: function ( json ) {
6397 _fnLanguageCompat( json );
6398 _fnCamelToHungarian( defaults.oLanguage, json );
6399 $.extend( true, oLanguage, json );
6400 _fnInitialise( oSettings );
6401 },
6402 error: function () {
6403 // Error occurred loading language file, continue on as best we can
6404 _fnInitialise( oSettings );
6405 }
6406 } );
6407 bInitHandedOff = true;
6408 }
6409
6410 /*
6411 * Stripes
6412 */
6413 if ( oInit.asStripeClasses === null )
6414 {
6415 oSettings.asStripeClasses =[
6416 oClasses.sStripeOdd,
6417 oClasses.sStripeEven
6418 ];
6419 }
6420
6421 /* Remove row stripe classes if they are already on the table row */
6422 var stripeClasses = oSettings.asStripeClasses;
6423 var rowOne = $this.children('tbody').find('tr').eq(0);
6424 if ( $.inArray( true, $.map( stripeClasses, function(el, i) {
6425 return rowOne.hasClass(el);
6426 } ) ) !== -1 ) {
6427 $('tbody tr', this).removeClass( stripeClasses.join(' ') );
6428 oSettings.asDestroyStripes = stripeClasses.slice();
6429 }
6430
6431 /*
6432 * Columns
6433 * See if we should load columns automatically or use defined ones
6434 */
6435 var anThs = [];
6436 var aoColumnsInit;
6437 var nThead = this.getElementsByTagName('thead');
6438 if ( nThead.length !== 0 )
6439 {
6440 _fnDetectHeader( oSettings.aoHeader, nThead[0] );
6441 anThs = _fnGetUniqueThs( oSettings );
6442 }
6443
6444 /* If not given a column array, generate one with nulls */
6445 if ( oInit.aoColumns === null )
6446 {
6447 aoColumnsInit = [];
6448 for ( i=0, iLen=anThs.length ; i<iLen ; i++ )
6449 {
6450 aoColumnsInit.push( null );
6451 }
6452 }
6453 else
6454 {
6455 aoColumnsInit = oInit.aoColumns;
6456 }
6457
6458 /* Add the columns */
6459 for ( i=0, iLen=aoColumnsInit.length ; i<iLen ; i++ )
6460 {
6461 _fnAddColumn( oSettings, anThs ? anThs[i] : null );
6462 }
6463
6464 /* Apply the column definitions */
6465 _fnApplyColumnDefs( oSettings, oInit.aoColumnDefs, aoColumnsInit, function (iCol, oDef) {
6466 _fnColumnOptions( oSettings, iCol, oDef );
6467 } );
6468
6469 /* HTML5 attribute detection - build an mData object automatically if the
6470 * attributes are found
6471 */
6472 if ( rowOne.length ) {
6473 var a = function ( cell, name ) {
6474 return cell.getAttribute( 'data-'+name ) !== null ? name : null;
6475 };
6476
6477 $( rowOne[0] ).children('th, td').each( function (i, cell) {
6478 var col = oSettings.aoColumns[i];
6479
6480 if ( col.mData === i ) {
6481 var sort = a( cell, 'sort' ) || a( cell, 'order' );
6482 var filter = a( cell, 'filter' ) || a( cell, 'search' );
6483
6484 if ( sort !== null || filter !== null ) {
6485 col.mData = {
6486 _: i+'.display',
6487 sort: sort !== null ? i+'.@data-'+sort : undefined,
6488 type: sort !== null ? i+'.@data-'+sort : undefined,
6489 filter: filter !== null ? i+'.@data-'+filter : undefined
6490 };
6491
6492 _fnColumnOptions( oSettings, i );
6493 }
6494 }
6495 } );
6496 }
6497
6498 var features = oSettings.oFeatures;
6499
6500 /* Must be done after everything which can be overridden by the state saving! */
6501 if ( oInit.bStateSave )
6502 {
6503 features.bStateSave = true;
6504 _fnLoadState( oSettings, oInit );
6505 _fnCallbackReg( oSettings, 'aoDrawCallback', _fnSaveState, 'state_save' );
6506 }
6507
6508
6509 /*
6510 * Sorting
6511 * @todo For modularisation (1.11) this needs to do into a sort start up handler
6512 */
6513
6514 // If aaSorting is not defined, then we use the first indicator in asSorting
6515 // in case that has been altered, so the default sort reflects that option
6516 if ( oInit.aaSorting === undefined )
6517 {
6518 var sorting = oSettings.aaSorting;
6519 for ( i=0, iLen=sorting.length ; i<iLen ; i++ )
6520 {
6521 sorting[i][1] = oSettings.aoColumns[ i ].asSorting[0];
6522 }
6523 }
6524
6525 /* Do a first pass on the sorting classes (allows any size changes to be taken into
6526 * account, and also will apply sorting disabled classes if disabled
6527 */
6528 _fnSortingClasses( oSettings );
6529
6530 if ( features.bSort )
6531 {
6532 _fnCallbackReg( oSettings, 'aoDrawCallback', function () {
6533 if ( oSettings.bSorted ) {
6534 var aSort = _fnSortFlatten( oSettings );
6535 var sortedColumns = {};
6536
6537 $.each( aSort, function (i, val) {
6538 sortedColumns[ val.src ] = val.dir;
6539 } );
6540
6541 _fnCallbackFire( oSettings, null, 'order', [oSettings, aSort, sortedColumns] );
6542 _fnSortAria( oSettings );
6543 }
6544 } );
6545 }
6546
6547 _fnCallbackReg( oSettings, 'aoDrawCallback', function () {
6548 if ( oSettings.bSorted || _fnDataSource( oSettings ) === 'ssp' || features.bDeferRender ) {
6549 _fnSortingClasses( oSettings );
6550 }
6551 }, 'sc' );
6552
6553
6554 /*
6555 * Final init
6556 * Cache the header, body and footer as required, creating them if needed
6557 */
6558
6559 // Work around for Webkit bug 83867 - store the caption-side before removing from doc
6560 var captions = $this.children('caption').each( function () {
6561 this._captionSide = $this.css('caption-side');
6562 } );
6563
6564 var thead = $this.children('thead');
6565 if ( thead.length === 0 )
6566 {
6567 thead = $('<thead/>').appendTo(this);
6568 }
6569 oSettings.nTHead = thead[0];
6570
6571 var tbody = $this.children('tbody');
6572 if ( tbody.length === 0 )
6573 {
6574 tbody = $('<tbody/>').appendTo(this);
6575 }
6576 oSettings.nTBody = tbody[0];
6577
6578 var tfoot = $this.children('tfoot');
6579 if ( tfoot.length === 0 && captions.length > 0 && (oSettings.oScroll.sX !== "" || oSettings.oScroll.sY !== "") )
6580 {
6581 // If we are a scrolling table, and no footer has been given, then we need to create
6582 // a tfoot element for the caption element to be appended to
6583 tfoot = $('<tfoot/>').appendTo(this);
6584 }
6585
6586 if ( tfoot.length === 0 || tfoot.children().length === 0 ) {
6587 $this.addClass( oClasses.sNoFooter );
6588 }
6589 else if ( tfoot.length > 0 ) {
6590 oSettings.nTFoot = tfoot[0];
6591 _fnDetectHeader( oSettings.aoFooter, oSettings.nTFoot );
6592 }
6593
6594 /* Check if there is data passing into the constructor */
6595 if ( oInit.aaData )
6596 {
6597 for ( i=0 ; i<oInit.aaData.length ; i++ )
6598 {
6599 _fnAddData( oSettings, oInit.aaData[ i ] );
6600 }
6601 }
6602 else if ( oSettings.bDeferLoading || _fnDataSource( oSettings ) == 'dom' )
6603 {
6604 /* Grab the data from the page - only do this when deferred loading or no Ajax
6605 * source since there is no point in reading the DOM data if we are then going
6606 * to replace it with Ajax data
6607 */
6608 _fnAddTr( oSettings, $(oSettings.nTBody).children('tr') );
6609 }
6610
6611 /* Copy the data index array */
6612 oSettings.aiDisplay = oSettings.aiDisplayMaster.slice();
6613
6614 /* Initialisation complete - table can be drawn */
6615 oSettings.bInitialised = true;
6616
6617 /* Check if we need to initialise the table (it might not have been handed off to the
6618 * language processor)
6619 */
6620 if ( bInitHandedOff === false )
6621 {
6622 _fnInitialise( oSettings );
6623 }
6624 } );
6625 _that = null;
6626 return this;
6627 };
6628
6629
6630
6631 /**
6632 * Computed structure of the DataTables API, defined by the options passed to
6633 * `DataTable.Api.register()` when building the API.
6634 *
6635 * The structure is built in order to speed creation and extension of the Api
6636 * objects since the extensions are effectively pre-parsed.
6637 *
6638 * The array is an array of objects with the following structure, where this
6639 * base array represents the Api prototype base:
6640 *
6641 * [
6642 * {
6643 * name: 'data' -- string - Property name
6644 * val: function () {}, -- function - Api method (or undefined if just an object
6645 * methodExt: [ ... ], -- array - Array of Api object definitions to extend the method result
6646 * propExt: [ ... ] -- array - Array of Api object definitions to extend the property
6647 * },
6648 * {
6649 * name: 'row'
6650 * val: {},
6651 * methodExt: [ ... ],
6652 * propExt: [
6653 * {
6654 * name: 'data'
6655 * val: function () {},
6656 * methodExt: [ ... ],
6657 * propExt: [ ... ]
6658 * },
6659 * ...
6660 * ]
6661 * }
6662 * ]
6663 *
6664 * @type {Array}
6665 * @ignore
6666 */
6667 var __apiStruct = [];
6668
6669
6670 /**
6671 * `Array.prototype` reference.
6672 *
6673 * @type object
6674 * @ignore
6675 */
6676 var __arrayProto = Array.prototype;
6677
6678
6679 /**
6680 * Abstraction for `context` parameter of the `Api` constructor to allow it to
6681 * take several different forms for ease of use.
6682 *
6683 * Each of the input parameter types will be converted to a DataTables settings
6684 * object where possible.
6685 *
6686 * @param {string|node|jQuery|object} mixed DataTable identifier. Can be one
6687 * of:
6688 *
6689 * * `string` - jQuery selector. Any DataTables' matching the given selector
6690 * with be found and used.
6691 * * `node` - `TABLE` node which has already been formed into a DataTable.
6692 * * `jQuery` - A jQuery object of `TABLE` nodes.
6693 * * `object` - DataTables settings object
6694 * * `DataTables.Api` - API instance
6695 * @return {array|null} Matching DataTables settings objects. `null` or
6696 * `undefined` is returned if no matching DataTable is found.
6697 * @ignore
6698 */
6699 var _toSettings = function ( mixed )
6700 {
6701 var idx, jq;
6702 var settings = DataTable.settings;
6703 var tables = $.map( settings, function (el, i) {
6704 return el.nTable;
6705 } );
6706
6707 if ( ! mixed ) {
6708 return [];
6709 }
6710 else if ( mixed.nTable && mixed.oApi ) {
6711 // DataTables settings object
6712 return [ mixed ];
6713 }
6714 else if ( mixed.nodeName && mixed.nodeName.toLowerCase() === 'table' ) {
6715 // Table node
6716 idx = $.inArray( mixed, tables );
6717 return idx !== -1 ? [ settings[idx] ] : null;
6718 }
6719 else if ( mixed && typeof mixed.settings === 'function' ) {
6720 return mixed.settings().toArray();
6721 }
6722 else if ( typeof mixed === 'string' ) {
6723 // jQuery selector
6724 jq = $(mixed);
6725 }
6726 else if ( mixed instanceof $ ) {
6727 // jQuery object (also DataTables instance)
6728 jq = mixed;
6729 }
6730
6731 if ( jq ) {
6732 return jq.map( function(i) {
6733 idx = $.inArray( this, tables );
6734 return idx !== -1 ? settings[idx] : null;
6735 } ).toArray();
6736 }
6737 };
6738
6739
6740 /**
6741 * DataTables API class - used to control and interface with one or more
6742 * DataTables enhanced tables.
6743 *
6744 * The API class is heavily based on jQuery, presenting a chainable interface
6745 * that you can use to interact with tables. Each instance of the API class has
6746 * a "context" - i.e. the tables that it will operate on. This could be a single
6747 * table, all tables on a page or a sub-set thereof.
6748 *
6749 * Additionally the API is designed to allow you to easily work with the data in
6750 * the tables, retrieving and manipulating it as required. This is done by
6751 * presenting the API class as an array like interface. The contents of the
6752 * array depend upon the actions requested by each method (for example
6753 * `rows().nodes()` will return an array of nodes, while `rows().data()` will
6754 * return an array of objects or arrays depending upon your table's
6755 * configuration). The API object has a number of array like methods (`push`,
6756 * `pop`, `reverse` etc) as well as additional helper methods (`each`, `pluck`,
6757 * `unique` etc) to assist your working with the data held in a table.
6758 *
6759 * Most methods (those which return an Api instance) are chainable, which means
6760 * the return from a method call also has all of the methods available that the
6761 * top level object had. For example, these two calls are equivalent:
6762 *
6763 * // Not chained
6764 * api.row.add( {...} );
6765 * api.draw();
6766 *
6767 * // Chained
6768 * api.row.add( {...} ).draw();
6769 *
6770 * @class DataTable.Api
6771 * @param {array|object|string|jQuery} context DataTable identifier. This is
6772 * used to define which DataTables enhanced tables this API will operate on.
6773 * Can be one of:
6774 *
6775 * * `string` - jQuery selector. Any DataTables' matching the given selector
6776 * with be found and used.
6777 * * `node` - `TABLE` node which has already been formed into a DataTable.
6778 * * `jQuery` - A jQuery object of `TABLE` nodes.
6779 * * `object` - DataTables settings object
6780 * @param {array} [data] Data to initialise the Api instance with.
6781 *
6782 * @example
6783 * // Direct initialisation during DataTables construction
6784 * var api = $('#example').DataTable();
6785 *
6786 * @example
6787 * // Initialisation using a DataTables jQuery object
6788 * var api = $('#example').dataTable().api();
6789 *
6790 * @example
6791 * // Initialisation as a constructor
6792 * var api = new $.fn.DataTable.Api( 'table.dataTable' );
6793 */
6794 _Api = function ( context, data )
6795 {
6796 if ( ! (this instanceof _Api) ) {
6797 return new _Api( context, data );
6798 }
6799
6800 var settings = [];
6801 var ctxSettings = function ( o ) {
6802 var a = _toSettings( o );
6803 if ( a ) {
6804 settings = settings.concat( a );
6805 }
6806 };
6807
6808 if ( $.isArray( context ) ) {
6809 for ( var i=0, ien=context.length ; i<ien ; i++ ) {
6810 ctxSettings( context[i] );
6811 }
6812 }
6813 else {
6814 ctxSettings( context );
6815 }
6816
6817 // Remove duplicates
6818 this.context = _unique( settings );
6819
6820 // Initial data
6821 if ( data ) {
6822 $.merge( this, data );
6823 }
6824
6825 // selector
6826 this.selector = {
6827 rows: null,
6828 cols: null,
6829 opts: null
6830 };
6831
6832 _Api.extend( this, this, __apiStruct );
6833 };
6834
6835 DataTable.Api = _Api;
6836
6837 // Don't destroy the existing prototype, just extend it. Required for jQuery 2's
6838 // isPlainObject.
6839 $.extend( _Api.prototype, {
6840 any: function ()
6841 {
6842 return this.count() !== 0;
6843 },
6844
6845
6846 concat: __arrayProto.concat,
6847
6848
6849 context: [], // array of table settings objects
6850
6851
6852 count: function ()
6853 {
6854 return this.flatten().length;
6855 },
6856
6857
6858 each: function ( fn )
6859 {
6860 for ( var i=0, ien=this.length ; i<ien; i++ ) {
6861 fn.call( this, this[i], i, this );
6862 }
6863
6864 return this;
6865 },
6866
6867
6868 eq: function ( idx )
6869 {
6870 var ctx = this.context;
6871
6872 return ctx.length > idx ?
6873 new _Api( ctx[idx], this[idx] ) :
6874 null;
6875 },
6876
6877
6878 filter: function ( fn )
6879 {
6880 var a = [];
6881
6882 if ( __arrayProto.filter ) {
6883 a = __arrayProto.filter.call( this, fn, this );
6884 }
6885 else {
6886 // Compatibility for browsers without EMCA-252-5 (JS 1.6)
6887 for ( var i=0, ien=this.length ; i<ien ; i++ ) {
6888 if ( fn.call( this, this[i], i, this ) ) {
6889 a.push( this[i] );
6890 }
6891 }
6892 }
6893
6894 return new _Api( this.context, a );
6895 },
6896
6897
6898 flatten: function ()
6899 {
6900 var a = [];
6901 return new _Api( this.context, a.concat.apply( a, this.toArray() ) );
6902 },
6903
6904
6905 join: __arrayProto.join,
6906
6907
6908 indexOf: __arrayProto.indexOf || function (obj, start)
6909 {
6910 for ( var i=(start || 0), ien=this.length ; i<ien ; i++ ) {
6911 if ( this[i] === obj ) {
6912 return i;
6913 }
6914 }
6915 return -1;
6916 },
6917
6918 iterator: function ( flatten, type, fn, alwaysNew ) {
6919 var
6920 a = [], ret,
6921 i, ien, j, jen,
6922 context = this.context,
6923 rows, items, item,
6924 selector = this.selector;
6925
6926 // Argument shifting
6927 if ( typeof flatten === 'string' ) {
6928 alwaysNew = fn;
6929 fn = type;
6930 type = flatten;
6931 flatten = false;
6932 }
6933
6934 for ( i=0, ien=context.length ; i<ien ; i++ ) {
6935 var apiInst = new _Api( context[i] );
6936
6937 if ( type === 'table' ) {
6938 ret = fn.call( apiInst, context[i], i );
6939
6940 if ( ret !== undefined ) {
6941 a.push( ret );
6942 }
6943 }
6944 else if ( type === 'columns' || type === 'rows' ) {
6945 // this has same length as context - one entry for each table
6946 ret = fn.call( apiInst, context[i], this[i], i );
6947
6948 if ( ret !== undefined ) {
6949 a.push( ret );
6950 }
6951 }
6952 else if ( type === 'column' || type === 'column-rows' || type === 'row' || type === 'cell' ) {
6953 // columns and rows share the same structure.
6954 // 'this' is an array of column indexes for each context
6955 items = this[i];
6956
6957 if ( type === 'column-rows' ) {
6958 rows = _selector_row_indexes( context[i], selector.opts );
6959 }
6960
6961 for ( j=0, jen=items.length ; j<jen ; j++ ) {
6962 item = items[j];
6963
6964 if ( type === 'cell' ) {
6965 ret = fn.call( apiInst, context[i], item.row, item.column, i, j );
6966 }
6967 else {
6968 ret = fn.call( apiInst, context[i], item, i, j, rows );
6969 }
6970
6971 if ( ret !== undefined ) {
6972 a.push( ret );
6973 }
6974 }
6975 }
6976 }
6977
6978 if ( a.length || alwaysNew ) {
6979 var api = new _Api( context, flatten ? a.concat.apply( [], a ) : a );
6980 var apiSelector = api.selector;
6981 apiSelector.rows = selector.rows;
6982 apiSelector.cols = selector.cols;
6983 apiSelector.opts = selector.opts;
6984 return api;
6985 }
6986 return this;
6987 },
6988
6989
6990 lastIndexOf: __arrayProto.lastIndexOf || function (obj, start)
6991 {
6992 // Bit cheeky...
6993 return this.indexOf.apply( this.toArray.reverse(), arguments );
6994 },
6995
6996
6997 length: 0,
6998
6999
7000 map: function ( fn )
7001 {
7002 var a = [];
7003
7004 if ( __arrayProto.map ) {
7005 a = __arrayProto.map.call( this, fn, this );
7006 }
7007 else {
7008 // Compatibility for browsers without EMCA-252-5 (JS 1.6)
7009 for ( var i=0, ien=this.length ; i<ien ; i++ ) {
7010 a.push( fn.call( this, this[i], i ) );
7011 }
7012 }
7013
7014 return new _Api( this.context, a );
7015 },
7016
7017
7018 pluck: function ( prop )
7019 {
7020 return this.map( function ( el ) {
7021 return el[ prop ];
7022 } );
7023 },
7024
7025 pop: __arrayProto.pop,
7026
7027
7028 push: __arrayProto.push,
7029
7030
7031 // Does not return an API instance
7032 reduce: __arrayProto.reduce || function ( fn, init )
7033 {
7034 return _fnReduce( this, fn, init, 0, this.length, 1 );
7035 },
7036
7037
7038 reduceRight: __arrayProto.reduceRight || function ( fn, init )
7039 {
7040 return _fnReduce( this, fn, init, this.length-1, -1, -1 );
7041 },
7042
7043
7044 reverse: __arrayProto.reverse,
7045
7046
7047 // Object with rows, columns and opts
7048 selector: null,
7049
7050
7051 shift: __arrayProto.shift,
7052
7053
7054 sort: __arrayProto.sort, // ? name - order?
7055
7056
7057 splice: __arrayProto.splice,
7058
7059
7060 toArray: function ()
7061 {
7062 return __arrayProto.slice.call( this );
7063 },
7064
7065
7066 to$: function ()
7067 {
7068 return $( this );
7069 },
7070
7071
7072 toJQuery: function ()
7073 {
7074 return $( this );
7075 },
7076
7077
7078 unique: function ()
7079 {
7080 return new _Api( this.context, _unique(this) );
7081 },
7082
7083
7084 unshift: __arrayProto.unshift
7085 } );
7086
7087
7088 _Api.extend = function ( scope, obj, ext )
7089 {
7090 // Only extend API instances and static properties of the API
7091 if ( ! ext.length || ! obj || ( ! (obj instanceof _Api) && ! obj.__dt_wrapper ) ) {
7092 return;
7093 }
7094
7095 var
7096 i, ien,
7097 j, jen,
7098 struct, inner,
7099 methodScoping = function ( scope, fn, struc ) {
7100 return function () {
7101 var ret = fn.apply( scope, arguments );
7102
7103 // Method extension
7104 _Api.extend( ret, ret, struc.methodExt );
7105 return ret;
7106 };
7107 };
7108
7109 for ( i=0, ien=ext.length ; i<ien ; i++ ) {
7110 struct = ext[i];
7111
7112 // Value
7113 obj[ struct.name ] = typeof struct.val === 'function' ?
7114 methodScoping( scope, struct.val, struct ) :
7115 $.isPlainObject( struct.val ) ?
7116 {} :
7117 struct.val;
7118
7119 obj[ struct.name ].__dt_wrapper = true;
7120
7121 // Property extension
7122 _Api.extend( scope, obj[ struct.name ], struct.propExt );
7123 }
7124 };
7125
7126
7127 // @todo - Is there need for an augment function?
7128 // _Api.augment = function ( inst, name )
7129 // {
7130 // // Find src object in the structure from the name
7131 // var parts = name.split('.');
7132
7133 // _Api.extend( inst, obj );
7134 // };
7135
7136
7137 // [
7138 // {
7139 // name: 'data' -- string - Property name
7140 // val: function () {}, -- function - Api method (or undefined if just an object
7141 // methodExt: [ ... ], -- array - Array of Api object definitions to extend the method result
7142 // propExt: [ ... ] -- array - Array of Api object definitions to extend the property
7143 // },
7144 // {
7145 // name: 'row'
7146 // val: {},
7147 // methodExt: [ ... ],
7148 // propExt: [
7149 // {
7150 // name: 'data'
7151 // val: function () {},
7152 // methodExt: [ ... ],
7153 // propExt: [ ... ]
7154 // },
7155 // ...
7156 // ]
7157 // }
7158 // ]
7159
7160 _Api.register = _api_register = function ( name, val )
7161 {
7162 if ( $.isArray( name ) ) {
7163 for ( var j=0, jen=name.length ; j<jen ; j++ ) {
7164 _Api.register( name[j], val );
7165 }
7166 return;
7167 }
7168
7169 var
7170 i, ien,
7171 heir = name.split('.'),
7172 struct = __apiStruct,
7173 key, method;
7174
7175 var find = function ( src, name ) {
7176 for ( var i=0, ien=src.length ; i<ien ; i++ ) {
7177 if ( src[i].name === name ) {
7178 return src[i];
7179 }
7180 }
7181 return null;
7182 };
7183
7184 for ( i=0, ien=heir.length ; i<ien ; i++ ) {
7185 method = heir[i].indexOf('()') !== -1;
7186 key = method ?
7187 heir[i].replace('()', '') :
7188 heir[i];
7189
7190 var src = find( struct, key );
7191 if ( ! src ) {
7192 src = {
7193 name: key,
7194 val: {},
7195 methodExt: [],
7196 propExt: []
7197 };
7198 struct.push( src );
7199 }
7200
7201 if ( i === ien-1 ) {
7202 src.val = val;
7203 }
7204 else {
7205 struct = method ?
7206 src.methodExt :
7207 src.propExt;
7208 }
7209 }
7210 };
7211
7212
7213 _Api.registerPlural = _api_registerPlural = function ( pluralName, singularName, val ) {
7214 _Api.register( pluralName, val );
7215
7216 _Api.register( singularName, function () {
7217 var ret = val.apply( this, arguments );
7218
7219 if ( ret === this ) {
7220 // Returned item is the API instance that was passed in, return it
7221 return this;
7222 }
7223 else if ( ret instanceof _Api ) {
7224 // New API instance returned, want the value from the first item
7225 // in the returned array for the singular result.
7226 return ret.length ?
7227 $.isArray( ret[0] ) ?
7228 new _Api( ret.context, ret[0] ) : // Array results are 'enhanced'
7229 ret[0] :
7230 undefined;
7231 }
7232
7233 // Non-API return - just fire it back
7234 return ret;
7235 } );
7236 };
7237
7238
7239 /**
7240 * Selector for HTML tables. Apply the given selector to the give array of
7241 * DataTables settings objects.
7242 *
7243 * @param {string|integer} [selector] jQuery selector string or integer
7244 * @param {array} Array of DataTables settings objects to be filtered
7245 * @return {array}
7246 * @ignore
7247 */
7248 var __table_selector = function ( selector, a )
7249 {
7250 // Integer is used to pick out a table by index
7251 if ( typeof selector === 'number' ) {
7252 return [ a[ selector ] ];
7253 }
7254
7255 // Perform a jQuery selector on the table nodes
7256 var nodes = $.map( a, function (el, i) {
7257 return el.nTable;
7258 } );
7259
7260 return $(nodes)
7261 .filter( selector )
7262 .map( function (i) {
7263 // Need to translate back from the table node to the settings
7264 var idx = $.inArray( this, nodes );
7265 return a[ idx ];
7266 } )
7267 .toArray();
7268 };
7269
7270
7271
7272 /**
7273 * Context selector for the API's context (i.e. the tables the API instance
7274 * refers to.
7275 *
7276 * @name DataTable.Api#tables
7277 * @param {string|integer} [selector] Selector to pick which tables the iterator
7278 * should operate on. If not given, all tables in the current context are
7279 * used. This can be given as a jQuery selector (for example `':gt(0)'`) to
7280 * select multiple tables or as an integer to select a single table.
7281 * @returns {DataTable.Api} Returns a new API instance if a selector is given.
7282 */
7283 _api_register( 'tables()', function ( selector ) {
7284 // A new instance is created if there was a selector specified
7285 return selector ?
7286 new _Api( __table_selector( selector, this.context ) ) :
7287 this;
7288 } );
7289
7290
7291 _api_register( 'table()', function ( selector ) {
7292 var tables = this.tables( selector );
7293 var ctx = tables.context;
7294
7295 // Truncate to the first matched table
7296 return ctx.length ?
7297 new _Api( ctx[0] ) :
7298 tables;
7299 } );
7300
7301
7302 _api_registerPlural( 'tables().nodes()', 'table().node()' , function () {
7303 return this.iterator( 'table', function ( ctx ) {
7304 return ctx.nTable;
7305 }, 1 );
7306 } );
7307
7308
7309 _api_registerPlural( 'tables().body()', 'table().body()' , function () {
7310 return this.iterator( 'table', function ( ctx ) {
7311 return ctx.nTBody;
7312 }, 1 );
7313 } );
7314
7315
7316 _api_registerPlural( 'tables().header()', 'table().header()' , function () {
7317 return this.iterator( 'table', function ( ctx ) {
7318 return ctx.nTHead;
7319 }, 1 );
7320 } );
7321
7322
7323 _api_registerPlural( 'tables().footer()', 'table().footer()' , function () {
7324 return this.iterator( 'table', function ( ctx ) {
7325 return ctx.nTFoot;
7326 }, 1 );
7327 } );
7328
7329
7330 _api_registerPlural( 'tables().containers()', 'table().container()' , function () {
7331 return this.iterator( 'table', function ( ctx ) {
7332 return ctx.nTableWrapper;
7333 }, 1 );
7334 } );
7335
7336
7337
7338 /**
7339 * Redraw the tables in the current context.
7340 */
7341 _api_register( 'draw()', function ( paging ) {
7342 return this.iterator( 'table', function ( settings ) {
7343 if ( paging === 'page' ) {
7344 _fnDraw( settings );
7345 }
7346 else {
7347 if ( typeof paging === 'string' ) {
7348 paging = paging === 'full-hold' ?
7349 false :
7350 true;
7351 }
7352
7353 _fnReDraw( settings, paging===false );
7354 }
7355 } );
7356 } );
7357
7358
7359
7360 /**
7361 * Get the current page index.
7362 *
7363 * @return {integer} Current page index (zero based)
7364 *//**
7365 * Set the current page.
7366 *
7367 * Note that if you attempt to show a page which does not exist, DataTables will
7368 * not throw an error, but rather reset the paging.
7369 *
7370 * @param {integer|string} action The paging action to take. This can be one of:
7371 * * `integer` - The page index to jump to
7372 * * `string` - An action to take:
7373 * * `first` - Jump to first page.
7374 * * `next` - Jump to the next page
7375 * * `previous` - Jump to previous page
7376 * * `last` - Jump to the last page.
7377 * @returns {DataTables.Api} this
7378 */
7379 _api_register( 'page()', function ( action ) {
7380 if ( action === undefined ) {
7381 return this.page.info().page; // not an expensive call
7382 }
7383
7384 // else, have an action to take on all tables
7385 return this.iterator( 'table', function ( settings ) {
7386 _fnPageChange( settings, action );
7387 } );
7388 } );
7389
7390
7391 /**
7392 * Paging information for the first table in the current context.
7393 *
7394 * If you require paging information for another table, use the `table()` method
7395 * with a suitable selector.
7396 *
7397 * @return {object} Object with the following properties set:
7398 * * `page` - Current page index (zero based - i.e. the first page is `0`)
7399 * * `pages` - Total number of pages
7400 * * `start` - Display index for the first record shown on the current page
7401 * * `end` - Display index for the last record shown on the current page
7402 * * `length` - Display length (number of records). Note that generally `start
7403 * + length = end`, but this is not always true, for example if there are
7404 * only 2 records to show on the final page, with a length of 10.
7405 * * `recordsTotal` - Full data set length
7406 * * `recordsDisplay` - Data set length once the current filtering criterion
7407 * are applied.
7408 */
7409 _api_register( 'page.info()', function ( action ) {
7410 if ( this.context.length === 0 ) {
7411 return undefined;
7412 }
7413
7414 var
7415 settings = this.context[0],
7416 start = settings._iDisplayStart,
7417 len = settings.oFeatures.bPaginate ? settings._iDisplayLength : -1,
7418 visRecords = settings.fnRecordsDisplay(),
7419 all = len === -1;
7420
7421 return {
7422 "page": all ? 0 : Math.floor( start / len ),
7423 "pages": all ? 1 : Math.ceil( visRecords / len ),
7424 "start": start,
7425 "end": settings.fnDisplayEnd(),
7426 "length": len,
7427 "recordsTotal": settings.fnRecordsTotal(),
7428 "recordsDisplay": visRecords,
7429 "serverSide": _fnDataSource( settings ) === 'ssp'
7430 };
7431 } );
7432
7433
7434 /**
7435 * Get the current page length.
7436 *
7437 * @return {integer} Current page length. Note `-1` indicates that all records
7438 * are to be shown.
7439 *//**
7440 * Set the current page length.
7441 *
7442 * @param {integer} Page length to set. Use `-1` to show all records.
7443 * @returns {DataTables.Api} this
7444 */
7445 _api_register( 'page.len()', function ( len ) {
7446 // Note that we can't call this function 'length()' because `length`
7447 // is a Javascript property of functions which defines how many arguments
7448 // the function expects.
7449 if ( len === undefined ) {
7450 return this.context.length !== 0 ?
7451 this.context[0]._iDisplayLength :
7452 undefined;
7453 }
7454
7455 // else, set the page length
7456 return this.iterator( 'table', function ( settings ) {
7457 _fnLengthChange( settings, len );
7458 } );
7459 } );
7460
7461
7462
7463 var __reload = function ( settings, holdPosition, callback ) {
7464 // Use the draw event to trigger a callback
7465 if ( callback ) {
7466 var api = new _Api( settings );
7467
7468 api.one( 'draw', function () {
7469 callback( api.ajax.json() );
7470 } );
7471 }
7472
7473 if ( _fnDataSource( settings ) == 'ssp' ) {
7474 _fnReDraw( settings, holdPosition );
7475 }
7476 else {
7477 _fnProcessingDisplay( settings, true );
7478
7479 // Cancel an existing request
7480 var xhr = settings.jqXHR;
7481 if ( xhr && xhr.readyState !== 4 ) {
7482 xhr.abort();
7483 }
7484
7485 // Trigger xhr
7486 _fnBuildAjax( settings, [], function( json ) {
7487 _fnClearTable( settings );
7488
7489 var data = _fnAjaxDataSrc( settings, json );
7490 for ( var i=0, ien=data.length ; i<ien ; i++ ) {
7491 _fnAddData( settings, data[i] );
7492 }
7493
7494 _fnReDraw( settings, holdPosition );
7495 _fnProcessingDisplay( settings, false );
7496 } );
7497 }
7498 };
7499
7500
7501 /**
7502 * Get the JSON response from the last Ajax request that DataTables made to the
7503 * server. Note that this returns the JSON from the first table in the current
7504 * context.
7505 *
7506 * @return {object} JSON received from the server.
7507 */
7508 _api_register( 'ajax.json()', function () {
7509 var ctx = this.context;
7510
7511 if ( ctx.length > 0 ) {
7512 return ctx[0].json;
7513 }
7514
7515 // else return undefined;
7516 } );
7517
7518
7519 /**
7520 * Get the data submitted in the last Ajax request
7521 */
7522 _api_register( 'ajax.params()', function () {
7523 var ctx = this.context;
7524
7525 if ( ctx.length > 0 ) {
7526 return ctx[0].oAjaxData;
7527 }
7528
7529 // else return undefined;
7530 } );
7531
7532
7533 /**
7534 * Reload tables from the Ajax data source. Note that this function will
7535 * automatically re-draw the table when the remote data has been loaded.
7536 *
7537 * @param {boolean} [reset=true] Reset (default) or hold the current paging
7538 * position. A full re-sort and re-filter is performed when this method is
7539 * called, which is why the pagination reset is the default action.
7540 * @returns {DataTables.Api} this
7541 */
7542 _api_register( 'ajax.reload()', function ( callback, resetPaging ) {
7543 return this.iterator( 'table', function (settings) {
7544 __reload( settings, resetPaging===false, callback );
7545 } );
7546 } );
7547
7548
7549 /**
7550 * Get the current Ajax URL. Note that this returns the URL from the first
7551 * table in the current context.
7552 *
7553 * @return {string} Current Ajax source URL
7554 *//**
7555 * Set the Ajax URL. Note that this will set the URL for all tables in the
7556 * current context.
7557 *
7558 * @param {string} url URL to set.
7559 * @returns {DataTables.Api} this
7560 */
7561 _api_register( 'ajax.url()', function ( url ) {
7562 var ctx = this.context;
7563
7564 if ( url === undefined ) {
7565 // get
7566 if ( ctx.length === 0 ) {
7567 return undefined;
7568 }
7569 ctx = ctx[0];
7570
7571 return ctx.ajax ?
7572 $.isPlainObject( ctx.ajax ) ?
7573 ctx.ajax.url :
7574 ctx.ajax :
7575 ctx.sAjaxSource;
7576 }
7577
7578 // set
7579 return this.iterator( 'table', function ( settings ) {
7580 if ( $.isPlainObject( settings.ajax ) ) {
7581 settings.ajax.url = url;
7582 }
7583 else {
7584 settings.ajax = url;
7585 }
7586 // No need to consider sAjaxSource here since DataTables gives priority
7587 // to `ajax` over `sAjaxSource`. So setting `ajax` here, renders any
7588 // value of `sAjaxSource` redundant.
7589 } );
7590 } );
7591
7592
7593 /**
7594 * Load data from the newly set Ajax URL. Note that this method is only
7595 * available when `ajax.url()` is used to set a URL. Additionally, this method
7596 * has the same effect as calling `ajax.reload()` but is provided for
7597 * convenience when setting a new URL. Like `ajax.reload()` it will
7598 * automatically redraw the table once the remote data has been loaded.
7599 *
7600 * @returns {DataTables.Api} this
7601 */
7602 _api_register( 'ajax.url().load()', function ( callback, resetPaging ) {
7603 // Same as a reload, but makes sense to present it for easy access after a
7604 // url change
7605 return this.iterator( 'table', function ( ctx ) {
7606 __reload( ctx, resetPaging===false, callback );
7607 } );
7608 } );
7609
7610
7611
7612
7613 var _selector_run = function ( type, selector, selectFn, settings, opts )
7614 {
7615 var
7616 out = [], res,
7617 a, i, ien, j, jen,
7618 selectorType = typeof selector;
7619
7620 // Can't just check for isArray here, as an API or jQuery instance might be
7621 // given with their array like look
7622 if ( ! selector || selectorType === 'string' || selectorType === 'function' || selector.length === undefined ) {
7623 selector = [ selector ];
7624 }
7625
7626 for ( i=0, ien=selector.length ; i<ien ; i++ ) {
7627 a = selector[i] && selector[i].split ?
7628 selector[i].split(',') :
7629 [ selector[i] ];
7630
7631 for ( j=0, jen=a.length ; j<jen ; j++ ) {
7632 res = selectFn( typeof a[j] === 'string' ? $.trim(a[j]) : a[j] );
7633
7634 if ( res && res.length ) {
7635 out = out.concat( res );
7636 }
7637 }
7638 }
7639
7640 // selector extensions
7641 var ext = _ext.selector[ type ];
7642 if ( ext.length ) {
7643 for ( i=0, ien=ext.length ; i<ien ; i++ ) {
7644 out = ext[i]( settings, opts, out );
7645 }
7646 }
7647
7648 return _unique( out );
7649 };
7650
7651
7652 var _selector_opts = function ( opts )
7653 {
7654 if ( ! opts ) {
7655 opts = {};
7656 }
7657
7658 // Backwards compatibility for 1.9- which used the terminology filter rather
7659 // than search
7660 if ( opts.filter && opts.search === undefined ) {
7661 opts.search = opts.filter;
7662 }
7663
7664 return $.extend( {
7665 search: 'none',
7666 order: 'current',
7667 page: 'all'
7668 }, opts );
7669 };
7670
7671
7672 var _selector_first = function ( inst )
7673 {
7674 // Reduce the API instance to the first item found
7675 for ( var i=0, ien=inst.length ; i<ien ; i++ ) {
7676 if ( inst[i].length > 0 ) {
7677 // Assign the first element to the first item in the instance
7678 // and truncate the instance and context
7679 inst[0] = inst[i];
7680 inst[0].length = 1;
7681 inst.length = 1;
7682 inst.context = [ inst.context[i] ];
7683
7684 return inst;
7685 }
7686 }
7687
7688 // Not found - return an empty instance
7689 inst.length = 0;
7690 return inst;
7691 };
7692
7693
7694 var _selector_row_indexes = function ( settings, opts )
7695 {
7696 var
7697 i, ien, tmp, a=[],
7698 displayFiltered = settings.aiDisplay,
7699 displayMaster = settings.aiDisplayMaster;
7700
7701 var
7702 search = opts.search, // none, applied, removed
7703 order = opts.order, // applied, current, index (original - compatibility with 1.9)
7704 page = opts.page; // all, current
7705
7706 if ( _fnDataSource( settings ) == 'ssp' ) {
7707 // In server-side processing mode, most options are irrelevant since
7708 // rows not shown don't exist and the index order is the applied order
7709 // Removed is a special case - for consistency just return an empty
7710 // array
7711 return search === 'removed' ?
7712 [] :
7713 _range( 0, displayMaster.length );
7714 }
7715 else if ( page == 'current' ) {
7716 // Current page implies that order=current and fitler=applied, since it is
7717 // fairly senseless otherwise, regardless of what order and search actually
7718 // are
7719 for ( i=settings._iDisplayStart, ien=settings.fnDisplayEnd() ; i<ien ; i++ ) {
7720 a.push( displayFiltered[i] );
7721 }
7722 }
7723 else if ( order == 'current' || order == 'applied' ) {
7724 a = search == 'none' ?
7725 displayMaster.slice() : // no search
7726 search == 'applied' ?
7727 displayFiltered.slice() : // applied search
7728 $.map( displayMaster, function (el, i) { // removed search
7729 return $.inArray( el, displayFiltered ) === -1 ? el : null;
7730 } );
7731 }
7732 else if ( order == 'index' || order == 'original' ) {
7733 for ( i=0, ien=settings.aoData.length ; i<ien ; i++ ) {
7734 if ( search == 'none' ) {
7735 a.push( i );
7736 }
7737 else { // applied | removed
7738 tmp = $.inArray( i, displayFiltered );
7739
7740 if ((tmp === -1 && search == 'removed') ||
7741 (tmp >= 0 && search == 'applied') )
7742 {
7743 a.push( i );
7744 }
7745 }
7746 }
7747 }
7748
7749 return a;
7750 };
7751
7752
7753 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
7754 * Rows
7755 *
7756 * {} - no selector - use all available rows
7757 * {integer} - row aoData index
7758 * {node} - TR node
7759 * {string} - jQuery selector to apply to the TR elements
7760 * {array} - jQuery array of nodes, or simply an array of TR nodes
7761 *
7762 */
7763
7764
7765 var __row_selector = function ( settings, selector, opts )
7766 {
7767 var run = function ( sel ) {
7768 var selInt = _intVal( sel );
7769 var i, ien;
7770
7771 // Short cut - selector is a number and no options provided (default is
7772 // all records, so no need to check if the index is in there, since it
7773 // must be - dev error if the index doesn't exist).
7774 if ( selInt !== null && ! opts ) {
7775 return [ selInt ];
7776 }
7777
7778 var rows = _selector_row_indexes( settings, opts );
7779
7780 if ( selInt !== null && $.inArray( selInt, rows ) !== -1 ) {
7781 // Selector - integer
7782 return [ selInt ];
7783 }
7784 else if ( ! sel ) {
7785 // Selector - none
7786 return rows;
7787 }
7788
7789 // Selector - function
7790 if ( typeof sel === 'function' ) {
7791 return $.map( rows, function (idx) {
7792 var row = settings.aoData[ idx ];
7793 return sel( idx, row._aData, row.nTr ) ? idx : null;
7794 } );
7795 }
7796
7797 // Get nodes in the order from the `rows` array with null values removed
7798 var nodes = _removeEmpty(
7799 _pluck_order( settings.aoData, rows, 'nTr' )
7800 );
7801
7802 // Selector - node
7803 if ( sel.nodeName ) {
7804 if ( $.inArray( sel, nodes ) !== -1 ) {
7805 return [ sel._DT_RowIndex ]; // sel is a TR node that is in the table
7806 // and DataTables adds a prop for fast lookup
7807 }
7808 }
7809
7810 // ID selector. Want to always be able to select rows by id, regardless
7811 // of if the tr element has been created or not, so can't rely upon
7812 // jQuery here - hence a custom implementation. This does not match
7813 // Sizzle's fast selector or HTML4 - in HTML5 the ID can be anything,
7814 // but to select it using a CSS selector engine (like Sizzle or
7815 // querySelect) it would need to need to be escaped for some characters.
7816 // DataTables simplifies this for row selectors since you can select
7817 // only a row. A # indicates an id any anything that follows is the id -
7818 // unescaped.
7819 if ( typeof sel === 'string' && sel.charAt(0) === '#' ) {
7820 // get row index from id
7821 var rowObj = settings.aIds[ sel.replace( /^#/, '' ) ];
7822 if ( rowObj !== undefined ) {
7823 return [ rowObj.idx ];
7824 }
7825
7826 // need to fall through to jQuery in case there is DOM id that
7827 // matches
7828 }
7829
7830 // Selector - jQuery selector string, array of nodes or jQuery object/
7831 // As jQuery's .filter() allows jQuery objects to be passed in filter,
7832 // it also allows arrays, so this will cope with all three options
7833 return $(nodes)
7834 .filter( sel )
7835 .map( function () {
7836 return this._DT_RowIndex;
7837 } )
7838 .toArray();
7839 };
7840
7841 return _selector_run( 'row', selector, run, settings, opts );
7842 };
7843
7844
7845 _api_register( 'rows()', function ( selector, opts ) {
7846 // argument shifting
7847 if ( selector === undefined ) {
7848 selector = '';
7849 }
7850 else if ( $.isPlainObject( selector ) ) {
7851 opts = selector;
7852 selector = '';
7853 }
7854
7855 opts = _selector_opts( opts );
7856
7857 var inst = this.iterator( 'table', function ( settings ) {
7858 return __row_selector( settings, selector, opts );
7859 }, 1 );
7860
7861 // Want argument shifting here and in __row_selector?
7862 inst.selector.rows = selector;
7863 inst.selector.opts = opts;
7864
7865 return inst;
7866 } );
7867
7868 _api_register( 'rows().nodes()', function () {
7869 return this.iterator( 'row', function ( settings, row ) {
7870 return settings.aoData[ row ].nTr || undefined;
7871 }, 1 );
7872 } );
7873
7874 _api_register( 'rows().data()', function () {
7875 return this.iterator( true, 'rows', function ( settings, rows ) {
7876 return _pluck_order( settings.aoData, rows, '_aData' );
7877 }, 1 );
7878 } );
7879
7880 _api_registerPlural( 'rows().cache()', 'row().cache()', function ( type ) {
7881 return this.iterator( 'row', function ( settings, row ) {
7882 var r = settings.aoData[ row ];
7883 return type === 'search' ? r._aFilterData : r._aSortData;
7884 }, 1 );
7885 } );
7886
7887 _api_registerPlural( 'rows().invalidate()', 'row().invalidate()', function ( src ) {
7888 return this.iterator( 'row', function ( settings, row ) {
7889 _fnInvalidate( settings, row, src );
7890 } );
7891 } );
7892
7893 _api_registerPlural( 'rows().indexes()', 'row().index()', function () {
7894 return this.iterator( 'row', function ( settings, row ) {
7895 return row;
7896 }, 1 );
7897 } );
7898
7899 _api_registerPlural( 'rows().ids()', 'row().id()', function ( hash ) {
7900 var a = [];
7901 var context = this.context;
7902
7903 // `iterator` will drop undefined values, but in this case we want them
7904 for ( var i=0, ien=context.length ; i<ien ; i++ ) {
7905 for ( var j=0, jen=this[i].length ; j<jen ; j++ ) {
7906 var id = context[i].rowIdFn( context[i].aoData[ this[i][j] ]._aData );
7907 a.push( (hash === true ? '#' : '' )+ id );
7908 }
7909 }
7910
7911 return new _Api( context, a );
7912 } );
7913
7914 _api_registerPlural( 'rows().remove()', 'row().remove()', function () {
7915 var that = this;
7916
7917 this.iterator( 'row', function ( settings, row, thatIdx ) {
7918 var data = settings.aoData;
7919 var rowData = data[ row ];
7920 var i, ien, j, jen;
7921 var loopRow, loopCells;
7922
7923 data.splice( row, 1 );
7924
7925 // Update the cached indexes
7926 for ( i=0, ien=data.length ; i<ien ; i++ ) {
7927 loopRow = data[i];
7928 loopCells = loopRow.anCells;
7929
7930 // Rows
7931 if ( loopRow.nTr !== null ) {
7932 loopRow.nTr._DT_RowIndex = i;
7933 }
7934
7935 // Cells
7936 if ( loopCells !== null ) {
7937 for ( j=0, jen=loopCells.length ; j<jen ; j++ ) {
7938 loopCells[j]._DT_CellIndex.row = i;
7939 }
7940 }
7941 }
7942
7943 // Delete from the display arrays
7944 _fnDeleteIndex( settings.aiDisplayMaster, row );
7945 _fnDeleteIndex( settings.aiDisplay, row );
7946 _fnDeleteIndex( that[ thatIdx ], row, false ); // maintain local indexes
7947
7948 // Check for an 'overflow' they case for displaying the table
7949 _fnLengthOverflow( settings );
7950
7951 // Remove the row's ID reference if there is one
7952 var id = settings.rowIdFn( rowData._aData );
7953 if ( id !== undefined ) {
7954 delete settings.aIds[ id ];
7955 }
7956 } );
7957
7958 this.iterator( 'table', function ( settings ) {
7959 for ( var i=0, ien=settings.aoData.length ; i<ien ; i++ ) {
7960 settings.aoData[i].idx = i;
7961 }
7962 } );
7963
7964 return this;
7965 } );
7966
7967
7968 _api_register( 'rows.add()', function ( rows ) {
7969 var newRows = this.iterator( 'table', function ( settings ) {
7970 var row, i, ien;
7971 var out = [];
7972
7973 for ( i=0, ien=rows.length ; i<ien ; i++ ) {
7974 row = rows[i];
7975
7976 if ( row.nodeName && row.nodeName.toUpperCase() === 'TR' ) {
7977 out.push( _fnAddTr( settings, row )[0] );
7978 }
7979 else {
7980 out.push( _fnAddData( settings, row ) );
7981 }
7982 }
7983
7984 return out;
7985 }, 1 );
7986
7987 // Return an Api.rows() extended instance, so rows().nodes() etc can be used
7988 var modRows = this.rows( -1 );
7989 modRows.pop();
7990 $.merge( modRows, newRows );
7991
7992 return modRows;
7993 } );
7994
7995
7996
7997
7998
7999 /**
8000 *
8001 */
8002 _api_register( 'row()', function ( selector, opts ) {
8003 return _selector_first( this.rows( selector, opts ) );
8004 } );
8005
8006
8007 _api_register( 'row().data()', function ( data ) {
8008 var ctx = this.context;
8009
8010 if ( data === undefined ) {
8011 // Get
8012 return ctx.length && this.length ?
8013 ctx[0].aoData[ this[0] ]._aData :
8014 undefined;
8015 }
8016
8017 // Set
8018 ctx[0].aoData[ this[0] ]._aData = data;
8019
8020 // Automatically invalidate
8021 _fnInvalidate( ctx[0], this[0], 'data' );
8022
8023 return this;
8024 } );
8025
8026
8027 _api_register( 'row().node()', function () {
8028 var ctx = this.context;
8029
8030 return ctx.length && this.length ?
8031 ctx[0].aoData[ this[0] ].nTr || null :
8032 null;
8033 } );
8034
8035
8036 _api_register( 'row.add()', function ( row ) {
8037 // Allow a jQuery object to be passed in - only a single row is added from
8038 // it though - the first element in the set
8039 if ( row instanceof $ && row.length ) {
8040 row = row[0];
8041 }
8042
8043 var rows = this.iterator( 'table', function ( settings ) {
8044 if ( row.nodeName && row.nodeName.toUpperCase() === 'TR' ) {
8045 return _fnAddTr( settings, row )[0];
8046 }
8047 return _fnAddData( settings, row );
8048 } );
8049
8050 // Return an Api.rows() extended instance, with the newly added row selected
8051 return this.row( rows[0] );
8052 } );
8053
8054
8055
8056 var __details_add = function ( ctx, row, data, klass )
8057 {
8058 // Convert to array of TR elements
8059 var rows = [];
8060 var addRow = function ( r, k ) {
8061 // Recursion to allow for arrays of jQuery objects
8062 if ( $.isArray( r ) || r instanceof $ ) {
8063 for ( var i=0, ien=r.length ; i<ien ; i++ ) {
8064 addRow( r[i], k );
8065 }
8066 return;
8067 }
8068
8069 // If we get a TR element, then just add it directly - up to the dev
8070 // to add the correct number of columns etc
8071 if ( r.nodeName && r.nodeName.toLowerCase() === 'tr' ) {
8072 rows.push( r );
8073 }
8074 else {
8075 // Otherwise create a row with a wrapper
8076 var created = $('<tr><td/></tr>').addClass( k );
8077 $('td', created)
8078 .addClass( k )
8079 .html( r )
8080 [0].colSpan = _fnVisbleColumns( ctx );
8081
8082 rows.push( created[0] );
8083 }
8084 };
8085
8086 addRow( data, klass );
8087
8088 if ( row._details ) {
8089 row._details.remove();
8090 }
8091
8092 row._details = $(rows);
8093
8094 // If the children were already shown, that state should be retained
8095 if ( row._detailsShow ) {
8096 row._details.insertAfter( row.nTr );
8097 }
8098 };
8099
8100
8101 var __details_remove = function ( api, idx )
8102 {
8103 var ctx = api.context;
8104
8105 if ( ctx.length ) {
8106 var row = ctx[0].aoData[ idx !== undefined ? idx : api[0] ];
8107
8108 if ( row && row._details ) {
8109 row._details.remove();
8110
8111 row._detailsShow = undefined;
8112 row._details = undefined;
8113 }
8114 }
8115 };
8116
8117
8118 var __details_display = function ( api, show ) {
8119 var ctx = api.context;
8120
8121 if ( ctx.length && api.length ) {
8122 var row = ctx[0].aoData[ api[0] ];
8123
8124 if ( row._details ) {
8125 row._detailsShow = show;
8126
8127 if ( show ) {
8128 row._details.insertAfter( row.nTr );
8129 }
8130 else {
8131 row._details.detach();
8132 }
8133
8134 __details_events( ctx[0] );
8135 }
8136 }
8137 };
8138
8139
8140 var __details_events = function ( settings )
8141 {
8142 var api = new _Api( settings );
8143 var namespace = '.dt.DT_details';
8144 var drawEvent = 'draw'+namespace;
8145 var colvisEvent = 'column-visibility'+namespace;
8146 var destroyEvent = 'destroy'+namespace;
8147 var data = settings.aoData;
8148
8149 api.off( drawEvent +' '+ colvisEvent +' '+ destroyEvent );
8150
8151 if ( _pluck( data, '_details' ).length > 0 ) {
8152 // On each draw, insert the required elements into the document
8153 api.on( drawEvent, function ( e, ctx ) {
8154 if ( settings !== ctx ) {
8155 return;
8156 }
8157
8158 api.rows( {page:'current'} ).eq(0).each( function (idx) {
8159 // Internal data grab
8160 var row = data[ idx ];
8161
8162 if ( row._detailsShow ) {
8163 row._details.insertAfter( row.nTr );
8164 }
8165 } );
8166 } );
8167
8168 // Column visibility change - update the colspan
8169 api.on( colvisEvent, function ( e, ctx, idx, vis ) {
8170 if ( settings !== ctx ) {
8171 return;
8172 }
8173
8174 // Update the colspan for the details rows (note, only if it already has
8175 // a colspan)
8176 var row, visible = _fnVisbleColumns( ctx );
8177
8178 for ( var i=0, ien=data.length ; i<ien ; i++ ) {
8179 row = data[i];
8180
8181 if ( row._details ) {
8182 row._details.children('td[colspan]').attr('colspan', visible );
8183 }
8184 }
8185 } );
8186
8187 // Table destroyed - nuke any child rows
8188 api.on( destroyEvent, function ( e, ctx ) {
8189 if ( settings !== ctx ) {
8190 return;
8191 }
8192
8193 for ( var i=0, ien=data.length ; i<ien ; i++ ) {
8194 if ( data[i]._details ) {
8195 __details_remove( api, i );
8196 }
8197 }
8198 } );
8199 }
8200 };
8201
8202 // Strings for the method names to help minification
8203 var _emp = '';
8204 var _child_obj = _emp+'row().child';
8205 var _child_mth = _child_obj+'()';
8206
8207 // data can be:
8208 // tr
8209 // string
8210 // jQuery or array of any of the above
8211 _api_register( _child_mth, function ( data, klass ) {
8212 var ctx = this.context;
8213
8214 if ( data === undefined ) {
8215 // get
8216 return ctx.length && this.length ?
8217 ctx[0].aoData[ this[0] ]._details :
8218 undefined;
8219 }
8220 else if ( data === true ) {
8221 // show
8222 this.child.show();
8223 }
8224 else if ( data === false ) {
8225 // remove
8226 __details_remove( this );
8227 }
8228 else if ( ctx.length && this.length ) {
8229 // set
8230 __details_add( ctx[0], ctx[0].aoData[ this[0] ], data, klass );
8231 }
8232
8233 return this;
8234 } );
8235
8236
8237 _api_register( [
8238 _child_obj+'.show()',
8239 _child_mth+'.show()' // only when `child()` was called with parameters (without
8240 ], function ( show ) { // it returns an object and this method is not executed)
8241 __details_display( this, true );
8242 return this;
8243 } );
8244
8245
8246 _api_register( [
8247 _child_obj+'.hide()',
8248 _child_mth+'.hide()' // only when `child()` was called with parameters (without
8249 ], function () { // it returns an object and this method is not executed)
8250 __details_display( this, false );
8251 return this;
8252 } );
8253
8254
8255 _api_register( [
8256 _child_obj+'.remove()',
8257 _child_mth+'.remove()' // only when `child()` was called with parameters (without
8258 ], function () { // it returns an object and this method is not executed)
8259 __details_remove( this );
8260 return this;
8261 } );
8262
8263
8264 _api_register( _child_obj+'.isShown()', function () {
8265 var ctx = this.context;
8266
8267 if ( ctx.length && this.length ) {
8268 // _detailsShown as false or undefined will fall through to return false
8269 return ctx[0].aoData[ this[0] ]._detailsShow || false;
8270 }
8271 return false;
8272 } );
8273
8274
8275
8276 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
8277 * Columns
8278 *
8279 * {integer} - column index (>=0 count from left, <0 count from right)
8280 * "{integer}:visIdx" - visible column index (i.e. translate to column index) (>=0 count from left, <0 count from right)
8281 * "{integer}:visible" - alias for {integer}:visIdx (>=0 count from left, <0 count from right)
8282 * "{string}:name" - column name
8283 * "{string}" - jQuery selector on column header nodes
8284 *
8285 */
8286
8287 // can be an array of these items, comma separated list, or an array of comma
8288 // separated lists
8289
8290 var __re_column_selector = /^(.+):(name|visIdx|visible)$/;
8291
8292
8293 // r1 and r2 are redundant - but it means that the parameters match for the
8294 // iterator callback in columns().data()
8295 var __columnData = function ( settings, column, r1, r2, rows ) {
8296 var a = [];
8297 for ( var row=0, ien=rows.length ; row<ien ; row++ ) {
8298 a.push( _fnGetCellData( settings, rows[row], column ) );
8299 }
8300 return a;
8301 };
8302
8303
8304 var __column_selector = function ( settings, selector, opts )
8305 {
8306 var
8307 columns = settings.aoColumns,
8308 names = _pluck( columns, 'sName' ),
8309 nodes = _pluck( columns, 'nTh' );
8310
8311 var run = function ( s ) {
8312 var selInt = _intVal( s );
8313
8314 // Selector - all
8315 if ( s === '' ) {
8316 return _range( columns.length );
8317 }
8318
8319 // Selector - index
8320 if ( selInt !== null ) {
8321 return [ selInt >= 0 ?
8322 selInt : // Count from left
8323 columns.length + selInt // Count from right (+ because its a negative value)
8324 ];
8325 }
8326
8327 // Selector = function
8328 if ( typeof s === 'function' ) {
8329 var rows = _selector_row_indexes( settings, opts );
8330
8331 return $.map( columns, function (col, idx) {
8332 return s(
8333 idx,
8334 __columnData( settings, idx, 0, 0, rows ),
8335 nodes[ idx ]
8336 ) ? idx : null;
8337 } );
8338 }
8339
8340 // jQuery or string selector
8341 var match = typeof s === 'string' ?
8342 s.match( __re_column_selector ) :
8343 '';
8344
8345 if ( match ) {
8346 switch( match[2] ) {
8347 case 'visIdx':
8348 case 'visible':
8349 var idx = parseInt( match[1], 10 );
8350 // Visible index given, convert to column index
8351 if ( idx < 0 ) {
8352 // Counting from the right
8353 var visColumns = $.map( columns, function (col,i) {
8354 return col.bVisible ? i : null;
8355 } );
8356 return [ visColumns[ visColumns.length + idx ] ];
8357 }
8358 // Counting from the left
8359 return [ _fnVisibleToColumnIndex( settings, idx ) ];
8360
8361 case 'name':
8362 // match by name. `names` is column index complete and in order
8363 return $.map( names, function (name, i) {
8364 return name === match[1] ? i : null;
8365 } );
8366 }
8367 }
8368 else {
8369 // jQuery selector on the TH elements for the columns
8370 return $( nodes )
8371 .filter( s )
8372 .map( function () {
8373 return $.inArray( this, nodes ); // `nodes` is column index complete and in order
8374 } )
8375 .toArray();
8376 }
8377 };
8378
8379 return _selector_run( 'column', selector, run, settings, opts );
8380 };
8381
8382
8383 var __setColumnVis = function ( settings, column, vis, recalc ) {
8384 var
8385 cols = settings.aoColumns,
8386 col = cols[ column ],
8387 data = settings.aoData,
8388 row, cells, i, ien, tr;
8389
8390 // Get
8391 if ( vis === undefined ) {
8392 return col.bVisible;
8393 }
8394
8395 // Set
8396 // No change
8397 if ( col.bVisible === vis ) {
8398 return;
8399 }
8400
8401 if ( vis ) {
8402 // Insert column
8403 // Need to decide if we should use appendChild or insertBefore
8404 var insertBefore = $.inArray( true, _pluck(cols, 'bVisible'), column+1 );
8405
8406 for ( i=0, ien=data.length ; i<ien ; i++ ) {
8407 tr = data[i].nTr;
8408 cells = data[i].anCells;
8409
8410 if ( tr ) {
8411 // insertBefore can act like appendChild if 2nd arg is null
8412 tr.insertBefore( cells[ column ], cells[ insertBefore ] || null );
8413 }
8414 }
8415 }
8416 else {
8417 // Remove column
8418 $( _pluck( settings.aoData, 'anCells', column ) ).detach();
8419 }
8420
8421 // Common actions
8422 col.bVisible = vis;
8423 _fnDrawHead( settings, settings.aoHeader );
8424 _fnDrawHead( settings, settings.aoFooter );
8425
8426 if ( recalc === undefined || recalc ) {
8427 // Automatically adjust column sizing
8428 _fnAdjustColumnSizing( settings );
8429
8430 // Realign columns for scrolling
8431 if ( settings.oScroll.sX || settings.oScroll.sY ) {
8432 _fnScrollDraw( settings );
8433 }
8434 }
8435
8436 _fnCallbackFire( settings, null, 'column-visibility', [settings, column, vis, recalc] );
8437
8438 _fnSaveState( settings );
8439 };
8440
8441
8442 _api_register( 'columns()', function ( selector, opts ) {
8443 // argument shifting
8444 if ( selector === undefined ) {
8445 selector = '';
8446 }
8447 else if ( $.isPlainObject( selector ) ) {
8448 opts = selector;
8449 selector = '';
8450 }
8451
8452 opts = _selector_opts( opts );
8453
8454 var inst = this.iterator( 'table', function ( settings ) {
8455 return __column_selector( settings, selector, opts );
8456 }, 1 );
8457
8458 // Want argument shifting here and in _row_selector?
8459 inst.selector.cols = selector;
8460 inst.selector.opts = opts;
8461
8462 return inst;
8463 } );
8464
8465 _api_registerPlural( 'columns().header()', 'column().header()', function ( selector, opts ) {
8466 return this.iterator( 'column', function ( settings, column ) {
8467 return settings.aoColumns[column].nTh;
8468 }, 1 );
8469 } );
8470
8471 _api_registerPlural( 'columns().footer()', 'column().footer()', function ( selector, opts ) {
8472 return this.iterator( 'column', function ( settings, column ) {
8473 return settings.aoColumns[column].nTf;
8474 }, 1 );
8475 } );
8476
8477 _api_registerPlural( 'columns().data()', 'column().data()', function () {
8478 return this.iterator( 'column-rows', __columnData, 1 );
8479 } );
8480
8481 _api_registerPlural( 'columns().dataSrc()', 'column().dataSrc()', function () {
8482 return this.iterator( 'column', function ( settings, column ) {
8483 return settings.aoColumns[column].mData;
8484 }, 1 );
8485 } );
8486
8487 _api_registerPlural( 'columns().cache()', 'column().cache()', function ( type ) {
8488 return this.iterator( 'column-rows', function ( settings, column, i, j, rows ) {
8489 return _pluck_order( settings.aoData, rows,
8490 type === 'search' ? '_aFilterData' : '_aSortData', column
8491 );
8492 }, 1 );
8493 } );
8494
8495 _api_registerPlural( 'columns().nodes()', 'column().nodes()', function () {
8496 return this.iterator( 'column-rows', function ( settings, column, i, j, rows ) {
8497 return _pluck_order( settings.aoData, rows, 'anCells', column ) ;
8498 }, 1 );
8499 } );
8500
8501 _api_registerPlural( 'columns().visible()', 'column().visible()', function ( vis, calc ) {
8502 return this.iterator( 'column', function ( settings, column ) {
8503 if ( vis === undefined ) {
8504 return settings.aoColumns[ column ].bVisible;
8505 } // else
8506 __setColumnVis( settings, column, vis, calc );
8507 } );
8508 } );
8509
8510 _api_registerPlural( 'columns().indexes()', 'column().index()', function ( type ) {
8511 return this.iterator( 'column', function ( settings, column ) {
8512 return type === 'visible' ?
8513 _fnColumnIndexToVisible( settings, column ) :
8514 column;
8515 }, 1 );
8516 } );
8517
8518 _api_register( 'columns.adjust()', function () {
8519 return this.iterator( 'table', function ( settings ) {
8520 _fnAdjustColumnSizing( settings );
8521 }, 1 );
8522 } );
8523
8524 _api_register( 'column.index()', function ( type, idx ) {
8525 if ( this.context.length !== 0 ) {
8526 var ctx = this.context[0];
8527
8528 if ( type === 'fromVisible' || type === 'toData' ) {
8529 return _fnVisibleToColumnIndex( ctx, idx );
8530 }
8531 else if ( type === 'fromData' || type === 'toVisible' ) {
8532 return _fnColumnIndexToVisible( ctx, idx );
8533 }
8534 }
8535 } );
8536
8537 _api_register( 'column()', function ( selector, opts ) {
8538 return _selector_first( this.columns( selector, opts ) );
8539 } );
8540
8541
8542
8543
8544 var __cell_selector = function ( settings, selector, opts )
8545 {
8546 var data = settings.aoData;
8547 var rows = _selector_row_indexes( settings, opts );
8548 var cells = _removeEmpty( _pluck_order( data, rows, 'anCells' ) );
8549 var allCells = $( [].concat.apply([], cells) );
8550 var row;
8551 var columns = settings.aoColumns.length;
8552 var a, i, ien, j, o, host;
8553
8554 var run = function ( s ) {
8555 var fnSelector = typeof s === 'function';
8556
8557 if ( s === null || s === undefined || fnSelector ) {
8558 // All cells and function selectors
8559 a = [];
8560
8561 for ( i=0, ien=rows.length ; i<ien ; i++ ) {
8562 row = rows[i];
8563
8564 for ( j=0 ; j<columns ; j++ ) {
8565 o = {
8566 row: row,
8567 column: j
8568 };
8569
8570 if ( fnSelector ) {
8571 // Selector - function
8572 host = data[ row ];
8573
8574 if ( s( o, _fnGetCellData(settings, row, j), host.anCells ? host.anCells[j] : null ) ) {
8575 a.push( o );
8576 }
8577 }
8578 else {
8579 // Selector - all
8580 a.push( o );
8581 }
8582 }
8583 }
8584
8585 return a;
8586 }
8587
8588 // Selector - index
8589 if ( $.isPlainObject( s ) ) {
8590 return [s];
8591 }
8592
8593 // Selector - jQuery filtered cells
8594 return allCells
8595 .filter( s )
8596 .map( function (i, el) {
8597 return { // use a new object, in case someone changes the values
8598 row: el._DT_CellIndex.row,
8599 column: el._DT_CellIndex.column
8600 };
8601 } )
8602 .toArray();
8603 };
8604
8605 return _selector_run( 'cell', selector, run, settings, opts );
8606 };
8607
8608
8609
8610
8611 _api_register( 'cells()', function ( rowSelector, columnSelector, opts ) {
8612 // Argument shifting
8613 if ( $.isPlainObject( rowSelector ) ) {
8614 // Indexes
8615 if ( rowSelector.row === undefined ) {
8616 // Selector options in first parameter
8617 opts = rowSelector;
8618 rowSelector = null;
8619 }
8620 else {
8621 // Cell index objects in first parameter
8622 opts = columnSelector;
8623 columnSelector = null;
8624 }
8625 }
8626 if ( $.isPlainObject( columnSelector ) ) {
8627 opts = columnSelector;
8628 columnSelector = null;
8629 }
8630
8631 // Cell selector
8632 if ( columnSelector === null || columnSelector === undefined ) {
8633 return this.iterator( 'table', function ( settings ) {
8634 return __cell_selector( settings, rowSelector, _selector_opts( opts ) );
8635 } );
8636 }
8637
8638 // Row + column selector
8639 var columns = this.columns( columnSelector, opts );
8640 var rows = this.rows( rowSelector, opts );
8641 var a, i, ien, j, jen;
8642
8643 var cells = this.iterator( 'table', function ( settings, idx ) {
8644 a = [];
8645
8646 for ( i=0, ien=rows[idx].length ; i<ien ; i++ ) {
8647 for ( j=0, jen=columns[idx].length ; j<jen ; j++ ) {
8648 a.push( {
8649 row: rows[idx][i],
8650 column: columns[idx][j]
8651 } );
8652 }
8653 }
8654
8655 return a;
8656 }, 1 );
8657
8658 $.extend( cells.selector, {
8659 cols: columnSelector,
8660 rows: rowSelector,
8661 opts: opts
8662 } );
8663
8664 return cells;
8665 } );
8666
8667
8668 _api_registerPlural( 'cells().nodes()', 'cell().node()', function () {
8669 return this.iterator( 'cell', function ( settings, row, column ) {
8670 var cells = settings.aoData[ row ].anCells;
8671 return cells ?
8672 cells[ column ] :
8673 undefined;
8674 }, 1 );
8675 } );
8676
8677
8678 _api_register( 'cells().data()', function () {
8679 return this.iterator( 'cell', function ( settings, row, column ) {
8680 return _fnGetCellData( settings, row, column );
8681 }, 1 );
8682 } );
8683
8684
8685 _api_registerPlural( 'cells().cache()', 'cell().cache()', function ( type ) {
8686 type = type === 'search' ? '_aFilterData' : '_aSortData';
8687
8688 return this.iterator( 'cell', function ( settings, row, column ) {
8689 return settings.aoData[ row ][ type ][ column ];
8690 }, 1 );
8691 } );
8692
8693
8694 _api_registerPlural( 'cells().render()', 'cell().render()', function ( type ) {
8695 return this.iterator( 'cell', function ( settings, row, column ) {
8696 return _fnGetCellData( settings, row, column, type );
8697 }, 1 );
8698 } );
8699
8700
8701 _api_registerPlural( 'cells().indexes()', 'cell().index()', function () {
8702 return this.iterator( 'cell', function ( settings, row, column ) {
8703 return {
8704 row: row,
8705 column: column,
8706 columnVisible: _fnColumnIndexToVisible( settings, column )
8707 };
8708 }, 1 );
8709 } );
8710
8711
8712 _api_registerPlural( 'cells().invalidate()', 'cell().invalidate()', function ( src ) {
8713 return this.iterator( 'cell', function ( settings, row, column ) {
8714 _fnInvalidate( settings, row, src, column );
8715 } );
8716 } );
8717
8718
8719
8720 _api_register( 'cell()', function ( rowSelector, columnSelector, opts ) {
8721 return _selector_first( this.cells( rowSelector, columnSelector, opts ) );
8722 } );
8723
8724
8725 _api_register( 'cell().data()', function ( data ) {
8726 var ctx = this.context;
8727 var cell = this[0];
8728
8729 if ( data === undefined ) {
8730 // Get
8731 return ctx.length && cell.length ?
8732 _fnGetCellData( ctx[0], cell[0].row, cell[0].column ) :
8733 undefined;
8734 }
8735
8736 // Set
8737 _fnSetCellData( ctx[0], cell[0].row, cell[0].column, data );
8738 _fnInvalidate( ctx[0], cell[0].row, 'data', cell[0].column );
8739
8740 return this;
8741 } );
8742
8743
8744
8745 /**
8746 * Get current ordering (sorting) that has been applied to the table.
8747 *
8748 * @returns {array} 2D array containing the sorting information for the first
8749 * table in the current context. Each element in the parent array represents
8750 * a column being sorted upon (i.e. multi-sorting with two columns would have
8751 * 2 inner arrays). The inner arrays may have 2 or 3 elements. The first is
8752 * the column index that the sorting condition applies to, the second is the
8753 * direction of the sort (`desc` or `asc`) and, optionally, the third is the
8754 * index of the sorting order from the `column.sorting` initialisation array.
8755 *//**
8756 * Set the ordering for the table.
8757 *
8758 * @param {integer} order Column index to sort upon.
8759 * @param {string} direction Direction of the sort to be applied (`asc` or `desc`)
8760 * @returns {DataTables.Api} this
8761 *//**
8762 * Set the ordering for the table.
8763 *
8764 * @param {array} order 1D array of sorting information to be applied.
8765 * @param {array} [...] Optional additional sorting conditions
8766 * @returns {DataTables.Api} this
8767 *//**
8768 * Set the ordering for the table.
8769 *
8770 * @param {array} order 2D array of sorting information to be applied.
8771 * @returns {DataTables.Api} this
8772 */
8773 _api_register( 'order()', function ( order, dir ) {
8774 var ctx = this.context;
8775
8776 if ( order === undefined ) {
8777 // get
8778 return ctx.length !== 0 ?
8779 ctx[0].aaSorting :
8780 undefined;
8781 }
8782
8783 // set
8784 if ( typeof order === 'number' ) {
8785 // Simple column / direction passed in
8786 order = [ [ order, dir ] ];
8787 }
8788 else if ( ! $.isArray( order[0] ) ) {
8789 // Arguments passed in (list of 1D arrays)
8790 order = Array.prototype.slice.call( arguments );
8791 }
8792 // otherwise a 2D array was passed in
8793
8794 return this.iterator( 'table', function ( settings ) {
8795 settings.aaSorting = order.slice();
8796 } );
8797 } );
8798
8799
8800 /**
8801 * Attach a sort listener to an element for a given column
8802 *
8803 * @param {node|jQuery|string} node Identifier for the element(s) to attach the
8804 * listener to. This can take the form of a single DOM node, a jQuery
8805 * collection of nodes or a jQuery selector which will identify the node(s).
8806 * @param {integer} column the column that a click on this node will sort on
8807 * @param {function} [callback] callback function when sort is run
8808 * @returns {DataTables.Api} this
8809 */
8810 _api_register( 'order.listener()', function ( node, column, callback ) {
8811 return this.iterator( 'table', function ( settings ) {
8812 _fnSortAttachListener( settings, node, column, callback );
8813 } );
8814 } );
8815
8816
8817 _api_register( 'order.fixed()', function ( set ) {
8818 if ( ! set ) {
8819 var ctx = this.context;
8820 var fixed = ctx.length ?
8821 ctx[0].aaSortingFixed :
8822 undefined;
8823
8824 return $.isArray( fixed ) ?
8825 { pre: fixed } :
8826 fixed;
8827 }
8828
8829 return this.iterator( 'table', function ( settings ) {
8830 settings.aaSortingFixed = $.extend( true, {}, set );
8831 } );
8832 } );
8833
8834
8835 // Order by the selected column(s)
8836 _api_register( [
8837 'columns().order()',
8838 'column().order()'
8839 ], function ( dir ) {
8840 var that = this;
8841
8842 return this.iterator( 'table', function ( settings, i ) {
8843 var sort = [];
8844
8845 $.each( that[i], function (j, col) {
8846 sort.push( [ col, dir ] );
8847 } );
8848
8849 settings.aaSorting = sort;
8850 } );
8851 } );
8852
8853
8854
8855 _api_register( 'search()', function ( input, regex, smart, caseInsen ) {
8856 var ctx = this.context;
8857
8858 if ( input === undefined ) {
8859 // get
8860 return ctx.length !== 0 ?
8861 ctx[0].oPreviousSearch.sSearch :
8862 undefined;
8863 }
8864
8865 // set
8866 return this.iterator( 'table', function ( settings ) {
8867 if ( ! settings.oFeatures.bFilter ) {
8868 return;
8869 }
8870
8871 _fnFilterComplete( settings, $.extend( {}, settings.oPreviousSearch, {
8872 "sSearch": input+"",
8873 "bRegex": regex === null ? false : regex,
8874 "bSmart": smart === null ? true : smart,
8875 "bCaseInsensitive": caseInsen === null ? true : caseInsen
8876 } ), 1 );
8877 } );
8878 } );
8879
8880
8881 _api_registerPlural(
8882 'columns().search()',
8883 'column().search()',
8884 function ( input, regex, smart, caseInsen ) {
8885 return this.iterator( 'column', function ( settings, column ) {
8886 var preSearch = settings.aoPreSearchCols;
8887
8888 if ( input === undefined ) {
8889 // get
8890 return preSearch[ column ].sSearch;
8891 }
8892
8893 // set
8894 if ( ! settings.oFeatures.bFilter ) {
8895 return;
8896 }
8897
8898 $.extend( preSearch[ column ], {
8899 "sSearch": input+"",
8900 "bRegex": regex === null ? false : regex,
8901 "bSmart": smart === null ? true : smart,
8902 "bCaseInsensitive": caseInsen === null ? true : caseInsen
8903 } );
8904
8905 _fnFilterComplete( settings, settings.oPreviousSearch, 1 );
8906 } );
8907 }
8908 );
8909
8910 /*
8911 * State API methods
8912 */
8913
8914 _api_register( 'state()', function () {
8915 return this.context.length ?
8916 this.context[0].oSavedState :
8917 null;
8918 } );
8919
8920
8921 _api_register( 'state.clear()', function () {
8922 return this.iterator( 'table', function ( settings ) {
8923 // Save an empty object
8924 settings.fnStateSaveCallback.call( settings.oInstance, settings, {} );
8925 } );
8926 } );
8927
8928
8929 _api_register( 'state.loaded()', function () {
8930 return this.context.length ?
8931 this.context[0].oLoadedState :
8932 null;
8933 } );
8934
8935
8936 _api_register( 'state.save()', function () {
8937 return this.iterator( 'table', function ( settings ) {
8938 _fnSaveState( settings );
8939 } );
8940 } );
8941
8942
8943
8944 /**
8945 * Provide a common method for plug-ins to check the version of DataTables being
8946 * used, in order to ensure compatibility.
8947 *
8948 * @param {string} version Version string to check for, in the format "X.Y.Z".
8949 * Note that the formats "X" and "X.Y" are also acceptable.
8950 * @returns {boolean} true if this version of DataTables is greater or equal to
8951 * the required version, or false if this version of DataTales is not
8952 * suitable
8953 * @static
8954 * @dtopt API-Static
8955 *
8956 * @example
8957 * alert( $.fn.dataTable.versionCheck( '1.9.0' ) );
8958 */
8959 DataTable.versionCheck = DataTable.fnVersionCheck = function( version )
8960 {
8961 var aThis = DataTable.version.split('.');
8962 var aThat = version.split('.');
8963 var iThis, iThat;
8964
8965 for ( var i=0, iLen=aThat.length ; i<iLen ; i++ ) {
8966 iThis = parseInt( aThis[i], 10 ) || 0;
8967 iThat = parseInt( aThat[i], 10 ) || 0;
8968
8969 // Parts are the same, keep comparing
8970 if (iThis === iThat) {
8971 continue;
8972 }
8973
8974 // Parts are different, return immediately
8975 return iThis > iThat;
8976 }
8977
8978 return true;
8979 };
8980
8981
8982 /**
8983 * Check if a `<table>` node is a DataTable table already or not.
8984 *
8985 * @param {node|jquery|string} table Table node, jQuery object or jQuery
8986 * selector for the table to test. Note that if more than more than one
8987 * table is passed on, only the first will be checked
8988 * @returns {boolean} true the table given is a DataTable, or false otherwise
8989 * @static
8990 * @dtopt API-Static
8991 *
8992 * @example
8993 * if ( ! $.fn.DataTable.isDataTable( '#example' ) ) {
8994 * $('#example').dataTable();
8995 * }
8996 */
8997 DataTable.isDataTable = DataTable.fnIsDataTable = function ( table )
8998 {
8999 var t = $(table).get(0);
9000 var is = false;
9001
9002 $.each( DataTable.settings, function (i, o) {
9003 var head = o.nScrollHead ? $('table', o.nScrollHead)[0] : null;
9004 var foot = o.nScrollFoot ? $('table', o.nScrollFoot)[0] : null;
9005
9006 if ( o.nTable === t || head === t || foot === t ) {
9007 is = true;
9008 }
9009 } );
9010
9011 return is;
9012 };
9013
9014
9015 /**
9016 * Get all DataTable tables that have been initialised - optionally you can
9017 * select to get only currently visible tables.
9018 *
9019 * @param {boolean} [visible=false] Flag to indicate if you want all (default)
9020 * or visible tables only.
9021 * @returns {array} Array of `table` nodes (not DataTable instances) which are
9022 * DataTables
9023 * @static
9024 * @dtopt API-Static
9025 *
9026 * @example
9027 * $.each( $.fn.dataTable.tables(true), function () {
9028 * $(table).DataTable().columns.adjust();
9029 * } );
9030 */
9031 DataTable.tables = DataTable.fnTables = function ( visible )
9032 {
9033 var api = false;
9034
9035 if ( $.isPlainObject( visible ) ) {
9036 api = visible.api;
9037 visible = visible.visible;
9038 }
9039
9040 var a = $.map( DataTable.settings, function (o) {
9041 if ( !visible || (visible && $(o.nTable).is(':visible')) ) {
9042 return o.nTable;
9043 }
9044 } );
9045
9046 return api ?
9047 new _Api( a ) :
9048 a;
9049 };
9050
9051
9052 /**
9053 * DataTables utility methods
9054 *
9055 * This namespace provides helper methods that DataTables uses internally to
9056 * create a DataTable, but which are not exclusively used only for DataTables.
9057 * These methods can be used by extension authors to save the duplication of
9058 * code.
9059 *
9060 * @namespace
9061 */
9062 DataTable.util = {
9063 /**
9064 * Throttle the calls to a function. Arguments and context are maintained
9065 * for the throttled function.
9066 *
9067 * @param {function} fn Function to be called
9068 * @param {integer} freq Call frequency in mS
9069 * @return {function} Wrapped function
9070 */
9071 throttle: _fnThrottle,
9072
9073
9074 /**
9075 * Escape a string such that it can be used in a regular expression
9076 *
9077 * @param {string} sVal string to escape
9078 * @returns {string} escaped string
9079 */
9080 escapeRegex: _fnEscapeRegex
9081 };
9082
9083
9084 /**
9085 * Convert from camel case parameters to Hungarian notation. This is made public
9086 * for the extensions to provide the same ability as DataTables core to accept
9087 * either the 1.9 style Hungarian notation, or the 1.10+ style camelCase
9088 * parameters.
9089 *
9090 * @param {object} src The model object which holds all parameters that can be
9091 * mapped.
9092 * @param {object} user The object to convert from camel case to Hungarian.
9093 * @param {boolean} force When set to `true`, properties which already have a
9094 * Hungarian value in the `user` object will be overwritten. Otherwise they
9095 * won't be.
9096 */
9097 DataTable.camelToHungarian = _fnCamelToHungarian;
9098
9099
9100
9101 /**
9102 *
9103 */
9104 _api_register( '$()', function ( selector, opts ) {
9105 var
9106 rows = this.rows( opts ).nodes(), // Get all rows
9107 jqRows = $(rows);
9108
9109 return $( [].concat(
9110 jqRows.filter( selector ).toArray(),
9111 jqRows.find( selector ).toArray()
9112 ) );
9113 } );
9114
9115
9116 // jQuery functions to operate on the tables
9117 $.each( [ 'on', 'one', 'off' ], function (i, key) {
9118 _api_register( key+'()', function ( /* event, handler */ ) {
9119 var args = Array.prototype.slice.call(arguments);
9120
9121 // Add the `dt` namespace automatically if it isn't already present
9122 if ( ! args[0].match(/\.dt\b/) ) {
9123 args[0] += '.dt';
9124 }
9125
9126 var inst = $( this.tables().nodes() );
9127 inst[key].apply( inst, args );
9128 return this;
9129 } );
9130 } );
9131
9132
9133 _api_register( 'clear()', function () {
9134 return this.iterator( 'table', function ( settings ) {
9135 _fnClearTable( settings );
9136 } );
9137 } );
9138
9139
9140 _api_register( 'settings()', function () {
9141 return new _Api( this.context, this.context );
9142 } );
9143
9144
9145 _api_register( 'init()', function () {
9146 var ctx = this.context;
9147 return ctx.length ? ctx[0].oInit : null;
9148 } );
9149
9150
9151 _api_register( 'data()', function () {
9152 return this.iterator( 'table', function ( settings ) {
9153 return _pluck( settings.aoData, '_aData' );
9154 } ).flatten();
9155 } );
9156
9157
9158 _api_register( 'destroy()', function ( remove ) {
9159 remove = remove || false;
9160
9161 return this.iterator( 'table', function ( settings ) {
9162 var orig = settings.nTableWrapper.parentNode;
9163 var classes = settings.oClasses;
9164 var table = settings.nTable;
9165 var tbody = settings.nTBody;
9166 var thead = settings.nTHead;
9167 var tfoot = settings.nTFoot;
9168 var jqTable = $(table);
9169 var jqTbody = $(tbody);
9170 var jqWrapper = $(settings.nTableWrapper);
9171 var rows = $.map( settings.aoData, function (r) { return r.nTr; } );
9172 var i, ien;
9173
9174 // Flag to note that the table is currently being destroyed - no action
9175 // should be taken
9176 settings.bDestroying = true;
9177
9178 // Fire off the destroy callbacks for plug-ins etc
9179 _fnCallbackFire( settings, "aoDestroyCallback", "destroy", [settings] );
9180
9181 // If not being removed from the document, make all columns visible
9182 if ( ! remove ) {
9183 new _Api( settings ).columns().visible( true );
9184 }
9185
9186 // Blitz all `DT` namespaced events (these are internal events, the
9187 // lowercase, `dt` events are user subscribed and they are responsible
9188 // for removing them
9189 jqWrapper.unbind('.DT').find(':not(tbody *)').unbind('.DT');
9190 $(window).unbind('.DT-'+settings.sInstance);
9191
9192 // When scrolling we had to break the table up - restore it
9193 if ( table != thead.parentNode ) {
9194 jqTable.children('thead').detach();
9195 jqTable.append( thead );
9196 }
9197
9198 if ( tfoot && table != tfoot.parentNode ) {
9199 jqTable.children('tfoot').detach();
9200 jqTable.append( tfoot );
9201 }
9202
9203 settings.aaSorting = [];
9204 settings.aaSortingFixed = [];
9205 _fnSortingClasses( settings );
9206
9207 $( rows ).removeClass( settings.asStripeClasses.join(' ') );
9208
9209 $('th, td', thead).removeClass( classes.sSortable+' '+
9210 classes.sSortableAsc+' '+classes.sSortableDesc+' '+classes.sSortableNone
9211 );
9212
9213 if ( settings.bJUI ) {
9214 $('th span.'+classes.sSortIcon+ ', td span.'+classes.sSortIcon, thead).detach();
9215 $('th, td', thead).each( function () {
9216 var wrapper = $('div.'+classes.sSortJUIWrapper, this);
9217 $(this).append( wrapper.contents() );
9218 wrapper.detach();
9219 } );
9220 }
9221
9222 // Add the TR elements back into the table in their original order
9223 jqTbody.children().detach();
9224 jqTbody.append( rows );
9225
9226 // Remove the DataTables generated nodes, events and classes
9227 var removedMethod = remove ? 'remove' : 'detach';
9228 jqTable[ removedMethod ]();
9229 jqWrapper[ removedMethod ]();
9230
9231 // If we need to reattach the table to the document
9232 if ( ! remove && orig ) {
9233 // insertBefore acts like appendChild if !arg[1]
9234 orig.insertBefore( table, settings.nTableReinsertBefore );
9235
9236 // Restore the width of the original table - was read from the style property,
9237 // so we can restore directly to that
9238 jqTable
9239 .css( 'width', settings.sDestroyWidth )
9240 .removeClass( classes.sTable );
9241
9242 // If the were originally stripe classes - then we add them back here.
9243 // Note this is not fool proof (for example if not all rows had stripe
9244 // classes - but it's a good effort without getting carried away
9245 ien = settings.asDestroyStripes.length;
9246
9247 if ( ien ) {
9248 jqTbody.children().each( function (i) {
9249 $(this).addClass( settings.asDestroyStripes[i % ien] );
9250 } );
9251 }
9252 }
9253
9254 /* Remove the settings object from the settings array */
9255 var idx = $.inArray( settings, DataTable.settings );
9256 if ( idx !== -1 ) {
9257 DataTable.settings.splice( idx, 1 );
9258 }
9259 } );
9260 } );
9261
9262
9263 // Add the `every()` method for rows, columns and cells in a compact form
9264 $.each( [ 'column', 'row', 'cell' ], function ( i, type ) {
9265 _api_register( type+'s().every()', function ( fn ) {
9266 var opts = this.selector.opts;
9267 var api = this;
9268
9269 return this.iterator( type, function ( settings, arg1, arg2, arg3, arg4 ) {
9270 // Rows and columns:
9271 // arg1 - index
9272 // arg2 - table counter
9273 // arg3 - loop counter
9274 // arg4 - undefined
9275 // Cells:
9276 // arg1 - row index
9277 // arg2 - column index
9278 // arg3 - table counter
9279 // arg4 - loop counter
9280 fn.call(
9281 api[ type ](
9282 arg1,
9283 type==='cell' ? arg2 : opts,
9284 type==='cell' ? opts : undefined
9285 ),
9286 arg1, arg2, arg3, arg4
9287 );
9288 } );
9289 } );
9290 } );
9291
9292
9293 // i18n method for extensions to be able to use the language object from the
9294 // DataTable
9295 _api_register( 'i18n()', function ( token, def, plural ) {
9296 var ctx = this.context[0];
9297 var resolved = _fnGetObjectDataFn( token )( ctx.oLanguage );
9298
9299 if ( resolved === undefined ) {
9300 resolved = def;
9301 }
9302
9303 if ( plural !== undefined && $.isPlainObject( resolved ) ) {
9304 resolved = resolved[ plural ] !== undefined ?
9305 resolved[ plural ] :
9306 resolved._;
9307 }
9308
9309 return resolved.replace( '%d', plural ); // nb: plural might be undefined,
9310 } );
9311
9312 /**
9313 * Version string for plug-ins to check compatibility. Allowed format is
9314 * `a.b.c-d` where: a:int, b:int, c:int, d:string(dev|beta|alpha). `d` is used
9315 * only for non-release builds. See http://semver.org/ for more information.
9316 * @member
9317 * @type string
9318 * @default Version number
9319 */
9320 DataTable.version = "1.10.10";
9321
9322 /**
9323 * Private data store, containing all of the settings objects that are
9324 * created for the tables on a given page.
9325 *
9326 * Note that the `DataTable.settings` object is aliased to
9327 * `jQuery.fn.dataTableExt` through which it may be accessed and
9328 * manipulated, or `jQuery.fn.dataTable.settings`.
9329 * @member
9330 * @type array
9331 * @default []
9332 * @private
9333 */
9334 DataTable.settings = [];
9335
9336 /**
9337 * Object models container, for the various models that DataTables has
9338 * available to it. These models define the objects that are used to hold
9339 * the active state and configuration of the table.
9340 * @namespace
9341 */
9342 DataTable.models = {};
9343
9344
9345
9346 /**
9347 * Template object for the way in which DataTables holds information about
9348 * search information for the global filter and individual column filters.
9349 * @namespace
9350 */
9351 DataTable.models.oSearch = {
9352 /**
9353 * Flag to indicate if the filtering should be case insensitive or not
9354 * @type boolean
9355 * @default true
9356 */
9357 "bCaseInsensitive": true,
9358
9359 /**
9360 * Applied search term
9361 * @type string
9362 * @default <i>Empty string</i>
9363 */
9364 "sSearch": "",
9365
9366 /**
9367 * Flag to indicate if the search term should be interpreted as a
9368 * regular expression (true) or not (false) and therefore and special
9369 * regex characters escaped.
9370 * @type boolean
9371 * @default false
9372 */
9373 "bRegex": false,
9374
9375 /**
9376 * Flag to indicate if DataTables is to use its smart filtering or not.
9377 * @type boolean
9378 * @default true
9379 */
9380 "bSmart": true
9381 };
9382
9383
9384
9385
9386 /**
9387 * Template object for the way in which DataTables holds information about
9388 * each individual row. This is the object format used for the settings
9389 * aoData array.
9390 * @namespace
9391 */
9392 DataTable.models.oRow = {
9393 /**
9394 * TR element for the row
9395 * @type node
9396 * @default null
9397 */
9398 "nTr": null,
9399
9400 /**
9401 * Array of TD elements for each row. This is null until the row has been
9402 * created.
9403 * @type array nodes
9404 * @default []
9405 */
9406 "anCells": null,
9407
9408 /**
9409 * Data object from the original data source for the row. This is either
9410 * an array if using the traditional form of DataTables, or an object if
9411 * using mData options. The exact type will depend on the passed in
9412 * data from the data source, or will be an array if using DOM a data
9413 * source.
9414 * @type array|object
9415 * @default []
9416 */
9417 "_aData": [],
9418
9419 /**
9420 * Sorting data cache - this array is ostensibly the same length as the
9421 * number of columns (although each index is generated only as it is
9422 * needed), and holds the data that is used for sorting each column in the
9423 * row. We do this cache generation at the start of the sort in order that
9424 * the formatting of the sort data need be done only once for each cell
9425 * per sort. This array should not be read from or written to by anything
9426 * other than the master sorting methods.
9427 * @type array
9428 * @default null
9429 * @private
9430 */
9431 "_aSortData": null,
9432
9433 /**
9434 * Per cell filtering data cache. As per the sort data cache, used to
9435 * increase the performance of the filtering in DataTables
9436 * @type array
9437 * @default null
9438 * @private
9439 */
9440 "_aFilterData": null,
9441
9442 /**
9443 * Filtering data cache. This is the same as the cell filtering cache, but
9444 * in this case a string rather than an array. This is easily computed with
9445 * a join on `_aFilterData`, but is provided as a cache so the join isn't
9446 * needed on every search (memory traded for performance)
9447 * @type array
9448 * @default null
9449 * @private
9450 */
9451 "_sFilterRow": null,
9452
9453 /**
9454 * Cache of the class name that DataTables has applied to the row, so we
9455 * can quickly look at this variable rather than needing to do a DOM check
9456 * on className for the nTr property.
9457 * @type string
9458 * @default <i>Empty string</i>
9459 * @private
9460 */
9461 "_sRowStripe": "",
9462
9463 /**
9464 * Denote if the original data source was from the DOM, or the data source
9465 * object. This is used for invalidating data, so DataTables can
9466 * automatically read data from the original source, unless uninstructed
9467 * otherwise.
9468 * @type string
9469 * @default null
9470 * @private
9471 */
9472 "src": null,
9473
9474 /**
9475 * Index in the aoData array. This saves an indexOf lookup when we have the
9476 * object, but want to know the index
9477 * @type integer
9478 * @default -1
9479 * @private
9480 */
9481 "idx": -1
9482 };
9483
9484
9485 /**
9486 * Template object for the column information object in DataTables. This object
9487 * is held in the settings aoColumns array and contains all the information that
9488 * DataTables needs about each individual column.
9489 *
9490 * Note that this object is related to {@link DataTable.defaults.column}
9491 * but this one is the internal data store for DataTables's cache of columns.
9492 * It should NOT be manipulated outside of DataTables. Any configuration should
9493 * be done through the initialisation options.
9494 * @namespace
9495 */
9496 DataTable.models.oColumn = {
9497 /**
9498 * Column index. This could be worked out on-the-fly with $.inArray, but it
9499 * is faster to just hold it as a variable
9500 * @type integer
9501 * @default null
9502 */
9503 "idx": null,
9504
9505 /**
9506 * A list of the columns that sorting should occur on when this column
9507 * is sorted. That this property is an array allows multi-column sorting
9508 * to be defined for a column (for example first name / last name columns
9509 * would benefit from this). The values are integers pointing to the
9510 * columns to be sorted on (typically it will be a single integer pointing
9511 * at itself, but that doesn't need to be the case).
9512 * @type array
9513 */
9514 "aDataSort": null,
9515
9516 /**
9517 * Define the sorting directions that are applied to the column, in sequence
9518 * as the column is repeatedly sorted upon - i.e. the first value is used
9519 * as the sorting direction when the column if first sorted (clicked on).
9520 * Sort it again (click again) and it will move on to the next index.
9521 * Repeat until loop.
9522 * @type array
9523 */
9524 "asSorting": null,
9525
9526 /**
9527 * Flag to indicate if the column is searchable, and thus should be included
9528 * in the filtering or not.
9529 * @type boolean
9530 */
9531 "bSearchable": null,
9532
9533 /**
9534 * Flag to indicate if the column is sortable or not.
9535 * @type boolean
9536 */
9537 "bSortable": null,
9538
9539 /**
9540 * Flag to indicate if the column is currently visible in the table or not
9541 * @type boolean
9542 */
9543 "bVisible": null,
9544
9545 /**
9546 * Store for manual type assignment using the `column.type` option. This
9547 * is held in store so we can manipulate the column's `sType` property.
9548 * @type string
9549 * @default null
9550 * @private
9551 */
9552 "_sManualType": null,
9553
9554 /**
9555 * Flag to indicate if HTML5 data attributes should be used as the data
9556 * source for filtering or sorting. True is either are.
9557 * @type boolean
9558 * @default false
9559 * @private
9560 */
9561 "_bAttrSrc": false,
9562
9563 /**
9564 * Developer definable function that is called whenever a cell is created (Ajax source,
9565 * etc) or processed for input (DOM source). This can be used as a compliment to mRender
9566 * allowing you to modify the DOM element (add background colour for example) when the
9567 * element is available.
9568 * @type function
9569 * @param {element} nTd The TD node that has been created
9570 * @param {*} sData The Data for the cell
9571 * @param {array|object} oData The data for the whole row
9572 * @param {int} iRow The row index for the aoData data store
9573 * @default null
9574 */
9575 "fnCreatedCell": null,
9576
9577 /**
9578 * Function to get data from a cell in a column. You should <b>never</b>
9579 * access data directly through _aData internally in DataTables - always use
9580 * the method attached to this property. It allows mData to function as
9581 * required. This function is automatically assigned by the column
9582 * initialisation method
9583 * @type function
9584 * @param {array|object} oData The data array/object for the array
9585 * (i.e. aoData[]._aData)
9586 * @param {string} sSpecific The specific data type you want to get -
9587 * 'display', 'type' 'filter' 'sort'
9588 * @returns {*} The data for the cell from the given row's data
9589 * @default null
9590 */
9591 "fnGetData": null,
9592
9593 /**
9594 * Function to set data for a cell in the column. You should <b>never</b>
9595 * set the data directly to _aData internally in DataTables - always use
9596 * this method. It allows mData to function as required. This function
9597 * is automatically assigned by the column initialisation method
9598 * @type function
9599 * @param {array|object} oData The data array/object for the array
9600 * (i.e. aoData[]._aData)
9601 * @param {*} sValue Value to set
9602 * @default null
9603 */
9604 "fnSetData": null,
9605
9606 /**
9607 * Property to read the value for the cells in the column from the data
9608 * source array / object. If null, then the default content is used, if a
9609 * function is given then the return from the function is used.
9610 * @type function|int|string|null
9611 * @default null
9612 */
9613 "mData": null,
9614
9615 /**
9616 * Partner property to mData which is used (only when defined) to get
9617 * the data - i.e. it is basically the same as mData, but without the
9618 * 'set' option, and also the data fed to it is the result from mData.
9619 * This is the rendering method to match the data method of mData.
9620 * @type function|int|string|null
9621 * @default null
9622 */
9623 "mRender": null,
9624
9625 /**
9626 * Unique header TH/TD element for this column - this is what the sorting
9627 * listener is attached to (if sorting is enabled.)
9628 * @type node
9629 * @default null
9630 */
9631 "nTh": null,
9632
9633 /**
9634 * Unique footer TH/TD element for this column (if there is one). Not used
9635 * in DataTables as such, but can be used for plug-ins to reference the
9636 * footer for each column.
9637 * @type node
9638 * @default null
9639 */
9640 "nTf": null,
9641
9642 /**
9643 * The class to apply to all TD elements in the table's TBODY for the column
9644 * @type string
9645 * @default null
9646 */
9647 "sClass": null,
9648
9649 /**
9650 * When DataTables calculates the column widths to assign to each column,
9651 * it finds the longest string in each column and then constructs a
9652 * temporary table and reads the widths from that. The problem with this
9653 * is that "mmm" is much wider then "iiii", but the latter is a longer
9654 * string - thus the calculation can go wrong (doing it properly and putting
9655 * it into an DOM object and measuring that is horribly(!) slow). Thus as
9656 * a "work around" we provide this option. It will append its value to the
9657 * text that is found to be the longest string for the column - i.e. padding.
9658 * @type string
9659 */
9660 "sContentPadding": null,
9661
9662 /**
9663 * Allows a default value to be given for a column's data, and will be used
9664 * whenever a null data source is encountered (this can be because mData
9665 * is set to null, or because the data source itself is null).
9666 * @type string
9667 * @default null
9668 */
9669 "sDefaultContent": null,
9670
9671 /**
9672 * Name for the column, allowing reference to the column by name as well as
9673 * by index (needs a lookup to work by name).
9674 * @type string
9675 */
9676 "sName": null,
9677
9678 /**
9679 * Custom sorting data type - defines which of the available plug-ins in
9680 * afnSortData the custom sorting will use - if any is defined.
9681 * @type string
9682 * @default std
9683 */
9684 "sSortDataType": 'std',
9685
9686 /**
9687 * Class to be applied to the header element when sorting on this column
9688 * @type string
9689 * @default null
9690 */
9691 "sSortingClass": null,
9692
9693 /**
9694 * Class to be applied to the header element when sorting on this column -
9695 * when jQuery UI theming is used.
9696 * @type string
9697 * @default null
9698 */
9699 "sSortingClassJUI": null,
9700
9701 /**
9702 * Title of the column - what is seen in the TH element (nTh).
9703 * @type string
9704 */
9705 "sTitle": null,
9706
9707 /**
9708 * Column sorting and filtering type
9709 * @type string
9710 * @default null
9711 */
9712 "sType": null,
9713
9714 /**
9715 * Width of the column
9716 * @type string
9717 * @default null
9718 */
9719 "sWidth": null,
9720
9721 /**
9722 * Width of the column when it was first "encountered"
9723 * @type string
9724 * @default null
9725 */
9726 "sWidthOrig": null
9727 };
9728
9729
9730 /*
9731 * Developer note: The properties of the object below are given in Hungarian
9732 * notation, that was used as the interface for DataTables prior to v1.10, however
9733 * from v1.10 onwards the primary interface is camel case. In order to avoid
9734 * breaking backwards compatibility utterly with this change, the Hungarian
9735 * version is still, internally the primary interface, but is is not documented
9736 * - hence the @name tags in each doc comment. This allows a Javascript function
9737 * to create a map from Hungarian notation to camel case (going the other direction
9738 * would require each property to be listed, which would at around 3K to the size
9739 * of DataTables, while this method is about a 0.5K hit.
9740 *
9741 * Ultimately this does pave the way for Hungarian notation to be dropped
9742 * completely, but that is a massive amount of work and will break current
9743 * installs (therefore is on-hold until v2).
9744 */
9745
9746 /**
9747 * Initialisation options that can be given to DataTables at initialisation
9748 * time.
9749 * @namespace
9750 */
9751 DataTable.defaults = {
9752 /**
9753 * An array of data to use for the table, passed in at initialisation which
9754 * will be used in preference to any data which is already in the DOM. This is
9755 * particularly useful for constructing tables purely in Javascript, for
9756 * example with a custom Ajax call.
9757 * @type array
9758 * @default null
9759 *
9760 * @dtopt Option
9761 * @name DataTable.defaults.data
9762 *
9763 * @example
9764 * // Using a 2D array data source
9765 * $(document).ready( function () {
9766 * $('#example').dataTable( {
9767 * "data": [
9768 * ['Trident', 'Internet Explorer 4.0', 'Win 95+', 4, 'X'],
9769 * ['Trident', 'Internet Explorer 5.0', 'Win 95+', 5, 'C'],
9770 * ],
9771 * "columns": [
9772 * { "title": "Engine" },
9773 * { "title": "Browser" },
9774 * { "title": "Platform" },
9775 * { "title": "Version" },
9776 * { "title": "Grade" }
9777 * ]
9778 * } );
9779 * } );
9780 *
9781 * @example
9782 * // Using an array of objects as a data source (`data`)
9783 * $(document).ready( function () {
9784 * $('#example').dataTable( {
9785 * "data": [
9786 * {
9787 * "engine": "Trident",
9788 * "browser": "Internet Explorer 4.0",
9789 * "platform": "Win 95+",
9790 * "version": 4,
9791 * "grade": "X"
9792 * },
9793 * {
9794 * "engine": "Trident",
9795 * "browser": "Internet Explorer 5.0",
9796 * "platform": "Win 95+",
9797 * "version": 5,
9798 * "grade": "C"
9799 * }
9800 * ],
9801 * "columns": [
9802 * { "title": "Engine", "data": "engine" },
9803 * { "title": "Browser", "data": "browser" },
9804 * { "title": "Platform", "data": "platform" },
9805 * { "title": "Version", "data": "version" },
9806 * { "title": "Grade", "data": "grade" }
9807 * ]
9808 * } );
9809 * } );
9810 */
9811 "aaData": null,
9812
9813
9814 /**
9815 * If ordering is enabled, then DataTables will perform a first pass sort on
9816 * initialisation. You can define which column(s) the sort is performed
9817 * upon, and the sorting direction, with this variable. The `sorting` array
9818 * should contain an array for each column to be sorted initially containing
9819 * the column's index and a direction string ('asc' or 'desc').
9820 * @type array
9821 * @default [[0,'asc']]
9822 *
9823 * @dtopt Option
9824 * @name DataTable.defaults.order
9825 *
9826 * @example
9827 * // Sort by 3rd column first, and then 4th column
9828 * $(document).ready( function() {
9829 * $('#example').dataTable( {
9830 * "order": [[2,'asc'], [3,'desc']]
9831 * } );
9832 * } );
9833 *
9834 * // No initial sorting
9835 * $(document).ready( function() {
9836 * $('#example').dataTable( {
9837 * "order": []
9838 * } );
9839 * } );
9840 */
9841 "aaSorting": [[0,'asc']],
9842
9843
9844 /**
9845 * This parameter is basically identical to the `sorting` parameter, but
9846 * cannot be overridden by user interaction with the table. What this means
9847 * is that you could have a column (visible or hidden) which the sorting
9848 * will always be forced on first - any sorting after that (from the user)
9849 * will then be performed as required. This can be useful for grouping rows
9850 * together.
9851 * @type array
9852 * @default null
9853 *
9854 * @dtopt Option
9855 * @name DataTable.defaults.orderFixed
9856 *
9857 * @example
9858 * $(document).ready( function() {
9859 * $('#example').dataTable( {
9860 * "orderFixed": [[0,'asc']]
9861 * } );
9862 * } )
9863 */
9864 "aaSortingFixed": [],
9865
9866
9867 /**
9868 * DataTables can be instructed to load data to display in the table from a
9869 * Ajax source. This option defines how that Ajax call is made and where to.
9870 *
9871 * The `ajax` property has three different modes of operation, depending on
9872 * how it is defined. These are:
9873 *
9874 * * `string` - Set the URL from where the data should be loaded from.
9875 * * `object` - Define properties for `jQuery.ajax`.
9876 * * `function` - Custom data get function
9877 *
9878 * `string`
9879 * --------
9880 *
9881 * As a string, the `ajax` property simply defines the URL from which
9882 * DataTables will load data.
9883 *
9884 * `object`
9885 * --------
9886 *
9887 * As an object, the parameters in the object are passed to
9888 * [jQuery.ajax](http://api.jquery.com/jQuery.ajax/) allowing fine control
9889 * of the Ajax request. DataTables has a number of default parameters which
9890 * you can override using this option. Please refer to the jQuery
9891 * documentation for a full description of the options available, although
9892 * the following parameters provide additional options in DataTables or
9893 * require special consideration:
9894 *
9895 * * `data` - As with jQuery, `data` can be provided as an object, but it
9896 * can also be used as a function to manipulate the data DataTables sends
9897 * to the server. The function takes a single parameter, an object of
9898 * parameters with the values that DataTables has readied for sending. An
9899 * object may be returned which will be merged into the DataTables
9900 * defaults, or you can add the items to the object that was passed in and
9901 * not return anything from the function. This supersedes `fnServerParams`
9902 * from DataTables 1.9-.
9903 *
9904 * * `dataSrc` - By default DataTables will look for the property `data` (or
9905 * `aaData` for compatibility with DataTables 1.9-) when obtaining data
9906 * from an Ajax source or for server-side processing - this parameter
9907 * allows that property to be changed. You can use Javascript dotted
9908 * object notation to get a data source for multiple levels of nesting, or
9909 * it my be used as a function. As a function it takes a single parameter,
9910 * the JSON returned from the server, which can be manipulated as
9911 * required, with the returned value being that used by DataTables as the
9912 * data source for the table. This supersedes `sAjaxDataProp` from
9913 * DataTables 1.9-.
9914 *
9915 * * `success` - Should not be overridden it is used internally in
9916 * DataTables. To manipulate / transform the data returned by the server
9917 * use `ajax.dataSrc`, or use `ajax` as a function (see below).
9918 *
9919 * `function`
9920 * ----------
9921 *
9922 * As a function, making the Ajax call is left up to yourself allowing
9923 * complete control of the Ajax request. Indeed, if desired, a method other
9924 * than Ajax could be used to obtain the required data, such as Web storage
9925 * or an AIR database.
9926 *
9927 * The function is given four parameters and no return is required. The
9928 * parameters are:
9929 *
9930 * 1. _object_ - Data to send to the server
9931 * 2. _function_ - Callback function that must be executed when the required
9932 * data has been obtained. That data should be passed into the callback
9933 * as the only parameter
9934 * 3. _object_ - DataTables settings object for the table
9935 *
9936 * Note that this supersedes `fnServerData` from DataTables 1.9-.
9937 *
9938 * @type string|object|function
9939 * @default null
9940 *
9941 * @dtopt Option
9942 * @name DataTable.defaults.ajax
9943 * @since 1.10.0
9944 *
9945 * @example
9946 * // Get JSON data from a file via Ajax.
9947 * // Note DataTables expects data in the form `{ data: [ ...data... ] }` by default).
9948 * $('#example').dataTable( {
9949 * "ajax": "data.json"
9950 * } );
9951 *
9952 * @example
9953 * // Get JSON data from a file via Ajax, using `dataSrc` to change
9954 * // `data` to `tableData` (i.e. `{ tableData: [ ...data... ] }`)
9955 * $('#example').dataTable( {
9956 * "ajax": {
9957 * "url": "data.json",
9958 * "dataSrc": "tableData"
9959 * }
9960 * } );
9961 *
9962 * @example
9963 * // Get JSON data from a file via Ajax, using `dataSrc` to read data
9964 * // from a plain array rather than an array in an object
9965 * $('#example').dataTable( {
9966 * "ajax": {
9967 * "url": "data.json",
9968 * "dataSrc": ""
9969 * }
9970 * } );
9971 *
9972 * @example
9973 * // Manipulate the data returned from the server - add a link to data
9974 * // (note this can, should, be done using `render` for the column - this
9975 * // is just a simple example of how the data can be manipulated).
9976 * $('#example').dataTable( {
9977 * "ajax": {
9978 * "url": "data.json",
9979 * "dataSrc": function ( json ) {
9980 * for ( var i=0, ien=json.length ; i<ien ; i++ ) {
9981 * json[i][0] = '<a href="/message/'+json[i][0]+'>View message</a>';
9982 * }
9983 * return json;
9984 * }
9985 * }
9986 * } );
9987 *
9988 * @example
9989 * // Add data to the request
9990 * $('#example').dataTable( {
9991 * "ajax": {
9992 * "url": "data.json",
9993 * "data": function ( d ) {
9994 * return {
9995 * "extra_search": $('#extra').val()
9996 * };
9997 * }
9998 * }
9999 * } );
10000 *
10001 * @example
10002 * // Send request as POST
10003 * $('#example').dataTable( {
10004 * "ajax": {
10005 * "url": "data.json",
10006 * "type": "POST"
10007 * }
10008 * } );
10009 *
10010 * @example
10011 * // Get the data from localStorage (could interface with a form for
10012 * // adding, editing and removing rows).
10013 * $('#example').dataTable( {
10014 * "ajax": function (data, callback, settings) {
10015 * callback(
10016 * JSON.parse( localStorage.getItem('dataTablesData') )
10017 * );
10018 * }
10019 * } );
10020 */
10021 "ajax": null,
10022
10023
10024 /**
10025 * This parameter allows you to readily specify the entries in the length drop
10026 * down menu that DataTables shows when pagination is enabled. It can be
10027 * either a 1D array of options which will be used for both the displayed
10028 * option and the value, or a 2D array which will use the array in the first
10029 * position as the value, and the array in the second position as the
10030 * displayed options (useful for language strings such as 'All').
10031 *
10032 * Note that the `pageLength` property will be automatically set to the
10033 * first value given in this array, unless `pageLength` is also provided.
10034 * @type array
10035 * @default [ 10, 25, 50, 100 ]
10036 *
10037 * @dtopt Option
10038 * @name DataTable.defaults.lengthMenu
10039 *
10040 * @example
10041 * $(document).ready( function() {
10042 * $('#example').dataTable( {
10043 * "lengthMenu": [[10, 25, 50, -1], [10, 25, 50, "All"]]
10044 * } );
10045 * } );
10046 */
10047 "aLengthMenu": [ 10, 25, 50, 100 ],
10048
10049
10050 /**
10051 * The `columns` option in the initialisation parameter allows you to define
10052 * details about the way individual columns behave. For a full list of
10053 * column options that can be set, please see
10054 * {@link DataTable.defaults.column}. Note that if you use `columns` to
10055 * define your columns, you must have an entry in the array for every single
10056 * column that you have in your table (these can be null if you don't which
10057 * to specify any options).
10058 * @member
10059 *
10060 * @name DataTable.defaults.column
10061 */
10062 "aoColumns": null,
10063
10064 /**
10065 * Very similar to `columns`, `columnDefs` allows you to target a specific
10066 * column, multiple columns, or all columns, using the `targets` property of
10067 * each object in the array. This allows great flexibility when creating
10068 * tables, as the `columnDefs` arrays can be of any length, targeting the
10069 * columns you specifically want. `columnDefs` may use any of the column
10070 * options available: {@link DataTable.defaults.column}, but it _must_
10071 * have `targets` defined in each object in the array. Values in the `targets`
10072 * array may be:
10073 * <ul>
10074 * <li>a string - class name will be matched on the TH for the column</li>
10075 * <li>0 or a positive integer - column index counting from the left</li>
10076 * <li>a negative integer - column index counting from the right</li>
10077 * <li>the string "_all" - all columns (i.e. assign a default)</li>
10078 * </ul>
10079 * @member
10080 *
10081 * @name DataTable.defaults.columnDefs
10082 */
10083 "aoColumnDefs": null,
10084
10085
10086 /**
10087 * Basically the same as `search`, this parameter defines the individual column
10088 * filtering state at initialisation time. The array must be of the same size
10089 * as the number of columns, and each element be an object with the parameters
10090 * `search` and `escapeRegex` (the latter is optional). 'null' is also
10091 * accepted and the default will be used.
10092 * @type array
10093 * @default []
10094 *
10095 * @dtopt Option
10096 * @name DataTable.defaults.searchCols
10097 *
10098 * @example
10099 * $(document).ready( function() {
10100 * $('#example').dataTable( {
10101 * "searchCols": [
10102 * null,
10103 * { "search": "My filter" },
10104 * null,
10105 * { "search": "^[0-9]", "escapeRegex": false }
10106 * ]
10107 * } );
10108 * } )
10109 */
10110 "aoSearchCols": [],
10111
10112
10113 /**
10114 * An array of CSS classes that should be applied to displayed rows. This
10115 * array may be of any length, and DataTables will apply each class
10116 * sequentially, looping when required.
10117 * @type array
10118 * @default null <i>Will take the values determined by the `oClasses.stripe*`
10119 * options</i>
10120 *
10121 * @dtopt Option
10122 * @name DataTable.defaults.stripeClasses
10123 *
10124 * @example
10125 * $(document).ready( function() {
10126 * $('#example').dataTable( {
10127 * "stripeClasses": [ 'strip1', 'strip2', 'strip3' ]
10128 * } );
10129 * } )
10130 */
10131 "asStripeClasses": null,
10132
10133
10134 /**
10135 * Enable or disable automatic column width calculation. This can be disabled
10136 * as an optimisation (it takes some time to calculate the widths) if the
10137 * tables widths are passed in using `columns`.
10138 * @type boolean
10139 * @default true
10140 *
10141 * @dtopt Features
10142 * @name DataTable.defaults.autoWidth
10143 *
10144 * @example
10145 * $(document).ready( function () {
10146 * $('#example').dataTable( {
10147 * "autoWidth": false
10148 * } );
10149 * } );
10150 */
10151 "bAutoWidth": true,
10152
10153
10154 /**
10155 * Deferred rendering can provide DataTables with a huge speed boost when you
10156 * are using an Ajax or JS data source for the table. This option, when set to
10157 * true, will cause DataTables to defer the creation of the table elements for
10158 * each row until they are needed for a draw - saving a significant amount of
10159 * time.
10160 * @type boolean
10161 * @default false
10162 *
10163 * @dtopt Features
10164 * @name DataTable.defaults.deferRender
10165 *
10166 * @example
10167 * $(document).ready( function() {
10168 * $('#example').dataTable( {
10169 * "ajax": "sources/arrays.txt",
10170 * "deferRender": true
10171 * } );
10172 * } );
10173 */
10174 "bDeferRender": false,
10175
10176
10177 /**
10178 * Replace a DataTable which matches the given selector and replace it with
10179 * one which has the properties of the new initialisation object passed. If no
10180 * table matches the selector, then the new DataTable will be constructed as
10181 * per normal.
10182 * @type boolean
10183 * @default false
10184 *
10185 * @dtopt Options
10186 * @name DataTable.defaults.destroy
10187 *
10188 * @example
10189 * $(document).ready( function() {
10190 * $('#example').dataTable( {
10191 * "srollY": "200px",
10192 * "paginate": false
10193 * } );
10194 *
10195 * // Some time later....
10196 * $('#example').dataTable( {
10197 * "filter": false,
10198 * "destroy": true
10199 * } );
10200 * } );
10201 */
10202 "bDestroy": false,
10203
10204
10205 /**
10206 * Enable or disable filtering of data. Filtering in DataTables is "smart" in
10207 * that it allows the end user to input multiple words (space separated) and
10208 * will match a row containing those words, even if not in the order that was
10209 * specified (this allow matching across multiple columns). Note that if you
10210 * wish to use filtering in DataTables this must remain 'true' - to remove the
10211 * default filtering input box and retain filtering abilities, please use
10212 * {@link DataTable.defaults.dom}.
10213 * @type boolean
10214 * @default true
10215 *
10216 * @dtopt Features
10217 * @name DataTable.defaults.searching
10218 *
10219 * @example
10220 * $(document).ready( function () {
10221 * $('#example').dataTable( {
10222 * "searching": false
10223 * } );
10224 * } );
10225 */
10226 "bFilter": true,
10227
10228
10229 /**
10230 * Enable or disable the table information display. This shows information
10231 * about the data that is currently visible on the page, including information
10232 * about filtered data if that action is being performed.
10233 * @type boolean
10234 * @default true
10235 *
10236 * @dtopt Features
10237 * @name DataTable.defaults.info
10238 *
10239 * @example
10240 * $(document).ready( function () {
10241 * $('#example').dataTable( {
10242 * "info": false
10243 * } );
10244 * } );
10245 */
10246 "bInfo": true,
10247
10248
10249 /**
10250 * Enable jQuery UI ThemeRoller support (required as ThemeRoller requires some
10251 * slightly different and additional mark-up from what DataTables has
10252 * traditionally used).
10253 * @type boolean
10254 * @default false
10255 *
10256 * @dtopt Features
10257 * @name DataTable.defaults.jQueryUI
10258 *
10259 * @example
10260 * $(document).ready( function() {
10261 * $('#example').dataTable( {
10262 * "jQueryUI": true
10263 * } );
10264 * } );
10265 */
10266 "bJQueryUI": false,
10267
10268
10269 /**
10270 * Allows the end user to select the size of a formatted page from a select
10271 * menu (sizes are 10, 25, 50 and 100). Requires pagination (`paginate`).
10272 * @type boolean
10273 * @default true
10274 *
10275 * @dtopt Features
10276 * @name DataTable.defaults.lengthChange
10277 *
10278 * @example
10279 * $(document).ready( function () {
10280 * $('#example').dataTable( {
10281 * "lengthChange": false
10282 * } );
10283 * } );
10284 */
10285 "bLengthChange": true,
10286
10287
10288 /**
10289 * Enable or disable pagination.
10290 * @type boolean
10291 * @default true
10292 *
10293 * @dtopt Features
10294 * @name DataTable.defaults.paging
10295 *
10296 * @example
10297 * $(document).ready( function () {
10298 * $('#example').dataTable( {
10299 * "paging": false
10300 * } );
10301 * } );
10302 */
10303 "bPaginate": true,
10304
10305
10306 /**
10307 * Enable or disable the display of a 'processing' indicator when the table is
10308 * being processed (e.g. a sort). This is particularly useful for tables with
10309 * large amounts of data where it can take a noticeable amount of time to sort
10310 * the entries.
10311 * @type boolean
10312 * @default false
10313 *
10314 * @dtopt Features
10315 * @name DataTable.defaults.processing
10316 *
10317 * @example
10318 * $(document).ready( function () {
10319 * $('#example').dataTable( {
10320 * "processing": true
10321 * } );
10322 * } );
10323 */
10324 "bProcessing": false,
10325
10326
10327 /**
10328 * Retrieve the DataTables object for the given selector. Note that if the
10329 * table has already been initialised, this parameter will cause DataTables
10330 * to simply return the object that has already been set up - it will not take
10331 * account of any changes you might have made to the initialisation object
10332 * passed to DataTables (setting this parameter to true is an acknowledgement
10333 * that you understand this). `destroy` can be used to reinitialise a table if
10334 * you need.
10335 * @type boolean
10336 * @default false
10337 *
10338 * @dtopt Options
10339 * @name DataTable.defaults.retrieve
10340 *
10341 * @example
10342 * $(document).ready( function() {
10343 * initTable();
10344 * tableActions();
10345 * } );
10346 *
10347 * function initTable ()
10348 * {
10349 * return $('#example').dataTable( {
10350 * "scrollY": "200px",
10351 * "paginate": false,
10352 * "retrieve": true
10353 * } );
10354 * }
10355 *
10356 * function tableActions ()
10357 * {
10358 * var table = initTable();
10359 * // perform API operations with oTable
10360 * }
10361 */
10362 "bRetrieve": false,
10363
10364
10365 /**
10366 * When vertical (y) scrolling is enabled, DataTables will force the height of
10367 * the table's viewport to the given height at all times (useful for layout).
10368 * However, this can look odd when filtering data down to a small data set,
10369 * and the footer is left "floating" further down. This parameter (when
10370 * enabled) will cause DataTables to collapse the table's viewport down when
10371 * the result set will fit within the given Y height.
10372 * @type boolean
10373 * @default false
10374 *
10375 * @dtopt Options
10376 * @name DataTable.defaults.scrollCollapse
10377 *
10378 * @example
10379 * $(document).ready( function() {
10380 * $('#example').dataTable( {
10381 * "scrollY": "200",
10382 * "scrollCollapse": true
10383 * } );
10384 * } );
10385 */
10386 "bScrollCollapse": false,
10387
10388
10389 /**
10390 * Configure DataTables to use server-side processing. Note that the
10391 * `ajax` parameter must also be given in order to give DataTables a
10392 * source to obtain the required data for each draw.
10393 * @type boolean
10394 * @default false
10395 *
10396 * @dtopt Features
10397 * @dtopt Server-side
10398 * @name DataTable.defaults.serverSide
10399 *
10400 * @example
10401 * $(document).ready( function () {
10402 * $('#example').dataTable( {
10403 * "serverSide": true,
10404 * "ajax": "xhr.php"
10405 * } );
10406 * } );
10407 */
10408 "bServerSide": false,
10409
10410
10411 /**
10412 * Enable or disable sorting of columns. Sorting of individual columns can be
10413 * disabled by the `sortable` option for each column.
10414 * @type boolean
10415 * @default true
10416 *
10417 * @dtopt Features
10418 * @name DataTable.defaults.ordering
10419 *
10420 * @example
10421 * $(document).ready( function () {
10422 * $('#example').dataTable( {
10423 * "ordering": false
10424 * } );
10425 * } );
10426 */
10427 "bSort": true,
10428
10429
10430 /**
10431 * Enable or display DataTables' ability to sort multiple columns at the
10432 * same time (activated by shift-click by the user).
10433 * @type boolean
10434 * @default true
10435 *
10436 * @dtopt Options
10437 * @name DataTable.defaults.orderMulti
10438 *
10439 * @example
10440 * // Disable multiple column sorting ability
10441 * $(document).ready( function () {
10442 * $('#example').dataTable( {
10443 * "orderMulti": false
10444 * } );
10445 * } );
10446 */
10447 "bSortMulti": true,
10448
10449
10450 /**
10451 * Allows control over whether DataTables should use the top (true) unique
10452 * cell that is found for a single column, or the bottom (false - default).
10453 * This is useful when using complex headers.
10454 * @type boolean
10455 * @default false
10456 *
10457 * @dtopt Options
10458 * @name DataTable.defaults.orderCellsTop
10459 *
10460 * @example
10461 * $(document).ready( function() {
10462 * $('#example').dataTable( {
10463 * "orderCellsTop": true
10464 * } );
10465 * } );
10466 */
10467 "bSortCellsTop": false,
10468
10469
10470 /**
10471 * Enable or disable the addition of the classes `sorting\_1`, `sorting\_2` and
10472 * `sorting\_3` to the columns which are currently being sorted on. This is
10473 * presented as a feature switch as it can increase processing time (while
10474 * classes are removed and added) so for large data sets you might want to
10475 * turn this off.
10476 * @type boolean
10477 * @default true
10478 *
10479 * @dtopt Features
10480 * @name DataTable.defaults.orderClasses
10481 *
10482 * @example
10483 * $(document).ready( function () {
10484 * $('#example').dataTable( {
10485 * "orderClasses": false
10486 * } );
10487 * } );
10488 */
10489 "bSortClasses": true,
10490
10491
10492 /**
10493 * Enable or disable state saving. When enabled HTML5 `localStorage` will be
10494 * used to save table display information such as pagination information,
10495 * display length, filtering and sorting. As such when the end user reloads
10496 * the page the display display will match what thy had previously set up.
10497 *
10498 * Due to the use of `localStorage` the default state saving is not supported
10499 * in IE6 or 7. If state saving is required in those browsers, use
10500 * `stateSaveCallback` to provide a storage solution such as cookies.
10501 * @type boolean
10502 * @default false
10503 *
10504 * @dtopt Features
10505 * @name DataTable.defaults.stateSave
10506 *
10507 * @example
10508 * $(document).ready( function () {
10509 * $('#example').dataTable( {
10510 * "stateSave": true
10511 * } );
10512 * } );
10513 */
10514 "bStateSave": false,
10515
10516
10517 /**
10518 * This function is called when a TR element is created (and all TD child
10519 * elements have been inserted), or registered if using a DOM source, allowing
10520 * manipulation of the TR element (adding classes etc).
10521 * @type function
10522 * @param {node} row "TR" element for the current row
10523 * @param {array} data Raw data array for this row
10524 * @param {int} dataIndex The index of this row in the internal aoData array
10525 *
10526 * @dtopt Callbacks
10527 * @name DataTable.defaults.createdRow
10528 *
10529 * @example
10530 * $(document).ready( function() {
10531 * $('#example').dataTable( {
10532 * "createdRow": function( row, data, dataIndex ) {
10533 * // Bold the grade for all 'A' grade browsers
10534 * if ( data[4] == "A" )
10535 * {
10536 * $('td:eq(4)', row).html( '<b>A</b>' );
10537 * }
10538 * }
10539 * } );
10540 * } );
10541 */
10542 "fnCreatedRow": null,
10543
10544
10545 /**
10546 * This function is called on every 'draw' event, and allows you to
10547 * dynamically modify any aspect you want about the created DOM.
10548 * @type function
10549 * @param {object} settings DataTables settings object
10550 *
10551 * @dtopt Callbacks
10552 * @name DataTable.defaults.drawCallback
10553 *
10554 * @example
10555 * $(document).ready( function() {
10556 * $('#example').dataTable( {
10557 * "drawCallback": function( settings ) {
10558 * alert( 'DataTables has redrawn the table' );
10559 * }
10560 * } );
10561 * } );
10562 */
10563 "fnDrawCallback": null,
10564
10565
10566 /**
10567 * Identical to fnHeaderCallback() but for the table footer this function
10568 * allows you to modify the table footer on every 'draw' event.
10569 * @type function
10570 * @param {node} foot "TR" element for the footer
10571 * @param {array} data Full table data (as derived from the original HTML)
10572 * @param {int} start Index for the current display starting point in the
10573 * display array
10574 * @param {int} end Index for the current display ending point in the
10575 * display array
10576 * @param {array int} display Index array to translate the visual position
10577 * to the full data array
10578 *
10579 * @dtopt Callbacks
10580 * @name DataTable.defaults.footerCallback
10581 *
10582 * @example
10583 * $(document).ready( function() {
10584 * $('#example').dataTable( {
10585 * "footerCallback": function( tfoot, data, start, end, display ) {
10586 * tfoot.getElementsByTagName('th')[0].innerHTML = "Starting index is "+start;
10587 * }
10588 * } );
10589 * } )
10590 */
10591 "fnFooterCallback": null,
10592
10593
10594 /**
10595 * When rendering large numbers in the information element for the table
10596 * (i.e. "Showing 1 to 10 of 57 entries") DataTables will render large numbers
10597 * to have a comma separator for the 'thousands' units (e.g. 1 million is
10598 * rendered as "1,000,000") to help readability for the end user. This
10599 * function will override the default method DataTables uses.
10600 * @type function
10601 * @member
10602 * @param {int} toFormat number to be formatted
10603 * @returns {string} formatted string for DataTables to show the number
10604 *
10605 * @dtopt Callbacks
10606 * @name DataTable.defaults.formatNumber
10607 *
10608 * @example
10609 * // Format a number using a single quote for the separator (note that
10610 * // this can also be done with the language.thousands option)
10611 * $(document).ready( function() {
10612 * $('#example').dataTable( {
10613 * "formatNumber": function ( toFormat ) {
10614 * return toFormat.toString().replace(
10615 * /\B(?=(\d{3})+(?!\d))/g, "'"
10616 * );
10617 * };
10618 * } );
10619 * } );
10620 */
10621 "fnFormatNumber": function ( toFormat ) {
10622 return toFormat.toString().replace(
10623 /\B(?=(\d{3})+(?!\d))/g,
10624 this.oLanguage.sThousands
10625 );
10626 },
10627
10628
10629 /**
10630 * This function is called on every 'draw' event, and allows you to
10631 * dynamically modify the header row. This can be used to calculate and
10632 * display useful information about the table.
10633 * @type function
10634 * @param {node} head "TR" element for the header
10635 * @param {array} data Full table data (as derived from the original HTML)
10636 * @param {int} start Index for the current display starting point in the
10637 * display array
10638 * @param {int} end Index for the current display ending point in the
10639 * display array
10640 * @param {array int} display Index array to translate the visual position
10641 * to the full data array
10642 *
10643 * @dtopt Callbacks
10644 * @name DataTable.defaults.headerCallback
10645 *
10646 * @example
10647 * $(document).ready( function() {
10648 * $('#example').dataTable( {
10649 * "fheaderCallback": function( head, data, start, end, display ) {
10650 * head.getElementsByTagName('th')[0].innerHTML = "Displaying "+(end-start)+" records";
10651 * }
10652 * } );
10653 * } )
10654 */
10655 "fnHeaderCallback": null,
10656
10657
10658 /**
10659 * The information element can be used to convey information about the current
10660 * state of the table. Although the internationalisation options presented by
10661 * DataTables are quite capable of dealing with most customisations, there may
10662 * be times where you wish to customise the string further. This callback
10663 * allows you to do exactly that.
10664 * @type function
10665 * @param {object} oSettings DataTables settings object
10666 * @param {int} start Starting position in data for the draw
10667 * @param {int} end End position in data for the draw
10668 * @param {int} max Total number of rows in the table (regardless of
10669 * filtering)
10670 * @param {int} total Total number of rows in the data set, after filtering
10671 * @param {string} pre The string that DataTables has formatted using it's
10672 * own rules
10673 * @returns {string} The string to be displayed in the information element.
10674 *
10675 * @dtopt Callbacks
10676 * @name DataTable.defaults.infoCallback
10677 *
10678 * @example
10679 * $('#example').dataTable( {
10680 * "infoCallback": function( settings, start, end, max, total, pre ) {
10681 * return start +" to "+ end;
10682 * }
10683 * } );
10684 */
10685 "fnInfoCallback": null,
10686
10687
10688 /**
10689 * Called when the table has been initialised. Normally DataTables will
10690 * initialise sequentially and there will be no need for this function,
10691 * however, this does not hold true when using external language information
10692 * since that is obtained using an async XHR call.
10693 * @type function
10694 * @param {object} settings DataTables settings object
10695 * @param {object} json The JSON object request from the server - only
10696 * present if client-side Ajax sourced data is used
10697 *
10698 * @dtopt Callbacks
10699 * @name DataTable.defaults.initComplete
10700 *
10701 * @example
10702 * $(document).ready( function() {
10703 * $('#example').dataTable( {
10704 * "initComplete": function(settings, json) {
10705 * alert( 'DataTables has finished its initialisation.' );
10706 * }
10707 * } );
10708 * } )
10709 */
10710 "fnInitComplete": null,
10711
10712
10713 /**
10714 * Called at the very start of each table draw and can be used to cancel the
10715 * draw by returning false, any other return (including undefined) results in
10716 * the full draw occurring).
10717 * @type function
10718 * @param {object} settings DataTables settings object
10719 * @returns {boolean} False will cancel the draw, anything else (including no
10720 * return) will allow it to complete.
10721 *
10722 * @dtopt Callbacks
10723 * @name DataTable.defaults.preDrawCallback
10724 *
10725 * @example
10726 * $(document).ready( function() {
10727 * $('#example').dataTable( {
10728 * "preDrawCallback": function( settings ) {
10729 * if ( $('#test').val() == 1 ) {
10730 * return false;
10731 * }
10732 * }
10733 * } );
10734 * } );
10735 */
10736 "fnPreDrawCallback": null,
10737
10738
10739 /**
10740 * This function allows you to 'post process' each row after it have been
10741 * generated for each table draw, but before it is rendered on screen. This
10742 * function might be used for setting the row class name etc.
10743 * @type function
10744 * @param {node} row "TR" element for the current row
10745 * @param {array} data Raw data array for this row
10746 * @param {int} displayIndex The display index for the current table draw
10747 * @param {int} displayIndexFull The index of the data in the full list of
10748 * rows (after filtering)
10749 *
10750 * @dtopt Callbacks
10751 * @name DataTable.defaults.rowCallback
10752 *
10753 * @example
10754 * $(document).ready( function() {
10755 * $('#example').dataTable( {
10756 * "rowCallback": function( row, data, displayIndex, displayIndexFull ) {
10757 * // Bold the grade for all 'A' grade browsers
10758 * if ( data[4] == "A" ) {
10759 * $('td:eq(4)', row).html( '<b>A</b>' );
10760 * }
10761 * }
10762 * } );
10763 * } );
10764 */
10765 "fnRowCallback": null,
10766
10767
10768 /**
10769 * __Deprecated__ The functionality provided by this parameter has now been
10770 * superseded by that provided through `ajax`, which should be used instead.
10771 *
10772 * This parameter allows you to override the default function which obtains
10773 * the data from the server so something more suitable for your application.
10774 * For example you could use POST data, or pull information from a Gears or
10775 * AIR database.
10776 * @type function
10777 * @member
10778 * @param {string} source HTTP source to obtain the data from (`ajax`)
10779 * @param {array} data A key/value pair object containing the data to send
10780 * to the server
10781 * @param {function} callback to be called on completion of the data get
10782 * process that will draw the data on the page.
10783 * @param {object} settings DataTables settings object
10784 *
10785 * @dtopt Callbacks
10786 * @dtopt Server-side
10787 * @name DataTable.defaults.serverData
10788 *
10789 * @deprecated 1.10. Please use `ajax` for this functionality now.
10790 */
10791 "fnServerData": null,
10792
10793
10794 /**
10795 * __Deprecated__ The functionality provided by this parameter has now been
10796 * superseded by that provided through `ajax`, which should be used instead.
10797 *
10798 * It is often useful to send extra data to the server when making an Ajax
10799 * request - for example custom filtering information, and this callback
10800 * function makes it trivial to send extra information to the server. The
10801 * passed in parameter is the data set that has been constructed by
10802 * DataTables, and you can add to this or modify it as you require.
10803 * @type function
10804 * @param {array} data Data array (array of objects which are name/value
10805 * pairs) that has been constructed by DataTables and will be sent to the
10806 * server. In the case of Ajax sourced data with server-side processing
10807 * this will be an empty array, for server-side processing there will be a
10808 * significant number of parameters!
10809 * @returns {undefined} Ensure that you modify the data array passed in,
10810 * as this is passed by reference.
10811 *
10812 * @dtopt Callbacks
10813 * @dtopt Server-side
10814 * @name DataTable.defaults.serverParams
10815 *
10816 * @deprecated 1.10. Please use `ajax` for this functionality now.
10817 */
10818 "fnServerParams": null,
10819
10820
10821 /**
10822 * Load the table state. With this function you can define from where, and how, the
10823 * state of a table is loaded. By default DataTables will load from `localStorage`
10824 * but you might wish to use a server-side database or cookies.
10825 * @type function
10826 * @member
10827 * @param {object} settings DataTables settings object
10828 * @return {object} The DataTables state object to be loaded
10829 *
10830 * @dtopt Callbacks
10831 * @name DataTable.defaults.stateLoadCallback
10832 *
10833 * @example
10834 * $(document).ready( function() {
10835 * $('#example').dataTable( {
10836 * "stateSave": true,
10837 * "stateLoadCallback": function (settings) {
10838 * var o;
10839 *
10840 * // Send an Ajax request to the server to get the data. Note that
10841 * // this is a synchronous request.
10842 * $.ajax( {
10843 * "url": "/state_load",
10844 * "async": false,
10845 * "dataType": "json",
10846 * "success": function (json) {
10847 * o = json;
10848 * }
10849 * } );
10850 *
10851 * return o;
10852 * }
10853 * } );
10854 * } );
10855 */
10856 "fnStateLoadCallback": function ( settings ) {
10857 try {
10858 return JSON.parse(
10859 (settings.iStateDuration === -1 ? sessionStorage : localStorage).getItem(
10860 'DataTables_'+settings.sInstance+'_'+location.pathname
10861 )
10862 );
10863 } catch (e) {}
10864 },
10865
10866
10867 /**
10868 * Callback which allows modification of the saved state prior to loading that state.
10869 * This callback is called when the table is loading state from the stored data, but
10870 * prior to the settings object being modified by the saved state. Note that for
10871 * plug-in authors, you should use the `stateLoadParams` event to load parameters for
10872 * a plug-in.
10873 * @type function
10874 * @param {object} settings DataTables settings object
10875 * @param {object} data The state object that is to be loaded
10876 *
10877 * @dtopt Callbacks
10878 * @name DataTable.defaults.stateLoadParams
10879 *
10880 * @example
10881 * // Remove a saved filter, so filtering is never loaded
10882 * $(document).ready( function() {
10883 * $('#example').dataTable( {
10884 * "stateSave": true,
10885 * "stateLoadParams": function (settings, data) {
10886 * data.oSearch.sSearch = "";
10887 * }
10888 * } );
10889 * } );
10890 *
10891 * @example
10892 * // Disallow state loading by returning false
10893 * $(document).ready( function() {
10894 * $('#example').dataTable( {
10895 * "stateSave": true,
10896 * "stateLoadParams": function (settings, data) {
10897 * return false;
10898 * }
10899 * } );
10900 * } );
10901 */
10902 "fnStateLoadParams": null,
10903
10904
10905 /**
10906 * Callback that is called when the state has been loaded from the state saving method
10907 * and the DataTables settings object has been modified as a result of the loaded state.
10908 * @type function
10909 * @param {object} settings DataTables settings object
10910 * @param {object} data The state object that was loaded
10911 *
10912 * @dtopt Callbacks
10913 * @name DataTable.defaults.stateLoaded
10914 *
10915 * @example
10916 * // Show an alert with the filtering value that was saved
10917 * $(document).ready( function() {
10918 * $('#example').dataTable( {
10919 * "stateSave": true,
10920 * "stateLoaded": function (settings, data) {
10921 * alert( 'Saved filter was: '+data.oSearch.sSearch );
10922 * }
10923 * } );
10924 * } );
10925 */
10926 "fnStateLoaded": null,
10927
10928
10929 /**
10930 * Save the table state. This function allows you to define where and how the state
10931 * information for the table is stored By default DataTables will use `localStorage`
10932 * but you might wish to use a server-side database or cookies.
10933 * @type function
10934 * @member
10935 * @param {object} settings DataTables settings object
10936 * @param {object} data The state object to be saved
10937 *
10938 * @dtopt Callbacks
10939 * @name DataTable.defaults.stateSaveCallback
10940 *
10941 * @example
10942 * $(document).ready( function() {
10943 * $('#example').dataTable( {
10944 * "stateSave": true,
10945 * "stateSaveCallback": function (settings, data) {
10946 * // Send an Ajax request to the server with the state object
10947 * $.ajax( {
10948 * "url": "/state_save",
10949 * "data": data,
10950 * "dataType": "json",
10951 * "method": "POST"
10952 * "success": function () {}
10953 * } );
10954 * }
10955 * } );
10956 * } );
10957 */
10958 "fnStateSaveCallback": function ( settings, data ) {
10959 try {
10960 (settings.iStateDuration === -1 ? sessionStorage : localStorage).setItem(
10961 'DataTables_'+settings.sInstance+'_'+location.pathname,
10962 JSON.stringify( data )
10963 );
10964 } catch (e) {}
10965 },
10966
10967
10968 /**
10969 * Callback which allows modification of the state to be saved. Called when the table
10970 * has changed state a new state save is required. This method allows modification of
10971 * the state saving object prior to actually doing the save, including addition or
10972 * other state properties or modification. Note that for plug-in authors, you should
10973 * use the `stateSaveParams` event to save parameters for a plug-in.
10974 * @type function
10975 * @param {object} settings DataTables settings object
10976 * @param {object} data The state object to be saved
10977 *
10978 * @dtopt Callbacks
10979 * @name DataTable.defaults.stateSaveParams
10980 *
10981 * @example
10982 * // Remove a saved filter, so filtering is never saved
10983 * $(document).ready( function() {
10984 * $('#example').dataTable( {
10985 * "stateSave": true,
10986 * "stateSaveParams": function (settings, data) {
10987 * data.oSearch.sSearch = "";
10988 * }
10989 * } );
10990 * } );
10991 */
10992 "fnStateSaveParams": null,
10993
10994
10995 /**
10996 * Duration for which the saved state information is considered valid. After this period
10997 * has elapsed the state will be returned to the default.
10998 * Value is given in seconds.
10999 * @type int
11000 * @default 7200 <i>(2 hours)</i>
11001 *
11002 * @dtopt Options
11003 * @name DataTable.defaults.stateDuration
11004 *
11005 * @example
11006 * $(document).ready( function() {
11007 * $('#example').dataTable( {
11008 * "stateDuration": 60*60*24; // 1 day
11009 * } );
11010 * } )
11011 */
11012 "iStateDuration": 7200,
11013
11014
11015 /**
11016 * When enabled DataTables will not make a request to the server for the first
11017 * page draw - rather it will use the data already on the page (no sorting etc
11018 * will be applied to it), thus saving on an XHR at load time. `deferLoading`
11019 * is used to indicate that deferred loading is required, but it is also used
11020 * to tell DataTables how many records there are in the full table (allowing
11021 * the information element and pagination to be displayed correctly). In the case
11022 * where a filtering is applied to the table on initial load, this can be
11023 * indicated by giving the parameter as an array, where the first element is
11024 * the number of records available after filtering and the second element is the
11025 * number of records without filtering (allowing the table information element
11026 * to be shown correctly).
11027 * @type int | array
11028 * @default null
11029 *
11030 * @dtopt Options
11031 * @name DataTable.defaults.deferLoading
11032 *
11033 * @example
11034 * // 57 records available in the table, no filtering applied
11035 * $(document).ready( function() {
11036 * $('#example').dataTable( {
11037 * "serverSide": true,
11038 * "ajax": "scripts/server_processing.php",
11039 * "deferLoading": 57
11040 * } );
11041 * } );
11042 *
11043 * @example
11044 * // 57 records after filtering, 100 without filtering (an initial filter applied)
11045 * $(document).ready( function() {
11046 * $('#example').dataTable( {
11047 * "serverSide": true,
11048 * "ajax": "scripts/server_processing.php",
11049 * "deferLoading": [ 57, 100 ],
11050 * "search": {
11051 * "search": "my_filter"
11052 * }
11053 * } );
11054 * } );
11055 */
11056 "iDeferLoading": null,
11057
11058
11059 /**
11060 * Number of rows to display on a single page when using pagination. If
11061 * feature enabled (`lengthChange`) then the end user will be able to override
11062 * this to a custom setting using a pop-up menu.
11063 * @type int
11064 * @default 10
11065 *
11066 * @dtopt Options
11067 * @name DataTable.defaults.pageLength
11068 *
11069 * @example
11070 * $(document).ready( function() {
11071 * $('#example').dataTable( {
11072 * "pageLength": 50
11073 * } );
11074 * } )
11075 */
11076 "iDisplayLength": 10,
11077
11078
11079 /**
11080 * Define the starting point for data display when using DataTables with
11081 * pagination. Note that this parameter is the number of records, rather than
11082 * the page number, so if you have 10 records per page and want to start on
11083 * the third page, it should be "20".
11084 * @type int
11085 * @default 0
11086 *
11087 * @dtopt Options
11088 * @name DataTable.defaults.displayStart
11089 *
11090 * @example
11091 * $(document).ready( function() {
11092 * $('#example').dataTable( {
11093 * "displayStart": 20
11094 * } );
11095 * } )
11096 */
11097 "iDisplayStart": 0,
11098
11099
11100 /**
11101 * By default DataTables allows keyboard navigation of the table (sorting, paging,
11102 * and filtering) by adding a `tabindex` attribute to the required elements. This
11103 * allows you to tab through the controls and press the enter key to activate them.
11104 * The tabindex is default 0, meaning that the tab follows the flow of the document.
11105 * You can overrule this using this parameter if you wish. Use a value of -1 to
11106 * disable built-in keyboard navigation.
11107 * @type int
11108 * @default 0
11109 *
11110 * @dtopt Options
11111 * @name DataTable.defaults.tabIndex
11112 *
11113 * @example
11114 * $(document).ready( function() {
11115 * $('#example').dataTable( {
11116 * "tabIndex": 1
11117 * } );
11118 * } );
11119 */
11120 "iTabIndex": 0,
11121
11122
11123 /**
11124 * Classes that DataTables assigns to the various components and features
11125 * that it adds to the HTML table. This allows classes to be configured
11126 * during initialisation in addition to through the static
11127 * {@link DataTable.ext.oStdClasses} object).
11128 * @namespace
11129 * @name DataTable.defaults.classes
11130 */
11131 "oClasses": {},
11132
11133
11134 /**
11135 * All strings that DataTables uses in the user interface that it creates
11136 * are defined in this object, allowing you to modified them individually or
11137 * completely replace them all as required.
11138 * @namespace
11139 * @name DataTable.defaults.language
11140 */
11141 "oLanguage": {
11142 /**
11143 * Strings that are used for WAI-ARIA labels and controls only (these are not
11144 * actually visible on the page, but will be read by screenreaders, and thus
11145 * must be internationalised as well).
11146 * @namespace
11147 * @name DataTable.defaults.language.aria
11148 */
11149 "oAria": {
11150 /**
11151 * ARIA label that is added to the table headers when the column may be
11152 * sorted ascending by activing the column (click or return when focused).
11153 * Note that the column header is prefixed to this string.
11154 * @type string
11155 * @default : activate to sort column ascending
11156 *
11157 * @dtopt Language
11158 * @name DataTable.defaults.language.aria.sortAscending
11159 *
11160 * @example
11161 * $(document).ready( function() {
11162 * $('#example').dataTable( {
11163 * "language": {
11164 * "aria": {
11165 * "sortAscending": " - click/return to sort ascending"
11166 * }
11167 * }
11168 * } );
11169 * } );
11170 */
11171 "sSortAscending": ": activate to sort column ascending",
11172
11173 /**
11174 * ARIA label that is added to the table headers when the column may be
11175 * sorted descending by activing the column (click or return when focused).
11176 * Note that the column header is prefixed to this string.
11177 * @type string
11178 * @default : activate to sort column ascending
11179 *
11180 * @dtopt Language
11181 * @name DataTable.defaults.language.aria.sortDescending
11182 *
11183 * @example
11184 * $(document).ready( function() {
11185 * $('#example').dataTable( {
11186 * "language": {
11187 * "aria": {
11188 * "sortDescending": " - click/return to sort descending"
11189 * }
11190 * }
11191 * } );
11192 * } );
11193 */
11194 "sSortDescending": ": activate to sort column descending"
11195 },
11196
11197 /**
11198 * Pagination string used by DataTables for the built-in pagination
11199 * control types.
11200 * @namespace
11201 * @name DataTable.defaults.language.paginate
11202 */
11203 "oPaginate": {
11204 /**
11205 * Text to use when using the 'full_numbers' type of pagination for the
11206 * button to take the user to the first page.
11207 * @type string
11208 * @default First
11209 *
11210 * @dtopt Language
11211 * @name DataTable.defaults.language.paginate.first
11212 *
11213 * @example
11214 * $(document).ready( function() {
11215 * $('#example').dataTable( {
11216 * "language": {
11217 * "paginate": {
11218 * "first": "First page"
11219 * }
11220 * }
11221 * } );
11222 * } );
11223 */
11224 "sFirst": "First",
11225
11226
11227 /**
11228 * Text to use when using the 'full_numbers' type of pagination for the
11229 * button to take the user to the last page.
11230 * @type string
11231 * @default Last
11232 *
11233 * @dtopt Language
11234 * @name DataTable.defaults.language.paginate.last
11235 *
11236 * @example
11237 * $(document).ready( function() {
11238 * $('#example').dataTable( {
11239 * "language": {
11240 * "paginate": {
11241 * "last": "Last page"
11242 * }
11243 * }
11244 * } );
11245 * } );
11246 */
11247 "sLast": "Last",
11248
11249
11250 /**
11251 * Text to use for the 'next' pagination button (to take the user to the
11252 * next page).
11253 * @type string
11254 * @default Next
11255 *
11256 * @dtopt Language
11257 * @name DataTable.defaults.language.paginate.next
11258 *
11259 * @example
11260 * $(document).ready( function() {
11261 * $('#example').dataTable( {
11262 * "language": {
11263 * "paginate": {
11264 * "next": "Next page"
11265 * }
11266 * }
11267 * } );
11268 * } );
11269 */
11270 "sNext": "Next",
11271
11272
11273 /**
11274 * Text to use for the 'previous' pagination button (to take the user to
11275 * the previous page).
11276 * @type string
11277 * @default Previous
11278 *
11279 * @dtopt Language
11280 * @name DataTable.defaults.language.paginate.previous
11281 *
11282 * @example
11283 * $(document).ready( function() {
11284 * $('#example').dataTable( {
11285 * "language": {
11286 * "paginate": {
11287 * "previous": "Previous page"
11288 * }
11289 * }
11290 * } );
11291 * } );
11292 */
11293 "sPrevious": "Previous"
11294 },
11295
11296 /**
11297 * This string is shown in preference to `zeroRecords` when the table is
11298 * empty of data (regardless of filtering). Note that this is an optional
11299 * parameter - if it is not given, the value of `zeroRecords` will be used
11300 * instead (either the default or given value).
11301 * @type string
11302 * @default No data available in table
11303 *
11304 * @dtopt Language
11305 * @name DataTable.defaults.language.emptyTable
11306 *
11307 * @example
11308 * $(document).ready( function() {
11309 * $('#example').dataTable( {
11310 * "language": {
11311 * "emptyTable": "No data available in table"
11312 * }
11313 * } );
11314 * } );
11315 */
11316 "sEmptyTable": "No data available in table",
11317
11318
11319 /**
11320 * This string gives information to the end user about the information
11321 * that is current on display on the page. The following tokens can be
11322 * used in the string and will be dynamically replaced as the table
11323 * display updates. This tokens can be placed anywhere in the string, or
11324 * removed as needed by the language requires:
11325 *
11326 * * `\_START\_` - Display index of the first record on the current page
11327 * * `\_END\_` - Display index of the last record on the current page
11328 * * `\_TOTAL\_` - Number of records in the table after filtering
11329 * * `\_MAX\_` - Number of records in the table without filtering
11330 * * `\_PAGE\_` - Current page number
11331 * * `\_PAGES\_` - Total number of pages of data in the table
11332 *
11333 * @type string
11334 * @default Showing _START_ to _END_ of _TOTAL_ entries
11335 *
11336 * @dtopt Language
11337 * @name DataTable.defaults.language.info
11338 *
11339 * @example
11340 * $(document).ready( function() {
11341 * $('#example').dataTable( {
11342 * "language": {
11343 * "info": "Showing page _PAGE_ of _PAGES_"
11344 * }
11345 * } );
11346 * } );
11347 */
11348 "sInfo": "Showing _START_ to _END_ of _TOTAL_ entries",
11349
11350
11351 /**
11352 * Display information string for when the table is empty. Typically the
11353 * format of this string should match `info`.
11354 * @type string
11355 * @default Showing 0 to 0 of 0 entries
11356 *
11357 * @dtopt Language
11358 * @name DataTable.defaults.language.infoEmpty
11359 *
11360 * @example
11361 * $(document).ready( function() {
11362 * $('#example').dataTable( {
11363 * "language": {
11364 * "infoEmpty": "No entries to show"
11365 * }
11366 * } );
11367 * } );
11368 */
11369 "sInfoEmpty": "Showing 0 to 0 of 0 entries",
11370
11371
11372 /**
11373 * When a user filters the information in a table, this string is appended
11374 * to the information (`info`) to give an idea of how strong the filtering
11375 * is. The variable _MAX_ is dynamically updated.
11376 * @type string
11377 * @default (filtered from _MAX_ total entries)
11378 *
11379 * @dtopt Language
11380 * @name DataTable.defaults.language.infoFiltered
11381 *
11382 * @example
11383 * $(document).ready( function() {
11384 * $('#example').dataTable( {
11385 * "language": {
11386 * "infoFiltered": " - filtering from _MAX_ records"
11387 * }
11388 * } );
11389 * } );
11390 */
11391 "sInfoFiltered": "(filtered from _MAX_ total entries)",
11392
11393
11394 /**
11395 * If can be useful to append extra information to the info string at times,
11396 * and this variable does exactly that. This information will be appended to
11397 * the `info` (`infoEmpty` and `infoFiltered` in whatever combination they are
11398 * being used) at all times.
11399 * @type string
11400 * @default <i>Empty string</i>
11401 *
11402 * @dtopt Language
11403 * @name DataTable.defaults.language.infoPostFix
11404 *
11405 * @example
11406 * $(document).ready( function() {
11407 * $('#example').dataTable( {
11408 * "language": {
11409 * "infoPostFix": "All records shown are derived from real information."
11410 * }
11411 * } );
11412 * } );
11413 */
11414 "sInfoPostFix": "",
11415
11416
11417 /**
11418 * This decimal place operator is a little different from the other
11419 * language options since DataTables doesn't output floating point
11420 * numbers, so it won't ever use this for display of a number. Rather,
11421 * what this parameter does is modify the sort methods of the table so
11422 * that numbers which are in a format which has a character other than
11423 * a period (`.`) as a decimal place will be sorted numerically.
11424 *
11425 * Note that numbers with different decimal places cannot be shown in
11426 * the same table and still be sortable, the table must be consistent.
11427 * However, multiple different tables on the page can use different
11428 * decimal place characters.
11429 * @type string
11430 * @default
11431 *
11432 * @dtopt Language
11433 * @name DataTable.defaults.language.decimal
11434 *
11435 * @example
11436 * $(document).ready( function() {
11437 * $('#example').dataTable( {
11438 * "language": {
11439 * "decimal": ","
11440 * "thousands": "."
11441 * }
11442 * } );
11443 * } );
11444 */
11445 "sDecimal": "",
11446
11447
11448 /**
11449 * DataTables has a build in number formatter (`formatNumber`) which is
11450 * used to format large numbers that are used in the table information.
11451 * By default a comma is used, but this can be trivially changed to any
11452 * character you wish with this parameter.
11453 * @type string
11454 * @default ,
11455 *
11456 * @dtopt Language
11457 * @name DataTable.defaults.language.thousands
11458 *
11459 * @example
11460 * $(document).ready( function() {
11461 * $('#example').dataTable( {
11462 * "language": {
11463 * "thousands": "'"
11464 * }
11465 * } );
11466 * } );
11467 */
11468 "sThousands": ",",
11469
11470
11471 /**
11472 * Detail the action that will be taken when the drop down menu for the
11473 * pagination length option is changed. The '_MENU_' variable is replaced
11474 * with a default select list of 10, 25, 50 and 100, and can be replaced
11475 * with a custom select box if required.
11476 * @type string
11477 * @default Show _MENU_ entries
11478 *
11479 * @dtopt Language
11480 * @name DataTable.defaults.language.lengthMenu
11481 *
11482 * @example
11483 * // Language change only
11484 * $(document).ready( function() {
11485 * $('#example').dataTable( {
11486 * "language": {
11487 * "lengthMenu": "Display _MENU_ records"
11488 * }
11489 * } );
11490 * } );
11491 *
11492 * @example
11493 * // Language and options change
11494 * $(document).ready( function() {
11495 * $('#example').dataTable( {
11496 * "language": {
11497 * "lengthMenu": 'Display <select>'+
11498 * '<option value="10">10</option>'+
11499 * '<option value="20">20</option>'+
11500 * '<option value="30">30</option>'+
11501 * '<option value="40">40</option>'+
11502 * '<option value="50">50</option>'+
11503 * '<option value="-1">All</option>'+
11504 * '</select> records'
11505 * }
11506 * } );
11507 * } );
11508 */
11509 "sLengthMenu": "Show _MENU_ entries",
11510
11511
11512 /**
11513 * When using Ajax sourced data and during the first draw when DataTables is
11514 * gathering the data, this message is shown in an empty row in the table to
11515 * indicate to the end user the the data is being loaded. Note that this
11516 * parameter is not used when loading data by server-side processing, just
11517 * Ajax sourced data with client-side processing.
11518 * @type string
11519 * @default Loading...
11520 *
11521 * @dtopt Language
11522 * @name DataTable.defaults.language.loadingRecords
11523 *
11524 * @example
11525 * $(document).ready( function() {
11526 * $('#example').dataTable( {
11527 * "language": {
11528 * "loadingRecords": "Please wait - loading..."
11529 * }
11530 * } );
11531 * } );
11532 */
11533 "sLoadingRecords": "Loading...",
11534
11535
11536 /**
11537 * Text which is displayed when the table is processing a user action
11538 * (usually a sort command or similar).
11539 * @type string
11540 * @default Processing...
11541 *
11542 * @dtopt Language
11543 * @name DataTable.defaults.language.processing
11544 *
11545 * @example
11546 * $(document).ready( function() {
11547 * $('#example').dataTable( {
11548 * "language": {
11549 * "processing": "DataTables is currently busy"
11550 * }
11551 * } );
11552 * } );
11553 */
11554 "sProcessing": "Processing...",
11555
11556
11557 /**
11558 * Details the actions that will be taken when the user types into the
11559 * filtering input text box. The variable "_INPUT_", if used in the string,
11560 * is replaced with the HTML text box for the filtering input allowing
11561 * control over where it appears in the string. If "_INPUT_" is not given
11562 * then the input box is appended to the string automatically.
11563 * @type string
11564 * @default Search:
11565 *
11566 * @dtopt Language
11567 * @name DataTable.defaults.language.search
11568 *
11569 * @example
11570 * // Input text box will be appended at the end automatically
11571 * $(document).ready( function() {
11572 * $('#example').dataTable( {
11573 * "language": {
11574 * "search": "Filter records:"
11575 * }
11576 * } );
11577 * } );
11578 *
11579 * @example
11580 * // Specify where the filter should appear
11581 * $(document).ready( function() {
11582 * $('#example').dataTable( {
11583 * "language": {
11584 * "search": "Apply filter _INPUT_ to table"
11585 * }
11586 * } );
11587 * } );
11588 */
11589 "sSearch": "Search:",
11590
11591
11592 /**
11593 * Assign a `placeholder` attribute to the search `input` element
11594 * @type string
11595 * @default
11596 *
11597 * @dtopt Language
11598 * @name DataTable.defaults.language.searchPlaceholder
11599 */
11600 "sSearchPlaceholder": "",
11601
11602
11603 /**
11604 * All of the language information can be stored in a file on the
11605 * server-side, which DataTables will look up if this parameter is passed.
11606 * It must store the URL of the language file, which is in a JSON format,
11607 * and the object has the same properties as the oLanguage object in the
11608 * initialiser object (i.e. the above parameters). Please refer to one of
11609 * the example language files to see how this works in action.
11610 * @type string
11611 * @default <i>Empty string - i.e. disabled</i>
11612 *
11613 * @dtopt Language
11614 * @name DataTable.defaults.language.url
11615 *
11616 * @example
11617 * $(document).ready( function() {
11618 * $('#example').dataTable( {
11619 * "language": {
11620 * "url": "http://www.sprymedia.co.uk/dataTables/lang.txt"
11621 * }
11622 * } );
11623 * } );
11624 */
11625 "sUrl": "",
11626
11627
11628 /**
11629 * Text shown inside the table records when the is no information to be
11630 * displayed after filtering. `emptyTable` is shown when there is simply no
11631 * information in the table at all (regardless of filtering).
11632 * @type string
11633 * @default No matching records found
11634 *
11635 * @dtopt Language
11636 * @name DataTable.defaults.language.zeroRecords
11637 *
11638 * @example
11639 * $(document).ready( function() {
11640 * $('#example').dataTable( {
11641 * "language": {
11642 * "zeroRecords": "No records to display"
11643 * }
11644 * } );
11645 * } );
11646 */
11647 "sZeroRecords": "No matching records found"
11648 },
11649
11650
11651 /**
11652 * This parameter allows you to have define the global filtering state at
11653 * initialisation time. As an object the `search` parameter must be
11654 * defined, but all other parameters are optional. When `regex` is true,
11655 * the search string will be treated as a regular expression, when false
11656 * (default) it will be treated as a straight string. When `smart`
11657 * DataTables will use it's smart filtering methods (to word match at
11658 * any point in the data), when false this will not be done.
11659 * @namespace
11660 * @extends DataTable.models.oSearch
11661 *
11662 * @dtopt Options
11663 * @name DataTable.defaults.search
11664 *
11665 * @example
11666 * $(document).ready( function() {
11667 * $('#example').dataTable( {
11668 * "search": {"search": "Initial search"}
11669 * } );
11670 * } )
11671 */
11672 "oSearch": $.extend( {}, DataTable.models.oSearch ),
11673
11674
11675 /**
11676 * __Deprecated__ The functionality provided by this parameter has now been
11677 * superseded by that provided through `ajax`, which should be used instead.
11678 *
11679 * By default DataTables will look for the property `data` (or `aaData` for
11680 * compatibility with DataTables 1.9-) when obtaining data from an Ajax
11681 * source or for server-side processing - this parameter allows that
11682 * property to be changed. You can use Javascript dotted object notation to
11683 * get a data source for multiple levels of nesting.
11684 * @type string
11685 * @default data
11686 *
11687 * @dtopt Options
11688 * @dtopt Server-side
11689 * @name DataTable.defaults.ajaxDataProp
11690 *
11691 * @deprecated 1.10. Please use `ajax` for this functionality now.
11692 */
11693 "sAjaxDataProp": "data",
11694
11695
11696 /**
11697 * __Deprecated__ The functionality provided by this parameter has now been
11698 * superseded by that provided through `ajax`, which should be used instead.
11699 *
11700 * You can instruct DataTables to load data from an external
11701 * source using this parameter (use aData if you want to pass data in you
11702 * already have). Simply provide a url a JSON object can be obtained from.
11703 * @type string
11704 * @default null
11705 *
11706 * @dtopt Options
11707 * @dtopt Server-side
11708 * @name DataTable.defaults.ajaxSource
11709 *
11710 * @deprecated 1.10. Please use `ajax` for this functionality now.
11711 */
11712 "sAjaxSource": null,
11713
11714
11715 /**
11716 * This initialisation variable allows you to specify exactly where in the
11717 * DOM you want DataTables to inject the various controls it adds to the page
11718 * (for example you might want the pagination controls at the top of the
11719 * table). DIV elements (with or without a custom class) can also be added to
11720 * aid styling. The follow syntax is used:
11721 * <ul>
11722 * <li>The following options are allowed:
11723 * <ul>
11724 * <li>'l' - Length changing</li>
11725 * <li>'f' - Filtering input</li>
11726 * <li>'t' - The table!</li>
11727 * <li>'i' - Information</li>
11728 * <li>'p' - Pagination</li>
11729 * <li>'r' - pRocessing</li>
11730 * </ul>
11731 * </li>
11732 * <li>The following constants are allowed:
11733 * <ul>
11734 * <li>'H' - jQueryUI theme "header" classes ('fg-toolbar ui-widget-header ui-corner-tl ui-corner-tr ui-helper-clearfix')</li>
11735 * <li>'F' - jQueryUI theme "footer" classes ('fg-toolbar ui-widget-header ui-corner-bl ui-corner-br ui-helper-clearfix')</li>
11736 * </ul>
11737 * </li>
11738 * <li>The following syntax is expected:
11739 * <ul>
11740 * <li>'&lt;' and '&gt;' - div elements</li>
11741 * <li>'&lt;"class" and '&gt;' - div with a class</li>
11742 * <li>'&lt;"#id" and '&gt;' - div with an ID</li>
11743 * </ul>
11744 * </li>
11745 * <li>Examples:
11746 * <ul>
11747 * <li>'&lt;"wrapper"flipt&gt;'</li>
11748 * <li>'&lt;lf&lt;t&gt;ip&gt;'</li>
11749 * </ul>
11750 * </li>
11751 * </ul>
11752 * @type string
11753 * @default lfrtip <i>(when `jQueryUI` is false)</i> <b>or</b>
11754 * <"H"lfr>t<"F"ip> <i>(when `jQueryUI` is true)</i>
11755 *
11756 * @dtopt Options
11757 * @name DataTable.defaults.dom
11758 *
11759 * @example
11760 * $(document).ready( function() {
11761 * $('#example').dataTable( {
11762 * "dom": '&lt;"top"i&gt;rt&lt;"bottom"flp&gt;&lt;"clear"&gt;'
11763 * } );
11764 * } );
11765 */
11766 "sDom": "lfrtip",
11767
11768
11769 /**
11770 * Search delay option. This will throttle full table searches that use the
11771 * DataTables provided search input element (it does not effect calls to
11772 * `dt-api search()`, providing a delay before the search is made.
11773 * @type integer
11774 * @default 0
11775 *
11776 * @dtopt Options
11777 * @name DataTable.defaults.searchDelay
11778 *
11779 * @example
11780 * $(document).ready( function() {
11781 * $('#example').dataTable( {
11782 * "searchDelay": 200
11783 * } );
11784 * } )
11785 */
11786 "searchDelay": null,
11787
11788
11789 /**
11790 * DataTables features four different built-in options for the buttons to
11791 * display for pagination control:
11792 *
11793 * * `simple` - 'Previous' and 'Next' buttons only
11794 * * 'simple_numbers` - 'Previous' and 'Next' buttons, plus page numbers
11795 * * `full` - 'First', 'Previous', 'Next' and 'Last' buttons
11796 * * `full_numbers` - 'First', 'Previous', 'Next' and 'Last' buttons, plus
11797 * page numbers
11798 *
11799 * Further methods can be added using {@link DataTable.ext.oPagination}.
11800 * @type string
11801 * @default simple_numbers
11802 *
11803 * @dtopt Options
11804 * @name DataTable.defaults.pagingType
11805 *
11806 * @example
11807 * $(document).ready( function() {
11808 * $('#example').dataTable( {
11809 * "pagingType": "full_numbers"
11810 * } );
11811 * } )
11812 */
11813 "sPaginationType": "simple_numbers",
11814
11815
11816 /**
11817 * Enable horizontal scrolling. When a table is too wide to fit into a
11818 * certain layout, or you have a large number of columns in the table, you
11819 * can enable x-scrolling to show the table in a viewport, which can be
11820 * scrolled. This property can be `true` which will allow the table to
11821 * scroll horizontally when needed, or any CSS unit, or a number (in which
11822 * case it will be treated as a pixel measurement). Setting as simply `true`
11823 * is recommended.
11824 * @type boolean|string
11825 * @default <i>blank string - i.e. disabled</i>
11826 *
11827 * @dtopt Features
11828 * @name DataTable.defaults.scrollX
11829 *
11830 * @example
11831 * $(document).ready( function() {
11832 * $('#example').dataTable( {
11833 * "scrollX": true,
11834 * "scrollCollapse": true
11835 * } );
11836 * } );
11837 */
11838 "sScrollX": "",
11839
11840
11841 /**
11842 * This property can be used to force a DataTable to use more width than it
11843 * might otherwise do when x-scrolling is enabled. For example if you have a
11844 * table which requires to be well spaced, this parameter is useful for
11845 * "over-sizing" the table, and thus forcing scrolling. This property can by
11846 * any CSS unit, or a number (in which case it will be treated as a pixel
11847 * measurement).
11848 * @type string
11849 * @default <i>blank string - i.e. disabled</i>
11850 *
11851 * @dtopt Options
11852 * @name DataTable.defaults.scrollXInner
11853 *
11854 * @example
11855 * $(document).ready( function() {
11856 * $('#example').dataTable( {
11857 * "scrollX": "100%",
11858 * "scrollXInner": "110%"
11859 * } );
11860 * } );
11861 */
11862 "sScrollXInner": "",
11863
11864
11865 /**
11866 * Enable vertical scrolling. Vertical scrolling will constrain the DataTable
11867 * to the given height, and enable scrolling for any data which overflows the
11868 * current viewport. This can be used as an alternative to paging to display
11869 * a lot of data in a small area (although paging and scrolling can both be
11870 * enabled at the same time). This property can be any CSS unit, or a number
11871 * (in which case it will be treated as a pixel measurement).
11872 * @type string
11873 * @default <i>blank string - i.e. disabled</i>
11874 *
11875 * @dtopt Features
11876 * @name DataTable.defaults.scrollY
11877 *
11878 * @example
11879 * $(document).ready( function() {
11880 * $('#example').dataTable( {
11881 * "scrollY": "200px",
11882 * "paginate": false
11883 * } );
11884 * } );
11885 */
11886 "sScrollY": "",
11887
11888
11889 /**
11890 * __Deprecated__ The functionality provided by this parameter has now been
11891 * superseded by that provided through `ajax`, which should be used instead.
11892 *
11893 * Set the HTTP method that is used to make the Ajax call for server-side
11894 * processing or Ajax sourced data.
11895 * @type string
11896 * @default GET
11897 *
11898 * @dtopt Options
11899 * @dtopt Server-side
11900 * @name DataTable.defaults.serverMethod
11901 *
11902 * @deprecated 1.10. Please use `ajax` for this functionality now.
11903 */
11904 "sServerMethod": "GET",
11905
11906
11907 /**
11908 * DataTables makes use of renderers when displaying HTML elements for
11909 * a table. These renderers can be added or modified by plug-ins to
11910 * generate suitable mark-up for a site. For example the Bootstrap
11911 * integration plug-in for DataTables uses a paging button renderer to
11912 * display pagination buttons in the mark-up required by Bootstrap.
11913 *
11914 * For further information about the renderers available see
11915 * DataTable.ext.renderer
11916 * @type string|object
11917 * @default null
11918 *
11919 * @name DataTable.defaults.renderer
11920 *
11921 */
11922 "renderer": null,
11923
11924
11925 /**
11926 * Set the data property name that DataTables should use to get a row's id
11927 * to set as the `id` property in the node.
11928 * @type string
11929 * @default DT_RowId
11930 *
11931 * @name DataTable.defaults.rowId
11932 */
11933 "rowId": "DT_RowId"
11934 };
11935
11936 _fnHungarianMap( DataTable.defaults );
11937
11938
11939
11940 /*
11941 * Developer note - See note in model.defaults.js about the use of Hungarian
11942 * notation and camel case.
11943 */
11944
11945 /**
11946 * Column options that can be given to DataTables at initialisation time.
11947 * @namespace
11948 */
11949 DataTable.defaults.column = {
11950 /**
11951 * Define which column(s) an order will occur on for this column. This
11952 * allows a column's ordering to take multiple columns into account when
11953 * doing a sort or use the data from a different column. For example first
11954 * name / last name columns make sense to do a multi-column sort over the
11955 * two columns.
11956 * @type array|int
11957 * @default null <i>Takes the value of the column index automatically</i>
11958 *
11959 * @name DataTable.defaults.column.orderData
11960 * @dtopt Columns
11961 *
11962 * @example
11963 * // Using `columnDefs`
11964 * $(document).ready( function() {
11965 * $('#example').dataTable( {
11966 * "columnDefs": [
11967 * { "orderData": [ 0, 1 ], "targets": [ 0 ] },
11968 * { "orderData": [ 1, 0 ], "targets": [ 1 ] },
11969 * { "orderData": 2, "targets": [ 2 ] }
11970 * ]
11971 * } );
11972 * } );
11973 *
11974 * @example
11975 * // Using `columns`
11976 * $(document).ready( function() {
11977 * $('#example').dataTable( {
11978 * "columns": [
11979 * { "orderData": [ 0, 1 ] },
11980 * { "orderData": [ 1, 0 ] },
11981 * { "orderData": 2 },
11982 * null,
11983 * null
11984 * ]
11985 * } );
11986 * } );
11987 */
11988 "aDataSort": null,
11989 "iDataSort": -1,
11990
11991
11992 /**
11993 * You can control the default ordering direction, and even alter the
11994 * behaviour of the sort handler (i.e. only allow ascending ordering etc)
11995 * using this parameter.
11996 * @type array
11997 * @default [ 'asc', 'desc' ]
11998 *
11999 * @name DataTable.defaults.column.orderSequence
12000 * @dtopt Columns
12001 *
12002 * @example
12003 * // Using `columnDefs`
12004 * $(document).ready( function() {
12005 * $('#example').dataTable( {
12006 * "columnDefs": [
12007 * { "orderSequence": [ "asc" ], "targets": [ 1 ] },
12008 * { "orderSequence": [ "desc", "asc", "asc" ], "targets": [ 2 ] },
12009 * { "orderSequence": [ "desc" ], "targets": [ 3 ] }
12010 * ]
12011 * } );
12012 * } );
12013 *
12014 * @example
12015 * // Using `columns`
12016 * $(document).ready( function() {
12017 * $('#example').dataTable( {
12018 * "columns": [
12019 * null,
12020 * { "orderSequence": [ "asc" ] },
12021 * { "orderSequence": [ "desc", "asc", "asc" ] },
12022 * { "orderSequence": [ "desc" ] },
12023 * null
12024 * ]
12025 * } );
12026 * } );
12027 */
12028 "asSorting": [ 'asc', 'desc' ],
12029
12030
12031 /**
12032 * Enable or disable filtering on the data in this column.
12033 * @type boolean
12034 * @default true
12035 *
12036 * @name DataTable.defaults.column.searchable
12037 * @dtopt Columns
12038 *
12039 * @example
12040 * // Using `columnDefs`
12041 * $(document).ready( function() {
12042 * $('#example').dataTable( {
12043 * "columnDefs": [
12044 * { "searchable": false, "targets": [ 0 ] }
12045 * ] } );
12046 * } );
12047 *
12048 * @example
12049 * // Using `columns`
12050 * $(document).ready( function() {
12051 * $('#example').dataTable( {
12052 * "columns": [
12053 * { "searchable": false },
12054 * null,
12055 * null,
12056 * null,
12057 * null
12058 * ] } );
12059 * } );
12060 */
12061 "bSearchable": true,
12062
12063
12064 /**
12065 * Enable or disable ordering on this column.
12066 * @type boolean
12067 * @default true
12068 *
12069 * @name DataTable.defaults.column.orderable
12070 * @dtopt Columns
12071 *
12072 * @example
12073 * // Using `columnDefs`
12074 * $(document).ready( function() {
12075 * $('#example').dataTable( {
12076 * "columnDefs": [
12077 * { "orderable": false, "targets": [ 0 ] }
12078 * ] } );
12079 * } );
12080 *
12081 * @example
12082 * // Using `columns`
12083 * $(document).ready( function() {
12084 * $('#example').dataTable( {
12085 * "columns": [
12086 * { "orderable": false },
12087 * null,
12088 * null,
12089 * null,
12090 * null
12091 * ] } );
12092 * } );
12093 */
12094 "bSortable": true,
12095
12096
12097 /**
12098 * Enable or disable the display of this column.
12099 * @type boolean
12100 * @default true
12101 *
12102 * @name DataTable.defaults.column.visible
12103 * @dtopt Columns
12104 *
12105 * @example
12106 * // Using `columnDefs`
12107 * $(document).ready( function() {
12108 * $('#example').dataTable( {
12109 * "columnDefs": [
12110 * { "visible": false, "targets": [ 0 ] }
12111 * ] } );
12112 * } );
12113 *
12114 * @example
12115 * // Using `columns`
12116 * $(document).ready( function() {
12117 * $('#example').dataTable( {
12118 * "columns": [
12119 * { "visible": false },
12120 * null,
12121 * null,
12122 * null,
12123 * null
12124 * ] } );
12125 * } );
12126 */
12127 "bVisible": true,
12128
12129
12130 /**
12131 * Developer definable function that is called whenever a cell is created (Ajax source,
12132 * etc) or processed for input (DOM source). This can be used as a compliment to mRender
12133 * allowing you to modify the DOM element (add background colour for example) when the
12134 * element is available.
12135 * @type function
12136 * @param {element} td The TD node that has been created
12137 * @param {*} cellData The Data for the cell
12138 * @param {array|object} rowData The data for the whole row
12139 * @param {int} row The row index for the aoData data store
12140 * @param {int} col The column index for aoColumns
12141 *
12142 * @name DataTable.defaults.column.createdCell
12143 * @dtopt Columns
12144 *
12145 * @example
12146 * $(document).ready( function() {
12147 * $('#example').dataTable( {
12148 * "columnDefs": [ {
12149 * "targets": [3],
12150 * "createdCell": function (td, cellData, rowData, row, col) {
12151 * if ( cellData == "1.7" ) {
12152 * $(td).css('color', 'blue')
12153 * }
12154 * }
12155 * } ]
12156 * });
12157 * } );
12158 */
12159 "fnCreatedCell": null,
12160
12161
12162 /**
12163 * This parameter has been replaced by `data` in DataTables to ensure naming
12164 * consistency. `dataProp` can still be used, as there is backwards
12165 * compatibility in DataTables for this option, but it is strongly
12166 * recommended that you use `data` in preference to `dataProp`.
12167 * @name DataTable.defaults.column.dataProp
12168 */
12169
12170
12171 /**
12172 * This property can be used to read data from any data source property,
12173 * including deeply nested objects / properties. `data` can be given in a
12174 * number of different ways which effect its behaviour:
12175 *
12176 * * `integer` - treated as an array index for the data source. This is the
12177 * default that DataTables uses (incrementally increased for each column).
12178 * * `string` - read an object property from the data source. There are
12179 * three 'special' options that can be used in the string to alter how
12180 * DataTables reads the data from the source object:
12181 * * `.` - Dotted Javascript notation. Just as you use a `.` in
12182 * Javascript to read from nested objects, so to can the options
12183 * specified in `data`. For example: `browser.version` or
12184 * `browser.name`. If your object parameter name contains a period, use
12185 * `\\` to escape it - i.e. `first\\.name`.
12186 * * `[]` - Array notation. DataTables can automatically combine data
12187 * from and array source, joining the data with the characters provided
12188 * between the two brackets. For example: `name[, ]` would provide a
12189 * comma-space separated list from the source array. If no characters
12190 * are provided between the brackets, the original array source is
12191 * returned.
12192 * * `()` - Function notation. Adding `()` to the end of a parameter will
12193 * execute a function of the name given. For example: `browser()` for a
12194 * simple function on the data source, `browser.version()` for a
12195 * function in a nested property or even `browser().version` to get an
12196 * object property if the function called returns an object. Note that
12197 * function notation is recommended for use in `render` rather than
12198 * `data` as it is much simpler to use as a renderer.
12199 * * `null` - use the original data source for the row rather than plucking
12200 * data directly from it. This action has effects on two other
12201 * initialisation options:
12202 * * `defaultContent` - When null is given as the `data` option and
12203 * `defaultContent` is specified for the column, the value defined by
12204 * `defaultContent` will be used for the cell.
12205 * * `render` - When null is used for the `data` option and the `render`
12206 * option is specified for the column, the whole data source for the
12207 * row is used for the renderer.
12208 * * `function` - the function given will be executed whenever DataTables
12209 * needs to set or get the data for a cell in the column. The function
12210 * takes three parameters:
12211 * * Parameters:
12212 * * `{array|object}` The data source for the row
12213 * * `{string}` The type call data requested - this will be 'set' when
12214 * setting data or 'filter', 'display', 'type', 'sort' or undefined
12215 * when gathering data. Note that when `undefined` is given for the
12216 * type DataTables expects to get the raw data for the object back<
12217 * * `{*}` Data to set when the second parameter is 'set'.
12218 * * Return:
12219 * * The return value from the function is not required when 'set' is
12220 * the type of call, but otherwise the return is what will be used
12221 * for the data requested.
12222 *
12223 * Note that `data` is a getter and setter option. If you just require
12224 * formatting of data for output, you will likely want to use `render` which
12225 * is simply a getter and thus simpler to use.
12226 *
12227 * Note that prior to DataTables 1.9.2 `data` was called `mDataProp`. The
12228 * name change reflects the flexibility of this property and is consistent
12229 * with the naming of mRender. If 'mDataProp' is given, then it will still
12230 * be used by DataTables, as it automatically maps the old name to the new
12231 * if required.
12232 *
12233 * @type string|int|function|null
12234 * @default null <i>Use automatically calculated column index</i>
12235 *
12236 * @name DataTable.defaults.column.data
12237 * @dtopt Columns
12238 *
12239 * @example
12240 * // Read table data from objects
12241 * // JSON structure for each row:
12242 * // {
12243 * // "engine": {value},
12244 * // "browser": {value},
12245 * // "platform": {value},
12246 * // "version": {value},
12247 * // "grade": {value}
12248 * // }
12249 * $(document).ready( function() {
12250 * $('#example').dataTable( {
12251 * "ajaxSource": "sources/objects.txt",
12252 * "columns": [
12253 * { "data": "engine" },
12254 * { "data": "browser" },
12255 * { "data": "platform" },
12256 * { "data": "version" },
12257 * { "data": "grade" }
12258 * ]
12259 * } );
12260 * } );
12261 *
12262 * @example
12263 * // Read information from deeply nested objects
12264 * // JSON structure for each row:
12265 * // {
12266 * // "engine": {value},
12267 * // "browser": {value},
12268 * // "platform": {
12269 * // "inner": {value}
12270 * // },
12271 * // "details": [
12272 * // {value}, {value}
12273 * // ]
12274 * // }
12275 * $(document).ready( function() {
12276 * $('#example').dataTable( {
12277 * "ajaxSource": "sources/deep.txt",
12278 * "columns": [
12279 * { "data": "engine" },
12280 * { "data": "browser" },
12281 * { "data": "platform.inner" },
12282 * { "data": "platform.details.0" },
12283 * { "data": "platform.details.1" }
12284 * ]
12285 * } );
12286 * } );
12287 *
12288 * @example
12289 * // Using `data` as a function to provide different information for
12290 * // sorting, filtering and display. In this case, currency (price)
12291 * $(document).ready( function() {
12292 * $('#example').dataTable( {
12293 * "columnDefs": [ {
12294 * "targets": [ 0 ],
12295 * "data": function ( source, type, val ) {
12296 * if (type === 'set') {
12297 * source.price = val;
12298 * // Store the computed dislay and filter values for efficiency
12299 * source.price_display = val=="" ? "" : "$"+numberFormat(val);
12300 * source.price_filter = val=="" ? "" : "$"+numberFormat(val)+" "+val;
12301 * return;
12302 * }
12303 * else if (type === 'display') {
12304 * return source.price_display;
12305 * }
12306 * else if (type === 'filter') {
12307 * return source.price_filter;
12308 * }
12309 * // 'sort', 'type' and undefined all just use the integer
12310 * return source.price;
12311 * }
12312 * } ]
12313 * } );
12314 * } );
12315 *
12316 * @example
12317 * // Using default content
12318 * $(document).ready( function() {
12319 * $('#example').dataTable( {
12320 * "columnDefs": [ {
12321 * "targets": [ 0 ],
12322 * "data": null,
12323 * "defaultContent": "Click to edit"
12324 * } ]
12325 * } );
12326 * } );
12327 *
12328 * @example
12329 * // Using array notation - outputting a list from an array
12330 * $(document).ready( function() {
12331 * $('#example').dataTable( {
12332 * "columnDefs": [ {
12333 * "targets": [ 0 ],
12334 * "data": "name[, ]"
12335 * } ]
12336 * } );
12337 * } );
12338 *
12339 */
12340 "mData": null,
12341
12342
12343 /**
12344 * This property is the rendering partner to `data` and it is suggested that
12345 * when you want to manipulate data for display (including filtering,
12346 * sorting etc) without altering the underlying data for the table, use this
12347 * property. `render` can be considered to be the the read only companion to
12348 * `data` which is read / write (then as such more complex). Like `data`
12349 * this option can be given in a number of different ways to effect its
12350 * behaviour:
12351 *
12352 * * `integer` - treated as an array index for the data source. This is the
12353 * default that DataTables uses (incrementally increased for each column).
12354 * * `string` - read an object property from the data source. There are
12355 * three 'special' options that can be used in the string to alter how
12356 * DataTables reads the data from the source object:
12357 * * `.` - Dotted Javascript notation. Just as you use a `.` in
12358 * Javascript to read from nested objects, so to can the options
12359 * specified in `data`. For example: `browser.version` or
12360 * `browser.name`. If your object parameter name contains a period, use
12361 * `\\` to escape it - i.e. `first\\.name`.
12362 * * `[]` - Array notation. DataTables can automatically combine data
12363 * from and array source, joining the data with the characters provided
12364 * between the two brackets. For example: `name[, ]` would provide a
12365 * comma-space separated list from the source array. If no characters
12366 * are provided between the brackets, the original array source is
12367 * returned.
12368 * * `()` - Function notation. Adding `()` to the end of a parameter will
12369 * execute a function of the name given. For example: `browser()` for a
12370 * simple function on the data source, `browser.version()` for a
12371 * function in a nested property or even `browser().version` to get an
12372 * object property if the function called returns an object.
12373 * * `object` - use different data for the different data types requested by
12374 * DataTables ('filter', 'display', 'type' or 'sort'). The property names
12375 * of the object is the data type the property refers to and the value can
12376 * defined using an integer, string or function using the same rules as
12377 * `render` normally does. Note that an `_` option _must_ be specified.
12378 * This is the default value to use if you haven't specified a value for
12379 * the data type requested by DataTables.
12380 * * `function` - the function given will be executed whenever DataTables
12381 * needs to set or get the data for a cell in the column. The function
12382 * takes three parameters:
12383 * * Parameters:
12384 * * {array|object} The data source for the row (based on `data`)
12385 * * {string} The type call data requested - this will be 'filter',
12386 * 'display', 'type' or 'sort'.
12387 * * {array|object} The full data source for the row (not based on
12388 * `data`)
12389 * * Return:
12390 * * The return value from the function is what will be used for the
12391 * data requested.
12392 *
12393 * @type string|int|function|object|null
12394 * @default null Use the data source value.
12395 *
12396 * @name DataTable.defaults.column.render
12397 * @dtopt Columns
12398 *
12399 * @example
12400 * // Create a comma separated list from an array of objects
12401 * $(document).ready( function() {
12402 * $('#example').dataTable( {
12403 * "ajaxSource": "sources/deep.txt",
12404 * "columns": [
12405 * { "data": "engine" },
12406 * { "data": "browser" },
12407 * {
12408 * "data": "platform",
12409 * "render": "[, ].name"
12410 * }
12411 * ]
12412 * } );
12413 * } );
12414 *
12415 * @example
12416 * // Execute a function to obtain data
12417 * $(document).ready( function() {
12418 * $('#example').dataTable( {
12419 * "columnDefs": [ {
12420 * "targets": [ 0 ],
12421 * "data": null, // Use the full data source object for the renderer's source
12422 * "render": "browserName()"
12423 * } ]
12424 * } );
12425 * } );
12426 *
12427 * @example
12428 * // As an object, extracting different data for the different types
12429 * // This would be used with a data source such as:
12430 * // { "phone": 5552368, "phone_filter": "5552368 555-2368", "phone_display": "555-2368" }
12431 * // Here the `phone` integer is used for sorting and type detection, while `phone_filter`
12432 * // (which has both forms) is used for filtering for if a user inputs either format, while
12433 * // the formatted phone number is the one that is shown in the table.
12434 * $(document).ready( function() {
12435 * $('#example').dataTable( {
12436 * "columnDefs": [ {
12437 * "targets": [ 0 ],
12438 * "data": null, // Use the full data source object for the renderer's source
12439 * "render": {
12440 * "_": "phone",
12441 * "filter": "phone_filter",
12442 * "display": "phone_display"
12443 * }
12444 * } ]
12445 * } );
12446 * } );
12447 *
12448 * @example
12449 * // Use as a function to create a link from the data source
12450 * $(document).ready( function() {
12451 * $('#example').dataTable( {
12452 * "columnDefs": [ {
12453 * "targets": [ 0 ],
12454 * "data": "download_link",
12455 * "render": function ( data, type, full ) {
12456 * return '<a href="'+data+'">Download</a>';
12457 * }
12458 * } ]
12459 * } );
12460 * } );
12461 */
12462 "mRender": null,
12463
12464
12465 /**
12466 * Change the cell type created for the column - either TD cells or TH cells. This
12467 * can be useful as TH cells have semantic meaning in the table body, allowing them
12468 * to act as a header for a row (you may wish to add scope='row' to the TH elements).
12469 * @type string
12470 * @default td
12471 *
12472 * @name DataTable.defaults.column.cellType
12473 * @dtopt Columns
12474 *
12475 * @example
12476 * // Make the first column use TH cells
12477 * $(document).ready( function() {
12478 * $('#example').dataTable( {
12479 * "columnDefs": [ {
12480 * "targets": [ 0 ],
12481 * "cellType": "th"
12482 * } ]
12483 * } );
12484 * } );
12485 */
12486 "sCellType": "td",
12487
12488
12489 /**
12490 * Class to give to each cell in this column.
12491 * @type string
12492 * @default <i>Empty string</i>
12493 *
12494 * @name DataTable.defaults.column.class
12495 * @dtopt Columns
12496 *
12497 * @example
12498 * // Using `columnDefs`
12499 * $(document).ready( function() {
12500 * $('#example').dataTable( {
12501 * "columnDefs": [
12502 * { "class": "my_class", "targets": [ 0 ] }
12503 * ]
12504 * } );
12505 * } );
12506 *
12507 * @example
12508 * // Using `columns`
12509 * $(document).ready( function() {
12510 * $('#example').dataTable( {
12511 * "columns": [
12512 * { "class": "my_class" },
12513 * null,
12514 * null,
12515 * null,
12516 * null
12517 * ]
12518 * } );
12519 * } );
12520 */
12521 "sClass": "",
12522
12523 /**
12524 * When DataTables calculates the column widths to assign to each column,
12525 * it finds the longest string in each column and then constructs a
12526 * temporary table and reads the widths from that. The problem with this
12527 * is that "mmm" is much wider then "iiii", but the latter is a longer
12528 * string - thus the calculation can go wrong (doing it properly and putting
12529 * it into an DOM object and measuring that is horribly(!) slow). Thus as
12530 * a "work around" we provide this option. It will append its value to the
12531 * text that is found to be the longest string for the column - i.e. padding.
12532 * Generally you shouldn't need this!
12533 * @type string
12534 * @default <i>Empty string<i>
12535 *
12536 * @name DataTable.defaults.column.contentPadding
12537 * @dtopt Columns
12538 *
12539 * @example
12540 * // Using `columns`
12541 * $(document).ready( function() {
12542 * $('#example').dataTable( {
12543 * "columns": [
12544 * null,
12545 * null,
12546 * null,
12547 * {
12548 * "contentPadding": "mmm"
12549 * }
12550 * ]
12551 * } );
12552 * } );
12553 */
12554 "sContentPadding": "",
12555
12556
12557 /**
12558 * Allows a default value to be given for a column's data, and will be used
12559 * whenever a null data source is encountered (this can be because `data`
12560 * is set to null, or because the data source itself is null).
12561 * @type string
12562 * @default null
12563 *
12564 * @name DataTable.defaults.column.defaultContent
12565 * @dtopt Columns
12566 *
12567 * @example
12568 * // Using `columnDefs`
12569 * $(document).ready( function() {
12570 * $('#example').dataTable( {
12571 * "columnDefs": [
12572 * {
12573 * "data": null,
12574 * "defaultContent": "Edit",
12575 * "targets": [ -1 ]
12576 * }
12577 * ]
12578 * } );
12579 * } );
12580 *
12581 * @example
12582 * // Using `columns`
12583 * $(document).ready( function() {
12584 * $('#example').dataTable( {
12585 * "columns": [
12586 * null,
12587 * null,
12588 * null,
12589 * {
12590 * "data": null,
12591 * "defaultContent": "Edit"
12592 * }
12593 * ]
12594 * } );
12595 * } );
12596 */
12597 "sDefaultContent": null,
12598
12599
12600 /**
12601 * This parameter is only used in DataTables' server-side processing. It can
12602 * be exceptionally useful to know what columns are being displayed on the
12603 * client side, and to map these to database fields. When defined, the names
12604 * also allow DataTables to reorder information from the server if it comes
12605 * back in an unexpected order (i.e. if you switch your columns around on the
12606 * client-side, your server-side code does not also need updating).
12607 * @type string
12608 * @default <i>Empty string</i>
12609 *
12610 * @name DataTable.defaults.column.name
12611 * @dtopt Columns
12612 *
12613 * @example
12614 * // Using `columnDefs`
12615 * $(document).ready( function() {
12616 * $('#example').dataTable( {
12617 * "columnDefs": [
12618 * { "name": "engine", "targets": [ 0 ] },
12619 * { "name": "browser", "targets": [ 1 ] },
12620 * { "name": "platform", "targets": [ 2 ] },
12621 * { "name": "version", "targets": [ 3 ] },
12622 * { "name": "grade", "targets": [ 4 ] }
12623 * ]
12624 * } );
12625 * } );
12626 *
12627 * @example
12628 * // Using `columns`
12629 * $(document).ready( function() {
12630 * $('#example').dataTable( {
12631 * "columns": [
12632 * { "name": "engine" },
12633 * { "name": "browser" },
12634 * { "name": "platform" },
12635 * { "name": "version" },
12636 * { "name": "grade" }
12637 * ]
12638 * } );
12639 * } );
12640 */
12641 "sName": "",
12642
12643
12644 /**
12645 * Defines a data source type for the ordering which can be used to read
12646 * real-time information from the table (updating the internally cached
12647 * version) prior to ordering. This allows ordering to occur on user
12648 * editable elements such as form inputs.
12649 * @type string
12650 * @default std
12651 *
12652 * @name DataTable.defaults.column.orderDataType
12653 * @dtopt Columns
12654 *
12655 * @example
12656 * // Using `columnDefs`
12657 * $(document).ready( function() {
12658 * $('#example').dataTable( {
12659 * "columnDefs": [
12660 * { "orderDataType": "dom-text", "targets": [ 2, 3 ] },
12661 * { "type": "numeric", "targets": [ 3 ] },
12662 * { "orderDataType": "dom-select", "targets": [ 4 ] },
12663 * { "orderDataType": "dom-checkbox", "targets": [ 5 ] }
12664 * ]
12665 * } );
12666 * } );
12667 *
12668 * @example
12669 * // Using `columns`
12670 * $(document).ready( function() {
12671 * $('#example').dataTable( {
12672 * "columns": [
12673 * null,
12674 * null,
12675 * { "orderDataType": "dom-text" },
12676 * { "orderDataType": "dom-text", "type": "numeric" },
12677 * { "orderDataType": "dom-select" },
12678 * { "orderDataType": "dom-checkbox" }
12679 * ]
12680 * } );
12681 * } );
12682 */
12683 "sSortDataType": "std",
12684
12685
12686 /**
12687 * The title of this column.
12688 * @type string
12689 * @default null <i>Derived from the 'TH' value for this column in the
12690 * original HTML table.</i>
12691 *
12692 * @name DataTable.defaults.column.title
12693 * @dtopt Columns
12694 *
12695 * @example
12696 * // Using `columnDefs`
12697 * $(document).ready( function() {
12698 * $('#example').dataTable( {
12699 * "columnDefs": [
12700 * { "title": "My column title", "targets": [ 0 ] }
12701 * ]
12702 * } );
12703 * } );
12704 *
12705 * @example
12706 * // Using `columns`
12707 * $(document).ready( function() {
12708 * $('#example').dataTable( {
12709 * "columns": [
12710 * { "title": "My column title" },
12711 * null,
12712 * null,
12713 * null,
12714 * null
12715 * ]
12716 * } );
12717 * } );
12718 */
12719 "sTitle": null,
12720
12721
12722 /**
12723 * The type allows you to specify how the data for this column will be
12724 * ordered. Four types (string, numeric, date and html (which will strip
12725 * HTML tags before ordering)) are currently available. Note that only date
12726 * formats understood by Javascript's Date() object will be accepted as type
12727 * date. For example: "Mar 26, 2008 5:03 PM". May take the values: 'string',
12728 * 'numeric', 'date' or 'html' (by default). Further types can be adding
12729 * through plug-ins.
12730 * @type string
12731 * @default null <i>Auto-detected from raw data</i>
12732 *
12733 * @name DataTable.defaults.column.type
12734 * @dtopt Columns
12735 *
12736 * @example
12737 * // Using `columnDefs`
12738 * $(document).ready( function() {
12739 * $('#example').dataTable( {
12740 * "columnDefs": [
12741 * { "type": "html", "targets": [ 0 ] }
12742 * ]
12743 * } );
12744 * } );
12745 *
12746 * @example
12747 * // Using `columns`
12748 * $(document).ready( function() {
12749 * $('#example').dataTable( {
12750 * "columns": [
12751 * { "type": "html" },
12752 * null,
12753 * null,
12754 * null,
12755 * null
12756 * ]
12757 * } );
12758 * } );
12759 */
12760 "sType": null,
12761
12762
12763 /**
12764 * Defining the width of the column, this parameter may take any CSS value
12765 * (3em, 20px etc). DataTables applies 'smart' widths to columns which have not
12766 * been given a specific width through this interface ensuring that the table
12767 * remains readable.
12768 * @type string
12769 * @default null <i>Automatic</i>
12770 *
12771 * @name DataTable.defaults.column.width
12772 * @dtopt Columns
12773 *
12774 * @example
12775 * // Using `columnDefs`
12776 * $(document).ready( function() {
12777 * $('#example').dataTable( {
12778 * "columnDefs": [
12779 * { "width": "20%", "targets": [ 0 ] }
12780 * ]
12781 * } );
12782 * } );
12783 *
12784 * @example
12785 * // Using `columns`
12786 * $(document).ready( function() {
12787 * $('#example').dataTable( {
12788 * "columns": [
12789 * { "width": "20%" },
12790 * null,
12791 * null,
12792 * null,
12793 * null
12794 * ]
12795 * } );
12796 * } );
12797 */
12798 "sWidth": null
12799 };
12800
12801 _fnHungarianMap( DataTable.defaults.column );
12802
12803
12804
12805 /**
12806 * DataTables settings object - this holds all the information needed for a
12807 * given table, including configuration, data and current application of the
12808 * table options. DataTables does not have a single instance for each DataTable
12809 * with the settings attached to that instance, but rather instances of the
12810 * DataTable "class" are created on-the-fly as needed (typically by a
12811 * $().dataTable() call) and the settings object is then applied to that
12812 * instance.
12813 *
12814 * Note that this object is related to {@link DataTable.defaults} but this
12815 * one is the internal data store for DataTables's cache of columns. It should
12816 * NOT be manipulated outside of DataTables. Any configuration should be done
12817 * through the initialisation options.
12818 * @namespace
12819 * @todo Really should attach the settings object to individual instances so we
12820 * don't need to create new instances on each $().dataTable() call (if the
12821 * table already exists). It would also save passing oSettings around and
12822 * into every single function. However, this is a very significant
12823 * architecture change for DataTables and will almost certainly break
12824 * backwards compatibility with older installations. This is something that
12825 * will be done in 2.0.
12826 */
12827 DataTable.models.oSettings = {
12828 /**
12829 * Primary features of DataTables and their enablement state.
12830 * @namespace
12831 */
12832 "oFeatures": {
12833
12834 /**
12835 * Flag to say if DataTables should automatically try to calculate the
12836 * optimum table and columns widths (true) or not (false).
12837 * Note that this parameter will be set by the initialisation routine. To
12838 * set a default use {@link DataTable.defaults}.
12839 * @type boolean
12840 */
12841 "bAutoWidth": null,
12842
12843 /**
12844 * Delay the creation of TR and TD elements until they are actually
12845 * needed by a driven page draw. This can give a significant speed
12846 * increase for Ajax source and Javascript source data, but makes no
12847 * difference at all fro DOM and server-side processing tables.
12848 * Note that this parameter will be set by the initialisation routine. To
12849 * set a default use {@link DataTable.defaults}.
12850 * @type boolean
12851 */
12852 "bDeferRender": null,
12853
12854 /**
12855 * Enable filtering on the table or not. Note that if this is disabled
12856 * then there is no filtering at all on the table, including fnFilter.
12857 * To just remove the filtering input use sDom and remove the 'f' option.
12858 * Note that this parameter will be set by the initialisation routine. To
12859 * set a default use {@link DataTable.defaults}.
12860 * @type boolean
12861 */
12862 "bFilter": null,
12863
12864 /**
12865 * Table information element (the 'Showing x of y records' div) enable
12866 * flag.
12867 * Note that this parameter will be set by the initialisation routine. To
12868 * set a default use {@link DataTable.defaults}.
12869 * @type boolean
12870 */
12871 "bInfo": null,
12872
12873 /**
12874 * Present a user control allowing the end user to change the page size
12875 * when pagination is enabled.
12876 * Note that this parameter will be set by the initialisation routine. To
12877 * set a default use {@link DataTable.defaults}.
12878 * @type boolean
12879 */
12880 "bLengthChange": null,
12881
12882 /**
12883 * Pagination enabled or not. Note that if this is disabled then length
12884 * changing must also be disabled.
12885 * Note that this parameter will be set by the initialisation routine. To
12886 * set a default use {@link DataTable.defaults}.
12887 * @type boolean
12888 */
12889 "bPaginate": null,
12890
12891 /**
12892 * Processing indicator enable flag whenever DataTables is enacting a
12893 * user request - typically an Ajax request for server-side processing.
12894 * Note that this parameter will be set by the initialisation routine. To
12895 * set a default use {@link DataTable.defaults}.
12896 * @type boolean
12897 */
12898 "bProcessing": null,
12899
12900 /**
12901 * Server-side processing enabled flag - when enabled DataTables will
12902 * get all data from the server for every draw - there is no filtering,
12903 * sorting or paging done on the client-side.
12904 * Note that this parameter will be set by the initialisation routine. To
12905 * set a default use {@link DataTable.defaults}.
12906 * @type boolean
12907 */
12908 "bServerSide": null,
12909
12910 /**
12911 * Sorting enablement flag.
12912 * Note that this parameter will be set by the initialisation routine. To
12913 * set a default use {@link DataTable.defaults}.
12914 * @type boolean
12915 */
12916 "bSort": null,
12917
12918 /**
12919 * Multi-column sorting
12920 * Note that this parameter will be set by the initialisation routine. To
12921 * set a default use {@link DataTable.defaults}.
12922 * @type boolean
12923 */
12924 "bSortMulti": null,
12925
12926 /**
12927 * Apply a class to the columns which are being sorted to provide a
12928 * visual highlight or not. This can slow things down when enabled since
12929 * there is a lot of DOM interaction.
12930 * Note that this parameter will be set by the initialisation routine. To
12931 * set a default use {@link DataTable.defaults}.
12932 * @type boolean
12933 */
12934 "bSortClasses": null,
12935
12936 /**
12937 * State saving enablement flag.
12938 * Note that this parameter will be set by the initialisation routine. To
12939 * set a default use {@link DataTable.defaults}.
12940 * @type boolean
12941 */
12942 "bStateSave": null
12943 },
12944
12945
12946 /**
12947 * Scrolling settings for a table.
12948 * @namespace
12949 */
12950 "oScroll": {
12951 /**
12952 * When the table is shorter in height than sScrollY, collapse the
12953 * table container down to the height of the table (when true).
12954 * Note that this parameter will be set by the initialisation routine. To
12955 * set a default use {@link DataTable.defaults}.
12956 * @type boolean
12957 */
12958 "bCollapse": null,
12959
12960 /**
12961 * Width of the scrollbar for the web-browser's platform. Calculated
12962 * during table initialisation.
12963 * @type int
12964 * @default 0
12965 */
12966 "iBarWidth": 0,
12967
12968 /**
12969 * Viewport width for horizontal scrolling. Horizontal scrolling is
12970 * disabled if an empty string.
12971 * Note that this parameter will be set by the initialisation routine. To
12972 * set a default use {@link DataTable.defaults}.
12973 * @type string
12974 */
12975 "sX": null,
12976
12977 /**
12978 * Width to expand the table to when using x-scrolling. Typically you
12979 * should not need to use this.
12980 * Note that this parameter will be set by the initialisation routine. To
12981 * set a default use {@link DataTable.defaults}.
12982 * @type string
12983 * @deprecated
12984 */
12985 "sXInner": null,
12986
12987 /**
12988 * Viewport height for vertical scrolling. Vertical scrolling is disabled
12989 * if an empty string.
12990 * Note that this parameter will be set by the initialisation routine. To
12991 * set a default use {@link DataTable.defaults}.
12992 * @type string
12993 */
12994 "sY": null
12995 },
12996
12997 /**
12998 * Language information for the table.
12999 * @namespace
13000 * @extends DataTable.defaults.oLanguage
13001 */
13002 "oLanguage": {
13003 /**
13004 * Information callback function. See
13005 * {@link DataTable.defaults.fnInfoCallback}
13006 * @type function
13007 * @default null
13008 */
13009 "fnInfoCallback": null
13010 },
13011
13012 /**
13013 * Browser support parameters
13014 * @namespace
13015 */
13016 "oBrowser": {
13017 /**
13018 * Indicate if the browser incorrectly calculates width:100% inside a
13019 * scrolling element (IE6/7)
13020 * @type boolean
13021 * @default false
13022 */
13023 "bScrollOversize": false,
13024
13025 /**
13026 * Determine if the vertical scrollbar is on the right or left of the
13027 * scrolling container - needed for rtl language layout, although not
13028 * all browsers move the scrollbar (Safari).
13029 * @type boolean
13030 * @default false
13031 */
13032 "bScrollbarLeft": false,
13033
13034 /**
13035 * Flag for if `getBoundingClientRect` is fully supported or not
13036 * @type boolean
13037 * @default false
13038 */
13039 "bBounding": false,
13040
13041 /**
13042 * Browser scrollbar width
13043 * @type integer
13044 * @default 0
13045 */
13046 "barWidth": 0
13047 },
13048
13049
13050 "ajax": null,
13051
13052
13053 /**
13054 * Array referencing the nodes which are used for the features. The
13055 * parameters of this object match what is allowed by sDom - i.e.
13056 * <ul>
13057 * <li>'l' - Length changing</li>
13058 * <li>'f' - Filtering input</li>
13059 * <li>'t' - The table!</li>
13060 * <li>'i' - Information</li>
13061 * <li>'p' - Pagination</li>
13062 * <li>'r' - pRocessing</li>
13063 * </ul>
13064 * @type array
13065 * @default []
13066 */
13067 "aanFeatures": [],
13068
13069 /**
13070 * Store data information - see {@link DataTable.models.oRow} for detailed
13071 * information.
13072 * @type array
13073 * @default []
13074 */
13075 "aoData": [],
13076
13077 /**
13078 * Array of indexes which are in the current display (after filtering etc)
13079 * @type array
13080 * @default []
13081 */
13082 "aiDisplay": [],
13083
13084 /**
13085 * Array of indexes for display - no filtering
13086 * @type array
13087 * @default []
13088 */
13089 "aiDisplayMaster": [],
13090
13091 /**
13092 * Map of row ids to data indexes
13093 * @type object
13094 * @default {}
13095 */
13096 "aIds": {},
13097
13098 /**
13099 * Store information about each column that is in use
13100 * @type array
13101 * @default []
13102 */
13103 "aoColumns": [],
13104
13105 /**
13106 * Store information about the table's header
13107 * @type array
13108 * @default []
13109 */
13110 "aoHeader": [],
13111
13112 /**
13113 * Store information about the table's footer
13114 * @type array
13115 * @default []
13116 */
13117 "aoFooter": [],
13118
13119 /**
13120 * Store the applied global search information in case we want to force a
13121 * research or compare the old search to a new one.
13122 * Note that this parameter will be set by the initialisation routine. To
13123 * set a default use {@link DataTable.defaults}.
13124 * @namespace
13125 * @extends DataTable.models.oSearch
13126 */
13127 "oPreviousSearch": {},
13128
13129 /**
13130 * Store the applied search for each column - see
13131 * {@link DataTable.models.oSearch} for the format that is used for the
13132 * filtering information for each column.
13133 * @type array
13134 * @default []
13135 */
13136 "aoPreSearchCols": [],
13137
13138 /**
13139 * Sorting that is applied to the table. Note that the inner arrays are
13140 * used in the following manner:
13141 * <ul>
13142 * <li>Index 0 - column number</li>
13143 * <li>Index 1 - current sorting direction</li>
13144 * </ul>
13145 * Note that this parameter will be set by the initialisation routine. To
13146 * set a default use {@link DataTable.defaults}.
13147 * @type array
13148 * @todo These inner arrays should really be objects
13149 */
13150 "aaSorting": null,
13151
13152 /**
13153 * Sorting that is always applied to the table (i.e. prefixed in front of
13154 * aaSorting).
13155 * Note that this parameter will be set by the initialisation routine. To
13156 * set a default use {@link DataTable.defaults}.
13157 * @type array
13158 * @default []
13159 */
13160 "aaSortingFixed": [],
13161
13162 /**
13163 * Classes to use for the striping of a table.
13164 * Note that this parameter will be set by the initialisation routine. To
13165 * set a default use {@link DataTable.defaults}.
13166 * @type array
13167 * @default []
13168 */
13169 "asStripeClasses": null,
13170
13171 /**
13172 * If restoring a table - we should restore its striping classes as well
13173 * @type array
13174 * @default []
13175 */
13176 "asDestroyStripes": [],
13177
13178 /**
13179 * If restoring a table - we should restore its width
13180 * @type int
13181 * @default 0
13182 */
13183 "sDestroyWidth": 0,
13184
13185 /**
13186 * Callback functions array for every time a row is inserted (i.e. on a draw).
13187 * @type array
13188 * @default []
13189 */
13190 "aoRowCallback": [],
13191
13192 /**
13193 * Callback functions for the header on each draw.
13194 * @type array
13195 * @default []
13196 */
13197 "aoHeaderCallback": [],
13198
13199 /**
13200 * Callback function for the footer on each draw.
13201 * @type array
13202 * @default []
13203 */
13204 "aoFooterCallback": [],
13205
13206 /**
13207 * Array of callback functions for draw callback functions
13208 * @type array
13209 * @default []
13210 */
13211 "aoDrawCallback": [],
13212
13213 /**
13214 * Array of callback functions for row created function
13215 * @type array
13216 * @default []
13217 */
13218 "aoRowCreatedCallback": [],
13219
13220 /**
13221 * Callback functions for just before the table is redrawn. A return of
13222 * false will be used to cancel the draw.
13223 * @type array
13224 * @default []
13225 */
13226 "aoPreDrawCallback": [],
13227
13228 /**
13229 * Callback functions for when the table has been initialised.
13230 * @type array
13231 * @default []
13232 */
13233 "aoInitComplete": [],
13234
13235
13236 /**
13237 * Callbacks for modifying the settings to be stored for state saving, prior to
13238 * saving state.
13239 * @type array
13240 * @default []
13241 */
13242 "aoStateSaveParams": [],
13243
13244 /**
13245 * Callbacks for modifying the settings that have been stored for state saving
13246 * prior to using the stored values to restore the state.
13247 * @type array
13248 * @default []
13249 */
13250 "aoStateLoadParams": [],
13251
13252 /**
13253 * Callbacks for operating on the settings object once the saved state has been
13254 * loaded
13255 * @type array
13256 * @default []
13257 */
13258 "aoStateLoaded": [],
13259
13260 /**
13261 * Cache the table ID for quick access
13262 * @type string
13263 * @default <i>Empty string</i>
13264 */
13265 "sTableId": "",
13266
13267 /**
13268 * The TABLE node for the main table
13269 * @type node
13270 * @default null
13271 */
13272 "nTable": null,
13273
13274 /**
13275 * Permanent ref to the thead element
13276 * @type node
13277 * @default null
13278 */
13279 "nTHead": null,
13280
13281 /**
13282 * Permanent ref to the tfoot element - if it exists
13283 * @type node
13284 * @default null
13285 */
13286 "nTFoot": null,
13287
13288 /**
13289 * Permanent ref to the tbody element
13290 * @type node
13291 * @default null
13292 */
13293 "nTBody": null,
13294
13295 /**
13296 * Cache the wrapper node (contains all DataTables controlled elements)
13297 * @type node
13298 * @default null
13299 */
13300 "nTableWrapper": null,
13301
13302 /**
13303 * Indicate if when using server-side processing the loading of data
13304 * should be deferred until the second draw.
13305 * Note that this parameter will be set by the initialisation routine. To
13306 * set a default use {@link DataTable.defaults}.
13307 * @type boolean
13308 * @default false
13309 */
13310 "bDeferLoading": false,
13311
13312 /**
13313 * Indicate if all required information has been read in
13314 * @type boolean
13315 * @default false
13316 */
13317 "bInitialised": false,
13318
13319 /**
13320 * Information about open rows. Each object in the array has the parameters
13321 * 'nTr' and 'nParent'
13322 * @type array
13323 * @default []
13324 */
13325 "aoOpenRows": [],
13326
13327 /**
13328 * Dictate the positioning of DataTables' control elements - see
13329 * {@link DataTable.model.oInit.sDom}.
13330 * Note that this parameter will be set by the initialisation routine. To
13331 * set a default use {@link DataTable.defaults}.
13332 * @type string
13333 * @default null
13334 */
13335 "sDom": null,
13336
13337 /**
13338 * Search delay (in mS)
13339 * @type integer
13340 * @default null
13341 */
13342 "searchDelay": null,
13343
13344 /**
13345 * Which type of pagination should be used.
13346 * Note that this parameter will be set by the initialisation routine. To
13347 * set a default use {@link DataTable.defaults}.
13348 * @type string
13349 * @default two_button
13350 */
13351 "sPaginationType": "two_button",
13352
13353 /**
13354 * The state duration (for `stateSave`) in seconds.
13355 * Note that this parameter will be set by the initialisation routine. To
13356 * set a default use {@link DataTable.defaults}.
13357 * @type int
13358 * @default 0
13359 */
13360 "iStateDuration": 0,
13361
13362 /**
13363 * Array of callback functions for state saving. Each array element is an
13364 * object with the following parameters:
13365 * <ul>
13366 * <li>function:fn - function to call. Takes two parameters, oSettings
13367 * and the JSON string to save that has been thus far created. Returns
13368 * a JSON string to be inserted into a json object
13369 * (i.e. '"param": [ 0, 1, 2]')</li>
13370 * <li>string:sName - name of callback</li>
13371 * </ul>
13372 * @type array
13373 * @default []
13374 */
13375 "aoStateSave": [],
13376
13377 /**
13378 * Array of callback functions for state loading. Each array element is an
13379 * object with the following parameters:
13380 * <ul>
13381 * <li>function:fn - function to call. Takes two parameters, oSettings
13382 * and the object stored. May return false to cancel state loading</li>
13383 * <li>string:sName - name of callback</li>
13384 * </ul>
13385 * @type array
13386 * @default []
13387 */
13388 "aoStateLoad": [],
13389
13390 /**
13391 * State that was saved. Useful for back reference
13392 * @type object
13393 * @default null
13394 */
13395 "oSavedState": null,
13396
13397 /**
13398 * State that was loaded. Useful for back reference
13399 * @type object
13400 * @default null
13401 */
13402 "oLoadedState": null,
13403
13404 /**
13405 * Source url for AJAX data for the table.
13406 * Note that this parameter will be set by the initialisation routine. To
13407 * set a default use {@link DataTable.defaults}.
13408 * @type string
13409 * @default null
13410 */
13411 "sAjaxSource": null,
13412
13413 /**
13414 * Property from a given object from which to read the table data from. This
13415 * can be an empty string (when not server-side processing), in which case
13416 * it is assumed an an array is given directly.
13417 * Note that this parameter will be set by the initialisation routine. To
13418 * set a default use {@link DataTable.defaults}.
13419 * @type string
13420 */
13421 "sAjaxDataProp": null,
13422
13423 /**
13424 * Note if draw should be blocked while getting data
13425 * @type boolean
13426 * @default true
13427 */
13428 "bAjaxDataGet": true,
13429
13430 /**
13431 * The last jQuery XHR object that was used for server-side data gathering.
13432 * This can be used for working with the XHR information in one of the
13433 * callbacks
13434 * @type object
13435 * @default null
13436 */
13437 "jqXHR": null,
13438
13439 /**
13440 * JSON returned from the server in the last Ajax request
13441 * @type object
13442 * @default undefined
13443 */
13444 "json": undefined,
13445
13446 /**
13447 * Data submitted as part of the last Ajax request
13448 * @type object
13449 * @default undefined
13450 */
13451 "oAjaxData": undefined,
13452
13453 /**
13454 * Function to get the server-side data.
13455 * Note that this parameter will be set by the initialisation routine. To
13456 * set a default use {@link DataTable.defaults}.
13457 * @type function
13458 */
13459 "fnServerData": null,
13460
13461 /**
13462 * Functions which are called prior to sending an Ajax request so extra
13463 * parameters can easily be sent to the server
13464 * @type array
13465 * @default []
13466 */
13467 "aoServerParams": [],
13468
13469 /**
13470 * Send the XHR HTTP method - GET or POST (could be PUT or DELETE if
13471 * required).
13472 * Note that this parameter will be set by the initialisation routine. To
13473 * set a default use {@link DataTable.defaults}.
13474 * @type string
13475 */
13476 "sServerMethod": null,
13477
13478 /**
13479 * Format numbers for display.
13480 * Note that this parameter will be set by the initialisation routine. To
13481 * set a default use {@link DataTable.defaults}.
13482 * @type function
13483 */
13484 "fnFormatNumber": null,
13485
13486 /**
13487 * List of options that can be used for the user selectable length menu.
13488 * Note that this parameter will be set by the initialisation routine. To
13489 * set a default use {@link DataTable.defaults}.
13490 * @type array
13491 * @default []
13492 */
13493 "aLengthMenu": null,
13494
13495 /**
13496 * Counter for the draws that the table does. Also used as a tracker for
13497 * server-side processing
13498 * @type int
13499 * @default 0
13500 */
13501 "iDraw": 0,
13502
13503 /**
13504 * Indicate if a redraw is being done - useful for Ajax
13505 * @type boolean
13506 * @default false
13507 */
13508 "bDrawing": false,
13509
13510 /**
13511 * Draw index (iDraw) of the last error when parsing the returned data
13512 * @type int
13513 * @default -1
13514 */
13515 "iDrawError": -1,
13516
13517 /**
13518 * Paging display length
13519 * @type int
13520 * @default 10
13521 */
13522 "_iDisplayLength": 10,
13523
13524 /**
13525 * Paging start point - aiDisplay index
13526 * @type int
13527 * @default 0
13528 */
13529 "_iDisplayStart": 0,
13530
13531 /**
13532 * Server-side processing - number of records in the result set
13533 * (i.e. before filtering), Use fnRecordsTotal rather than
13534 * this property to get the value of the number of records, regardless of
13535 * the server-side processing setting.
13536 * @type int
13537 * @default 0
13538 * @private
13539 */
13540 "_iRecordsTotal": 0,
13541
13542 /**
13543 * Server-side processing - number of records in the current display set
13544 * (i.e. after filtering). Use fnRecordsDisplay rather than
13545 * this property to get the value of the number of records, regardless of
13546 * the server-side processing setting.
13547 * @type boolean
13548 * @default 0
13549 * @private
13550 */
13551 "_iRecordsDisplay": 0,
13552
13553 /**
13554 * Flag to indicate if jQuery UI marking and classes should be used.
13555 * Note that this parameter will be set by the initialisation routine. To
13556 * set a default use {@link DataTable.defaults}.
13557 * @type boolean
13558 */
13559 "bJUI": null,
13560
13561 /**
13562 * The classes to use for the table
13563 * @type object
13564 * @default {}
13565 */
13566 "oClasses": {},
13567
13568 /**
13569 * Flag attached to the settings object so you can check in the draw
13570 * callback if filtering has been done in the draw. Deprecated in favour of
13571 * events.
13572 * @type boolean
13573 * @default false
13574 * @deprecated
13575 */
13576 "bFiltered": false,
13577
13578 /**
13579 * Flag attached to the settings object so you can check in the draw
13580 * callback if sorting has been done in the draw. Deprecated in favour of
13581 * events.
13582 * @type boolean
13583 * @default false
13584 * @deprecated
13585 */
13586 "bSorted": false,
13587
13588 /**
13589 * Indicate that if multiple rows are in the header and there is more than
13590 * one unique cell per column, if the top one (true) or bottom one (false)
13591 * should be used for sorting / title by DataTables.
13592 * Note that this parameter will be set by the initialisation routine. To
13593 * set a default use {@link DataTable.defaults}.
13594 * @type boolean
13595 */
13596 "bSortCellsTop": null,
13597
13598 /**
13599 * Initialisation object that is used for the table
13600 * @type object
13601 * @default null
13602 */
13603 "oInit": null,
13604
13605 /**
13606 * Destroy callback functions - for plug-ins to attach themselves to the
13607 * destroy so they can clean up markup and events.
13608 * @type array
13609 * @default []
13610 */
13611 "aoDestroyCallback": [],
13612
13613
13614 /**
13615 * Get the number of records in the current record set, before filtering
13616 * @type function
13617 */
13618 "fnRecordsTotal": function ()
13619 {
13620 return _fnDataSource( this ) == 'ssp' ?
13621 this._iRecordsTotal * 1 :
13622 this.aiDisplayMaster.length;
13623 },
13624
13625 /**
13626 * Get the number of records in the current record set, after filtering
13627 * @type function
13628 */
13629 "fnRecordsDisplay": function ()
13630 {
13631 return _fnDataSource( this ) == 'ssp' ?
13632 this._iRecordsDisplay * 1 :
13633 this.aiDisplay.length;
13634 },
13635
13636 /**
13637 * Get the display end point - aiDisplay index
13638 * @type function
13639 */
13640 "fnDisplayEnd": function ()
13641 {
13642 var
13643 len = this._iDisplayLength,
13644 start = this._iDisplayStart,
13645 calc = start + len,
13646 records = this.aiDisplay.length,
13647 features = this.oFeatures,
13648 paginate = features.bPaginate;
13649
13650 if ( features.bServerSide ) {
13651 return paginate === false || len === -1 ?
13652 start + records :
13653 Math.min( start+len, this._iRecordsDisplay );
13654 }
13655 else {
13656 return ! paginate || calc>records || len===-1 ?
13657 records :
13658 calc;
13659 }
13660 },
13661
13662 /**
13663 * The DataTables object for this table
13664 * @type object
13665 * @default null
13666 */
13667 "oInstance": null,
13668
13669 /**
13670 * Unique identifier for each instance of the DataTables object. If there
13671 * is an ID on the table node, then it takes that value, otherwise an
13672 * incrementing internal counter is used.
13673 * @type string
13674 * @default null
13675 */
13676 "sInstance": null,
13677
13678 /**
13679 * tabindex attribute value that is added to DataTables control elements, allowing
13680 * keyboard navigation of the table and its controls.
13681 */
13682 "iTabIndex": 0,
13683
13684 /**
13685 * DIV container for the footer scrolling table if scrolling
13686 */
13687 "nScrollHead": null,
13688
13689 /**
13690 * DIV container for the footer scrolling table if scrolling
13691 */
13692 "nScrollFoot": null,
13693
13694 /**
13695 * Last applied sort
13696 * @type array
13697 * @default []
13698 */
13699 "aLastSort": [],
13700
13701 /**
13702 * Stored plug-in instances
13703 * @type object
13704 * @default {}
13705 */
13706 "oPlugins": {},
13707
13708 /**
13709 * Function used to get a row's id from the row's data
13710 * @type function
13711 * @default null
13712 */
13713 "rowIdFn": null,
13714
13715 /**
13716 * Data location where to store a row's id
13717 * @type string
13718 * @default null
13719 */
13720 "rowId": null
13721 };
13722
13723 /**
13724 * Extension object for DataTables that is used to provide all extension
13725 * options.
13726 *
13727 * Note that the `DataTable.ext` object is available through
13728 * `jQuery.fn.dataTable.ext` where it may be accessed and manipulated. It is
13729 * also aliased to `jQuery.fn.dataTableExt` for historic reasons.
13730 * @namespace
13731 * @extends DataTable.models.ext
13732 */
13733
13734
13735 /**
13736 * DataTables extensions
13737 *
13738 * This namespace acts as a collection area for plug-ins that can be used to
13739 * extend DataTables capabilities. Indeed many of the build in methods
13740 * use this method to provide their own capabilities (sorting methods for
13741 * example).
13742 *
13743 * Note that this namespace is aliased to `jQuery.fn.dataTableExt` for legacy
13744 * reasons
13745 *
13746 * @namespace
13747 */
13748 DataTable.ext = _ext = {
13749 /**
13750 * Buttons. For use with the Buttons extension for DataTables. This is
13751 * defined here so other extensions can define buttons regardless of load
13752 * order. It is _not_ used by DataTables core.
13753 *
13754 * @type object
13755 * @default {}
13756 */
13757 buttons: {},
13758
13759
13760 /**
13761 * Element class names
13762 *
13763 * @type object
13764 * @default {}
13765 */
13766 classes: {},
13767
13768
13769 /**
13770 * DataTables build type (expanded by the download builder)
13771 *
13772 * @type string
13773 */
13774 build:"dt/dt-1.10.10,r-2.0.0",
13775
13776
13777 /**
13778 * Error reporting.
13779 *
13780 * How should DataTables report an error. Can take the value 'alert',
13781 * 'throw', 'none' or a function.
13782 *
13783 * @type string|function
13784 * @default alert
13785 */
13786 errMode: "alert",
13787
13788
13789 /**
13790 * Feature plug-ins.
13791 *
13792 * This is an array of objects which describe the feature plug-ins that are
13793 * available to DataTables. These feature plug-ins are then available for
13794 * use through the `dom` initialisation option.
13795 *
13796 * Each feature plug-in is described by an object which must have the
13797 * following properties:
13798 *
13799 * * `fnInit` - function that is used to initialise the plug-in,
13800 * * `cFeature` - a character so the feature can be enabled by the `dom`
13801 * instillation option. This is case sensitive.
13802 *
13803 * The `fnInit` function has the following input parameters:
13804 *
13805 * 1. `{object}` DataTables settings object: see
13806 * {@link DataTable.models.oSettings}
13807 *
13808 * And the following return is expected:
13809 *
13810 * * {node|null} The element which contains your feature. Note that the
13811 * return may also be void if your plug-in does not require to inject any
13812 * DOM elements into DataTables control (`dom`) - for example this might
13813 * be useful when developing a plug-in which allows table control via
13814 * keyboard entry
13815 *
13816 * @type array
13817 *
13818 * @example
13819 * $.fn.dataTable.ext.features.push( {
13820 * "fnInit": function( oSettings ) {
13821 * return new TableTools( { "oDTSettings": oSettings } );
13822 * },
13823 * "cFeature": "T"
13824 * } );
13825 */
13826 feature: [],
13827
13828
13829 /**
13830 * Row searching.
13831 *
13832 * This method of searching is complimentary to the default type based
13833 * searching, and a lot more comprehensive as it allows you complete control
13834 * over the searching logic. Each element in this array is a function
13835 * (parameters described below) that is called for every row in the table,
13836 * and your logic decides if it should be included in the searching data set
13837 * or not.
13838 *
13839 * Searching functions have the following input parameters:
13840 *
13841 * 1. `{object}` DataTables settings object: see
13842 * {@link DataTable.models.oSettings}
13843 * 2. `{array|object}` Data for the row to be processed (same as the
13844 * original format that was passed in as the data source, or an array
13845 * from a DOM data source
13846 * 3. `{int}` Row index ({@link DataTable.models.oSettings.aoData}), which
13847 * can be useful to retrieve the `TR` element if you need DOM interaction.
13848 *
13849 * And the following return is expected:
13850 *
13851 * * {boolean} Include the row in the searched result set (true) or not
13852 * (false)
13853 *
13854 * Note that as with the main search ability in DataTables, technically this
13855 * is "filtering", since it is subtractive. However, for consistency in
13856 * naming we call it searching here.
13857 *
13858 * @type array
13859 * @default []
13860 *
13861 * @example
13862 * // The following example shows custom search being applied to the
13863 * // fourth column (i.e. the data[3] index) based on two input values
13864 * // from the end-user, matching the data in a certain range.
13865 * $.fn.dataTable.ext.search.push(
13866 * function( settings, data, dataIndex ) {
13867 * var min = document.getElementById('min').value * 1;
13868 * var max = document.getElementById('max').value * 1;
13869 * var version = data[3] == "-" ? 0 : data[3]*1;
13870 *
13871 * if ( min == "" && max == "" ) {
13872 * return true;
13873 * }
13874 * else if ( min == "" && version < max ) {
13875 * return true;
13876 * }
13877 * else if ( min < version && "" == max ) {
13878 * return true;
13879 * }
13880 * else if ( min < version && version < max ) {
13881 * return true;
13882 * }
13883 * return false;
13884 * }
13885 * );
13886 */
13887 search: [],
13888
13889
13890 /**
13891 * Selector extensions
13892 *
13893 * The `selector` option can be used to extend the options available for the
13894 * selector modifier options (`selector-modifier` object data type) that
13895 * each of the three built in selector types offer (row, column and cell +
13896 * their plural counterparts). For example the Select extension uses this
13897 * mechanism to provide an option to select only rows, columns and cells
13898 * that have been marked as selected by the end user (`{selected: true}`),
13899 * which can be used in conjunction with the existing built in selector
13900 * options.
13901 *
13902 * Each property is an array to which functions can be pushed. The functions
13903 * take three attributes:
13904 *
13905 * * Settings object for the host table
13906 * * Options object (`selector-modifier` object type)
13907 * * Array of selected item indexes
13908 *
13909 * The return is an array of the resulting item indexes after the custom
13910 * selector has been applied.
13911 *
13912 * @type object
13913 */
13914 selector: {
13915 cell: [],
13916 column: [],
13917 row: []
13918 },
13919
13920
13921 /**
13922 * Internal functions, exposed for used in plug-ins.
13923 *
13924 * Please note that you should not need to use the internal methods for
13925 * anything other than a plug-in (and even then, try to avoid if possible).
13926 * The internal function may change between releases.
13927 *
13928 * @type object
13929 * @default {}
13930 */
13931 internal: {},
13932
13933
13934 /**
13935 * Legacy configuration options. Enable and disable legacy options that
13936 * are available in DataTables.
13937 *
13938 * @type object
13939 */
13940 legacy: {
13941 /**
13942 * Enable / disable DataTables 1.9 compatible server-side processing
13943 * requests
13944 *
13945 * @type boolean
13946 * @default null
13947 */
13948 ajax: null
13949 },
13950
13951
13952 /**
13953 * Pagination plug-in methods.
13954 *
13955 * Each entry in this object is a function and defines which buttons should
13956 * be shown by the pagination rendering method that is used for the table:
13957 * {@link DataTable.ext.renderer.pageButton}. The renderer addresses how the
13958 * buttons are displayed in the document, while the functions here tell it
13959 * what buttons to display. This is done by returning an array of button
13960 * descriptions (what each button will do).
13961 *
13962 * Pagination types (the four built in options and any additional plug-in
13963 * options defined here) can be used through the `paginationType`
13964 * initialisation parameter.
13965 *
13966 * The functions defined take two parameters:
13967 *
13968 * 1. `{int} page` The current page index
13969 * 2. `{int} pages` The number of pages in the table
13970 *
13971 * Each function is expected to return an array where each element of the
13972 * array can be one of:
13973 *
13974 * * `first` - Jump to first page when activated
13975 * * `last` - Jump to last page when activated
13976 * * `previous` - Show previous page when activated
13977 * * `next` - Show next page when activated
13978 * * `{int}` - Show page of the index given
13979 * * `{array}` - A nested array containing the above elements to add a
13980 * containing 'DIV' element (might be useful for styling).
13981 *
13982 * Note that DataTables v1.9- used this object slightly differently whereby
13983 * an object with two functions would be defined for each plug-in. That
13984 * ability is still supported by DataTables 1.10+ to provide backwards
13985 * compatibility, but this option of use is now decremented and no longer
13986 * documented in DataTables 1.10+.
13987 *
13988 * @type object
13989 * @default {}
13990 *
13991 * @example
13992 * // Show previous, next and current page buttons only
13993 * $.fn.dataTableExt.oPagination.current = function ( page, pages ) {
13994 * return [ 'previous', page, 'next' ];
13995 * };
13996 */
13997 pager: {},
13998
13999
14000 renderer: {
14001 pageButton: {},
14002 header: {}
14003 },
14004
14005
14006 /**
14007 * Ordering plug-ins - custom data source
14008 *
14009 * The extension options for ordering of data available here is complimentary
14010 * to the default type based ordering that DataTables typically uses. It
14011 * allows much greater control over the the data that is being used to
14012 * order a column, but is necessarily therefore more complex.
14013 *
14014 * This type of ordering is useful if you want to do ordering based on data
14015 * live from the DOM (for example the contents of an 'input' element) rather
14016 * than just the static string that DataTables knows of.
14017 *
14018 * The way these plug-ins work is that you create an array of the values you
14019 * wish to be ordering for the column in question and then return that
14020 * array. The data in the array much be in the index order of the rows in
14021 * the table (not the currently ordering order!). Which order data gathering
14022 * function is run here depends on the `dt-init columns.orderDataType`
14023 * parameter that is used for the column (if any).
14024 *
14025 * The functions defined take two parameters:
14026 *
14027 * 1. `{object}` DataTables settings object: see
14028 * {@link DataTable.models.oSettings}
14029 * 2. `{int}` Target column index
14030 *
14031 * Each function is expected to return an array:
14032 *
14033 * * `{array}` Data for the column to be ordering upon
14034 *
14035 * @type array
14036 *
14037 * @example
14038 * // Ordering using `input` node values
14039 * $.fn.dataTable.ext.order['dom-text'] = function ( settings, col )
14040 * {
14041 * return this.api().column( col, {order:'index'} ).nodes().map( function ( td, i ) {
14042 * return $('input', td).val();
14043 * } );
14044 * }
14045 */
14046 order: {},
14047
14048
14049 /**
14050 * Type based plug-ins.
14051 *
14052 * Each column in DataTables has a type assigned to it, either by automatic
14053 * detection or by direct assignment using the `type` option for the column.
14054 * The type of a column will effect how it is ordering and search (plug-ins
14055 * can also make use of the column type if required).
14056 *
14057 * @namespace
14058 */
14059 type: {
14060 /**
14061 * Type detection functions.
14062 *
14063 * The functions defined in this object are used to automatically detect
14064 * a column's type, making initialisation of DataTables super easy, even
14065 * when complex data is in the table.
14066 *
14067 * The functions defined take two parameters:
14068 *
14069 * 1. `{*}` Data from the column cell to be analysed
14070 * 2. `{settings}` DataTables settings object. This can be used to
14071 * perform context specific type detection - for example detection
14072 * based on language settings such as using a comma for a decimal
14073 * place. Generally speaking the options from the settings will not
14074 * be required
14075 *
14076 * Each function is expected to return:
14077 *
14078 * * `{string|null}` Data type detected, or null if unknown (and thus
14079 * pass it on to the other type detection functions.
14080 *
14081 * @type array
14082 *
14083 * @example
14084 * // Currency type detection plug-in:
14085 * $.fn.dataTable.ext.type.detect.push(
14086 * function ( data, settings ) {
14087 * // Check the numeric part
14088 * if ( ! $.isNumeric( data.substring(1) ) ) {
14089 * return null;
14090 * }
14091 *
14092 * // Check prefixed by currency
14093 * if ( data.charAt(0) == '$' || data.charAt(0) == '&pound;' ) {
14094 * return 'currency';
14095 * }
14096 * return null;
14097 * }
14098 * );
14099 */
14100 detect: [],
14101
14102
14103 /**
14104 * Type based search formatting.
14105 *
14106 * The type based searching functions can be used to pre-format the
14107 * data to be search on. For example, it can be used to strip HTML
14108 * tags or to de-format telephone numbers for numeric only searching.
14109 *
14110 * Note that is a search is not defined for a column of a given type,
14111 * no search formatting will be performed.
14112 *
14113 * Pre-processing of searching data plug-ins - When you assign the sType
14114 * for a column (or have it automatically detected for you by DataTables
14115 * or a type detection plug-in), you will typically be using this for
14116 * custom sorting, but it can also be used to provide custom searching
14117 * by allowing you to pre-processing the data and returning the data in
14118 * the format that should be searched upon. This is done by adding
14119 * functions this object with a parameter name which matches the sType
14120 * for that target column. This is the corollary of <i>afnSortData</i>
14121 * for searching data.
14122 *
14123 * The functions defined take a single parameter:
14124 *
14125 * 1. `{*}` Data from the column cell to be prepared for searching
14126 *
14127 * Each function is expected to return:
14128 *
14129 * * `{string|null}` Formatted string that will be used for the searching.
14130 *
14131 * @type object
14132 * @default {}
14133 *
14134 * @example
14135 * $.fn.dataTable.ext.type.search['title-numeric'] = function ( d ) {
14136 * return d.replace(/\n/g," ").replace( /<.*?>/g, "" );
14137 * }
14138 */
14139 search: {},
14140
14141
14142 /**
14143 * Type based ordering.
14144 *
14145 * The column type tells DataTables what ordering to apply to the table
14146 * when a column is sorted upon. The order for each type that is defined,
14147 * is defined by the functions available in this object.
14148 *
14149 * Each ordering option can be described by three properties added to
14150 * this object:
14151 *
14152 * * `{type}-pre` - Pre-formatting function
14153 * * `{type}-asc` - Ascending order function
14154 * * `{type}-desc` - Descending order function
14155 *
14156 * All three can be used together, only `{type}-pre` or only
14157 * `{type}-asc` and `{type}-desc` together. It is generally recommended
14158 * that only `{type}-pre` is used, as this provides the optimal
14159 * implementation in terms of speed, although the others are provided
14160 * for compatibility with existing Javascript sort functions.
14161 *
14162 * `{type}-pre`: Functions defined take a single parameter:
14163 *
14164 * 1. `{*}` Data from the column cell to be prepared for ordering
14165 *
14166 * And return:
14167 *
14168 * * `{*}` Data to be sorted upon
14169 *
14170 * `{type}-asc` and `{type}-desc`: Functions are typical Javascript sort
14171 * functions, taking two parameters:
14172 *
14173 * 1. `{*}` Data to compare to the second parameter
14174 * 2. `{*}` Data to compare to the first parameter
14175 *
14176 * And returning:
14177 *
14178 * * `{*}` Ordering match: <0 if first parameter should be sorted lower
14179 * than the second parameter, ===0 if the two parameters are equal and
14180 * >0 if the first parameter should be sorted height than the second
14181 * parameter.
14182 *
14183 * @type object
14184 * @default {}
14185 *
14186 * @example
14187 * // Numeric ordering of formatted numbers with a pre-formatter
14188 * $.extend( $.fn.dataTable.ext.type.order, {
14189 * "string-pre": function(x) {
14190 * a = (a === "-" || a === "") ? 0 : a.replace( /[^\d\-\.]/g, "" );
14191 * return parseFloat( a );
14192 * }
14193 * } );
14194 *
14195 * @example
14196 * // Case-sensitive string ordering, with no pre-formatting method
14197 * $.extend( $.fn.dataTable.ext.order, {
14198 * "string-case-asc": function(x,y) {
14199 * return ((x < y) ? -1 : ((x > y) ? 1 : 0));
14200 * },
14201 * "string-case-desc": function(x,y) {
14202 * return ((x < y) ? 1 : ((x > y) ? -1 : 0));
14203 * }
14204 * } );
14205 */
14206 order: {}
14207 },
14208
14209 /**
14210 * Unique DataTables instance counter
14211 *
14212 * @type int
14213 * @private
14214 */
14215 _unique: 0,
14216
14217
14218 //
14219 // Depreciated
14220 // The following properties are retained for backwards compatiblity only.
14221 // The should not be used in new projects and will be removed in a future
14222 // version
14223 //
14224
14225 /**
14226 * Version check function.
14227 * @type function
14228 * @depreciated Since 1.10
14229 */
14230 fnVersionCheck: DataTable.fnVersionCheck,
14231
14232
14233 /**
14234 * Index for what 'this' index API functions should use
14235 * @type int
14236 * @deprecated Since v1.10
14237 */
14238 iApiIndex: 0,
14239
14240
14241 /**
14242 * jQuery UI class container
14243 * @type object
14244 * @deprecated Since v1.10
14245 */
14246 oJUIClasses: {},
14247
14248
14249 /**
14250 * Software version
14251 * @type string
14252 * @deprecated Since v1.10
14253 */
14254 sVersion: DataTable.version
14255 };
14256
14257
14258 //
14259 // Backwards compatibility. Alias to pre 1.10 Hungarian notation counter parts
14260 //
14261 $.extend( _ext, {
14262 afnFiltering: _ext.search,
14263 aTypes: _ext.type.detect,
14264 ofnSearch: _ext.type.search,
14265 oSort: _ext.type.order,
14266 afnSortData: _ext.order,
14267 aoFeatures: _ext.feature,
14268 oApi: _ext.internal,
14269 oStdClasses: _ext.classes,
14270 oPagination: _ext.pager
14271 } );
14272
14273
14274 $.extend( DataTable.ext.classes, {
14275 "sTable": "dataTable",
14276 "sNoFooter": "no-footer",
14277
14278 /* Paging buttons */
14279 "sPageButton": "paginate_button",
14280 "sPageButtonActive": "current",
14281 "sPageButtonDisabled": "disabled",
14282
14283 /* Striping classes */
14284 "sStripeOdd": "odd",
14285 "sStripeEven": "even",
14286
14287 /* Empty row */
14288 "sRowEmpty": "dataTables_empty",
14289
14290 /* Features */
14291 "sWrapper": "dataTables_wrapper",
14292 "sFilter": "dataTables_filter",
14293 "sInfo": "dataTables_info",
14294 "sPaging": "dataTables_paginate paging_", /* Note that the type is postfixed */
14295 "sLength": "dataTables_length",
14296 "sProcessing": "dataTables_processing",
14297
14298 /* Sorting */
14299 "sSortAsc": "sorting_asc",
14300 "sSortDesc": "sorting_desc",
14301 "sSortable": "sorting", /* Sortable in both directions */
14302 "sSortableAsc": "sorting_asc_disabled",
14303 "sSortableDesc": "sorting_desc_disabled",
14304 "sSortableNone": "sorting_disabled",
14305 "sSortColumn": "sorting_", /* Note that an int is postfixed for the sorting order */
14306
14307 /* Filtering */
14308 "sFilterInput": "",
14309
14310 /* Page length */
14311 "sLengthSelect": "",
14312
14313 /* Scrolling */
14314 "sScrollWrapper": "dataTables_scroll",
14315 "sScrollHead": "dataTables_scrollHead",
14316 "sScrollHeadInner": "dataTables_scrollHeadInner",
14317 "sScrollBody": "dataTables_scrollBody",
14318 "sScrollFoot": "dataTables_scrollFoot",
14319 "sScrollFootInner": "dataTables_scrollFootInner",
14320
14321 /* Misc */
14322 "sHeaderTH": "",
14323 "sFooterTH": "",
14324
14325 // Deprecated
14326 "sSortJUIAsc": "",
14327 "sSortJUIDesc": "",
14328 "sSortJUI": "",
14329 "sSortJUIAscAllowed": "",
14330 "sSortJUIDescAllowed": "",
14331 "sSortJUIWrapper": "",
14332 "sSortIcon": "",
14333 "sJUIHeader": "",
14334 "sJUIFooter": ""
14335 } );
14336
14337
14338 (function() {
14339
14340 // Reused strings for better compression. Closure compiler appears to have a
14341 // weird edge case where it is trying to expand strings rather than use the
14342 // variable version. This results in about 200 bytes being added, for very
14343 // little preference benefit since it this run on script load only.
14344 var _empty = '';
14345 _empty = '';
14346
14347 var _stateDefault = _empty + 'ui-state-default';
14348 var _sortIcon = _empty + 'css_right ui-icon ui-icon-';
14349 var _headerFooter = _empty + 'fg-toolbar ui-toolbar ui-widget-header ui-helper-clearfix';
14350
14351 $.extend( DataTable.ext.oJUIClasses, DataTable.ext.classes, {
14352 /* Full numbers paging buttons */
14353 "sPageButton": "fg-button ui-button "+_stateDefault,
14354 "sPageButtonActive": "ui-state-disabled",
14355 "sPageButtonDisabled": "ui-state-disabled",
14356
14357 /* Features */
14358 "sPaging": "dataTables_paginate fg-buttonset ui-buttonset fg-buttonset-multi "+
14359 "ui-buttonset-multi paging_", /* Note that the type is postfixed */
14360
14361 /* Sorting */
14362 "sSortAsc": _stateDefault+" sorting_asc",
14363 "sSortDesc": _stateDefault+" sorting_desc",
14364 "sSortable": _stateDefault+" sorting",
14365 "sSortableAsc": _stateDefault+" sorting_asc_disabled",
14366 "sSortableDesc": _stateDefault+" sorting_desc_disabled",
14367 "sSortableNone": _stateDefault+" sorting_disabled",
14368 "sSortJUIAsc": _sortIcon+"triangle-1-n",
14369 "sSortJUIDesc": _sortIcon+"triangle-1-s",
14370 "sSortJUI": _sortIcon+"carat-2-n-s",
14371 "sSortJUIAscAllowed": _sortIcon+"carat-1-n",
14372 "sSortJUIDescAllowed": _sortIcon+"carat-1-s",
14373 "sSortJUIWrapper": "DataTables_sort_wrapper",
14374 "sSortIcon": "DataTables_sort_icon",
14375
14376 /* Scrolling */
14377 "sScrollHead": "dataTables_scrollHead "+_stateDefault,
14378 "sScrollFoot": "dataTables_scrollFoot "+_stateDefault,
14379
14380 /* Misc */
14381 "sHeaderTH": _stateDefault,
14382 "sFooterTH": _stateDefault,
14383 "sJUIHeader": _headerFooter+" ui-corner-tl ui-corner-tr",
14384 "sJUIFooter": _headerFooter+" ui-corner-bl ui-corner-br"
14385 } );
14386
14387 }());
14388
14389
14390
14391 var extPagination = DataTable.ext.pager;
14392
14393 function _numbers ( page, pages ) {
14394 var
14395 numbers = [],
14396 buttons = extPagination.numbers_length,
14397 half = Math.floor( buttons / 2 ),
14398 i = 1;
14399
14400 if ( pages <= buttons ) {
14401 numbers = _range( 0, pages );
14402 }
14403 else if ( page <= half ) {
14404 numbers = _range( 0, buttons-2 );
14405 numbers.push( 'ellipsis' );
14406 numbers.push( pages-1 );
14407 }
14408 else if ( page >= pages - 1 - half ) {
14409 numbers = _range( pages-(buttons-2), pages );
14410 numbers.splice( 0, 0, 'ellipsis' ); // no unshift in ie6
14411 numbers.splice( 0, 0, 0 );
14412 }
14413 else {
14414 numbers = _range( page-half+2, page+half-1 );
14415 numbers.push( 'ellipsis' );
14416 numbers.push( pages-1 );
14417 numbers.splice( 0, 0, 'ellipsis' );
14418 numbers.splice( 0, 0, 0 );
14419 }
14420
14421 numbers.DT_el = 'span';
14422 return numbers;
14423 }
14424
14425
14426 $.extend( extPagination, {
14427 simple: function ( page, pages ) {
14428 return [ 'previous', 'next' ];
14429 },
14430
14431 full: function ( page, pages ) {
14432 return [ 'first', 'previous', 'next', 'last' ];
14433 },
14434
14435 numbers: function ( page, pages ) {
14436 return [ _numbers(page, pages) ];
14437 },
14438
14439 simple_numbers: function ( page, pages ) {
14440 return [ 'previous', _numbers(page, pages), 'next' ];
14441 },
14442
14443 full_numbers: function ( page, pages ) {
14444 return [ 'first', 'previous', _numbers(page, pages), 'next', 'last' ];
14445 },
14446
14447 // For testing and plug-ins to use
14448 _numbers: _numbers,
14449
14450 // Number of number buttons (including ellipsis) to show. _Must be odd!_
14451 numbers_length: 7
14452 } );
14453
14454
14455 $.extend( true, DataTable.ext.renderer, {
14456 pageButton: {
14457 _: function ( settings, host, idx, buttons, page, pages ) {
14458 var classes = settings.oClasses;
14459 var lang = settings.oLanguage.oPaginate;
14460 var aria = settings.oLanguage.oAria.paginate || {};
14461 var btnDisplay, btnClass, counter=0;
14462
14463 var attach = function( container, buttons ) {
14464 var i, ien, node, button;
14465 var clickHandler = function ( e ) {
14466 _fnPageChange( settings, e.data.action, true );
14467 };
14468
14469 for ( i=0, ien=buttons.length ; i<ien ; i++ ) {
14470 button = buttons[i];
14471
14472 if ( $.isArray( button ) ) {
14473 var inner = $( '<'+(button.DT_el || 'div')+'/>' )
14474 .appendTo( container );
14475 attach( inner, button );
14476 }
14477 else {
14478 btnDisplay = null;
14479 btnClass = '';
14480
14481 switch ( button ) {
14482 case 'ellipsis':
14483 container.append('<span class="ellipsis">&#x2026;</span>');
14484 break;
14485
14486 case 'first':
14487 btnDisplay = lang.sFirst;
14488 btnClass = button + (page > 0 ?
14489 '' : ' '+classes.sPageButtonDisabled);
14490 break;
14491
14492 case 'previous':
14493 btnDisplay = lang.sPrevious;
14494 btnClass = button + (page > 0 ?
14495 '' : ' '+classes.sPageButtonDisabled);
14496 break;
14497
14498 case 'next':
14499 btnDisplay = lang.sNext;
14500 btnClass = button + (page < pages-1 ?
14501 '' : ' '+classes.sPageButtonDisabled);
14502 break;
14503
14504 case 'last':
14505 btnDisplay = lang.sLast;
14506 btnClass = button + (page < pages-1 ?
14507 '' : ' '+classes.sPageButtonDisabled);
14508 break;
14509
14510 default:
14511 btnDisplay = button + 1;
14512 btnClass = page === button ?
14513 classes.sPageButtonActive : '';
14514 break;
14515 }
14516
14517 if ( btnDisplay !== null ) {
14518 node = $('<a>', {
14519 'class': classes.sPageButton+' '+btnClass,
14520 'aria-controls': settings.sTableId,
14521 'aria-label': aria[ button ],
14522 'data-dt-idx': counter,
14523 'tabindex': settings.iTabIndex,
14524 'id': idx === 0 && typeof button === 'string' ?
14525 settings.sTableId +'_'+ button :
14526 null
14527 } )
14528 .html( btnDisplay )
14529 .appendTo( container );
14530
14531 _fnBindAction(
14532 node, {action: button}, clickHandler
14533 );
14534
14535 counter++;
14536 }
14537 }
14538 }
14539 };
14540
14541 // IE9 throws an 'unknown error' if document.activeElement is used
14542 // inside an iframe or frame. Try / catch the error. Not good for
14543 // accessibility, but neither are frames.
14544 var activeEl;
14545
14546 try {
14547 // Because this approach is destroying and recreating the paging
14548 // elements, focus is lost on the select button which is bad for
14549 // accessibility. So we want to restore focus once the draw has
14550 // completed
14551 activeEl = $(host).find(document.activeElement).data('dt-idx');
14552 }
14553 catch (e) {}
14554
14555 attach( $(host).empty(), buttons );
14556
14557 if ( activeEl ) {
14558 $(host).find( '[data-dt-idx='+activeEl+']' ).focus();
14559 }
14560 }
14561 }
14562 } );
14563
14564
14565
14566 // Built in type detection. See model.ext.aTypes for information about
14567 // what is required from this methods.
14568 $.extend( DataTable.ext.type.detect, [
14569 // Plain numbers - first since V8 detects some plain numbers as dates
14570 // e.g. Date.parse('55') (but not all, e.g. Date.parse('22')...).
14571 function ( d, settings )
14572 {
14573 var decimal = settings.oLanguage.sDecimal;
14574 return _isNumber( d, decimal ) ? 'num'+decimal : null;
14575 },
14576
14577 // Dates (only those recognised by the browser's Date.parse)
14578 function ( d, settings )
14579 {
14580 // V8 will remove any unknown characters at the start and end of the
14581 // expression, leading to false matches such as `$245.12` or `10%` being
14582 // a valid date. See forum thread 18941 for detail.
14583 if ( d && !(d instanceof Date) && ( ! _re_date_start.test(d) || ! _re_date_end.test(d) ) ) {
14584 return null;
14585 }
14586 var parsed = Date.parse(d);
14587 return (parsed !== null && !isNaN(parsed)) || _empty(d) ? 'date' : null;
14588 },
14589
14590 // Formatted numbers
14591 function ( d, settings )
14592 {
14593 var decimal = settings.oLanguage.sDecimal;
14594 return _isNumber( d, decimal, true ) ? 'num-fmt'+decimal : null;
14595 },
14596
14597 // HTML numeric
14598 function ( d, settings )
14599 {
14600 var decimal = settings.oLanguage.sDecimal;
14601 return _htmlNumeric( d, decimal ) ? 'html-num'+decimal : null;
14602 },
14603
14604 // HTML numeric, formatted
14605 function ( d, settings )
14606 {
14607 var decimal = settings.oLanguage.sDecimal;
14608 return _htmlNumeric( d, decimal, true ) ? 'html-num-fmt'+decimal : null;
14609 },
14610
14611 // HTML (this is strict checking - there must be html)
14612 function ( d, settings )
14613 {
14614 return _empty( d ) || (typeof d === 'string' && d.indexOf('<') !== -1) ?
14615 'html' : null;
14616 }
14617 ] );
14618
14619
14620
14621 // Filter formatting functions. See model.ext.ofnSearch for information about
14622 // what is required from these methods.
14623 //
14624 // Note that additional search methods are added for the html numbers and
14625 // html formatted numbers by `_addNumericSort()` when we know what the decimal
14626 // place is
14627
14628
14629 $.extend( DataTable.ext.type.search, {
14630 html: function ( data ) {
14631 return _empty(data) ?
14632 data :
14633 typeof data === 'string' ?
14634 data
14635 .replace( _re_new_lines, " " )
14636 .replace( _re_html, "" ) :
14637 '';
14638 },
14639
14640 string: function ( data ) {
14641 return _empty(data) ?
14642 data :
14643 typeof data === 'string' ?
14644 data.replace( _re_new_lines, " " ) :
14645 data;
14646 }
14647 } );
14648
14649
14650
14651 var __numericReplace = function ( d, decimalPlace, re1, re2 ) {
14652 if ( d !== 0 && (!d || d === '-') ) {
14653 return -Infinity;
14654 }
14655
14656 // If a decimal place other than `.` is used, it needs to be given to the
14657 // function so we can detect it and replace with a `.` which is the only
14658 // decimal place Javascript recognises - it is not locale aware.
14659 if ( decimalPlace ) {
14660 d = _numToDecimal( d, decimalPlace );
14661 }
14662
14663 if ( d.replace ) {
14664 if ( re1 ) {
14665 d = d.replace( re1, '' );
14666 }
14667
14668 if ( re2 ) {
14669 d = d.replace( re2, '' );
14670 }
14671 }
14672
14673 return d * 1;
14674 };
14675
14676
14677 // Add the numeric 'deformatting' functions for sorting and search. This is done
14678 // in a function to provide an easy ability for the language options to add
14679 // additional methods if a non-period decimal place is used.
14680 function _addNumericSort ( decimalPlace ) {
14681 $.each(
14682 {
14683 // Plain numbers
14684 "num": function ( d ) {
14685 return __numericReplace( d, decimalPlace );
14686 },
14687
14688 // Formatted numbers
14689 "num-fmt": function ( d ) {
14690 return __numericReplace( d, decimalPlace, _re_formatted_numeric );
14691 },
14692
14693 // HTML numeric
14694 "html-num": function ( d ) {
14695 return __numericReplace( d, decimalPlace, _re_html );
14696 },
14697
14698 // HTML numeric, formatted
14699 "html-num-fmt": function ( d ) {
14700 return __numericReplace( d, decimalPlace, _re_html, _re_formatted_numeric );
14701 }
14702 },
14703 function ( key, fn ) {
14704 // Add the ordering method
14705 _ext.type.order[ key+decimalPlace+'-pre' ] = fn;
14706
14707 // For HTML types add a search formatter that will strip the HTML
14708 if ( key.match(/^html\-/) ) {
14709 _ext.type.search[ key+decimalPlace ] = _ext.type.search.html;
14710 }
14711 }
14712 );
14713 }
14714
14715
14716 // Default sort methods
14717 $.extend( _ext.type.order, {
14718 // Dates
14719 "date-pre": function ( d ) {
14720 return Date.parse( d ) || 0;
14721 },
14722
14723 // html
14724 "html-pre": function ( a ) {
14725 return _empty(a) ?
14726 '' :
14727 a.replace ?
14728 a.replace( /<.*?>/g, "" ).toLowerCase() :
14729 a+'';
14730 },
14731
14732 // string
14733 "string-pre": function ( a ) {
14734 // This is a little complex, but faster than always calling toString,
14735 // http://jsperf.com/tostring-v-check
14736 return _empty(a) ?
14737 '' :
14738 typeof a === 'string' ?
14739 a.toLowerCase() :
14740 ! a.toString ?
14741 '' :
14742 a.toString();
14743 },
14744
14745 // string-asc and -desc are retained only for compatibility with the old
14746 // sort methods
14747 "string-asc": function ( x, y ) {
14748 return ((x < y) ? -1 : ((x > y) ? 1 : 0));
14749 },
14750
14751 "string-desc": function ( x, y ) {
14752 return ((x < y) ? 1 : ((x > y) ? -1 : 0));
14753 }
14754 } );
14755
14756
14757 // Numeric sorting types - order doesn't matter here
14758 _addNumericSort( '' );
14759
14760
14761 $.extend( true, DataTable.ext.renderer, {
14762 header: {
14763 _: function ( settings, cell, column, classes ) {
14764 // No additional mark-up required
14765 // Attach a sort listener to update on sort - note that using the
14766 // `DT` namespace will allow the event to be removed automatically
14767 // on destroy, while the `dt` namespaced event is the one we are
14768 // listening for
14769 $(settings.nTable).on( 'order.dt.DT', function ( e, ctx, sorting, columns ) {
14770 if ( settings !== ctx ) { // need to check this this is the host
14771 return; // table, not a nested one
14772 }
14773
14774 var colIdx = column.idx;
14775
14776 cell
14777 .removeClass(
14778 column.sSortingClass +' '+
14779 classes.sSortAsc +' '+
14780 classes.sSortDesc
14781 )
14782 .addClass( columns[ colIdx ] == 'asc' ?
14783 classes.sSortAsc : columns[ colIdx ] == 'desc' ?
14784 classes.sSortDesc :
14785 column.sSortingClass
14786 );
14787 } );
14788 },
14789
14790 jqueryui: function ( settings, cell, column, classes ) {
14791 $('<div/>')
14792 .addClass( classes.sSortJUIWrapper )
14793 .append( cell.contents() )
14794 .append( $('<span/>')
14795 .addClass( classes.sSortIcon+' '+column.sSortingClassJUI )
14796 )
14797 .appendTo( cell );
14798
14799 // Attach a sort listener to update on sort
14800 $(settings.nTable).on( 'order.dt.DT', function ( e, ctx, sorting, columns ) {
14801 if ( settings !== ctx ) {
14802 return;
14803 }
14804
14805 var colIdx = column.idx;
14806
14807 cell
14808 .removeClass( classes.sSortAsc +" "+classes.sSortDesc )
14809 .addClass( columns[ colIdx ] == 'asc' ?
14810 classes.sSortAsc : columns[ colIdx ] == 'desc' ?
14811 classes.sSortDesc :
14812 column.sSortingClass
14813 );
14814
14815 cell
14816 .find( 'span.'+classes.sSortIcon )
14817 .removeClass(
14818 classes.sSortJUIAsc +" "+
14819 classes.sSortJUIDesc +" "+
14820 classes.sSortJUI +" "+
14821 classes.sSortJUIAscAllowed +" "+
14822 classes.sSortJUIDescAllowed
14823 )
14824 .addClass( columns[ colIdx ] == 'asc' ?
14825 classes.sSortJUIAsc : columns[ colIdx ] == 'desc' ?
14826 classes.sSortJUIDesc :
14827 column.sSortingClassJUI
14828 );
14829 } );
14830 }
14831 }
14832 } );
14833
14834 /*
14835 * Public helper functions. These aren't used internally by DataTables, or
14836 * called by any of the options passed into DataTables, but they can be used
14837 * externally by developers working with DataTables. They are helper functions
14838 * to make working with DataTables a little bit easier.
14839 */
14840
14841 /**
14842 * Helpers for `columns.render`.
14843 *
14844 * The options defined here can be used with the `columns.render` initialisation
14845 * option to provide a display renderer. The following functions are defined:
14846 *
14847 * * `number` - Will format numeric data (defined by `columns.data`) for
14848 * display, retaining the original unformatted data for sorting and filtering.
14849 * It takes 5 parameters:
14850 * * `string` - Thousands grouping separator
14851 * * `string` - Decimal point indicator
14852 * * `integer` - Number of decimal points to show
14853 * * `string` (optional) - Prefix.
14854 * * `string` (optional) - Postfix (/suffix).
14855 * * `text` - Escape HTML to help prevent XSS attacks. It has no optional
14856 * parameters.
14857 *
14858 * @example
14859 * // Column definition using the number renderer
14860 * {
14861 * data: "salary",
14862 * render: $.fn.dataTable.render.number( '\'', '.', 0, '$' )
14863 * }
14864 *
14865 * @namespace
14866 */
14867 DataTable.render = {
14868 number: function ( thousands, decimal, precision, prefix, postfix ) {
14869 return {
14870 display: function ( d ) {
14871 if ( typeof d !== 'number' && typeof d !== 'string' ) {
14872 return d;
14873 }
14874
14875 var negative = d < 0 ? '-' : '';
14876 var flo = parseFloat( d );
14877
14878 // If NaN then there isn't much formatting that we can do - just
14879 // return immediately
14880 if ( isNaN( flo ) ) {
14881 return d;
14882 }
14883
14884 d = Math.abs( flo );
14885
14886 var intPart = parseInt( d, 10 );
14887 var floatPart = precision ?
14888 decimal+(d - intPart).toFixed( precision ).substring( 2 ):
14889 '';
14890
14891 return negative + (prefix||'') +
14892 intPart.toString().replace(
14893 /\B(?=(\d{3})+(?!\d))/g, thousands
14894 ) +
14895 floatPart +
14896 (postfix||'');
14897 }
14898 };
14899 },
14900
14901 text: function () {
14902 return {
14903 display: function ( d ) {
14904 return typeof d === 'string' ?
14905 d.replace(/</g, '&lt;').replace(/>/g, '&gt;').replace(/"/g, '&quot;') :
14906 d;
14907 }
14908 };
14909 }
14910 };
14911
14912
14913 /*
14914 * This is really a good bit rubbish this method of exposing the internal methods
14915 * publicly... - To be fixed in 2.0 using methods on the prototype
14916 */
14917
14918
14919 /**
14920 * Create a wrapper function for exporting an internal functions to an external API.
14921 * @param {string} fn API function name
14922 * @returns {function} wrapped function
14923 * @memberof DataTable#internal
14924 */
14925 function _fnExternApiFunc (fn)
14926 {
14927 return function() {
14928 var args = [_fnSettingsFromNode( this[DataTable.ext.iApiIndex] )].concat(
14929 Array.prototype.slice.call(arguments)
14930 );
14931 return DataTable.ext.internal[fn].apply( this, args );
14932 };
14933 }
14934
14935
14936 /**
14937 * Reference to internal functions for use by plug-in developers. Note that
14938 * these methods are references to internal functions and are considered to be
14939 * private. If you use these methods, be aware that they are liable to change
14940 * between versions.
14941 * @namespace
14942 */
14943 $.extend( DataTable.ext.internal, {
14944 _fnExternApiFunc: _fnExternApiFunc,
14945 _fnBuildAjax: _fnBuildAjax,
14946 _fnAjaxUpdate: _fnAjaxUpdate,
14947 _fnAjaxParameters: _fnAjaxParameters,
14948 _fnAjaxUpdateDraw: _fnAjaxUpdateDraw,
14949 _fnAjaxDataSrc: _fnAjaxDataSrc,
14950 _fnAddColumn: _fnAddColumn,
14951 _fnColumnOptions: _fnColumnOptions,
14952 _fnAdjustColumnSizing: _fnAdjustColumnSizing,
14953 _fnVisibleToColumnIndex: _fnVisibleToColumnIndex,
14954 _fnColumnIndexToVisible: _fnColumnIndexToVisible,
14955 _fnVisbleColumns: _fnVisbleColumns,
14956 _fnGetColumns: _fnGetColumns,
14957 _fnColumnTypes: _fnColumnTypes,
14958 _fnApplyColumnDefs: _fnApplyColumnDefs,
14959 _fnHungarianMap: _fnHungarianMap,
14960 _fnCamelToHungarian: _fnCamelToHungarian,
14961 _fnLanguageCompat: _fnLanguageCompat,
14962 _fnBrowserDetect: _fnBrowserDetect,
14963 _fnAddData: _fnAddData,
14964 _fnAddTr: _fnAddTr,
14965 _fnNodeToDataIndex: _fnNodeToDataIndex,
14966 _fnNodeToColumnIndex: _fnNodeToColumnIndex,
14967 _fnGetCellData: _fnGetCellData,
14968 _fnSetCellData: _fnSetCellData,
14969 _fnSplitObjNotation: _fnSplitObjNotation,
14970 _fnGetObjectDataFn: _fnGetObjectDataFn,
14971 _fnSetObjectDataFn: _fnSetObjectDataFn,
14972 _fnGetDataMaster: _fnGetDataMaster,
14973 _fnClearTable: _fnClearTable,
14974 _fnDeleteIndex: _fnDeleteIndex,
14975 _fnInvalidate: _fnInvalidate,
14976 _fnGetRowElements: _fnGetRowElements,
14977 _fnCreateTr: _fnCreateTr,
14978 _fnBuildHead: _fnBuildHead,
14979 _fnDrawHead: _fnDrawHead,
14980 _fnDraw: _fnDraw,
14981 _fnReDraw: _fnReDraw,
14982 _fnAddOptionsHtml: _fnAddOptionsHtml,
14983 _fnDetectHeader: _fnDetectHeader,
14984 _fnGetUniqueThs: _fnGetUniqueThs,
14985 _fnFeatureHtmlFilter: _fnFeatureHtmlFilter,
14986 _fnFilterComplete: _fnFilterComplete,
14987 _fnFilterCustom: _fnFilterCustom,
14988 _fnFilterColumn: _fnFilterColumn,
14989 _fnFilter: _fnFilter,
14990 _fnFilterCreateSearch: _fnFilterCreateSearch,
14991 _fnEscapeRegex: _fnEscapeRegex,
14992 _fnFilterData: _fnFilterData,
14993 _fnFeatureHtmlInfo: _fnFeatureHtmlInfo,
14994 _fnUpdateInfo: _fnUpdateInfo,
14995 _fnInfoMacros: _fnInfoMacros,
14996 _fnInitialise: _fnInitialise,
14997 _fnInitComplete: _fnInitComplete,
14998 _fnLengthChange: _fnLengthChange,
14999 _fnFeatureHtmlLength: _fnFeatureHtmlLength,
15000 _fnFeatureHtmlPaginate: _fnFeatureHtmlPaginate,
15001 _fnPageChange: _fnPageChange,
15002 _fnFeatureHtmlProcessing: _fnFeatureHtmlProcessing,
15003 _fnProcessingDisplay: _fnProcessingDisplay,
15004 _fnFeatureHtmlTable: _fnFeatureHtmlTable,
15005 _fnScrollDraw: _fnScrollDraw,
15006 _fnApplyToChildren: _fnApplyToChildren,
15007 _fnCalculateColumnWidths: _fnCalculateColumnWidths,
15008 _fnThrottle: _fnThrottle,
15009 _fnConvertToWidth: _fnConvertToWidth,
15010 _fnGetWidestNode: _fnGetWidestNode,
15011 _fnGetMaxLenString: _fnGetMaxLenString,
15012 _fnStringToCss: _fnStringToCss,
15013 _fnSortFlatten: _fnSortFlatten,
15014 _fnSort: _fnSort,
15015 _fnSortAria: _fnSortAria,
15016 _fnSortListener: _fnSortListener,
15017 _fnSortAttachListener: _fnSortAttachListener,
15018 _fnSortingClasses: _fnSortingClasses,
15019 _fnSortData: _fnSortData,
15020 _fnSaveState: _fnSaveState,
15021 _fnLoadState: _fnLoadState,
15022 _fnSettingsFromNode: _fnSettingsFromNode,
15023 _fnLog: _fnLog,
15024 _fnMap: _fnMap,
15025 _fnBindAction: _fnBindAction,
15026 _fnCallbackReg: _fnCallbackReg,
15027 _fnCallbackFire: _fnCallbackFire,
15028 _fnLengthOverflow: _fnLengthOverflow,
15029 _fnRenderer: _fnRenderer,
15030 _fnDataSource: _fnDataSource,
15031 _fnRowAttributes: _fnRowAttributes,
15032 _fnCalculateEnd: function () {} // Used by a lot of plug-ins, but redundant
15033 // in 1.10, so this dead-end function is
15034 // added to prevent errors
15035 } );
15036
15037
15038 // jQuery access
15039 $.fn.dataTable = DataTable;
15040
15041 // Provide access to the host jQuery object (circular reference)
15042 DataTable.$ = $;
15043
15044 // Legacy aliases
15045 $.fn.dataTableSettings = DataTable.settings;
15046 $.fn.dataTableExt = DataTable.ext;
15047
15048 // With a capital `D` we return a DataTables API instance rather than a
15049 // jQuery object
15050 $.fn.DataTable = function ( opts ) {
15051 return $(this).dataTable( opts ).api();
15052 };
15053
15054 // All properties that are available to $.fn.dataTable should also be
15055 // available on $.fn.DataTable
15056 $.each( DataTable, function ( prop, val ) {
15057 $.fn.DataTable[ prop ] = val;
15058 } );
15059
15060
15061 // Information about events fired by DataTables - for documentation.
15062 /**
15063 * Draw event, fired whenever the table is redrawn on the page, at the same
15064 * point as fnDrawCallback. This may be useful for binding events or
15065 * performing calculations when the table is altered at all.
15066 * @name DataTable#draw.dt
15067 * @event
15068 * @param {event} e jQuery event object
15069 * @param {object} o DataTables settings object {@link DataTable.models.oSettings}
15070 */
15071
15072 /**
15073 * Search event, fired when the searching applied to the table (using the
15074 * built-in global search, or column filters) is altered.
15075 * @name DataTable#search.dt
15076 * @event
15077 * @param {event} e jQuery event object
15078 * @param {object} o DataTables settings object {@link DataTable.models.oSettings}
15079 */
15080
15081 /**
15082 * Page change event, fired when the paging of the table is altered.
15083 * @name DataTable#page.dt
15084 * @event
15085 * @param {event} e jQuery event object
15086 * @param {object} o DataTables settings object {@link DataTable.models.oSettings}
15087 */
15088
15089 /**
15090 * Order event, fired when the ordering applied to the table is altered.
15091 * @name DataTable#order.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 * DataTables initialisation complete event, fired when the table is fully
15099 * drawn, including Ajax data loaded, if Ajax data is required.
15100 * @name DataTable#init.dt
15101 * @event
15102 * @param {event} e jQuery event object
15103 * @param {object} oSettings DataTables settings object
15104 * @param {object} json The JSON object request from the server - only
15105 * present if client-side Ajax sourced data is used</li></ol>
15106 */
15107
15108 /**
15109 * State save event, fired when the table has changed state a new state save
15110 * is required. This event allows modification of the state saving object
15111 * prior to actually doing the save, including addition or other state
15112 * properties (for plug-ins) or modification of a DataTables core property.
15113 * @name DataTable#stateSaveParams.dt
15114 * @event
15115 * @param {event} e jQuery event object
15116 * @param {object} oSettings DataTables settings object
15117 * @param {object} json The state information to be saved
15118 */
15119
15120 /**
15121 * State load event, fired when the table is loading state from the stored
15122 * data, but prior to the settings object being modified by the saved state
15123 * - allowing modification of the saved state is required or loading of
15124 * state for a plug-in.
15125 * @name DataTable#stateLoadParams.dt
15126 * @event
15127 * @param {event} e jQuery event object
15128 * @param {object} oSettings DataTables settings object
15129 * @param {object} json The saved state information
15130 */
15131
15132 /**
15133 * State loaded event, fired when state has been loaded from stored data and
15134 * the settings object has been modified by the loaded data.
15135 * @name DataTable#stateLoaded.dt
15136 * @event
15137 * @param {event} e jQuery event object
15138 * @param {object} oSettings DataTables settings object
15139 * @param {object} json The saved state information
15140 */
15141
15142 /**
15143 * Processing event, fired when DataTables is doing some kind of processing
15144 * (be it, order, searcg or anything else). It can be used to indicate to
15145 * the end user that there is something happening, or that something has
15146 * finished.
15147 * @name DataTable#processing.dt
15148 * @event
15149 * @param {event} e jQuery event object
15150 * @param {object} oSettings DataTables settings object
15151 * @param {boolean} bShow Flag for if DataTables is doing processing or not
15152 */
15153
15154 /**
15155 * Ajax (XHR) event, fired whenever an Ajax request is completed from a
15156 * request to made to the server for new data. This event is called before
15157 * DataTables processed the returned data, so it can also be used to pre-
15158 * process the data returned from the server, if needed.
15159 *
15160 * Note that this trigger is called in `fnServerData`, if you override
15161 * `fnServerData` and which to use this event, you need to trigger it in you
15162 * success function.
15163 * @name DataTable#xhr.dt
15164 * @event
15165 * @param {event} e jQuery event object
15166 * @param {object} o DataTables settings object {@link DataTable.models.oSettings}
15167 * @param {object} json JSON returned from the server
15168 *
15169 * @example
15170 * // Use a custom property returned from the server in another DOM element
15171 * $('#table').dataTable().on('xhr.dt', function (e, settings, json) {
15172 * $('#status').html( json.status );
15173 * } );
15174 *
15175 * @example
15176 * // Pre-process the data returned from the server
15177 * $('#table').dataTable().on('xhr.dt', function (e, settings, json) {
15178 * for ( var i=0, ien=json.aaData.length ; i<ien ; i++ ) {
15179 * json.aaData[i].sum = json.aaData[i].one + json.aaData[i].two;
15180 * }
15181 * // Note no return - manipulate the data directly in the JSON object.
15182 * } );
15183 */
15184
15185 /**
15186 * Destroy event, fired when the DataTable is destroyed by calling fnDestroy
15187 * or passing the bDestroy:true parameter in the initialisation object. This
15188 * can be used to remove bound events, added DOM nodes, etc.
15189 * @name DataTable#destroy.dt
15190 * @event
15191 * @param {event} e jQuery event object
15192 * @param {object} o DataTables settings object {@link DataTable.models.oSettings}
15193 */
15194
15195 /**
15196 * Page length change event, fired when number of records to show on each
15197 * page (the length) is changed.
15198 * @name DataTable#length.dt
15199 * @event
15200 * @param {event} e jQuery event object
15201 * @param {object} o DataTables settings object {@link DataTable.models.oSettings}
15202 * @param {integer} len New length
15203 */
15204
15205 /**
15206 * Column sizing has changed.
15207 * @name DataTable#column-sizing.dt
15208 * @event
15209 * @param {event} e jQuery event object
15210 * @param {object} o DataTables settings object {@link DataTable.models.oSettings}
15211 */
15212
15213 /**
15214 * Column visibility has changed.
15215 * @name DataTable#column-visibility.dt
15216 * @event
15217 * @param {event} e jQuery event object
15218 * @param {object} o DataTables settings object {@link DataTable.models.oSettings}
15219 * @param {int} column Column index
15220 * @param {bool} vis `false` if column now hidden, or `true` if visible
15221 */
15222
15223 return $.fn.dataTable;
15224 }));
15225
15226
15227 /*! Responsive 2.0.0
15228 * 2014-2015 SpryMedia Ltd - datatables.net/license
15229 */
15230
15231 /**
15232 * @summary Responsive
15233 * @description Responsive tables plug-in for DataTables
15234 * @version 2.0.0
15235 * @file dataTables.responsive.js
15236 * @author SpryMedia Ltd (www.sprymedia.co.uk)
15237 * @contact www.sprymedia.co.uk/contact
15238 * @copyright Copyright 2014-2015 SpryMedia Ltd.
15239 *
15240 * This source file is free software, available under the following license:
15241 * MIT license - http://datatables.net/license/mit
15242 *
15243 * This source file is distributed in the hope that it will be useful, but
15244 * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
15245 * or FITNESS FOR A PARTICULAR PURPOSE. See the license files for details.
15246 *
15247 * For details please refer to: http://www.datatables.net
15248 */
15249 (function( factory ){
15250 if ( typeof define === 'function' && define.amd ) {
15251 // AMD
15252 define( ['jquery', 'datatables.net'], function ( $ ) {
15253 return factory( $, window, document );
15254 } );
15255 }
15256 else if ( typeof exports === 'object' ) {
15257 // CommonJS
15258 module.exports = function (root, $) {
15259 if ( ! root ) {
15260 root = window;
15261 }
15262
15263 if ( ! $ || ! $.fn.dataTable ) {
15264 $ = require('datatables.net')(root, $).$;
15265 }
15266
15267 return factory( $, root, root.document );
15268 };
15269 }
15270 else {
15271 // Browser
15272 factory( jQuery, window, document );
15273 }
15274 }(function( $, window, document, undefined ) {
15275 'use strict';
15276 var DataTable = $.fn.dataTable;
15277
15278
15279 /**
15280 * Responsive is a plug-in for the DataTables library that makes use of
15281 * DataTables' ability to change the visibility of columns, changing the
15282 * visibility of columns so the displayed columns fit into the table container.
15283 * The end result is that complex tables will be dynamically adjusted to fit
15284 * into the viewport, be it on a desktop, tablet or mobile browser.
15285 *
15286 * Responsive for DataTables has two modes of operation, which can used
15287 * individually or combined:
15288 *
15289 * * Class name based control - columns assigned class names that match the
15290 * breakpoint logic can be shown / hidden as required for each breakpoint.
15291 * * Automatic control - columns are automatically hidden when there is no
15292 * room left to display them. Columns removed from the right.
15293 *
15294 * In additional to column visibility control, Responsive also has built into
15295 * options to use DataTables' child row display to show / hide the information
15296 * from the table that has been hidden. There are also two modes of operation
15297 * for this child row display:
15298 *
15299 * * Inline - when the control element that the user can use to show / hide
15300 * child rows is displayed inside the first column of the table.
15301 * * Column - where a whole column is dedicated to be the show / hide control.
15302 *
15303 * Initialisation of Responsive is performed by:
15304 *
15305 * * Adding the class `responsive` or `dt-responsive` to the table. In this case
15306 * Responsive will automatically be initialised with the default configuration
15307 * options when the DataTable is created.
15308 * * Using the `responsive` option in the DataTables configuration options. This
15309 * can also be used to specify the configuration options, or simply set to
15310 * `true` to use the defaults.
15311 *
15312 * @class
15313 * @param {object} settings DataTables settings object for the host table
15314 * @param {object} [opts] Configuration options
15315 * @requires jQuery 1.7+
15316 * @requires DataTables 1.10.3+
15317 *
15318 * @example
15319 * $('#example').DataTable( {
15320 * responsive: true
15321 * } );
15322 * } );
15323 */
15324 var Responsive = function ( settings, opts ) {
15325 // Sanity check that we are using DataTables 1.10 or newer
15326 if ( ! DataTable.versionCheck || ! DataTable.versionCheck( '1.10.3' ) ) {
15327 throw 'DataTables Responsive requires DataTables 1.10.3 or newer';
15328 }
15329
15330 this.s = {
15331 dt: new DataTable.Api( settings ),
15332 columns: [],
15333 current: []
15334 };
15335
15336 // Check if responsive has already been initialised on this table
15337 if ( this.s.dt.settings()[0].responsive ) {
15338 return;
15339 }
15340
15341 // details is an object, but for simplicity the user can give it as a string
15342 if ( opts && typeof opts.details === 'string' ) {
15343 opts.details = { type: opts.details };
15344 }
15345
15346 this.c = $.extend( true, {}, Responsive.defaults, DataTable.defaults.responsive, opts );
15347 settings.responsive = this;
15348 this._constructor();
15349 };
15350
15351 $.extend( Responsive.prototype, {
15352 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
15353 * Constructor
15354 */
15355
15356 /**
15357 * Initialise the Responsive instance
15358 *
15359 * @private
15360 */
15361 _constructor: function ()
15362 {
15363 var that = this;
15364 var dt = this.s.dt;
15365 var dtPrivateSettings = dt.settings()[0];
15366
15367 dt.settings()[0]._responsive = this;
15368
15369 // Use DataTables' throttle function to avoid processor thrashing on
15370 // resize
15371 $(window).on( 'resize.dtr orientationchange.dtr', DataTable.util.throttle( function () {
15372 that._resize();
15373 } ) );
15374
15375 // DataTables doesn't currently trigger an event when a row is added, so
15376 // we need to hook into its private API to enforce the hidden rows when
15377 // new data is added
15378 dtPrivateSettings.oApi._fnCallbackReg( dtPrivateSettings, 'aoRowCreatedCallback', function (tr, data, idx) {
15379 if ( $.inArray( false, that.s.current ) !== -1 ) {
15380 $('td, th', tr).each( function ( i ) {
15381 var idx = dt.column.index( 'toData', i );
15382
15383 if ( that.s.current[idx] === false ) {
15384 $(this).css('display', 'none');
15385 }
15386 } );
15387 }
15388 } );
15389
15390 // Destroy event handler
15391 dt.on( 'destroy.dtr', function () {
15392 dt.off( '.dtr' );
15393 $( dt.table().body() ).off( '.dtr' );
15394 $(window).off( 'resize.dtr orientationchange.dtr' );
15395
15396 // Restore the columns that we've hidden
15397 $.each( that.s.current, function ( i, val ) {
15398 if ( val === false ) {
15399 that._setColumnVis( i, true );
15400 }
15401 } );
15402 } );
15403
15404 // Reorder the breakpoints array here in case they have been added out
15405 // of order
15406 this.c.breakpoints.sort( function (a, b) {
15407 return a.width < b.width ? 1 :
15408 a.width > b.width ? -1 : 0;
15409 } );
15410
15411 this._classLogic();
15412 this._resizeAuto();
15413
15414 // Details handler
15415 var details = this.c.details;
15416 if ( details.type !== false ) {
15417 that._detailsInit();
15418
15419 // DataTables will trigger this event on every column it shows and
15420 // hides individually
15421 dt.on( 'column-visibility.dtr', function (e, ctx, col, vis) {
15422 that._classLogic();
15423 that._resizeAuto();
15424 that._resize();
15425 } );
15426
15427 // Redraw the details box on each draw which will happen if the data
15428 // has changed. This is used until DataTables implements a native
15429 // `updated` event for rows
15430 dt.on( 'draw.dtr', function () {
15431 that._redrawChildren();
15432 } );
15433
15434 $(dt.table().node()).addClass( 'dtr-'+details.type );
15435 }
15436
15437 dt.on( 'column-reorder.dtr', function (e, settings, details) {
15438 // This requires ColReorder 1.2.1 or newer
15439 if ( details.drop ) {
15440 that._classLogic();
15441 that._resizeAuto();
15442 that._resize();
15443 }
15444 } );
15445
15446 // First pass - draw the table for the current viewport size
15447 this._resize();
15448 },
15449
15450
15451 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
15452 * Private methods
15453 */
15454
15455 /**
15456 * Calculate the visibility for the columns in a table for a given
15457 * breakpoint. The result is pre-determined based on the class logic if
15458 * class names are used to control all columns, but the width of the table
15459 * is also used if there are columns which are to be automatically shown
15460 * and hidden.
15461 *
15462 * @param {string} breakpoint Breakpoint name to use for the calculation
15463 * @return {array} Array of boolean values initiating the visibility of each
15464 * column.
15465 * @private
15466 */
15467 _columnsVisiblity: function ( breakpoint )
15468 {
15469 var dt = this.s.dt;
15470 var columns = this.s.columns;
15471 var i, ien;
15472
15473 // Create an array that defines the column ordering based first on the
15474 // column's priority, and secondly the column index. This allows the
15475 // columns to be removed from the right if the priority matches
15476 var order = columns
15477 .map( function ( col, idx ) {
15478 return {
15479 columnIdx: idx,
15480 priority: col.priority
15481 };
15482 } )
15483 .sort( function ( a, b ) {
15484 if ( a.priority !== b.priority ) {
15485 return a.priority - b.priority;
15486 }
15487 return a.columnIdx - b.columnIdx;
15488 } );
15489
15490
15491 // Class logic - determine which columns are in this breakpoint based
15492 // on the classes. If no class control (i.e. `auto`) then `-` is used
15493 // to indicate this to the rest of the function
15494 var display = $.map( columns, function ( col ) {
15495 return col.auto && col.minWidth === null ?
15496 false :
15497 col.auto === true ?
15498 '-' :
15499 $.inArray( breakpoint, col.includeIn ) !== -1;
15500 } );
15501
15502 // Auto column control - first pass: how much width is taken by the
15503 // ones that must be included from the non-auto columns
15504 var requiredWidth = 0;
15505 for ( i=0, ien=display.length ; i<ien ; i++ ) {
15506 if ( display[i] === true ) {
15507 requiredWidth += columns[i].minWidth;
15508 }
15509 }
15510
15511 // Second pass, use up any remaining width for other columns. For
15512 // scrolling tables we need to subtract the width of the scrollbar. It
15513 // may not be requires which makes this sub-optimal, but it would
15514 // require another full redraw to make complete use of those extra few
15515 // pixels
15516 var scrolling = dt.settings()[0].oScroll;
15517 var bar = scrolling.sY || scrolling.sX ? scrolling.iBarWidth : 0;
15518 var widthAvailable = dt.table().container().offsetWidth - bar;
15519 var usedWidth = widthAvailable - requiredWidth;
15520
15521 // Control column needs to always be included. This makes it sub-
15522 // optimal in terms of using the available with, but to stop layout
15523 // thrashing or overflow. Also we need to account for the control column
15524 // width first so we know how much width is available for the other
15525 // columns, since the control column might not be the first one shown
15526 for ( i=0, ien=display.length ; i<ien ; i++ ) {
15527 if ( columns[i].control ) {
15528 usedWidth -= columns[i].minWidth;
15529 }
15530 }
15531
15532 // Allow columns to be shown (counting by priority and then right to
15533 // left) until we run out of room
15534 var empty = false;
15535 for ( i=0, ien=order.length ; i<ien ; i++ ) {
15536 var colIdx = order[i].columnIdx;
15537
15538 if ( display[colIdx] === '-' && ! columns[colIdx].control && columns[colIdx].minWidth ) {
15539 // Once we've found a column that won't fit we don't let any
15540 // others display either, or columns might disappear in the
15541 // middle of the table
15542 if ( empty || usedWidth - columns[colIdx].minWidth < 0 ) {
15543 empty = true;
15544 display[colIdx] = false;
15545 }
15546 else {
15547 display[colIdx] = true;
15548 }
15549
15550 usedWidth -= columns[colIdx].minWidth;
15551 }
15552 }
15553
15554 // Determine if the 'control' column should be shown (if there is one).
15555 // This is the case when there is a hidden column (that is not the
15556 // control column). The two loops look inefficient here, but they are
15557 // trivial and will fly through. We need to know the outcome from the
15558 // first , before the action in the second can be taken
15559 var showControl = false;
15560
15561 for ( i=0, ien=columns.length ; i<ien ; i++ ) {
15562 if ( ! columns[i].control && ! columns[i].never && ! display[i] ) {
15563 showControl = true;
15564 break;
15565 }
15566 }
15567
15568 for ( i=0, ien=columns.length ; i<ien ; i++ ) {
15569 if ( columns[i].control ) {
15570 display[i] = showControl;
15571 }
15572 }
15573
15574 // Finally we need to make sure that there is at least one column that
15575 // is visible
15576 if ( $.inArray( true, display ) === -1 ) {
15577 display[0] = true;
15578 }
15579
15580 return display;
15581 },
15582
15583
15584 /**
15585 * Create the internal `columns` array with information about the columns
15586 * for the table. This includes determining which breakpoints the column
15587 * will appear in, based upon class names in the column, which makes up the
15588 * vast majority of this method.
15589 *
15590 * @private
15591 */
15592 _classLogic: function ()
15593 {
15594 var that = this;
15595 var calc = {};
15596 var breakpoints = this.c.breakpoints;
15597 var dt = this.s.dt;
15598 var columns = dt.columns().eq(0).map( function (i) {
15599 var column = this.column(i);
15600 var className = column.header().className;
15601 var priority = dt.settings()[0].aoColumns[i].responsivePriority;
15602
15603 if ( priority === undefined ) {
15604 priority = $(column.header).data('priority') !== undefined ?
15605 $(column.header).data('priority') * 1 :
15606 10000;
15607 }
15608
15609 return {
15610 className: className,
15611 includeIn: [],
15612 auto: false,
15613 control: false,
15614 never: className.match(/\bnever\b/) ? true : false,
15615 priority: priority
15616 };
15617 } );
15618
15619 // Simply add a breakpoint to `includeIn` array, ensuring that there are
15620 // no duplicates
15621 var add = function ( colIdx, name ) {
15622 var includeIn = columns[ colIdx ].includeIn;
15623
15624 if ( $.inArray( name, includeIn ) === -1 ) {
15625 includeIn.push( name );
15626 }
15627 };
15628
15629 var column = function ( colIdx, name, operator, matched ) {
15630 var size, i, ien;
15631
15632 if ( ! operator ) {
15633 columns[ colIdx ].includeIn.push( name );
15634 }
15635 else if ( operator === 'max-' ) {
15636 // Add this breakpoint and all smaller
15637 size = that._find( name ).width;
15638
15639 for ( i=0, ien=breakpoints.length ; i<ien ; i++ ) {
15640 if ( breakpoints[i].width <= size ) {
15641 add( colIdx, breakpoints[i].name );
15642 }
15643 }
15644 }
15645 else if ( operator === 'min-' ) {
15646 // Add this breakpoint and all larger
15647 size = that._find( name ).width;
15648
15649 for ( i=0, ien=breakpoints.length ; i<ien ; i++ ) {
15650 if ( breakpoints[i].width >= size ) {
15651 add( colIdx, breakpoints[i].name );
15652 }
15653 }
15654 }
15655 else if ( operator === 'not-' ) {
15656 // Add all but this breakpoint
15657 for ( i=0, ien=breakpoints.length ; i<ien ; i++ ) {
15658 if ( breakpoints[i].name.indexOf( matched ) === -1 ) {
15659 add( colIdx, breakpoints[i].name );
15660 }
15661 }
15662 }
15663 };
15664
15665 // Loop over each column and determine if it has a responsive control
15666 // class
15667 columns.each( function ( col, i ) {
15668 var classNames = col.className.split(' ');
15669 var hasClass = false;
15670
15671 // Split the class name up so multiple rules can be applied if needed
15672 for ( var k=0, ken=classNames.length ; k<ken ; k++ ) {
15673 var className = $.trim( classNames[k] );
15674
15675 if ( className === 'all' ) {
15676 // Include in all
15677 hasClass = true;
15678 col.includeIn = $.map( breakpoints, function (a) {
15679 return a.name;
15680 } );
15681 return;
15682 }
15683 else if ( className === 'none' || col.never ) {
15684 // Include in none (default) and no auto
15685 hasClass = true;
15686 return;
15687 }
15688 else if ( className === 'control' ) {
15689 // Special column that is only visible, when one of the other
15690 // columns is hidden. This is used for the details control
15691 hasClass = true;
15692 col.control = true;
15693 return;
15694 }
15695
15696 $.each( breakpoints, function ( j, breakpoint ) {
15697 // Does this column have a class that matches this breakpoint?
15698 var brokenPoint = breakpoint.name.split('-');
15699 var re = new RegExp( '(min\\-|max\\-|not\\-)?('+brokenPoint[0]+')(\\-[_a-zA-Z0-9])?' );
15700 var match = className.match( re );
15701
15702 if ( match ) {
15703 hasClass = true;
15704
15705 if ( match[2] === brokenPoint[0] && match[3] === '-'+brokenPoint[1] ) {
15706 // Class name matches breakpoint name fully
15707 column( i, breakpoint.name, match[1], match[2]+match[3] );
15708 }
15709 else if ( match[2] === brokenPoint[0] && ! match[3] ) {
15710 // Class name matched primary breakpoint name with no qualifier
15711 column( i, breakpoint.name, match[1], match[2] );
15712 }
15713 }
15714 } );
15715 }
15716
15717 // If there was no control class, then automatic sizing is used
15718 if ( ! hasClass ) {
15719 col.auto = true;
15720 }
15721 } );
15722
15723 this.s.columns = columns;
15724 },
15725
15726
15727 /**
15728 * Show the details for the child row
15729 *
15730 * @param {DataTables.Api} row API instance for the row
15731 * @param {boolean} update Update flag
15732 * @private
15733 */
15734 _detailsDisplay: function ( row, update )
15735 {
15736 var that = this;
15737 var dt = this.s.dt;
15738
15739 var res = this.c.details.display( row, update, function () {
15740 return that.c.details.renderer(
15741 dt, row[0], that._detailsObj(row[0])
15742 );
15743 } );
15744
15745 if ( res === true || res === false ) {
15746 $(dt.table().node()).triggerHandler( 'responsive-display.dt', [dt, row, res, update] );
15747 }
15748 },
15749
15750
15751 /**
15752 * Initialisation for the details handler
15753 *
15754 * @private
15755 */
15756 _detailsInit: function ()
15757 {
15758 var that = this;
15759 var dt = this.s.dt;
15760 var details = this.c.details;
15761
15762 // The inline type always uses the first child as the target
15763 if ( details.type === 'inline' ) {
15764 details.target = 'td:first-child';
15765 }
15766
15767 // Keyboard accessibility
15768 dt.on( 'draw.dtr', function () {
15769 that._tabIndexes();
15770 } );
15771 that._tabIndexes(); // Initial draw has already happened
15772
15773 $( dt.table().body() ).on( 'keyup.dtr', 'td', function (e) {
15774 if ( e.keyCode === 13 && $(this).data('dtr-keyboard') ) {
15775 $(this).click();
15776 }
15777 } );
15778
15779 // type.target can be a string jQuery selector or a column index
15780 var target = details.target;
15781 var selector = typeof target === 'string' ? target : 'td';
15782
15783 // Click handler to show / hide the details rows when they are available
15784 $( dt.table().body() )
15785 .on( 'mousedown.dtr', selector, function (e) {
15786 // For mouse users, prevent the focus ring from showing
15787 e.preventDefault();
15788 } )
15789 .on( 'click.dtr', selector, function () {
15790 // If the table is not collapsed (i.e. there is no hidden columns)
15791 // then take no action
15792 if ( ! $(dt.table().node()).hasClass('collapsed' ) ) {
15793 return;
15794 }
15795
15796 // Check that the row is actually a DataTable's controlled node
15797 if ( ! dt.row( $(this).closest('tr') ).length ) {
15798 return;
15799 }
15800
15801 // For column index, we determine if we should act or not in the
15802 // handler - otherwise it is already okay
15803 if ( typeof target === 'number' ) {
15804 var targetIdx = target < 0 ?
15805 dt.columns().eq(0).length + target :
15806 target;
15807
15808 if ( dt.cell( this ).index().column !== targetIdx ) {
15809 return;
15810 }
15811 }
15812
15813 // $().closest() includes itself in its check
15814 var row = dt.row( $(this).closest('tr') );
15815
15816 // The renderer is given as a function so the caller can execute it
15817 // only when they need (i.e. if hiding there is no point is running
15818 // the renderer)
15819 that._detailsDisplay( row, false );
15820 } );
15821 },
15822
15823
15824 /**
15825 * Get the details to pass to a renderer for a row
15826 * @param {int} rowIdx Row index
15827 * @private
15828 */
15829 _detailsObj: function ( rowIdx )
15830 {
15831 var that = this;
15832 var dt = this.s.dt;
15833
15834 return $.map( this.s.columns, function( col, i ) {
15835 if ( col.never ) {
15836 return;
15837 }
15838
15839 return {
15840 title: dt.settings()[0].aoColumns[ i ].sTitle,
15841 data: dt.cell( rowIdx, i ).render( that.c.orthogonal ),
15842 hidden: dt.column( i ).visible() && !that.s.current[ i ]
15843 };
15844 } );
15845 },
15846
15847
15848 /**
15849 * Find a breakpoint object from a name
15850 *
15851 * @param {string} name Breakpoint name to find
15852 * @return {object} Breakpoint description object
15853 * @private
15854 */
15855 _find: function ( name )
15856 {
15857 var breakpoints = this.c.breakpoints;
15858
15859 for ( var i=0, ien=breakpoints.length ; i<ien ; i++ ) {
15860 if ( breakpoints[i].name === name ) {
15861 return breakpoints[i];
15862 }
15863 }
15864 },
15865
15866
15867 /**
15868 * Re-create the contents of the child rows as the display has changed in
15869 * some way.
15870 *
15871 * @private
15872 */
15873 _redrawChildren: function ()
15874 {
15875 var that = this;
15876 var dt = this.s.dt;
15877
15878 dt.rows( {page: 'current'} ).iterator( 'row', function ( settings, idx ) {
15879 var row = dt.row( idx );
15880
15881 that._detailsDisplay( dt.row( idx ), true );
15882 } );
15883 },
15884
15885
15886 /**
15887 * Alter the table display for a resized viewport. This involves first
15888 * determining what breakpoint the window currently is in, getting the
15889 * column visibilities to apply and then setting them.
15890 *
15891 * @private
15892 */
15893 _resize: function ()
15894 {
15895 var that = this;
15896 var dt = this.s.dt;
15897 var width = $(window).width();
15898 var breakpoints = this.c.breakpoints;
15899 var breakpoint = breakpoints[0].name;
15900 var columns = this.s.columns;
15901 var i, ien;
15902 var oldVis = this.s.current.slice();
15903
15904 // Determine what breakpoint we are currently at
15905 for ( i=breakpoints.length-1 ; i>=0 ; i-- ) {
15906 if ( width <= breakpoints[i].width ) {
15907 breakpoint = breakpoints[i].name;
15908 break;
15909 }
15910 }
15911
15912 // Show the columns for that break point
15913 var columnsVis = this._columnsVisiblity( breakpoint );
15914 this.s.current = columnsVis;
15915
15916 // Set the class before the column visibility is changed so event
15917 // listeners know what the state is. Need to determine if there are
15918 // any columns that are not visible but can be shown
15919 var collapsedClass = false;
15920 for ( i=0, ien=columns.length ; i<ien ; i++ ) {
15921 if ( columnsVis[i] === false && ! columns[i].never ) {
15922 collapsedClass = true;
15923 break;
15924 }
15925 }
15926
15927 $( dt.table().node() ).toggleClass( 'collapsed', collapsedClass );
15928
15929 var changed = false;
15930
15931 dt.columns().eq(0).each( function ( colIdx, i ) {
15932 if ( columnsVis[i] !== oldVis[i] ) {
15933 changed = true;
15934 that._setColumnVis( colIdx, columnsVis[i] );
15935 }
15936 } );
15937
15938 if ( changed ) {
15939 this._redrawChildren();
15940 }
15941 },
15942
15943
15944 /**
15945 * Determine the width of each column in the table so the auto column hiding
15946 * has that information to work with. This method is never going to be 100%
15947 * perfect since column widths can change slightly per page, but without
15948 * seriously compromising performance this is quite effective.
15949 *
15950 * @private
15951 */
15952 _resizeAuto: function ()
15953 {
15954 var dt = this.s.dt;
15955 var columns = this.s.columns;
15956
15957 // Are we allowed to do auto sizing?
15958 if ( ! this.c.auto ) {
15959 return;
15960 }
15961
15962 // Are there any columns that actually need auto-sizing, or do they all
15963 // have classes defined
15964 if ( $.inArray( true, $.map( columns, function (c) { return c.auto; } ) ) === -1 ) {
15965 return;
15966 }
15967
15968 // Clone the table with the current data in it
15969 var tableWidth = dt.table().node().offsetWidth;
15970 var columnWidths = dt.columns;
15971 var clonedTable = dt.table().node().cloneNode( false );
15972 var clonedHeader = $( dt.table().header().cloneNode( false ) ).appendTo( clonedTable );
15973 var clonedBody = $( dt.table().body().cloneNode( false ) ).appendTo( clonedTable );
15974
15975 // Header
15976 var headerCells = dt.columns()
15977 .header()
15978 .filter( function (idx) {
15979 return dt.column(idx).visible();
15980 } )
15981 .to$()
15982 .clone( false )
15983 .css( 'display', 'table-cell' );
15984
15985 // Body rows - we don't need to take account of DataTables' column
15986 // visibility since we implement our own here (hence the `display` set)
15987 $(clonedBody)
15988 .append( $(dt.rows( { page: 'current' } ).nodes()).clone( false ) )
15989 .find( 'th, td' ).css( 'display', '' );
15990
15991 // Footer
15992 var footer = dt.table().footer();
15993 if ( footer ) {
15994 var clonedFooter = $( footer.cloneNode( false ) ).appendTo( clonedTable );
15995 var footerCells = dt.columns()
15996 .header()
15997 .filter( function (idx) {
15998 return dt.column(idx).visible();
15999 } )
16000 .to$()
16001 .clone( false )
16002 .css( 'display', 'table-cell' );
16003
16004 $('<tr/>')
16005 .append( footerCells )
16006 .appendTo( clonedFooter );
16007 }
16008
16009 $('<tr/>')
16010 .append( headerCells )
16011 .appendTo( clonedHeader );
16012
16013 // In the inline case extra padding is applied to the first column to
16014 // give space for the show / hide icon. We need to use this in the
16015 // calculation
16016 if ( this.c.details.type === 'inline' ) {
16017 $(clonedTable).addClass( 'dtr-inline collapsed' );
16018 }
16019
16020 var inserted = $('<div/>')
16021 .css( {
16022 width: 1,
16023 height: 1,
16024 overflow: 'hidden'
16025 } )
16026 .append( clonedTable );
16027
16028 inserted.insertBefore( dt.table().node() );
16029
16030 // The cloned header now contains the smallest that each column can be
16031 headerCells.each( function (i) {
16032 var idx = dt.column.index( 'fromVisible', i );
16033 columns[ idx ].minWidth = this.offsetWidth || 0;
16034 } );
16035
16036 inserted.remove();
16037 },
16038
16039 /**
16040 * Set a column's visibility.
16041 *
16042 * We don't use DataTables' column visibility controls in order to ensure
16043 * that column visibility can Responsive can no-exist. Since only IE8+ is
16044 * supported (and all evergreen browsers of course) the control of the
16045 * display attribute works well.
16046 *
16047 * @param {integer} col Column index
16048 * @param {boolean} showHide Show or hide (true or false)
16049 * @private
16050 */
16051 _setColumnVis: function ( col, showHide )
16052 {
16053 var dt = this.s.dt;
16054 var display = showHide ? '' : 'none'; // empty string will remove the attr
16055
16056 $( dt.column( col ).header() ).css( 'display', display );
16057 $( dt.column( col ).footer() ).css( 'display', display );
16058 dt.column( col ).nodes().to$().css( 'display', display );
16059 },
16060
16061
16062 /**
16063 * Update the cell tab indexes for keyboard accessibility. This is called on
16064 * every table draw - that is potentially inefficient, but also the least
16065 * complex option given that column visibility can change on the fly. Its a
16066 * shame user-focus was removed from CSS 3 UI, as it would have solved this
16067 * issue with a single CSS statement.
16068 *
16069 * @private
16070 */
16071 _tabIndexes: function ()
16072 {
16073 var dt = this.s.dt;
16074 var cells = dt.cells( { page: 'current' } ).nodes().to$();
16075 var ctx = dt.settings()[0];
16076 var target = this.c.details.target;
16077
16078 cells.filter( '[data-dtr-keyboard]' ).removeData( '[data-dtr-keyboard]' );
16079
16080 var selector = typeof target === 'number' ?
16081 ':eq('+target+')' :
16082 target;
16083
16084 $( selector, dt.rows( { page: 'current' } ).nodes() )
16085 .attr( 'tabIndex', ctx.iTabIndex )
16086 .data( 'dtr-keyboard', 1 );
16087 }
16088 } );
16089
16090
16091 /**
16092 * List of default breakpoints. Each item in the array is an object with two
16093 * properties:
16094 *
16095 * * `name` - the breakpoint name.
16096 * * `width` - the breakpoint width
16097 *
16098 * @name Responsive.breakpoints
16099 * @static
16100 */
16101 Responsive.breakpoints = [
16102 { name: 'desktop', width: Infinity },
16103 { name: 'tablet-l', width: 1024 },
16104 { name: 'tablet-p', width: 768 },
16105 { name: 'mobile-l', width: 480 },
16106 { name: 'mobile-p', width: 320 }
16107 ];
16108
16109
16110 /**
16111 * Display methods - functions which define how the hidden data should be shown
16112 * in the table.
16113 *
16114 * @namespace
16115 * @name Responsive.defaults
16116 * @static
16117 */
16118 Responsive.display = {
16119 childRow: function ( row, update, render ) {
16120 if ( update ) {
16121 if ( $(row.node()).hasClass('parent') ) {
16122 row.child( render(), 'child' ).show();
16123
16124 return true;
16125 }
16126 }
16127 else {
16128 if ( ! row.child.isShown() ) {
16129 row.child( render(), 'child' ).show();
16130 $( row.node() ).addClass( 'parent' );
16131
16132 return true;
16133 }
16134 else {
16135 row.child( false );
16136 $( row.node() ).removeClass( 'parent' );
16137
16138 return false;
16139 }
16140 }
16141 },
16142
16143 childRowImmediate: function ( row, update, render ) {
16144 if ( (! update && row.child.isShown()) || ! row.responsive.hasHidden() ) {
16145 // User interaction and the row is show, or nothing to show
16146 row.child( false );
16147 $( row.node() ).removeClass( 'parent' );
16148
16149 return false;
16150 }
16151 else {
16152 // Display
16153 row.child( render(), 'child' ).show();
16154 $( row.node() ).addClass( 'parent' );
16155
16156 return true;
16157 }
16158 },
16159
16160 // This is a wrapper so the modal options for Bootstrap and jQuery UI can
16161 // have options passed into them. This specific one doesn't need to be a
16162 // function but it is for consistency in the `modal` name
16163 modal: function ( options ) {
16164 return function ( row, update, render ) {
16165 if ( ! update ) {
16166 // Show a modal
16167 var close = function () {
16168 modal.remove(); // will tidy events for us
16169 $(document).off( 'keypress.dtr' );
16170 };
16171
16172 var modal = $('<div class="dtr-modal"/>')
16173 .append( $('<div class="dtr-modal-display"/>')
16174 .append( $('<div class="dtr-modal-content"/>')
16175 .append( render() )
16176 )
16177 .append( $('<div class="dtr-modal-close">&times;</div>' )
16178 .click( function () {
16179 close();
16180 } )
16181 )
16182 )
16183 .append( $('<div class="dtr-modal-background"/>')
16184 .click( function () {
16185 close();
16186 } )
16187 )
16188 .appendTo( 'body' );
16189
16190 if ( options && options.header ) {
16191 modal.find( 'div.dtr-modal-content' ).prepend(
16192 '<h2>'+options.header( row )+'</h2>'
16193 );
16194 }
16195
16196 $(document).on( 'keyup.dtr', function (e) {
16197 if ( e.keyCode === 27 ) {
16198 e.stopPropagation();
16199
16200 close();
16201 }
16202 } );
16203 }
16204 else {
16205 $('div.dtr-modal-content')
16206 .empty()
16207 .append( render() );
16208 }
16209 };
16210 }
16211 };
16212
16213
16214 /**
16215 * Responsive default settings for initialisation
16216 *
16217 * @namespace
16218 * @name Responsive.defaults
16219 * @static
16220 */
16221 Responsive.defaults = {
16222 /**
16223 * List of breakpoints for the instance. Note that this means that each
16224 * instance can have its own breakpoints. Additionally, the breakpoints
16225 * cannot be changed once an instance has been creased.
16226 *
16227 * @type {Array}
16228 * @default Takes the value of `Responsive.breakpoints`
16229 */
16230 breakpoints: Responsive.breakpoints,
16231
16232 /**
16233 * Enable / disable auto hiding calculations. It can help to increase
16234 * performance slightly if you disable this option, but all columns would
16235 * need to have breakpoint classes assigned to them
16236 *
16237 * @type {Boolean}
16238 * @default `true`
16239 */
16240 auto: true,
16241
16242 /**
16243 * Details control. If given as a string value, the `type` property of the
16244 * default object is set to that value, and the defaults used for the rest
16245 * of the object - this is for ease of implementation.
16246 *
16247 * The object consists of the following properties:
16248 *
16249 * * `display` - A function that is used to show and hide the hidden details
16250 * * `renderer` - function that is called for display of the child row data.
16251 * The default function will show the data from the hidden columns
16252 * * `target` - Used as the selector for what objects to attach the child
16253 * open / close to
16254 * * `type` - `false` to disable the details display, `inline` or `column`
16255 * for the two control types
16256 *
16257 * @type {Object|string}
16258 */
16259 details: {
16260 display: Responsive.display.childRow,
16261
16262 renderer: function ( api, rowIdx, columns ) {
16263 var data = $.map( columns, function ( col, i ) {
16264 return col.hidden ?
16265 '<li data-dtr-index="'+i+'">'+
16266 '<span class="dtr-title">'+
16267 col.title+
16268 '</span> '+
16269 '<span class="dtr-data">'+
16270 col.data+
16271 '</span>'+
16272 '</li>' :
16273 '';
16274 } ).join('');
16275
16276 return data ?
16277 $('<ul data-dtr-index="'+rowIdx+'"/>').append( data ) :
16278 false;
16279 },
16280
16281 target: 0,
16282
16283 type: 'inline'
16284 },
16285
16286 /**
16287 * Orthogonal data request option. This is used to define the data type
16288 * requested when Responsive gets the data to show in the child row.
16289 *
16290 * @type {String}
16291 */
16292 orthogonal: 'display'
16293 };
16294
16295
16296 /*
16297 * API
16298 */
16299 var Api = $.fn.dataTable.Api;
16300
16301 // Doesn't do anything - work around for a bug in DT... Not documented
16302 Api.register( 'responsive()', function () {
16303 return this;
16304 } );
16305
16306 Api.register( 'responsive.index()', function ( li ) {
16307 li = $(li);
16308
16309 return {
16310 column: li.data('dtr-index'),
16311 row: li.parent().data('dtr-index')
16312 };
16313 } );
16314
16315 Api.register( 'responsive.rebuild()', function () {
16316 return this.iterator( 'table', function ( ctx ) {
16317 if ( ctx._responsive ) {
16318 ctx._responsive._classLogic();
16319 }
16320 } );
16321 } );
16322
16323 Api.register( 'responsive.recalc()', function () {
16324 return this.iterator( 'table', function ( ctx ) {
16325 if ( ctx._responsive ) {
16326 ctx._responsive._resizeAuto();
16327 ctx._responsive._resize();
16328 }
16329 } );
16330 } );
16331
16332 Api.register( 'responsive.hasHidden()', function () {
16333 var ctx = this.context[0];
16334
16335 return ctx._responsive ?
16336 $.inArray( false, ctx._responsive.s.current ) !== -1 :
16337 false;
16338 } );
16339
16340
16341 /**
16342 * Version information
16343 *
16344 * @name Responsive.version
16345 * @static
16346 */
16347 Responsive.version = '2.0.0';
16348
16349
16350 $.fn.dataTable.Responsive = Responsive;
16351 $.fn.DataTable.Responsive = Responsive;
16352
16353 // Attach a listener to the document which listens for DataTables initialisation
16354 // events so we can automatically initialise
16355 $(document).on( 'init.dt.dtr', function (e, settings, json) {
16356 if ( e.namespace !== 'dt' ) {
16357 return;
16358 }
16359
16360 if ( $(settings.nTable).hasClass( 'responsive' ) ||
16361 $(settings.nTable).hasClass( 'dt-responsive' ) ||
16362 settings.oInit.responsive ||
16363 DataTable.defaults.responsive
16364 ) {
16365 var init = settings.oInit.responsive;
16366
16367 if ( init !== false ) {
16368 new Responsive( settings, $.isPlainObject( init ) ? init : {} );
16369 }
16370 }
16371 } );
16372
16373
16374 return Responsive;
16375 }));
16376
16377
16378