blob: e1376d93257d2f853ad57117d3d4213cdf6ee125 [file] [log] [blame]
Copybara botbe50d492023-11-30 00:16:42 +01001/*! DataTables 1.10.18
2 * ©2008-2018 SpryMedia Ltd - datatables.net/license
3 */
4
5/**
6 * @summary DataTables
7 * @description Paginate, search and order HTML tables
8 * @version 1.10.18
9 * @file jquery.dataTables.js
10 * @author SpryMedia Ltd
11 * @contact www.datatables.net
12 * @copyright Copyright 2008-2018 SpryMedia Ltd.
13 *
14 * This source file is free software, available under the following license:
15 * MIT license - http://datatables.net/license
16 *
17 * This source file is distributed in the hope that it will be useful, but
18 * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
19 * or FITNESS FOR A PARTICULAR PURPOSE. See the license files for details.
20 *
21 * For details please refer to: http://www.datatables.net
22 */
23
24/*jslint evil: true, undef: true, browser: true */
25/*globals $,require,jQuery,define,_selector_run,_selector_opts,_selector_first,_selector_row_indexes,_ext,_Api,_api_register,_api_registerPlural,_re_new_lines,_re_html,_re_formatted_numeric,_re_escape_regex,_empty,_intVal,_numToDecimal,_isNumber,_isHtml,_htmlNumeric,_pluck,_pluck_order,_range,_stripHtml,_unique,_fnBuildAjax,_fnAjaxUpdate,_fnAjaxParameters,_fnAjaxUpdateDraw,_fnAjaxDataSrc,_fnAddColumn,_fnColumnOptions,_fnAdjustColumnSizing,_fnVisibleToColumnIndex,_fnColumnIndexToVisible,_fnVisbleColumns,_fnGetColumns,_fnColumnTypes,_fnApplyColumnDefs,_fnHungarianMap,_fnCamelToHungarian,_fnLanguageCompat,_fnBrowserDetect,_fnAddData,_fnAddTr,_fnNodeToDataIndex,_fnNodeToColumnIndex,_fnGetCellData,_fnSetCellData,_fnSplitObjNotation,_fnGetObjectDataFn,_fnSetObjectDataFn,_fnGetDataMaster,_fnClearTable,_fnDeleteIndex,_fnInvalidate,_fnGetRowElements,_fnCreateTr,_fnBuildHead,_fnDrawHead,_fnDraw,_fnReDraw,_fnAddOptionsHtml,_fnDetectHeader,_fnGetUniqueThs,_fnFeatureHtmlFilter,_fnFilterComplete,_fnFilterCustom,_fnFilterColumn,_fnFilter,_fnFilterCreateSearch,_fnEscapeRegex,_fnFilterData,_fnFeatureHtmlInfo,_fnUpdateInfo,_fnInfoMacros,_fnInitialise,_fnInitComplete,_fnLengthChange,_fnFeatureHtmlLength,_fnFeatureHtmlPaginate,_fnPageChange,_fnFeatureHtmlProcessing,_fnProcessingDisplay,_fnFeatureHtmlTable,_fnScrollDraw,_fnApplyToChildren,_fnCalculateColumnWidths,_fnThrottle,_fnConvertToWidth,_fnGetWidestNode,_fnGetMaxLenString,_fnStringToCss,_fnSortFlatten,_fnSort,_fnSortAria,_fnSortListener,_fnSortAttachListener,_fnSortingClasses,_fnSortData,_fnSaveState,_fnLoadState,_fnSettingsFromNode,_fnLog,_fnMap,_fnBindAction,_fnCallbackReg,_fnCallbackFire,_fnLengthOverflow,_fnRenderer,_fnDataSource,_fnRowAttributes*/
26
27(function( factory ) {
28 "use strict";
29
30 if ( typeof define === 'function' && define.amd ) {
31 // AMD
32 define( ['jquery'], function ( $ ) {
33 return factory( $, window, document );
34 } );
35 }
36 else if ( typeof exports === 'object' ) {
37 // CommonJS
38 module.exports = function (root, $) {
39 if ( ! root ) {
40 // CommonJS environments without a window global must pass a
41 // root. This will give an error otherwise
42 root = window;
43 }
44
45 if ( ! $ ) {
46 $ = typeof window !== 'undefined' ? // jQuery's factory checks for a global window
47 require('jquery') :
48 require('jquery')( root );
49 }
50
51 return factory( $, root, root.document );
52 };
53 }
54 else {
55 // Browser
56 factory( jQuery, window, document );
57 }
58}
59(function( $, window, document, undefined ) {
60 "use strict";
61
62 /**
63 * DataTables is a plug-in for the jQuery Javascript library. It is a highly
64 * flexible tool, based upon the foundations of progressive enhancement,
65 * which will add advanced interaction controls to any HTML table. For a
66 * full list of features please refer to
67 * [DataTables.net](href="http://datatables.net).
68 *
69 * Note that the `DataTable` object is not a global variable but is aliased
70 * to `jQuery.fn.DataTable` and `jQuery.fn.dataTable` through which it may
71 * be accessed.
72 *
73 * @class
74 * @param {object} [init={}] Configuration object for DataTables. Options
75 * are defined by {@link DataTable.defaults}
76 * @requires jQuery 1.7+
77 *
78 * @example
79 * // Basic initialisation
80 * $(document).ready( function {
81 * $('#example').dataTable();
82 * } );
83 *
84 * @example
85 * // Initialisation with configuration options - in this case, disable
86 * // pagination and sorting.
87 * $(document).ready( function {
88 * $('#example').dataTable( {
89 * "paginate": false,
90 * "sort": false
91 * } );
92 * } );
93 */
94 var DataTable = function ( options )
95 {
96 /**
97 * Perform a jQuery selector action on the table's TR elements (from the tbody) and
98 * return the resulting jQuery object.
99 * @param {string|node|jQuery} sSelector jQuery selector or node collection to act on
100 * @param {object} [oOpts] Optional parameters for modifying the rows to be included
101 * @param {string} [oOpts.filter=none] Select TR elements that meet the current filter
102 * criterion ("applied") or all TR elements (i.e. no filter).
103 * @param {string} [oOpts.order=current] Order of the TR elements in the processed array.
104 * Can be either 'current', whereby the current sorting of the table is used, or
105 * 'original' whereby the original order the data was read into the table is used.
106 * @param {string} [oOpts.page=all] Limit the selection to the currently displayed page
107 * ("current") or not ("all"). If 'current' is given, then order is assumed to be
108 * 'current' and filter is 'applied', regardless of what they might be given as.
109 * @returns {object} jQuery object, filtered by the given selector.
110 * @dtopt API
111 * @deprecated Since v1.10
112 *
113 * @example
114 * $(document).ready(function() {
115 * var oTable = $('#example').dataTable();
116 *
117 * // Highlight every second row
118 * oTable.$('tr:odd').css('backgroundColor', 'blue');
119 * } );
120 *
121 * @example
122 * $(document).ready(function() {
123 * var oTable = $('#example').dataTable();
124 *
125 * // Filter to rows with 'Webkit' in them, add a background colour and then
126 * // remove the filter, thus highlighting the 'Webkit' rows only.
127 * oTable.fnFilter('Webkit');
128 * oTable.$('tr', {"search": "applied"}).css('backgroundColor', 'blue');
129 * oTable.fnFilter('');
130 * } );
131 */
132 this.$ = function ( sSelector, oOpts )
133 {
134 return this.api(true).$( sSelector, oOpts );
135 };
136
137
138 /**
139 * Almost identical to $ in operation, but in this case returns the data for the matched
140 * rows - as such, the jQuery selector used should match TR row nodes or TD/TH cell nodes
141 * rather than any descendants, so the data can be obtained for the row/cell. If matching
142 * rows are found, the data returned is the original data array/object that was used to
143 * create the row (or a generated array if from a DOM source).
144 *
145 * This method is often useful in-combination with $ where both functions are given the
146 * same parameters and the array indexes will match identically.
147 * @param {string|node|jQuery} sSelector jQuery selector or node collection to act on
148 * @param {object} [oOpts] Optional parameters for modifying the rows to be included
149 * @param {string} [oOpts.filter=none] Select elements that meet the current filter
150 * criterion ("applied") or all elements (i.e. no filter).
151 * @param {string} [oOpts.order=current] Order of the data in the processed array.
152 * Can be either 'current', whereby the current sorting of the table is used, or
153 * 'original' whereby the original order the data was read into the table is used.
154 * @param {string} [oOpts.page=all] Limit the selection to the currently displayed page
155 * ("current") or not ("all"). If 'current' is given, then order is assumed to be
156 * 'current' and filter is 'applied', regardless of what they might be given as.
157 * @returns {array} Data for the matched elements. If any elements, as a result of the
158 * selector, were not TR, TD or TH elements in the DataTable, they will have a null
159 * entry in the array.
160 * @dtopt API
161 * @deprecated Since v1.10
162 *
163 * @example
164 * $(document).ready(function() {
165 * var oTable = $('#example').dataTable();
166 *
167 * // Get the data from the first row in the table
168 * var data = oTable._('tr:first');
169 *
170 * // Do something useful with the data
171 * alert( "First cell is: "+data[0] );
172 * } );
173 *
174 * @example
175 * $(document).ready(function() {
176 * var oTable = $('#example').dataTable();
177 *
178 * // Filter to 'Webkit' and get all data for
179 * oTable.fnFilter('Webkit');
180 * var data = oTable._('tr', {"search": "applied"});
181 *
182 * // Do something with the data
183 * alert( data.length+" rows matched the search" );
184 * } );
185 */
186 this._ = function ( sSelector, oOpts )
187 {
188 return this.api(true).rows( sSelector, oOpts ).data();
189 };
190
191
192 /**
193 * Create a DataTables Api instance, with the currently selected tables for
194 * the Api's context.
195 * @param {boolean} [traditional=false] Set the API instance's context to be
196 * only the table referred to by the `DataTable.ext.iApiIndex` option, as was
197 * used in the API presented by DataTables 1.9- (i.e. the traditional mode),
198 * or if all tables captured in the jQuery object should be used.
199 * @return {DataTables.Api}
200 */
201 this.api = function ( traditional )
202 {
203 return traditional ?
204 new _Api(
205 _fnSettingsFromNode( this[ _ext.iApiIndex ] )
206 ) :
207 new _Api( this );
208 };
209
210
211 /**
212 * Add a single new row or multiple rows of data to the table. Please note
213 * that this is suitable for client-side processing only - if you are using
214 * server-side processing (i.e. "bServerSide": true), then to add data, you
215 * must add it to the data source, i.e. the server-side, through an Ajax call.
216 * @param {array|object} data The data to be added to the table. This can be:
217 * <ul>
218 * <li>1D array of data - add a single row with the data provided</li>
219 * <li>2D array of arrays - add multiple rows in a single call</li>
220 * <li>object - data object when using <i>mData</i></li>
221 * <li>array of objects - multiple data objects when using <i>mData</i></li>
222 * </ul>
223 * @param {bool} [redraw=true] redraw the table or not
224 * @returns {array} An array of integers, representing the list of indexes in
225 * <i>aoData</i> ({@link DataTable.models.oSettings}) that have been added to
226 * the table.
227 * @dtopt API
228 * @deprecated Since v1.10
229 *
230 * @example
231 * // Global var for counter
232 * var giCount = 2;
233 *
234 * $(document).ready(function() {
235 * $('#example').dataTable();
236 * } );
237 *
238 * function fnClickAddRow() {
239 * $('#example').dataTable().fnAddData( [
240 * giCount+".1",
241 * giCount+".2",
242 * giCount+".3",
243 * giCount+".4" ]
244 * );
245 *
246 * giCount++;
247 * }
248 */
249 this.fnAddData = function( data, redraw )
250 {
251 var api = this.api( true );
252
253 /* Check if we want to add multiple rows or not */
254 var rows = $.isArray(data) && ( $.isArray(data[0]) || $.isPlainObject(data[0]) ) ?
255 api.rows.add( data ) :
256 api.row.add( data );
257
258 if ( redraw === undefined || redraw ) {
259 api.draw();
260 }
261
262 return rows.flatten().toArray();
263 };
264
265
266 /**
267 * This function will make DataTables recalculate the column sizes, based on the data
268 * contained in the table and the sizes applied to the columns (in the DOM, CSS or
269 * through the sWidth parameter). This can be useful when the width of the table's
270 * parent element changes (for example a window resize).
271 * @param {boolean} [bRedraw=true] Redraw the table or not, you will typically want to
272 * @dtopt API
273 * @deprecated Since v1.10
274 *
275 * @example
276 * $(document).ready(function() {
277 * var oTable = $('#example').dataTable( {
278 * "sScrollY": "200px",
279 * "bPaginate": false
280 * } );
281 *
282 * $(window).on('resize', function () {
283 * oTable.fnAdjustColumnSizing();
284 * } );
285 * } );
286 */
287 this.fnAdjustColumnSizing = function ( bRedraw )
288 {
289 var api = this.api( true ).columns.adjust();
290 var settings = api.settings()[0];
291 var scroll = settings.oScroll;
292
293 if ( bRedraw === undefined || bRedraw ) {
294 api.draw( false );
295 }
296 else if ( scroll.sX !== "" || scroll.sY !== "" ) {
297 /* If not redrawing, but scrolling, we want to apply the new column sizes anyway */
298 _fnScrollDraw( settings );
299 }
300 };
301
302
303 /**
304 * Quickly and simply clear a table
305 * @param {bool} [bRedraw=true] redraw the table or not
306 * @dtopt API
307 * @deprecated Since v1.10
308 *
309 * @example
310 * $(document).ready(function() {
311 * var oTable = $('#example').dataTable();
312 *
313 * // Immediately 'nuke' the current rows (perhaps waiting for an Ajax callback...)
314 * oTable.fnClearTable();
315 * } );
316 */
317 this.fnClearTable = function( bRedraw )
318 {
319 var api = this.api( true ).clear();
320
321 if ( bRedraw === undefined || bRedraw ) {
322 api.draw();
323 }
324 };
325
326
327 /**
328 * The exact opposite of 'opening' a row, this function will close any rows which
329 * are currently 'open'.
330 * @param {node} nTr the table row to 'close'
331 * @returns {int} 0 on success, or 1 if failed (can't find the row)
332 * @dtopt API
333 * @deprecated Since v1.10
334 *
335 * @example
336 * $(document).ready(function() {
337 * var oTable;
338 *
339 * // 'open' an information row when a row is clicked on
340 * $('#example tbody tr').click( function () {
341 * if ( oTable.fnIsOpen(this) ) {
342 * oTable.fnClose( this );
343 * } else {
344 * oTable.fnOpen( this, "Temporary row opened", "info_row" );
345 * }
346 * } );
347 *
348 * oTable = $('#example').dataTable();
349 * } );
350 */
351 this.fnClose = function( nTr )
352 {
353 this.api( true ).row( nTr ).child.hide();
354 };
355
356
357 /**
358 * Remove a row for the table
359 * @param {mixed} target The index of the row from aoData to be deleted, or
360 * the TR element you want to delete
361 * @param {function|null} [callBack] Callback function
362 * @param {bool} [redraw=true] Redraw the table or not
363 * @returns {array} The row that was deleted
364 * @dtopt API
365 * @deprecated Since v1.10
366 *
367 * @example
368 * $(document).ready(function() {
369 * var oTable = $('#example').dataTable();
370 *
371 * // Immediately remove the first row
372 * oTable.fnDeleteRow( 0 );
373 * } );
374 */
375 this.fnDeleteRow = function( target, callback, redraw )
376 {
377 var api = this.api( true );
378 var rows = api.rows( target );
379 var settings = rows.settings()[0];
380 var data = settings.aoData[ rows[0][0] ];
381
382 rows.remove();
383
384 if ( callback ) {
385 callback.call( this, settings, data );
386 }
387
388 if ( redraw === undefined || redraw ) {
389 api.draw();
390 }
391
392 return data;
393 };
394
395
396 /**
397 * Restore the table to it's original state in the DOM by removing all of DataTables
398 * enhancements, alterations to the DOM structure of the table and event listeners.
399 * @param {boolean} [remove=false] Completely remove the table from the DOM
400 * @dtopt API
401 * @deprecated Since v1.10
402 *
403 * @example
404 * $(document).ready(function() {
405 * // This example is fairly pointless in reality, but shows how fnDestroy can be used
406 * var oTable = $('#example').dataTable();
407 * oTable.fnDestroy();
408 * } );
409 */
410 this.fnDestroy = function ( remove )
411 {
412 this.api( true ).destroy( remove );
413 };
414
415
416 /**
417 * Redraw the table
418 * @param {bool} [complete=true] Re-filter and resort (if enabled) the table before the draw.
419 * @dtopt API
420 * @deprecated Since v1.10
421 *
422 * @example
423 * $(document).ready(function() {
424 * var oTable = $('#example').dataTable();
425 *
426 * // Re-draw the table - you wouldn't want to do it here, but it's an example :-)
427 * oTable.fnDraw();
428 * } );
429 */
430 this.fnDraw = function( complete )
431 {
432 // Note that this isn't an exact match to the old call to _fnDraw - it takes
433 // into account the new data, but can hold position.
434 this.api( true ).draw( complete );
435 };
436
437
438 /**
439 * Filter the input based on data
440 * @param {string} sInput String to filter the table on
441 * @param {int|null} [iColumn] Column to limit filtering to
442 * @param {bool} [bRegex=false] Treat as regular expression or not
443 * @param {bool} [bSmart=true] Perform smart filtering or not
444 * @param {bool} [bShowGlobal=true] Show the input global filter in it's input box(es)
445 * @param {bool} [bCaseInsensitive=true] Do case-insensitive matching (true) or not (false)
446 * @dtopt API
447 * @deprecated Since v1.10
448 *
449 * @example
450 * $(document).ready(function() {
451 * var oTable = $('#example').dataTable();
452 *
453 * // Sometime later - filter...
454 * oTable.fnFilter( 'test string' );
455 * } );
456 */
457 this.fnFilter = function( sInput, iColumn, bRegex, bSmart, bShowGlobal, bCaseInsensitive )
458 {
459 var api = this.api( true );
460
461 if ( iColumn === null || iColumn === undefined ) {
462 api.search( sInput, bRegex, bSmart, bCaseInsensitive );
463 }
464 else {
465 api.column( iColumn ).search( sInput, bRegex, bSmart, bCaseInsensitive );
466 }
467
468 api.draw();
469 };
470
471
472 /**
473 * Get the data for the whole table, an individual row or an individual cell based on the
474 * provided parameters.
475 * @param {int|node} [src] A TR row node, TD/TH cell node or an integer. If given as
476 * a TR node then the data source for the whole row will be returned. If given as a
477 * TD/TH cell node then iCol will be automatically calculated and the data for the
478 * cell returned. If given as an integer, then this is treated as the aoData internal
479 * data index for the row (see fnGetPosition) and the data for that row used.
480 * @param {int} [col] Optional column index that you want the data of.
481 * @returns {array|object|string} If mRow is undefined, then the data for all rows is
482 * returned. If mRow is defined, just data for that row, and is iCol is
483 * defined, only data for the designated cell is returned.
484 * @dtopt API
485 * @deprecated Since v1.10
486 *
487 * @example
488 * // Row data
489 * $(document).ready(function() {
490 * oTable = $('#example').dataTable();
491 *
492 * oTable.$('tr').click( function () {
493 * var data = oTable.fnGetData( this );
494 * // ... do something with the array / object of data for the row
495 * } );
496 * } );
497 *
498 * @example
499 * // Individual cell data
500 * $(document).ready(function() {
501 * oTable = $('#example').dataTable();
502 *
503 * oTable.$('td').click( function () {
504 * var sData = oTable.fnGetData( this );
505 * alert( 'The cell clicked on had the value of '+sData );
506 * } );
507 * } );
508 */
509 this.fnGetData = function( src, col )
510 {
511 var api = this.api( true );
512
513 if ( src !== undefined ) {
514 var type = src.nodeName ? src.nodeName.toLowerCase() : '';
515
516 return col !== undefined || type == 'td' || type == 'th' ?
517 api.cell( src, col ).data() :
518 api.row( src ).data() || null;
519 }
520
521 return api.data().toArray();
522 };
523
524
525 /**
526 * Get an array of the TR nodes that are used in the table's body. Note that you will
527 * typically want to use the '$' API method in preference to this as it is more
528 * flexible.
529 * @param {int} [iRow] Optional row index for the TR element you want
530 * @returns {array|node} If iRow is undefined, returns an array of all TR elements
531 * in the table's body, or iRow is defined, just the TR element requested.
532 * @dtopt API
533 * @deprecated Since v1.10
534 *
535 * @example
536 * $(document).ready(function() {
537 * var oTable = $('#example').dataTable();
538 *
539 * // Get the nodes from the table
540 * var nNodes = oTable.fnGetNodes( );
541 * } );
542 */
543 this.fnGetNodes = function( iRow )
544 {
545 var api = this.api( true );
546
547 return iRow !== undefined ?
548 api.row( iRow ).node() :
549 api.rows().nodes().flatten().toArray();
550 };
551
552
553 /**
554 * Get the array indexes of a particular cell from it's DOM element
555 * and column index including hidden columns
556 * @param {node} node this can either be a TR, TD or TH in the table's body
557 * @returns {int} If nNode is given as a TR, then a single index is returned, or
558 * if given as a cell, an array of [row index, column index (visible),
559 * column index (all)] is given.
560 * @dtopt API
561 * @deprecated Since v1.10
562 *
563 * @example
564 * $(document).ready(function() {
565 * $('#example tbody td').click( function () {
566 * // Get the position of the current data from the node
567 * var aPos = oTable.fnGetPosition( this );
568 *
569 * // Get the data array for this row
570 * var aData = oTable.fnGetData( aPos[0] );
571 *
572 * // Update the data array and return the value
573 * aData[ aPos[1] ] = 'clicked';
574 * this.innerHTML = 'clicked';
575 * } );
576 *
577 * // Init DataTables
578 * oTable = $('#example').dataTable();
579 * } );
580 */
581 this.fnGetPosition = function( node )
582 {
583 var api = this.api( true );
584 var nodeName = node.nodeName.toUpperCase();
585
586 if ( nodeName == 'TR' ) {
587 return api.row( node ).index();
588 }
589 else if ( nodeName == 'TD' || nodeName == 'TH' ) {
590 var cell = api.cell( node ).index();
591
592 return [
593 cell.row,
594 cell.columnVisible,
595 cell.column
596 ];
597 }
598 return null;
599 };
600
601
602 /**
603 * Check to see if a row is 'open' or not.
604 * @param {node} nTr the table row to check
605 * @returns {boolean} true if the row is currently open, false otherwise
606 * @dtopt API
607 * @deprecated Since v1.10
608 *
609 * @example
610 * $(document).ready(function() {
611 * var oTable;
612 *
613 * // 'open' an information row when a row is clicked on
614 * $('#example tbody tr').click( function () {
615 * if ( oTable.fnIsOpen(this) ) {
616 * oTable.fnClose( this );
617 * } else {
618 * oTable.fnOpen( this, "Temporary row opened", "info_row" );
619 * }
620 * } );
621 *
622 * oTable = $('#example').dataTable();
623 * } );
624 */
625 this.fnIsOpen = function( nTr )
626 {
627 return this.api( true ).row( nTr ).child.isShown();
628 };
629
630
631 /**
632 * This function will place a new row directly after a row which is currently
633 * on display on the page, with the HTML contents that is passed into the
634 * function. This can be used, for example, to ask for confirmation that a
635 * particular record should be deleted.
636 * @param {node} nTr The table row to 'open'
637 * @param {string|node|jQuery} mHtml The HTML to put into the row
638 * @param {string} sClass Class to give the new TD cell
639 * @returns {node} The row opened. Note that if the table row passed in as the
640 * first parameter, is not found in the table, this method will silently
641 * return.
642 * @dtopt API
643 * @deprecated Since v1.10
644 *
645 * @example
646 * $(document).ready(function() {
647 * var oTable;
648 *
649 * // 'open' an information row when a row is clicked on
650 * $('#example tbody tr').click( function () {
651 * if ( oTable.fnIsOpen(this) ) {
652 * oTable.fnClose( this );
653 * } else {
654 * oTable.fnOpen( this, "Temporary row opened", "info_row" );
655 * }
656 * } );
657 *
658 * oTable = $('#example').dataTable();
659 * } );
660 */
661 this.fnOpen = function( nTr, mHtml, sClass )
662 {
663 return this.api( true )
664 .row( nTr )
665 .child( mHtml, sClass )
666 .show()
667 .child()[0];
668 };
669
670
671 /**
672 * Change the pagination - provides the internal logic for pagination in a simple API
673 * function. With this function you can have a DataTables table go to the next,
674 * previous, first or last pages.
675 * @param {string|int} mAction Paging action to take: "first", "previous", "next" or "last"
676 * or page number to jump to (integer), note that page 0 is the first page.
677 * @param {bool} [bRedraw=true] Redraw the table or not
678 * @dtopt API
679 * @deprecated Since v1.10
680 *
681 * @example
682 * $(document).ready(function() {
683 * var oTable = $('#example').dataTable();
684 * oTable.fnPageChange( 'next' );
685 * } );
686 */
687 this.fnPageChange = function ( mAction, bRedraw )
688 {
689 var api = this.api( true ).page( mAction );
690
691 if ( bRedraw === undefined || bRedraw ) {
692 api.draw(false);
693 }
694 };
695
696
697 /**
698 * Show a particular column
699 * @param {int} iCol The column whose display should be changed
700 * @param {bool} bShow Show (true) or hide (false) the column
701 * @param {bool} [bRedraw=true] Redraw the table or not
702 * @dtopt API
703 * @deprecated Since v1.10
704 *
705 * @example
706 * $(document).ready(function() {
707 * var oTable = $('#example').dataTable();
708 *
709 * // Hide the second column after initialisation
710 * oTable.fnSetColumnVis( 1, false );
711 * } );
712 */
713 this.fnSetColumnVis = function ( iCol, bShow, bRedraw )
714 {
715 var api = this.api( true ).column( iCol ).visible( bShow );
716
717 if ( bRedraw === undefined || bRedraw ) {
718 api.columns.adjust().draw();
719 }
720 };
721
722
723 /**
724 * Get the settings for a particular table for external manipulation
725 * @returns {object} DataTables settings object. See
726 * {@link DataTable.models.oSettings}
727 * @dtopt API
728 * @deprecated Since v1.10
729 *
730 * @example
731 * $(document).ready(function() {
732 * var oTable = $('#example').dataTable();
733 * var oSettings = oTable.fnSettings();
734 *
735 * // Show an example parameter from the settings
736 * alert( oSettings._iDisplayStart );
737 * } );
738 */
739 this.fnSettings = function()
740 {
741 return _fnSettingsFromNode( this[_ext.iApiIndex] );
742 };
743
744
745 /**
746 * Sort the table by a particular column
747 * @param {int} iCol the data index to sort on. Note that this will not match the
748 * 'display index' if you have hidden data entries
749 * @dtopt API
750 * @deprecated Since v1.10
751 *
752 * @example
753 * $(document).ready(function() {
754 * var oTable = $('#example').dataTable();
755 *
756 * // Sort immediately with columns 0 and 1
757 * oTable.fnSort( [ [0,'asc'], [1,'asc'] ] );
758 * } );
759 */
760 this.fnSort = function( aaSort )
761 {
762 this.api( true ).order( aaSort ).draw();
763 };
764
765
766 /**
767 * Attach a sort listener to an element for a given column
768 * @param {node} nNode the element to attach the sort listener to
769 * @param {int} iColumn the column that a click on this node will sort on
770 * @param {function} [fnCallback] callback function when sort is run
771 * @dtopt API
772 * @deprecated Since v1.10
773 *
774 * @example
775 * $(document).ready(function() {
776 * var oTable = $('#example').dataTable();
777 *
778 * // Sort on column 1, when 'sorter' is clicked on
779 * oTable.fnSortListener( document.getElementById('sorter'), 1 );
780 * } );
781 */
782 this.fnSortListener = function( nNode, iColumn, fnCallback )
783 {
784 this.api( true ).order.listener( nNode, iColumn, fnCallback );
785 };
786
787
788 /**
789 * Update a table cell or row - this method will accept either a single value to
790 * update the cell with, an array of values with one element for each column or
791 * an object in the same format as the original data source. The function is
792 * self-referencing in order to make the multi column updates easier.
793 * @param {object|array|string} mData Data to update the cell/row with
794 * @param {node|int} mRow TR element you want to update or the aoData index
795 * @param {int} [iColumn] The column to update, give as null or undefined to
796 * update a whole row.
797 * @param {bool} [bRedraw=true] Redraw the table or not
798 * @param {bool} [bAction=true] Perform pre-draw actions or not
799 * @returns {int} 0 on success, 1 on error
800 * @dtopt API
801 * @deprecated Since v1.10
802 *
803 * @example
804 * $(document).ready(function() {
805 * var oTable = $('#example').dataTable();
806 * oTable.fnUpdate( 'Example update', 0, 0 ); // Single cell
807 * oTable.fnUpdate( ['a', 'b', 'c', 'd', 'e'], $('tbody tr')[0] ); // Row
808 * } );
809 */
810 this.fnUpdate = function( mData, mRow, iColumn, bRedraw, bAction )
811 {
812 var api = this.api( true );
813
814 if ( iColumn === undefined || iColumn === null ) {
815 api.row( mRow ).data( mData );
816 }
817 else {
818 api.cell( mRow, iColumn ).data( mData );
819 }
820
821 if ( bAction === undefined || bAction ) {
822 api.columns.adjust();
823 }
824
825 if ( bRedraw === undefined || bRedraw ) {
826 api.draw();
827 }
828 return 0;
829 };
830
831
832 /**
833 * Provide a common method for plug-ins to check the version of DataTables being used, in order
834 * to ensure compatibility.
835 * @param {string} sVersion Version string to check for, in the format "X.Y.Z". Note that the
836 * formats "X" and "X.Y" are also acceptable.
837 * @returns {boolean} true if this version of DataTables is greater or equal to the required
838 * version, or false if this version of DataTales is not suitable
839 * @method
840 * @dtopt API
841 * @deprecated Since v1.10
842 *
843 * @example
844 * $(document).ready(function() {
845 * var oTable = $('#example').dataTable();
846 * alert( oTable.fnVersionCheck( '1.9.0' ) );
847 * } );
848 */
849 this.fnVersionCheck = _ext.fnVersionCheck;
850
851
852 var _that = this;
853 var emptyInit = options === undefined;
854 var len = this.length;
855
856 if ( emptyInit ) {
857 options = {};
858 }
859
860 this.oApi = this.internal = _ext.internal;
861
862 // Extend with old style plug-in API methods
863 for ( var fn in DataTable.ext.internal ) {
864 if ( fn ) {
865 this[fn] = _fnExternApiFunc(fn);
866 }
867 }
868
869 this.each(function() {
870 // For each initialisation we want to give it a clean initialisation
871 // object that can be bashed around
872 var o = {};
873 var oInit = len > 1 ? // optimisation for single table case
874 _fnExtend( o, options, true ) :
875 options;
876
877 /*global oInit,_that,emptyInit*/
878 var i=0, iLen, j, jLen, k, kLen;
879 var sId = this.getAttribute( 'id' );
880 var bInitHandedOff = false;
881 var defaults = DataTable.defaults;
882 var $this = $(this);
883
884
885 /* Sanity check */
886 if ( this.nodeName.toLowerCase() != 'table' )
887 {
888 _fnLog( null, 0, 'Non-table node initialisation ('+this.nodeName+')', 2 );
889 return;
890 }
891
892 /* Backwards compatibility for the defaults */
893 _fnCompatOpts( defaults );
894 _fnCompatCols( defaults.column );
895
896 /* Convert the camel-case defaults to Hungarian */
897 _fnCamelToHungarian( defaults, defaults, true );
898 _fnCamelToHungarian( defaults.column, defaults.column, true );
899
900 /* Setting up the initialisation object */
901 _fnCamelToHungarian( defaults, $.extend( oInit, $this.data() ) );
902
903
904
905 /* Check to see if we are re-initialising a table */
906 var allSettings = DataTable.settings;
907 for ( i=0, iLen=allSettings.length ; i<iLen ; i++ )
908 {
909 var s = allSettings[i];
910
911 /* Base check on table node */
912 if (
913 s.nTable == this ||
914 (s.nTHead && s.nTHead.parentNode == this) ||
915 (s.nTFoot && s.nTFoot.parentNode == this)
916 ) {
917 var bRetrieve = oInit.bRetrieve !== undefined ? oInit.bRetrieve : defaults.bRetrieve;
918 var bDestroy = oInit.bDestroy !== undefined ? oInit.bDestroy : defaults.bDestroy;
919
920 if ( emptyInit || bRetrieve )
921 {
922 return s.oInstance;
923 }
924 else if ( bDestroy )
925 {
926 s.oInstance.fnDestroy();
927 break;
928 }
929 else
930 {
931 _fnLog( s, 0, 'Cannot reinitialise DataTable', 3 );
932 return;
933 }
934 }
935
936 /* If the element we are initialising has the same ID as a table which was previously
937 * initialised, but the table nodes don't match (from before) then we destroy the old
938 * instance by simply deleting it. This is under the assumption that the table has been
939 * destroyed by other methods. Anyone using non-id selectors will need to do this manually
940 */
941 if ( s.sTableId == this.id )
942 {
943 allSettings.splice( i, 1 );
944 break;
945 }
946 }
947
948 /* Ensure the table has an ID - required for accessibility */
949 if ( sId === null || sId === "" )
950 {
951 sId = "DataTables_Table_"+(DataTable.ext._unique++);
952 this.id = sId;
953 }
954
955 /* Create the settings object for this table and set some of the default parameters */
956 var oSettings = $.extend( true, {}, DataTable.models.oSettings, {
957 "sDestroyWidth": $this[0].style.width,
958 "sInstance": sId,
959 "sTableId": sId
960 } );
961 oSettings.nTable = this;
962 oSettings.oApi = _that.internal;
963 oSettings.oInit = oInit;
964
965 allSettings.push( oSettings );
966
967 // Need to add the instance after the instance after the settings object has been added
968 // to the settings array, so we can self reference the table instance if more than one
969 oSettings.oInstance = (_that.length===1) ? _that : $this.dataTable();
970
971 // Backwards compatibility, before we apply all the defaults
972 _fnCompatOpts( oInit );
973 _fnLanguageCompat( oInit.oLanguage );
974
975 // If the length menu is given, but the init display length is not, use the length menu
976 if ( oInit.aLengthMenu && ! oInit.iDisplayLength )
977 {
978 oInit.iDisplayLength = $.isArray( oInit.aLengthMenu[0] ) ?
979 oInit.aLengthMenu[0][0] : oInit.aLengthMenu[0];
980 }
981
982 // Apply the defaults and init options to make a single init object will all
983 // options defined from defaults and instance options.
984 oInit = _fnExtend( $.extend( true, {}, defaults ), oInit );
985
986
987 // Map the initialisation options onto the settings object
988 _fnMap( oSettings.oFeatures, oInit, [
989 "bPaginate",
990 "bLengthChange",
991 "bFilter",
992 "bSort",
993 "bSortMulti",
994 "bInfo",
995 "bProcessing",
996 "bAutoWidth",
997 "bSortClasses",
998 "bServerSide",
999 "bDeferRender"
1000 ] );
1001 _fnMap( oSettings, oInit, [
1002 "asStripeClasses",
1003 "ajax",
1004 "fnServerData",
1005 "fnFormatNumber",
1006 "sServerMethod",
1007 "aaSorting",
1008 "aaSortingFixed",
1009 "aLengthMenu",
1010 "sPaginationType",
1011 "sAjaxSource",
1012 "sAjaxDataProp",
1013 "iStateDuration",
1014 "sDom",
1015 "bSortCellsTop",
1016 "iTabIndex",
1017 "fnStateLoadCallback",
1018 "fnStateSaveCallback",
1019 "renderer",
1020 "searchDelay",
1021 "rowId",
1022 [ "iCookieDuration", "iStateDuration" ], // backwards compat
1023 [ "oSearch", "oPreviousSearch" ],
1024 [ "aoSearchCols", "aoPreSearchCols" ],
1025 [ "iDisplayLength", "_iDisplayLength" ]
1026 ] );
1027 _fnMap( oSettings.oScroll, oInit, [
1028 [ "sScrollX", "sX" ],
1029 [ "sScrollXInner", "sXInner" ],
1030 [ "sScrollY", "sY" ],
1031 [ "bScrollCollapse", "bCollapse" ]
1032 ] );
1033 _fnMap( oSettings.oLanguage, oInit, "fnInfoCallback" );
1034
1035 /* Callback functions which are array driven */
1036 _fnCallbackReg( oSettings, 'aoDrawCallback', oInit.fnDrawCallback, 'user' );
1037 _fnCallbackReg( oSettings, 'aoServerParams', oInit.fnServerParams, 'user' );
1038 _fnCallbackReg( oSettings, 'aoStateSaveParams', oInit.fnStateSaveParams, 'user' );
1039 _fnCallbackReg( oSettings, 'aoStateLoadParams', oInit.fnStateLoadParams, 'user' );
1040 _fnCallbackReg( oSettings, 'aoStateLoaded', oInit.fnStateLoaded, 'user' );
1041 _fnCallbackReg( oSettings, 'aoRowCallback', oInit.fnRowCallback, 'user' );
1042 _fnCallbackReg( oSettings, 'aoRowCreatedCallback', oInit.fnCreatedRow, 'user' );
1043 _fnCallbackReg( oSettings, 'aoHeaderCallback', oInit.fnHeaderCallback, 'user' );
1044 _fnCallbackReg( oSettings, 'aoFooterCallback', oInit.fnFooterCallback, 'user' );
1045 _fnCallbackReg( oSettings, 'aoInitComplete', oInit.fnInitComplete, 'user' );
1046 _fnCallbackReg( oSettings, 'aoPreDrawCallback', oInit.fnPreDrawCallback, 'user' );
1047
1048 oSettings.rowIdFn = _fnGetObjectDataFn( oInit.rowId );
1049
1050 /* Browser support detection */
1051 _fnBrowserDetect( oSettings );
1052
1053 var oClasses = oSettings.oClasses;
1054
1055 $.extend( oClasses, DataTable.ext.classes, oInit.oClasses );
1056 $this.addClass( oClasses.sTable );
1057
1058
1059 if ( oSettings.iInitDisplayStart === undefined )
1060 {
1061 /* Display start point, taking into account the save saving */
1062 oSettings.iInitDisplayStart = oInit.iDisplayStart;
1063 oSettings._iDisplayStart = oInit.iDisplayStart;
1064 }
1065
1066 if ( oInit.iDeferLoading !== null )
1067 {
1068 oSettings.bDeferLoading = true;
1069 var tmp = $.isArray( oInit.iDeferLoading );
1070 oSettings._iRecordsDisplay = tmp ? oInit.iDeferLoading[0] : oInit.iDeferLoading;
1071 oSettings._iRecordsTotal = tmp ? oInit.iDeferLoading[1] : oInit.iDeferLoading;
1072 }
1073
1074 /* Language definitions */
1075 var oLanguage = oSettings.oLanguage;
1076 $.extend( true, oLanguage, oInit.oLanguage );
1077
1078 if ( oLanguage.sUrl )
1079 {
1080 /* Get the language definitions from a file - because this Ajax call makes the language
1081 * get async to the remainder of this function we use bInitHandedOff to indicate that
1082 * _fnInitialise will be fired by the returned Ajax handler, rather than the constructor
1083 */
1084 $.ajax( {
1085 dataType: 'json',
1086 url: oLanguage.sUrl,
1087 success: function ( json ) {
1088 _fnLanguageCompat( json );
1089 _fnCamelToHungarian( defaults.oLanguage, json );
1090 $.extend( true, oLanguage, json );
1091 _fnInitialise( oSettings );
1092 },
1093 error: function () {
1094 // Error occurred loading language file, continue on as best we can
1095 _fnInitialise( oSettings );
1096 }
1097 } );
1098 bInitHandedOff = true;
1099 }
1100
1101 /*
1102 * Stripes
1103 */
1104 if ( oInit.asStripeClasses === null )
1105 {
1106 oSettings.asStripeClasses =[
1107 oClasses.sStripeOdd,
1108 oClasses.sStripeEven
1109 ];
1110 }
1111
1112 /* Remove row stripe classes if they are already on the table row */
1113 var stripeClasses = oSettings.asStripeClasses;
1114 var rowOne = $this.children('tbody').find('tr').eq(0);
1115 if ( $.inArray( true, $.map( stripeClasses, function(el, i) {
1116 return rowOne.hasClass(el);
1117 } ) ) !== -1 ) {
1118 $('tbody tr', this).removeClass( stripeClasses.join(' ') );
1119 oSettings.asDestroyStripes = stripeClasses.slice();
1120 }
1121
1122 /*
1123 * Columns
1124 * See if we should load columns automatically or use defined ones
1125 */
1126 var anThs = [];
1127 var aoColumnsInit;
1128 var nThead = this.getElementsByTagName('thead');
1129 if ( nThead.length !== 0 )
1130 {
1131 _fnDetectHeader( oSettings.aoHeader, nThead[0] );
1132 anThs = _fnGetUniqueThs( oSettings );
1133 }
1134
1135 /* If not given a column array, generate one with nulls */
1136 if ( oInit.aoColumns === null )
1137 {
1138 aoColumnsInit = [];
1139 for ( i=0, iLen=anThs.length ; i<iLen ; i++ )
1140 {
1141 aoColumnsInit.push( null );
1142 }
1143 }
1144 else
1145 {
1146 aoColumnsInit = oInit.aoColumns;
1147 }
1148
1149 /* Add the columns */
1150 for ( i=0, iLen=aoColumnsInit.length ; i<iLen ; i++ )
1151 {
1152 _fnAddColumn( oSettings, anThs ? anThs[i] : null );
1153 }
1154
1155 /* Apply the column definitions */
1156 _fnApplyColumnDefs( oSettings, oInit.aoColumnDefs, aoColumnsInit, function (iCol, oDef) {
1157 _fnColumnOptions( oSettings, iCol, oDef );
1158 } );
1159
1160 /* HTML5 attribute detection - build an mData object automatically if the
1161 * attributes are found
1162 */
1163 if ( rowOne.length ) {
1164 var a = function ( cell, name ) {
1165 return cell.getAttribute( 'data-'+name ) !== null ? name : null;
1166 };
1167
1168 $( rowOne[0] ).children('th, td').each( function (i, cell) {
1169 var col = oSettings.aoColumns[i];
1170
1171 if ( col.mData === i ) {
1172 var sort = a( cell, 'sort' ) || a( cell, 'order' );
1173 var filter = a( cell, 'filter' ) || a( cell, 'search' );
1174
1175 if ( sort !== null || filter !== null ) {
1176 col.mData = {
1177 _: i+'.display',
1178 sort: sort !== null ? i+'.@data-'+sort : undefined,
1179 type: sort !== null ? i+'.@data-'+sort : undefined,
1180 filter: filter !== null ? i+'.@data-'+filter : undefined
1181 };
1182
1183 _fnColumnOptions( oSettings, i );
1184 }
1185 }
1186 } );
1187 }
1188
1189 var features = oSettings.oFeatures;
1190 var loadedInit = function () {
1191 /*
1192 * Sorting
1193 * @todo For modularisation (1.11) this needs to do into a sort start up handler
1194 */
1195
1196 // If aaSorting is not defined, then we use the first indicator in asSorting
1197 // in case that has been altered, so the default sort reflects that option
1198 if ( oInit.aaSorting === undefined ) {
1199 var sorting = oSettings.aaSorting;
1200 for ( i=0, iLen=sorting.length ; i<iLen ; i++ ) {
1201 sorting[i][1] = oSettings.aoColumns[ i ].asSorting[0];
1202 }
1203 }
1204
1205 /* Do a first pass on the sorting classes (allows any size changes to be taken into
1206 * account, and also will apply sorting disabled classes if disabled
1207 */
1208 _fnSortingClasses( oSettings );
1209
1210 if ( features.bSort ) {
1211 _fnCallbackReg( oSettings, 'aoDrawCallback', function () {
1212 if ( oSettings.bSorted ) {
1213 var aSort = _fnSortFlatten( oSettings );
1214 var sortedColumns = {};
1215
1216 $.each( aSort, function (i, val) {
1217 sortedColumns[ val.src ] = val.dir;
1218 } );
1219
1220 _fnCallbackFire( oSettings, null, 'order', [oSettings, aSort, sortedColumns] );
1221 _fnSortAria( oSettings );
1222 }
1223 } );
1224 }
1225
1226 _fnCallbackReg( oSettings, 'aoDrawCallback', function () {
1227 if ( oSettings.bSorted || _fnDataSource( oSettings ) === 'ssp' || features.bDeferRender ) {
1228 _fnSortingClasses( oSettings );
1229 }
1230 }, 'sc' );
1231
1232
1233 /*
1234 * Final init
1235 * Cache the header, body and footer as required, creating them if needed
1236 */
1237
1238 // Work around for Webkit bug 83867 - store the caption-side before removing from doc
1239 var captions = $this.children('caption').each( function () {
1240 this._captionSide = $(this).css('caption-side');
1241 } );
1242
1243 var thead = $this.children('thead');
1244 if ( thead.length === 0 ) {
1245 thead = $('<thead/>').appendTo($this);
1246 }
1247 oSettings.nTHead = thead[0];
1248
1249 var tbody = $this.children('tbody');
1250 if ( tbody.length === 0 ) {
1251 tbody = $('<tbody/>').appendTo($this);
1252 }
1253 oSettings.nTBody = tbody[0];
1254
1255 var tfoot = $this.children('tfoot');
1256 if ( tfoot.length === 0 && captions.length > 0 && (oSettings.oScroll.sX !== "" || oSettings.oScroll.sY !== "") ) {
1257 // If we are a scrolling table, and no footer has been given, then we need to create
1258 // a tfoot element for the caption element to be appended to
1259 tfoot = $('<tfoot/>').appendTo($this);
1260 }
1261
1262 if ( tfoot.length === 0 || tfoot.children().length === 0 ) {
1263 $this.addClass( oClasses.sNoFooter );
1264 }
1265 else if ( tfoot.length > 0 ) {
1266 oSettings.nTFoot = tfoot[0];
1267 _fnDetectHeader( oSettings.aoFooter, oSettings.nTFoot );
1268 }
1269
1270 /* Check if there is data passing into the constructor */
1271 if ( oInit.aaData ) {
1272 for ( i=0 ; i<oInit.aaData.length ; i++ ) {
1273 _fnAddData( oSettings, oInit.aaData[ i ] );
1274 }
1275 }
1276 else if ( oSettings.bDeferLoading || _fnDataSource( oSettings ) == 'dom' ) {
1277 /* Grab the data from the page - only do this when deferred loading or no Ajax
1278 * source since there is no point in reading the DOM data if we are then going
1279 * to replace it with Ajax data
1280 */
1281 _fnAddTr( oSettings, $(oSettings.nTBody).children('tr') );
1282 }
1283
1284 /* Copy the data index array */
1285 oSettings.aiDisplay = oSettings.aiDisplayMaster.slice();
1286
1287 /* Initialisation complete - table can be drawn */
1288 oSettings.bInitialised = true;
1289
1290 /* Check if we need to initialise the table (it might not have been handed off to the
1291 * language processor)
1292 */
1293 if ( bInitHandedOff === false ) {
1294 _fnInitialise( oSettings );
1295 }
1296 };
1297
1298 /* Must be done after everything which can be overridden by the state saving! */
1299 if ( oInit.bStateSave )
1300 {
1301 features.bStateSave = true;
1302 _fnCallbackReg( oSettings, 'aoDrawCallback', _fnSaveState, 'state_save' );
1303 _fnLoadState( oSettings, oInit, loadedInit );
1304 }
1305 else {
1306 loadedInit();
1307 }
1308
1309 } );
1310 _that = null;
1311 return this;
1312 };
1313
1314
1315 /*
1316 * It is useful to have variables which are scoped locally so only the
1317 * DataTables functions can access them and they don't leak into global space.
1318 * At the same time these functions are often useful over multiple files in the
1319 * core and API, so we list, or at least document, all variables which are used
1320 * by DataTables as private variables here. This also ensures that there is no
1321 * clashing of variable names and that they can easily referenced for reuse.
1322 */
1323
1324
1325 // Defined else where
1326 // _selector_run
1327 // _selector_opts
1328 // _selector_first
1329 // _selector_row_indexes
1330
1331 var _ext; // DataTable.ext
1332 var _Api; // DataTable.Api
1333 var _api_register; // DataTable.Api.register
1334 var _api_registerPlural; // DataTable.Api.registerPlural
1335
1336 var _re_dic = {};
1337 var _re_new_lines = /[\r\n]/g;
1338 var _re_html = /<.*?>/g;
1339
1340 // This is not strict ISO8601 - Date.parse() is quite lax, although
1341 // implementations differ between browsers.
1342 var _re_date = /^\d{2,4}[\.\/\-]\d{1,2}[\.\/\-]\d{1,2}([T ]{1}\d{1,2}[:\.]\d{2}([\.:]\d{2})?)?$/;
1343
1344 // Escape regular expression special characters
1345 var _re_escape_regex = new RegExp( '(\\' + [ '/', '.', '*', '+', '?', '|', '(', ')', '[', ']', '{', '}', '\\', '$', '^', '-' ].join('|\\') + ')', 'g' );
1346
1347 // http://en.wikipedia.org/wiki/Foreign_exchange_market
1348 // - \u20BD - Russian ruble.
1349 // - \u20a9 - South Korean Won
1350 // - \u20BA - Turkish Lira
1351 // - \u20B9 - Indian Rupee
1352 // - R - Brazil (R$) and South Africa
1353 // - fr - Swiss Franc
1354 // - kr - Swedish krona, Norwegian krone and Danish krone
1355 // - \u2009 is thin space and \u202F is narrow no-break space, both used in many
1356 // - Ƀ - Bitcoin
1357 // - Ξ - Ethereum
1358 // standards as thousands separators.
1359 var _re_formatted_numeric = /[',$£€¥%\u2009\u202F\u20BD\u20a9\u20BArfkɃΞ]/gi;
1360
1361
1362 var _empty = function ( d ) {
1363 return !d || d === true || d === '-' ? true : false;
1364 };
1365
1366
1367 var _intVal = function ( s ) {
1368 var integer = parseInt( s, 10 );
1369 return !isNaN(integer) && isFinite(s) ? integer : null;
1370 };
1371
1372 // Convert from a formatted number with characters other than `.` as the
1373 // decimal place, to a Javascript number
1374 var _numToDecimal = function ( num, decimalPoint ) {
1375 // Cache created regular expressions for speed as this function is called often
1376 if ( ! _re_dic[ decimalPoint ] ) {
1377 _re_dic[ decimalPoint ] = new RegExp( _fnEscapeRegex( decimalPoint ), 'g' );
1378 }
1379 return typeof num === 'string' && decimalPoint !== '.' ?
1380 num.replace( /\./g, '' ).replace( _re_dic[ decimalPoint ], '.' ) :
1381 num;
1382 };
1383
1384
1385 var _isNumber = function ( d, decimalPoint, formatted ) {
1386 var strType = typeof d === 'string';
1387
1388 // If empty return immediately so there must be a number if it is a
1389 // formatted string (this stops the string "k", or "kr", etc being detected
1390 // as a formatted number for currency
1391 if ( _empty( d ) ) {
1392 return true;
1393 }
1394
1395 if ( decimalPoint && strType ) {
1396 d = _numToDecimal( d, decimalPoint );
1397 }
1398
1399 if ( formatted && strType ) {
1400 d = d.replace( _re_formatted_numeric, '' );
1401 }
1402
1403 return !isNaN( parseFloat(d) ) && isFinite( d );
1404 };
1405
1406
1407 // A string without HTML in it can be considered to be HTML still
1408 var _isHtml = function ( d ) {
1409 return _empty( d ) || typeof d === 'string';
1410 };
1411
1412
1413 var _htmlNumeric = function ( d, decimalPoint, formatted ) {
1414 if ( _empty( d ) ) {
1415 return true;
1416 }
1417
1418 var html = _isHtml( d );
1419 return ! html ?
1420 null :
1421 _isNumber( _stripHtml( d ), decimalPoint, formatted ) ?
1422 true :
1423 null;
1424 };
1425
1426
1427 var _pluck = function ( a, prop, prop2 ) {
1428 var out = [];
1429 var i=0, ien=a.length;
1430
1431 // Could have the test in the loop for slightly smaller code, but speed
1432 // is essential here
1433 if ( prop2 !== undefined ) {
1434 for ( ; i<ien ; i++ ) {
1435 if ( a[i] && a[i][ prop ] ) {
1436 out.push( a[i][ prop ][ prop2 ] );
1437 }
1438 }
1439 }
1440 else {
1441 for ( ; i<ien ; i++ ) {
1442 if ( a[i] ) {
1443 out.push( a[i][ prop ] );
1444 }
1445 }
1446 }
1447
1448 return out;
1449 };
1450
1451
1452 // Basically the same as _pluck, but rather than looping over `a` we use `order`
1453 // as the indexes to pick from `a`
1454 var _pluck_order = function ( a, order, prop, prop2 )
1455 {
1456 var out = [];
1457 var i=0, ien=order.length;
1458
1459 // Could have the test in the loop for slightly smaller code, but speed
1460 // is essential here
1461 if ( prop2 !== undefined ) {
1462 for ( ; i<ien ; i++ ) {
1463 if ( a[ order[i] ][ prop ] ) {
1464 out.push( a[ order[i] ][ prop ][ prop2 ] );
1465 }
1466 }
1467 }
1468 else {
1469 for ( ; i<ien ; i++ ) {
1470 out.push( a[ order[i] ][ prop ] );
1471 }
1472 }
1473
1474 return out;
1475 };
1476
1477
1478 var _range = function ( len, start )
1479 {
1480 var out = [];
1481 var end;
1482
1483 if ( start === undefined ) {
1484 start = 0;
1485 end = len;
1486 }
1487 else {
1488 end = start;
1489 start = len;
1490 }
1491
1492 for ( var i=start ; i<end ; i++ ) {
1493 out.push( i );
1494 }
1495
1496 return out;
1497 };
1498
1499
1500 var _removeEmpty = function ( a )
1501 {
1502 var out = [];
1503
1504 for ( var i=0, ien=a.length ; i<ien ; i++ ) {
1505 if ( a[i] ) { // careful - will remove all falsy values!
1506 out.push( a[i] );
1507 }
1508 }
1509
1510 return out;
1511 };
1512
1513
1514 var _stripHtml = function ( d ) {
1515 return d.replace( _re_html, '' );
1516 };
1517
1518
1519 /**
1520 * Determine if all values in the array are unique. This means we can short
1521 * cut the _unique method at the cost of a single loop. A sorted array is used
1522 * to easily check the values.
1523 *
1524 * @param {array} src Source array
1525 * @return {boolean} true if all unique, false otherwise
1526 * @ignore
1527 */
1528 var _areAllUnique = function ( src ) {
1529 if ( src.length < 2 ) {
1530 return true;
1531 }
1532
1533 var sorted = src.slice().sort();
1534 var last = sorted[0];
1535
1536 for ( var i=1, ien=sorted.length ; i<ien ; i++ ) {
1537 if ( sorted[i] === last ) {
1538 return false;
1539 }
1540
1541 last = sorted[i];
1542 }
1543
1544 return true;
1545 };
1546
1547
1548 /**
1549 * Find the unique elements in a source array.
1550 *
1551 * @param {array} src Source array
1552 * @return {array} Array of unique items
1553 * @ignore
1554 */
1555 var _unique = function ( src )
1556 {
1557 if ( _areAllUnique( src ) ) {
1558 return src.slice();
1559 }
1560
1561 // A faster unique method is to use object keys to identify used values,
1562 // but this doesn't work with arrays or objects, which we must also
1563 // consider. See jsperf.com/compare-array-unique-versions/4 for more
1564 // information.
1565 var
1566 out = [],
1567 val,
1568 i, ien=src.length,
1569 j, k=0;
1570
1571 again: for ( i=0 ; i<ien ; i++ ) {
1572 val = src[i];
1573
1574 for ( j=0 ; j<k ; j++ ) {
1575 if ( out[j] === val ) {
1576 continue again;
1577 }
1578 }
1579
1580 out.push( val );
1581 k++;
1582 }
1583
1584 return out;
1585 };
1586
1587
1588 /**
1589 * DataTables utility methods
1590 *
1591 * This namespace provides helper methods that DataTables uses internally to
1592 * create a DataTable, but which are not exclusively used only for DataTables.
1593 * These methods can be used by extension authors to save the duplication of
1594 * code.
1595 *
1596 * @namespace
1597 */
1598 DataTable.util = {
1599 /**
1600 * Throttle the calls to a function. Arguments and context are maintained
1601 * for the throttled function.
1602 *
1603 * @param {function} fn Function to be called
1604 * @param {integer} freq Call frequency in mS
1605 * @return {function} Wrapped function
1606 */
1607 throttle: function ( fn, freq ) {
1608 var
1609 frequency = freq !== undefined ? freq : 200,
1610 last,
1611 timer;
1612
1613 return function () {
1614 var
1615 that = this,
1616 now = +new Date(),
1617 args = arguments;
1618
1619 if ( last && now < last + frequency ) {
1620 clearTimeout( timer );
1621
1622 timer = setTimeout( function () {
1623 last = undefined;
1624 fn.apply( that, args );
1625 }, frequency );
1626 }
1627 else {
1628 last = now;
1629 fn.apply( that, args );
1630 }
1631 };
1632 },
1633
1634
1635 /**
1636 * Escape a string such that it can be used in a regular expression
1637 *
1638 * @param {string} val string to escape
1639 * @returns {string} escaped string
1640 */
1641 escapeRegex: function ( val ) {
1642 return val.replace( _re_escape_regex, '\\$1' );
1643 }
1644 };
1645
1646
1647
1648 /**
1649 * Create a mapping object that allows camel case parameters to be looked up
1650 * for their Hungarian counterparts. The mapping is stored in a private
1651 * parameter called `_hungarianMap` which can be accessed on the source object.
1652 * @param {object} o
1653 * @memberof DataTable#oApi
1654 */
1655 function _fnHungarianMap ( o )
1656 {
1657 var
1658 hungarian = 'a aa ai ao as b fn i m o s ',
1659 match,
1660 newKey,
1661 map = {};
1662
1663 $.each( o, function (key, val) {
1664 match = key.match(/^([^A-Z]+?)([A-Z])/);
1665
1666 if ( match && hungarian.indexOf(match[1]+' ') !== -1 )
1667 {
1668 newKey = key.replace( match[0], match[2].toLowerCase() );
1669 map[ newKey ] = key;
1670
1671 if ( match[1] === 'o' )
1672 {
1673 _fnHungarianMap( o[key] );
1674 }
1675 }
1676 } );
1677
1678 o._hungarianMap = map;
1679 }
1680
1681
1682 /**
1683 * Convert from camel case parameters to Hungarian, based on a Hungarian map
1684 * created by _fnHungarianMap.
1685 * @param {object} src The model object which holds all parameters that can be
1686 * mapped.
1687 * @param {object} user The object to convert from camel case to Hungarian.
1688 * @param {boolean} force When set to `true`, properties which already have a
1689 * Hungarian value in the `user` object will be overwritten. Otherwise they
1690 * won't be.
1691 * @memberof DataTable#oApi
1692 */
1693 function _fnCamelToHungarian ( src, user, force )
1694 {
1695 if ( ! src._hungarianMap ) {
1696 _fnHungarianMap( src );
1697 }
1698
1699 var hungarianKey;
1700
1701 $.each( user, function (key, val) {
1702 hungarianKey = src._hungarianMap[ key ];
1703
1704 if ( hungarianKey !== undefined && (force || user[hungarianKey] === undefined) )
1705 {
1706 // For objects, we need to buzz down into the object to copy parameters
1707 if ( hungarianKey.charAt(0) === 'o' )
1708 {
1709 // Copy the camelCase options over to the hungarian
1710 if ( ! user[ hungarianKey ] ) {
1711 user[ hungarianKey ] = {};
1712 }
1713 $.extend( true, user[hungarianKey], user[key] );
1714
1715 _fnCamelToHungarian( src[hungarianKey], user[hungarianKey], force );
1716 }
1717 else {
1718 user[hungarianKey] = user[ key ];
1719 }
1720 }
1721 } );
1722 }
1723
1724
1725 /**
1726 * Language compatibility - when certain options are given, and others aren't, we
1727 * need to duplicate the values over, in order to provide backwards compatibility
1728 * with older language files.
1729 * @param {object} oSettings dataTables settings object
1730 * @memberof DataTable#oApi
1731 */
1732 function _fnLanguageCompat( lang )
1733 {
1734 // Note the use of the Hungarian notation for the parameters in this method as
1735 // this is called after the mapping of camelCase to Hungarian
1736 var defaults = DataTable.defaults.oLanguage;
1737
1738 // Default mapping
1739 var defaultDecimal = defaults.sDecimal;
1740 if ( defaultDecimal ) {
1741 _addNumericSort( defaultDecimal );
1742 }
1743
1744 if ( lang ) {
1745 var zeroRecords = lang.sZeroRecords;
1746
1747 // Backwards compatibility - if there is no sEmptyTable given, then use the same as
1748 // sZeroRecords - assuming that is given.
1749 if ( ! lang.sEmptyTable && zeroRecords &&
1750 defaults.sEmptyTable === "No data available in table" )
1751 {
1752 _fnMap( lang, lang, 'sZeroRecords', 'sEmptyTable' );
1753 }
1754
1755 // Likewise with loading records
1756 if ( ! lang.sLoadingRecords && zeroRecords &&
1757 defaults.sLoadingRecords === "Loading..." )
1758 {
1759 _fnMap( lang, lang, 'sZeroRecords', 'sLoadingRecords' );
1760 }
1761
1762 // Old parameter name of the thousands separator mapped onto the new
1763 if ( lang.sInfoThousands ) {
1764 lang.sThousands = lang.sInfoThousands;
1765 }
1766
1767 var decimal = lang.sDecimal;
1768 if ( decimal && defaultDecimal !== decimal ) {
1769 _addNumericSort( decimal );
1770 }
1771 }
1772 }
1773
1774
1775 /**
1776 * Map one parameter onto another
1777 * @param {object} o Object to map
1778 * @param {*} knew The new parameter name
1779 * @param {*} old The old parameter name
1780 */
1781 var _fnCompatMap = function ( o, knew, old ) {
1782 if ( o[ knew ] !== undefined ) {
1783 o[ old ] = o[ knew ];
1784 }
1785 };
1786
1787
1788 /**
1789 * Provide backwards compatibility for the main DT options. Note that the new
1790 * options are mapped onto the old parameters, so this is an external interface
1791 * change only.
1792 * @param {object} init Object to map
1793 */
1794 function _fnCompatOpts ( init )
1795 {
1796 _fnCompatMap( init, 'ordering', 'bSort' );
1797 _fnCompatMap( init, 'orderMulti', 'bSortMulti' );
1798 _fnCompatMap( init, 'orderClasses', 'bSortClasses' );
1799 _fnCompatMap( init, 'orderCellsTop', 'bSortCellsTop' );
1800 _fnCompatMap( init, 'order', 'aaSorting' );
1801 _fnCompatMap( init, 'orderFixed', 'aaSortingFixed' );
1802 _fnCompatMap( init, 'paging', 'bPaginate' );
1803 _fnCompatMap( init, 'pagingType', 'sPaginationType' );
1804 _fnCompatMap( init, 'pageLength', 'iDisplayLength' );
1805 _fnCompatMap( init, 'searching', 'bFilter' );
1806
1807 // Boolean initialisation of x-scrolling
1808 if ( typeof init.sScrollX === 'boolean' ) {
1809 init.sScrollX = init.sScrollX ? '100%' : '';
1810 }
1811 if ( typeof init.scrollX === 'boolean' ) {
1812 init.scrollX = init.scrollX ? '100%' : '';
1813 }
1814
1815 // Column search objects are in an array, so it needs to be converted
1816 // element by element
1817 var searchCols = init.aoSearchCols;
1818
1819 if ( searchCols ) {
1820 for ( var i=0, ien=searchCols.length ; i<ien ; i++ ) {
1821 if ( searchCols[i] ) {
1822 _fnCamelToHungarian( DataTable.models.oSearch, searchCols[i] );
1823 }
1824 }
1825 }
1826 }
1827
1828
1829 /**
1830 * Provide backwards compatibility for column options. Note that the new options
1831 * are mapped onto the old parameters, so this is an external interface change
1832 * only.
1833 * @param {object} init Object to map
1834 */
1835 function _fnCompatCols ( init )
1836 {
1837 _fnCompatMap( init, 'orderable', 'bSortable' );
1838 _fnCompatMap( init, 'orderData', 'aDataSort' );
1839 _fnCompatMap( init, 'orderSequence', 'asSorting' );
1840 _fnCompatMap( init, 'orderDataType', 'sortDataType' );
1841
1842 // orderData can be given as an integer
1843 var dataSort = init.aDataSort;
1844 if ( typeof dataSort === 'number' && ! $.isArray( dataSort ) ) {
1845 init.aDataSort = [ dataSort ];
1846 }
1847 }
1848
1849
1850 /**
1851 * Browser feature detection for capabilities, quirks
1852 * @param {object} settings dataTables settings object
1853 * @memberof DataTable#oApi
1854 */
1855 function _fnBrowserDetect( settings )
1856 {
1857 // We don't need to do this every time DataTables is constructed, the values
1858 // calculated are specific to the browser and OS configuration which we
1859 // don't expect to change between initialisations
1860 if ( ! DataTable.__browser ) {
1861 var browser = {};
1862 DataTable.__browser = browser;
1863
1864 // Scrolling feature / quirks detection
1865 var n = $('<div/>')
1866 .css( {
1867 position: 'fixed',
1868 top: 0,
1869 left: $(window).scrollLeft()*-1, // allow for scrolling
1870 height: 1,
1871 width: 1,
1872 overflow: 'hidden'
1873 } )
1874 .append(
1875 $('<div/>')
1876 .css( {
1877 position: 'absolute',
1878 top: 1,
1879 left: 1,
1880 width: 100,
1881 overflow: 'scroll'
1882 } )
1883 .append(
1884 $('<div/>')
1885 .css( {
1886 width: '100%',
1887 height: 10
1888 } )
1889 )
1890 )
1891 .appendTo( 'body' );
1892
1893 var outer = n.children();
1894 var inner = outer.children();
1895
1896 // Numbers below, in order, are:
1897 // inner.offsetWidth, inner.clientWidth, outer.offsetWidth, outer.clientWidth
1898 //
1899 // IE6 XP: 100 100 100 83
1900 // IE7 Vista: 100 100 100 83
1901 // IE 8+ Windows: 83 83 100 83
1902 // Evergreen Windows: 83 83 100 83
1903 // Evergreen Mac with scrollbars: 85 85 100 85
1904 // Evergreen Mac without scrollbars: 100 100 100 100
1905
1906 // Get scrollbar width
1907 browser.barWidth = outer[0].offsetWidth - outer[0].clientWidth;
1908
1909 // IE6/7 will oversize a width 100% element inside a scrolling element, to
1910 // include the width of the scrollbar, while other browsers ensure the inner
1911 // element is contained without forcing scrolling
1912 browser.bScrollOversize = inner[0].offsetWidth === 100 && outer[0].clientWidth !== 100;
1913
1914 // In rtl text layout, some browsers (most, but not all) will place the
1915 // scrollbar on the left, rather than the right.
1916 browser.bScrollbarLeft = Math.round( inner.offset().left ) !== 1;
1917
1918 // IE8- don't provide height and width for getBoundingClientRect
1919 browser.bBounding = n[0].getBoundingClientRect().width ? true : false;
1920
1921 n.remove();
1922 }
1923
1924 $.extend( settings.oBrowser, DataTable.__browser );
1925 settings.oScroll.iBarWidth = DataTable.__browser.barWidth;
1926 }
1927
1928
1929 /**
1930 * Array.prototype reduce[Right] method, used for browsers which don't support
1931 * JS 1.6. Done this way to reduce code size, since we iterate either way
1932 * @param {object} settings dataTables settings object
1933 * @memberof DataTable#oApi
1934 */
1935 function _fnReduce ( that, fn, init, start, end, inc )
1936 {
1937 var
1938 i = start,
1939 value,
1940 isSet = false;
1941
1942 if ( init !== undefined ) {
1943 value = init;
1944 isSet = true;
1945 }
1946
1947 while ( i !== end ) {
1948 if ( ! that.hasOwnProperty(i) ) {
1949 continue;
1950 }
1951
1952 value = isSet ?
1953 fn( value, that[i], i, that ) :
1954 that[i];
1955
1956 isSet = true;
1957 i += inc;
1958 }
1959
1960 return value;
1961 }
1962
1963 /**
1964 * Add a column to the list used for the table with default values
1965 * @param {object} oSettings dataTables settings object
1966 * @param {node} nTh The th element for this column
1967 * @memberof DataTable#oApi
1968 */
1969 function _fnAddColumn( oSettings, nTh )
1970 {
1971 // Add column to aoColumns array
1972 var oDefaults = DataTable.defaults.column;
1973 var iCol = oSettings.aoColumns.length;
1974 var oCol = $.extend( {}, DataTable.models.oColumn, oDefaults, {
1975 "nTh": nTh ? nTh : document.createElement('th'),
1976 "sTitle": oDefaults.sTitle ? oDefaults.sTitle : nTh ? nTh.innerHTML : '',
1977 "aDataSort": oDefaults.aDataSort ? oDefaults.aDataSort : [iCol],
1978 "mData": oDefaults.mData ? oDefaults.mData : iCol,
1979 idx: iCol
1980 } );
1981 oSettings.aoColumns.push( oCol );
1982
1983 // Add search object for column specific search. Note that the `searchCols[ iCol ]`
1984 // passed into extend can be undefined. This allows the user to give a default
1985 // with only some of the parameters defined, and also not give a default
1986 var searchCols = oSettings.aoPreSearchCols;
1987 searchCols[ iCol ] = $.extend( {}, DataTable.models.oSearch, searchCols[ iCol ] );
1988
1989 // Use the default column options function to initialise classes etc
1990 _fnColumnOptions( oSettings, iCol, $(nTh).data() );
1991 }
1992
1993
1994 /**
1995 * Apply options for a column
1996 * @param {object} oSettings dataTables settings object
1997 * @param {int} iCol column index to consider
1998 * @param {object} oOptions object with sType, bVisible and bSearchable etc
1999 * @memberof DataTable#oApi
2000 */
2001 function _fnColumnOptions( oSettings, iCol, oOptions )
2002 {
2003 var oCol = oSettings.aoColumns[ iCol ];
2004 var oClasses = oSettings.oClasses;
2005 var th = $(oCol.nTh);
2006
2007 // Try to get width information from the DOM. We can't get it from CSS
2008 // as we'd need to parse the CSS stylesheet. `width` option can override
2009 if ( ! oCol.sWidthOrig ) {
2010 // Width attribute
2011 oCol.sWidthOrig = th.attr('width') || null;
2012
2013 // Style attribute
2014 var t = (th.attr('style') || '').match(/width:\s*(\d+[pxem%]+)/);
2015 if ( t ) {
2016 oCol.sWidthOrig = t[1];
2017 }
2018 }
2019
2020 /* User specified column options */
2021 if ( oOptions !== undefined && oOptions !== null )
2022 {
2023 // Backwards compatibility
2024 _fnCompatCols( oOptions );
2025
2026 // Map camel case parameters to their Hungarian counterparts
2027 _fnCamelToHungarian( DataTable.defaults.column, oOptions );
2028
2029 /* Backwards compatibility for mDataProp */
2030 if ( oOptions.mDataProp !== undefined && !oOptions.mData )
2031 {
2032 oOptions.mData = oOptions.mDataProp;
2033 }
2034
2035 if ( oOptions.sType )
2036 {
2037 oCol._sManualType = oOptions.sType;
2038 }
2039
2040 // `class` is a reserved word in Javascript, so we need to provide
2041 // the ability to use a valid name for the camel case input
2042 if ( oOptions.className && ! oOptions.sClass )
2043 {
2044 oOptions.sClass = oOptions.className;
2045 }
2046 if ( oOptions.sClass ) {
2047 th.addClass( oOptions.sClass );
2048 }
2049
2050 $.extend( oCol, oOptions );
2051 _fnMap( oCol, oOptions, "sWidth", "sWidthOrig" );
2052
2053 /* iDataSort to be applied (backwards compatibility), but aDataSort will take
2054 * priority if defined
2055 */
2056 if ( oOptions.iDataSort !== undefined )
2057 {
2058 oCol.aDataSort = [ oOptions.iDataSort ];
2059 }
2060 _fnMap( oCol, oOptions, "aDataSort" );
2061 }
2062
2063 /* Cache the data get and set functions for speed */
2064 var mDataSrc = oCol.mData;
2065 var mData = _fnGetObjectDataFn( mDataSrc );
2066 var mRender = oCol.mRender ? _fnGetObjectDataFn( oCol.mRender ) : null;
2067
2068 var attrTest = function( src ) {
2069 return typeof src === 'string' && src.indexOf('@') !== -1;
2070 };
2071 oCol._bAttrSrc = $.isPlainObject( mDataSrc ) && (
2072 attrTest(mDataSrc.sort) || attrTest(mDataSrc.type) || attrTest(mDataSrc.filter)
2073 );
2074 oCol._setter = null;
2075
2076 oCol.fnGetData = function (rowData, type, meta) {
2077 var innerData = mData( rowData, type, undefined, meta );
2078
2079 return mRender && type ?
2080 mRender( innerData, type, rowData, meta ) :
2081 innerData;
2082 };
2083 oCol.fnSetData = function ( rowData, val, meta ) {
2084 return _fnSetObjectDataFn( mDataSrc )( rowData, val, meta );
2085 };
2086
2087 // Indicate if DataTables should read DOM data as an object or array
2088 // Used in _fnGetRowElements
2089 if ( typeof mDataSrc !== 'number' ) {
2090 oSettings._rowReadObject = true;
2091 }
2092
2093 /* Feature sorting overrides column specific when off */
2094 if ( !oSettings.oFeatures.bSort )
2095 {
2096 oCol.bSortable = false;
2097 th.addClass( oClasses.sSortableNone ); // Have to add class here as order event isn't called
2098 }
2099
2100 /* Check that the class assignment is correct for sorting */
2101 var bAsc = $.inArray('asc', oCol.asSorting) !== -1;
2102 var bDesc = $.inArray('desc', oCol.asSorting) !== -1;
2103 if ( !oCol.bSortable || (!bAsc && !bDesc) )
2104 {
2105 oCol.sSortingClass = oClasses.sSortableNone;
2106 oCol.sSortingClassJUI = "";
2107 }
2108 else if ( bAsc && !bDesc )
2109 {
2110 oCol.sSortingClass = oClasses.sSortableAsc;
2111 oCol.sSortingClassJUI = oClasses.sSortJUIAscAllowed;
2112 }
2113 else if ( !bAsc && bDesc )
2114 {
2115 oCol.sSortingClass = oClasses.sSortableDesc;
2116 oCol.sSortingClassJUI = oClasses.sSortJUIDescAllowed;
2117 }
2118 else
2119 {
2120 oCol.sSortingClass = oClasses.sSortable;
2121 oCol.sSortingClassJUI = oClasses.sSortJUI;
2122 }
2123 }
2124
2125
2126 /**
2127 * Adjust the table column widths for new data. Note: you would probably want to
2128 * do a redraw after calling this function!
2129 * @param {object} settings dataTables settings object
2130 * @memberof DataTable#oApi
2131 */
2132 function _fnAdjustColumnSizing ( settings )
2133 {
2134 /* Not interested in doing column width calculation if auto-width is disabled */
2135 if ( settings.oFeatures.bAutoWidth !== false )
2136 {
2137 var columns = settings.aoColumns;
2138
2139 _fnCalculateColumnWidths( settings );
2140 for ( var i=0 , iLen=columns.length ; i<iLen ; i++ )
2141 {
2142 columns[i].nTh.style.width = columns[i].sWidth;
2143 }
2144 }
2145
2146 var scroll = settings.oScroll;
2147 if ( scroll.sY !== '' || scroll.sX !== '')
2148 {
2149 _fnScrollDraw( settings );
2150 }
2151
2152 _fnCallbackFire( settings, null, 'column-sizing', [settings] );
2153 }
2154
2155
2156 /**
2157 * Covert the index of a visible column to the index in the data array (take account
2158 * of hidden columns)
2159 * @param {object} oSettings dataTables settings object
2160 * @param {int} iMatch Visible column index to lookup
2161 * @returns {int} i the data index
2162 * @memberof DataTable#oApi
2163 */
2164 function _fnVisibleToColumnIndex( oSettings, iMatch )
2165 {
2166 var aiVis = _fnGetColumns( oSettings, 'bVisible' );
2167
2168 return typeof aiVis[iMatch] === 'number' ?
2169 aiVis[iMatch] :
2170 null;
2171 }
2172
2173
2174 /**
2175 * Covert the index of an index in the data array and convert it to the visible
2176 * column index (take account of hidden columns)
2177 * @param {int} iMatch Column index to lookup
2178 * @param {object} oSettings dataTables settings object
2179 * @returns {int} i the data index
2180 * @memberof DataTable#oApi
2181 */
2182 function _fnColumnIndexToVisible( oSettings, iMatch )
2183 {
2184 var aiVis = _fnGetColumns( oSettings, 'bVisible' );
2185 var iPos = $.inArray( iMatch, aiVis );
2186
2187 return iPos !== -1 ? iPos : null;
2188 }
2189
2190
2191 /**
2192 * Get the number of visible columns
2193 * @param {object} oSettings dataTables settings object
2194 * @returns {int} i the number of visible columns
2195 * @memberof DataTable#oApi
2196 */
2197 function _fnVisbleColumns( oSettings )
2198 {
2199 var vis = 0;
2200
2201 // No reduce in IE8, use a loop for now
2202 $.each( oSettings.aoColumns, function ( i, col ) {
2203 if ( col.bVisible && $(col.nTh).css('display') !== 'none' ) {
2204 vis++;
2205 }
2206 } );
2207
2208 return vis;
2209 }
2210
2211
2212 /**
2213 * Get an array of column indexes that match a given property
2214 * @param {object} oSettings dataTables settings object
2215 * @param {string} sParam Parameter in aoColumns to look for - typically
2216 * bVisible or bSearchable
2217 * @returns {array} Array of indexes with matched properties
2218 * @memberof DataTable#oApi
2219 */
2220 function _fnGetColumns( oSettings, sParam )
2221 {
2222 var a = [];
2223
2224 $.map( oSettings.aoColumns, function(val, i) {
2225 if ( val[sParam] ) {
2226 a.push( i );
2227 }
2228 } );
2229
2230 return a;
2231 }
2232
2233
2234 /**
2235 * Calculate the 'type' of a column
2236 * @param {object} settings dataTables settings object
2237 * @memberof DataTable#oApi
2238 */
2239 function _fnColumnTypes ( settings )
2240 {
2241 var columns = settings.aoColumns;
2242 var data = settings.aoData;
2243 var types = DataTable.ext.type.detect;
2244 var i, ien, j, jen, k, ken;
2245 var col, cell, detectedType, cache;
2246
2247 // For each column, spin over the
2248 for ( i=0, ien=columns.length ; i<ien ; i++ ) {
2249 col = columns[i];
2250 cache = [];
2251
2252 if ( ! col.sType && col._sManualType ) {
2253 col.sType = col._sManualType;
2254 }
2255 else if ( ! col.sType ) {
2256 for ( j=0, jen=types.length ; j<jen ; j++ ) {
2257 for ( k=0, ken=data.length ; k<ken ; k++ ) {
2258 // Use a cache array so we only need to get the type data
2259 // from the formatter once (when using multiple detectors)
2260 if ( cache[k] === undefined ) {
2261 cache[k] = _fnGetCellData( settings, k, i, 'type' );
2262 }
2263
2264 detectedType = types[j]( cache[k], settings );
2265
2266 // If null, then this type can't apply to this column, so
2267 // rather than testing all cells, break out. There is an
2268 // exception for the last type which is `html`. We need to
2269 // scan all rows since it is possible to mix string and HTML
2270 // types
2271 if ( ! detectedType && j !== types.length-1 ) {
2272 break;
2273 }
2274
2275 // Only a single match is needed for html type since it is
2276 // bottom of the pile and very similar to string
2277 if ( detectedType === 'html' ) {
2278 break;
2279 }
2280 }
2281
2282 // Type is valid for all data points in the column - use this
2283 // type
2284 if ( detectedType ) {
2285 col.sType = detectedType;
2286 break;
2287 }
2288 }
2289
2290 // Fall back - if no type was detected, always use string
2291 if ( ! col.sType ) {
2292 col.sType = 'string';
2293 }
2294 }
2295 }
2296 }
2297
2298
2299 /**
2300 * Take the column definitions and static columns arrays and calculate how
2301 * they relate to column indexes. The callback function will then apply the
2302 * definition found for a column to a suitable configuration object.
2303 * @param {object} oSettings dataTables settings object
2304 * @param {array} aoColDefs The aoColumnDefs array that is to be applied
2305 * @param {array} aoCols The aoColumns array that defines columns individually
2306 * @param {function} fn Callback function - takes two parameters, the calculated
2307 * column index and the definition for that column.
2308 * @memberof DataTable#oApi
2309 */
2310 function _fnApplyColumnDefs( oSettings, aoColDefs, aoCols, fn )
2311 {
2312 var i, iLen, j, jLen, k, kLen, def;
2313 var columns = oSettings.aoColumns;
2314
2315 // Column definitions with aTargets
2316 if ( aoColDefs )
2317 {
2318 /* Loop over the definitions array - loop in reverse so first instance has priority */
2319 for ( i=aoColDefs.length-1 ; i>=0 ; i-- )
2320 {
2321 def = aoColDefs[i];
2322
2323 /* Each definition can target multiple columns, as it is an array */
2324 var aTargets = def.targets !== undefined ?
2325 def.targets :
2326 def.aTargets;
2327
2328 if ( ! $.isArray( aTargets ) )
2329 {
2330 aTargets = [ aTargets ];
2331 }
2332
2333 for ( j=0, jLen=aTargets.length ; j<jLen ; j++ )
2334 {
2335 if ( typeof aTargets[j] === 'number' && aTargets[j] >= 0 )
2336 {
2337 /* Add columns that we don't yet know about */
2338 while( columns.length <= aTargets[j] )
2339 {
2340 _fnAddColumn( oSettings );
2341 }
2342
2343 /* Integer, basic index */
2344 fn( aTargets[j], def );
2345 }
2346 else if ( typeof aTargets[j] === 'number' && aTargets[j] < 0 )
2347 {
2348 /* Negative integer, right to left column counting */
2349 fn( columns.length+aTargets[j], def );
2350 }
2351 else if ( typeof aTargets[j] === 'string' )
2352 {
2353 /* Class name matching on TH element */
2354 for ( k=0, kLen=columns.length ; k<kLen ; k++ )
2355 {
2356 if ( aTargets[j] == "_all" ||
2357 $(columns[k].nTh).hasClass( aTargets[j] ) )
2358 {
2359 fn( k, def );
2360 }
2361 }
2362 }
2363 }
2364 }
2365 }
2366
2367 // Statically defined columns array
2368 if ( aoCols )
2369 {
2370 for ( i=0, iLen=aoCols.length ; i<iLen ; i++ )
2371 {
2372 fn( i, aoCols[i] );
2373 }
2374 }
2375 }
2376
2377 /**
2378 * Add a data array to the table, creating DOM node etc. This is the parallel to
2379 * _fnGatherData, but for adding rows from a Javascript source, rather than a
2380 * DOM source.
2381 * @param {object} oSettings dataTables settings object
2382 * @param {array} aData data array to be added
2383 * @param {node} [nTr] TR element to add to the table - optional. If not given,
2384 * DataTables will create a row automatically
2385 * @param {array} [anTds] Array of TD|TH elements for the row - must be given
2386 * if nTr is.
2387 * @returns {int} >=0 if successful (index of new aoData entry), -1 if failed
2388 * @memberof DataTable#oApi
2389 */
2390 function _fnAddData ( oSettings, aDataIn, nTr, anTds )
2391 {
2392 /* Create the object for storing information about this new row */
2393 var iRow = oSettings.aoData.length;
2394 var oData = $.extend( true, {}, DataTable.models.oRow, {
2395 src: nTr ? 'dom' : 'data',
2396 idx: iRow
2397 } );
2398
2399 oData._aData = aDataIn;
2400 oSettings.aoData.push( oData );
2401
2402 /* Create the cells */
2403 var nTd, sThisType;
2404 var columns = oSettings.aoColumns;
2405
2406 // Invalidate the column types as the new data needs to be revalidated
2407 for ( var i=0, iLen=columns.length ; i<iLen ; i++ )
2408 {
2409 columns[i].sType = null;
2410 }
2411
2412 /* Add to the display array */
2413 oSettings.aiDisplayMaster.push( iRow );
2414
2415 var id = oSettings.rowIdFn( aDataIn );
2416 if ( id !== undefined ) {
2417 oSettings.aIds[ id ] = oData;
2418 }
2419
2420 /* Create the DOM information, or register it if already present */
2421 if ( nTr || ! oSettings.oFeatures.bDeferRender )
2422 {
2423 _fnCreateTr( oSettings, iRow, nTr, anTds );
2424 }
2425
2426 return iRow;
2427 }
2428
2429
2430 /**
2431 * Add one or more TR elements to the table. Generally we'd expect to
2432 * use this for reading data from a DOM sourced table, but it could be
2433 * used for an TR element. Note that if a TR is given, it is used (i.e.
2434 * it is not cloned).
2435 * @param {object} settings dataTables settings object
2436 * @param {array|node|jQuery} trs The TR element(s) to add to the table
2437 * @returns {array} Array of indexes for the added rows
2438 * @memberof DataTable#oApi
2439 */
2440 function _fnAddTr( settings, trs )
2441 {
2442 var row;
2443
2444 // Allow an individual node to be passed in
2445 if ( ! (trs instanceof $) ) {
2446 trs = $(trs);
2447 }
2448
2449 return trs.map( function (i, el) {
2450 row = _fnGetRowElements( settings, el );
2451 return _fnAddData( settings, row.data, el, row.cells );
2452 } );
2453 }
2454
2455
2456 /**
2457 * Take a TR element and convert it to an index in aoData
2458 * @param {object} oSettings dataTables settings object
2459 * @param {node} n the TR element to find
2460 * @returns {int} index if the node is found, null if not
2461 * @memberof DataTable#oApi
2462 */
2463 function _fnNodeToDataIndex( oSettings, n )
2464 {
2465 return (n._DT_RowIndex!==undefined) ? n._DT_RowIndex : null;
2466 }
2467
2468
2469 /**
2470 * Take a TD element and convert it into a column data index (not the visible index)
2471 * @param {object} oSettings dataTables settings object
2472 * @param {int} iRow The row number the TD/TH can be found in
2473 * @param {node} n The TD/TH element to find
2474 * @returns {int} index if the node is found, -1 if not
2475 * @memberof DataTable#oApi
2476 */
2477 function _fnNodeToColumnIndex( oSettings, iRow, n )
2478 {
2479 return $.inArray( n, oSettings.aoData[ iRow ].anCells );
2480 }
2481
2482
2483 /**
2484 * Get the data for a given cell from the internal cache, taking into account data mapping
2485 * @param {object} settings dataTables settings object
2486 * @param {int} rowIdx aoData row id
2487 * @param {int} colIdx Column index
2488 * @param {string} type data get type ('display', 'type' 'filter' 'sort')
2489 * @returns {*} Cell data
2490 * @memberof DataTable#oApi
2491 */
2492 function _fnGetCellData( settings, rowIdx, colIdx, type )
2493 {
2494 var draw = settings.iDraw;
2495 var col = settings.aoColumns[colIdx];
2496 var rowData = settings.aoData[rowIdx]._aData;
2497 var defaultContent = col.sDefaultContent;
2498 var cellData = col.fnGetData( rowData, type, {
2499 settings: settings,
2500 row: rowIdx,
2501 col: colIdx
2502 } );
2503
2504 if ( cellData === undefined ) {
2505 if ( settings.iDrawError != draw && defaultContent === null ) {
2506 _fnLog( settings, 0, "Requested unknown parameter "+
2507 (typeof col.mData=='function' ? '{function}' : "'"+col.mData+"'")+
2508 " for row "+rowIdx+", column "+colIdx, 4 );
2509 settings.iDrawError = draw;
2510 }
2511 return defaultContent;
2512 }
2513
2514 // When the data source is null and a specific data type is requested (i.e.
2515 // not the original data), we can use default column data
2516 if ( (cellData === rowData || cellData === null) && defaultContent !== null && type !== undefined ) {
2517 cellData = defaultContent;
2518 }
2519 else if ( typeof cellData === 'function' ) {
2520 // If the data source is a function, then we run it and use the return,
2521 // executing in the scope of the data object (for instances)
2522 return cellData.call( rowData );
2523 }
2524
2525 if ( cellData === null && type == 'display' ) {
2526 return '';
2527 }
2528 return cellData;
2529 }
2530
2531
2532 /**
2533 * Set the value for a specific cell, into the internal data cache
2534 * @param {object} settings dataTables settings object
2535 * @param {int} rowIdx aoData row id
2536 * @param {int} colIdx Column index
2537 * @param {*} val Value to set
2538 * @memberof DataTable#oApi
2539 */
2540 function _fnSetCellData( settings, rowIdx, colIdx, val )
2541 {
2542 var col = settings.aoColumns[colIdx];
2543 var rowData = settings.aoData[rowIdx]._aData;
2544
2545 col.fnSetData( rowData, val, {
2546 settings: settings,
2547 row: rowIdx,
2548 col: colIdx
2549 } );
2550 }
2551
2552
2553 // Private variable that is used to match action syntax in the data property object
2554 var __reArray = /\[.*?\]$/;
2555 var __reFn = /\(\)$/;
2556
2557 /**
2558 * Split string on periods, taking into account escaped periods
2559 * @param {string} str String to split
2560 * @return {array} Split string
2561 */
2562 function _fnSplitObjNotation( str )
2563 {
2564 return $.map( str.match(/(\\.|[^\.])+/g) || [''], function ( s ) {
2565 return s.replace(/\\\./g, '.');
2566 } );
2567 }
2568
2569
2570 /**
2571 * Return a function that can be used to get data from a source object, taking
2572 * into account the ability to use nested objects as a source
2573 * @param {string|int|function} mSource The data source for the object
2574 * @returns {function} Data get function
2575 * @memberof DataTable#oApi
2576 */
2577 function _fnGetObjectDataFn( mSource )
2578 {
2579 if ( $.isPlainObject( mSource ) )
2580 {
2581 /* Build an object of get functions, and wrap them in a single call */
2582 var o = {};
2583 $.each( mSource, function (key, val) {
2584 if ( val ) {
2585 o[key] = _fnGetObjectDataFn( val );
2586 }
2587 } );
2588
2589 return function (data, type, row, meta) {
2590 var t = o[type] || o._;
2591 return t !== undefined ?
2592 t(data, type, row, meta) :
2593 data;
2594 };
2595 }
2596 else if ( mSource === null )
2597 {
2598 /* Give an empty string for rendering / sorting etc */
2599 return function (data) { // type, row and meta also passed, but not used
2600 return data;
2601 };
2602 }
2603 else if ( typeof mSource === 'function' )
2604 {
2605 return function (data, type, row, meta) {
2606 return mSource( data, type, row, meta );
2607 };
2608 }
2609 else if ( typeof mSource === 'string' && (mSource.indexOf('.') !== -1 ||
2610 mSource.indexOf('[') !== -1 || mSource.indexOf('(') !== -1) )
2611 {
2612 /* If there is a . in the source string then the data source is in a
2613 * nested object so we loop over the data for each level to get the next
2614 * level down. On each loop we test for undefined, and if found immediately
2615 * return. This allows entire objects to be missing and sDefaultContent to
2616 * be used if defined, rather than throwing an error
2617 */
2618 var fetchData = function (data, type, src) {
2619 var arrayNotation, funcNotation, out, innerSrc;
2620
2621 if ( src !== "" )
2622 {
2623 var a = _fnSplitObjNotation( src );
2624
2625 for ( var i=0, iLen=a.length ; i<iLen ; i++ )
2626 {
2627 // Check if we are dealing with special notation
2628 arrayNotation = a[i].match(__reArray);
2629 funcNotation = a[i].match(__reFn);
2630
2631 if ( arrayNotation )
2632 {
2633 // Array notation
2634 a[i] = a[i].replace(__reArray, '');
2635
2636 // Condition allows simply [] to be passed in
2637 if ( a[i] !== "" ) {
2638 data = data[ a[i] ];
2639 }
2640 out = [];
2641
2642 // Get the remainder of the nested object to get
2643 a.splice( 0, i+1 );
2644 innerSrc = a.join('.');
2645
2646 // Traverse each entry in the array getting the properties requested
2647 if ( $.isArray( data ) ) {
2648 for ( var j=0, jLen=data.length ; j<jLen ; j++ ) {
2649 out.push( fetchData( data[j], type, innerSrc ) );
2650 }
2651 }
2652
2653 // If a string is given in between the array notation indicators, that
2654 // is used to join the strings together, otherwise an array is returned
2655 var join = arrayNotation[0].substring(1, arrayNotation[0].length-1);
2656 data = (join==="") ? out : out.join(join);
2657
2658 // The inner call to fetchData has already traversed through the remainder
2659 // of the source requested, so we exit from the loop
2660 break;
2661 }
2662 else if ( funcNotation )
2663 {
2664 // Function call
2665 a[i] = a[i].replace(__reFn, '');
2666 data = data[ a[i] ]();
2667 continue;
2668 }
2669
2670 if ( data === null || data[ a[i] ] === undefined )
2671 {
2672 return undefined;
2673 }
2674 data = data[ a[i] ];
2675 }
2676 }
2677
2678 return data;
2679 };
2680
2681 return function (data, type) { // row and meta also passed, but not used
2682 return fetchData( data, type, mSource );
2683 };
2684 }
2685 else
2686 {
2687 /* Array or flat object mapping */
2688 return function (data, type) { // row and meta also passed, but not used
2689 return data[mSource];
2690 };
2691 }
2692 }
2693
2694
2695 /**
2696 * Return a function that can be used to set data from a source object, taking
2697 * into account the ability to use nested objects as a source
2698 * @param {string|int|function} mSource The data source for the object
2699 * @returns {function} Data set function
2700 * @memberof DataTable#oApi
2701 */
2702 function _fnSetObjectDataFn( mSource )
2703 {
2704 if ( $.isPlainObject( mSource ) )
2705 {
2706 /* Unlike get, only the underscore (global) option is used for for
2707 * setting data since we don't know the type here. This is why an object
2708 * option is not documented for `mData` (which is read/write), but it is
2709 * for `mRender` which is read only.
2710 */
2711 return _fnSetObjectDataFn( mSource._ );
2712 }
2713 else if ( mSource === null )
2714 {
2715 /* Nothing to do when the data source is null */
2716 return function () {};
2717 }
2718 else if ( typeof mSource === 'function' )
2719 {
2720 return function (data, val, meta) {
2721 mSource( data, 'set', val, meta );
2722 };
2723 }
2724 else if ( typeof mSource === 'string' && (mSource.indexOf('.') !== -1 ||
2725 mSource.indexOf('[') !== -1 || mSource.indexOf('(') !== -1) )
2726 {
2727 /* Like the get, we need to get data from a nested object */
2728 var setData = function (data, val, src) {
2729 var a = _fnSplitObjNotation( src ), b;
2730 var aLast = a[a.length-1];
2731 var arrayNotation, funcNotation, o, innerSrc;
2732
2733 for ( var i=0, iLen=a.length-1 ; i<iLen ; i++ )
2734 {
2735 // Check if we are dealing with an array notation request
2736 arrayNotation = a[i].match(__reArray);
2737 funcNotation = a[i].match(__reFn);
2738
2739 if ( arrayNotation )
2740 {
2741 a[i] = a[i].replace(__reArray, '');
2742 data[ a[i] ] = [];
2743
2744 // Get the remainder of the nested object to set so we can recurse
2745 b = a.slice();
2746 b.splice( 0, i+1 );
2747 innerSrc = b.join('.');
2748
2749 // Traverse each entry in the array setting the properties requested
2750 if ( $.isArray( val ) )
2751 {
2752 for ( var j=0, jLen=val.length ; j<jLen ; j++ )
2753 {
2754 o = {};
2755 setData( o, val[j], innerSrc );
2756 data[ a[i] ].push( o );
2757 }
2758 }
2759 else
2760 {
2761 // We've been asked to save data to an array, but it
2762 // isn't array data to be saved. Best that can be done
2763 // is to just save the value.
2764 data[ a[i] ] = val;
2765 }
2766
2767 // The inner call to setData has already traversed through the remainder
2768 // of the source and has set the data, thus we can exit here
2769 return;
2770 }
2771 else if ( funcNotation )
2772 {
2773 // Function call
2774 a[i] = a[i].replace(__reFn, '');
2775 data = data[ a[i] ]( val );
2776 }
2777
2778 // If the nested object doesn't currently exist - since we are
2779 // trying to set the value - create it
2780 if ( data[ a[i] ] === null || data[ a[i] ] === undefined )
2781 {
2782 data[ a[i] ] = {};
2783 }
2784 data = data[ a[i] ];
2785 }
2786
2787 // Last item in the input - i.e, the actual set
2788 if ( aLast.match(__reFn ) )
2789 {
2790 // Function call
2791 data = data[ aLast.replace(__reFn, '') ]( val );
2792 }
2793 else
2794 {
2795 // If array notation is used, we just want to strip it and use the property name
2796 // and assign the value. If it isn't used, then we get the result we want anyway
2797 data[ aLast.replace(__reArray, '') ] = val;
2798 }
2799 };
2800
2801 return function (data, val) { // meta is also passed in, but not used
2802 return setData( data, val, mSource );
2803 };
2804 }
2805 else
2806 {
2807 /* Array or flat object mapping */
2808 return function (data, val) { // meta is also passed in, but not used
2809 data[mSource] = val;
2810 };
2811 }
2812 }
2813
2814
2815 /**
2816 * Return an array with the full table data
2817 * @param {object} oSettings dataTables settings object
2818 * @returns array {array} aData Master data array
2819 * @memberof DataTable#oApi
2820 */
2821 function _fnGetDataMaster ( settings )
2822 {
2823 return _pluck( settings.aoData, '_aData' );
2824 }
2825
2826
2827 /**
2828 * Nuke the table
2829 * @param {object} oSettings dataTables settings object
2830 * @memberof DataTable#oApi
2831 */
2832 function _fnClearTable( settings )
2833 {
2834 settings.aoData.length = 0;
2835 settings.aiDisplayMaster.length = 0;
2836 settings.aiDisplay.length = 0;
2837 settings.aIds = {};
2838 }
2839
2840
2841 /**
2842 * Take an array of integers (index array) and remove a target integer (value - not
2843 * the key!)
2844 * @param {array} a Index array to target
2845 * @param {int} iTarget value to find
2846 * @memberof DataTable#oApi
2847 */
2848 function _fnDeleteIndex( a, iTarget, splice )
2849 {
2850 var iTargetIndex = -1;
2851
2852 for ( var i=0, iLen=a.length ; i<iLen ; i++ )
2853 {
2854 if ( a[i] == iTarget )
2855 {
2856 iTargetIndex = i;
2857 }
2858 else if ( a[i] > iTarget )
2859 {
2860 a[i]--;
2861 }
2862 }
2863
2864 if ( iTargetIndex != -1 && splice === undefined )
2865 {
2866 a.splice( iTargetIndex, 1 );
2867 }
2868 }
2869
2870
2871 /**
2872 * Mark cached data as invalid such that a re-read of the data will occur when
2873 * the cached data is next requested. Also update from the data source object.
2874 *
2875 * @param {object} settings DataTables settings object
2876 * @param {int} rowIdx Row index to invalidate
2877 * @param {string} [src] Source to invalidate from: undefined, 'auto', 'dom'
2878 * or 'data'
2879 * @param {int} [colIdx] Column index to invalidate. If undefined the whole
2880 * row will be invalidated
2881 * @memberof DataTable#oApi
2882 *
2883 * @todo For the modularisation of v1.11 this will need to become a callback, so
2884 * the sort and filter methods can subscribe to it. That will required
2885 * initialisation options for sorting, which is why it is not already baked in
2886 */
2887 function _fnInvalidate( settings, rowIdx, src, colIdx )
2888 {
2889 var row = settings.aoData[ rowIdx ];
2890 var i, ien;
2891 var cellWrite = function ( cell, col ) {
2892 // This is very frustrating, but in IE if you just write directly
2893 // to innerHTML, and elements that are overwritten are GC'ed,
2894 // even if there is a reference to them elsewhere
2895 while ( cell.childNodes.length ) {
2896 cell.removeChild( cell.firstChild );
2897 }
2898
2899 cell.innerHTML = _fnGetCellData( settings, rowIdx, col, 'display' );
2900 };
2901
2902 // Are we reading last data from DOM or the data object?
2903 if ( src === 'dom' || ((! src || src === 'auto') && row.src === 'dom') ) {
2904 // Read the data from the DOM
2905 row._aData = _fnGetRowElements(
2906 settings, row, colIdx, colIdx === undefined ? undefined : row._aData
2907 )
2908 .data;
2909 }
2910 else {
2911 // Reading from data object, update the DOM
2912 var cells = row.anCells;
2913
2914 if ( cells ) {
2915 if ( colIdx !== undefined ) {
2916 cellWrite( cells[colIdx], colIdx );
2917 }
2918 else {
2919 for ( i=0, ien=cells.length ; i<ien ; i++ ) {
2920 cellWrite( cells[i], i );
2921 }
2922 }
2923 }
2924 }
2925
2926 // For both row and cell invalidation, the cached data for sorting and
2927 // filtering is nulled out
2928 row._aSortData = null;
2929 row._aFilterData = null;
2930
2931 // Invalidate the type for a specific column (if given) or all columns since
2932 // the data might have changed
2933 var cols = settings.aoColumns;
2934 if ( colIdx !== undefined ) {
2935 cols[ colIdx ].sType = null;
2936 }
2937 else {
2938 for ( i=0, ien=cols.length ; i<ien ; i++ ) {
2939 cols[i].sType = null;
2940 }
2941
2942 // Update DataTables special `DT_*` attributes for the row
2943 _fnRowAttributes( settings, row );
2944 }
2945 }
2946
2947
2948 /**
2949 * Build a data source object from an HTML row, reading the contents of the
2950 * cells that are in the row.
2951 *
2952 * @param {object} settings DataTables settings object
2953 * @param {node|object} TR element from which to read data or existing row
2954 * object from which to re-read the data from the cells
2955 * @param {int} [colIdx] Optional column index
2956 * @param {array|object} [d] Data source object. If `colIdx` is given then this
2957 * parameter should also be given and will be used to write the data into.
2958 * Only the column in question will be written
2959 * @returns {object} Object with two parameters: `data` the data read, in
2960 * document order, and `cells` and array of nodes (they can be useful to the
2961 * caller, so rather than needing a second traversal to get them, just return
2962 * them from here).
2963 * @memberof DataTable#oApi
2964 */
2965 function _fnGetRowElements( settings, row, colIdx, d )
2966 {
2967 var
2968 tds = [],
2969 td = row.firstChild,
2970 name, col, o, i=0, contents,
2971 columns = settings.aoColumns,
2972 objectRead = settings._rowReadObject;
2973
2974 // Allow the data object to be passed in, or construct
2975 d = d !== undefined ?
2976 d :
2977 objectRead ?
2978 {} :
2979 [];
2980
2981 var attr = function ( str, td ) {
2982 if ( typeof str === 'string' ) {
2983 var idx = str.indexOf('@');
2984
2985 if ( idx !== -1 ) {
2986 var attr = str.substring( idx+1 );
2987 var setter = _fnSetObjectDataFn( str );
2988 setter( d, td.getAttribute( attr ) );
2989 }
2990 }
2991 };
2992
2993 // Read data from a cell and store into the data object
2994 var cellProcess = function ( cell ) {
2995 if ( colIdx === undefined || colIdx === i ) {
2996 col = columns[i];
2997 contents = $.trim(cell.innerHTML);
2998
2999 if ( col && col._bAttrSrc ) {
3000 var setter = _fnSetObjectDataFn( col.mData._ );
3001 setter( d, contents );
3002
3003 attr( col.mData.sort, cell );
3004 attr( col.mData.type, cell );
3005 attr( col.mData.filter, cell );
3006 }
3007 else {
3008 // Depending on the `data` option for the columns the data can
3009 // be read to either an object or an array.
3010 if ( objectRead ) {
3011 if ( ! col._setter ) {
3012 // Cache the setter function
3013 col._setter = _fnSetObjectDataFn( col.mData );
3014 }
3015 col._setter( d, contents );
3016 }
3017 else {
3018 d[i] = contents;
3019 }
3020 }
3021 }
3022
3023 i++;
3024 };
3025
3026 if ( td ) {
3027 // `tr` element was passed in
3028 while ( td ) {
3029 name = td.nodeName.toUpperCase();
3030
3031 if ( name == "TD" || name == "TH" ) {
3032 cellProcess( td );
3033 tds.push( td );
3034 }
3035
3036 td = td.nextSibling;
3037 }
3038 }
3039 else {
3040 // Existing row object passed in
3041 tds = row.anCells;
3042
3043 for ( var j=0, jen=tds.length ; j<jen ; j++ ) {
3044 cellProcess( tds[j] );
3045 }
3046 }
3047
3048 // Read the ID from the DOM if present
3049 var rowNode = row.firstChild ? row : row.nTr;
3050
3051 if ( rowNode ) {
3052 var id = rowNode.getAttribute( 'id' );
3053
3054 if ( id ) {
3055 _fnSetObjectDataFn( settings.rowId )( d, id );
3056 }
3057 }
3058
3059 return {
3060 data: d,
3061 cells: tds
3062 };
3063 }
3064 /**
3065 * Create a new TR element (and it's TD children) for a row
3066 * @param {object} oSettings dataTables settings object
3067 * @param {int} iRow Row to consider
3068 * @param {node} [nTrIn] TR element to add to the table - optional. If not given,
3069 * DataTables will create a row automatically
3070 * @param {array} [anTds] Array of TD|TH elements for the row - must be given
3071 * if nTr is.
3072 * @memberof DataTable#oApi
3073 */
3074 function _fnCreateTr ( oSettings, iRow, nTrIn, anTds )
3075 {
3076 var
3077 row = oSettings.aoData[iRow],
3078 rowData = row._aData,
3079 cells = [],
3080 nTr, nTd, oCol,
3081 i, iLen;
3082
3083 if ( row.nTr === null )
3084 {
3085 nTr = nTrIn || document.createElement('tr');
3086
3087 row.nTr = nTr;
3088 row.anCells = cells;
3089
3090 /* Use a private property on the node to allow reserve mapping from the node
3091 * to the aoData array for fast look up
3092 */
3093 nTr._DT_RowIndex = iRow;
3094
3095 /* Special parameters can be given by the data source to be used on the row */
3096 _fnRowAttributes( oSettings, row );
3097
3098 /* Process each column */
3099 for ( i=0, iLen=oSettings.aoColumns.length ; i<iLen ; i++ )
3100 {
3101 oCol = oSettings.aoColumns[i];
3102
3103 nTd = nTrIn ? anTds[i] : document.createElement( oCol.sCellType );
3104 nTd._DT_CellIndex = {
3105 row: iRow,
3106 column: i
3107 };
3108
3109 cells.push( nTd );
3110
3111 // Need to create the HTML if new, or if a rendering function is defined
3112 if ( (!nTrIn || oCol.mRender || oCol.mData !== i) &&
3113 (!$.isPlainObject(oCol.mData) || oCol.mData._ !== i+'.display')
3114 ) {
3115 nTd.innerHTML = _fnGetCellData( oSettings, iRow, i, 'display' );
3116 }
3117
3118 /* Add user defined class */
3119 if ( oCol.sClass )
3120 {
3121 nTd.className += ' '+oCol.sClass;
3122 }
3123
3124 // Visibility - add or remove as required
3125 if ( oCol.bVisible && ! nTrIn )
3126 {
3127 nTr.appendChild( nTd );
3128 }
3129 else if ( ! oCol.bVisible && nTrIn )
3130 {
3131 nTd.parentNode.removeChild( nTd );
3132 }
3133
3134 if ( oCol.fnCreatedCell )
3135 {
3136 oCol.fnCreatedCell.call( oSettings.oInstance,
3137 nTd, _fnGetCellData( oSettings, iRow, i ), rowData, iRow, i
3138 );
3139 }
3140 }
3141
3142 _fnCallbackFire( oSettings, 'aoRowCreatedCallback', null, [nTr, rowData, iRow, cells] );
3143 }
3144
3145 // Remove once webkit bug 131819 and Chromium bug 365619 have been resolved
3146 // and deployed
3147 row.nTr.setAttribute( 'role', 'row' );
3148 }
3149
3150
3151 /**
3152 * Add attributes to a row based on the special `DT_*` parameters in a data
3153 * source object.
3154 * @param {object} settings DataTables settings object
3155 * @param {object} DataTables row object for the row to be modified
3156 * @memberof DataTable#oApi
3157 */
3158 function _fnRowAttributes( settings, row )
3159 {
3160 var tr = row.nTr;
3161 var data = row._aData;
3162
3163 if ( tr ) {
3164 var id = settings.rowIdFn( data );
3165
3166 if ( id ) {
3167 tr.id = id;
3168 }
3169
3170 if ( data.DT_RowClass ) {
3171 // Remove any classes added by DT_RowClass before
3172 var a = data.DT_RowClass.split(' ');
3173 row.__rowc = row.__rowc ?
3174 _unique( row.__rowc.concat( a ) ) :
3175 a;
3176
3177 $(tr)
3178 .removeClass( row.__rowc.join(' ') )
3179 .addClass( data.DT_RowClass );
3180 }
3181
3182 if ( data.DT_RowAttr ) {
3183 $(tr).attr( data.DT_RowAttr );
3184 }
3185
3186 if ( data.DT_RowData ) {
3187 $(tr).data( data.DT_RowData );
3188 }
3189 }
3190 }
3191
3192
3193 /**
3194 * Create the HTML header for the table
3195 * @param {object} oSettings dataTables settings object
3196 * @memberof DataTable#oApi
3197 */
3198 function _fnBuildHead( oSettings )
3199 {
3200 var i, ien, cell, row, column;
3201 var thead = oSettings.nTHead;
3202 var tfoot = oSettings.nTFoot;
3203 var createHeader = $('th, td', thead).length === 0;
3204 var classes = oSettings.oClasses;
3205 var columns = oSettings.aoColumns;
3206
3207 if ( createHeader ) {
3208 row = $('<tr/>').appendTo( thead );
3209 }
3210
3211 for ( i=0, ien=columns.length ; i<ien ; i++ ) {
3212 column = columns[i];
3213 cell = $( column.nTh ).addClass( column.sClass );
3214
3215 if ( createHeader ) {
3216 cell.appendTo( row );
3217 }
3218
3219 // 1.11 move into sorting
3220 if ( oSettings.oFeatures.bSort ) {
3221 cell.addClass( column.sSortingClass );
3222
3223 if ( column.bSortable !== false ) {
3224 cell
3225 .attr( 'tabindex', oSettings.iTabIndex )
3226 .attr( 'aria-controls', oSettings.sTableId );
3227
3228 _fnSortAttachListener( oSettings, column.nTh, i );
3229 }
3230 }
3231
3232 if ( column.sTitle != cell[0].innerHTML ) {
3233 cell.html( column.sTitle );
3234 }
3235
3236 _fnRenderer( oSettings, 'header' )(
3237 oSettings, cell, column, classes
3238 );
3239 }
3240
3241 if ( createHeader ) {
3242 _fnDetectHeader( oSettings.aoHeader, thead );
3243 }
3244
3245 /* ARIA role for the rows */
3246 $(thead).find('>tr').attr('role', 'row');
3247
3248 /* Deal with the footer - add classes if required */
3249 $(thead).find('>tr>th, >tr>td').addClass( classes.sHeaderTH );
3250 $(tfoot).find('>tr>th, >tr>td').addClass( classes.sFooterTH );
3251
3252 // Cache the footer cells. Note that we only take the cells from the first
3253 // row in the footer. If there is more than one row the user wants to
3254 // interact with, they need to use the table().foot() method. Note also this
3255 // allows cells to be used for multiple columns using colspan
3256 if ( tfoot !== null ) {
3257 var cells = oSettings.aoFooter[0];
3258
3259 for ( i=0, ien=cells.length ; i<ien ; i++ ) {
3260 column = columns[i];
3261 column.nTf = cells[i].cell;
3262
3263 if ( column.sClass ) {
3264 $(column.nTf).addClass( column.sClass );
3265 }
3266 }
3267 }
3268 }
3269
3270
3271 /**
3272 * Draw the header (or footer) element based on the column visibility states. The
3273 * methodology here is to use the layout array from _fnDetectHeader, modified for
3274 * the instantaneous column visibility, to construct the new layout. The grid is
3275 * traversed over cell at a time in a rows x columns grid fashion, although each
3276 * cell insert can cover multiple elements in the grid - which is tracks using the
3277 * aApplied array. Cell inserts in the grid will only occur where there isn't
3278 * already a cell in that position.
3279 * @param {object} oSettings dataTables settings object
3280 * @param array {objects} aoSource Layout array from _fnDetectHeader
3281 * @param {boolean} [bIncludeHidden=false] If true then include the hidden columns in the calc,
3282 * @memberof DataTable#oApi
3283 */
3284 function _fnDrawHead( oSettings, aoSource, bIncludeHidden )
3285 {
3286 var i, iLen, j, jLen, k, kLen, n, nLocalTr;
3287 var aoLocal = [];
3288 var aApplied = [];
3289 var iColumns = oSettings.aoColumns.length;
3290 var iRowspan, iColspan;
3291
3292 if ( ! aoSource )
3293 {
3294 return;
3295 }
3296
3297 if ( bIncludeHidden === undefined )
3298 {
3299 bIncludeHidden = false;
3300 }
3301
3302 /* Make a copy of the master layout array, but without the visible columns in it */
3303 for ( i=0, iLen=aoSource.length ; i<iLen ; i++ )
3304 {
3305 aoLocal[i] = aoSource[i].slice();
3306 aoLocal[i].nTr = aoSource[i].nTr;
3307
3308 /* Remove any columns which are currently hidden */
3309 for ( j=iColumns-1 ; j>=0 ; j-- )
3310 {
3311 if ( !oSettings.aoColumns[j].bVisible && !bIncludeHidden )
3312 {
3313 aoLocal[i].splice( j, 1 );
3314 }
3315 }
3316
3317 /* Prep the applied array - it needs an element for each row */
3318 aApplied.push( [] );
3319 }
3320
3321 for ( i=0, iLen=aoLocal.length ; i<iLen ; i++ )
3322 {
3323 nLocalTr = aoLocal[i].nTr;
3324
3325 /* All cells are going to be replaced, so empty out the row */
3326 if ( nLocalTr )
3327 {
3328 while( (n = nLocalTr.firstChild) )
3329 {
3330 nLocalTr.removeChild( n );
3331 }
3332 }
3333
3334 for ( j=0, jLen=aoLocal[i].length ; j<jLen ; j++ )
3335 {
3336 iRowspan = 1;
3337 iColspan = 1;
3338
3339 /* Check to see if there is already a cell (row/colspan) covering our target
3340 * insert point. If there is, then there is nothing to do.
3341 */
3342 if ( aApplied[i][j] === undefined )
3343 {
3344 nLocalTr.appendChild( aoLocal[i][j].cell );
3345 aApplied[i][j] = 1;
3346
3347 /* Expand the cell to cover as many rows as needed */
3348 while ( aoLocal[i+iRowspan] !== undefined &&
3349 aoLocal[i][j].cell == aoLocal[i+iRowspan][j].cell )
3350 {
3351 aApplied[i+iRowspan][j] = 1;
3352 iRowspan++;
3353 }
3354
3355 /* Expand the cell to cover as many columns as needed */
3356 while ( aoLocal[i][j+iColspan] !== undefined &&
3357 aoLocal[i][j].cell == aoLocal[i][j+iColspan].cell )
3358 {
3359 /* Must update the applied array over the rows for the columns */
3360 for ( k=0 ; k<iRowspan ; k++ )
3361 {
3362 aApplied[i+k][j+iColspan] = 1;
3363 }
3364 iColspan++;
3365 }
3366
3367 /* Do the actual expansion in the DOM */
3368 $(aoLocal[i][j].cell)
3369 .attr('rowspan', iRowspan)
3370 .attr('colspan', iColspan);
3371 }
3372 }
3373 }
3374 }
3375
3376
3377 /**
3378 * Insert the required TR nodes into the table for display
3379 * @param {object} oSettings dataTables settings object
3380 * @memberof DataTable#oApi
3381 */
3382 function _fnDraw( oSettings )
3383 {
3384 /* Provide a pre-callback function which can be used to cancel the draw is false is returned */
3385 var aPreDraw = _fnCallbackFire( oSettings, 'aoPreDrawCallback', 'preDraw', [oSettings] );
3386 if ( $.inArray( false, aPreDraw ) !== -1 )
3387 {
3388 _fnProcessingDisplay( oSettings, false );
3389 return;
3390 }
3391
3392 var i, iLen, n;
3393 var anRows = [];
3394 var iRowCount = 0;
3395 var asStripeClasses = oSettings.asStripeClasses;
3396 var iStripes = asStripeClasses.length;
3397 var iOpenRows = oSettings.aoOpenRows.length;
3398 var oLang = oSettings.oLanguage;
3399 var iInitDisplayStart = oSettings.iInitDisplayStart;
3400 var bServerSide = _fnDataSource( oSettings ) == 'ssp';
3401 var aiDisplay = oSettings.aiDisplay;
3402
3403 oSettings.bDrawing = true;
3404
3405 /* Check and see if we have an initial draw position from state saving */
3406 if ( iInitDisplayStart !== undefined && iInitDisplayStart !== -1 )
3407 {
3408 oSettings._iDisplayStart = bServerSide ?
3409 iInitDisplayStart :
3410 iInitDisplayStart >= oSettings.fnRecordsDisplay() ?
3411 0 :
3412 iInitDisplayStart;
3413
3414 oSettings.iInitDisplayStart = -1;
3415 }
3416
3417 var iDisplayStart = oSettings._iDisplayStart;
3418 var iDisplayEnd = oSettings.fnDisplayEnd();
3419
3420 /* Server-side processing draw intercept */
3421 if ( oSettings.bDeferLoading )
3422 {
3423 oSettings.bDeferLoading = false;
3424 oSettings.iDraw++;
3425 _fnProcessingDisplay( oSettings, false );
3426 }
3427 else if ( !bServerSide )
3428 {
3429 oSettings.iDraw++;
3430 }
3431 else if ( !oSettings.bDestroying && !_fnAjaxUpdate( oSettings ) )
3432 {
3433 return;
3434 }
3435
3436 if ( aiDisplay.length !== 0 )
3437 {
3438 var iStart = bServerSide ? 0 : iDisplayStart;
3439 var iEnd = bServerSide ? oSettings.aoData.length : iDisplayEnd;
3440
3441 for ( var j=iStart ; j<iEnd ; j++ )
3442 {
3443 var iDataIndex = aiDisplay[j];
3444 var aoData = oSettings.aoData[ iDataIndex ];
3445 if ( aoData.nTr === null )
3446 {
3447 _fnCreateTr( oSettings, iDataIndex );
3448 }
3449
3450 var nRow = aoData.nTr;
3451
3452 /* Remove the old striping classes and then add the new one */
3453 if ( iStripes !== 0 )
3454 {
3455 var sStripe = asStripeClasses[ iRowCount % iStripes ];
3456 if ( aoData._sRowStripe != sStripe )
3457 {
3458 $(nRow).removeClass( aoData._sRowStripe ).addClass( sStripe );
3459 aoData._sRowStripe = sStripe;
3460 }
3461 }
3462
3463 // Row callback functions - might want to manipulate the row
3464 // iRowCount and j are not currently documented. Are they at all
3465 // useful?
3466 _fnCallbackFire( oSettings, 'aoRowCallback', null,
3467 [nRow, aoData._aData, iRowCount, j, iDataIndex] );
3468
3469 anRows.push( nRow );
3470 iRowCount++;
3471 }
3472 }
3473 else
3474 {
3475 /* Table is empty - create a row with an empty message in it */
3476 var sZero = oLang.sZeroRecords;
3477 if ( oSettings.iDraw == 1 && _fnDataSource( oSettings ) == 'ajax' )
3478 {
3479 sZero = oLang.sLoadingRecords;
3480 }
3481 else if ( oLang.sEmptyTable && oSettings.fnRecordsTotal() === 0 )
3482 {
3483 sZero = oLang.sEmptyTable;
3484 }
3485
3486 anRows[ 0 ] = $( '<tr/>', { 'class': iStripes ? asStripeClasses[0] : '' } )
3487 .append( $('<td />', {
3488 'valign': 'top',
3489 'colSpan': _fnVisbleColumns( oSettings ),
3490 'class': oSettings.oClasses.sRowEmpty
3491 } ).html( sZero ) )[0];
3492 }
3493
3494 /* Header and footer callbacks */
3495 _fnCallbackFire( oSettings, 'aoHeaderCallback', 'header', [ $(oSettings.nTHead).children('tr')[0],
3496 _fnGetDataMaster( oSettings ), iDisplayStart, iDisplayEnd, aiDisplay ] );
3497
3498 _fnCallbackFire( oSettings, 'aoFooterCallback', 'footer', [ $(oSettings.nTFoot).children('tr')[0],
3499 _fnGetDataMaster( oSettings ), iDisplayStart, iDisplayEnd, aiDisplay ] );
3500
3501 var body = $(oSettings.nTBody);
3502
3503 body.children().detach();
3504 body.append( $(anRows) );
3505
3506 /* Call all required callback functions for the end of a draw */
3507 _fnCallbackFire( oSettings, 'aoDrawCallback', 'draw', [oSettings] );
3508
3509 /* Draw is complete, sorting and filtering must be as well */
3510 oSettings.bSorted = false;
3511 oSettings.bFiltered = false;
3512 oSettings.bDrawing = false;
3513 }
3514
3515
3516 /**
3517 * Redraw the table - taking account of the various features which are enabled
3518 * @param {object} oSettings dataTables settings object
3519 * @param {boolean} [holdPosition] Keep the current paging position. By default
3520 * the paging is reset to the first page
3521 * @memberof DataTable#oApi
3522 */
3523 function _fnReDraw( settings, holdPosition )
3524 {
3525 var
3526 features = settings.oFeatures,
3527 sort = features.bSort,
3528 filter = features.bFilter;
3529
3530 if ( sort ) {
3531 _fnSort( settings );
3532 }
3533
3534 if ( filter ) {
3535 _fnFilterComplete( settings, settings.oPreviousSearch );
3536 }
3537 else {
3538 // No filtering, so we want to just use the display master
3539 settings.aiDisplay = settings.aiDisplayMaster.slice();
3540 }
3541
3542 if ( holdPosition !== true ) {
3543 settings._iDisplayStart = 0;
3544 }
3545
3546 // Let any modules know about the draw hold position state (used by
3547 // scrolling internally)
3548 settings._drawHold = holdPosition;
3549
3550 _fnDraw( settings );
3551
3552 settings._drawHold = false;
3553 }
3554
3555
3556 /**
3557 * Add the options to the page HTML for the table
3558 * @param {object} oSettings dataTables settings object
3559 * @memberof DataTable#oApi
3560 */
3561 function _fnAddOptionsHtml ( oSettings )
3562 {
3563 var classes = oSettings.oClasses;
3564 var table = $(oSettings.nTable);
3565 var holding = $('<div/>').insertBefore( table ); // Holding element for speed
3566 var features = oSettings.oFeatures;
3567
3568 // All DataTables are wrapped in a div
3569 var insert = $('<div/>', {
3570 id: oSettings.sTableId+'_wrapper',
3571 'class': classes.sWrapper + (oSettings.nTFoot ? '' : ' '+classes.sNoFooter)
3572 } );
3573
3574 oSettings.nHolding = holding[0];
3575 oSettings.nTableWrapper = insert[0];
3576 oSettings.nTableReinsertBefore = oSettings.nTable.nextSibling;
3577
3578 /* Loop over the user set positioning and place the elements as needed */
3579 var aDom = oSettings.sDom.split('');
3580 var featureNode, cOption, nNewNode, cNext, sAttr, j;
3581 for ( var i=0 ; i<aDom.length ; i++ )
3582 {
3583 featureNode = null;
3584 cOption = aDom[i];
3585
3586 if ( cOption == '<' )
3587 {
3588 /* New container div */
3589 nNewNode = $('<div/>')[0];
3590
3591 /* Check to see if we should append an id and/or a class name to the container */
3592 cNext = aDom[i+1];
3593 if ( cNext == "'" || cNext == '"' )
3594 {
3595 sAttr = "";
3596 j = 2;
3597 while ( aDom[i+j] != cNext )
3598 {
3599 sAttr += aDom[i+j];
3600 j++;
3601 }
3602
3603 /* Replace jQuery UI constants @todo depreciated */
3604 if ( sAttr == "H" )
3605 {
3606 sAttr = classes.sJUIHeader;
3607 }
3608 else if ( sAttr == "F" )
3609 {
3610 sAttr = classes.sJUIFooter;
3611 }
3612
3613 /* The attribute can be in the format of "#id.class", "#id" or "class" This logic
3614 * breaks the string into parts and applies them as needed
3615 */
3616 if ( sAttr.indexOf('.') != -1 )
3617 {
3618 var aSplit = sAttr.split('.');
3619 nNewNode.id = aSplit[0].substr(1, aSplit[0].length-1);
3620 nNewNode.className = aSplit[1];
3621 }
3622 else if ( sAttr.charAt(0) == "#" )
3623 {
3624 nNewNode.id = sAttr.substr(1, sAttr.length-1);
3625 }
3626 else
3627 {
3628 nNewNode.className = sAttr;
3629 }
3630
3631 i += j; /* Move along the position array */
3632 }
3633
3634 insert.append( nNewNode );
3635 insert = $(nNewNode);
3636 }
3637 else if ( cOption == '>' )
3638 {
3639 /* End container div */
3640 insert = insert.parent();
3641 }
3642 // @todo Move options into their own plugins?
3643 else if ( cOption == 'l' && features.bPaginate && features.bLengthChange )
3644 {
3645 /* Length */
3646 featureNode = _fnFeatureHtmlLength( oSettings );
3647 }
3648 else if ( cOption == 'f' && features.bFilter )
3649 {
3650 /* Filter */
3651 featureNode = _fnFeatureHtmlFilter( oSettings );
3652 }
3653 else if ( cOption == 'r' && features.bProcessing )
3654 {
3655 /* pRocessing */
3656 featureNode = _fnFeatureHtmlProcessing( oSettings );
3657 }
3658 else if ( cOption == 't' )
3659 {
3660 /* Table */
3661 featureNode = _fnFeatureHtmlTable( oSettings );
3662 }
3663 else if ( cOption == 'i' && features.bInfo )
3664 {
3665 /* Info */
3666 featureNode = _fnFeatureHtmlInfo( oSettings );
3667 }
3668 else if ( cOption == 'p' && features.bPaginate )
3669 {
3670 /* Pagination */
3671 featureNode = _fnFeatureHtmlPaginate( oSettings );
3672 }
3673 else if ( DataTable.ext.feature.length !== 0 )
3674 {
3675 /* Plug-in features */
3676 var aoFeatures = DataTable.ext.feature;
3677 for ( var k=0, kLen=aoFeatures.length ; k<kLen ; k++ )
3678 {
3679 if ( cOption == aoFeatures[k].cFeature )
3680 {
3681 featureNode = aoFeatures[k].fnInit( oSettings );
3682 break;
3683 }
3684 }
3685 }
3686
3687 /* Add to the 2D features array */
3688 if ( featureNode )
3689 {
3690 var aanFeatures = oSettings.aanFeatures;
3691
3692 if ( ! aanFeatures[cOption] )
3693 {
3694 aanFeatures[cOption] = [];
3695 }
3696
3697 aanFeatures[cOption].push( featureNode );
3698 insert.append( featureNode );
3699 }
3700 }
3701
3702 /* Built our DOM structure - replace the holding div with what we want */
3703 holding.replaceWith( insert );
3704 oSettings.nHolding = null;
3705 }
3706
3707
3708 /**
3709 * Use the DOM source to create up an array of header cells. The idea here is to
3710 * create a layout grid (array) of rows x columns, which contains a reference
3711 * to the cell that that point in the grid (regardless of col/rowspan), such that
3712 * any column / row could be removed and the new grid constructed
3713 * @param array {object} aLayout Array to store the calculated layout in
3714 * @param {node} nThead The header/footer element for the table
3715 * @memberof DataTable#oApi
3716 */
3717 function _fnDetectHeader ( aLayout, nThead )
3718 {
3719 var nTrs = $(nThead).children('tr');
3720 var nTr, nCell;
3721 var i, k, l, iLen, jLen, iColShifted, iColumn, iColspan, iRowspan;
3722 var bUnique;
3723 var fnShiftCol = function ( a, i, j ) {
3724 var k = a[i];
3725 while ( k[j] ) {
3726 j++;
3727 }
3728 return j;
3729 };
3730
3731 aLayout.splice( 0, aLayout.length );
3732
3733 /* We know how many rows there are in the layout - so prep it */
3734 for ( i=0, iLen=nTrs.length ; i<iLen ; i++ )
3735 {
3736 aLayout.push( [] );
3737 }
3738
3739 /* Calculate a layout array */
3740 for ( i=0, iLen=nTrs.length ; i<iLen ; i++ )
3741 {
3742 nTr = nTrs[i];
3743 iColumn = 0;
3744
3745 /* For every cell in the row... */
3746 nCell = nTr.firstChild;
3747 while ( nCell ) {
3748 if ( nCell.nodeName.toUpperCase() == "TD" ||
3749 nCell.nodeName.toUpperCase() == "TH" )
3750 {
3751 /* Get the col and rowspan attributes from the DOM and sanitise them */
3752 iColspan = nCell.getAttribute('colspan') * 1;
3753 iRowspan = nCell.getAttribute('rowspan') * 1;
3754 iColspan = (!iColspan || iColspan===0 || iColspan===1) ? 1 : iColspan;
3755 iRowspan = (!iRowspan || iRowspan===0 || iRowspan===1) ? 1 : iRowspan;
3756
3757 /* There might be colspan cells already in this row, so shift our target
3758 * accordingly
3759 */
3760 iColShifted = fnShiftCol( aLayout, i, iColumn );
3761
3762 /* Cache calculation for unique columns */
3763 bUnique = iColspan === 1 ? true : false;
3764
3765 /* If there is col / rowspan, copy the information into the layout grid */
3766 for ( l=0 ; l<iColspan ; l++ )
3767 {
3768 for ( k=0 ; k<iRowspan ; k++ )
3769 {
3770 aLayout[i+k][iColShifted+l] = {
3771 "cell": nCell,
3772 "unique": bUnique
3773 };
3774 aLayout[i+k].nTr = nTr;
3775 }
3776 }
3777 }
3778 nCell = nCell.nextSibling;
3779 }
3780 }
3781 }
3782
3783
3784 /**
3785 * Get an array of unique th elements, one for each column
3786 * @param {object} oSettings dataTables settings object
3787 * @param {node} nHeader automatically detect the layout from this node - optional
3788 * @param {array} aLayout thead/tfoot layout from _fnDetectHeader - optional
3789 * @returns array {node} aReturn list of unique th's
3790 * @memberof DataTable#oApi
3791 */
3792 function _fnGetUniqueThs ( oSettings, nHeader, aLayout )
3793 {
3794 var aReturn = [];
3795 if ( !aLayout )
3796 {
3797 aLayout = oSettings.aoHeader;
3798 if ( nHeader )
3799 {
3800 aLayout = [];
3801 _fnDetectHeader( aLayout, nHeader );
3802 }
3803 }
3804
3805 for ( var i=0, iLen=aLayout.length ; i<iLen ; i++ )
3806 {
3807 for ( var j=0, jLen=aLayout[i].length ; j<jLen ; j++ )
3808 {
3809 if ( aLayout[i][j].unique &&
3810 (!aReturn[j] || !oSettings.bSortCellsTop) )
3811 {
3812 aReturn[j] = aLayout[i][j].cell;
3813 }
3814 }
3815 }
3816
3817 return aReturn;
3818 }
3819
3820 /**
3821 * Create an Ajax call based on the table's settings, taking into account that
3822 * parameters can have multiple forms, and backwards compatibility.
3823 *
3824 * @param {object} oSettings dataTables settings object
3825 * @param {array} data Data to send to the server, required by
3826 * DataTables - may be augmented by developer callbacks
3827 * @param {function} fn Callback function to run when data is obtained
3828 */
3829 function _fnBuildAjax( oSettings, data, fn )
3830 {
3831 // Compatibility with 1.9-, allow fnServerData and event to manipulate
3832 _fnCallbackFire( oSettings, 'aoServerParams', 'serverParams', [data] );
3833
3834 // Convert to object based for 1.10+ if using the old array scheme which can
3835 // come from server-side processing or serverParams
3836 if ( data && $.isArray(data) ) {
3837 var tmp = {};
3838 var rbracket = /(.*?)\[\]$/;
3839
3840 $.each( data, function (key, val) {
3841 var match = val.name.match(rbracket);
3842
3843 if ( match ) {
3844 // Support for arrays
3845 var name = match[0];
3846
3847 if ( ! tmp[ name ] ) {
3848 tmp[ name ] = [];
3849 }
3850 tmp[ name ].push( val.value );
3851 }
3852 else {
3853 tmp[val.name] = val.value;
3854 }
3855 } );
3856 data = tmp;
3857 }
3858
3859 var ajaxData;
3860 var ajax = oSettings.ajax;
3861 var instance = oSettings.oInstance;
3862 var callback = function ( json ) {
3863 _fnCallbackFire( oSettings, null, 'xhr', [oSettings, json, oSettings.jqXHR] );
3864 fn( json );
3865 };
3866
3867 if ( $.isPlainObject( ajax ) && ajax.data )
3868 {
3869 ajaxData = ajax.data;
3870
3871 var newData = typeof ajaxData === 'function' ?
3872 ajaxData( data, oSettings ) : // fn can manipulate data or return
3873 ajaxData; // an object object or array to merge
3874
3875 // If the function returned something, use that alone
3876 data = typeof ajaxData === 'function' && newData ?
3877 newData :
3878 $.extend( true, data, newData );
3879
3880 // Remove the data property as we've resolved it already and don't want
3881 // jQuery to do it again (it is restored at the end of the function)
3882 delete ajax.data;
3883 }
3884
3885 var baseAjax = {
3886 "data": data,
3887 "success": function (json) {
3888 var error = json.error || json.sError;
3889 if ( error ) {
3890 _fnLog( oSettings, 0, error );
3891 }
3892
3893 oSettings.json = json;
3894 callback( json );
3895 },
3896 "dataType": "json",
3897 "cache": false,
3898 "type": oSettings.sServerMethod,
3899 "error": function (xhr, error, thrown) {
3900 var ret = _fnCallbackFire( oSettings, null, 'xhr', [oSettings, null, oSettings.jqXHR] );
3901
3902 if ( $.inArray( true, ret ) === -1 ) {
3903 if ( error == "parsererror" ) {
3904 _fnLog( oSettings, 0, 'Invalid JSON response', 1 );
3905 }
3906 else if ( xhr.readyState === 4 ) {
3907 _fnLog( oSettings, 0, 'Ajax error', 7 );
3908 }
3909 }
3910
3911 _fnProcessingDisplay( oSettings, false );
3912 }
3913 };
3914
3915 // Store the data submitted for the API
3916 oSettings.oAjaxData = data;
3917
3918 // Allow plug-ins and external processes to modify the data
3919 _fnCallbackFire( oSettings, null, 'preXhr', [oSettings, data] );
3920
3921 if ( oSettings.fnServerData )
3922 {
3923 // DataTables 1.9- compatibility
3924 oSettings.fnServerData.call( instance,
3925 oSettings.sAjaxSource,
3926 $.map( data, function (val, key) { // Need to convert back to 1.9 trad format
3927 return { name: key, value: val };
3928 } ),
3929 callback,
3930 oSettings
3931 );
3932 }
3933 else if ( oSettings.sAjaxSource || typeof ajax === 'string' )
3934 {
3935 // DataTables 1.9- compatibility
3936 oSettings.jqXHR = $.ajax( $.extend( baseAjax, {
3937 url: ajax || oSettings.sAjaxSource
3938 } ) );
3939 }
3940 else if ( typeof ajax === 'function' )
3941 {
3942 // Is a function - let the caller define what needs to be done
3943 oSettings.jqXHR = ajax.call( instance, data, callback, oSettings );
3944 }
3945 else
3946 {
3947 // Object to extend the base settings
3948 oSettings.jqXHR = $.ajax( $.extend( baseAjax, ajax ) );
3949
3950 // Restore for next time around
3951 ajax.data = ajaxData;
3952 }
3953 }
3954
3955
3956 /**
3957 * Update the table using an Ajax call
3958 * @param {object} settings dataTables settings object
3959 * @returns {boolean} Block the table drawing or not
3960 * @memberof DataTable#oApi
3961 */
3962 function _fnAjaxUpdate( settings )
3963 {
3964 if ( settings.bAjaxDataGet ) {
3965 settings.iDraw++;
3966 _fnProcessingDisplay( settings, true );
3967
3968 _fnBuildAjax(
3969 settings,
3970 _fnAjaxParameters( settings ),
3971 function(json) {
3972 _fnAjaxUpdateDraw( settings, json );
3973 }
3974 );
3975
3976 return false;
3977 }
3978 return true;
3979 }
3980
3981
3982 /**
3983 * Build up the parameters in an object needed for a server-side processing
3984 * request. Note that this is basically done twice, is different ways - a modern
3985 * method which is used by default in DataTables 1.10 which uses objects and
3986 * arrays, or the 1.9- method with is name / value pairs. 1.9 method is used if
3987 * the sAjaxSource option is used in the initialisation, or the legacyAjax
3988 * option is set.
3989 * @param {object} oSettings dataTables settings object
3990 * @returns {bool} block the table drawing or not
3991 * @memberof DataTable#oApi
3992 */
3993 function _fnAjaxParameters( settings )
3994 {
3995 var
3996 columns = settings.aoColumns,
3997 columnCount = columns.length,
3998 features = settings.oFeatures,
3999 preSearch = settings.oPreviousSearch,
4000 preColSearch = settings.aoPreSearchCols,
4001 i, data = [], dataProp, column, columnSearch,
4002 sort = _fnSortFlatten( settings ),
4003 displayStart = settings._iDisplayStart,
4004 displayLength = features.bPaginate !== false ?
4005 settings._iDisplayLength :
4006 -1;
4007
4008 var param = function ( name, value ) {
4009 data.push( { 'name': name, 'value': value } );
4010 };
4011
4012 // DataTables 1.9- compatible method
4013 param( 'sEcho', settings.iDraw );
4014 param( 'iColumns', columnCount );
4015 param( 'sColumns', _pluck( columns, 'sName' ).join(',') );
4016 param( 'iDisplayStart', displayStart );
4017 param( 'iDisplayLength', displayLength );
4018
4019 // DataTables 1.10+ method
4020 var d = {
4021 draw: settings.iDraw,
4022 columns: [],
4023 order: [],
4024 start: displayStart,
4025 length: displayLength,
4026 search: {
4027 value: preSearch.sSearch,
4028 regex: preSearch.bRegex
4029 }
4030 };
4031
4032 for ( i=0 ; i<columnCount ; i++ ) {
4033 column = columns[i];
4034 columnSearch = preColSearch[i];
4035 dataProp = typeof column.mData=="function" ? 'function' : column.mData ;
4036
4037 d.columns.push( {
4038 data: dataProp,
4039 name: column.sName,
4040 searchable: column.bSearchable,
4041 orderable: column.bSortable,
4042 search: {
4043 value: columnSearch.sSearch,
4044 regex: columnSearch.bRegex
4045 }
4046 } );
4047
4048 param( "mDataProp_"+i, dataProp );
4049
4050 if ( features.bFilter ) {
4051 param( 'sSearch_'+i, columnSearch.sSearch );
4052 param( 'bRegex_'+i, columnSearch.bRegex );
4053 param( 'bSearchable_'+i, column.bSearchable );
4054 }
4055
4056 if ( features.bSort ) {
4057 param( 'bSortable_'+i, column.bSortable );
4058 }
4059 }
4060
4061 if ( features.bFilter ) {
4062 param( 'sSearch', preSearch.sSearch );
4063 param( 'bRegex', preSearch.bRegex );
4064 }
4065
4066 if ( features.bSort ) {
4067 $.each( sort, function ( i, val ) {
4068 d.order.push( { column: val.col, dir: val.dir } );
4069
4070 param( 'iSortCol_'+i, val.col );
4071 param( 'sSortDir_'+i, val.dir );
4072 } );
4073
4074 param( 'iSortingCols', sort.length );
4075 }
4076
4077 // If the legacy.ajax parameter is null, then we automatically decide which
4078 // form to use, based on sAjaxSource
4079 var legacy = DataTable.ext.legacy.ajax;
4080 if ( legacy === null ) {
4081 return settings.sAjaxSource ? data : d;
4082 }
4083
4084 // Otherwise, if legacy has been specified then we use that to decide on the
4085 // form
4086 return legacy ? data : d;
4087 }
4088
4089
4090 /**
4091 * Data the data from the server (nuking the old) and redraw the table
4092 * @param {object} oSettings dataTables settings object
4093 * @param {object} json json data return from the server.
4094 * @param {string} json.sEcho Tracking flag for DataTables to match requests
4095 * @param {int} json.iTotalRecords Number of records in the data set, not accounting for filtering
4096 * @param {int} json.iTotalDisplayRecords Number of records in the data set, accounting for filtering
4097 * @param {array} json.aaData The data to display on this page
4098 * @param {string} [json.sColumns] Column ordering (sName, comma separated)
4099 * @memberof DataTable#oApi
4100 */
4101 function _fnAjaxUpdateDraw ( settings, json )
4102 {
4103 // v1.10 uses camelCase variables, while 1.9 uses Hungarian notation.
4104 // Support both
4105 var compat = function ( old, modern ) {
4106 return json[old] !== undefined ? json[old] : json[modern];
4107 };
4108
4109 var data = _fnAjaxDataSrc( settings, json );
4110 var draw = compat( 'sEcho', 'draw' );
4111 var recordsTotal = compat( 'iTotalRecords', 'recordsTotal' );
4112 var recordsFiltered = compat( 'iTotalDisplayRecords', 'recordsFiltered' );
4113
4114 if ( draw ) {
4115 // Protect against out of sequence returns
4116 if ( draw*1 < settings.iDraw ) {
4117 return;
4118 }
4119 settings.iDraw = draw * 1;
4120 }
4121
4122 _fnClearTable( settings );
4123 settings._iRecordsTotal = parseInt(recordsTotal, 10);
4124 settings._iRecordsDisplay = parseInt(recordsFiltered, 10);
4125
4126 for ( var i=0, ien=data.length ; i<ien ; i++ ) {
4127 _fnAddData( settings, data[i] );
4128 }
4129 settings.aiDisplay = settings.aiDisplayMaster.slice();
4130
4131 settings.bAjaxDataGet = false;
4132 _fnDraw( settings );
4133
4134 if ( ! settings._bInitComplete ) {
4135 _fnInitComplete( settings, json );
4136 }
4137
4138 settings.bAjaxDataGet = true;
4139 _fnProcessingDisplay( settings, false );
4140 }
4141
4142
4143 /**
4144 * Get the data from the JSON data source to use for drawing a table. Using
4145 * `_fnGetObjectDataFn` allows the data to be sourced from a property of the
4146 * source object, or from a processing function.
4147 * @param {object} oSettings dataTables settings object
4148 * @param {object} json Data source object / array from the server
4149 * @return {array} Array of data to use
4150 */
4151 function _fnAjaxDataSrc ( oSettings, json )
4152 {
4153 var dataSrc = $.isPlainObject( oSettings.ajax ) && oSettings.ajax.dataSrc !== undefined ?
4154 oSettings.ajax.dataSrc :
4155 oSettings.sAjaxDataProp; // Compatibility with 1.9-.
4156
4157 // Compatibility with 1.9-. In order to read from aaData, check if the
4158 // default has been changed, if not, check for aaData
4159 if ( dataSrc === 'data' ) {
4160 return json.aaData || json[dataSrc];
4161 }
4162
4163 return dataSrc !== "" ?
4164 _fnGetObjectDataFn( dataSrc )( json ) :
4165 json;
4166 }
4167
4168 /**
4169 * Generate the node required for filtering text
4170 * @returns {node} Filter control element
4171 * @param {object} oSettings dataTables settings object
4172 * @memberof DataTable#oApi
4173 */
4174 function _fnFeatureHtmlFilter ( settings )
4175 {
4176 var classes = settings.oClasses;
4177 var tableId = settings.sTableId;
4178 var language = settings.oLanguage;
4179 var previousSearch = settings.oPreviousSearch;
4180 var features = settings.aanFeatures;
4181 var input = '<input type="search" class="'+classes.sFilterInput+'"/>';
4182
4183 var str = language.sSearch;
4184 str = str.match(/_INPUT_/) ?
4185 str.replace('_INPUT_', input) :
4186 str+input;
4187
4188 var filter = $('<div/>', {
4189 'id': ! features.f ? tableId+'_filter' : null,
4190 'class': classes.sFilter
4191 } )
4192 .append( $('<label/>' ).append( str ) );
4193
4194 var searchFn = function() {
4195 /* Update all other filter input elements for the new display */
4196 var n = features.f;
4197 var val = !this.value ? "" : this.value; // mental IE8 fix :-(
4198
4199 /* Now do the filter */
4200 if ( val != previousSearch.sSearch ) {
4201 _fnFilterComplete( settings, {
4202 "sSearch": val,
4203 "bRegex": previousSearch.bRegex,
4204 "bSmart": previousSearch.bSmart ,
4205 "bCaseInsensitive": previousSearch.bCaseInsensitive
4206 } );
4207
4208 // Need to redraw, without resorting
4209 settings._iDisplayStart = 0;
4210 _fnDraw( settings );
4211 }
4212 };
4213
4214 var searchDelay = settings.searchDelay !== null ?
4215 settings.searchDelay :
4216 _fnDataSource( settings ) === 'ssp' ?
4217 400 :
4218 0;
4219
4220 var jqFilter = $('input', filter)
4221 .val( previousSearch.sSearch )
4222 .attr( 'placeholder', language.sSearchPlaceholder )
4223 .on(
4224 'keyup.DT search.DT input.DT paste.DT cut.DT',
4225 searchDelay ?
4226 _fnThrottle( searchFn, searchDelay ) :
4227 searchFn
4228 )
4229 .on( 'keypress.DT', function(e) {
4230 /* Prevent form submission */
4231 if ( e.keyCode == 13 ) {
4232 return false;
4233 }
4234 } )
4235 .attr('aria-controls', tableId);
4236
4237 // Update the input elements whenever the table is filtered
4238 $(settings.nTable).on( 'search.dt.DT', function ( ev, s ) {
4239 if ( settings === s ) {
4240 // IE9 throws an 'unknown error' if document.activeElement is used
4241 // inside an iframe or frame...
4242 try {
4243 if ( jqFilter[0] !== document.activeElement ) {
4244 jqFilter.val( previousSearch.sSearch );
4245 }
4246 }
4247 catch ( e ) {}
4248 }
4249 } );
4250
4251 return filter[0];
4252 }
4253
4254
4255 /**
4256 * Filter the table using both the global filter and column based filtering
4257 * @param {object} oSettings dataTables settings object
4258 * @param {object} oSearch search information
4259 * @param {int} [iForce] force a research of the master array (1) or not (undefined or 0)
4260 * @memberof DataTable#oApi
4261 */
4262 function _fnFilterComplete ( oSettings, oInput, iForce )
4263 {
4264 var oPrevSearch = oSettings.oPreviousSearch;
4265 var aoPrevSearch = oSettings.aoPreSearchCols;
4266 var fnSaveFilter = function ( oFilter ) {
4267 /* Save the filtering values */
4268 oPrevSearch.sSearch = oFilter.sSearch;
4269 oPrevSearch.bRegex = oFilter.bRegex;
4270 oPrevSearch.bSmart = oFilter.bSmart;
4271 oPrevSearch.bCaseInsensitive = oFilter.bCaseInsensitive;
4272 };
4273 var fnRegex = function ( o ) {
4274 // Backwards compatibility with the bEscapeRegex option
4275 return o.bEscapeRegex !== undefined ? !o.bEscapeRegex : o.bRegex;
4276 };
4277
4278 // Resolve any column types that are unknown due to addition or invalidation
4279 // @todo As per sort - can this be moved into an event handler?
4280 _fnColumnTypes( oSettings );
4281
4282 /* In server-side processing all filtering is done by the server, so no point hanging around here */
4283 if ( _fnDataSource( oSettings ) != 'ssp' )
4284 {
4285 /* Global filter */
4286 _fnFilter( oSettings, oInput.sSearch, iForce, fnRegex(oInput), oInput.bSmart, oInput.bCaseInsensitive );
4287 fnSaveFilter( oInput );
4288
4289 /* Now do the individual column filter */
4290 for ( var i=0 ; i<aoPrevSearch.length ; i++ )
4291 {
4292 _fnFilterColumn( oSettings, aoPrevSearch[i].sSearch, i, fnRegex(aoPrevSearch[i]),
4293 aoPrevSearch[i].bSmart, aoPrevSearch[i].bCaseInsensitive );
4294 }
4295
4296 /* Custom filtering */
4297 _fnFilterCustom( oSettings );
4298 }
4299 else
4300 {
4301 fnSaveFilter( oInput );
4302 }
4303
4304 /* Tell the draw function we have been filtering */
4305 oSettings.bFiltered = true;
4306 _fnCallbackFire( oSettings, null, 'search', [oSettings] );
4307 }
4308
4309
4310 /**
4311 * Apply custom filtering functions
4312 * @param {object} oSettings dataTables settings object
4313 * @memberof DataTable#oApi
4314 */
4315 function _fnFilterCustom( settings )
4316 {
4317 var filters = DataTable.ext.search;
4318 var displayRows = settings.aiDisplay;
4319 var row, rowIdx;
4320
4321 for ( var i=0, ien=filters.length ; i<ien ; i++ ) {
4322 var rows = [];
4323
4324 // Loop over each row and see if it should be included
4325 for ( var j=0, jen=displayRows.length ; j<jen ; j++ ) {
4326 rowIdx = displayRows[ j ];
4327 row = settings.aoData[ rowIdx ];
4328
4329 if ( filters[i]( settings, row._aFilterData, rowIdx, row._aData, j ) ) {
4330 rows.push( rowIdx );
4331 }
4332 }
4333
4334 // So the array reference doesn't break set the results into the
4335 // existing array
4336 displayRows.length = 0;
4337 $.merge( displayRows, rows );
4338 }
4339 }
4340
4341
4342 /**
4343 * Filter the table on a per-column basis
4344 * @param {object} oSettings dataTables settings object
4345 * @param {string} sInput string to filter on
4346 * @param {int} iColumn column to filter
4347 * @param {bool} bRegex treat search string as a regular expression or not
4348 * @param {bool} bSmart use smart filtering or not
4349 * @param {bool} bCaseInsensitive Do case insenstive matching or not
4350 * @memberof DataTable#oApi
4351 */
4352 function _fnFilterColumn ( settings, searchStr, colIdx, regex, smart, caseInsensitive )
4353 {
4354 if ( searchStr === '' ) {
4355 return;
4356 }
4357
4358 var data;
4359 var out = [];
4360 var display = settings.aiDisplay;
4361 var rpSearch = _fnFilterCreateSearch( searchStr, regex, smart, caseInsensitive );
4362
4363 for ( var i=0 ; i<display.length ; i++ ) {
4364 data = settings.aoData[ display[i] ]._aFilterData[ colIdx ];
4365
4366 if ( rpSearch.test( data ) ) {
4367 out.push( display[i] );
4368 }
4369 }
4370
4371 settings.aiDisplay = out;
4372 }
4373
4374
4375 /**
4376 * Filter the data table based on user input and draw the table
4377 * @param {object} settings dataTables settings object
4378 * @param {string} input string to filter on
4379 * @param {int} force optional - force a research of the master array (1) or not (undefined or 0)
4380 * @param {bool} regex treat as a regular expression or not
4381 * @param {bool} smart perform smart filtering or not
4382 * @param {bool} caseInsensitive Do case insenstive matching or not
4383 * @memberof DataTable#oApi
4384 */
4385 function _fnFilter( settings, input, force, regex, smart, caseInsensitive )
4386 {
4387 var rpSearch = _fnFilterCreateSearch( input, regex, smart, caseInsensitive );
4388 var prevSearch = settings.oPreviousSearch.sSearch;
4389 var displayMaster = settings.aiDisplayMaster;
4390 var display, invalidated, i;
4391 var filtered = [];
4392
4393 // Need to take account of custom filtering functions - always filter
4394 if ( DataTable.ext.search.length !== 0 ) {
4395 force = true;
4396 }
4397
4398 // Check if any of the rows were invalidated
4399 invalidated = _fnFilterData( settings );
4400
4401 // If the input is blank - we just want the full data set
4402 if ( input.length <= 0 ) {
4403 settings.aiDisplay = displayMaster.slice();
4404 }
4405 else {
4406 // New search - start from the master array
4407 if ( invalidated ||
4408 force ||
4409 prevSearch.length > input.length ||
4410 input.indexOf(prevSearch) !== 0 ||
4411 settings.bSorted // On resort, the display master needs to be
4412 // re-filtered since indexes will have changed
4413 ) {
4414 settings.aiDisplay = displayMaster.slice();
4415 }
4416
4417 // Search the display array
4418 display = settings.aiDisplay;
4419
4420 for ( i=0 ; i<display.length ; i++ ) {
4421 if ( rpSearch.test( settings.aoData[ display[i] ]._sFilterRow ) ) {
4422 filtered.push( display[i] );
4423 }
4424 }
4425
4426 settings.aiDisplay = filtered;
4427 }
4428 }
4429
4430
4431 /**
4432 * Build a regular expression object suitable for searching a table
4433 * @param {string} sSearch string to search for
4434 * @param {bool} bRegex treat as a regular expression or not
4435 * @param {bool} bSmart perform smart filtering or not
4436 * @param {bool} bCaseInsensitive Do case insensitive matching or not
4437 * @returns {RegExp} constructed object
4438 * @memberof DataTable#oApi
4439 */
4440 function _fnFilterCreateSearch( search, regex, smart, caseInsensitive )
4441 {
4442 search = regex ?
4443 search :
4444 _fnEscapeRegex( search );
4445
4446 if ( smart ) {
4447 /* For smart filtering we want to allow the search to work regardless of
4448 * word order. We also want double quoted text to be preserved, so word
4449 * order is important - a la google. So this is what we want to
4450 * generate:
4451 *
4452 * ^(?=.*?\bone\b)(?=.*?\btwo three\b)(?=.*?\bfour\b).*$
4453 */
4454 var a = $.map( search.match( /"[^"]+"|[^ ]+/g ) || [''], function ( word ) {
4455 if ( word.charAt(0) === '"' ) {
4456 var m = word.match( /^"(.*)"$/ );
4457 word = m ? m[1] : word;
4458 }
4459
4460 return word.replace('"', '');
4461 } );
4462
4463 search = '^(?=.*?'+a.join( ')(?=.*?' )+').*$';
4464 }
4465
4466 return new RegExp( search, caseInsensitive ? 'i' : '' );
4467 }
4468
4469
4470 /**
4471 * Escape a string such that it can be used in a regular expression
4472 * @param {string} sVal string to escape
4473 * @returns {string} escaped string
4474 * @memberof DataTable#oApi
4475 */
4476 var _fnEscapeRegex = DataTable.util.escapeRegex;
4477
4478 var __filter_div = $('<div>')[0];
4479 var __filter_div_textContent = __filter_div.textContent !== undefined;
4480
4481 // Update the filtering data for each row if needed (by invalidation or first run)
4482 function _fnFilterData ( settings )
4483 {
4484 var columns = settings.aoColumns;
4485 var column;
4486 var i, j, ien, jen, filterData, cellData, row;
4487 var fomatters = DataTable.ext.type.search;
4488 var wasInvalidated = false;
4489
4490 for ( i=0, ien=settings.aoData.length ; i<ien ; i++ ) {
4491 row = settings.aoData[i];
4492
4493 if ( ! row._aFilterData ) {
4494 filterData = [];
4495
4496 for ( j=0, jen=columns.length ; j<jen ; j++ ) {
4497 column = columns[j];
4498
4499 if ( column.bSearchable ) {
4500 cellData = _fnGetCellData( settings, i, j, 'filter' );
4501
4502 if ( fomatters[ column.sType ] ) {
4503 cellData = fomatters[ column.sType ]( cellData );
4504 }
4505
4506 // Search in DataTables 1.10 is string based. In 1.11 this
4507 // should be altered to also allow strict type checking.
4508 if ( cellData === null ) {
4509 cellData = '';
4510 }
4511
4512 if ( typeof cellData !== 'string' && cellData.toString ) {
4513 cellData = cellData.toString();
4514 }
4515 }
4516 else {
4517 cellData = '';
4518 }
4519
4520 // If it looks like there is an HTML entity in the string,
4521 // attempt to decode it so sorting works as expected. Note that
4522 // we could use a single line of jQuery to do this, but the DOM
4523 // method used here is much faster http://jsperf.com/html-decode
4524 if ( cellData.indexOf && cellData.indexOf('&') !== -1 ) {
4525 __filter_div.innerHTML = cellData;
4526 cellData = __filter_div_textContent ?
4527 __filter_div.textContent :
4528 __filter_div.innerText;
4529 }
4530
4531 if ( cellData.replace ) {
4532 cellData = cellData.replace(/[\r\n]/g, '');
4533 }
4534
4535 filterData.push( cellData );
4536 }
4537
4538 row._aFilterData = filterData;
4539 row._sFilterRow = filterData.join(' ');
4540 wasInvalidated = true;
4541 }
4542 }
4543
4544 return wasInvalidated;
4545 }
4546
4547
4548 /**
4549 * Convert from the internal Hungarian notation to camelCase for external
4550 * interaction
4551 * @param {object} obj Object to convert
4552 * @returns {object} Inverted object
4553 * @memberof DataTable#oApi
4554 */
4555 function _fnSearchToCamel ( obj )
4556 {
4557 return {
4558 search: obj.sSearch,
4559 smart: obj.bSmart,
4560 regex: obj.bRegex,
4561 caseInsensitive: obj.bCaseInsensitive
4562 };
4563 }
4564
4565
4566
4567 /**
4568 * Convert from camelCase notation to the internal Hungarian. We could use the
4569 * Hungarian convert function here, but this is cleaner
4570 * @param {object} obj Object to convert
4571 * @returns {object} Inverted object
4572 * @memberof DataTable#oApi
4573 */
4574 function _fnSearchToHung ( obj )
4575 {
4576 return {
4577 sSearch: obj.search,
4578 bSmart: obj.smart,
4579 bRegex: obj.regex,
4580 bCaseInsensitive: obj.caseInsensitive
4581 };
4582 }
4583
4584 /**
4585 * Generate the node required for the info display
4586 * @param {object} oSettings dataTables settings object
4587 * @returns {node} Information element
4588 * @memberof DataTable#oApi
4589 */
4590 function _fnFeatureHtmlInfo ( settings )
4591 {
4592 var
4593 tid = settings.sTableId,
4594 nodes = settings.aanFeatures.i,
4595 n = $('<div/>', {
4596 'class': settings.oClasses.sInfo,
4597 'id': ! nodes ? tid+'_info' : null
4598 } );
4599
4600 if ( ! nodes ) {
4601 // Update display on each draw
4602 settings.aoDrawCallback.push( {
4603 "fn": _fnUpdateInfo,
4604 "sName": "information"
4605 } );
4606
4607 n
4608 .attr( 'role', 'status' )
4609 .attr( 'aria-live', 'polite' );
4610
4611 // Table is described by our info div
4612 $(settings.nTable).attr( 'aria-describedby', tid+'_info' );
4613 }
4614
4615 return n[0];
4616 }
4617
4618
4619 /**
4620 * Update the information elements in the display
4621 * @param {object} settings dataTables settings object
4622 * @memberof DataTable#oApi
4623 */
4624 function _fnUpdateInfo ( settings )
4625 {
4626 /* Show information about the table */
4627 var nodes = settings.aanFeatures.i;
4628 if ( nodes.length === 0 ) {
4629 return;
4630 }
4631
4632 var
4633 lang = settings.oLanguage,
4634 start = settings._iDisplayStart+1,
4635 end = settings.fnDisplayEnd(),
4636 max = settings.fnRecordsTotal(),
4637 total = settings.fnRecordsDisplay(),
4638 out = total ?
4639 lang.sInfo :
4640 lang.sInfoEmpty;
4641
4642 if ( total !== max ) {
4643 /* Record set after filtering */
4644 out += ' ' + lang.sInfoFiltered;
4645 }
4646
4647 // Convert the macros
4648 out += lang.sInfoPostFix;
4649 out = _fnInfoMacros( settings, out );
4650
4651 var callback = lang.fnInfoCallback;
4652 if ( callback !== null ) {
4653 out = callback.call( settings.oInstance,
4654 settings, start, end, max, total, out
4655 );
4656 }
4657
4658 $(nodes).html( out );
4659 }
4660
4661
4662 function _fnInfoMacros ( settings, str )
4663 {
4664 // When infinite scrolling, we are always starting at 1. _iDisplayStart is used only
4665 // internally
4666 var
4667 formatter = settings.fnFormatNumber,
4668 start = settings._iDisplayStart+1,
4669 len = settings._iDisplayLength,
4670 vis = settings.fnRecordsDisplay(),
4671 all = len === -1;
4672
4673 return str.
4674 replace(/_START_/g, formatter.call( settings, start ) ).
4675 replace(/_END_/g, formatter.call( settings, settings.fnDisplayEnd() ) ).
4676 replace(/_MAX_/g, formatter.call( settings, settings.fnRecordsTotal() ) ).
4677 replace(/_TOTAL_/g, formatter.call( settings, vis ) ).
4678 replace(/_PAGE_/g, formatter.call( settings, all ? 1 : Math.ceil( start / len ) ) ).
4679 replace(/_PAGES_/g, formatter.call( settings, all ? 1 : Math.ceil( vis / len ) ) );
4680 }
4681
4682
4683
4684 /**
4685 * Draw the table for the first time, adding all required features
4686 * @param {object} settings dataTables settings object
4687 * @memberof DataTable#oApi
4688 */
4689 function _fnInitialise ( settings )
4690 {
4691 var i, iLen, iAjaxStart=settings.iInitDisplayStart;
4692 var columns = settings.aoColumns, column;
4693 var features = settings.oFeatures;
4694 var deferLoading = settings.bDeferLoading; // value modified by the draw
4695
4696 /* Ensure that the table data is fully initialised */
4697 if ( ! settings.bInitialised ) {
4698 setTimeout( function(){ _fnInitialise( settings ); }, 200 );
4699 return;
4700 }
4701
4702 /* Show the display HTML options */
4703 _fnAddOptionsHtml( settings );
4704
4705 /* Build and draw the header / footer for the table */
4706 _fnBuildHead( settings );
4707 _fnDrawHead( settings, settings.aoHeader );
4708 _fnDrawHead( settings, settings.aoFooter );
4709
4710 /* Okay to show that something is going on now */
4711 _fnProcessingDisplay( settings, true );
4712
4713 /* Calculate sizes for columns */
4714 if ( features.bAutoWidth ) {
4715 _fnCalculateColumnWidths( settings );
4716 }
4717
4718 for ( i=0, iLen=columns.length ; i<iLen ; i++ ) {
4719 column = columns[i];
4720
4721 if ( column.sWidth ) {
4722 column.nTh.style.width = _fnStringToCss( column.sWidth );
4723 }
4724 }
4725
4726 _fnCallbackFire( settings, null, 'preInit', [settings] );
4727
4728 // If there is default sorting required - let's do it. The sort function
4729 // will do the drawing for us. Otherwise we draw the table regardless of the
4730 // Ajax source - this allows the table to look initialised for Ajax sourcing
4731 // data (show 'loading' message possibly)
4732 _fnReDraw( settings );
4733
4734 // Server-side processing init complete is done by _fnAjaxUpdateDraw
4735 var dataSrc = _fnDataSource( settings );
4736 if ( dataSrc != 'ssp' || deferLoading ) {
4737 // if there is an ajax source load the data
4738 if ( dataSrc == 'ajax' ) {
4739 _fnBuildAjax( settings, [], function(json) {
4740 var aData = _fnAjaxDataSrc( settings, json );
4741
4742 // Got the data - add it to the table
4743 for ( i=0 ; i<aData.length ; i++ ) {
4744 _fnAddData( settings, aData[i] );
4745 }
4746
4747 // Reset the init display for cookie saving. We've already done
4748 // a filter, and therefore cleared it before. So we need to make
4749 // it appear 'fresh'
4750 settings.iInitDisplayStart = iAjaxStart;
4751
4752 _fnReDraw( settings );
4753
4754 _fnProcessingDisplay( settings, false );
4755 _fnInitComplete( settings, json );
4756 }, settings );
4757 }
4758 else {
4759 _fnProcessingDisplay( settings, false );
4760 _fnInitComplete( settings );
4761 }
4762 }
4763 }
4764
4765
4766 /**
4767 * Draw the table for the first time, adding all required features
4768 * @param {object} oSettings dataTables settings object
4769 * @param {object} [json] JSON from the server that completed the table, if using Ajax source
4770 * with client-side processing (optional)
4771 * @memberof DataTable#oApi
4772 */
4773 function _fnInitComplete ( settings, json )
4774 {
4775 settings._bInitComplete = true;
4776
4777 // When data was added after the initialisation (data or Ajax) we need to
4778 // calculate the column sizing
4779 if ( json || settings.oInit.aaData ) {
4780 _fnAdjustColumnSizing( settings );
4781 }
4782
4783 _fnCallbackFire( settings, null, 'plugin-init', [settings, json] );
4784 _fnCallbackFire( settings, 'aoInitComplete', 'init', [settings, json] );
4785 }
4786
4787
4788 function _fnLengthChange ( settings, val )
4789 {
4790 var len = parseInt( val, 10 );
4791 settings._iDisplayLength = len;
4792
4793 _fnLengthOverflow( settings );
4794
4795 // Fire length change event
4796 _fnCallbackFire( settings, null, 'length', [settings, len] );
4797 }
4798
4799
4800 /**
4801 * Generate the node required for user display length changing
4802 * @param {object} settings dataTables settings object
4803 * @returns {node} Display length feature node
4804 * @memberof DataTable#oApi
4805 */
4806 function _fnFeatureHtmlLength ( settings )
4807 {
4808 var
4809 classes = settings.oClasses,
4810 tableId = settings.sTableId,
4811 menu = settings.aLengthMenu,
4812 d2 = $.isArray( menu[0] ),
4813 lengths = d2 ? menu[0] : menu,
4814 language = d2 ? menu[1] : menu;
4815
4816 var select = $('<select/>', {
4817 'name': tableId+'_length',
4818 'aria-controls': tableId,
4819 'class': classes.sLengthSelect
4820 } );
4821
4822 for ( var i=0, ien=lengths.length ; i<ien ; i++ ) {
4823 select[0][ i ] = new Option(
4824 typeof language[i] === 'number' ?
4825 settings.fnFormatNumber( language[i] ) :
4826 language[i],
4827 lengths[i]
4828 );
4829 }
4830
4831 var div = $('<div><label/></div>').addClass( classes.sLength );
4832 if ( ! settings.aanFeatures.l ) {
4833 div[0].id = tableId+'_length';
4834 }
4835
4836 div.children().append(
4837 settings.oLanguage.sLengthMenu.replace( '_MENU_', select[0].outerHTML )
4838 );
4839
4840 // Can't use `select` variable as user might provide their own and the
4841 // reference is broken by the use of outerHTML
4842 $('select', div)
4843 .val( settings._iDisplayLength )
4844 .on( 'change.DT', function(e) {
4845 _fnLengthChange( settings, $(this).val() );
4846 _fnDraw( settings );
4847 } );
4848
4849 // Update node value whenever anything changes the table's length
4850 $(settings.nTable).on( 'length.dt.DT', function (e, s, len) {
4851 if ( settings === s ) {
4852 $('select', div).val( len );
4853 }
4854 } );
4855
4856 return div[0];
4857 }
4858
4859
4860
4861 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
4862 * Note that most of the paging logic is done in
4863 * DataTable.ext.pager
4864 */
4865
4866 /**
4867 * Generate the node required for default pagination
4868 * @param {object} oSettings dataTables settings object
4869 * @returns {node} Pagination feature node
4870 * @memberof DataTable#oApi
4871 */
4872 function _fnFeatureHtmlPaginate ( settings )
4873 {
4874 var
4875 type = settings.sPaginationType,
4876 plugin = DataTable.ext.pager[ type ],
4877 modern = typeof plugin === 'function',
4878 redraw = function( settings ) {
4879 _fnDraw( settings );
4880 },
4881 node = $('<div/>').addClass( settings.oClasses.sPaging + type )[0],
4882 features = settings.aanFeatures;
4883
4884 if ( ! modern ) {
4885 plugin.fnInit( settings, node, redraw );
4886 }
4887
4888 /* Add a draw callback for the pagination on first instance, to update the paging display */
4889 if ( ! features.p )
4890 {
4891 node.id = settings.sTableId+'_paginate';
4892
4893 settings.aoDrawCallback.push( {
4894 "fn": function( settings ) {
4895 if ( modern ) {
4896 var
4897 start = settings._iDisplayStart,
4898 len = settings._iDisplayLength,
4899 visRecords = settings.fnRecordsDisplay(),
4900 all = len === -1,
4901 page = all ? 0 : Math.ceil( start / len ),
4902 pages = all ? 1 : Math.ceil( visRecords / len ),
4903 buttons = plugin(page, pages),
4904 i, ien;
4905
4906 for ( i=0, ien=features.p.length ; i<ien ; i++ ) {
4907 _fnRenderer( settings, 'pageButton' )(
4908 settings, features.p[i], i, buttons, page, pages
4909 );
4910 }
4911 }
4912 else {
4913 plugin.fnUpdate( settings, redraw );
4914 }
4915 },
4916 "sName": "pagination"
4917 } );
4918 }
4919
4920 return node;
4921 }
4922
4923
4924 /**
4925 * Alter the display settings to change the page
4926 * @param {object} settings DataTables settings object
4927 * @param {string|int} action Paging action to take: "first", "previous",
4928 * "next" or "last" or page number to jump to (integer)
4929 * @param [bool] redraw Automatically draw the update or not
4930 * @returns {bool} true page has changed, false - no change
4931 * @memberof DataTable#oApi
4932 */
4933 function _fnPageChange ( settings, action, redraw )
4934 {
4935 var
4936 start = settings._iDisplayStart,
4937 len = settings._iDisplayLength,
4938 records = settings.fnRecordsDisplay();
4939
4940 if ( records === 0 || len === -1 )
4941 {
4942 start = 0;
4943 }
4944 else if ( typeof action === "number" )
4945 {
4946 start = action * len;
4947
4948 if ( start > records )
4949 {
4950 start = 0;
4951 }
4952 }
4953 else if ( action == "first" )
4954 {
4955 start = 0;
4956 }
4957 else if ( action == "previous" )
4958 {
4959 start = len >= 0 ?
4960 start - len :
4961 0;
4962
4963 if ( start < 0 )
4964 {
4965 start = 0;
4966 }
4967 }
4968 else if ( action == "next" )
4969 {
4970 if ( start + len < records )
4971 {
4972 start += len;
4973 }
4974 }
4975 else if ( action == "last" )
4976 {
4977 start = Math.floor( (records-1) / len) * len;
4978 }
4979 else
4980 {
4981 _fnLog( settings, 0, "Unknown paging action: "+action, 5 );
4982 }
4983
4984 var changed = settings._iDisplayStart !== start;
4985 settings._iDisplayStart = start;
4986
4987 if ( changed ) {
4988 _fnCallbackFire( settings, null, 'page', [settings] );
4989
4990 if ( redraw ) {
4991 _fnDraw( settings );
4992 }
4993 }
4994
4995 return changed;
4996 }
4997
4998
4999
5000 /**
5001 * Generate the node required for the processing node
5002 * @param {object} settings dataTables settings object
5003 * @returns {node} Processing element
5004 * @memberof DataTable#oApi
5005 */
5006 function _fnFeatureHtmlProcessing ( settings )
5007 {
5008 return $('<div/>', {
5009 'id': ! settings.aanFeatures.r ? settings.sTableId+'_processing' : null,
5010 'class': settings.oClasses.sProcessing
5011 } )
5012 .html( settings.oLanguage.sProcessing )
5013 .insertBefore( settings.nTable )[0];
5014 }
5015
5016
5017 /**
5018 * Display or hide the processing indicator
5019 * @param {object} settings dataTables settings object
5020 * @param {bool} show Show the processing indicator (true) or not (false)
5021 * @memberof DataTable#oApi
5022 */
5023 function _fnProcessingDisplay ( settings, show )
5024 {
5025 if ( settings.oFeatures.bProcessing ) {
5026 $(settings.aanFeatures.r).css( 'display', show ? 'block' : 'none' );
5027 }
5028
5029 _fnCallbackFire( settings, null, 'processing', [settings, show] );
5030 }
5031
5032 /**
5033 * Add any control elements for the table - specifically scrolling
5034 * @param {object} settings dataTables settings object
5035 * @returns {node} Node to add to the DOM
5036 * @memberof DataTable#oApi
5037 */
5038 function _fnFeatureHtmlTable ( settings )
5039 {
5040 var table = $(settings.nTable);
5041
5042 // Add the ARIA grid role to the table
5043 table.attr( 'role', 'grid' );
5044
5045 // Scrolling from here on in
5046 var scroll = settings.oScroll;
5047
5048 if ( scroll.sX === '' && scroll.sY === '' ) {
5049 return settings.nTable;
5050 }
5051
5052 var scrollX = scroll.sX;
5053 var scrollY = scroll.sY;
5054 var classes = settings.oClasses;
5055 var caption = table.children('caption');
5056 var captionSide = caption.length ? caption[0]._captionSide : null;
5057 var headerClone = $( table[0].cloneNode(false) );
5058 var footerClone = $( table[0].cloneNode(false) );
5059 var footer = table.children('tfoot');
5060 var _div = '<div/>';
5061 var size = function ( s ) {
5062 return !s ? null : _fnStringToCss( s );
5063 };
5064
5065 if ( ! footer.length ) {
5066 footer = null;
5067 }
5068
5069 /*
5070 * The HTML structure that we want to generate in this function is:
5071 * div - scroller
5072 * div - scroll head
5073 * div - scroll head inner
5074 * table - scroll head table
5075 * thead - thead
5076 * div - scroll body
5077 * table - table (master table)
5078 * thead - thead clone for sizing
5079 * tbody - tbody
5080 * div - scroll foot
5081 * div - scroll foot inner
5082 * table - scroll foot table
5083 * tfoot - tfoot
5084 */
5085 var scroller = $( _div, { 'class': classes.sScrollWrapper } )
5086 .append(
5087 $(_div, { 'class': classes.sScrollHead } )
5088 .css( {
5089 overflow: 'hidden',
5090 position: 'relative',
5091 border: 0,
5092 width: scrollX ? size(scrollX) : '100%'
5093 } )
5094 .append(
5095 $(_div, { 'class': classes.sScrollHeadInner } )
5096 .css( {
5097 'box-sizing': 'content-box',
5098 width: scroll.sXInner || '100%'
5099 } )
5100 .append(
5101 headerClone
5102 .removeAttr('id')
5103 .css( 'margin-left', 0 )
5104 .append( captionSide === 'top' ? caption : null )
5105 .append(
5106 table.children('thead')
5107 )
5108 )
5109 )
5110 )
5111 .append(
5112 $(_div, { 'class': classes.sScrollBody } )
5113 .css( {
5114 position: 'relative',
5115 overflow: 'auto',
5116 width: size( scrollX )
5117 } )
5118 .append( table )
5119 );
5120
5121 if ( footer ) {
5122 scroller.append(
5123 $(_div, { 'class': classes.sScrollFoot } )
5124 .css( {
5125 overflow: 'hidden',
5126 border: 0,
5127 width: scrollX ? size(scrollX) : '100%'
5128 } )
5129 .append(
5130 $(_div, { 'class': classes.sScrollFootInner } )
5131 .append(
5132 footerClone
5133 .removeAttr('id')
5134 .css( 'margin-left', 0 )
5135 .append( captionSide === 'bottom' ? caption : null )
5136 .append(
5137 table.children('tfoot')
5138 )
5139 )
5140 )
5141 );
5142 }
5143
5144 var children = scroller.children();
5145 var scrollHead = children[0];
5146 var scrollBody = children[1];
5147 var scrollFoot = footer ? children[2] : null;
5148
5149 // When the body is scrolled, then we also want to scroll the headers
5150 if ( scrollX ) {
5151 $(scrollBody).on( 'scroll.DT', function (e) {
5152 var scrollLeft = this.scrollLeft;
5153
5154 scrollHead.scrollLeft = scrollLeft;
5155
5156 if ( footer ) {
5157 scrollFoot.scrollLeft = scrollLeft;
5158 }
5159 } );
5160 }
5161
5162 $(scrollBody).css(
5163 scrollY && scroll.bCollapse ? 'max-height' : 'height',
5164 scrollY
5165 );
5166
5167 settings.nScrollHead = scrollHead;
5168 settings.nScrollBody = scrollBody;
5169 settings.nScrollFoot = scrollFoot;
5170
5171 // On redraw - align columns
5172 settings.aoDrawCallback.push( {
5173 "fn": _fnScrollDraw,
5174 "sName": "scrolling"
5175 } );
5176
5177 return scroller[0];
5178 }
5179
5180
5181
5182 /**
5183 * Update the header, footer and body tables for resizing - i.e. column
5184 * alignment.
5185 *
5186 * Welcome to the most horrible function DataTables. The process that this
5187 * function follows is basically:
5188 * 1. Re-create the table inside the scrolling div
5189 * 2. Take live measurements from the DOM
5190 * 3. Apply the measurements to align the columns
5191 * 4. Clean up
5192 *
5193 * @param {object} settings dataTables settings object
5194 * @memberof DataTable#oApi
5195 */
5196 function _fnScrollDraw ( settings )
5197 {
5198 // Given that this is such a monster function, a lot of variables are use
5199 // to try and keep the minimised size as small as possible
5200 var
5201 scroll = settings.oScroll,
5202 scrollX = scroll.sX,
5203 scrollXInner = scroll.sXInner,
5204 scrollY = scroll.sY,
5205 barWidth = scroll.iBarWidth,
5206 divHeader = $(settings.nScrollHead),
5207 divHeaderStyle = divHeader[0].style,
5208 divHeaderInner = divHeader.children('div'),
5209 divHeaderInnerStyle = divHeaderInner[0].style,
5210 divHeaderTable = divHeaderInner.children('table'),
5211 divBodyEl = settings.nScrollBody,
5212 divBody = $(divBodyEl),
5213 divBodyStyle = divBodyEl.style,
5214 divFooter = $(settings.nScrollFoot),
5215 divFooterInner = divFooter.children('div'),
5216 divFooterTable = divFooterInner.children('table'),
5217 header = $(settings.nTHead),
5218 table = $(settings.nTable),
5219 tableEl = table[0],
5220 tableStyle = tableEl.style,
5221 footer = settings.nTFoot ? $(settings.nTFoot) : null,
5222 browser = settings.oBrowser,
5223 ie67 = browser.bScrollOversize,
5224 dtHeaderCells = _pluck( settings.aoColumns, 'nTh' ),
5225 headerTrgEls, footerTrgEls,
5226 headerSrcEls, footerSrcEls,
5227 headerCopy, footerCopy,
5228 headerWidths=[], footerWidths=[],
5229 headerContent=[], footerContent=[],
5230 idx, correction, sanityWidth,
5231 zeroOut = function(nSizer) {
5232 var style = nSizer.style;
5233 style.paddingTop = "0";
5234 style.paddingBottom = "0";
5235 style.borderTopWidth = "0";
5236 style.borderBottomWidth = "0";
5237 style.height = 0;
5238 };
5239
5240 // If the scrollbar visibility has changed from the last draw, we need to
5241 // adjust the column sizes as the table width will have changed to account
5242 // for the scrollbar
5243 var scrollBarVis = divBodyEl.scrollHeight > divBodyEl.clientHeight;
5244
5245 if ( settings.scrollBarVis !== scrollBarVis && settings.scrollBarVis !== undefined ) {
5246 settings.scrollBarVis = scrollBarVis;
5247 _fnAdjustColumnSizing( settings );
5248 return; // adjust column sizing will call this function again
5249 }
5250 else {
5251 settings.scrollBarVis = scrollBarVis;
5252 }
5253
5254 /*
5255 * 1. Re-create the table inside the scrolling div
5256 */
5257
5258 // Remove the old minimised thead and tfoot elements in the inner table
5259 table.children('thead, tfoot').remove();
5260
5261 if ( footer ) {
5262 footerCopy = footer.clone().prependTo( table );
5263 footerTrgEls = footer.find('tr'); // the original tfoot is in its own table and must be sized
5264 footerSrcEls = footerCopy.find('tr');
5265 }
5266
5267 // Clone the current header and footer elements and then place it into the inner table
5268 headerCopy = header.clone().prependTo( table );
5269 headerTrgEls = header.find('tr'); // original header is in its own table
5270 headerSrcEls = headerCopy.find('tr');
5271 headerCopy.find('th, td').removeAttr('tabindex');
5272
5273
5274 /*
5275 * 2. Take live measurements from the DOM - do not alter the DOM itself!
5276 */
5277
5278 // Remove old sizing and apply the calculated column widths
5279 // Get the unique column headers in the newly created (cloned) header. We want to apply the
5280 // calculated sizes to this header
5281 if ( ! scrollX )
5282 {
5283 divBodyStyle.width = '100%';
5284 divHeader[0].style.width = '100%';
5285 }
5286
5287 $.each( _fnGetUniqueThs( settings, headerCopy ), function ( i, el ) {
5288 idx = _fnVisibleToColumnIndex( settings, i );
5289 el.style.width = settings.aoColumns[idx].sWidth;
5290 } );
5291
5292 if ( footer ) {
5293 _fnApplyToChildren( function(n) {
5294 n.style.width = "";
5295 }, footerSrcEls );
5296 }
5297
5298 // Size the table as a whole
5299 sanityWidth = table.outerWidth();
5300 if ( scrollX === "" ) {
5301 // No x scrolling
5302 tableStyle.width = "100%";
5303
5304 // IE7 will make the width of the table when 100% include the scrollbar
5305 // - which is shouldn't. When there is a scrollbar we need to take this
5306 // into account.
5307 if ( ie67 && (table.find('tbody').height() > divBodyEl.offsetHeight ||
5308 divBody.css('overflow-y') == "scroll")
5309 ) {
5310 tableStyle.width = _fnStringToCss( table.outerWidth() - barWidth);
5311 }
5312
5313 // Recalculate the sanity width
5314 sanityWidth = table.outerWidth();
5315 }
5316 else if ( scrollXInner !== "" ) {
5317 // legacy x scroll inner has been given - use it
5318 tableStyle.width = _fnStringToCss(scrollXInner);
5319
5320 // Recalculate the sanity width
5321 sanityWidth = table.outerWidth();
5322 }
5323
5324 // Hidden header should have zero height, so remove padding and borders. Then
5325 // set the width based on the real headers
5326
5327 // Apply all styles in one pass
5328 _fnApplyToChildren( zeroOut, headerSrcEls );
5329
5330 // Read all widths in next pass
5331 _fnApplyToChildren( function(nSizer) {
5332 headerContent.push( nSizer.innerHTML );
5333 headerWidths.push( _fnStringToCss( $(nSizer).css('width') ) );
5334 }, headerSrcEls );
5335
5336 // Apply all widths in final pass
5337 _fnApplyToChildren( function(nToSize, i) {
5338 // Only apply widths to the DataTables detected header cells - this
5339 // prevents complex headers from having contradictory sizes applied
5340 if ( $.inArray( nToSize, dtHeaderCells ) !== -1 ) {
5341 nToSize.style.width = headerWidths[i];
5342 }
5343 }, headerTrgEls );
5344
5345 $(headerSrcEls).height(0);
5346
5347 /* Same again with the footer if we have one */
5348 if ( footer )
5349 {
5350 _fnApplyToChildren( zeroOut, footerSrcEls );
5351
5352 _fnApplyToChildren( function(nSizer) {
5353 footerContent.push( nSizer.innerHTML );
5354 footerWidths.push( _fnStringToCss( $(nSizer).css('width') ) );
5355 }, footerSrcEls );
5356
5357 _fnApplyToChildren( function(nToSize, i) {
5358 nToSize.style.width = footerWidths[i];
5359 }, footerTrgEls );
5360
5361 $(footerSrcEls).height(0);
5362 }
5363
5364
5365 /*
5366 * 3. Apply the measurements
5367 */
5368
5369 // "Hide" the header and footer that we used for the sizing. We need to keep
5370 // the content of the cell so that the width applied to the header and body
5371 // both match, but we want to hide it completely. We want to also fix their
5372 // width to what they currently are
5373 _fnApplyToChildren( function(nSizer, i) {
5374 nSizer.innerHTML = '<div class="dataTables_sizing">'+headerContent[i]+'</div>';
5375 nSizer.childNodes[0].style.height = "0";
5376 nSizer.childNodes[0].style.overflow = "hidden";
5377 nSizer.style.width = headerWidths[i];
5378 }, headerSrcEls );
5379
5380 if ( footer )
5381 {
5382 _fnApplyToChildren( function(nSizer, i) {
5383 nSizer.innerHTML = '<div class="dataTables_sizing">'+footerContent[i]+'</div>';
5384 nSizer.childNodes[0].style.height = "0";
5385 nSizer.childNodes[0].style.overflow = "hidden";
5386 nSizer.style.width = footerWidths[i];
5387 }, footerSrcEls );
5388 }
5389
5390 // Sanity check that the table is of a sensible width. If not then we are going to get
5391 // misalignment - try to prevent this by not allowing the table to shrink below its min width
5392 if ( table.outerWidth() < sanityWidth )
5393 {
5394 // The min width depends upon if we have a vertical scrollbar visible or not */
5395 correction = ((divBodyEl.scrollHeight > divBodyEl.offsetHeight ||
5396 divBody.css('overflow-y') == "scroll")) ?
5397 sanityWidth+barWidth :
5398 sanityWidth;
5399
5400 // IE6/7 are a law unto themselves...
5401 if ( ie67 && (divBodyEl.scrollHeight >
5402 divBodyEl.offsetHeight || divBody.css('overflow-y') == "scroll")
5403 ) {
5404 tableStyle.width = _fnStringToCss( correction-barWidth );
5405 }
5406
5407 // And give the user a warning that we've stopped the table getting too small
5408 if ( scrollX === "" || scrollXInner !== "" ) {
5409 _fnLog( settings, 1, 'Possible column misalignment', 6 );
5410 }
5411 }
5412 else
5413 {
5414 correction = '100%';
5415 }
5416
5417 // Apply to the container elements
5418 divBodyStyle.width = _fnStringToCss( correction );
5419 divHeaderStyle.width = _fnStringToCss( correction );
5420
5421 if ( footer ) {
5422 settings.nScrollFoot.style.width = _fnStringToCss( correction );
5423 }
5424
5425
5426 /*
5427 * 4. Clean up
5428 */
5429 if ( ! scrollY ) {
5430 /* IE7< puts a vertical scrollbar in place (when it shouldn't be) due to subtracting
5431 * the scrollbar height from the visible display, rather than adding it on. We need to
5432 * set the height in order to sort this. Don't want to do it in any other browsers.
5433 */
5434 if ( ie67 ) {
5435 divBodyStyle.height = _fnStringToCss( tableEl.offsetHeight+barWidth );
5436 }
5437 }
5438
5439 /* Finally set the width's of the header and footer tables */
5440 var iOuterWidth = table.outerWidth();
5441 divHeaderTable[0].style.width = _fnStringToCss( iOuterWidth );
5442 divHeaderInnerStyle.width = _fnStringToCss( iOuterWidth );
5443
5444 // Figure out if there are scrollbar present - if so then we need a the header and footer to
5445 // provide a bit more space to allow "overflow" scrolling (i.e. past the scrollbar)
5446 var bScrolling = table.height() > divBodyEl.clientHeight || divBody.css('overflow-y') == "scroll";
5447 var padding = 'padding' + (browser.bScrollbarLeft ? 'Left' : 'Right' );
5448 divHeaderInnerStyle[ padding ] = bScrolling ? barWidth+"px" : "0px";
5449
5450 if ( footer ) {
5451 divFooterTable[0].style.width = _fnStringToCss( iOuterWidth );
5452 divFooterInner[0].style.width = _fnStringToCss( iOuterWidth );
5453 divFooterInner[0].style[padding] = bScrolling ? barWidth+"px" : "0px";
5454 }
5455
5456 // Correct DOM ordering for colgroup - comes before the thead
5457 table.children('colgroup').insertBefore( table.children('thead') );
5458
5459 /* Adjust the position of the header in case we loose the y-scrollbar */
5460 divBody.scroll();
5461
5462 // If sorting or filtering has occurred, jump the scrolling back to the top
5463 // only if we aren't holding the position
5464 if ( (settings.bSorted || settings.bFiltered) && ! settings._drawHold ) {
5465 divBodyEl.scrollTop = 0;
5466 }
5467 }
5468
5469
5470
5471 /**
5472 * Apply a given function to the display child nodes of an element array (typically
5473 * TD children of TR rows
5474 * @param {function} fn Method to apply to the objects
5475 * @param array {nodes} an1 List of elements to look through for display children
5476 * @param array {nodes} an2 Another list (identical structure to the first) - optional
5477 * @memberof DataTable#oApi
5478 */
5479 function _fnApplyToChildren( fn, an1, an2 )
5480 {
5481 var index=0, i=0, iLen=an1.length;
5482 var nNode1, nNode2;
5483
5484 while ( i < iLen ) {
5485 nNode1 = an1[i].firstChild;
5486 nNode2 = an2 ? an2[i].firstChild : null;
5487
5488 while ( nNode1 ) {
5489 if ( nNode1.nodeType === 1 ) {
5490 if ( an2 ) {
5491 fn( nNode1, nNode2, index );
5492 }
5493 else {
5494 fn( nNode1, index );
5495 }
5496
5497 index++;
5498 }
5499
5500 nNode1 = nNode1.nextSibling;
5501 nNode2 = an2 ? nNode2.nextSibling : null;
5502 }
5503
5504 i++;
5505 }
5506 }
5507
5508
5509
5510 var __re_html_remove = /<.*?>/g;
5511
5512
5513 /**
5514 * Calculate the width of columns for the table
5515 * @param {object} oSettings dataTables settings object
5516 * @memberof DataTable#oApi
5517 */
5518 function _fnCalculateColumnWidths ( oSettings )
5519 {
5520 var
5521 table = oSettings.nTable,
5522 columns = oSettings.aoColumns,
5523 scroll = oSettings.oScroll,
5524 scrollY = scroll.sY,
5525 scrollX = scroll.sX,
5526 scrollXInner = scroll.sXInner,
5527 columnCount = columns.length,
5528 visibleColumns = _fnGetColumns( oSettings, 'bVisible' ),
5529 headerCells = $('th', oSettings.nTHead),
5530 tableWidthAttr = table.getAttribute('width'), // from DOM element
5531 tableContainer = table.parentNode,
5532 userInputs = false,
5533 i, column, columnIdx, width, outerWidth,
5534 browser = oSettings.oBrowser,
5535 ie67 = browser.bScrollOversize;
5536
5537 var styleWidth = table.style.width;
5538 if ( styleWidth && styleWidth.indexOf('%') !== -1 ) {
5539 tableWidthAttr = styleWidth;
5540 }
5541
5542 /* Convert any user input sizes into pixel sizes */
5543 for ( i=0 ; i<visibleColumns.length ; i++ ) {
5544 column = columns[ visibleColumns[i] ];
5545
5546 if ( column.sWidth !== null ) {
5547 column.sWidth = _fnConvertToWidth( column.sWidthOrig, tableContainer );
5548
5549 userInputs = true;
5550 }
5551 }
5552
5553 /* If the number of columns in the DOM equals the number that we have to
5554 * process in DataTables, then we can use the offsets that are created by
5555 * the web- browser. No custom sizes can be set in order for this to happen,
5556 * nor scrolling used
5557 */
5558 if ( ie67 || ! userInputs && ! scrollX && ! scrollY &&
5559 columnCount == _fnVisbleColumns( oSettings ) &&
5560 columnCount == headerCells.length
5561 ) {
5562 for ( i=0 ; i<columnCount ; i++ ) {
5563 var colIdx = _fnVisibleToColumnIndex( oSettings, i );
5564
5565 if ( colIdx !== null ) {
5566 columns[ colIdx ].sWidth = _fnStringToCss( headerCells.eq(i).width() );
5567 }
5568 }
5569 }
5570 else
5571 {
5572 // Otherwise construct a single row, worst case, table with the widest
5573 // node in the data, assign any user defined widths, then insert it into
5574 // the DOM and allow the browser to do all the hard work of calculating
5575 // table widths
5576 var tmpTable = $(table).clone() // don't use cloneNode - IE8 will remove events on the main table
5577 .css( 'visibility', 'hidden' )
5578 .removeAttr( 'id' );
5579
5580 // Clean up the table body
5581 tmpTable.find('tbody tr').remove();
5582 var tr = $('<tr/>').appendTo( tmpTable.find('tbody') );
5583
5584 // Clone the table header and footer - we can't use the header / footer
5585 // from the cloned table, since if scrolling is active, the table's
5586 // real header and footer are contained in different table tags
5587 tmpTable.find('thead, tfoot').remove();
5588 tmpTable
5589 .append( $(oSettings.nTHead).clone() )
5590 .append( $(oSettings.nTFoot).clone() );
5591
5592 // Remove any assigned widths from the footer (from scrolling)
5593 tmpTable.find('tfoot th, tfoot td').css('width', '');
5594
5595 // Apply custom sizing to the cloned header
5596 headerCells = _fnGetUniqueThs( oSettings, tmpTable.find('thead')[0] );
5597
5598 for ( i=0 ; i<visibleColumns.length ; i++ ) {
5599 column = columns[ visibleColumns[i] ];
5600
5601 headerCells[i].style.width = column.sWidthOrig !== null && column.sWidthOrig !== '' ?
5602 _fnStringToCss( column.sWidthOrig ) :
5603 '';
5604
5605 // For scrollX we need to force the column width otherwise the
5606 // browser will collapse it. If this width is smaller than the
5607 // width the column requires, then it will have no effect
5608 if ( column.sWidthOrig && scrollX ) {
5609 $( headerCells[i] ).append( $('<div/>').css( {
5610 width: column.sWidthOrig,
5611 margin: 0,
5612 padding: 0,
5613 border: 0,
5614 height: 1
5615 } ) );
5616 }
5617 }
5618
5619 // Find the widest cell for each column and put it into the table
5620 if ( oSettings.aoData.length ) {
5621 for ( i=0 ; i<visibleColumns.length ; i++ ) {
5622 columnIdx = visibleColumns[i];
5623 column = columns[ columnIdx ];
5624
5625 $( _fnGetWidestNode( oSettings, columnIdx ) )
5626 .clone( false )
5627 .append( column.sContentPadding )
5628 .appendTo( tr );
5629 }
5630 }
5631
5632 // Tidy the temporary table - remove name attributes so there aren't
5633 // duplicated in the dom (radio elements for example)
5634 $('[name]', tmpTable).removeAttr('name');
5635
5636 // Table has been built, attach to the document so we can work with it.
5637 // A holding element is used, positioned at the top of the container
5638 // with minimal height, so it has no effect on if the container scrolls
5639 // or not. Otherwise it might trigger scrolling when it actually isn't
5640 // needed
5641 var holder = $('<div/>').css( scrollX || scrollY ?
5642 {
5643 position: 'absolute',
5644 top: 0,
5645 left: 0,
5646 height: 1,
5647 right: 0,
5648 overflow: 'hidden'
5649 } :
5650 {}
5651 )
5652 .append( tmpTable )
5653 .appendTo( tableContainer );
5654
5655 // When scrolling (X or Y) we want to set the width of the table as
5656 // appropriate. However, when not scrolling leave the table width as it
5657 // is. This results in slightly different, but I think correct behaviour
5658 if ( scrollX && scrollXInner ) {
5659 tmpTable.width( scrollXInner );
5660 }
5661 else if ( scrollX ) {
5662 tmpTable.css( 'width', 'auto' );
5663 tmpTable.removeAttr('width');
5664
5665 // If there is no width attribute or style, then allow the table to
5666 // collapse
5667 if ( tmpTable.width() < tableContainer.clientWidth && tableWidthAttr ) {
5668 tmpTable.width( tableContainer.clientWidth );
5669 }
5670 }
5671 else if ( scrollY ) {
5672 tmpTable.width( tableContainer.clientWidth );
5673 }
5674 else if ( tableWidthAttr ) {
5675 tmpTable.width( tableWidthAttr );
5676 }
5677
5678 // Get the width of each column in the constructed table - we need to
5679 // know the inner width (so it can be assigned to the other table's
5680 // cells) and the outer width so we can calculate the full width of the
5681 // table. This is safe since DataTables requires a unique cell for each
5682 // column, but if ever a header can span multiple columns, this will
5683 // need to be modified.
5684 var total = 0;
5685 for ( i=0 ; i<visibleColumns.length ; i++ ) {
5686 var cell = $(headerCells[i]);
5687 var border = cell.outerWidth() - cell.width();
5688
5689 // Use getBounding... where possible (not IE8-) because it can give
5690 // sub-pixel accuracy, which we then want to round up!
5691 var bounding = browser.bBounding ?
5692 Math.ceil( headerCells[i].getBoundingClientRect().width ) :
5693 cell.outerWidth();
5694
5695 // Total is tracked to remove any sub-pixel errors as the outerWidth
5696 // of the table might not equal the total given here (IE!).
5697 total += bounding;
5698
5699 // Width for each column to use
5700 columns[ visibleColumns[i] ].sWidth = _fnStringToCss( bounding - border );
5701 }
5702
5703 table.style.width = _fnStringToCss( total );
5704
5705 // Finished with the table - ditch it
5706 holder.remove();
5707 }
5708
5709 // If there is a width attr, we want to attach an event listener which
5710 // allows the table sizing to automatically adjust when the window is
5711 // resized. Use the width attr rather than CSS, since we can't know if the
5712 // CSS is a relative value or absolute - DOM read is always px.
5713 if ( tableWidthAttr ) {
5714 table.style.width = _fnStringToCss( tableWidthAttr );
5715 }
5716
5717 if ( (tableWidthAttr || scrollX) && ! oSettings._reszEvt ) {
5718 var bindResize = function () {
5719 $(window).on('resize.DT-'+oSettings.sInstance, _fnThrottle( function () {
5720 _fnAdjustColumnSizing( oSettings );
5721 } ) );
5722 };
5723
5724 // IE6/7 will crash if we bind a resize event handler on page load.
5725 // To be removed in 1.11 which drops IE6/7 support
5726 if ( ie67 ) {
5727 setTimeout( bindResize, 1000 );
5728 }
5729 else {
5730 bindResize();
5731 }
5732
5733 oSettings._reszEvt = true;
5734 }
5735 }
5736
5737
5738 /**
5739 * Throttle the calls to a function. Arguments and context are maintained for
5740 * the throttled function
5741 * @param {function} fn Function to be called
5742 * @param {int} [freq=200] call frequency in mS
5743 * @returns {function} wrapped function
5744 * @memberof DataTable#oApi
5745 */
5746 var _fnThrottle = DataTable.util.throttle;
5747
5748
5749 /**
5750 * Convert a CSS unit width to pixels (e.g. 2em)
5751 * @param {string} width width to be converted
5752 * @param {node} parent parent to get the with for (required for relative widths) - optional
5753 * @returns {int} width in pixels
5754 * @memberof DataTable#oApi
5755 */
5756 function _fnConvertToWidth ( width, parent )
5757 {
5758 if ( ! width ) {
5759 return 0;
5760 }
5761
5762 var n = $('<div/>')
5763 .css( 'width', _fnStringToCss( width ) )
5764 .appendTo( parent || document.body );
5765
5766 var val = n[0].offsetWidth;
5767 n.remove();
5768
5769 return val;
5770 }
5771
5772
5773 /**
5774 * Get the widest node
5775 * @param {object} settings dataTables settings object
5776 * @param {int} colIdx column of interest
5777 * @returns {node} widest table node
5778 * @memberof DataTable#oApi
5779 */
5780 function _fnGetWidestNode( settings, colIdx )
5781 {
5782 var idx = _fnGetMaxLenString( settings, colIdx );
5783 if ( idx < 0 ) {
5784 return null;
5785 }
5786
5787 var data = settings.aoData[ idx ];
5788 return ! data.nTr ? // Might not have been created when deferred rendering
5789 $('<td/>').html( _fnGetCellData( settings, idx, colIdx, 'display' ) )[0] :
5790 data.anCells[ colIdx ];
5791 }
5792
5793
5794 /**
5795 * Get the maximum strlen for each data column
5796 * @param {object} settings dataTables settings object
5797 * @param {int} colIdx column of interest
5798 * @returns {string} max string length for each column
5799 * @memberof DataTable#oApi
5800 */
5801 function _fnGetMaxLenString( settings, colIdx )
5802 {
5803 var s, max=-1, maxIdx = -1;
5804
5805 for ( var i=0, ien=settings.aoData.length ; i<ien ; i++ ) {
5806 s = _fnGetCellData( settings, i, colIdx, 'display' )+'';
5807 s = s.replace( __re_html_remove, '' );
5808 s = s.replace( /&nbsp;/g, ' ' );
5809
5810 if ( s.length > max ) {
5811 max = s.length;
5812 maxIdx = i;
5813 }
5814 }
5815
5816 return maxIdx;
5817 }
5818
5819
5820 /**
5821 * Append a CSS unit (only if required) to a string
5822 * @param {string} value to css-ify
5823 * @returns {string} value with css unit
5824 * @memberof DataTable#oApi
5825 */
5826 function _fnStringToCss( s )
5827 {
5828 if ( s === null ) {
5829 return '0px';
5830 }
5831
5832 if ( typeof s == 'number' ) {
5833 return s < 0 ?
5834 '0px' :
5835 s+'px';
5836 }
5837
5838 // Check it has a unit character already
5839 return s.match(/\d$/) ?
5840 s+'px' :
5841 s;
5842 }
5843
5844
5845
5846 function _fnSortFlatten ( settings )
5847 {
5848 var
5849 i, iLen, k, kLen,
5850 aSort = [],
5851 aiOrig = [],
5852 aoColumns = settings.aoColumns,
5853 aDataSort, iCol, sType, srcCol,
5854 fixed = settings.aaSortingFixed,
5855 fixedObj = $.isPlainObject( fixed ),
5856 nestedSort = [],
5857 add = function ( a ) {
5858 if ( a.length && ! $.isArray( a[0] ) ) {
5859 // 1D array
5860 nestedSort.push( a );
5861 }
5862 else {
5863 // 2D array
5864 $.merge( nestedSort, a );
5865 }
5866 };
5867
5868 // Build the sort array, with pre-fix and post-fix options if they have been
5869 // specified
5870 if ( $.isArray( fixed ) ) {
5871 add( fixed );
5872 }
5873
5874 if ( fixedObj && fixed.pre ) {
5875 add( fixed.pre );
5876 }
5877
5878 add( settings.aaSorting );
5879
5880 if (fixedObj && fixed.post ) {
5881 add( fixed.post );
5882 }
5883
5884 for ( i=0 ; i<nestedSort.length ; i++ )
5885 {
5886 srcCol = nestedSort[i][0];
5887 aDataSort = aoColumns[ srcCol ].aDataSort;
5888
5889 for ( k=0, kLen=aDataSort.length ; k<kLen ; k++ )
5890 {
5891 iCol = aDataSort[k];
5892 sType = aoColumns[ iCol ].sType || 'string';
5893
5894 if ( nestedSort[i]._idx === undefined ) {
5895 nestedSort[i]._idx = $.inArray( nestedSort[i][1], aoColumns[iCol].asSorting );
5896 }
5897
5898 aSort.push( {
5899 src: srcCol,
5900 col: iCol,
5901 dir: nestedSort[i][1],
5902 index: nestedSort[i]._idx,
5903 type: sType,
5904 formatter: DataTable.ext.type.order[ sType+"-pre" ]
5905 } );
5906 }
5907 }
5908
5909 return aSort;
5910 }
5911
5912 /**
5913 * Change the order of the table
5914 * @param {object} oSettings dataTables settings object
5915 * @memberof DataTable#oApi
5916 * @todo This really needs split up!
5917 */
5918 function _fnSort ( oSettings )
5919 {
5920 var
5921 i, ien, iLen, j, jLen, k, kLen,
5922 sDataType, nTh,
5923 aiOrig = [],
5924 oExtSort = DataTable.ext.type.order,
5925 aoData = oSettings.aoData,
5926 aoColumns = oSettings.aoColumns,
5927 aDataSort, data, iCol, sType, oSort,
5928 formatters = 0,
5929 sortCol,
5930 displayMaster = oSettings.aiDisplayMaster,
5931 aSort;
5932
5933 // Resolve any column types that are unknown due to addition or invalidation
5934 // @todo Can this be moved into a 'data-ready' handler which is called when
5935 // data is going to be used in the table?
5936 _fnColumnTypes( oSettings );
5937
5938 aSort = _fnSortFlatten( oSettings );
5939
5940 for ( i=0, ien=aSort.length ; i<ien ; i++ ) {
5941 sortCol = aSort[i];
5942
5943 // Track if we can use the fast sort algorithm
5944 if ( sortCol.formatter ) {
5945 formatters++;
5946 }
5947
5948 // Load the data needed for the sort, for each cell
5949 _fnSortData( oSettings, sortCol.col );
5950 }
5951
5952 /* No sorting required if server-side or no sorting array */
5953 if ( _fnDataSource( oSettings ) != 'ssp' && aSort.length !== 0 )
5954 {
5955 // Create a value - key array of the current row positions such that we can use their
5956 // current position during the sort, if values match, in order to perform stable sorting
5957 for ( i=0, iLen=displayMaster.length ; i<iLen ; i++ ) {
5958 aiOrig[ displayMaster[i] ] = i;
5959 }
5960
5961 /* Do the sort - here we want multi-column sorting based on a given data source (column)
5962 * and sorting function (from oSort) in a certain direction. It's reasonably complex to
5963 * follow on it's own, but this is what we want (example two column sorting):
5964 * fnLocalSorting = function(a,b){
5965 * var iTest;
5966 * iTest = oSort['string-asc']('data11', 'data12');
5967 * if (iTest !== 0)
5968 * return iTest;
5969 * iTest = oSort['numeric-desc']('data21', 'data22');
5970 * if (iTest !== 0)
5971 * return iTest;
5972 * return oSort['numeric-asc']( aiOrig[a], aiOrig[b] );
5973 * }
5974 * Basically we have a test for each sorting column, if the data in that column is equal,
5975 * test the next column. If all columns match, then we use a numeric sort on the row
5976 * positions in the original data array to provide a stable sort.
5977 *
5978 * Note - I know it seems excessive to have two sorting methods, but the first is around
5979 * 15% faster, so the second is only maintained for backwards compatibility with sorting
5980 * methods which do not have a pre-sort formatting function.
5981 */
5982 if ( formatters === aSort.length ) {
5983 // All sort types have formatting functions
5984 displayMaster.sort( function ( a, b ) {
5985 var
5986 x, y, k, test, sort,
5987 len=aSort.length,
5988 dataA = aoData[a]._aSortData,
5989 dataB = aoData[b]._aSortData;
5990
5991 for ( k=0 ; k<len ; k++ ) {
5992 sort = aSort[k];
5993
5994 x = dataA[ sort.col ];
5995 y = dataB[ sort.col ];
5996
5997 test = x<y ? -1 : x>y ? 1 : 0;
5998 if ( test !== 0 ) {
5999 return sort.dir === 'asc' ? test : -test;
6000 }
6001 }
6002
6003 x = aiOrig[a];
6004 y = aiOrig[b];
6005 return x<y ? -1 : x>y ? 1 : 0;
6006 } );
6007 }
6008 else {
6009 // Depreciated - remove in 1.11 (providing a plug-in option)
6010 // Not all sort types have formatting methods, so we have to call their sorting
6011 // methods.
6012 displayMaster.sort( function ( a, b ) {
6013 var
6014 x, y, k, l, test, sort, fn,
6015 len=aSort.length,
6016 dataA = aoData[a]._aSortData,
6017 dataB = aoData[b]._aSortData;
6018
6019 for ( k=0 ; k<len ; k++ ) {
6020 sort = aSort[k];
6021
6022 x = dataA[ sort.col ];
6023 y = dataB[ sort.col ];
6024
6025 fn = oExtSort[ sort.type+"-"+sort.dir ] || oExtSort[ "string-"+sort.dir ];
6026 test = fn( x, y );
6027 if ( test !== 0 ) {
6028 return test;
6029 }
6030 }
6031
6032 x = aiOrig[a];
6033 y = aiOrig[b];
6034 return x<y ? -1 : x>y ? 1 : 0;
6035 } );
6036 }
6037 }
6038
6039 /* Tell the draw function that we have sorted the data */
6040 oSettings.bSorted = true;
6041 }
6042
6043
6044 function _fnSortAria ( settings )
6045 {
6046 var label;
6047 var nextSort;
6048 var columns = settings.aoColumns;
6049 var aSort = _fnSortFlatten( settings );
6050 var oAria = settings.oLanguage.oAria;
6051
6052 // ARIA attributes - need to loop all columns, to update all (removing old
6053 // attributes as needed)
6054 for ( var i=0, iLen=columns.length ; i<iLen ; i++ )
6055 {
6056 var col = columns[i];
6057 var asSorting = col.asSorting;
6058 var sTitle = col.sTitle.replace( /<.*?>/g, "" );
6059 var th = col.nTh;
6060
6061 // IE7 is throwing an error when setting these properties with jQuery's
6062 // attr() and removeAttr() methods...
6063 th.removeAttribute('aria-sort');
6064
6065 /* In ARIA only the first sorting column can be marked as sorting - no multi-sort option */
6066 if ( col.bSortable ) {
6067 if ( aSort.length > 0 && aSort[0].col == i ) {
6068 th.setAttribute('aria-sort', aSort[0].dir=="asc" ? "ascending" : "descending" );
6069 nextSort = asSorting[ aSort[0].index+1 ] || asSorting[0];
6070 }
6071 else {
6072 nextSort = asSorting[0];
6073 }
6074
6075 label = sTitle + ( nextSort === "asc" ?
6076 oAria.sSortAscending :
6077 oAria.sSortDescending
6078 );
6079 }
6080 else {
6081 label = sTitle;
6082 }
6083
6084 th.setAttribute('aria-label', label);
6085 }
6086 }
6087
6088
6089 /**
6090 * Function to run on user sort request
6091 * @param {object} settings dataTables settings object
6092 * @param {node} attachTo node to attach the handler to
6093 * @param {int} colIdx column sorting index
6094 * @param {boolean} [append=false] Append the requested sort to the existing
6095 * sort if true (i.e. multi-column sort)
6096 * @param {function} [callback] callback function
6097 * @memberof DataTable#oApi
6098 */
6099 function _fnSortListener ( settings, colIdx, append, callback )
6100 {
6101 var col = settings.aoColumns[ colIdx ];
6102 var sorting = settings.aaSorting;
6103 var asSorting = col.asSorting;
6104 var nextSortIdx;
6105 var next = function ( a, overflow ) {
6106 var idx = a._idx;
6107 if ( idx === undefined ) {
6108 idx = $.inArray( a[1], asSorting );
6109 }
6110
6111 return idx+1 < asSorting.length ?
6112 idx+1 :
6113 overflow ?
6114 null :
6115 0;
6116 };
6117
6118 // Convert to 2D array if needed
6119 if ( typeof sorting[0] === 'number' ) {
6120 sorting = settings.aaSorting = [ sorting ];
6121 }
6122
6123 // If appending the sort then we are multi-column sorting
6124 if ( append && settings.oFeatures.bSortMulti ) {
6125 // Are we already doing some kind of sort on this column?
6126 var sortIdx = $.inArray( colIdx, _pluck(sorting, '0') );
6127
6128 if ( sortIdx !== -1 ) {
6129 // Yes, modify the sort
6130 nextSortIdx = next( sorting[sortIdx], true );
6131
6132 if ( nextSortIdx === null && sorting.length === 1 ) {
6133 nextSortIdx = 0; // can't remove sorting completely
6134 }
6135
6136 if ( nextSortIdx === null ) {
6137 sorting.splice( sortIdx, 1 );
6138 }
6139 else {
6140 sorting[sortIdx][1] = asSorting[ nextSortIdx ];
6141 sorting[sortIdx]._idx = nextSortIdx;
6142 }
6143 }
6144 else {
6145 // No sort on this column yet
6146 sorting.push( [ colIdx, asSorting[0], 0 ] );
6147 sorting[sorting.length-1]._idx = 0;
6148 }
6149 }
6150 else if ( sorting.length && sorting[0][0] == colIdx ) {
6151 // Single column - already sorting on this column, modify the sort
6152 nextSortIdx = next( sorting[0] );
6153
6154 sorting.length = 1;
6155 sorting[0][1] = asSorting[ nextSortIdx ];
6156 sorting[0]._idx = nextSortIdx;
6157 }
6158 else {
6159 // Single column - sort only on this column
6160 sorting.length = 0;
6161 sorting.push( [ colIdx, asSorting[0] ] );
6162 sorting[0]._idx = 0;
6163 }
6164
6165 // Run the sort by calling a full redraw
6166 _fnReDraw( settings );
6167
6168 // callback used for async user interaction
6169 if ( typeof callback == 'function' ) {
6170 callback( settings );
6171 }
6172 }
6173
6174
6175 /**
6176 * Attach a sort handler (click) to a node
6177 * @param {object} settings dataTables settings object
6178 * @param {node} attachTo node to attach the handler to
6179 * @param {int} colIdx column sorting index
6180 * @param {function} [callback] callback function
6181 * @memberof DataTable#oApi
6182 */
6183 function _fnSortAttachListener ( settings, attachTo, colIdx, callback )
6184 {
6185 var col = settings.aoColumns[ colIdx ];
6186
6187 _fnBindAction( attachTo, {}, function (e) {
6188 /* If the column is not sortable - don't to anything */
6189 if ( col.bSortable === false ) {
6190 return;
6191 }
6192
6193 // If processing is enabled use a timeout to allow the processing
6194 // display to be shown - otherwise to it synchronously
6195 if ( settings.oFeatures.bProcessing ) {
6196 _fnProcessingDisplay( settings, true );
6197
6198 setTimeout( function() {
6199 _fnSortListener( settings, colIdx, e.shiftKey, callback );
6200
6201 // In server-side processing, the draw callback will remove the
6202 // processing display
6203 if ( _fnDataSource( settings ) !== 'ssp' ) {
6204 _fnProcessingDisplay( settings, false );
6205 }
6206 }, 0 );
6207 }
6208 else {
6209 _fnSortListener( settings, colIdx, e.shiftKey, callback );
6210 }
6211 } );
6212 }
6213
6214
6215 /**
6216 * Set the sorting classes on table's body, Note: it is safe to call this function
6217 * when bSort and bSortClasses are false
6218 * @param {object} oSettings dataTables settings object
6219 * @memberof DataTable#oApi
6220 */
6221 function _fnSortingClasses( settings )
6222 {
6223 var oldSort = settings.aLastSort;
6224 var sortClass = settings.oClasses.sSortColumn;
6225 var sort = _fnSortFlatten( settings );
6226 var features = settings.oFeatures;
6227 var i, ien, colIdx;
6228
6229 if ( features.bSort && features.bSortClasses ) {
6230 // Remove old sorting classes
6231 for ( i=0, ien=oldSort.length ; i<ien ; i++ ) {
6232 colIdx = oldSort[i].src;
6233
6234 // Remove column sorting
6235 $( _pluck( settings.aoData, 'anCells', colIdx ) )
6236 .removeClass( sortClass + (i<2 ? i+1 : 3) );
6237 }
6238
6239 // Add new column sorting
6240 for ( i=0, ien=sort.length ; i<ien ; i++ ) {
6241 colIdx = sort[i].src;
6242
6243 $( _pluck( settings.aoData, 'anCells', colIdx ) )
6244 .addClass( sortClass + (i<2 ? i+1 : 3) );
6245 }
6246 }
6247
6248 settings.aLastSort = sort;
6249 }
6250
6251
6252 // Get the data to sort a column, be it from cache, fresh (populating the
6253 // cache), or from a sort formatter
6254 function _fnSortData( settings, idx )
6255 {
6256 // Custom sorting function - provided by the sort data type
6257 var column = settings.aoColumns[ idx ];
6258 var customSort = DataTable.ext.order[ column.sSortDataType ];
6259 var customData;
6260
6261 if ( customSort ) {
6262 customData = customSort.call( settings.oInstance, settings, idx,
6263 _fnColumnIndexToVisible( settings, idx )
6264 );
6265 }
6266
6267 // Use / populate cache
6268 var row, cellData;
6269 var formatter = DataTable.ext.type.order[ column.sType+"-pre" ];
6270
6271 for ( var i=0, ien=settings.aoData.length ; i<ien ; i++ ) {
6272 row = settings.aoData[i];
6273
6274 if ( ! row._aSortData ) {
6275 row._aSortData = [];
6276 }
6277
6278 if ( ! row._aSortData[idx] || customSort ) {
6279 cellData = customSort ?
6280 customData[i] : // If there was a custom sort function, use data from there
6281 _fnGetCellData( settings, i, idx, 'sort' );
6282
6283 row._aSortData[ idx ] = formatter ?
6284 formatter( cellData ) :
6285 cellData;
6286 }
6287 }
6288 }
6289
6290
6291
6292 /**
6293 * Save the state of a table
6294 * @param {object} oSettings dataTables settings object
6295 * @memberof DataTable#oApi
6296 */
6297 function _fnSaveState ( settings )
6298 {
6299 if ( !settings.oFeatures.bStateSave || settings.bDestroying )
6300 {
6301 return;
6302 }
6303
6304 /* Store the interesting variables */
6305 var state = {
6306 time: +new Date(),
6307 start: settings._iDisplayStart,
6308 length: settings._iDisplayLength,
6309 order: $.extend( true, [], settings.aaSorting ),
6310 search: _fnSearchToCamel( settings.oPreviousSearch ),
6311 columns: $.map( settings.aoColumns, function ( col, i ) {
6312 return {
6313 visible: col.bVisible,
6314 search: _fnSearchToCamel( settings.aoPreSearchCols[i] )
6315 };
6316 } )
6317 };
6318
6319 _fnCallbackFire( settings, "aoStateSaveParams", 'stateSaveParams', [settings, state] );
6320
6321 settings.oSavedState = state;
6322 settings.fnStateSaveCallback.call( settings.oInstance, settings, state );
6323 }
6324
6325
6326 /**
6327 * Attempt to load a saved table state
6328 * @param {object} oSettings dataTables settings object
6329 * @param {object} oInit DataTables init object so we can override settings
6330 * @param {function} callback Callback to execute when the state has been loaded
6331 * @memberof DataTable#oApi
6332 */
6333 function _fnLoadState ( settings, oInit, callback )
6334 {
6335 var i, ien;
6336 var columns = settings.aoColumns;
6337 var loaded = function ( s ) {
6338 if ( ! s || ! s.time ) {
6339 callback();
6340 return;
6341 }
6342
6343 // Allow custom and plug-in manipulation functions to alter the saved data set and
6344 // cancelling of loading by returning false
6345 var abStateLoad = _fnCallbackFire( settings, 'aoStateLoadParams', 'stateLoadParams', [settings, s] );
6346 if ( $.inArray( false, abStateLoad ) !== -1 ) {
6347 callback();
6348 return;
6349 }
6350
6351 // Reject old data
6352 var duration = settings.iStateDuration;
6353 if ( duration > 0 && s.time < +new Date() - (duration*1000) ) {
6354 callback();
6355 return;
6356 }
6357
6358 // Number of columns have changed - all bets are off, no restore of settings
6359 if ( s.columns && columns.length !== s.columns.length ) {
6360 callback();
6361 return;
6362 }
6363
6364 // Store the saved state so it might be accessed at any time
6365 settings.oLoadedState = $.extend( true, {}, s );
6366
6367 // Restore key features - todo - for 1.11 this needs to be done by
6368 // subscribed events
6369 if ( s.start !== undefined ) {
6370 settings._iDisplayStart = s.start;
6371 settings.iInitDisplayStart = s.start;
6372 }
6373 if ( s.length !== undefined ) {
6374 settings._iDisplayLength = s.length;
6375 }
6376
6377 // Order
6378 if ( s.order !== undefined ) {
6379 settings.aaSorting = [];
6380 $.each( s.order, function ( i, col ) {
6381 settings.aaSorting.push( col[0] >= columns.length ?
6382 [ 0, col[1] ] :
6383 col
6384 );
6385 } );
6386 }
6387
6388 // Search
6389 if ( s.search !== undefined ) {
6390 $.extend( settings.oPreviousSearch, _fnSearchToHung( s.search ) );
6391 }
6392
6393 // Columns
6394 //
6395 if ( s.columns ) {
6396 for ( i=0, ien=s.columns.length ; i<ien ; i++ ) {
6397 var col = s.columns[i];
6398
6399 // Visibility
6400 if ( col.visible !== undefined ) {
6401 columns[i].bVisible = col.visible;
6402 }
6403
6404 // Search
6405 if ( col.search !== undefined ) {
6406 $.extend( settings.aoPreSearchCols[i], _fnSearchToHung( col.search ) );
6407 }
6408 }
6409 }
6410
6411 _fnCallbackFire( settings, 'aoStateLoaded', 'stateLoaded', [settings, s] );
6412 callback();
6413 }
6414
6415 if ( ! settings.oFeatures.bStateSave ) {
6416 callback();
6417 return;
6418 }
6419
6420 var state = settings.fnStateLoadCallback.call( settings.oInstance, settings, loaded );
6421
6422 if ( state !== undefined ) {
6423 loaded( state );
6424 }
6425 // otherwise, wait for the loaded callback to be executed
6426 }
6427
6428
6429 /**
6430 * Return the settings object for a particular table
6431 * @param {node} table table we are using as a dataTable
6432 * @returns {object} Settings object - or null if not found
6433 * @memberof DataTable#oApi
6434 */
6435 function _fnSettingsFromNode ( table )
6436 {
6437 var settings = DataTable.settings;
6438 var idx = $.inArray( table, _pluck( settings, 'nTable' ) );
6439
6440 return idx !== -1 ?
6441 settings[ idx ] :
6442 null;
6443 }
6444
6445
6446 /**
6447 * Log an error message
6448 * @param {object} settings dataTables settings object
6449 * @param {int} level log error messages, or display them to the user
6450 * @param {string} msg error message
6451 * @param {int} tn Technical note id to get more information about the error.
6452 * @memberof DataTable#oApi
6453 */
6454 function _fnLog( settings, level, msg, tn )
6455 {
6456 msg = 'DataTables warning: '+
6457 (settings ? 'table id='+settings.sTableId+' - ' : '')+msg;
6458
6459 if ( tn ) {
6460 msg += '. For more information about this error, please see '+
6461 'http://datatables.net/tn/'+tn;
6462 }
6463
6464 if ( ! level ) {
6465 // Backwards compatibility pre 1.10
6466 var ext = DataTable.ext;
6467 var type = ext.sErrMode || ext.errMode;
6468
6469 if ( settings ) {
6470 _fnCallbackFire( settings, null, 'error', [ settings, tn, msg ] );
6471 }
6472
6473 if ( type == 'alert' ) {
6474 alert( msg );
6475 }
6476 else if ( type == 'throw' ) {
6477 throw new Error(msg);
6478 }
6479 else if ( typeof type == 'function' ) {
6480 type( settings, tn, msg );
6481 }
6482 }
6483 else if ( window.console && console.log ) {
6484 console.log( msg );
6485 }
6486 }
6487
6488
6489 /**
6490 * See if a property is defined on one object, if so assign it to the other object
6491 * @param {object} ret target object
6492 * @param {object} src source object
6493 * @param {string} name property
6494 * @param {string} [mappedName] name to map too - optional, name used if not given
6495 * @memberof DataTable#oApi
6496 */
6497 function _fnMap( ret, src, name, mappedName )
6498 {
6499 if ( $.isArray( name ) ) {
6500 $.each( name, function (i, val) {
6501 if ( $.isArray( val ) ) {
6502 _fnMap( ret, src, val[0], val[1] );
6503 }
6504 else {
6505 _fnMap( ret, src, val );
6506 }
6507 } );
6508
6509 return;
6510 }
6511
6512 if ( mappedName === undefined ) {
6513 mappedName = name;
6514 }
6515
6516 if ( src[name] !== undefined ) {
6517 ret[mappedName] = src[name];
6518 }
6519 }
6520
6521
6522 /**
6523 * Extend objects - very similar to jQuery.extend, but deep copy objects, and
6524 * shallow copy arrays. The reason we need to do this, is that we don't want to
6525 * deep copy array init values (such as aaSorting) since the dev wouldn't be
6526 * able to override them, but we do want to deep copy arrays.
6527 * @param {object} out Object to extend
6528 * @param {object} extender Object from which the properties will be applied to
6529 * out
6530 * @param {boolean} breakRefs If true, then arrays will be sliced to take an
6531 * independent copy with the exception of the `data` or `aaData` parameters
6532 * if they are present. This is so you can pass in a collection to
6533 * DataTables and have that used as your data source without breaking the
6534 * references
6535 * @returns {object} out Reference, just for convenience - out === the return.
6536 * @memberof DataTable#oApi
6537 * @todo This doesn't take account of arrays inside the deep copied objects.
6538 */
6539 function _fnExtend( out, extender, breakRefs )
6540 {
6541 var val;
6542
6543 for ( var prop in extender ) {
6544 if ( extender.hasOwnProperty(prop) ) {
6545 val = extender[prop];
6546
6547 if ( $.isPlainObject( val ) ) {
6548 if ( ! $.isPlainObject( out[prop] ) ) {
6549 out[prop] = {};
6550 }
6551 $.extend( true, out[prop], val );
6552 }
6553 else if ( breakRefs && prop !== 'data' && prop !== 'aaData' && $.isArray(val) ) {
6554 out[prop] = val.slice();
6555 }
6556 else {
6557 out[prop] = val;
6558 }
6559 }
6560 }
6561
6562 return out;
6563 }
6564
6565
6566 /**
6567 * Bind an event handers to allow a click or return key to activate the callback.
6568 * This is good for accessibility since a return on the keyboard will have the
6569 * same effect as a click, if the element has focus.
6570 * @param {element} n Element to bind the action to
6571 * @param {object} oData Data object to pass to the triggered function
6572 * @param {function} fn Callback function for when the event is triggered
6573 * @memberof DataTable#oApi
6574 */
6575 function _fnBindAction( n, oData, fn )
6576 {
6577 $(n)
6578 .on( 'click.DT', oData, function (e) {
6579 $(n).blur(); // Remove focus outline for mouse users
6580 fn(e);
6581 } )
6582 .on( 'keypress.DT', oData, function (e){
6583 if ( e.which === 13 ) {
6584 e.preventDefault();
6585 fn(e);
6586 }
6587 } )
6588 .on( 'selectstart.DT', function () {
6589 /* Take the brutal approach to cancelling text selection */
6590 return false;
6591 } );
6592 }
6593
6594
6595 /**
6596 * Register a callback function. Easily allows a callback function to be added to
6597 * an array store of callback functions that can then all be called together.
6598 * @param {object} oSettings dataTables settings object
6599 * @param {string} sStore Name of the array storage for the callbacks in oSettings
6600 * @param {function} fn Function to be called back
6601 * @param {string} sName Identifying name for the callback (i.e. a label)
6602 * @memberof DataTable#oApi
6603 */
6604 function _fnCallbackReg( oSettings, sStore, fn, sName )
6605 {
6606 if ( fn )
6607 {
6608 oSettings[sStore].push( {
6609 "fn": fn,
6610 "sName": sName
6611 } );
6612 }
6613 }
6614
6615
6616 /**
6617 * Fire callback functions and trigger events. Note that the loop over the
6618 * callback array store is done backwards! Further note that you do not want to
6619 * fire off triggers in time sensitive applications (for example cell creation)
6620 * as its slow.
6621 * @param {object} settings dataTables settings object
6622 * @param {string} callbackArr Name of the array storage for the callbacks in
6623 * oSettings
6624 * @param {string} eventName Name of the jQuery custom event to trigger. If
6625 * null no trigger is fired
6626 * @param {array} args Array of arguments to pass to the callback function /
6627 * trigger
6628 * @memberof DataTable#oApi
6629 */
6630 function _fnCallbackFire( settings, callbackArr, eventName, args )
6631 {
6632 var ret = [];
6633
6634 if ( callbackArr ) {
6635 ret = $.map( settings[callbackArr].slice().reverse(), function (val, i) {
6636 return val.fn.apply( settings.oInstance, args );
6637 } );
6638 }
6639
6640 if ( eventName !== null ) {
6641 var e = $.Event( eventName+'.dt' );
6642
6643 $(settings.nTable).trigger( e, args );
6644
6645 ret.push( e.result );
6646 }
6647
6648 return ret;
6649 }
6650
6651
6652 function _fnLengthOverflow ( settings )
6653 {
6654 var
6655 start = settings._iDisplayStart,
6656 end = settings.fnDisplayEnd(),
6657 len = settings._iDisplayLength;
6658
6659 /* If we have space to show extra rows (backing up from the end point - then do so */
6660 if ( start >= end )
6661 {
6662 start = end - len;
6663 }
6664
6665 // Keep the start record on the current page
6666 start -= (start % len);
6667
6668 if ( len === -1 || start < 0 )
6669 {
6670 start = 0;
6671 }
6672
6673 settings._iDisplayStart = start;
6674 }
6675
6676
6677 function _fnRenderer( settings, type )
6678 {
6679 var renderer = settings.renderer;
6680 var host = DataTable.ext.renderer[type];
6681
6682 if ( $.isPlainObject( renderer ) && renderer[type] ) {
6683 // Specific renderer for this type. If available use it, otherwise use
6684 // the default.
6685 return host[renderer[type]] || host._;
6686 }
6687 else if ( typeof renderer === 'string' ) {
6688 // Common renderer - if there is one available for this type use it,
6689 // otherwise use the default
6690 return host[renderer] || host._;
6691 }
6692
6693 // Use the default
6694 return host._;
6695 }
6696
6697
6698 /**
6699 * Detect the data source being used for the table. Used to simplify the code
6700 * a little (ajax) and to make it compress a little smaller.
6701 *
6702 * @param {object} settings dataTables settings object
6703 * @returns {string} Data source
6704 * @memberof DataTable#oApi
6705 */
6706 function _fnDataSource ( settings )
6707 {
6708 if ( settings.oFeatures.bServerSide ) {
6709 return 'ssp';
6710 }
6711 else if ( settings.ajax || settings.sAjaxSource ) {
6712 return 'ajax';
6713 }
6714 return 'dom';
6715 }
6716
6717
6718
6719
6720 /**
6721 * Computed structure of the DataTables API, defined by the options passed to
6722 * `DataTable.Api.register()` when building the API.
6723 *
6724 * The structure is built in order to speed creation and extension of the Api
6725 * objects since the extensions are effectively pre-parsed.
6726 *
6727 * The array is an array of objects with the following structure, where this
6728 * base array represents the Api prototype base:
6729 *
6730 * [
6731 * {
6732 * name: 'data' -- string - Property name
6733 * val: function () {}, -- function - Api method (or undefined if just an object
6734 * methodExt: [ ... ], -- array - Array of Api object definitions to extend the method result
6735 * propExt: [ ... ] -- array - Array of Api object definitions to extend the property
6736 * },
6737 * {
6738 * name: 'row'
6739 * val: {},
6740 * methodExt: [ ... ],
6741 * propExt: [
6742 * {
6743 * name: 'data'
6744 * val: function () {},
6745 * methodExt: [ ... ],
6746 * propExt: [ ... ]
6747 * },
6748 * ...
6749 * ]
6750 * }
6751 * ]
6752 *
6753 * @type {Array}
6754 * @ignore
6755 */
6756 var __apiStruct = [];
6757
6758
6759 /**
6760 * `Array.prototype` reference.
6761 *
6762 * @type object
6763 * @ignore
6764 */
6765 var __arrayProto = Array.prototype;
6766
6767
6768 /**
6769 * Abstraction for `context` parameter of the `Api` constructor to allow it to
6770 * take several different forms for ease of use.
6771 *
6772 * Each of the input parameter types will be converted to a DataTables settings
6773 * object where possible.
6774 *
6775 * @param {string|node|jQuery|object} mixed DataTable identifier. Can be one
6776 * of:
6777 *
6778 * * `string` - jQuery selector. Any DataTables' matching the given selector
6779 * with be found and used.
6780 * * `node` - `TABLE` node which has already been formed into a DataTable.
6781 * * `jQuery` - A jQuery object of `TABLE` nodes.
6782 * * `object` - DataTables settings object
6783 * * `DataTables.Api` - API instance
6784 * @return {array|null} Matching DataTables settings objects. `null` or
6785 * `undefined` is returned if no matching DataTable is found.
6786 * @ignore
6787 */
6788 var _toSettings = function ( mixed )
6789 {
6790 var idx, jq;
6791 var settings = DataTable.settings;
6792 var tables = $.map( settings, function (el, i) {
6793 return el.nTable;
6794 } );
6795
6796 if ( ! mixed ) {
6797 return [];
6798 }
6799 else if ( mixed.nTable && mixed.oApi ) {
6800 // DataTables settings object
6801 return [ mixed ];
6802 }
6803 else if ( mixed.nodeName && mixed.nodeName.toLowerCase() === 'table' ) {
6804 // Table node
6805 idx = $.inArray( mixed, tables );
6806 return idx !== -1 ? [ settings[idx] ] : null;
6807 }
6808 else if ( mixed && typeof mixed.settings === 'function' ) {
6809 return mixed.settings().toArray();
6810 }
6811 else if ( typeof mixed === 'string' ) {
6812 // jQuery selector
6813 jq = $(mixed);
6814 }
6815 else if ( mixed instanceof $ ) {
6816 // jQuery object (also DataTables instance)
6817 jq = mixed;
6818 }
6819
6820 if ( jq ) {
6821 return jq.map( function(i) {
6822 idx = $.inArray( this, tables );
6823 return idx !== -1 ? settings[idx] : null;
6824 } ).toArray();
6825 }
6826 };
6827
6828
6829 /**
6830 * DataTables API class - used to control and interface with one or more
6831 * DataTables enhanced tables.
6832 *
6833 * The API class is heavily based on jQuery, presenting a chainable interface
6834 * that you can use to interact with tables. Each instance of the API class has
6835 * a "context" - i.e. the tables that it will operate on. This could be a single
6836 * table, all tables on a page or a sub-set thereof.
6837 *
6838 * Additionally the API is designed to allow you to easily work with the data in
6839 * the tables, retrieving and manipulating it as required. This is done by
6840 * presenting the API class as an array like interface. The contents of the
6841 * array depend upon the actions requested by each method (for example
6842 * `rows().nodes()` will return an array of nodes, while `rows().data()` will
6843 * return an array of objects or arrays depending upon your table's
6844 * configuration). The API object has a number of array like methods (`push`,
6845 * `pop`, `reverse` etc) as well as additional helper methods (`each`, `pluck`,
6846 * `unique` etc) to assist your working with the data held in a table.
6847 *
6848 * Most methods (those which return an Api instance) are chainable, which means
6849 * the return from a method call also has all of the methods available that the
6850 * top level object had. For example, these two calls are equivalent:
6851 *
6852 * // Not chained
6853 * api.row.add( {...} );
6854 * api.draw();
6855 *
6856 * // Chained
6857 * api.row.add( {...} ).draw();
6858 *
6859 * @class DataTable.Api
6860 * @param {array|object|string|jQuery} context DataTable identifier. This is
6861 * used to define which DataTables enhanced tables this API will operate on.
6862 * Can be one of:
6863 *
6864 * * `string` - jQuery selector. Any DataTables' matching the given selector
6865 * with be found and used.
6866 * * `node` - `TABLE` node which has already been formed into a DataTable.
6867 * * `jQuery` - A jQuery object of `TABLE` nodes.
6868 * * `object` - DataTables settings object
6869 * @param {array} [data] Data to initialise the Api instance with.
6870 *
6871 * @example
6872 * // Direct initialisation during DataTables construction
6873 * var api = $('#example').DataTable();
6874 *
6875 * @example
6876 * // Initialisation using a DataTables jQuery object
6877 * var api = $('#example').dataTable().api();
6878 *
6879 * @example
6880 * // Initialisation as a constructor
6881 * var api = new $.fn.DataTable.Api( 'table.dataTable' );
6882 */
6883 _Api = function ( context, data )
6884 {
6885 if ( ! (this instanceof _Api) ) {
6886 return new _Api( context, data );
6887 }
6888
6889 var settings = [];
6890 var ctxSettings = function ( o ) {
6891 var a = _toSettings( o );
6892 if ( a ) {
6893 settings = settings.concat( a );
6894 }
6895 };
6896
6897 if ( $.isArray( context ) ) {
6898 for ( var i=0, ien=context.length ; i<ien ; i++ ) {
6899 ctxSettings( context[i] );
6900 }
6901 }
6902 else {
6903 ctxSettings( context );
6904 }
6905
6906 // Remove duplicates
6907 this.context = _unique( settings );
6908
6909 // Initial data
6910 if ( data ) {
6911 $.merge( this, data );
6912 }
6913
6914 // selector
6915 this.selector = {
6916 rows: null,
6917 cols: null,
6918 opts: null
6919 };
6920
6921 _Api.extend( this, this, __apiStruct );
6922 };
6923
6924 DataTable.Api = _Api;
6925
6926 // Don't destroy the existing prototype, just extend it. Required for jQuery 2's
6927 // isPlainObject.
6928 $.extend( _Api.prototype, {
6929 any: function ()
6930 {
6931 return this.count() !== 0;
6932 },
6933
6934
6935 concat: __arrayProto.concat,
6936
6937
6938 context: [], // array of table settings objects
6939
6940
6941 count: function ()
6942 {
6943 return this.flatten().length;
6944 },
6945
6946
6947 each: function ( fn )
6948 {
6949 for ( var i=0, ien=this.length ; i<ien; i++ ) {
6950 fn.call( this, this[i], i, this );
6951 }
6952
6953 return this;
6954 },
6955
6956
6957 eq: function ( idx )
6958 {
6959 var ctx = this.context;
6960
6961 return ctx.length > idx ?
6962 new _Api( ctx[idx], this[idx] ) :
6963 null;
6964 },
6965
6966
6967 filter: function ( fn )
6968 {
6969 var a = [];
6970
6971 if ( __arrayProto.filter ) {
6972 a = __arrayProto.filter.call( this, fn, this );
6973 }
6974 else {
6975 // Compatibility for browsers without EMCA-252-5 (JS 1.6)
6976 for ( var i=0, ien=this.length ; i<ien ; i++ ) {
6977 if ( fn.call( this, this[i], i, this ) ) {
6978 a.push( this[i] );
6979 }
6980 }
6981 }
6982
6983 return new _Api( this.context, a );
6984 },
6985
6986
6987 flatten: function ()
6988 {
6989 var a = [];
6990 return new _Api( this.context, a.concat.apply( a, this.toArray() ) );
6991 },
6992
6993
6994 join: __arrayProto.join,
6995
6996
6997 indexOf: __arrayProto.indexOf || function (obj, start)
6998 {
6999 for ( var i=(start || 0), ien=this.length ; i<ien ; i++ ) {
7000 if ( this[i] === obj ) {
7001 return i;
7002 }
7003 }
7004 return -1;
7005 },
7006
7007 iterator: function ( flatten, type, fn, alwaysNew ) {
7008 var
7009 a = [], ret,
7010 i, ien, j, jen,
7011 context = this.context,
7012 rows, items, item,
7013 selector = this.selector;
7014
7015 // Argument shifting
7016 if ( typeof flatten === 'string' ) {
7017 alwaysNew = fn;
7018 fn = type;
7019 type = flatten;
7020 flatten = false;
7021 }
7022
7023 for ( i=0, ien=context.length ; i<ien ; i++ ) {
7024 var apiInst = new _Api( context[i] );
7025
7026 if ( type === 'table' ) {
7027 ret = fn.call( apiInst, context[i], i );
7028
7029 if ( ret !== undefined ) {
7030 a.push( ret );
7031 }
7032 }
7033 else if ( type === 'columns' || type === 'rows' ) {
7034 // this has same length as context - one entry for each table
7035 ret = fn.call( apiInst, context[i], this[i], i );
7036
7037 if ( ret !== undefined ) {
7038 a.push( ret );
7039 }
7040 }
7041 else if ( type === 'column' || type === 'column-rows' || type === 'row' || type === 'cell' ) {
7042 // columns and rows share the same structure.
7043 // 'this' is an array of column indexes for each context
7044 items = this[i];
7045
7046 if ( type === 'column-rows' ) {
7047 rows = _selector_row_indexes( context[i], selector.opts );
7048 }
7049
7050 for ( j=0, jen=items.length ; j<jen ; j++ ) {
7051 item = items[j];
7052
7053 if ( type === 'cell' ) {
7054 ret = fn.call( apiInst, context[i], item.row, item.column, i, j );
7055 }
7056 else {
7057 ret = fn.call( apiInst, context[i], item, i, j, rows );
7058 }
7059
7060 if ( ret !== undefined ) {
7061 a.push( ret );
7062 }
7063 }
7064 }
7065 }
7066
7067 if ( a.length || alwaysNew ) {
7068 var api = new _Api( context, flatten ? a.concat.apply( [], a ) : a );
7069 var apiSelector = api.selector;
7070 apiSelector.rows = selector.rows;
7071 apiSelector.cols = selector.cols;
7072 apiSelector.opts = selector.opts;
7073 return api;
7074 }
7075 return this;
7076 },
7077
7078
7079 lastIndexOf: __arrayProto.lastIndexOf || function (obj, start)
7080 {
7081 // Bit cheeky...
7082 return this.indexOf.apply( this.toArray.reverse(), arguments );
7083 },
7084
7085
7086 length: 0,
7087
7088
7089 map: function ( fn )
7090 {
7091 var a = [];
7092
7093 if ( __arrayProto.map ) {
7094 a = __arrayProto.map.call( this, fn, this );
7095 }
7096 else {
7097 // Compatibility for browsers without EMCA-252-5 (JS 1.6)
7098 for ( var i=0, ien=this.length ; i<ien ; i++ ) {
7099 a.push( fn.call( this, this[i], i ) );
7100 }
7101 }
7102
7103 return new _Api( this.context, a );
7104 },
7105
7106
7107 pluck: function ( prop )
7108 {
7109 return this.map( function ( el ) {
7110 return el[ prop ];
7111 } );
7112 },
7113
7114 pop: __arrayProto.pop,
7115
7116
7117 push: __arrayProto.push,
7118
7119
7120 // Does not return an API instance
7121 reduce: __arrayProto.reduce || function ( fn, init )
7122 {
7123 return _fnReduce( this, fn, init, 0, this.length, 1 );
7124 },
7125
7126
7127 reduceRight: __arrayProto.reduceRight || function ( fn, init )
7128 {
7129 return _fnReduce( this, fn, init, this.length-1, -1, -1 );
7130 },
7131
7132
7133 reverse: __arrayProto.reverse,
7134
7135
7136 // Object with rows, columns and opts
7137 selector: null,
7138
7139
7140 shift: __arrayProto.shift,
7141
7142
7143 slice: function () {
7144 return new _Api( this.context, this );
7145 },
7146
7147
7148 sort: __arrayProto.sort, // ? name - order?
7149
7150
7151 splice: __arrayProto.splice,
7152
7153
7154 toArray: function ()
7155 {
7156 return __arrayProto.slice.call( this );
7157 },
7158
7159
7160 to$: function ()
7161 {
7162 return $( this );
7163 },
7164
7165
7166 toJQuery: function ()
7167 {
7168 return $( this );
7169 },
7170
7171
7172 unique: function ()
7173 {
7174 return new _Api( this.context, _unique(this) );
7175 },
7176
7177
7178 unshift: __arrayProto.unshift
7179 } );
7180
7181
7182 _Api.extend = function ( scope, obj, ext )
7183 {
7184 // Only extend API instances and static properties of the API
7185 if ( ! ext.length || ! obj || ( ! (obj instanceof _Api) && ! obj.__dt_wrapper ) ) {
7186 return;
7187 }
7188
7189 var
7190 i, ien,
7191 j, jen,
7192 struct, inner,
7193 methodScoping = function ( scope, fn, struc ) {
7194 return function () {
7195 var ret = fn.apply( scope, arguments );
7196
7197 // Method extension
7198 _Api.extend( ret, ret, struc.methodExt );
7199 return ret;
7200 };
7201 };
7202
7203 for ( i=0, ien=ext.length ; i<ien ; i++ ) {
7204 struct = ext[i];
7205
7206 // Value
7207 obj[ struct.name ] = typeof struct.val === 'function' ?
7208 methodScoping( scope, struct.val, struct ) :
7209 $.isPlainObject( struct.val ) ?
7210 {} :
7211 struct.val;
7212
7213 obj[ struct.name ].__dt_wrapper = true;
7214
7215 // Property extension
7216 _Api.extend( scope, obj[ struct.name ], struct.propExt );
7217 }
7218 };
7219
7220
7221 // @todo - Is there need for an augment function?
7222 // _Api.augment = function ( inst, name )
7223 // {
7224 // // Find src object in the structure from the name
7225 // var parts = name.split('.');
7226
7227 // _Api.extend( inst, obj );
7228 // };
7229
7230
7231 // [
7232 // {
7233 // name: 'data' -- string - Property name
7234 // val: function () {}, -- function - Api method (or undefined if just an object
7235 // methodExt: [ ... ], -- array - Array of Api object definitions to extend the method result
7236 // propExt: [ ... ] -- array - Array of Api object definitions to extend the property
7237 // },
7238 // {
7239 // name: 'row'
7240 // val: {},
7241 // methodExt: [ ... ],
7242 // propExt: [
7243 // {
7244 // name: 'data'
7245 // val: function () {},
7246 // methodExt: [ ... ],
7247 // propExt: [ ... ]
7248 // },
7249 // ...
7250 // ]
7251 // }
7252 // ]
7253
7254 _Api.register = _api_register = function ( name, val )
7255 {
7256 if ( $.isArray( name ) ) {
7257 for ( var j=0, jen=name.length ; j<jen ; j++ ) {
7258 _Api.register( name[j], val );
7259 }
7260 return;
7261 }
7262
7263 var
7264 i, ien,
7265 heir = name.split('.'),
7266 struct = __apiStruct,
7267 key, method;
7268
7269 var find = function ( src, name ) {
7270 for ( var i=0, ien=src.length ; i<ien ; i++ ) {
7271 if ( src[i].name === name ) {
7272 return src[i];
7273 }
7274 }
7275 return null;
7276 };
7277
7278 for ( i=0, ien=heir.length ; i<ien ; i++ ) {
7279 method = heir[i].indexOf('()') !== -1;
7280 key = method ?
7281 heir[i].replace('()', '') :
7282 heir[i];
7283
7284 var src = find( struct, key );
7285 if ( ! src ) {
7286 src = {
7287 name: key,
7288 val: {},
7289 methodExt: [],
7290 propExt: []
7291 };
7292 struct.push( src );
7293 }
7294
7295 if ( i === ien-1 ) {
7296 src.val = val;
7297 }
7298 else {
7299 struct = method ?
7300 src.methodExt :
7301 src.propExt;
7302 }
7303 }
7304 };
7305
7306
7307 _Api.registerPlural = _api_registerPlural = function ( pluralName, singularName, val ) {
7308 _Api.register( pluralName, val );
7309
7310 _Api.register( singularName, function () {
7311 var ret = val.apply( this, arguments );
7312
7313 if ( ret === this ) {
7314 // Returned item is the API instance that was passed in, return it
7315 return this;
7316 }
7317 else if ( ret instanceof _Api ) {
7318 // New API instance returned, want the value from the first item
7319 // in the returned array for the singular result.
7320 return ret.length ?
7321 $.isArray( ret[0] ) ?
7322 new _Api( ret.context, ret[0] ) : // Array results are 'enhanced'
7323 ret[0] :
7324 undefined;
7325 }
7326
7327 // Non-API return - just fire it back
7328 return ret;
7329 } );
7330 };
7331
7332
7333 /**
7334 * Selector for HTML tables. Apply the given selector to the give array of
7335 * DataTables settings objects.
7336 *
7337 * @param {string|integer} [selector] jQuery selector string or integer
7338 * @param {array} Array of DataTables settings objects to be filtered
7339 * @return {array}
7340 * @ignore
7341 */
7342 var __table_selector = function ( selector, a )
7343 {
7344 // Integer is used to pick out a table by index
7345 if ( typeof selector === 'number' ) {
7346 return [ a[ selector ] ];
7347 }
7348
7349 // Perform a jQuery selector on the table nodes
7350 var nodes = $.map( a, function (el, i) {
7351 return el.nTable;
7352 } );
7353
7354 return $(nodes)
7355 .filter( selector )
7356 .map( function (i) {
7357 // Need to translate back from the table node to the settings
7358 var idx = $.inArray( this, nodes );
7359 return a[ idx ];
7360 } )
7361 .toArray();
7362 };
7363
7364
7365
7366 /**
7367 * Context selector for the API's context (i.e. the tables the API instance
7368 * refers to.
7369 *
7370 * @name DataTable.Api#tables
7371 * @param {string|integer} [selector] Selector to pick which tables the iterator
7372 * should operate on. If not given, all tables in the current context are
7373 * used. This can be given as a jQuery selector (for example `':gt(0)'`) to
7374 * select multiple tables or as an integer to select a single table.
7375 * @returns {DataTable.Api} Returns a new API instance if a selector is given.
7376 */
7377 _api_register( 'tables()', function ( selector ) {
7378 // A new instance is created if there was a selector specified
7379 return selector ?
7380 new _Api( __table_selector( selector, this.context ) ) :
7381 this;
7382 } );
7383
7384
7385 _api_register( 'table()', function ( selector ) {
7386 var tables = this.tables( selector );
7387 var ctx = tables.context;
7388
7389 // Truncate to the first matched table
7390 return ctx.length ?
7391 new _Api( ctx[0] ) :
7392 tables;
7393 } );
7394
7395
7396 _api_registerPlural( 'tables().nodes()', 'table().node()' , function () {
7397 return this.iterator( 'table', function ( ctx ) {
7398 return ctx.nTable;
7399 }, 1 );
7400 } );
7401
7402
7403 _api_registerPlural( 'tables().body()', 'table().body()' , function () {
7404 return this.iterator( 'table', function ( ctx ) {
7405 return ctx.nTBody;
7406 }, 1 );
7407 } );
7408
7409
7410 _api_registerPlural( 'tables().header()', 'table().header()' , function () {
7411 return this.iterator( 'table', function ( ctx ) {
7412 return ctx.nTHead;
7413 }, 1 );
7414 } );
7415
7416
7417 _api_registerPlural( 'tables().footer()', 'table().footer()' , function () {
7418 return this.iterator( 'table', function ( ctx ) {
7419 return ctx.nTFoot;
7420 }, 1 );
7421 } );
7422
7423
7424 _api_registerPlural( 'tables().containers()', 'table().container()' , function () {
7425 return this.iterator( 'table', function ( ctx ) {
7426 return ctx.nTableWrapper;
7427 }, 1 );
7428 } );
7429
7430
7431
7432 /**
7433 * Redraw the tables in the current context.
7434 */
7435 _api_register( 'draw()', function ( paging ) {
7436 return this.iterator( 'table', function ( settings ) {
7437 if ( paging === 'page' ) {
7438 _fnDraw( settings );
7439 }
7440 else {
7441 if ( typeof paging === 'string' ) {
7442 paging = paging === 'full-hold' ?
7443 false :
7444 true;
7445 }
7446
7447 _fnReDraw( settings, paging===false );
7448 }
7449 } );
7450 } );
7451
7452
7453
7454 /**
7455 * Get the current page index.
7456 *
7457 * @return {integer} Current page index (zero based)
7458 *//**
7459 * Set the current page.
7460 *
7461 * Note that if you attempt to show a page which does not exist, DataTables will
7462 * not throw an error, but rather reset the paging.
7463 *
7464 * @param {integer|string} action The paging action to take. This can be one of:
7465 * * `integer` - The page index to jump to
7466 * * `string` - An action to take:
7467 * * `first` - Jump to first page.
7468 * * `next` - Jump to the next page
7469 * * `previous` - Jump to previous page
7470 * * `last` - Jump to the last page.
7471 * @returns {DataTables.Api} this
7472 */
7473 _api_register( 'page()', function ( action ) {
7474 if ( action === undefined ) {
7475 return this.page.info().page; // not an expensive call
7476 }
7477
7478 // else, have an action to take on all tables
7479 return this.iterator( 'table', function ( settings ) {
7480 _fnPageChange( settings, action );
7481 } );
7482 } );
7483
7484
7485 /**
7486 * Paging information for the first table in the current context.
7487 *
7488 * If you require paging information for another table, use the `table()` method
7489 * with a suitable selector.
7490 *
7491 * @return {object} Object with the following properties set:
7492 * * `page` - Current page index (zero based - i.e. the first page is `0`)
7493 * * `pages` - Total number of pages
7494 * * `start` - Display index for the first record shown on the current page
7495 * * `end` - Display index for the last record shown on the current page
7496 * * `length` - Display length (number of records). Note that generally `start
7497 * + length = end`, but this is not always true, for example if there are
7498 * only 2 records to show on the final page, with a length of 10.
7499 * * `recordsTotal` - Full data set length
7500 * * `recordsDisplay` - Data set length once the current filtering criterion
7501 * are applied.
7502 */
7503 _api_register( 'page.info()', function ( action ) {
7504 if ( this.context.length === 0 ) {
7505 return undefined;
7506 }
7507
7508 var
7509 settings = this.context[0],
7510 start = settings._iDisplayStart,
7511 len = settings.oFeatures.bPaginate ? settings._iDisplayLength : -1,
7512 visRecords = settings.fnRecordsDisplay(),
7513 all = len === -1;
7514
7515 return {
7516 "page": all ? 0 : Math.floor( start / len ),
7517 "pages": all ? 1 : Math.ceil( visRecords / len ),
7518 "start": start,
7519 "end": settings.fnDisplayEnd(),
7520 "length": len,
7521 "recordsTotal": settings.fnRecordsTotal(),
7522 "recordsDisplay": visRecords,
7523 "serverSide": _fnDataSource( settings ) === 'ssp'
7524 };
7525 } );
7526
7527
7528 /**
7529 * Get the current page length.
7530 *
7531 * @return {integer} Current page length. Note `-1` indicates that all records
7532 * are to be shown.
7533 *//**
7534 * Set the current page length.
7535 *
7536 * @param {integer} Page length to set. Use `-1` to show all records.
7537 * @returns {DataTables.Api} this
7538 */
7539 _api_register( 'page.len()', function ( len ) {
7540 // Note that we can't call this function 'length()' because `length`
7541 // is a Javascript property of functions which defines how many arguments
7542 // the function expects.
7543 if ( len === undefined ) {
7544 return this.context.length !== 0 ?
7545 this.context[0]._iDisplayLength :
7546 undefined;
7547 }
7548
7549 // else, set the page length
7550 return this.iterator( 'table', function ( settings ) {
7551 _fnLengthChange( settings, len );
7552 } );
7553 } );
7554
7555
7556
7557 var __reload = function ( settings, holdPosition, callback ) {
7558 // Use the draw event to trigger a callback
7559 if ( callback ) {
7560 var api = new _Api( settings );
7561
7562 api.one( 'draw', function () {
7563 callback( api.ajax.json() );
7564 } );
7565 }
7566
7567 if ( _fnDataSource( settings ) == 'ssp' ) {
7568 _fnReDraw( settings, holdPosition );
7569 }
7570 else {
7571 _fnProcessingDisplay( settings, true );
7572
7573 // Cancel an existing request
7574 var xhr = settings.jqXHR;
7575 if ( xhr && xhr.readyState !== 4 ) {
7576 xhr.abort();
7577 }
7578
7579 // Trigger xhr
7580 _fnBuildAjax( settings, [], function( json ) {
7581 _fnClearTable( settings );
7582
7583 var data = _fnAjaxDataSrc( settings, json );
7584 for ( var i=0, ien=data.length ; i<ien ; i++ ) {
7585 _fnAddData( settings, data[i] );
7586 }
7587
7588 _fnReDraw( settings, holdPosition );
7589 _fnProcessingDisplay( settings, false );
7590 } );
7591 }
7592 };
7593
7594
7595 /**
7596 * Get the JSON response from the last Ajax request that DataTables made to the
7597 * server. Note that this returns the JSON from the first table in the current
7598 * context.
7599 *
7600 * @return {object} JSON received from the server.
7601 */
7602 _api_register( 'ajax.json()', function () {
7603 var ctx = this.context;
7604
7605 if ( ctx.length > 0 ) {
7606 return ctx[0].json;
7607 }
7608
7609 // else return undefined;
7610 } );
7611
7612
7613 /**
7614 * Get the data submitted in the last Ajax request
7615 */
7616 _api_register( 'ajax.params()', function () {
7617 var ctx = this.context;
7618
7619 if ( ctx.length > 0 ) {
7620 return ctx[0].oAjaxData;
7621 }
7622
7623 // else return undefined;
7624 } );
7625
7626
7627 /**
7628 * Reload tables from the Ajax data source. Note that this function will
7629 * automatically re-draw the table when the remote data has been loaded.
7630 *
7631 * @param {boolean} [reset=true] Reset (default) or hold the current paging
7632 * position. A full re-sort and re-filter is performed when this method is
7633 * called, which is why the pagination reset is the default action.
7634 * @returns {DataTables.Api} this
7635 */
7636 _api_register( 'ajax.reload()', function ( callback, resetPaging ) {
7637 return this.iterator( 'table', function (settings) {
7638 __reload( settings, resetPaging===false, callback );
7639 } );
7640 } );
7641
7642
7643 /**
7644 * Get the current Ajax URL. Note that this returns the URL from the first
7645 * table in the current context.
7646 *
7647 * @return {string} Current Ajax source URL
7648 *//**
7649 * Set the Ajax URL. Note that this will set the URL for all tables in the
7650 * current context.
7651 *
7652 * @param {string} url URL to set.
7653 * @returns {DataTables.Api} this
7654 */
7655 _api_register( 'ajax.url()', function ( url ) {
7656 var ctx = this.context;
7657
7658 if ( url === undefined ) {
7659 // get
7660 if ( ctx.length === 0 ) {
7661 return undefined;
7662 }
7663 ctx = ctx[0];
7664
7665 return ctx.ajax ?
7666 $.isPlainObject( ctx.ajax ) ?
7667 ctx.ajax.url :
7668 ctx.ajax :
7669 ctx.sAjaxSource;
7670 }
7671
7672 // set
7673 return this.iterator( 'table', function ( settings ) {
7674 if ( $.isPlainObject( settings.ajax ) ) {
7675 settings.ajax.url = url;
7676 }
7677 else {
7678 settings.ajax = url;
7679 }
7680 // No need to consider sAjaxSource here since DataTables gives priority
7681 // to `ajax` over `sAjaxSource`. So setting `ajax` here, renders any
7682 // value of `sAjaxSource` redundant.
7683 } );
7684 } );
7685
7686
7687 /**
7688 * Load data from the newly set Ajax URL. Note that this method is only
7689 * available when `ajax.url()` is used to set a URL. Additionally, this method
7690 * has the same effect as calling `ajax.reload()` but is provided for
7691 * convenience when setting a new URL. Like `ajax.reload()` it will
7692 * automatically redraw the table once the remote data has been loaded.
7693 *
7694 * @returns {DataTables.Api} this
7695 */
7696 _api_register( 'ajax.url().load()', function ( callback, resetPaging ) {
7697 // Same as a reload, but makes sense to present it for easy access after a
7698 // url change
7699 return this.iterator( 'table', function ( ctx ) {
7700 __reload( ctx, resetPaging===false, callback );
7701 } );
7702 } );
7703
7704
7705
7706
7707 var _selector_run = function ( type, selector, selectFn, settings, opts )
7708 {
7709 var
7710 out = [], res,
7711 a, i, ien, j, jen,
7712 selectorType = typeof selector;
7713
7714 // Can't just check for isArray here, as an API or jQuery instance might be
7715 // given with their array like look
7716 if ( ! selector || selectorType === 'string' || selectorType === 'function' || selector.length === undefined ) {
7717 selector = [ selector ];
7718 }
7719
7720 for ( i=0, ien=selector.length ; i<ien ; i++ ) {
7721 // Only split on simple strings - complex expressions will be jQuery selectors
7722 a = selector[i] && selector[i].split && ! selector[i].match(/[\[\(:]/) ?
7723 selector[i].split(',') :
7724 [ selector[i] ];
7725
7726 for ( j=0, jen=a.length ; j<jen ; j++ ) {
7727 res = selectFn( typeof a[j] === 'string' ? $.trim(a[j]) : a[j] );
7728
7729 if ( res && res.length ) {
7730 out = out.concat( res );
7731 }
7732 }
7733 }
7734
7735 // selector extensions
7736 var ext = _ext.selector[ type ];
7737 if ( ext.length ) {
7738 for ( i=0, ien=ext.length ; i<ien ; i++ ) {
7739 out = ext[i]( settings, opts, out );
7740 }
7741 }
7742
7743 return _unique( out );
7744 };
7745
7746
7747 var _selector_opts = function ( opts )
7748 {
7749 if ( ! opts ) {
7750 opts = {};
7751 }
7752
7753 // Backwards compatibility for 1.9- which used the terminology filter rather
7754 // than search
7755 if ( opts.filter && opts.search === undefined ) {
7756 opts.search = opts.filter;
7757 }
7758
7759 return $.extend( {
7760 search: 'none',
7761 order: 'current',
7762 page: 'all'
7763 }, opts );
7764 };
7765
7766
7767 var _selector_first = function ( inst )
7768 {
7769 // Reduce the API instance to the first item found
7770 for ( var i=0, ien=inst.length ; i<ien ; i++ ) {
7771 if ( inst[i].length > 0 ) {
7772 // Assign the first element to the first item in the instance
7773 // and truncate the instance and context
7774 inst[0] = inst[i];
7775 inst[0].length = 1;
7776 inst.length = 1;
7777 inst.context = [ inst.context[i] ];
7778
7779 return inst;
7780 }
7781 }
7782
7783 // Not found - return an empty instance
7784 inst.length = 0;
7785 return inst;
7786 };
7787
7788
7789 var _selector_row_indexes = function ( settings, opts )
7790 {
7791 var
7792 i, ien, tmp, a=[],
7793 displayFiltered = settings.aiDisplay,
7794 displayMaster = settings.aiDisplayMaster;
7795
7796 var
7797 search = opts.search, // none, applied, removed
7798 order = opts.order, // applied, current, index (original - compatibility with 1.9)
7799 page = opts.page; // all, current
7800
7801 if ( _fnDataSource( settings ) == 'ssp' ) {
7802 // In server-side processing mode, most options are irrelevant since
7803 // rows not shown don't exist and the index order is the applied order
7804 // Removed is a special case - for consistency just return an empty
7805 // array
7806 return search === 'removed' ?
7807 [] :
7808 _range( 0, displayMaster.length );
7809 }
7810 else if ( page == 'current' ) {
7811 // Current page implies that order=current and fitler=applied, since it is
7812 // fairly senseless otherwise, regardless of what order and search actually
7813 // are
7814 for ( i=settings._iDisplayStart, ien=settings.fnDisplayEnd() ; i<ien ; i++ ) {
7815 a.push( displayFiltered[i] );
7816 }
7817 }
7818 else if ( order == 'current' || order == 'applied' ) {
7819 if ( search == 'none') {
7820 a = displayMaster.slice();
7821 }
7822 else if ( search == 'applied' ) {
7823 a = displayFiltered.slice();
7824 }
7825 else if ( search == 'removed' ) {
7826 // O(n+m) solution by creating a hash map
7827 var displayFilteredMap = {};
7828
7829 for ( var i=0, ien=displayFiltered.length ; i<ien ; i++ ) {
7830 displayFilteredMap[displayFiltered[i]] = null;
7831 }
7832
7833 a = $.map( displayMaster, function (el) {
7834 return ! displayFilteredMap.hasOwnProperty(el) ?
7835 el :
7836 null;
7837 } );
7838 }
7839 }
7840 else if ( order == 'index' || order == 'original' ) {
7841 for ( i=0, ien=settings.aoData.length ; i<ien ; i++ ) {
7842 if ( search == 'none' ) {
7843 a.push( i );
7844 }
7845 else { // applied | removed
7846 tmp = $.inArray( i, displayFiltered );
7847
7848 if ((tmp === -1 && search == 'removed') ||
7849 (tmp >= 0 && search == 'applied') )
7850 {
7851 a.push( i );
7852 }
7853 }
7854 }
7855 }
7856
7857 return a;
7858 };
7859
7860
7861 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
7862 * Rows
7863 *
7864 * {} - no selector - use all available rows
7865 * {integer} - row aoData index
7866 * {node} - TR node
7867 * {string} - jQuery selector to apply to the TR elements
7868 * {array} - jQuery array of nodes, or simply an array of TR nodes
7869 *
7870 */
7871 var __row_selector = function ( settings, selector, opts )
7872 {
7873 var rows;
7874 var run = function ( sel ) {
7875 var selInt = _intVal( sel );
7876 var i, ien;
7877 var aoData = settings.aoData;
7878
7879 // Short cut - selector is a number and no options provided (default is
7880 // all records, so no need to check if the index is in there, since it
7881 // must be - dev error if the index doesn't exist).
7882 if ( selInt !== null && ! opts ) {
7883 return [ selInt ];
7884 }
7885
7886 if ( ! rows ) {
7887 rows = _selector_row_indexes( settings, opts );
7888 }
7889
7890 if ( selInt !== null && $.inArray( selInt, rows ) !== -1 ) {
7891 // Selector - integer
7892 return [ selInt ];
7893 }
7894 else if ( sel === null || sel === undefined || sel === '' ) {
7895 // Selector - none
7896 return rows;
7897 }
7898
7899 // Selector - function
7900 if ( typeof sel === 'function' ) {
7901 return $.map( rows, function (idx) {
7902 var row = aoData[ idx ];
7903 return sel( idx, row._aData, row.nTr ) ? idx : null;
7904 } );
7905 }
7906
7907 // Selector - node
7908 if ( sel.nodeName ) {
7909 var rowIdx = sel._DT_RowIndex; // Property added by DT for fast lookup
7910 var cellIdx = sel._DT_CellIndex;
7911
7912 if ( rowIdx !== undefined ) {
7913 // Make sure that the row is actually still present in the table
7914 return aoData[ rowIdx ] && aoData[ rowIdx ].nTr === sel ?
7915 [ rowIdx ] :
7916 [];
7917 }
7918 else if ( cellIdx ) {
7919 return aoData[ cellIdx.row ] && aoData[ cellIdx.row ].nTr === sel ?
7920 [ cellIdx.row ] :
7921 [];
7922 }
7923 else {
7924 var host = $(sel).closest('*[data-dt-row]');
7925 return host.length ?
7926 [ host.data('dt-row') ] :
7927 [];
7928 }
7929 }
7930
7931 // ID selector. Want to always be able to select rows by id, regardless
7932 // of if the tr element has been created or not, so can't rely upon
7933 // jQuery here - hence a custom implementation. This does not match
7934 // Sizzle's fast selector or HTML4 - in HTML5 the ID can be anything,
7935 // but to select it using a CSS selector engine (like Sizzle or
7936 // querySelect) it would need to need to be escaped for some characters.
7937 // DataTables simplifies this for row selectors since you can select
7938 // only a row. A # indicates an id any anything that follows is the id -
7939 // unescaped.
7940 if ( typeof sel === 'string' && sel.charAt(0) === '#' ) {
7941 // get row index from id
7942 var rowObj = settings.aIds[ sel.replace( /^#/, '' ) ];
7943 if ( rowObj !== undefined ) {
7944 return [ rowObj.idx ];
7945 }
7946
7947 // need to fall through to jQuery in case there is DOM id that
7948 // matches
7949 }
7950
7951 // Get nodes in the order from the `rows` array with null values removed
7952 var nodes = _removeEmpty(
7953 _pluck_order( settings.aoData, rows, 'nTr' )
7954 );
7955
7956 // Selector - jQuery selector string, array of nodes or jQuery object/
7957 // As jQuery's .filter() allows jQuery objects to be passed in filter,
7958 // it also allows arrays, so this will cope with all three options
7959 return $(nodes)
7960 .filter( sel )
7961 .map( function () {
7962 return this._DT_RowIndex;
7963 } )
7964 .toArray();
7965 };
7966
7967 return _selector_run( 'row', selector, run, settings, opts );
7968 };
7969
7970
7971 _api_register( 'rows()', function ( selector, opts ) {
7972 // argument shifting
7973 if ( selector === undefined ) {
7974 selector = '';
7975 }
7976 else if ( $.isPlainObject( selector ) ) {
7977 opts = selector;
7978 selector = '';
7979 }
7980
7981 opts = _selector_opts( opts );
7982
7983 var inst = this.iterator( 'table', function ( settings ) {
7984 return __row_selector( settings, selector, opts );
7985 }, 1 );
7986
7987 // Want argument shifting here and in __row_selector?
7988 inst.selector.rows = selector;
7989 inst.selector.opts = opts;
7990
7991 return inst;
7992 } );
7993
7994 _api_register( 'rows().nodes()', function () {
7995 return this.iterator( 'row', function ( settings, row ) {
7996 return settings.aoData[ row ].nTr || undefined;
7997 }, 1 );
7998 } );
7999
8000 _api_register( 'rows().data()', function () {
8001 return this.iterator( true, 'rows', function ( settings, rows ) {
8002 return _pluck_order( settings.aoData, rows, '_aData' );
8003 }, 1 );
8004 } );
8005
8006 _api_registerPlural( 'rows().cache()', 'row().cache()', function ( type ) {
8007 return this.iterator( 'row', function ( settings, row ) {
8008 var r = settings.aoData[ row ];
8009 return type === 'search' ? r._aFilterData : r._aSortData;
8010 }, 1 );
8011 } );
8012
8013 _api_registerPlural( 'rows().invalidate()', 'row().invalidate()', function ( src ) {
8014 return this.iterator( 'row', function ( settings, row ) {
8015 _fnInvalidate( settings, row, src );
8016 } );
8017 } );
8018
8019 _api_registerPlural( 'rows().indexes()', 'row().index()', function () {
8020 return this.iterator( 'row', function ( settings, row ) {
8021 return row;
8022 }, 1 );
8023 } );
8024
8025 _api_registerPlural( 'rows().ids()', 'row().id()', function ( hash ) {
8026 var a = [];
8027 var context = this.context;
8028
8029 // `iterator` will drop undefined values, but in this case we want them
8030 for ( var i=0, ien=context.length ; i<ien ; i++ ) {
8031 for ( var j=0, jen=this[i].length ; j<jen ; j++ ) {
8032 var id = context[i].rowIdFn( context[i].aoData[ this[i][j] ]._aData );
8033 a.push( (hash === true ? '#' : '' )+ id );
8034 }
8035 }
8036
8037 return new _Api( context, a );
8038 } );
8039
8040 _api_registerPlural( 'rows().remove()', 'row().remove()', function () {
8041 var that = this;
8042
8043 this.iterator( 'row', function ( settings, row, thatIdx ) {
8044 var data = settings.aoData;
8045 var rowData = data[ row ];
8046 var i, ien, j, jen;
8047 var loopRow, loopCells;
8048
8049 data.splice( row, 1 );
8050
8051 // Update the cached indexes
8052 for ( i=0, ien=data.length ; i<ien ; i++ ) {
8053 loopRow = data[i];
8054 loopCells = loopRow.anCells;
8055
8056 // Rows
8057 if ( loopRow.nTr !== null ) {
8058 loopRow.nTr._DT_RowIndex = i;
8059 }
8060
8061 // Cells
8062 if ( loopCells !== null ) {
8063 for ( j=0, jen=loopCells.length ; j<jen ; j++ ) {
8064 loopCells[j]._DT_CellIndex.row = i;
8065 }
8066 }
8067 }
8068
8069 // Delete from the display arrays
8070 _fnDeleteIndex( settings.aiDisplayMaster, row );
8071 _fnDeleteIndex( settings.aiDisplay, row );
8072 _fnDeleteIndex( that[ thatIdx ], row, false ); // maintain local indexes
8073
8074 // For server-side processing tables - subtract the deleted row from the count
8075 if ( settings._iRecordsDisplay > 0 ) {
8076 settings._iRecordsDisplay--;
8077 }
8078
8079 // Check for an 'overflow' they case for displaying the table
8080 _fnLengthOverflow( settings );
8081
8082 // Remove the row's ID reference if there is one
8083 var id = settings.rowIdFn( rowData._aData );
8084 if ( id !== undefined ) {
8085 delete settings.aIds[ id ];
8086 }
8087 } );
8088
8089 this.iterator( 'table', function ( settings ) {
8090 for ( var i=0, ien=settings.aoData.length ; i<ien ; i++ ) {
8091 settings.aoData[i].idx = i;
8092 }
8093 } );
8094
8095 return this;
8096 } );
8097
8098
8099 _api_register( 'rows.add()', function ( rows ) {
8100 var newRows = this.iterator( 'table', function ( settings ) {
8101 var row, i, ien;
8102 var out = [];
8103
8104 for ( i=0, ien=rows.length ; i<ien ; i++ ) {
8105 row = rows[i];
8106
8107 if ( row.nodeName && row.nodeName.toUpperCase() === 'TR' ) {
8108 out.push( _fnAddTr( settings, row )[0] );
8109 }
8110 else {
8111 out.push( _fnAddData( settings, row ) );
8112 }
8113 }
8114
8115 return out;
8116 }, 1 );
8117
8118 // Return an Api.rows() extended instance, so rows().nodes() etc can be used
8119 var modRows = this.rows( -1 );
8120 modRows.pop();
8121 $.merge( modRows, newRows );
8122
8123 return modRows;
8124 } );
8125
8126
8127
8128
8129
8130 /**
8131 *
8132 */
8133 _api_register( 'row()', function ( selector, opts ) {
8134 return _selector_first( this.rows( selector, opts ) );
8135 } );
8136
8137
8138 _api_register( 'row().data()', function ( data ) {
8139 var ctx = this.context;
8140
8141 if ( data === undefined ) {
8142 // Get
8143 return ctx.length && this.length ?
8144 ctx[0].aoData[ this[0] ]._aData :
8145 undefined;
8146 }
8147
8148 // Set
8149 var row = ctx[0].aoData[ this[0] ];
8150 row._aData = data;
8151
8152 // If the DOM has an id, and the data source is an array
8153 if ( $.isArray( data ) && row.nTr.id ) {
8154 _fnSetObjectDataFn( ctx[0].rowId )( data, row.nTr.id );
8155 }
8156
8157 // Automatically invalidate
8158 _fnInvalidate( ctx[0], this[0], 'data' );
8159
8160 return this;
8161 } );
8162
8163
8164 _api_register( 'row().node()', function () {
8165 var ctx = this.context;
8166
8167 return ctx.length && this.length ?
8168 ctx[0].aoData[ this[0] ].nTr || null :
8169 null;
8170 } );
8171
8172
8173 _api_register( 'row.add()', function ( row ) {
8174 // Allow a jQuery object to be passed in - only a single row is added from
8175 // it though - the first element in the set
8176 if ( row instanceof $ && row.length ) {
8177 row = row[0];
8178 }
8179
8180 var rows = this.iterator( 'table', function ( settings ) {
8181 if ( row.nodeName && row.nodeName.toUpperCase() === 'TR' ) {
8182 return _fnAddTr( settings, row )[0];
8183 }
8184 return _fnAddData( settings, row );
8185 } );
8186
8187 // Return an Api.rows() extended instance, with the newly added row selected
8188 return this.row( rows[0] );
8189 } );
8190
8191
8192
8193 var __details_add = function ( ctx, row, data, klass )
8194 {
8195 // Convert to array of TR elements
8196 var rows = [];
8197 var addRow = function ( r, k ) {
8198 // Recursion to allow for arrays of jQuery objects
8199 if ( $.isArray( r ) || r instanceof $ ) {
8200 for ( var i=0, ien=r.length ; i<ien ; i++ ) {
8201 addRow( r[i], k );
8202 }
8203 return;
8204 }
8205
8206 // If we get a TR element, then just add it directly - up to the dev
8207 // to add the correct number of columns etc
8208 if ( r.nodeName && r.nodeName.toLowerCase() === 'tr' ) {
8209 rows.push( r );
8210 }
8211 else {
8212 // Otherwise create a row with a wrapper
8213 var created = $('<tr><td/></tr>').addClass( k );
8214 $('td', created)
8215 .addClass( k )
8216 .html( r )
8217 [0].colSpan = _fnVisbleColumns( ctx );
8218
8219 rows.push( created[0] );
8220 }
8221 };
8222
8223 addRow( data, klass );
8224
8225 if ( row._details ) {
8226 row._details.detach();
8227 }
8228
8229 row._details = $(rows);
8230
8231 // If the children were already shown, that state should be retained
8232 if ( row._detailsShow ) {
8233 row._details.insertAfter( row.nTr );
8234 }
8235 };
8236
8237
8238 var __details_remove = function ( api, idx )
8239 {
8240 var ctx = api.context;
8241
8242 if ( ctx.length ) {
8243 var row = ctx[0].aoData[ idx !== undefined ? idx : api[0] ];
8244
8245 if ( row && row._details ) {
8246 row._details.remove();
8247
8248 row._detailsShow = undefined;
8249 row._details = undefined;
8250 }
8251 }
8252 };
8253
8254
8255 var __details_display = function ( api, show ) {
8256 var ctx = api.context;
8257
8258 if ( ctx.length && api.length ) {
8259 var row = ctx[0].aoData[ api[0] ];
8260
8261 if ( row._details ) {
8262 row._detailsShow = show;
8263
8264 if ( show ) {
8265 row._details.insertAfter( row.nTr );
8266 }
8267 else {
8268 row._details.detach();
8269 }
8270
8271 __details_events( ctx[0] );
8272 }
8273 }
8274 };
8275
8276
8277 var __details_events = function ( settings )
8278 {
8279 var api = new _Api( settings );
8280 var namespace = '.dt.DT_details';
8281 var drawEvent = 'draw'+namespace;
8282 var colvisEvent = 'column-visibility'+namespace;
8283 var destroyEvent = 'destroy'+namespace;
8284 var data = settings.aoData;
8285
8286 api.off( drawEvent +' '+ colvisEvent +' '+ destroyEvent );
8287
8288 if ( _pluck( data, '_details' ).length > 0 ) {
8289 // On each draw, insert the required elements into the document
8290 api.on( drawEvent, function ( e, ctx ) {
8291 if ( settings !== ctx ) {
8292 return;
8293 }
8294
8295 api.rows( {page:'current'} ).eq(0).each( function (idx) {
8296 // Internal data grab
8297 var row = data[ idx ];
8298
8299 if ( row._detailsShow ) {
8300 row._details.insertAfter( row.nTr );
8301 }
8302 } );
8303 } );
8304
8305 // Column visibility change - update the colspan
8306 api.on( colvisEvent, function ( e, ctx, idx, vis ) {
8307 if ( settings !== ctx ) {
8308 return;
8309 }
8310
8311 // Update the colspan for the details rows (note, only if it already has
8312 // a colspan)
8313 var row, visible = _fnVisbleColumns( ctx );
8314
8315 for ( var i=0, ien=data.length ; i<ien ; i++ ) {
8316 row = data[i];
8317
8318 if ( row._details ) {
8319 row._details.children('td[colspan]').attr('colspan', visible );
8320 }
8321 }
8322 } );
8323
8324 // Table destroyed - nuke any child rows
8325 api.on( destroyEvent, function ( e, ctx ) {
8326 if ( settings !== ctx ) {
8327 return;
8328 }
8329
8330 for ( var i=0, ien=data.length ; i<ien ; i++ ) {
8331 if ( data[i]._details ) {
8332 __details_remove( api, i );
8333 }
8334 }
8335 } );
8336 }
8337 };
8338
8339 // Strings for the method names to help minification
8340 var _emp = '';
8341 var _child_obj = _emp+'row().child';
8342 var _child_mth = _child_obj+'()';
8343
8344 // data can be:
8345 // tr
8346 // string
8347 // jQuery or array of any of the above
8348 _api_register( _child_mth, function ( data, klass ) {
8349 var ctx = this.context;
8350
8351 if ( data === undefined ) {
8352 // get
8353 return ctx.length && this.length ?
8354 ctx[0].aoData[ this[0] ]._details :
8355 undefined;
8356 }
8357 else if ( data === true ) {
8358 // show
8359 this.child.show();
8360 }
8361 else if ( data === false ) {
8362 // remove
8363 __details_remove( this );
8364 }
8365 else if ( ctx.length && this.length ) {
8366 // set
8367 __details_add( ctx[0], ctx[0].aoData[ this[0] ], data, klass );
8368 }
8369
8370 return this;
8371 } );
8372
8373
8374 _api_register( [
8375 _child_obj+'.show()',
8376 _child_mth+'.show()' // only when `child()` was called with parameters (without
8377 ], function ( show ) { // it returns an object and this method is not executed)
8378 __details_display( this, true );
8379 return this;
8380 } );
8381
8382
8383 _api_register( [
8384 _child_obj+'.hide()',
8385 _child_mth+'.hide()' // only when `child()` was called with parameters (without
8386 ], function () { // it returns an object and this method is not executed)
8387 __details_display( this, false );
8388 return this;
8389 } );
8390
8391
8392 _api_register( [
8393 _child_obj+'.remove()',
8394 _child_mth+'.remove()' // only when `child()` was called with parameters (without
8395 ], function () { // it returns an object and this method is not executed)
8396 __details_remove( this );
8397 return this;
8398 } );
8399
8400
8401 _api_register( _child_obj+'.isShown()', function () {
8402 var ctx = this.context;
8403
8404 if ( ctx.length && this.length ) {
8405 // _detailsShown as false or undefined will fall through to return false
8406 return ctx[0].aoData[ this[0] ]._detailsShow || false;
8407 }
8408 return false;
8409 } );
8410
8411
8412
8413 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
8414 * Columns
8415 *
8416 * {integer} - column index (>=0 count from left, <0 count from right)
8417 * "{integer}:visIdx" - visible column index (i.e. translate to column index) (>=0 count from left, <0 count from right)
8418 * "{integer}:visible" - alias for {integer}:visIdx (>=0 count from left, <0 count from right)
8419 * "{string}:name" - column name
8420 * "{string}" - jQuery selector on column header nodes
8421 *
8422 */
8423
8424 // can be an array of these items, comma separated list, or an array of comma
8425 // separated lists
8426
8427 var __re_column_selector = /^([^:]+):(name|visIdx|visible)$/;
8428
8429
8430 // r1 and r2 are redundant - but it means that the parameters match for the
8431 // iterator callback in columns().data()
8432 var __columnData = function ( settings, column, r1, r2, rows ) {
8433 var a = [];
8434 for ( var row=0, ien=rows.length ; row<ien ; row++ ) {
8435 a.push( _fnGetCellData( settings, rows[row], column ) );
8436 }
8437 return a;
8438 };
8439
8440
8441 var __column_selector = function ( settings, selector, opts )
8442 {
8443 var
8444 columns = settings.aoColumns,
8445 names = _pluck( columns, 'sName' ),
8446 nodes = _pluck( columns, 'nTh' );
8447
8448 var run = function ( s ) {
8449 var selInt = _intVal( s );
8450
8451 // Selector - all
8452 if ( s === '' ) {
8453 return _range( columns.length );
8454 }
8455
8456 // Selector - index
8457 if ( selInt !== null ) {
8458 return [ selInt >= 0 ?
8459 selInt : // Count from left
8460 columns.length + selInt // Count from right (+ because its a negative value)
8461 ];
8462 }
8463
8464 // Selector = function
8465 if ( typeof s === 'function' ) {
8466 var rows = _selector_row_indexes( settings, opts );
8467
8468 return $.map( columns, function (col, idx) {
8469 return s(
8470 idx,
8471 __columnData( settings, idx, 0, 0, rows ),
8472 nodes[ idx ]
8473 ) ? idx : null;
8474 } );
8475 }
8476
8477 // jQuery or string selector
8478 var match = typeof s === 'string' ?
8479 s.match( __re_column_selector ) :
8480 '';
8481
8482 if ( match ) {
8483 switch( match[2] ) {
8484 case 'visIdx':
8485 case 'visible':
8486 var idx = parseInt( match[1], 10 );
8487 // Visible index given, convert to column index
8488 if ( idx < 0 ) {
8489 // Counting from the right
8490 var visColumns = $.map( columns, function (col,i) {
8491 return col.bVisible ? i : null;
8492 } );
8493 return [ visColumns[ visColumns.length + idx ] ];
8494 }
8495 // Counting from the left
8496 return [ _fnVisibleToColumnIndex( settings, idx ) ];
8497
8498 case 'name':
8499 // match by name. `names` is column index complete and in order
8500 return $.map( names, function (name, i) {
8501 return name === match[1] ? i : null;
8502 } );
8503
8504 default:
8505 return [];
8506 }
8507 }
8508
8509 // Cell in the table body
8510 if ( s.nodeName && s._DT_CellIndex ) {
8511 return [ s._DT_CellIndex.column ];
8512 }
8513
8514 // jQuery selector on the TH elements for the columns
8515 var jqResult = $( nodes )
8516 .filter( s )
8517 .map( function () {
8518 return $.inArray( this, nodes ); // `nodes` is column index complete and in order
8519 } )
8520 .toArray();
8521
8522 if ( jqResult.length || ! s.nodeName ) {
8523 return jqResult;
8524 }
8525
8526 // Otherwise a node which might have a `dt-column` data attribute, or be
8527 // a child or such an element
8528 var host = $(s).closest('*[data-dt-column]');
8529 return host.length ?
8530 [ host.data('dt-column') ] :
8531 [];
8532 };
8533
8534 return _selector_run( 'column', selector, run, settings, opts );
8535 };
8536
8537
8538 var __setColumnVis = function ( settings, column, vis ) {
8539 var
8540 cols = settings.aoColumns,
8541 col = cols[ column ],
8542 data = settings.aoData,
8543 row, cells, i, ien, tr;
8544
8545 // Get
8546 if ( vis === undefined ) {
8547 return col.bVisible;
8548 }
8549
8550 // Set
8551 // No change
8552 if ( col.bVisible === vis ) {
8553 return;
8554 }
8555
8556 if ( vis ) {
8557 // Insert column
8558 // Need to decide if we should use appendChild or insertBefore
8559 var insertBefore = $.inArray( true, _pluck(cols, 'bVisible'), column+1 );
8560
8561 for ( i=0, ien=data.length ; i<ien ; i++ ) {
8562 tr = data[i].nTr;
8563 cells = data[i].anCells;
8564
8565 if ( tr ) {
8566 // insertBefore can act like appendChild if 2nd arg is null
8567 tr.insertBefore( cells[ column ], cells[ insertBefore ] || null );
8568 }
8569 }
8570 }
8571 else {
8572 // Remove column
8573 $( _pluck( settings.aoData, 'anCells', column ) ).detach();
8574 }
8575
8576 // Common actions
8577 col.bVisible = vis;
8578 _fnDrawHead( settings, settings.aoHeader );
8579 _fnDrawHead( settings, settings.aoFooter );
8580
8581 // Update colspan for no records display. Child rows and extensions will use their own
8582 // listeners to do this - only need to update the empty table item here
8583 if ( ! settings.aiDisplay.length ) {
8584 $(settings.nTBody).find('td[colspan]').attr('colspan', _fnVisbleColumns(settings));
8585 }
8586
8587 _fnSaveState( settings );
8588 };
8589
8590
8591 _api_register( 'columns()', function ( selector, opts ) {
8592 // argument shifting
8593 if ( selector === undefined ) {
8594 selector = '';
8595 }
8596 else if ( $.isPlainObject( selector ) ) {
8597 opts = selector;
8598 selector = '';
8599 }
8600
8601 opts = _selector_opts( opts );
8602
8603 var inst = this.iterator( 'table', function ( settings ) {
8604 return __column_selector( settings, selector, opts );
8605 }, 1 );
8606
8607 // Want argument shifting here and in _row_selector?
8608 inst.selector.cols = selector;
8609 inst.selector.opts = opts;
8610
8611 return inst;
8612 } );
8613
8614 _api_registerPlural( 'columns().header()', 'column().header()', function ( selector, opts ) {
8615 return this.iterator( 'column', function ( settings, column ) {
8616 return settings.aoColumns[column].nTh;
8617 }, 1 );
8618 } );
8619
8620 _api_registerPlural( 'columns().footer()', 'column().footer()', function ( selector, opts ) {
8621 return this.iterator( 'column', function ( settings, column ) {
8622 return settings.aoColumns[column].nTf;
8623 }, 1 );
8624 } );
8625
8626 _api_registerPlural( 'columns().data()', 'column().data()', function () {
8627 return this.iterator( 'column-rows', __columnData, 1 );
8628 } );
8629
8630 _api_registerPlural( 'columns().dataSrc()', 'column().dataSrc()', function () {
8631 return this.iterator( 'column', function ( settings, column ) {
8632 return settings.aoColumns[column].mData;
8633 }, 1 );
8634 } );
8635
8636 _api_registerPlural( 'columns().cache()', 'column().cache()', function ( type ) {
8637 return this.iterator( 'column-rows', function ( settings, column, i, j, rows ) {
8638 return _pluck_order( settings.aoData, rows,
8639 type === 'search' ? '_aFilterData' : '_aSortData', column
8640 );
8641 }, 1 );
8642 } );
8643
8644 _api_registerPlural( 'columns().nodes()', 'column().nodes()', function () {
8645 return this.iterator( 'column-rows', function ( settings, column, i, j, rows ) {
8646 return _pluck_order( settings.aoData, rows, 'anCells', column ) ;
8647 }, 1 );
8648 } );
8649
8650 _api_registerPlural( 'columns().visible()', 'column().visible()', function ( vis, calc ) {
8651 var ret = this.iterator( 'column', function ( settings, column ) {
8652 if ( vis === undefined ) {
8653 return settings.aoColumns[ column ].bVisible;
8654 } // else
8655 __setColumnVis( settings, column, vis );
8656 } );
8657
8658 // Group the column visibility changes
8659 if ( vis !== undefined ) {
8660 // Second loop once the first is done for events
8661 this.iterator( 'column', function ( settings, column ) {
8662 _fnCallbackFire( settings, null, 'column-visibility', [settings, column, vis, calc] );
8663 } );
8664
8665 if ( calc === undefined || calc ) {
8666 this.columns.adjust();
8667 }
8668 }
8669
8670 return ret;
8671 } );
8672
8673 _api_registerPlural( 'columns().indexes()', 'column().index()', function ( type ) {
8674 return this.iterator( 'column', function ( settings, column ) {
8675 return type === 'visible' ?
8676 _fnColumnIndexToVisible( settings, column ) :
8677 column;
8678 }, 1 );
8679 } );
8680
8681 _api_register( 'columns.adjust()', function () {
8682 return this.iterator( 'table', function ( settings ) {
8683 _fnAdjustColumnSizing( settings );
8684 }, 1 );
8685 } );
8686
8687 _api_register( 'column.index()', function ( type, idx ) {
8688 if ( this.context.length !== 0 ) {
8689 var ctx = this.context[0];
8690
8691 if ( type === 'fromVisible' || type === 'toData' ) {
8692 return _fnVisibleToColumnIndex( ctx, idx );
8693 }
8694 else if ( type === 'fromData' || type === 'toVisible' ) {
8695 return _fnColumnIndexToVisible( ctx, idx );
8696 }
8697 }
8698 } );
8699
8700 _api_register( 'column()', function ( selector, opts ) {
8701 return _selector_first( this.columns( selector, opts ) );
8702 } );
8703
8704
8705
8706 var __cell_selector = function ( settings, selector, opts )
8707 {
8708 var data = settings.aoData;
8709 var rows = _selector_row_indexes( settings, opts );
8710 var cells = _removeEmpty( _pluck_order( data, rows, 'anCells' ) );
8711 var allCells = $( [].concat.apply([], cells) );
8712 var row;
8713 var columns = settings.aoColumns.length;
8714 var a, i, ien, j, o, host;
8715
8716 var run = function ( s ) {
8717 var fnSelector = typeof s === 'function';
8718
8719 if ( s === null || s === undefined || fnSelector ) {
8720 // All cells and function selectors
8721 a = [];
8722
8723 for ( i=0, ien=rows.length ; i<ien ; i++ ) {
8724 row = rows[i];
8725
8726 for ( j=0 ; j<columns ; j++ ) {
8727 o = {
8728 row: row,
8729 column: j
8730 };
8731
8732 if ( fnSelector ) {
8733 // Selector - function
8734 host = data[ row ];
8735
8736 if ( s( o, _fnGetCellData(settings, row, j), host.anCells ? host.anCells[j] : null ) ) {
8737 a.push( o );
8738 }
8739 }
8740 else {
8741 // Selector - all
8742 a.push( o );
8743 }
8744 }
8745 }
8746
8747 return a;
8748 }
8749
8750 // Selector - index
8751 if ( $.isPlainObject( s ) ) {
8752 // Valid cell index and its in the array of selectable rows
8753 return s.column !== undefined && s.row !== undefined && $.inArray( s.row, rows ) !== -1 ?
8754 [s] :
8755 [];
8756 }
8757
8758 // Selector - jQuery filtered cells
8759 var jqResult = allCells
8760 .filter( s )
8761 .map( function (i, el) {
8762 return { // use a new object, in case someone changes the values
8763 row: el._DT_CellIndex.row,
8764 column: el._DT_CellIndex.column
8765 };
8766 } )
8767 .toArray();
8768
8769 if ( jqResult.length || ! s.nodeName ) {
8770 return jqResult;
8771 }
8772
8773 // Otherwise the selector is a node, and there is one last option - the
8774 // element might be a child of an element which has dt-row and dt-column
8775 // data attributes
8776 host = $(s).closest('*[data-dt-row]');
8777 return host.length ?
8778 [ {
8779 row: host.data('dt-row'),
8780 column: host.data('dt-column')
8781 } ] :
8782 [];
8783 };
8784
8785 return _selector_run( 'cell', selector, run, settings, opts );
8786 };
8787
8788
8789
8790
8791 _api_register( 'cells()', function ( rowSelector, columnSelector, opts ) {
8792 // Argument shifting
8793 if ( $.isPlainObject( rowSelector ) ) {
8794 // Indexes
8795 if ( rowSelector.row === undefined ) {
8796 // Selector options in first parameter
8797 opts = rowSelector;
8798 rowSelector = null;
8799 }
8800 else {
8801 // Cell index objects in first parameter
8802 opts = columnSelector;
8803 columnSelector = null;
8804 }
8805 }
8806 if ( $.isPlainObject( columnSelector ) ) {
8807 opts = columnSelector;
8808 columnSelector = null;
8809 }
8810
8811 // Cell selector
8812 if ( columnSelector === null || columnSelector === undefined ) {
8813 return this.iterator( 'table', function ( settings ) {
8814 return __cell_selector( settings, rowSelector, _selector_opts( opts ) );
8815 } );
8816 }
8817
8818 // Row + column selector
8819 var columns = this.columns( columnSelector );
8820 var rows = this.rows( rowSelector );
8821 var a, i, ien, j, jen;
8822
8823 this.iterator( 'table', function ( settings, idx ) {
8824 a = [];
8825
8826 for ( i=0, ien=rows[idx].length ; i<ien ; i++ ) {
8827 for ( j=0, jen=columns[idx].length ; j<jen ; j++ ) {
8828 a.push( {
8829 row: rows[idx][i],
8830 column: columns[idx][j]
8831 } );
8832 }
8833 }
8834 }, 1 );
8835
8836 // Now pass through the cell selector for options
8837 var cells = this.cells( a, opts );
8838
8839 $.extend( cells.selector, {
8840 cols: columnSelector,
8841 rows: rowSelector,
8842 opts: opts
8843 } );
8844
8845 return cells;
8846 } );
8847
8848
8849 _api_registerPlural( 'cells().nodes()', 'cell().node()', function () {
8850 return this.iterator( 'cell', function ( settings, row, column ) {
8851 var data = settings.aoData[ row ];
8852
8853 return data && data.anCells ?
8854 data.anCells[ column ] :
8855 undefined;
8856 }, 1 );
8857 } );
8858
8859
8860 _api_register( 'cells().data()', function () {
8861 return this.iterator( 'cell', function ( settings, row, column ) {
8862 return _fnGetCellData( settings, row, column );
8863 }, 1 );
8864 } );
8865
8866
8867 _api_registerPlural( 'cells().cache()', 'cell().cache()', function ( type ) {
8868 type = type === 'search' ? '_aFilterData' : '_aSortData';
8869
8870 return this.iterator( 'cell', function ( settings, row, column ) {
8871 return settings.aoData[ row ][ type ][ column ];
8872 }, 1 );
8873 } );
8874
8875
8876 _api_registerPlural( 'cells().render()', 'cell().render()', function ( type ) {
8877 return this.iterator( 'cell', function ( settings, row, column ) {
8878 return _fnGetCellData( settings, row, column, type );
8879 }, 1 );
8880 } );
8881
8882
8883 _api_registerPlural( 'cells().indexes()', 'cell().index()', function () {
8884 return this.iterator( 'cell', function ( settings, row, column ) {
8885 return {
8886 row: row,
8887 column: column,
8888 columnVisible: _fnColumnIndexToVisible( settings, column )
8889 };
8890 }, 1 );
8891 } );
8892
8893
8894 _api_registerPlural( 'cells().invalidate()', 'cell().invalidate()', function ( src ) {
8895 return this.iterator( 'cell', function ( settings, row, column ) {
8896 _fnInvalidate( settings, row, src, column );
8897 } );
8898 } );
8899
8900
8901
8902 _api_register( 'cell()', function ( rowSelector, columnSelector, opts ) {
8903 return _selector_first( this.cells( rowSelector, columnSelector, opts ) );
8904 } );
8905
8906
8907 _api_register( 'cell().data()', function ( data ) {
8908 var ctx = this.context;
8909 var cell = this[0];
8910
8911 if ( data === undefined ) {
8912 // Get
8913 return ctx.length && cell.length ?
8914 _fnGetCellData( ctx[0], cell[0].row, cell[0].column ) :
8915 undefined;
8916 }
8917
8918 // Set
8919 _fnSetCellData( ctx[0], cell[0].row, cell[0].column, data );
8920 _fnInvalidate( ctx[0], cell[0].row, 'data', cell[0].column );
8921
8922 return this;
8923 } );
8924
8925
8926
8927 /**
8928 * Get current ordering (sorting) that has been applied to the table.
8929 *
8930 * @returns {array} 2D array containing the sorting information for the first
8931 * table in the current context. Each element in the parent array represents
8932 * a column being sorted upon (i.e. multi-sorting with two columns would have
8933 * 2 inner arrays). The inner arrays may have 2 or 3 elements. The first is
8934 * the column index that the sorting condition applies to, the second is the
8935 * direction of the sort (`desc` or `asc`) and, optionally, the third is the
8936 * index of the sorting order from the `column.sorting` initialisation array.
8937 *//**
8938 * Set the ordering for the table.
8939 *
8940 * @param {integer} order Column index to sort upon.
8941 * @param {string} direction Direction of the sort to be applied (`asc` or `desc`)
8942 * @returns {DataTables.Api} this
8943 *//**
8944 * Set the ordering for the table.
8945 *
8946 * @param {array} order 1D array of sorting information to be applied.
8947 * @param {array} [...] Optional additional sorting conditions
8948 * @returns {DataTables.Api} this
8949 *//**
8950 * Set the ordering for the table.
8951 *
8952 * @param {array} order 2D array of sorting information to be applied.
8953 * @returns {DataTables.Api} this
8954 */
8955 _api_register( 'order()', function ( order, dir ) {
8956 var ctx = this.context;
8957
8958 if ( order === undefined ) {
8959 // get
8960 return ctx.length !== 0 ?
8961 ctx[0].aaSorting :
8962 undefined;
8963 }
8964
8965 // set
8966 if ( typeof order === 'number' ) {
8967 // Simple column / direction passed in
8968 order = [ [ order, dir ] ];
8969 }
8970 else if ( order.length && ! $.isArray( order[0] ) ) {
8971 // Arguments passed in (list of 1D arrays)
8972 order = Array.prototype.slice.call( arguments );
8973 }
8974 // otherwise a 2D array was passed in
8975
8976 return this.iterator( 'table', function ( settings ) {
8977 settings.aaSorting = order.slice();
8978 } );
8979 } );
8980
8981
8982 /**
8983 * Attach a sort listener to an element for a given column
8984 *
8985 * @param {node|jQuery|string} node Identifier for the element(s) to attach the
8986 * listener to. This can take the form of a single DOM node, a jQuery
8987 * collection of nodes or a jQuery selector which will identify the node(s).
8988 * @param {integer} column the column that a click on this node will sort on
8989 * @param {function} [callback] callback function when sort is run
8990 * @returns {DataTables.Api} this
8991 */
8992 _api_register( 'order.listener()', function ( node, column, callback ) {
8993 return this.iterator( 'table', function ( settings ) {
8994 _fnSortAttachListener( settings, node, column, callback );
8995 } );
8996 } );
8997
8998
8999 _api_register( 'order.fixed()', function ( set ) {
9000 if ( ! set ) {
9001 var ctx = this.context;
9002 var fixed = ctx.length ?
9003 ctx[0].aaSortingFixed :
9004 undefined;
9005
9006 return $.isArray( fixed ) ?
9007 { pre: fixed } :
9008 fixed;
9009 }
9010
9011 return this.iterator( 'table', function ( settings ) {
9012 settings.aaSortingFixed = $.extend( true, {}, set );
9013 } );
9014 } );
9015
9016
9017 // Order by the selected column(s)
9018 _api_register( [
9019 'columns().order()',
9020 'column().order()'
9021 ], function ( dir ) {
9022 var that = this;
9023
9024 return this.iterator( 'table', function ( settings, i ) {
9025 var sort = [];
9026
9027 $.each( that[i], function (j, col) {
9028 sort.push( [ col, dir ] );
9029 } );
9030
9031 settings.aaSorting = sort;
9032 } );
9033 } );
9034
9035
9036
9037 _api_register( 'search()', function ( input, regex, smart, caseInsen ) {
9038 var ctx = this.context;
9039
9040 if ( input === undefined ) {
9041 // get
9042 return ctx.length !== 0 ?
9043 ctx[0].oPreviousSearch.sSearch :
9044 undefined;
9045 }
9046
9047 // set
9048 return this.iterator( 'table', function ( settings ) {
9049 if ( ! settings.oFeatures.bFilter ) {
9050 return;
9051 }
9052
9053 _fnFilterComplete( settings, $.extend( {}, settings.oPreviousSearch, {
9054 "sSearch": input+"",
9055 "bRegex": regex === null ? false : regex,
9056 "bSmart": smart === null ? true : smart,
9057 "bCaseInsensitive": caseInsen === null ? true : caseInsen
9058 } ), 1 );
9059 } );
9060 } );
9061
9062
9063 _api_registerPlural(
9064 'columns().search()',
9065 'column().search()',
9066 function ( input, regex, smart, caseInsen ) {
9067 return this.iterator( 'column', function ( settings, column ) {
9068 var preSearch = settings.aoPreSearchCols;
9069
9070 if ( input === undefined ) {
9071 // get
9072 return preSearch[ column ].sSearch;
9073 }
9074
9075 // set
9076 if ( ! settings.oFeatures.bFilter ) {
9077 return;
9078 }
9079
9080 $.extend( preSearch[ column ], {
9081 "sSearch": input+"",
9082 "bRegex": regex === null ? false : regex,
9083 "bSmart": smart === null ? true : smart,
9084 "bCaseInsensitive": caseInsen === null ? true : caseInsen
9085 } );
9086
9087 _fnFilterComplete( settings, settings.oPreviousSearch, 1 );
9088 } );
9089 }
9090 );
9091
9092 /*
9093 * State API methods
9094 */
9095
9096 _api_register( 'state()', function () {
9097 return this.context.length ?
9098 this.context[0].oSavedState :
9099 null;
9100 } );
9101
9102
9103 _api_register( 'state.clear()', function () {
9104 return this.iterator( 'table', function ( settings ) {
9105 // Save an empty object
9106 settings.fnStateSaveCallback.call( settings.oInstance, settings, {} );
9107 } );
9108 } );
9109
9110
9111 _api_register( 'state.loaded()', function () {
9112 return this.context.length ?
9113 this.context[0].oLoadedState :
9114 null;
9115 } );
9116
9117
9118 _api_register( 'state.save()', function () {
9119 return this.iterator( 'table', function ( settings ) {
9120 _fnSaveState( settings );
9121 } );
9122 } );
9123
9124
9125
9126 /**
9127 * Provide a common method for plug-ins to check the version of DataTables being
9128 * used, in order to ensure compatibility.
9129 *
9130 * @param {string} version Version string to check for, in the format "X.Y.Z".
9131 * Note that the formats "X" and "X.Y" are also acceptable.
9132 * @returns {boolean} true if this version of DataTables is greater or equal to
9133 * the required version, or false if this version of DataTales is not
9134 * suitable
9135 * @static
9136 * @dtopt API-Static
9137 *
9138 * @example
9139 * alert( $.fn.dataTable.versionCheck( '1.9.0' ) );
9140 */
9141 DataTable.versionCheck = DataTable.fnVersionCheck = function( version )
9142 {
9143 var aThis = DataTable.version.split('.');
9144 var aThat = version.split('.');
9145 var iThis, iThat;
9146
9147 for ( var i=0, iLen=aThat.length ; i<iLen ; i++ ) {
9148 iThis = parseInt( aThis[i], 10 ) || 0;
9149 iThat = parseInt( aThat[i], 10 ) || 0;
9150
9151 // Parts are the same, keep comparing
9152 if (iThis === iThat) {
9153 continue;
9154 }
9155
9156 // Parts are different, return immediately
9157 return iThis > iThat;
9158 }
9159
9160 return true;
9161 };
9162
9163
9164 /**
9165 * Check if a `<table>` node is a DataTable table already or not.
9166 *
9167 * @param {node|jquery|string} table Table node, jQuery object or jQuery
9168 * selector for the table to test. Note that if more than more than one
9169 * table is passed on, only the first will be checked
9170 * @returns {boolean} true the table given is a DataTable, or false otherwise
9171 * @static
9172 * @dtopt API-Static
9173 *
9174 * @example
9175 * if ( ! $.fn.DataTable.isDataTable( '#example' ) ) {
9176 * $('#example').dataTable();
9177 * }
9178 */
9179 DataTable.isDataTable = DataTable.fnIsDataTable = function ( table )
9180 {
9181 var t = $(table).get(0);
9182 var is = false;
9183
9184 if ( table instanceof DataTable.Api ) {
9185 return true;
9186 }
9187
9188 $.each( DataTable.settings, function (i, o) {
9189 var head = o.nScrollHead ? $('table', o.nScrollHead)[0] : null;
9190 var foot = o.nScrollFoot ? $('table', o.nScrollFoot)[0] : null;
9191
9192 if ( o.nTable === t || head === t || foot === t ) {
9193 is = true;
9194 }
9195 } );
9196
9197 return is;
9198 };
9199
9200
9201 /**
9202 * Get all DataTable tables that have been initialised - optionally you can
9203 * select to get only currently visible tables.
9204 *
9205 * @param {boolean} [visible=false] Flag to indicate if you want all (default)
9206 * or visible tables only.
9207 * @returns {array} Array of `table` nodes (not DataTable instances) which are
9208 * DataTables
9209 * @static
9210 * @dtopt API-Static
9211 *
9212 * @example
9213 * $.each( $.fn.dataTable.tables(true), function () {
9214 * $(table).DataTable().columns.adjust();
9215 * } );
9216 */
9217 DataTable.tables = DataTable.fnTables = function ( visible )
9218 {
9219 var api = false;
9220
9221 if ( $.isPlainObject( visible ) ) {
9222 api = visible.api;
9223 visible = visible.visible;
9224 }
9225
9226 var a = $.map( DataTable.settings, function (o) {
9227 if ( !visible || (visible && $(o.nTable).is(':visible')) ) {
9228 return o.nTable;
9229 }
9230 } );
9231
9232 return api ?
9233 new _Api( a ) :
9234 a;
9235 };
9236
9237
9238 /**
9239 * Convert from camel case parameters to Hungarian notation. This is made public
9240 * for the extensions to provide the same ability as DataTables core to accept
9241 * either the 1.9 style Hungarian notation, or the 1.10+ style camelCase
9242 * parameters.
9243 *
9244 * @param {object} src The model object which holds all parameters that can be
9245 * mapped.
9246 * @param {object} user The object to convert from camel case to Hungarian.
9247 * @param {boolean} force When set to `true`, properties which already have a
9248 * Hungarian value in the `user` object will be overwritten. Otherwise they
9249 * won't be.
9250 */
9251 DataTable.camelToHungarian = _fnCamelToHungarian;
9252
9253
9254
9255 /**
9256 *
9257 */
9258 _api_register( '$()', function ( selector, opts ) {
9259 var
9260 rows = this.rows( opts ).nodes(), // Get all rows
9261 jqRows = $(rows);
9262
9263 return $( [].concat(
9264 jqRows.filter( selector ).toArray(),
9265 jqRows.find( selector ).toArray()
9266 ) );
9267 } );
9268
9269
9270 // jQuery functions to operate on the tables
9271 $.each( [ 'on', 'one', 'off' ], function (i, key) {
9272 _api_register( key+'()', function ( /* event, handler */ ) {
9273 var args = Array.prototype.slice.call(arguments);
9274
9275 // Add the `dt` namespace automatically if it isn't already present
9276 args[0] = $.map( args[0].split( /\s/ ), function ( e ) {
9277 return ! e.match(/\.dt\b/) ?
9278 e+'.dt' :
9279 e;
9280 } ).join( ' ' );
9281
9282 var inst = $( this.tables().nodes() );
9283 inst[key].apply( inst, args );
9284 return this;
9285 } );
9286 } );
9287
9288
9289 _api_register( 'clear()', function () {
9290 return this.iterator( 'table', function ( settings ) {
9291 _fnClearTable( settings );
9292 } );
9293 } );
9294
9295
9296 _api_register( 'settings()', function () {
9297 return new _Api( this.context, this.context );
9298 } );
9299
9300
9301 _api_register( 'init()', function () {
9302 var ctx = this.context;
9303 return ctx.length ? ctx[0].oInit : null;
9304 } );
9305
9306
9307 _api_register( 'data()', function () {
9308 return this.iterator( 'table', function ( settings ) {
9309 return _pluck( settings.aoData, '_aData' );
9310 } ).flatten();
9311 } );
9312
9313
9314 _api_register( 'destroy()', function ( remove ) {
9315 remove = remove || false;
9316
9317 return this.iterator( 'table', function ( settings ) {
9318 var orig = settings.nTableWrapper.parentNode;
9319 var classes = settings.oClasses;
9320 var table = settings.nTable;
9321 var tbody = settings.nTBody;
9322 var thead = settings.nTHead;
9323 var tfoot = settings.nTFoot;
9324 var jqTable = $(table);
9325 var jqTbody = $(tbody);
9326 var jqWrapper = $(settings.nTableWrapper);
9327 var rows = $.map( settings.aoData, function (r) { return r.nTr; } );
9328 var i, ien;
9329
9330 // Flag to note that the table is currently being destroyed - no action
9331 // should be taken
9332 settings.bDestroying = true;
9333
9334 // Fire off the destroy callbacks for plug-ins etc
9335 _fnCallbackFire( settings, "aoDestroyCallback", "destroy", [settings] );
9336
9337 // If not being removed from the document, make all columns visible
9338 if ( ! remove ) {
9339 new _Api( settings ).columns().visible( true );
9340 }
9341
9342 // Blitz all `DT` namespaced events (these are internal events, the
9343 // lowercase, `dt` events are user subscribed and they are responsible
9344 // for removing them
9345 jqWrapper.off('.DT').find(':not(tbody *)').off('.DT');
9346 $(window).off('.DT-'+settings.sInstance);
9347
9348 // When scrolling we had to break the table up - restore it
9349 if ( table != thead.parentNode ) {
9350 jqTable.children('thead').detach();
9351 jqTable.append( thead );
9352 }
9353
9354 if ( tfoot && table != tfoot.parentNode ) {
9355 jqTable.children('tfoot').detach();
9356 jqTable.append( tfoot );
9357 }
9358
9359 settings.aaSorting = [];
9360 settings.aaSortingFixed = [];
9361 _fnSortingClasses( settings );
9362
9363 $( rows ).removeClass( settings.asStripeClasses.join(' ') );
9364
9365 $('th, td', thead).removeClass( classes.sSortable+' '+
9366 classes.sSortableAsc+' '+classes.sSortableDesc+' '+classes.sSortableNone
9367 );
9368
9369 // Add the TR elements back into the table in their original order
9370 jqTbody.children().detach();
9371 jqTbody.append( rows );
9372
9373 // Remove the DataTables generated nodes, events and classes
9374 var removedMethod = remove ? 'remove' : 'detach';
9375 jqTable[ removedMethod ]();
9376 jqWrapper[ removedMethod ]();
9377
9378 // If we need to reattach the table to the document
9379 if ( ! remove && orig ) {
9380 // insertBefore acts like appendChild if !arg[1]
9381 orig.insertBefore( table, settings.nTableReinsertBefore );
9382
9383 // Restore the width of the original table - was read from the style property,
9384 // so we can restore directly to that
9385 jqTable
9386 .css( 'width', settings.sDestroyWidth )
9387 .removeClass( classes.sTable );
9388
9389 // If the were originally stripe classes - then we add them back here.
9390 // Note this is not fool proof (for example if not all rows had stripe
9391 // classes - but it's a good effort without getting carried away
9392 ien = settings.asDestroyStripes.length;
9393
9394 if ( ien ) {
9395 jqTbody.children().each( function (i) {
9396 $(this).addClass( settings.asDestroyStripes[i % ien] );
9397 } );
9398 }
9399 }
9400
9401 /* Remove the settings object from the settings array */
9402 var idx = $.inArray( settings, DataTable.settings );
9403 if ( idx !== -1 ) {
9404 DataTable.settings.splice( idx, 1 );
9405 }
9406 } );
9407 } );
9408
9409
9410 // Add the `every()` method for rows, columns and cells in a compact form
9411 $.each( [ 'column', 'row', 'cell' ], function ( i, type ) {
9412 _api_register( type+'s().every()', function ( fn ) {
9413 var opts = this.selector.opts;
9414 var api = this;
9415
9416 return this.iterator( type, function ( settings, arg1, arg2, arg3, arg4 ) {
9417 // Rows and columns:
9418 // arg1 - index
9419 // arg2 - table counter
9420 // arg3 - loop counter
9421 // arg4 - undefined
9422 // Cells:
9423 // arg1 - row index
9424 // arg2 - column index
9425 // arg3 - table counter
9426 // arg4 - loop counter
9427 fn.call(
9428 api[ type ](
9429 arg1,
9430 type==='cell' ? arg2 : opts,
9431 type==='cell' ? opts : undefined
9432 ),
9433 arg1, arg2, arg3, arg4
9434 );
9435 } );
9436 } );
9437 } );
9438
9439
9440 // i18n method for extensions to be able to use the language object from the
9441 // DataTable
9442 _api_register( 'i18n()', function ( token, def, plural ) {
9443 var ctx = this.context[0];
9444 var resolved = _fnGetObjectDataFn( token )( ctx.oLanguage );
9445
9446 if ( resolved === undefined ) {
9447 resolved = def;
9448 }
9449
9450 if ( plural !== undefined && $.isPlainObject( resolved ) ) {
9451 resolved = resolved[ plural ] !== undefined ?
9452 resolved[ plural ] :
9453 resolved._;
9454 }
9455
9456 return resolved.replace( '%d', plural ); // nb: plural might be undefined,
9457 } );
9458
9459 /**
9460 * Version string for plug-ins to check compatibility. Allowed format is
9461 * `a.b.c-d` where: a:int, b:int, c:int, d:string(dev|beta|alpha). `d` is used
9462 * only for non-release builds. See http://semver.org/ for more information.
9463 * @member
9464 * @type string
9465 * @default Version number
9466 */
9467 DataTable.version = "1.10.18";
9468
9469 /**
9470 * Private data store, containing all of the settings objects that are
9471 * created for the tables on a given page.
9472 *
9473 * Note that the `DataTable.settings` object is aliased to
9474 * `jQuery.fn.dataTableExt` through which it may be accessed and
9475 * manipulated, or `jQuery.fn.dataTable.settings`.
9476 * @member
9477 * @type array
9478 * @default []
9479 * @private
9480 */
9481 DataTable.settings = [];
9482
9483 /**
9484 * Object models container, for the various models that DataTables has
9485 * available to it. These models define the objects that are used to hold
9486 * the active state and configuration of the table.
9487 * @namespace
9488 */
9489 DataTable.models = {};
9490
9491
9492
9493 /**
9494 * Template object for the way in which DataTables holds information about
9495 * search information for the global filter and individual column filters.
9496 * @namespace
9497 */
9498 DataTable.models.oSearch = {
9499 /**
9500 * Flag to indicate if the filtering should be case insensitive or not
9501 * @type boolean
9502 * @default true
9503 */
9504 "bCaseInsensitive": true,
9505
9506 /**
9507 * Applied search term
9508 * @type string
9509 * @default <i>Empty string</i>
9510 */
9511 "sSearch": "",
9512
9513 /**
9514 * Flag to indicate if the search term should be interpreted as a
9515 * regular expression (true) or not (false) and therefore and special
9516 * regex characters escaped.
9517 * @type boolean
9518 * @default false
9519 */
9520 "bRegex": false,
9521
9522 /**
9523 * Flag to indicate if DataTables is to use its smart filtering or not.
9524 * @type boolean
9525 * @default true
9526 */
9527 "bSmart": true
9528 };
9529
9530
9531
9532
9533 /**
9534 * Template object for the way in which DataTables holds information about
9535 * each individual row. This is the object format used for the settings
9536 * aoData array.
9537 * @namespace
9538 */
9539 DataTable.models.oRow = {
9540 /**
9541 * TR element for the row
9542 * @type node
9543 * @default null
9544 */
9545 "nTr": null,
9546
9547 /**
9548 * Array of TD elements for each row. This is null until the row has been
9549 * created.
9550 * @type array nodes
9551 * @default []
9552 */
9553 "anCells": null,
9554
9555 /**
9556 * Data object from the original data source for the row. This is either
9557 * an array if using the traditional form of DataTables, or an object if
9558 * using mData options. The exact type will depend on the passed in
9559 * data from the data source, or will be an array if using DOM a data
9560 * source.
9561 * @type array|object
9562 * @default []
9563 */
9564 "_aData": [],
9565
9566 /**
9567 * Sorting data cache - this array is ostensibly the same length as the
9568 * number of columns (although each index is generated only as it is
9569 * needed), and holds the data that is used for sorting each column in the
9570 * row. We do this cache generation at the start of the sort in order that
9571 * the formatting of the sort data need be done only once for each cell
9572 * per sort. This array should not be read from or written to by anything
9573 * other than the master sorting methods.
9574 * @type array
9575 * @default null
9576 * @private
9577 */
9578 "_aSortData": null,
9579
9580 /**
9581 * Per cell filtering data cache. As per the sort data cache, used to
9582 * increase the performance of the filtering in DataTables
9583 * @type array
9584 * @default null
9585 * @private
9586 */
9587 "_aFilterData": null,
9588
9589 /**
9590 * Filtering data cache. This is the same as the cell filtering cache, but
9591 * in this case a string rather than an array. This is easily computed with
9592 * a join on `_aFilterData`, but is provided as a cache so the join isn't
9593 * needed on every search (memory traded for performance)
9594 * @type array
9595 * @default null
9596 * @private
9597 */
9598 "_sFilterRow": null,
9599
9600 /**
9601 * Cache of the class name that DataTables has applied to the row, so we
9602 * can quickly look at this variable rather than needing to do a DOM check
9603 * on className for the nTr property.
9604 * @type string
9605 * @default <i>Empty string</i>
9606 * @private
9607 */
9608 "_sRowStripe": "",
9609
9610 /**
9611 * Denote if the original data source was from the DOM, or the data source
9612 * object. This is used for invalidating data, so DataTables can
9613 * automatically read data from the original source, unless uninstructed
9614 * otherwise.
9615 * @type string
9616 * @default null
9617 * @private
9618 */
9619 "src": null,
9620
9621 /**
9622 * Index in the aoData array. This saves an indexOf lookup when we have the
9623 * object, but want to know the index
9624 * @type integer
9625 * @default -1
9626 * @private
9627 */
9628 "idx": -1
9629 };
9630
9631
9632 /**
9633 * Template object for the column information object in DataTables. This object
9634 * is held in the settings aoColumns array and contains all the information that
9635 * DataTables needs about each individual column.
9636 *
9637 * Note that this object is related to {@link DataTable.defaults.column}
9638 * but this one is the internal data store for DataTables's cache of columns.
9639 * It should NOT be manipulated outside of DataTables. Any configuration should
9640 * be done through the initialisation options.
9641 * @namespace
9642 */
9643 DataTable.models.oColumn = {
9644 /**
9645 * Column index. This could be worked out on-the-fly with $.inArray, but it
9646 * is faster to just hold it as a variable
9647 * @type integer
9648 * @default null
9649 */
9650 "idx": null,
9651
9652 /**
9653 * A list of the columns that sorting should occur on when this column
9654 * is sorted. That this property is an array allows multi-column sorting
9655 * to be defined for a column (for example first name / last name columns
9656 * would benefit from this). The values are integers pointing to the
9657 * columns to be sorted on (typically it will be a single integer pointing
9658 * at itself, but that doesn't need to be the case).
9659 * @type array
9660 */
9661 "aDataSort": null,
9662
9663 /**
9664 * Define the sorting directions that are applied to the column, in sequence
9665 * as the column is repeatedly sorted upon - i.e. the first value is used
9666 * as the sorting direction when the column if first sorted (clicked on).
9667 * Sort it again (click again) and it will move on to the next index.
9668 * Repeat until loop.
9669 * @type array
9670 */
9671 "asSorting": null,
9672
9673 /**
9674 * Flag to indicate if the column is searchable, and thus should be included
9675 * in the filtering or not.
9676 * @type boolean
9677 */
9678 "bSearchable": null,
9679
9680 /**
9681 * Flag to indicate if the column is sortable or not.
9682 * @type boolean
9683 */
9684 "bSortable": null,
9685
9686 /**
9687 * Flag to indicate if the column is currently visible in the table or not
9688 * @type boolean
9689 */
9690 "bVisible": null,
9691
9692 /**
9693 * Store for manual type assignment using the `column.type` option. This
9694 * is held in store so we can manipulate the column's `sType` property.
9695 * @type string
9696 * @default null
9697 * @private
9698 */
9699 "_sManualType": null,
9700
9701 /**
9702 * Flag to indicate if HTML5 data attributes should be used as the data
9703 * source for filtering or sorting. True is either are.
9704 * @type boolean
9705 * @default false
9706 * @private
9707 */
9708 "_bAttrSrc": false,
9709
9710 /**
9711 * Developer definable function that is called whenever a cell is created (Ajax source,
9712 * etc) or processed for input (DOM source). This can be used as a compliment to mRender
9713 * allowing you to modify the DOM element (add background colour for example) when the
9714 * element is available.
9715 * @type function
9716 * @param {element} nTd The TD node that has been created
9717 * @param {*} sData The Data for the cell
9718 * @param {array|object} oData The data for the whole row
9719 * @param {int} iRow The row index for the aoData data store
9720 * @default null
9721 */
9722 "fnCreatedCell": null,
9723
9724 /**
9725 * Function to get data from a cell in a column. You should <b>never</b>
9726 * access data directly through _aData internally in DataTables - always use
9727 * the method attached to this property. It allows mData to function as
9728 * required. This function is automatically assigned by the column
9729 * initialisation method
9730 * @type function
9731 * @param {array|object} oData The data array/object for the array
9732 * (i.e. aoData[]._aData)
9733 * @param {string} sSpecific The specific data type you want to get -
9734 * 'display', 'type' 'filter' 'sort'
9735 * @returns {*} The data for the cell from the given row's data
9736 * @default null
9737 */
9738 "fnGetData": null,
9739
9740 /**
9741 * Function to set data for a cell in the column. You should <b>never</b>
9742 * set the data directly to _aData internally in DataTables - always use
9743 * this method. It allows mData to function as required. This function
9744 * is automatically assigned by the column initialisation method
9745 * @type function
9746 * @param {array|object} oData The data array/object for the array
9747 * (i.e. aoData[]._aData)
9748 * @param {*} sValue Value to set
9749 * @default null
9750 */
9751 "fnSetData": null,
9752
9753 /**
9754 * Property to read the value for the cells in the column from the data
9755 * source array / object. If null, then the default content is used, if a
9756 * function is given then the return from the function is used.
9757 * @type function|int|string|null
9758 * @default null
9759 */
9760 "mData": null,
9761
9762 /**
9763 * Partner property to mData which is used (only when defined) to get
9764 * the data - i.e. it is basically the same as mData, but without the
9765 * 'set' option, and also the data fed to it is the result from mData.
9766 * This is the rendering method to match the data method of mData.
9767 * @type function|int|string|null
9768 * @default null
9769 */
9770 "mRender": null,
9771
9772 /**
9773 * Unique header TH/TD element for this column - this is what the sorting
9774 * listener is attached to (if sorting is enabled.)
9775 * @type node
9776 * @default null
9777 */
9778 "nTh": null,
9779
9780 /**
9781 * Unique footer TH/TD element for this column (if there is one). Not used
9782 * in DataTables as such, but can be used for plug-ins to reference the
9783 * footer for each column.
9784 * @type node
9785 * @default null
9786 */
9787 "nTf": null,
9788
9789 /**
9790 * The class to apply to all TD elements in the table's TBODY for the column
9791 * @type string
9792 * @default null
9793 */
9794 "sClass": null,
9795
9796 /**
9797 * When DataTables calculates the column widths to assign to each column,
9798 * it finds the longest string in each column and then constructs a
9799 * temporary table and reads the widths from that. The problem with this
9800 * is that "mmm" is much wider then "iiii", but the latter is a longer
9801 * string - thus the calculation can go wrong (doing it properly and putting
9802 * it into an DOM object and measuring that is horribly(!) slow). Thus as
9803 * a "work around" we provide this option. It will append its value to the
9804 * text that is found to be the longest string for the column - i.e. padding.
9805 * @type string
9806 */
9807 "sContentPadding": null,
9808
9809 /**
9810 * Allows a default value to be given for a column's data, and will be used
9811 * whenever a null data source is encountered (this can be because mData
9812 * is set to null, or because the data source itself is null).
9813 * @type string
9814 * @default null
9815 */
9816 "sDefaultContent": null,
9817
9818 /**
9819 * Name for the column, allowing reference to the column by name as well as
9820 * by index (needs a lookup to work by name).
9821 * @type string
9822 */
9823 "sName": null,
9824
9825 /**
9826 * Custom sorting data type - defines which of the available plug-ins in
9827 * afnSortData the custom sorting will use - if any is defined.
9828 * @type string
9829 * @default std
9830 */
9831 "sSortDataType": 'std',
9832
9833 /**
9834 * Class to be applied to the header element when sorting on this column
9835 * @type string
9836 * @default null
9837 */
9838 "sSortingClass": null,
9839
9840 /**
9841 * Class to be applied to the header element when sorting on this column -
9842 * when jQuery UI theming is used.
9843 * @type string
9844 * @default null
9845 */
9846 "sSortingClassJUI": null,
9847
9848 /**
9849 * Title of the column - what is seen in the TH element (nTh).
9850 * @type string
9851 */
9852 "sTitle": null,
9853
9854 /**
9855 * Column sorting and filtering type
9856 * @type string
9857 * @default null
9858 */
9859 "sType": null,
9860
9861 /**
9862 * Width of the column
9863 * @type string
9864 * @default null
9865 */
9866 "sWidth": null,
9867
9868 /**
9869 * Width of the column when it was first "encountered"
9870 * @type string
9871 * @default null
9872 */
9873 "sWidthOrig": null
9874 };
9875
9876
9877 /*
9878 * Developer note: The properties of the object below are given in Hungarian
9879 * notation, that was used as the interface for DataTables prior to v1.10, however
9880 * from v1.10 onwards the primary interface is camel case. In order to avoid
9881 * breaking backwards compatibility utterly with this change, the Hungarian
9882 * version is still, internally the primary interface, but is is not documented
9883 * - hence the @name tags in each doc comment. This allows a Javascript function
9884 * to create a map from Hungarian notation to camel case (going the other direction
9885 * would require each property to be listed, which would at around 3K to the size
9886 * of DataTables, while this method is about a 0.5K hit.
9887 *
9888 * Ultimately this does pave the way for Hungarian notation to be dropped
9889 * completely, but that is a massive amount of work and will break current
9890 * installs (therefore is on-hold until v2).
9891 */
9892
9893 /**
9894 * Initialisation options that can be given to DataTables at initialisation
9895 * time.
9896 * @namespace
9897 */
9898 DataTable.defaults = {
9899 /**
9900 * An array of data to use for the table, passed in at initialisation which
9901 * will be used in preference to any data which is already in the DOM. This is
9902 * particularly useful for constructing tables purely in Javascript, for
9903 * example with a custom Ajax call.
9904 * @type array
9905 * @default null
9906 *
9907 * @dtopt Option
9908 * @name DataTable.defaults.data
9909 *
9910 * @example
9911 * // Using a 2D array data source
9912 * $(document).ready( function () {
9913 * $('#example').dataTable( {
9914 * "data": [
9915 * ['Trident', 'Internet Explorer 4.0', 'Win 95+', 4, 'X'],
9916 * ['Trident', 'Internet Explorer 5.0', 'Win 95+', 5, 'C'],
9917 * ],
9918 * "columns": [
9919 * { "title": "Engine" },
9920 * { "title": "Browser" },
9921 * { "title": "Platform" },
9922 * { "title": "Version" },
9923 * { "title": "Grade" }
9924 * ]
9925 * } );
9926 * } );
9927 *
9928 * @example
9929 * // Using an array of objects as a data source (`data`)
9930 * $(document).ready( function () {
9931 * $('#example').dataTable( {
9932 * "data": [
9933 * {
9934 * "engine": "Trident",
9935 * "browser": "Internet Explorer 4.0",
9936 * "platform": "Win 95+",
9937 * "version": 4,
9938 * "grade": "X"
9939 * },
9940 * {
9941 * "engine": "Trident",
9942 * "browser": "Internet Explorer 5.0",
9943 * "platform": "Win 95+",
9944 * "version": 5,
9945 * "grade": "C"
9946 * }
9947 * ],
9948 * "columns": [
9949 * { "title": "Engine", "data": "engine" },
9950 * { "title": "Browser", "data": "browser" },
9951 * { "title": "Platform", "data": "platform" },
9952 * { "title": "Version", "data": "version" },
9953 * { "title": "Grade", "data": "grade" }
9954 * ]
9955 * } );
9956 * } );
9957 */
9958 "aaData": null,
9959
9960
9961 /**
9962 * If ordering is enabled, then DataTables will perform a first pass sort on
9963 * initialisation. You can define which column(s) the sort is performed
9964 * upon, and the sorting direction, with this variable. The `sorting` array
9965 * should contain an array for each column to be sorted initially containing
9966 * the column's index and a direction string ('asc' or 'desc').
9967 * @type array
9968 * @default [[0,'asc']]
9969 *
9970 * @dtopt Option
9971 * @name DataTable.defaults.order
9972 *
9973 * @example
9974 * // Sort by 3rd column first, and then 4th column
9975 * $(document).ready( function() {
9976 * $('#example').dataTable( {
9977 * "order": [[2,'asc'], [3,'desc']]
9978 * } );
9979 * } );
9980 *
9981 * // No initial sorting
9982 * $(document).ready( function() {
9983 * $('#example').dataTable( {
9984 * "order": []
9985 * } );
9986 * } );
9987 */
9988 "aaSorting": [[0,'asc']],
9989
9990
9991 /**
9992 * This parameter is basically identical to the `sorting` parameter, but
9993 * cannot be overridden by user interaction with the table. What this means
9994 * is that you could have a column (visible or hidden) which the sorting
9995 * will always be forced on first - any sorting after that (from the user)
9996 * will then be performed as required. This can be useful for grouping rows
9997 * together.
9998 * @type array
9999 * @default null
10000 *
10001 * @dtopt Option
10002 * @name DataTable.defaults.orderFixed
10003 *
10004 * @example
10005 * $(document).ready( function() {
10006 * $('#example').dataTable( {
10007 * "orderFixed": [[0,'asc']]
10008 * } );
10009 * } )
10010 */
10011 "aaSortingFixed": [],
10012
10013
10014 /**
10015 * DataTables can be instructed to load data to display in the table from a
10016 * Ajax source. This option defines how that Ajax call is made and where to.
10017 *
10018 * The `ajax` property has three different modes of operation, depending on
10019 * how it is defined. These are:
10020 *
10021 * * `string` - Set the URL from where the data should be loaded from.
10022 * * `object` - Define properties for `jQuery.ajax`.
10023 * * `function` - Custom data get function
10024 *
10025 * `string`
10026 * --------
10027 *
10028 * As a string, the `ajax` property simply defines the URL from which
10029 * DataTables will load data.
10030 *
10031 * `object`
10032 * --------
10033 *
10034 * As an object, the parameters in the object are passed to
10035 * [jQuery.ajax](http://api.jquery.com/jQuery.ajax/) allowing fine control
10036 * of the Ajax request. DataTables has a number of default parameters which
10037 * you can override using this option. Please refer to the jQuery
10038 * documentation for a full description of the options available, although
10039 * the following parameters provide additional options in DataTables or
10040 * require special consideration:
10041 *
10042 * * `data` - As with jQuery, `data` can be provided as an object, but it
10043 * can also be used as a function to manipulate the data DataTables sends
10044 * to the server. The function takes a single parameter, an object of
10045 * parameters with the values that DataTables has readied for sending. An
10046 * object may be returned which will be merged into the DataTables
10047 * defaults, or you can add the items to the object that was passed in and
10048 * not return anything from the function. This supersedes `fnServerParams`
10049 * from DataTables 1.9-.
10050 *
10051 * * `dataSrc` - By default DataTables will look for the property `data` (or
10052 * `aaData` for compatibility with DataTables 1.9-) when obtaining data
10053 * from an Ajax source or for server-side processing - this parameter
10054 * allows that property to be changed. You can use Javascript dotted
10055 * object notation to get a data source for multiple levels of nesting, or
10056 * it my be used as a function. As a function it takes a single parameter,
10057 * the JSON returned from the server, which can be manipulated as
10058 * required, with the returned value being that used by DataTables as the
10059 * data source for the table. This supersedes `sAjaxDataProp` from
10060 * DataTables 1.9-.
10061 *
10062 * * `success` - Should not be overridden it is used internally in
10063 * DataTables. To manipulate / transform the data returned by the server
10064 * use `ajax.dataSrc`, or use `ajax` as a function (see below).
10065 *
10066 * `function`
10067 * ----------
10068 *
10069 * As a function, making the Ajax call is left up to yourself allowing
10070 * complete control of the Ajax request. Indeed, if desired, a method other
10071 * than Ajax could be used to obtain the required data, such as Web storage
10072 * or an AIR database.
10073 *
10074 * The function is given four parameters and no return is required. The
10075 * parameters are:
10076 *
10077 * 1. _object_ - Data to send to the server
10078 * 2. _function_ - Callback function that must be executed when the required
10079 * data has been obtained. That data should be passed into the callback
10080 * as the only parameter
10081 * 3. _object_ - DataTables settings object for the table
10082 *
10083 * Note that this supersedes `fnServerData` from DataTables 1.9-.
10084 *
10085 * @type string|object|function
10086 * @default null
10087 *
10088 * @dtopt Option
10089 * @name DataTable.defaults.ajax
10090 * @since 1.10.0
10091 *
10092 * @example
10093 * // Get JSON data from a file via Ajax.
10094 * // Note DataTables expects data in the form `{ data: [ ...data... ] }` by default).
10095 * $('#example').dataTable( {
10096 * "ajax": "data.json"
10097 * } );
10098 *
10099 * @example
10100 * // Get JSON data from a file via Ajax, using `dataSrc` to change
10101 * // `data` to `tableData` (i.e. `{ tableData: [ ...data... ] }`)
10102 * $('#example').dataTable( {
10103 * "ajax": {
10104 * "url": "data.json",
10105 * "dataSrc": "tableData"
10106 * }
10107 * } );
10108 *
10109 * @example
10110 * // Get JSON data from a file via Ajax, using `dataSrc` to read data
10111 * // from a plain array rather than an array in an object
10112 * $('#example').dataTable( {
10113 * "ajax": {
10114 * "url": "data.json",
10115 * "dataSrc": ""
10116 * }
10117 * } );
10118 *
10119 * @example
10120 * // Manipulate the data returned from the server - add a link to data
10121 * // (note this can, should, be done using `render` for the column - this
10122 * // is just a simple example of how the data can be manipulated).
10123 * $('#example').dataTable( {
10124 * "ajax": {
10125 * "url": "data.json",
10126 * "dataSrc": function ( json ) {
10127 * for ( var i=0, ien=json.length ; i<ien ; i++ ) {
10128 * json[i][0] = '<a href="/message/'+json[i][0]+'>View message</a>';
10129 * }
10130 * return json;
10131 * }
10132 * }
10133 * } );
10134 *
10135 * @example
10136 * // Add data to the request
10137 * $('#example').dataTable( {
10138 * "ajax": {
10139 * "url": "data.json",
10140 * "data": function ( d ) {
10141 * return {
10142 * "extra_search": $('#extra').val()
10143 * };
10144 * }
10145 * }
10146 * } );
10147 *
10148 * @example
10149 * // Send request as POST
10150 * $('#example').dataTable( {
10151 * "ajax": {
10152 * "url": "data.json",
10153 * "type": "POST"
10154 * }
10155 * } );
10156 *
10157 * @example
10158 * // Get the data from localStorage (could interface with a form for
10159 * // adding, editing and removing rows).
10160 * $('#example').dataTable( {
10161 * "ajax": function (data, callback, settings) {
10162 * callback(
10163 * JSON.parse( localStorage.getItem('dataTablesData') )
10164 * );
10165 * }
10166 * } );
10167 */
10168 "ajax": null,
10169
10170
10171 /**
10172 * This parameter allows you to readily specify the entries in the length drop
10173 * down menu that DataTables shows when pagination is enabled. It can be
10174 * either a 1D array of options which will be used for both the displayed
10175 * option and the value, or a 2D array which will use the array in the first
10176 * position as the value, and the array in the second position as the
10177 * displayed options (useful for language strings such as 'All').
10178 *
10179 * Note that the `pageLength` property will be automatically set to the
10180 * first value given in this array, unless `pageLength` is also provided.
10181 * @type array
10182 * @default [ 10, 25, 50, 100 ]
10183 *
10184 * @dtopt Option
10185 * @name DataTable.defaults.lengthMenu
10186 *
10187 * @example
10188 * $(document).ready( function() {
10189 * $('#example').dataTable( {
10190 * "lengthMenu": [[10, 25, 50, -1], [10, 25, 50, "All"]]
10191 * } );
10192 * } );
10193 */
10194 "aLengthMenu": [ 10, 25, 50, 100 ],
10195
10196
10197 /**
10198 * The `columns` option in the initialisation parameter allows you to define
10199 * details about the way individual columns behave. For a full list of
10200 * column options that can be set, please see
10201 * {@link DataTable.defaults.column}. Note that if you use `columns` to
10202 * define your columns, you must have an entry in the array for every single
10203 * column that you have in your table (these can be null if you don't which
10204 * to specify any options).
10205 * @member
10206 *
10207 * @name DataTable.defaults.column
10208 */
10209 "aoColumns": null,
10210
10211 /**
10212 * Very similar to `columns`, `columnDefs` allows you to target a specific
10213 * column, multiple columns, or all columns, using the `targets` property of
10214 * each object in the array. This allows great flexibility when creating
10215 * tables, as the `columnDefs` arrays can be of any length, targeting the
10216 * columns you specifically want. `columnDefs` may use any of the column
10217 * options available: {@link DataTable.defaults.column}, but it _must_
10218 * have `targets` defined in each object in the array. Values in the `targets`
10219 * array may be:
10220 * <ul>
10221 * <li>a string - class name will be matched on the TH for the column</li>
10222 * <li>0 or a positive integer - column index counting from the left</li>
10223 * <li>a negative integer - column index counting from the right</li>
10224 * <li>the string "_all" - all columns (i.e. assign a default)</li>
10225 * </ul>
10226 * @member
10227 *
10228 * @name DataTable.defaults.columnDefs
10229 */
10230 "aoColumnDefs": null,
10231
10232
10233 /**
10234 * Basically the same as `search`, this parameter defines the individual column
10235 * filtering state at initialisation time. The array must be of the same size
10236 * as the number of columns, and each element be an object with the parameters
10237 * `search` and `escapeRegex` (the latter is optional). 'null' is also
10238 * accepted and the default will be used.
10239 * @type array
10240 * @default []
10241 *
10242 * @dtopt Option
10243 * @name DataTable.defaults.searchCols
10244 *
10245 * @example
10246 * $(document).ready( function() {
10247 * $('#example').dataTable( {
10248 * "searchCols": [
10249 * null,
10250 * { "search": "My filter" },
10251 * null,
10252 * { "search": "^[0-9]", "escapeRegex": false }
10253 * ]
10254 * } );
10255 * } )
10256 */
10257 "aoSearchCols": [],
10258
10259
10260 /**
10261 * An array of CSS classes that should be applied to displayed rows. This
10262 * array may be of any length, and DataTables will apply each class
10263 * sequentially, looping when required.
10264 * @type array
10265 * @default null <i>Will take the values determined by the `oClasses.stripe*`
10266 * options</i>
10267 *
10268 * @dtopt Option
10269 * @name DataTable.defaults.stripeClasses
10270 *
10271 * @example
10272 * $(document).ready( function() {
10273 * $('#example').dataTable( {
10274 * "stripeClasses": [ 'strip1', 'strip2', 'strip3' ]
10275 * } );
10276 * } )
10277 */
10278 "asStripeClasses": null,
10279
10280
10281 /**
10282 * Enable or disable automatic column width calculation. This can be disabled
10283 * as an optimisation (it takes some time to calculate the widths) if the
10284 * tables widths are passed in using `columns`.
10285 * @type boolean
10286 * @default true
10287 *
10288 * @dtopt Features
10289 * @name DataTable.defaults.autoWidth
10290 *
10291 * @example
10292 * $(document).ready( function () {
10293 * $('#example').dataTable( {
10294 * "autoWidth": false
10295 * } );
10296 * } );
10297 */
10298 "bAutoWidth": true,
10299
10300
10301 /**
10302 * Deferred rendering can provide DataTables with a huge speed boost when you
10303 * are using an Ajax or JS data source for the table. This option, when set to
10304 * true, will cause DataTables to defer the creation of the table elements for
10305 * each row until they are needed for a draw - saving a significant amount of
10306 * time.
10307 * @type boolean
10308 * @default false
10309 *
10310 * @dtopt Features
10311 * @name DataTable.defaults.deferRender
10312 *
10313 * @example
10314 * $(document).ready( function() {
10315 * $('#example').dataTable( {
10316 * "ajax": "sources/arrays.txt",
10317 * "deferRender": true
10318 * } );
10319 * } );
10320 */
10321 "bDeferRender": false,
10322
10323
10324 /**
10325 * Replace a DataTable which matches the given selector and replace it with
10326 * one which has the properties of the new initialisation object passed. If no
10327 * table matches the selector, then the new DataTable will be constructed as
10328 * per normal.
10329 * @type boolean
10330 * @default false
10331 *
10332 * @dtopt Options
10333 * @name DataTable.defaults.destroy
10334 *
10335 * @example
10336 * $(document).ready( function() {
10337 * $('#example').dataTable( {
10338 * "srollY": "200px",
10339 * "paginate": false
10340 * } );
10341 *
10342 * // Some time later....
10343 * $('#example').dataTable( {
10344 * "filter": false,
10345 * "destroy": true
10346 * } );
10347 * } );
10348 */
10349 "bDestroy": false,
10350
10351
10352 /**
10353 * Enable or disable filtering of data. Filtering in DataTables is "smart" in
10354 * that it allows the end user to input multiple words (space separated) and
10355 * will match a row containing those words, even if not in the order that was
10356 * specified (this allow matching across multiple columns). Note that if you
10357 * wish to use filtering in DataTables this must remain 'true' - to remove the
10358 * default filtering input box and retain filtering abilities, please use
10359 * {@link DataTable.defaults.dom}.
10360 * @type boolean
10361 * @default true
10362 *
10363 * @dtopt Features
10364 * @name DataTable.defaults.searching
10365 *
10366 * @example
10367 * $(document).ready( function () {
10368 * $('#example').dataTable( {
10369 * "searching": false
10370 * } );
10371 * } );
10372 */
10373 "bFilter": true,
10374
10375
10376 /**
10377 * Enable or disable the table information display. This shows information
10378 * about the data that is currently visible on the page, including information
10379 * about filtered data if that action is being performed.
10380 * @type boolean
10381 * @default true
10382 *
10383 * @dtopt Features
10384 * @name DataTable.defaults.info
10385 *
10386 * @example
10387 * $(document).ready( function () {
10388 * $('#example').dataTable( {
10389 * "info": false
10390 * } );
10391 * } );
10392 */
10393 "bInfo": true,
10394
10395
10396 /**
10397 * Allows the end user to select the size of a formatted page from a select
10398 * menu (sizes are 10, 25, 50 and 100). Requires pagination (`paginate`).
10399 * @type boolean
10400 * @default true
10401 *
10402 * @dtopt Features
10403 * @name DataTable.defaults.lengthChange
10404 *
10405 * @example
10406 * $(document).ready( function () {
10407 * $('#example').dataTable( {
10408 * "lengthChange": false
10409 * } );
10410 * } );
10411 */
10412 "bLengthChange": true,
10413
10414
10415 /**
10416 * Enable or disable pagination.
10417 * @type boolean
10418 * @default true
10419 *
10420 * @dtopt Features
10421 * @name DataTable.defaults.paging
10422 *
10423 * @example
10424 * $(document).ready( function () {
10425 * $('#example').dataTable( {
10426 * "paging": false
10427 * } );
10428 * } );
10429 */
10430 "bPaginate": true,
10431
10432
10433 /**
10434 * Enable or disable the display of a 'processing' indicator when the table is
10435 * being processed (e.g. a sort). This is particularly useful for tables with
10436 * large amounts of data where it can take a noticeable amount of time to sort
10437 * the entries.
10438 * @type boolean
10439 * @default false
10440 *
10441 * @dtopt Features
10442 * @name DataTable.defaults.processing
10443 *
10444 * @example
10445 * $(document).ready( function () {
10446 * $('#example').dataTable( {
10447 * "processing": true
10448 * } );
10449 * } );
10450 */
10451 "bProcessing": false,
10452
10453
10454 /**
10455 * Retrieve the DataTables object for the given selector. Note that if the
10456 * table has already been initialised, this parameter will cause DataTables
10457 * to simply return the object that has already been set up - it will not take
10458 * account of any changes you might have made to the initialisation object
10459 * passed to DataTables (setting this parameter to true is an acknowledgement
10460 * that you understand this). `destroy` can be used to reinitialise a table if
10461 * you need.
10462 * @type boolean
10463 * @default false
10464 *
10465 * @dtopt Options
10466 * @name DataTable.defaults.retrieve
10467 *
10468 * @example
10469 * $(document).ready( function() {
10470 * initTable();
10471 * tableActions();
10472 * } );
10473 *
10474 * function initTable ()
10475 * {
10476 * return $('#example').dataTable( {
10477 * "scrollY": "200px",
10478 * "paginate": false,
10479 * "retrieve": true
10480 * } );
10481 * }
10482 *
10483 * function tableActions ()
10484 * {
10485 * var table = initTable();
10486 * // perform API operations with oTable
10487 * }
10488 */
10489 "bRetrieve": false,
10490
10491
10492 /**
10493 * When vertical (y) scrolling is enabled, DataTables will force the height of
10494 * the table's viewport to the given height at all times (useful for layout).
10495 * However, this can look odd when filtering data down to a small data set,
10496 * and the footer is left "floating" further down. This parameter (when
10497 * enabled) will cause DataTables to collapse the table's viewport down when
10498 * the result set will fit within the given Y height.
10499 * @type boolean
10500 * @default false
10501 *
10502 * @dtopt Options
10503 * @name DataTable.defaults.scrollCollapse
10504 *
10505 * @example
10506 * $(document).ready( function() {
10507 * $('#example').dataTable( {
10508 * "scrollY": "200",
10509 * "scrollCollapse": true
10510 * } );
10511 * } );
10512 */
10513 "bScrollCollapse": false,
10514
10515
10516 /**
10517 * Configure DataTables to use server-side processing. Note that the
10518 * `ajax` parameter must also be given in order to give DataTables a
10519 * source to obtain the required data for each draw.
10520 * @type boolean
10521 * @default false
10522 *
10523 * @dtopt Features
10524 * @dtopt Server-side
10525 * @name DataTable.defaults.serverSide
10526 *
10527 * @example
10528 * $(document).ready( function () {
10529 * $('#example').dataTable( {
10530 * "serverSide": true,
10531 * "ajax": "xhr.php"
10532 * } );
10533 * } );
10534 */
10535 "bServerSide": false,
10536
10537
10538 /**
10539 * Enable or disable sorting of columns. Sorting of individual columns can be
10540 * disabled by the `sortable` option for each column.
10541 * @type boolean
10542 * @default true
10543 *
10544 * @dtopt Features
10545 * @name DataTable.defaults.ordering
10546 *
10547 * @example
10548 * $(document).ready( function () {
10549 * $('#example').dataTable( {
10550 * "ordering": false
10551 * } );
10552 * } );
10553 */
10554 "bSort": true,
10555
10556
10557 /**
10558 * Enable or display DataTables' ability to sort multiple columns at the
10559 * same time (activated by shift-click by the user).
10560 * @type boolean
10561 * @default true
10562 *
10563 * @dtopt Options
10564 * @name DataTable.defaults.orderMulti
10565 *
10566 * @example
10567 * // Disable multiple column sorting ability
10568 * $(document).ready( function () {
10569 * $('#example').dataTable( {
10570 * "orderMulti": false
10571 * } );
10572 * } );
10573 */
10574 "bSortMulti": true,
10575
10576
10577 /**
10578 * Allows control over whether DataTables should use the top (true) unique
10579 * cell that is found for a single column, or the bottom (false - default).
10580 * This is useful when using complex headers.
10581 * @type boolean
10582 * @default false
10583 *
10584 * @dtopt Options
10585 * @name DataTable.defaults.orderCellsTop
10586 *
10587 * @example
10588 * $(document).ready( function() {
10589 * $('#example').dataTable( {
10590 * "orderCellsTop": true
10591 * } );
10592 * } );
10593 */
10594 "bSortCellsTop": false,
10595
10596
10597 /**
10598 * Enable or disable the addition of the classes `sorting\_1`, `sorting\_2` and
10599 * `sorting\_3` to the columns which are currently being sorted on. This is
10600 * presented as a feature switch as it can increase processing time (while
10601 * classes are removed and added) so for large data sets you might want to
10602 * turn this off.
10603 * @type boolean
10604 * @default true
10605 *
10606 * @dtopt Features
10607 * @name DataTable.defaults.orderClasses
10608 *
10609 * @example
10610 * $(document).ready( function () {
10611 * $('#example').dataTable( {
10612 * "orderClasses": false
10613 * } );
10614 * } );
10615 */
10616 "bSortClasses": true,
10617
10618
10619 /**
10620 * Enable or disable state saving. When enabled HTML5 `localStorage` will be
10621 * used to save table display information such as pagination information,
10622 * display length, filtering and sorting. As such when the end user reloads
10623 * the page the display display will match what thy had previously set up.
10624 *
10625 * Due to the use of `localStorage` the default state saving is not supported
10626 * in IE6 or 7. If state saving is required in those browsers, use
10627 * `stateSaveCallback` to provide a storage solution such as cookies.
10628 * @type boolean
10629 * @default false
10630 *
10631 * @dtopt Features
10632 * @name DataTable.defaults.stateSave
10633 *
10634 * @example
10635 * $(document).ready( function () {
10636 * $('#example').dataTable( {
10637 * "stateSave": true
10638 * } );
10639 * } );
10640 */
10641 "bStateSave": false,
10642
10643
10644 /**
10645 * This function is called when a TR element is created (and all TD child
10646 * elements have been inserted), or registered if using a DOM source, allowing
10647 * manipulation of the TR element (adding classes etc).
10648 * @type function
10649 * @param {node} row "TR" element for the current row
10650 * @param {array} data Raw data array for this row
10651 * @param {int} dataIndex The index of this row in the internal aoData array
10652 *
10653 * @dtopt Callbacks
10654 * @name DataTable.defaults.createdRow
10655 *
10656 * @example
10657 * $(document).ready( function() {
10658 * $('#example').dataTable( {
10659 * "createdRow": function( row, data, dataIndex ) {
10660 * // Bold the grade for all 'A' grade browsers
10661 * if ( data[4] == "A" )
10662 * {
10663 * $('td:eq(4)', row).html( '<b>A</b>' );
10664 * }
10665 * }
10666 * } );
10667 * } );
10668 */
10669 "fnCreatedRow": null,
10670
10671
10672 /**
10673 * This function is called on every 'draw' event, and allows you to
10674 * dynamically modify any aspect you want about the created DOM.
10675 * @type function
10676 * @param {object} settings DataTables settings object
10677 *
10678 * @dtopt Callbacks
10679 * @name DataTable.defaults.drawCallback
10680 *
10681 * @example
10682 * $(document).ready( function() {
10683 * $('#example').dataTable( {
10684 * "drawCallback": function( settings ) {
10685 * alert( 'DataTables has redrawn the table' );
10686 * }
10687 * } );
10688 * } );
10689 */
10690 "fnDrawCallback": null,
10691
10692
10693 /**
10694 * Identical to fnHeaderCallback() but for the table footer this function
10695 * allows you to modify the table footer on every 'draw' event.
10696 * @type function
10697 * @param {node} foot "TR" element for the footer
10698 * @param {array} data Full table data (as derived from the original HTML)
10699 * @param {int} start Index for the current display starting point in the
10700 * display array
10701 * @param {int} end Index for the current display ending point in the
10702 * display array
10703 * @param {array int} display Index array to translate the visual position
10704 * to the full data array
10705 *
10706 * @dtopt Callbacks
10707 * @name DataTable.defaults.footerCallback
10708 *
10709 * @example
10710 * $(document).ready( function() {
10711 * $('#example').dataTable( {
10712 * "footerCallback": function( tfoot, data, start, end, display ) {
10713 * tfoot.getElementsByTagName('th')[0].innerHTML = "Starting index is "+start;
10714 * }
10715 * } );
10716 * } )
10717 */
10718 "fnFooterCallback": null,
10719
10720
10721 /**
10722 * When rendering large numbers in the information element for the table
10723 * (i.e. "Showing 1 to 10 of 57 entries") DataTables will render large numbers
10724 * to have a comma separator for the 'thousands' units (e.g. 1 million is
10725 * rendered as "1,000,000") to help readability for the end user. This
10726 * function will override the default method DataTables uses.
10727 * @type function
10728 * @member
10729 * @param {int} toFormat number to be formatted
10730 * @returns {string} formatted string for DataTables to show the number
10731 *
10732 * @dtopt Callbacks
10733 * @name DataTable.defaults.formatNumber
10734 *
10735 * @example
10736 * // Format a number using a single quote for the separator (note that
10737 * // this can also be done with the language.thousands option)
10738 * $(document).ready( function() {
10739 * $('#example').dataTable( {
10740 * "formatNumber": function ( toFormat ) {
10741 * return toFormat.toString().replace(
10742 * /\B(?=(\d{3})+(?!\d))/g, "'"
10743 * );
10744 * };
10745 * } );
10746 * } );
10747 */
10748 "fnFormatNumber": function ( toFormat ) {
10749 return toFormat.toString().replace(
10750 /\B(?=(\d{3})+(?!\d))/g,
10751 this.oLanguage.sThousands
10752 );
10753 },
10754
10755
10756 /**
10757 * This function is called on every 'draw' event, and allows you to
10758 * dynamically modify the header row. This can be used to calculate and
10759 * display useful information about the table.
10760 * @type function
10761 * @param {node} head "TR" element for the header
10762 * @param {array} data Full table data (as derived from the original HTML)
10763 * @param {int} start Index for the current display starting point in the
10764 * display array
10765 * @param {int} end Index for the current display ending point in the
10766 * display array
10767 * @param {array int} display Index array to translate the visual position
10768 * to the full data array
10769 *
10770 * @dtopt Callbacks
10771 * @name DataTable.defaults.headerCallback
10772 *
10773 * @example
10774 * $(document).ready( function() {
10775 * $('#example').dataTable( {
10776 * "fheaderCallback": function( head, data, start, end, display ) {
10777 * head.getElementsByTagName('th')[0].innerHTML = "Displaying "+(end-start)+" records";
10778 * }
10779 * } );
10780 * } )
10781 */
10782 "fnHeaderCallback": null,
10783
10784
10785 /**
10786 * The information element can be used to convey information about the current
10787 * state of the table. Although the internationalisation options presented by
10788 * DataTables are quite capable of dealing with most customisations, there may
10789 * be times where you wish to customise the string further. This callback
10790 * allows you to do exactly that.
10791 * @type function
10792 * @param {object} oSettings DataTables settings object
10793 * @param {int} start Starting position in data for the draw
10794 * @param {int} end End position in data for the draw
10795 * @param {int} max Total number of rows in the table (regardless of
10796 * filtering)
10797 * @param {int} total Total number of rows in the data set, after filtering
10798 * @param {string} pre The string that DataTables has formatted using it's
10799 * own rules
10800 * @returns {string} The string to be displayed in the information element.
10801 *
10802 * @dtopt Callbacks
10803 * @name DataTable.defaults.infoCallback
10804 *
10805 * @example
10806 * $('#example').dataTable( {
10807 * "infoCallback": function( settings, start, end, max, total, pre ) {
10808 * return start +" to "+ end;
10809 * }
10810 * } );
10811 */
10812 "fnInfoCallback": null,
10813
10814
10815 /**
10816 * Called when the table has been initialised. Normally DataTables will
10817 * initialise sequentially and there will be no need for this function,
10818 * however, this does not hold true when using external language information
10819 * since that is obtained using an async XHR call.
10820 * @type function
10821 * @param {object} settings DataTables settings object
10822 * @param {object} json The JSON object request from the server - only
10823 * present if client-side Ajax sourced data is used
10824 *
10825 * @dtopt Callbacks
10826 * @name DataTable.defaults.initComplete
10827 *
10828 * @example
10829 * $(document).ready( function() {
10830 * $('#example').dataTable( {
10831 * "initComplete": function(settings, json) {
10832 * alert( 'DataTables has finished its initialisation.' );
10833 * }
10834 * } );
10835 * } )
10836 */
10837 "fnInitComplete": null,
10838
10839
10840 /**
10841 * Called at the very start of each table draw and can be used to cancel the
10842 * draw by returning false, any other return (including undefined) results in
10843 * the full draw occurring).
10844 * @type function
10845 * @param {object} settings DataTables settings object
10846 * @returns {boolean} False will cancel the draw, anything else (including no
10847 * return) will allow it to complete.
10848 *
10849 * @dtopt Callbacks
10850 * @name DataTable.defaults.preDrawCallback
10851 *
10852 * @example
10853 * $(document).ready( function() {
10854 * $('#example').dataTable( {
10855 * "preDrawCallback": function( settings ) {
10856 * if ( $('#test').val() == 1 ) {
10857 * return false;
10858 * }
10859 * }
10860 * } );
10861 * } );
10862 */
10863 "fnPreDrawCallback": null,
10864
10865
10866 /**
10867 * This function allows you to 'post process' each row after it have been
10868 * generated for each table draw, but before it is rendered on screen. This
10869 * function might be used for setting the row class name etc.
10870 * @type function
10871 * @param {node} row "TR" element for the current row
10872 * @param {array} data Raw data array for this row
10873 * @param {int} displayIndex The display index for the current table draw
10874 * @param {int} displayIndexFull The index of the data in the full list of
10875 * rows (after filtering)
10876 *
10877 * @dtopt Callbacks
10878 * @name DataTable.defaults.rowCallback
10879 *
10880 * @example
10881 * $(document).ready( function() {
10882 * $('#example').dataTable( {
10883 * "rowCallback": function( row, data, displayIndex, displayIndexFull ) {
10884 * // Bold the grade for all 'A' grade browsers
10885 * if ( data[4] == "A" ) {
10886 * $('td:eq(4)', row).html( '<b>A</b>' );
10887 * }
10888 * }
10889 * } );
10890 * } );
10891 */
10892 "fnRowCallback": null,
10893
10894
10895 /**
10896 * __Deprecated__ The functionality provided by this parameter has now been
10897 * superseded by that provided through `ajax`, which should be used instead.
10898 *
10899 * This parameter allows you to override the default function which obtains
10900 * the data from the server so something more suitable for your application.
10901 * For example you could use POST data, or pull information from a Gears or
10902 * AIR database.
10903 * @type function
10904 * @member
10905 * @param {string} source HTTP source to obtain the data from (`ajax`)
10906 * @param {array} data A key/value pair object containing the data to send
10907 * to the server
10908 * @param {function} callback to be called on completion of the data get
10909 * process that will draw the data on the page.
10910 * @param {object} settings DataTables settings object
10911 *
10912 * @dtopt Callbacks
10913 * @dtopt Server-side
10914 * @name DataTable.defaults.serverData
10915 *
10916 * @deprecated 1.10. Please use `ajax` for this functionality now.
10917 */
10918 "fnServerData": null,
10919
10920
10921 /**
10922 * __Deprecated__ The functionality provided by this parameter has now been
10923 * superseded by that provided through `ajax`, which should be used instead.
10924 *
10925 * It is often useful to send extra data to the server when making an Ajax
10926 * request - for example custom filtering information, and this callback
10927 * function makes it trivial to send extra information to the server. The
10928 * passed in parameter is the data set that has been constructed by
10929 * DataTables, and you can add to this or modify it as you require.
10930 * @type function
10931 * @param {array} data Data array (array of objects which are name/value
10932 * pairs) that has been constructed by DataTables and will be sent to the
10933 * server. In the case of Ajax sourced data with server-side processing
10934 * this will be an empty array, for server-side processing there will be a
10935 * significant number of parameters!
10936 * @returns {undefined} Ensure that you modify the data array passed in,
10937 * as this is passed by reference.
10938 *
10939 * @dtopt Callbacks
10940 * @dtopt Server-side
10941 * @name DataTable.defaults.serverParams
10942 *
10943 * @deprecated 1.10. Please use `ajax` for this functionality now.
10944 */
10945 "fnServerParams": null,
10946
10947
10948 /**
10949 * Load the table state. With this function you can define from where, and how, the
10950 * state of a table is loaded. By default DataTables will load from `localStorage`
10951 * but you might wish to use a server-side database or cookies.
10952 * @type function
10953 * @member
10954 * @param {object} settings DataTables settings object
10955 * @param {object} callback Callback that can be executed when done. It
10956 * should be passed the loaded state object.
10957 * @return {object} The DataTables state object to be loaded
10958 *
10959 * @dtopt Callbacks
10960 * @name DataTable.defaults.stateLoadCallback
10961 *
10962 * @example
10963 * $(document).ready( function() {
10964 * $('#example').dataTable( {
10965 * "stateSave": true,
10966 * "stateLoadCallback": function (settings, callback) {
10967 * $.ajax( {
10968 * "url": "/state_load",
10969 * "dataType": "json",
10970 * "success": function (json) {
10971 * callback( json );
10972 * }
10973 * } );
10974 * }
10975 * } );
10976 * } );
10977 */
10978 "fnStateLoadCallback": function ( settings ) {
10979 try {
10980 return JSON.parse(
10981 (settings.iStateDuration === -1 ? sessionStorage : localStorage).getItem(
10982 'DataTables_'+settings.sInstance+'_'+location.pathname
10983 )
10984 );
10985 } catch (e) {}
10986 },
10987
10988
10989 /**
10990 * Callback which allows modification of the saved state prior to loading that state.
10991 * This callback is called when the table is loading state from the stored data, but
10992 * prior to the settings object being modified by the saved state. Note that for
10993 * plug-in authors, you should use the `stateLoadParams` event to load parameters for
10994 * a plug-in.
10995 * @type function
10996 * @param {object} settings DataTables settings object
10997 * @param {object} data The state object that is to be loaded
10998 *
10999 * @dtopt Callbacks
11000 * @name DataTable.defaults.stateLoadParams
11001 *
11002 * @example
11003 * // Remove a saved filter, so filtering is never loaded
11004 * $(document).ready( function() {
11005 * $('#example').dataTable( {
11006 * "stateSave": true,
11007 * "stateLoadParams": function (settings, data) {
11008 * data.oSearch.sSearch = "";
11009 * }
11010 * } );
11011 * } );
11012 *
11013 * @example
11014 * // Disallow state loading by returning false
11015 * $(document).ready( function() {
11016 * $('#example').dataTable( {
11017 * "stateSave": true,
11018 * "stateLoadParams": function (settings, data) {
11019 * return false;
11020 * }
11021 * } );
11022 * } );
11023 */
11024 "fnStateLoadParams": null,
11025
11026
11027 /**
11028 * Callback that is called when the state has been loaded from the state saving method
11029 * and the DataTables settings object has been modified as a result of the loaded state.
11030 * @type function
11031 * @param {object} settings DataTables settings object
11032 * @param {object} data The state object that was loaded
11033 *
11034 * @dtopt Callbacks
11035 * @name DataTable.defaults.stateLoaded
11036 *
11037 * @example
11038 * // Show an alert with the filtering value that was saved
11039 * $(document).ready( function() {
11040 * $('#example').dataTable( {
11041 * "stateSave": true,
11042 * "stateLoaded": function (settings, data) {
11043 * alert( 'Saved filter was: '+data.oSearch.sSearch );
11044 * }
11045 * } );
11046 * } );
11047 */
11048 "fnStateLoaded": null,
11049
11050
11051 /**
11052 * Save the table state. This function allows you to define where and how the state
11053 * information for the table is stored By default DataTables will use `localStorage`
11054 * but you might wish to use a server-side database or cookies.
11055 * @type function
11056 * @member
11057 * @param {object} settings DataTables settings object
11058 * @param {object} data The state object to be saved
11059 *
11060 * @dtopt Callbacks
11061 * @name DataTable.defaults.stateSaveCallback
11062 *
11063 * @example
11064 * $(document).ready( function() {
11065 * $('#example').dataTable( {
11066 * "stateSave": true,
11067 * "stateSaveCallback": function (settings, data) {
11068 * // Send an Ajax request to the server with the state object
11069 * $.ajax( {
11070 * "url": "/state_save",
11071 * "data": data,
11072 * "dataType": "json",
11073 * "method": "POST"
11074 * "success": function () {}
11075 * } );
11076 * }
11077 * } );
11078 * } );
11079 */
11080 "fnStateSaveCallback": function ( settings, data ) {
11081 try {
11082 (settings.iStateDuration === -1 ? sessionStorage : localStorage).setItem(
11083 'DataTables_'+settings.sInstance+'_'+location.pathname,
11084 JSON.stringify( data )
11085 );
11086 } catch (e) {}
11087 },
11088
11089
11090 /**
11091 * Callback which allows modification of the state to be saved. Called when the table
11092 * has changed state a new state save is required. This method allows modification of
11093 * the state saving object prior to actually doing the save, including addition or
11094 * other state properties or modification. Note that for plug-in authors, you should
11095 * use the `stateSaveParams` event to save parameters for a plug-in.
11096 * @type function
11097 * @param {object} settings DataTables settings object
11098 * @param {object} data The state object to be saved
11099 *
11100 * @dtopt Callbacks
11101 * @name DataTable.defaults.stateSaveParams
11102 *
11103 * @example
11104 * // Remove a saved filter, so filtering is never saved
11105 * $(document).ready( function() {
11106 * $('#example').dataTable( {
11107 * "stateSave": true,
11108 * "stateSaveParams": function (settings, data) {
11109 * data.oSearch.sSearch = "";
11110 * }
11111 * } );
11112 * } );
11113 */
11114 "fnStateSaveParams": null,
11115
11116
11117 /**
11118 * Duration for which the saved state information is considered valid. After this period
11119 * has elapsed the state will be returned to the default.
11120 * Value is given in seconds.
11121 * @type int
11122 * @default 7200 <i>(2 hours)</i>
11123 *
11124 * @dtopt Options
11125 * @name DataTable.defaults.stateDuration
11126 *
11127 * @example
11128 * $(document).ready( function() {
11129 * $('#example').dataTable( {
11130 * "stateDuration": 60*60*24; // 1 day
11131 * } );
11132 * } )
11133 */
11134 "iStateDuration": 7200,
11135
11136
11137 /**
11138 * When enabled DataTables will not make a request to the server for the first
11139 * page draw - rather it will use the data already on the page (no sorting etc
11140 * will be applied to it), thus saving on an XHR at load time. `deferLoading`
11141 * is used to indicate that deferred loading is required, but it is also used
11142 * to tell DataTables how many records there are in the full table (allowing
11143 * the information element and pagination to be displayed correctly). In the case
11144 * where a filtering is applied to the table on initial load, this can be
11145 * indicated by giving the parameter as an array, where the first element is
11146 * the number of records available after filtering and the second element is the
11147 * number of records without filtering (allowing the table information element
11148 * to be shown correctly).
11149 * @type int | array
11150 * @default null
11151 *
11152 * @dtopt Options
11153 * @name DataTable.defaults.deferLoading
11154 *
11155 * @example
11156 * // 57 records available in the table, no filtering applied
11157 * $(document).ready( function() {
11158 * $('#example').dataTable( {
11159 * "serverSide": true,
11160 * "ajax": "scripts/server_processing.php",
11161 * "deferLoading": 57
11162 * } );
11163 * } );
11164 *
11165 * @example
11166 * // 57 records after filtering, 100 without filtering (an initial filter applied)
11167 * $(document).ready( function() {
11168 * $('#example').dataTable( {
11169 * "serverSide": true,
11170 * "ajax": "scripts/server_processing.php",
11171 * "deferLoading": [ 57, 100 ],
11172 * "search": {
11173 * "search": "my_filter"
11174 * }
11175 * } );
11176 * } );
11177 */
11178 "iDeferLoading": null,
11179
11180
11181 /**
11182 * Number of rows to display on a single page when using pagination. If
11183 * feature enabled (`lengthChange`) then the end user will be able to override
11184 * this to a custom setting using a pop-up menu.
11185 * @type int
11186 * @default 10
11187 *
11188 * @dtopt Options
11189 * @name DataTable.defaults.pageLength
11190 *
11191 * @example
11192 * $(document).ready( function() {
11193 * $('#example').dataTable( {
11194 * "pageLength": 50
11195 * } );
11196 * } )
11197 */
11198 "iDisplayLength": 10,
11199
11200
11201 /**
11202 * Define the starting point for data display when using DataTables with
11203 * pagination. Note that this parameter is the number of records, rather than
11204 * the page number, so if you have 10 records per page and want to start on
11205 * the third page, it should be "20".
11206 * @type int
11207 * @default 0
11208 *
11209 * @dtopt Options
11210 * @name DataTable.defaults.displayStart
11211 *
11212 * @example
11213 * $(document).ready( function() {
11214 * $('#example').dataTable( {
11215 * "displayStart": 20
11216 * } );
11217 * } )
11218 */
11219 "iDisplayStart": 0,
11220
11221
11222 /**
11223 * By default DataTables allows keyboard navigation of the table (sorting, paging,
11224 * and filtering) by adding a `tabindex` attribute to the required elements. This
11225 * allows you to tab through the controls and press the enter key to activate them.
11226 * The tabindex is default 0, meaning that the tab follows the flow of the document.
11227 * You can overrule this using this parameter if you wish. Use a value of -1 to
11228 * disable built-in keyboard navigation.
11229 * @type int
11230 * @default 0
11231 *
11232 * @dtopt Options
11233 * @name DataTable.defaults.tabIndex
11234 *
11235 * @example
11236 * $(document).ready( function() {
11237 * $('#example').dataTable( {
11238 * "tabIndex": 1
11239 * } );
11240 * } );
11241 */
11242 "iTabIndex": 0,
11243
11244
11245 /**
11246 * Classes that DataTables assigns to the various components and features
11247 * that it adds to the HTML table. This allows classes to be configured
11248 * during initialisation in addition to through the static
11249 * {@link DataTable.ext.oStdClasses} object).
11250 * @namespace
11251 * @name DataTable.defaults.classes
11252 */
11253 "oClasses": {},
11254
11255
11256 /**
11257 * All strings that DataTables uses in the user interface that it creates
11258 * are defined in this object, allowing you to modified them individually or
11259 * completely replace them all as required.
11260 * @namespace
11261 * @name DataTable.defaults.language
11262 */
11263 "oLanguage": {
11264 /**
11265 * Strings that are used for WAI-ARIA labels and controls only (these are not
11266 * actually visible on the page, but will be read by screenreaders, and thus
11267 * must be internationalised as well).
11268 * @namespace
11269 * @name DataTable.defaults.language.aria
11270 */
11271 "oAria": {
11272 /**
11273 * ARIA label that is added to the table headers when the column may be
11274 * sorted ascending by activing the column (click or return when focused).
11275 * Note that the column header is prefixed to this string.
11276 * @type string
11277 * @default : activate to sort column ascending
11278 *
11279 * @dtopt Language
11280 * @name DataTable.defaults.language.aria.sortAscending
11281 *
11282 * @example
11283 * $(document).ready( function() {
11284 * $('#example').dataTable( {
11285 * "language": {
11286 * "aria": {
11287 * "sortAscending": " - click/return to sort ascending"
11288 * }
11289 * }
11290 * } );
11291 * } );
11292 */
11293 "sSortAscending": ": activate to sort column ascending",
11294
11295 /**
11296 * ARIA label that is added to the table headers when the column may be
11297 * sorted descending by activing the column (click or return when focused).
11298 * Note that the column header is prefixed to this string.
11299 * @type string
11300 * @default : activate to sort column ascending
11301 *
11302 * @dtopt Language
11303 * @name DataTable.defaults.language.aria.sortDescending
11304 *
11305 * @example
11306 * $(document).ready( function() {
11307 * $('#example').dataTable( {
11308 * "language": {
11309 * "aria": {
11310 * "sortDescending": " - click/return to sort descending"
11311 * }
11312 * }
11313 * } );
11314 * } );
11315 */
11316 "sSortDescending": ": activate to sort column descending"
11317 },
11318
11319 /**
11320 * Pagination string used by DataTables for the built-in pagination
11321 * control types.
11322 * @namespace
11323 * @name DataTable.defaults.language.paginate
11324 */
11325 "oPaginate": {
11326 /**
11327 * Text to use when using the 'full_numbers' type of pagination for the
11328 * button to take the user to the first page.
11329 * @type string
11330 * @default First
11331 *
11332 * @dtopt Language
11333 * @name DataTable.defaults.language.paginate.first
11334 *
11335 * @example
11336 * $(document).ready( function() {
11337 * $('#example').dataTable( {
11338 * "language": {
11339 * "paginate": {
11340 * "first": "First page"
11341 * }
11342 * }
11343 * } );
11344 * } );
11345 */
11346 "sFirst": "First",
11347
11348
11349 /**
11350 * Text to use when using the 'full_numbers' type of pagination for the
11351 * button to take the user to the last page.
11352 * @type string
11353 * @default Last
11354 *
11355 * @dtopt Language
11356 * @name DataTable.defaults.language.paginate.last
11357 *
11358 * @example
11359 * $(document).ready( function() {
11360 * $('#example').dataTable( {
11361 * "language": {
11362 * "paginate": {
11363 * "last": "Last page"
11364 * }
11365 * }
11366 * } );
11367 * } );
11368 */
11369 "sLast": "Last",
11370
11371
11372 /**
11373 * Text to use for the 'next' pagination button (to take the user to the
11374 * next page).
11375 * @type string
11376 * @default Next
11377 *
11378 * @dtopt Language
11379 * @name DataTable.defaults.language.paginate.next
11380 *
11381 * @example
11382 * $(document).ready( function() {
11383 * $('#example').dataTable( {
11384 * "language": {
11385 * "paginate": {
11386 * "next": "Next page"
11387 * }
11388 * }
11389 * } );
11390 * } );
11391 */
11392 "sNext": "Next",
11393
11394
11395 /**
11396 * Text to use for the 'previous' pagination button (to take the user to
11397 * the previous page).
11398 * @type string
11399 * @default Previous
11400 *
11401 * @dtopt Language
11402 * @name DataTable.defaults.language.paginate.previous
11403 *
11404 * @example
11405 * $(document).ready( function() {
11406 * $('#example').dataTable( {
11407 * "language": {
11408 * "paginate": {
11409 * "previous": "Previous page"
11410 * }
11411 * }
11412 * } );
11413 * } );
11414 */
11415 "sPrevious": "Previous"
11416 },
11417
11418 /**
11419 * This string is shown in preference to `zeroRecords` when the table is
11420 * empty of data (regardless of filtering). Note that this is an optional
11421 * parameter - if it is not given, the value of `zeroRecords` will be used
11422 * instead (either the default or given value).
11423 * @type string
11424 * @default No data available in table
11425 *
11426 * @dtopt Language
11427 * @name DataTable.defaults.language.emptyTable
11428 *
11429 * @example
11430 * $(document).ready( function() {
11431 * $('#example').dataTable( {
11432 * "language": {
11433 * "emptyTable": "No data available in table"
11434 * }
11435 * } );
11436 * } );
11437 */
11438 "sEmptyTable": "No data available in table",
11439
11440
11441 /**
11442 * This string gives information to the end user about the information
11443 * that is current on display on the page. The following tokens can be
11444 * used in the string and will be dynamically replaced as the table
11445 * display updates. This tokens can be placed anywhere in the string, or
11446 * removed as needed by the language requires:
11447 *
11448 * * `\_START\_` - Display index of the first record on the current page
11449 * * `\_END\_` - Display index of the last record on the current page
11450 * * `\_TOTAL\_` - Number of records in the table after filtering
11451 * * `\_MAX\_` - Number of records in the table without filtering
11452 * * `\_PAGE\_` - Current page number
11453 * * `\_PAGES\_` - Total number of pages of data in the table
11454 *
11455 * @type string
11456 * @default Showing _START_ to _END_ of _TOTAL_ entries
11457 *
11458 * @dtopt Language
11459 * @name DataTable.defaults.language.info
11460 *
11461 * @example
11462 * $(document).ready( function() {
11463 * $('#example').dataTable( {
11464 * "language": {
11465 * "info": "Showing page _PAGE_ of _PAGES_"
11466 * }
11467 * } );
11468 * } );
11469 */
11470 "sInfo": "Showing _START_ to _END_ of _TOTAL_ entries",
11471
11472
11473 /**
11474 * Display information string for when the table is empty. Typically the
11475 * format of this string should match `info`.
11476 * @type string
11477 * @default Showing 0 to 0 of 0 entries
11478 *
11479 * @dtopt Language
11480 * @name DataTable.defaults.language.infoEmpty
11481 *
11482 * @example
11483 * $(document).ready( function() {
11484 * $('#example').dataTable( {
11485 * "language": {
11486 * "infoEmpty": "No entries to show"
11487 * }
11488 * } );
11489 * } );
11490 */
11491 "sInfoEmpty": "Showing 0 to 0 of 0 entries",
11492
11493
11494 /**
11495 * When a user filters the information in a table, this string is appended
11496 * to the information (`info`) to give an idea of how strong the filtering
11497 * is. The variable _MAX_ is dynamically updated.
11498 * @type string
11499 * @default (filtered from _MAX_ total entries)
11500 *
11501 * @dtopt Language
11502 * @name DataTable.defaults.language.infoFiltered
11503 *
11504 * @example
11505 * $(document).ready( function() {
11506 * $('#example').dataTable( {
11507 * "language": {
11508 * "infoFiltered": " - filtering from _MAX_ records"
11509 * }
11510 * } );
11511 * } );
11512 */
11513 "sInfoFiltered": "(filtered from _MAX_ total entries)",
11514
11515
11516 /**
11517 * If can be useful to append extra information to the info string at times,
11518 * and this variable does exactly that. This information will be appended to
11519 * the `info` (`infoEmpty` and `infoFiltered` in whatever combination they are
11520 * being used) at all times.
11521 * @type string
11522 * @default <i>Empty string</i>
11523 *
11524 * @dtopt Language
11525 * @name DataTable.defaults.language.infoPostFix
11526 *
11527 * @example
11528 * $(document).ready( function() {
11529 * $('#example').dataTable( {
11530 * "language": {
11531 * "infoPostFix": "All records shown are derived from real information."
11532 * }
11533 * } );
11534 * } );
11535 */
11536 "sInfoPostFix": "",
11537
11538
11539 /**
11540 * This decimal place operator is a little different from the other
11541 * language options since DataTables doesn't output floating point
11542 * numbers, so it won't ever use this for display of a number. Rather,
11543 * what this parameter does is modify the sort methods of the table so
11544 * that numbers which are in a format which has a character other than
11545 * a period (`.`) as a decimal place will be sorted numerically.
11546 *
11547 * Note that numbers with different decimal places cannot be shown in
11548 * the same table and still be sortable, the table must be consistent.
11549 * However, multiple different tables on the page can use different
11550 * decimal place characters.
11551 * @type string
11552 * @default
11553 *
11554 * @dtopt Language
11555 * @name DataTable.defaults.language.decimal
11556 *
11557 * @example
11558 * $(document).ready( function() {
11559 * $('#example').dataTable( {
11560 * "language": {
11561 * "decimal": ","
11562 * "thousands": "."
11563 * }
11564 * } );
11565 * } );
11566 */
11567 "sDecimal": "",
11568
11569
11570 /**
11571 * DataTables has a build in number formatter (`formatNumber`) which is
11572 * used to format large numbers that are used in the table information.
11573 * By default a comma is used, but this can be trivially changed to any
11574 * character you wish with this parameter.
11575 * @type string
11576 * @default ,
11577 *
11578 * @dtopt Language
11579 * @name DataTable.defaults.language.thousands
11580 *
11581 * @example
11582 * $(document).ready( function() {
11583 * $('#example').dataTable( {
11584 * "language": {
11585 * "thousands": "'"
11586 * }
11587 * } );
11588 * } );
11589 */
11590 "sThousands": ",",
11591
11592
11593 /**
11594 * Detail the action that will be taken when the drop down menu for the
11595 * pagination length option is changed. The '_MENU_' variable is replaced
11596 * with a default select list of 10, 25, 50 and 100, and can be replaced
11597 * with a custom select box if required.
11598 * @type string
11599 * @default Show _MENU_ entries
11600 *
11601 * @dtopt Language
11602 * @name DataTable.defaults.language.lengthMenu
11603 *
11604 * @example
11605 * // Language change only
11606 * $(document).ready( function() {
11607 * $('#example').dataTable( {
11608 * "language": {
11609 * "lengthMenu": "Display _MENU_ records"
11610 * }
11611 * } );
11612 * } );
11613 *
11614 * @example
11615 * // Language and options change
11616 * $(document).ready( function() {
11617 * $('#example').dataTable( {
11618 * "language": {
11619 * "lengthMenu": 'Display <select>'+
11620 * '<option value="10">10</option>'+
11621 * '<option value="20">20</option>'+
11622 * '<option value="30">30</option>'+
11623 * '<option value="40">40</option>'+
11624 * '<option value="50">50</option>'+
11625 * '<option value="-1">All</option>'+
11626 * '</select> records'
11627 * }
11628 * } );
11629 * } );
11630 */
11631 "sLengthMenu": "Show _MENU_ entries",
11632
11633
11634 /**
11635 * When using Ajax sourced data and during the first draw when DataTables is
11636 * gathering the data, this message is shown in an empty row in the table to
11637 * indicate to the end user the the data is being loaded. Note that this
11638 * parameter is not used when loading data by server-side processing, just
11639 * Ajax sourced data with client-side processing.
11640 * @type string
11641 * @default Loading...
11642 *
11643 * @dtopt Language
11644 * @name DataTable.defaults.language.loadingRecords
11645 *
11646 * @example
11647 * $(document).ready( function() {
11648 * $('#example').dataTable( {
11649 * "language": {
11650 * "loadingRecords": "Please wait - loading..."
11651 * }
11652 * } );
11653 * } );
11654 */
11655 "sLoadingRecords": "Loading...",
11656
11657
11658 /**
11659 * Text which is displayed when the table is processing a user action
11660 * (usually a sort command or similar).
11661 * @type string
11662 * @default Processing...
11663 *
11664 * @dtopt Language
11665 * @name DataTable.defaults.language.processing
11666 *
11667 * @example
11668 * $(document).ready( function() {
11669 * $('#example').dataTable( {
11670 * "language": {
11671 * "processing": "DataTables is currently busy"
11672 * }
11673 * } );
11674 * } );
11675 */
11676 "sProcessing": "Processing...",
11677
11678
11679 /**
11680 * Details the actions that will be taken when the user types into the
11681 * filtering input text box. The variable "_INPUT_", if used in the string,
11682 * is replaced with the HTML text box for the filtering input allowing
11683 * control over where it appears in the string. If "_INPUT_" is not given
11684 * then the input box is appended to the string automatically.
11685 * @type string
11686 * @default Search:
11687 *
11688 * @dtopt Language
11689 * @name DataTable.defaults.language.search
11690 *
11691 * @example
11692 * // Input text box will be appended at the end automatically
11693 * $(document).ready( function() {
11694 * $('#example').dataTable( {
11695 * "language": {
11696 * "search": "Filter records:"
11697 * }
11698 * } );
11699 * } );
11700 *
11701 * @example
11702 * // Specify where the filter should appear
11703 * $(document).ready( function() {
11704 * $('#example').dataTable( {
11705 * "language": {
11706 * "search": "Apply filter _INPUT_ to table"
11707 * }
11708 * } );
11709 * } );
11710 */
11711 "sSearch": "Search:",
11712
11713
11714 /**
11715 * Assign a `placeholder` attribute to the search `input` element
11716 * @type string
11717 * @default
11718 *
11719 * @dtopt Language
11720 * @name DataTable.defaults.language.searchPlaceholder
11721 */
11722 "sSearchPlaceholder": "",
11723
11724
11725 /**
11726 * All of the language information can be stored in a file on the
11727 * server-side, which DataTables will look up if this parameter is passed.
11728 * It must store the URL of the language file, which is in a JSON format,
11729 * and the object has the same properties as the oLanguage object in the
11730 * initialiser object (i.e. the above parameters). Please refer to one of
11731 * the example language files to see how this works in action.
11732 * @type string
11733 * @default <i>Empty string - i.e. disabled</i>
11734 *
11735 * @dtopt Language
11736 * @name DataTable.defaults.language.url
11737 *
11738 * @example
11739 * $(document).ready( function() {
11740 * $('#example').dataTable( {
11741 * "language": {
11742 * "url": "http://www.sprymedia.co.uk/dataTables/lang.txt"
11743 * }
11744 * } );
11745 * } );
11746 */
11747 "sUrl": "",
11748
11749
11750 /**
11751 * Text shown inside the table records when the is no information to be
11752 * displayed after filtering. `emptyTable` is shown when there is simply no
11753 * information in the table at all (regardless of filtering).
11754 * @type string
11755 * @default No matching records found
11756 *
11757 * @dtopt Language
11758 * @name DataTable.defaults.language.zeroRecords
11759 *
11760 * @example
11761 * $(document).ready( function() {
11762 * $('#example').dataTable( {
11763 * "language": {
11764 * "zeroRecords": "No records to display"
11765 * }
11766 * } );
11767 * } );
11768 */
11769 "sZeroRecords": "No matching records found"
11770 },
11771
11772
11773 /**
11774 * This parameter allows you to have define the global filtering state at
11775 * initialisation time. As an object the `search` parameter must be
11776 * defined, but all other parameters are optional. When `regex` is true,
11777 * the search string will be treated as a regular expression, when false
11778 * (default) it will be treated as a straight string. When `smart`
11779 * DataTables will use it's smart filtering methods (to word match at
11780 * any point in the data), when false this will not be done.
11781 * @namespace
11782 * @extends DataTable.models.oSearch
11783 *
11784 * @dtopt Options
11785 * @name DataTable.defaults.search
11786 *
11787 * @example
11788 * $(document).ready( function() {
11789 * $('#example').dataTable( {
11790 * "search": {"search": "Initial search"}
11791 * } );
11792 * } )
11793 */
11794 "oSearch": $.extend( {}, DataTable.models.oSearch ),
11795
11796
11797 /**
11798 * __Deprecated__ The functionality provided by this parameter has now been
11799 * superseded by that provided through `ajax`, which should be used instead.
11800 *
11801 * By default DataTables will look for the property `data` (or `aaData` for
11802 * compatibility with DataTables 1.9-) when obtaining data from an Ajax
11803 * source or for server-side processing - this parameter allows that
11804 * property to be changed. You can use Javascript dotted object notation to
11805 * get a data source for multiple levels of nesting.
11806 * @type string
11807 * @default data
11808 *
11809 * @dtopt Options
11810 * @dtopt Server-side
11811 * @name DataTable.defaults.ajaxDataProp
11812 *
11813 * @deprecated 1.10. Please use `ajax` for this functionality now.
11814 */
11815 "sAjaxDataProp": "data",
11816
11817
11818 /**
11819 * __Deprecated__ The functionality provided by this parameter has now been
11820 * superseded by that provided through `ajax`, which should be used instead.
11821 *
11822 * You can instruct DataTables to load data from an external
11823 * source using this parameter (use aData if you want to pass data in you
11824 * already have). Simply provide a url a JSON object can be obtained from.
11825 * @type string
11826 * @default null
11827 *
11828 * @dtopt Options
11829 * @dtopt Server-side
11830 * @name DataTable.defaults.ajaxSource
11831 *
11832 * @deprecated 1.10. Please use `ajax` for this functionality now.
11833 */
11834 "sAjaxSource": null,
11835
11836
11837 /**
11838 * This initialisation variable allows you to specify exactly where in the
11839 * DOM you want DataTables to inject the various controls it adds to the page
11840 * (for example you might want the pagination controls at the top of the
11841 * table). DIV elements (with or without a custom class) can also be added to
11842 * aid styling. The follow syntax is used:
11843 * <ul>
11844 * <li>The following options are allowed:
11845 * <ul>
11846 * <li>'l' - Length changing</li>
11847 * <li>'f' - Filtering input</li>
11848 * <li>'t' - The table!</li>
11849 * <li>'i' - Information</li>
11850 * <li>'p' - Pagination</li>
11851 * <li>'r' - pRocessing</li>
11852 * </ul>
11853 * </li>
11854 * <li>The following constants are allowed:
11855 * <ul>
11856 * <li>'H' - jQueryUI theme "header" classes ('fg-toolbar ui-widget-header ui-corner-tl ui-corner-tr ui-helper-clearfix')</li>
11857 * <li>'F' - jQueryUI theme "footer" classes ('fg-toolbar ui-widget-header ui-corner-bl ui-corner-br ui-helper-clearfix')</li>
11858 * </ul>
11859 * </li>
11860 * <li>The following syntax is expected:
11861 * <ul>
11862 * <li>'&lt;' and '&gt;' - div elements</li>
11863 * <li>'&lt;"class" and '&gt;' - div with a class</li>
11864 * <li>'&lt;"#id" and '&gt;' - div with an ID</li>
11865 * </ul>
11866 * </li>
11867 * <li>Examples:
11868 * <ul>
11869 * <li>'&lt;"wrapper"flipt&gt;'</li>
11870 * <li>'&lt;lf&lt;t&gt;ip&gt;'</li>
11871 * </ul>
11872 * </li>
11873 * </ul>
11874 * @type string
11875 * @default lfrtip <i>(when `jQueryUI` is false)</i> <b>or</b>
11876 * <"H"lfr>t<"F"ip> <i>(when `jQueryUI` is true)</i>
11877 *
11878 * @dtopt Options
11879 * @name DataTable.defaults.dom
11880 *
11881 * @example
11882 * $(document).ready( function() {
11883 * $('#example').dataTable( {
11884 * "dom": '&lt;"top"i&gt;rt&lt;"bottom"flp&gt;&lt;"clear"&gt;'
11885 * } );
11886 * } );
11887 */
11888 "sDom": "lfrtip",
11889
11890
11891 /**
11892 * Search delay option. This will throttle full table searches that use the
11893 * DataTables provided search input element (it does not effect calls to
11894 * `dt-api search()`, providing a delay before the search is made.
11895 * @type integer
11896 * @default 0
11897 *
11898 * @dtopt Options
11899 * @name DataTable.defaults.searchDelay
11900 *
11901 * @example
11902 * $(document).ready( function() {
11903 * $('#example').dataTable( {
11904 * "searchDelay": 200
11905 * } );
11906 * } )
11907 */
11908 "searchDelay": null,
11909
11910
11911 /**
11912 * DataTables features six different built-in options for the buttons to
11913 * display for pagination control:
11914 *
11915 * * `numbers` - Page number buttons only
11916 * * `simple` - 'Previous' and 'Next' buttons only
11917 * * 'simple_numbers` - 'Previous' and 'Next' buttons, plus page numbers
11918 * * `full` - 'First', 'Previous', 'Next' and 'Last' buttons
11919 * * `full_numbers` - 'First', 'Previous', 'Next' and 'Last' buttons, plus page numbers
11920 * * `first_last_numbers` - 'First' and 'Last' buttons, plus page numbers
11921 *
11922 * Further methods can be added using {@link DataTable.ext.oPagination}.
11923 * @type string
11924 * @default simple_numbers
11925 *
11926 * @dtopt Options
11927 * @name DataTable.defaults.pagingType
11928 *
11929 * @example
11930 * $(document).ready( function() {
11931 * $('#example').dataTable( {
11932 * "pagingType": "full_numbers"
11933 * } );
11934 * } )
11935 */
11936 "sPaginationType": "simple_numbers",
11937
11938
11939 /**
11940 * Enable horizontal scrolling. When a table is too wide to fit into a
11941 * certain layout, or you have a large number of columns in the table, you
11942 * can enable x-scrolling to show the table in a viewport, which can be
11943 * scrolled. This property can be `true` which will allow the table to
11944 * scroll horizontally when needed, or any CSS unit, or a number (in which
11945 * case it will be treated as a pixel measurement). Setting as simply `true`
11946 * is recommended.
11947 * @type boolean|string
11948 * @default <i>blank string - i.e. disabled</i>
11949 *
11950 * @dtopt Features
11951 * @name DataTable.defaults.scrollX
11952 *
11953 * @example
11954 * $(document).ready( function() {
11955 * $('#example').dataTable( {
11956 * "scrollX": true,
11957 * "scrollCollapse": true
11958 * } );
11959 * } );
11960 */
11961 "sScrollX": "",
11962
11963
11964 /**
11965 * This property can be used to force a DataTable to use more width than it
11966 * might otherwise do when x-scrolling is enabled. For example if you have a
11967 * table which requires to be well spaced, this parameter is useful for
11968 * "over-sizing" the table, and thus forcing scrolling. This property can by
11969 * any CSS unit, or a number (in which case it will be treated as a pixel
11970 * measurement).
11971 * @type string
11972 * @default <i>blank string - i.e. disabled</i>
11973 *
11974 * @dtopt Options
11975 * @name DataTable.defaults.scrollXInner
11976 *
11977 * @example
11978 * $(document).ready( function() {
11979 * $('#example').dataTable( {
11980 * "scrollX": "100%",
11981 * "scrollXInner": "110%"
11982 * } );
11983 * } );
11984 */
11985 "sScrollXInner": "",
11986
11987
11988 /**
11989 * Enable vertical scrolling. Vertical scrolling will constrain the DataTable
11990 * to the given height, and enable scrolling for any data which overflows the
11991 * current viewport. This can be used as an alternative to paging to display
11992 * a lot of data in a small area (although paging and scrolling can both be
11993 * enabled at the same time). This property can be any CSS unit, or a number
11994 * (in which case it will be treated as a pixel measurement).
11995 * @type string
11996 * @default <i>blank string - i.e. disabled</i>
11997 *
11998 * @dtopt Features
11999 * @name DataTable.defaults.scrollY
12000 *
12001 * @example
12002 * $(document).ready( function() {
12003 * $('#example').dataTable( {
12004 * "scrollY": "200px",
12005 * "paginate": false
12006 * } );
12007 * } );
12008 */
12009 "sScrollY": "",
12010
12011
12012 /**
12013 * __Deprecated__ The functionality provided by this parameter has now been
12014 * superseded by that provided through `ajax`, which should be used instead.
12015 *
12016 * Set the HTTP method that is used to make the Ajax call for server-side
12017 * processing or Ajax sourced data.
12018 * @type string
12019 * @default GET
12020 *
12021 * @dtopt Options
12022 * @dtopt Server-side
12023 * @name DataTable.defaults.serverMethod
12024 *
12025 * @deprecated 1.10. Please use `ajax` for this functionality now.
12026 */
12027 "sServerMethod": "GET",
12028
12029
12030 /**
12031 * DataTables makes use of renderers when displaying HTML elements for
12032 * a table. These renderers can be added or modified by plug-ins to
12033 * generate suitable mark-up for a site. For example the Bootstrap
12034 * integration plug-in for DataTables uses a paging button renderer to
12035 * display pagination buttons in the mark-up required by Bootstrap.
12036 *
12037 * For further information about the renderers available see
12038 * DataTable.ext.renderer
12039 * @type string|object
12040 * @default null
12041 *
12042 * @name DataTable.defaults.renderer
12043 *
12044 */
12045 "renderer": null,
12046
12047
12048 /**
12049 * Set the data property name that DataTables should use to get a row's id
12050 * to set as the `id` property in the node.
12051 * @type string
12052 * @default DT_RowId
12053 *
12054 * @name DataTable.defaults.rowId
12055 */
12056 "rowId": "DT_RowId"
12057 };
12058
12059 _fnHungarianMap( DataTable.defaults );
12060
12061
12062
12063 /*
12064 * Developer note - See note in model.defaults.js about the use of Hungarian
12065 * notation and camel case.
12066 */
12067
12068 /**
12069 * Column options that can be given to DataTables at initialisation time.
12070 * @namespace
12071 */
12072 DataTable.defaults.column = {
12073 /**
12074 * Define which column(s) an order will occur on for this column. This
12075 * allows a column's ordering to take multiple columns into account when
12076 * doing a sort or use the data from a different column. For example first
12077 * name / last name columns make sense to do a multi-column sort over the
12078 * two columns.
12079 * @type array|int
12080 * @default null <i>Takes the value of the column index automatically</i>
12081 *
12082 * @name DataTable.defaults.column.orderData
12083 * @dtopt Columns
12084 *
12085 * @example
12086 * // Using `columnDefs`
12087 * $(document).ready( function() {
12088 * $('#example').dataTable( {
12089 * "columnDefs": [
12090 * { "orderData": [ 0, 1 ], "targets": [ 0 ] },
12091 * { "orderData": [ 1, 0 ], "targets": [ 1 ] },
12092 * { "orderData": 2, "targets": [ 2 ] }
12093 * ]
12094 * } );
12095 * } );
12096 *
12097 * @example
12098 * // Using `columns`
12099 * $(document).ready( function() {
12100 * $('#example').dataTable( {
12101 * "columns": [
12102 * { "orderData": [ 0, 1 ] },
12103 * { "orderData": [ 1, 0 ] },
12104 * { "orderData": 2 },
12105 * null,
12106 * null
12107 * ]
12108 * } );
12109 * } );
12110 */
12111 "aDataSort": null,
12112 "iDataSort": -1,
12113
12114
12115 /**
12116 * You can control the default ordering direction, and even alter the
12117 * behaviour of the sort handler (i.e. only allow ascending ordering etc)
12118 * using this parameter.
12119 * @type array
12120 * @default [ 'asc', 'desc' ]
12121 *
12122 * @name DataTable.defaults.column.orderSequence
12123 * @dtopt Columns
12124 *
12125 * @example
12126 * // Using `columnDefs`
12127 * $(document).ready( function() {
12128 * $('#example').dataTable( {
12129 * "columnDefs": [
12130 * { "orderSequence": [ "asc" ], "targets": [ 1 ] },
12131 * { "orderSequence": [ "desc", "asc", "asc" ], "targets": [ 2 ] },
12132 * { "orderSequence": [ "desc" ], "targets": [ 3 ] }
12133 * ]
12134 * } );
12135 * } );
12136 *
12137 * @example
12138 * // Using `columns`
12139 * $(document).ready( function() {
12140 * $('#example').dataTable( {
12141 * "columns": [
12142 * null,
12143 * { "orderSequence": [ "asc" ] },
12144 * { "orderSequence": [ "desc", "asc", "asc" ] },
12145 * { "orderSequence": [ "desc" ] },
12146 * null
12147 * ]
12148 * } );
12149 * } );
12150 */
12151 "asSorting": [ 'asc', 'desc' ],
12152
12153
12154 /**
12155 * Enable or disable filtering on the data in this column.
12156 * @type boolean
12157 * @default true
12158 *
12159 * @name DataTable.defaults.column.searchable
12160 * @dtopt Columns
12161 *
12162 * @example
12163 * // Using `columnDefs`
12164 * $(document).ready( function() {
12165 * $('#example').dataTable( {
12166 * "columnDefs": [
12167 * { "searchable": false, "targets": [ 0 ] }
12168 * ] } );
12169 * } );
12170 *
12171 * @example
12172 * // Using `columns`
12173 * $(document).ready( function() {
12174 * $('#example').dataTable( {
12175 * "columns": [
12176 * { "searchable": false },
12177 * null,
12178 * null,
12179 * null,
12180 * null
12181 * ] } );
12182 * } );
12183 */
12184 "bSearchable": true,
12185
12186
12187 /**
12188 * Enable or disable ordering on this column.
12189 * @type boolean
12190 * @default true
12191 *
12192 * @name DataTable.defaults.column.orderable
12193 * @dtopt Columns
12194 *
12195 * @example
12196 * // Using `columnDefs`
12197 * $(document).ready( function() {
12198 * $('#example').dataTable( {
12199 * "columnDefs": [
12200 * { "orderable": false, "targets": [ 0 ] }
12201 * ] } );
12202 * } );
12203 *
12204 * @example
12205 * // Using `columns`
12206 * $(document).ready( function() {
12207 * $('#example').dataTable( {
12208 * "columns": [
12209 * { "orderable": false },
12210 * null,
12211 * null,
12212 * null,
12213 * null
12214 * ] } );
12215 * } );
12216 */
12217 "bSortable": true,
12218
12219
12220 /**
12221 * Enable or disable the display of this column.
12222 * @type boolean
12223 * @default true
12224 *
12225 * @name DataTable.defaults.column.visible
12226 * @dtopt Columns
12227 *
12228 * @example
12229 * // Using `columnDefs`
12230 * $(document).ready( function() {
12231 * $('#example').dataTable( {
12232 * "columnDefs": [
12233 * { "visible": false, "targets": [ 0 ] }
12234 * ] } );
12235 * } );
12236 *
12237 * @example
12238 * // Using `columns`
12239 * $(document).ready( function() {
12240 * $('#example').dataTable( {
12241 * "columns": [
12242 * { "visible": false },
12243 * null,
12244 * null,
12245 * null,
12246 * null
12247 * ] } );
12248 * } );
12249 */
12250 "bVisible": true,
12251
12252
12253 /**
12254 * Developer definable function that is called whenever a cell is created (Ajax source,
12255 * etc) or processed for input (DOM source). This can be used as a compliment to mRender
12256 * allowing you to modify the DOM element (add background colour for example) when the
12257 * element is available.
12258 * @type function
12259 * @param {element} td The TD node that has been created
12260 * @param {*} cellData The Data for the cell
12261 * @param {array|object} rowData The data for the whole row
12262 * @param {int} row The row index for the aoData data store
12263 * @param {int} col The column index for aoColumns
12264 *
12265 * @name DataTable.defaults.column.createdCell
12266 * @dtopt Columns
12267 *
12268 * @example
12269 * $(document).ready( function() {
12270 * $('#example').dataTable( {
12271 * "columnDefs": [ {
12272 * "targets": [3],
12273 * "createdCell": function (td, cellData, rowData, row, col) {
12274 * if ( cellData == "1.7" ) {
12275 * $(td).css('color', 'blue')
12276 * }
12277 * }
12278 * } ]
12279 * });
12280 * } );
12281 */
12282 "fnCreatedCell": null,
12283
12284
12285 /**
12286 * This parameter has been replaced by `data` in DataTables to ensure naming
12287 * consistency. `dataProp` can still be used, as there is backwards
12288 * compatibility in DataTables for this option, but it is strongly
12289 * recommended that you use `data` in preference to `dataProp`.
12290 * @name DataTable.defaults.column.dataProp
12291 */
12292
12293
12294 /**
12295 * This property can be used to read data from any data source property,
12296 * including deeply nested objects / properties. `data` can be given in a
12297 * number of different ways which effect its behaviour:
12298 *
12299 * * `integer` - treated as an array index for the data source. This is the
12300 * default that DataTables uses (incrementally increased for each column).
12301 * * `string` - read an object property from the data source. There are
12302 * three 'special' options that can be used in the string to alter how
12303 * DataTables reads the data from the source object:
12304 * * `.` - Dotted Javascript notation. Just as you use a `.` in
12305 * Javascript to read from nested objects, so to can the options
12306 * specified in `data`. For example: `browser.version` or
12307 * `browser.name`. If your object parameter name contains a period, use
12308 * `\\` to escape it - i.e. `first\\.name`.
12309 * * `[]` - Array notation. DataTables can automatically combine data
12310 * from and array source, joining the data with the characters provided
12311 * between the two brackets. For example: `name[, ]` would provide a
12312 * comma-space separated list from the source array. If no characters
12313 * are provided between the brackets, the original array source is
12314 * returned.
12315 * * `()` - Function notation. Adding `()` to the end of a parameter will
12316 * execute a function of the name given. For example: `browser()` for a
12317 * simple function on the data source, `browser.version()` for a
12318 * function in a nested property or even `browser().version` to get an
12319 * object property if the function called returns an object. Note that
12320 * function notation is recommended for use in `render` rather than
12321 * `data` as it is much simpler to use as a renderer.
12322 * * `null` - use the original data source for the row rather than plucking
12323 * data directly from it. This action has effects on two other
12324 * initialisation options:
12325 * * `defaultContent` - When null is given as the `data` option and
12326 * `defaultContent` is specified for the column, the value defined by
12327 * `defaultContent` will be used for the cell.
12328 * * `render` - When null is used for the `data` option and the `render`
12329 * option is specified for the column, the whole data source for the
12330 * row is used for the renderer.
12331 * * `function` - the function given will be executed whenever DataTables
12332 * needs to set or get the data for a cell in the column. The function
12333 * takes three parameters:
12334 * * Parameters:
12335 * * `{array|object}` The data source for the row
12336 * * `{string}` The type call data requested - this will be 'set' when
12337 * setting data or 'filter', 'display', 'type', 'sort' or undefined
12338 * when gathering data. Note that when `undefined` is given for the
12339 * type DataTables expects to get the raw data for the object back<
12340 * * `{*}` Data to set when the second parameter is 'set'.
12341 * * Return:
12342 * * The return value from the function is not required when 'set' is
12343 * the type of call, but otherwise the return is what will be used
12344 * for the data requested.
12345 *
12346 * Note that `data` is a getter and setter option. If you just require
12347 * formatting of data for output, you will likely want to use `render` which
12348 * is simply a getter and thus simpler to use.
12349 *
12350 * Note that prior to DataTables 1.9.2 `data` was called `mDataProp`. The
12351 * name change reflects the flexibility of this property and is consistent
12352 * with the naming of mRender. If 'mDataProp' is given, then it will still
12353 * be used by DataTables, as it automatically maps the old name to the new
12354 * if required.
12355 *
12356 * @type string|int|function|null
12357 * @default null <i>Use automatically calculated column index</i>
12358 *
12359 * @name DataTable.defaults.column.data
12360 * @dtopt Columns
12361 *
12362 * @example
12363 * // Read table data from objects
12364 * // JSON structure for each row:
12365 * // {
12366 * // "engine": {value},
12367 * // "browser": {value},
12368 * // "platform": {value},
12369 * // "version": {value},
12370 * // "grade": {value}
12371 * // }
12372 * $(document).ready( function() {
12373 * $('#example').dataTable( {
12374 * "ajaxSource": "sources/objects.txt",
12375 * "columns": [
12376 * { "data": "engine" },
12377 * { "data": "browser" },
12378 * { "data": "platform" },
12379 * { "data": "version" },
12380 * { "data": "grade" }
12381 * ]
12382 * } );
12383 * } );
12384 *
12385 * @example
12386 * // Read information from deeply nested objects
12387 * // JSON structure for each row:
12388 * // {
12389 * // "engine": {value},
12390 * // "browser": {value},
12391 * // "platform": {
12392 * // "inner": {value}
12393 * // },
12394 * // "details": [
12395 * // {value}, {value}
12396 * // ]
12397 * // }
12398 * $(document).ready( function() {
12399 * $('#example').dataTable( {
12400 * "ajaxSource": "sources/deep.txt",
12401 * "columns": [
12402 * { "data": "engine" },
12403 * { "data": "browser" },
12404 * { "data": "platform.inner" },
12405 * { "data": "details.0" },
12406 * { "data": "details.1" }
12407 * ]
12408 * } );
12409 * } );
12410 *
12411 * @example
12412 * // Using `data` as a function to provide different information for
12413 * // sorting, filtering and display. In this case, currency (price)
12414 * $(document).ready( function() {
12415 * $('#example').dataTable( {
12416 * "columnDefs": [ {
12417 * "targets": [ 0 ],
12418 * "data": function ( source, type, val ) {
12419 * if (type === 'set') {
12420 * source.price = val;
12421 * // Store the computed dislay and filter values for efficiency
12422 * source.price_display = val=="" ? "" : "$"+numberFormat(val);
12423 * source.price_filter = val=="" ? "" : "$"+numberFormat(val)+" "+val;
12424 * return;
12425 * }
12426 * else if (type === 'display') {
12427 * return source.price_display;
12428 * }
12429 * else if (type === 'filter') {
12430 * return source.price_filter;
12431 * }
12432 * // 'sort', 'type' and undefined all just use the integer
12433 * return source.price;
12434 * }
12435 * } ]
12436 * } );
12437 * } );
12438 *
12439 * @example
12440 * // Using default content
12441 * $(document).ready( function() {
12442 * $('#example').dataTable( {
12443 * "columnDefs": [ {
12444 * "targets": [ 0 ],
12445 * "data": null,
12446 * "defaultContent": "Click to edit"
12447 * } ]
12448 * } );
12449 * } );
12450 *
12451 * @example
12452 * // Using array notation - outputting a list from an array
12453 * $(document).ready( function() {
12454 * $('#example').dataTable( {
12455 * "columnDefs": [ {
12456 * "targets": [ 0 ],
12457 * "data": "name[, ]"
12458 * } ]
12459 * } );
12460 * } );
12461 *
12462 */
12463 "mData": null,
12464
12465
12466 /**
12467 * This property is the rendering partner to `data` and it is suggested that
12468 * when you want to manipulate data for display (including filtering,
12469 * sorting etc) without altering the underlying data for the table, use this
12470 * property. `render` can be considered to be the the read only companion to
12471 * `data` which is read / write (then as such more complex). Like `data`
12472 * this option can be given in a number of different ways to effect its
12473 * behaviour:
12474 *
12475 * * `integer` - treated as an array index for the data source. This is the
12476 * default that DataTables uses (incrementally increased for each column).
12477 * * `string` - read an object property from the data source. There are
12478 * three 'special' options that can be used in the string to alter how
12479 * DataTables reads the data from the source object:
12480 * * `.` - Dotted Javascript notation. Just as you use a `.` in
12481 * Javascript to read from nested objects, so to can the options
12482 * specified in `data`. For example: `browser.version` or
12483 * `browser.name`. If your object parameter name contains a period, use
12484 * `\\` to escape it - i.e. `first\\.name`.
12485 * * `[]` - Array notation. DataTables can automatically combine data
12486 * from and array source, joining the data with the characters provided
12487 * between the two brackets. For example: `name[, ]` would provide a
12488 * comma-space separated list from the source array. If no characters
12489 * are provided between the brackets, the original array source is
12490 * returned.
12491 * * `()` - Function notation. Adding `()` to the end of a parameter will
12492 * execute a function of the name given. For example: `browser()` for a
12493 * simple function on the data source, `browser.version()` for a
12494 * function in a nested property or even `browser().version` to get an
12495 * object property if the function called returns an object.
12496 * * `object` - use different data for the different data types requested by
12497 * DataTables ('filter', 'display', 'type' or 'sort'). The property names
12498 * of the object is the data type the property refers to and the value can
12499 * defined using an integer, string or function using the same rules as
12500 * `render` normally does. Note that an `_` option _must_ be specified.
12501 * This is the default value to use if you haven't specified a value for
12502 * the data type requested by DataTables.
12503 * * `function` - the function given will be executed whenever DataTables
12504 * needs to set or get the data for a cell in the column. The function
12505 * takes three parameters:
12506 * * Parameters:
12507 * * {array|object} The data source for the row (based on `data`)
12508 * * {string} The type call data requested - this will be 'filter',
12509 * 'display', 'type' or 'sort'.
12510 * * {array|object} The full data source for the row (not based on
12511 * `data`)
12512 * * Return:
12513 * * The return value from the function is what will be used for the
12514 * data requested.
12515 *
12516 * @type string|int|function|object|null
12517 * @default null Use the data source value.
12518 *
12519 * @name DataTable.defaults.column.render
12520 * @dtopt Columns
12521 *
12522 * @example
12523 * // Create a comma separated list from an array of objects
12524 * $(document).ready( function() {
12525 * $('#example').dataTable( {
12526 * "ajaxSource": "sources/deep.txt",
12527 * "columns": [
12528 * { "data": "engine" },
12529 * { "data": "browser" },
12530 * {
12531 * "data": "platform",
12532 * "render": "[, ].name"
12533 * }
12534 * ]
12535 * } );
12536 * } );
12537 *
12538 * @example
12539 * // Execute a function to obtain data
12540 * $(document).ready( function() {
12541 * $('#example').dataTable( {
12542 * "columnDefs": [ {
12543 * "targets": [ 0 ],
12544 * "data": null, // Use the full data source object for the renderer's source
12545 * "render": "browserName()"
12546 * } ]
12547 * } );
12548 * } );
12549 *
12550 * @example
12551 * // As an object, extracting different data for the different types
12552 * // This would be used with a data source such as:
12553 * // { "phone": 5552368, "phone_filter": "5552368 555-2368", "phone_display": "555-2368" }
12554 * // Here the `phone` integer is used for sorting and type detection, while `phone_filter`
12555 * // (which has both forms) is used for filtering for if a user inputs either format, while
12556 * // the formatted phone number is the one that is shown in the table.
12557 * $(document).ready( function() {
12558 * $('#example').dataTable( {
12559 * "columnDefs": [ {
12560 * "targets": [ 0 ],
12561 * "data": null, // Use the full data source object for the renderer's source
12562 * "render": {
12563 * "_": "phone",
12564 * "filter": "phone_filter",
12565 * "display": "phone_display"
12566 * }
12567 * } ]
12568 * } );
12569 * } );
12570 *
12571 * @example
12572 * // Use as a function to create a link from the data source
12573 * $(document).ready( function() {
12574 * $('#example').dataTable( {
12575 * "columnDefs": [ {
12576 * "targets": [ 0 ],
12577 * "data": "download_link",
12578 * "render": function ( data, type, full ) {
12579 * return '<a href="'+data+'">Download</a>';
12580 * }
12581 * } ]
12582 * } );
12583 * } );
12584 */
12585 "mRender": null,
12586
12587
12588 /**
12589 * Change the cell type created for the column - either TD cells or TH cells. This
12590 * can be useful as TH cells have semantic meaning in the table body, allowing them
12591 * to act as a header for a row (you may wish to add scope='row' to the TH elements).
12592 * @type string
12593 * @default td
12594 *
12595 * @name DataTable.defaults.column.cellType
12596 * @dtopt Columns
12597 *
12598 * @example
12599 * // Make the first column use TH cells
12600 * $(document).ready( function() {
12601 * $('#example').dataTable( {
12602 * "columnDefs": [ {
12603 * "targets": [ 0 ],
12604 * "cellType": "th"
12605 * } ]
12606 * } );
12607 * } );
12608 */
12609 "sCellType": "td",
12610
12611
12612 /**
12613 * Class to give to each cell in this column.
12614 * @type string
12615 * @default <i>Empty string</i>
12616 *
12617 * @name DataTable.defaults.column.class
12618 * @dtopt Columns
12619 *
12620 * @example
12621 * // Using `columnDefs`
12622 * $(document).ready( function() {
12623 * $('#example').dataTable( {
12624 * "columnDefs": [
12625 * { "class": "my_class", "targets": [ 0 ] }
12626 * ]
12627 * } );
12628 * } );
12629 *
12630 * @example
12631 * // Using `columns`
12632 * $(document).ready( function() {
12633 * $('#example').dataTable( {
12634 * "columns": [
12635 * { "class": "my_class" },
12636 * null,
12637 * null,
12638 * null,
12639 * null
12640 * ]
12641 * } );
12642 * } );
12643 */
12644 "sClass": "",
12645
12646 /**
12647 * When DataTables calculates the column widths to assign to each column,
12648 * it finds the longest string in each column and then constructs a
12649 * temporary table and reads the widths from that. The problem with this
12650 * is that "mmm" is much wider then "iiii", but the latter is a longer
12651 * string - thus the calculation can go wrong (doing it properly and putting
12652 * it into an DOM object and measuring that is horribly(!) slow). Thus as
12653 * a "work around" we provide this option. It will append its value to the
12654 * text that is found to be the longest string for the column - i.e. padding.
12655 * Generally you shouldn't need this!
12656 * @type string
12657 * @default <i>Empty string<i>
12658 *
12659 * @name DataTable.defaults.column.contentPadding
12660 * @dtopt Columns
12661 *
12662 * @example
12663 * // Using `columns`
12664 * $(document).ready( function() {
12665 * $('#example').dataTable( {
12666 * "columns": [
12667 * null,
12668 * null,
12669 * null,
12670 * {
12671 * "contentPadding": "mmm"
12672 * }
12673 * ]
12674 * } );
12675 * } );
12676 */
12677 "sContentPadding": "",
12678
12679
12680 /**
12681 * Allows a default value to be given for a column's data, and will be used
12682 * whenever a null data source is encountered (this can be because `data`
12683 * is set to null, or because the data source itself is null).
12684 * @type string
12685 * @default null
12686 *
12687 * @name DataTable.defaults.column.defaultContent
12688 * @dtopt Columns
12689 *
12690 * @example
12691 * // Using `columnDefs`
12692 * $(document).ready( function() {
12693 * $('#example').dataTable( {
12694 * "columnDefs": [
12695 * {
12696 * "data": null,
12697 * "defaultContent": "Edit",
12698 * "targets": [ -1 ]
12699 * }
12700 * ]
12701 * } );
12702 * } );
12703 *
12704 * @example
12705 * // Using `columns`
12706 * $(document).ready( function() {
12707 * $('#example').dataTable( {
12708 * "columns": [
12709 * null,
12710 * null,
12711 * null,
12712 * {
12713 * "data": null,
12714 * "defaultContent": "Edit"
12715 * }
12716 * ]
12717 * } );
12718 * } );
12719 */
12720 "sDefaultContent": null,
12721
12722
12723 /**
12724 * This parameter is only used in DataTables' server-side processing. It can
12725 * be exceptionally useful to know what columns are being displayed on the
12726 * client side, and to map these to database fields. When defined, the names
12727 * also allow DataTables to reorder information from the server if it comes
12728 * back in an unexpected order (i.e. if you switch your columns around on the
12729 * client-side, your server-side code does not also need updating).
12730 * @type string
12731 * @default <i>Empty string</i>
12732 *
12733 * @name DataTable.defaults.column.name
12734 * @dtopt Columns
12735 *
12736 * @example
12737 * // Using `columnDefs`
12738 * $(document).ready( function() {
12739 * $('#example').dataTable( {
12740 * "columnDefs": [
12741 * { "name": "engine", "targets": [ 0 ] },
12742 * { "name": "browser", "targets": [ 1 ] },
12743 * { "name": "platform", "targets": [ 2 ] },
12744 * { "name": "version", "targets": [ 3 ] },
12745 * { "name": "grade", "targets": [ 4 ] }
12746 * ]
12747 * } );
12748 * } );
12749 *
12750 * @example
12751 * // Using `columns`
12752 * $(document).ready( function() {
12753 * $('#example').dataTable( {
12754 * "columns": [
12755 * { "name": "engine" },
12756 * { "name": "browser" },
12757 * { "name": "platform" },
12758 * { "name": "version" },
12759 * { "name": "grade" }
12760 * ]
12761 * } );
12762 * } );
12763 */
12764 "sName": "",
12765
12766
12767 /**
12768 * Defines a data source type for the ordering which can be used to read
12769 * real-time information from the table (updating the internally cached
12770 * version) prior to ordering. This allows ordering to occur on user
12771 * editable elements such as form inputs.
12772 * @type string
12773 * @default std
12774 *
12775 * @name DataTable.defaults.column.orderDataType
12776 * @dtopt Columns
12777 *
12778 * @example
12779 * // Using `columnDefs`
12780 * $(document).ready( function() {
12781 * $('#example').dataTable( {
12782 * "columnDefs": [
12783 * { "orderDataType": "dom-text", "targets": [ 2, 3 ] },
12784 * { "type": "numeric", "targets": [ 3 ] },
12785 * { "orderDataType": "dom-select", "targets": [ 4 ] },
12786 * { "orderDataType": "dom-checkbox", "targets": [ 5 ] }
12787 * ]
12788 * } );
12789 * } );
12790 *
12791 * @example
12792 * // Using `columns`
12793 * $(document).ready( function() {
12794 * $('#example').dataTable( {
12795 * "columns": [
12796 * null,
12797 * null,
12798 * { "orderDataType": "dom-text" },
12799 * { "orderDataType": "dom-text", "type": "numeric" },
12800 * { "orderDataType": "dom-select" },
12801 * { "orderDataType": "dom-checkbox" }
12802 * ]
12803 * } );
12804 * } );
12805 */
12806 "sSortDataType": "std",
12807
12808
12809 /**
12810 * The title of this column.
12811 * @type string
12812 * @default null <i>Derived from the 'TH' value for this column in the
12813 * original HTML table.</i>
12814 *
12815 * @name DataTable.defaults.column.title
12816 * @dtopt Columns
12817 *
12818 * @example
12819 * // Using `columnDefs`
12820 * $(document).ready( function() {
12821 * $('#example').dataTable( {
12822 * "columnDefs": [
12823 * { "title": "My column title", "targets": [ 0 ] }
12824 * ]
12825 * } );
12826 * } );
12827 *
12828 * @example
12829 * // Using `columns`
12830 * $(document).ready( function() {
12831 * $('#example').dataTable( {
12832 * "columns": [
12833 * { "title": "My column title" },
12834 * null,
12835 * null,
12836 * null,
12837 * null
12838 * ]
12839 * } );
12840 * } );
12841 */
12842 "sTitle": null,
12843
12844
12845 /**
12846 * The type allows you to specify how the data for this column will be
12847 * ordered. Four types (string, numeric, date and html (which will strip
12848 * HTML tags before ordering)) are currently available. Note that only date
12849 * formats understood by Javascript's Date() object will be accepted as type
12850 * date. For example: "Mar 26, 2008 5:03 PM". May take the values: 'string',
12851 * 'numeric', 'date' or 'html' (by default). Further types can be adding
12852 * through plug-ins.
12853 * @type string
12854 * @default null <i>Auto-detected from raw data</i>
12855 *
12856 * @name DataTable.defaults.column.type
12857 * @dtopt Columns
12858 *
12859 * @example
12860 * // Using `columnDefs`
12861 * $(document).ready( function() {
12862 * $('#example').dataTable( {
12863 * "columnDefs": [
12864 * { "type": "html", "targets": [ 0 ] }
12865 * ]
12866 * } );
12867 * } );
12868 *
12869 * @example
12870 * // Using `columns`
12871 * $(document).ready( function() {
12872 * $('#example').dataTable( {
12873 * "columns": [
12874 * { "type": "html" },
12875 * null,
12876 * null,
12877 * null,
12878 * null
12879 * ]
12880 * } );
12881 * } );
12882 */
12883 "sType": null,
12884
12885
12886 /**
12887 * Defining the width of the column, this parameter may take any CSS value
12888 * (3em, 20px etc). DataTables applies 'smart' widths to columns which have not
12889 * been given a specific width through this interface ensuring that the table
12890 * remains readable.
12891 * @type string
12892 * @default null <i>Automatic</i>
12893 *
12894 * @name DataTable.defaults.column.width
12895 * @dtopt Columns
12896 *
12897 * @example
12898 * // Using `columnDefs`
12899 * $(document).ready( function() {
12900 * $('#example').dataTable( {
12901 * "columnDefs": [
12902 * { "width": "20%", "targets": [ 0 ] }
12903 * ]
12904 * } );
12905 * } );
12906 *
12907 * @example
12908 * // Using `columns`
12909 * $(document).ready( function() {
12910 * $('#example').dataTable( {
12911 * "columns": [
12912 * { "width": "20%" },
12913 * null,
12914 * null,
12915 * null,
12916 * null
12917 * ]
12918 * } );
12919 * } );
12920 */
12921 "sWidth": null
12922 };
12923
12924 _fnHungarianMap( DataTable.defaults.column );
12925
12926
12927
12928 /**
12929 * DataTables settings object - this holds all the information needed for a
12930 * given table, including configuration, data and current application of the
12931 * table options. DataTables does not have a single instance for each DataTable
12932 * with the settings attached to that instance, but rather instances of the
12933 * DataTable "class" are created on-the-fly as needed (typically by a
12934 * $().dataTable() call) and the settings object is then applied to that
12935 * instance.
12936 *
12937 * Note that this object is related to {@link DataTable.defaults} but this
12938 * one is the internal data store for DataTables's cache of columns. It should
12939 * NOT be manipulated outside of DataTables. Any configuration should be done
12940 * through the initialisation options.
12941 * @namespace
12942 * @todo Really should attach the settings object to individual instances so we
12943 * don't need to create new instances on each $().dataTable() call (if the
12944 * table already exists). It would also save passing oSettings around and
12945 * into every single function. However, this is a very significant
12946 * architecture change for DataTables and will almost certainly break
12947 * backwards compatibility with older installations. This is something that
12948 * will be done in 2.0.
12949 */
12950 DataTable.models.oSettings = {
12951 /**
12952 * Primary features of DataTables and their enablement state.
12953 * @namespace
12954 */
12955 "oFeatures": {
12956
12957 /**
12958 * Flag to say if DataTables should automatically try to calculate the
12959 * optimum table and columns widths (true) or not (false).
12960 * Note that this parameter will be set by the initialisation routine. To
12961 * set a default use {@link DataTable.defaults}.
12962 * @type boolean
12963 */
12964 "bAutoWidth": null,
12965
12966 /**
12967 * Delay the creation of TR and TD elements until they are actually
12968 * needed by a driven page draw. This can give a significant speed
12969 * increase for Ajax source and Javascript source data, but makes no
12970 * difference at all fro DOM and server-side processing tables.
12971 * Note that this parameter will be set by the initialisation routine. To
12972 * set a default use {@link DataTable.defaults}.
12973 * @type boolean
12974 */
12975 "bDeferRender": null,
12976
12977 /**
12978 * Enable filtering on the table or not. Note that if this is disabled
12979 * then there is no filtering at all on the table, including fnFilter.
12980 * To just remove the filtering input use sDom and remove the 'f' option.
12981 * Note that this parameter will be set by the initialisation routine. To
12982 * set a default use {@link DataTable.defaults}.
12983 * @type boolean
12984 */
12985 "bFilter": null,
12986
12987 /**
12988 * Table information element (the 'Showing x of y records' div) enable
12989 * flag.
12990 * Note that this parameter will be set by the initialisation routine. To
12991 * set a default use {@link DataTable.defaults}.
12992 * @type boolean
12993 */
12994 "bInfo": null,
12995
12996 /**
12997 * Present a user control allowing the end user to change the page size
12998 * when pagination is enabled.
12999 * Note that this parameter will be set by the initialisation routine. To
13000 * set a default use {@link DataTable.defaults}.
13001 * @type boolean
13002 */
13003 "bLengthChange": null,
13004
13005 /**
13006 * Pagination enabled or not. Note that if this is disabled then length
13007 * changing must also be disabled.
13008 * Note that this parameter will be set by the initialisation routine. To
13009 * set a default use {@link DataTable.defaults}.
13010 * @type boolean
13011 */
13012 "bPaginate": null,
13013
13014 /**
13015 * Processing indicator enable flag whenever DataTables is enacting a
13016 * user request - typically an Ajax request for server-side processing.
13017 * Note that this parameter will be set by the initialisation routine. To
13018 * set a default use {@link DataTable.defaults}.
13019 * @type boolean
13020 */
13021 "bProcessing": null,
13022
13023 /**
13024 * Server-side processing enabled flag - when enabled DataTables will
13025 * get all data from the server for every draw - there is no filtering,
13026 * sorting or paging done on the client-side.
13027 * Note that this parameter will be set by the initialisation routine. To
13028 * set a default use {@link DataTable.defaults}.
13029 * @type boolean
13030 */
13031 "bServerSide": null,
13032
13033 /**
13034 * Sorting enablement flag.
13035 * Note that this parameter will be set by the initialisation routine. To
13036 * set a default use {@link DataTable.defaults}.
13037 * @type boolean
13038 */
13039 "bSort": null,
13040
13041 /**
13042 * Multi-column sorting
13043 * Note that this parameter will be set by the initialisation routine. To
13044 * set a default use {@link DataTable.defaults}.
13045 * @type boolean
13046 */
13047 "bSortMulti": null,
13048
13049 /**
13050 * Apply a class to the columns which are being sorted to provide a
13051 * visual highlight or not. This can slow things down when enabled since
13052 * there is a lot of DOM interaction.
13053 * Note that this parameter will be set by the initialisation routine. To
13054 * set a default use {@link DataTable.defaults}.
13055 * @type boolean
13056 */
13057 "bSortClasses": null,
13058
13059 /**
13060 * State saving enablement flag.
13061 * Note that this parameter will be set by the initialisation routine. To
13062 * set a default use {@link DataTable.defaults}.
13063 * @type boolean
13064 */
13065 "bStateSave": null
13066 },
13067
13068
13069 /**
13070 * Scrolling settings for a table.
13071 * @namespace
13072 */
13073 "oScroll": {
13074 /**
13075 * When the table is shorter in height than sScrollY, collapse the
13076 * table container down to the height of the table (when true).
13077 * Note that this parameter will be set by the initialisation routine. To
13078 * set a default use {@link DataTable.defaults}.
13079 * @type boolean
13080 */
13081 "bCollapse": null,
13082
13083 /**
13084 * Width of the scrollbar for the web-browser's platform. Calculated
13085 * during table initialisation.
13086 * @type int
13087 * @default 0
13088 */
13089 "iBarWidth": 0,
13090
13091 /**
13092 * Viewport width for horizontal scrolling. Horizontal scrolling is
13093 * disabled if an empty string.
13094 * Note that this parameter will be set by the initialisation routine. To
13095 * set a default use {@link DataTable.defaults}.
13096 * @type string
13097 */
13098 "sX": null,
13099
13100 /**
13101 * Width to expand the table to when using x-scrolling. Typically you
13102 * should not need to use this.
13103 * Note that this parameter will be set by the initialisation routine. To
13104 * set a default use {@link DataTable.defaults}.
13105 * @type string
13106 * @deprecated
13107 */
13108 "sXInner": null,
13109
13110 /**
13111 * Viewport height for vertical scrolling. Vertical scrolling is disabled
13112 * if an empty string.
13113 * Note that this parameter will be set by the initialisation routine. To
13114 * set a default use {@link DataTable.defaults}.
13115 * @type string
13116 */
13117 "sY": null
13118 },
13119
13120 /**
13121 * Language information for the table.
13122 * @namespace
13123 * @extends DataTable.defaults.oLanguage
13124 */
13125 "oLanguage": {
13126 /**
13127 * Information callback function. See
13128 * {@link DataTable.defaults.fnInfoCallback}
13129 * @type function
13130 * @default null
13131 */
13132 "fnInfoCallback": null
13133 },
13134
13135 /**
13136 * Browser support parameters
13137 * @namespace
13138 */
13139 "oBrowser": {
13140 /**
13141 * Indicate if the browser incorrectly calculates width:100% inside a
13142 * scrolling element (IE6/7)
13143 * @type boolean
13144 * @default false
13145 */
13146 "bScrollOversize": false,
13147
13148 /**
13149 * Determine if the vertical scrollbar is on the right or left of the
13150 * scrolling container - needed for rtl language layout, although not
13151 * all browsers move the scrollbar (Safari).
13152 * @type boolean
13153 * @default false
13154 */
13155 "bScrollbarLeft": false,
13156
13157 /**
13158 * Flag for if `getBoundingClientRect` is fully supported or not
13159 * @type boolean
13160 * @default false
13161 */
13162 "bBounding": false,
13163
13164 /**
13165 * Browser scrollbar width
13166 * @type integer
13167 * @default 0
13168 */
13169 "barWidth": 0
13170 },
13171
13172
13173 "ajax": null,
13174
13175
13176 /**
13177 * Array referencing the nodes which are used for the features. The
13178 * parameters of this object match what is allowed by sDom - i.e.
13179 * <ul>
13180 * <li>'l' - Length changing</li>
13181 * <li>'f' - Filtering input</li>
13182 * <li>'t' - The table!</li>
13183 * <li>'i' - Information</li>
13184 * <li>'p' - Pagination</li>
13185 * <li>'r' - pRocessing</li>
13186 * </ul>
13187 * @type array
13188 * @default []
13189 */
13190 "aanFeatures": [],
13191
13192 /**
13193 * Store data information - see {@link DataTable.models.oRow} for detailed
13194 * information.
13195 * @type array
13196 * @default []
13197 */
13198 "aoData": [],
13199
13200 /**
13201 * Array of indexes which are in the current display (after filtering etc)
13202 * @type array
13203 * @default []
13204 */
13205 "aiDisplay": [],
13206
13207 /**
13208 * Array of indexes for display - no filtering
13209 * @type array
13210 * @default []
13211 */
13212 "aiDisplayMaster": [],
13213
13214 /**
13215 * Map of row ids to data indexes
13216 * @type object
13217 * @default {}
13218 */
13219 "aIds": {},
13220
13221 /**
13222 * Store information about each column that is in use
13223 * @type array
13224 * @default []
13225 */
13226 "aoColumns": [],
13227
13228 /**
13229 * Store information about the table's header
13230 * @type array
13231 * @default []
13232 */
13233 "aoHeader": [],
13234
13235 /**
13236 * Store information about the table's footer
13237 * @type array
13238 * @default []
13239 */
13240 "aoFooter": [],
13241
13242 /**
13243 * Store the applied global search information in case we want to force a
13244 * research or compare the old search to a new one.
13245 * Note that this parameter will be set by the initialisation routine. To
13246 * set a default use {@link DataTable.defaults}.
13247 * @namespace
13248 * @extends DataTable.models.oSearch
13249 */
13250 "oPreviousSearch": {},
13251
13252 /**
13253 * Store the applied search for each column - see
13254 * {@link DataTable.models.oSearch} for the format that is used for the
13255 * filtering information for each column.
13256 * @type array
13257 * @default []
13258 */
13259 "aoPreSearchCols": [],
13260
13261 /**
13262 * Sorting that is applied to the table. Note that the inner arrays are
13263 * used in the following manner:
13264 * <ul>
13265 * <li>Index 0 - column number</li>
13266 * <li>Index 1 - current sorting direction</li>
13267 * </ul>
13268 * Note that this parameter will be set by the initialisation routine. To
13269 * set a default use {@link DataTable.defaults}.
13270 * @type array
13271 * @todo These inner arrays should really be objects
13272 */
13273 "aaSorting": null,
13274
13275 /**
13276 * Sorting that is always applied to the table (i.e. prefixed in front of
13277 * aaSorting).
13278 * Note that this parameter will be set by the initialisation routine. To
13279 * set a default use {@link DataTable.defaults}.
13280 * @type array
13281 * @default []
13282 */
13283 "aaSortingFixed": [],
13284
13285 /**
13286 * Classes to use for the striping of a table.
13287 * Note that this parameter will be set by the initialisation routine. To
13288 * set a default use {@link DataTable.defaults}.
13289 * @type array
13290 * @default []
13291 */
13292 "asStripeClasses": null,
13293
13294 /**
13295 * If restoring a table - we should restore its striping classes as well
13296 * @type array
13297 * @default []
13298 */
13299 "asDestroyStripes": [],
13300
13301 /**
13302 * If restoring a table - we should restore its width
13303 * @type int
13304 * @default 0
13305 */
13306 "sDestroyWidth": 0,
13307
13308 /**
13309 * Callback functions array for every time a row is inserted (i.e. on a draw).
13310 * @type array
13311 * @default []
13312 */
13313 "aoRowCallback": [],
13314
13315 /**
13316 * Callback functions for the header on each draw.
13317 * @type array
13318 * @default []
13319 */
13320 "aoHeaderCallback": [],
13321
13322 /**
13323 * Callback function for the footer on each draw.
13324 * @type array
13325 * @default []
13326 */
13327 "aoFooterCallback": [],
13328
13329 /**
13330 * Array of callback functions for draw callback functions
13331 * @type array
13332 * @default []
13333 */
13334 "aoDrawCallback": [],
13335
13336 /**
13337 * Array of callback functions for row created function
13338 * @type array
13339 * @default []
13340 */
13341 "aoRowCreatedCallback": [],
13342
13343 /**
13344 * Callback functions for just before the table is redrawn. A return of
13345 * false will be used to cancel the draw.
13346 * @type array
13347 * @default []
13348 */
13349 "aoPreDrawCallback": [],
13350
13351 /**
13352 * Callback functions for when the table has been initialised.
13353 * @type array
13354 * @default []
13355 */
13356 "aoInitComplete": [],
13357
13358
13359 /**
13360 * Callbacks for modifying the settings to be stored for state saving, prior to
13361 * saving state.
13362 * @type array
13363 * @default []
13364 */
13365 "aoStateSaveParams": [],
13366
13367 /**
13368 * Callbacks for modifying the settings that have been stored for state saving
13369 * prior to using the stored values to restore the state.
13370 * @type array
13371 * @default []
13372 */
13373 "aoStateLoadParams": [],
13374
13375 /**
13376 * Callbacks for operating on the settings object once the saved state has been
13377 * loaded
13378 * @type array
13379 * @default []
13380 */
13381 "aoStateLoaded": [],
13382
13383 /**
13384 * Cache the table ID for quick access
13385 * @type string
13386 * @default <i>Empty string</i>
13387 */
13388 "sTableId": "",
13389
13390 /**
13391 * The TABLE node for the main table
13392 * @type node
13393 * @default null
13394 */
13395 "nTable": null,
13396
13397 /**
13398 * Permanent ref to the thead element
13399 * @type node
13400 * @default null
13401 */
13402 "nTHead": null,
13403
13404 /**
13405 * Permanent ref to the tfoot element - if it exists
13406 * @type node
13407 * @default null
13408 */
13409 "nTFoot": null,
13410
13411 /**
13412 * Permanent ref to the tbody element
13413 * @type node
13414 * @default null
13415 */
13416 "nTBody": null,
13417
13418 /**
13419 * Cache the wrapper node (contains all DataTables controlled elements)
13420 * @type node
13421 * @default null
13422 */
13423 "nTableWrapper": null,
13424
13425 /**
13426 * Indicate if when using server-side processing the loading of data
13427 * should be deferred until the second draw.
13428 * Note that this parameter will be set by the initialisation routine. To
13429 * set a default use {@link DataTable.defaults}.
13430 * @type boolean
13431 * @default false
13432 */
13433 "bDeferLoading": false,
13434
13435 /**
13436 * Indicate if all required information has been read in
13437 * @type boolean
13438 * @default false
13439 */
13440 "bInitialised": false,
13441
13442 /**
13443 * Information about open rows. Each object in the array has the parameters
13444 * 'nTr' and 'nParent'
13445 * @type array
13446 * @default []
13447 */
13448 "aoOpenRows": [],
13449
13450 /**
13451 * Dictate the positioning of DataTables' control elements - see
13452 * {@link DataTable.model.oInit.sDom}.
13453 * Note that this parameter will be set by the initialisation routine. To
13454 * set a default use {@link DataTable.defaults}.
13455 * @type string
13456 * @default null
13457 */
13458 "sDom": null,
13459
13460 /**
13461 * Search delay (in mS)
13462 * @type integer
13463 * @default null
13464 */
13465 "searchDelay": null,
13466
13467 /**
13468 * Which type of pagination should be used.
13469 * Note that this parameter will be set by the initialisation routine. To
13470 * set a default use {@link DataTable.defaults}.
13471 * @type string
13472 * @default two_button
13473 */
13474 "sPaginationType": "two_button",
13475
13476 /**
13477 * The state duration (for `stateSave`) in seconds.
13478 * Note that this parameter will be set by the initialisation routine. To
13479 * set a default use {@link DataTable.defaults}.
13480 * @type int
13481 * @default 0
13482 */
13483 "iStateDuration": 0,
13484
13485 /**
13486 * Array of callback functions for state saving. Each array element is an
13487 * object with the following parameters:
13488 * <ul>
13489 * <li>function:fn - function to call. Takes two parameters, oSettings
13490 * and the JSON string to save that has been thus far created. Returns
13491 * a JSON string to be inserted into a json object
13492 * (i.e. '"param": [ 0, 1, 2]')</li>
13493 * <li>string:sName - name of callback</li>
13494 * </ul>
13495 * @type array
13496 * @default []
13497 */
13498 "aoStateSave": [],
13499
13500 /**
13501 * Array of callback functions for state loading. Each array element is an
13502 * object with the following parameters:
13503 * <ul>
13504 * <li>function:fn - function to call. Takes two parameters, oSettings
13505 * and the object stored. May return false to cancel state loading</li>
13506 * <li>string:sName - name of callback</li>
13507 * </ul>
13508 * @type array
13509 * @default []
13510 */
13511 "aoStateLoad": [],
13512
13513 /**
13514 * State that was saved. Useful for back reference
13515 * @type object
13516 * @default null
13517 */
13518 "oSavedState": null,
13519
13520 /**
13521 * State that was loaded. Useful for back reference
13522 * @type object
13523 * @default null
13524 */
13525 "oLoadedState": null,
13526
13527 /**
13528 * Source url for AJAX data for the table.
13529 * Note that this parameter will be set by the initialisation routine. To
13530 * set a default use {@link DataTable.defaults}.
13531 * @type string
13532 * @default null
13533 */
13534 "sAjaxSource": null,
13535
13536 /**
13537 * Property from a given object from which to read the table data from. This
13538 * can be an empty string (when not server-side processing), in which case
13539 * it is assumed an an array is given directly.
13540 * Note that this parameter will be set by the initialisation routine. To
13541 * set a default use {@link DataTable.defaults}.
13542 * @type string
13543 */
13544 "sAjaxDataProp": null,
13545
13546 /**
13547 * Note if draw should be blocked while getting data
13548 * @type boolean
13549 * @default true
13550 */
13551 "bAjaxDataGet": true,
13552
13553 /**
13554 * The last jQuery XHR object that was used for server-side data gathering.
13555 * This can be used for working with the XHR information in one of the
13556 * callbacks
13557 * @type object
13558 * @default null
13559 */
13560 "jqXHR": null,
13561
13562 /**
13563 * JSON returned from the server in the last Ajax request
13564 * @type object
13565 * @default undefined
13566 */
13567 "json": undefined,
13568
13569 /**
13570 * Data submitted as part of the last Ajax request
13571 * @type object
13572 * @default undefined
13573 */
13574 "oAjaxData": undefined,
13575
13576 /**
13577 * Function to get the server-side data.
13578 * Note that this parameter will be set by the initialisation routine. To
13579 * set a default use {@link DataTable.defaults}.
13580 * @type function
13581 */
13582 "fnServerData": null,
13583
13584 /**
13585 * Functions which are called prior to sending an Ajax request so extra
13586 * parameters can easily be sent to the server
13587 * @type array
13588 * @default []
13589 */
13590 "aoServerParams": [],
13591
13592 /**
13593 * Send the XHR HTTP method - GET or POST (could be PUT or DELETE if
13594 * required).
13595 * Note that this parameter will be set by the initialisation routine. To
13596 * set a default use {@link DataTable.defaults}.
13597 * @type string
13598 */
13599 "sServerMethod": null,
13600
13601 /**
13602 * Format numbers for display.
13603 * Note that this parameter will be set by the initialisation routine. To
13604 * set a default use {@link DataTable.defaults}.
13605 * @type function
13606 */
13607 "fnFormatNumber": null,
13608
13609 /**
13610 * List of options that can be used for the user selectable length menu.
13611 * Note that this parameter will be set by the initialisation routine. To
13612 * set a default use {@link DataTable.defaults}.
13613 * @type array
13614 * @default []
13615 */
13616 "aLengthMenu": null,
13617
13618 /**
13619 * Counter for the draws that the table does. Also used as a tracker for
13620 * server-side processing
13621 * @type int
13622 * @default 0
13623 */
13624 "iDraw": 0,
13625
13626 /**
13627 * Indicate if a redraw is being done - useful for Ajax
13628 * @type boolean
13629 * @default false
13630 */
13631 "bDrawing": false,
13632
13633 /**
13634 * Draw index (iDraw) of the last error when parsing the returned data
13635 * @type int
13636 * @default -1
13637 */
13638 "iDrawError": -1,
13639
13640 /**
13641 * Paging display length
13642 * @type int
13643 * @default 10
13644 */
13645 "_iDisplayLength": 10,
13646
13647 /**
13648 * Paging start point - aiDisplay index
13649 * @type int
13650 * @default 0
13651 */
13652 "_iDisplayStart": 0,
13653
13654 /**
13655 * Server-side processing - number of records in the result set
13656 * (i.e. before filtering), Use fnRecordsTotal rather than
13657 * this property to get the value of the number of records, regardless of
13658 * the server-side processing setting.
13659 * @type int
13660 * @default 0
13661 * @private
13662 */
13663 "_iRecordsTotal": 0,
13664
13665 /**
13666 * Server-side processing - number of records in the current display set
13667 * (i.e. after filtering). Use fnRecordsDisplay rather than
13668 * this property to get the value of the number of records, regardless of
13669 * the server-side processing setting.
13670 * @type boolean
13671 * @default 0
13672 * @private
13673 */
13674 "_iRecordsDisplay": 0,
13675
13676 /**
13677 * The classes to use for the table
13678 * @type object
13679 * @default {}
13680 */
13681 "oClasses": {},
13682
13683 /**
13684 * Flag attached to the settings object so you can check in the draw
13685 * callback if filtering has been done in the draw. Deprecated in favour of
13686 * events.
13687 * @type boolean
13688 * @default false
13689 * @deprecated
13690 */
13691 "bFiltered": false,
13692
13693 /**
13694 * Flag attached to the settings object so you can check in the draw
13695 * callback if sorting has been done in the draw. Deprecated in favour of
13696 * events.
13697 * @type boolean
13698 * @default false
13699 * @deprecated
13700 */
13701 "bSorted": false,
13702
13703 /**
13704 * Indicate that if multiple rows are in the header and there is more than
13705 * one unique cell per column, if the top one (true) or bottom one (false)
13706 * should be used for sorting / title by DataTables.
13707 * Note that this parameter will be set by the initialisation routine. To
13708 * set a default use {@link DataTable.defaults}.
13709 * @type boolean
13710 */
13711 "bSortCellsTop": null,
13712
13713 /**
13714 * Initialisation object that is used for the table
13715 * @type object
13716 * @default null
13717 */
13718 "oInit": null,
13719
13720 /**
13721 * Destroy callback functions - for plug-ins to attach themselves to the
13722 * destroy so they can clean up markup and events.
13723 * @type array
13724 * @default []
13725 */
13726 "aoDestroyCallback": [],
13727
13728
13729 /**
13730 * Get the number of records in the current record set, before filtering
13731 * @type function
13732 */
13733 "fnRecordsTotal": function ()
13734 {
13735 return _fnDataSource( this ) == 'ssp' ?
13736 this._iRecordsTotal * 1 :
13737 this.aiDisplayMaster.length;
13738 },
13739
13740 /**
13741 * Get the number of records in the current record set, after filtering
13742 * @type function
13743 */
13744 "fnRecordsDisplay": function ()
13745 {
13746 return _fnDataSource( this ) == 'ssp' ?
13747 this._iRecordsDisplay * 1 :
13748 this.aiDisplay.length;
13749 },
13750
13751 /**
13752 * Get the display end point - aiDisplay index
13753 * @type function
13754 */
13755 "fnDisplayEnd": function ()
13756 {
13757 var
13758 len = this._iDisplayLength,
13759 start = this._iDisplayStart,
13760 calc = start + len,
13761 records = this.aiDisplay.length,
13762 features = this.oFeatures,
13763 paginate = features.bPaginate;
13764
13765 if ( features.bServerSide ) {
13766 return paginate === false || len === -1 ?
13767 start + records :
13768 Math.min( start+len, this._iRecordsDisplay );
13769 }
13770 else {
13771 return ! paginate || calc>records || len===-1 ?
13772 records :
13773 calc;
13774 }
13775 },
13776
13777 /**
13778 * The DataTables object for this table
13779 * @type object
13780 * @default null
13781 */
13782 "oInstance": null,
13783
13784 /**
13785 * Unique identifier for each instance of the DataTables object. If there
13786 * is an ID on the table node, then it takes that value, otherwise an
13787 * incrementing internal counter is used.
13788 * @type string
13789 * @default null
13790 */
13791 "sInstance": null,
13792
13793 /**
13794 * tabindex attribute value that is added to DataTables control elements, allowing
13795 * keyboard navigation of the table and its controls.
13796 */
13797 "iTabIndex": 0,
13798
13799 /**
13800 * DIV container for the footer scrolling table if scrolling
13801 */
13802 "nScrollHead": null,
13803
13804 /**
13805 * DIV container for the footer scrolling table if scrolling
13806 */
13807 "nScrollFoot": null,
13808
13809 /**
13810 * Last applied sort
13811 * @type array
13812 * @default []
13813 */
13814 "aLastSort": [],
13815
13816 /**
13817 * Stored plug-in instances
13818 * @type object
13819 * @default {}
13820 */
13821 "oPlugins": {},
13822
13823 /**
13824 * Function used to get a row's id from the row's data
13825 * @type function
13826 * @default null
13827 */
13828 "rowIdFn": null,
13829
13830 /**
13831 * Data location where to store a row's id
13832 * @type string
13833 * @default null
13834 */
13835 "rowId": null
13836 };
13837
13838 /**
13839 * Extension object for DataTables that is used to provide all extension
13840 * options.
13841 *
13842 * Note that the `DataTable.ext` object is available through
13843 * `jQuery.fn.dataTable.ext` where it may be accessed and manipulated. It is
13844 * also aliased to `jQuery.fn.dataTableExt` for historic reasons.
13845 * @namespace
13846 * @extends DataTable.models.ext
13847 */
13848
13849
13850 /**
13851 * DataTables extensions
13852 *
13853 * This namespace acts as a collection area for plug-ins that can be used to
13854 * extend DataTables capabilities. Indeed many of the build in methods
13855 * use this method to provide their own capabilities (sorting methods for
13856 * example).
13857 *
13858 * Note that this namespace is aliased to `jQuery.fn.dataTableExt` for legacy
13859 * reasons
13860 *
13861 * @namespace
13862 */
13863 DataTable.ext = _ext = {
13864 /**
13865 * Buttons. For use with the Buttons extension for DataTables. This is
13866 * defined here so other extensions can define buttons regardless of load
13867 * order. It is _not_ used by DataTables core.
13868 *
13869 * @type object
13870 * @default {}
13871 */
13872 buttons: {},
13873
13874
13875 /**
13876 * Element class names
13877 *
13878 * @type object
13879 * @default {}
13880 */
13881 classes: {},
13882
13883
13884 /**
13885 * DataTables build type (expanded by the download builder)
13886 *
13887 * @type string
13888 */
13889 builder: "-source-",
13890
13891
13892 /**
13893 * Error reporting.
13894 *
13895 * How should DataTables report an error. Can take the value 'alert',
13896 * 'throw', 'none' or a function.
13897 *
13898 * @type string|function
13899 * @default alert
13900 */
13901 errMode: "alert",
13902
13903
13904 /**
13905 * Feature plug-ins.
13906 *
13907 * This is an array of objects which describe the feature plug-ins that are
13908 * available to DataTables. These feature plug-ins are then available for
13909 * use through the `dom` initialisation option.
13910 *
13911 * Each feature plug-in is described by an object which must have the
13912 * following properties:
13913 *
13914 * * `fnInit` - function that is used to initialise the plug-in,
13915 * * `cFeature` - a character so the feature can be enabled by the `dom`
13916 * instillation option. This is case sensitive.
13917 *
13918 * The `fnInit` function has the following input parameters:
13919 *
13920 * 1. `{object}` DataTables settings object: see
13921 * {@link DataTable.models.oSettings}
13922 *
13923 * And the following return is expected:
13924 *
13925 * * {node|null} The element which contains your feature. Note that the
13926 * return may also be void if your plug-in does not require to inject any
13927 * DOM elements into DataTables control (`dom`) - for example this might
13928 * be useful when developing a plug-in which allows table control via
13929 * keyboard entry
13930 *
13931 * @type array
13932 *
13933 * @example
13934 * $.fn.dataTable.ext.features.push( {
13935 * "fnInit": function( oSettings ) {
13936 * return new TableTools( { "oDTSettings": oSettings } );
13937 * },
13938 * "cFeature": "T"
13939 * } );
13940 */
13941 feature: [],
13942
13943
13944 /**
13945 * Row searching.
13946 *
13947 * This method of searching is complimentary to the default type based
13948 * searching, and a lot more comprehensive as it allows you complete control
13949 * over the searching logic. Each element in this array is a function
13950 * (parameters described below) that is called for every row in the table,
13951 * and your logic decides if it should be included in the searching data set
13952 * or not.
13953 *
13954 * Searching functions have the following input parameters:
13955 *
13956 * 1. `{object}` DataTables settings object: see
13957 * {@link DataTable.models.oSettings}
13958 * 2. `{array|object}` Data for the row to be processed (same as the
13959 * original format that was passed in as the data source, or an array
13960 * from a DOM data source
13961 * 3. `{int}` Row index ({@link DataTable.models.oSettings.aoData}), which
13962 * can be useful to retrieve the `TR` element if you need DOM interaction.
13963 *
13964 * And the following return is expected:
13965 *
13966 * * {boolean} Include the row in the searched result set (true) or not
13967 * (false)
13968 *
13969 * Note that as with the main search ability in DataTables, technically this
13970 * is "filtering", since it is subtractive. However, for consistency in
13971 * naming we call it searching here.
13972 *
13973 * @type array
13974 * @default []
13975 *
13976 * @example
13977 * // The following example shows custom search being applied to the
13978 * // fourth column (i.e. the data[3] index) based on two input values
13979 * // from the end-user, matching the data in a certain range.
13980 * $.fn.dataTable.ext.search.push(
13981 * function( settings, data, dataIndex ) {
13982 * var min = document.getElementById('min').value * 1;
13983 * var max = document.getElementById('max').value * 1;
13984 * var version = data[3] == "-" ? 0 : data[3]*1;
13985 *
13986 * if ( min == "" && max == "" ) {
13987 * return true;
13988 * }
13989 * else if ( min == "" && version < max ) {
13990 * return true;
13991 * }
13992 * else if ( min < version && "" == max ) {
13993 * return true;
13994 * }
13995 * else if ( min < version && version < max ) {
13996 * return true;
13997 * }
13998 * return false;
13999 * }
14000 * );
14001 */
14002 search: [],
14003
14004
14005 /**
14006 * Selector extensions
14007 *
14008 * The `selector` option can be used to extend the options available for the
14009 * selector modifier options (`selector-modifier` object data type) that
14010 * each of the three built in selector types offer (row, column and cell +
14011 * their plural counterparts). For example the Select extension uses this
14012 * mechanism to provide an option to select only rows, columns and cells
14013 * that have been marked as selected by the end user (`{selected: true}`),
14014 * which can be used in conjunction with the existing built in selector
14015 * options.
14016 *
14017 * Each property is an array to which functions can be pushed. The functions
14018 * take three attributes:
14019 *
14020 * * Settings object for the host table
14021 * * Options object (`selector-modifier` object type)
14022 * * Array of selected item indexes
14023 *
14024 * The return is an array of the resulting item indexes after the custom
14025 * selector has been applied.
14026 *
14027 * @type object
14028 */
14029 selector: {
14030 cell: [],
14031 column: [],
14032 row: []
14033 },
14034
14035
14036 /**
14037 * Internal functions, exposed for used in plug-ins.
14038 *
14039 * Please note that you should not need to use the internal methods for
14040 * anything other than a plug-in (and even then, try to avoid if possible).
14041 * The internal function may change between releases.
14042 *
14043 * @type object
14044 * @default {}
14045 */
14046 internal: {},
14047
14048
14049 /**
14050 * Legacy configuration options. Enable and disable legacy options that
14051 * are available in DataTables.
14052 *
14053 * @type object
14054 */
14055 legacy: {
14056 /**
14057 * Enable / disable DataTables 1.9 compatible server-side processing
14058 * requests
14059 *
14060 * @type boolean
14061 * @default null
14062 */
14063 ajax: null
14064 },
14065
14066
14067 /**
14068 * Pagination plug-in methods.
14069 *
14070 * Each entry in this object is a function and defines which buttons should
14071 * be shown by the pagination rendering method that is used for the table:
14072 * {@link DataTable.ext.renderer.pageButton}. The renderer addresses how the
14073 * buttons are displayed in the document, while the functions here tell it
14074 * what buttons to display. This is done by returning an array of button
14075 * descriptions (what each button will do).
14076 *
14077 * Pagination types (the four built in options and any additional plug-in
14078 * options defined here) can be used through the `paginationType`
14079 * initialisation parameter.
14080 *
14081 * The functions defined take two parameters:
14082 *
14083 * 1. `{int} page` The current page index
14084 * 2. `{int} pages` The number of pages in the table
14085 *
14086 * Each function is expected to return an array where each element of the
14087 * array can be one of:
14088 *
14089 * * `first` - Jump to first page when activated
14090 * * `last` - Jump to last page when activated
14091 * * `previous` - Show previous page when activated
14092 * * `next` - Show next page when activated
14093 * * `{int}` - Show page of the index given
14094 * * `{array}` - A nested array containing the above elements to add a
14095 * containing 'DIV' element (might be useful for styling).
14096 *
14097 * Note that DataTables v1.9- used this object slightly differently whereby
14098 * an object with two functions would be defined for each plug-in. That
14099 * ability is still supported by DataTables 1.10+ to provide backwards
14100 * compatibility, but this option of use is now decremented and no longer
14101 * documented in DataTables 1.10+.
14102 *
14103 * @type object
14104 * @default {}
14105 *
14106 * @example
14107 * // Show previous, next and current page buttons only
14108 * $.fn.dataTableExt.oPagination.current = function ( page, pages ) {
14109 * return [ 'previous', page, 'next' ];
14110 * };
14111 */
14112 pager: {},
14113
14114
14115 renderer: {
14116 pageButton: {},
14117 header: {}
14118 },
14119
14120
14121 /**
14122 * Ordering plug-ins - custom data source
14123 *
14124 * The extension options for ordering of data available here is complimentary
14125 * to the default type based ordering that DataTables typically uses. It
14126 * allows much greater control over the the data that is being used to
14127 * order a column, but is necessarily therefore more complex.
14128 *
14129 * This type of ordering is useful if you want to do ordering based on data
14130 * live from the DOM (for example the contents of an 'input' element) rather
14131 * than just the static string that DataTables knows of.
14132 *
14133 * The way these plug-ins work is that you create an array of the values you
14134 * wish to be ordering for the column in question and then return that
14135 * array. The data in the array much be in the index order of the rows in
14136 * the table (not the currently ordering order!). Which order data gathering
14137 * function is run here depends on the `dt-init columns.orderDataType`
14138 * parameter that is used for the column (if any).
14139 *
14140 * The functions defined take two parameters:
14141 *
14142 * 1. `{object}` DataTables settings object: see
14143 * {@link DataTable.models.oSettings}
14144 * 2. `{int}` Target column index
14145 *
14146 * Each function is expected to return an array:
14147 *
14148 * * `{array}` Data for the column to be ordering upon
14149 *
14150 * @type array
14151 *
14152 * @example
14153 * // Ordering using `input` node values
14154 * $.fn.dataTable.ext.order['dom-text'] = function ( settings, col )
14155 * {
14156 * return this.api().column( col, {order:'index'} ).nodes().map( function ( td, i ) {
14157 * return $('input', td).val();
14158 * } );
14159 * }
14160 */
14161 order: {},
14162
14163
14164 /**
14165 * Type based plug-ins.
14166 *
14167 * Each column in DataTables has a type assigned to it, either by automatic
14168 * detection or by direct assignment using the `type` option for the column.
14169 * The type of a column will effect how it is ordering and search (plug-ins
14170 * can also make use of the column type if required).
14171 *
14172 * @namespace
14173 */
14174 type: {
14175 /**
14176 * Type detection functions.
14177 *
14178 * The functions defined in this object are used to automatically detect
14179 * a column's type, making initialisation of DataTables super easy, even
14180 * when complex data is in the table.
14181 *
14182 * The functions defined take two parameters:
14183 *
14184 * 1. `{*}` Data from the column cell to be analysed
14185 * 2. `{settings}` DataTables settings object. This can be used to
14186 * perform context specific type detection - for example detection
14187 * based on language settings such as using a comma for a decimal
14188 * place. Generally speaking the options from the settings will not
14189 * be required
14190 *
14191 * Each function is expected to return:
14192 *
14193 * * `{string|null}` Data type detected, or null if unknown (and thus
14194 * pass it on to the other type detection functions.
14195 *
14196 * @type array
14197 *
14198 * @example
14199 * // Currency type detection plug-in:
14200 * $.fn.dataTable.ext.type.detect.push(
14201 * function ( data, settings ) {
14202 * // Check the numeric part
14203 * if ( ! data.substring(1).match(/[0-9]/) ) {
14204 * return null;
14205 * }
14206 *
14207 * // Check prefixed by currency
14208 * if ( data.charAt(0) == '$' || data.charAt(0) == '&pound;' ) {
14209 * return 'currency';
14210 * }
14211 * return null;
14212 * }
14213 * );
14214 */
14215 detect: [],
14216
14217
14218 /**
14219 * Type based search formatting.
14220 *
14221 * The type based searching functions can be used to pre-format the
14222 * data to be search on. For example, it can be used to strip HTML
14223 * tags or to de-format telephone numbers for numeric only searching.
14224 *
14225 * Note that is a search is not defined for a column of a given type,
14226 * no search formatting will be performed.
14227 *
14228 * Pre-processing of searching data plug-ins - When you assign the sType
14229 * for a column (or have it automatically detected for you by DataTables
14230 * or a type detection plug-in), you will typically be using this for
14231 * custom sorting, but it can also be used to provide custom searching
14232 * by allowing you to pre-processing the data and returning the data in
14233 * the format that should be searched upon. This is done by adding
14234 * functions this object with a parameter name which matches the sType
14235 * for that target column. This is the corollary of <i>afnSortData</i>
14236 * for searching data.
14237 *
14238 * The functions defined take a single parameter:
14239 *
14240 * 1. `{*}` Data from the column cell to be prepared for searching
14241 *
14242 * Each function is expected to return:
14243 *
14244 * * `{string|null}` Formatted string that will be used for the searching.
14245 *
14246 * @type object
14247 * @default {}
14248 *
14249 * @example
14250 * $.fn.dataTable.ext.type.search['title-numeric'] = function ( d ) {
14251 * return d.replace(/\n/g," ").replace( /<.*?>/g, "" );
14252 * }
14253 */
14254 search: {},
14255
14256
14257 /**
14258 * Type based ordering.
14259 *
14260 * The column type tells DataTables what ordering to apply to the table
14261 * when a column is sorted upon. The order for each type that is defined,
14262 * is defined by the functions available in this object.
14263 *
14264 * Each ordering option can be described by three properties added to
14265 * this object:
14266 *
14267 * * `{type}-pre` - Pre-formatting function
14268 * * `{type}-asc` - Ascending order function
14269 * * `{type}-desc` - Descending order function
14270 *
14271 * All three can be used together, only `{type}-pre` or only
14272 * `{type}-asc` and `{type}-desc` together. It is generally recommended
14273 * that only `{type}-pre` is used, as this provides the optimal
14274 * implementation in terms of speed, although the others are provided
14275 * for compatibility with existing Javascript sort functions.
14276 *
14277 * `{type}-pre`: Functions defined take a single parameter:
14278 *
14279 * 1. `{*}` Data from the column cell to be prepared for ordering
14280 *
14281 * And return:
14282 *
14283 * * `{*}` Data to be sorted upon
14284 *
14285 * `{type}-asc` and `{type}-desc`: Functions are typical Javascript sort
14286 * functions, taking two parameters:
14287 *
14288 * 1. `{*}` Data to compare to the second parameter
14289 * 2. `{*}` Data to compare to the first parameter
14290 *
14291 * And returning:
14292 *
14293 * * `{*}` Ordering match: <0 if first parameter should be sorted lower
14294 * than the second parameter, ===0 if the two parameters are equal and
14295 * >0 if the first parameter should be sorted height than the second
14296 * parameter.
14297 *
14298 * @type object
14299 * @default {}
14300 *
14301 * @example
14302 * // Numeric ordering of formatted numbers with a pre-formatter
14303 * $.extend( $.fn.dataTable.ext.type.order, {
14304 * "string-pre": function(x) {
14305 * a = (a === "-" || a === "") ? 0 : a.replace( /[^\d\-\.]/g, "" );
14306 * return parseFloat( a );
14307 * }
14308 * } );
14309 *
14310 * @example
14311 * // Case-sensitive string ordering, with no pre-formatting method
14312 * $.extend( $.fn.dataTable.ext.order, {
14313 * "string-case-asc": function(x,y) {
14314 * return ((x < y) ? -1 : ((x > y) ? 1 : 0));
14315 * },
14316 * "string-case-desc": function(x,y) {
14317 * return ((x < y) ? 1 : ((x > y) ? -1 : 0));
14318 * }
14319 * } );
14320 */
14321 order: {}
14322 },
14323
14324 /**
14325 * Unique DataTables instance counter
14326 *
14327 * @type int
14328 * @private
14329 */
14330 _unique: 0,
14331
14332
14333 //
14334 // Depreciated
14335 // The following properties are retained for backwards compatiblity only.
14336 // The should not be used in new projects and will be removed in a future
14337 // version
14338 //
14339
14340 /**
14341 * Version check function.
14342 * @type function
14343 * @depreciated Since 1.10
14344 */
14345 fnVersionCheck: DataTable.fnVersionCheck,
14346
14347
14348 /**
14349 * Index for what 'this' index API functions should use
14350 * @type int
14351 * @deprecated Since v1.10
14352 */
14353 iApiIndex: 0,
14354
14355
14356 /**
14357 * jQuery UI class container
14358 * @type object
14359 * @deprecated Since v1.10
14360 */
14361 oJUIClasses: {},
14362
14363
14364 /**
14365 * Software version
14366 * @type string
14367 * @deprecated Since v1.10
14368 */
14369 sVersion: DataTable.version
14370 };
14371
14372
14373 //
14374 // Backwards compatibility. Alias to pre 1.10 Hungarian notation counter parts
14375 //
14376 $.extend( _ext, {
14377 afnFiltering: _ext.search,
14378 aTypes: _ext.type.detect,
14379 ofnSearch: _ext.type.search,
14380 oSort: _ext.type.order,
14381 afnSortData: _ext.order,
14382 aoFeatures: _ext.feature,
14383 oApi: _ext.internal,
14384 oStdClasses: _ext.classes,
14385 oPagination: _ext.pager
14386 } );
14387
14388
14389 $.extend( DataTable.ext.classes, {
14390 "sTable": "dataTable",
14391 "sNoFooter": "no-footer",
14392
14393 /* Paging buttons */
14394 "sPageButton": "paginate_button",
14395 "sPageButtonActive": "current",
14396 "sPageButtonDisabled": "disabled",
14397
14398 /* Striping classes */
14399 "sStripeOdd": "odd",
14400 "sStripeEven": "even",
14401
14402 /* Empty row */
14403 "sRowEmpty": "dataTables_empty",
14404
14405 /* Features */
14406 "sWrapper": "dataTables_wrapper",
14407 "sFilter": "dataTables_filter",
14408 "sInfo": "dataTables_info",
14409 "sPaging": "dataTables_paginate paging_", /* Note that the type is postfixed */
14410 "sLength": "dataTables_length",
14411 "sProcessing": "dataTables_processing",
14412
14413 /* Sorting */
14414 "sSortAsc": "sorting_asc",
14415 "sSortDesc": "sorting_desc",
14416 "sSortable": "sorting", /* Sortable in both directions */
14417 "sSortableAsc": "sorting_asc_disabled",
14418 "sSortableDesc": "sorting_desc_disabled",
14419 "sSortableNone": "sorting_disabled",
14420 "sSortColumn": "sorting_", /* Note that an int is postfixed for the sorting order */
14421
14422 /* Filtering */
14423 "sFilterInput": "",
14424
14425 /* Page length */
14426 "sLengthSelect": "",
14427
14428 /* Scrolling */
14429 "sScrollWrapper": "dataTables_scroll",
14430 "sScrollHead": "dataTables_scrollHead",
14431 "sScrollHeadInner": "dataTables_scrollHeadInner",
14432 "sScrollBody": "dataTables_scrollBody",
14433 "sScrollFoot": "dataTables_scrollFoot",
14434 "sScrollFootInner": "dataTables_scrollFootInner",
14435
14436 /* Misc */
14437 "sHeaderTH": "",
14438 "sFooterTH": "",
14439
14440 // Deprecated
14441 "sSortJUIAsc": "",
14442 "sSortJUIDesc": "",
14443 "sSortJUI": "",
14444 "sSortJUIAscAllowed": "",
14445 "sSortJUIDescAllowed": "",
14446 "sSortJUIWrapper": "",
14447 "sSortIcon": "",
14448 "sJUIHeader": "",
14449 "sJUIFooter": ""
14450 } );
14451
14452
14453 var extPagination = DataTable.ext.pager;
14454
14455 function _numbers ( page, pages ) {
14456 var
14457 numbers = [],
14458 buttons = extPagination.numbers_length,
14459 half = Math.floor( buttons / 2 ),
14460 i = 1;
14461
14462 if ( pages <= buttons ) {
14463 numbers = _range( 0, pages );
14464 }
14465 else if ( page <= half ) {
14466 numbers = _range( 0, buttons-2 );
14467 numbers.push( 'ellipsis' );
14468 numbers.push( pages-1 );
14469 }
14470 else if ( page >= pages - 1 - half ) {
14471 numbers = _range( pages-(buttons-2), pages );
14472 numbers.splice( 0, 0, 'ellipsis' ); // no unshift in ie6
14473 numbers.splice( 0, 0, 0 );
14474 }
14475 else {
14476 numbers = _range( page-half+2, page+half-1 );
14477 numbers.push( 'ellipsis' );
14478 numbers.push( pages-1 );
14479 numbers.splice( 0, 0, 'ellipsis' );
14480 numbers.splice( 0, 0, 0 );
14481 }
14482
14483 numbers.DT_el = 'span';
14484 return numbers;
14485 }
14486
14487
14488 $.extend( extPagination, {
14489 simple: function ( page, pages ) {
14490 return [ 'previous', 'next' ];
14491 },
14492
14493 full: function ( page, pages ) {
14494 return [ 'first', 'previous', 'next', 'last' ];
14495 },
14496
14497 numbers: function ( page, pages ) {
14498 return [ _numbers(page, pages) ];
14499 },
14500
14501 simple_numbers: function ( page, pages ) {
14502 return [ 'previous', _numbers(page, pages), 'next' ];
14503 },
14504
14505 full_numbers: function ( page, pages ) {
14506 return [ 'first', 'previous', _numbers(page, pages), 'next', 'last' ];
14507 },
14508
14509 first_last_numbers: function (page, pages) {
14510 return ['first', _numbers(page, pages), 'last'];
14511 },
14512
14513 // For testing and plug-ins to use
14514 _numbers: _numbers,
14515
14516 // Number of number buttons (including ellipsis) to show. _Must be odd!_
14517 numbers_length: 7
14518 } );
14519
14520
14521 $.extend( true, DataTable.ext.renderer, {
14522 pageButton: {
14523 _: function ( settings, host, idx, buttons, page, pages ) {
14524 var classes = settings.oClasses;
14525 var lang = settings.oLanguage.oPaginate;
14526 var aria = settings.oLanguage.oAria.paginate || {};
14527 var btnDisplay, btnClass, counter=0;
14528
14529 var attach = function( container, buttons ) {
14530 var i, ien, node, button;
14531 var clickHandler = function ( e ) {
14532 _fnPageChange( settings, e.data.action, true );
14533 };
14534
14535 for ( i=0, ien=buttons.length ; i<ien ; i++ ) {
14536 button = buttons[i];
14537
14538 if ( $.isArray( button ) ) {
14539 var inner = $( '<'+(button.DT_el || 'div')+'/>' )
14540 .appendTo( container );
14541 attach( inner, button );
14542 }
14543 else {
14544 btnDisplay = null;
14545 btnClass = '';
14546
14547 switch ( button ) {
14548 case 'ellipsis':
14549 container.append('<span class="ellipsis">&#x2026;</span>');
14550 break;
14551
14552 case 'first':
14553 btnDisplay = lang.sFirst;
14554 btnClass = button + (page > 0 ?
14555 '' : ' '+classes.sPageButtonDisabled);
14556 break;
14557
14558 case 'previous':
14559 btnDisplay = lang.sPrevious;
14560 btnClass = button + (page > 0 ?
14561 '' : ' '+classes.sPageButtonDisabled);
14562 break;
14563
14564 case 'next':
14565 btnDisplay = lang.sNext;
14566 btnClass = button + (page < pages-1 ?
14567 '' : ' '+classes.sPageButtonDisabled);
14568 break;
14569
14570 case 'last':
14571 btnDisplay = lang.sLast;
14572 btnClass = button + (page < pages-1 ?
14573 '' : ' '+classes.sPageButtonDisabled);
14574 break;
14575
14576 default:
14577 btnDisplay = button + 1;
14578 btnClass = page === button ?
14579 classes.sPageButtonActive : '';
14580 break;
14581 }
14582
14583 if ( btnDisplay !== null ) {
14584 node = $('<a>', {
14585 'class': classes.sPageButton+' '+btnClass,
14586 'aria-controls': settings.sTableId,
14587 'aria-label': aria[ button ],
14588 'data-dt-idx': counter,
14589 'tabindex': settings.iTabIndex,
14590 'id': idx === 0 && typeof button === 'string' ?
14591 settings.sTableId +'_'+ button :
14592 null
14593 } )
14594 .html( btnDisplay )
14595 .appendTo( container );
14596
14597 _fnBindAction(
14598 node, {action: button}, clickHandler
14599 );
14600
14601 counter++;
14602 }
14603 }
14604 }
14605 };
14606
14607 // IE9 throws an 'unknown error' if document.activeElement is used
14608 // inside an iframe or frame. Try / catch the error. Not good for
14609 // accessibility, but neither are frames.
14610 var activeEl;
14611
14612 try {
14613 // Because this approach is destroying and recreating the paging
14614 // elements, focus is lost on the select button which is bad for
14615 // accessibility. So we want to restore focus once the draw has
14616 // completed
14617 activeEl = $(host).find(document.activeElement).data('dt-idx');
14618 }
14619 catch (e) {}
14620
14621 attach( $(host).empty(), buttons );
14622
14623 if ( activeEl !== undefined ) {
14624 $(host).find( '[data-dt-idx='+activeEl+']' ).focus();
14625 }
14626 }
14627 }
14628 } );
14629
14630
14631
14632 // Built in type detection. See model.ext.aTypes for information about
14633 // what is required from this methods.
14634 $.extend( DataTable.ext.type.detect, [
14635 // Plain numbers - first since V8 detects some plain numbers as dates
14636 // e.g. Date.parse('55') (but not all, e.g. Date.parse('22')...).
14637 function ( d, settings )
14638 {
14639 var decimal = settings.oLanguage.sDecimal;
14640 return _isNumber( d, decimal ) ? 'num'+decimal : null;
14641 },
14642
14643 // Dates (only those recognised by the browser's Date.parse)
14644 function ( d, settings )
14645 {
14646 // V8 tries _very_ hard to make a string passed into `Date.parse()`
14647 // valid, so we need to use a regex to restrict date formats. Use a
14648 // plug-in for anything other than ISO8601 style strings
14649 if ( d && !(d instanceof Date) && ! _re_date.test(d) ) {
14650 return null;
14651 }
14652 var parsed = Date.parse(d);
14653 return (parsed !== null && !isNaN(parsed)) || _empty(d) ? 'date' : null;
14654 },
14655
14656 // Formatted numbers
14657 function ( d, settings )
14658 {
14659 var decimal = settings.oLanguage.sDecimal;
14660 return _isNumber( d, decimal, true ) ? 'num-fmt'+decimal : null;
14661 },
14662
14663 // HTML numeric
14664 function ( d, settings )
14665 {
14666 var decimal = settings.oLanguage.sDecimal;
14667 return _htmlNumeric( d, decimal ) ? 'html-num'+decimal : null;
14668 },
14669
14670 // HTML numeric, formatted
14671 function ( d, settings )
14672 {
14673 var decimal = settings.oLanguage.sDecimal;
14674 return _htmlNumeric( d, decimal, true ) ? 'html-num-fmt'+decimal : null;
14675 },
14676
14677 // HTML (this is strict checking - there must be html)
14678 function ( d, settings )
14679 {
14680 return _empty( d ) || (typeof d === 'string' && d.indexOf('<') !== -1) ?
14681 'html' : null;
14682 }
14683 ] );
14684
14685
14686
14687 // Filter formatting functions. See model.ext.ofnSearch for information about
14688 // what is required from these methods.
14689 //
14690 // Note that additional search methods are added for the html numbers and
14691 // html formatted numbers by `_addNumericSort()` when we know what the decimal
14692 // place is
14693
14694
14695 $.extend( DataTable.ext.type.search, {
14696 html: function ( data ) {
14697 return _empty(data) ?
14698 data :
14699 typeof data === 'string' ?
14700 data
14701 .replace( _re_new_lines, " " )
14702 .replace( _re_html, "" ) :
14703 '';
14704 },
14705
14706 string: function ( data ) {
14707 return _empty(data) ?
14708 data :
14709 typeof data === 'string' ?
14710 data.replace( _re_new_lines, " " ) :
14711 data;
14712 }
14713 } );
14714
14715
14716
14717 var __numericReplace = function ( d, decimalPlace, re1, re2 ) {
14718 if ( d !== 0 && (!d || d === '-') ) {
14719 return -Infinity;
14720 }
14721
14722 // If a decimal place other than `.` is used, it needs to be given to the
14723 // function so we can detect it and replace with a `.` which is the only
14724 // decimal place Javascript recognises - it is not locale aware.
14725 if ( decimalPlace ) {
14726 d = _numToDecimal( d, decimalPlace );
14727 }
14728
14729 if ( d.replace ) {
14730 if ( re1 ) {
14731 d = d.replace( re1, '' );
14732 }
14733
14734 if ( re2 ) {
14735 d = d.replace( re2, '' );
14736 }
14737 }
14738
14739 return d * 1;
14740 };
14741
14742
14743 // Add the numeric 'deformatting' functions for sorting and search. This is done
14744 // in a function to provide an easy ability for the language options to add
14745 // additional methods if a non-period decimal place is used.
14746 function _addNumericSort ( decimalPlace ) {
14747 $.each(
14748 {
14749 // Plain numbers
14750 "num": function ( d ) {
14751 return __numericReplace( d, decimalPlace );
14752 },
14753
14754 // Formatted numbers
14755 "num-fmt": function ( d ) {
14756 return __numericReplace( d, decimalPlace, _re_formatted_numeric );
14757 },
14758
14759 // HTML numeric
14760 "html-num": function ( d ) {
14761 return __numericReplace( d, decimalPlace, _re_html );
14762 },
14763
14764 // HTML numeric, formatted
14765 "html-num-fmt": function ( d ) {
14766 return __numericReplace( d, decimalPlace, _re_html, _re_formatted_numeric );
14767 }
14768 },
14769 function ( key, fn ) {
14770 // Add the ordering method
14771 _ext.type.order[ key+decimalPlace+'-pre' ] = fn;
14772
14773 // For HTML types add a search formatter that will strip the HTML
14774 if ( key.match(/^html\-/) ) {
14775 _ext.type.search[ key+decimalPlace ] = _ext.type.search.html;
14776 }
14777 }
14778 );
14779 }
14780
14781
14782 // Default sort methods
14783 $.extend( _ext.type.order, {
14784 // Dates
14785 "date-pre": function ( d ) {
14786 var ts = Date.parse( d );
14787 return isNaN(ts) ? -Infinity : ts;
14788 },
14789
14790 // html
14791 "html-pre": function ( a ) {
14792 return _empty(a) ?
14793 '' :
14794 a.replace ?
14795 a.replace( /<.*?>/g, "" ).toLowerCase() :
14796 a+'';
14797 },
14798
14799 // string
14800 "string-pre": function ( a ) {
14801 // This is a little complex, but faster than always calling toString,
14802 // http://jsperf.com/tostring-v-check
14803 return _empty(a) ?
14804 '' :
14805 typeof a === 'string' ?
14806 a.toLowerCase() :
14807 ! a.toString ?
14808 '' :
14809 a.toString();
14810 },
14811
14812 // string-asc and -desc are retained only for compatibility with the old
14813 // sort methods
14814 "string-asc": function ( x, y ) {
14815 return ((x < y) ? -1 : ((x > y) ? 1 : 0));
14816 },
14817
14818 "string-desc": function ( x, y ) {
14819 return ((x < y) ? 1 : ((x > y) ? -1 : 0));
14820 }
14821 } );
14822
14823
14824 // Numeric sorting types - order doesn't matter here
14825 _addNumericSort( '' );
14826
14827
14828 $.extend( true, DataTable.ext.renderer, {
14829 header: {
14830 _: function ( settings, cell, column, classes ) {
14831 // No additional mark-up required
14832 // Attach a sort listener to update on sort - note that using the
14833 // `DT` namespace will allow the event to be removed automatically
14834 // on destroy, while the `dt` namespaced event is the one we are
14835 // listening for
14836 $(settings.nTable).on( 'order.dt.DT', function ( e, ctx, sorting, columns ) {
14837 if ( settings !== ctx ) { // need to check this this is the host
14838 return; // table, not a nested one
14839 }
14840
14841 var colIdx = column.idx;
14842
14843 cell
14844 .removeClass(
14845 column.sSortingClass +' '+
14846 classes.sSortAsc +' '+
14847 classes.sSortDesc
14848 )
14849 .addClass( columns[ colIdx ] == 'asc' ?
14850 classes.sSortAsc : columns[ colIdx ] == 'desc' ?
14851 classes.sSortDesc :
14852 column.sSortingClass
14853 );
14854 } );
14855 },
14856
14857 jqueryui: function ( settings, cell, column, classes ) {
14858 $('<div/>')
14859 .addClass( classes.sSortJUIWrapper )
14860 .append( cell.contents() )
14861 .append( $('<span/>')
14862 .addClass( classes.sSortIcon+' '+column.sSortingClassJUI )
14863 )
14864 .appendTo( cell );
14865
14866 // Attach a sort listener to update on sort
14867 $(settings.nTable).on( 'order.dt.DT', function ( e, ctx, sorting, columns ) {
14868 if ( settings !== ctx ) {
14869 return;
14870 }
14871
14872 var colIdx = column.idx;
14873
14874 cell
14875 .removeClass( classes.sSortAsc +" "+classes.sSortDesc )
14876 .addClass( columns[ colIdx ] == 'asc' ?
14877 classes.sSortAsc : columns[ colIdx ] == 'desc' ?
14878 classes.sSortDesc :
14879 column.sSortingClass
14880 );
14881
14882 cell
14883 .find( 'span.'+classes.sSortIcon )
14884 .removeClass(
14885 classes.sSortJUIAsc +" "+
14886 classes.sSortJUIDesc +" "+
14887 classes.sSortJUI +" "+
14888 classes.sSortJUIAscAllowed +" "+
14889 classes.sSortJUIDescAllowed
14890 )
14891 .addClass( columns[ colIdx ] == 'asc' ?
14892 classes.sSortJUIAsc : columns[ colIdx ] == 'desc' ?
14893 classes.sSortJUIDesc :
14894 column.sSortingClassJUI
14895 );
14896 } );
14897 }
14898 }
14899 } );
14900
14901 /*
14902 * Public helper functions. These aren't used internally by DataTables, or
14903 * called by any of the options passed into DataTables, but they can be used
14904 * externally by developers working with DataTables. They are helper functions
14905 * to make working with DataTables a little bit easier.
14906 */
14907
14908 var __htmlEscapeEntities = function ( d ) {
14909 return typeof d === 'string' ?
14910 d.replace(/</g, '&lt;').replace(/>/g, '&gt;').replace(/"/g, '&quot;') :
14911 d;
14912 };
14913
14914 /**
14915 * Helpers for `columns.render`.
14916 *
14917 * The options defined here can be used with the `columns.render` initialisation
14918 * option to provide a display renderer. The following functions are defined:
14919 *
14920 * * `number` - Will format numeric data (defined by `columns.data`) for
14921 * display, retaining the original unformatted data for sorting and filtering.
14922 * It takes 5 parameters:
14923 * * `string` - Thousands grouping separator
14924 * * `string` - Decimal point indicator
14925 * * `integer` - Number of decimal points to show
14926 * * `string` (optional) - Prefix.
14927 * * `string` (optional) - Postfix (/suffix).
14928 * * `text` - Escape HTML to help prevent XSS attacks. It has no optional
14929 * parameters.
14930 *
14931 * @example
14932 * // Column definition using the number renderer
14933 * {
14934 * data: "salary",
14935 * render: $.fn.dataTable.render.number( '\'', '.', 0, '$' )
14936 * }
14937 *
14938 * @namespace
14939 */
14940 DataTable.render = {
14941 number: function ( thousands, decimal, precision, prefix, postfix ) {
14942 return {
14943 display: function ( d ) {
14944 if ( typeof d !== 'number' && typeof d !== 'string' ) {
14945 return d;
14946 }
14947
14948 var negative = d < 0 ? '-' : '';
14949 var flo = parseFloat( d );
14950
14951 // If NaN then there isn't much formatting that we can do - just
14952 // return immediately, escaping any HTML (this was supposed to
14953 // be a number after all)
14954 if ( isNaN( flo ) ) {
14955 return __htmlEscapeEntities( d );
14956 }
14957
14958 flo = flo.toFixed( precision );
14959 d = Math.abs( flo );
14960
14961 var intPart = parseInt( d, 10 );
14962 var floatPart = precision ?
14963 decimal+(d - intPart).toFixed( precision ).substring( 2 ):
14964 '';
14965
14966 return negative + (prefix||'') +
14967 intPart.toString().replace(
14968 /\B(?=(\d{3})+(?!\d))/g, thousands
14969 ) +
14970 floatPart +
14971 (postfix||'');
14972 }
14973 };
14974 },
14975
14976 text: function () {
14977 return {
14978 display: __htmlEscapeEntities
14979 };
14980 }
14981 };
14982
14983
14984 /*
14985 * This is really a good bit rubbish this method of exposing the internal methods
14986 * publicly... - To be fixed in 2.0 using methods on the prototype
14987 */
14988
14989
14990 /**
14991 * Create a wrapper function for exporting an internal functions to an external API.
14992 * @param {string} fn API function name
14993 * @returns {function} wrapped function
14994 * @memberof DataTable#internal
14995 */
14996 function _fnExternApiFunc (fn)
14997 {
14998 return function() {
14999 var args = [_fnSettingsFromNode( this[DataTable.ext.iApiIndex] )].concat(
15000 Array.prototype.slice.call(arguments)
15001 );
15002 return DataTable.ext.internal[fn].apply( this, args );
15003 };
15004 }
15005
15006
15007 /**
15008 * Reference to internal functions for use by plug-in developers. Note that
15009 * these methods are references to internal functions and are considered to be
15010 * private. If you use these methods, be aware that they are liable to change
15011 * between versions.
15012 * @namespace
15013 */
15014 $.extend( DataTable.ext.internal, {
15015 _fnExternApiFunc: _fnExternApiFunc,
15016 _fnBuildAjax: _fnBuildAjax,
15017 _fnAjaxUpdate: _fnAjaxUpdate,
15018 _fnAjaxParameters: _fnAjaxParameters,
15019 _fnAjaxUpdateDraw: _fnAjaxUpdateDraw,
15020 _fnAjaxDataSrc: _fnAjaxDataSrc,
15021 _fnAddColumn: _fnAddColumn,
15022 _fnColumnOptions: _fnColumnOptions,
15023 _fnAdjustColumnSizing: _fnAdjustColumnSizing,
15024 _fnVisibleToColumnIndex: _fnVisibleToColumnIndex,
15025 _fnColumnIndexToVisible: _fnColumnIndexToVisible,
15026 _fnVisbleColumns: _fnVisbleColumns,
15027 _fnGetColumns: _fnGetColumns,
15028 _fnColumnTypes: _fnColumnTypes,
15029 _fnApplyColumnDefs: _fnApplyColumnDefs,
15030 _fnHungarianMap: _fnHungarianMap,
15031 _fnCamelToHungarian: _fnCamelToHungarian,
15032 _fnLanguageCompat: _fnLanguageCompat,
15033 _fnBrowserDetect: _fnBrowserDetect,
15034 _fnAddData: _fnAddData,
15035 _fnAddTr: _fnAddTr,
15036 _fnNodeToDataIndex: _fnNodeToDataIndex,
15037 _fnNodeToColumnIndex: _fnNodeToColumnIndex,
15038 _fnGetCellData: _fnGetCellData,
15039 _fnSetCellData: _fnSetCellData,
15040 _fnSplitObjNotation: _fnSplitObjNotation,
15041 _fnGetObjectDataFn: _fnGetObjectDataFn,
15042 _fnSetObjectDataFn: _fnSetObjectDataFn,
15043 _fnGetDataMaster: _fnGetDataMaster,
15044 _fnClearTable: _fnClearTable,
15045 _fnDeleteIndex: _fnDeleteIndex,
15046 _fnInvalidate: _fnInvalidate,
15047 _fnGetRowElements: _fnGetRowElements,
15048 _fnCreateTr: _fnCreateTr,
15049 _fnBuildHead: _fnBuildHead,
15050 _fnDrawHead: _fnDrawHead,
15051 _fnDraw: _fnDraw,
15052 _fnReDraw: _fnReDraw,
15053 _fnAddOptionsHtml: _fnAddOptionsHtml,
15054 _fnDetectHeader: _fnDetectHeader,
15055 _fnGetUniqueThs: _fnGetUniqueThs,
15056 _fnFeatureHtmlFilter: _fnFeatureHtmlFilter,
15057 _fnFilterComplete: _fnFilterComplete,
15058 _fnFilterCustom: _fnFilterCustom,
15059 _fnFilterColumn: _fnFilterColumn,
15060 _fnFilter: _fnFilter,
15061 _fnFilterCreateSearch: _fnFilterCreateSearch,
15062 _fnEscapeRegex: _fnEscapeRegex,
15063 _fnFilterData: _fnFilterData,
15064 _fnFeatureHtmlInfo: _fnFeatureHtmlInfo,
15065 _fnUpdateInfo: _fnUpdateInfo,
15066 _fnInfoMacros: _fnInfoMacros,
15067 _fnInitialise: _fnInitialise,
15068 _fnInitComplete: _fnInitComplete,
15069 _fnLengthChange: _fnLengthChange,
15070 _fnFeatureHtmlLength: _fnFeatureHtmlLength,
15071 _fnFeatureHtmlPaginate: _fnFeatureHtmlPaginate,
15072 _fnPageChange: _fnPageChange,
15073 _fnFeatureHtmlProcessing: _fnFeatureHtmlProcessing,
15074 _fnProcessingDisplay: _fnProcessingDisplay,
15075 _fnFeatureHtmlTable: _fnFeatureHtmlTable,
15076 _fnScrollDraw: _fnScrollDraw,
15077 _fnApplyToChildren: _fnApplyToChildren,
15078 _fnCalculateColumnWidths: _fnCalculateColumnWidths,
15079 _fnThrottle: _fnThrottle,
15080 _fnConvertToWidth: _fnConvertToWidth,
15081 _fnGetWidestNode: _fnGetWidestNode,
15082 _fnGetMaxLenString: _fnGetMaxLenString,
15083 _fnStringToCss: _fnStringToCss,
15084 _fnSortFlatten: _fnSortFlatten,
15085 _fnSort: _fnSort,
15086 _fnSortAria: _fnSortAria,
15087 _fnSortListener: _fnSortListener,
15088 _fnSortAttachListener: _fnSortAttachListener,
15089 _fnSortingClasses: _fnSortingClasses,
15090 _fnSortData: _fnSortData,
15091 _fnSaveState: _fnSaveState,
15092 _fnLoadState: _fnLoadState,
15093 _fnSettingsFromNode: _fnSettingsFromNode,
15094 _fnLog: _fnLog,
15095 _fnMap: _fnMap,
15096 _fnBindAction: _fnBindAction,
15097 _fnCallbackReg: _fnCallbackReg,
15098 _fnCallbackFire: _fnCallbackFire,
15099 _fnLengthOverflow: _fnLengthOverflow,
15100 _fnRenderer: _fnRenderer,
15101 _fnDataSource: _fnDataSource,
15102 _fnRowAttributes: _fnRowAttributes,
15103 _fnExtend: _fnExtend,
15104 _fnCalculateEnd: function () {} // Used by a lot of plug-ins, but redundant
15105 // in 1.10, so this dead-end function is
15106 // added to prevent errors
15107 } );
15108
15109
15110 // jQuery access
15111 $.fn.dataTable = DataTable;
15112
15113 // Provide access to the host jQuery object (circular reference)
15114 DataTable.$ = $;
15115
15116 // Legacy aliases
15117 $.fn.dataTableSettings = DataTable.settings;
15118 $.fn.dataTableExt = DataTable.ext;
15119
15120 // With a capital `D` we return a DataTables API instance rather than a
15121 // jQuery object
15122 $.fn.DataTable = function ( opts ) {
15123 return $(this).dataTable( opts ).api();
15124 };
15125
15126 // All properties that are available to $.fn.dataTable should also be
15127 // available on $.fn.DataTable
15128 $.each( DataTable, function ( prop, val ) {
15129 $.fn.DataTable[ prop ] = val;
15130 } );
15131
15132
15133 // Information about events fired by DataTables - for documentation.
15134 /**
15135 * Draw event, fired whenever the table is redrawn on the page, at the same
15136 * point as fnDrawCallback. This may be useful for binding events or
15137 * performing calculations when the table is altered at all.
15138 * @name DataTable#draw.dt
15139 * @event
15140 * @param {event} e jQuery event object
15141 * @param {object} o DataTables settings object {@link DataTable.models.oSettings}
15142 */
15143
15144 /**
15145 * Search event, fired when the searching applied to the table (using the
15146 * built-in global search, or column filters) is altered.
15147 * @name DataTable#search.dt
15148 * @event
15149 * @param {event} e jQuery event object
15150 * @param {object} o DataTables settings object {@link DataTable.models.oSettings}
15151 */
15152
15153 /**
15154 * Page change event, fired when the paging of the table is altered.
15155 * @name DataTable#page.dt
15156 * @event
15157 * @param {event} e jQuery event object
15158 * @param {object} o DataTables settings object {@link DataTable.models.oSettings}
15159 */
15160
15161 /**
15162 * Order event, fired when the ordering applied to the table is altered.
15163 * @name DataTable#order.dt
15164 * @event
15165 * @param {event} e jQuery event object
15166 * @param {object} o DataTables settings object {@link DataTable.models.oSettings}
15167 */
15168
15169 /**
15170 * DataTables initialisation complete event, fired when the table is fully
15171 * drawn, including Ajax data loaded, if Ajax data is required.
15172 * @name DataTable#init.dt
15173 * @event
15174 * @param {event} e jQuery event object
15175 * @param {object} oSettings DataTables settings object
15176 * @param {object} json The JSON object request from the server - only
15177 * present if client-side Ajax sourced data is used</li></ol>
15178 */
15179
15180 /**
15181 * State save event, fired when the table has changed state a new state save
15182 * is required. This event allows modification of the state saving object
15183 * prior to actually doing the save, including addition or other state
15184 * properties (for plug-ins) or modification of a DataTables core property.
15185 * @name DataTable#stateSaveParams.dt
15186 * @event
15187 * @param {event} e jQuery event object
15188 * @param {object} oSettings DataTables settings object
15189 * @param {object} json The state information to be saved
15190 */
15191
15192 /**
15193 * State load event, fired when the table is loading state from the stored
15194 * data, but prior to the settings object being modified by the saved state
15195 * - allowing modification of the saved state is required or loading of
15196 * state for a plug-in.
15197 * @name DataTable#stateLoadParams.dt
15198 * @event
15199 * @param {event} e jQuery event object
15200 * @param {object} oSettings DataTables settings object
15201 * @param {object} json The saved state information
15202 */
15203
15204 /**
15205 * State loaded event, fired when state has been loaded from stored data and
15206 * the settings object has been modified by the loaded data.
15207 * @name DataTable#stateLoaded.dt
15208 * @event
15209 * @param {event} e jQuery event object
15210 * @param {object} oSettings DataTables settings object
15211 * @param {object} json The saved state information
15212 */
15213
15214 /**
15215 * Processing event, fired when DataTables is doing some kind of processing
15216 * (be it, order, searcg or anything else). It can be used to indicate to
15217 * the end user that there is something happening, or that something has
15218 * finished.
15219 * @name DataTable#processing.dt
15220 * @event
15221 * @param {event} e jQuery event object
15222 * @param {object} oSettings DataTables settings object
15223 * @param {boolean} bShow Flag for if DataTables is doing processing or not
15224 */
15225
15226 /**
15227 * Ajax (XHR) event, fired whenever an Ajax request is completed from a
15228 * request to made to the server for new data. This event is called before
15229 * DataTables processed the returned data, so it can also be used to pre-
15230 * process the data returned from the server, if needed.
15231 *
15232 * Note that this trigger is called in `fnServerData`, if you override
15233 * `fnServerData` and which to use this event, you need to trigger it in you
15234 * success function.
15235 * @name DataTable#xhr.dt
15236 * @event
15237 * @param {event} e jQuery event object
15238 * @param {object} o DataTables settings object {@link DataTable.models.oSettings}
15239 * @param {object} json JSON returned from the server
15240 *
15241 * @example
15242 * // Use a custom property returned from the server in another DOM element
15243 * $('#table').dataTable().on('xhr.dt', function (e, settings, json) {
15244 * $('#status').html( json.status );
15245 * } );
15246 *
15247 * @example
15248 * // Pre-process the data returned from the server
15249 * $('#table').dataTable().on('xhr.dt', function (e, settings, json) {
15250 * for ( var i=0, ien=json.aaData.length ; i<ien ; i++ ) {
15251 * json.aaData[i].sum = json.aaData[i].one + json.aaData[i].two;
15252 * }
15253 * // Note no return - manipulate the data directly in the JSON object.
15254 * } );
15255 */
15256
15257 /**
15258 * Destroy event, fired when the DataTable is destroyed by calling fnDestroy
15259 * or passing the bDestroy:true parameter in the initialisation object. This
15260 * can be used to remove bound events, added DOM nodes, etc.
15261 * @name DataTable#destroy.dt
15262 * @event
15263 * @param {event} e jQuery event object
15264 * @param {object} o DataTables settings object {@link DataTable.models.oSettings}
15265 */
15266
15267 /**
15268 * Page length change event, fired when number of records to show on each
15269 * page (the length) is changed.
15270 * @name DataTable#length.dt
15271 * @event
15272 * @param {event} e jQuery event object
15273 * @param {object} o DataTables settings object {@link DataTable.models.oSettings}
15274 * @param {integer} len New length
15275 */
15276
15277 /**
15278 * Column sizing has changed.
15279 * @name DataTable#column-sizing.dt
15280 * @event
15281 * @param {event} e jQuery event object
15282 * @param {object} o DataTables settings object {@link DataTable.models.oSettings}
15283 */
15284
15285 /**
15286 * Column visibility has changed.
15287 * @name DataTable#column-visibility.dt
15288 * @event
15289 * @param {event} e jQuery event object
15290 * @param {object} o DataTables settings object {@link DataTable.models.oSettings}
15291 * @param {int} column Column index
15292 * @param {bool} vis `false` if column now hidden, or `true` if visible
15293 */
15294
15295 return $.fn.dataTable;
15296}));