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