PluginProbe
Ultimate Store Kit – Store Builder Addons for Elementor, WooCommerce Store Builder, EDD Store Builder / 1.6.2
Ultimate Store Kit – Store Builder Addons for Elementor, WooCommerce Store Builder, EDD Store Builder v1.6.2
3.1.4 3.0.8 3.0.9 3.1.0 3.1.2 3.1.3 3.0.7 3.0.5 3.0.4 3.0.3 3.0.2 trunk 1.5.0 1.5.1 1.5.2 1.6.1 1.6.2 1.6.3 1.6.4 2.0.0 2.0.1 2.0.2 2.0.3 2.0.4 2.0.5 All 93 releases
ultimate-store-kit / assets / vendor / js / datatables.js

datatables.js in Ultimate Store Kit – Store Builder Addons for Elementor, WooCommerce Store Builder, EDD Store Builder 1.6.2, at assets/vendor/js/datatables.js

15,354 lines 438.7 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 /*! DataTables 1.10.21
2 * ©2008-2020 SpryMedia Ltd - datatables.net/license
3 */
4
5 /**
6 * @summary DataTables
7 * @description Paginate, search and order HTML tables
8 * @version 1.10.21
9 * @file jquery.dataTables.js
10 * @author SpryMedia Ltd
11 * @contact www.datatables.net
12 * @copyright Copyright 2008-2020 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() ), true );
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\u2028]/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, true );
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, create;
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 create = nTrIn ? false : true;
3103
3104 nTd = create ? document.createElement( oCol.sCellType ) : anTds[i];
3105 nTd._DT_CellIndex = {
3106 row: iRow,
3107 column: i
3108 };
3109
3110 cells.push( nTd );
3111
3112 // Need to create the HTML if new, or if a rendering function is defined
3113 if ( create || ((!nTrIn || oCol.mRender || oCol.mData !== i) &&
3114 (!$.isPlainObject(oCol.mData) || oCol.mData._ !== i+'.display')
3115 )) {
3116 nTd.innerHTML = _fnGetCellData( oSettings, iRow, i, 'display' );
3117 }
3118
3119 /* Add user defined class */
3120 if ( oCol.sClass )
3121 {
3122 nTd.className += ' '+oCol.sClass;
3123 }
3124
3125 // Visibility - add or remove as required
3126 if ( oCol.bVisible && ! nTrIn )
3127 {
3128 nTr.appendChild( nTd );
3129 }
3130 else if ( ! oCol.bVisible && nTrIn )
3131 {
3132 nTd.parentNode.removeChild( nTd );
3133 }
3134
3135 if ( oCol.fnCreatedCell )
3136 {
3137 oCol.fnCreatedCell.call( oSettings.oInstance,
3138 nTd, _fnGetCellData( oSettings, iRow, i ), rowData, iRow, i
3139 );
3140 }
3141 }
3142
3143 _fnCallbackFire( oSettings, 'aoRowCreatedCallback', null, [nTr, rowData, iRow, cells] );
3144 }
3145
3146 // Remove once webkit bug 131819 and Chromium bug 365619 have been resolved
3147 // and deployed
3148 row.nTr.setAttribute( 'role', 'row' );
3149 }
3150
3151
3152 /**
3153 * Add attributes to a row based on the special `DT_*` parameters in a data
3154 * source object.
3155 * @param {object} settings DataTables settings object
3156 * @param {object} DataTables row object for the row to be modified
3157 * @memberof DataTable#oApi
3158 */
3159 function _fnRowAttributes( settings, row )
3160 {
3161 var tr = row.nTr;
3162 var data = row._aData;
3163
3164 if ( tr ) {
3165 var id = settings.rowIdFn( data );
3166
3167 if ( id ) {
3168 tr.id = id;
3169 }
3170
3171 if ( data.DT_RowClass ) {
3172 // Remove any classes added by DT_RowClass before
3173 var a = data.DT_RowClass.split(' ');
3174 row.__rowc = row.__rowc ?
3175 _unique( row.__rowc.concat( a ) ) :
3176 a;
3177
3178 $(tr)
3179 .removeClass( row.__rowc.join(' ') )
3180 .addClass( data.DT_RowClass );
3181 }
3182
3183 if ( data.DT_RowAttr ) {
3184 $(tr).attr( data.DT_RowAttr );
3185 }
3186
3187 if ( data.DT_RowData ) {
3188 $(tr).data( data.DT_RowData );
3189 }
3190 }
3191 }
3192
3193
3194 /**
3195 * Create the HTML header for the table
3196 * @param {object} oSettings dataTables settings object
3197 * @memberof DataTable#oApi
3198 */
3199 function _fnBuildHead( oSettings )
3200 {
3201 var i, ien, cell, row, column;
3202 var thead = oSettings.nTHead;
3203 var tfoot = oSettings.nTFoot;
3204 var createHeader = $('th, td', thead).length === 0;
3205 var classes = oSettings.oClasses;
3206 var columns = oSettings.aoColumns;
3207
3208 if ( createHeader ) {
3209 row = $('<tr/>').appendTo( thead );
3210 }
3211
3212 for ( i=0, ien=columns.length ; i<ien ; i++ ) {
3213 column = columns[i];
3214 cell = $( column.nTh ).addClass( column.sClass );
3215
3216 if ( createHeader ) {
3217 cell.appendTo( row );
3218 }
3219
3220 // 1.11 move into sorting
3221 if ( oSettings.oFeatures.bSort ) {
3222 cell.addClass( column.sSortingClass );
3223
3224 if ( column.bSortable !== false ) {
3225 cell
3226 .attr( 'tabindex', oSettings.iTabIndex )
3227 .attr( 'aria-controls', oSettings.sTableId );
3228
3229 _fnSortAttachListener( oSettings, column.nTh, i );
3230 }
3231 }
3232
3233 if ( column.sTitle != cell[0].innerHTML ) {
3234 cell.html( column.sTitle );
3235 }
3236
3237 _fnRenderer( oSettings, 'header' )(
3238 oSettings, cell, column, classes
3239 );
3240 }
3241
3242 if ( createHeader ) {
3243 _fnDetectHeader( oSettings.aoHeader, thead );
3244 }
3245
3246 /* ARIA role for the rows */
3247 $(thead).find('>tr').attr('role', 'row');
3248
3249 /* Deal with the footer - add classes if required */
3250 $(thead).find('>tr>th, >tr>td').addClass( classes.sHeaderTH );
3251 $(tfoot).find('>tr>th, >tr>td').addClass( classes.sFooterTH );
3252
3253 // Cache the footer cells. Note that we only take the cells from the first
3254 // row in the footer. If there is more than one row the user wants to
3255 // interact with, they need to use the table().foot() method. Note also this
3256 // allows cells to be used for multiple columns using colspan
3257 if ( tfoot !== null ) {
3258 var cells = oSettings.aoFooter[0];
3259
3260 for ( i=0, ien=cells.length ; i<ien ; i++ ) {
3261 column = columns[i];
3262 column.nTf = cells[i].cell;
3263
3264 if ( column.sClass ) {
3265 $(column.nTf).addClass( column.sClass );
3266 }
3267 }
3268 }
3269 }
3270
3271
3272 /**
3273 * Draw the header (or footer) element based on the column visibility states. The
3274 * methodology here is to use the layout array from _fnDetectHeader, modified for
3275 * the instantaneous column visibility, to construct the new layout. The grid is
3276 * traversed over cell at a time in a rows x columns grid fashion, although each
3277 * cell insert can cover multiple elements in the grid - which is tracks using the
3278 * aApplied array. Cell inserts in the grid will only occur where there isn't
3279 * already a cell in that position.
3280 * @param {object} oSettings dataTables settings object
3281 * @param array {objects} aoSource Layout array from _fnDetectHeader
3282 * @param {boolean} [bIncludeHidden=false] If true then include the hidden columns in the calc,
3283 * @memberof DataTable#oApi
3284 */
3285 function _fnDrawHead( oSettings, aoSource, bIncludeHidden )
3286 {
3287 var i, iLen, j, jLen, k, kLen, n, nLocalTr;
3288 var aoLocal = [];
3289 var aApplied = [];
3290 var iColumns = oSettings.aoColumns.length;
3291 var iRowspan, iColspan;
3292
3293 if ( ! aoSource )
3294 {
3295 return;
3296 }
3297
3298 if ( bIncludeHidden === undefined )
3299 {
3300 bIncludeHidden = false;
3301 }
3302
3303 /* Make a copy of the master layout array, but without the visible columns in it */
3304 for ( i=0, iLen=aoSource.length ; i<iLen ; i++ )
3305 {
3306 aoLocal[i] = aoSource[i].slice();
3307 aoLocal[i].nTr = aoSource[i].nTr;
3308
3309 /* Remove any columns which are currently hidden */
3310 for ( j=iColumns-1 ; j>=0 ; j-- )
3311 {
3312 if ( !oSettings.aoColumns[j].bVisible && !bIncludeHidden )
3313 {
3314 aoLocal[i].splice( j, 1 );
3315 }
3316 }
3317
3318 /* Prep the applied array - it needs an element for each row */
3319 aApplied.push( [] );
3320 }
3321
3322 for ( i=0, iLen=aoLocal.length ; i<iLen ; i++ )
3323 {
3324 nLocalTr = aoLocal[i].nTr;
3325
3326 /* All cells are going to be replaced, so empty out the row */
3327 if ( nLocalTr )
3328 {
3329 while( (n = nLocalTr.firstChild) )
3330 {
3331 nLocalTr.removeChild( n );
3332 }
3333 }
3334
3335 for ( j=0, jLen=aoLocal[i].length ; j<jLen ; j++ )
3336 {
3337 iRowspan = 1;
3338 iColspan = 1;
3339
3340 /* Check to see if there is already a cell (row/colspan) covering our target
3341 * insert point. If there is, then there is nothing to do.
3342 */
3343 if ( aApplied[i][j] === undefined )
3344 {
3345 nLocalTr.appendChild( aoLocal[i][j].cell );
3346 aApplied[i][j] = 1;
3347
3348 /* Expand the cell to cover as many rows as needed */
3349 while ( aoLocal[i+iRowspan] !== undefined &&
3350 aoLocal[i][j].cell == aoLocal[i+iRowspan][j].cell )
3351 {
3352 aApplied[i+iRowspan][j] = 1;
3353 iRowspan++;
3354 }
3355
3356 /* Expand the cell to cover as many columns as needed */
3357 while ( aoLocal[i][j+iColspan] !== undefined &&
3358 aoLocal[i][j].cell == aoLocal[i][j+iColspan].cell )
3359 {
3360 /* Must update the applied array over the rows for the columns */
3361 for ( k=0 ; k<iRowspan ; k++ )
3362 {
3363 aApplied[i+k][j+iColspan] = 1;
3364 }
3365 iColspan++;
3366 }
3367
3368 /* Do the actual expansion in the DOM */
3369 $(aoLocal[i][j].cell)
3370 .attr('rowspan', iRowspan)
3371 .attr('colspan', iColspan);
3372 }
3373 }
3374 }
3375 }
3376
3377
3378 /**
3379 * Insert the required TR nodes into the table for display
3380 * @param {object} oSettings dataTables settings object
3381 * @memberof DataTable#oApi
3382 */
3383 function _fnDraw( oSettings )
3384 {
3385 /* Provide a pre-callback function which can be used to cancel the draw is false is returned */
3386 var aPreDraw = _fnCallbackFire( oSettings, 'aoPreDrawCallback', 'preDraw', [oSettings] );
3387 if ( $.inArray( false, aPreDraw ) !== -1 )
3388 {
3389 _fnProcessingDisplay( oSettings, false );
3390 return;
3391 }
3392
3393 var i, iLen, n;
3394 var anRows = [];
3395 var iRowCount = 0;
3396 var asStripeClasses = oSettings.asStripeClasses;
3397 var iStripes = asStripeClasses.length;
3398 var iOpenRows = oSettings.aoOpenRows.length;
3399 var oLang = oSettings.oLanguage;
3400 var iInitDisplayStart = oSettings.iInitDisplayStart;
3401 var bServerSide = _fnDataSource( oSettings ) == 'ssp';
3402 var aiDisplay = oSettings.aiDisplay;
3403
3404 oSettings.bDrawing = true;
3405
3406 /* Check and see if we have an initial draw position from state saving */
3407 if ( iInitDisplayStart !== undefined && iInitDisplayStart !== -1 )
3408 {
3409 oSettings._iDisplayStart = bServerSide ?
3410 iInitDisplayStart :
3411 iInitDisplayStart >= oSettings.fnRecordsDisplay() ?
3412 0 :
3413 iInitDisplayStart;
3414
3415 oSettings.iInitDisplayStart = -1;
3416 }
3417
3418 var iDisplayStart = oSettings._iDisplayStart;
3419 var iDisplayEnd = oSettings.fnDisplayEnd();
3420
3421 /* Server-side processing draw intercept */
3422 if ( oSettings.bDeferLoading )
3423 {
3424 oSettings.bDeferLoading = false;
3425 oSettings.iDraw++;
3426 _fnProcessingDisplay( oSettings, false );
3427 }
3428 else if ( !bServerSide )
3429 {
3430 oSettings.iDraw++;
3431 }
3432 else if ( !oSettings.bDestroying && !_fnAjaxUpdate( oSettings ) )
3433 {
3434 return;
3435 }
3436
3437 if ( aiDisplay.length !== 0 )
3438 {
3439 var iStart = bServerSide ? 0 : iDisplayStart;
3440 var iEnd = bServerSide ? oSettings.aoData.length : iDisplayEnd;
3441
3442 for ( var j=iStart ; j<iEnd ; j++ )
3443 {
3444 var iDataIndex = aiDisplay[j];
3445 var aoData = oSettings.aoData[ iDataIndex ];
3446 if ( aoData.nTr === null )
3447 {
3448 _fnCreateTr( oSettings, iDataIndex );
3449 }
3450
3451 var nRow = aoData.nTr;
3452
3453 /* Remove the old striping classes and then add the new one */
3454 if ( iStripes !== 0 )
3455 {
3456 var sStripe = asStripeClasses[ iRowCount % iStripes ];
3457 if ( aoData._sRowStripe != sStripe )
3458 {
3459 $(nRow).removeClass( aoData._sRowStripe ).addClass( sStripe );
3460 aoData._sRowStripe = sStripe;
3461 }
3462 }
3463
3464 // Row callback functions - might want to manipulate the row
3465 // iRowCount and j are not currently documented. Are they at all
3466 // useful?
3467 _fnCallbackFire( oSettings, 'aoRowCallback', null,
3468 [nRow, aoData._aData, iRowCount, j, iDataIndex] );
3469
3470 anRows.push( nRow );
3471 iRowCount++;
3472 }
3473 }
3474 else
3475 {
3476 /* Table is empty - create a row with an empty message in it */
3477 var sZero = oLang.sZeroRecords;
3478 if ( oSettings.iDraw == 1 && _fnDataSource( oSettings ) == 'ajax' )
3479 {
3480 sZero = oLang.sLoadingRecords;
3481 }
3482 else if ( oLang.sEmptyTable && oSettings.fnRecordsTotal() === 0 )
3483 {
3484 sZero = oLang.sEmptyTable;
3485 }
3486
3487 anRows[ 0 ] = $( '<tr/>', { 'class': iStripes ? asStripeClasses[0] : '' } )
3488 .append( $('<td />', {
3489 'valign': 'top',
3490 'colSpan': _fnVisbleColumns( oSettings ),
3491 'class': oSettings.oClasses.sRowEmpty
3492 } ).html( sZero ) )[0];
3493 }
3494
3495 /* Header and footer callbacks */
3496 _fnCallbackFire( oSettings, 'aoHeaderCallback', 'header', [ $(oSettings.nTHead).children('tr')[0],
3497 _fnGetDataMaster( oSettings ), iDisplayStart, iDisplayEnd, aiDisplay ] );
3498
3499 _fnCallbackFire( oSettings, 'aoFooterCallback', 'footer', [ $(oSettings.nTFoot).children('tr')[0],
3500 _fnGetDataMaster( oSettings ), iDisplayStart, iDisplayEnd, aiDisplay ] );
3501
3502 var body = $(oSettings.nTBody);
3503
3504 body.children().detach();
3505 body.append( $(anRows) );
3506
3507 /* Call all required callback functions for the end of a draw */
3508 _fnCallbackFire( oSettings, 'aoDrawCallback', 'draw', [oSettings] );
3509
3510 /* Draw is complete, sorting and filtering must be as well */
3511 oSettings.bSorted = false;
3512 oSettings.bFiltered = false;
3513 oSettings.bDrawing = false;
3514 }
3515
3516
3517 /**
3518 * Redraw the table - taking account of the various features which are enabled
3519 * @param {object} oSettings dataTables settings object
3520 * @param {boolean} [holdPosition] Keep the current paging position. By default
3521 * the paging is reset to the first page
3522 * @memberof DataTable#oApi
3523 */
3524 function _fnReDraw( settings, holdPosition )
3525 {
3526 var
3527 features = settings.oFeatures,
3528 sort = features.bSort,
3529 filter = features.bFilter;
3530
3531 if ( sort ) {
3532 _fnSort( settings );
3533 }
3534
3535 if ( filter ) {
3536 _fnFilterComplete( settings, settings.oPreviousSearch );
3537 }
3538 else {
3539 // No filtering, so we want to just use the display master
3540 settings.aiDisplay = settings.aiDisplayMaster.slice();
3541 }
3542
3543 if ( holdPosition !== true ) {
3544 settings._iDisplayStart = 0;
3545 }
3546
3547 // Let any modules know about the draw hold position state (used by
3548 // scrolling internally)
3549 settings._drawHold = holdPosition;
3550
3551 _fnDraw( settings );
3552
3553 settings._drawHold = false;
3554 }
3555
3556
3557 /**
3558 * Add the options to the page HTML for the table
3559 * @param {object} oSettings dataTables settings object
3560 * @memberof DataTable#oApi
3561 */
3562 function _fnAddOptionsHtml ( oSettings )
3563 {
3564 var classes = oSettings.oClasses;
3565 var table = $(oSettings.nTable);
3566 var holding = $('<div/>').insertBefore( table ); // Holding element for speed
3567 var features = oSettings.oFeatures;
3568
3569 // All DataTables are wrapped in a div
3570 var insert = $('<div/>', {
3571 id: oSettings.sTableId+'_wrapper',
3572 'class': classes.sWrapper + (oSettings.nTFoot ? '' : ' '+classes.sNoFooter)
3573 } );
3574
3575 oSettings.nHolding = holding[0];
3576 oSettings.nTableWrapper = insert[0];
3577 oSettings.nTableReinsertBefore = oSettings.nTable.nextSibling;
3578
3579 /* Loop over the user set positioning and place the elements as needed */
3580 var aDom = oSettings.sDom.split('');
3581 var featureNode, cOption, nNewNode, cNext, sAttr, j;
3582 for ( var i=0 ; i<aDom.length ; i++ )
3583 {
3584 featureNode = null;
3585 cOption = aDom[i];
3586
3587 if ( cOption == '<' )
3588 {
3589 /* New container div */
3590 nNewNode = $('<div/>')[0];
3591
3592 /* Check to see if we should append an id and/or a class name to the container */
3593 cNext = aDom[i+1];
3594 if ( cNext == "'" || cNext == '"' )
3595 {
3596 sAttr = "";
3597 j = 2;
3598 while ( aDom[i+j] != cNext )
3599 {
3600 sAttr += aDom[i+j];
3601 j++;
3602 }
3603
3604 /* Replace jQuery UI constants @todo depreciated */
3605 if ( sAttr == "H" )
3606 {
3607 sAttr = classes.sJUIHeader;
3608 }
3609 else if ( sAttr == "F" )
3610 {
3611 sAttr = classes.sJUIFooter;
3612 }
3613
3614 /* The attribute can be in the format of "#id.class", "#id" or "class" This logic
3615 * breaks the string into parts and applies them as needed
3616 */
3617 if ( sAttr.indexOf('.') != -1 )
3618 {
3619 var aSplit = sAttr.split('.');
3620 nNewNode.id = aSplit[0].substr(1, aSplit[0].length-1);
3621 nNewNode.className = aSplit[1];
3622 }
3623 else if ( sAttr.charAt(0) == "#" )
3624 {
3625 nNewNode.id = sAttr.substr(1, sAttr.length-1);
3626 }
3627 else
3628 {
3629 nNewNode.className = sAttr;
3630 }
3631
3632 i += j; /* Move along the position array */
3633 }
3634
3635 insert.append( nNewNode );
3636 insert = $(nNewNode);
3637 }
3638 else if ( cOption == '>' )
3639 {
3640 /* End container div */
3641 insert = insert.parent();
3642 }
3643 // @todo Move options into their own plugins?
3644 else if ( cOption == 'l' && features.bPaginate && features.bLengthChange )
3645 {
3646 /* Length */
3647 featureNode = _fnFeatureHtmlLength( oSettings );
3648 }
3649 else if ( cOption == 'f' && features.bFilter )
3650 {
3651 /* Filter */
3652 featureNode = _fnFeatureHtmlFilter( oSettings );
3653 }
3654 else if ( cOption == 'r' && features.bProcessing )
3655 {
3656 /* pRocessing */
3657 featureNode = _fnFeatureHtmlProcessing( oSettings );
3658 }
3659 else if ( cOption == 't' )
3660 {
3661 /* Table */
3662 featureNode = _fnFeatureHtmlTable( oSettings );
3663 }
3664 else if ( cOption == 'i' && features.bInfo )
3665 {
3666 /* Info */
3667 featureNode = _fnFeatureHtmlInfo( oSettings );
3668 }
3669 else if ( cOption == 'p' && features.bPaginate )
3670 {
3671 /* Pagination */
3672 featureNode = _fnFeatureHtmlPaginate( oSettings );
3673 }
3674 else if ( DataTable.ext.feature.length !== 0 )
3675 {
3676 /* Plug-in features */
3677 var aoFeatures = DataTable.ext.feature;
3678 for ( var k=0, kLen=aoFeatures.length ; k<kLen ; k++ )
3679 {
3680 if ( cOption == aoFeatures[k].cFeature )
3681 {
3682 featureNode = aoFeatures[k].fnInit( oSettings );
3683 break;
3684 }
3685 }
3686 }
3687
3688 /* Add to the 2D features array */
3689 if ( featureNode )
3690 {
3691 var aanFeatures = oSettings.aanFeatures;
3692
3693 if ( ! aanFeatures[cOption] )
3694 {
3695 aanFeatures[cOption] = [];
3696 }
3697
3698 aanFeatures[cOption].push( featureNode );
3699 insert.append( featureNode );
3700 }
3701 }
3702
3703 /* Built our DOM structure - replace the holding div with what we want */
3704 holding.replaceWith( insert );
3705 oSettings.nHolding = null;
3706 }
3707
3708
3709 /**
3710 * Use the DOM source to create up an array of header cells. The idea here is to
3711 * create a layout grid (array) of rows x columns, which contains a reference
3712 * to the cell that that point in the grid (regardless of col/rowspan), such that
3713 * any column / row could be removed and the new grid constructed
3714 * @param array {object} aLayout Array to store the calculated layout in
3715 * @param {node} nThead The header/footer element for the table
3716 * @memberof DataTable#oApi
3717 */
3718 function _fnDetectHeader ( aLayout, nThead )
3719 {
3720 var nTrs = $(nThead).children('tr');
3721 var nTr, nCell;
3722 var i, k, l, iLen, jLen, iColShifted, iColumn, iColspan, iRowspan;
3723 var bUnique;
3724 var fnShiftCol = function ( a, i, j ) {
3725 var k = a[i];
3726 while ( k[j] ) {
3727 j++;
3728 }
3729 return j;
3730 };
3731
3732 aLayout.splice( 0, aLayout.length );
3733
3734 /* We know how many rows there are in the layout - so prep it */
3735 for ( i=0, iLen=nTrs.length ; i<iLen ; i++ )
3736 {
3737 aLayout.push( [] );
3738 }
3739
3740 /* Calculate a layout array */
3741 for ( i=0, iLen=nTrs.length ; i<iLen ; i++ )
3742 {
3743 nTr = nTrs[i];
3744 iColumn = 0;
3745
3746 /* For every cell in the row... */
3747 nCell = nTr.firstChild;
3748 while ( nCell ) {
3749 if ( nCell.nodeName.toUpperCase() == "TD" ||
3750 nCell.nodeName.toUpperCase() == "TH" )
3751 {
3752 /* Get the col and rowspan attributes from the DOM and sanitise them */
3753 iColspan = nCell.getAttribute('colspan') * 1;
3754 iRowspan = nCell.getAttribute('rowspan') * 1;
3755 iColspan = (!iColspan || iColspan===0 || iColspan===1) ? 1 : iColspan;
3756 iRowspan = (!iRowspan || iRowspan===0 || iRowspan===1) ? 1 : iRowspan;
3757
3758 /* There might be colspan cells already in this row, so shift our target
3759 * accordingly
3760 */
3761 iColShifted = fnShiftCol( aLayout, i, iColumn );
3762
3763 /* Cache calculation for unique columns */
3764 bUnique = iColspan === 1 ? true : false;
3765
3766 /* If there is col / rowspan, copy the information into the layout grid */
3767 for ( l=0 ; l<iColspan ; l++ )
3768 {
3769 for ( k=0 ; k<iRowspan ; k++ )
3770 {
3771 aLayout[i+k][iColShifted+l] = {
3772 "cell": nCell,
3773 "unique": bUnique
3774 };
3775 aLayout[i+k].nTr = nTr;
3776 }
3777 }
3778 }
3779 nCell = nCell.nextSibling;
3780 }
3781 }
3782 }
3783
3784
3785 /**
3786 * Get an array of unique th elements, one for each column
3787 * @param {object} oSettings dataTables settings object
3788 * @param {node} nHeader automatically detect the layout from this node - optional
3789 * @param {array} aLayout thead/tfoot layout from _fnDetectHeader - optional
3790 * @returns array {node} aReturn list of unique th's
3791 * @memberof DataTable#oApi
3792 */
3793 function _fnGetUniqueThs ( oSettings, nHeader, aLayout )
3794 {
3795 var aReturn = [];
3796 if ( !aLayout )
3797 {
3798 aLayout = oSettings.aoHeader;
3799 if ( nHeader )
3800 {
3801 aLayout = [];
3802 _fnDetectHeader( aLayout, nHeader );
3803 }
3804 }
3805
3806 for ( var i=0, iLen=aLayout.length ; i<iLen ; i++ )
3807 {
3808 for ( var j=0, jLen=aLayout[i].length ; j<jLen ; j++ )
3809 {
3810 if ( aLayout[i][j].unique &&
3811 (!aReturn[j] || !oSettings.bSortCellsTop) )
3812 {
3813 aReturn[j] = aLayout[i][j].cell;
3814 }
3815 }
3816 }
3817
3818 return aReturn;
3819 }
3820
3821 /**
3822 * Create an Ajax call based on the table's settings, taking into account that
3823 * parameters can have multiple forms, and backwards compatibility.
3824 *
3825 * @param {object} oSettings dataTables settings object
3826 * @param {array} data Data to send to the server, required by
3827 * DataTables - may be augmented by developer callbacks
3828 * @param {function} fn Callback function to run when data is obtained
3829 */
3830 function _fnBuildAjax( oSettings, data, fn )
3831 {
3832 // Compatibility with 1.9-, allow fnServerData and event to manipulate
3833 _fnCallbackFire( oSettings, 'aoServerParams', 'serverParams', [data] );
3834
3835 // Convert to object based for 1.10+ if using the old array scheme which can
3836 // come from server-side processing or serverParams
3837 if ( data && $.isArray(data) ) {
3838 var tmp = {};
3839 var rbracket = /(.*?)\[\]$/;
3840
3841 $.each( data, function (key, val) {
3842 var match = val.name.match(rbracket);
3843
3844 if ( match ) {
3845 // Support for arrays
3846 var name = match[0];
3847
3848 if ( ! tmp[ name ] ) {
3849 tmp[ name ] = [];
3850 }
3851 tmp[ name ].push( val.value );
3852 }
3853 else {
3854 tmp[val.name] = val.value;
3855 }
3856 } );
3857 data = tmp;
3858 }
3859
3860 var ajaxData;
3861 var ajax = oSettings.ajax;
3862 var instance = oSettings.oInstance;
3863 var callback = function ( json ) {
3864 _fnCallbackFire( oSettings, null, 'xhr', [oSettings, json, oSettings.jqXHR] );
3865 fn( json );
3866 };
3867
3868 if ( $.isPlainObject( ajax ) && ajax.data )
3869 {
3870 ajaxData = ajax.data;
3871
3872 var newData = typeof ajaxData === 'function' ?
3873 ajaxData( data, oSettings ) : // fn can manipulate data or return
3874 ajaxData; // an object object or array to merge
3875
3876 // If the function returned something, use that alone
3877 data = typeof ajaxData === 'function' && newData ?
3878 newData :
3879 $.extend( true, data, newData );
3880
3881 // Remove the data property as we've resolved it already and don't want
3882 // jQuery to do it again (it is restored at the end of the function)
3883 delete ajax.data;
3884 }
3885
3886 var baseAjax = {
3887 "data": data,
3888 "success": function (json) {
3889 var error = json.error || json.sError;
3890 if ( error ) {
3891 _fnLog( oSettings, 0, error );
3892 }
3893
3894 oSettings.json = json;
3895 callback( json );
3896 },
3897 "dataType": "json",
3898 "cache": false,
3899 "type": oSettings.sServerMethod,
3900 "error": function (xhr, error, thrown) {
3901 var ret = _fnCallbackFire( oSettings, null, 'xhr', [oSettings, null, oSettings.jqXHR] );
3902
3903 if ( $.inArray( true, ret ) === -1 ) {
3904 if ( error == "parsererror" ) {
3905 _fnLog( oSettings, 0, 'Invalid JSON response', 1 );
3906 }
3907 else if ( xhr.readyState === 4 ) {
3908 _fnLog( oSettings, 0, 'Ajax error', 7 );
3909 }
3910 }
3911
3912 _fnProcessingDisplay( oSettings, false );
3913 }
3914 };
3915
3916 // Store the data submitted for the API
3917 oSettings.oAjaxData = data;
3918
3919 // Allow plug-ins and external processes to modify the data
3920 _fnCallbackFire( oSettings, null, 'preXhr', [oSettings, data] );
3921
3922 if ( oSettings.fnServerData )
3923 {
3924 // DataTables 1.9- compatibility
3925 oSettings.fnServerData.call( instance,
3926 oSettings.sAjaxSource,
3927 $.map( data, function (val, key) { // Need to convert back to 1.9 trad format
3928 return { name: key, value: val };
3929 } ),
3930 callback,
3931 oSettings
3932 );
3933 }
3934 else if ( oSettings.sAjaxSource || typeof ajax === 'string' )
3935 {
3936 // DataTables 1.9- compatibility
3937 oSettings.jqXHR = $.ajax( $.extend( baseAjax, {
3938 url: ajax || oSettings.sAjaxSource
3939 } ) );
3940 }
3941 else if ( typeof ajax === 'function' )
3942 {
3943 // Is a function - let the caller define what needs to be done
3944 oSettings.jqXHR = ajax.call( instance, data, callback, oSettings );
3945 }
3946 else
3947 {
3948 // Object to extend the base settings
3949 oSettings.jqXHR = $.ajax( $.extend( baseAjax, ajax ) );
3950
3951 // Restore for next time around
3952 ajax.data = ajaxData;
3953 }
3954 }
3955
3956
3957 /**
3958 * Update the table using an Ajax call
3959 * @param {object} settings dataTables settings object
3960 * @returns {boolean} Block the table drawing or not
3961 * @memberof DataTable#oApi
3962 */
3963 function _fnAjaxUpdate( settings )
3964 {
3965 if ( settings.bAjaxDataGet ) {
3966 settings.iDraw++;
3967 _fnProcessingDisplay( settings, true );
3968
3969 _fnBuildAjax(
3970 settings,
3971 _fnAjaxParameters( settings ),
3972 function(json) {
3973 _fnAjaxUpdateDraw( settings, json );
3974 }
3975 );
3976
3977 return false;
3978 }
3979 return true;
3980 }
3981
3982
3983 /**
3984 * Build up the parameters in an object needed for a server-side processing
3985 * request. Note that this is basically done twice, is different ways - a modern
3986 * method which is used by default in DataTables 1.10 which uses objects and
3987 * arrays, or the 1.9- method with is name / value pairs. 1.9 method is used if
3988 * the sAjaxSource option is used in the initialisation, or the legacyAjax
3989 * option is set.
3990 * @param {object} oSettings dataTables settings object
3991 * @returns {bool} block the table drawing or not
3992 * @memberof DataTable#oApi
3993 */
3994 function _fnAjaxParameters( settings )
3995 {
3996 var
3997 columns = settings.aoColumns,
3998 columnCount = columns.length,
3999 features = settings.oFeatures,
4000 preSearch = settings.oPreviousSearch,
4001 preColSearch = settings.aoPreSearchCols,
4002 i, data = [], dataProp, column, columnSearch,
4003 sort = _fnSortFlatten( settings ),
4004 displayStart = settings._iDisplayStart,
4005 displayLength = features.bPaginate !== false ?
4006 settings._iDisplayLength :
4007 -1;
4008
4009 var param = function ( name, value ) {
4010 data.push( { 'name': name, 'value': value } );
4011 };
4012
4013 // DataTables 1.9- compatible method
4014 param( 'sEcho', settings.iDraw );
4015 param( 'iColumns', columnCount );
4016 param( 'sColumns', _pluck( columns, 'sName' ).join(',') );
4017 param( 'iDisplayStart', displayStart );
4018 param( 'iDisplayLength', displayLength );
4019
4020 // DataTables 1.10+ method
4021 var d = {
4022 draw: settings.iDraw,
4023 columns: [],
4024 order: [],
4025 start: displayStart,
4026 length: displayLength,
4027 search: {
4028 value: preSearch.sSearch,
4029 regex: preSearch.bRegex
4030 }
4031 };
4032
4033 for ( i=0 ; i<columnCount ; i++ ) {
4034 column = columns[i];
4035 columnSearch = preColSearch[i];
4036 dataProp = typeof column.mData=="function" ? 'function' : column.mData ;
4037
4038 d.columns.push( {
4039 data: dataProp,
4040 name: column.sName,
4041 searchable: column.bSearchable,
4042 orderable: column.bSortable,
4043 search: {
4044 value: columnSearch.sSearch,
4045 regex: columnSearch.bRegex
4046 }
4047 } );
4048
4049 param( "mDataProp_"+i, dataProp );
4050
4051 if ( features.bFilter ) {
4052 param( 'sSearch_'+i, columnSearch.sSearch );
4053 param( 'bRegex_'+i, columnSearch.bRegex );
4054 param( 'bSearchable_'+i, column.bSearchable );
4055 }
4056
4057 if ( features.bSort ) {
4058 param( 'bSortable_'+i, column.bSortable );
4059 }
4060 }
4061
4062 if ( features.bFilter ) {
4063 param( 'sSearch', preSearch.sSearch );
4064 param( 'bRegex', preSearch.bRegex );
4065 }
4066
4067 if ( features.bSort ) {
4068 $.each( sort, function ( i, val ) {
4069 d.order.push( { column: val.col, dir: val.dir } );
4070
4071 param( 'iSortCol_'+i, val.col );
4072 param( 'sSortDir_'+i, val.dir );
4073 } );
4074
4075 param( 'iSortingCols', sort.length );
4076 }
4077
4078 // If the legacy.ajax parameter is null, then we automatically decide which
4079 // form to use, based on sAjaxSource
4080 var legacy = DataTable.ext.legacy.ajax;
4081 if ( legacy === null ) {
4082 return settings.sAjaxSource ? data : d;
4083 }
4084
4085 // Otherwise, if legacy has been specified then we use that to decide on the
4086 // form
4087 return legacy ? data : d;
4088 }
4089
4090
4091 /**
4092 * Data the data from the server (nuking the old) and redraw the table
4093 * @param {object} oSettings dataTables settings object
4094 * @param {object} json json data return from the server.
4095 * @param {string} json.sEcho Tracking flag for DataTables to match requests
4096 * @param {int} json.iTotalRecords Number of records in the data set, not accounting for filtering
4097 * @param {int} json.iTotalDisplayRecords Number of records in the data set, accounting for filtering
4098 * @param {array} json.aaData The data to display on this page
4099 * @param {string} [json.sColumns] Column ordering (sName, comma separated)
4100 * @memberof DataTable#oApi
4101 */
4102 function _fnAjaxUpdateDraw ( settings, json )
4103 {
4104 // v1.10 uses camelCase variables, while 1.9 uses Hungarian notation.
4105 // Support both
4106 var compat = function ( old, modern ) {
4107 return json[old] !== undefined ? json[old] : json[modern];
4108 };
4109
4110 var data = _fnAjaxDataSrc( settings, json );
4111 var draw = compat( 'sEcho', 'draw' );
4112 var recordsTotal = compat( 'iTotalRecords', 'recordsTotal' );
4113 var recordsFiltered = compat( 'iTotalDisplayRecords', 'recordsFiltered' );
4114
4115 if ( draw !== undefined ) {
4116 // Protect against out of sequence returns
4117 if ( draw*1 < settings.iDraw ) {
4118 return;
4119 }
4120 settings.iDraw = draw * 1;
4121 }
4122
4123 _fnClearTable( settings );
4124 settings._iRecordsTotal = parseInt(recordsTotal, 10);
4125 settings._iRecordsDisplay = parseInt(recordsFiltered, 10);
4126
4127 for ( var i=0, ien=data.length ; i<ien ; i++ ) {
4128 _fnAddData( settings, data[i] );
4129 }
4130 settings.aiDisplay = settings.aiDisplayMaster.slice();
4131
4132 settings.bAjaxDataGet = false;
4133 _fnDraw( settings );
4134
4135 if ( ! settings._bInitComplete ) {
4136 _fnInitComplete( settings, json );
4137 }
4138
4139 settings.bAjaxDataGet = true;
4140 _fnProcessingDisplay( settings, false );
4141 }
4142
4143
4144 /**
4145 * Get the data from the JSON data source to use for drawing a table. Using
4146 * `_fnGetObjectDataFn` allows the data to be sourced from a property of the
4147 * source object, or from a processing function.
4148 * @param {object} oSettings dataTables settings object
4149 * @param {object} json Data source object / array from the server
4150 * @return {array} Array of data to use
4151 */
4152 function _fnAjaxDataSrc ( oSettings, json )
4153 {
4154 var dataSrc = $.isPlainObject( oSettings.ajax ) && oSettings.ajax.dataSrc !== undefined ?
4155 oSettings.ajax.dataSrc :
4156 oSettings.sAjaxDataProp; // Compatibility with 1.9-.
4157
4158 // Compatibility with 1.9-. In order to read from aaData, check if the
4159 // default has been changed, if not, check for aaData
4160 if ( dataSrc === 'data' ) {
4161 return json.aaData || json[dataSrc];
4162 }
4163
4164 return dataSrc !== "" ?
4165 _fnGetObjectDataFn( dataSrc )( json ) :
4166 json;
4167 }
4168
4169 /**
4170 * Generate the node required for filtering text
4171 * @returns {node} Filter control element
4172 * @param {object} oSettings dataTables settings object
4173 * @memberof DataTable#oApi
4174 */
4175 function _fnFeatureHtmlFilter ( settings )
4176 {
4177 var classes = settings.oClasses;
4178 var tableId = settings.sTableId;
4179 var language = settings.oLanguage;
4180 var previousSearch = settings.oPreviousSearch;
4181 var features = settings.aanFeatures;
4182 var input = '<input type="search" class="'+classes.sFilterInput+'"/>';
4183
4184 var str = language.sSearch;
4185 str = str.match(/_INPUT_/) ?
4186 str.replace('_INPUT_', input) :
4187 str+input;
4188
4189 var filter = $('<div/>', {
4190 'id': ! features.f ? tableId+'_filter' : null,
4191 'class': classes.sFilter
4192 } )
4193 .append( $('<label/>' ).append( str ) );
4194
4195 var searchFn = function() {
4196 /* Update all other filter input elements for the new display */
4197 var n = features.f;
4198 var val = !this.value ? "" : this.value; // mental IE8 fix :-(
4199
4200 /* Now do the filter */
4201 if ( val != previousSearch.sSearch ) {
4202 _fnFilterComplete( settings, {
4203 "sSearch": val,
4204 "bRegex": previousSearch.bRegex,
4205 "bSmart": previousSearch.bSmart ,
4206 "bCaseInsensitive": previousSearch.bCaseInsensitive
4207 } );
4208
4209 // Need to redraw, without resorting
4210 settings._iDisplayStart = 0;
4211 _fnDraw( settings );
4212 }
4213 };
4214
4215 var searchDelay = settings.searchDelay !== null ?
4216 settings.searchDelay :
4217 _fnDataSource( settings ) === 'ssp' ?
4218 400 :
4219 0;
4220
4221 var jqFilter = $('input', filter)
4222 .val( previousSearch.sSearch )
4223 .attr( 'placeholder', language.sSearchPlaceholder )
4224 .on(
4225 'keyup.DT search.DT input.DT paste.DT cut.DT',
4226 searchDelay ?
4227 _fnThrottle( searchFn, searchDelay ) :
4228 searchFn
4229 )
4230 .on( 'mouseup', function(e) {
4231 // Edge fix! Edge 17 does not trigger anything other than mouse events when clicking
4232 // on the clear icon (Edge bug 17584515). This is safe in other browsers as `searchFn`
4233 // checks the value to see if it has changed. In other browsers it won't have.
4234 setTimeout( function () {
4235 searchFn.call(jqFilter[0]);
4236 }, 10);
4237 } )
4238 .on( 'keypress.DT', function(e) {
4239 /* Prevent form submission */
4240 if ( e.keyCode == 13 ) {
4241 return false;
4242 }
4243 } )
4244 .attr('aria-controls', tableId);
4245
4246 // Update the input elements whenever the table is filtered
4247 $(settings.nTable).on( 'search.dt.DT', function ( ev, s ) {
4248 if ( settings === s ) {
4249 // IE9 throws an 'unknown error' if document.activeElement is used
4250 // inside an iframe or frame...
4251 try {
4252 if ( jqFilter[0] !== document.activeElement ) {
4253 jqFilter.val( previousSearch.sSearch );
4254 }
4255 }
4256 catch ( e ) {}
4257 }
4258 } );
4259
4260 return filter[0];
4261 }
4262
4263
4264 /**
4265 * Filter the table using both the global filter and column based filtering
4266 * @param {object} oSettings dataTables settings object
4267 * @param {object} oSearch search information
4268 * @param {int} [iForce] force a research of the master array (1) or not (undefined or 0)
4269 * @memberof DataTable#oApi
4270 */
4271 function _fnFilterComplete ( oSettings, oInput, iForce )
4272 {
4273 var oPrevSearch = oSettings.oPreviousSearch;
4274 var aoPrevSearch = oSettings.aoPreSearchCols;
4275 var fnSaveFilter = function ( oFilter ) {
4276 /* Save the filtering values */
4277 oPrevSearch.sSearch = oFilter.sSearch;
4278 oPrevSearch.bRegex = oFilter.bRegex;
4279 oPrevSearch.bSmart = oFilter.bSmart;
4280 oPrevSearch.bCaseInsensitive = oFilter.bCaseInsensitive;
4281 };
4282 var fnRegex = function ( o ) {
4283 // Backwards compatibility with the bEscapeRegex option
4284 return o.bEscapeRegex !== undefined ? !o.bEscapeRegex : o.bRegex;
4285 };
4286
4287 // Resolve any column types that are unknown due to addition or invalidation
4288 // @todo As per sort - can this be moved into an event handler?
4289 _fnColumnTypes( oSettings );
4290
4291 /* In server-side processing all filtering is done by the server, so no point hanging around here */
4292 if ( _fnDataSource( oSettings ) != 'ssp' )
4293 {
4294 /* Global filter */
4295 _fnFilter( oSettings, oInput.sSearch, iForce, fnRegex(oInput), oInput.bSmart, oInput.bCaseInsensitive );
4296 fnSaveFilter( oInput );
4297
4298 /* Now do the individual column filter */
4299 for ( var i=0 ; i<aoPrevSearch.length ; i++ )
4300 {
4301 _fnFilterColumn( oSettings, aoPrevSearch[i].sSearch, i, fnRegex(aoPrevSearch[i]),
4302 aoPrevSearch[i].bSmart, aoPrevSearch[i].bCaseInsensitive );
4303 }
4304
4305 /* Custom filtering */
4306 _fnFilterCustom( oSettings );
4307 }
4308 else
4309 {
4310 fnSaveFilter( oInput );
4311 }
4312
4313 /* Tell the draw function we have been filtering */
4314 oSettings.bFiltered = true;
4315 _fnCallbackFire( oSettings, null, 'search', [oSettings] );
4316 }
4317
4318
4319 /**
4320 * Apply custom filtering functions
4321 * @param {object} oSettings dataTables settings object
4322 * @memberof DataTable#oApi
4323 */
4324 function _fnFilterCustom( settings )
4325 {
4326 var filters = DataTable.ext.search;
4327 var displayRows = settings.aiDisplay;
4328 var row, rowIdx;
4329
4330 for ( var i=0, ien=filters.length ; i<ien ; i++ ) {
4331 var rows = [];
4332
4333 // Loop over each row and see if it should be included
4334 for ( var j=0, jen=displayRows.length ; j<jen ; j++ ) {
4335 rowIdx = displayRows[ j ];
4336 row = settings.aoData[ rowIdx ];
4337
4338 if ( filters[i]( settings, row._aFilterData, rowIdx, row._aData, j ) ) {
4339 rows.push( rowIdx );
4340 }
4341 }
4342
4343 // So the array reference doesn't break set the results into the
4344 // existing array
4345 displayRows.length = 0;
4346 $.merge( displayRows, rows );
4347 }
4348 }
4349
4350
4351 /**
4352 * Filter the table on a per-column basis
4353 * @param {object} oSettings dataTables settings object
4354 * @param {string} sInput string to filter on
4355 * @param {int} iColumn column to filter
4356 * @param {bool} bRegex treat search string as a regular expression or not
4357 * @param {bool} bSmart use smart filtering or not
4358 * @param {bool} bCaseInsensitive Do case insenstive matching or not
4359 * @memberof DataTable#oApi
4360 */
4361 function _fnFilterColumn ( settings, searchStr, colIdx, regex, smart, caseInsensitive )
4362 {
4363 if ( searchStr === '' ) {
4364 return;
4365 }
4366
4367 var data;
4368 var out = [];
4369 var display = settings.aiDisplay;
4370 var rpSearch = _fnFilterCreateSearch( searchStr, regex, smart, caseInsensitive );
4371
4372 for ( var i=0 ; i<display.length ; i++ ) {
4373 data = settings.aoData[ display[i] ]._aFilterData[ colIdx ];
4374
4375 if ( rpSearch.test( data ) ) {
4376 out.push( display[i] );
4377 }
4378 }
4379
4380 settings.aiDisplay = out;
4381 }
4382
4383
4384 /**
4385 * Filter the data table based on user input and draw the table
4386 * @param {object} settings dataTables settings object
4387 * @param {string} input string to filter on
4388 * @param {int} force optional - force a research of the master array (1) or not (undefined or 0)
4389 * @param {bool} regex treat as a regular expression or not
4390 * @param {bool} smart perform smart filtering or not
4391 * @param {bool} caseInsensitive Do case insenstive matching or not
4392 * @memberof DataTable#oApi
4393 */
4394 function _fnFilter( settings, input, force, regex, smart, caseInsensitive )
4395 {
4396 var rpSearch = _fnFilterCreateSearch( input, regex, smart, caseInsensitive );
4397 var prevSearch = settings.oPreviousSearch.sSearch;
4398 var displayMaster = settings.aiDisplayMaster;
4399 var display, invalidated, i;
4400 var filtered = [];
4401
4402 // Need to take account of custom filtering functions - always filter
4403 if ( DataTable.ext.search.length !== 0 ) {
4404 force = true;
4405 }
4406
4407 // Check if any of the rows were invalidated
4408 invalidated = _fnFilterData( settings );
4409
4410 // If the input is blank - we just want the full data set
4411 if ( input.length <= 0 ) {
4412 settings.aiDisplay = displayMaster.slice();
4413 }
4414 else {
4415 // New search - start from the master array
4416 if ( invalidated ||
4417 force ||
4418 regex ||
4419 prevSearch.length > input.length ||
4420 input.indexOf(prevSearch) !== 0 ||
4421 settings.bSorted // On resort, the display master needs to be
4422 // re-filtered since indexes will have changed
4423 ) {
4424 settings.aiDisplay = displayMaster.slice();
4425 }
4426
4427 // Search the display array
4428 display = settings.aiDisplay;
4429
4430 for ( i=0 ; i<display.length ; i++ ) {
4431 if ( rpSearch.test( settings.aoData[ display[i] ]._sFilterRow ) ) {
4432 filtered.push( display[i] );
4433 }
4434 }
4435
4436 settings.aiDisplay = filtered;
4437 }
4438 }
4439
4440
4441 /**
4442 * Build a regular expression object suitable for searching a table
4443 * @param {string} sSearch string to search for
4444 * @param {bool} bRegex treat as a regular expression or not
4445 * @param {bool} bSmart perform smart filtering or not
4446 * @param {bool} bCaseInsensitive Do case insensitive matching or not
4447 * @returns {RegExp} constructed object
4448 * @memberof DataTable#oApi
4449 */
4450 function _fnFilterCreateSearch( search, regex, smart, caseInsensitive )
4451 {
4452 search = regex ?
4453 search :
4454 _fnEscapeRegex( search );
4455
4456 if ( smart ) {
4457 /* For smart filtering we want to allow the search to work regardless of
4458 * word order. We also want double quoted text to be preserved, so word
4459 * order is important - a la google. So this is what we want to
4460 * generate:
4461 *
4462 * ^(?=.*?\bone\b)(?=.*?\btwo three\b)(?=.*?\bfour\b).*$
4463 */
4464 var a = $.map( search.match( /"[^"]+"|[^ ]+/g ) || [''], function ( word ) {
4465 if ( word.charAt(0) === '"' ) {
4466 var m = word.match( /^"(.*)"$/ );
4467 word = m ? m[1] : word;
4468 }
4469
4470 return word.replace('"', '');
4471 } );
4472
4473 search = '^(?=.*?'+a.join( ')(?=.*?' )+').*$';
4474 }
4475
4476 return new RegExp( search, caseInsensitive ? 'i' : '' );
4477 }
4478
4479
4480 /**
4481 * Escape a string such that it can be used in a regular expression
4482 * @param {string} sVal string to escape
4483 * @returns {string} escaped string
4484 * @memberof DataTable#oApi
4485 */
4486 var _fnEscapeRegex = DataTable.util.escapeRegex;
4487
4488 var __filter_div = $('<div>')[0];
4489 var __filter_div_textContent = __filter_div.textContent !== undefined;
4490
4491 // Update the filtering data for each row if needed (by invalidation or first run)
4492 function _fnFilterData ( settings )
4493 {
4494 var columns = settings.aoColumns;
4495 var column;
4496 var i, j, ien, jen, filterData, cellData, row;
4497 var fomatters = DataTable.ext.type.search;
4498 var wasInvalidated = false;
4499
4500 for ( i=0, ien=settings.aoData.length ; i<ien ; i++ ) {
4501 row = settings.aoData[i];
4502
4503 if ( ! row._aFilterData ) {
4504 filterData = [];
4505
4506 for ( j=0, jen=columns.length ; j<jen ; j++ ) {
4507 column = columns[j];
4508
4509 if ( column.bSearchable ) {
4510 cellData = _fnGetCellData( settings, i, j, 'filter' );
4511
4512 if ( fomatters[ column.sType ] ) {
4513 cellData = fomatters[ column.sType ]( cellData );
4514 }
4515
4516 // Search in DataTables 1.10 is string based. In 1.11 this
4517 // should be altered to also allow strict type checking.
4518 if ( cellData === null ) {
4519 cellData = '';
4520 }
4521
4522 if ( typeof cellData !== 'string' && cellData.toString ) {
4523 cellData = cellData.toString();
4524 }
4525 }
4526 else {
4527 cellData = '';
4528 }
4529
4530 // If it looks like there is an HTML entity in the string,
4531 // attempt to decode it so sorting works as expected. Note that
4532 // we could use a single line of jQuery to do this, but the DOM
4533 // method used here is much faster http://jsperf.com/html-decode
4534 if ( cellData.indexOf && cellData.indexOf('&') !== -1 ) {
4535 __filter_div.innerHTML = cellData;
4536 cellData = __filter_div_textContent ?
4537 __filter_div.textContent :
4538 __filter_div.innerText;
4539 }
4540
4541 if ( cellData.replace ) {
4542 cellData = cellData.replace(/[\r\n\u2028]/g, '');
4543 }
4544
4545 filterData.push( cellData );
4546 }
4547
4548 row._aFilterData = filterData;
4549 row._sFilterRow = filterData.join(' ');
4550 wasInvalidated = true;
4551 }
4552 }
4553
4554 return wasInvalidated;
4555 }
4556
4557
4558 /**
4559 * Convert from the internal Hungarian notation to camelCase for external
4560 * interaction
4561 * @param {object} obj Object to convert
4562 * @returns {object} Inverted object
4563 * @memberof DataTable#oApi
4564 */
4565 function _fnSearchToCamel ( obj )
4566 {
4567 return {
4568 search: obj.sSearch,
4569 smart: obj.bSmart,
4570 regex: obj.bRegex,
4571 caseInsensitive: obj.bCaseInsensitive
4572 };
4573 }
4574
4575
4576
4577 /**
4578 * Convert from camelCase notation to the internal Hungarian. We could use the
4579 * Hungarian convert function here, but this is cleaner
4580 * @param {object} obj Object to convert
4581 * @returns {object} Inverted object
4582 * @memberof DataTable#oApi
4583 */
4584 function _fnSearchToHung ( obj )
4585 {
4586 return {
4587 sSearch: obj.search,
4588 bSmart: obj.smart,
4589 bRegex: obj.regex,
4590 bCaseInsensitive: obj.caseInsensitive
4591 };
4592 }
4593
4594 /**
4595 * Generate the node required for the info display
4596 * @param {object} oSettings dataTables settings object
4597 * @returns {node} Information element
4598 * @memberof DataTable#oApi
4599 */
4600 function _fnFeatureHtmlInfo ( settings )
4601 {
4602 var
4603 tid = settings.sTableId,
4604 nodes = settings.aanFeatures.i,
4605 n = $('<div/>', {
4606 'class': settings.oClasses.sInfo,
4607 'id': ! nodes ? tid+'_info' : null
4608 } );
4609
4610 if ( ! nodes ) {
4611 // Update display on each draw
4612 settings.aoDrawCallback.push( {
4613 "fn": _fnUpdateInfo,
4614 "sName": "information"
4615 } );
4616
4617 n
4618 .attr( 'role', 'status' )
4619 .attr( 'aria-live', 'polite' );
4620
4621 // Table is described by our info div
4622 $(settings.nTable).attr( 'aria-describedby', tid+'_info' );
4623 }
4624
4625 return n[0];
4626 }
4627
4628
4629 /**
4630 * Update the information elements in the display
4631 * @param {object} settings dataTables settings object
4632 * @memberof DataTable#oApi
4633 */
4634 function _fnUpdateInfo ( settings )
4635 {
4636 /* Show information about the table */
4637 var nodes = settings.aanFeatures.i;
4638 if ( nodes.length === 0 ) {
4639 return;
4640 }
4641
4642 var
4643 lang = settings.oLanguage,
4644 start = settings._iDisplayStart+1,
4645 end = settings.fnDisplayEnd(),
4646 max = settings.fnRecordsTotal(),
4647 total = settings.fnRecordsDisplay(),
4648 out = total ?
4649 lang.sInfo :
4650 lang.sInfoEmpty;
4651
4652 if ( total !== max ) {
4653 /* Record set after filtering */
4654 out += ' ' + lang.sInfoFiltered;
4655 }
4656
4657 // Convert the macros
4658 out += lang.sInfoPostFix;
4659 out = _fnInfoMacros( settings, out );
4660
4661 var callback = lang.fnInfoCallback;
4662 if ( callback !== null ) {
4663 out = callback.call( settings.oInstance,
4664 settings, start, end, max, total, out
4665 );
4666 }
4667
4668 $(nodes).html( out );
4669 }
4670
4671
4672 function _fnInfoMacros ( settings, str )
4673 {
4674 // When infinite scrolling, we are always starting at 1. _iDisplayStart is used only
4675 // internally
4676 var
4677 formatter = settings.fnFormatNumber,
4678 start = settings._iDisplayStart+1,
4679 len = settings._iDisplayLength,
4680 vis = settings.fnRecordsDisplay(),
4681 all = len === -1;
4682
4683 return str.
4684 replace(/_START_/g, formatter.call( settings, start ) ).
4685 replace(/_END_/g, formatter.call( settings, settings.fnDisplayEnd() ) ).
4686 replace(/_MAX_/g, formatter.call( settings, settings.fnRecordsTotal() ) ).
4687 replace(/_TOTAL_/g, formatter.call( settings, vis ) ).
4688 replace(/_PAGE_/g, formatter.call( settings, all ? 1 : Math.ceil( start / len ) ) ).
4689 replace(/_PAGES_/g, formatter.call( settings, all ? 1 : Math.ceil( vis / len ) ) );
4690 }
4691
4692
4693
4694 /**
4695 * Draw the table for the first time, adding all required features
4696 * @param {object} settings dataTables settings object
4697 * @memberof DataTable#oApi
4698 */
4699 function _fnInitialise ( settings )
4700 {
4701 var i, iLen, iAjaxStart=settings.iInitDisplayStart;
4702 var columns = settings.aoColumns, column;
4703 var features = settings.oFeatures;
4704 var deferLoading = settings.bDeferLoading; // value modified by the draw
4705
4706 /* Ensure that the table data is fully initialised */
4707 if ( ! settings.bInitialised ) {
4708 setTimeout( function(){ _fnInitialise( settings ); }, 200 );
4709 return;
4710 }
4711
4712 /* Show the display HTML options */
4713 _fnAddOptionsHtml( settings );
4714
4715 /* Build and draw the header / footer for the table */
4716 _fnBuildHead( settings );
4717 _fnDrawHead( settings, settings.aoHeader );
4718 _fnDrawHead( settings, settings.aoFooter );
4719
4720 /* Okay to show that something is going on now */
4721 _fnProcessingDisplay( settings, true );
4722
4723 /* Calculate sizes for columns */
4724 if ( features.bAutoWidth ) {
4725 _fnCalculateColumnWidths( settings );
4726 }
4727
4728 for ( i=0, iLen=columns.length ; i<iLen ; i++ ) {
4729 column = columns[i];
4730
4731 if ( column.sWidth ) {
4732 column.nTh.style.width = _fnStringToCss( column.sWidth );
4733 }
4734 }
4735
4736 _fnCallbackFire( settings, null, 'preInit', [settings] );
4737
4738 // If there is default sorting required - let's do it. The sort function
4739 // will do the drawing for us. Otherwise we draw the table regardless of the
4740 // Ajax source - this allows the table to look initialised for Ajax sourcing
4741 // data (show 'loading' message possibly)
4742 _fnReDraw( settings );
4743
4744 // Server-side processing init complete is done by _fnAjaxUpdateDraw
4745 var dataSrc = _fnDataSource( settings );
4746 if ( dataSrc != 'ssp' || deferLoading ) {
4747 // if there is an ajax source load the data
4748 if ( dataSrc == 'ajax' ) {
4749 _fnBuildAjax( settings, [], function(json) {
4750 var aData = _fnAjaxDataSrc( settings, json );
4751
4752 // Got the data - add it to the table
4753 for ( i=0 ; i<aData.length ; i++ ) {
4754 _fnAddData( settings, aData[i] );
4755 }
4756
4757 // Reset the init display for cookie saving. We've already done
4758 // a filter, and therefore cleared it before. So we need to make
4759 // it appear 'fresh'
4760 settings.iInitDisplayStart = iAjaxStart;
4761
4762 _fnReDraw( settings );
4763
4764 _fnProcessingDisplay( settings, false );
4765 _fnInitComplete( settings, json );
4766 }, settings );
4767 }
4768 else {
4769 _fnProcessingDisplay( settings, false );
4770 _fnInitComplete( settings );
4771 }
4772 }
4773 }
4774
4775
4776 /**
4777 * Draw the table for the first time, adding all required features
4778 * @param {object} oSettings dataTables settings object
4779 * @param {object} [json] JSON from the server that completed the table, if using Ajax source
4780 * with client-side processing (optional)
4781 * @memberof DataTable#oApi
4782 */
4783 function _fnInitComplete ( settings, json )
4784 {
4785 settings._bInitComplete = true;
4786
4787 // When data was added after the initialisation (data or Ajax) we need to
4788 // calculate the column sizing
4789 if ( json || settings.oInit.aaData ) {
4790 _fnAdjustColumnSizing( settings );
4791 }
4792
4793 _fnCallbackFire( settings, null, 'plugin-init', [settings, json] );
4794 _fnCallbackFire( settings, 'aoInitComplete', 'init', [settings, json] );
4795 }
4796
4797
4798 function _fnLengthChange ( settings, val )
4799 {
4800 var len = parseInt( val, 10 );
4801 settings._iDisplayLength = len;
4802
4803 _fnLengthOverflow( settings );
4804
4805 // Fire length change event
4806 _fnCallbackFire( settings, null, 'length', [settings, len] );
4807 }
4808
4809
4810 /**
4811 * Generate the node required for user display length changing
4812 * @param {object} settings dataTables settings object
4813 * @returns {node} Display length feature node
4814 * @memberof DataTable#oApi
4815 */
4816 function _fnFeatureHtmlLength ( settings )
4817 {
4818 var
4819 classes = settings.oClasses,
4820 tableId = settings.sTableId,
4821 menu = settings.aLengthMenu,
4822 d2 = $.isArray( menu[0] ),
4823 lengths = d2 ? menu[0] : menu,
4824 language = d2 ? menu[1] : menu;
4825
4826 var select = $('<select/>', {
4827 'name': tableId+'_length',
4828 'aria-controls': tableId,
4829 'class': classes.sLengthSelect
4830 } );
4831
4832 for ( var i=0, ien=lengths.length ; i<ien ; i++ ) {
4833 select[0][ i ] = new Option(
4834 typeof language[i] === 'number' ?
4835 settings.fnFormatNumber( language[i] ) :
4836 language[i],
4837 lengths[i]
4838 );
4839 }
4840
4841 var div = $('<div><label/></div>').addClass( classes.sLength );
4842 if ( ! settings.aanFeatures.l ) {
4843 div[0].id = tableId+'_length';
4844 }
4845
4846 div.children().append(
4847 settings.oLanguage.sLengthMenu.replace( '_MENU_', select[0].outerHTML )
4848 );
4849
4850 // Can't use `select` variable as user might provide their own and the
4851 // reference is broken by the use of outerHTML
4852 $('select', div)
4853 .val( settings._iDisplayLength )
4854 .on( 'change.DT', function(e) {
4855 _fnLengthChange( settings, $(this).val() );
4856 _fnDraw( settings );
4857 } );
4858
4859 // Update node value whenever anything changes the table's length
4860 $(settings.nTable).on( 'length.dt.DT', function (e, s, len) {
4861 if ( settings === s ) {
4862 $('select', div).val( len );
4863 }
4864 } );
4865
4866 return div[0];
4867 }
4868
4869
4870
4871 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
4872 * Note that most of the paging logic is done in
4873 * DataTable.ext.pager
4874 */
4875
4876 /**
4877 * Generate the node required for default pagination
4878 * @param {object} oSettings dataTables settings object
4879 * @returns {node} Pagination feature node
4880 * @memberof DataTable#oApi
4881 */
4882 function _fnFeatureHtmlPaginate ( settings )
4883 {
4884 var
4885 type = settings.sPaginationType,
4886 plugin = DataTable.ext.pager[ type ],
4887 modern = typeof plugin === 'function',
4888 redraw = function( settings ) {
4889 _fnDraw( settings );
4890 },
4891 node = $('<div/>').addClass( settings.oClasses.sPaging + type )[0],
4892 features = settings.aanFeatures;
4893
4894 if ( ! modern ) {
4895 plugin.fnInit( settings, node, redraw );
4896 }
4897
4898 /* Add a draw callback for the pagination on first instance, to update the paging display */
4899 if ( ! features.p )
4900 {
4901 node.id = settings.sTableId+'_paginate';
4902
4903 settings.aoDrawCallback.push( {
4904 "fn": function( settings ) {
4905 if ( modern ) {
4906 var
4907 start = settings._iDisplayStart,
4908 len = settings._iDisplayLength,
4909 visRecords = settings.fnRecordsDisplay(),
4910 all = len === -1,
4911 page = all ? 0 : Math.ceil( start / len ),
4912 pages = all ? 1 : Math.ceil( visRecords / len ),
4913 buttons = plugin(page, pages),
4914 i, ien;
4915
4916 for ( i=0, ien=features.p.length ; i<ien ; i++ ) {
4917 _fnRenderer( settings, 'pageButton' )(
4918 settings, features.p[i], i, buttons, page, pages
4919 );
4920 }
4921 }
4922 else {
4923 plugin.fnUpdate( settings, redraw );
4924 }
4925 },
4926 "sName": "pagination"
4927 } );
4928 }
4929
4930 return node;
4931 }
4932
4933
4934 /**
4935 * Alter the display settings to change the page
4936 * @param {object} settings DataTables settings object
4937 * @param {string|int} action Paging action to take: "first", "previous",
4938 * "next" or "last" or page number to jump to (integer)
4939 * @param [bool] redraw Automatically draw the update or not
4940 * @returns {bool} true page has changed, false - no change
4941 * @memberof DataTable#oApi
4942 */
4943 function _fnPageChange ( settings, action, redraw )
4944 {
4945 var
4946 start = settings._iDisplayStart,
4947 len = settings._iDisplayLength,
4948 records = settings.fnRecordsDisplay();
4949
4950 if ( records === 0 || len === -1 )
4951 {
4952 start = 0;
4953 }
4954 else if ( typeof action === "number" )
4955 {
4956 start = action * len;
4957
4958 if ( start > records )
4959 {
4960 start = 0;
4961 }
4962 }
4963 else if ( action == "first" )
4964 {
4965 start = 0;
4966 }
4967 else if ( action == "previous" )
4968 {
4969 start = len >= 0 ?
4970 start - len :
4971 0;
4972
4973 if ( start < 0 )
4974 {
4975 start = 0;
4976 }
4977 }
4978 else if ( action == "next" )
4979 {
4980 if ( start + len < records )
4981 {
4982 start += len;
4983 }
4984 }
4985 else if ( action == "last" )
4986 {
4987 start = Math.floor( (records-1) / len) * len;
4988 }
4989 else
4990 {
4991 _fnLog( settings, 0, "Unknown paging action: "+action, 5 );
4992 }
4993
4994 var changed = settings._iDisplayStart !== start;
4995 settings._iDisplayStart = start;
4996
4997 if ( changed ) {
4998 _fnCallbackFire( settings, null, 'page', [settings] );
4999
5000 if ( redraw ) {
5001 _fnDraw( settings );
5002 }
5003 }
5004
5005 return changed;
5006 }
5007
5008
5009
5010 /**
5011 * Generate the node required for the processing node
5012 * @param {object} settings dataTables settings object
5013 * @returns {node} Processing element
5014 * @memberof DataTable#oApi
5015 */
5016 function _fnFeatureHtmlProcessing ( settings )
5017 {
5018 return $('<div/>', {
5019 'id': ! settings.aanFeatures.r ? settings.sTableId+'_processing' : null,
5020 'class': settings.oClasses.sProcessing
5021 } )
5022 .html( settings.oLanguage.sProcessing )
5023 .insertBefore( settings.nTable )[0];
5024 }
5025
5026
5027 /**
5028 * Display or hide the processing indicator
5029 * @param {object} settings dataTables settings object
5030 * @param {bool} show Show the processing indicator (true) or not (false)
5031 * @memberof DataTable#oApi
5032 */
5033 function _fnProcessingDisplay ( settings, show )
5034 {
5035 if ( settings.oFeatures.bProcessing ) {
5036 $(settings.aanFeatures.r).css( 'display', show ? 'block' : 'none' );
5037 }
5038
5039 _fnCallbackFire( settings, null, 'processing', [settings, show] );
5040 }
5041
5042 /**
5043 * Add any control elements for the table - specifically scrolling
5044 * @param {object} settings dataTables settings object
5045 * @returns {node} Node to add to the DOM
5046 * @memberof DataTable#oApi
5047 */
5048 function _fnFeatureHtmlTable ( settings )
5049 {
5050 var table = $(settings.nTable);
5051
5052 // Add the ARIA grid role to the table
5053 table.attr( 'role', 'grid' );
5054
5055 // Scrolling from here on in
5056 var scroll = settings.oScroll;
5057
5058 if ( scroll.sX === '' && scroll.sY === '' ) {
5059 return settings.nTable;
5060 }
5061
5062 var scrollX = scroll.sX;
5063 var scrollY = scroll.sY;
5064 var classes = settings.oClasses;
5065 var caption = table.children('caption');
5066 var captionSide = caption.length ? caption[0]._captionSide : null;
5067 var headerClone = $( table[0].cloneNode(false) );
5068 var footerClone = $( table[0].cloneNode(false) );
5069 var footer = table.children('tfoot');
5070 var _div = '<div/>';
5071 var size = function ( s ) {
5072 return !s ? null : _fnStringToCss( s );
5073 };
5074
5075 if ( ! footer.length ) {
5076 footer = null;
5077 }
5078
5079 /*
5080 * The HTML structure that we want to generate in this function is:
5081 * div - scroller
5082 * div - scroll head
5083 * div - scroll head inner
5084 * table - scroll head table
5085 * thead - thead
5086 * div - scroll body
5087 * table - table (master table)
5088 * thead - thead clone for sizing
5089 * tbody - tbody
5090 * div - scroll foot
5091 * div - scroll foot inner
5092 * table - scroll foot table
5093 * tfoot - tfoot
5094 */
5095 var scroller = $( _div, { 'class': classes.sScrollWrapper } )
5096 .append(
5097 $(_div, { 'class': classes.sScrollHead } )
5098 .css( {
5099 overflow: 'hidden',
5100 position: 'relative',
5101 border: 0,
5102 width: scrollX ? size(scrollX) : '100%'
5103 } )
5104 .append(
5105 $(_div, { 'class': classes.sScrollHeadInner } )
5106 .css( {
5107 'box-sizing': 'content-box',
5108 width: scroll.sXInner || '100%'
5109 } )
5110 .append(
5111 headerClone
5112 .removeAttr('id')
5113 .css( 'margin-left', 0 )
5114 .append( captionSide === 'top' ? caption : null )
5115 .append(
5116 table.children('thead')
5117 )
5118 )
5119 )
5120 )
5121 .append(
5122 $(_div, { 'class': classes.sScrollBody } )
5123 .css( {
5124 position: 'relative',
5125 overflow: 'auto',
5126 width: size( scrollX )
5127 } )
5128 .append( table )
5129 );
5130
5131 if ( footer ) {
5132 scroller.append(
5133 $(_div, { 'class': classes.sScrollFoot } )
5134 .css( {
5135 overflow: 'hidden',
5136 border: 0,
5137 width: scrollX ? size(scrollX) : '100%'
5138 } )
5139 .append(
5140 $(_div, { 'class': classes.sScrollFootInner } )
5141 .append(
5142 footerClone
5143 .removeAttr('id')
5144 .css( 'margin-left', 0 )
5145 .append( captionSide === 'bottom' ? caption : null )
5146 .append(
5147 table.children('tfoot')
5148 )
5149 )
5150 )
5151 );
5152 }
5153
5154 var children = scroller.children();
5155 var scrollHead = children[0];
5156 var scrollBody = children[1];
5157 var scrollFoot = footer ? children[2] : null;
5158
5159 // When the body is scrolled, then we also want to scroll the headers
5160 if ( scrollX ) {
5161 $(scrollBody).on( 'scroll.DT', function (e) {
5162 var scrollLeft = this.scrollLeft;
5163
5164 scrollHead.scrollLeft = scrollLeft;
5165
5166 if ( footer ) {
5167 scrollFoot.scrollLeft = scrollLeft;
5168 }
5169 } );
5170 }
5171
5172 $(scrollBody).css('max-height', scrollY);
5173 if (! scroll.bCollapse) {
5174 $(scrollBody).css('height', scrollY);
5175 }
5176
5177 settings.nScrollHead = scrollHead;
5178 settings.nScrollBody = scrollBody;
5179 settings.nScrollFoot = scrollFoot;
5180
5181 // On redraw - align columns
5182 settings.aoDrawCallback.push( {
5183 "fn": _fnScrollDraw,
5184 "sName": "scrolling"
5185 } );
5186
5187 return scroller[0];
5188 }
5189
5190
5191
5192 /**
5193 * Update the header, footer and body tables for resizing - i.e. column
5194 * alignment.
5195 *
5196 * Welcome to the most horrible function DataTables. The process that this
5197 * function follows is basically:
5198 * 1. Re-create the table inside the scrolling div
5199 * 2. Take live measurements from the DOM
5200 * 3. Apply the measurements to align the columns
5201 * 4. Clean up
5202 *
5203 * @param {object} settings dataTables settings object
5204 * @memberof DataTable#oApi
5205 */
5206 function _fnScrollDraw ( settings )
5207 {
5208 // Given that this is such a monster function, a lot of variables are use
5209 // to try and keep the minimised size as small as possible
5210 var
5211 scroll = settings.oScroll,
5212 scrollX = scroll.sX,
5213 scrollXInner = scroll.sXInner,
5214 scrollY = scroll.sY,
5215 barWidth = scroll.iBarWidth,
5216 divHeader = $(settings.nScrollHead),
5217 divHeaderStyle = divHeader[0].style,
5218 divHeaderInner = divHeader.children('div'),
5219 divHeaderInnerStyle = divHeaderInner[0].style,
5220 divHeaderTable = divHeaderInner.children('table'),
5221 divBodyEl = settings.nScrollBody,
5222 divBody = $(divBodyEl),
5223 divBodyStyle = divBodyEl.style,
5224 divFooter = $(settings.nScrollFoot),
5225 divFooterInner = divFooter.children('div'),
5226 divFooterTable = divFooterInner.children('table'),
5227 header = $(settings.nTHead),
5228 table = $(settings.nTable),
5229 tableEl = table[0],
5230 tableStyle = tableEl.style,
5231 footer = settings.nTFoot ? $(settings.nTFoot) : null,
5232 browser = settings.oBrowser,
5233 ie67 = browser.bScrollOversize,
5234 dtHeaderCells = _pluck( settings.aoColumns, 'nTh' ),
5235 headerTrgEls, footerTrgEls,
5236 headerSrcEls, footerSrcEls,
5237 headerCopy, footerCopy,
5238 headerWidths=[], footerWidths=[],
5239 headerContent=[], footerContent=[],
5240 idx, correction, sanityWidth,
5241 zeroOut = function(nSizer) {
5242 var style = nSizer.style;
5243 style.paddingTop = "0";
5244 style.paddingBottom = "0";
5245 style.borderTopWidth = "0";
5246 style.borderBottomWidth = "0";
5247 style.height = 0;
5248 };
5249
5250 // If the scrollbar visibility has changed from the last draw, we need to
5251 // adjust the column sizes as the table width will have changed to account
5252 // for the scrollbar
5253 var scrollBarVis = divBodyEl.scrollHeight > divBodyEl.clientHeight;
5254
5255 if ( settings.scrollBarVis !== scrollBarVis && settings.scrollBarVis !== undefined ) {
5256 settings.scrollBarVis = scrollBarVis;
5257 _fnAdjustColumnSizing( settings );
5258 return; // adjust column sizing will call this function again
5259 }
5260 else {
5261 settings.scrollBarVis = scrollBarVis;
5262 }
5263
5264 /*
5265 * 1. Re-create the table inside the scrolling div
5266 */
5267
5268 // Remove the old minimised thead and tfoot elements in the inner table
5269 table.children('thead, tfoot').remove();
5270
5271 if ( footer ) {
5272 footerCopy = footer.clone().prependTo( table );
5273 footerTrgEls = footer.find('tr'); // the original tfoot is in its own table and must be sized
5274 footerSrcEls = footerCopy.find('tr');
5275 }
5276
5277 // Clone the current header and footer elements and then place it into the inner table
5278 headerCopy = header.clone().prependTo( table );
5279 headerTrgEls = header.find('tr'); // original header is in its own table
5280 headerSrcEls = headerCopy.find('tr');
5281 headerCopy.find('th, td').removeAttr('tabindex');
5282
5283
5284 /*
5285 * 2. Take live measurements from the DOM - do not alter the DOM itself!
5286 */
5287
5288 // Remove old sizing and apply the calculated column widths
5289 // Get the unique column headers in the newly created (cloned) header. We want to apply the
5290 // calculated sizes to this header
5291 if ( ! scrollX )
5292 {
5293 divBodyStyle.width = '100%';
5294 divHeader[0].style.width = '100%';
5295 }
5296
5297 $.each( _fnGetUniqueThs( settings, headerCopy ), function ( i, el ) {
5298 idx = _fnVisibleToColumnIndex( settings, i );
5299 el.style.width = settings.aoColumns[idx].sWidth;
5300 } );
5301
5302 if ( footer ) {
5303 _fnApplyToChildren( function(n) {
5304 n.style.width = "";
5305 }, footerSrcEls );
5306 }
5307
5308 // Size the table as a whole
5309 sanityWidth = table.outerWidth();
5310 if ( scrollX === "" ) {
5311 // No x scrolling
5312 tableStyle.width = "100%";
5313
5314 // IE7 will make the width of the table when 100% include the scrollbar
5315 // - which is shouldn't. When there is a scrollbar we need to take this
5316 // into account.
5317 if ( ie67 && (table.find('tbody').height() > divBodyEl.offsetHeight ||
5318 divBody.css('overflow-y') == "scroll")
5319 ) {
5320 tableStyle.width = _fnStringToCss( table.outerWidth() - barWidth);
5321 }
5322
5323 // Recalculate the sanity width
5324 sanityWidth = table.outerWidth();
5325 }
5326 else if ( scrollXInner !== "" ) {
5327 // legacy x scroll inner has been given - use it
5328 tableStyle.width = _fnStringToCss(scrollXInner);
5329
5330 // Recalculate the sanity width
5331 sanityWidth = table.outerWidth();
5332 }
5333
5334 // Hidden header should have zero height, so remove padding and borders. Then
5335 // set the width based on the real headers
5336
5337 // Apply all styles in one pass
5338 _fnApplyToChildren( zeroOut, headerSrcEls );
5339
5340 // Read all widths in next pass
5341 _fnApplyToChildren( function(nSizer) {
5342 headerContent.push( nSizer.innerHTML );
5343 headerWidths.push( _fnStringToCss( $(nSizer).css('width') ) );
5344 }, headerSrcEls );
5345
5346 // Apply all widths in final pass
5347 _fnApplyToChildren( function(nToSize, i) {
5348 // Only apply widths to the DataTables detected header cells - this
5349 // prevents complex headers from having contradictory sizes applied
5350 if ( $.inArray( nToSize, dtHeaderCells ) !== -1 ) {
5351 nToSize.style.width = headerWidths[i];
5352 }
5353 }, headerTrgEls );
5354
5355 $(headerSrcEls).height(0);
5356
5357 /* Same again with the footer if we have one */
5358 if ( footer )
5359 {
5360 _fnApplyToChildren( zeroOut, footerSrcEls );
5361
5362 _fnApplyToChildren( function(nSizer) {
5363 footerContent.push( nSizer.innerHTML );
5364 footerWidths.push( _fnStringToCss( $(nSizer).css('width') ) );
5365 }, footerSrcEls );
5366
5367 _fnApplyToChildren( function(nToSize, i) {
5368 nToSize.style.width = footerWidths[i];
5369 }, footerTrgEls );
5370
5371 $(footerSrcEls).height(0);
5372 }
5373
5374
5375 /*
5376 * 3. Apply the measurements
5377 */
5378
5379 // "Hide" the header and footer that we used for the sizing. We need to keep
5380 // the content of the cell so that the width applied to the header and body
5381 // both match, but we want to hide it completely. We want to also fix their
5382 // width to what they currently are
5383 _fnApplyToChildren( function(nSizer, i) {
5384 nSizer.innerHTML = '<div class="dataTables_sizing">'+headerContent[i]+'</div>';
5385 nSizer.childNodes[0].style.height = "0";
5386 nSizer.childNodes[0].style.overflow = "hidden";
5387 nSizer.style.width = headerWidths[i];
5388 }, headerSrcEls );
5389
5390 if ( footer )
5391 {
5392 _fnApplyToChildren( function(nSizer, i) {
5393 nSizer.innerHTML = '<div class="dataTables_sizing">'+footerContent[i]+'</div>';
5394 nSizer.childNodes[0].style.height = "0";
5395 nSizer.childNodes[0].style.overflow = "hidden";
5396 nSizer.style.width = footerWidths[i];
5397 }, footerSrcEls );
5398 }
5399
5400 // Sanity check that the table is of a sensible width. If not then we are going to get
5401 // misalignment - try to prevent this by not allowing the table to shrink below its min width
5402 if ( table.outerWidth() < sanityWidth )
5403 {
5404 // The min width depends upon if we have a vertical scrollbar visible or not */
5405 correction = ((divBodyEl.scrollHeight > divBodyEl.offsetHeight ||
5406 divBody.css('overflow-y') == "scroll")) ?
5407 sanityWidth+barWidth :
5408 sanityWidth;
5409
5410 // IE6/7 are a law unto themselves...
5411 if ( ie67 && (divBodyEl.scrollHeight >
5412 divBodyEl.offsetHeight || divBody.css('overflow-y') == "scroll")
5413 ) {
5414 tableStyle.width = _fnStringToCss( correction-barWidth );
5415 }
5416
5417 // And give the user a warning that we've stopped the table getting too small
5418 if ( scrollX === "" || scrollXInner !== "" ) {
5419 _fnLog( settings, 1, 'Possible column misalignment', 6 );
5420 }
5421 }
5422 else
5423 {
5424 correction = '100%';
5425 }
5426
5427 // Apply to the container elements
5428 divBodyStyle.width = _fnStringToCss( correction );
5429 divHeaderStyle.width = _fnStringToCss( correction );
5430
5431 if ( footer ) {
5432 settings.nScrollFoot.style.width = _fnStringToCss( correction );
5433 }
5434
5435
5436 /*
5437 * 4. Clean up
5438 */
5439 if ( ! scrollY ) {
5440 /* IE7< puts a vertical scrollbar in place (when it shouldn't be) due to subtracting
5441 * the scrollbar height from the visible display, rather than adding it on. We need to
5442 * set the height in order to sort this. Don't want to do it in any other browsers.
5443 */
5444 if ( ie67 ) {
5445 divBodyStyle.height = _fnStringToCss( tableEl.offsetHeight+barWidth );
5446 }
5447 }
5448
5449 /* Finally set the width's of the header and footer tables */
5450 var iOuterWidth = table.outerWidth();
5451 divHeaderTable[0].style.width = _fnStringToCss( iOuterWidth );
5452 divHeaderInnerStyle.width = _fnStringToCss( iOuterWidth );
5453
5454 // Figure out if there are scrollbar present - if so then we need a the header and footer to
5455 // provide a bit more space to allow "overflow" scrolling (i.e. past the scrollbar)
5456 var bScrolling = table.height() > divBodyEl.clientHeight || divBody.css('overflow-y') == "scroll";
5457 var padding = 'padding' + (browser.bScrollbarLeft ? 'Left' : 'Right' );
5458 divHeaderInnerStyle[ padding ] = bScrolling ? barWidth+"px" : "0px";
5459
5460 if ( footer ) {
5461 divFooterTable[0].style.width = _fnStringToCss( iOuterWidth );
5462 divFooterInner[0].style.width = _fnStringToCss( iOuterWidth );
5463 divFooterInner[0].style[padding] = bScrolling ? barWidth+"px" : "0px";
5464 }
5465
5466 // Correct DOM ordering for colgroup - comes before the thead
5467 table.children('colgroup').insertBefore( table.children('thead') );
5468
5469 /* Adjust the position of the header in case we loose the y-scrollbar */
5470 divBody.trigger('scroll');
5471
5472 // If sorting or filtering has occurred, jump the scrolling back to the top
5473 // only if we aren't holding the position
5474 if ( (settings.bSorted || settings.bFiltered) && ! settings._drawHold ) {
5475 divBodyEl.scrollTop = 0;
5476 }
5477 }
5478
5479
5480
5481 /**
5482 * Apply a given function to the display child nodes of an element array (typically
5483 * TD children of TR rows
5484 * @param {function} fn Method to apply to the objects
5485 * @param array {nodes} an1 List of elements to look through for display children
5486 * @param array {nodes} an2 Another list (identical structure to the first) - optional
5487 * @memberof DataTable#oApi
5488 */
5489 function _fnApplyToChildren( fn, an1, an2 )
5490 {
5491 var index=0, i=0, iLen=an1.length;
5492 var nNode1, nNode2;
5493
5494 while ( i < iLen ) {
5495 nNode1 = an1[i].firstChild;
5496 nNode2 = an2 ? an2[i].firstChild : null;
5497
5498 while ( nNode1 ) {
5499 if ( nNode1.nodeType === 1 ) {
5500 if ( an2 ) {
5501 fn( nNode1, nNode2, index );
5502 }
5503 else {
5504 fn( nNode1, index );
5505 }
5506
5507 index++;
5508 }
5509
5510 nNode1 = nNode1.nextSibling;
5511 nNode2 = an2 ? nNode2.nextSibling : null;
5512 }
5513
5514 i++;
5515 }
5516 }
5517
5518
5519
5520 var __re_html_remove = /<.*?>/g;
5521
5522
5523 /**
5524 * Calculate the width of columns for the table
5525 * @param {object} oSettings dataTables settings object
5526 * @memberof DataTable#oApi
5527 */
5528 function _fnCalculateColumnWidths ( oSettings )
5529 {
5530 var
5531 table = oSettings.nTable,
5532 columns = oSettings.aoColumns,
5533 scroll = oSettings.oScroll,
5534 scrollY = scroll.sY,
5535 scrollX = scroll.sX,
5536 scrollXInner = scroll.sXInner,
5537 columnCount = columns.length,
5538 visibleColumns = _fnGetColumns( oSettings, 'bVisible' ),
5539 headerCells = $('th', oSettings.nTHead),
5540 tableWidthAttr = table.getAttribute('width'), // from DOM element
5541 tableContainer = table.parentNode,
5542 userInputs = false,
5543 i, column, columnIdx, width, outerWidth,
5544 browser = oSettings.oBrowser,
5545 ie67 = browser.bScrollOversize;
5546
5547 var styleWidth = table.style.width;
5548 if ( styleWidth && styleWidth.indexOf('%') !== -1 ) {
5549 tableWidthAttr = styleWidth;
5550 }
5551
5552 /* Convert any user input sizes into pixel sizes */
5553 for ( i=0 ; i<visibleColumns.length ; i++ ) {
5554 column = columns[ visibleColumns[i] ];
5555
5556 if ( column.sWidth !== null ) {
5557 column.sWidth = _fnConvertToWidth( column.sWidthOrig, tableContainer );
5558
5559 userInputs = true;
5560 }
5561 }
5562
5563 /* If the number of columns in the DOM equals the number that we have to
5564 * process in DataTables, then we can use the offsets that are created by
5565 * the web- browser. No custom sizes can be set in order for this to happen,
5566 * nor scrolling used
5567 */
5568 if ( ie67 || ! userInputs && ! scrollX && ! scrollY &&
5569 columnCount == _fnVisbleColumns( oSettings ) &&
5570 columnCount == headerCells.length
5571 ) {
5572 for ( i=0 ; i<columnCount ; i++ ) {
5573 var colIdx = _fnVisibleToColumnIndex( oSettings, i );
5574
5575 if ( colIdx !== null ) {
5576 columns[ colIdx ].sWidth = _fnStringToCss( headerCells.eq(i).width() );
5577 }
5578 }
5579 }
5580 else
5581 {
5582 // Otherwise construct a single row, worst case, table with the widest
5583 // node in the data, assign any user defined widths, then insert it into
5584 // the DOM and allow the browser to do all the hard work of calculating
5585 // table widths
5586 var tmpTable = $(table).clone() // don't use cloneNode - IE8 will remove events on the main table
5587 .css( 'visibility', 'hidden' )
5588 .removeAttr( 'id' );
5589
5590 // Clean up the table body
5591 tmpTable.find('tbody tr').remove();
5592 var tr = $('<tr/>').appendTo( tmpTable.find('tbody') );
5593
5594 // Clone the table header and footer - we can't use the header / footer
5595 // from the cloned table, since if scrolling is active, the table's
5596 // real header and footer are contained in different table tags
5597 tmpTable.find('thead, tfoot').remove();
5598 tmpTable
5599 .append( $(oSettings.nTHead).clone() )
5600 .append( $(oSettings.nTFoot).clone() );
5601
5602 // Remove any assigned widths from the footer (from scrolling)
5603 tmpTable.find('tfoot th, tfoot td').css('width', '');
5604
5605 // Apply custom sizing to the cloned header
5606 headerCells = _fnGetUniqueThs( oSettings, tmpTable.find('thead')[0] );
5607
5608 for ( i=0 ; i<visibleColumns.length ; i++ ) {
5609 column = columns[ visibleColumns[i] ];
5610
5611 headerCells[i].style.width = column.sWidthOrig !== null && column.sWidthOrig !== '' ?
5612 _fnStringToCss( column.sWidthOrig ) :
5613 '';
5614
5615 // For scrollX we need to force the column width otherwise the
5616 // browser will collapse it. If this width is smaller than the
5617 // width the column requires, then it will have no effect
5618 if ( column.sWidthOrig && scrollX ) {
5619 $( headerCells[i] ).append( $('<div/>').css( {
5620 width: column.sWidthOrig,
5621 margin: 0,
5622 padding: 0,
5623 border: 0,
5624 height: 1
5625 } ) );
5626 }
5627 }
5628
5629 // Find the widest cell for each column and put it into the table
5630 if ( oSettings.aoData.length ) {
5631 for ( i=0 ; i<visibleColumns.length ; i++ ) {
5632 columnIdx = visibleColumns[i];
5633 column = columns[ columnIdx ];
5634
5635 $( _fnGetWidestNode( oSettings, columnIdx ) )
5636 .clone( false )
5637 .append( column.sContentPadding )
5638 .appendTo( tr );
5639 }
5640 }
5641
5642 // Tidy the temporary table - remove name attributes so there aren't
5643 // duplicated in the dom (radio elements for example)
5644 $('[name]', tmpTable).removeAttr('name');
5645
5646 // Table has been built, attach to the document so we can work with it.
5647 // A holding element is used, positioned at the top of the container
5648 // with minimal height, so it has no effect on if the container scrolls
5649 // or not. Otherwise it might trigger scrolling when it actually isn't
5650 // needed
5651 var holder = $('<div/>').css( scrollX || scrollY ?
5652 {
5653 position: 'absolute',
5654 top: 0,
5655 left: 0,
5656 height: 1,
5657 right: 0,
5658 overflow: 'hidden'
5659 } :
5660 {}
5661 )
5662 .append( tmpTable )
5663 .appendTo( tableContainer );
5664
5665 // When scrolling (X or Y) we want to set the width of the table as
5666 // appropriate. However, when not scrolling leave the table width as it
5667 // is. This results in slightly different, but I think correct behaviour
5668 if ( scrollX && scrollXInner ) {
5669 tmpTable.width( scrollXInner );
5670 }
5671 else if ( scrollX ) {
5672 tmpTable.css( 'width', 'auto' );
5673 tmpTable.removeAttr('width');
5674
5675 // If there is no width attribute or style, then allow the table to
5676 // collapse
5677 if ( tmpTable.width() < tableContainer.clientWidth && tableWidthAttr ) {
5678 tmpTable.width( tableContainer.clientWidth );
5679 }
5680 }
5681 else if ( scrollY ) {
5682 tmpTable.width( tableContainer.clientWidth );
5683 }
5684 else if ( tableWidthAttr ) {
5685 tmpTable.width( tableWidthAttr );
5686 }
5687
5688 // Get the width of each column in the constructed table - we need to
5689 // know the inner width (so it can be assigned to the other table's
5690 // cells) and the outer width so we can calculate the full width of the
5691 // table. This is safe since DataTables requires a unique cell for each
5692 // column, but if ever a header can span multiple columns, this will
5693 // need to be modified.
5694 var total = 0;
5695 for ( i=0 ; i<visibleColumns.length ; i++ ) {
5696 var cell = $(headerCells[i]);
5697 var border = cell.outerWidth() - cell.width();
5698
5699 // Use getBounding... where possible (not IE8-) because it can give
5700 // sub-pixel accuracy, which we then want to round up!
5701 var bounding = browser.bBounding ?
5702 Math.ceil( headerCells[i].getBoundingClientRect().width ) :
5703 cell.outerWidth();
5704
5705 // Total is tracked to remove any sub-pixel errors as the outerWidth
5706 // of the table might not equal the total given here (IE!).
5707 total += bounding;
5708
5709 // Width for each column to use
5710 columns[ visibleColumns[i] ].sWidth = _fnStringToCss( bounding - border );
5711 }
5712
5713 table.style.width = _fnStringToCss( total );
5714
5715 // Finished with the table - ditch it
5716 holder.remove();
5717 }
5718
5719 // If there is a width attr, we want to attach an event listener which
5720 // allows the table sizing to automatically adjust when the window is
5721 // resized. Use the width attr rather than CSS, since we can't know if the
5722 // CSS is a relative value or absolute - DOM read is always px.
5723 if ( tableWidthAttr ) {
5724 table.style.width = _fnStringToCss( tableWidthAttr );
5725 }
5726
5727 if ( (tableWidthAttr || scrollX) && ! oSettings._reszEvt ) {
5728 var bindResize = function () {
5729 $(window).on('resize.DT-'+oSettings.sInstance, _fnThrottle( function () {
5730 _fnAdjustColumnSizing( oSettings );
5731 } ) );
5732 };
5733
5734 // IE6/7 will crash if we bind a resize event handler on page load.
5735 // To be removed in 1.11 which drops IE6/7 support
5736 if ( ie67 ) {
5737 setTimeout( bindResize, 1000 );
5738 }
5739 else {
5740 bindResize();
5741 }
5742
5743 oSettings._reszEvt = true;
5744 }
5745 }
5746
5747
5748 /**
5749 * Throttle the calls to a function. Arguments and context are maintained for
5750 * the throttled function
5751 * @param {function} fn Function to be called
5752 * @param {int} [freq=200] call frequency in mS
5753 * @returns {function} wrapped function
5754 * @memberof DataTable#oApi
5755 */
5756 var _fnThrottle = DataTable.util.throttle;
5757
5758
5759 /**
5760 * Convert a CSS unit width to pixels (e.g. 2em)
5761 * @param {string} width width to be converted
5762 * @param {node} parent parent to get the with for (required for relative widths) - optional
5763 * @returns {int} width in pixels
5764 * @memberof DataTable#oApi
5765 */
5766 function _fnConvertToWidth ( width, parent )
5767 {
5768 if ( ! width ) {
5769 return 0;
5770 }
5771
5772 var n = $('<div/>')
5773 .css( 'width', _fnStringToCss( width ) )
5774 .appendTo( parent || document.body );
5775
5776 var val = n[0].offsetWidth;
5777 n.remove();
5778
5779 return val;
5780 }
5781
5782
5783 /**
5784 * Get the widest node
5785 * @param {object} settings dataTables settings object
5786 * @param {int} colIdx column of interest
5787 * @returns {node} widest table node
5788 * @memberof DataTable#oApi
5789 */
5790 function _fnGetWidestNode( settings, colIdx )
5791 {
5792 var idx = _fnGetMaxLenString( settings, colIdx );
5793 if ( idx < 0 ) {
5794 return null;
5795 }
5796
5797 var data = settings.aoData[ idx ];
5798 return ! data.nTr ? // Might not have been created when deferred rendering
5799 $('<td/>').html( _fnGetCellData( settings, idx, colIdx, 'display' ) )[0] :
5800 data.anCells[ colIdx ];
5801 }
5802
5803
5804 /**
5805 * Get the maximum strlen for each data column
5806 * @param {object} settings dataTables settings object
5807 * @param {int} colIdx column of interest
5808 * @returns {string} max string length for each column
5809 * @memberof DataTable#oApi
5810 */
5811 function _fnGetMaxLenString( settings, colIdx )
5812 {
5813 var s, max=-1, maxIdx = -1;
5814
5815 for ( var i=0, ien=settings.aoData.length ; i<ien ; i++ ) {
5816 s = _fnGetCellData( settings, i, colIdx, 'display' )+'';
5817 s = s.replace( __re_html_remove, '' );
5818 s = s.replace( /&nbsp;/g, ' ' );
5819
5820 if ( s.length > max ) {
5821 max = s.length;
5822 maxIdx = i;
5823 }
5824 }
5825
5826 return maxIdx;
5827 }
5828
5829
5830 /**
5831 * Append a CSS unit (only if required) to a string
5832 * @param {string} value to css-ify
5833 * @returns {string} value with css unit
5834 * @memberof DataTable#oApi
5835 */
5836 function _fnStringToCss( s )
5837 {
5838 if ( s === null ) {
5839 return '0px';
5840 }
5841
5842 if ( typeof s == 'number' ) {
5843 return s < 0 ?
5844 '0px' :
5845 s+'px';
5846 }
5847
5848 // Check it has a unit character already
5849 return s.match(/\d$/) ?
5850 s+'px' :
5851 s;
5852 }
5853
5854
5855
5856 function _fnSortFlatten ( settings )
5857 {
5858 var
5859 i, iLen, k, kLen,
5860 aSort = [],
5861 aiOrig = [],
5862 aoColumns = settings.aoColumns,
5863 aDataSort, iCol, sType, srcCol,
5864 fixed = settings.aaSortingFixed,
5865 fixedObj = $.isPlainObject( fixed ),
5866 nestedSort = [],
5867 add = function ( a ) {
5868 if ( a.length && ! $.isArray( a[0] ) ) {
5869 // 1D array
5870 nestedSort.push( a );
5871 }
5872 else {
5873 // 2D array
5874 $.merge( nestedSort, a );
5875 }
5876 };
5877
5878 // Build the sort array, with pre-fix and post-fix options if they have been
5879 // specified
5880 if ( $.isArray( fixed ) ) {
5881 add( fixed );
5882 }
5883
5884 if ( fixedObj && fixed.pre ) {
5885 add( fixed.pre );
5886 }
5887
5888 add( settings.aaSorting );
5889
5890 if (fixedObj && fixed.post ) {
5891 add( fixed.post );
5892 }
5893
5894 for ( i=0 ; i<nestedSort.length ; i++ )
5895 {
5896 srcCol = nestedSort[i][0];
5897 aDataSort = aoColumns[ srcCol ].aDataSort;
5898
5899 for ( k=0, kLen=aDataSort.length ; k<kLen ; k++ )
5900 {
5901 iCol = aDataSort[k];
5902 sType = aoColumns[ iCol ].sType || 'string';
5903
5904 if ( nestedSort[i]._idx === undefined ) {
5905 nestedSort[i]._idx = $.inArray( nestedSort[i][1], aoColumns[iCol].asSorting );
5906 }
5907
5908 aSort.push( {
5909 src: srcCol,
5910 col: iCol,
5911 dir: nestedSort[i][1],
5912 index: nestedSort[i]._idx,
5913 type: sType,
5914 formatter: DataTable.ext.type.order[ sType+"-pre" ]
5915 } );
5916 }
5917 }
5918
5919 return aSort;
5920 }
5921
5922 /**
5923 * Change the order of the table
5924 * @param {object} oSettings dataTables settings object
5925 * @memberof DataTable#oApi
5926 * @todo This really needs split up!
5927 */
5928 function _fnSort ( oSettings )
5929 {
5930 var
5931 i, ien, iLen, j, jLen, k, kLen,
5932 sDataType, nTh,
5933 aiOrig = [],
5934 oExtSort = DataTable.ext.type.order,
5935 aoData = oSettings.aoData,
5936 aoColumns = oSettings.aoColumns,
5937 aDataSort, data, iCol, sType, oSort,
5938 formatters = 0,
5939 sortCol,
5940 displayMaster = oSettings.aiDisplayMaster,
5941 aSort;
5942
5943 // Resolve any column types that are unknown due to addition or invalidation
5944 // @todo Can this be moved into a 'data-ready' handler which is called when
5945 // data is going to be used in the table?
5946 _fnColumnTypes( oSettings );
5947
5948 aSort = _fnSortFlatten( oSettings );
5949
5950 for ( i=0, ien=aSort.length ; i<ien ; i++ ) {
5951 sortCol = aSort[i];
5952
5953 // Track if we can use the fast sort algorithm
5954 if ( sortCol.formatter ) {
5955 formatters++;
5956 }
5957
5958 // Load the data needed for the sort, for each cell
5959 _fnSortData( oSettings, sortCol.col );
5960 }
5961
5962 /* No sorting required if server-side or no sorting array */
5963 if ( _fnDataSource( oSettings ) != 'ssp' && aSort.length !== 0 )
5964 {
5965 // Create a value - key array of the current row positions such that we can use their
5966 // current position during the sort, if values match, in order to perform stable sorting
5967 for ( i=0, iLen=displayMaster.length ; i<iLen ; i++ ) {
5968 aiOrig[ displayMaster[i] ] = i;
5969 }
5970
5971 /* Do the sort - here we want multi-column sorting based on a given data source (column)
5972 * and sorting function (from oSort) in a certain direction. It's reasonably complex to
5973 * follow on it's own, but this is what we want (example two column sorting):
5974 * fnLocalSorting = function(a,b){
5975 * var iTest;
5976 * iTest = oSort['string-asc']('data11', 'data12');
5977 * if (iTest !== 0)
5978 * return iTest;
5979 * iTest = oSort['numeric-desc']('data21', 'data22');
5980 * if (iTest !== 0)
5981 * return iTest;
5982 * return oSort['numeric-asc']( aiOrig[a], aiOrig[b] );
5983 * }
5984 * Basically we have a test for each sorting column, if the data in that column is equal,
5985 * test the next column. If all columns match, then we use a numeric sort on the row
5986 * positions in the original data array to provide a stable sort.
5987 *
5988 * Note - I know it seems excessive to have two sorting methods, but the first is around
5989 * 15% faster, so the second is only maintained for backwards compatibility with sorting
5990 * methods which do not have a pre-sort formatting function.
5991 */
5992 if ( formatters === aSort.length ) {
5993 // All sort types have formatting functions
5994 displayMaster.sort( function ( a, b ) {
5995 var
5996 x, y, k, test, sort,
5997 len=aSort.length,
5998 dataA = aoData[a]._aSortData,
5999 dataB = aoData[b]._aSortData;
6000
6001 for ( k=0 ; k<len ; k++ ) {
6002 sort = aSort[k];
6003
6004 x = dataA[ sort.col ];
6005 y = dataB[ sort.col ];
6006
6007 test = x<y ? -1 : x>y ? 1 : 0;
6008 if ( test !== 0 ) {
6009 return sort.dir === 'asc' ? test : -test;
6010 }
6011 }
6012
6013 x = aiOrig[a];
6014 y = aiOrig[b];
6015 return x<y ? -1 : x>y ? 1 : 0;
6016 } );
6017 }
6018 else {
6019 // Depreciated - remove in 1.11 (providing a plug-in option)
6020 // Not all sort types have formatting methods, so we have to call their sorting
6021 // methods.
6022 displayMaster.sort( function ( a, b ) {
6023 var
6024 x, y, k, l, test, sort, fn,
6025 len=aSort.length,
6026 dataA = aoData[a]._aSortData,
6027 dataB = aoData[b]._aSortData;
6028
6029 for ( k=0 ; k<len ; k++ ) {
6030 sort = aSort[k];
6031
6032 x = dataA[ sort.col ];
6033 y = dataB[ sort.col ];
6034
6035 fn = oExtSort[ sort.type+"-"+sort.dir ] || oExtSort[ "string-"+sort.dir ];
6036 test = fn( x, y );
6037 if ( test !== 0 ) {
6038 return test;
6039 }
6040 }
6041
6042 x = aiOrig[a];
6043 y = aiOrig[b];
6044 return x<y ? -1 : x>y ? 1 : 0;
6045 } );
6046 }
6047 }
6048
6049 /* Tell the draw function that we have sorted the data */
6050 oSettings.bSorted = true;
6051 }
6052
6053
6054 function _fnSortAria ( settings )
6055 {
6056 var label;
6057 var nextSort;
6058 var columns = settings.aoColumns;
6059 var aSort = _fnSortFlatten( settings );
6060 var oAria = settings.oLanguage.oAria;
6061
6062 // ARIA attributes - need to loop all columns, to update all (removing old
6063 // attributes as needed)
6064 for ( var i=0, iLen=columns.length ; i<iLen ; i++ )
6065 {
6066 var col = columns[i];
6067 var asSorting = col.asSorting;
6068 var sTitle = col.sTitle.replace( /<.*?>/g, "" );
6069 var th = col.nTh;
6070
6071 // IE7 is throwing an error when setting these properties with jQuery's
6072 // attr() and removeAttr() methods...
6073 th.removeAttribute('aria-sort');
6074
6075 /* In ARIA only the first sorting column can be marked as sorting - no multi-sort option */
6076 if ( col.bSortable ) {
6077 if ( aSort.length > 0 && aSort[0].col == i ) {
6078 th.setAttribute('aria-sort', aSort[0].dir=="asc" ? "ascending" : "descending" );
6079 nextSort = asSorting[ aSort[0].index+1 ] || asSorting[0];
6080 }
6081 else {
6082 nextSort = asSorting[0];
6083 }
6084
6085 label = sTitle + ( nextSort === "asc" ?
6086 oAria.sSortAscending :
6087 oAria.sSortDescending
6088 );
6089 }
6090 else {
6091 label = sTitle;
6092 }
6093
6094 th.setAttribute('aria-label', label);
6095 }
6096 }
6097
6098
6099 /**
6100 * Function to run on user sort request
6101 * @param {object} settings dataTables settings object
6102 * @param {node} attachTo node to attach the handler to
6103 * @param {int} colIdx column sorting index
6104 * @param {boolean} [append=false] Append the requested sort to the existing
6105 * sort if true (i.e. multi-column sort)
6106 * @param {function} [callback] callback function
6107 * @memberof DataTable#oApi
6108 */
6109 function _fnSortListener ( settings, colIdx, append, callback )
6110 {
6111 var col = settings.aoColumns[ colIdx ];
6112 var sorting = settings.aaSorting;
6113 var asSorting = col.asSorting;
6114 var nextSortIdx;
6115 var next = function ( a, overflow ) {
6116 var idx = a._idx;
6117 if ( idx === undefined ) {
6118 idx = $.inArray( a[1], asSorting );
6119 }
6120
6121 return idx+1 < asSorting.length ?
6122 idx+1 :
6123 overflow ?
6124 null :
6125 0;
6126 };
6127
6128 // Convert to 2D array if needed
6129 if ( typeof sorting[0] === 'number' ) {
6130 sorting = settings.aaSorting = [ sorting ];
6131 }
6132
6133 // If appending the sort then we are multi-column sorting
6134 if ( append && settings.oFeatures.bSortMulti ) {
6135 // Are we already doing some kind of sort on this column?
6136 var sortIdx = $.inArray( colIdx, _pluck(sorting, '0') );
6137
6138 if ( sortIdx !== -1 ) {
6139 // Yes, modify the sort
6140 nextSortIdx = next( sorting[sortIdx], true );
6141
6142 if ( nextSortIdx === null && sorting.length === 1 ) {
6143 nextSortIdx = 0; // can't remove sorting completely
6144 }
6145
6146 if ( nextSortIdx === null ) {
6147 sorting.splice( sortIdx, 1 );
6148 }
6149 else {
6150 sorting[sortIdx][1] = asSorting[ nextSortIdx ];
6151 sorting[sortIdx]._idx = nextSortIdx;
6152 }
6153 }
6154 else {
6155 // No sort on this column yet
6156 sorting.push( [ colIdx, asSorting[0], 0 ] );
6157 sorting[sorting.length-1]._idx = 0;
6158 }
6159 }
6160 else if ( sorting.length && sorting[0][0] == colIdx ) {
6161 // Single column - already sorting on this column, modify the sort
6162 nextSortIdx = next( sorting[0] );
6163
6164 sorting.length = 1;
6165 sorting[0][1] = asSorting[ nextSortIdx ];
6166 sorting[0]._idx = nextSortIdx;
6167 }
6168 else {
6169 // Single column - sort only on this column
6170 sorting.length = 0;
6171 sorting.push( [ colIdx, asSorting[0] ] );
6172 sorting[0]._idx = 0;
6173 }
6174
6175 // Run the sort by calling a full redraw
6176 _fnReDraw( settings );
6177
6178 // callback used for async user interaction
6179 if ( typeof callback == 'function' ) {
6180 callback( settings );
6181 }
6182 }
6183
6184
6185 /**
6186 * Attach a sort handler (click) to a node
6187 * @param {object} settings dataTables settings object
6188 * @param {node} attachTo node to attach the handler to
6189 * @param {int} colIdx column sorting index
6190 * @param {function} [callback] callback function
6191 * @memberof DataTable#oApi
6192 */
6193 function _fnSortAttachListener ( settings, attachTo, colIdx, callback )
6194 {
6195 var col = settings.aoColumns[ colIdx ];
6196
6197 _fnBindAction( attachTo, {}, function (e) {
6198 /* If the column is not sortable - don't to anything */
6199 if ( col.bSortable === false ) {
6200 return;
6201 }
6202
6203 // If processing is enabled use a timeout to allow the processing
6204 // display to be shown - otherwise to it synchronously
6205 if ( settings.oFeatures.bProcessing ) {
6206 _fnProcessingDisplay( settings, true );
6207
6208 setTimeout( function() {
6209 _fnSortListener( settings, colIdx, e.shiftKey, callback );
6210
6211 // In server-side processing, the draw callback will remove the
6212 // processing display
6213 if ( _fnDataSource( settings ) !== 'ssp' ) {
6214 _fnProcessingDisplay( settings, false );
6215 }
6216 }, 0 );
6217 }
6218 else {
6219 _fnSortListener( settings, colIdx, e.shiftKey, callback );
6220 }
6221 } );
6222 }
6223
6224
6225 /**
6226 * Set the sorting classes on table's body, Note: it is safe to call this function
6227 * when bSort and bSortClasses are false
6228 * @param {object} oSettings dataTables settings object
6229 * @memberof DataTable#oApi
6230 */
6231 function _fnSortingClasses( settings )
6232 {
6233 var oldSort = settings.aLastSort;
6234 var sortClass = settings.oClasses.sSortColumn;
6235 var sort = _fnSortFlatten( settings );
6236 var features = settings.oFeatures;
6237 var i, ien, colIdx;
6238
6239 if ( features.bSort && features.bSortClasses ) {
6240 // Remove old sorting classes
6241 for ( i=0, ien=oldSort.length ; i<ien ; i++ ) {
6242 colIdx = oldSort[i].src;
6243
6244 // Remove column sorting
6245 $( _pluck( settings.aoData, 'anCells', colIdx ) )
6246 .removeClass( sortClass + (i<2 ? i+1 : 3) );
6247 }
6248
6249 // Add new column sorting
6250 for ( i=0, ien=sort.length ; i<ien ; i++ ) {
6251 colIdx = sort[i].src;
6252
6253 $( _pluck( settings.aoData, 'anCells', colIdx ) )
6254 .addClass( sortClass + (i<2 ? i+1 : 3) );
6255 }
6256 }
6257
6258 settings.aLastSort = sort;
6259 }
6260
6261
6262 // Get the data to sort a column, be it from cache, fresh (populating the
6263 // cache), or from a sort formatter
6264 function _fnSortData( settings, idx )
6265 {
6266 // Custom sorting function - provided by the sort data type
6267 var column = settings.aoColumns[ idx ];
6268 var customSort = DataTable.ext.order[ column.sSortDataType ];
6269 var customData;
6270
6271 if ( customSort ) {
6272 customData = customSort.call( settings.oInstance, settings, idx,
6273 _fnColumnIndexToVisible( settings, idx )
6274 );
6275 }
6276
6277 // Use / populate cache
6278 var row, cellData;
6279 var formatter = DataTable.ext.type.order[ column.sType+"-pre" ];
6280
6281 for ( var i=0, ien=settings.aoData.length ; i<ien ; i++ ) {
6282 row = settings.aoData[i];
6283
6284 if ( ! row._aSortData ) {
6285 row._aSortData = [];
6286 }
6287
6288 if ( ! row._aSortData[idx] || customSort ) {
6289 cellData = customSort ?
6290 customData[i] : // If there was a custom sort function, use data from there
6291 _fnGetCellData( settings, i, idx, 'sort' );
6292
6293 row._aSortData[ idx ] = formatter ?
6294 formatter( cellData ) :
6295 cellData;
6296 }
6297 }
6298 }
6299
6300
6301
6302 /**
6303 * Save the state of a table
6304 * @param {object} oSettings dataTables settings object
6305 * @memberof DataTable#oApi
6306 */
6307 function _fnSaveState ( settings )
6308 {
6309 if ( !settings.oFeatures.bStateSave || settings.bDestroying )
6310 {
6311 return;
6312 }
6313
6314 /* Store the interesting variables */
6315 var state = {
6316 time: +new Date(),
6317 start: settings._iDisplayStart,
6318 length: settings._iDisplayLength,
6319 order: $.extend( true, [], settings.aaSorting ),
6320 search: _fnSearchToCamel( settings.oPreviousSearch ),
6321 columns: $.map( settings.aoColumns, function ( col, i ) {
6322 return {
6323 visible: col.bVisible,
6324 search: _fnSearchToCamel( settings.aoPreSearchCols[i] )
6325 };
6326 } )
6327 };
6328
6329 _fnCallbackFire( settings, "aoStateSaveParams", 'stateSaveParams', [settings, state] );
6330
6331 settings.oSavedState = state;
6332 settings.fnStateSaveCallback.call( settings.oInstance, settings, state );
6333 }
6334
6335
6336 /**
6337 * Attempt to load a saved table state
6338 * @param {object} oSettings dataTables settings object
6339 * @param {object} oInit DataTables init object so we can override settings
6340 * @param {function} callback Callback to execute when the state has been loaded
6341 * @memberof DataTable#oApi
6342 */
6343 function _fnLoadState ( settings, oInit, callback )
6344 {
6345 var i, ien;
6346 var columns = settings.aoColumns;
6347 var loaded = function ( s ) {
6348 if ( ! s || ! s.time ) {
6349 callback();
6350 return;
6351 }
6352
6353 // Allow custom and plug-in manipulation functions to alter the saved data set and
6354 // cancelling of loading by returning false
6355 var abStateLoad = _fnCallbackFire( settings, 'aoStateLoadParams', 'stateLoadParams', [settings, s] );
6356 if ( $.inArray( false, abStateLoad ) !== -1 ) {
6357 callback();
6358 return;
6359 }
6360
6361 // Reject old data
6362 var duration = settings.iStateDuration;
6363 if ( duration > 0 && s.time < +new Date() - (duration*1000) ) {
6364 callback();
6365 return;
6366 }
6367
6368 // Number of columns have changed - all bets are off, no restore of settings
6369 if ( s.columns && columns.length !== s.columns.length ) {
6370 callback();
6371 return;
6372 }
6373
6374 // Store the saved state so it might be accessed at any time
6375 settings.oLoadedState = $.extend( true, {}, s );
6376
6377 // Restore key features - todo - for 1.11 this needs to be done by
6378 // subscribed events
6379 if ( s.start !== undefined ) {
6380 settings._iDisplayStart = s.start;
6381 settings.iInitDisplayStart = s.start;
6382 }
6383 if ( s.length !== undefined ) {
6384 settings._iDisplayLength = s.length;
6385 }
6386
6387 // Order
6388 if ( s.order !== undefined ) {
6389 settings.aaSorting = [];
6390 $.each( s.order, function ( i, col ) {
6391 settings.aaSorting.push( col[0] >= columns.length ?
6392 [ 0, col[1] ] :
6393 col
6394 );
6395 } );
6396 }
6397
6398 // Search
6399 if ( s.search !== undefined ) {
6400 $.extend( settings.oPreviousSearch, _fnSearchToHung( s.search ) );
6401 }
6402
6403 // Columns
6404 //
6405 if ( s.columns ) {
6406 for ( i=0, ien=s.columns.length ; i<ien ; i++ ) {
6407 var col = s.columns[i];
6408
6409 // Visibility
6410 if ( col.visible !== undefined ) {
6411 columns[i].bVisible = col.visible;
6412 }
6413
6414 // Search
6415 if ( col.search !== undefined ) {
6416 $.extend( settings.aoPreSearchCols[i], _fnSearchToHung( col.search ) );
6417 }
6418 }
6419 }
6420
6421 _fnCallbackFire( settings, 'aoStateLoaded', 'stateLoaded', [settings, s] );
6422 callback();
6423 };
6424
6425 if ( ! settings.oFeatures.bStateSave ) {
6426 callback();
6427 return;
6428 }
6429
6430 var state = settings.fnStateLoadCallback.call( settings.oInstance, settings, loaded );
6431
6432 if ( state !== undefined ) {
6433 loaded( state );
6434 }
6435 // otherwise, wait for the loaded callback to be executed
6436 }
6437
6438
6439 /**
6440 * Return the settings object for a particular table
6441 * @param {node} table table we are using as a dataTable
6442 * @returns {object} Settings object - or null if not found
6443 * @memberof DataTable#oApi
6444 */
6445 function _fnSettingsFromNode ( table )
6446 {
6447 var settings = DataTable.settings;
6448 var idx = $.inArray( table, _pluck( settings, 'nTable' ) );
6449
6450 return idx !== -1 ?
6451 settings[ idx ] :
6452 null;
6453 }
6454
6455
6456 /**
6457 * Log an error message
6458 * @param {object} settings dataTables settings object
6459 * @param {int} level log error messages, or display them to the user
6460 * @param {string} msg error message
6461 * @param {int} tn Technical note id to get more information about the error.
6462 * @memberof DataTable#oApi
6463 */
6464 function _fnLog( settings, level, msg, tn )
6465 {
6466 msg = 'DataTables warning: '+
6467 (settings ? 'table id='+settings.sTableId+' - ' : '')+msg;
6468
6469 if ( tn ) {
6470 msg += '. For more information about this error, please see '+
6471 'http://datatables.net/tn/'+tn;
6472 }
6473
6474 if ( ! level ) {
6475 // Backwards compatibility pre 1.10
6476 var ext = DataTable.ext;
6477 var type = ext.sErrMode || ext.errMode;
6478
6479 if ( settings ) {
6480 _fnCallbackFire( settings, null, 'error', [ settings, tn, msg ] );
6481 }
6482
6483 if ( type == 'alert' ) {
6484 alert( msg );
6485 }
6486 else if ( type == 'throw' ) {
6487 throw new Error(msg);
6488 }
6489 else if ( typeof type == 'function' ) {
6490 type( settings, tn, msg );
6491 }
6492 }
6493 else if ( window.console && console.log ) {
6494 console.log( msg );
6495 }
6496 }
6497
6498
6499 /**
6500 * See if a property is defined on one object, if so assign it to the other object
6501 * @param {object} ret target object
6502 * @param {object} src source object
6503 * @param {string} name property
6504 * @param {string} [mappedName] name to map too - optional, name used if not given
6505 * @memberof DataTable#oApi
6506 */
6507 function _fnMap( ret, src, name, mappedName )
6508 {
6509 if ( $.isArray( name ) ) {
6510 $.each( name, function (i, val) {
6511 if ( $.isArray( val ) ) {
6512 _fnMap( ret, src, val[0], val[1] );
6513 }
6514 else {
6515 _fnMap( ret, src, val );
6516 }
6517 } );
6518
6519 return;
6520 }
6521
6522 if ( mappedName === undefined ) {
6523 mappedName = name;
6524 }
6525
6526 if ( src[name] !== undefined ) {
6527 ret[mappedName] = src[name];
6528 }
6529 }
6530
6531
6532 /**
6533 * Extend objects - very similar to jQuery.extend, but deep copy objects, and
6534 * shallow copy arrays. The reason we need to do this, is that we don't want to
6535 * deep copy array init values (such as aaSorting) since the dev wouldn't be
6536 * able to override them, but we do want to deep copy arrays.
6537 * @param {object} out Object to extend
6538 * @param {object} extender Object from which the properties will be applied to
6539 * out
6540 * @param {boolean} breakRefs If true, then arrays will be sliced to take an
6541 * independent copy with the exception of the `data` or `aaData` parameters
6542 * if they are present. This is so you can pass in a collection to
6543 * DataTables and have that used as your data source without breaking the
6544 * references
6545 * @returns {object} out Reference, just for convenience - out === the return.
6546 * @memberof DataTable#oApi
6547 * @todo This doesn't take account of arrays inside the deep copied objects.
6548 */
6549 function _fnExtend( out, extender, breakRefs )
6550 {
6551 var val;
6552
6553 for ( var prop in extender ) {
6554 if ( extender.hasOwnProperty(prop) ) {
6555 val = extender[prop];
6556
6557 if ( $.isPlainObject( val ) ) {
6558 if ( ! $.isPlainObject( out[prop] ) ) {
6559 out[prop] = {};
6560 }
6561 $.extend( true, out[prop], val );
6562 }
6563 else if ( breakRefs && prop !== 'data' && prop !== 'aaData' && $.isArray(val) ) {
6564 out[prop] = val.slice();
6565 }
6566 else {
6567 out[prop] = val;
6568 }
6569 }
6570 }
6571
6572 return out;
6573 }
6574
6575
6576 /**
6577 * Bind an event handers to allow a click or return key to activate the callback.
6578 * This is good for accessibility since a return on the keyboard will have the
6579 * same effect as a click, if the element has focus.
6580 * @param {element} n Element to bind the action to
6581 * @param {object} oData Data object to pass to the triggered function
6582 * @param {function} fn Callback function for when the event is triggered
6583 * @memberof DataTable#oApi
6584 */
6585 function _fnBindAction( n, oData, fn )
6586 {
6587 $(n)
6588 .on( 'click.DT', oData, function (e) {
6589 $(n).trigger('blur'); // Remove focus outline for mouse users
6590 fn(e);
6591 } )
6592 .on( 'keypress.DT', oData, function (e){
6593 if ( e.which === 13 ) {
6594 e.preventDefault();
6595 fn(e);
6596 }
6597 } )
6598 .on( 'selectstart.DT', function () {
6599 /* Take the brutal approach to cancelling text selection */
6600 return false;
6601 } );
6602 }
6603
6604
6605 /**
6606 * Register a callback function. Easily allows a callback function to be added to
6607 * an array store of callback functions that can then all be called together.
6608 * @param {object} oSettings dataTables settings object
6609 * @param {string} sStore Name of the array storage for the callbacks in oSettings
6610 * @param {function} fn Function to be called back
6611 * @param {string} sName Identifying name for the callback (i.e. a label)
6612 * @memberof DataTable#oApi
6613 */
6614 function _fnCallbackReg( oSettings, sStore, fn, sName )
6615 {
6616 if ( fn )
6617 {
6618 oSettings[sStore].push( {
6619 "fn": fn,
6620 "sName": sName
6621 } );
6622 }
6623 }
6624
6625
6626 /**
6627 * Fire callback functions and trigger events. Note that the loop over the
6628 * callback array store is done backwards! Further note that you do not want to
6629 * fire off triggers in time sensitive applications (for example cell creation)
6630 * as its slow.
6631 * @param {object} settings dataTables settings object
6632 * @param {string} callbackArr Name of the array storage for the callbacks in
6633 * oSettings
6634 * @param {string} eventName Name of the jQuery custom event to trigger. If
6635 * null no trigger is fired
6636 * @param {array} args Array of arguments to pass to the callback function /
6637 * trigger
6638 * @memberof DataTable#oApi
6639 */
6640 function _fnCallbackFire( settings, callbackArr, eventName, args )
6641 {
6642 var ret = [];
6643
6644 if ( callbackArr ) {
6645 ret = $.map( settings[callbackArr].slice().reverse(), function (val, i) {
6646 return val.fn.apply( settings.oInstance, args );
6647 } );
6648 }
6649
6650 if ( eventName !== null ) {
6651 var e = $.Event( eventName+'.dt' );
6652
6653 $(settings.nTable).trigger( e, args );
6654
6655 ret.push( e.result );
6656 }
6657
6658 return ret;
6659 }
6660
6661
6662 function _fnLengthOverflow ( settings )
6663 {
6664 var
6665 start = settings._iDisplayStart,
6666 end = settings.fnDisplayEnd(),
6667 len = settings._iDisplayLength;
6668
6669 /* If we have space to show extra rows (backing up from the end point - then do so */
6670 if ( start >= end )
6671 {
6672 start = end - len;
6673 }
6674
6675 // Keep the start record on the current page
6676 start -= (start % len);
6677
6678 if ( len === -1 || start < 0 )
6679 {
6680 start = 0;
6681 }
6682
6683 settings._iDisplayStart = start;
6684 }
6685
6686
6687 function _fnRenderer( settings, type )
6688 {
6689 var renderer = settings.renderer;
6690 var host = DataTable.ext.renderer[type];
6691
6692 if ( $.isPlainObject( renderer ) && renderer[type] ) {
6693 // Specific renderer for this type. If available use it, otherwise use
6694 // the default.
6695 return host[renderer[type]] || host._;
6696 }
6697 else if ( typeof renderer === 'string' ) {
6698 // Common renderer - if there is one available for this type use it,
6699 // otherwise use the default
6700 return host[renderer] || host._;
6701 }
6702
6703 // Use the default
6704 return host._;
6705 }
6706
6707
6708 /**
6709 * Detect the data source being used for the table. Used to simplify the code
6710 * a little (ajax) and to make it compress a little smaller.
6711 *
6712 * @param {object} settings dataTables settings object
6713 * @returns {string} Data source
6714 * @memberof DataTable#oApi
6715 */
6716 function _fnDataSource ( settings )
6717 {
6718 if ( settings.oFeatures.bServerSide ) {
6719 return 'ssp';
6720 }
6721 else if ( settings.ajax || settings.sAjaxSource ) {
6722 return 'ajax';
6723 }
6724 return 'dom';
6725 }
6726
6727
6728
6729
6730 /**
6731 * Computed structure of the DataTables API, defined by the options passed to
6732 * `DataTable.Api.register()` when building the API.
6733 *
6734 * The structure is built in order to speed creation and extension of the Api
6735 * objects since the extensions are effectively pre-parsed.
6736 *
6737 * The array is an array of objects with the following structure, where this
6738 * base array represents the Api prototype base:
6739 *
6740 * [
6741 * {
6742 * name: 'data' -- string - Property name
6743 * val: function () {}, -- function - Api method (or undefined if just an object
6744 * methodExt: [ ... ], -- array - Array of Api object definitions to extend the method result
6745 * propExt: [ ... ] -- array - Array of Api object definitions to extend the property
6746 * },
6747 * {
6748 * name: 'row'
6749 * val: {},
6750 * methodExt: [ ... ],
6751 * propExt: [
6752 * {
6753 * name: 'data'
6754 * val: function () {},
6755 * methodExt: [ ... ],
6756 * propExt: [ ... ]
6757 * },
6758 * ...
6759 * ]
6760 * }
6761 * ]
6762 *
6763 * @type {Array}
6764 * @ignore
6765 */
6766 var __apiStruct = [];
6767
6768
6769 /**
6770 * `Array.prototype` reference.
6771 *
6772 * @type object
6773 * @ignore
6774 */
6775 var __arrayProto = Array.prototype;
6776
6777
6778 /**
6779 * Abstraction for `context` parameter of the `Api` constructor to allow it to
6780 * take several different forms for ease of use.
6781 *
6782 * Each of the input parameter types will be converted to a DataTables settings
6783 * object where possible.
6784 *
6785 * @param {string|node|jQuery|object} mixed DataTable identifier. Can be one
6786 * of:
6787 *
6788 * * `string` - jQuery selector. Any DataTables' matching the given selector
6789 * with be found and used.
6790 * * `node` - `TABLE` node which has already been formed into a DataTable.
6791 * * `jQuery` - A jQuery object of `TABLE` nodes.
6792 * * `object` - DataTables settings object
6793 * * `DataTables.Api` - API instance
6794 * @return {array|null} Matching DataTables settings objects. `null` or
6795 * `undefined` is returned if no matching DataTable is found.
6796 * @ignore
6797 */
6798 var _toSettings = function ( mixed )
6799 {
6800 var idx, jq;
6801 var settings = DataTable.settings;
6802 var tables = $.map( settings, function (el, i) {
6803 return el.nTable;
6804 } );
6805
6806 if ( ! mixed ) {
6807 return [];
6808 }
6809 else if ( mixed.nTable && mixed.oApi ) {
6810 // DataTables settings object
6811 return [ mixed ];
6812 }
6813 else if ( mixed.nodeName && mixed.nodeName.toLowerCase() === 'table' ) {
6814 // Table node
6815 idx = $.inArray( mixed, tables );
6816 return idx !== -1 ? [ settings[idx] ] : null;
6817 }
6818 else if ( mixed && typeof mixed.settings === 'function' ) {
6819 return mixed.settings().toArray();
6820 }
6821 else if ( typeof mixed === 'string' ) {
6822 // jQuery selector
6823 jq = $(mixed);
6824 }
6825 else if ( mixed instanceof $ ) {
6826 // jQuery object (also DataTables instance)
6827 jq = mixed;
6828 }
6829
6830 if ( jq ) {
6831 return jq.map( function(i) {
6832 idx = $.inArray( this, tables );
6833 return idx !== -1 ? settings[idx] : null;
6834 } ).toArray();
6835 }
6836 };
6837
6838
6839 /**
6840 * DataTables API class - used to control and interface with one or more
6841 * DataTables enhanced tables.
6842 *
6843 * The API class is heavily based on jQuery, presenting a chainable interface
6844 * that you can use to interact with tables. Each instance of the API class has
6845 * a "context" - i.e. the tables that it will operate on. This could be a single
6846 * table, all tables on a page or a sub-set thereof.
6847 *
6848 * Additionally the API is designed to allow you to easily work with the data in
6849 * the tables, retrieving and manipulating it as required. This is done by
6850 * presenting the API class as an array like interface. The contents of the
6851 * array depend upon the actions requested by each method (for example
6852 * `rows().nodes()` will return an array of nodes, while `rows().data()` will
6853 * return an array of objects or arrays depending upon your table's
6854 * configuration). The API object has a number of array like methods (`push`,
6855 * `pop`, `reverse` etc) as well as additional helper methods (`each`, `pluck`,
6856 * `unique` etc) to assist your working with the data held in a table.
6857 *
6858 * Most methods (those which return an Api instance) are chainable, which means
6859 * the return from a method call also has all of the methods available that the
6860 * top level object had. For example, these two calls are equivalent:
6861 *
6862 * // Not chained
6863 * api.row.add( {...} );
6864 * api.draw();
6865 *
6866 * // Chained
6867 * api.row.add( {...} ).draw();
6868 *
6869 * @class DataTable.Api
6870 * @param {array|object|string|jQuery} context DataTable identifier. This is
6871 * used to define which DataTables enhanced tables this API will operate on.
6872 * Can be one of:
6873 *
6874 * * `string` - jQuery selector. Any DataTables' matching the given selector
6875 * with be found and used.
6876 * * `node` - `TABLE` node which has already been formed into a DataTable.
6877 * * `jQuery` - A jQuery object of `TABLE` nodes.
6878 * * `object` - DataTables settings object
6879 * @param {array} [data] Data to initialise the Api instance with.
6880 *
6881 * @example
6882 * // Direct initialisation during DataTables construction
6883 * var api = $('#example').DataTable();
6884 *
6885 * @example
6886 * // Initialisation using a DataTables jQuery object
6887 * var api = $('#example').dataTable().api();
6888 *
6889 * @example
6890 * // Initialisation as a constructor
6891 * var api = new $.fn.DataTable.Api( 'table.dataTable' );
6892 */
6893 _Api = function ( context, data )
6894 {
6895 if ( ! (this instanceof _Api) ) {
6896 return new _Api( context, data );
6897 }
6898
6899 var settings = [];
6900 var ctxSettings = function ( o ) {
6901 var a = _toSettings( o );
6902 if ( a ) {
6903 settings.push.apply( settings, a );
6904 }
6905 };
6906
6907 if ( $.isArray( context ) ) {
6908 for ( var i=0, ien=context.length ; i<ien ; i++ ) {
6909 ctxSettings( context[i] );
6910 }
6911 }
6912 else {
6913 ctxSettings( context );
6914 }
6915
6916 // Remove duplicates
6917 this.context = _unique( settings );
6918
6919 // Initial data
6920 if ( data ) {
6921 $.merge( this, data );
6922 }
6923
6924 // selector
6925 this.selector = {
6926 rows: null,
6927 cols: null,
6928 opts: null
6929 };
6930
6931 _Api.extend( this, this, __apiStruct );
6932 };
6933
6934 DataTable.Api = _Api;
6935
6936 // Don't destroy the existing prototype, just extend it. Required for jQuery 2's
6937 // isPlainObject.
6938 $.extend( _Api.prototype, {
6939 any: function ()
6940 {
6941 return this.count() !== 0;
6942 },
6943
6944
6945 concat: __arrayProto.concat,
6946
6947
6948 context: [], // array of table settings objects
6949
6950
6951 count: function ()
6952 {
6953 return this.flatten().length;
6954 },
6955
6956
6957 each: function ( fn )
6958 {
6959 for ( var i=0, ien=this.length ; i<ien; i++ ) {
6960 fn.call( this, this[i], i, this );
6961 }
6962
6963 return this;
6964 },
6965
6966
6967 eq: function ( idx )
6968 {
6969 var ctx = this.context;
6970
6971 return ctx.length > idx ?
6972 new _Api( ctx[idx], this[idx] ) :
6973 null;
6974 },
6975
6976
6977 filter: function ( fn )
6978 {
6979 var a = [];
6980
6981 if ( __arrayProto.filter ) {
6982 a = __arrayProto.filter.call( this, fn, this );
6983 }
6984 else {
6985 // Compatibility for browsers without EMCA-252-5 (JS 1.6)
6986 for ( var i=0, ien=this.length ; i<ien ; i++ ) {
6987 if ( fn.call( this, this[i], i, this ) ) {
6988 a.push( this[i] );
6989 }
6990 }
6991 }
6992
6993 return new _Api( this.context, a );
6994 },
6995
6996
6997 flatten: function ()
6998 {
6999 var a = [];
7000 return new _Api( this.context, a.concat.apply( a, this.toArray() ) );
7001 },
7002
7003
7004 join: __arrayProto.join,
7005
7006
7007 indexOf: __arrayProto.indexOf || function (obj, start)
7008 {
7009 for ( var i=(start || 0), ien=this.length ; i<ien ; i++ ) {
7010 if ( this[i] === obj ) {
7011 return i;
7012 }
7013 }
7014 return -1;
7015 },
7016
7017 iterator: function ( flatten, type, fn, alwaysNew ) {
7018 var
7019 a = [], ret,
7020 i, ien, j, jen,
7021 context = this.context,
7022 rows, items, item,
7023 selector = this.selector;
7024
7025 // Argument shifting
7026 if ( typeof flatten === 'string' ) {
7027 alwaysNew = fn;
7028 fn = type;
7029 type = flatten;
7030 flatten = false;
7031 }
7032
7033 for ( i=0, ien=context.length ; i<ien ; i++ ) {
7034 var apiInst = new _Api( context[i] );
7035
7036 if ( type === 'table' ) {
7037 ret = fn.call( apiInst, context[i], i );
7038
7039 if ( ret !== undefined ) {
7040 a.push( ret );
7041 }
7042 }
7043 else if ( type === 'columns' || type === 'rows' ) {
7044 // this has same length as context - one entry for each table
7045 ret = fn.call( apiInst, context[i], this[i], i );
7046
7047 if ( ret !== undefined ) {
7048 a.push( ret );
7049 }
7050 }
7051 else if ( type === 'column' || type === 'column-rows' || type === 'row' || type === 'cell' ) {
7052 // columns and rows share the same structure.
7053 // 'this' is an array of column indexes for each context
7054 items = this[i];
7055
7056 if ( type === 'column-rows' ) {
7057 rows = _selector_row_indexes( context[i], selector.opts );
7058 }
7059
7060 for ( j=0, jen=items.length ; j<jen ; j++ ) {
7061 item = items[j];
7062
7063 if ( type === 'cell' ) {
7064 ret = fn.call( apiInst, context[i], item.row, item.column, i, j );
7065 }
7066 else {
7067 ret = fn.call( apiInst, context[i], item, i, j, rows );
7068 }
7069
7070 if ( ret !== undefined ) {
7071 a.push( ret );
7072 }
7073 }
7074 }
7075 }
7076
7077 if ( a.length || alwaysNew ) {
7078 var api = new _Api( context, flatten ? a.concat.apply( [], a ) : a );
7079 var apiSelector = api.selector;
7080 apiSelector.rows = selector.rows;
7081 apiSelector.cols = selector.cols;
7082 apiSelector.opts = selector.opts;
7083 return api;
7084 }
7085 return this;
7086 },
7087
7088
7089 lastIndexOf: __arrayProto.lastIndexOf || function (obj, start)
7090 {
7091 // Bit cheeky...
7092 return this.indexOf.apply( this.toArray.reverse(), arguments );
7093 },
7094
7095
7096 length: 0,
7097
7098
7099 map: function ( fn )
7100 {
7101 var a = [];
7102
7103 if ( __arrayProto.map ) {
7104 a = __arrayProto.map.call( this, fn, this );
7105 }
7106 else {
7107 // Compatibility for browsers without EMCA-252-5 (JS 1.6)
7108 for ( var i=0, ien=this.length ; i<ien ; i++ ) {
7109 a.push( fn.call( this, this[i], i ) );
7110 }
7111 }
7112
7113 return new _Api( this.context, a );
7114 },
7115
7116
7117 pluck: function ( prop )
7118 {
7119 return this.map( function ( el ) {
7120 return el[ prop ];
7121 } );
7122 },
7123
7124 pop: __arrayProto.pop,
7125
7126
7127 push: __arrayProto.push,
7128
7129
7130 // Does not return an API instance
7131 reduce: __arrayProto.reduce || function ( fn, init )
7132 {
7133 return _fnReduce( this, fn, init, 0, this.length, 1 );
7134 },
7135
7136
7137 reduceRight: __arrayProto.reduceRight || function ( fn, init )
7138 {
7139 return _fnReduce( this, fn, init, this.length-1, -1, -1 );
7140 },
7141
7142
7143 reverse: __arrayProto.reverse,
7144
7145
7146 // Object with rows, columns and opts
7147 selector: null,
7148
7149
7150 shift: __arrayProto.shift,
7151
7152
7153 slice: function () {
7154 return new _Api( this.context, this );
7155 },
7156
7157
7158 sort: __arrayProto.sort, // ? name - order?
7159
7160
7161 splice: __arrayProto.splice,
7162
7163
7164 toArray: function ()
7165 {
7166 return __arrayProto.slice.call( this );
7167 },
7168
7169
7170 to$: function ()
7171 {
7172 return $( this );
7173 },
7174
7175
7176 toJQuery: function ()
7177 {
7178 return $( this );
7179 },
7180
7181
7182 unique: function ()
7183 {
7184 return new _Api( this.context, _unique(this) );
7185 },
7186
7187
7188 unshift: __arrayProto.unshift
7189 } );
7190
7191
7192 _Api.extend = function ( scope, obj, ext )
7193 {
7194 // Only extend API instances and static properties of the API
7195 if ( ! ext.length || ! obj || ( ! (obj instanceof _Api) && ! obj.__dt_wrapper ) ) {
7196 return;
7197 }
7198
7199 var
7200 i, ien,
7201 struct,
7202 methodScoping = function ( scope, fn, struc ) {
7203 return function () {
7204 var ret = fn.apply( scope, arguments );
7205
7206 // Method extension
7207 _Api.extend( ret, ret, struc.methodExt );
7208 return ret;
7209 };
7210 };
7211
7212 for ( i=0, ien=ext.length ; i<ien ; i++ ) {
7213 struct = ext[i];
7214
7215 // Value
7216 obj[ struct.name ] = struct.type === 'function' ?
7217 methodScoping( scope, struct.val, struct ) :
7218 struct.type === 'object' ?
7219 {} :
7220 struct.val;
7221
7222 obj[ struct.name ].__dt_wrapper = true;
7223
7224 // Property extension
7225 _Api.extend( scope, obj[ struct.name ], struct.propExt );
7226 }
7227 };
7228
7229
7230 // @todo - Is there need for an augment function?
7231 // _Api.augment = function ( inst, name )
7232 // {
7233 // // Find src object in the structure from the name
7234 // var parts = name.split('.');
7235
7236 // _Api.extend( inst, obj );
7237 // };
7238
7239
7240 // [
7241 // {
7242 // name: 'data' -- string - Property name
7243 // val: function () {}, -- function - Api method (or undefined if just an object
7244 // methodExt: [ ... ], -- array - Array of Api object definitions to extend the method result
7245 // propExt: [ ... ] -- array - Array of Api object definitions to extend the property
7246 // },
7247 // {
7248 // name: 'row'
7249 // val: {},
7250 // methodExt: [ ... ],
7251 // propExt: [
7252 // {
7253 // name: 'data'
7254 // val: function () {},
7255 // methodExt: [ ... ],
7256 // propExt: [ ... ]
7257 // },
7258 // ...
7259 // ]
7260 // }
7261 // ]
7262
7263 _Api.register = _api_register = function ( name, val )
7264 {
7265 if ( $.isArray( name ) ) {
7266 for ( var j=0, jen=name.length ; j<jen ; j++ ) {
7267 _Api.register( name[j], val );
7268 }
7269 return;
7270 }
7271
7272 var
7273 i, ien,
7274 heir = name.split('.'),
7275 struct = __apiStruct,
7276 key, method;
7277
7278 var find = function ( src, name ) {
7279 for ( var i=0, ien=src.length ; i<ien ; i++ ) {
7280 if ( src[i].name === name ) {
7281 return src[i];
7282 }
7283 }
7284 return null;
7285 };
7286
7287 for ( i=0, ien=heir.length ; i<ien ; i++ ) {
7288 method = heir[i].indexOf('()') !== -1;
7289 key = method ?
7290 heir[i].replace('()', '') :
7291 heir[i];
7292
7293 var src = find( struct, key );
7294 if ( ! src ) {
7295 src = {
7296 name: key,
7297 val: {},
7298 methodExt: [],
7299 propExt: [],
7300 type: 'object'
7301 };
7302 struct.push( src );
7303 }
7304
7305 if ( i === ien-1 ) {
7306 src.val = val;
7307 src.type = typeof val === 'function' ?
7308 'function' :
7309 $.isPlainObject( val ) ?
7310 'object' :
7311 'other';
7312 }
7313 else {
7314 struct = method ?
7315 src.methodExt :
7316 src.propExt;
7317 }
7318 }
7319 };
7320
7321 _Api.registerPlural = _api_registerPlural = function ( pluralName, singularName, val ) {
7322 _Api.register( pluralName, val );
7323
7324 _Api.register( singularName, function () {
7325 var ret = val.apply( this, arguments );
7326
7327 if ( ret === this ) {
7328 // Returned item is the API instance that was passed in, return it
7329 return this;
7330 }
7331 else if ( ret instanceof _Api ) {
7332 // New API instance returned, want the value from the first item
7333 // in the returned array for the singular result.
7334 return ret.length ?
7335 $.isArray( ret[0] ) ?
7336 new _Api( ret.context, ret[0] ) : // Array results are 'enhanced'
7337 ret[0] :
7338 undefined;
7339 }
7340
7341 // Non-API return - just fire it back
7342 return ret;
7343 } );
7344 };
7345
7346
7347 /**
7348 * Selector for HTML tables. Apply the given selector to the give array of
7349 * DataTables settings objects.
7350 *
7351 * @param {string|integer} [selector] jQuery selector string or integer
7352 * @param {array} Array of DataTables settings objects to be filtered
7353 * @return {array}
7354 * @ignore
7355 */
7356 var __table_selector = function ( selector, a )
7357 {
7358 if ( $.isArray(selector) ) {
7359 return $.map( selector, function (item) {
7360 return __table_selector(item, a);
7361 } );
7362 }
7363
7364 // Integer is used to pick out a table by index
7365 if ( typeof selector === 'number' ) {
7366 return [ a[ selector ] ];
7367 }
7368
7369 // Perform a jQuery selector on the table nodes
7370 var nodes = $.map( a, function (el, i) {
7371 return el.nTable;
7372 } );
7373
7374 return $(nodes)
7375 .filter( selector )
7376 .map( function (i) {
7377 // Need to translate back from the table node to the settings
7378 var idx = $.inArray( this, nodes );
7379 return a[ idx ];
7380 } )
7381 .toArray();
7382 };
7383
7384
7385
7386 /**
7387 * Context selector for the API's context (i.e. the tables the API instance
7388 * refers to.
7389 *
7390 * @name DataTable.Api#tables
7391 * @param {string|integer} [selector] Selector to pick which tables the iterator
7392 * should operate on. If not given, all tables in the current context are
7393 * used. This can be given as a jQuery selector (for example `':gt(0)'`) to
7394 * select multiple tables or as an integer to select a single table.
7395 * @returns {DataTable.Api} Returns a new API instance if a selector is given.
7396 */
7397 _api_register( 'tables()', function ( selector ) {
7398 // A new instance is created if there was a selector specified
7399 return selector !== undefined && selector !== null ?
7400 new _Api( __table_selector( selector, this.context ) ) :
7401 this;
7402 } );
7403
7404
7405 _api_register( 'table()', function ( selector ) {
7406 var tables = this.tables( selector );
7407 var ctx = tables.context;
7408
7409 // Truncate to the first matched table
7410 return ctx.length ?
7411 new _Api( ctx[0] ) :
7412 tables;
7413 } );
7414
7415
7416 _api_registerPlural( 'tables().nodes()', 'table().node()' , function () {
7417 return this.iterator( 'table', function ( ctx ) {
7418 return ctx.nTable;
7419 }, 1 );
7420 } );
7421
7422
7423 _api_registerPlural( 'tables().body()', 'table().body()' , function () {
7424 return this.iterator( 'table', function ( ctx ) {
7425 return ctx.nTBody;
7426 }, 1 );
7427 } );
7428
7429
7430 _api_registerPlural( 'tables().header()', 'table().header()' , function () {
7431 return this.iterator( 'table', function ( ctx ) {
7432 return ctx.nTHead;
7433 }, 1 );
7434 } );
7435
7436
7437 _api_registerPlural( 'tables().footer()', 'table().footer()' , function () {
7438 return this.iterator( 'table', function ( ctx ) {
7439 return ctx.nTFoot;
7440 }, 1 );
7441 } );
7442
7443
7444 _api_registerPlural( 'tables().containers()', 'table().container()' , function () {
7445 return this.iterator( 'table', function ( ctx ) {
7446 return ctx.nTableWrapper;
7447 }, 1 );
7448 } );
7449
7450
7451
7452 /**
7453 * Redraw the tables in the current context.
7454 */
7455 _api_register( 'draw()', function ( paging ) {
7456 return this.iterator( 'table', function ( settings ) {
7457 if ( paging === 'page' ) {
7458 _fnDraw( settings );
7459 }
7460 else {
7461 if ( typeof paging === 'string' ) {
7462 paging = paging === 'full-hold' ?
7463 false :
7464 true;
7465 }
7466
7467 _fnReDraw( settings, paging===false );
7468 }
7469 } );
7470 } );
7471
7472
7473
7474 /**
7475 * Get the current page index.
7476 *
7477 * @return {integer} Current page index (zero based)
7478 *//**
7479 * Set the current page.
7480 *
7481 * Note that if you attempt to show a page which does not exist, DataTables will
7482 * not throw an error, but rather reset the paging.
7483 *
7484 * @param {integer|string} action The paging action to take. This can be one of:
7485 * * `integer` - The page index to jump to
7486 * * `string` - An action to take:
7487 * * `first` - Jump to first page.
7488 * * `next` - Jump to the next page
7489 * * `previous` - Jump to previous page
7490 * * `last` - Jump to the last page.
7491 * @returns {DataTables.Api} this
7492 */
7493 _api_register( 'page()', function ( action ) {
7494 if ( action === undefined ) {
7495 return this.page.info().page; // not an expensive call
7496 }
7497
7498 // else, have an action to take on all tables
7499 return this.iterator( 'table', function ( settings ) {
7500 _fnPageChange( settings, action );
7501 } );
7502 } );
7503
7504
7505 /**
7506 * Paging information for the first table in the current context.
7507 *
7508 * If you require paging information for another table, use the `table()` method
7509 * with a suitable selector.
7510 *
7511 * @return {object} Object with the following properties set:
7512 * * `page` - Current page index (zero based - i.e. the first page is `0`)
7513 * * `pages` - Total number of pages
7514 * * `start` - Display index for the first record shown on the current page
7515 * * `end` - Display index for the last record shown on the current page
7516 * * `length` - Display length (number of records). Note that generally `start
7517 * + length = end`, but this is not always true, for example if there are
7518 * only 2 records to show on the final page, with a length of 10.
7519 * * `recordsTotal` - Full data set length
7520 * * `recordsDisplay` - Data set length once the current filtering criterion
7521 * are applied.
7522 */
7523 _api_register( 'page.info()', function ( action ) {
7524 if ( this.context.length === 0 ) {
7525 return undefined;
7526 }
7527
7528 var
7529 settings = this.context[0],
7530 start = settings._iDisplayStart,
7531 len = settings.oFeatures.bPaginate ? settings._iDisplayLength : -1,
7532 visRecords = settings.fnRecordsDisplay(),
7533 all = len === -1;
7534
7535 return {
7536 "page": all ? 0 : Math.floor( start / len ),
7537 "pages": all ? 1 : Math.ceil( visRecords / len ),
7538 "start": start,
7539 "end": settings.fnDisplayEnd(),
7540 "length": len,
7541 "recordsTotal": settings.fnRecordsTotal(),
7542 "recordsDisplay": visRecords,
7543 "serverSide": _fnDataSource( settings ) === 'ssp'
7544 };
7545 } );
7546
7547
7548 /**
7549 * Get the current page length.
7550 *
7551 * @return {integer} Current page length. Note `-1` indicates that all records
7552 * are to be shown.
7553 *//**
7554 * Set the current page length.
7555 *
7556 * @param {integer} Page length to set. Use `-1` to show all records.
7557 * @returns {DataTables.Api} this
7558 */
7559 _api_register( 'page.len()', function ( len ) {
7560 // Note that we can't call this function 'length()' because `length`
7561 // is a Javascript property of functions which defines how many arguments
7562 // the function expects.
7563 if ( len === undefined ) {
7564 return this.context.length !== 0 ?
7565 this.context[0]._iDisplayLength :
7566 undefined;
7567 }
7568
7569 // else, set the page length
7570 return this.iterator( 'table', function ( settings ) {
7571 _fnLengthChange( settings, len );
7572 } );
7573 } );
7574
7575
7576
7577 var __reload = function ( settings, holdPosition, callback ) {
7578 // Use the draw event to trigger a callback
7579 if ( callback ) {
7580 var api = new _Api( settings );
7581
7582 api.one( 'draw', function () {
7583 callback( api.ajax.json() );
7584 } );
7585 }
7586
7587 if ( _fnDataSource( settings ) == 'ssp' ) {
7588 _fnReDraw( settings, holdPosition );
7589 }
7590 else {
7591 _fnProcessingDisplay( settings, true );
7592
7593 // Cancel an existing request
7594 var xhr = settings.jqXHR;
7595 if ( xhr && xhr.readyState !== 4 ) {
7596 xhr.abort();
7597 }
7598
7599 // Trigger xhr
7600 _fnBuildAjax( settings, [], function( json ) {
7601 _fnClearTable( settings );
7602
7603 var data = _fnAjaxDataSrc( settings, json );
7604 for ( var i=0, ien=data.length ; i<ien ; i++ ) {
7605 _fnAddData( settings, data[i] );
7606 }
7607
7608 _fnReDraw( settings, holdPosition );
7609 _fnProcessingDisplay( settings, false );
7610 } );
7611 }
7612 };
7613
7614
7615 /**
7616 * Get the JSON response from the last Ajax request that DataTables made to the
7617 * server. Note that this returns the JSON from the first table in the current
7618 * context.
7619 *
7620 * @return {object} JSON received from the server.
7621 */
7622 _api_register( 'ajax.json()', function () {
7623 var ctx = this.context;
7624
7625 if ( ctx.length > 0 ) {
7626 return ctx[0].json;
7627 }
7628
7629 // else return undefined;
7630 } );
7631
7632
7633 /**
7634 * Get the data submitted in the last Ajax request
7635 */
7636 _api_register( 'ajax.params()', function () {
7637 var ctx = this.context;
7638
7639 if ( ctx.length > 0 ) {
7640 return ctx[0].oAjaxData;
7641 }
7642
7643 // else return undefined;
7644 } );
7645
7646
7647 /**
7648 * Reload tables from the Ajax data source. Note that this function will
7649 * automatically re-draw the table when the remote data has been loaded.
7650 *
7651 * @param {boolean} [reset=true] Reset (default) or hold the current paging
7652 * position. A full re-sort and re-filter is performed when this method is
7653 * called, which is why the pagination reset is the default action.
7654 * @returns {DataTables.Api} this
7655 */
7656 _api_register( 'ajax.reload()', function ( callback, resetPaging ) {
7657 return this.iterator( 'table', function (settings) {
7658 __reload( settings, resetPaging===false, callback );
7659 } );
7660 } );
7661
7662
7663 /**
7664 * Get the current Ajax URL. Note that this returns the URL from the first
7665 * table in the current context.
7666 *
7667 * @return {string} Current Ajax source URL
7668 *//**
7669 * Set the Ajax URL. Note that this will set the URL for all tables in the
7670 * current context.
7671 *
7672 * @param {string} url URL to set.
7673 * @returns {DataTables.Api} this
7674 */
7675 _api_register( 'ajax.url()', function ( url ) {
7676 var ctx = this.context;
7677
7678 if ( url === undefined ) {
7679 // get
7680 if ( ctx.length === 0 ) {
7681 return undefined;
7682 }
7683 ctx = ctx[0];
7684
7685 return ctx.ajax ?
7686 $.isPlainObject( ctx.ajax ) ?
7687 ctx.ajax.url :
7688 ctx.ajax :
7689 ctx.sAjaxSource;
7690 }
7691
7692 // set
7693 return this.iterator( 'table', function ( settings ) {
7694 if ( $.isPlainObject( settings.ajax ) ) {
7695 settings.ajax.url = url;
7696 }
7697 else {
7698 settings.ajax = url;
7699 }
7700 // No need to consider sAjaxSource here since DataTables gives priority
7701 // to `ajax` over `sAjaxSource`. So setting `ajax` here, renders any
7702 // value of `sAjaxSource` redundant.
7703 } );
7704 } );
7705
7706
7707 /**
7708 * Load data from the newly set Ajax URL. Note that this method is only
7709 * available when `ajax.url()` is used to set a URL. Additionally, this method
7710 * has the same effect as calling `ajax.reload()` but is provided for
7711 * convenience when setting a new URL. Like `ajax.reload()` it will
7712 * automatically redraw the table once the remote data has been loaded.
7713 *
7714 * @returns {DataTables.Api} this
7715 */
7716 _api_register( 'ajax.url().load()', function ( callback, resetPaging ) {
7717 // Same as a reload, but makes sense to present it for easy access after a
7718 // url change
7719 return this.iterator( 'table', function ( ctx ) {
7720 __reload( ctx, resetPaging===false, callback );
7721 } );
7722 } );
7723
7724
7725
7726
7727 var _selector_run = function ( type, selector, selectFn, settings, opts )
7728 {
7729 var
7730 out = [], res,
7731 a, i, ien, j, jen,
7732 selectorType = typeof selector;
7733
7734 // Can't just check for isArray here, as an API or jQuery instance might be
7735 // given with their array like look
7736 if ( ! selector || selectorType === 'string' || selectorType === 'function' || selector.length === undefined ) {
7737 selector = [ selector ];
7738 }
7739
7740 for ( i=0, ien=selector.length ; i<ien ; i++ ) {
7741 // Only split on simple strings - complex expressions will be jQuery selectors
7742 a = selector[i] && selector[i].split && ! selector[i].match(/[\[\(:]/) ?
7743 selector[i].split(',') :
7744 [ selector[i] ];
7745
7746 for ( j=0, jen=a.length ; j<jen ; j++ ) {
7747 res = selectFn( typeof a[j] === 'string' ? $.trim(a[j]) : a[j] );
7748
7749 if ( res && res.length ) {
7750 out = out.concat( res );
7751 }
7752 }
7753 }
7754
7755 // selector extensions
7756 var ext = _ext.selector[ type ];
7757 if ( ext.length ) {
7758 for ( i=0, ien=ext.length ; i<ien ; i++ ) {
7759 out = ext[i]( settings, opts, out );
7760 }
7761 }
7762
7763 return _unique( out );
7764 };
7765
7766
7767 var _selector_opts = function ( opts )
7768 {
7769 if ( ! opts ) {
7770 opts = {};
7771 }
7772
7773 // Backwards compatibility for 1.9- which used the terminology filter rather
7774 // than search
7775 if ( opts.filter && opts.search === undefined ) {
7776 opts.search = opts.filter;
7777 }
7778
7779 return $.extend( {
7780 search: 'none',
7781 order: 'current',
7782 page: 'all'
7783 }, opts );
7784 };
7785
7786
7787 var _selector_first = function ( inst )
7788 {
7789 // Reduce the API instance to the first item found
7790 for ( var i=0, ien=inst.length ; i<ien ; i++ ) {
7791 if ( inst[i].length > 0 ) {
7792 // Assign the first element to the first item in the instance
7793 // and truncate the instance and context
7794 inst[0] = inst[i];
7795 inst[0].length = 1;
7796 inst.length = 1;
7797 inst.context = [ inst.context[i] ];
7798
7799 return inst;
7800 }
7801 }
7802
7803 // Not found - return an empty instance
7804 inst.length = 0;
7805 return inst;
7806 };
7807
7808
7809 var _selector_row_indexes = function ( settings, opts )
7810 {
7811 var
7812 i, ien, tmp, a=[],
7813 displayFiltered = settings.aiDisplay,
7814 displayMaster = settings.aiDisplayMaster;
7815
7816 var
7817 search = opts.search, // none, applied, removed
7818 order = opts.order, // applied, current, index (original - compatibility with 1.9)
7819 page = opts.page; // all, current
7820
7821 if ( _fnDataSource( settings ) == 'ssp' ) {
7822 // In server-side processing mode, most options are irrelevant since
7823 // rows not shown don't exist and the index order is the applied order
7824 // Removed is a special case - for consistency just return an empty
7825 // array
7826 return search === 'removed' ?
7827 [] :
7828 _range( 0, displayMaster.length );
7829 }
7830 else if ( page == 'current' ) {
7831 // Current page implies that order=current and fitler=applied, since it is
7832 // fairly senseless otherwise, regardless of what order and search actually
7833 // are
7834 for ( i=settings._iDisplayStart, ien=settings.fnDisplayEnd() ; i<ien ; i++ ) {
7835 a.push( displayFiltered[i] );
7836 }
7837 }
7838 else if ( order == 'current' || order == 'applied' ) {
7839 if ( search == 'none') {
7840 a = displayMaster.slice();
7841 }
7842 else if ( search == 'applied' ) {
7843 a = displayFiltered.slice();
7844 }
7845 else if ( search == 'removed' ) {
7846 // O(n+m) solution by creating a hash map
7847 var displayFilteredMap = {};
7848
7849 for ( var i=0, ien=displayFiltered.length ; i<ien ; i++ ) {
7850 displayFilteredMap[displayFiltered[i]] = null;
7851 }
7852
7853 a = $.map( displayMaster, function (el) {
7854 return ! displayFilteredMap.hasOwnProperty(el) ?
7855 el :
7856 null;
7857 } );
7858 }
7859 }
7860 else if ( order == 'index' || order == 'original' ) {
7861 for ( i=0, ien=settings.aoData.length ; i<ien ; i++ ) {
7862 if ( search == 'none' ) {
7863 a.push( i );
7864 }
7865 else { // applied | removed
7866 tmp = $.inArray( i, displayFiltered );
7867
7868 if ((tmp === -1 && search == 'removed') ||
7869 (tmp >= 0 && search == 'applied') )
7870 {
7871 a.push( i );
7872 }
7873 }
7874 }
7875 }
7876
7877 return a;
7878 };
7879
7880
7881 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
7882 * Rows
7883 *
7884 * {} - no selector - use all available rows
7885 * {integer} - row aoData index
7886 * {node} - TR node
7887 * {string} - jQuery selector to apply to the TR elements
7888 * {array} - jQuery array of nodes, or simply an array of TR nodes
7889 *
7890 */
7891 var __row_selector = function ( settings, selector, opts )
7892 {
7893 var rows;
7894 var run = function ( sel ) {
7895 var selInt = _intVal( sel );
7896 var i, ien;
7897 var aoData = settings.aoData;
7898
7899 // Short cut - selector is a number and no options provided (default is
7900 // all records, so no need to check if the index is in there, since it
7901 // must be - dev error if the index doesn't exist).
7902 if ( selInt !== null && ! opts ) {
7903 return [ selInt ];
7904 }
7905
7906 if ( ! rows ) {
7907 rows = _selector_row_indexes( settings, opts );
7908 }
7909
7910 if ( selInt !== null && $.inArray( selInt, rows ) !== -1 ) {
7911 // Selector - integer
7912 return [ selInt ];
7913 }
7914 else if ( sel === null || sel === undefined || sel === '' ) {
7915 // Selector - none
7916 return rows;
7917 }
7918
7919 // Selector - function
7920 if ( typeof sel === 'function' ) {
7921 return $.map( rows, function (idx) {
7922 var row = aoData[ idx ];
7923 return sel( idx, row._aData, row.nTr ) ? idx : null;
7924 } );
7925 }
7926
7927 // Selector - node
7928 if ( sel.nodeName ) {
7929 var rowIdx = sel._DT_RowIndex; // Property added by DT for fast lookup
7930 var cellIdx = sel._DT_CellIndex;
7931
7932 if ( rowIdx !== undefined ) {
7933 // Make sure that the row is actually still present in the table
7934 return aoData[ rowIdx ] && aoData[ rowIdx ].nTr === sel ?
7935 [ rowIdx ] :
7936 [];
7937 }
7938 else if ( cellIdx ) {
7939 return aoData[ cellIdx.row ] && aoData[ cellIdx.row ].nTr === sel.parentNode ?
7940 [ cellIdx.row ] :
7941 [];
7942 }
7943 else {
7944 var host = $(sel).closest('*[data-dt-row]');
7945 return host.length ?
7946 [ host.data('dt-row') ] :
7947 [];
7948 }
7949 }
7950
7951 // ID selector. Want to always be able to select rows by id, regardless
7952 // of if the tr element has been created or not, so can't rely upon
7953 // jQuery here - hence a custom implementation. This does not match
7954 // Sizzle's fast selector or HTML4 - in HTML5 the ID can be anything,
7955 // but to select it using a CSS selector engine (like Sizzle or
7956 // querySelect) it would need to need to be escaped for some characters.
7957 // DataTables simplifies this for row selectors since you can select
7958 // only a row. A # indicates an id any anything that follows is the id -
7959 // unescaped.
7960 if ( typeof sel === 'string' && sel.charAt(0) === '#' ) {
7961 // get row index from id
7962 var rowObj = settings.aIds[ sel.replace( /^#/, '' ) ];
7963 if ( rowObj !== undefined ) {
7964 return [ rowObj.idx ];
7965 }
7966
7967 // need to fall through to jQuery in case there is DOM id that
7968 // matches
7969 }
7970
7971 // Get nodes in the order from the `rows` array with null values removed
7972 var nodes = _removeEmpty(
7973 _pluck_order( settings.aoData, rows, 'nTr' )
7974 );
7975
7976 // Selector - jQuery selector string, array of nodes or jQuery object/
7977 // As jQuery's .filter() allows jQuery objects to be passed in filter,
7978 // it also allows arrays, so this will cope with all three options
7979 return $(nodes)
7980 .filter( sel )
7981 .map( function () {
7982 return this._DT_RowIndex;
7983 } )
7984 .toArray();
7985 };
7986
7987 return _selector_run( 'row', selector, run, settings, opts );
7988 };
7989
7990
7991 _api_register( 'rows()', function ( selector, opts ) {
7992 // argument shifting
7993 if ( selector === undefined ) {
7994 selector = '';
7995 }
7996 else if ( $.isPlainObject( selector ) ) {
7997 opts = selector;
7998 selector = '';
7999 }
8000
8001 opts = _selector_opts( opts );
8002
8003 var inst = this.iterator( 'table', function ( settings ) {
8004 return __row_selector( settings, selector, opts );
8005 }, 1 );
8006
8007 // Want argument shifting here and in __row_selector?
8008 inst.selector.rows = selector;
8009 inst.selector.opts = opts;
8010
8011 return inst;
8012 } );
8013
8014 _api_register( 'rows().nodes()', function () {
8015 return this.iterator( 'row', function ( settings, row ) {
8016 return settings.aoData[ row ].nTr || undefined;
8017 }, 1 );
8018 } );
8019
8020 _api_register( 'rows().data()', function () {
8021 return this.iterator( true, 'rows', function ( settings, rows ) {
8022 return _pluck_order( settings.aoData, rows, '_aData' );
8023 }, 1 );
8024 } );
8025
8026 _api_registerPlural( 'rows().cache()', 'row().cache()', function ( type ) {
8027 return this.iterator( 'row', function ( settings, row ) {
8028 var r = settings.aoData[ row ];
8029 return type === 'search' ? r._aFilterData : r._aSortData;
8030 }, 1 );
8031 } );
8032
8033 _api_registerPlural( 'rows().invalidate()', 'row().invalidate()', function ( src ) {
8034 return this.iterator( 'row', function ( settings, row ) {
8035 _fnInvalidate( settings, row, src );
8036 } );
8037 } );
8038
8039 _api_registerPlural( 'rows().indexes()', 'row().index()', function () {
8040 return this.iterator( 'row', function ( settings, row ) {
8041 return row;
8042 }, 1 );
8043 } );
8044
8045 _api_registerPlural( 'rows().ids()', 'row().id()', function ( hash ) {
8046 var a = [];
8047 var context = this.context;
8048
8049 // `iterator` will drop undefined values, but in this case we want them
8050 for ( var i=0, ien=context.length ; i<ien ; i++ ) {
8051 for ( var j=0, jen=this[i].length ; j<jen ; j++ ) {
8052 var id = context[i].rowIdFn( context[i].aoData[ this[i][j] ]._aData );
8053 a.push( (hash === true ? '#' : '' )+ id );
8054 }
8055 }
8056
8057 return new _Api( context, a );
8058 } );
8059
8060 _api_registerPlural( 'rows().remove()', 'row().remove()', function () {
8061 var that = this;
8062
8063 this.iterator( 'row', function ( settings, row, thatIdx ) {
8064 var data = settings.aoData;
8065 var rowData = data[ row ];
8066 var i, ien, j, jen;
8067 var loopRow, loopCells;
8068
8069 data.splice( row, 1 );
8070
8071 // Update the cached indexes
8072 for ( i=0, ien=data.length ; i<ien ; i++ ) {
8073 loopRow = data[i];
8074 loopCells = loopRow.anCells;
8075
8076 // Rows
8077 if ( loopRow.nTr !== null ) {
8078 loopRow.nTr._DT_RowIndex = i;
8079 }
8080
8081 // Cells
8082 if ( loopCells !== null ) {
8083 for ( j=0, jen=loopCells.length ; j<jen ; j++ ) {
8084 loopCells[j]._DT_CellIndex.row = i;
8085 }
8086 }
8087 }
8088
8089 // Delete from the display arrays
8090 _fnDeleteIndex( settings.aiDisplayMaster, row );
8091 _fnDeleteIndex( settings.aiDisplay, row );
8092 _fnDeleteIndex( that[ thatIdx ], row, false ); // maintain local indexes
8093
8094 // For server-side processing tables - subtract the deleted row from the count
8095 if ( settings._iRecordsDisplay > 0 ) {
8096 settings._iRecordsDisplay--;
8097 }
8098
8099 // Check for an 'overflow' they case for displaying the table
8100 _fnLengthOverflow( settings );
8101
8102 // Remove the row's ID reference if there is one
8103 var id = settings.rowIdFn( rowData._aData );
8104 if ( id !== undefined ) {
8105 delete settings.aIds[ id ];
8106 }
8107 } );
8108
8109 this.iterator( 'table', function ( settings ) {
8110 for ( var i=0, ien=settings.aoData.length ; i<ien ; i++ ) {
8111 settings.aoData[i].idx = i;
8112 }
8113 } );
8114
8115 return this;
8116 } );
8117
8118
8119 _api_register( 'rows.add()', function ( rows ) {
8120 var newRows = this.iterator( 'table', function ( settings ) {
8121 var row, i, ien;
8122 var out = [];
8123
8124 for ( i=0, ien=rows.length ; i<ien ; i++ ) {
8125 row = rows[i];
8126
8127 if ( row.nodeName && row.nodeName.toUpperCase() === 'TR' ) {
8128 out.push( _fnAddTr( settings, row )[0] );
8129 }
8130 else {
8131 out.push( _fnAddData( settings, row ) );
8132 }
8133 }
8134
8135 return out;
8136 }, 1 );
8137
8138 // Return an Api.rows() extended instance, so rows().nodes() etc can be used
8139 var modRows = this.rows( -1 );
8140 modRows.pop();
8141 $.merge( modRows, newRows );
8142
8143 return modRows;
8144 } );
8145
8146
8147
8148
8149
8150 /**
8151 *
8152 */
8153 _api_register( 'row()', function ( selector, opts ) {
8154 return _selector_first( this.rows( selector, opts ) );
8155 } );
8156
8157
8158 _api_register( 'row().data()', function ( data ) {
8159 var ctx = this.context;
8160
8161 if ( data === undefined ) {
8162 // Get
8163 return ctx.length && this.length ?
8164 ctx[0].aoData[ this[0] ]._aData :
8165 undefined;
8166 }
8167
8168 // Set
8169 var row = ctx[0].aoData[ this[0] ];
8170 row._aData = data;
8171
8172 // If the DOM has an id, and the data source is an array
8173 if ( $.isArray( data ) && row.nTr && row.nTr.id ) {
8174 _fnSetObjectDataFn( ctx[0].rowId )( data, row.nTr.id );
8175 }
8176
8177 // Automatically invalidate
8178 _fnInvalidate( ctx[0], this[0], 'data' );
8179
8180 return this;
8181 } );
8182
8183
8184 _api_register( 'row().node()', function () {
8185 var ctx = this.context;
8186
8187 return ctx.length && this.length ?
8188 ctx[0].aoData[ this[0] ].nTr || null :
8189 null;
8190 } );
8191
8192
8193 _api_register( 'row.add()', function ( row ) {
8194 // Allow a jQuery object to be passed in - only a single row is added from
8195 // it though - the first element in the set
8196 if ( row instanceof $ && row.length ) {
8197 row = row[0];
8198 }
8199
8200 var rows = this.iterator( 'table', function ( settings ) {
8201 if ( row.nodeName && row.nodeName.toUpperCase() === 'TR' ) {
8202 return _fnAddTr( settings, row )[0];
8203 }
8204 return _fnAddData( settings, row );
8205 } );
8206
8207 // Return an Api.rows() extended instance, with the newly added row selected
8208 return this.row( rows[0] );
8209 } );
8210
8211
8212
8213 var __details_add = function ( ctx, row, data, klass )
8214 {
8215 // Convert to array of TR elements
8216 var rows = [];
8217 var addRow = function ( r, k ) {
8218 // Recursion to allow for arrays of jQuery objects
8219 if ( $.isArray( r ) || r instanceof $ ) {
8220 for ( var i=0, ien=r.length ; i<ien ; i++ ) {
8221 addRow( r[i], k );
8222 }
8223 return;
8224 }
8225
8226 // If we get a TR element, then just add it directly - up to the dev
8227 // to add the correct number of columns etc
8228 if ( r.nodeName && r.nodeName.toLowerCase() === 'tr' ) {
8229 rows.push( r );
8230 }
8231 else {
8232 // Otherwise create a row with a wrapper
8233 var created = $('<tr><td/></tr>').addClass( k );
8234 $('td', created)
8235 .addClass( k )
8236 .html( r )
8237 [0].colSpan = _fnVisbleColumns( ctx );
8238
8239 rows.push( created[0] );
8240 }
8241 };
8242
8243 addRow( data, klass );
8244
8245 if ( row._details ) {
8246 row._details.detach();
8247 }
8248
8249 row._details = $(rows);
8250
8251 // If the children were already shown, that state should be retained
8252 if ( row._detailsShow ) {
8253 row._details.insertAfter( row.nTr );
8254 }
8255 };
8256
8257
8258 var __details_remove = function ( api, idx )
8259 {
8260 var ctx = api.context;
8261
8262 if ( ctx.length ) {
8263 var row = ctx[0].aoData[ idx !== undefined ? idx : api[0] ];
8264
8265 if ( row && row._details ) {
8266 row._details.remove();
8267
8268 row._detailsShow = undefined;
8269 row._details = undefined;
8270 }
8271 }
8272 };
8273
8274
8275 var __details_display = function ( api, show ) {
8276 var ctx = api.context;
8277
8278 if ( ctx.length && api.length ) {
8279 var row = ctx[0].aoData[ api[0] ];
8280
8281 if ( row._details ) {
8282 row._detailsShow = show;
8283
8284 if ( show ) {
8285 row._details.insertAfter( row.nTr );
8286 }
8287 else {
8288 row._details.detach();
8289 }
8290
8291 __details_events( ctx[0] );
8292 }
8293 }
8294 };
8295
8296
8297 var __details_events = function ( settings )
8298 {
8299 var api = new _Api( settings );
8300 var namespace = '.dt.DT_details';
8301 var drawEvent = 'draw'+namespace;
8302 var colvisEvent = 'column-visibility'+namespace;
8303 var destroyEvent = 'destroy'+namespace;
8304 var data = settings.aoData;
8305
8306 api.off( drawEvent +' '+ colvisEvent +' '+ destroyEvent );
8307
8308 if ( _pluck( data, '_details' ).length > 0 ) {
8309 // On each draw, insert the required elements into the document
8310 api.on( drawEvent, function ( e, ctx ) {
8311 if ( settings !== ctx ) {
8312 return;
8313 }
8314
8315 api.rows( {page:'current'} ).eq(0).each( function (idx) {
8316 // Internal data grab
8317 var row = data[ idx ];
8318
8319 if ( row._detailsShow ) {
8320 row._details.insertAfter( row.nTr );
8321 }
8322 } );
8323 } );
8324
8325 // Column visibility change - update the colspan
8326 api.on( colvisEvent, function ( e, ctx, idx, vis ) {
8327 if ( settings !== ctx ) {
8328 return;
8329 }
8330
8331 // Update the colspan for the details rows (note, only if it already has
8332 // a colspan)
8333 var row, visible = _fnVisbleColumns( ctx );
8334
8335 for ( var i=0, ien=data.length ; i<ien ; i++ ) {
8336 row = data[i];
8337
8338 if ( row._details ) {
8339 row._details.children('td[colspan]').attr('colspan', visible );
8340 }
8341 }
8342 } );
8343
8344 // Table destroyed - nuke any child rows
8345 api.on( destroyEvent, function ( e, ctx ) {
8346 if ( settings !== ctx ) {
8347 return;
8348 }
8349
8350 for ( var i=0, ien=data.length ; i<ien ; i++ ) {
8351 if ( data[i]._details ) {
8352 __details_remove( api, i );
8353 }
8354 }
8355 } );
8356 }
8357 };
8358
8359 // Strings for the method names to help minification
8360 var _emp = '';
8361 var _child_obj = _emp+'row().child';
8362 var _child_mth = _child_obj+'()';
8363
8364 // data can be:
8365 // tr
8366 // string
8367 // jQuery or array of any of the above
8368 _api_register( _child_mth, function ( data, klass ) {
8369 var ctx = this.context;
8370
8371 if ( data === undefined ) {
8372 // get
8373 return ctx.length && this.length ?
8374 ctx[0].aoData[ this[0] ]._details :
8375 undefined;
8376 }
8377 else if ( data === true ) {
8378 // show
8379 this.child.show();
8380 }
8381 else if ( data === false ) {
8382 // remove
8383 __details_remove( this );
8384 }
8385 else if ( ctx.length && this.length ) {
8386 // set
8387 __details_add( ctx[0], ctx[0].aoData[ this[0] ], data, klass );
8388 }
8389
8390 return this;
8391 } );
8392
8393
8394 _api_register( [
8395 _child_obj+'.show()',
8396 _child_mth+'.show()' // only when `child()` was called with parameters (without
8397 ], function ( show ) { // it returns an object and this method is not executed)
8398 __details_display( this, true );
8399 return this;
8400 } );
8401
8402
8403 _api_register( [
8404 _child_obj+'.hide()',
8405 _child_mth+'.hide()' // only when `child()` was called with parameters (without
8406 ], function () { // it returns an object and this method is not executed)
8407 __details_display( this, false );
8408 return this;
8409 } );
8410
8411
8412 _api_register( [
8413 _child_obj+'.remove()',
8414 _child_mth+'.remove()' // only when `child()` was called with parameters (without
8415 ], function () { // it returns an object and this method is not executed)
8416 __details_remove( this );
8417 return this;
8418 } );
8419
8420
8421 _api_register( _child_obj+'.isShown()', function () {
8422 var ctx = this.context;
8423
8424 if ( ctx.length && this.length ) {
8425 // _detailsShown as false or undefined will fall through to return false
8426 return ctx[0].aoData[ this[0] ]._detailsShow || false;
8427 }
8428 return false;
8429 } );
8430
8431
8432
8433 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
8434 * Columns
8435 *
8436 * {integer} - column index (>=0 count from left, <0 count from right)
8437 * "{integer}:visIdx" - visible column index (i.e. translate to column index) (>=0 count from left, <0 count from right)
8438 * "{integer}:visible" - alias for {integer}:visIdx (>=0 count from left, <0 count from right)
8439 * "{string}:name" - column name
8440 * "{string}" - jQuery selector on column header nodes
8441 *
8442 */
8443
8444 // can be an array of these items, comma separated list, or an array of comma
8445 // separated lists
8446
8447 var __re_column_selector = /^([^:]+):(name|visIdx|visible)$/;
8448
8449
8450 // r1 and r2 are redundant - but it means that the parameters match for the
8451 // iterator callback in columns().data()
8452 var __columnData = function ( settings, column, r1, r2, rows ) {
8453 var a = [];
8454 for ( var row=0, ien=rows.length ; row<ien ; row++ ) {
8455 a.push( _fnGetCellData( settings, rows[row], column ) );
8456 }
8457 return a;
8458 };
8459
8460
8461 var __column_selector = function ( settings, selector, opts )
8462 {
8463 var
8464 columns = settings.aoColumns,
8465 names = _pluck( columns, 'sName' ),
8466 nodes = _pluck( columns, 'nTh' );
8467
8468 var run = function ( s ) {
8469 var selInt = _intVal( s );
8470
8471 // Selector - all
8472 if ( s === '' ) {
8473 return _range( columns.length );
8474 }
8475
8476 // Selector - index
8477 if ( selInt !== null ) {
8478 return [ selInt >= 0 ?
8479 selInt : // Count from left
8480 columns.length + selInt // Count from right (+ because its a negative value)
8481 ];
8482 }
8483
8484 // Selector = function
8485 if ( typeof s === 'function' ) {
8486 var rows = _selector_row_indexes( settings, opts );
8487
8488 return $.map( columns, function (col, idx) {
8489 return s(
8490 idx,
8491 __columnData( settings, idx, 0, 0, rows ),
8492 nodes[ idx ]
8493 ) ? idx : null;
8494 } );
8495 }
8496
8497 // jQuery or string selector
8498 var match = typeof s === 'string' ?
8499 s.match( __re_column_selector ) :
8500 '';
8501
8502 if ( match ) {
8503 switch( match[2] ) {
8504 case 'visIdx':
8505 case 'visible':
8506 var idx = parseInt( match[1], 10 );
8507 // Visible index given, convert to column index
8508 if ( idx < 0 ) {
8509 // Counting from the right
8510 var visColumns = $.map( columns, function (col,i) {
8511 return col.bVisible ? i : null;
8512 } );
8513 return [ visColumns[ visColumns.length + idx ] ];
8514 }
8515 // Counting from the left
8516 return [ _fnVisibleToColumnIndex( settings, idx ) ];
8517
8518 case 'name':
8519 // match by name. `names` is column index complete and in order
8520 return $.map( names, function (name, i) {
8521 return name === match[1] ? i : null;
8522 } );
8523
8524 default:
8525 return [];
8526 }
8527 }
8528
8529 // Cell in the table body
8530 if ( s.nodeName && s._DT_CellIndex ) {
8531 return [ s._DT_CellIndex.column ];
8532 }
8533
8534 // jQuery selector on the TH elements for the columns
8535 var jqResult = $( nodes )
8536 .filter( s )
8537 .map( function () {
8538 return $.inArray( this, nodes ); // `nodes` is column index complete and in order
8539 } )
8540 .toArray();
8541
8542 if ( jqResult.length || ! s.nodeName ) {
8543 return jqResult;
8544 }
8545
8546 // Otherwise a node which might have a `dt-column` data attribute, or be
8547 // a child or such an element
8548 var host = $(s).closest('*[data-dt-column]');
8549 return host.length ?
8550 [ host.data('dt-column') ] :
8551 [];
8552 };
8553
8554 return _selector_run( 'column', selector, run, settings, opts );
8555 };
8556
8557
8558 var __setColumnVis = function ( settings, column, vis ) {
8559 var
8560 cols = settings.aoColumns,
8561 col = cols[ column ],
8562 data = settings.aoData,
8563 row, cells, i, ien, tr;
8564
8565 // Get
8566 if ( vis === undefined ) {
8567 return col.bVisible;
8568 }
8569
8570 // Set
8571 // No change
8572 if ( col.bVisible === vis ) {
8573 return;
8574 }
8575
8576 if ( vis ) {
8577 // Insert column
8578 // Need to decide if we should use appendChild or insertBefore
8579 var insertBefore = $.inArray( true, _pluck(cols, 'bVisible'), column+1 );
8580
8581 for ( i=0, ien=data.length ; i<ien ; i++ ) {
8582 tr = data[i].nTr;
8583 cells = data[i].anCells;
8584
8585 if ( tr ) {
8586 // insertBefore can act like appendChild if 2nd arg is null
8587 tr.insertBefore( cells[ column ], cells[ insertBefore ] || null );
8588 }
8589 }
8590 }
8591 else {
8592 // Remove column
8593 $( _pluck( settings.aoData, 'anCells', column ) ).detach();
8594 }
8595
8596 // Common actions
8597 col.bVisible = vis;
8598 };
8599
8600
8601 _api_register( 'columns()', function ( selector, opts ) {
8602 // argument shifting
8603 if ( selector === undefined ) {
8604 selector = '';
8605 }
8606 else if ( $.isPlainObject( selector ) ) {
8607 opts = selector;
8608 selector = '';
8609 }
8610
8611 opts = _selector_opts( opts );
8612
8613 var inst = this.iterator( 'table', function ( settings ) {
8614 return __column_selector( settings, selector, opts );
8615 }, 1 );
8616
8617 // Want argument shifting here and in _row_selector?
8618 inst.selector.cols = selector;
8619 inst.selector.opts = opts;
8620
8621 return inst;
8622 } );
8623
8624 _api_registerPlural( 'columns().header()', 'column().header()', function ( selector, opts ) {
8625 return this.iterator( 'column', function ( settings, column ) {
8626 return settings.aoColumns[column].nTh;
8627 }, 1 );
8628 } );
8629
8630 _api_registerPlural( 'columns().footer()', 'column().footer()', function ( selector, opts ) {
8631 return this.iterator( 'column', function ( settings, column ) {
8632 return settings.aoColumns[column].nTf;
8633 }, 1 );
8634 } );
8635
8636 _api_registerPlural( 'columns().data()', 'column().data()', function () {
8637 return this.iterator( 'column-rows', __columnData, 1 );
8638 } );
8639
8640 _api_registerPlural( 'columns().dataSrc()', 'column().dataSrc()', function () {
8641 return this.iterator( 'column', function ( settings, column ) {
8642 return settings.aoColumns[column].mData;
8643 }, 1 );
8644 } );
8645
8646 _api_registerPlural( 'columns().cache()', 'column().cache()', function ( type ) {
8647 return this.iterator( 'column-rows', function ( settings, column, i, j, rows ) {
8648 return _pluck_order( settings.aoData, rows,
8649 type === 'search' ? '_aFilterData' : '_aSortData', column
8650 );
8651 }, 1 );
8652 } );
8653
8654 _api_registerPlural( 'columns().nodes()', 'column().nodes()', function () {
8655 return this.iterator( 'column-rows', function ( settings, column, i, j, rows ) {
8656 return _pluck_order( settings.aoData, rows, 'anCells', column ) ;
8657 }, 1 );
8658 } );
8659
8660 _api_registerPlural( 'columns().visible()', 'column().visible()', function ( vis, calc ) {
8661 var that = this;
8662 var ret = this.iterator( 'column', function ( settings, column ) {
8663 if ( vis === undefined ) {
8664 return settings.aoColumns[ column ].bVisible;
8665 } // else
8666 __setColumnVis( settings, column, vis );
8667 } );
8668
8669 // Group the column visibility changes
8670 if ( vis !== undefined ) {
8671 this.iterator( 'table', function ( settings ) {
8672 // Redraw the header after changes
8673 _fnDrawHead( settings, settings.aoHeader );
8674 _fnDrawHead( settings, settings.aoFooter );
8675
8676 // Update colspan for no records display. Child rows and extensions will use their own
8677 // listeners to do this - only need to update the empty table item here
8678 if ( ! settings.aiDisplay.length ) {
8679 $(settings.nTBody).find('td[colspan]').attr('colspan', _fnVisbleColumns(settings));
8680 }
8681
8682 _fnSaveState( settings );
8683
8684 // Second loop once the first is done for events
8685 that.iterator( 'column', function ( settings, column ) {
8686 _fnCallbackFire( settings, null, 'column-visibility', [settings, column, vis, calc] );
8687 } );
8688
8689 if ( calc === undefined || calc ) {
8690 that.columns.adjust();
8691 }
8692 });
8693 }
8694
8695 return ret;
8696 } );
8697
8698 _api_registerPlural( 'columns().indexes()', 'column().index()', function ( type ) {
8699 return this.iterator( 'column', function ( settings, column ) {
8700 return type === 'visible' ?
8701 _fnColumnIndexToVisible( settings, column ) :
8702 column;
8703 }, 1 );
8704 } );
8705
8706 _api_register( 'columns.adjust()', function () {
8707 return this.iterator( 'table', function ( settings ) {
8708 _fnAdjustColumnSizing( settings );
8709 }, 1 );
8710 } );
8711
8712 _api_register( 'column.index()', function ( type, idx ) {
8713 if ( this.context.length !== 0 ) {
8714 var ctx = this.context[0];
8715
8716 if ( type === 'fromVisible' || type === 'toData' ) {
8717 return _fnVisibleToColumnIndex( ctx, idx );
8718 }
8719 else if ( type === 'fromData' || type === 'toVisible' ) {
8720 return _fnColumnIndexToVisible( ctx, idx );
8721 }
8722 }
8723 } );
8724
8725 _api_register( 'column()', function ( selector, opts ) {
8726 return _selector_first( this.columns( selector, opts ) );
8727 } );
8728
8729
8730
8731 var __cell_selector = function ( settings, selector, opts )
8732 {
8733 var data = settings.aoData;
8734 var rows = _selector_row_indexes( settings, opts );
8735 var cells = _removeEmpty( _pluck_order( data, rows, 'anCells' ) );
8736 var allCells = $( [].concat.apply([], cells) );
8737 var row;
8738 var columns = settings.aoColumns.length;
8739 var a, i, ien, j, o, host;
8740
8741 var run = function ( s ) {
8742 var fnSelector = typeof s === 'function';
8743
8744 if ( s === null || s === undefined || fnSelector ) {
8745 // All cells and function selectors
8746 a = [];
8747
8748 for ( i=0, ien=rows.length ; i<ien ; i++ ) {
8749 row = rows[i];
8750
8751 for ( j=0 ; j<columns ; j++ ) {
8752 o = {
8753 row: row,
8754 column: j
8755 };
8756
8757 if ( fnSelector ) {
8758 // Selector - function
8759 host = data[ row ];
8760
8761 if ( s( o, _fnGetCellData(settings, row, j), host.anCells ? host.anCells[j] : null ) ) {
8762 a.push( o );
8763 }
8764 }
8765 else {
8766 // Selector - all
8767 a.push( o );
8768 }
8769 }
8770 }
8771
8772 return a;
8773 }
8774
8775 // Selector - index
8776 if ( $.isPlainObject( s ) ) {
8777 // Valid cell index and its in the array of selectable rows
8778 return s.column !== undefined && s.row !== undefined && $.inArray( s.row, rows ) !== -1 ?
8779 [s] :
8780 [];
8781 }
8782
8783 // Selector - jQuery filtered cells
8784 var jqResult = allCells
8785 .filter( s )
8786 .map( function (i, el) {
8787 return { // use a new object, in case someone changes the values
8788 row: el._DT_CellIndex.row,
8789 column: el._DT_CellIndex.column
8790 };
8791 } )
8792 .toArray();
8793
8794 if ( jqResult.length || ! s.nodeName ) {
8795 return jqResult;
8796 }
8797
8798 // Otherwise the selector is a node, and there is one last option - the
8799 // element might be a child of an element which has dt-row and dt-column
8800 // data attributes
8801 host = $(s).closest('*[data-dt-row]');
8802 return host.length ?
8803 [ {
8804 row: host.data('dt-row'),
8805 column: host.data('dt-column')
8806 } ] :
8807 [];
8808 };
8809
8810 return _selector_run( 'cell', selector, run, settings, opts );
8811 };
8812
8813
8814
8815
8816 _api_register( 'cells()', function ( rowSelector, columnSelector, opts ) {
8817 // Argument shifting
8818 if ( $.isPlainObject( rowSelector ) ) {
8819 // Indexes
8820 if ( rowSelector.row === undefined ) {
8821 // Selector options in first parameter
8822 opts = rowSelector;
8823 rowSelector = null;
8824 }
8825 else {
8826 // Cell index objects in first parameter
8827 opts = columnSelector;
8828 columnSelector = null;
8829 }
8830 }
8831 if ( $.isPlainObject( columnSelector ) ) {
8832 opts = columnSelector;
8833 columnSelector = null;
8834 }
8835
8836 // Cell selector
8837 if ( columnSelector === null || columnSelector === undefined ) {
8838 return this.iterator( 'table', function ( settings ) {
8839 return __cell_selector( settings, rowSelector, _selector_opts( opts ) );
8840 } );
8841 }
8842
8843 // The default built in options need to apply to row and columns
8844 var internalOpts = opts ? {
8845 page: opts.page,
8846 order: opts.order,
8847 search: opts.search
8848 } : {};
8849
8850 // Row + column selector
8851 var columns = this.columns( columnSelector, internalOpts );
8852 var rows = this.rows( rowSelector, internalOpts );
8853 var i, ien, j, jen;
8854
8855 var cellsNoOpts = this.iterator( 'table', function ( settings, idx ) {
8856 var a = [];
8857
8858 for ( i=0, ien=rows[idx].length ; i<ien ; i++ ) {
8859 for ( j=0, jen=columns[idx].length ; j<jen ; j++ ) {
8860 a.push( {
8861 row: rows[idx][i],
8862 column: columns[idx][j]
8863 } );
8864 }
8865 }
8866
8867 return a;
8868 }, 1 );
8869
8870 // There is currently only one extension which uses a cell selector extension
8871 // It is a _major_ performance drag to run this if it isn't needed, so this is
8872 // an extension specific check at the moment
8873 var cells = opts && opts.selected ?
8874 this.cells( cellsNoOpts, opts ) :
8875 cellsNoOpts;
8876
8877 $.extend( cells.selector, {
8878 cols: columnSelector,
8879 rows: rowSelector,
8880 opts: opts
8881 } );
8882
8883 return cells;
8884 } );
8885
8886
8887 _api_registerPlural( 'cells().nodes()', 'cell().node()', function () {
8888 return this.iterator( 'cell', function ( settings, row, column ) {
8889 var data = settings.aoData[ row ];
8890
8891 return data && data.anCells ?
8892 data.anCells[ column ] :
8893 undefined;
8894 }, 1 );
8895 } );
8896
8897
8898 _api_register( 'cells().data()', function () {
8899 return this.iterator( 'cell', function ( settings, row, column ) {
8900 return _fnGetCellData( settings, row, column );
8901 }, 1 );
8902 } );
8903
8904
8905 _api_registerPlural( 'cells().cache()', 'cell().cache()', function ( type ) {
8906 type = type === 'search' ? '_aFilterData' : '_aSortData';
8907
8908 return this.iterator( 'cell', function ( settings, row, column ) {
8909 return settings.aoData[ row ][ type ][ column ];
8910 }, 1 );
8911 } );
8912
8913
8914 _api_registerPlural( 'cells().render()', 'cell().render()', function ( type ) {
8915 return this.iterator( 'cell', function ( settings, row, column ) {
8916 return _fnGetCellData( settings, row, column, type );
8917 }, 1 );
8918 } );
8919
8920
8921 _api_registerPlural( 'cells().indexes()', 'cell().index()', function () {
8922 return this.iterator( 'cell', function ( settings, row, column ) {
8923 return {
8924 row: row,
8925 column: column,
8926 columnVisible: _fnColumnIndexToVisible( settings, column )
8927 };
8928 }, 1 );
8929 } );
8930
8931
8932 _api_registerPlural( 'cells().invalidate()', 'cell().invalidate()', function ( src ) {
8933 return this.iterator( 'cell', function ( settings, row, column ) {
8934 _fnInvalidate( settings, row, src, column );
8935 } );
8936 } );
8937
8938
8939
8940 _api_register( 'cell()', function ( rowSelector, columnSelector, opts ) {
8941 return _selector_first( this.cells( rowSelector, columnSelector, opts ) );
8942 } );
8943
8944
8945 _api_register( 'cell().data()', function ( data ) {
8946 var ctx = this.context;
8947 var cell = this[0];
8948
8949 if ( data === undefined ) {
8950 // Get
8951 return ctx.length && cell.length ?
8952 _fnGetCellData( ctx[0], cell[0].row, cell[0].column ) :
8953 undefined;
8954 }
8955
8956 // Set
8957 _fnSetCellData( ctx[0], cell[0].row, cell[0].column, data );
8958 _fnInvalidate( ctx[0], cell[0].row, 'data', cell[0].column );
8959
8960 return this;
8961 } );
8962
8963
8964
8965 /**
8966 * Get current ordering (sorting) that has been applied to the table.
8967 *
8968 * @returns {array} 2D array containing the sorting information for the first
8969 * table in the current context. Each element in the parent array represents
8970 * a column being sorted upon (i.e. multi-sorting with two columns would have
8971 * 2 inner arrays). The inner arrays may have 2 or 3 elements. The first is
8972 * the column index that the sorting condition applies to, the second is the
8973 * direction of the sort (`desc` or `asc`) and, optionally, the third is the
8974 * index of the sorting order from the `column.sorting` initialisation array.
8975 *//**
8976 * Set the ordering for the table.
8977 *
8978 * @param {integer} order Column index to sort upon.
8979 * @param {string} direction Direction of the sort to be applied (`asc` or `desc`)
8980 * @returns {DataTables.Api} this
8981 *//**
8982 * Set the ordering for the table.
8983 *
8984 * @param {array} order 1D array of sorting information to be applied.
8985 * @param {array} [...] Optional additional sorting conditions
8986 * @returns {DataTables.Api} this
8987 *//**
8988 * Set the ordering for the table.
8989 *
8990 * @param {array} order 2D array of sorting information to be applied.
8991 * @returns {DataTables.Api} this
8992 */
8993 _api_register( 'order()', function ( order, dir ) {
8994 var ctx = this.context;
8995
8996 if ( order === undefined ) {
8997 // get
8998 return ctx.length !== 0 ?
8999 ctx[0].aaSorting :
9000 undefined;
9001 }
9002
9003 // set
9004 if ( typeof order === 'number' ) {
9005 // Simple column / direction passed in
9006 order = [ [ order, dir ] ];
9007 }
9008 else if ( order.length && ! $.isArray( order[0] ) ) {
9009 // Arguments passed in (list of 1D arrays)
9010 order = Array.prototype.slice.call( arguments );
9011 }
9012 // otherwise a 2D array was passed in
9013
9014 return this.iterator( 'table', function ( settings ) {
9015 settings.aaSorting = order.slice();
9016 } );
9017 } );
9018
9019
9020 /**
9021 * Attach a sort listener to an element for a given column
9022 *
9023 * @param {node|jQuery|string} node Identifier for the element(s) to attach the
9024 * listener to. This can take the form of a single DOM node, a jQuery
9025 * collection of nodes or a jQuery selector which will identify the node(s).
9026 * @param {integer} column the column that a click on this node will sort on
9027 * @param {function} [callback] callback function when sort is run
9028 * @returns {DataTables.Api} this
9029 */
9030 _api_register( 'order.listener()', function ( node, column, callback ) {
9031 return this.iterator( 'table', function ( settings ) {
9032 _fnSortAttachListener( settings, node, column, callback );
9033 } );
9034 } );
9035
9036
9037 _api_register( 'order.fixed()', function ( set ) {
9038 if ( ! set ) {
9039 var ctx = this.context;
9040 var fixed = ctx.length ?
9041 ctx[0].aaSortingFixed :
9042 undefined;
9043
9044 return $.isArray( fixed ) ?
9045 { pre: fixed } :
9046 fixed;
9047 }
9048
9049 return this.iterator( 'table', function ( settings ) {
9050 settings.aaSortingFixed = $.extend( true, {}, set );
9051 } );
9052 } );
9053
9054
9055 // Order by the selected column(s)
9056 _api_register( [
9057 'columns().order()',
9058 'column().order()'
9059 ], function ( dir ) {
9060 var that = this;
9061
9062 return this.iterator( 'table', function ( settings, i ) {
9063 var sort = [];
9064
9065 $.each( that[i], function (j, col) {
9066 sort.push( [ col, dir ] );
9067 } );
9068
9069 settings.aaSorting = sort;
9070 } );
9071 } );
9072
9073
9074
9075 _api_register( 'search()', function ( input, regex, smart, caseInsen ) {
9076 var ctx = this.context;
9077
9078 if ( input === undefined ) {
9079 // get
9080 return ctx.length !== 0 ?
9081 ctx[0].oPreviousSearch.sSearch :
9082 undefined;
9083 }
9084
9085 // set
9086 return this.iterator( 'table', function ( settings ) {
9087 if ( ! settings.oFeatures.bFilter ) {
9088 return;
9089 }
9090
9091 _fnFilterComplete( settings, $.extend( {}, settings.oPreviousSearch, {
9092 "sSearch": input+"",
9093 "bRegex": regex === null ? false : regex,
9094 "bSmart": smart === null ? true : smart,
9095 "bCaseInsensitive": caseInsen === null ? true : caseInsen
9096 } ), 1 );
9097 } );
9098 } );
9099
9100
9101 _api_registerPlural(
9102 'columns().search()',
9103 'column().search()',
9104 function ( input, regex, smart, caseInsen ) {
9105 return this.iterator( 'column', function ( settings, column ) {
9106 var preSearch = settings.aoPreSearchCols;
9107
9108 if ( input === undefined ) {
9109 // get
9110 return preSearch[ column ].sSearch;
9111 }
9112
9113 // set
9114 if ( ! settings.oFeatures.bFilter ) {
9115 return;
9116 }
9117
9118 $.extend( preSearch[ column ], {
9119 "sSearch": input+"",
9120 "bRegex": regex === null ? false : regex,
9121 "bSmart": smart === null ? true : smart,
9122 "bCaseInsensitive": caseInsen === null ? true : caseInsen
9123 } );
9124
9125 _fnFilterComplete( settings, settings.oPreviousSearch, 1 );
9126 } );
9127 }
9128 );
9129
9130 /*
9131 * State API methods
9132 */
9133
9134 _api_register( 'state()', function () {
9135 return this.context.length ?
9136 this.context[0].oSavedState :
9137 null;
9138 } );
9139
9140
9141 _api_register( 'state.clear()', function () {
9142 return this.iterator( 'table', function ( settings ) {
9143 // Save an empty object
9144 settings.fnStateSaveCallback.call( settings.oInstance, settings, {} );
9145 } );
9146 } );
9147
9148
9149 _api_register( 'state.loaded()', function () {
9150 return this.context.length ?
9151 this.context[0].oLoadedState :
9152 null;
9153 } );
9154
9155
9156 _api_register( 'state.save()', function () {
9157 return this.iterator( 'table', function ( settings ) {
9158 _fnSaveState( settings );
9159 } );
9160 } );
9161
9162
9163
9164 /**
9165 * Provide a common method for plug-ins to check the version of DataTables being
9166 * used, in order to ensure compatibility.
9167 *
9168 * @param {string} version Version string to check for, in the format "X.Y.Z".
9169 * Note that the formats "X" and "X.Y" are also acceptable.
9170 * @returns {boolean} true if this version of DataTables is greater or equal to
9171 * the required version, or false if this version of DataTales is not
9172 * suitable
9173 * @static
9174 * @dtopt API-Static
9175 *
9176 * @example
9177 * alert( $.fn.dataTable.versionCheck( '1.9.0' ) );
9178 */
9179 DataTable.versionCheck = DataTable.fnVersionCheck = function( version )
9180 {
9181 var aThis = DataTable.version.split('.');
9182 var aThat = version.split('.');
9183 var iThis, iThat;
9184
9185 for ( var i=0, iLen=aThat.length ; i<iLen ; i++ ) {
9186 iThis = parseInt( aThis[i], 10 ) || 0;
9187 iThat = parseInt( aThat[i], 10 ) || 0;
9188
9189 // Parts are the same, keep comparing
9190 if (iThis === iThat) {
9191 continue;
9192 }
9193
9194 // Parts are different, return immediately
9195 return iThis > iThat;
9196 }
9197
9198 return true;
9199 };
9200
9201
9202 /**
9203 * Check if a `<table>` node is a DataTable table already or not.
9204 *
9205 * @param {node|jquery|string} table Table node, jQuery object or jQuery
9206 * selector for the table to test. Note that if more than more than one
9207 * table is passed on, only the first will be checked
9208 * @returns {boolean} true the table given is a DataTable, or false otherwise
9209 * @static
9210 * @dtopt API-Static
9211 *
9212 * @example
9213 * if ( ! $.fn.DataTable.isDataTable( '#example' ) ) {
9214 * $('#example').dataTable();
9215 * }
9216 */
9217 DataTable.isDataTable = DataTable.fnIsDataTable = function ( table )
9218 {
9219 var t = $(table).get(0);
9220 var is = false;
9221
9222 if ( table instanceof DataTable.Api ) {
9223 return true;
9224 }
9225
9226 $.each( DataTable.settings, function (i, o) {
9227 var head = o.nScrollHead ? $('table', o.nScrollHead)[0] : null;
9228 var foot = o.nScrollFoot ? $('table', o.nScrollFoot)[0] : null;
9229
9230 if ( o.nTable === t || head === t || foot === t ) {
9231 is = true;
9232 }
9233 } );
9234
9235 return is;
9236 };
9237
9238
9239 /**
9240 * Get all DataTable tables that have been initialised - optionally you can
9241 * select to get only currently visible tables.
9242 *
9243 * @param {boolean} [visible=false] Flag to indicate if you want all (default)
9244 * or visible tables only.
9245 * @returns {array} Array of `table` nodes (not DataTable instances) which are
9246 * DataTables
9247 * @static
9248 * @dtopt API-Static
9249 *
9250 * @example
9251 * $.each( $.fn.dataTable.tables(true), function () {
9252 * $(table).DataTable().columns.adjust();
9253 * } );
9254 */
9255 DataTable.tables = DataTable.fnTables = function ( visible )
9256 {
9257 var api = false;
9258
9259 if ( $.isPlainObject( visible ) ) {
9260 api = visible.api;
9261 visible = visible.visible;
9262 }
9263
9264 var a = $.map( DataTable.settings, function (o) {
9265 if ( !visible || (visible && $(o.nTable).is(':visible')) ) {
9266 return o.nTable;
9267 }
9268 } );
9269
9270 return api ?
9271 new _Api( a ) :
9272 a;
9273 };
9274
9275
9276 /**
9277 * Convert from camel case parameters to Hungarian notation. This is made public
9278 * for the extensions to provide the same ability as DataTables core to accept
9279 * either the 1.9 style Hungarian notation, or the 1.10+ style camelCase
9280 * parameters.
9281 *
9282 * @param {object} src The model object which holds all parameters that can be
9283 * mapped.
9284 * @param {object} user The object to convert from camel case to Hungarian.
9285 * @param {boolean} force When set to `true`, properties which already have a
9286 * Hungarian value in the `user` object will be overwritten. Otherwise they
9287 * won't be.
9288 */
9289 DataTable.camelToHungarian = _fnCamelToHungarian;
9290
9291
9292
9293 /**
9294 *
9295 */
9296 _api_register( '$()', function ( selector, opts ) {
9297 var
9298 rows = this.rows( opts ).nodes(), // Get all rows
9299 jqRows = $(rows);
9300
9301 return $( [].concat(
9302 jqRows.filter( selector ).toArray(),
9303 jqRows.find( selector ).toArray()
9304 ) );
9305 } );
9306
9307
9308 // jQuery functions to operate on the tables
9309 $.each( [ 'on', 'one', 'off' ], function (i, key) {
9310 _api_register( key+'()', function ( /* event, handler */ ) {
9311 var args = Array.prototype.slice.call(arguments);
9312
9313 // Add the `dt` namespace automatically if it isn't already present
9314 args[0] = $.map( args[0].split( /\s/ ), function ( e ) {
9315 return ! e.match(/\.dt\b/) ?
9316 e+'.dt' :
9317 e;
9318 } ).join( ' ' );
9319
9320 var inst = $( this.tables().nodes() );
9321 inst[key].apply( inst, args );
9322 return this;
9323 } );
9324 } );
9325
9326
9327 _api_register( 'clear()', function () {
9328 return this.iterator( 'table', function ( settings ) {
9329 _fnClearTable( settings );
9330 } );
9331 } );
9332
9333
9334 _api_register( 'settings()', function () {
9335 return new _Api( this.context, this.context );
9336 } );
9337
9338
9339 _api_register( 'init()', function () {
9340 var ctx = this.context;
9341 return ctx.length ? ctx[0].oInit : null;
9342 } );
9343
9344
9345 _api_register( 'data()', function () {
9346 return this.iterator( 'table', function ( settings ) {
9347 return _pluck( settings.aoData, '_aData' );
9348 } ).flatten();
9349 } );
9350
9351
9352 _api_register( 'destroy()', function ( remove ) {
9353 remove = remove || false;
9354
9355 return this.iterator( 'table', function ( settings ) {
9356 var orig = settings.nTableWrapper.parentNode;
9357 var classes = settings.oClasses;
9358 var table = settings.nTable;
9359 var tbody = settings.nTBody;
9360 var thead = settings.nTHead;
9361 var tfoot = settings.nTFoot;
9362 var jqTable = $(table);
9363 var jqTbody = $(tbody);
9364 var jqWrapper = $(settings.nTableWrapper);
9365 var rows = $.map( settings.aoData, function (r) { return r.nTr; } );
9366 var i, ien;
9367
9368 // Flag to note that the table is currently being destroyed - no action
9369 // should be taken
9370 settings.bDestroying = true;
9371
9372 // Fire off the destroy callbacks for plug-ins etc
9373 _fnCallbackFire( settings, "aoDestroyCallback", "destroy", [settings] );
9374
9375 // If not being removed from the document, make all columns visible
9376 if ( ! remove ) {
9377 new _Api( settings ).columns().visible( true );
9378 }
9379
9380 // Blitz all `DT` namespaced events (these are internal events, the
9381 // lowercase, `dt` events are user subscribed and they are responsible
9382 // for removing them
9383 jqWrapper.off('.DT').find(':not(tbody *)').off('.DT');
9384 $(window).off('.DT-'+settings.sInstance);
9385
9386 // When scrolling we had to break the table up - restore it
9387 if ( table != thead.parentNode ) {
9388 jqTable.children('thead').detach();
9389 jqTable.append( thead );
9390 }
9391
9392 if ( tfoot && table != tfoot.parentNode ) {
9393 jqTable.children('tfoot').detach();
9394 jqTable.append( tfoot );
9395 }
9396
9397 settings.aaSorting = [];
9398 settings.aaSortingFixed = [];
9399 _fnSortingClasses( settings );
9400
9401 $( rows ).removeClass( settings.asStripeClasses.join(' ') );
9402
9403 $('th, td', thead).removeClass( classes.sSortable+' '+
9404 classes.sSortableAsc+' '+classes.sSortableDesc+' '+classes.sSortableNone
9405 );
9406
9407 // Add the TR elements back into the table in their original order
9408 jqTbody.children().detach();
9409 jqTbody.append( rows );
9410
9411 // Remove the DataTables generated nodes, events and classes
9412 var removedMethod = remove ? 'remove' : 'detach';
9413 jqTable[ removedMethod ]();
9414 jqWrapper[ removedMethod ]();
9415
9416 // If we need to reattach the table to the document
9417 if ( ! remove && orig ) {
9418 // insertBefore acts like appendChild if !arg[1]
9419 orig.insertBefore( table, settings.nTableReinsertBefore );
9420
9421 // Restore the width of the original table - was read from the style property,
9422 // so we can restore directly to that
9423 jqTable
9424 .css( 'width', settings.sDestroyWidth )
9425 .removeClass( classes.sTable );
9426
9427 // If the were originally stripe classes - then we add them back here.
9428 // Note this is not fool proof (for example if not all rows had stripe
9429 // classes - but it's a good effort without getting carried away
9430 ien = settings.asDestroyStripes.length;
9431
9432 if ( ien ) {
9433 jqTbody.children().each( function (i) {
9434 $(this).addClass( settings.asDestroyStripes[i % ien] );
9435 } );
9436 }
9437 }
9438
9439 /* Remove the settings object from the settings array */
9440 var idx = $.inArray( settings, DataTable.settings );
9441 if ( idx !== -1 ) {
9442 DataTable.settings.splice( idx, 1 );
9443 }
9444 } );
9445 } );
9446
9447
9448 // Add the `every()` method for rows, columns and cells in a compact form
9449 $.each( [ 'column', 'row', 'cell' ], function ( i, type ) {
9450 _api_register( type+'s().every()', function ( fn ) {
9451 var opts = this.selector.opts;
9452 var api = this;
9453
9454 return this.iterator( type, function ( settings, arg1, arg2, arg3, arg4 ) {
9455 // Rows and columns:
9456 // arg1 - index
9457 // arg2 - table counter
9458 // arg3 - loop counter
9459 // arg4 - undefined
9460 // Cells:
9461 // arg1 - row index
9462 // arg2 - column index
9463 // arg3 - table counter
9464 // arg4 - loop counter
9465 fn.call(
9466 api[ type ](
9467 arg1,
9468 type==='cell' ? arg2 : opts,
9469 type==='cell' ? opts : undefined
9470 ),
9471 arg1, arg2, arg3, arg4
9472 );
9473 } );
9474 } );
9475 } );
9476
9477
9478 // i18n method for extensions to be able to use the language object from the
9479 // DataTable
9480 _api_register( 'i18n()', function ( token, def, plural ) {
9481 var ctx = this.context[0];
9482 var resolved = _fnGetObjectDataFn( token )( ctx.oLanguage );
9483
9484 if ( resolved === undefined ) {
9485 resolved = def;
9486 }
9487
9488 if ( plural !== undefined && $.isPlainObject( resolved ) ) {
9489 resolved = resolved[ plural ] !== undefined ?
9490 resolved[ plural ] :
9491 resolved._;
9492 }
9493
9494 return resolved.replace( '%d', plural ); // nb: plural might be undefined,
9495 } );
9496 /**
9497 * Version string for plug-ins to check compatibility. Allowed format is
9498 * `a.b.c-d` where: a:int, b:int, c:int, d:string(dev|beta|alpha). `d` is used
9499 * only for non-release builds. See http://semver.org/ for more information.
9500 * @member
9501 * @type string
9502 * @default Version number
9503 */
9504 DataTable.version = "1.10.21";
9505
9506 /**
9507 * Private data store, containing all of the settings objects that are
9508 * created for the tables on a given page.
9509 *
9510 * Note that the `DataTable.settings` object is aliased to
9511 * `jQuery.fn.dataTableExt` through which it may be accessed and
9512 * manipulated, or `jQuery.fn.dataTable.settings`.
9513 * @member
9514 * @type array
9515 * @default []
9516 * @private
9517 */
9518 DataTable.settings = [];
9519
9520 /**
9521 * Object models container, for the various models that DataTables has
9522 * available to it. These models define the objects that are used to hold
9523 * the active state and configuration of the table.
9524 * @namespace
9525 */
9526 DataTable.models = {};
9527
9528
9529
9530 /**
9531 * Template object for the way in which DataTables holds information about
9532 * search information for the global filter and individual column filters.
9533 * @namespace
9534 */
9535 DataTable.models.oSearch = {
9536 /**
9537 * Flag to indicate if the filtering should be case insensitive or not
9538 * @type boolean
9539 * @default true
9540 */
9541 "bCaseInsensitive": true,
9542
9543 /**
9544 * Applied search term
9545 * @type string
9546 * @default <i>Empty string</i>
9547 */
9548 "sSearch": "",
9549
9550 /**
9551 * Flag to indicate if the search term should be interpreted as a
9552 * regular expression (true) or not (false) and therefore and special
9553 * regex characters escaped.
9554 * @type boolean
9555 * @default false
9556 */
9557 "bRegex": false,
9558
9559 /**
9560 * Flag to indicate if DataTables is to use its smart filtering or not.
9561 * @type boolean
9562 * @default true
9563 */
9564 "bSmart": true
9565 };
9566
9567
9568
9569
9570 /**
9571 * Template object for the way in which DataTables holds information about
9572 * each individual row. This is the object format used for the settings
9573 * aoData array.
9574 * @namespace
9575 */
9576 DataTable.models.oRow = {
9577 /**
9578 * TR element for the row
9579 * @type node
9580 * @default null
9581 */
9582 "nTr": null,
9583
9584 /**
9585 * Array of TD elements for each row. This is null until the row has been
9586 * created.
9587 * @type array nodes
9588 * @default []
9589 */
9590 "anCells": null,
9591
9592 /**
9593 * Data object from the original data source for the row. This is either
9594 * an array if using the traditional form of DataTables, or an object if
9595 * using mData options. The exact type will depend on the passed in
9596 * data from the data source, or will be an array if using DOM a data
9597 * source.
9598 * @type array|object
9599 * @default []
9600 */
9601 "_aData": [],
9602
9603 /**
9604 * Sorting data cache - this array is ostensibly the same length as the
9605 * number of columns (although each index is generated only as it is
9606 * needed), and holds the data that is used for sorting each column in the
9607 * row. We do this cache generation at the start of the sort in order that
9608 * the formatting of the sort data need be done only once for each cell
9609 * per sort. This array should not be read from or written to by anything
9610 * other than the master sorting methods.
9611 * @type array
9612 * @default null
9613 * @private
9614 */
9615 "_aSortData": null,
9616
9617 /**
9618 * Per cell filtering data cache. As per the sort data cache, used to
9619 * increase the performance of the filtering in DataTables
9620 * @type array
9621 * @default null
9622 * @private
9623 */
9624 "_aFilterData": null,
9625
9626 /**
9627 * Filtering data cache. This is the same as the cell filtering cache, but
9628 * in this case a string rather than an array. This is easily computed with
9629 * a join on `_aFilterData`, but is provided as a cache so the join isn't
9630 * needed on every search (memory traded for performance)
9631 * @type array
9632 * @default null
9633 * @private
9634 */
9635 "_sFilterRow": null,
9636
9637 /**
9638 * Cache of the class name that DataTables has applied to the row, so we
9639 * can quickly look at this variable rather than needing to do a DOM check
9640 * on className for the nTr property.
9641 * @type string
9642 * @default <i>Empty string</i>
9643 * @private
9644 */
9645 "_sRowStripe": "",
9646
9647 /**
9648 * Denote if the original data source was from the DOM, or the data source
9649 * object. This is used for invalidating data, so DataTables can
9650 * automatically read data from the original source, unless uninstructed
9651 * otherwise.
9652 * @type string
9653 * @default null
9654 * @private
9655 */
9656 "src": null,
9657
9658 /**
9659 * Index in the aoData array. This saves an indexOf lookup when we have the
9660 * object, but want to know the index
9661 * @type integer
9662 * @default -1
9663 * @private
9664 */
9665 "idx": -1
9666 };
9667
9668
9669 /**
9670 * Template object for the column information object in DataTables. This object
9671 * is held in the settings aoColumns array and contains all the information that
9672 * DataTables needs about each individual column.
9673 *
9674 * Note that this object is related to {@link DataTable.defaults.column}
9675 * but this one is the internal data store for DataTables's cache of columns.
9676 * It should NOT be manipulated outside of DataTables. Any configuration should
9677 * be done through the initialisation options.
9678 * @namespace
9679 */
9680 DataTable.models.oColumn = {
9681 /**
9682 * Column index. This could be worked out on-the-fly with $.inArray, but it
9683 * is faster to just hold it as a variable
9684 * @type integer
9685 * @default null
9686 */
9687 "idx": null,
9688
9689 /**
9690 * A list of the columns that sorting should occur on when this column
9691 * is sorted. That this property is an array allows multi-column sorting
9692 * to be defined for a column (for example first name / last name columns
9693 * would benefit from this). The values are integers pointing to the
9694 * columns to be sorted on (typically it will be a single integer pointing
9695 * at itself, but that doesn't need to be the case).
9696 * @type array
9697 */
9698 "aDataSort": null,
9699
9700 /**
9701 * Define the sorting directions that are applied to the column, in sequence
9702 * as the column is repeatedly sorted upon - i.e. the first value is used
9703 * as the sorting direction when the column if first sorted (clicked on).
9704 * Sort it again (click again) and it will move on to the next index.
9705 * Repeat until loop.
9706 * @type array
9707 */
9708 "asSorting": null,
9709
9710 /**
9711 * Flag to indicate if the column is searchable, and thus should be included
9712 * in the filtering or not.
9713 * @type boolean
9714 */
9715 "bSearchable": null,
9716
9717 /**
9718 * Flag to indicate if the column is sortable or not.
9719 * @type boolean
9720 */
9721 "bSortable": null,
9722
9723 /**
9724 * Flag to indicate if the column is currently visible in the table or not
9725 * @type boolean
9726 */
9727 "bVisible": null,
9728
9729 /**
9730 * Store for manual type assignment using the `column.type` option. This
9731 * is held in store so we can manipulate the column's `sType` property.
9732 * @type string
9733 * @default null
9734 * @private
9735 */
9736 "_sManualType": null,
9737
9738 /**
9739 * Flag to indicate if HTML5 data attributes should be used as the data
9740 * source for filtering or sorting. True is either are.
9741 * @type boolean
9742 * @default false
9743 * @private
9744 */
9745 "_bAttrSrc": false,
9746
9747 /**
9748 * Developer definable function that is called whenever a cell is created (Ajax source,
9749 * etc) or processed for input (DOM source). This can be used as a compliment to mRender
9750 * allowing you to modify the DOM element (add background colour for example) when the
9751 * element is available.
9752 * @type function
9753 * @param {element} nTd The TD node that has been created
9754 * @param {*} sData The Data for the cell
9755 * @param {array|object} oData The data for the whole row
9756 * @param {int} iRow The row index for the aoData data store
9757 * @default null
9758 */
9759 "fnCreatedCell": null,
9760
9761 /**
9762 * Function to get data from a cell in a column. You should <b>never</b>
9763 * access data directly through _aData internally in DataTables - always use
9764 * the method attached to this property. It allows mData to function as
9765 * required. This function is automatically assigned by the column
9766 * initialisation method
9767 * @type function
9768 * @param {array|object} oData The data array/object for the array
9769 * (i.e. aoData[]._aData)
9770 * @param {string} sSpecific The specific data type you want to get -
9771 * 'display', 'type' 'filter' 'sort'
9772 * @returns {*} The data for the cell from the given row's data
9773 * @default null
9774 */
9775 "fnGetData": null,
9776
9777 /**
9778 * Function to set data for a cell in the column. You should <b>never</b>
9779 * set the data directly to _aData internally in DataTables - always use
9780 * this method. It allows mData to function as required. This function
9781 * is automatically assigned by the column initialisation method
9782 * @type function
9783 * @param {array|object} oData The data array/object for the array
9784 * (i.e. aoData[]._aData)
9785 * @param {*} sValue Value to set
9786 * @default null
9787 */
9788 "fnSetData": null,
9789
9790 /**
9791 * Property to read the value for the cells in the column from the data
9792 * source array / object. If null, then the default content is used, if a
9793 * function is given then the return from the function is used.
9794 * @type function|int|string|null
9795 * @default null
9796 */
9797 "mData": null,
9798
9799 /**
9800 * Partner property to mData which is used (only when defined) to get
9801 * the data - i.e. it is basically the same as mData, but without the
9802 * 'set' option, and also the data fed to it is the result from mData.
9803 * This is the rendering method to match the data method of mData.
9804 * @type function|int|string|null
9805 * @default null
9806 */
9807 "mRender": null,
9808
9809 /**
9810 * Unique header TH/TD element for this column - this is what the sorting
9811 * listener is attached to (if sorting is enabled.)
9812 * @type node
9813 * @default null
9814 */
9815 "nTh": null,
9816
9817 /**
9818 * Unique footer TH/TD element for this column (if there is one). Not used
9819 * in DataTables as such, but can be used for plug-ins to reference the
9820 * footer for each column.
9821 * @type node
9822 * @default null
9823 */
9824 "nTf": null,
9825
9826 /**
9827 * The class to apply to all TD elements in the table's TBODY for the column
9828 * @type string
9829 * @default null
9830 */
9831 "sClass": null,
9832
9833 /**
9834 * When DataTables calculates the column widths to assign to each column,
9835 * it finds the longest string in each column and then constructs a
9836 * temporary table and reads the widths from that. The problem with this
9837 * is that "mmm" is much wider then "iiii", but the latter is a longer
9838 * string - thus the calculation can go wrong (doing it properly and putting
9839 * it into an DOM object and measuring that is horribly(!) slow). Thus as
9840 * a "work around" we provide this option. It will append its value to the
9841 * text that is found to be the longest string for the column - i.e. padding.
9842 * @type string
9843 */
9844 "sContentPadding": null,
9845
9846 /**
9847 * Allows a default value to be given for a column's data, and will be used
9848 * whenever a null data source is encountered (this can be because mData
9849 * is set to null, or because the data source itself is null).
9850 * @type string
9851 * @default null
9852 */
9853 "sDefaultContent": null,
9854
9855 /**
9856 * Name for the column, allowing reference to the column by name as well as
9857 * by index (needs a lookup to work by name).
9858 * @type string
9859 */
9860 "sName": null,
9861
9862 /**
9863 * Custom sorting data type - defines which of the available plug-ins in
9864 * afnSortData the custom sorting will use - if any is defined.
9865 * @type string
9866 * @default std
9867 */
9868 "sSortDataType": 'std',
9869
9870 /**
9871 * Class to be applied to the header element when sorting on this column
9872 * @type string
9873 * @default null
9874 */
9875 "sSortingClass": null,
9876
9877 /**
9878 * Class to be applied to the header element when sorting on this column -
9879 * when jQuery UI theming is used.
9880 * @type string
9881 * @default null
9882 */
9883 "sSortingClassJUI": null,
9884
9885 /**
9886 * Title of the column - what is seen in the TH element (nTh).
9887 * @type string
9888 */
9889 "sTitle": null,
9890
9891 /**
9892 * Column sorting and filtering type
9893 * @type string
9894 * @default null
9895 */
9896 "sType": null,
9897
9898 /**
9899 * Width of the column
9900 * @type string
9901 * @default null
9902 */
9903 "sWidth": null,
9904
9905 /**
9906 * Width of the column when it was first "encountered"
9907 * @type string
9908 * @default null
9909 */
9910 "sWidthOrig": null
9911 };
9912
9913
9914 /*
9915 * Developer note: The properties of the object below are given in Hungarian
9916 * notation, that was used as the interface for DataTables prior to v1.10, however
9917 * from v1.10 onwards the primary interface is camel case. In order to avoid
9918 * breaking backwards compatibility utterly with this change, the Hungarian
9919 * version is still, internally the primary interface, but is is not documented
9920 * - hence the @name tags in each doc comment. This allows a Javascript function
9921 * to create a map from Hungarian notation to camel case (going the other direction
9922 * would require each property to be listed, which would at around 3K to the size
9923 * of DataTables, while this method is about a 0.5K hit.
9924 *
9925 * Ultimately this does pave the way for Hungarian notation to be dropped
9926 * completely, but that is a massive amount of work and will break current
9927 * installs (therefore is on-hold until v2).
9928 */
9929
9930 /**
9931 * Initialisation options that can be given to DataTables at initialisation
9932 * time.
9933 * @namespace
9934 */
9935 DataTable.defaults = {
9936 /**
9937 * An array of data to use for the table, passed in at initialisation which
9938 * will be used in preference to any data which is already in the DOM. This is
9939 * particularly useful for constructing tables purely in Javascript, for
9940 * example with a custom Ajax call.
9941 * @type array
9942 * @default null
9943 *
9944 * @dtopt Option
9945 * @name DataTable.defaults.data
9946 *
9947 * @example
9948 * // Using a 2D array data source
9949 * $(document).ready( function () {
9950 * $('#example').dataTable( {
9951 * "data": [
9952 * ['Trident', 'Internet Explorer 4.0', 'Win 95+', 4, 'X'],
9953 * ['Trident', 'Internet Explorer 5.0', 'Win 95+', 5, 'C'],
9954 * ],
9955 * "columns": [
9956 * { "title": "Engine" },
9957 * { "title": "Browser" },
9958 * { "title": "Platform" },
9959 * { "title": "Version" },
9960 * { "title": "Grade" }
9961 * ]
9962 * } );
9963 * } );
9964 *
9965 * @example
9966 * // Using an array of objects as a data source (`data`)
9967 * $(document).ready( function () {
9968 * $('#example').dataTable( {
9969 * "data": [
9970 * {
9971 * "engine": "Trident",
9972 * "browser": "Internet Explorer 4.0",
9973 * "platform": "Win 95+",
9974 * "version": 4,
9975 * "grade": "X"
9976 * },
9977 * {
9978 * "engine": "Trident",
9979 * "browser": "Internet Explorer 5.0",
9980 * "platform": "Win 95+",
9981 * "version": 5,
9982 * "grade": "C"
9983 * }
9984 * ],
9985 * "columns": [
9986 * { "title": "Engine", "data": "engine" },
9987 * { "title": "Browser", "data": "browser" },
9988 * { "title": "Platform", "data": "platform" },
9989 * { "title": "Version", "data": "version" },
9990 * { "title": "Grade", "data": "grade" }
9991 * ]
9992 * } );
9993 * } );
9994 */
9995 "aaData": null,
9996
9997
9998 /**
9999 * If ordering is enabled, then DataTables will perform a first pass sort on
10000 * initialisation. You can define which column(s) the sort is performed
10001 * upon, and the sorting direction, with this variable. The `sorting` array
10002 * should contain an array for each column to be sorted initially containing
10003 * the column's index and a direction string ('asc' or 'desc').
10004 * @type array
10005 * @default [[0,'asc']]
10006 *
10007 * @dtopt Option
10008 * @name DataTable.defaults.order
10009 *
10010 * @example
10011 * // Sort by 3rd column first, and then 4th column
10012 * $(document).ready( function() {
10013 * $('#example').dataTable( {
10014 * "order": [[2,'asc'], [3,'desc']]
10015 * } );
10016 * } );
10017 *
10018 * // No initial sorting
10019 * $(document).ready( function() {
10020 * $('#example').dataTable( {
10021 * "order": []
10022 * } );
10023 * } );
10024 */
10025 "aaSorting": [[0,'asc']],
10026
10027
10028 /**
10029 * This parameter is basically identical to the `sorting` parameter, but
10030 * cannot be overridden by user interaction with the table. What this means
10031 * is that you could have a column (visible or hidden) which the sorting
10032 * will always be forced on first - any sorting after that (from the user)
10033 * will then be performed as required. This can be useful for grouping rows
10034 * together.
10035 * @type array
10036 * @default null
10037 *
10038 * @dtopt Option
10039 * @name DataTable.defaults.orderFixed
10040 *
10041 * @example
10042 * $(document).ready( function() {
10043 * $('#example').dataTable( {
10044 * "orderFixed": [[0,'asc']]
10045 * } );
10046 * } )
10047 */
10048 "aaSortingFixed": [],
10049
10050
10051 /**
10052 * DataTables can be instructed to load data to display in the table from a
10053 * Ajax source. This option defines how that Ajax call is made and where to.
10054 *
10055 * The `ajax` property has three different modes of operation, depending on
10056 * how it is defined. These are:
10057 *
10058 * * `string` - Set the URL from where the data should be loaded from.
10059 * * `object` - Define properties for `jQuery.ajax`.
10060 * * `function` - Custom data get function
10061 *
10062 * `string`
10063 * --------
10064 *
10065 * As a string, the `ajax` property simply defines the URL from which
10066 * DataTables will load data.
10067 *
10068 * `object`
10069 * --------
10070 *
10071 * As an object, the parameters in the object are passed to
10072 * [jQuery.ajax](http://api.jquery.com/jQuery.ajax/) allowing fine control
10073 * of the Ajax request. DataTables has a number of default parameters which
10074 * you can override using this option. Please refer to the jQuery
10075 * documentation for a full description of the options available, although
10076 * the following parameters provide additional options in DataTables or
10077 * require special consideration:
10078 *
10079 * * `data` - As with jQuery, `data` can be provided as an object, but it
10080 * can also be used as a function to manipulate the data DataTables sends
10081 * to the server. The function takes a single parameter, an object of
10082 * parameters with the values that DataTables has readied for sending. An
10083 * object may be returned which will be merged into the DataTables
10084 * defaults, or you can add the items to the object that was passed in and
10085 * not return anything from the function. This supersedes `fnServerParams`
10086 * from DataTables 1.9-.
10087 *
10088 * * `dataSrc` - By default DataTables will look for the property `data` (or
10089 * `aaData` for compatibility with DataTables 1.9-) when obtaining data
10090 * from an Ajax source or for server-side processing - this parameter
10091 * allows that property to be changed. You can use Javascript dotted
10092 * object notation to get a data source for multiple levels of nesting, or
10093 * it my be used as a function. As a function it takes a single parameter,
10094 * the JSON returned from the server, which can be manipulated as
10095 * required, with the returned value being that used by DataTables as the
10096 * data source for the table. This supersedes `sAjaxDataProp` from
10097 * DataTables 1.9-.
10098 *
10099 * * `success` - Should not be overridden it is used internally in
10100 * DataTables. To manipulate / transform the data returned by the server
10101 * use `ajax.dataSrc`, or use `ajax` as a function (see below).
10102 *
10103 * `function`
10104 * ----------
10105 *
10106 * As a function, making the Ajax call is left up to yourself allowing
10107 * complete control of the Ajax request. Indeed, if desired, a method other
10108 * than Ajax could be used to obtain the required data, such as Web storage
10109 * or an AIR database.
10110 *
10111 * The function is given four parameters and no return is required. The
10112 * parameters are:
10113 *
10114 * 1. _object_ - Data to send to the server
10115 * 2. _function_ - Callback function that must be executed when the required
10116 * data has been obtained. That data should be passed into the callback
10117 * as the only parameter
10118 * 3. _object_ - DataTables settings object for the table
10119 *
10120 * Note that this supersedes `fnServerData` from DataTables 1.9-.
10121 *
10122 * @type string|object|function
10123 * @default null
10124 *
10125 * @dtopt Option
10126 * @name DataTable.defaults.ajax
10127 * @since 1.10.0
10128 *
10129 * @example
10130 * // Get JSON data from a file via Ajax.
10131 * // Note DataTables expects data in the form `{ data: [ ...data... ] }` by default).
10132 * $('#example').dataTable( {
10133 * "ajax": "data.json"
10134 * } );
10135 *
10136 * @example
10137 * // Get JSON data from a file via Ajax, using `dataSrc` to change
10138 * // `data` to `tableData` (i.e. `{ tableData: [ ...data... ] }`)
10139 * $('#example').dataTable( {
10140 * "ajax": {
10141 * "url": "data.json",
10142 * "dataSrc": "tableData"
10143 * }
10144 * } );
10145 *
10146 * @example
10147 * // Get JSON data from a file via Ajax, using `dataSrc` to read data
10148 * // from a plain array rather than an array in an object
10149 * $('#example').dataTable( {
10150 * "ajax": {
10151 * "url": "data.json",
10152 * "dataSrc": ""
10153 * }
10154 * } );
10155 *
10156 * @example
10157 * // Manipulate the data returned from the server - add a link to data
10158 * // (note this can, should, be done using `render` for the column - this
10159 * // is just a simple example of how the data can be manipulated).
10160 * $('#example').dataTable( {
10161 * "ajax": {
10162 * "url": "data.json",
10163 * "dataSrc": function ( json ) {
10164 * for ( var i=0, ien=json.length ; i<ien ; i++ ) {
10165 * json[i][0] = '<a href="/message/'+json[i][0]+'>View message</a>';
10166 * }
10167 * return json;
10168 * }
10169 * }
10170 * } );
10171 *
10172 * @example
10173 * // Add data to the request
10174 * $('#example').dataTable( {
10175 * "ajax": {
10176 * "url": "data.json",
10177 * "data": function ( d ) {
10178 * return {
10179 * "extra_search": $('#extra').val()
10180 * };
10181 * }
10182 * }
10183 * } );
10184 *
10185 * @example
10186 * // Send request as POST
10187 * $('#example').dataTable( {
10188 * "ajax": {
10189 * "url": "data.json",
10190 * "type": "POST"
10191 * }
10192 * } );
10193 *
10194 * @example
10195 * // Get the data from localStorage (could interface with a form for
10196 * // adding, editing and removing rows).
10197 * $('#example').dataTable( {
10198 * "ajax": function (data, callback, settings) {
10199 * callback(
10200 * JSON.parse( localStorage.getItem('dataTablesData') )
10201 * );
10202 * }
10203 * } );
10204 */
10205 "ajax": null,
10206
10207
10208 /**
10209 * This parameter allows you to readily specify the entries in the length drop
10210 * down menu that DataTables shows when pagination is enabled. It can be
10211 * either a 1D array of options which will be used for both the displayed
10212 * option and the value, or a 2D array which will use the array in the first
10213 * position as the value, and the array in the second position as the
10214 * displayed options (useful for language strings such as 'All').
10215 *
10216 * Note that the `pageLength` property will be automatically set to the
10217 * first value given in this array, unless `pageLength` is also provided.
10218 * @type array
10219 * @default [ 10, 25, 50, 100 ]
10220 *
10221 * @dtopt Option
10222 * @name DataTable.defaults.lengthMenu
10223 *
10224 * @example
10225 * $(document).ready( function() {
10226 * $('#example').dataTable( {
10227 * "lengthMenu": [[10, 25, 50, -1], [10, 25, 50, "All"]]
10228 * } );
10229 * } );
10230 */
10231 "aLengthMenu": [ 10, 25, 50, 100 ],
10232
10233
10234 /**
10235 * The `columns` option in the initialisation parameter allows you to define
10236 * details about the way individual columns behave. For a full list of
10237 * column options that can be set, please see
10238 * {@link DataTable.defaults.column}. Note that if you use `columns` to
10239 * define your columns, you must have an entry in the array for every single
10240 * column that you have in your table (these can be null if you don't which
10241 * to specify any options).
10242 * @member
10243 *
10244 * @name DataTable.defaults.column
10245 */
10246 "aoColumns": null,
10247
10248 /**
10249 * Very similar to `columns`, `columnDefs` allows you to target a specific
10250 * column, multiple columns, or all columns, using the `targets` property of
10251 * each object in the array. This allows great flexibility when creating
10252 * tables, as the `columnDefs` arrays can be of any length, targeting the
10253 * columns you specifically want. `columnDefs` may use any of the column
10254 * options available: {@link DataTable.defaults.column}, but it _must_
10255 * have `targets` defined in each object in the array. Values in the `targets`
10256 * array may be:
10257 * <ul>
10258 * <li>a string - class name will be matched on the TH for the column</li>
10259 * <li>0 or a positive integer - column index counting from the left</li>
10260 * <li>a negative integer - column index counting from the right</li>
10261 * <li>the string "_all" - all columns (i.e. assign a default)</li>
10262 * </ul>
10263 * @member
10264 *
10265 * @name DataTable.defaults.columnDefs
10266 */
10267 "aoColumnDefs": null,
10268
10269
10270 /**
10271 * Basically the same as `search`, this parameter defines the individual column
10272 * filtering state at initialisation time. The array must be of the same size
10273 * as the number of columns, and each element be an object with the parameters
10274 * `search` and `escapeRegex` (the latter is optional). 'null' is also
10275 * accepted and the default will be used.
10276 * @type array
10277 * @default []
10278 *
10279 * @dtopt Option
10280 * @name DataTable.defaults.searchCols
10281 *
10282 * @example
10283 * $(document).ready( function() {
10284 * $('#example').dataTable( {
10285 * "searchCols": [
10286 * null,
10287 * { "search": "My filter" },
10288 * null,
10289 * { "search": "^[0-9]", "escapeRegex": false }
10290 * ]
10291 * } );
10292 * } )
10293 */
10294 "aoSearchCols": [],
10295
10296
10297 /**
10298 * An array of CSS classes that should be applied to displayed rows. This
10299 * array may be of any length, and DataTables will apply each class
10300 * sequentially, looping when required.
10301 * @type array
10302 * @default null <i>Will take the values determined by the `oClasses.stripe*`
10303 * options</i>
10304 *
10305 * @dtopt Option
10306 * @name DataTable.defaults.stripeClasses
10307 *
10308 * @example
10309 * $(document).ready( function() {
10310 * $('#example').dataTable( {
10311 * "stripeClasses": [ 'strip1', 'strip2', 'strip3' ]
10312 * } );
10313 * } )
10314 */
10315 "asStripeClasses": null,
10316
10317
10318 /**
10319 * Enable or disable automatic column width calculation. This can be disabled
10320 * as an optimisation (it takes some time to calculate the widths) if the
10321 * tables widths are passed in using `columns`.
10322 * @type boolean
10323 * @default true
10324 *
10325 * @dtopt Features
10326 * @name DataTable.defaults.autoWidth
10327 *
10328 * @example
10329 * $(document).ready( function () {
10330 * $('#example').dataTable( {
10331 * "autoWidth": false
10332 * } );
10333 * } );
10334 */
10335 "bAutoWidth": true,
10336
10337
10338 /**
10339 * Deferred rendering can provide DataTables with a huge speed boost when you
10340 * are using an Ajax or JS data source for the table. This option, when set to
10341 * true, will cause DataTables to defer the creation of the table elements for
10342 * each row until they are needed for a draw - saving a significant amount of
10343 * time.
10344 * @type boolean
10345 * @default false
10346 *
10347 * @dtopt Features
10348 * @name DataTable.defaults.deferRender
10349 *
10350 * @example
10351 * $(document).ready( function() {
10352 * $('#example').dataTable( {
10353 * "ajax": "sources/arrays.txt",
10354 * "deferRender": true
10355 * } );
10356 * } );
10357 */
10358 "bDeferRender": false,
10359
10360
10361 /**
10362 * Replace a DataTable which matches the given selector and replace it with
10363 * one which has the properties of the new initialisation object passed. If no
10364 * table matches the selector, then the new DataTable will be constructed as
10365 * per normal.
10366 * @type boolean
10367 * @default false
10368 *
10369 * @dtopt Options
10370 * @name DataTable.defaults.destroy
10371 *
10372 * @example
10373 * $(document).ready( function() {
10374 * $('#example').dataTable( {
10375 * "srollY": "200px",
10376 * "paginate": false
10377 * } );
10378 *
10379 * // Some time later....
10380 * $('#example').dataTable( {
10381 * "filter": false,
10382 * "destroy": true
10383 * } );
10384 * } );
10385 */
10386 "bDestroy": false,
10387
10388
10389 /**
10390 * Enable or disable filtering of data. Filtering in DataTables is "smart" in
10391 * that it allows the end user to input multiple words (space separated) and
10392 * will match a row containing those words, even if not in the order that was
10393 * specified (this allow matching across multiple columns). Note that if you
10394 * wish to use filtering in DataTables this must remain 'true' - to remove the
10395 * default filtering input box and retain filtering abilities, please use
10396 * {@link DataTable.defaults.dom}.
10397 * @type boolean
10398 * @default true
10399 *
10400 * @dtopt Features
10401 * @name DataTable.defaults.searching
10402 *
10403 * @example
10404 * $(document).ready( function () {
10405 * $('#example').dataTable( {
10406 * "searching": false
10407 * } );
10408 * } );
10409 */
10410 "bFilter": true,
10411
10412
10413 /**
10414 * Enable or disable the table information display. This shows information
10415 * about the data that is currently visible on the page, including information
10416 * about filtered data if that action is being performed.
10417 * @type boolean
10418 * @default true
10419 *
10420 * @dtopt Features
10421 * @name DataTable.defaults.info
10422 *
10423 * @example
10424 * $(document).ready( function () {
10425 * $('#example').dataTable( {
10426 * "info": false
10427 * } );
10428 * } );
10429 */
10430 "bInfo": true,
10431
10432
10433 /**
10434 * Allows the end user to select the size of a formatted page from a select
10435 * menu (sizes are 10, 25, 50 and 100). Requires pagination (`paginate`).
10436 * @type boolean
10437 * @default true
10438 *
10439 * @dtopt Features
10440 * @name DataTable.defaults.lengthChange
10441 *
10442 * @example
10443 * $(document).ready( function () {
10444 * $('#example').dataTable( {
10445 * "lengthChange": false
10446 * } );
10447 * } );
10448 */
10449 "bLengthChange": true,
10450
10451
10452 /**
10453 * Enable or disable pagination.
10454 * @type boolean
10455 * @default true
10456 *
10457 * @dtopt Features
10458 * @name DataTable.defaults.paging
10459 *
10460 * @example
10461 * $(document).ready( function () {
10462 * $('#example').dataTable( {
10463 * "paging": false
10464 * } );
10465 * } );
10466 */
10467 "bPaginate": true,
10468
10469
10470 /**
10471 * Enable or disable the display of a 'processing' indicator when the table is
10472 * being processed (e.g. a sort). This is particularly useful for tables with
10473 * large amounts of data where it can take a noticeable amount of time to sort
10474 * the entries.
10475 * @type boolean
10476 * @default false
10477 *
10478 * @dtopt Features
10479 * @name DataTable.defaults.processing
10480 *
10481 * @example
10482 * $(document).ready( function () {
10483 * $('#example').dataTable( {
10484 * "processing": true
10485 * } );
10486 * } );
10487 */
10488 "bProcessing": false,
10489
10490
10491 /**
10492 * Retrieve the DataTables object for the given selector. Note that if the
10493 * table has already been initialised, this parameter will cause DataTables
10494 * to simply return the object that has already been set up - it will not take
10495 * account of any changes you might have made to the initialisation object
10496 * passed to DataTables (setting this parameter to true is an acknowledgement
10497 * that you understand this). `destroy` can be used to reinitialise a table if
10498 * you need.
10499 * @type boolean
10500 * @default false
10501 *
10502 * @dtopt Options
10503 * @name DataTable.defaults.retrieve
10504 *
10505 * @example
10506 * $(document).ready( function() {
10507 * initTable();
10508 * tableActions();
10509 * } );
10510 *
10511 * function initTable ()
10512 * {
10513 * return $('#example').dataTable( {
10514 * "scrollY": "200px",
10515 * "paginate": false,
10516 * "retrieve": true
10517 * } );
10518 * }
10519 *
10520 * function tableActions ()
10521 * {
10522 * var table = initTable();
10523 * // perform API operations with oTable
10524 * }
10525 */
10526 "bRetrieve": false,
10527
10528
10529 /**
10530 * When vertical (y) scrolling is enabled, DataTables will force the height of
10531 * the table's viewport to the given height at all times (useful for layout).
10532 * However, this can look odd when filtering data down to a small data set,
10533 * and the footer is left "floating" further down. This parameter (when
10534 * enabled) will cause DataTables to collapse the table's viewport down when
10535 * the result set will fit within the given Y height.
10536 * @type boolean
10537 * @default false
10538 *
10539 * @dtopt Options
10540 * @name DataTable.defaults.scrollCollapse
10541 *
10542 * @example
10543 * $(document).ready( function() {
10544 * $('#example').dataTable( {
10545 * "scrollY": "200",
10546 * "scrollCollapse": true
10547 * } );
10548 * } );
10549 */
10550 "bScrollCollapse": false,
10551
10552
10553 /**
10554 * Configure DataTables to use server-side processing. Note that the
10555 * `ajax` parameter must also be given in order to give DataTables a
10556 * source to obtain the required data for each draw.
10557 * @type boolean
10558 * @default false
10559 *
10560 * @dtopt Features
10561 * @dtopt Server-side
10562 * @name DataTable.defaults.serverSide
10563 *
10564 * @example
10565 * $(document).ready( function () {
10566 * $('#example').dataTable( {
10567 * "serverSide": true,
10568 * "ajax": "xhr.php"
10569 * } );
10570 * } );
10571 */
10572 "bServerSide": false,
10573
10574
10575 /**
10576 * Enable or disable sorting of columns. Sorting of individual columns can be
10577 * disabled by the `sortable` option for each column.
10578 * @type boolean
10579 * @default true
10580 *
10581 * @dtopt Features
10582 * @name DataTable.defaults.ordering
10583 *
10584 * @example
10585 * $(document).ready( function () {
10586 * $('#example').dataTable( {
10587 * "ordering": false
10588 * } );
10589 * } );
10590 */
10591 "bSort": true,
10592
10593
10594 /**
10595 * Enable or display DataTables' ability to sort multiple columns at the
10596 * same time (activated by shift-click by the user).
10597 * @type boolean
10598 * @default true
10599 *
10600 * @dtopt Options
10601 * @name DataTable.defaults.orderMulti
10602 *
10603 * @example
10604 * // Disable multiple column sorting ability
10605 * $(document).ready( function () {
10606 * $('#example').dataTable( {
10607 * "orderMulti": false
10608 * } );
10609 * } );
10610 */
10611 "bSortMulti": true,
10612
10613
10614 /**
10615 * Allows control over whether DataTables should use the top (true) unique
10616 * cell that is found for a single column, or the bottom (false - default).
10617 * This is useful when using complex headers.
10618 * @type boolean
10619 * @default false
10620 *
10621 * @dtopt Options
10622 * @name DataTable.defaults.orderCellsTop
10623 *
10624 * @example
10625 * $(document).ready( function() {
10626 * $('#example').dataTable( {
10627 * "orderCellsTop": true
10628 * } );
10629 * } );
10630 */
10631 "bSortCellsTop": false,
10632
10633
10634 /**
10635 * Enable or disable the addition of the classes `sorting\_1`, `sorting\_2` and
10636 * `sorting\_3` to the columns which are currently being sorted on. This is
10637 * presented as a feature switch as it can increase processing time (while
10638 * classes are removed and added) so for large data sets you might want to
10639 * turn this off.
10640 * @type boolean
10641 * @default true
10642 *
10643 * @dtopt Features
10644 * @name DataTable.defaults.orderClasses
10645 *
10646 * @example
10647 * $(document).ready( function () {
10648 * $('#example').dataTable( {
10649 * "orderClasses": false
10650 * } );
10651 * } );
10652 */
10653 "bSortClasses": true,
10654
10655
10656 /**
10657 * Enable or disable state saving. When enabled HTML5 `localStorage` will be
10658 * used to save table display information such as pagination information,
10659 * display length, filtering and sorting. As such when the end user reloads
10660 * the page the display display will match what thy had previously set up.
10661 *
10662 * Due to the use of `localStorage` the default state saving is not supported
10663 * in IE6 or 7. If state saving is required in those browsers, use
10664 * `stateSaveCallback` to provide a storage solution such as cookies.
10665 * @type boolean
10666 * @default false
10667 *
10668 * @dtopt Features
10669 * @name DataTable.defaults.stateSave
10670 *
10671 * @example
10672 * $(document).ready( function () {
10673 * $('#example').dataTable( {
10674 * "stateSave": true
10675 * } );
10676 * } );
10677 */
10678 "bStateSave": false,
10679
10680
10681 /**
10682 * This function is called when a TR element is created (and all TD child
10683 * elements have been inserted), or registered if using a DOM source, allowing
10684 * manipulation of the TR element (adding classes etc).
10685 * @type function
10686 * @param {node} row "TR" element for the current row
10687 * @param {array} data Raw data array for this row
10688 * @param {int} dataIndex The index of this row in the internal aoData array
10689 *
10690 * @dtopt Callbacks
10691 * @name DataTable.defaults.createdRow
10692 *
10693 * @example
10694 * $(document).ready( function() {
10695 * $('#example').dataTable( {
10696 * "createdRow": function( row, data, dataIndex ) {
10697 * // Bold the grade for all 'A' grade browsers
10698 * if ( data[4] == "A" )
10699 * {
10700 * $('td:eq(4)', row).html( '<b>A</b>' );
10701 * }
10702 * }
10703 * } );
10704 * } );
10705 */
10706 "fnCreatedRow": null,
10707
10708
10709 /**
10710 * This function is called on every 'draw' event, and allows you to
10711 * dynamically modify any aspect you want about the created DOM.
10712 * @type function
10713 * @param {object} settings DataTables settings object
10714 *
10715 * @dtopt Callbacks
10716 * @name DataTable.defaults.drawCallback
10717 *
10718 * @example
10719 * $(document).ready( function() {
10720 * $('#example').dataTable( {
10721 * "drawCallback": function( settings ) {
10722 * alert( 'DataTables has redrawn the table' );
10723 * }
10724 * } );
10725 * } );
10726 */
10727 "fnDrawCallback": null,
10728
10729
10730 /**
10731 * Identical to fnHeaderCallback() but for the table footer this function
10732 * allows you to modify the table footer on every 'draw' event.
10733 * @type function
10734 * @param {node} foot "TR" element for the footer
10735 * @param {array} data Full table data (as derived from the original HTML)
10736 * @param {int} start Index for the current display starting point in the
10737 * display array
10738 * @param {int} end Index for the current display ending point in the
10739 * display array
10740 * @param {array int} display Index array to translate the visual position
10741 * to the full data array
10742 *
10743 * @dtopt Callbacks
10744 * @name DataTable.defaults.footerCallback
10745 *
10746 * @example
10747 * $(document).ready( function() {
10748 * $('#example').dataTable( {
10749 * "footerCallback": function( tfoot, data, start, end, display ) {
10750 * tfoot.getElementsByTagName('th')[0].innerHTML = "Starting index is "+start;
10751 * }
10752 * } );
10753 * } )
10754 */
10755 "fnFooterCallback": null,
10756
10757
10758 /**
10759 * When rendering large numbers in the information element for the table
10760 * (i.e. "Showing 1 to 10 of 57 entries") DataTables will render large numbers
10761 * to have a comma separator for the 'thousands' units (e.g. 1 million is
10762 * rendered as "1,000,000") to help readability for the end user. This
10763 * function will override the default method DataTables uses.
10764 * @type function
10765 * @member
10766 * @param {int} toFormat number to be formatted
10767 * @returns {string} formatted string for DataTables to show the number
10768 *
10769 * @dtopt Callbacks
10770 * @name DataTable.defaults.formatNumber
10771 *
10772 * @example
10773 * // Format a number using a single quote for the separator (note that
10774 * // this can also be done with the language.thousands option)
10775 * $(document).ready( function() {
10776 * $('#example').dataTable( {
10777 * "formatNumber": function ( toFormat ) {
10778 * return toFormat.toString().replace(
10779 * /\B(?=(\d{3})+(?!\d))/g, "'"
10780 * );
10781 * };
10782 * } );
10783 * } );
10784 */
10785 "fnFormatNumber": function ( toFormat ) {
10786 return toFormat.toString().replace(
10787 /\B(?=(\d{3})+(?!\d))/g,
10788 this.oLanguage.sThousands
10789 );
10790 },
10791
10792
10793 /**
10794 * This function is called on every 'draw' event, and allows you to
10795 * dynamically modify the header row. This can be used to calculate and
10796 * display useful information about the table.
10797 * @type function
10798 * @param {node} head "TR" element for the header
10799 * @param {array} data Full table data (as derived from the original HTML)
10800 * @param {int} start Index for the current display starting point in the
10801 * display array
10802 * @param {int} end Index for the current display ending point in the
10803 * display array
10804 * @param {array int} display Index array to translate the visual position
10805 * to the full data array
10806 *
10807 * @dtopt Callbacks
10808 * @name DataTable.defaults.headerCallback
10809 *
10810 * @example
10811 * $(document).ready( function() {
10812 * $('#example').dataTable( {
10813 * "fheaderCallback": function( head, data, start, end, display ) {
10814 * head.getElementsByTagName('th')[0].innerHTML = "Displaying "+(end-start)+" records";
10815 * }
10816 * } );
10817 * } )
10818 */
10819 "fnHeaderCallback": null,
10820
10821
10822 /**
10823 * The information element can be used to convey information about the current
10824 * state of the table. Although the internationalisation options presented by
10825 * DataTables are quite capable of dealing with most customisations, there may
10826 * be times where you wish to customise the string further. This callback
10827 * allows you to do exactly that.
10828 * @type function
10829 * @param {object} oSettings DataTables settings object
10830 * @param {int} start Starting position in data for the draw
10831 * @param {int} end End position in data for the draw
10832 * @param {int} max Total number of rows in the table (regardless of
10833 * filtering)
10834 * @param {int} total Total number of rows in the data set, after filtering
10835 * @param {string} pre The string that DataTables has formatted using it's
10836 * own rules
10837 * @returns {string} The string to be displayed in the information element.
10838 *
10839 * @dtopt Callbacks
10840 * @name DataTable.defaults.infoCallback
10841 *
10842 * @example
10843 * $('#example').dataTable( {
10844 * "infoCallback": function( settings, start, end, max, total, pre ) {
10845 * return start +" to "+ end;
10846 * }
10847 * } );
10848 */
10849 "fnInfoCallback": null,
10850
10851
10852 /**
10853 * Called when the table has been initialised. Normally DataTables will
10854 * initialise sequentially and there will be no need for this function,
10855 * however, this does not hold true when using external language information
10856 * since that is obtained using an async XHR call.
10857 * @type function
10858 * @param {object} settings DataTables settings object
10859 * @param {object} json The JSON object request from the server - only
10860 * present if client-side Ajax sourced data is used
10861 *
10862 * @dtopt Callbacks
10863 * @name DataTable.defaults.initComplete
10864 *
10865 * @example
10866 * $(document).ready( function() {
10867 * $('#example').dataTable( {
10868 * "initComplete": function(settings, json) {
10869 * alert( 'DataTables has finished its initialisation.' );
10870 * }
10871 * } );
10872 * } )
10873 */
10874 "fnInitComplete": null,
10875
10876
10877 /**
10878 * Called at the very start of each table draw and can be used to cancel the
10879 * draw by returning false, any other return (including undefined) results in
10880 * the full draw occurring).
10881 * @type function
10882 * @param {object} settings DataTables settings object
10883 * @returns {boolean} False will cancel the draw, anything else (including no
10884 * return) will allow it to complete.
10885 *
10886 * @dtopt Callbacks
10887 * @name DataTable.defaults.preDrawCallback
10888 *
10889 * @example
10890 * $(document).ready( function() {
10891 * $('#example').dataTable( {
10892 * "preDrawCallback": function( settings ) {
10893 * if ( $('#test').val() == 1 ) {
10894 * return false;
10895 * }
10896 * }
10897 * } );
10898 * } );
10899 */
10900 "fnPreDrawCallback": null,
10901
10902
10903 /**
10904 * This function allows you to 'post process' each row after it have been
10905 * generated for each table draw, but before it is rendered on screen. This
10906 * function might be used for setting the row class name etc.
10907 * @type function
10908 * @param {node} row "TR" element for the current row
10909 * @param {array} data Raw data array for this row
10910 * @param {int} displayIndex The display index for the current table draw
10911 * @param {int} displayIndexFull The index of the data in the full list of
10912 * rows (after filtering)
10913 *
10914 * @dtopt Callbacks
10915 * @name DataTable.defaults.rowCallback
10916 *
10917 * @example
10918 * $(document).ready( function() {
10919 * $('#example').dataTable( {
10920 * "rowCallback": function( row, data, displayIndex, displayIndexFull ) {
10921 * // Bold the grade for all 'A' grade browsers
10922 * if ( data[4] == "A" ) {
10923 * $('td:eq(4)', row).html( '<b>A</b>' );
10924 * }
10925 * }
10926 * } );
10927 * } );
10928 */
10929 "fnRowCallback": null,
10930
10931
10932 /**
10933 * __Deprecated__ The functionality provided by this parameter has now been
10934 * superseded by that provided through `ajax`, which should be used instead.
10935 *
10936 * This parameter allows you to override the default function which obtains
10937 * the data from the server so something more suitable for your application.
10938 * For example you could use POST data, or pull information from a Gears or
10939 * AIR database.
10940 * @type function
10941 * @member
10942 * @param {string} source HTTP source to obtain the data from (`ajax`)
10943 * @param {array} data A key/value pair object containing the data to send
10944 * to the server
10945 * @param {function} callback to be called on completion of the data get
10946 * process that will draw the data on the page.
10947 * @param {object} settings DataTables settings object
10948 *
10949 * @dtopt Callbacks
10950 * @dtopt Server-side
10951 * @name DataTable.defaults.serverData
10952 *
10953 * @deprecated 1.10. Please use `ajax` for this functionality now.
10954 */
10955 "fnServerData": null,
10956
10957
10958 /**
10959 * __Deprecated__ The functionality provided by this parameter has now been
10960 * superseded by that provided through `ajax`, which should be used instead.
10961 *
10962 * It is often useful to send extra data to the server when making an Ajax
10963 * request - for example custom filtering information, and this callback
10964 * function makes it trivial to send extra information to the server. The
10965 * passed in parameter is the data set that has been constructed by
10966 * DataTables, and you can add to this or modify it as you require.
10967 * @type function
10968 * @param {array} data Data array (array of objects which are name/value
10969 * pairs) that has been constructed by DataTables and will be sent to the
10970 * server. In the case of Ajax sourced data with server-side processing
10971 * this will be an empty array, for server-side processing there will be a
10972 * significant number of parameters!
10973 * @returns {undefined} Ensure that you modify the data array passed in,
10974 * as this is passed by reference.
10975 *
10976 * @dtopt Callbacks
10977 * @dtopt Server-side
10978 * @name DataTable.defaults.serverParams
10979 *
10980 * @deprecated 1.10. Please use `ajax` for this functionality now.
10981 */
10982 "fnServerParams": null,
10983
10984
10985 /**
10986 * Load the table state. With this function you can define from where, and how, the
10987 * state of a table is loaded. By default DataTables will load from `localStorage`
10988 * but you might wish to use a server-side database or cookies.
10989 * @type function
10990 * @member
10991 * @param {object} settings DataTables settings object
10992 * @param {object} callback Callback that can be executed when done. It
10993 * should be passed the loaded state object.
10994 * @return {object} The DataTables state object to be loaded
10995 *
10996 * @dtopt Callbacks
10997 * @name DataTable.defaults.stateLoadCallback
10998 *
10999 * @example
11000 * $(document).ready( function() {
11001 * $('#example').dataTable( {
11002 * "stateSave": true,
11003 * "stateLoadCallback": function (settings, callback) {
11004 * $.ajax( {
11005 * "url": "/state_load",
11006 * "dataType": "json",
11007 * "success": function (json) {
11008 * callback( json );
11009 * }
11010 * } );
11011 * }
11012 * } );
11013 * } );
11014 */
11015 "fnStateLoadCallback": function ( settings ) {
11016 try {
11017 return JSON.parse(
11018 (settings.iStateDuration === -1 ? sessionStorage : localStorage).getItem(
11019 'DataTables_'+settings.sInstance+'_'+location.pathname
11020 )
11021 );
11022 } catch (e) {
11023 return {};
11024 }
11025 },
11026
11027
11028 /**
11029 * Callback which allows modification of the saved state prior to loading that state.
11030 * This callback is called when the table is loading state from the stored data, but
11031 * prior to the settings object being modified by the saved state. Note that for
11032 * plug-in authors, you should use the `stateLoadParams` event to load parameters for
11033 * a plug-in.
11034 * @type function
11035 * @param {object} settings DataTables settings object
11036 * @param {object} data The state object that is to be loaded
11037 *
11038 * @dtopt Callbacks
11039 * @name DataTable.defaults.stateLoadParams
11040 *
11041 * @example
11042 * // Remove a saved filter, so filtering is never loaded
11043 * $(document).ready( function() {
11044 * $('#example').dataTable( {
11045 * "stateSave": true,
11046 * "stateLoadParams": function (settings, data) {
11047 * data.oSearch.sSearch = "";
11048 * }
11049 * } );
11050 * } );
11051 *
11052 * @example
11053 * // Disallow state loading by returning false
11054 * $(document).ready( function() {
11055 * $('#example').dataTable( {
11056 * "stateSave": true,
11057 * "stateLoadParams": function (settings, data) {
11058 * return false;
11059 * }
11060 * } );
11061 * } );
11062 */
11063 "fnStateLoadParams": null,
11064
11065
11066 /**
11067 * Callback that is called when the state has been loaded from the state saving method
11068 * and the DataTables settings object has been modified as a result of the loaded state.
11069 * @type function
11070 * @param {object} settings DataTables settings object
11071 * @param {object} data The state object that was loaded
11072 *
11073 * @dtopt Callbacks
11074 * @name DataTable.defaults.stateLoaded
11075 *
11076 * @example
11077 * // Show an alert with the filtering value that was saved
11078 * $(document).ready( function() {
11079 * $('#example').dataTable( {
11080 * "stateSave": true,
11081 * "stateLoaded": function (settings, data) {
11082 * alert( 'Saved filter was: '+data.oSearch.sSearch );
11083 * }
11084 * } );
11085 * } );
11086 */
11087 "fnStateLoaded": null,
11088
11089
11090 /**
11091 * Save the table state. This function allows you to define where and how the state
11092 * information for the table is stored By default DataTables will use `localStorage`
11093 * but you might wish to use a server-side database or cookies.
11094 * @type function
11095 * @member
11096 * @param {object} settings DataTables settings object
11097 * @param {object} data The state object to be saved
11098 *
11099 * @dtopt Callbacks
11100 * @name DataTable.defaults.stateSaveCallback
11101 *
11102 * @example
11103 * $(document).ready( function() {
11104 * $('#example').dataTable( {
11105 * "stateSave": true,
11106 * "stateSaveCallback": function (settings, data) {
11107 * // Send an Ajax request to the server with the state object
11108 * $.ajax( {
11109 * "url": "/state_save",
11110 * "data": data,
11111 * "dataType": "json",
11112 * "method": "POST"
11113 * "success": function () {}
11114 * } );
11115 * }
11116 * } );
11117 * } );
11118 */
11119 "fnStateSaveCallback": function ( settings, data ) {
11120 try {
11121 (settings.iStateDuration === -1 ? sessionStorage : localStorage).setItem(
11122 'DataTables_'+settings.sInstance+'_'+location.pathname,
11123 JSON.stringify( data )
11124 );
11125 } catch (e) {}
11126 },
11127
11128
11129 /**
11130 * Callback which allows modification of the state to be saved. Called when the table
11131 * has changed state a new state save is required. This method allows modification of
11132 * the state saving object prior to actually doing the save, including addition or
11133 * other state properties or modification. Note that for plug-in authors, you should
11134 * use the `stateSaveParams` event to save parameters for a plug-in.
11135 * @type function
11136 * @param {object} settings DataTables settings object
11137 * @param {object} data The state object to be saved
11138 *
11139 * @dtopt Callbacks
11140 * @name DataTable.defaults.stateSaveParams
11141 *
11142 * @example
11143 * // Remove a saved filter, so filtering is never saved
11144 * $(document).ready( function() {
11145 * $('#example').dataTable( {
11146 * "stateSave": true,
11147 * "stateSaveParams": function (settings, data) {
11148 * data.oSearch.sSearch = "";
11149 * }
11150 * } );
11151 * } );
11152 */
11153 "fnStateSaveParams": null,
11154
11155
11156 /**
11157 * Duration for which the saved state information is considered valid. After this period
11158 * has elapsed the state will be returned to the default.
11159 * Value is given in seconds.
11160 * @type int
11161 * @default 7200 <i>(2 hours)</i>
11162 *
11163 * @dtopt Options
11164 * @name DataTable.defaults.stateDuration
11165 *
11166 * @example
11167 * $(document).ready( function() {
11168 * $('#example').dataTable( {
11169 * "stateDuration": 60*60*24; // 1 day
11170 * } );
11171 * } )
11172 */
11173 "iStateDuration": 7200,
11174
11175
11176 /**
11177 * When enabled DataTables will not make a request to the server for the first
11178 * page draw - rather it will use the data already on the page (no sorting etc
11179 * will be applied to it), thus saving on an XHR at load time. `deferLoading`
11180 * is used to indicate that deferred loading is required, but it is also used
11181 * to tell DataTables how many records there are in the full table (allowing
11182 * the information element and pagination to be displayed correctly). In the case
11183 * where a filtering is applied to the table on initial load, this can be
11184 * indicated by giving the parameter as an array, where the first element is
11185 * the number of records available after filtering and the second element is the
11186 * number of records without filtering (allowing the table information element
11187 * to be shown correctly).
11188 * @type int | array
11189 * @default null
11190 *
11191 * @dtopt Options
11192 * @name DataTable.defaults.deferLoading
11193 *
11194 * @example
11195 * // 57 records available in the table, no filtering applied
11196 * $(document).ready( function() {
11197 * $('#example').dataTable( {
11198 * "serverSide": true,
11199 * "ajax": "scripts/server_processing.php",
11200 * "deferLoading": 57
11201 * } );
11202 * } );
11203 *
11204 * @example
11205 * // 57 records after filtering, 100 without filtering (an initial filter applied)
11206 * $(document).ready( function() {
11207 * $('#example').dataTable( {
11208 * "serverSide": true,
11209 * "ajax": "scripts/server_processing.php",
11210 * "deferLoading": [ 57, 100 ],
11211 * "search": {
11212 * "search": "my_filter"
11213 * }
11214 * } );
11215 * } );
11216 */
11217 "iDeferLoading": null,
11218
11219
11220 /**
11221 * Number of rows to display on a single page when using pagination. If
11222 * feature enabled (`lengthChange`) then the end user will be able to override
11223 * this to a custom setting using a pop-up menu.
11224 * @type int
11225 * @default 10
11226 *
11227 * @dtopt Options
11228 * @name DataTable.defaults.pageLength
11229 *
11230 * @example
11231 * $(document).ready( function() {
11232 * $('#example').dataTable( {
11233 * "pageLength": 50
11234 * } );
11235 * } )
11236 */
11237 "iDisplayLength": 10,
11238
11239
11240 /**
11241 * Define the starting point for data display when using DataTables with
11242 * pagination. Note that this parameter is the number of records, rather than
11243 * the page number, so if you have 10 records per page and want to start on
11244 * the third page, it should be "20".
11245 * @type int
11246 * @default 0
11247 *
11248 * @dtopt Options
11249 * @name DataTable.defaults.displayStart
11250 *
11251 * @example
11252 * $(document).ready( function() {
11253 * $('#example').dataTable( {
11254 * "displayStart": 20
11255 * } );
11256 * } )
11257 */
11258 "iDisplayStart": 0,
11259
11260
11261 /**
11262 * By default DataTables allows keyboard navigation of the table (sorting, paging,
11263 * and filtering) by adding a `tabindex` attribute to the required elements. This
11264 * allows you to tab through the controls and press the enter key to activate them.
11265 * The tabindex is default 0, meaning that the tab follows the flow of the document.
11266 * You can overrule this using this parameter if you wish. Use a value of -1 to
11267 * disable built-in keyboard navigation.
11268 * @type int
11269 * @default 0
11270 *
11271 * @dtopt Options
11272 * @name DataTable.defaults.tabIndex
11273 *
11274 * @example
11275 * $(document).ready( function() {
11276 * $('#example').dataTable( {
11277 * "tabIndex": 1
11278 * } );
11279 * } );
11280 */
11281 "iTabIndex": 0,
11282
11283
11284 /**
11285 * Classes that DataTables assigns to the various components and features
11286 * that it adds to the HTML table. This allows classes to be configured
11287 * during initialisation in addition to through the static
11288 * {@link DataTable.ext.oStdClasses} object).
11289 * @namespace
11290 * @name DataTable.defaults.classes
11291 */
11292 "oClasses": {},
11293
11294
11295 /**
11296 * All strings that DataTables uses in the user interface that it creates
11297 * are defined in this object, allowing you to modified them individually or
11298 * completely replace them all as required.
11299 * @namespace
11300 * @name DataTable.defaults.language
11301 */
11302 "oLanguage": {
11303 /**
11304 * Strings that are used for WAI-ARIA labels and controls only (these are not
11305 * actually visible on the page, but will be read by screenreaders, and thus
11306 * must be internationalised as well).
11307 * @namespace
11308 * @name DataTable.defaults.language.aria
11309 */
11310 "oAria": {
11311 /**
11312 * ARIA label that is added to the table headers when the column may be
11313 * sorted ascending by activing the column (click or return when focused).
11314 * Note that the column header is prefixed to this string.
11315 * @type string
11316 * @default : activate to sort column ascending
11317 *
11318 * @dtopt Language
11319 * @name DataTable.defaults.language.aria.sortAscending
11320 *
11321 * @example
11322 * $(document).ready( function() {
11323 * $('#example').dataTable( {
11324 * "language": {
11325 * "aria": {
11326 * "sortAscending": " - click/return to sort ascending"
11327 * }
11328 * }
11329 * } );
11330 * } );
11331 */
11332 "sSortAscending": ": activate to sort column ascending",
11333
11334 /**
11335 * ARIA label that is added to the table headers when the column may be
11336 * sorted descending by activing the column (click or return when focused).
11337 * Note that the column header is prefixed to this string.
11338 * @type string
11339 * @default : activate to sort column ascending
11340 *
11341 * @dtopt Language
11342 * @name DataTable.defaults.language.aria.sortDescending
11343 *
11344 * @example
11345 * $(document).ready( function() {
11346 * $('#example').dataTable( {
11347 * "language": {
11348 * "aria": {
11349 * "sortDescending": " - click/return to sort descending"
11350 * }
11351 * }
11352 * } );
11353 * } );
11354 */
11355 "sSortDescending": ": activate to sort column descending"
11356 },
11357
11358 /**
11359 * Pagination string used by DataTables for the built-in pagination
11360 * control types.
11361 * @namespace
11362 * @name DataTable.defaults.language.paginate
11363 */
11364 "oPaginate": {
11365 /**
11366 * Text to use when using the 'full_numbers' type of pagination for the
11367 * button to take the user to the first page.
11368 * @type string
11369 * @default First
11370 *
11371 * @dtopt Language
11372 * @name DataTable.defaults.language.paginate.first
11373 *
11374 * @example
11375 * $(document).ready( function() {
11376 * $('#example').dataTable( {
11377 * "language": {
11378 * "paginate": {
11379 * "first": "First page"
11380 * }
11381 * }
11382 * } );
11383 * } );
11384 */
11385 "sFirst": "First",
11386
11387
11388 /**
11389 * Text to use when using the 'full_numbers' type of pagination for the
11390 * button to take the user to the last page.
11391 * @type string
11392 * @default Last
11393 *
11394 * @dtopt Language
11395 * @name DataTable.defaults.language.paginate.last
11396 *
11397 * @example
11398 * $(document).ready( function() {
11399 * $('#example').dataTable( {
11400 * "language": {
11401 * "paginate": {
11402 * "last": "Last page"
11403 * }
11404 * }
11405 * } );
11406 * } );
11407 */
11408 "sLast": "Last",
11409
11410
11411 /**
11412 * Text to use for the 'next' pagination button (to take the user to the
11413 * next page).
11414 * @type string
11415 * @default Next
11416 *
11417 * @dtopt Language
11418 * @name DataTable.defaults.language.paginate.next
11419 *
11420 * @example
11421 * $(document).ready( function() {
11422 * $('#example').dataTable( {
11423 * "language": {
11424 * "paginate": {
11425 * "next": "Next page"
11426 * }
11427 * }
11428 * } );
11429 * } );
11430 */
11431 "sNext": "Next",
11432
11433
11434 /**
11435 * Text to use for the 'previous' pagination button (to take the user to
11436 * the previous page).
11437 * @type string
11438 * @default Previous
11439 *
11440 * @dtopt Language
11441 * @name DataTable.defaults.language.paginate.previous
11442 *
11443 * @example
11444 * $(document).ready( function() {
11445 * $('#example').dataTable( {
11446 * "language": {
11447 * "paginate": {
11448 * "previous": "Previous page"
11449 * }
11450 * }
11451 * } );
11452 * } );
11453 */
11454 "sPrevious": "Previous"
11455 },
11456
11457 /**
11458 * This string is shown in preference to `zeroRecords` when the table is
11459 * empty of data (regardless of filtering). Note that this is an optional
11460 * parameter - if it is not given, the value of `zeroRecords` will be used
11461 * instead (either the default or given value).
11462 * @type string
11463 * @default No data available in table
11464 *
11465 * @dtopt Language
11466 * @name DataTable.defaults.language.emptyTable
11467 *
11468 * @example
11469 * $(document).ready( function() {
11470 * $('#example').dataTable( {
11471 * "language": {
11472 * "emptyTable": "No data available in table"
11473 * }
11474 * } );
11475 * } );
11476 */
11477 "sEmptyTable": "No data available in table",
11478
11479
11480 /**
11481 * This string gives information to the end user about the information
11482 * that is current on display on the page. The following tokens can be
11483 * used in the string and will be dynamically replaced as the table
11484 * display updates. This tokens can be placed anywhere in the string, or
11485 * removed as needed by the language requires:
11486 *
11487 * * `\_START\_` - Display index of the first record on the current page
11488 * * `\_END\_` - Display index of the last record on the current page
11489 * * `\_TOTAL\_` - Number of records in the table after filtering
11490 * * `\_MAX\_` - Number of records in the table without filtering
11491 * * `\_PAGE\_` - Current page number
11492 * * `\_PAGES\_` - Total number of pages of data in the table
11493 *
11494 * @type string
11495 * @default Showing _START_ to _END_ of _TOTAL_ entries
11496 *
11497 * @dtopt Language
11498 * @name DataTable.defaults.language.info
11499 *
11500 * @example
11501 * $(document).ready( function() {
11502 * $('#example').dataTable( {
11503 * "language": {
11504 * "info": "Showing page _PAGE_ of _PAGES_"
11505 * }
11506 * } );
11507 * } );
11508 */
11509 "sInfo": "Showing _START_ to _END_ of _TOTAL_ entries",
11510
11511
11512 /**
11513 * Display information string for when the table is empty. Typically the
11514 * format of this string should match `info`.
11515 * @type string
11516 * @default Showing 0 to 0 of 0 entries
11517 *
11518 * @dtopt Language
11519 * @name DataTable.defaults.language.infoEmpty
11520 *
11521 * @example
11522 * $(document).ready( function() {
11523 * $('#example').dataTable( {
11524 * "language": {
11525 * "infoEmpty": "No entries to show"
11526 * }
11527 * } );
11528 * } );
11529 */
11530 "sInfoEmpty": "Showing 0 to 0 of 0 entries",
11531
11532
11533 /**
11534 * When a user filters the information in a table, this string is appended
11535 * to the information (`info`) to give an idea of how strong the filtering
11536 * is. The variable _MAX_ is dynamically updated.
11537 * @type string
11538 * @default (filtered from _MAX_ total entries)
11539 *
11540 * @dtopt Language
11541 * @name DataTable.defaults.language.infoFiltered
11542 *
11543 * @example
11544 * $(document).ready( function() {
11545 * $('#example').dataTable( {
11546 * "language": {
11547 * "infoFiltered": " - filtering from _MAX_ records"
11548 * }
11549 * } );
11550 * } );
11551 */
11552 "sInfoFiltered": "(filtered from _MAX_ total entries)",
11553
11554
11555 /**
11556 * If can be useful to append extra information to the info string at times,
11557 * and this variable does exactly that. This information will be appended to
11558 * the `info` (`infoEmpty` and `infoFiltered` in whatever combination they are
11559 * being used) at all times.
11560 * @type string
11561 * @default <i>Empty string</i>
11562 *
11563 * @dtopt Language
11564 * @name DataTable.defaults.language.infoPostFix
11565 *
11566 * @example
11567 * $(document).ready( function() {
11568 * $('#example').dataTable( {
11569 * "language": {
11570 * "infoPostFix": "All records shown are derived from real information."
11571 * }
11572 * } );
11573 * } );
11574 */
11575 "sInfoPostFix": "",
11576
11577
11578 /**
11579 * This decimal place operator is a little different from the other
11580 * language options since DataTables doesn't output floating point
11581 * numbers, so it won't ever use this for display of a number. Rather,
11582 * what this parameter does is modify the sort methods of the table so
11583 * that numbers which are in a format which has a character other than
11584 * a period (`.`) as a decimal place will be sorted numerically.
11585 *
11586 * Note that numbers with different decimal places cannot be shown in
11587 * the same table and still be sortable, the table must be consistent.
11588 * However, multiple different tables on the page can use different
11589 * decimal place characters.
11590 * @type string
11591 * @default
11592 *
11593 * @dtopt Language
11594 * @name DataTable.defaults.language.decimal
11595 *
11596 * @example
11597 * $(document).ready( function() {
11598 * $('#example').dataTable( {
11599 * "language": {
11600 * "decimal": ","
11601 * "thousands": "."
11602 * }
11603 * } );
11604 * } );
11605 */
11606 "sDecimal": "",
11607
11608
11609 /**
11610 * DataTables has a build in number formatter (`formatNumber`) which is
11611 * used to format large numbers that are used in the table information.
11612 * By default a comma is used, but this can be trivially changed to any
11613 * character you wish with this parameter.
11614 * @type string
11615 * @default ,
11616 *
11617 * @dtopt Language
11618 * @name DataTable.defaults.language.thousands
11619 *
11620 * @example
11621 * $(document).ready( function() {
11622 * $('#example').dataTable( {
11623 * "language": {
11624 * "thousands": "'"
11625 * }
11626 * } );
11627 * } );
11628 */
11629 "sThousands": ",",
11630
11631
11632 /**
11633 * Detail the action that will be taken when the drop down menu for the
11634 * pagination length option is changed. The '_MENU_' variable is replaced
11635 * with a default select list of 10, 25, 50 and 100, and can be replaced
11636 * with a custom select box if required.
11637 * @type string
11638 * @default Show _MENU_ entries
11639 *
11640 * @dtopt Language
11641 * @name DataTable.defaults.language.lengthMenu
11642 *
11643 * @example
11644 * // Language change only
11645 * $(document).ready( function() {
11646 * $('#example').dataTable( {
11647 * "language": {
11648 * "lengthMenu": "Display _MENU_ records"
11649 * }
11650 * } );
11651 * } );
11652 *
11653 * @example
11654 * // Language and options change
11655 * $(document).ready( function() {
11656 * $('#example').dataTable( {
11657 * "language": {
11658 * "lengthMenu": 'Display <select>'+
11659 * '<option value="10">10</option>'+
11660 * '<option value="20">20</option>'+
11661 * '<option value="30">30</option>'+
11662 * '<option value="40">40</option>'+
11663 * '<option value="50">50</option>'+
11664 * '<option value="-1">All</option>'+
11665 * '</select> records'
11666 * }
11667 * } );
11668 * } );
11669 */
11670 "sLengthMenu": "Show _MENU_ entries",
11671
11672
11673 /**
11674 * When using Ajax sourced data and during the first draw when DataTables is
11675 * gathering the data, this message is shown in an empty row in the table to
11676 * indicate to the end user the the data is being loaded. Note that this
11677 * parameter is not used when loading data by server-side processing, just
11678 * Ajax sourced data with client-side processing.
11679 * @type string
11680 * @default Loading...
11681 *
11682 * @dtopt Language
11683 * @name DataTable.defaults.language.loadingRecords
11684 *
11685 * @example
11686 * $(document).ready( function() {
11687 * $('#example').dataTable( {
11688 * "language": {
11689 * "loadingRecords": "Please wait - loading..."
11690 * }
11691 * } );
11692 * } );
11693 */
11694 "sLoadingRecords": "Loading...",
11695
11696
11697 /**
11698 * Text which is displayed when the table is processing a user action
11699 * (usually a sort command or similar).
11700 * @type string
11701 * @default Processing...
11702 *
11703 * @dtopt Language
11704 * @name DataTable.defaults.language.processing
11705 *
11706 * @example
11707 * $(document).ready( function() {
11708 * $('#example').dataTable( {
11709 * "language": {
11710 * "processing": "DataTables is currently busy"
11711 * }
11712 * } );
11713 * } );
11714 */
11715 "sProcessing": "Processing...",
11716
11717
11718 /**
11719 * Details the actions that will be taken when the user types into the
11720 * filtering input text box. The variable "_INPUT_", if used in the string,
11721 * is replaced with the HTML text box for the filtering input allowing
11722 * control over where it appears in the string. If "_INPUT_" is not given
11723 * then the input box is appended to the string automatically.
11724 * @type string
11725 * @default Search:
11726 *
11727 * @dtopt Language
11728 * @name DataTable.defaults.language.search
11729 *
11730 * @example
11731 * // Input text box will be appended at the end automatically
11732 * $(document).ready( function() {
11733 * $('#example').dataTable( {
11734 * "language": {
11735 * "search": "Filter records:"
11736 * }
11737 * } );
11738 * } );
11739 *
11740 * @example
11741 * // Specify where the filter should appear
11742 * $(document).ready( function() {
11743 * $('#example').dataTable( {
11744 * "language": {
11745 * "search": "Apply filter _INPUT_ to table"
11746 * }
11747 * } );
11748 * } );
11749 */
11750 "sSearch": "Search:",
11751
11752
11753 /**
11754 * Assign a `placeholder` attribute to the search `input` element
11755 * @type string
11756 * @default
11757 *
11758 * @dtopt Language
11759 * @name DataTable.defaults.language.searchPlaceholder
11760 */
11761 "sSearchPlaceholder": "",
11762
11763
11764 /**
11765 * All of the language information can be stored in a file on the
11766 * server-side, which DataTables will look up if this parameter is passed.
11767 * It must store the URL of the language file, which is in a JSON format,
11768 * and the object has the same properties as the oLanguage object in the
11769 * initialiser object (i.e. the above parameters). Please refer to one of
11770 * the example language files to see how this works in action.
11771 * @type string
11772 * @default <i>Empty string - i.e. disabled</i>
11773 *
11774 * @dtopt Language
11775 * @name DataTable.defaults.language.url
11776 *
11777 * @example
11778 * $(document).ready( function() {
11779 * $('#example').dataTable( {
11780 * "language": {
11781 * "url": "http://www.sprymedia.co.uk/dataTables/lang.txt"
11782 * }
11783 * } );
11784 * } );
11785 */
11786 "sUrl": "",
11787
11788
11789 /**
11790 * Text shown inside the table records when the is no information to be
11791 * displayed after filtering. `emptyTable` is shown when there is simply no
11792 * information in the table at all (regardless of filtering).
11793 * @type string
11794 * @default No matching records found
11795 *
11796 * @dtopt Language
11797 * @name DataTable.defaults.language.zeroRecords
11798 *
11799 * @example
11800 * $(document).ready( function() {
11801 * $('#example').dataTable( {
11802 * "language": {
11803 * "zeroRecords": "No records to display"
11804 * }
11805 * } );
11806 * } );
11807 */
11808 "sZeroRecords": "No matching records found"
11809 },
11810
11811
11812 /**
11813 * This parameter allows you to have define the global filtering state at
11814 * initialisation time. As an object the `search` parameter must be
11815 * defined, but all other parameters are optional. When `regex` is true,
11816 * the search string will be treated as a regular expression, when false
11817 * (default) it will be treated as a straight string. When `smart`
11818 * DataTables will use it's smart filtering methods (to word match at
11819 * any point in the data), when false this will not be done.
11820 * @namespace
11821 * @extends DataTable.models.oSearch
11822 *
11823 * @dtopt Options
11824 * @name DataTable.defaults.search
11825 *
11826 * @example
11827 * $(document).ready( function() {
11828 * $('#example').dataTable( {
11829 * "search": {"search": "Initial search"}
11830 * } );
11831 * } )
11832 */
11833 "oSearch": $.extend( {}, DataTable.models.oSearch ),
11834
11835
11836 /**
11837 * __Deprecated__ The functionality provided by this parameter has now been
11838 * superseded by that provided through `ajax`, which should be used instead.
11839 *
11840 * By default DataTables will look for the property `data` (or `aaData` for
11841 * compatibility with DataTables 1.9-) when obtaining data from an Ajax
11842 * source or for server-side processing - this parameter allows that
11843 * property to be changed. You can use Javascript dotted object notation to
11844 * get a data source for multiple levels of nesting.
11845 * @type string
11846 * @default data
11847 *
11848 * @dtopt Options
11849 * @dtopt Server-side
11850 * @name DataTable.defaults.ajaxDataProp
11851 *
11852 * @deprecated 1.10. Please use `ajax` for this functionality now.
11853 */
11854 "sAjaxDataProp": "data",
11855
11856
11857 /**
11858 * __Deprecated__ The functionality provided by this parameter has now been
11859 * superseded by that provided through `ajax`, which should be used instead.
11860 *
11861 * You can instruct DataTables to load data from an external
11862 * source using this parameter (use aData if you want to pass data in you
11863 * already have). Simply provide a url a JSON object can be obtained from.
11864 * @type string
11865 * @default null
11866 *
11867 * @dtopt Options
11868 * @dtopt Server-side
11869 * @name DataTable.defaults.ajaxSource
11870 *
11871 * @deprecated 1.10. Please use `ajax` for this functionality now.
11872 */
11873 "sAjaxSource": null,
11874
11875
11876 /**
11877 * This initialisation variable allows you to specify exactly where in the
11878 * DOM you want DataTables to inject the various controls it adds to the page
11879 * (for example you might want the pagination controls at the top of the
11880 * table). DIV elements (with or without a custom class) can also be added to
11881 * aid styling. The follow syntax is used:
11882 * <ul>
11883 * <li>The following options are allowed:
11884 * <ul>
11885 * <li>'l' - Length changing</li>
11886 * <li>'f' - Filtering input</li>
11887 * <li>'t' - The table!</li>
11888 * <li>'i' - Information</li>
11889 * <li>'p' - Pagination</li>
11890 * <li>'r' - pRocessing</li>
11891 * </ul>
11892 * </li>
11893 * <li>The following constants are allowed:
11894 * <ul>
11895 * <li>'H' - jQueryUI theme "header" classes ('fg-toolbar ui-widget-header ui-corner-tl ui-corner-tr ui-helper-clearfix')</li>
11896 * <li>'F' - jQueryUI theme "footer" classes ('fg-toolbar ui-widget-header ui-corner-bl ui-corner-br ui-helper-clearfix')</li>
11897 * </ul>
11898 * </li>
11899 * <li>The following syntax is expected:
11900 * <ul>
11901 * <li>'&lt;' and '&gt;' - div elements</li>
11902 * <li>'&lt;"class" and '&gt;' - div with a class</li>
11903 * <li>'&lt;"#id" and '&gt;' - div with an ID</li>
11904 * </ul>
11905 * </li>
11906 * <li>Examples:
11907 * <ul>
11908 * <li>'&lt;"wrapper"flipt&gt;'</li>
11909 * <li>'&lt;lf&lt;t&gt;ip&gt;'</li>
11910 * </ul>
11911 * </li>
11912 * </ul>
11913 * @type string
11914 * @default lfrtip <i>(when `jQueryUI` is false)</i> <b>or</b>
11915 * <"H"lfr>t<"F"ip> <i>(when `jQueryUI` is true)</i>
11916 *
11917 * @dtopt Options
11918 * @name DataTable.defaults.dom
11919 *
11920 * @example
11921 * $(document).ready( function() {
11922 * $('#example').dataTable( {
11923 * "dom": '&lt;"top"i&gt;rt&lt;"bottom"flp&gt;&lt;"clear"&gt;'
11924 * } );
11925 * } );
11926 */
11927 "sDom": "lfrtip",
11928
11929
11930 /**
11931 * Search delay option. This will throttle full table searches that use the
11932 * DataTables provided search input element (it does not effect calls to
11933 * `dt-api search()`, providing a delay before the search is made.
11934 * @type integer
11935 * @default 0
11936 *
11937 * @dtopt Options
11938 * @name DataTable.defaults.searchDelay
11939 *
11940 * @example
11941 * $(document).ready( function() {
11942 * $('#example').dataTable( {
11943 * "searchDelay": 200
11944 * } );
11945 * } )
11946 */
11947 "searchDelay": null,
11948
11949
11950 /**
11951 * DataTables features six different built-in options for the buttons to
11952 * display for pagination control:
11953 *
11954 * * `numbers` - Page number buttons only
11955 * * `simple` - 'Previous' and 'Next' buttons only
11956 * * 'simple_numbers` - 'Previous' and 'Next' buttons, plus page numbers
11957 * * `full` - 'First', 'Previous', 'Next' and 'Last' buttons
11958 * * `full_numbers` - 'First', 'Previous', 'Next' and 'Last' buttons, plus page numbers
11959 * * `first_last_numbers` - 'First' and 'Last' buttons, plus page numbers
11960 *
11961 * Further methods can be added using {@link DataTable.ext.oPagination}.
11962 * @type string
11963 * @default simple_numbers
11964 *
11965 * @dtopt Options
11966 * @name DataTable.defaults.pagingType
11967 *
11968 * @example
11969 * $(document).ready( function() {
11970 * $('#example').dataTable( {
11971 * "pagingType": "full_numbers"
11972 * } );
11973 * } )
11974 */
11975 "sPaginationType": "simple_numbers",
11976
11977
11978 /**
11979 * Enable horizontal scrolling. When a table is too wide to fit into a
11980 * certain layout, or you have a large number of columns in the table, you
11981 * can enable x-scrolling to show the table in a viewport, which can be
11982 * scrolled. This property can be `true` which will allow the table to
11983 * scroll horizontally when needed, or any CSS unit, or a number (in which
11984 * case it will be treated as a pixel measurement). Setting as simply `true`
11985 * is recommended.
11986 * @type boolean|string
11987 * @default <i>blank string - i.e. disabled</i>
11988 *
11989 * @dtopt Features
11990 * @name DataTable.defaults.scrollX
11991 *
11992 * @example
11993 * $(document).ready( function() {
11994 * $('#example').dataTable( {
11995 * "scrollX": true,
11996 * "scrollCollapse": true
11997 * } );
11998 * } );
11999 */
12000 "sScrollX": "",
12001
12002
12003 /**
12004 * This property can be used to force a DataTable to use more width than it
12005 * might otherwise do when x-scrolling is enabled. For example if you have a
12006 * table which requires to be well spaced, this parameter is useful for
12007 * "over-sizing" the table, and thus forcing scrolling. This property can by
12008 * any CSS unit, or a number (in which case it will be treated as a pixel
12009 * measurement).
12010 * @type string
12011 * @default <i>blank string - i.e. disabled</i>
12012 *
12013 * @dtopt Options
12014 * @name DataTable.defaults.scrollXInner
12015 *
12016 * @example
12017 * $(document).ready( function() {
12018 * $('#example').dataTable( {
12019 * "scrollX": "100%",
12020 * "scrollXInner": "110%"
12021 * } );
12022 * } );
12023 */
12024 "sScrollXInner": "",
12025
12026
12027 /**
12028 * Enable vertical scrolling. Vertical scrolling will constrain the DataTable
12029 * to the given height, and enable scrolling for any data which overflows the
12030 * current viewport. This can be used as an alternative to paging to display
12031 * a lot of data in a small area (although paging and scrolling can both be
12032 * enabled at the same time). This property can be any CSS unit, or a number
12033 * (in which case it will be treated as a pixel measurement).
12034 * @type string
12035 * @default <i>blank string - i.e. disabled</i>
12036 *
12037 * @dtopt Features
12038 * @name DataTable.defaults.scrollY
12039 *
12040 * @example
12041 * $(document).ready( function() {
12042 * $('#example').dataTable( {
12043 * "scrollY": "200px",
12044 * "paginate": false
12045 * } );
12046 * } );
12047 */
12048 "sScrollY": "",
12049
12050
12051 /**
12052 * __Deprecated__ The functionality provided by this parameter has now been
12053 * superseded by that provided through `ajax`, which should be used instead.
12054 *
12055 * Set the HTTP method that is used to make the Ajax call for server-side
12056 * processing or Ajax sourced data.
12057 * @type string
12058 * @default GET
12059 *
12060 * @dtopt Options
12061 * @dtopt Server-side
12062 * @name DataTable.defaults.serverMethod
12063 *
12064 * @deprecated 1.10. Please use `ajax` for this functionality now.
12065 */
12066 "sServerMethod": "GET",
12067
12068
12069 /**
12070 * DataTables makes use of renderers when displaying HTML elements for
12071 * a table. These renderers can be added or modified by plug-ins to
12072 * generate suitable mark-up for a site. For example the Bootstrap
12073 * integration plug-in for DataTables uses a paging button renderer to
12074 * display pagination buttons in the mark-up required by Bootstrap.
12075 *
12076 * For further information about the renderers available see
12077 * DataTable.ext.renderer
12078 * @type string|object
12079 * @default null
12080 *
12081 * @name DataTable.defaults.renderer
12082 *
12083 */
12084 "renderer": null,
12085
12086
12087 /**
12088 * Set the data property name that DataTables should use to get a row's id
12089 * to set as the `id` property in the node.
12090 * @type string
12091 * @default DT_RowId
12092 *
12093 * @name DataTable.defaults.rowId
12094 */
12095 "rowId": "DT_RowId"
12096 };
12097
12098 _fnHungarianMap( DataTable.defaults );
12099
12100
12101
12102 /*
12103 * Developer note - See note in model.defaults.js about the use of Hungarian
12104 * notation and camel case.
12105 */
12106
12107 /**
12108 * Column options that can be given to DataTables at initialisation time.
12109 * @namespace
12110 */
12111 DataTable.defaults.column = {
12112 /**
12113 * Define which column(s) an order will occur on for this column. This
12114 * allows a column's ordering to take multiple columns into account when
12115 * doing a sort or use the data from a different column. For example first
12116 * name / last name columns make sense to do a multi-column sort over the
12117 * two columns.
12118 * @type array|int
12119 * @default null <i>Takes the value of the column index automatically</i>
12120 *
12121 * @name DataTable.defaults.column.orderData
12122 * @dtopt Columns
12123 *
12124 * @example
12125 * // Using `columnDefs`
12126 * $(document).ready( function() {
12127 * $('#example').dataTable( {
12128 * "columnDefs": [
12129 * { "orderData": [ 0, 1 ], "targets": [ 0 ] },
12130 * { "orderData": [ 1, 0 ], "targets": [ 1 ] },
12131 * { "orderData": 2, "targets": [ 2 ] }
12132 * ]
12133 * } );
12134 * } );
12135 *
12136 * @example
12137 * // Using `columns`
12138 * $(document).ready( function() {
12139 * $('#example').dataTable( {
12140 * "columns": [
12141 * { "orderData": [ 0, 1 ] },
12142 * { "orderData": [ 1, 0 ] },
12143 * { "orderData": 2 },
12144 * null,
12145 * null
12146 * ]
12147 * } );
12148 * } );
12149 */
12150 "aDataSort": null,
12151 "iDataSort": -1,
12152
12153
12154 /**
12155 * You can control the default ordering direction, and even alter the
12156 * behaviour of the sort handler (i.e. only allow ascending ordering etc)
12157 * using this parameter.
12158 * @type array
12159 * @default [ 'asc', 'desc' ]
12160 *
12161 * @name DataTable.defaults.column.orderSequence
12162 * @dtopt Columns
12163 *
12164 * @example
12165 * // Using `columnDefs`
12166 * $(document).ready( function() {
12167 * $('#example').dataTable( {
12168 * "columnDefs": [
12169 * { "orderSequence": [ "asc" ], "targets": [ 1 ] },
12170 * { "orderSequence": [ "desc", "asc", "asc" ], "targets": [ 2 ] },
12171 * { "orderSequence": [ "desc" ], "targets": [ 3 ] }
12172 * ]
12173 * } );
12174 * } );
12175 *
12176 * @example
12177 * // Using `columns`
12178 * $(document).ready( function() {
12179 * $('#example').dataTable( {
12180 * "columns": [
12181 * null,
12182 * { "orderSequence": [ "asc" ] },
12183 * { "orderSequence": [ "desc", "asc", "asc" ] },
12184 * { "orderSequence": [ "desc" ] },
12185 * null
12186 * ]
12187 * } );
12188 * } );
12189 */
12190 "asSorting": [ 'asc', 'desc' ],
12191
12192
12193 /**
12194 * Enable or disable filtering on the data in this column.
12195 * @type boolean
12196 * @default true
12197 *
12198 * @name DataTable.defaults.column.searchable
12199 * @dtopt Columns
12200 *
12201 * @example
12202 * // Using `columnDefs`
12203 * $(document).ready( function() {
12204 * $('#example').dataTable( {
12205 * "columnDefs": [
12206 * { "searchable": false, "targets": [ 0 ] }
12207 * ] } );
12208 * } );
12209 *
12210 * @example
12211 * // Using `columns`
12212 * $(document).ready( function() {
12213 * $('#example').dataTable( {
12214 * "columns": [
12215 * { "searchable": false },
12216 * null,
12217 * null,
12218 * null,
12219 * null
12220 * ] } );
12221 * } );
12222 */
12223 "bSearchable": true,
12224
12225
12226 /**
12227 * Enable or disable ordering on this column.
12228 * @type boolean
12229 * @default true
12230 *
12231 * @name DataTable.defaults.column.orderable
12232 * @dtopt Columns
12233 *
12234 * @example
12235 * // Using `columnDefs`
12236 * $(document).ready( function() {
12237 * $('#example').dataTable( {
12238 * "columnDefs": [
12239 * { "orderable": false, "targets": [ 0 ] }
12240 * ] } );
12241 * } );
12242 *
12243 * @example
12244 * // Using `columns`
12245 * $(document).ready( function() {
12246 * $('#example').dataTable( {
12247 * "columns": [
12248 * { "orderable": false },
12249 * null,
12250 * null,
12251 * null,
12252 * null
12253 * ] } );
12254 * } );
12255 */
12256 "bSortable": true,
12257
12258
12259 /**
12260 * Enable or disable the display of this column.
12261 * @type boolean
12262 * @default true
12263 *
12264 * @name DataTable.defaults.column.visible
12265 * @dtopt Columns
12266 *
12267 * @example
12268 * // Using `columnDefs`
12269 * $(document).ready( function() {
12270 * $('#example').dataTable( {
12271 * "columnDefs": [
12272 * { "visible": false, "targets": [ 0 ] }
12273 * ] } );
12274 * } );
12275 *
12276 * @example
12277 * // Using `columns`
12278 * $(document).ready( function() {
12279 * $('#example').dataTable( {
12280 * "columns": [
12281 * { "visible": false },
12282 * null,
12283 * null,
12284 * null,
12285 * null
12286 * ] } );
12287 * } );
12288 */
12289 "bVisible": true,
12290
12291
12292 /**
12293 * Developer definable function that is called whenever a cell is created (Ajax source,
12294 * etc) or processed for input (DOM source). This can be used as a compliment to mRender
12295 * allowing you to modify the DOM element (add background colour for example) when the
12296 * element is available.
12297 * @type function
12298 * @param {element} td The TD node that has been created
12299 * @param {*} cellData The Data for the cell
12300 * @param {array|object} rowData The data for the whole row
12301 * @param {int} row The row index for the aoData data store
12302 * @param {int} col The column index for aoColumns
12303 *
12304 * @name DataTable.defaults.column.createdCell
12305 * @dtopt Columns
12306 *
12307 * @example
12308 * $(document).ready( function() {
12309 * $('#example').dataTable( {
12310 * "columnDefs": [ {
12311 * "targets": [3],
12312 * "createdCell": function (td, cellData, rowData, row, col) {
12313 * if ( cellData == "1.7" ) {
12314 * $(td).css('color', 'blue')
12315 * }
12316 * }
12317 * } ]
12318 * });
12319 * } );
12320 */
12321 "fnCreatedCell": null,
12322
12323
12324 /**
12325 * This parameter has been replaced by `data` in DataTables to ensure naming
12326 * consistency. `dataProp` can still be used, as there is backwards
12327 * compatibility in DataTables for this option, but it is strongly
12328 * recommended that you use `data` in preference to `dataProp`.
12329 * @name DataTable.defaults.column.dataProp
12330 */
12331
12332
12333 /**
12334 * This property can be used to read data from any data source property,
12335 * including deeply nested objects / properties. `data` can be given in a
12336 * number of different ways which effect its behaviour:
12337 *
12338 * * `integer` - treated as an array index for the data source. This is the
12339 * default that DataTables uses (incrementally increased for each column).
12340 * * `string` - read an object property from the data source. There are
12341 * three 'special' options that can be used in the string to alter how
12342 * DataTables reads the data from the source object:
12343 * * `.` - Dotted Javascript notation. Just as you use a `.` in
12344 * Javascript to read from nested objects, so to can the options
12345 * specified in `data`. For example: `browser.version` or
12346 * `browser.name`. If your object parameter name contains a period, use
12347 * `\\` to escape it - i.e. `first\\.name`.
12348 * * `[]` - Array notation. DataTables can automatically combine data
12349 * from and array source, joining the data with the characters provided
12350 * between the two brackets. For example: `name[, ]` would provide a
12351 * comma-space separated list from the source array. If no characters
12352 * are provided between the brackets, the original array source is
12353 * returned.
12354 * * `()` - Function notation. Adding `()` to the end of a parameter will
12355 * execute a function of the name given. For example: `browser()` for a
12356 * simple function on the data source, `browser.version()` for a
12357 * function in a nested property or even `browser().version` to get an
12358 * object property if the function called returns an object. Note that
12359 * function notation is recommended for use in `render` rather than
12360 * `data` as it is much simpler to use as a renderer.
12361 * * `null` - use the original data source for the row rather than plucking
12362 * data directly from it. This action has effects on two other
12363 * initialisation options:
12364 * * `defaultContent` - When null is given as the `data` option and
12365 * `defaultContent` is specified for the column, the value defined by
12366 * `defaultContent` will be used for the cell.
12367 * * `render` - When null is used for the `data` option and the `render`
12368 * option is specified for the column, the whole data source for the
12369 * row is used for the renderer.
12370 * * `function` - the function given will be executed whenever DataTables
12371 * needs to set or get the data for a cell in the column. The function
12372 * takes three parameters:
12373 * * Parameters:
12374 * * `{array|object}` The data source for the row
12375 * * `{string}` The type call data requested - this will be 'set' when
12376 * setting data or 'filter', 'display', 'type', 'sort' or undefined
12377 * when gathering data. Note that when `undefined` is given for the
12378 * type DataTables expects to get the raw data for the object back<
12379 * * `{*}` Data to set when the second parameter is 'set'.
12380 * * Return:
12381 * * The return value from the function is not required when 'set' is
12382 * the type of call, but otherwise the return is what will be used
12383 * for the data requested.
12384 *
12385 * Note that `data` is a getter and setter option. If you just require
12386 * formatting of data for output, you will likely want to use `render` which
12387 * is simply a getter and thus simpler to use.
12388 *
12389 * Note that prior to DataTables 1.9.2 `data` was called `mDataProp`. The
12390 * name change reflects the flexibility of this property and is consistent
12391 * with the naming of mRender. If 'mDataProp' is given, then it will still
12392 * be used by DataTables, as it automatically maps the old name to the new
12393 * if required.
12394 *
12395 * @type string|int|function|null
12396 * @default null <i>Use automatically calculated column index</i>
12397 *
12398 * @name DataTable.defaults.column.data
12399 * @dtopt Columns
12400 *
12401 * @example
12402 * // Read table data from objects
12403 * // JSON structure for each row:
12404 * // {
12405 * // "engine": {value},
12406 * // "browser": {value},
12407 * // "platform": {value},
12408 * // "version": {value},
12409 * // "grade": {value}
12410 * // }
12411 * $(document).ready( function() {
12412 * $('#example').dataTable( {
12413 * "ajaxSource": "sources/objects.txt",
12414 * "columns": [
12415 * { "data": "engine" },
12416 * { "data": "browser" },
12417 * { "data": "platform" },
12418 * { "data": "version" },
12419 * { "data": "grade" }
12420 * ]
12421 * } );
12422 * } );
12423 *
12424 * @example
12425 * // Read information from deeply nested objects
12426 * // JSON structure for each row:
12427 * // {
12428 * // "engine": {value},
12429 * // "browser": {value},
12430 * // "platform": {
12431 * // "inner": {value}
12432 * // },
12433 * // "details": [
12434 * // {value}, {value}
12435 * // ]
12436 * // }
12437 * $(document).ready( function() {
12438 * $('#example').dataTable( {
12439 * "ajaxSource": "sources/deep.txt",
12440 * "columns": [
12441 * { "data": "engine" },
12442 * { "data": "browser" },
12443 * { "data": "platform.inner" },
12444 * { "data": "details.0" },
12445 * { "data": "details.1" }
12446 * ]
12447 * } );
12448 * } );
12449 *
12450 * @example
12451 * // Using `data` as a function to provide different information for
12452 * // sorting, filtering and display. In this case, currency (price)
12453 * $(document).ready( function() {
12454 * $('#example').dataTable( {
12455 * "columnDefs": [ {
12456 * "targets": [ 0 ],
12457 * "data": function ( source, type, val ) {
12458 * if (type === 'set') {
12459 * source.price = val;
12460 * // Store the computed dislay and filter values for efficiency
12461 * source.price_display = val=="" ? "" : "$"+numberFormat(val);
12462 * source.price_filter = val=="" ? "" : "$"+numberFormat(val)+" "+val;
12463 * return;
12464 * }
12465 * else if (type === 'display') {
12466 * return source.price_display;
12467 * }
12468 * else if (type === 'filter') {
12469 * return source.price_filter;
12470 * }
12471 * // 'sort', 'type' and undefined all just use the integer
12472 * return source.price;
12473 * }
12474 * } ]
12475 * } );
12476 * } );
12477 *
12478 * @example
12479 * // Using default content
12480 * $(document).ready( function() {
12481 * $('#example').dataTable( {
12482 * "columnDefs": [ {
12483 * "targets": [ 0 ],
12484 * "data": null,
12485 * "defaultContent": "Click to edit"
12486 * } ]
12487 * } );
12488 * } );
12489 *
12490 * @example
12491 * // Using array notation - outputting a list from an array
12492 * $(document).ready( function() {
12493 * $('#example').dataTable( {
12494 * "columnDefs": [ {
12495 * "targets": [ 0 ],
12496 * "data": "name[, ]"
12497 * } ]
12498 * } );
12499 * } );
12500 *
12501 */
12502 "mData": null,
12503
12504
12505 /**
12506 * This property is the rendering partner to `data` and it is suggested that
12507 * when you want to manipulate data for display (including filtering,
12508 * sorting etc) without altering the underlying data for the table, use this
12509 * property. `render` can be considered to be the the read only companion to
12510 * `data` which is read / write (then as such more complex). Like `data`
12511 * this option can be given in a number of different ways to effect its
12512 * behaviour:
12513 *
12514 * * `integer` - treated as an array index for the data source. This is the
12515 * default that DataTables uses (incrementally increased for each column).
12516 * * `string` - read an object property from the data source. There are
12517 * three 'special' options that can be used in the string to alter how
12518 * DataTables reads the data from the source object:
12519 * * `.` - Dotted Javascript notation. Just as you use a `.` in
12520 * Javascript to read from nested objects, so to can the options
12521 * specified in `data`. For example: `browser.version` or
12522 * `browser.name`. If your object parameter name contains a period, use
12523 * `\\` to escape it - i.e. `first\\.name`.
12524 * * `[]` - Array notation. DataTables can automatically combine data
12525 * from and array source, joining the data with the characters provided
12526 * between the two brackets. For example: `name[, ]` would provide a
12527 * comma-space separated list from the source array. If no characters
12528 * are provided between the brackets, the original array source is
12529 * returned.
12530 * * `()` - Function notation. Adding `()` to the end of a parameter will
12531 * execute a function of the name given. For example: `browser()` for a
12532 * simple function on the data source, `browser.version()` for a
12533 * function in a nested property or even `browser().version` to get an
12534 * object property if the function called returns an object.
12535 * * `object` - use different data for the different data types requested by
12536 * DataTables ('filter', 'display', 'type' or 'sort'). The property names
12537 * of the object is the data type the property refers to and the value can
12538 * defined using an integer, string or function using the same rules as
12539 * `render` normally does. Note that an `_` option _must_ be specified.
12540 * This is the default value to use if you haven't specified a value for
12541 * the data type requested by DataTables.
12542 * * `function` - the function given will be executed whenever DataTables
12543 * needs to set or get the data for a cell in the column. The function
12544 * takes three parameters:
12545 * * Parameters:
12546 * * {array|object} The data source for the row (based on `data`)
12547 * * {string} The type call data requested - this will be 'filter',
12548 * 'display', 'type' or 'sort'.
12549 * * {array|object} The full data source for the row (not based on
12550 * `data`)
12551 * * Return:
12552 * * The return value from the function is what will be used for the
12553 * data requested.
12554 *
12555 * @type string|int|function|object|null
12556 * @default null Use the data source value.
12557 *
12558 * @name DataTable.defaults.column.render
12559 * @dtopt Columns
12560 *
12561 * @example
12562 * // Create a comma separated list from an array of objects
12563 * $(document).ready( function() {
12564 * $('#example').dataTable( {
12565 * "ajaxSource": "sources/deep.txt",
12566 * "columns": [
12567 * { "data": "engine" },
12568 * { "data": "browser" },
12569 * {
12570 * "data": "platform",
12571 * "render": "[, ].name"
12572 * }
12573 * ]
12574 * } );
12575 * } );
12576 *
12577 * @example
12578 * // Execute a function to obtain data
12579 * $(document).ready( function() {
12580 * $('#example').dataTable( {
12581 * "columnDefs": [ {
12582 * "targets": [ 0 ],
12583 * "data": null, // Use the full data source object for the renderer's source
12584 * "render": "browserName()"
12585 * } ]
12586 * } );
12587 * } );
12588 *
12589 * @example
12590 * // As an object, extracting different data for the different types
12591 * // This would be used with a data source such as:
12592 * // { "phone": 5552368, "phone_filter": "5552368 555-2368", "phone_display": "555-2368" }
12593 * // Here the `phone` integer is used for sorting and type detection, while `phone_filter`
12594 * // (which has both forms) is used for filtering for if a user inputs either format, while
12595 * // the formatted phone number is the one that is shown in the table.
12596 * $(document).ready( function() {
12597 * $('#example').dataTable( {
12598 * "columnDefs": [ {
12599 * "targets": [ 0 ],
12600 * "data": null, // Use the full data source object for the renderer's source
12601 * "render": {
12602 * "_": "phone",
12603 * "filter": "phone_filter",
12604 * "display": "phone_display"
12605 * }
12606 * } ]
12607 * } );
12608 * } );
12609 *
12610 * @example
12611 * // Use as a function to create a link from the data source
12612 * $(document).ready( function() {
12613 * $('#example').dataTable( {
12614 * "columnDefs": [ {
12615 * "targets": [ 0 ],
12616 * "data": "download_link",
12617 * "render": function ( data, type, full ) {
12618 * return '<a href="'+data+'">Download</a>';
12619 * }
12620 * } ]
12621 * } );
12622 * } );
12623 */
12624 "mRender": null,
12625
12626
12627 /**
12628 * Change the cell type created for the column - either TD cells or TH cells. This
12629 * can be useful as TH cells have semantic meaning in the table body, allowing them
12630 * to act as a header for a row (you may wish to add scope='row' to the TH elements).
12631 * @type string
12632 * @default td
12633 *
12634 * @name DataTable.defaults.column.cellType
12635 * @dtopt Columns
12636 *
12637 * @example
12638 * // Make the first column use TH cells
12639 * $(document).ready( function() {
12640 * $('#example').dataTable( {
12641 * "columnDefs": [ {
12642 * "targets": [ 0 ],
12643 * "cellType": "th"
12644 * } ]
12645 * } );
12646 * } );
12647 */
12648 "sCellType": "td",
12649
12650
12651 /**
12652 * Class to give to each cell in this column.
12653 * @type string
12654 * @default <i>Empty string</i>
12655 *
12656 * @name DataTable.defaults.column.class
12657 * @dtopt Columns
12658 *
12659 * @example
12660 * // Using `columnDefs`
12661 * $(document).ready( function() {
12662 * $('#example').dataTable( {
12663 * "columnDefs": [
12664 * { "class": "my_class", "targets": [ 0 ] }
12665 * ]
12666 * } );
12667 * } );
12668 *
12669 * @example
12670 * // Using `columns`
12671 * $(document).ready( function() {
12672 * $('#example').dataTable( {
12673 * "columns": [
12674 * { "class": "my_class" },
12675 * null,
12676 * null,
12677 * null,
12678 * null
12679 * ]
12680 * } );
12681 * } );
12682 */
12683 "sClass": "",
12684
12685 /**
12686 * When DataTables calculates the column widths to assign to each column,
12687 * it finds the longest string in each column and then constructs a
12688 * temporary table and reads the widths from that. The problem with this
12689 * is that "mmm" is much wider then "iiii", but the latter is a longer
12690 * string - thus the calculation can go wrong (doing it properly and putting
12691 * it into an DOM object and measuring that is horribly(!) slow). Thus as
12692 * a "work around" we provide this option. It will append its value to the
12693 * text that is found to be the longest string for the column - i.e. padding.
12694 * Generally you shouldn't need this!
12695 * @type string
12696 * @default <i>Empty string<i>
12697 *
12698 * @name DataTable.defaults.column.contentPadding
12699 * @dtopt Columns
12700 *
12701 * @example
12702 * // Using `columns`
12703 * $(document).ready( function() {
12704 * $('#example').dataTable( {
12705 * "columns": [
12706 * null,
12707 * null,
12708 * null,
12709 * {
12710 * "contentPadding": "mmm"
12711 * }
12712 * ]
12713 * } );
12714 * } );
12715 */
12716 "sContentPadding": "",
12717
12718
12719 /**
12720 * Allows a default value to be given for a column's data, and will be used
12721 * whenever a null data source is encountered (this can be because `data`
12722 * is set to null, or because the data source itself is null).
12723 * @type string
12724 * @default null
12725 *
12726 * @name DataTable.defaults.column.defaultContent
12727 * @dtopt Columns
12728 *
12729 * @example
12730 * // Using `columnDefs`
12731 * $(document).ready( function() {
12732 * $('#example').dataTable( {
12733 * "columnDefs": [
12734 * {
12735 * "data": null,
12736 * "defaultContent": "Edit",
12737 * "targets": [ -1 ]
12738 * }
12739 * ]
12740 * } );
12741 * } );
12742 *
12743 * @example
12744 * // Using `columns`
12745 * $(document).ready( function() {
12746 * $('#example').dataTable( {
12747 * "columns": [
12748 * null,
12749 * null,
12750 * null,
12751 * {
12752 * "data": null,
12753 * "defaultContent": "Edit"
12754 * }
12755 * ]
12756 * } );
12757 * } );
12758 */
12759 "sDefaultContent": null,
12760
12761
12762 /**
12763 * This parameter is only used in DataTables' server-side processing. It can
12764 * be exceptionally useful to know what columns are being displayed on the
12765 * client side, and to map these to database fields. When defined, the names
12766 * also allow DataTables to reorder information from the server if it comes
12767 * back in an unexpected order (i.e. if you switch your columns around on the
12768 * client-side, your server-side code does not also need updating).
12769 * @type string
12770 * @default <i>Empty string</i>
12771 *
12772 * @name DataTable.defaults.column.name
12773 * @dtopt Columns
12774 *
12775 * @example
12776 * // Using `columnDefs`
12777 * $(document).ready( function() {
12778 * $('#example').dataTable( {
12779 * "columnDefs": [
12780 * { "name": "engine", "targets": [ 0 ] },
12781 * { "name": "browser", "targets": [ 1 ] },
12782 * { "name": "platform", "targets": [ 2 ] },
12783 * { "name": "version", "targets": [ 3 ] },
12784 * { "name": "grade", "targets": [ 4 ] }
12785 * ]
12786 * } );
12787 * } );
12788 *
12789 * @example
12790 * // Using `columns`
12791 * $(document).ready( function() {
12792 * $('#example').dataTable( {
12793 * "columns": [
12794 * { "name": "engine" },
12795 * { "name": "browser" },
12796 * { "name": "platform" },
12797 * { "name": "version" },
12798 * { "name": "grade" }
12799 * ]
12800 * } );
12801 * } );
12802 */
12803 "sName": "",
12804
12805
12806 /**
12807 * Defines a data source type for the ordering which can be used to read
12808 * real-time information from the table (updating the internally cached
12809 * version) prior to ordering. This allows ordering to occur on user
12810 * editable elements such as form inputs.
12811 * @type string
12812 * @default std
12813 *
12814 * @name DataTable.defaults.column.orderDataType
12815 * @dtopt Columns
12816 *
12817 * @example
12818 * // Using `columnDefs`
12819 * $(document).ready( function() {
12820 * $('#example').dataTable( {
12821 * "columnDefs": [
12822 * { "orderDataType": "dom-text", "targets": [ 2, 3 ] },
12823 * { "type": "numeric", "targets": [ 3 ] },
12824 * { "orderDataType": "dom-select", "targets": [ 4 ] },
12825 * { "orderDataType": "dom-checkbox", "targets": [ 5 ] }
12826 * ]
12827 * } );
12828 * } );
12829 *
12830 * @example
12831 * // Using `columns`
12832 * $(document).ready( function() {
12833 * $('#example').dataTable( {
12834 * "columns": [
12835 * null,
12836 * null,
12837 * { "orderDataType": "dom-text" },
12838 * { "orderDataType": "dom-text", "type": "numeric" },
12839 * { "orderDataType": "dom-select" },
12840 * { "orderDataType": "dom-checkbox" }
12841 * ]
12842 * } );
12843 * } );
12844 */
12845 "sSortDataType": "std",
12846
12847
12848 /**
12849 * The title of this column.
12850 * @type string
12851 * @default null <i>Derived from the 'TH' value for this column in the
12852 * original HTML table.</i>
12853 *
12854 * @name DataTable.defaults.column.title
12855 * @dtopt Columns
12856 *
12857 * @example
12858 * // Using `columnDefs`
12859 * $(document).ready( function() {
12860 * $('#example').dataTable( {
12861 * "columnDefs": [
12862 * { "title": "My column title", "targets": [ 0 ] }
12863 * ]
12864 * } );
12865 * } );
12866 *
12867 * @example
12868 * // Using `columns`
12869 * $(document).ready( function() {
12870 * $('#example').dataTable( {
12871 * "columns": [
12872 * { "title": "My column title" },
12873 * null,
12874 * null,
12875 * null,
12876 * null
12877 * ]
12878 * } );
12879 * } );
12880 */
12881 "sTitle": null,
12882
12883
12884 /**
12885 * The type allows you to specify how the data for this column will be
12886 * ordered. Four types (string, numeric, date and html (which will strip
12887 * HTML tags before ordering)) are currently available. Note that only date
12888 * formats understood by Javascript's Date() object will be accepted as type
12889 * date. For example: "Mar 26, 2008 5:03 PM". May take the values: 'string',
12890 * 'numeric', 'date' or 'html' (by default). Further types can be adding
12891 * through plug-ins.
12892 * @type string
12893 * @default null <i>Auto-detected from raw data</i>
12894 *
12895 * @name DataTable.defaults.column.type
12896 * @dtopt Columns
12897 *
12898 * @example
12899 * // Using `columnDefs`
12900 * $(document).ready( function() {
12901 * $('#example').dataTable( {
12902 * "columnDefs": [
12903 * { "type": "html", "targets": [ 0 ] }
12904 * ]
12905 * } );
12906 * } );
12907 *
12908 * @example
12909 * // Using `columns`
12910 * $(document).ready( function() {
12911 * $('#example').dataTable( {
12912 * "columns": [
12913 * { "type": "html" },
12914 * null,
12915 * null,
12916 * null,
12917 * null
12918 * ]
12919 * } );
12920 * } );
12921 */
12922 "sType": null,
12923
12924
12925 /**
12926 * Defining the width of the column, this parameter may take any CSS value
12927 * (3em, 20px etc). DataTables applies 'smart' widths to columns which have not
12928 * been given a specific width through this interface ensuring that the table
12929 * remains readable.
12930 * @type string
12931 * @default null <i>Automatic</i>
12932 *
12933 * @name DataTable.defaults.column.width
12934 * @dtopt Columns
12935 *
12936 * @example
12937 * // Using `columnDefs`
12938 * $(document).ready( function() {
12939 * $('#example').dataTable( {
12940 * "columnDefs": [
12941 * { "width": "20%", "targets": [ 0 ] }
12942 * ]
12943 * } );
12944 * } );
12945 *
12946 * @example
12947 * // Using `columns`
12948 * $(document).ready( function() {
12949 * $('#example').dataTable( {
12950 * "columns": [
12951 * { "width": "20%" },
12952 * null,
12953 * null,
12954 * null,
12955 * null
12956 * ]
12957 * } );
12958 * } );
12959 */
12960 "sWidth": null
12961 };
12962
12963 _fnHungarianMap( DataTable.defaults.column );
12964
12965
12966
12967 /**
12968 * DataTables settings object - this holds all the information needed for a
12969 * given table, including configuration, data and current application of the
12970 * table options. DataTables does not have a single instance for each DataTable
12971 * with the settings attached to that instance, but rather instances of the
12972 * DataTable "class" are created on-the-fly as needed (typically by a
12973 * $().dataTable() call) and the settings object is then applied to that
12974 * instance.
12975 *
12976 * Note that this object is related to {@link DataTable.defaults} but this
12977 * one is the internal data store for DataTables's cache of columns. It should
12978 * NOT be manipulated outside of DataTables. Any configuration should be done
12979 * through the initialisation options.
12980 * @namespace
12981 * @todo Really should attach the settings object to individual instances so we
12982 * don't need to create new instances on each $().dataTable() call (if the
12983 * table already exists). It would also save passing oSettings around and
12984 * into every single function. However, this is a very significant
12985 * architecture change for DataTables and will almost certainly break
12986 * backwards compatibility with older installations. This is something that
12987 * will be done in 2.0.
12988 */
12989 DataTable.models.oSettings = {
12990 /**
12991 * Primary features of DataTables and their enablement state.
12992 * @namespace
12993 */
12994 "oFeatures": {
12995
12996 /**
12997 * Flag to say if DataTables should automatically try to calculate the
12998 * optimum table and columns widths (true) or not (false).
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 "bAutoWidth": null,
13004
13005 /**
13006 * Delay the creation of TR and TD elements until they are actually
13007 * needed by a driven page draw. This can give a significant speed
13008 * increase for Ajax source and Javascript source data, but makes no
13009 * difference at all fro DOM and server-side processing tables.
13010 * Note that this parameter will be set by the initialisation routine. To
13011 * set a default use {@link DataTable.defaults}.
13012 * @type boolean
13013 */
13014 "bDeferRender": null,
13015
13016 /**
13017 * Enable filtering on the table or not. Note that if this is disabled
13018 * then there is no filtering at all on the table, including fnFilter.
13019 * To just remove the filtering input use sDom and remove the 'f' option.
13020 * Note that this parameter will be set by the initialisation routine. To
13021 * set a default use {@link DataTable.defaults}.
13022 * @type boolean
13023 */
13024 "bFilter": null,
13025
13026 /**
13027 * Table information element (the 'Showing x of y records' div) enable
13028 * flag.
13029 * Note that this parameter will be set by the initialisation routine. To
13030 * set a default use {@link DataTable.defaults}.
13031 * @type boolean
13032 */
13033 "bInfo": null,
13034
13035 /**
13036 * Present a user control allowing the end user to change the page size
13037 * when pagination is enabled.
13038 * Note that this parameter will be set by the initialisation routine. To
13039 * set a default use {@link DataTable.defaults}.
13040 * @type boolean
13041 */
13042 "bLengthChange": null,
13043
13044 /**
13045 * Pagination enabled or not. Note that if this is disabled then length
13046 * changing must also be disabled.
13047 * Note that this parameter will be set by the initialisation routine. To
13048 * set a default use {@link DataTable.defaults}.
13049 * @type boolean
13050 */
13051 "bPaginate": null,
13052
13053 /**
13054 * Processing indicator enable flag whenever DataTables is enacting a
13055 * user request - typically an Ajax request for server-side processing.
13056 * Note that this parameter will be set by the initialisation routine. To
13057 * set a default use {@link DataTable.defaults}.
13058 * @type boolean
13059 */
13060 "bProcessing": null,
13061
13062 /**
13063 * Server-side processing enabled flag - when enabled DataTables will
13064 * get all data from the server for every draw - there is no filtering,
13065 * sorting or paging done on the client-side.
13066 * Note that this parameter will be set by the initialisation routine. To
13067 * set a default use {@link DataTable.defaults}.
13068 * @type boolean
13069 */
13070 "bServerSide": null,
13071
13072 /**
13073 * Sorting enablement flag.
13074 * Note that this parameter will be set by the initialisation routine. To
13075 * set a default use {@link DataTable.defaults}.
13076 * @type boolean
13077 */
13078 "bSort": null,
13079
13080 /**
13081 * Multi-column sorting
13082 * Note that this parameter will be set by the initialisation routine. To
13083 * set a default use {@link DataTable.defaults}.
13084 * @type boolean
13085 */
13086 "bSortMulti": null,
13087
13088 /**
13089 * Apply a class to the columns which are being sorted to provide a
13090 * visual highlight or not. This can slow things down when enabled since
13091 * there is a lot of DOM interaction.
13092 * Note that this parameter will be set by the initialisation routine. To
13093 * set a default use {@link DataTable.defaults}.
13094 * @type boolean
13095 */
13096 "bSortClasses": null,
13097
13098 /**
13099 * State saving enablement flag.
13100 * Note that this parameter will be set by the initialisation routine. To
13101 * set a default use {@link DataTable.defaults}.
13102 * @type boolean
13103 */
13104 "bStateSave": null
13105 },
13106
13107
13108 /**
13109 * Scrolling settings for a table.
13110 * @namespace
13111 */
13112 "oScroll": {
13113 /**
13114 * When the table is shorter in height than sScrollY, collapse the
13115 * table container down to the height of the table (when true).
13116 * Note that this parameter will be set by the initialisation routine. To
13117 * set a default use {@link DataTable.defaults}.
13118 * @type boolean
13119 */
13120 "bCollapse": null,
13121
13122 /**
13123 * Width of the scrollbar for the web-browser's platform. Calculated
13124 * during table initialisation.
13125 * @type int
13126 * @default 0
13127 */
13128 "iBarWidth": 0,
13129
13130 /**
13131 * Viewport width for horizontal scrolling. Horizontal scrolling is
13132 * disabled if an empty string.
13133 * Note that this parameter will be set by the initialisation routine. To
13134 * set a default use {@link DataTable.defaults}.
13135 * @type string
13136 */
13137 "sX": null,
13138
13139 /**
13140 * Width to expand the table to when using x-scrolling. Typically you
13141 * should not need to use this.
13142 * Note that this parameter will be set by the initialisation routine. To
13143 * set a default use {@link DataTable.defaults}.
13144 * @type string
13145 * @deprecated
13146 */
13147 "sXInner": null,
13148
13149 /**
13150 * Viewport height for vertical scrolling. Vertical scrolling is disabled
13151 * if an empty string.
13152 * Note that this parameter will be set by the initialisation routine. To
13153 * set a default use {@link DataTable.defaults}.
13154 * @type string
13155 */
13156 "sY": null
13157 },
13158
13159 /**
13160 * Language information for the table.
13161 * @namespace
13162 * @extends DataTable.defaults.oLanguage
13163 */
13164 "oLanguage": {
13165 /**
13166 * Information callback function. See
13167 * {@link DataTable.defaults.fnInfoCallback}
13168 * @type function
13169 * @default null
13170 */
13171 "fnInfoCallback": null
13172 },
13173
13174 /**
13175 * Browser support parameters
13176 * @namespace
13177 */
13178 "oBrowser": {
13179 /**
13180 * Indicate if the browser incorrectly calculates width:100% inside a
13181 * scrolling element (IE6/7)
13182 * @type boolean
13183 * @default false
13184 */
13185 "bScrollOversize": false,
13186
13187 /**
13188 * Determine if the vertical scrollbar is on the right or left of the
13189 * scrolling container - needed for rtl language layout, although not
13190 * all browsers move the scrollbar (Safari).
13191 * @type boolean
13192 * @default false
13193 */
13194 "bScrollbarLeft": false,
13195
13196 /**
13197 * Flag for if `getBoundingClientRect` is fully supported or not
13198 * @type boolean
13199 * @default false
13200 */
13201 "bBounding": false,
13202
13203 /**
13204 * Browser scrollbar width
13205 * @type integer
13206 * @default 0
13207 */
13208 "barWidth": 0
13209 },
13210
13211
13212 "ajax": null,
13213
13214
13215 /**
13216 * Array referencing the nodes which are used for the features. The
13217 * parameters of this object match what is allowed by sDom - i.e.
13218 * <ul>
13219 * <li>'l' - Length changing</li>
13220 * <li>'f' - Filtering input</li>
13221 * <li>'t' - The table!</li>
13222 * <li>'i' - Information</li>
13223 * <li>'p' - Pagination</li>
13224 * <li>'r' - pRocessing</li>
13225 * </ul>
13226 * @type array
13227 * @default []
13228 */
13229 "aanFeatures": [],
13230
13231 /**
13232 * Store data information - see {@link DataTable.models.oRow} for detailed
13233 * information.
13234 * @type array
13235 * @default []
13236 */
13237 "aoData": [],
13238
13239 /**
13240 * Array of indexes which are in the current display (after filtering etc)
13241 * @type array
13242 * @default []
13243 */
13244 "aiDisplay": [],
13245
13246 /**
13247 * Array of indexes for display - no filtering
13248 * @type array
13249 * @default []
13250 */
13251 "aiDisplayMaster": [],
13252
13253 /**
13254 * Map of row ids to data indexes
13255 * @type object
13256 * @default {}
13257 */
13258 "aIds": {},
13259
13260 /**
13261 * Store information about each column that is in use
13262 * @type array
13263 * @default []
13264 */
13265 "aoColumns": [],
13266
13267 /**
13268 * Store information about the table's header
13269 * @type array
13270 * @default []
13271 */
13272 "aoHeader": [],
13273
13274 /**
13275 * Store information about the table's footer
13276 * @type array
13277 * @default []
13278 */
13279 "aoFooter": [],
13280
13281 /**
13282 * Store the applied global search information in case we want to force a
13283 * research or compare the old search to a new one.
13284 * Note that this parameter will be set by the initialisation routine. To
13285 * set a default use {@link DataTable.defaults}.
13286 * @namespace
13287 * @extends DataTable.models.oSearch
13288 */
13289 "oPreviousSearch": {},
13290
13291 /**
13292 * Store the applied search for each column - see
13293 * {@link DataTable.models.oSearch} for the format that is used for the
13294 * filtering information for each column.
13295 * @type array
13296 * @default []
13297 */
13298 "aoPreSearchCols": [],
13299
13300 /**
13301 * Sorting that is applied to the table. Note that the inner arrays are
13302 * used in the following manner:
13303 * <ul>
13304 * <li>Index 0 - column number</li>
13305 * <li>Index 1 - current sorting direction</li>
13306 * </ul>
13307 * Note that this parameter will be set by the initialisation routine. To
13308 * set a default use {@link DataTable.defaults}.
13309 * @type array
13310 * @todo These inner arrays should really be objects
13311 */
13312 "aaSorting": null,
13313
13314 /**
13315 * Sorting that is always applied to the table (i.e. prefixed in front of
13316 * aaSorting).
13317 * Note that this parameter will be set by the initialisation routine. To
13318 * set a default use {@link DataTable.defaults}.
13319 * @type array
13320 * @default []
13321 */
13322 "aaSortingFixed": [],
13323
13324 /**
13325 * Classes to use for the striping of a table.
13326 * Note that this parameter will be set by the initialisation routine. To
13327 * set a default use {@link DataTable.defaults}.
13328 * @type array
13329 * @default []
13330 */
13331 "asStripeClasses": null,
13332
13333 /**
13334 * If restoring a table - we should restore its striping classes as well
13335 * @type array
13336 * @default []
13337 */
13338 "asDestroyStripes": [],
13339
13340 /**
13341 * If restoring a table - we should restore its width
13342 * @type int
13343 * @default 0
13344 */
13345 "sDestroyWidth": 0,
13346
13347 /**
13348 * Callback functions array for every time a row is inserted (i.e. on a draw).
13349 * @type array
13350 * @default []
13351 */
13352 "aoRowCallback": [],
13353
13354 /**
13355 * Callback functions for the header on each draw.
13356 * @type array
13357 * @default []
13358 */
13359 "aoHeaderCallback": [],
13360
13361 /**
13362 * Callback function for the footer on each draw.
13363 * @type array
13364 * @default []
13365 */
13366 "aoFooterCallback": [],
13367
13368 /**
13369 * Array of callback functions for draw callback functions
13370 * @type array
13371 * @default []
13372 */
13373 "aoDrawCallback": [],
13374
13375 /**
13376 * Array of callback functions for row created function
13377 * @type array
13378 * @default []
13379 */
13380 "aoRowCreatedCallback": [],
13381
13382 /**
13383 * Callback functions for just before the table is redrawn. A return of
13384 * false will be used to cancel the draw.
13385 * @type array
13386 * @default []
13387 */
13388 "aoPreDrawCallback": [],
13389
13390 /**
13391 * Callback functions for when the table has been initialised.
13392 * @type array
13393 * @default []
13394 */
13395 "aoInitComplete": [],
13396
13397
13398 /**
13399 * Callbacks for modifying the settings to be stored for state saving, prior to
13400 * saving state.
13401 * @type array
13402 * @default []
13403 */
13404 "aoStateSaveParams": [],
13405
13406 /**
13407 * Callbacks for modifying the settings that have been stored for state saving
13408 * prior to using the stored values to restore the state.
13409 * @type array
13410 * @default []
13411 */
13412 "aoStateLoadParams": [],
13413
13414 /**
13415 * Callbacks for operating on the settings object once the saved state has been
13416 * loaded
13417 * @type array
13418 * @default []
13419 */
13420 "aoStateLoaded": [],
13421
13422 /**
13423 * Cache the table ID for quick access
13424 * @type string
13425 * @default <i>Empty string</i>
13426 */
13427 "sTableId": "",
13428
13429 /**
13430 * The TABLE node for the main table
13431 * @type node
13432 * @default null
13433 */
13434 "nTable": null,
13435
13436 /**
13437 * Permanent ref to the thead element
13438 * @type node
13439 * @default null
13440 */
13441 "nTHead": null,
13442
13443 /**
13444 * Permanent ref to the tfoot element - if it exists
13445 * @type node
13446 * @default null
13447 */
13448 "nTFoot": null,
13449
13450 /**
13451 * Permanent ref to the tbody element
13452 * @type node
13453 * @default null
13454 */
13455 "nTBody": null,
13456
13457 /**
13458 * Cache the wrapper node (contains all DataTables controlled elements)
13459 * @type node
13460 * @default null
13461 */
13462 "nTableWrapper": null,
13463
13464 /**
13465 * Indicate if when using server-side processing the loading of data
13466 * should be deferred until the second draw.
13467 * Note that this parameter will be set by the initialisation routine. To
13468 * set a default use {@link DataTable.defaults}.
13469 * @type boolean
13470 * @default false
13471 */
13472 "bDeferLoading": false,
13473
13474 /**
13475 * Indicate if all required information has been read in
13476 * @type boolean
13477 * @default false
13478 */
13479 "bInitialised": false,
13480
13481 /**
13482 * Information about open rows. Each object in the array has the parameters
13483 * 'nTr' and 'nParent'
13484 * @type array
13485 * @default []
13486 */
13487 "aoOpenRows": [],
13488
13489 /**
13490 * Dictate the positioning of DataTables' control elements - see
13491 * {@link DataTable.model.oInit.sDom}.
13492 * Note that this parameter will be set by the initialisation routine. To
13493 * set a default use {@link DataTable.defaults}.
13494 * @type string
13495 * @default null
13496 */
13497 "sDom": null,
13498
13499 /**
13500 * Search delay (in mS)
13501 * @type integer
13502 * @default null
13503 */
13504 "searchDelay": null,
13505
13506 /**
13507 * Which type of pagination should be used.
13508 * Note that this parameter will be set by the initialisation routine. To
13509 * set a default use {@link DataTable.defaults}.
13510 * @type string
13511 * @default two_button
13512 */
13513 "sPaginationType": "two_button",
13514
13515 /**
13516 * The state duration (for `stateSave`) in seconds.
13517 * Note that this parameter will be set by the initialisation routine. To
13518 * set a default use {@link DataTable.defaults}.
13519 * @type int
13520 * @default 0
13521 */
13522 "iStateDuration": 0,
13523
13524 /**
13525 * Array of callback functions for state saving. Each array element is an
13526 * object with the following parameters:
13527 * <ul>
13528 * <li>function:fn - function to call. Takes two parameters, oSettings
13529 * and the JSON string to save that has been thus far created. Returns
13530 * a JSON string to be inserted into a json object
13531 * (i.e. '"param": [ 0, 1, 2]')</li>
13532 * <li>string:sName - name of callback</li>
13533 * </ul>
13534 * @type array
13535 * @default []
13536 */
13537 "aoStateSave": [],
13538
13539 /**
13540 * Array of callback functions for state loading. Each array element is an
13541 * object with the following parameters:
13542 * <ul>
13543 * <li>function:fn - function to call. Takes two parameters, oSettings
13544 * and the object stored. May return false to cancel state loading</li>
13545 * <li>string:sName - name of callback</li>
13546 * </ul>
13547 * @type array
13548 * @default []
13549 */
13550 "aoStateLoad": [],
13551
13552 /**
13553 * State that was saved. Useful for back reference
13554 * @type object
13555 * @default null
13556 */
13557 "oSavedState": null,
13558
13559 /**
13560 * State that was loaded. Useful for back reference
13561 * @type object
13562 * @default null
13563 */
13564 "oLoadedState": null,
13565
13566 /**
13567 * Source url for AJAX data for the table.
13568 * Note that this parameter will be set by the initialisation routine. To
13569 * set a default use {@link DataTable.defaults}.
13570 * @type string
13571 * @default null
13572 */
13573 "sAjaxSource": null,
13574
13575 /**
13576 * Property from a given object from which to read the table data from. This
13577 * can be an empty string (when not server-side processing), in which case
13578 * it is assumed an an array is given directly.
13579 * Note that this parameter will be set by the initialisation routine. To
13580 * set a default use {@link DataTable.defaults}.
13581 * @type string
13582 */
13583 "sAjaxDataProp": null,
13584
13585 /**
13586 * Note if draw should be blocked while getting data
13587 * @type boolean
13588 * @default true
13589 */
13590 "bAjaxDataGet": true,
13591
13592 /**
13593 * The last jQuery XHR object that was used for server-side data gathering.
13594 * This can be used for working with the XHR information in one of the
13595 * callbacks
13596 * @type object
13597 * @default null
13598 */
13599 "jqXHR": null,
13600
13601 /**
13602 * JSON returned from the server in the last Ajax request
13603 * @type object
13604 * @default undefined
13605 */
13606 "json": undefined,
13607
13608 /**
13609 * Data submitted as part of the last Ajax request
13610 * @type object
13611 * @default undefined
13612 */
13613 "oAjaxData": undefined,
13614
13615 /**
13616 * Function to get the server-side data.
13617 * Note that this parameter will be set by the initialisation routine. To
13618 * set a default use {@link DataTable.defaults}.
13619 * @type function
13620 */
13621 "fnServerData": null,
13622
13623 /**
13624 * Functions which are called prior to sending an Ajax request so extra
13625 * parameters can easily be sent to the server
13626 * @type array
13627 * @default []
13628 */
13629 "aoServerParams": [],
13630
13631 /**
13632 * Send the XHR HTTP method - GET or POST (could be PUT or DELETE if
13633 * required).
13634 * Note that this parameter will be set by the initialisation routine. To
13635 * set a default use {@link DataTable.defaults}.
13636 * @type string
13637 */
13638 "sServerMethod": null,
13639
13640 /**
13641 * Format numbers for display.
13642 * Note that this parameter will be set by the initialisation routine. To
13643 * set a default use {@link DataTable.defaults}.
13644 * @type function
13645 */
13646 "fnFormatNumber": null,
13647
13648 /**
13649 * List of options that can be used for the user selectable length menu.
13650 * Note that this parameter will be set by the initialisation routine. To
13651 * set a default use {@link DataTable.defaults}.
13652 * @type array
13653 * @default []
13654 */
13655 "aLengthMenu": null,
13656
13657 /**
13658 * Counter for the draws that the table does. Also used as a tracker for
13659 * server-side processing
13660 * @type int
13661 * @default 0
13662 */
13663 "iDraw": 0,
13664
13665 /**
13666 * Indicate if a redraw is being done - useful for Ajax
13667 * @type boolean
13668 * @default false
13669 */
13670 "bDrawing": false,
13671
13672 /**
13673 * Draw index (iDraw) of the last error when parsing the returned data
13674 * @type int
13675 * @default -1
13676 */
13677 "iDrawError": -1,
13678
13679 /**
13680 * Paging display length
13681 * @type int
13682 * @default 10
13683 */
13684 "_iDisplayLength": 10,
13685
13686 /**
13687 * Paging start point - aiDisplay index
13688 * @type int
13689 * @default 0
13690 */
13691 "_iDisplayStart": 0,
13692
13693 /**
13694 * Server-side processing - number of records in the result set
13695 * (i.e. before filtering), Use fnRecordsTotal rather than
13696 * this property to get the value of the number of records, regardless of
13697 * the server-side processing setting.
13698 * @type int
13699 * @default 0
13700 * @private
13701 */
13702 "_iRecordsTotal": 0,
13703
13704 /**
13705 * Server-side processing - number of records in the current display set
13706 * (i.e. after filtering). Use fnRecordsDisplay rather than
13707 * this property to get the value of the number of records, regardless of
13708 * the server-side processing setting.
13709 * @type boolean
13710 * @default 0
13711 * @private
13712 */
13713 "_iRecordsDisplay": 0,
13714
13715 /**
13716 * The classes to use for the table
13717 * @type object
13718 * @default {}
13719 */
13720 "oClasses": {},
13721
13722 /**
13723 * Flag attached to the settings object so you can check in the draw
13724 * callback if filtering has been done in the draw. Deprecated in favour of
13725 * events.
13726 * @type boolean
13727 * @default false
13728 * @deprecated
13729 */
13730 "bFiltered": false,
13731
13732 /**
13733 * Flag attached to the settings object so you can check in the draw
13734 * callback if sorting has been done in the draw. Deprecated in favour of
13735 * events.
13736 * @type boolean
13737 * @default false
13738 * @deprecated
13739 */
13740 "bSorted": false,
13741
13742 /**
13743 * Indicate that if multiple rows are in the header and there is more than
13744 * one unique cell per column, if the top one (true) or bottom one (false)
13745 * should be used for sorting / title by DataTables.
13746 * Note that this parameter will be set by the initialisation routine. To
13747 * set a default use {@link DataTable.defaults}.
13748 * @type boolean
13749 */
13750 "bSortCellsTop": null,
13751
13752 /**
13753 * Initialisation object that is used for the table
13754 * @type object
13755 * @default null
13756 */
13757 "oInit": null,
13758
13759 /**
13760 * Destroy callback functions - for plug-ins to attach themselves to the
13761 * destroy so they can clean up markup and events.
13762 * @type array
13763 * @default []
13764 */
13765 "aoDestroyCallback": [],
13766
13767
13768 /**
13769 * Get the number of records in the current record set, before filtering
13770 * @type function
13771 */
13772 "fnRecordsTotal": function ()
13773 {
13774 return _fnDataSource( this ) == 'ssp' ?
13775 this._iRecordsTotal * 1 :
13776 this.aiDisplayMaster.length;
13777 },
13778
13779 /**
13780 * Get the number of records in the current record set, after filtering
13781 * @type function
13782 */
13783 "fnRecordsDisplay": function ()
13784 {
13785 return _fnDataSource( this ) == 'ssp' ?
13786 this._iRecordsDisplay * 1 :
13787 this.aiDisplay.length;
13788 },
13789
13790 /**
13791 * Get the display end point - aiDisplay index
13792 * @type function
13793 */
13794 "fnDisplayEnd": function ()
13795 {
13796 var
13797 len = this._iDisplayLength,
13798 start = this._iDisplayStart,
13799 calc = start + len,
13800 records = this.aiDisplay.length,
13801 features = this.oFeatures,
13802 paginate = features.bPaginate;
13803
13804 if ( features.bServerSide ) {
13805 return paginate === false || len === -1 ?
13806 start + records :
13807 Math.min( start+len, this._iRecordsDisplay );
13808 }
13809 else {
13810 return ! paginate || calc>records || len===-1 ?
13811 records :
13812 calc;
13813 }
13814 },
13815
13816 /**
13817 * The DataTables object for this table
13818 * @type object
13819 * @default null
13820 */
13821 "oInstance": null,
13822
13823 /**
13824 * Unique identifier for each instance of the DataTables object. If there
13825 * is an ID on the table node, then it takes that value, otherwise an
13826 * incrementing internal counter is used.
13827 * @type string
13828 * @default null
13829 */
13830 "sInstance": null,
13831
13832 /**
13833 * tabindex attribute value that is added to DataTables control elements, allowing
13834 * keyboard navigation of the table and its controls.
13835 */
13836 "iTabIndex": 0,
13837
13838 /**
13839 * DIV container for the footer scrolling table if scrolling
13840 */
13841 "nScrollHead": null,
13842
13843 /**
13844 * DIV container for the footer scrolling table if scrolling
13845 */
13846 "nScrollFoot": null,
13847
13848 /**
13849 * Last applied sort
13850 * @type array
13851 * @default []
13852 */
13853 "aLastSort": [],
13854
13855 /**
13856 * Stored plug-in instances
13857 * @type object
13858 * @default {}
13859 */
13860 "oPlugins": {},
13861
13862 /**
13863 * Function used to get a row's id from the row's data
13864 * @type function
13865 * @default null
13866 */
13867 "rowIdFn": null,
13868
13869 /**
13870 * Data location where to store a row's id
13871 * @type string
13872 * @default null
13873 */
13874 "rowId": null
13875 };
13876
13877 /**
13878 * Extension object for DataTables that is used to provide all extension
13879 * options.
13880 *
13881 * Note that the `DataTable.ext` object is available through
13882 * `jQuery.fn.dataTable.ext` where it may be accessed and manipulated. It is
13883 * also aliased to `jQuery.fn.dataTableExt` for historic reasons.
13884 * @namespace
13885 * @extends DataTable.models.ext
13886 */
13887
13888
13889 /**
13890 * DataTables extensions
13891 *
13892 * This namespace acts as a collection area for plug-ins that can be used to
13893 * extend DataTables capabilities. Indeed many of the build in methods
13894 * use this method to provide their own capabilities (sorting methods for
13895 * example).
13896 *
13897 * Note that this namespace is aliased to `jQuery.fn.dataTableExt` for legacy
13898 * reasons
13899 *
13900 * @namespace
13901 */
13902 DataTable.ext = _ext = {
13903 /**
13904 * Buttons. For use with the Buttons extension for DataTables. This is
13905 * defined here so other extensions can define buttons regardless of load
13906 * order. It is _not_ used by DataTables core.
13907 *
13908 * @type object
13909 * @default {}
13910 */
13911 buttons: {},
13912
13913
13914 /**
13915 * Element class names
13916 *
13917 * @type object
13918 * @default {}
13919 */
13920 classes: {},
13921
13922
13923 /**
13924 * DataTables build type (expanded by the download builder)
13925 *
13926 * @type string
13927 */
13928 builder: "-source-",
13929
13930
13931 /**
13932 * Error reporting.
13933 *
13934 * How should DataTables report an error. Can take the value 'alert',
13935 * 'throw', 'none' or a function.
13936 *
13937 * @type string|function
13938 * @default alert
13939 */
13940 errMode: "alert",
13941
13942
13943 /**
13944 * Feature plug-ins.
13945 *
13946 * This is an array of objects which describe the feature plug-ins that are
13947 * available to DataTables. These feature plug-ins are then available for
13948 * use through the `dom` initialisation option.
13949 *
13950 * Each feature plug-in is described by an object which must have the
13951 * following properties:
13952 *
13953 * * `fnInit` - function that is used to initialise the plug-in,
13954 * * `cFeature` - a character so the feature can be enabled by the `dom`
13955 * instillation option. This is case sensitive.
13956 *
13957 * The `fnInit` function has the following input parameters:
13958 *
13959 * 1. `{object}` DataTables settings object: see
13960 * {@link DataTable.models.oSettings}
13961 *
13962 * And the following return is expected:
13963 *
13964 * * {node|null} The element which contains your feature. Note that the
13965 * return may also be void if your plug-in does not require to inject any
13966 * DOM elements into DataTables control (`dom`) - for example this might
13967 * be useful when developing a plug-in which allows table control via
13968 * keyboard entry
13969 *
13970 * @type array
13971 *
13972 * @example
13973 * $.fn.dataTable.ext.features.push( {
13974 * "fnInit": function( oSettings ) {
13975 * return new TableTools( { "oDTSettings": oSettings } );
13976 * },
13977 * "cFeature": "T"
13978 * } );
13979 */
13980 feature: [],
13981
13982
13983 /**
13984 * Row searching.
13985 *
13986 * This method of searching is complimentary to the default type based
13987 * searching, and a lot more comprehensive as it allows you complete control
13988 * over the searching logic. Each element in this array is a function
13989 * (parameters described below) that is called for every row in the table,
13990 * and your logic decides if it should be included in the searching data set
13991 * or not.
13992 *
13993 * Searching functions have the following input parameters:
13994 *
13995 * 1. `{object}` DataTables settings object: see
13996 * {@link DataTable.models.oSettings}
13997 * 2. `{array|object}` Data for the row to be processed (same as the
13998 * original format that was passed in as the data source, or an array
13999 * from a DOM data source
14000 * 3. `{int}` Row index ({@link DataTable.models.oSettings.aoData}), which
14001 * can be useful to retrieve the `TR` element if you need DOM interaction.
14002 *
14003 * And the following return is expected:
14004 *
14005 * * {boolean} Include the row in the searched result set (true) or not
14006 * (false)
14007 *
14008 * Note that as with the main search ability in DataTables, technically this
14009 * is "filtering", since it is subtractive. However, for consistency in
14010 * naming we call it searching here.
14011 *
14012 * @type array
14013 * @default []
14014 *
14015 * @example
14016 * // The following example shows custom search being applied to the
14017 * // fourth column (i.e. the data[3] index) based on two input values
14018 * // from the end-user, matching the data in a certain range.
14019 * $.fn.dataTable.ext.search.push(
14020 * function( settings, data, dataIndex ) {
14021 * var min = document.getElementById('min').value * 1;
14022 * var max = document.getElementById('max').value * 1;
14023 * var version = data[3] == "-" ? 0 : data[3]*1;
14024 *
14025 * if ( min == "" && max == "" ) {
14026 * return true;
14027 * }
14028 * else if ( min == "" && version < max ) {
14029 * return true;
14030 * }
14031 * else if ( min < version && "" == max ) {
14032 * return true;
14033 * }
14034 * else if ( min < version && version < max ) {
14035 * return true;
14036 * }
14037 * return false;
14038 * }
14039 * );
14040 */
14041 search: [],
14042
14043
14044 /**
14045 * Selector extensions
14046 *
14047 * The `selector` option can be used to extend the options available for the
14048 * selector modifier options (`selector-modifier` object data type) that
14049 * each of the three built in selector types offer (row, column and cell +
14050 * their plural counterparts). For example the Select extension uses this
14051 * mechanism to provide an option to select only rows, columns and cells
14052 * that have been marked as selected by the end user (`{selected: true}`),
14053 * which can be used in conjunction with the existing built in selector
14054 * options.
14055 *
14056 * Each property is an array to which functions can be pushed. The functions
14057 * take three attributes:
14058 *
14059 * * Settings object for the host table
14060 * * Options object (`selector-modifier` object type)
14061 * * Array of selected item indexes
14062 *
14063 * The return is an array of the resulting item indexes after the custom
14064 * selector has been applied.
14065 *
14066 * @type object
14067 */
14068 selector: {
14069 cell: [],
14070 column: [],
14071 row: []
14072 },
14073
14074
14075 /**
14076 * Internal functions, exposed for used in plug-ins.
14077 *
14078 * Please note that you should not need to use the internal methods for
14079 * anything other than a plug-in (and even then, try to avoid if possible).
14080 * The internal function may change between releases.
14081 *
14082 * @type object
14083 * @default {}
14084 */
14085 internal: {},
14086
14087
14088 /**
14089 * Legacy configuration options. Enable and disable legacy options that
14090 * are available in DataTables.
14091 *
14092 * @type object
14093 */
14094 legacy: {
14095 /**
14096 * Enable / disable DataTables 1.9 compatible server-side processing
14097 * requests
14098 *
14099 * @type boolean
14100 * @default null
14101 */
14102 ajax: null
14103 },
14104
14105
14106 /**
14107 * Pagination plug-in methods.
14108 *
14109 * Each entry in this object is a function and defines which buttons should
14110 * be shown by the pagination rendering method that is used for the table:
14111 * {@link DataTable.ext.renderer.pageButton}. The renderer addresses how the
14112 * buttons are displayed in the document, while the functions here tell it
14113 * what buttons to display. This is done by returning an array of button
14114 * descriptions (what each button will do).
14115 *
14116 * Pagination types (the four built in options and any additional plug-in
14117 * options defined here) can be used through the `paginationType`
14118 * initialisation parameter.
14119 *
14120 * The functions defined take two parameters:
14121 *
14122 * 1. `{int} page` The current page index
14123 * 2. `{int} pages` The number of pages in the table
14124 *
14125 * Each function is expected to return an array where each element of the
14126 * array can be one of:
14127 *
14128 * * `first` - Jump to first page when activated
14129 * * `last` - Jump to last page when activated
14130 * * `previous` - Show previous page when activated
14131 * * `next` - Show next page when activated
14132 * * `{int}` - Show page of the index given
14133 * * `{array}` - A nested array containing the above elements to add a
14134 * containing 'DIV' element (might be useful for styling).
14135 *
14136 * Note that DataTables v1.9- used this object slightly differently whereby
14137 * an object with two functions would be defined for each plug-in. That
14138 * ability is still supported by DataTables 1.10+ to provide backwards
14139 * compatibility, but this option of use is now decremented and no longer
14140 * documented in DataTables 1.10+.
14141 *
14142 * @type object
14143 * @default {}
14144 *
14145 * @example
14146 * // Show previous, next and current page buttons only
14147 * $.fn.dataTableExt.oPagination.current = function ( page, pages ) {
14148 * return [ 'previous', page, 'next' ];
14149 * };
14150 */
14151 pager: {},
14152
14153
14154 renderer: {
14155 pageButton: {},
14156 header: {}
14157 },
14158
14159
14160 /**
14161 * Ordering plug-ins - custom data source
14162 *
14163 * The extension options for ordering of data available here is complimentary
14164 * to the default type based ordering that DataTables typically uses. It
14165 * allows much greater control over the the data that is being used to
14166 * order a column, but is necessarily therefore more complex.
14167 *
14168 * This type of ordering is useful if you want to do ordering based on data
14169 * live from the DOM (for example the contents of an 'input' element) rather
14170 * than just the static string that DataTables knows of.
14171 *
14172 * The way these plug-ins work is that you create an array of the values you
14173 * wish to be ordering for the column in question and then return that
14174 * array. The data in the array much be in the index order of the rows in
14175 * the table (not the currently ordering order!). Which order data gathering
14176 * function is run here depends on the `dt-init columns.orderDataType`
14177 * parameter that is used for the column (if any).
14178 *
14179 * The functions defined take two parameters:
14180 *
14181 * 1. `{object}` DataTables settings object: see
14182 * {@link DataTable.models.oSettings}
14183 * 2. `{int}` Target column index
14184 *
14185 * Each function is expected to return an array:
14186 *
14187 * * `{array}` Data for the column to be ordering upon
14188 *
14189 * @type array
14190 *
14191 * @example
14192 * // Ordering using `input` node values
14193 * $.fn.dataTable.ext.order['dom-text'] = function ( settings, col )
14194 * {
14195 * return this.api().column( col, {order:'index'} ).nodes().map( function ( td, i ) {
14196 * return $('input', td).val();
14197 * } );
14198 * }
14199 */
14200 order: {},
14201
14202
14203 /**
14204 * Type based plug-ins.
14205 *
14206 * Each column in DataTables has a type assigned to it, either by automatic
14207 * detection or by direct assignment using the `type` option for the column.
14208 * The type of a column will effect how it is ordering and search (plug-ins
14209 * can also make use of the column type if required).
14210 *
14211 * @namespace
14212 */
14213 type: {
14214 /**
14215 * Type detection functions.
14216 *
14217 * The functions defined in this object are used to automatically detect
14218 * a column's type, making initialisation of DataTables super easy, even
14219 * when complex data is in the table.
14220 *
14221 * The functions defined take two parameters:
14222 *
14223 * 1. `{*}` Data from the column cell to be analysed
14224 * 2. `{settings}` DataTables settings object. This can be used to
14225 * perform context specific type detection - for example detection
14226 * based on language settings such as using a comma for a decimal
14227 * place. Generally speaking the options from the settings will not
14228 * be required
14229 *
14230 * Each function is expected to return:
14231 *
14232 * * `{string|null}` Data type detected, or null if unknown (and thus
14233 * pass it on to the other type detection functions.
14234 *
14235 * @type array
14236 *
14237 * @example
14238 * // Currency type detection plug-in:
14239 * $.fn.dataTable.ext.type.detect.push(
14240 * function ( data, settings ) {
14241 * // Check the numeric part
14242 * if ( ! data.substring(1).match(/[0-9]/) ) {
14243 * return null;
14244 * }
14245 *
14246 * // Check prefixed by currency
14247 * if ( data.charAt(0) == '$' || data.charAt(0) == '&pound;' ) {
14248 * return 'currency';
14249 * }
14250 * return null;
14251 * }
14252 * );
14253 */
14254 detect: [],
14255
14256
14257 /**
14258 * Type based search formatting.
14259 *
14260 * The type based searching functions can be used to pre-format the
14261 * data to be search on. For example, it can be used to strip HTML
14262 * tags or to de-format telephone numbers for numeric only searching.
14263 *
14264 * Note that is a search is not defined for a column of a given type,
14265 * no search formatting will be performed.
14266 *
14267 * Pre-processing of searching data plug-ins - When you assign the sType
14268 * for a column (or have it automatically detected for you by DataTables
14269 * or a type detection plug-in), you will typically be using this for
14270 * custom sorting, but it can also be used to provide custom searching
14271 * by allowing you to pre-processing the data and returning the data in
14272 * the format that should be searched upon. This is done by adding
14273 * functions this object with a parameter name which matches the sType
14274 * for that target column. This is the corollary of <i>afnSortData</i>
14275 * for searching data.
14276 *
14277 * The functions defined take a single parameter:
14278 *
14279 * 1. `{*}` Data from the column cell to be prepared for searching
14280 *
14281 * Each function is expected to return:
14282 *
14283 * * `{string|null}` Formatted string that will be used for the searching.
14284 *
14285 * @type object
14286 * @default {}
14287 *
14288 * @example
14289 * $.fn.dataTable.ext.type.search['title-numeric'] = function ( d ) {
14290 * return d.replace(/\n/g," ").replace( /<.*?>/g, "" );
14291 * }
14292 */
14293 search: {},
14294
14295
14296 /**
14297 * Type based ordering.
14298 *
14299 * The column type tells DataTables what ordering to apply to the table
14300 * when a column is sorted upon. The order for each type that is defined,
14301 * is defined by the functions available in this object.
14302 *
14303 * Each ordering option can be described by three properties added to
14304 * this object:
14305 *
14306 * * `{type}-pre` - Pre-formatting function
14307 * * `{type}-asc` - Ascending order function
14308 * * `{type}-desc` - Descending order function
14309 *
14310 * All three can be used together, only `{type}-pre` or only
14311 * `{type}-asc` and `{type}-desc` together. It is generally recommended
14312 * that only `{type}-pre` is used, as this provides the optimal
14313 * implementation in terms of speed, although the others are provided
14314 * for compatibility with existing Javascript sort functions.
14315 *
14316 * `{type}-pre`: Functions defined take a single parameter:
14317 *
14318 * 1. `{*}` Data from the column cell to be prepared for ordering
14319 *
14320 * And return:
14321 *
14322 * * `{*}` Data to be sorted upon
14323 *
14324 * `{type}-asc` and `{type}-desc`: Functions are typical Javascript sort
14325 * functions, taking two parameters:
14326 *
14327 * 1. `{*}` Data to compare to the second parameter
14328 * 2. `{*}` Data to compare to the first parameter
14329 *
14330 * And returning:
14331 *
14332 * * `{*}` Ordering match: <0 if first parameter should be sorted lower
14333 * than the second parameter, ===0 if the two parameters are equal and
14334 * >0 if the first parameter should be sorted height than the second
14335 * parameter.
14336 *
14337 * @type object
14338 * @default {}
14339 *
14340 * @example
14341 * // Numeric ordering of formatted numbers with a pre-formatter
14342 * $.extend( $.fn.dataTable.ext.type.order, {
14343 * "string-pre": function(x) {
14344 * a = (a === "-" || a === "") ? 0 : a.replace( /[^\d\-\.]/g, "" );
14345 * return parseFloat( a );
14346 * }
14347 * } );
14348 *
14349 * @example
14350 * // Case-sensitive string ordering, with no pre-formatting method
14351 * $.extend( $.fn.dataTable.ext.order, {
14352 * "string-case-asc": function(x,y) {
14353 * return ((x < y) ? -1 : ((x > y) ? 1 : 0));
14354 * },
14355 * "string-case-desc": function(x,y) {
14356 * return ((x < y) ? 1 : ((x > y) ? -1 : 0));
14357 * }
14358 * } );
14359 */
14360 order: {}
14361 },
14362
14363 /**
14364 * Unique DataTables instance counter
14365 *
14366 * @type int
14367 * @private
14368 */
14369 _unique: 0,
14370
14371
14372 //
14373 // Depreciated
14374 // The following properties are retained for backwards compatiblity only.
14375 // The should not be used in new projects and will be removed in a future
14376 // version
14377 //
14378
14379 /**
14380 * Version check function.
14381 * @type function
14382 * @depreciated Since 1.10
14383 */
14384 fnVersionCheck: DataTable.fnVersionCheck,
14385
14386
14387 /**
14388 * Index for what 'this' index API functions should use
14389 * @type int
14390 * @deprecated Since v1.10
14391 */
14392 iApiIndex: 0,
14393
14394
14395 /**
14396 * jQuery UI class container
14397 * @type object
14398 * @deprecated Since v1.10
14399 */
14400 oJUIClasses: {},
14401
14402
14403 /**
14404 * Software version
14405 * @type string
14406 * @deprecated Since v1.10
14407 */
14408 sVersion: DataTable.version
14409 };
14410
14411
14412 //
14413 // Backwards compatibility. Alias to pre 1.10 Hungarian notation counter parts
14414 //
14415 $.extend( _ext, {
14416 afnFiltering: _ext.search,
14417 aTypes: _ext.type.detect,
14418 ofnSearch: _ext.type.search,
14419 oSort: _ext.type.order,
14420 afnSortData: _ext.order,
14421 aoFeatures: _ext.feature,
14422 oApi: _ext.internal,
14423 oStdClasses: _ext.classes,
14424 oPagination: _ext.pager
14425 } );
14426
14427
14428 $.extend( DataTable.ext.classes, {
14429 "sTable": "dataTable",
14430 "sNoFooter": "no-footer",
14431
14432 /* Paging buttons */
14433 "sPageButton": "paginate_button",
14434 "sPageButtonActive": "current",
14435 "sPageButtonDisabled": "disabled",
14436
14437 /* Striping classes */
14438 "sStripeOdd": "odd",
14439 "sStripeEven": "even",
14440
14441 /* Empty row */
14442 "sRowEmpty": "dataTables_empty",
14443
14444 /* Features */
14445 "sWrapper": "dataTables_wrapper",
14446 "sFilter": "dataTables_filter",
14447 "sInfo": "dataTables_info",
14448 "sPaging": "dataTables_paginate paging_", /* Note that the type is postfixed */
14449 "sLength": "dataTables_length",
14450 "sProcessing": "dataTables_processing",
14451
14452 /* Sorting */
14453 "sSortAsc": "sorting_asc",
14454 "sSortDesc": "sorting_desc",
14455 "sSortable": "sorting", /* Sortable in both directions */
14456 "sSortableAsc": "sorting_asc_disabled",
14457 "sSortableDesc": "sorting_desc_disabled",
14458 "sSortableNone": "sorting_disabled",
14459 "sSortColumn": "sorting_", /* Note that an int is postfixed for the sorting order */
14460
14461 /* Filtering */
14462 "sFilterInput": "",
14463
14464 /* Page length */
14465 "sLengthSelect": "",
14466
14467 /* Scrolling */
14468 "sScrollWrapper": "dataTables_scroll",
14469 "sScrollHead": "dataTables_scrollHead",
14470 "sScrollHeadInner": "dataTables_scrollHeadInner",
14471 "sScrollBody": "dataTables_scrollBody",
14472 "sScrollFoot": "dataTables_scrollFoot",
14473 "sScrollFootInner": "dataTables_scrollFootInner",
14474
14475 /* Misc */
14476 "sHeaderTH": "",
14477 "sFooterTH": "",
14478
14479 // Deprecated
14480 "sSortJUIAsc": "",
14481 "sSortJUIDesc": "",
14482 "sSortJUI": "",
14483 "sSortJUIAscAllowed": "",
14484 "sSortJUIDescAllowed": "",
14485 "sSortJUIWrapper": "",
14486 "sSortIcon": "",
14487 "sJUIHeader": "",
14488 "sJUIFooter": ""
14489 } );
14490
14491
14492 var extPagination = DataTable.ext.pager;
14493
14494 function _numbers ( page, pages ) {
14495 var
14496 numbers = [],
14497 buttons = extPagination.numbers_length,
14498 half = Math.floor( buttons / 2 ),
14499 i = 1;
14500
14501 if ( pages <= buttons ) {
14502 numbers = _range( 0, pages );
14503 }
14504 else if ( page <= half ) {
14505 numbers = _range( 0, buttons-2 );
14506 numbers.push( 'ellipsis' );
14507 numbers.push( pages-1 );
14508 }
14509 else if ( page >= pages - 1 - half ) {
14510 numbers = _range( pages-(buttons-2), pages );
14511 numbers.splice( 0, 0, 'ellipsis' ); // no unshift in ie6
14512 numbers.splice( 0, 0, 0 );
14513 }
14514 else {
14515 numbers = _range( page-half+2, page+half-1 );
14516 numbers.push( 'ellipsis' );
14517 numbers.push( pages-1 );
14518 numbers.splice( 0, 0, 'ellipsis' );
14519 numbers.splice( 0, 0, 0 );
14520 }
14521
14522 numbers.DT_el = 'span';
14523 return numbers;
14524 }
14525
14526
14527 $.extend( extPagination, {
14528 simple: function ( page, pages ) {
14529 return [ 'previous', 'next' ];
14530 },
14531
14532 full: function ( page, pages ) {
14533 return [ 'first', 'previous', 'next', 'last' ];
14534 },
14535
14536 numbers: function ( page, pages ) {
14537 return [ _numbers(page, pages) ];
14538 },
14539
14540 simple_numbers: function ( page, pages ) {
14541 return [ 'previous', _numbers(page, pages), 'next' ];
14542 },
14543
14544 full_numbers: function ( page, pages ) {
14545 return [ 'first', 'previous', _numbers(page, pages), 'next', 'last' ];
14546 },
14547
14548 first_last_numbers: function (page, pages) {
14549 return ['first', _numbers(page, pages), 'last'];
14550 },
14551
14552 // For testing and plug-ins to use
14553 _numbers: _numbers,
14554
14555 // Number of number buttons (including ellipsis) to show. _Must be odd!_
14556 numbers_length: 7
14557 } );
14558
14559
14560 $.extend( true, DataTable.ext.renderer, {
14561 pageButton: {
14562 _: function ( settings, host, idx, buttons, page, pages ) {
14563 var classes = settings.oClasses;
14564 var lang = settings.oLanguage.oPaginate;
14565 var aria = settings.oLanguage.oAria.paginate || {};
14566 var btnDisplay, btnClass, counter=0;
14567
14568 var attach = function( container, buttons ) {
14569 var i, ien, node, button, tabIndex;
14570 var disabledClass = classes.sPageButtonDisabled;
14571 var clickHandler = function ( e ) {
14572 _fnPageChange( settings, e.data.action, true );
14573 };
14574
14575 for ( i=0, ien=buttons.length ; i<ien ; i++ ) {
14576 button = buttons[i];
14577
14578 if ( $.isArray( button ) ) {
14579 var inner = $( '<'+(button.DT_el || 'div')+'/>' )
14580 .appendTo( container );
14581 attach( inner, button );
14582 }
14583 else {
14584 btnDisplay = null;
14585 btnClass = button;
14586 tabIndex = settings.iTabIndex;
14587
14588 switch ( button ) {
14589 case 'ellipsis':
14590 container.append('<span class="ellipsis">&#x2026;</span>');
14591 break;
14592
14593 case 'first':
14594 btnDisplay = lang.sFirst;
14595
14596 if ( page === 0 ) {
14597 tabIndex = -1;
14598 btnClass += ' ' + disabledClass;
14599 }
14600 break;
14601
14602 case 'previous':
14603 btnDisplay = lang.sPrevious;
14604
14605 if ( page === 0 ) {
14606 tabIndex = -1;
14607 btnClass += ' ' + disabledClass;
14608 }
14609 break;
14610
14611 case 'next':
14612 btnDisplay = lang.sNext;
14613
14614 if ( pages === 0 || page === pages-1 ) {
14615 tabIndex = -1;
14616 btnClass += ' ' + disabledClass;
14617 }
14618 break;
14619
14620 case 'last':
14621 btnDisplay = lang.sLast;
14622
14623 if ( page === pages-1 ) {
14624 tabIndex = -1;
14625 btnClass += ' ' + disabledClass;
14626 }
14627 break;
14628
14629 default:
14630 btnDisplay = button + 1;
14631 btnClass = page === button ?
14632 classes.sPageButtonActive : '';
14633 break;
14634 }
14635
14636 if ( btnDisplay !== null ) {
14637 node = $('<a>', {
14638 'class': classes.sPageButton+' '+btnClass,
14639 'aria-controls': settings.sTableId,
14640 'aria-label': aria[ button ],
14641 'data-dt-idx': counter,
14642 'tabindex': tabIndex,
14643 'id': idx === 0 && typeof button === 'string' ?
14644 settings.sTableId +'_'+ button :
14645 null
14646 } )
14647 .html( btnDisplay )
14648 .appendTo( container );
14649
14650 _fnBindAction(
14651 node, {action: button}, clickHandler
14652 );
14653
14654 counter++;
14655 }
14656 }
14657 }
14658 };
14659
14660 // IE9 throws an 'unknown error' if document.activeElement is used
14661 // inside an iframe or frame. Try / catch the error. Not good for
14662 // accessibility, but neither are frames.
14663 var activeEl;
14664
14665 try {
14666 // Because this approach is destroying and recreating the paging
14667 // elements, focus is lost on the select button which is bad for
14668 // accessibility. So we want to restore focus once the draw has
14669 // completed
14670 activeEl = $(host).find(document.activeElement).data('dt-idx');
14671 }
14672 catch (e) {}
14673
14674 attach( $(host).empty(), buttons );
14675
14676 if ( activeEl !== undefined ) {
14677 $(host).find( '[data-dt-idx='+activeEl+']' ).trigger('focus');
14678 }
14679 }
14680 }
14681 } );
14682
14683
14684
14685 // Built in type detection. See model.ext.aTypes for information about
14686 // what is required from this methods.
14687 $.extend( DataTable.ext.type.detect, [
14688 // Plain numbers - first since V8 detects some plain numbers as dates
14689 // e.g. Date.parse('55') (but not all, e.g. Date.parse('22')...).
14690 function ( d, settings )
14691 {
14692 var decimal = settings.oLanguage.sDecimal;
14693 return _isNumber( d, decimal ) ? 'num'+decimal : null;
14694 },
14695
14696 // Dates (only those recognised by the browser's Date.parse)
14697 function ( d, settings )
14698 {
14699 // V8 tries _very_ hard to make a string passed into `Date.parse()`
14700 // valid, so we need to use a regex to restrict date formats. Use a
14701 // plug-in for anything other than ISO8601 style strings
14702 if ( d && !(d instanceof Date) && ! _re_date.test(d) ) {
14703 return null;
14704 }
14705 var parsed = Date.parse(d);
14706 return (parsed !== null && !isNaN(parsed)) || _empty(d) ? 'date' : null;
14707 },
14708
14709 // Formatted numbers
14710 function ( d, settings )
14711 {
14712 var decimal = settings.oLanguage.sDecimal;
14713 return _isNumber( d, decimal, true ) ? 'num-fmt'+decimal : null;
14714 },
14715
14716 // HTML numeric
14717 function ( d, settings )
14718 {
14719 var decimal = settings.oLanguage.sDecimal;
14720 return _htmlNumeric( d, decimal ) ? 'html-num'+decimal : null;
14721 },
14722
14723 // HTML numeric, formatted
14724 function ( d, settings )
14725 {
14726 var decimal = settings.oLanguage.sDecimal;
14727 return _htmlNumeric( d, decimal, true ) ? 'html-num-fmt'+decimal : null;
14728 },
14729
14730 // HTML (this is strict checking - there must be html)
14731 function ( d, settings )
14732 {
14733 return _empty( d ) || (typeof d === 'string' && d.indexOf('<') !== -1) ?
14734 'html' : null;
14735 }
14736 ] );
14737
14738
14739
14740 // Filter formatting functions. See model.ext.ofnSearch for information about
14741 // what is required from these methods.
14742 //
14743 // Note that additional search methods are added for the html numbers and
14744 // html formatted numbers by `_addNumericSort()` when we know what the decimal
14745 // place is
14746
14747
14748 $.extend( DataTable.ext.type.search, {
14749 html: function ( data ) {
14750 return _empty(data) ?
14751 data :
14752 typeof data === 'string' ?
14753 data
14754 .replace( _re_new_lines, " " )
14755 .replace( _re_html, "" ) :
14756 '';
14757 },
14758
14759 string: function ( data ) {
14760 return _empty(data) ?
14761 data :
14762 typeof data === 'string' ?
14763 data.replace( _re_new_lines, " " ) :
14764 data;
14765 }
14766 } );
14767
14768
14769
14770 var __numericReplace = function ( d, decimalPlace, re1, re2 ) {
14771 if ( d !== 0 && (!d || d === '-') ) {
14772 return -Infinity;
14773 }
14774
14775 // If a decimal place other than `.` is used, it needs to be given to the
14776 // function so we can detect it and replace with a `.` which is the only
14777 // decimal place Javascript recognises - it is not locale aware.
14778 if ( decimalPlace ) {
14779 d = _numToDecimal( d, decimalPlace );
14780 }
14781
14782 if ( d.replace ) {
14783 if ( re1 ) {
14784 d = d.replace( re1, '' );
14785 }
14786
14787 if ( re2 ) {
14788 d = d.replace( re2, '' );
14789 }
14790 }
14791
14792 return d * 1;
14793 };
14794
14795
14796 // Add the numeric 'deformatting' functions for sorting and search. This is done
14797 // in a function to provide an easy ability for the language options to add
14798 // additional methods if a non-period decimal place is used.
14799 function _addNumericSort ( decimalPlace ) {
14800 $.each(
14801 {
14802 // Plain numbers
14803 "num": function ( d ) {
14804 return __numericReplace( d, decimalPlace );
14805 },
14806
14807 // Formatted numbers
14808 "num-fmt": function ( d ) {
14809 return __numericReplace( d, decimalPlace, _re_formatted_numeric );
14810 },
14811
14812 // HTML numeric
14813 "html-num": function ( d ) {
14814 return __numericReplace( d, decimalPlace, _re_html );
14815 },
14816
14817 // HTML numeric, formatted
14818 "html-num-fmt": function ( d ) {
14819 return __numericReplace( d, decimalPlace, _re_html, _re_formatted_numeric );
14820 }
14821 },
14822 function ( key, fn ) {
14823 // Add the ordering method
14824 _ext.type.order[ key+decimalPlace+'-pre' ] = fn;
14825
14826 // For HTML types add a search formatter that will strip the HTML
14827 if ( key.match(/^html\-/) ) {
14828 _ext.type.search[ key+decimalPlace ] = _ext.type.search.html;
14829 }
14830 }
14831 );
14832 }
14833
14834
14835 // Default sort methods
14836 $.extend( _ext.type.order, {
14837 // Dates
14838 "date-pre": function ( d ) {
14839 var ts = Date.parse( d );
14840 return isNaN(ts) ? -Infinity : ts;
14841 },
14842
14843 // html
14844 "html-pre": function ( a ) {
14845 return _empty(a) ?
14846 '' :
14847 a.replace ?
14848 a.replace( /<.*?>/g, "" ).toLowerCase() :
14849 a+'';
14850 },
14851
14852 // string
14853 "string-pre": function ( a ) {
14854 // This is a little complex, but faster than always calling toString,
14855 // http://jsperf.com/tostring-v-check
14856 return _empty(a) ?
14857 '' :
14858 typeof a === 'string' ?
14859 a.toLowerCase() :
14860 ! a.toString ?
14861 '' :
14862 a.toString();
14863 },
14864
14865 // string-asc and -desc are retained only for compatibility with the old
14866 // sort methods
14867 "string-asc": function ( x, y ) {
14868 return ((x < y) ? -1 : ((x > y) ? 1 : 0));
14869 },
14870
14871 "string-desc": function ( x, y ) {
14872 return ((x < y) ? 1 : ((x > y) ? -1 : 0));
14873 }
14874 } );
14875
14876
14877 // Numeric sorting types - order doesn't matter here
14878 _addNumericSort( '' );
14879
14880
14881 $.extend( true, DataTable.ext.renderer, {
14882 header: {
14883 _: function ( settings, cell, column, classes ) {
14884 // No additional mark-up required
14885 // Attach a sort listener to update on sort - note that using the
14886 // `DT` namespace will allow the event to be removed automatically
14887 // on destroy, while the `dt` namespaced event is the one we are
14888 // listening for
14889 $(settings.nTable).on( 'order.dt.DT', function ( e, ctx, sorting, columns ) {
14890 if ( settings !== ctx ) { // need to check this this is the host
14891 return; // table, not a nested one
14892 }
14893
14894 var colIdx = column.idx;
14895
14896 cell
14897 .removeClass(
14898 column.sSortingClass +' '+
14899 classes.sSortAsc +' '+
14900 classes.sSortDesc
14901 )
14902 .addClass( columns[ colIdx ] == 'asc' ?
14903 classes.sSortAsc : columns[ colIdx ] == 'desc' ?
14904 classes.sSortDesc :
14905 column.sSortingClass
14906 );
14907 } );
14908 },
14909
14910 jqueryui: function ( settings, cell, column, classes ) {
14911 $('<div/>')
14912 .addClass( classes.sSortJUIWrapper )
14913 .append( cell.contents() )
14914 .append( $('<span/>')
14915 .addClass( classes.sSortIcon+' '+column.sSortingClassJUI )
14916 )
14917 .appendTo( cell );
14918
14919 // Attach a sort listener to update on sort
14920 $(settings.nTable).on( 'order.dt.DT', function ( e, ctx, sorting, columns ) {
14921 if ( settings !== ctx ) {
14922 return;
14923 }
14924
14925 var colIdx = column.idx;
14926
14927 cell
14928 .removeClass( classes.sSortAsc +" "+classes.sSortDesc )
14929 .addClass( columns[ colIdx ] == 'asc' ?
14930 classes.sSortAsc : columns[ colIdx ] == 'desc' ?
14931 classes.sSortDesc :
14932 column.sSortingClass
14933 );
14934
14935 cell
14936 .find( 'span.'+classes.sSortIcon )
14937 .removeClass(
14938 classes.sSortJUIAsc +" "+
14939 classes.sSortJUIDesc +" "+
14940 classes.sSortJUI +" "+
14941 classes.sSortJUIAscAllowed +" "+
14942 classes.sSortJUIDescAllowed
14943 )
14944 .addClass( columns[ colIdx ] == 'asc' ?
14945 classes.sSortJUIAsc : columns[ colIdx ] == 'desc' ?
14946 classes.sSortJUIDesc :
14947 column.sSortingClassJUI
14948 );
14949 } );
14950 }
14951 }
14952 } );
14953
14954 /*
14955 * Public helper functions. These aren't used internally by DataTables, or
14956 * called by any of the options passed into DataTables, but they can be used
14957 * externally by developers working with DataTables. They are helper functions
14958 * to make working with DataTables a little bit easier.
14959 */
14960
14961 var __htmlEscapeEntities = function ( d ) {
14962 return typeof d === 'string' ?
14963 d
14964 .replace(/&/g, '&amp;')
14965 .replace(/</g, '&lt;')
14966 .replace(/>/g, '&gt;')
14967 .replace(/"/g, '&quot;') :
14968 d;
14969 };
14970
14971 /**
14972 * Helpers for `columns.render`.
14973 *
14974 * The options defined here can be used with the `columns.render` initialisation
14975 * option to provide a display renderer. The following functions are defined:
14976 *
14977 * * `number` - Will format numeric data (defined by `columns.data`) for
14978 * display, retaining the original unformatted data for sorting and filtering.
14979 * It takes 5 parameters:
14980 * * `string` - Thousands grouping separator
14981 * * `string` - Decimal point indicator
14982 * * `integer` - Number of decimal points to show
14983 * * `string` (optional) - Prefix.
14984 * * `string` (optional) - Postfix (/suffix).
14985 * * `text` - Escape HTML to help prevent XSS attacks. It has no optional
14986 * parameters.
14987 *
14988 * @example
14989 * // Column definition using the number renderer
14990 * {
14991 * data: "salary",
14992 * render: $.fn.dataTable.render.number( '\'', '.', 0, '$' )
14993 * }
14994 *
14995 * @namespace
14996 */
14997 DataTable.render = {
14998 number: function ( thousands, decimal, precision, prefix, postfix ) {
14999 return {
15000 display: function ( d ) {
15001 if ( typeof d !== 'number' && typeof d !== 'string' ) {
15002 return d;
15003 }
15004
15005 var negative = d < 0 ? '-' : '';
15006 var flo = parseFloat( d );
15007
15008 // If NaN then there isn't much formatting that we can do - just
15009 // return immediately, escaping any HTML (this was supposed to
15010 // be a number after all)
15011 if ( isNaN( flo ) ) {
15012 return __htmlEscapeEntities( d );
15013 }
15014
15015 flo = flo.toFixed( precision );
15016 d = Math.abs( flo );
15017
15018 var intPart = parseInt( d, 10 );
15019 var floatPart = precision ?
15020 decimal+(d - intPart).toFixed( precision ).substring( 2 ):
15021 '';
15022
15023 return negative + (prefix||'') +
15024 intPart.toString().replace(
15025 /\B(?=(\d{3})+(?!\d))/g, thousands
15026 ) +
15027 floatPart +
15028 (postfix||'');
15029 }
15030 };
15031 },
15032
15033 text: function () {
15034 return {
15035 display: __htmlEscapeEntities,
15036 filter: __htmlEscapeEntities
15037 };
15038 }
15039 };
15040
15041
15042 /*
15043 * This is really a good bit rubbish this method of exposing the internal methods
15044 * publicly... - To be fixed in 2.0 using methods on the prototype
15045 */
15046
15047
15048 /**
15049 * Create a wrapper function for exporting an internal functions to an external API.
15050 * @param {string} fn API function name
15051 * @returns {function} wrapped function
15052 * @memberof DataTable#internal
15053 */
15054 function _fnExternApiFunc (fn)
15055 {
15056 return function() {
15057 var args = [_fnSettingsFromNode( this[DataTable.ext.iApiIndex] )].concat(
15058 Array.prototype.slice.call(arguments)
15059 );
15060 return DataTable.ext.internal[fn].apply( this, args );
15061 };
15062 }
15063
15064
15065 /**
15066 * Reference to internal functions for use by plug-in developers. Note that
15067 * these methods are references to internal functions and are considered to be
15068 * private. If you use these methods, be aware that they are liable to change
15069 * between versions.
15070 * @namespace
15071 */
15072 $.extend( DataTable.ext.internal, {
15073 _fnExternApiFunc: _fnExternApiFunc,
15074 _fnBuildAjax: _fnBuildAjax,
15075 _fnAjaxUpdate: _fnAjaxUpdate,
15076 _fnAjaxParameters: _fnAjaxParameters,
15077 _fnAjaxUpdateDraw: _fnAjaxUpdateDraw,
15078 _fnAjaxDataSrc: _fnAjaxDataSrc,
15079 _fnAddColumn: _fnAddColumn,
15080 _fnColumnOptions: _fnColumnOptions,
15081 _fnAdjustColumnSizing: _fnAdjustColumnSizing,
15082 _fnVisibleToColumnIndex: _fnVisibleToColumnIndex,
15083 _fnColumnIndexToVisible: _fnColumnIndexToVisible,
15084 _fnVisbleColumns: _fnVisbleColumns,
15085 _fnGetColumns: _fnGetColumns,
15086 _fnColumnTypes: _fnColumnTypes,
15087 _fnApplyColumnDefs: _fnApplyColumnDefs,
15088 _fnHungarianMap: _fnHungarianMap,
15089 _fnCamelToHungarian: _fnCamelToHungarian,
15090 _fnLanguageCompat: _fnLanguageCompat,
15091 _fnBrowserDetect: _fnBrowserDetect,
15092 _fnAddData: _fnAddData,
15093 _fnAddTr: _fnAddTr,
15094 _fnNodeToDataIndex: _fnNodeToDataIndex,
15095 _fnNodeToColumnIndex: _fnNodeToColumnIndex,
15096 _fnGetCellData: _fnGetCellData,
15097 _fnSetCellData: _fnSetCellData,
15098 _fnSplitObjNotation: _fnSplitObjNotation,
15099 _fnGetObjectDataFn: _fnGetObjectDataFn,
15100 _fnSetObjectDataFn: _fnSetObjectDataFn,
15101 _fnGetDataMaster: _fnGetDataMaster,
15102 _fnClearTable: _fnClearTable,
15103 _fnDeleteIndex: _fnDeleteIndex,
15104 _fnInvalidate: _fnInvalidate,
15105 _fnGetRowElements: _fnGetRowElements,
15106 _fnCreateTr: _fnCreateTr,
15107 _fnBuildHead: _fnBuildHead,
15108 _fnDrawHead: _fnDrawHead,
15109 _fnDraw: _fnDraw,
15110 _fnReDraw: _fnReDraw,
15111 _fnAddOptionsHtml: _fnAddOptionsHtml,
15112 _fnDetectHeader: _fnDetectHeader,
15113 _fnGetUniqueThs: _fnGetUniqueThs,
15114 _fnFeatureHtmlFilter: _fnFeatureHtmlFilter,
15115 _fnFilterComplete: _fnFilterComplete,
15116 _fnFilterCustom: _fnFilterCustom,
15117 _fnFilterColumn: _fnFilterColumn,
15118 _fnFilter: _fnFilter,
15119 _fnFilterCreateSearch: _fnFilterCreateSearch,
15120 _fnEscapeRegex: _fnEscapeRegex,
15121 _fnFilterData: _fnFilterData,
15122 _fnFeatureHtmlInfo: _fnFeatureHtmlInfo,
15123 _fnUpdateInfo: _fnUpdateInfo,
15124 _fnInfoMacros: _fnInfoMacros,
15125 _fnInitialise: _fnInitialise,
15126 _fnInitComplete: _fnInitComplete,
15127 _fnLengthChange: _fnLengthChange,
15128 _fnFeatureHtmlLength: _fnFeatureHtmlLength,
15129 _fnFeatureHtmlPaginate: _fnFeatureHtmlPaginate,
15130 _fnPageChange: _fnPageChange,
15131 _fnFeatureHtmlProcessing: _fnFeatureHtmlProcessing,
15132 _fnProcessingDisplay: _fnProcessingDisplay,
15133 _fnFeatureHtmlTable: _fnFeatureHtmlTable,
15134 _fnScrollDraw: _fnScrollDraw,
15135 _fnApplyToChildren: _fnApplyToChildren,
15136 _fnCalculateColumnWidths: _fnCalculateColumnWidths,
15137 _fnThrottle: _fnThrottle,
15138 _fnConvertToWidth: _fnConvertToWidth,
15139 _fnGetWidestNode: _fnGetWidestNode,
15140 _fnGetMaxLenString: _fnGetMaxLenString,
15141 _fnStringToCss: _fnStringToCss,
15142 _fnSortFlatten: _fnSortFlatten,
15143 _fnSort: _fnSort,
15144 _fnSortAria: _fnSortAria,
15145 _fnSortListener: _fnSortListener,
15146 _fnSortAttachListener: _fnSortAttachListener,
15147 _fnSortingClasses: _fnSortingClasses,
15148 _fnSortData: _fnSortData,
15149 _fnSaveState: _fnSaveState,
15150 _fnLoadState: _fnLoadState,
15151 _fnSettingsFromNode: _fnSettingsFromNode,
15152 _fnLog: _fnLog,
15153 _fnMap: _fnMap,
15154 _fnBindAction: _fnBindAction,
15155 _fnCallbackReg: _fnCallbackReg,
15156 _fnCallbackFire: _fnCallbackFire,
15157 _fnLengthOverflow: _fnLengthOverflow,
15158 _fnRenderer: _fnRenderer,
15159 _fnDataSource: _fnDataSource,
15160 _fnRowAttributes: _fnRowAttributes,
15161 _fnExtend: _fnExtend,
15162 _fnCalculateEnd: function () {} // Used by a lot of plug-ins, but redundant
15163 // in 1.10, so this dead-end function is
15164 // added to prevent errors
15165 } );
15166
15167
15168 // jQuery access
15169 $.fn.dataTable = DataTable;
15170
15171 // Provide access to the host jQuery object (circular reference)
15172 DataTable.$ = $;
15173
15174 // Legacy aliases
15175 $.fn.dataTableSettings = DataTable.settings;
15176 $.fn.dataTableExt = DataTable.ext;
15177
15178 // With a capital `D` we return a DataTables API instance rather than a
15179 // jQuery object
15180 $.fn.DataTable = function ( opts ) {
15181 return $(this).dataTable( opts ).api();
15182 };
15183
15184 // All properties that are available to $.fn.dataTable should also be
15185 // available on $.fn.DataTable
15186 $.each( DataTable, function ( prop, val ) {
15187 $.fn.DataTable[ prop ] = val;
15188 } );
15189
15190
15191 // Information about events fired by DataTables - for documentation.
15192 /**
15193 * Draw event, fired whenever the table is redrawn on the page, at the same
15194 * point as fnDrawCallback. This may be useful for binding events or
15195 * performing calculations when the table is altered at all.
15196 * @name DataTable#draw.dt
15197 * @event
15198 * @param {event} e jQuery event object
15199 * @param {object} o DataTables settings object {@link DataTable.models.oSettings}
15200 */
15201
15202 /**
15203 * Search event, fired when the searching applied to the table (using the
15204 * built-in global search, or column filters) is altered.
15205 * @name DataTable#search.dt
15206 * @event
15207 * @param {event} e jQuery event object
15208 * @param {object} o DataTables settings object {@link DataTable.models.oSettings}
15209 */
15210
15211 /**
15212 * Page change event, fired when the paging of the table is altered.
15213 * @name DataTable#page.dt
15214 * @event
15215 * @param {event} e jQuery event object
15216 * @param {object} o DataTables settings object {@link DataTable.models.oSettings}
15217 */
15218
15219 /**
15220 * Order event, fired when the ordering applied to the table is altered.
15221 * @name DataTable#order.dt
15222 * @event
15223 * @param {event} e jQuery event object
15224 * @param {object} o DataTables settings object {@link DataTable.models.oSettings}
15225 */
15226
15227 /**
15228 * DataTables initialisation complete event, fired when the table is fully
15229 * drawn, including Ajax data loaded, if Ajax data is required.
15230 * @name DataTable#init.dt
15231 * @event
15232 * @param {event} e jQuery event object
15233 * @param {object} oSettings DataTables settings object
15234 * @param {object} json The JSON object request from the server - only
15235 * present if client-side Ajax sourced data is used</li></ol>
15236 */
15237
15238 /**
15239 * State save event, fired when the table has changed state a new state save
15240 * is required. This event allows modification of the state saving object
15241 * prior to actually doing the save, including addition or other state
15242 * properties (for plug-ins) or modification of a DataTables core property.
15243 * @name DataTable#stateSaveParams.dt
15244 * @event
15245 * @param {event} e jQuery event object
15246 * @param {object} oSettings DataTables settings object
15247 * @param {object} json The state information to be saved
15248 */
15249
15250 /**
15251 * State load event, fired when the table is loading state from the stored
15252 * data, but prior to the settings object being modified by the saved state
15253 * - allowing modification of the saved state is required or loading of
15254 * state for a plug-in.
15255 * @name DataTable#stateLoadParams.dt
15256 * @event
15257 * @param {event} e jQuery event object
15258 * @param {object} oSettings DataTables settings object
15259 * @param {object} json The saved state information
15260 */
15261
15262 /**
15263 * State loaded event, fired when state has been loaded from stored data and
15264 * the settings object has been modified by the loaded data.
15265 * @name DataTable#stateLoaded.dt
15266 * @event
15267 * @param {event} e jQuery event object
15268 * @param {object} oSettings DataTables settings object
15269 * @param {object} json The saved state information
15270 */
15271
15272 /**
15273 * Processing event, fired when DataTables is doing some kind of processing
15274 * (be it, order, search or anything else). It can be used to indicate to
15275 * the end user that there is something happening, or that something has
15276 * finished.
15277 * @name DataTable#processing.dt
15278 * @event
15279 * @param {event} e jQuery event object
15280 * @param {object} oSettings DataTables settings object
15281 * @param {boolean} bShow Flag for if DataTables is doing processing or not
15282 */
15283
15284 /**
15285 * Ajax (XHR) event, fired whenever an Ajax request is completed from a
15286 * request to made to the server for new data. This event is called before
15287 * DataTables processed the returned data, so it can also be used to pre-
15288 * process the data returned from the server, if needed.
15289 *
15290 * Note that this trigger is called in `fnServerData`, if you override
15291 * `fnServerData` and which to use this event, you need to trigger it in you
15292 * success function.
15293 * @name DataTable#xhr.dt
15294 * @event
15295 * @param {event} e jQuery event object
15296 * @param {object} o DataTables settings object {@link DataTable.models.oSettings}
15297 * @param {object} json JSON returned from the server
15298 *
15299 * @example
15300 * // Use a custom property returned from the server in another DOM element
15301 * $('#table').dataTable().on('xhr.dt', function (e, settings, json) {
15302 * $('#status').html( json.status );
15303 * } );
15304 *
15305 * @example
15306 * // Pre-process the data returned from the server
15307 * $('#table').dataTable().on('xhr.dt', function (e, settings, json) {
15308 * for ( var i=0, ien=json.aaData.length ; i<ien ; i++ ) {
15309 * json.aaData[i].sum = json.aaData[i].one + json.aaData[i].two;
15310 * }
15311 * // Note no return - manipulate the data directly in the JSON object.
15312 * } );
15313 */
15314
15315 /**
15316 * Destroy event, fired when the DataTable is destroyed by calling fnDestroy
15317 * or passing the bDestroy:true parameter in the initialisation object. This
15318 * can be used to remove bound events, added DOM nodes, etc.
15319 * @name DataTable#destroy.dt
15320 * @event
15321 * @param {event} e jQuery event object
15322 * @param {object} o DataTables settings object {@link DataTable.models.oSettings}
15323 */
15324
15325 /**
15326 * Page length change event, fired when number of records to show on each
15327 * page (the length) is changed.
15328 * @name DataTable#length.dt
15329 * @event
15330 * @param {event} e jQuery event object
15331 * @param {object} o DataTables settings object {@link DataTable.models.oSettings}
15332 * @param {integer} len New length
15333 */
15334
15335 /**
15336 * Column sizing has changed.
15337 * @name DataTable#column-sizing.dt
15338 * @event
15339 * @param {event} e jQuery event object
15340 * @param {object} o DataTables settings object {@link DataTable.models.oSettings}
15341 */
15342
15343 /**
15344 * Column visibility has changed.
15345 * @name DataTable#column-visibility.dt
15346 * @event
15347 * @param {event} e jQuery event object
15348 * @param {object} o DataTables settings object {@link DataTable.models.oSettings}
15349 * @param {int} column Column index
15350 * @param {bool} vis `false` if column now hidden, or `true` if visible
15351 */
15352
15353 return $.fn.dataTable;
15354 }));