PluginProbe
SupportCandy – AI Customer Support Ticket System & Live Chatbot Agent / 2.3.1
SupportCandy – AI Customer Support Ticket System & Live Chatbot Agent v2.3.1
3.5.4 3.5.3 3.5.2 3.5.1 3.4.9 3.5.0 3.4.8 3.4.7 trunk 2.3.1 3.3.6 3.3.7 3.3.8 3.3.9 3.4.0 3.4.1 3.4.2 3.4.3 3.4.4 3.4.5 3.4.6
supportcandy / asset / lib / DataTables / datatables.js

datatables.js in SupportCandy – AI Customer Support Ticket System & Live Chatbot Agent 2.3.1, at asset/lib/DataTables/datatables.js

15,258 lines 435.7 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 /*
2 * This combined file was created by the DataTables downloader builder:
3 * https://datatables.net/download
4 *
5 * To rebuild or modify this file with the latest versions of the included
6 * software please visit:
7 * https://datatables.net/download/#dt/dt-1.10.16
8 *
9 * Included libraries:
10 * DataTables 1.10.16
11 */
12
13 /*! DataTables 1.10.16
14 * ©2008-2017 SpryMedia Ltd - datatables.net/license
15 */
16
17 /**
18 * @summary DataTables
19 * @description Paginate, search and order HTML tables
20 * @version 1.10.16
21 * @file jquery.dataTables.js
22 * @author SpryMedia Ltd
23 * @contact www.datatables.net
24 * @copyright Copyright 2008-2017 SpryMedia Ltd.
25 *
26 * This source file is free software, available under the following license:
27 * MIT license - http://datatables.net/license
28 *
29 * This source file is distributed in the hope that it will be useful, but
30 * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
31 * or FITNESS FOR A PARTICULAR PURPOSE. See the license files for details.
32 *
33 * For details please refer to: http://www.datatables.net
34 */
35
36 /*jslint evil: true, undef: true, browser: true */
37 /*globals $,require,jQuery,define,_selector_run,_selector_opts,_selector_first,_selector_row_indexes,_ext,_Api,_api_register,_api_registerPlural,_re_new_lines,_re_html,_re_formatted_numeric,_re_escape_regex,_empty,_intVal,_numToDecimal,_isNumber,_isHtml,_htmlNumeric,_pluck,_pluck_order,_range,_stripHtml,_unique,_fnBuildAjax,_fnAjaxUpdate,_fnAjaxParameters,_fnAjaxUpdateDraw,_fnAjaxDataSrc,_fnAddColumn,_fnColumnOptions,_fnAdjustColumnSizing,_fnVisibleToColumnIndex,_fnColumnIndexToVisible,_fnVisbleColumns,_fnGetColumns,_fnColumnTypes,_fnApplyColumnDefs,_fnHungarianMap,_fnCamelToHungarian,_fnLanguageCompat,_fnBrowserDetect,_fnAddData,_fnAddTr,_fnNodeToDataIndex,_fnNodeToColumnIndex,_fnGetCellData,_fnSetCellData,_fnSplitObjNotation,_fnGetObjectDataFn,_fnSetObjectDataFn,_fnGetDataMaster,_fnClearTable,_fnDeleteIndex,_fnInvalidate,_fnGetRowElements,_fnCreateTr,_fnBuildHead,_fnDrawHead,_fnDraw,_fnReDraw,_fnAddOptionsHtml,_fnDetectHeader,_fnGetUniqueThs,_fnFeatureHtmlFilter,_fnFilterComplete,_fnFilterCustom,_fnFilterColumn,_fnFilter,_fnFilterCreateSearch,_fnEscapeRegex,_fnFilterData,_fnFeatureHtmlInfo,_fnUpdateInfo,_fnInfoMacros,_fnInitialise,_fnInitComplete,_fnLengthChange,_fnFeatureHtmlLength,_fnFeatureHtmlPaginate,_fnPageChange,_fnFeatureHtmlProcessing,_fnProcessingDisplay,_fnFeatureHtmlTable,_fnScrollDraw,_fnApplyToChildren,_fnCalculateColumnWidths,_fnThrottle,_fnConvertToWidth,_fnGetWidestNode,_fnGetMaxLenString,_fnStringToCss,_fnSortFlatten,_fnSort,_fnSortAria,_fnSortListener,_fnSortAttachListener,_fnSortingClasses,_fnSortData,_fnSaveState,_fnLoadState,_fnSettingsFromNode,_fnLog,_fnMap,_fnBindAction,_fnCallbackReg,_fnCallbackFire,_fnLengthOverflow,_fnRenderer,_fnDataSource,_fnRowAttributes*/
38
39 (function( factory ) {
40 "use strict";
41
42 if ( typeof define === 'function' && define.amd ) {
43 // AMD
44 define( ['jquery'], function ( $ ) {
45 return factory( $, window, document );
46 } );
47 }
48 else if ( typeof exports === 'object' ) {
49 // CommonJS
50 module.exports = function (root, $) {
51 if ( ! root ) {
52 // CommonJS environments without a window global must pass a
53 // root. This will give an error otherwise
54 root = window;
55 }
56
57 if ( ! $ ) {
58 $ = typeof window !== 'undefined' ? // jQuery's factory checks for a global window
59 require('jquery') :
60 require('jquery')( root );
61 }
62
63 return factory( $, root, root.document );
64 };
65 }
66 else {
67 // Browser
68 factory( jQuery, window, document );
69 }
70 }
71 (function( $, window, document, undefined ) {
72 "use strict";
73
74 /**
75 * DataTables is a plug-in for the jQuery Javascript library. It is a highly
76 * flexible tool, based upon the foundations of progressive enhancement,
77 * which will add advanced interaction controls to any HTML table. For a
78 * full list of features please refer to
79 * [DataTables.net](href="http://datatables.net).
80 *
81 * Note that the `DataTable` object is not a global variable but is aliased
82 * to `jQuery.fn.DataTable` and `jQuery.fn.dataTable` through which it may
83 * be accessed.
84 *
85 * @class
86 * @param {object} [init={}] Configuration object for DataTables. Options
87 * are defined by {@link DataTable.defaults}
88 * @requires jQuery 1.7+
89 *
90 * @example
91 * // Basic initialisation
92 * $(document).ready( function {
93 * $('#example').dataTable();
94 * } );
95 *
96 * @example
97 * // Initialisation with configuration options - in this case, disable
98 * // pagination and sorting.
99 * $(document).ready( function {
100 * $('#example').dataTable( {
101 * "paginate": false,
102 * "sort": false
103 * } );
104 * } );
105 */
106 var DataTable = function ( options )
107 {
108 /**
109 * Perform a jQuery selector action on the table's TR elements (from the tbody) and
110 * return the resulting jQuery object.
111 * @param {string|node|jQuery} sSelector jQuery selector or node collection to act on
112 * @param {object} [oOpts] Optional parameters for modifying the rows to be included
113 * @param {string} [oOpts.filter=none] Select TR elements that meet the current filter
114 * criterion ("applied") or all TR elements (i.e. no filter).
115 * @param {string} [oOpts.order=current] Order of the TR elements in the processed array.
116 * Can be either 'current', whereby the current sorting of the table is used, or
117 * 'original' whereby the original order the data was read into the table is used.
118 * @param {string} [oOpts.page=all] Limit the selection to the currently displayed page
119 * ("current") or not ("all"). If 'current' is given, then order is assumed to be
120 * 'current' and filter is 'applied', regardless of what they might be given as.
121 * @returns {object} jQuery object, filtered by the given selector.
122 * @dtopt API
123 * @deprecated Since v1.10
124 *
125 * @example
126 * $(document).ready(function() {
127 * var oTable = $('#example').dataTable();
128 *
129 * // Highlight every second row
130 * oTable.$('tr:odd').css('backgroundColor', 'blue');
131 * } );
132 *
133 * @example
134 * $(document).ready(function() {
135 * var oTable = $('#example').dataTable();
136 *
137 * // Filter to rows with 'Webkit' in them, add a background colour and then
138 * // remove the filter, thus highlighting the 'Webkit' rows only.
139 * oTable.fnFilter('Webkit');
140 * oTable.$('tr', {"search": "applied"}).css('backgroundColor', 'blue');
141 * oTable.fnFilter('');
142 * } );
143 */
144 this.$ = function ( sSelector, oOpts )
145 {
146 return this.api(true).$( sSelector, oOpts );
147 };
148
149
150 /**
151 * Almost identical to $ in operation, but in this case returns the data for the matched
152 * rows - as such, the jQuery selector used should match TR row nodes or TD/TH cell nodes
153 * rather than any descendants, so the data can be obtained for the row/cell. If matching
154 * rows are found, the data returned is the original data array/object that was used to
155 * create the row (or a generated array if from a DOM source).
156 *
157 * This method is often useful in-combination with $ where both functions are given the
158 * same parameters and the array indexes will match identically.
159 * @param {string|node|jQuery} sSelector jQuery selector or node collection to act on
160 * @param {object} [oOpts] Optional parameters for modifying the rows to be included
161 * @param {string} [oOpts.filter=none] Select elements that meet the current filter
162 * criterion ("applied") or all elements (i.e. no filter).
163 * @param {string} [oOpts.order=current] Order of the data in the processed array.
164 * Can be either 'current', whereby the current sorting of the table is used, or
165 * 'original' whereby the original order the data was read into the table is used.
166 * @param {string} [oOpts.page=all] Limit the selection to the currently displayed page
167 * ("current") or not ("all"). If 'current' is given, then order is assumed to be
168 * 'current' and filter is 'applied', regardless of what they might be given as.
169 * @returns {array} Data for the matched elements. If any elements, as a result of the
170 * selector, were not TR, TD or TH elements in the DataTable, they will have a null
171 * entry in the array.
172 * @dtopt API
173 * @deprecated Since v1.10
174 *
175 * @example
176 * $(document).ready(function() {
177 * var oTable = $('#example').dataTable();
178 *
179 * // Get the data from the first row in the table
180 * var data = oTable._('tr:first');
181 *
182 * // Do something useful with the data
183 * alert( "First cell is: "+data[0] );
184 * } );
185 *
186 * @example
187 * $(document).ready(function() {
188 * var oTable = $('#example').dataTable();
189 *
190 * // Filter to 'Webkit' and get all data for
191 * oTable.fnFilter('Webkit');
192 * var data = oTable._('tr', {"search": "applied"});
193 *
194 * // Do something with the data
195 * alert( data.length+" rows matched the search" );
196 * } );
197 */
198 this._ = function ( sSelector, oOpts )
199 {
200 return this.api(true).rows( sSelector, oOpts ).data();
201 };
202
203
204 /**
205 * Create a DataTables Api instance, with the currently selected tables for
206 * the Api's context.
207 * @param {boolean} [traditional=false] Set the API instance's context to be
208 * only the table referred to by the `DataTable.ext.iApiIndex` option, as was
209 * used in the API presented by DataTables 1.9- (i.e. the traditional mode),
210 * or if all tables captured in the jQuery object should be used.
211 * @return {DataTables.Api}
212 */
213 this.api = function ( traditional )
214 {
215 return traditional ?
216 new _Api(
217 _fnSettingsFromNode( this[ _ext.iApiIndex ] )
218 ) :
219 new _Api( this );
220 };
221
222
223 /**
224 * Add a single new row or multiple rows of data to the table. Please note
225 * that this is suitable for client-side processing only - if you are using
226 * server-side processing (i.e. "bServerSide": true), then to add data, you
227 * must add it to the data source, i.e. the server-side, through an Ajax call.
228 * @param {array|object} data The data to be added to the table. This can be:
229 * <ul>
230 * <li>1D array of data - add a single row with the data provided</li>
231 * <li>2D array of arrays - add multiple rows in a single call</li>
232 * <li>object - data object when using <i>mData</i></li>
233 * <li>array of objects - multiple data objects when using <i>mData</i></li>
234 * </ul>
235 * @param {bool} [redraw=true] redraw the table or not
236 * @returns {array} An array of integers, representing the list of indexes in
237 * <i>aoData</i> ({@link DataTable.models.oSettings}) that have been added to
238 * the table.
239 * @dtopt API
240 * @deprecated Since v1.10
241 *
242 * @example
243 * // Global var for counter
244 * var giCount = 2;
245 *
246 * $(document).ready(function() {
247 * $('#example').dataTable();
248 * } );
249 *
250 * function fnClickAddRow() {
251 * $('#example').dataTable().fnAddData( [
252 * giCount+".1",
253 * giCount+".2",
254 * giCount+".3",
255 * giCount+".4" ]
256 * );
257 *
258 * giCount++;
259 * }
260 */
261 this.fnAddData = function( data, redraw )
262 {
263 var api = this.api( true );
264
265 /* Check if we want to add multiple rows or not */
266 var rows = $.isArray(data) && ( $.isArray(data[0]) || $.isPlainObject(data[0]) ) ?
267 api.rows.add( data ) :
268 api.row.add( data );
269
270 if ( redraw === undefined || redraw ) {
271 api.draw();
272 }
273
274 return rows.flatten().toArray();
275 };
276
277
278 /**
279 * This function will make DataTables recalculate the column sizes, based on the data
280 * contained in the table and the sizes applied to the columns (in the DOM, CSS or
281 * through the sWidth parameter). This can be useful when the width of the table's
282 * parent element changes (for example a window resize).
283 * @param {boolean} [bRedraw=true] Redraw the table or not, you will typically want to
284 * @dtopt API
285 * @deprecated Since v1.10
286 *
287 * @example
288 * $(document).ready(function() {
289 * var oTable = $('#example').dataTable( {
290 * "sScrollY": "200px",
291 * "bPaginate": false
292 * } );
293 *
294 * $(window).on('resize', function () {
295 * oTable.fnAdjustColumnSizing();
296 * } );
297 * } );
298 */
299 this.fnAdjustColumnSizing = function ( bRedraw )
300 {
301 var api = this.api( true ).columns.adjust();
302 var settings = api.settings()[0];
303 var scroll = settings.oScroll;
304
305 if ( bRedraw === undefined || bRedraw ) {
306 api.draw( false );
307 }
308 else if ( scroll.sX !== "" || scroll.sY !== "" ) {
309 /* If not redrawing, but scrolling, we want to apply the new column sizes anyway */
310 _fnScrollDraw( settings );
311 }
312 };
313
314
315 /**
316 * Quickly and simply clear a table
317 * @param {bool} [bRedraw=true] redraw the table or not
318 * @dtopt API
319 * @deprecated Since v1.10
320 *
321 * @example
322 * $(document).ready(function() {
323 * var oTable = $('#example').dataTable();
324 *
325 * // Immediately 'nuke' the current rows (perhaps waiting for an Ajax callback...)
326 * oTable.fnClearTable();
327 * } );
328 */
329 this.fnClearTable = function( bRedraw )
330 {
331 var api = this.api( true ).clear();
332
333 if ( bRedraw === undefined || bRedraw ) {
334 api.draw();
335 }
336 };
337
338
339 /**
340 * The exact opposite of 'opening' a row, this function will close any rows which
341 * are currently 'open'.
342 * @param {node} nTr the table row to 'close'
343 * @returns {int} 0 on success, or 1 if failed (can't find the row)
344 * @dtopt API
345 * @deprecated Since v1.10
346 *
347 * @example
348 * $(document).ready(function() {
349 * var oTable;
350 *
351 * // 'open' an information row when a row is clicked on
352 * $('#example tbody tr').click( function () {
353 * if ( oTable.fnIsOpen(this) ) {
354 * oTable.fnClose( this );
355 * } else {
356 * oTable.fnOpen( this, "Temporary row opened", "info_row" );
357 * }
358 * } );
359 *
360 * oTable = $('#example').dataTable();
361 * } );
362 */
363 this.fnClose = function( nTr )
364 {
365 this.api( true ).row( nTr ).child.hide();
366 };
367
368
369 /**
370 * Remove a row for the table
371 * @param {mixed} target The index of the row from aoData to be deleted, or
372 * the TR element you want to delete
373 * @param {function|null} [callBack] Callback function
374 * @param {bool} [redraw=true] Redraw the table or not
375 * @returns {array} The row that was deleted
376 * @dtopt API
377 * @deprecated Since v1.10
378 *
379 * @example
380 * $(document).ready(function() {
381 * var oTable = $('#example').dataTable();
382 *
383 * // Immediately remove the first row
384 * oTable.fnDeleteRow( 0 );
385 * } );
386 */
387 this.fnDeleteRow = function( target, callback, redraw )
388 {
389 var api = this.api( true );
390 var rows = api.rows( target );
391 var settings = rows.settings()[0];
392 var data = settings.aoData[ rows[0][0] ];
393
394 rows.remove();
395
396 if ( callback ) {
397 callback.call( this, settings, data );
398 }
399
400 if ( redraw === undefined || redraw ) {
401 api.draw();
402 }
403
404 return data;
405 };
406
407
408 /**
409 * Restore the table to it's original state in the DOM by removing all of DataTables
410 * enhancements, alterations to the DOM structure of the table and event listeners.
411 * @param {boolean} [remove=false] Completely remove the table from the DOM
412 * @dtopt API
413 * @deprecated Since v1.10
414 *
415 * @example
416 * $(document).ready(function() {
417 * // This example is fairly pointless in reality, but shows how fnDestroy can be used
418 * var oTable = $('#example').dataTable();
419 * oTable.fnDestroy();
420 * } );
421 */
422 this.fnDestroy = function ( remove )
423 {
424 this.api( true ).destroy( remove );
425 };
426
427
428 /**
429 * Redraw the table
430 * @param {bool} [complete=true] Re-filter and resort (if enabled) the table before the draw.
431 * @dtopt API
432 * @deprecated Since v1.10
433 *
434 * @example
435 * $(document).ready(function() {
436 * var oTable = $('#example').dataTable();
437 *
438 * // Re-draw the table - you wouldn't want to do it here, but it's an example :-)
439 * oTable.fnDraw();
440 * } );
441 */
442 this.fnDraw = function( complete )
443 {
444 // Note that this isn't an exact match to the old call to _fnDraw - it takes
445 // into account the new data, but can hold position.
446 this.api( true ).draw( complete );
447 };
448
449
450 /**
451 * Filter the input based on data
452 * @param {string} sInput String to filter the table on
453 * @param {int|null} [iColumn] Column to limit filtering to
454 * @param {bool} [bRegex=false] Treat as regular expression or not
455 * @param {bool} [bSmart=true] Perform smart filtering or not
456 * @param {bool} [bShowGlobal=true] Show the input global filter in it's input box(es)
457 * @param {bool} [bCaseInsensitive=true] Do case-insensitive matching (true) or not (false)
458 * @dtopt API
459 * @deprecated Since v1.10
460 *
461 * @example
462 * $(document).ready(function() {
463 * var oTable = $('#example').dataTable();
464 *
465 * // Sometime later - filter...
466 * oTable.fnFilter( 'test string' );
467 * } );
468 */
469 this.fnFilter = function( sInput, iColumn, bRegex, bSmart, bShowGlobal, bCaseInsensitive )
470 {
471 var api = this.api( true );
472
473 if ( iColumn === null || iColumn === undefined ) {
474 api.search( sInput, bRegex, bSmart, bCaseInsensitive );
475 }
476 else {
477 api.column( iColumn ).search( sInput, bRegex, bSmart, bCaseInsensitive );
478 }
479
480 api.draw();
481 };
482
483
484 /**
485 * Get the data for the whole table, an individual row or an individual cell based on the
486 * provided parameters.
487 * @param {int|node} [src] A TR row node, TD/TH cell node or an integer. If given as
488 * a TR node then the data source for the whole row will be returned. If given as a
489 * TD/TH cell node then iCol will be automatically calculated and the data for the
490 * cell returned. If given as an integer, then this is treated as the aoData internal
491 * data index for the row (see fnGetPosition) and the data for that row used.
492 * @param {int} [col] Optional column index that you want the data of.
493 * @returns {array|object|string} If mRow is undefined, then the data for all rows is
494 * returned. If mRow is defined, just data for that row, and is iCol is
495 * defined, only data for the designated cell is returned.
496 * @dtopt API
497 * @deprecated Since v1.10
498 *
499 * @example
500 * // Row data
501 * $(document).ready(function() {
502 * oTable = $('#example').dataTable();
503 *
504 * oTable.$('tr').click( function () {
505 * var data = oTable.fnGetData( this );
506 * // ... do something with the array / object of data for the row
507 * } );
508 * } );
509 *
510 * @example
511 * // Individual cell data
512 * $(document).ready(function() {
513 * oTable = $('#example').dataTable();
514 *
515 * oTable.$('td').click( function () {
516 * var sData = oTable.fnGetData( this );
517 * alert( 'The cell clicked on had the value of '+sData );
518 * } );
519 * } );
520 */
521 this.fnGetData = function( src, col )
522 {
523 var api = this.api( true );
524
525 if ( src !== undefined ) {
526 var type = src.nodeName ? src.nodeName.toLowerCase() : '';
527
528 return col !== undefined || type == 'td' || type == 'th' ?
529 api.cell( src, col ).data() :
530 api.row( src ).data() || null;
531 }
532
533 return api.data().toArray();
534 };
535
536
537 /**
538 * Get an array of the TR nodes that are used in the table's body. Note that you will
539 * typically want to use the '$' API method in preference to this as it is more
540 * flexible.
541 * @param {int} [iRow] Optional row index for the TR element you want
542 * @returns {array|node} If iRow is undefined, returns an array of all TR elements
543 * in the table's body, or iRow is defined, just the TR element requested.
544 * @dtopt API
545 * @deprecated Since v1.10
546 *
547 * @example
548 * $(document).ready(function() {
549 * var oTable = $('#example').dataTable();
550 *
551 * // Get the nodes from the table
552 * var nNodes = oTable.fnGetNodes( );
553 * } );
554 */
555 this.fnGetNodes = function( iRow )
556 {
557 var api = this.api( true );
558
559 return iRow !== undefined ?
560 api.row( iRow ).node() :
561 api.rows().nodes().flatten().toArray();
562 };
563
564
565 /**
566 * Get the array indexes of a particular cell from it's DOM element
567 * and column index including hidden columns
568 * @param {node} node this can either be a TR, TD or TH in the table's body
569 * @returns {int} If nNode is given as a TR, then a single index is returned, or
570 * if given as a cell, an array of [row index, column index (visible),
571 * column index (all)] is given.
572 * @dtopt API
573 * @deprecated Since v1.10
574 *
575 * @example
576 * $(document).ready(function() {
577 * $('#example tbody td').click( function () {
578 * // Get the position of the current data from the node
579 * var aPos = oTable.fnGetPosition( this );
580 *
581 * // Get the data array for this row
582 * var aData = oTable.fnGetData( aPos[0] );
583 *
584 * // Update the data array and return the value
585 * aData[ aPos[1] ] = 'clicked';
586 * this.innerHTML = 'clicked';
587 * } );
588 *
589 * // Init DataTables
590 * oTable = $('#example').dataTable();
591 * } );
592 */
593 this.fnGetPosition = function( node )
594 {
595 var api = this.api( true );
596 var nodeName = node.nodeName.toUpperCase();
597
598 if ( nodeName == 'TR' ) {
599 return api.row( node ).index();
600 }
601 else if ( nodeName == 'TD' || nodeName == 'TH' ) {
602 var cell = api.cell( node ).index();
603
604 return [
605 cell.row,
606 cell.columnVisible,
607 cell.column
608 ];
609 }
610 return null;
611 };
612
613
614 /**
615 * Check to see if a row is 'open' or not.
616 * @param {node} nTr the table row to check
617 * @returns {boolean} true if the row is currently open, false otherwise
618 * @dtopt API
619 * @deprecated Since v1.10
620 *
621 * @example
622 * $(document).ready(function() {
623 * var oTable;
624 *
625 * // 'open' an information row when a row is clicked on
626 * $('#example tbody tr').click( function () {
627 * if ( oTable.fnIsOpen(this) ) {
628 * oTable.fnClose( this );
629 * } else {
630 * oTable.fnOpen( this, "Temporary row opened", "info_row" );
631 * }
632 * } );
633 *
634 * oTable = $('#example').dataTable();
635 * } );
636 */
637 this.fnIsOpen = function( nTr )
638 {
639 return this.api( true ).row( nTr ).child.isShown();
640 };
641
642
643 /**
644 * This function will place a new row directly after a row which is currently
645 * on display on the page, with the HTML contents that is passed into the
646 * function. This can be used, for example, to ask for confirmation that a
647 * particular record should be deleted.
648 * @param {node} nTr The table row to 'open'
649 * @param {string|node|jQuery} mHtml The HTML to put into the row
650 * @param {string} sClass Class to give the new TD cell
651 * @returns {node} The row opened. Note that if the table row passed in as the
652 * first parameter, is not found in the table, this method will silently
653 * return.
654 * @dtopt API
655 * @deprecated Since v1.10
656 *
657 * @example
658 * $(document).ready(function() {
659 * var oTable;
660 *
661 * // 'open' an information row when a row is clicked on
662 * $('#example tbody tr').click( function () {
663 * if ( oTable.fnIsOpen(this) ) {
664 * oTable.fnClose( this );
665 * } else {
666 * oTable.fnOpen( this, "Temporary row opened", "info_row" );
667 * }
668 * } );
669 *
670 * oTable = $('#example').dataTable();
671 * } );
672 */
673 this.fnOpen = function( nTr, mHtml, sClass )
674 {
675 return this.api( true )
676 .row( nTr )
677 .child( mHtml, sClass )
678 .show()
679 .child()[0];
680 };
681
682
683 /**
684 * Change the pagination - provides the internal logic for pagination in a simple API
685 * function. With this function you can have a DataTables table go to the next,
686 * previous, first or last pages.
687 * @param {string|int} mAction Paging action to take: "first", "previous", "next" or "last"
688 * or page number to jump to (integer), note that page 0 is the first page.
689 * @param {bool} [bRedraw=true] Redraw the table or not
690 * @dtopt API
691 * @deprecated Since v1.10
692 *
693 * @example
694 * $(document).ready(function() {
695 * var oTable = $('#example').dataTable();
696 * oTable.fnPageChange( 'next' );
697 * } );
698 */
699 this.fnPageChange = function ( mAction, bRedraw )
700 {
701 var api = this.api( true ).page( mAction );
702
703 if ( bRedraw === undefined || bRedraw ) {
704 api.draw(false);
705 }
706 };
707
708
709 /**
710 * Show a particular column
711 * @param {int} iCol The column whose display should be changed
712 * @param {bool} bShow Show (true) or hide (false) the column
713 * @param {bool} [bRedraw=true] Redraw the table or not
714 * @dtopt API
715 * @deprecated Since v1.10
716 *
717 * @example
718 * $(document).ready(function() {
719 * var oTable = $('#example').dataTable();
720 *
721 * // Hide the second column after initialisation
722 * oTable.fnSetColumnVis( 1, false );
723 * } );
724 */
725 this.fnSetColumnVis = function ( iCol, bShow, bRedraw )
726 {
727 var api = this.api( true ).column( iCol ).visible( bShow );
728
729 if ( bRedraw === undefined || bRedraw ) {
730 api.columns.adjust().draw();
731 }
732 };
733
734
735 /**
736 * Get the settings for a particular table for external manipulation
737 * @returns {object} DataTables settings object. See
738 * {@link DataTable.models.oSettings}
739 * @dtopt API
740 * @deprecated Since v1.10
741 *
742 * @example
743 * $(document).ready(function() {
744 * var oTable = $('#example').dataTable();
745 * var oSettings = oTable.fnSettings();
746 *
747 * // Show an example parameter from the settings
748 * alert( oSettings._iDisplayStart );
749 * } );
750 */
751 this.fnSettings = function()
752 {
753 return _fnSettingsFromNode( this[_ext.iApiIndex] );
754 };
755
756
757 /**
758 * Sort the table by a particular column
759 * @param {int} iCol the data index to sort on. Note that this will not match the
760 * 'display index' if you have hidden data entries
761 * @dtopt API
762 * @deprecated Since v1.10
763 *
764 * @example
765 * $(document).ready(function() {
766 * var oTable = $('#example').dataTable();
767 *
768 * // Sort immediately with columns 0 and 1
769 * oTable.fnSort( [ [0,'asc'], [1,'asc'] ] );
770 * } );
771 */
772 this.fnSort = function( aaSort )
773 {
774 this.api( true ).order( aaSort ).draw();
775 };
776
777
778 /**
779 * Attach a sort listener to an element for a given column
780 * @param {node} nNode the element to attach the sort listener to
781 * @param {int} iColumn the column that a click on this node will sort on
782 * @param {function} [fnCallback] callback function when sort is run
783 * @dtopt API
784 * @deprecated Since v1.10
785 *
786 * @example
787 * $(document).ready(function() {
788 * var oTable = $('#example').dataTable();
789 *
790 * // Sort on column 1, when 'sorter' is clicked on
791 * oTable.fnSortListener( document.getElementById('sorter'), 1 );
792 * } );
793 */
794 this.fnSortListener = function( nNode, iColumn, fnCallback )
795 {
796 this.api( true ).order.listener( nNode, iColumn, fnCallback );
797 };
798
799
800 /**
801 * Update a table cell or row - this method will accept either a single value to
802 * update the cell with, an array of values with one element for each column or
803 * an object in the same format as the original data source. The function is
804 * self-referencing in order to make the multi column updates easier.
805 * @param {object|array|string} mData Data to update the cell/row with
806 * @param {node|int} mRow TR element you want to update or the aoData index
807 * @param {int} [iColumn] The column to update, give as null or undefined to
808 * update a whole row.
809 * @param {bool} [bRedraw=true] Redraw the table or not
810 * @param {bool} [bAction=true] Perform pre-draw actions or not
811 * @returns {int} 0 on success, 1 on error
812 * @dtopt API
813 * @deprecated Since v1.10
814 *
815 * @example
816 * $(document).ready(function() {
817 * var oTable = $('#example').dataTable();
818 * oTable.fnUpdate( 'Example update', 0, 0 ); // Single cell
819 * oTable.fnUpdate( ['a', 'b', 'c', 'd', 'e'], $('tbody tr')[0] ); // Row
820 * } );
821 */
822 this.fnUpdate = function( mData, mRow, iColumn, bRedraw, bAction )
823 {
824 var api = this.api( true );
825
826 if ( iColumn === undefined || iColumn === null ) {
827 api.row( mRow ).data( mData );
828 }
829 else {
830 api.cell( mRow, iColumn ).data( mData );
831 }
832
833 if ( bAction === undefined || bAction ) {
834 api.columns.adjust();
835 }
836
837 if ( bRedraw === undefined || bRedraw ) {
838 api.draw();
839 }
840 return 0;
841 };
842
843
844 /**
845 * Provide a common method for plug-ins to check the version of DataTables being used, in order
846 * to ensure compatibility.
847 * @param {string} sVersion Version string to check for, in the format "X.Y.Z". Note that the
848 * formats "X" and "X.Y" are also acceptable.
849 * @returns {boolean} true if this version of DataTables is greater or equal to the required
850 * version, or false if this version of DataTales is not suitable
851 * @method
852 * @dtopt API
853 * @deprecated Since v1.10
854 *
855 * @example
856 * $(document).ready(function() {
857 * var oTable = $('#example').dataTable();
858 * alert( oTable.fnVersionCheck( '1.9.0' ) );
859 * } );
860 */
861 this.fnVersionCheck = _ext.fnVersionCheck;
862
863
864 var _that = this;
865 var emptyInit = options === undefined;
866 var len = this.length;
867
868 if ( emptyInit ) {
869 options = {};
870 }
871
872 this.oApi = this.internal = _ext.internal;
873
874 // Extend with old style plug-in API methods
875 for ( var fn in DataTable.ext.internal ) {
876 if ( fn ) {
877 this[fn] = _fnExternApiFunc(fn);
878 }
879 }
880
881 this.each(function() {
882 // For each initialisation we want to give it a clean initialisation
883 // object that can be bashed around
884 var o = {};
885 var oInit = len > 1 ? // optimisation for single table case
886 _fnExtend( o, options, true ) :
887 options;
888
889 /*global oInit,_that,emptyInit*/
890 var i=0, iLen, j, jLen, k, kLen;
891 var sId = this.getAttribute( 'id' );
892 var bInitHandedOff = false;
893 var defaults = DataTable.defaults;
894 var $this = $(this);
895
896
897 /* Sanity check */
898 if ( this.nodeName.toLowerCase() != 'table' )
899 {
900 _fnLog( null, 0, 'Non-table node initialisation ('+this.nodeName+')', 2 );
901 return;
902 }
903
904 /* Backwards compatibility for the defaults */
905 _fnCompatOpts( defaults );
906 _fnCompatCols( defaults.column );
907
908 /* Convert the camel-case defaults to Hungarian */
909 _fnCamelToHungarian( defaults, defaults, true );
910 _fnCamelToHungarian( defaults.column, defaults.column, true );
911
912 /* Setting up the initialisation object */
913 _fnCamelToHungarian( defaults, $.extend( oInit, $this.data() ) );
914
915
916
917 /* Check to see if we are re-initialising a table */
918 var allSettings = DataTable.settings;
919 for ( i=0, iLen=allSettings.length ; i<iLen ; i++ )
920 {
921 var s = allSettings[i];
922
923 /* Base check on table node */
924 if ( s.nTable == this || s.nTHead.parentNode == this || (s.nTFoot && s.nTFoot.parentNode == this) )
925 {
926 var bRetrieve = oInit.bRetrieve !== undefined ? oInit.bRetrieve : defaults.bRetrieve;
927 var bDestroy = oInit.bDestroy !== undefined ? oInit.bDestroy : defaults.bDestroy;
928
929 if ( emptyInit || bRetrieve )
930 {
931 return s.oInstance;
932 }
933 else if ( bDestroy )
934 {
935 s.oInstance.fnDestroy();
936 break;
937 }
938 else
939 {
940 _fnLog( s, 0, 'Cannot reinitialise DataTable', 3 );
941 return;
942 }
943 }
944
945 /* If the element we are initialising has the same ID as a table which was previously
946 * initialised, but the table nodes don't match (from before) then we destroy the old
947 * instance by simply deleting it. This is under the assumption that the table has been
948 * destroyed by other methods. Anyone using non-id selectors will need to do this manually
949 */
950 if ( s.sTableId == this.id )
951 {
952 allSettings.splice( i, 1 );
953 break;
954 }
955 }
956
957 /* Ensure the table has an ID - required for accessibility */
958 if ( sId === null || sId === "" )
959 {
960 sId = "DataTables_Table_"+(DataTable.ext._unique++);
961 this.id = sId;
962 }
963
964 /* Create the settings object for this table and set some of the default parameters */
965 var oSettings = $.extend( true, {}, DataTable.models.oSettings, {
966 "sDestroyWidth": $this[0].style.width,
967 "sInstance": sId,
968 "sTableId": sId
969 } );
970 oSettings.nTable = this;
971 oSettings.oApi = _that.internal;
972 oSettings.oInit = oInit;
973
974 allSettings.push( oSettings );
975
976 // Need to add the instance after the instance after the settings object has been added
977 // to the settings array, so we can self reference the table instance if more than one
978 oSettings.oInstance = (_that.length===1) ? _that : $this.dataTable();
979
980 // Backwards compatibility, before we apply all the defaults
981 _fnCompatOpts( oInit );
982
983 if ( oInit.oLanguage )
984 {
985 _fnLanguageCompat( oInit.oLanguage );
986 }
987
988 // If the length menu is given, but the init display length is not, use the length menu
989 if ( oInit.aLengthMenu && ! oInit.iDisplayLength )
990 {
991 oInit.iDisplayLength = $.isArray( oInit.aLengthMenu[0] ) ?
992 oInit.aLengthMenu[0][0] : oInit.aLengthMenu[0];
993 }
994
995 // Apply the defaults and init options to make a single init object will all
996 // options defined from defaults and instance options.
997 oInit = _fnExtend( $.extend( true, {}, defaults ), oInit );
998
999
1000 // Map the initialisation options onto the settings object
1001 _fnMap( oSettings.oFeatures, oInit, [
1002 "bPaginate",
1003 "bLengthChange",
1004 "bFilter",
1005 "bSort",
1006 "bSortMulti",
1007 "bInfo",
1008 "bProcessing",
1009 "bAutoWidth",
1010 "bSortClasses",
1011 "bServerSide",
1012 "bDeferRender"
1013 ] );
1014 _fnMap( oSettings, oInit, [
1015 "asStripeClasses",
1016 "ajax",
1017 "fnServerData",
1018 "fnFormatNumber",
1019 "sServerMethod",
1020 "aaSorting",
1021 "aaSortingFixed",
1022 "aLengthMenu",
1023 "sPaginationType",
1024 "sAjaxSource",
1025 "sAjaxDataProp",
1026 "iStateDuration",
1027 "sDom",
1028 "bSortCellsTop",
1029 "iTabIndex",
1030 "fnStateLoadCallback",
1031 "fnStateSaveCallback",
1032 "renderer",
1033 "searchDelay",
1034 "rowId",
1035 [ "iCookieDuration", "iStateDuration" ], // backwards compat
1036 [ "oSearch", "oPreviousSearch" ],
1037 [ "aoSearchCols", "aoPreSearchCols" ],
1038 [ "iDisplayLength", "_iDisplayLength" ]
1039 ] );
1040 _fnMap( oSettings.oScroll, oInit, [
1041 [ "sScrollX", "sX" ],
1042 [ "sScrollXInner", "sXInner" ],
1043 [ "sScrollY", "sY" ],
1044 [ "bScrollCollapse", "bCollapse" ]
1045 ] );
1046 _fnMap( oSettings.oLanguage, oInit, "fnInfoCallback" );
1047
1048 /* Callback functions which are array driven */
1049 _fnCallbackReg( oSettings, 'aoDrawCallback', oInit.fnDrawCallback, 'user' );
1050 _fnCallbackReg( oSettings, 'aoServerParams', oInit.fnServerParams, 'user' );
1051 _fnCallbackReg( oSettings, 'aoStateSaveParams', oInit.fnStateSaveParams, 'user' );
1052 _fnCallbackReg( oSettings, 'aoStateLoadParams', oInit.fnStateLoadParams, 'user' );
1053 _fnCallbackReg( oSettings, 'aoStateLoaded', oInit.fnStateLoaded, 'user' );
1054 _fnCallbackReg( oSettings, 'aoRowCallback', oInit.fnRowCallback, 'user' );
1055 _fnCallbackReg( oSettings, 'aoRowCreatedCallback', oInit.fnCreatedRow, 'user' );
1056 _fnCallbackReg( oSettings, 'aoHeaderCallback', oInit.fnHeaderCallback, 'user' );
1057 _fnCallbackReg( oSettings, 'aoFooterCallback', oInit.fnFooterCallback, 'user' );
1058 _fnCallbackReg( oSettings, 'aoInitComplete', oInit.fnInitComplete, 'user' );
1059 _fnCallbackReg( oSettings, 'aoPreDrawCallback', oInit.fnPreDrawCallback, 'user' );
1060
1061 oSettings.rowIdFn = _fnGetObjectDataFn( oInit.rowId );
1062
1063 /* Browser support detection */
1064 _fnBrowserDetect( oSettings );
1065
1066 var oClasses = oSettings.oClasses;
1067
1068 $.extend( oClasses, DataTable.ext.classes, oInit.oClasses );
1069 $this.addClass( oClasses.sTable );
1070
1071
1072 if ( oSettings.iInitDisplayStart === undefined )
1073 {
1074 /* Display start point, taking into account the save saving */
1075 oSettings.iInitDisplayStart = oInit.iDisplayStart;
1076 oSettings._iDisplayStart = oInit.iDisplayStart;
1077 }
1078
1079 if ( oInit.iDeferLoading !== null )
1080 {
1081 oSettings.bDeferLoading = true;
1082 var tmp = $.isArray( oInit.iDeferLoading );
1083 oSettings._iRecordsDisplay = tmp ? oInit.iDeferLoading[0] : oInit.iDeferLoading;
1084 oSettings._iRecordsTotal = tmp ? oInit.iDeferLoading[1] : oInit.iDeferLoading;
1085 }
1086
1087 /* Language definitions */
1088 var oLanguage = oSettings.oLanguage;
1089 $.extend( true, oLanguage, oInit.oLanguage );
1090
1091 if ( oLanguage.sUrl )
1092 {
1093 /* Get the language definitions from a file - because this Ajax call makes the language
1094 * get async to the remainder of this function we use bInitHandedOff to indicate that
1095 * _fnInitialise will be fired by the returned Ajax handler, rather than the constructor
1096 */
1097 $.ajax( {
1098 dataType: 'json',
1099 url: oLanguage.sUrl,
1100 success: function ( json ) {
1101 _fnLanguageCompat( json );
1102 _fnCamelToHungarian( defaults.oLanguage, json );
1103 $.extend( true, oLanguage, json );
1104 _fnInitialise( oSettings );
1105 },
1106 error: function () {
1107 // Error occurred loading language file, continue on as best we can
1108 _fnInitialise( oSettings );
1109 }
1110 } );
1111 bInitHandedOff = true;
1112 }
1113
1114 /*
1115 * Stripes
1116 */
1117 if ( oInit.asStripeClasses === null )
1118 {
1119 oSettings.asStripeClasses =[
1120 oClasses.sStripeOdd,
1121 oClasses.sStripeEven
1122 ];
1123 }
1124
1125 /* Remove row stripe classes if they are already on the table row */
1126 var stripeClasses = oSettings.asStripeClasses;
1127 var rowOne = $this.children('tbody').find('tr').eq(0);
1128 if ( $.inArray( true, $.map( stripeClasses, function(el, i) {
1129 return rowOne.hasClass(el);
1130 } ) ) !== -1 ) {
1131 $('tbody tr', this).removeClass( stripeClasses.join(' ') );
1132 oSettings.asDestroyStripes = stripeClasses.slice();
1133 }
1134
1135 /*
1136 * Columns
1137 * See if we should load columns automatically or use defined ones
1138 */
1139 var anThs = [];
1140 var aoColumnsInit;
1141 var nThead = this.getElementsByTagName('thead');
1142 if ( nThead.length !== 0 )
1143 {
1144 _fnDetectHeader( oSettings.aoHeader, nThead[0] );
1145 anThs = _fnGetUniqueThs( oSettings );
1146 }
1147
1148 /* If not given a column array, generate one with nulls */
1149 if ( oInit.aoColumns === null )
1150 {
1151 aoColumnsInit = [];
1152 for ( i=0, iLen=anThs.length ; i<iLen ; i++ )
1153 {
1154 aoColumnsInit.push( null );
1155 }
1156 }
1157 else
1158 {
1159 aoColumnsInit = oInit.aoColumns;
1160 }
1161
1162 /* Add the columns */
1163 for ( i=0, iLen=aoColumnsInit.length ; i<iLen ; i++ )
1164 {
1165 _fnAddColumn( oSettings, anThs ? anThs[i] : null );
1166 }
1167
1168 /* Apply the column definitions */
1169 _fnApplyColumnDefs( oSettings, oInit.aoColumnDefs, aoColumnsInit, function (iCol, oDef) {
1170 _fnColumnOptions( oSettings, iCol, oDef );
1171 } );
1172
1173 /* HTML5 attribute detection - build an mData object automatically if the
1174 * attributes are found
1175 */
1176 if ( rowOne.length ) {
1177 var a = function ( cell, name ) {
1178 return cell.getAttribute( 'data-'+name ) !== null ? name : null;
1179 };
1180
1181 $( rowOne[0] ).children('th, td').each( function (i, cell) {
1182 var col = oSettings.aoColumns[i];
1183
1184 if ( col.mData === i ) {
1185 var sort = a( cell, 'sort' ) || a( cell, 'order' );
1186 var filter = a( cell, 'filter' ) || a( cell, 'search' );
1187
1188 if ( sort !== null || filter !== null ) {
1189 col.mData = {
1190 _: i+'.display',
1191 sort: sort !== null ? i+'.@data-'+sort : undefined,
1192 type: sort !== null ? i+'.@data-'+sort : undefined,
1193 filter: filter !== null ? i+'.@data-'+filter : undefined
1194 };
1195
1196 _fnColumnOptions( oSettings, i );
1197 }
1198 }
1199 } );
1200 }
1201
1202 var features = oSettings.oFeatures;
1203 var loadedInit = function () {
1204 /*
1205 * Sorting
1206 * @todo For modularisation (1.11) this needs to do into a sort start up handler
1207 */
1208
1209 // If aaSorting is not defined, then we use the first indicator in asSorting
1210 // in case that has been altered, so the default sort reflects that option
1211 if ( oInit.aaSorting === undefined ) {
1212 var sorting = oSettings.aaSorting;
1213 for ( i=0, iLen=sorting.length ; i<iLen ; i++ ) {
1214 sorting[i][1] = oSettings.aoColumns[ i ].asSorting[0];
1215 }
1216 }
1217
1218 /* Do a first pass on the sorting classes (allows any size changes to be taken into
1219 * account, and also will apply sorting disabled classes if disabled
1220 */
1221 _fnSortingClasses( oSettings );
1222
1223 if ( features.bSort ) {
1224 _fnCallbackReg( oSettings, 'aoDrawCallback', function () {
1225 if ( oSettings.bSorted ) {
1226 var aSort = _fnSortFlatten( oSettings );
1227 var sortedColumns = {};
1228
1229 $.each( aSort, function (i, val) {
1230 sortedColumns[ val.src ] = val.dir;
1231 } );
1232
1233 _fnCallbackFire( oSettings, null, 'order', [oSettings, aSort, sortedColumns] );
1234 _fnSortAria( oSettings );
1235 }
1236 } );
1237 }
1238
1239 _fnCallbackReg( oSettings, 'aoDrawCallback', function () {
1240 if ( oSettings.bSorted || _fnDataSource( oSettings ) === 'ssp' || features.bDeferRender ) {
1241 _fnSortingClasses( oSettings );
1242 }
1243 }, 'sc' );
1244
1245
1246 /*
1247 * Final init
1248 * Cache the header, body and footer as required, creating them if needed
1249 */
1250
1251 // Work around for Webkit bug 83867 - store the caption-side before removing from doc
1252 var captions = $this.children('caption').each( function () {
1253 this._captionSide = $(this).css('caption-side');
1254 } );
1255
1256 var thead = $this.children('thead');
1257 if ( thead.length === 0 ) {
1258 thead = $('<thead/>').appendTo($this);
1259 }
1260 oSettings.nTHead = thead[0];
1261
1262 var tbody = $this.children('tbody');
1263 if ( tbody.length === 0 ) {
1264 tbody = $('<tbody/>').appendTo($this);
1265 }
1266 oSettings.nTBody = tbody[0];
1267
1268 var tfoot = $this.children('tfoot');
1269 if ( tfoot.length === 0 && captions.length > 0 && (oSettings.oScroll.sX !== "" || oSettings.oScroll.sY !== "") ) {
1270 // If we are a scrolling table, and no footer has been given, then we need to create
1271 // a tfoot element for the caption element to be appended to
1272 tfoot = $('<tfoot/>').appendTo($this);
1273 }
1274
1275 if ( tfoot.length === 0 || tfoot.children().length === 0 ) {
1276 $this.addClass( oClasses.sNoFooter );
1277 }
1278 else if ( tfoot.length > 0 ) {
1279 oSettings.nTFoot = tfoot[0];
1280 _fnDetectHeader( oSettings.aoFooter, oSettings.nTFoot );
1281 }
1282
1283 /* Check if there is data passing into the constructor */
1284 if ( oInit.aaData ) {
1285 for ( i=0 ; i<oInit.aaData.length ; i++ ) {
1286 _fnAddData( oSettings, oInit.aaData[ i ] );
1287 }
1288 }
1289 else if ( oSettings.bDeferLoading || _fnDataSource( oSettings ) == 'dom' ) {
1290 /* Grab the data from the page - only do this when deferred loading or no Ajax
1291 * source since there is no point in reading the DOM data if we are then going
1292 * to replace it with Ajax data
1293 */
1294 _fnAddTr( oSettings, $(oSettings.nTBody).children('tr') );
1295 }
1296
1297 /* Copy the data index array */
1298 oSettings.aiDisplay = oSettings.aiDisplayMaster.slice();
1299
1300 /* Initialisation complete - table can be drawn */
1301 oSettings.bInitialised = true;
1302
1303 /* Check if we need to initialise the table (it might not have been handed off to the
1304 * language processor)
1305 */
1306 if ( bInitHandedOff === false ) {
1307 _fnInitialise( oSettings );
1308 }
1309 };
1310
1311 /* Must be done after everything which can be overridden by the state saving! */
1312 if ( oInit.bStateSave )
1313 {
1314 features.bStateSave = true;
1315 _fnCallbackReg( oSettings, 'aoDrawCallback', _fnSaveState, 'state_save' );
1316 _fnLoadState( oSettings, oInit, loadedInit );
1317 }
1318 else {
1319 loadedInit();
1320 }
1321
1322 } );
1323 _that = null;
1324 return this;
1325 };
1326
1327
1328 /*
1329 * It is useful to have variables which are scoped locally so only the
1330 * DataTables functions can access them and they don't leak into global space.
1331 * At the same time these functions are often useful over multiple files in the
1332 * core and API, so we list, or at least document, all variables which are used
1333 * by DataTables as private variables here. This also ensures that there is no
1334 * clashing of variable names and that they can easily referenced for reuse.
1335 */
1336
1337
1338 // Defined else where
1339 // _selector_run
1340 // _selector_opts
1341 // _selector_first
1342 // _selector_row_indexes
1343
1344 var _ext; // DataTable.ext
1345 var _Api; // DataTable.Api
1346 var _api_register; // DataTable.Api.register
1347 var _api_registerPlural; // DataTable.Api.registerPlural
1348
1349 var _re_dic = {};
1350 var _re_new_lines = /[\r\n]/g;
1351 var _re_html = /<.*?>/g;
1352
1353 // This is not strict ISO8601 - Date.parse() is quite lax, although
1354 // implementations differ between browsers.
1355 var _re_date = /^\d{2,4}[\.\/\-]\d{1,2}[\.\/\-]\d{1,2}([T ]{1}\d{1,2}[:\.]\d{2}([\.:]\d{2})?)?$/;
1356
1357 // Escape regular expression special characters
1358 var _re_escape_regex = new RegExp( '(\\' + [ '/', '.', '*', '+', '?', '|', '(', ')', '[', ']', '{', '}', '\\', '$', '^', '-' ].join('|\\') + ')', 'g' );
1359
1360 // http://en.wikipedia.org/wiki/Foreign_exchange_market
1361 // - \u20BD - Russian ruble.
1362 // - \u20a9 - South Korean Won
1363 // - \u20BA - Turkish Lira
1364 // - \u20B9 - Indian Rupee
1365 // - R - Brazil (R$) and South Africa
1366 // - fr - Swiss Franc
1367 // - kr - Swedish krona, Norwegian krone and Danish krone
1368 // - \u2009 is thin space and \u202F is narrow no-break space, both used in many
1369 // standards as thousands separators.
1370 var _re_formatted_numeric = /[',$£€¥%\u2009\u202F\u20BD\u20a9\u20BArfk]/gi;
1371
1372
1373 var _empty = function ( d ) {
1374 return !d || d === true || d === '-' ? true : false;
1375 };
1376
1377
1378 var _intVal = function ( s ) {
1379 var integer = parseInt( s, 10 );
1380 return !isNaN(integer) && isFinite(s) ? integer : null;
1381 };
1382
1383 // Convert from a formatted number with characters other than `.` as the
1384 // decimal place, to a Javascript number
1385 var _numToDecimal = function ( num, decimalPoint ) {
1386 // Cache created regular expressions for speed as this function is called often
1387 if ( ! _re_dic[ decimalPoint ] ) {
1388 _re_dic[ decimalPoint ] = new RegExp( _fnEscapeRegex( decimalPoint ), 'g' );
1389 }
1390 return typeof num === 'string' && decimalPoint !== '.' ?
1391 num.replace( /\./g, '' ).replace( _re_dic[ decimalPoint ], '.' ) :
1392 num;
1393 };
1394
1395
1396 var _isNumber = function ( d, decimalPoint, formatted ) {
1397 var strType = typeof d === 'string';
1398
1399 // If empty return immediately so there must be a number if it is a
1400 // formatted string (this stops the string "k", or "kr", etc being detected
1401 // as a formatted number for currency
1402 if ( _empty( d ) ) {
1403 return true;
1404 }
1405
1406 if ( decimalPoint && strType ) {
1407 d = _numToDecimal( d, decimalPoint );
1408 }
1409
1410 if ( formatted && strType ) {
1411 d = d.replace( _re_formatted_numeric, '' );
1412 }
1413
1414 return !isNaN( parseFloat(d) ) && isFinite( d );
1415 };
1416
1417
1418 // A string without HTML in it can be considered to be HTML still
1419 var _isHtml = function ( d ) {
1420 return _empty( d ) || typeof d === 'string';
1421 };
1422
1423
1424 var _htmlNumeric = function ( d, decimalPoint, formatted ) {
1425 if ( _empty( d ) ) {
1426 return true;
1427 }
1428
1429 var html = _isHtml( d );
1430 return ! html ?
1431 null :
1432 _isNumber( _stripHtml( d ), decimalPoint, formatted ) ?
1433 true :
1434 null;
1435 };
1436
1437
1438 var _pluck = function ( a, prop, prop2 ) {
1439 var out = [];
1440 var i=0, ien=a.length;
1441
1442 // Could have the test in the loop for slightly smaller code, but speed
1443 // is essential here
1444 if ( prop2 !== undefined ) {
1445 for ( ; i<ien ; i++ ) {
1446 if ( a[i] && a[i][ prop ] ) {
1447 out.push( a[i][ prop ][ prop2 ] );
1448 }
1449 }
1450 }
1451 else {
1452 for ( ; i<ien ; i++ ) {
1453 if ( a[i] ) {
1454 out.push( a[i][ prop ] );
1455 }
1456 }
1457 }
1458
1459 return out;
1460 };
1461
1462
1463 // Basically the same as _pluck, but rather than looping over `a` we use `order`
1464 // as the indexes to pick from `a`
1465 var _pluck_order = function ( a, order, prop, prop2 )
1466 {
1467 var out = [];
1468 var i=0, ien=order.length;
1469
1470 // Could have the test in the loop for slightly smaller code, but speed
1471 // is essential here
1472 if ( prop2 !== undefined ) {
1473 for ( ; i<ien ; i++ ) {
1474 if ( a[ order[i] ][ prop ] ) {
1475 out.push( a[ order[i] ][ prop ][ prop2 ] );
1476 }
1477 }
1478 }
1479 else {
1480 for ( ; i<ien ; i++ ) {
1481 out.push( a[ order[i] ][ prop ] );
1482 }
1483 }
1484
1485 return out;
1486 };
1487
1488
1489 var _range = function ( len, start )
1490 {
1491 var out = [];
1492 var end;
1493
1494 if ( start === undefined ) {
1495 start = 0;
1496 end = len;
1497 }
1498 else {
1499 end = start;
1500 start = len;
1501 }
1502
1503 for ( var i=start ; i<end ; i++ ) {
1504 out.push( i );
1505 }
1506
1507 return out;
1508 };
1509
1510
1511 var _removeEmpty = function ( a )
1512 {
1513 var out = [];
1514
1515 for ( var i=0, ien=a.length ; i<ien ; i++ ) {
1516 if ( a[i] ) { // careful - will remove all falsy values!
1517 out.push( a[i] );
1518 }
1519 }
1520
1521 return out;
1522 };
1523
1524
1525 var _stripHtml = function ( d ) {
1526 return d.replace( _re_html, '' );
1527 };
1528
1529
1530 /**
1531 * Determine if all values in the array are unique. This means we can short
1532 * cut the _unique method at the cost of a single loop. A sorted array is used
1533 * to easily check the values.
1534 *
1535 * @param {array} src Source array
1536 * @return {boolean} true if all unique, false otherwise
1537 * @ignore
1538 */
1539 var _areAllUnique = function ( src ) {
1540 if ( src.length < 2 ) {
1541 return true;
1542 }
1543
1544 var sorted = src.slice().sort();
1545 var last = sorted[0];
1546
1547 for ( var i=1, ien=sorted.length ; i<ien ; i++ ) {
1548 if ( sorted[i] === last ) {
1549 return false;
1550 }
1551
1552 last = sorted[i];
1553 }
1554
1555 return true;
1556 };
1557
1558
1559 /**
1560 * Find the unique elements in a source array.
1561 *
1562 * @param {array} src Source array
1563 * @return {array} Array of unique items
1564 * @ignore
1565 */
1566 var _unique = function ( src )
1567 {
1568 if ( _areAllUnique( src ) ) {
1569 return src.slice();
1570 }
1571
1572 // A faster unique method is to use object keys to identify used values,
1573 // but this doesn't work with arrays or objects, which we must also
1574 // consider. See jsperf.com/compare-array-unique-versions/4 for more
1575 // information.
1576 var
1577 out = [],
1578 val,
1579 i, ien=src.length,
1580 j, k=0;
1581
1582 again: for ( i=0 ; i<ien ; i++ ) {
1583 val = src[i];
1584
1585 for ( j=0 ; j<k ; j++ ) {
1586 if ( out[j] === val ) {
1587 continue again;
1588 }
1589 }
1590
1591 out.push( val );
1592 k++;
1593 }
1594
1595 return out;
1596 };
1597
1598
1599 /**
1600 * DataTables utility methods
1601 *
1602 * This namespace provides helper methods that DataTables uses internally to
1603 * create a DataTable, but which are not exclusively used only for DataTables.
1604 * These methods can be used by extension authors to save the duplication of
1605 * code.
1606 *
1607 * @namespace
1608 */
1609 DataTable.util = {
1610 /**
1611 * Throttle the calls to a function. Arguments and context are maintained
1612 * for the throttled function.
1613 *
1614 * @param {function} fn Function to be called
1615 * @param {integer} freq Call frequency in mS
1616 * @return {function} Wrapped function
1617 */
1618 throttle: function ( fn, freq ) {
1619 var
1620 frequency = freq !== undefined ? freq : 200,
1621 last,
1622 timer;
1623
1624 return function () {
1625 var
1626 that = this,
1627 now = +new Date(),
1628 args = arguments;
1629
1630 if ( last && now < last + frequency ) {
1631 clearTimeout( timer );
1632
1633 timer = setTimeout( function () {
1634 last = undefined;
1635 fn.apply( that, args );
1636 }, frequency );
1637 }
1638 else {
1639 last = now;
1640 fn.apply( that, args );
1641 }
1642 };
1643 },
1644
1645
1646 /**
1647 * Escape a string such that it can be used in a regular expression
1648 *
1649 * @param {string} val string to escape
1650 * @returns {string} escaped string
1651 */
1652 escapeRegex: function ( val ) {
1653 return val.replace( _re_escape_regex, '\\$1' );
1654 }
1655 };
1656
1657
1658
1659 /**
1660 * Create a mapping object that allows camel case parameters to be looked up
1661 * for their Hungarian counterparts. The mapping is stored in a private
1662 * parameter called `_hungarianMap` which can be accessed on the source object.
1663 * @param {object} o
1664 * @memberof DataTable#oApi
1665 */
1666 function _fnHungarianMap ( o )
1667 {
1668 var
1669 hungarian = 'a aa ai ao as b fn i m o s ',
1670 match,
1671 newKey,
1672 map = {};
1673
1674 $.each( o, function (key, val) {
1675 match = key.match(/^([^A-Z]+?)([A-Z])/);
1676
1677 if ( match && hungarian.indexOf(match[1]+' ') !== -1 )
1678 {
1679 newKey = key.replace( match[0], match[2].toLowerCase() );
1680 map[ newKey ] = key;
1681
1682 if ( match[1] === 'o' )
1683 {
1684 _fnHungarianMap( o[key] );
1685 }
1686 }
1687 } );
1688
1689 o._hungarianMap = map;
1690 }
1691
1692
1693 /**
1694 * Convert from camel case parameters to Hungarian, based on a Hungarian map
1695 * created by _fnHungarianMap.
1696 * @param {object} src The model object which holds all parameters that can be
1697 * mapped.
1698 * @param {object} user The object to convert from camel case to Hungarian.
1699 * @param {boolean} force When set to `true`, properties which already have a
1700 * Hungarian value in the `user` object will be overwritten. Otherwise they
1701 * won't be.
1702 * @memberof DataTable#oApi
1703 */
1704 function _fnCamelToHungarian ( src, user, force )
1705 {
1706 if ( ! src._hungarianMap ) {
1707 _fnHungarianMap( src );
1708 }
1709
1710 var hungarianKey;
1711
1712 $.each( user, function (key, val) {
1713 hungarianKey = src._hungarianMap[ key ];
1714
1715 if ( hungarianKey !== undefined && (force || user[hungarianKey] === undefined) )
1716 {
1717 // For objects, we need to buzz down into the object to copy parameters
1718 if ( hungarianKey.charAt(0) === 'o' )
1719 {
1720 // Copy the camelCase options over to the hungarian
1721 if ( ! user[ hungarianKey ] ) {
1722 user[ hungarianKey ] = {};
1723 }
1724 $.extend( true, user[hungarianKey], user[key] );
1725
1726 _fnCamelToHungarian( src[hungarianKey], user[hungarianKey], force );
1727 }
1728 else {
1729 user[hungarianKey] = user[ key ];
1730 }
1731 }
1732 } );
1733 }
1734
1735
1736 /**
1737 * Language compatibility - when certain options are given, and others aren't, we
1738 * need to duplicate the values over, in order to provide backwards compatibility
1739 * with older language files.
1740 * @param {object} oSettings dataTables settings object
1741 * @memberof DataTable#oApi
1742 */
1743 function _fnLanguageCompat( lang )
1744 {
1745 var defaults = DataTable.defaults.oLanguage;
1746 var zeroRecords = lang.sZeroRecords;
1747
1748 /* Backwards compatibility - if there is no sEmptyTable given, then use the same as
1749 * sZeroRecords - assuming that is given.
1750 */
1751 if ( ! lang.sEmptyTable && zeroRecords &&
1752 defaults.sEmptyTable === "No data available in table" )
1753 {
1754 _fnMap( lang, lang, 'sZeroRecords', 'sEmptyTable' );
1755 }
1756
1757 /* Likewise with loading records */
1758 if ( ! lang.sLoadingRecords && zeroRecords &&
1759 defaults.sLoadingRecords === "Loading..." )
1760 {
1761 _fnMap( lang, lang, 'sZeroRecords', 'sLoadingRecords' );
1762 }
1763
1764 // Old parameter name of the thousands separator mapped onto the new
1765 if ( lang.sInfoThousands ) {
1766 lang.sThousands = lang.sInfoThousands;
1767 }
1768
1769 var decimal = lang.sDecimal;
1770 if ( decimal ) {
1771 _addNumericSort( decimal );
1772 }
1773 }
1774
1775
1776 /**
1777 * Map one parameter onto another
1778 * @param {object} o Object to map
1779 * @param {*} knew The new parameter name
1780 * @param {*} old The old parameter name
1781 */
1782 var _fnCompatMap = function ( o, knew, old ) {
1783 if ( o[ knew ] !== undefined ) {
1784 o[ old ] = o[ knew ];
1785 }
1786 };
1787
1788
1789 /**
1790 * Provide backwards compatibility for the main DT options. Note that the new
1791 * options are mapped onto the old parameters, so this is an external interface
1792 * change only.
1793 * @param {object} init Object to map
1794 */
1795 function _fnCompatOpts ( init )
1796 {
1797 _fnCompatMap( init, 'ordering', 'bSort' );
1798 _fnCompatMap( init, 'orderMulti', 'bSortMulti' );
1799 _fnCompatMap( init, 'orderClasses', 'bSortClasses' );
1800 _fnCompatMap( init, 'orderCellsTop', 'bSortCellsTop' );
1801 _fnCompatMap( init, 'order', 'aaSorting' );
1802 _fnCompatMap( init, 'orderFixed', 'aaSortingFixed' );
1803 _fnCompatMap( init, 'paging', 'bPaginate' );
1804 _fnCompatMap( init, 'pagingType', 'sPaginationType' );
1805 _fnCompatMap( init, 'pageLength', 'iDisplayLength' );
1806 _fnCompatMap( init, 'searching', 'bFilter' );
1807
1808 // Boolean initialisation of x-scrolling
1809 if ( typeof init.sScrollX === 'boolean' ) {
1810 init.sScrollX = init.sScrollX ? '100%' : '';
1811 }
1812 if ( typeof init.scrollX === 'boolean' ) {
1813 init.scrollX = init.scrollX ? '100%' : '';
1814 }
1815
1816 // Column search objects are in an array, so it needs to be converted
1817 // element by element
1818 var searchCols = init.aoSearchCols;
1819
1820 if ( searchCols ) {
1821 for ( var i=0, ien=searchCols.length ; i<ien ; i++ ) {
1822 if ( searchCols[i] ) {
1823 _fnCamelToHungarian( DataTable.models.oSearch, searchCols[i] );
1824 }
1825 }
1826 }
1827 }
1828
1829
1830 /**
1831 * Provide backwards compatibility for column options. Note that the new options
1832 * are mapped onto the old parameters, so this is an external interface change
1833 * only.
1834 * @param {object} init Object to map
1835 */
1836 function _fnCompatCols ( init )
1837 {
1838 _fnCompatMap( init, 'orderable', 'bSortable' );
1839 _fnCompatMap( init, 'orderData', 'aDataSort' );
1840 _fnCompatMap( init, 'orderSequence', 'asSorting' );
1841 _fnCompatMap( init, 'orderDataType', 'sortDataType' );
1842
1843 // orderData can be given as an integer
1844 var dataSort = init.aDataSort;
1845 if ( typeof dataSort === 'number' && ! $.isArray( dataSort ) ) {
1846 init.aDataSort = [ dataSort ];
1847 }
1848 }
1849
1850
1851 /**
1852 * Browser feature detection for capabilities, quirks
1853 * @param {object} settings dataTables settings object
1854 * @memberof DataTable#oApi
1855 */
1856 function _fnBrowserDetect( settings )
1857 {
1858 // We don't need to do this every time DataTables is constructed, the values
1859 // calculated are specific to the browser and OS configuration which we
1860 // don't expect to change between initialisations
1861 if ( ! DataTable.__browser ) {
1862 var browser = {};
1863 DataTable.__browser = browser;
1864
1865 // Scrolling feature / quirks detection
1866 var n = $('<div/>')
1867 .css( {
1868 position: 'fixed',
1869 top: 0,
1870 left: $(window).scrollLeft()*-1, // allow for scrolling
1871 height: 1,
1872 width: 1,
1873 overflow: 'hidden'
1874 } )
1875 .append(
1876 $('<div/>')
1877 .css( {
1878 position: 'absolute',
1879 top: 1,
1880 left: 1,
1881 width: 100,
1882 overflow: 'scroll'
1883 } )
1884 .append(
1885 $('<div/>')
1886 .css( {
1887 width: '100%',
1888 height: 10
1889 } )
1890 )
1891 )
1892 .appendTo( 'body' );
1893
1894 var outer = n.children();
1895 var inner = outer.children();
1896
1897 // Numbers below, in order, are:
1898 // inner.offsetWidth, inner.clientWidth, outer.offsetWidth, outer.clientWidth
1899 //
1900 // IE6 XP: 100 100 100 83
1901 // IE7 Vista: 100 100 100 83
1902 // IE 8+ Windows: 83 83 100 83
1903 // Evergreen Windows: 83 83 100 83
1904 // Evergreen Mac with scrollbars: 85 85 100 85
1905 // Evergreen Mac without scrollbars: 100 100 100 100
1906
1907 // Get scrollbar width
1908 browser.barWidth = outer[0].offsetWidth - outer[0].clientWidth;
1909
1910 // IE6/7 will oversize a width 100% element inside a scrolling element, to
1911 // include the width of the scrollbar, while other browsers ensure the inner
1912 // element is contained without forcing scrolling
1913 browser.bScrollOversize = inner[0].offsetWidth === 100 && outer[0].clientWidth !== 100;
1914
1915 // In rtl text layout, some browsers (most, but not all) will place the
1916 // scrollbar on the left, rather than the right.
1917 browser.bScrollbarLeft = Math.round( inner.offset().left ) !== 1;
1918
1919 // IE8- don't provide height and width for getBoundingClientRect
1920 browser.bBounding = n[0].getBoundingClientRect().width ? true : false;
1921
1922 n.remove();
1923 }
1924
1925 $.extend( settings.oBrowser, DataTable.__browser );
1926 settings.oScroll.iBarWidth = DataTable.__browser.barWidth;
1927 }
1928
1929
1930 /**
1931 * Array.prototype reduce[Right] method, used for browsers which don't support
1932 * JS 1.6. Done this way to reduce code size, since we iterate either way
1933 * @param {object} settings dataTables settings object
1934 * @memberof DataTable#oApi
1935 */
1936 function _fnReduce ( that, fn, init, start, end, inc )
1937 {
1938 var
1939 i = start,
1940 value,
1941 isSet = false;
1942
1943 if ( init !== undefined ) {
1944 value = init;
1945 isSet = true;
1946 }
1947
1948 while ( i !== end ) {
1949 if ( ! that.hasOwnProperty(i) ) {
1950 continue;
1951 }
1952
1953 value = isSet ?
1954 fn( value, that[i], i, that ) :
1955 that[i];
1956
1957 isSet = true;
1958 i += inc;
1959 }
1960
1961 return value;
1962 }
1963
1964 /**
1965 * Add a column to the list used for the table with default values
1966 * @param {object} oSettings dataTables settings object
1967 * @param {node} nTh The th element for this column
1968 * @memberof DataTable#oApi
1969 */
1970 function _fnAddColumn( oSettings, nTh )
1971 {
1972 // Add column to aoColumns array
1973 var oDefaults = DataTable.defaults.column;
1974 var iCol = oSettings.aoColumns.length;
1975 var oCol = $.extend( {}, DataTable.models.oColumn, oDefaults, {
1976 "nTh": nTh ? nTh : document.createElement('th'),
1977 "sTitle": oDefaults.sTitle ? oDefaults.sTitle : nTh ? nTh.innerHTML : '',
1978 "aDataSort": oDefaults.aDataSort ? oDefaults.aDataSort : [iCol],
1979 "mData": oDefaults.mData ? oDefaults.mData : iCol,
1980 idx: iCol
1981 } );
1982 oSettings.aoColumns.push( oCol );
1983
1984 // Add search object for column specific search. Note that the `searchCols[ iCol ]`
1985 // passed into extend can be undefined. This allows the user to give a default
1986 // with only some of the parameters defined, and also not give a default
1987 var searchCols = oSettings.aoPreSearchCols;
1988 searchCols[ iCol ] = $.extend( {}, DataTable.models.oSearch, searchCols[ iCol ] );
1989
1990 // Use the default column options function to initialise classes etc
1991 _fnColumnOptions( oSettings, iCol, $(nTh).data() );
1992 }
1993
1994
1995 /**
1996 * Apply options for a column
1997 * @param {object} oSettings dataTables settings object
1998 * @param {int} iCol column index to consider
1999 * @param {object} oOptions object with sType, bVisible and bSearchable etc
2000 * @memberof DataTable#oApi
2001 */
2002 function _fnColumnOptions( oSettings, iCol, oOptions )
2003 {
2004 var oCol = oSettings.aoColumns[ iCol ];
2005 var oClasses = oSettings.oClasses;
2006 var th = $(oCol.nTh);
2007
2008 // Try to get width information from the DOM. We can't get it from CSS
2009 // as we'd need to parse the CSS stylesheet. `width` option can override
2010 if ( ! oCol.sWidthOrig ) {
2011 // Width attribute
2012 oCol.sWidthOrig = th.attr('width') || null;
2013
2014 // Style attribute
2015 var t = (th.attr('style') || '').match(/width:\s*(\d+[pxem%]+)/);
2016 if ( t ) {
2017 oCol.sWidthOrig = t[1];
2018 }
2019 }
2020
2021 /* User specified column options */
2022 if ( oOptions !== undefined && oOptions !== null )
2023 {
2024 // Backwards compatibility
2025 _fnCompatCols( oOptions );
2026
2027 // Map camel case parameters to their Hungarian counterparts
2028 _fnCamelToHungarian( DataTable.defaults.column, oOptions );
2029
2030 /* Backwards compatibility for mDataProp */
2031 if ( oOptions.mDataProp !== undefined && !oOptions.mData )
2032 {
2033 oOptions.mData = oOptions.mDataProp;
2034 }
2035
2036 if ( oOptions.sType )
2037 {
2038 oCol._sManualType = oOptions.sType;
2039 }
2040
2041 // `class` is a reserved word in Javascript, so we need to provide
2042 // the ability to use a valid name for the camel case input
2043 if ( oOptions.className && ! oOptions.sClass )
2044 {
2045 oOptions.sClass = oOptions.className;
2046 }
2047 if ( oOptions.sClass ) {
2048 th.addClass( oOptions.sClass );
2049 }
2050
2051 $.extend( oCol, oOptions );
2052 _fnMap( oCol, oOptions, "sWidth", "sWidthOrig" );
2053
2054 /* iDataSort to be applied (backwards compatibility), but aDataSort will take
2055 * priority if defined
2056 */
2057 if ( oOptions.iDataSort !== undefined )
2058 {
2059 oCol.aDataSort = [ oOptions.iDataSort ];
2060 }
2061 _fnMap( oCol, oOptions, "aDataSort" );
2062 }
2063
2064 /* Cache the data get and set functions for speed */
2065 var mDataSrc = oCol.mData;
2066 var mData = _fnGetObjectDataFn( mDataSrc );
2067 var mRender = oCol.mRender ? _fnGetObjectDataFn( oCol.mRender ) : null;
2068
2069 var attrTest = function( src ) {
2070 return typeof src === 'string' && src.indexOf('@') !== -1;
2071 };
2072 oCol._bAttrSrc = $.isPlainObject( mDataSrc ) && (
2073 attrTest(mDataSrc.sort) || attrTest(mDataSrc.type) || attrTest(mDataSrc.filter)
2074 );
2075 oCol._setter = null;
2076
2077 oCol.fnGetData = function (rowData, type, meta) {
2078 var innerData = mData( rowData, type, undefined, meta );
2079
2080 return mRender && type ?
2081 mRender( innerData, type, rowData, meta ) :
2082 innerData;
2083 };
2084 oCol.fnSetData = function ( rowData, val, meta ) {
2085 return _fnSetObjectDataFn( mDataSrc )( rowData, val, meta );
2086 };
2087
2088 // Indicate if DataTables should read DOM data as an object or array
2089 // Used in _fnGetRowElements
2090 if ( typeof mDataSrc !== 'number' ) {
2091 oSettings._rowReadObject = true;
2092 }
2093
2094 /* Feature sorting overrides column specific when off */
2095 if ( !oSettings.oFeatures.bSort )
2096 {
2097 oCol.bSortable = false;
2098 th.addClass( oClasses.sSortableNone ); // Have to add class here as order event isn't called
2099 }
2100
2101 /* Check that the class assignment is correct for sorting */
2102 var bAsc = $.inArray('asc', oCol.asSorting) !== -1;
2103 var bDesc = $.inArray('desc', oCol.asSorting) !== -1;
2104 if ( !oCol.bSortable || (!bAsc && !bDesc) )
2105 {
2106 oCol.sSortingClass = oClasses.sSortableNone;
2107 oCol.sSortingClassJUI = "";
2108 }
2109 else if ( bAsc && !bDesc )
2110 {
2111 oCol.sSortingClass = oClasses.sSortableAsc;
2112 oCol.sSortingClassJUI = oClasses.sSortJUIAscAllowed;
2113 }
2114 else if ( !bAsc && bDesc )
2115 {
2116 oCol.sSortingClass = oClasses.sSortableDesc;
2117 oCol.sSortingClassJUI = oClasses.sSortJUIDescAllowed;
2118 }
2119 else
2120 {
2121 oCol.sSortingClass = oClasses.sSortable;
2122 oCol.sSortingClassJUI = oClasses.sSortJUI;
2123 }
2124 }
2125
2126
2127 /**
2128 * Adjust the table column widths for new data. Note: you would probably want to
2129 * do a redraw after calling this function!
2130 * @param {object} settings dataTables settings object
2131 * @memberof DataTable#oApi
2132 */
2133 function _fnAdjustColumnSizing ( settings )
2134 {
2135 /* Not interested in doing column width calculation if auto-width is disabled */
2136 if ( settings.oFeatures.bAutoWidth !== false )
2137 {
2138 var columns = settings.aoColumns;
2139
2140 _fnCalculateColumnWidths( settings );
2141 for ( var i=0 , iLen=columns.length ; i<iLen ; i++ )
2142 {
2143 columns[i].nTh.style.width = columns[i].sWidth;
2144 }
2145 }
2146
2147 var scroll = settings.oScroll;
2148 if ( scroll.sY !== '' || scroll.sX !== '')
2149 {
2150 _fnScrollDraw( settings );
2151 }
2152
2153 _fnCallbackFire( settings, null, 'column-sizing', [settings] );
2154 }
2155
2156
2157 /**
2158 * Covert the index of a visible column to the index in the data array (take account
2159 * of hidden columns)
2160 * @param {object} oSettings dataTables settings object
2161 * @param {int} iMatch Visible column index to lookup
2162 * @returns {int} i the data index
2163 * @memberof DataTable#oApi
2164 */
2165 function _fnVisibleToColumnIndex( oSettings, iMatch )
2166 {
2167 var aiVis = _fnGetColumns( oSettings, 'bVisible' );
2168
2169 return typeof aiVis[iMatch] === 'number' ?
2170 aiVis[iMatch] :
2171 null;
2172 }
2173
2174
2175 /**
2176 * Covert the index of an index in the data array and convert it to the visible
2177 * column index (take account of hidden columns)
2178 * @param {int} iMatch Column index to lookup
2179 * @param {object} oSettings dataTables settings object
2180 * @returns {int} i the data index
2181 * @memberof DataTable#oApi
2182 */
2183 function _fnColumnIndexToVisible( oSettings, iMatch )
2184 {
2185 var aiVis = _fnGetColumns( oSettings, 'bVisible' );
2186 var iPos = $.inArray( iMatch, aiVis );
2187
2188 return iPos !== -1 ? iPos : null;
2189 }
2190
2191
2192 /**
2193 * Get the number of visible columns
2194 * @param {object} oSettings dataTables settings object
2195 * @returns {int} i the number of visible columns
2196 * @memberof DataTable#oApi
2197 */
2198 function _fnVisbleColumns( oSettings )
2199 {
2200 var vis = 0;
2201
2202 // No reduce in IE8, use a loop for now
2203 $.each( oSettings.aoColumns, function ( i, col ) {
2204 if ( col.bVisible && $(col.nTh).css('display') !== 'none' ) {
2205 vis++;
2206 }
2207 } );
2208
2209 return vis;
2210 }
2211
2212
2213 /**
2214 * Get an array of column indexes that match a given property
2215 * @param {object} oSettings dataTables settings object
2216 * @param {string} sParam Parameter in aoColumns to look for - typically
2217 * bVisible or bSearchable
2218 * @returns {array} Array of indexes with matched properties
2219 * @memberof DataTable#oApi
2220 */
2221 function _fnGetColumns( oSettings, sParam )
2222 {
2223 var a = [];
2224
2225 $.map( oSettings.aoColumns, function(val, i) {
2226 if ( val[sParam] ) {
2227 a.push( i );
2228 }
2229 } );
2230
2231 return a;
2232 }
2233
2234
2235 /**
2236 * Calculate the 'type' of a column
2237 * @param {object} settings dataTables settings object
2238 * @memberof DataTable#oApi
2239 */
2240 function _fnColumnTypes ( settings )
2241 {
2242 var columns = settings.aoColumns;
2243 var data = settings.aoData;
2244 var types = DataTable.ext.type.detect;
2245 var i, ien, j, jen, k, ken;
2246 var col, cell, detectedType, cache;
2247
2248 // For each column, spin over the
2249 for ( i=0, ien=columns.length ; i<ien ; i++ ) {
2250 col = columns[i];
2251 cache = [];
2252
2253 if ( ! col.sType && col._sManualType ) {
2254 col.sType = col._sManualType;
2255 }
2256 else if ( ! col.sType ) {
2257 for ( j=0, jen=types.length ; j<jen ; j++ ) {
2258 for ( k=0, ken=data.length ; k<ken ; k++ ) {
2259 // Use a cache array so we only need to get the type data
2260 // from the formatter once (when using multiple detectors)
2261 if ( cache[k] === undefined ) {
2262 cache[k] = _fnGetCellData( settings, k, i, 'type' );
2263 }
2264
2265 detectedType = types[j]( cache[k], settings );
2266
2267 // If null, then this type can't apply to this column, so
2268 // rather than testing all cells, break out. There is an
2269 // exception for the last type which is `html`. We need to
2270 // scan all rows since it is possible to mix string and HTML
2271 // types
2272 if ( ! detectedType && j !== types.length-1 ) {
2273 break;
2274 }
2275
2276 // Only a single match is needed for html type since it is
2277 // bottom of the pile and very similar to string
2278 if ( detectedType === 'html' ) {
2279 break;
2280 }
2281 }
2282
2283 // Type is valid for all data points in the column - use this
2284 // type
2285 if ( detectedType ) {
2286 col.sType = detectedType;
2287 break;
2288 }
2289 }
2290
2291 // Fall back - if no type was detected, always use string
2292 if ( ! col.sType ) {
2293 col.sType = 'string';
2294 }
2295 }
2296 }
2297 }
2298
2299
2300 /**
2301 * Take the column definitions and static columns arrays and calculate how
2302 * they relate to column indexes. The callback function will then apply the
2303 * definition found for a column to a suitable configuration object.
2304 * @param {object} oSettings dataTables settings object
2305 * @param {array} aoColDefs The aoColumnDefs array that is to be applied
2306 * @param {array} aoCols The aoColumns array that defines columns individually
2307 * @param {function} fn Callback function - takes two parameters, the calculated
2308 * column index and the definition for that column.
2309 * @memberof DataTable#oApi
2310 */
2311 function _fnApplyColumnDefs( oSettings, aoColDefs, aoCols, fn )
2312 {
2313 var i, iLen, j, jLen, k, kLen, def;
2314 var columns = oSettings.aoColumns;
2315
2316 // Column definitions with aTargets
2317 if ( aoColDefs )
2318 {
2319 /* Loop over the definitions array - loop in reverse so first instance has priority */
2320 for ( i=aoColDefs.length-1 ; i>=0 ; i-- )
2321 {
2322 def = aoColDefs[i];
2323
2324 /* Each definition can target multiple columns, as it is an array */
2325 var aTargets = def.targets !== undefined ?
2326 def.targets :
2327 def.aTargets;
2328
2329 if ( ! $.isArray( aTargets ) )
2330 {
2331 aTargets = [ aTargets ];
2332 }
2333
2334 for ( j=0, jLen=aTargets.length ; j<jLen ; j++ )
2335 {
2336 if ( typeof aTargets[j] === 'number' && aTargets[j] >= 0 )
2337 {
2338 /* Add columns that we don't yet know about */
2339 while( columns.length <= aTargets[j] )
2340 {
2341 _fnAddColumn( oSettings );
2342 }
2343
2344 /* Integer, basic index */
2345 fn( aTargets[j], def );
2346 }
2347 else if ( typeof aTargets[j] === 'number' && aTargets[j] < 0 )
2348 {
2349 /* Negative integer, right to left column counting */
2350 fn( columns.length+aTargets[j], def );
2351 }
2352 else if ( typeof aTargets[j] === 'string' )
2353 {
2354 /* Class name matching on TH element */
2355 for ( k=0, kLen=columns.length ; k<kLen ; k++ )
2356 {
2357 if ( aTargets[j] == "_all" ||
2358 $(columns[k].nTh).hasClass( aTargets[j] ) )
2359 {
2360 fn( k, def );
2361 }
2362 }
2363 }
2364 }
2365 }
2366 }
2367
2368 // Statically defined columns array
2369 if ( aoCols )
2370 {
2371 for ( i=0, iLen=aoCols.length ; i<iLen ; i++ )
2372 {
2373 fn( i, aoCols[i] );
2374 }
2375 }
2376 }
2377
2378 /**
2379 * Add a data array to the table, creating DOM node etc. This is the parallel to
2380 * _fnGatherData, but for adding rows from a Javascript source, rather than a
2381 * DOM source.
2382 * @param {object} oSettings dataTables settings object
2383 * @param {array} aData data array to be added
2384 * @param {node} [nTr] TR element to add to the table - optional. If not given,
2385 * DataTables will create a row automatically
2386 * @param {array} [anTds] Array of TD|TH elements for the row - must be given
2387 * if nTr is.
2388 * @returns {int} >=0 if successful (index of new aoData entry), -1 if failed
2389 * @memberof DataTable#oApi
2390 */
2391 function _fnAddData ( oSettings, aDataIn, nTr, anTds )
2392 {
2393 /* Create the object for storing information about this new row */
2394 var iRow = oSettings.aoData.length;
2395 var oData = $.extend( true, {}, DataTable.models.oRow, {
2396 src: nTr ? 'dom' : 'data',
2397 idx: iRow
2398 } );
2399
2400 oData._aData = aDataIn;
2401 oSettings.aoData.push( oData );
2402
2403 /* Create the cells */
2404 var nTd, sThisType;
2405 var columns = oSettings.aoColumns;
2406
2407 // Invalidate the column types as the new data needs to be revalidated
2408 for ( var i=0, iLen=columns.length ; i<iLen ; i++ )
2409 {
2410 columns[i].sType = null;
2411 }
2412
2413 /* Add to the display array */
2414 oSettings.aiDisplayMaster.push( iRow );
2415
2416 var id = oSettings.rowIdFn( aDataIn );
2417 if ( id !== undefined ) {
2418 oSettings.aIds[ id ] = oData;
2419 }
2420
2421 /* Create the DOM information, or register it if already present */
2422 if ( nTr || ! oSettings.oFeatures.bDeferRender )
2423 {
2424 _fnCreateTr( oSettings, iRow, nTr, anTds );
2425 }
2426
2427 return iRow;
2428 }
2429
2430
2431 /**
2432 * Add one or more TR elements to the table. Generally we'd expect to
2433 * use this for reading data from a DOM sourced table, but it could be
2434 * used for an TR element. Note that if a TR is given, it is used (i.e.
2435 * it is not cloned).
2436 * @param {object} settings dataTables settings object
2437 * @param {array|node|jQuery} trs The TR element(s) to add to the table
2438 * @returns {array} Array of indexes for the added rows
2439 * @memberof DataTable#oApi
2440 */
2441 function _fnAddTr( settings, trs )
2442 {
2443 var row;
2444
2445 // Allow an individual node to be passed in
2446 if ( ! (trs instanceof $) ) {
2447 trs = $(trs);
2448 }
2449
2450 return trs.map( function (i, el) {
2451 row = _fnGetRowElements( settings, el );
2452 return _fnAddData( settings, row.data, el, row.cells );
2453 } );
2454 }
2455
2456
2457 /**
2458 * Take a TR element and convert it to an index in aoData
2459 * @param {object} oSettings dataTables settings object
2460 * @param {node} n the TR element to find
2461 * @returns {int} index if the node is found, null if not
2462 * @memberof DataTable#oApi
2463 */
2464 function _fnNodeToDataIndex( oSettings, n )
2465 {
2466 return (n._DT_RowIndex!==undefined) ? n._DT_RowIndex : null;
2467 }
2468
2469
2470 /**
2471 * Take a TD element and convert it into a column data index (not the visible index)
2472 * @param {object} oSettings dataTables settings object
2473 * @param {int} iRow The row number the TD/TH can be found in
2474 * @param {node} n The TD/TH element to find
2475 * @returns {int} index if the node is found, -1 if not
2476 * @memberof DataTable#oApi
2477 */
2478 function _fnNodeToColumnIndex( oSettings, iRow, n )
2479 {
2480 return $.inArray( n, oSettings.aoData[ iRow ].anCells );
2481 }
2482
2483
2484 /**
2485 * Get the data for a given cell from the internal cache, taking into account data mapping
2486 * @param {object} settings dataTables settings object
2487 * @param {int} rowIdx aoData row id
2488 * @param {int} colIdx Column index
2489 * @param {string} type data get type ('display', 'type' 'filter' 'sort')
2490 * @returns {*} Cell data
2491 * @memberof DataTable#oApi
2492 */
2493 function _fnGetCellData( settings, rowIdx, colIdx, type )
2494 {
2495 var draw = settings.iDraw;
2496 var col = settings.aoColumns[colIdx];
2497 var rowData = settings.aoData[rowIdx]._aData;
2498 var defaultContent = col.sDefaultContent;
2499 var cellData = col.fnGetData( rowData, type, {
2500 settings: settings,
2501 row: rowIdx,
2502 col: colIdx
2503 } );
2504
2505 if ( cellData === undefined ) {
2506 if ( settings.iDrawError != draw && defaultContent === null ) {
2507 _fnLog( settings, 0, "Requested unknown parameter "+
2508 (typeof col.mData=='function' ? '{function}' : "'"+col.mData+"'")+
2509 " for row "+rowIdx+", column "+colIdx, 4 );
2510 settings.iDrawError = draw;
2511 }
2512 return defaultContent;
2513 }
2514
2515 // When the data source is null and a specific data type is requested (i.e.
2516 // not the original data), we can use default column data
2517 if ( (cellData === rowData || cellData === null) && defaultContent !== null && type !== undefined ) {
2518 cellData = defaultContent;
2519 }
2520 else if ( typeof cellData === 'function' ) {
2521 // If the data source is a function, then we run it and use the return,
2522 // executing in the scope of the data object (for instances)
2523 return cellData.call( rowData );
2524 }
2525
2526 if ( cellData === null && type == 'display' ) {
2527 return '';
2528 }
2529 return cellData;
2530 }
2531
2532
2533 /**
2534 * Set the value for a specific cell, into the internal data cache
2535 * @param {object} settings dataTables settings object
2536 * @param {int} rowIdx aoData row id
2537 * @param {int} colIdx Column index
2538 * @param {*} val Value to set
2539 * @memberof DataTable#oApi
2540 */
2541 function _fnSetCellData( settings, rowIdx, colIdx, val )
2542 {
2543 var col = settings.aoColumns[colIdx];
2544 var rowData = settings.aoData[rowIdx]._aData;
2545
2546 col.fnSetData( rowData, val, {
2547 settings: settings,
2548 row: rowIdx,
2549 col: colIdx
2550 } );
2551 }
2552
2553
2554 // Private variable that is used to match action syntax in the data property object
2555 var __reArray = /\[.*?\]$/;
2556 var __reFn = /\(\)$/;
2557
2558 /**
2559 * Split string on periods, taking into account escaped periods
2560 * @param {string} str String to split
2561 * @return {array} Split string
2562 */
2563 function _fnSplitObjNotation( str )
2564 {
2565 return $.map( str.match(/(\\.|[^\.])+/g) || [''], function ( s ) {
2566 return s.replace(/\\\./g, '.');
2567 } );
2568 }
2569
2570
2571 /**
2572 * Return a function that can be used to get data from a source object, taking
2573 * into account the ability to use nested objects as a source
2574 * @param {string|int|function} mSource The data source for the object
2575 * @returns {function} Data get function
2576 * @memberof DataTable#oApi
2577 */
2578 function _fnGetObjectDataFn( mSource )
2579 {
2580 if ( $.isPlainObject( mSource ) )
2581 {
2582 /* Build an object of get functions, and wrap them in a single call */
2583 var o = {};
2584 $.each( mSource, function (key, val) {
2585 if ( val ) {
2586 o[key] = _fnGetObjectDataFn( val );
2587 }
2588 } );
2589
2590 return function (data, type, row, meta) {
2591 var t = o[type] || o._;
2592 return t !== undefined ?
2593 t(data, type, row, meta) :
2594 data;
2595 };
2596 }
2597 else if ( mSource === null )
2598 {
2599 /* Give an empty string for rendering / sorting etc */
2600 return function (data) { // type, row and meta also passed, but not used
2601 return data;
2602 };
2603 }
2604 else if ( typeof mSource === 'function' )
2605 {
2606 return function (data, type, row, meta) {
2607 return mSource( data, type, row, meta );
2608 };
2609 }
2610 else if ( typeof mSource === 'string' && (mSource.indexOf('.') !== -1 ||
2611 mSource.indexOf('[') !== -1 || mSource.indexOf('(') !== -1) )
2612 {
2613 /* If there is a . in the source string then the data source is in a
2614 * nested object so we loop over the data for each level to get the next
2615 * level down. On each loop we test for undefined, and if found immediately
2616 * return. This allows entire objects to be missing and sDefaultContent to
2617 * be used if defined, rather than throwing an error
2618 */
2619 var fetchData = function (data, type, src) {
2620 var arrayNotation, funcNotation, out, innerSrc;
2621
2622 if ( src !== "" )
2623 {
2624 var a = _fnSplitObjNotation( src );
2625
2626 for ( var i=0, iLen=a.length ; i<iLen ; i++ )
2627 {
2628 // Check if we are dealing with special notation
2629 arrayNotation = a[i].match(__reArray);
2630 funcNotation = a[i].match(__reFn);
2631
2632 if ( arrayNotation )
2633 {
2634 // Array notation
2635 a[i] = a[i].replace(__reArray, '');
2636
2637 // Condition allows simply [] to be passed in
2638 if ( a[i] !== "" ) {
2639 data = data[ a[i] ];
2640 }
2641 out = [];
2642
2643 // Get the remainder of the nested object to get
2644 a.splice( 0, i+1 );
2645 innerSrc = a.join('.');
2646
2647 // Traverse each entry in the array getting the properties requested
2648 if ( $.isArray( data ) ) {
2649 for ( var j=0, jLen=data.length ; j<jLen ; j++ ) {
2650 out.push( fetchData( data[j], type, innerSrc ) );
2651 }
2652 }
2653
2654 // If a string is given in between the array notation indicators, that
2655 // is used to join the strings together, otherwise an array is returned
2656 var join = arrayNotation[0].substring(1, arrayNotation[0].length-1);
2657 data = (join==="") ? out : out.join(join);
2658
2659 // The inner call to fetchData has already traversed through the remainder
2660 // of the source requested, so we exit from the loop
2661 break;
2662 }
2663 else if ( funcNotation )
2664 {
2665 // Function call
2666 a[i] = a[i].replace(__reFn, '');
2667 data = data[ a[i] ]();
2668 continue;
2669 }
2670
2671 if ( data === null || data[ a[i] ] === undefined )
2672 {
2673 return undefined;
2674 }
2675 data = data[ a[i] ];
2676 }
2677 }
2678
2679 return data;
2680 };
2681
2682 return function (data, type) { // row and meta also passed, but not used
2683 return fetchData( data, type, mSource );
2684 };
2685 }
2686 else
2687 {
2688 /* Array or flat object mapping */
2689 return function (data, type) { // row and meta also passed, but not used
2690 return data[mSource];
2691 };
2692 }
2693 }
2694
2695
2696 /**
2697 * Return a function that can be used to set data from a source object, taking
2698 * into account the ability to use nested objects as a source
2699 * @param {string|int|function} mSource The data source for the object
2700 * @returns {function} Data set function
2701 * @memberof DataTable#oApi
2702 */
2703 function _fnSetObjectDataFn( mSource )
2704 {
2705 if ( $.isPlainObject( mSource ) )
2706 {
2707 /* Unlike get, only the underscore (global) option is used for for
2708 * setting data since we don't know the type here. This is why an object
2709 * option is not documented for `mData` (which is read/write), but it is
2710 * for `mRender` which is read only.
2711 */
2712 return _fnSetObjectDataFn( mSource._ );
2713 }
2714 else if ( mSource === null )
2715 {
2716 /* Nothing to do when the data source is null */
2717 return function () {};
2718 }
2719 else if ( typeof mSource === 'function' )
2720 {
2721 return function (data, val, meta) {
2722 mSource( data, 'set', val, meta );
2723 };
2724 }
2725 else if ( typeof mSource === 'string' && (mSource.indexOf('.') !== -1 ||
2726 mSource.indexOf('[') !== -1 || mSource.indexOf('(') !== -1) )
2727 {
2728 /* Like the get, we need to get data from a nested object */
2729 var setData = function (data, val, src) {
2730 var a = _fnSplitObjNotation( src ), b;
2731 var aLast = a[a.length-1];
2732 var arrayNotation, funcNotation, o, innerSrc;
2733
2734 for ( var i=0, iLen=a.length-1 ; i<iLen ; i++ )
2735 {
2736 // Check if we are dealing with an array notation request
2737 arrayNotation = a[i].match(__reArray);
2738 funcNotation = a[i].match(__reFn);
2739
2740 if ( arrayNotation )
2741 {
2742 a[i] = a[i].replace(__reArray, '');
2743 data[ a[i] ] = [];
2744
2745 // Get the remainder of the nested object to set so we can recurse
2746 b = a.slice();
2747 b.splice( 0, i+1 );
2748 innerSrc = b.join('.');
2749
2750 // Traverse each entry in the array setting the properties requested
2751 if ( $.isArray( val ) )
2752 {
2753 for ( var j=0, jLen=val.length ; j<jLen ; j++ )
2754 {
2755 o = {};
2756 setData( o, val[j], innerSrc );
2757 data[ a[i] ].push( o );
2758 }
2759 }
2760 else
2761 {
2762 // We've been asked to save data to an array, but it
2763 // isn't array data to be saved. Best that can be done
2764 // is to just save the value.
2765 data[ a[i] ] = val;
2766 }
2767
2768 // The inner call to setData has already traversed through the remainder
2769 // of the source and has set the data, thus we can exit here
2770 return;
2771 }
2772 else if ( funcNotation )
2773 {
2774 // Function call
2775 a[i] = a[i].replace(__reFn, '');
2776 data = data[ a[i] ]( val );
2777 }
2778
2779 // If the nested object doesn't currently exist - since we are
2780 // trying to set the value - create it
2781 if ( data[ a[i] ] === null || data[ a[i] ] === undefined )
2782 {
2783 data[ a[i] ] = {};
2784 }
2785 data = data[ a[i] ];
2786 }
2787
2788 // Last item in the input - i.e, the actual set
2789 if ( aLast.match(__reFn ) )
2790 {
2791 // Function call
2792 data = data[ aLast.replace(__reFn, '') ]( val );
2793 }
2794 else
2795 {
2796 // If array notation is used, we just want to strip it and use the property name
2797 // and assign the value. If it isn't used, then we get the result we want anyway
2798 data[ aLast.replace(__reArray, '') ] = val;
2799 }
2800 };
2801
2802 return function (data, val) { // meta is also passed in, but not used
2803 return setData( data, val, mSource );
2804 };
2805 }
2806 else
2807 {
2808 /* Array or flat object mapping */
2809 return function (data, val) { // meta is also passed in, but not used
2810 data[mSource] = val;
2811 };
2812 }
2813 }
2814
2815
2816 /**
2817 * Return an array with the full table data
2818 * @param {object} oSettings dataTables settings object
2819 * @returns array {array} aData Master data array
2820 * @memberof DataTable#oApi
2821 */
2822 function _fnGetDataMaster ( settings )
2823 {
2824 return _pluck( settings.aoData, '_aData' );
2825 }
2826
2827
2828 /**
2829 * Nuke the table
2830 * @param {object} oSettings dataTables settings object
2831 * @memberof DataTable#oApi
2832 */
2833 function _fnClearTable( settings )
2834 {
2835 settings.aoData.length = 0;
2836 settings.aiDisplayMaster.length = 0;
2837 settings.aiDisplay.length = 0;
2838 settings.aIds = {};
2839 }
2840
2841
2842 /**
2843 * Take an array of integers (index array) and remove a target integer (value - not
2844 * the key!)
2845 * @param {array} a Index array to target
2846 * @param {int} iTarget value to find
2847 * @memberof DataTable#oApi
2848 */
2849 function _fnDeleteIndex( a, iTarget, splice )
2850 {
2851 var iTargetIndex = -1;
2852
2853 for ( var i=0, iLen=a.length ; i<iLen ; i++ )
2854 {
2855 if ( a[i] == iTarget )
2856 {
2857 iTargetIndex = i;
2858 }
2859 else if ( a[i] > iTarget )
2860 {
2861 a[i]--;
2862 }
2863 }
2864
2865 if ( iTargetIndex != -1 && splice === undefined )
2866 {
2867 a.splice( iTargetIndex, 1 );
2868 }
2869 }
2870
2871
2872 /**
2873 * Mark cached data as invalid such that a re-read of the data will occur when
2874 * the cached data is next requested. Also update from the data source object.
2875 *
2876 * @param {object} settings DataTables settings object
2877 * @param {int} rowIdx Row index to invalidate
2878 * @param {string} [src] Source to invalidate from: undefined, 'auto', 'dom'
2879 * or 'data'
2880 * @param {int} [colIdx] Column index to invalidate. If undefined the whole
2881 * row will be invalidated
2882 * @memberof DataTable#oApi
2883 *
2884 * @todo For the modularisation of v1.11 this will need to become a callback, so
2885 * the sort and filter methods can subscribe to it. That will required
2886 * initialisation options for sorting, which is why it is not already baked in
2887 */
2888 function _fnInvalidate( settings, rowIdx, src, colIdx )
2889 {
2890 var row = settings.aoData[ rowIdx ];
2891 var i, ien;
2892 var cellWrite = function ( cell, col ) {
2893 // This is very frustrating, but in IE if you just write directly
2894 // to innerHTML, and elements that are overwritten are GC'ed,
2895 // even if there is a reference to them elsewhere
2896 while ( cell.childNodes.length ) {
2897 cell.removeChild( cell.firstChild );
2898 }
2899
2900 cell.innerHTML = _fnGetCellData( settings, rowIdx, col, 'display' );
2901 };
2902
2903 // Are we reading last data from DOM or the data object?
2904 if ( src === 'dom' || ((! src || src === 'auto') && row.src === 'dom') ) {
2905 // Read the data from the DOM
2906 row._aData = _fnGetRowElements(
2907 settings, row, colIdx, colIdx === undefined ? undefined : row._aData
2908 )
2909 .data;
2910 }
2911 else {
2912 // Reading from data object, update the DOM
2913 var cells = row.anCells;
2914
2915 if ( cells ) {
2916 if ( colIdx !== undefined ) {
2917 cellWrite( cells[colIdx], colIdx );
2918 }
2919 else {
2920 for ( i=0, ien=cells.length ; i<ien ; i++ ) {
2921 cellWrite( cells[i], i );
2922 }
2923 }
2924 }
2925 }
2926
2927 // For both row and cell invalidation, the cached data for sorting and
2928 // filtering is nulled out
2929 row._aSortData = null;
2930 row._aFilterData = null;
2931
2932 // Invalidate the type for a specific column (if given) or all columns since
2933 // the data might have changed
2934 var cols = settings.aoColumns;
2935 if ( colIdx !== undefined ) {
2936 cols[ colIdx ].sType = null;
2937 }
2938 else {
2939 for ( i=0, ien=cols.length ; i<ien ; i++ ) {
2940 cols[i].sType = null;
2941 }
2942
2943 // Update DataTables special `DT_*` attributes for the row
2944 _fnRowAttributes( settings, row );
2945 }
2946 }
2947
2948
2949 /**
2950 * Build a data source object from an HTML row, reading the contents of the
2951 * cells that are in the row.
2952 *
2953 * @param {object} settings DataTables settings object
2954 * @param {node|object} TR element from which to read data or existing row
2955 * object from which to re-read the data from the cells
2956 * @param {int} [colIdx] Optional column index
2957 * @param {array|object} [d] Data source object. If `colIdx` is given then this
2958 * parameter should also be given and will be used to write the data into.
2959 * Only the column in question will be written
2960 * @returns {object} Object with two parameters: `data` the data read, in
2961 * document order, and `cells` and array of nodes (they can be useful to the
2962 * caller, so rather than needing a second traversal to get them, just return
2963 * them from here).
2964 * @memberof DataTable#oApi
2965 */
2966 function _fnGetRowElements( settings, row, colIdx, d )
2967 {
2968 var
2969 tds = [],
2970 td = row.firstChild,
2971 name, col, o, i=0, contents,
2972 columns = settings.aoColumns,
2973 objectRead = settings._rowReadObject;
2974
2975 // Allow the data object to be passed in, or construct
2976 d = d !== undefined ?
2977 d :
2978 objectRead ?
2979 {} :
2980 [];
2981
2982 var attr = function ( str, td ) {
2983 if ( typeof str === 'string' ) {
2984 var idx = str.indexOf('@');
2985
2986 if ( idx !== -1 ) {
2987 var attr = str.substring( idx+1 );
2988 var setter = _fnSetObjectDataFn( str );
2989 setter( d, td.getAttribute( attr ) );
2990 }
2991 }
2992 };
2993
2994 // Read data from a cell and store into the data object
2995 var cellProcess = function ( cell ) {
2996 if ( colIdx === undefined || colIdx === i ) {
2997 col = columns[i];
2998 contents = $.trim(cell.innerHTML);
2999
3000 if ( col && col._bAttrSrc ) {
3001 var setter = _fnSetObjectDataFn( col.mData._ );
3002 setter( d, contents );
3003
3004 attr( col.mData.sort, cell );
3005 attr( col.mData.type, cell );
3006 attr( col.mData.filter, cell );
3007 }
3008 else {
3009 // Depending on the `data` option for the columns the data can
3010 // be read to either an object or an array.
3011 if ( objectRead ) {
3012 if ( ! col._setter ) {
3013 // Cache the setter function
3014 col._setter = _fnSetObjectDataFn( col.mData );
3015 }
3016 col._setter( d, contents );
3017 }
3018 else {
3019 d[i] = contents;
3020 }
3021 }
3022 }
3023
3024 i++;
3025 };
3026
3027 if ( td ) {
3028 // `tr` element was passed in
3029 while ( td ) {
3030 name = td.nodeName.toUpperCase();
3031
3032 if ( name == "TD" || name == "TH" ) {
3033 cellProcess( td );
3034 tds.push( td );
3035 }
3036
3037 td = td.nextSibling;
3038 }
3039 }
3040 else {
3041 // Existing row object passed in
3042 tds = row.anCells;
3043
3044 for ( var j=0, jen=tds.length ; j<jen ; j++ ) {
3045 cellProcess( tds[j] );
3046 }
3047 }
3048
3049 // Read the ID from the DOM if present
3050 var rowNode = row.firstChild ? row : row.nTr;
3051
3052 if ( rowNode ) {
3053 var id = rowNode.getAttribute( 'id' );
3054
3055 if ( id ) {
3056 _fnSetObjectDataFn( settings.rowId )( d, id );
3057 }
3058 }
3059
3060 return {
3061 data: d,
3062 cells: tds
3063 };
3064 }
3065 /**
3066 * Create a new TR element (and it's TD children) for a row
3067 * @param {object} oSettings dataTables settings object
3068 * @param {int} iRow Row to consider
3069 * @param {node} [nTrIn] TR element to add to the table - optional. If not given,
3070 * DataTables will create a row automatically
3071 * @param {array} [anTds] Array of TD|TH elements for the row - must be given
3072 * if nTr is.
3073 * @memberof DataTable#oApi
3074 */
3075 function _fnCreateTr ( oSettings, iRow, nTrIn, anTds )
3076 {
3077 var
3078 row = oSettings.aoData[iRow],
3079 rowData = row._aData,
3080 cells = [],
3081 nTr, nTd, oCol,
3082 i, iLen;
3083
3084 if ( row.nTr === null )
3085 {
3086 nTr = nTrIn || document.createElement('tr');
3087
3088 row.nTr = nTr;
3089 row.anCells = cells;
3090
3091 /* Use a private property on the node to allow reserve mapping from the node
3092 * to the aoData array for fast look up
3093 */
3094 nTr._DT_RowIndex = iRow;
3095
3096 /* Special parameters can be given by the data source to be used on the row */
3097 _fnRowAttributes( oSettings, row );
3098
3099 /* Process each column */
3100 for ( i=0, iLen=oSettings.aoColumns.length ; i<iLen ; i++ )
3101 {
3102 oCol = oSettings.aoColumns[i];
3103
3104 nTd = nTrIn ? anTds[i] : document.createElement( oCol.sCellType );
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 ( (!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] );
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] );
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 = $.isFunction( ajaxData ) ?
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 = $.isFunction( ajaxData ) && 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 ( $.isFunction( ajax ) )
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 prevSearch.length > input.length ||
4411 input.indexOf(prevSearch) !== 0 ||
4412 settings.bSorted // On resort, the display master needs to be
4413 // re-filtered since indexes will have changed
4414 ) {
4415 settings.aiDisplay = displayMaster.slice();
4416 }
4417
4418 // Search the display array
4419 display = settings.aiDisplay;
4420
4421 for ( i=0 ; i<display.length ; i++ ) {
4422 if ( rpSearch.test( settings.aoData[ display[i] ]._sFilterRow ) ) {
4423 filtered.push( display[i] );
4424 }
4425 }
4426
4427 settings.aiDisplay = filtered;
4428 }
4429 }
4430
4431
4432 /**
4433 * Build a regular expression object suitable for searching a table
4434 * @param {string} sSearch string to search for
4435 * @param {bool} bRegex treat as a regular expression or not
4436 * @param {bool} bSmart perform smart filtering or not
4437 * @param {bool} bCaseInsensitive Do case insensitive matching or not
4438 * @returns {RegExp} constructed object
4439 * @memberof DataTable#oApi
4440 */
4441 function _fnFilterCreateSearch( search, regex, smart, caseInsensitive )
4442 {
4443 search = regex ?
4444 search :
4445 _fnEscapeRegex( search );
4446
4447 if ( smart ) {
4448 /* For smart filtering we want to allow the search to work regardless of
4449 * word order. We also want double quoted text to be preserved, so word
4450 * order is important - a la google. So this is what we want to
4451 * generate:
4452 *
4453 * ^(?=.*?\bone\b)(?=.*?\btwo three\b)(?=.*?\bfour\b).*$
4454 */
4455 var a = $.map( search.match( /"[^"]+"|[^ ]+/g ) || [''], function ( word ) {
4456 if ( word.charAt(0) === '"' ) {
4457 var m = word.match( /^"(.*)"$/ );
4458 word = m ? m[1] : word;
4459 }
4460
4461 return word.replace('"', '');
4462 } );
4463
4464 search = '^(?=.*?'+a.join( ')(?=.*?' )+').*$';
4465 }
4466
4467 return new RegExp( search, caseInsensitive ? 'i' : '' );
4468 }
4469
4470
4471 /**
4472 * Escape a string such that it can be used in a regular expression
4473 * @param {string} sVal string to escape
4474 * @returns {string} escaped string
4475 * @memberof DataTable#oApi
4476 */
4477 var _fnEscapeRegex = DataTable.util.escapeRegex;
4478
4479 var __filter_div = $('<div>')[0];
4480 var __filter_div_textContent = __filter_div.textContent !== undefined;
4481
4482 // Update the filtering data for each row if needed (by invalidation or first run)
4483 function _fnFilterData ( settings )
4484 {
4485 var columns = settings.aoColumns;
4486 var column;
4487 var i, j, ien, jen, filterData, cellData, row;
4488 var fomatters = DataTable.ext.type.search;
4489 var wasInvalidated = false;
4490
4491 for ( i=0, ien=settings.aoData.length ; i<ien ; i++ ) {
4492 row = settings.aoData[i];
4493
4494 if ( ! row._aFilterData ) {
4495 filterData = [];
4496
4497 for ( j=0, jen=columns.length ; j<jen ; j++ ) {
4498 column = columns[j];
4499
4500 if ( column.bSearchable ) {
4501 cellData = _fnGetCellData( settings, i, j, 'filter' );
4502
4503 if ( fomatters[ column.sType ] ) {
4504 cellData = fomatters[ column.sType ]( cellData );
4505 }
4506
4507 // Search in DataTables 1.10 is string based. In 1.11 this
4508 // should be altered to also allow strict type checking.
4509 if ( cellData === null ) {
4510 cellData = '';
4511 }
4512
4513 if ( typeof cellData !== 'string' && cellData.toString ) {
4514 cellData = cellData.toString();
4515 }
4516 }
4517 else {
4518 cellData = '';
4519 }
4520
4521 // If it looks like there is an HTML entity in the string,
4522 // attempt to decode it so sorting works as expected. Note that
4523 // we could use a single line of jQuery to do this, but the DOM
4524 // method used here is much faster http://jsperf.com/html-decode
4525 if ( cellData.indexOf && cellData.indexOf('&') !== -1 ) {
4526 __filter_div.innerHTML = cellData;
4527 cellData = __filter_div_textContent ?
4528 __filter_div.textContent :
4529 __filter_div.innerText;
4530 }
4531
4532 if ( cellData.replace ) {
4533 cellData = cellData.replace(/[\r\n]/g, '');
4534 }
4535
4536 filterData.push( cellData );
4537 }
4538
4539 row._aFilterData = filterData;
4540 row._sFilterRow = filterData.join(' ');
4541 wasInvalidated = true;
4542 }
4543 }
4544
4545 return wasInvalidated;
4546 }
4547
4548
4549 /**
4550 * Convert from the internal Hungarian notation to camelCase for external
4551 * interaction
4552 * @param {object} obj Object to convert
4553 * @returns {object} Inverted object
4554 * @memberof DataTable#oApi
4555 */
4556 function _fnSearchToCamel ( obj )
4557 {
4558 return {
4559 search: obj.sSearch,
4560 smart: obj.bSmart,
4561 regex: obj.bRegex,
4562 caseInsensitive: obj.bCaseInsensitive
4563 };
4564 }
4565
4566
4567
4568 /**
4569 * Convert from camelCase notation to the internal Hungarian. We could use the
4570 * Hungarian convert function here, but this is cleaner
4571 * @param {object} obj Object to convert
4572 * @returns {object} Inverted object
4573 * @memberof DataTable#oApi
4574 */
4575 function _fnSearchToHung ( obj )
4576 {
4577 return {
4578 sSearch: obj.search,
4579 bSmart: obj.smart,
4580 bRegex: obj.regex,
4581 bCaseInsensitive: obj.caseInsensitive
4582 };
4583 }
4584
4585 /**
4586 * Generate the node required for the info display
4587 * @param {object} oSettings dataTables settings object
4588 * @returns {node} Information element
4589 * @memberof DataTable#oApi
4590 */
4591 function _fnFeatureHtmlInfo ( settings )
4592 {
4593 var
4594 tid = settings.sTableId,
4595 nodes = settings.aanFeatures.i,
4596 n = $('<div/>', {
4597 'class': settings.oClasses.sInfo,
4598 'id': ! nodes ? tid+'_info' : null
4599 } );
4600
4601 if ( ! nodes ) {
4602 // Update display on each draw
4603 settings.aoDrawCallback.push( {
4604 "fn": _fnUpdateInfo,
4605 "sName": "information"
4606 } );
4607
4608 n
4609 .attr( 'role', 'status' )
4610 .attr( 'aria-live', 'polite' );
4611
4612 // Table is described by our info div
4613 $(settings.nTable).attr( 'aria-describedby', tid+'_info' );
4614 }
4615
4616 return n[0];
4617 }
4618
4619
4620 /**
4621 * Update the information elements in the display
4622 * @param {object} settings dataTables settings object
4623 * @memberof DataTable#oApi
4624 */
4625 function _fnUpdateInfo ( settings )
4626 {
4627 /* Show information about the table */
4628 var nodes = settings.aanFeatures.i;
4629 if ( nodes.length === 0 ) {
4630 return;
4631 }
4632
4633 var
4634 lang = settings.oLanguage,
4635 start = settings._iDisplayStart+1,
4636 end = settings.fnDisplayEnd(),
4637 max = settings.fnRecordsTotal(),
4638 total = settings.fnRecordsDisplay(),
4639 out = total ?
4640 lang.sInfo :
4641 lang.sInfoEmpty;
4642
4643 if ( total !== max ) {
4644 /* Record set after filtering */
4645 out += ' ' + lang.sInfoFiltered;
4646 }
4647
4648 // Convert the macros
4649 out += lang.sInfoPostFix;
4650 out = _fnInfoMacros( settings, out );
4651
4652 var callback = lang.fnInfoCallback;
4653 if ( callback !== null ) {
4654 out = callback.call( settings.oInstance,
4655 settings, start, end, max, total, out
4656 );
4657 }
4658
4659 $(nodes).html( out );
4660 }
4661
4662
4663 function _fnInfoMacros ( settings, str )
4664 {
4665 // When infinite scrolling, we are always starting at 1. _iDisplayStart is used only
4666 // internally
4667 var
4668 formatter = settings.fnFormatNumber,
4669 start = settings._iDisplayStart+1,
4670 len = settings._iDisplayLength,
4671 vis = settings.fnRecordsDisplay(),
4672 all = len === -1;
4673
4674 return str.
4675 replace(/_START_/g, formatter.call( settings, start ) ).
4676 replace(/_END_/g, formatter.call( settings, settings.fnDisplayEnd() ) ).
4677 replace(/_MAX_/g, formatter.call( settings, settings.fnRecordsTotal() ) ).
4678 replace(/_TOTAL_/g, formatter.call( settings, vis ) ).
4679 replace(/_PAGE_/g, formatter.call( settings, all ? 1 : Math.ceil( start / len ) ) ).
4680 replace(/_PAGES_/g, formatter.call( settings, all ? 1 : Math.ceil( vis / len ) ) );
4681 }
4682
4683
4684
4685 /**
4686 * Draw the table for the first time, adding all required features
4687 * @param {object} settings dataTables settings object
4688 * @memberof DataTable#oApi
4689 */
4690 function _fnInitialise ( settings )
4691 {
4692 var i, iLen, iAjaxStart=settings.iInitDisplayStart;
4693 var columns = settings.aoColumns, column;
4694 var features = settings.oFeatures;
4695 var deferLoading = settings.bDeferLoading; // value modified by the draw
4696
4697 /* Ensure that the table data is fully initialised */
4698 if ( ! settings.bInitialised ) {
4699 setTimeout( function(){ _fnInitialise( settings ); }, 200 );
4700 return;
4701 }
4702
4703 /* Show the display HTML options */
4704 _fnAddOptionsHtml( settings );
4705
4706 /* Build and draw the header / footer for the table */
4707 _fnBuildHead( settings );
4708 _fnDrawHead( settings, settings.aoHeader );
4709 _fnDrawHead( settings, settings.aoFooter );
4710
4711 /* Okay to show that something is going on now */
4712 _fnProcessingDisplay( settings, true );
4713
4714 /* Calculate sizes for columns */
4715 if ( features.bAutoWidth ) {
4716 _fnCalculateColumnWidths( settings );
4717 }
4718
4719 for ( i=0, iLen=columns.length ; i<iLen ; i++ ) {
4720 column = columns[i];
4721
4722 if ( column.sWidth ) {
4723 column.nTh.style.width = _fnStringToCss( column.sWidth );
4724 }
4725 }
4726
4727 _fnCallbackFire( settings, null, 'preInit', [settings] );
4728
4729 // If there is default sorting required - let's do it. The sort function
4730 // will do the drawing for us. Otherwise we draw the table regardless of the
4731 // Ajax source - this allows the table to look initialised for Ajax sourcing
4732 // data (show 'loading' message possibly)
4733 _fnReDraw( settings );
4734
4735 // Server-side processing init complete is done by _fnAjaxUpdateDraw
4736 var dataSrc = _fnDataSource( settings );
4737 if ( dataSrc != 'ssp' || deferLoading ) {
4738 // if there is an ajax source load the data
4739 if ( dataSrc == 'ajax' ) {
4740 _fnBuildAjax( settings, [], function(json) {
4741 var aData = _fnAjaxDataSrc( settings, json );
4742
4743 // Got the data - add it to the table
4744 for ( i=0 ; i<aData.length ; i++ ) {
4745 _fnAddData( settings, aData[i] );
4746 }
4747
4748 // Reset the init display for cookie saving. We've already done
4749 // a filter, and therefore cleared it before. So we need to make
4750 // it appear 'fresh'
4751 settings.iInitDisplayStart = iAjaxStart;
4752
4753 _fnReDraw( settings );
4754
4755 _fnProcessingDisplay( settings, false );
4756 _fnInitComplete( settings, json );
4757 }, settings );
4758 }
4759 else {
4760 _fnProcessingDisplay( settings, false );
4761 _fnInitComplete( settings );
4762 }
4763 }
4764 }
4765
4766
4767 /**
4768 * Draw the table for the first time, adding all required features
4769 * @param {object} oSettings dataTables settings object
4770 * @param {object} [json] JSON from the server that completed the table, if using Ajax source
4771 * with client-side processing (optional)
4772 * @memberof DataTable#oApi
4773 */
4774 function _fnInitComplete ( settings, json )
4775 {
4776 settings._bInitComplete = true;
4777
4778 // When data was added after the initialisation (data or Ajax) we need to
4779 // calculate the column sizing
4780 if ( json || settings.oInit.aaData ) {
4781 _fnAdjustColumnSizing( settings );
4782 }
4783
4784 _fnCallbackFire( settings, null, 'plugin-init', [settings, json] );
4785 _fnCallbackFire( settings, 'aoInitComplete', 'init', [settings, json] );
4786 }
4787
4788
4789 function _fnLengthChange ( settings, val )
4790 {
4791 var len = parseInt( val, 10 );
4792 settings._iDisplayLength = len;
4793
4794 _fnLengthOverflow( settings );
4795
4796 // Fire length change event
4797 _fnCallbackFire( settings, null, 'length', [settings, len] );
4798 }
4799
4800
4801 /**
4802 * Generate the node required for user display length changing
4803 * @param {object} settings dataTables settings object
4804 * @returns {node} Display length feature node
4805 * @memberof DataTable#oApi
4806 */
4807 function _fnFeatureHtmlLength ( settings )
4808 {
4809 var
4810 classes = settings.oClasses,
4811 tableId = settings.sTableId,
4812 menu = settings.aLengthMenu,
4813 d2 = $.isArray( menu[0] ),
4814 lengths = d2 ? menu[0] : menu,
4815 language = d2 ? menu[1] : menu;
4816
4817 var select = $('<select/>', {
4818 'name': tableId+'_length',
4819 'aria-controls': tableId,
4820 'class': classes.sLengthSelect
4821 } );
4822
4823 for ( var i=0, ien=lengths.length ; i<ien ; i++ ) {
4824 select[0][ i ] = new Option(
4825 typeof language[i] === 'number' ?
4826 settings.fnFormatNumber( language[i] ) :
4827 language[i],
4828 lengths[i]
4829 );
4830 }
4831
4832 var div = $('<div><label/></div>').addClass( classes.sLength );
4833 if ( ! settings.aanFeatures.l ) {
4834 div[0].id = tableId+'_length';
4835 }
4836
4837 div.children().append(
4838 settings.oLanguage.sLengthMenu.replace( '_MENU_', select[0].outerHTML )
4839 );
4840
4841 // Can't use `select` variable as user might provide their own and the
4842 // reference is broken by the use of outerHTML
4843 $('select', div)
4844 .val( settings._iDisplayLength )
4845 .on( 'change.DT', function(e) {
4846 _fnLengthChange( settings, $(this).val() );
4847 _fnDraw( settings );
4848 } );
4849
4850 // Update node value whenever anything changes the table's length
4851 $(settings.nTable).on( 'length.dt.DT', function (e, s, len) {
4852 if ( settings === s ) {
4853 $('select', div).val( len );
4854 }
4855 } );
4856
4857 return div[0];
4858 }
4859
4860
4861
4862 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
4863 * Note that most of the paging logic is done in
4864 * DataTable.ext.pager
4865 */
4866
4867 /**
4868 * Generate the node required for default pagination
4869 * @param {object} oSettings dataTables settings object
4870 * @returns {node} Pagination feature node
4871 * @memberof DataTable#oApi
4872 */
4873 function _fnFeatureHtmlPaginate ( settings )
4874 {
4875 var
4876 type = settings.sPaginationType,
4877 plugin = DataTable.ext.pager[ type ],
4878 modern = typeof plugin === 'function',
4879 redraw = function( settings ) {
4880 _fnDraw( settings );
4881 },
4882 node = $('<div/>').addClass( settings.oClasses.sPaging + type )[0],
4883 features = settings.aanFeatures;
4884
4885 if ( ! modern ) {
4886 plugin.fnInit( settings, node, redraw );
4887 }
4888
4889 /* Add a draw callback for the pagination on first instance, to update the paging display */
4890 if ( ! features.p )
4891 {
4892 node.id = settings.sTableId+'_paginate';
4893
4894 settings.aoDrawCallback.push( {
4895 "fn": function( settings ) {
4896 if ( modern ) {
4897 var
4898 start = settings._iDisplayStart,
4899 len = settings._iDisplayLength,
4900 visRecords = settings.fnRecordsDisplay(),
4901 all = len === -1,
4902 page = all ? 0 : Math.ceil( start / len ),
4903 pages = all ? 1 : Math.ceil( visRecords / len ),
4904 buttons = plugin(page, pages),
4905 i, ien;
4906
4907 for ( i=0, ien=features.p.length ; i<ien ; i++ ) {
4908 _fnRenderer( settings, 'pageButton' )(
4909 settings, features.p[i], i, buttons, page, pages
4910 );
4911 }
4912 }
4913 else {
4914 plugin.fnUpdate( settings, redraw );
4915 }
4916 },
4917 "sName": "pagination"
4918 } );
4919 }
4920
4921 return node;
4922 }
4923
4924
4925 /**
4926 * Alter the display settings to change the page
4927 * @param {object} settings DataTables settings object
4928 * @param {string|int} action Paging action to take: "first", "previous",
4929 * "next" or "last" or page number to jump to (integer)
4930 * @param [bool] redraw Automatically draw the update or not
4931 * @returns {bool} true page has changed, false - no change
4932 * @memberof DataTable#oApi
4933 */
4934 function _fnPageChange ( settings, action, redraw )
4935 {
4936 var
4937 start = settings._iDisplayStart,
4938 len = settings._iDisplayLength,
4939 records = settings.fnRecordsDisplay();
4940
4941 if ( records === 0 || len === -1 )
4942 {
4943 start = 0;
4944 }
4945 else if ( typeof action === "number" )
4946 {
4947 start = action * len;
4948
4949 if ( start > records )
4950 {
4951 start = 0;
4952 }
4953 }
4954 else if ( action == "first" )
4955 {
4956 start = 0;
4957 }
4958 else if ( action == "previous" )
4959 {
4960 start = len >= 0 ?
4961 start - len :
4962 0;
4963
4964 if ( start < 0 )
4965 {
4966 start = 0;
4967 }
4968 }
4969 else if ( action == "next" )
4970 {
4971 if ( start + len < records )
4972 {
4973 start += len;
4974 }
4975 }
4976 else if ( action == "last" )
4977 {
4978 start = Math.floor( (records-1) / len) * len;
4979 }
4980 else
4981 {
4982 _fnLog( settings, 0, "Unknown paging action: "+action, 5 );
4983 }
4984
4985 var changed = settings._iDisplayStart !== start;
4986 settings._iDisplayStart = start;
4987
4988 if ( changed ) {
4989 _fnCallbackFire( settings, null, 'page', [settings] );
4990
4991 if ( redraw ) {
4992 _fnDraw( settings );
4993 }
4994 }
4995
4996 return changed;
4997 }
4998
4999
5000
5001 /**
5002 * Generate the node required for the processing node
5003 * @param {object} settings dataTables settings object
5004 * @returns {node} Processing element
5005 * @memberof DataTable#oApi
5006 */
5007 function _fnFeatureHtmlProcessing ( settings )
5008 {
5009 return $('<div/>', {
5010 'id': ! settings.aanFeatures.r ? settings.sTableId+'_processing' : null,
5011 'class': settings.oClasses.sProcessing
5012 } )
5013 .html( settings.oLanguage.sProcessing )
5014 .insertBefore( settings.nTable )[0];
5015 }
5016
5017
5018 /**
5019 * Display or hide the processing indicator
5020 * @param {object} settings dataTables settings object
5021 * @param {bool} show Show the processing indicator (true) or not (false)
5022 * @memberof DataTable#oApi
5023 */
5024 function _fnProcessingDisplay ( settings, show )
5025 {
5026 if ( settings.oFeatures.bProcessing ) {
5027 $(settings.aanFeatures.r).css( 'display', show ? 'block' : 'none' );
5028 }
5029
5030 _fnCallbackFire( settings, null, 'processing', [settings, show] );
5031 }
5032
5033 /**
5034 * Add any control elements for the table - specifically scrolling
5035 * @param {object} settings dataTables settings object
5036 * @returns {node} Node to add to the DOM
5037 * @memberof DataTable#oApi
5038 */
5039 function _fnFeatureHtmlTable ( settings )
5040 {
5041 var table = $(settings.nTable);
5042
5043 // Add the ARIA grid role to the table
5044 table.attr( 'role', 'grid' );
5045
5046 // Scrolling from here on in
5047 var scroll = settings.oScroll;
5048
5049 if ( scroll.sX === '' && scroll.sY === '' ) {
5050 return settings.nTable;
5051 }
5052
5053 var scrollX = scroll.sX;
5054 var scrollY = scroll.sY;
5055 var classes = settings.oClasses;
5056 var caption = table.children('caption');
5057 var captionSide = caption.length ? caption[0]._captionSide : null;
5058 var headerClone = $( table[0].cloneNode(false) );
5059 var footerClone = $( table[0].cloneNode(false) );
5060 var footer = table.children('tfoot');
5061 var _div = '<div/>';
5062 var size = function ( s ) {
5063 return !s ? null : _fnStringToCss( s );
5064 };
5065
5066 if ( ! footer.length ) {
5067 footer = null;
5068 }
5069
5070 /*
5071 * The HTML structure that we want to generate in this function is:
5072 * div - scroller
5073 * div - scroll head
5074 * div - scroll head inner
5075 * table - scroll head table
5076 * thead - thead
5077 * div - scroll body
5078 * table - table (master table)
5079 * thead - thead clone for sizing
5080 * tbody - tbody
5081 * div - scroll foot
5082 * div - scroll foot inner
5083 * table - scroll foot table
5084 * tfoot - tfoot
5085 */
5086 var scroller = $( _div, { 'class': classes.sScrollWrapper } )
5087 .append(
5088 $(_div, { 'class': classes.sScrollHead } )
5089 .css( {
5090 overflow: 'hidden',
5091 position: 'relative',
5092 border: 0,
5093 width: scrollX ? size(scrollX) : '100%'
5094 } )
5095 .append(
5096 $(_div, { 'class': classes.sScrollHeadInner } )
5097 .css( {
5098 'box-sizing': 'content-box',
5099 width: scroll.sXInner || '100%'
5100 } )
5101 .append(
5102 headerClone
5103 .removeAttr('id')
5104 .css( 'margin-left', 0 )
5105 .append( captionSide === 'top' ? caption : null )
5106 .append(
5107 table.children('thead')
5108 )
5109 )
5110 )
5111 )
5112 .append(
5113 $(_div, { 'class': classes.sScrollBody } )
5114 .css( {
5115 position: 'relative',
5116 overflow: 'auto',
5117 width: size( scrollX )
5118 } )
5119 .append( table )
5120 );
5121
5122 if ( footer ) {
5123 scroller.append(
5124 $(_div, { 'class': classes.sScrollFoot } )
5125 .css( {
5126 overflow: 'hidden',
5127 border: 0,
5128 width: scrollX ? size(scrollX) : '100%'
5129 } )
5130 .append(
5131 $(_div, { 'class': classes.sScrollFootInner } )
5132 .append(
5133 footerClone
5134 .removeAttr('id')
5135 .css( 'margin-left', 0 )
5136 .append( captionSide === 'bottom' ? caption : null )
5137 .append(
5138 table.children('tfoot')
5139 )
5140 )
5141 )
5142 );
5143 }
5144
5145 var children = scroller.children();
5146 var scrollHead = children[0];
5147 var scrollBody = children[1];
5148 var scrollFoot = footer ? children[2] : null;
5149
5150 // When the body is scrolled, then we also want to scroll the headers
5151 if ( scrollX ) {
5152 $(scrollBody).on( 'scroll.DT', function (e) {
5153 var scrollLeft = this.scrollLeft;
5154
5155 scrollHead.scrollLeft = scrollLeft;
5156
5157 if ( footer ) {
5158 scrollFoot.scrollLeft = scrollLeft;
5159 }
5160 } );
5161 }
5162
5163 $(scrollBody).css(
5164 scrollY && scroll.bCollapse ? 'max-height' : 'height',
5165 scrollY
5166 );
5167
5168 settings.nScrollHead = scrollHead;
5169 settings.nScrollBody = scrollBody;
5170 settings.nScrollFoot = scrollFoot;
5171
5172 // On redraw - align columns
5173 settings.aoDrawCallback.push( {
5174 "fn": _fnScrollDraw,
5175 "sName": "scrolling"
5176 } );
5177
5178 return scroller[0];
5179 }
5180
5181
5182
5183 /**
5184 * Update the header, footer and body tables for resizing - i.e. column
5185 * alignment.
5186 *
5187 * Welcome to the most horrible function DataTables. The process that this
5188 * function follows is basically:
5189 * 1. Re-create the table inside the scrolling div
5190 * 2. Take live measurements from the DOM
5191 * 3. Apply the measurements to align the columns
5192 * 4. Clean up
5193 *
5194 * @param {object} settings dataTables settings object
5195 * @memberof DataTable#oApi
5196 */
5197 function _fnScrollDraw ( settings )
5198 {
5199 // Given that this is such a monster function, a lot of variables are use
5200 // to try and keep the minimised size as small as possible
5201 var
5202 scroll = settings.oScroll,
5203 scrollX = scroll.sX,
5204 scrollXInner = scroll.sXInner,
5205 scrollY = scroll.sY,
5206 barWidth = scroll.iBarWidth,
5207 divHeader = $(settings.nScrollHead),
5208 divHeaderStyle = divHeader[0].style,
5209 divHeaderInner = divHeader.children('div'),
5210 divHeaderInnerStyle = divHeaderInner[0].style,
5211 divHeaderTable = divHeaderInner.children('table'),
5212 divBodyEl = settings.nScrollBody,
5213 divBody = $(divBodyEl),
5214 divBodyStyle = divBodyEl.style,
5215 divFooter = $(settings.nScrollFoot),
5216 divFooterInner = divFooter.children('div'),
5217 divFooterTable = divFooterInner.children('table'),
5218 header = $(settings.nTHead),
5219 table = $(settings.nTable),
5220 tableEl = table[0],
5221 tableStyle = tableEl.style,
5222 footer = settings.nTFoot ? $(settings.nTFoot) : null,
5223 browser = settings.oBrowser,
5224 ie67 = browser.bScrollOversize,
5225 dtHeaderCells = _pluck( settings.aoColumns, 'nTh' ),
5226 headerTrgEls, footerTrgEls,
5227 headerSrcEls, footerSrcEls,
5228 headerCopy, footerCopy,
5229 headerWidths=[], footerWidths=[],
5230 headerContent=[], footerContent=[],
5231 idx, correction, sanityWidth,
5232 zeroOut = function(nSizer) {
5233 var style = nSizer.style;
5234 style.paddingTop = "0";
5235 style.paddingBottom = "0";
5236 style.borderTopWidth = "0";
5237 style.borderBottomWidth = "0";
5238 style.height = 0;
5239 };
5240
5241 // If the scrollbar visibility has changed from the last draw, we need to
5242 // adjust the column sizes as the table width will have changed to account
5243 // for the scrollbar
5244 var scrollBarVis = divBodyEl.scrollHeight > divBodyEl.clientHeight;
5245
5246 if ( settings.scrollBarVis !== scrollBarVis && settings.scrollBarVis !== undefined ) {
5247 settings.scrollBarVis = scrollBarVis;
5248 _fnAdjustColumnSizing( settings );
5249 return; // adjust column sizing will call this function again
5250 }
5251 else {
5252 settings.scrollBarVis = scrollBarVis;
5253 }
5254
5255 /*
5256 * 1. Re-create the table inside the scrolling div
5257 */
5258
5259 // Remove the old minimised thead and tfoot elements in the inner table
5260 table.children('thead, tfoot').remove();
5261
5262 if ( footer ) {
5263 footerCopy = footer.clone().prependTo( table );
5264 footerTrgEls = footer.find('tr'); // the original tfoot is in its own table and must be sized
5265 footerSrcEls = footerCopy.find('tr');
5266 }
5267
5268 // Clone the current header and footer elements and then place it into the inner table
5269 headerCopy = header.clone().prependTo( table );
5270 headerTrgEls = header.find('tr'); // original header is in its own table
5271 headerSrcEls = headerCopy.find('tr');
5272 headerCopy.find('th, td').removeAttr('tabindex');
5273
5274
5275 /*
5276 * 2. Take live measurements from the DOM - do not alter the DOM itself!
5277 */
5278
5279 // Remove old sizing and apply the calculated column widths
5280 // Get the unique column headers in the newly created (cloned) header. We want to apply the
5281 // calculated sizes to this header
5282 if ( ! scrollX )
5283 {
5284 divBodyStyle.width = '100%';
5285 divHeader[0].style.width = '100%';
5286 }
5287
5288 $.each( _fnGetUniqueThs( settings, headerCopy ), function ( i, el ) {
5289 idx = _fnVisibleToColumnIndex( settings, i );
5290 el.style.width = settings.aoColumns[idx].sWidth;
5291 } );
5292
5293 if ( footer ) {
5294 _fnApplyToChildren( function(n) {
5295 n.style.width = "";
5296 }, footerSrcEls );
5297 }
5298
5299 // Size the table as a whole
5300 sanityWidth = table.outerWidth();
5301 if ( scrollX === "" ) {
5302 // No x scrolling
5303 tableStyle.width = "100%";
5304
5305 // IE7 will make the width of the table when 100% include the scrollbar
5306 // - which is shouldn't. When there is a scrollbar we need to take this
5307 // into account.
5308 if ( ie67 && (table.find('tbody').height() > divBodyEl.offsetHeight ||
5309 divBody.css('overflow-y') == "scroll")
5310 ) {
5311 tableStyle.width = _fnStringToCss( table.outerWidth() - barWidth);
5312 }
5313
5314 // Recalculate the sanity width
5315 sanityWidth = table.outerWidth();
5316 }
5317 else if ( scrollXInner !== "" ) {
5318 // legacy x scroll inner has been given - use it
5319 tableStyle.width = _fnStringToCss(scrollXInner);
5320
5321 // Recalculate the sanity width
5322 sanityWidth = table.outerWidth();
5323 }
5324
5325 // Hidden header should have zero height, so remove padding and borders. Then
5326 // set the width based on the real headers
5327
5328 // Apply all styles in one pass
5329 _fnApplyToChildren( zeroOut, headerSrcEls );
5330
5331 // Read all widths in next pass
5332 _fnApplyToChildren( function(nSizer) {
5333 headerContent.push( nSizer.innerHTML );
5334 headerWidths.push( _fnStringToCss( $(nSizer).css('width') ) );
5335 }, headerSrcEls );
5336
5337 // Apply all widths in final pass
5338 _fnApplyToChildren( function(nToSize, i) {
5339 // Only apply widths to the DataTables detected header cells - this
5340 // prevents complex headers from having contradictory sizes applied
5341 if ( $.inArray( nToSize, dtHeaderCells ) !== -1 ) {
5342 nToSize.style.width = headerWidths[i];
5343 }
5344 }, headerTrgEls );
5345
5346 $(headerSrcEls).height(0);
5347
5348 /* Same again with the footer if we have one */
5349 if ( footer )
5350 {
5351 _fnApplyToChildren( zeroOut, footerSrcEls );
5352
5353 _fnApplyToChildren( function(nSizer) {
5354 footerContent.push( nSizer.innerHTML );
5355 footerWidths.push( _fnStringToCss( $(nSizer).css('width') ) );
5356 }, footerSrcEls );
5357
5358 _fnApplyToChildren( function(nToSize, i) {
5359 nToSize.style.width = footerWidths[i];
5360 }, footerTrgEls );
5361
5362 $(footerSrcEls).height(0);
5363 }
5364
5365
5366 /*
5367 * 3. Apply the measurements
5368 */
5369
5370 // "Hide" the header and footer that we used for the sizing. We need to keep
5371 // the content of the cell so that the width applied to the header and body
5372 // both match, but we want to hide it completely. We want to also fix their
5373 // width to what they currently are
5374 _fnApplyToChildren( function(nSizer, i) {
5375 nSizer.innerHTML = '<div class="dataTables_sizing" style="height:0;overflow:hidden;">'+headerContent[i]+'</div>';
5376 nSizer.style.width = headerWidths[i];
5377 }, headerSrcEls );
5378
5379 if ( footer )
5380 {
5381 _fnApplyToChildren( function(nSizer, i) {
5382 nSizer.innerHTML = '<div class="dataTables_sizing" style="height:0;overflow:hidden;">'+footerContent[i]+'</div>';
5383 nSizer.style.width = footerWidths[i];
5384 }, footerSrcEls );
5385 }
5386
5387 // Sanity check that the table is of a sensible width. If not then we are going to get
5388 // misalignment - try to prevent this by not allowing the table to shrink below its min width
5389 if ( table.outerWidth() < sanityWidth )
5390 {
5391 // The min width depends upon if we have a vertical scrollbar visible or not */
5392 correction = ((divBodyEl.scrollHeight > divBodyEl.offsetHeight ||
5393 divBody.css('overflow-y') == "scroll")) ?
5394 sanityWidth+barWidth :
5395 sanityWidth;
5396
5397 // IE6/7 are a law unto themselves...
5398 if ( ie67 && (divBodyEl.scrollHeight >
5399 divBodyEl.offsetHeight || divBody.css('overflow-y') == "scroll")
5400 ) {
5401 tableStyle.width = _fnStringToCss( correction-barWidth );
5402 }
5403
5404 // And give the user a warning that we've stopped the table getting too small
5405 if ( scrollX === "" || scrollXInner !== "" ) {
5406 _fnLog( settings, 1, 'Possible column misalignment', 6 );
5407 }
5408 }
5409 else
5410 {
5411 correction = '100%';
5412 }
5413
5414 // Apply to the container elements
5415 divBodyStyle.width = _fnStringToCss( correction );
5416 divHeaderStyle.width = _fnStringToCss( correction );
5417
5418 if ( footer ) {
5419 settings.nScrollFoot.style.width = _fnStringToCss( correction );
5420 }
5421
5422
5423 /*
5424 * 4. Clean up
5425 */
5426 if ( ! scrollY ) {
5427 /* IE7< puts a vertical scrollbar in place (when it shouldn't be) due to subtracting
5428 * the scrollbar height from the visible display, rather than adding it on. We need to
5429 * set the height in order to sort this. Don't want to do it in any other browsers.
5430 */
5431 if ( ie67 ) {
5432 divBodyStyle.height = _fnStringToCss( tableEl.offsetHeight+barWidth );
5433 }
5434 }
5435
5436 /* Finally set the width's of the header and footer tables */
5437 var iOuterWidth = table.outerWidth();
5438 divHeaderTable[0].style.width = _fnStringToCss( iOuterWidth );
5439 divHeaderInnerStyle.width = _fnStringToCss( iOuterWidth );
5440
5441 // Figure out if there are scrollbar present - if so then we need a the header and footer to
5442 // provide a bit more space to allow "overflow" scrolling (i.e. past the scrollbar)
5443 var bScrolling = table.height() > divBodyEl.clientHeight || divBody.css('overflow-y') == "scroll";
5444 var padding = 'padding' + (browser.bScrollbarLeft ? 'Left' : 'Right' );
5445 divHeaderInnerStyle[ padding ] = bScrolling ? barWidth+"px" : "0px";
5446
5447 if ( footer ) {
5448 divFooterTable[0].style.width = _fnStringToCss( iOuterWidth );
5449 divFooterInner[0].style.width = _fnStringToCss( iOuterWidth );
5450 divFooterInner[0].style[padding] = bScrolling ? barWidth+"px" : "0px";
5451 }
5452
5453 // Correct DOM ordering for colgroup - comes before the thead
5454 table.children('colgroup').insertBefore( table.children('thead') );
5455
5456 /* Adjust the position of the header in case we loose the y-scrollbar */
5457 divBody.scroll();
5458
5459 // If sorting or filtering has occurred, jump the scrolling back to the top
5460 // only if we aren't holding the position
5461 if ( (settings.bSorted || settings.bFiltered) && ! settings._drawHold ) {
5462 divBodyEl.scrollTop = 0;
5463 }
5464 }
5465
5466
5467
5468 /**
5469 * Apply a given function to the display child nodes of an element array (typically
5470 * TD children of TR rows
5471 * @param {function} fn Method to apply to the objects
5472 * @param array {nodes} an1 List of elements to look through for display children
5473 * @param array {nodes} an2 Another list (identical structure to the first) - optional
5474 * @memberof DataTable#oApi
5475 */
5476 function _fnApplyToChildren( fn, an1, an2 )
5477 {
5478 var index=0, i=0, iLen=an1.length;
5479 var nNode1, nNode2;
5480
5481 while ( i < iLen ) {
5482 nNode1 = an1[i].firstChild;
5483 nNode2 = an2 ? an2[i].firstChild : null;
5484
5485 while ( nNode1 ) {
5486 if ( nNode1.nodeType === 1 ) {
5487 if ( an2 ) {
5488 fn( nNode1, nNode2, index );
5489 }
5490 else {
5491 fn( nNode1, index );
5492 }
5493
5494 index++;
5495 }
5496
5497 nNode1 = nNode1.nextSibling;
5498 nNode2 = an2 ? nNode2.nextSibling : null;
5499 }
5500
5501 i++;
5502 }
5503 }
5504
5505
5506
5507 var __re_html_remove = /<.*?>/g;
5508
5509
5510 /**
5511 * Calculate the width of columns for the table
5512 * @param {object} oSettings dataTables settings object
5513 * @memberof DataTable#oApi
5514 */
5515 function _fnCalculateColumnWidths ( oSettings )
5516 {
5517 var
5518 table = oSettings.nTable,
5519 columns = oSettings.aoColumns,
5520 scroll = oSettings.oScroll,
5521 scrollY = scroll.sY,
5522 scrollX = scroll.sX,
5523 scrollXInner = scroll.sXInner,
5524 columnCount = columns.length,
5525 visibleColumns = _fnGetColumns( oSettings, 'bVisible' ),
5526 headerCells = $('th', oSettings.nTHead),
5527 tableWidthAttr = table.getAttribute('width'), // from DOM element
5528 tableContainer = table.parentNode,
5529 userInputs = false,
5530 i, column, columnIdx, width, outerWidth,
5531 browser = oSettings.oBrowser,
5532 ie67 = browser.bScrollOversize;
5533
5534 var styleWidth = table.style.width;
5535 if ( styleWidth && styleWidth.indexOf('%') !== -1 ) {
5536 tableWidthAttr = styleWidth;
5537 }
5538
5539 /* Convert any user input sizes into pixel sizes */
5540 for ( i=0 ; i<visibleColumns.length ; i++ ) {
5541 column = columns[ visibleColumns[i] ];
5542
5543 if ( column.sWidth !== null ) {
5544 column.sWidth = _fnConvertToWidth( column.sWidthOrig, tableContainer );
5545
5546 userInputs = true;
5547 }
5548 }
5549
5550 /* If the number of columns in the DOM equals the number that we have to
5551 * process in DataTables, then we can use the offsets that are created by
5552 * the web- browser. No custom sizes can be set in order for this to happen,
5553 * nor scrolling used
5554 */
5555 if ( ie67 || ! userInputs && ! scrollX && ! scrollY &&
5556 columnCount == _fnVisbleColumns( oSettings ) &&
5557 columnCount == headerCells.length
5558 ) {
5559 for ( i=0 ; i<columnCount ; i++ ) {
5560 var colIdx = _fnVisibleToColumnIndex( oSettings, i );
5561
5562 if ( colIdx !== null ) {
5563 columns[ colIdx ].sWidth = _fnStringToCss( headerCells.eq(i).width() );
5564 }
5565 }
5566 }
5567 else
5568 {
5569 // Otherwise construct a single row, worst case, table with the widest
5570 // node in the data, assign any user defined widths, then insert it into
5571 // the DOM and allow the browser to do all the hard work of calculating
5572 // table widths
5573 var tmpTable = $(table).clone() // don't use cloneNode - IE8 will remove events on the main table
5574 .css( 'visibility', 'hidden' )
5575 .removeAttr( 'id' );
5576
5577 // Clean up the table body
5578 tmpTable.find('tbody tr').remove();
5579 var tr = $('<tr/>').appendTo( tmpTable.find('tbody') );
5580
5581 // Clone the table header and footer - we can't use the header / footer
5582 // from the cloned table, since if scrolling is active, the table's
5583 // real header and footer are contained in different table tags
5584 tmpTable.find('thead, tfoot').remove();
5585 tmpTable
5586 .append( $(oSettings.nTHead).clone() )
5587 .append( $(oSettings.nTFoot).clone() );
5588
5589 // Remove any assigned widths from the footer (from scrolling)
5590 tmpTable.find('tfoot th, tfoot td').css('width', '');
5591
5592 // Apply custom sizing to the cloned header
5593 headerCells = _fnGetUniqueThs( oSettings, tmpTable.find('thead')[0] );
5594
5595 for ( i=0 ; i<visibleColumns.length ; i++ ) {
5596 column = columns[ visibleColumns[i] ];
5597
5598 headerCells[i].style.width = column.sWidthOrig !== null && column.sWidthOrig !== '' ?
5599 _fnStringToCss( column.sWidthOrig ) :
5600 '';
5601
5602 // For scrollX we need to force the column width otherwise the
5603 // browser will collapse it. If this width is smaller than the
5604 // width the column requires, then it will have no effect
5605 if ( column.sWidthOrig && scrollX ) {
5606 $( headerCells[i] ).append( $('<div/>').css( {
5607 width: column.sWidthOrig,
5608 margin: 0,
5609 padding: 0,
5610 border: 0,
5611 height: 1
5612 } ) );
5613 }
5614 }
5615
5616 // Find the widest cell for each column and put it into the table
5617 if ( oSettings.aoData.length ) {
5618 for ( i=0 ; i<visibleColumns.length ; i++ ) {
5619 columnIdx = visibleColumns[i];
5620 column = columns[ columnIdx ];
5621
5622 $( _fnGetWidestNode( oSettings, columnIdx ) )
5623 .clone( false )
5624 .append( column.sContentPadding )
5625 .appendTo( tr );
5626 }
5627 }
5628
5629 // Tidy the temporary table - remove name attributes so there aren't
5630 // duplicated in the dom (radio elements for example)
5631 $('[name]', tmpTable).removeAttr('name');
5632
5633 // Table has been built, attach to the document so we can work with it.
5634 // A holding element is used, positioned at the top of the container
5635 // with minimal height, so it has no effect on if the container scrolls
5636 // or not. Otherwise it might trigger scrolling when it actually isn't
5637 // needed
5638 var holder = $('<div/>').css( scrollX || scrollY ?
5639 {
5640 position: 'absolute',
5641 top: 0,
5642 left: 0,
5643 height: 1,
5644 right: 0,
5645 overflow: 'hidden'
5646 } :
5647 {}
5648 )
5649 .append( tmpTable )
5650 .appendTo( tableContainer );
5651
5652 // When scrolling (X or Y) we want to set the width of the table as
5653 // appropriate. However, when not scrolling leave the table width as it
5654 // is. This results in slightly different, but I think correct behaviour
5655 if ( scrollX && scrollXInner ) {
5656 tmpTable.width( scrollXInner );
5657 }
5658 else if ( scrollX ) {
5659 tmpTable.css( 'width', 'auto' );
5660 tmpTable.removeAttr('width');
5661
5662 // If there is no width attribute or style, then allow the table to
5663 // collapse
5664 if ( tmpTable.width() < tableContainer.clientWidth && tableWidthAttr ) {
5665 tmpTable.width( tableContainer.clientWidth );
5666 }
5667 }
5668 else if ( scrollY ) {
5669 tmpTable.width( tableContainer.clientWidth );
5670 }
5671 else if ( tableWidthAttr ) {
5672 tmpTable.width( tableWidthAttr );
5673 }
5674
5675 // Get the width of each column in the constructed table - we need to
5676 // know the inner width (so it can be assigned to the other table's
5677 // cells) and the outer width so we can calculate the full width of the
5678 // table. This is safe since DataTables requires a unique cell for each
5679 // column, but if ever a header can span multiple columns, this will
5680 // need to be modified.
5681 var total = 0;
5682 for ( i=0 ; i<visibleColumns.length ; i++ ) {
5683 var cell = $(headerCells[i]);
5684 var border = cell.outerWidth() - cell.width();
5685
5686 // Use getBounding... where possible (not IE8-) because it can give
5687 // sub-pixel accuracy, which we then want to round up!
5688 var bounding = browser.bBounding ?
5689 Math.ceil( headerCells[i].getBoundingClientRect().width ) :
5690 cell.outerWidth();
5691
5692 // Total is tracked to remove any sub-pixel errors as the outerWidth
5693 // of the table might not equal the total given here (IE!).
5694 total += bounding;
5695
5696 // Width for each column to use
5697 columns[ visibleColumns[i] ].sWidth = _fnStringToCss( bounding - border );
5698 }
5699
5700 table.style.width = _fnStringToCss( total );
5701
5702 // Finished with the table - ditch it
5703 holder.remove();
5704 }
5705
5706 // If there is a width attr, we want to attach an event listener which
5707 // allows the table sizing to automatically adjust when the window is
5708 // resized. Use the width attr rather than CSS, since we can't know if the
5709 // CSS is a relative value or absolute - DOM read is always px.
5710 if ( tableWidthAttr ) {
5711 table.style.width = _fnStringToCss( tableWidthAttr );
5712 }
5713
5714 if ( (tableWidthAttr || scrollX) && ! oSettings._reszEvt ) {
5715 var bindResize = function () {
5716 $(window).on('resize.DT-'+oSettings.sInstance, _fnThrottle( function () {
5717 _fnAdjustColumnSizing( oSettings );
5718 } ) );
5719 };
5720
5721 // IE6/7 will crash if we bind a resize event handler on page load.
5722 // To be removed in 1.11 which drops IE6/7 support
5723 if ( ie67 ) {
5724 setTimeout( bindResize, 1000 );
5725 }
5726 else {
5727 bindResize();
5728 }
5729
5730 oSettings._reszEvt = true;
5731 }
5732 }
5733
5734
5735 /**
5736 * Throttle the calls to a function. Arguments and context are maintained for
5737 * the throttled function
5738 * @param {function} fn Function to be called
5739 * @param {int} [freq=200] call frequency in mS
5740 * @returns {function} wrapped function
5741 * @memberof DataTable#oApi
5742 */
5743 var _fnThrottle = DataTable.util.throttle;
5744
5745
5746 /**
5747 * Convert a CSS unit width to pixels (e.g. 2em)
5748 * @param {string} width width to be converted
5749 * @param {node} parent parent to get the with for (required for relative widths) - optional
5750 * @returns {int} width in pixels
5751 * @memberof DataTable#oApi
5752 */
5753 function _fnConvertToWidth ( width, parent )
5754 {
5755 if ( ! width ) {
5756 return 0;
5757 }
5758
5759 var n = $('<div/>')
5760 .css( 'width', _fnStringToCss( width ) )
5761 .appendTo( parent || document.body );
5762
5763 var val = n[0].offsetWidth;
5764 n.remove();
5765
5766 return val;
5767 }
5768
5769
5770 /**
5771 * Get the widest node
5772 * @param {object} settings dataTables settings object
5773 * @param {int} colIdx column of interest
5774 * @returns {node} widest table node
5775 * @memberof DataTable#oApi
5776 */
5777 function _fnGetWidestNode( settings, colIdx )
5778 {
5779 var idx = _fnGetMaxLenString( settings, colIdx );
5780 if ( idx < 0 ) {
5781 return null;
5782 }
5783
5784 var data = settings.aoData[ idx ];
5785 return ! data.nTr ? // Might not have been created when deferred rendering
5786 $('<td/>').html( _fnGetCellData( settings, idx, colIdx, 'display' ) )[0] :
5787 data.anCells[ colIdx ];
5788 }
5789
5790
5791 /**
5792 * Get the maximum strlen for each data column
5793 * @param {object} settings dataTables settings object
5794 * @param {int} colIdx column of interest
5795 * @returns {string} max string length for each column
5796 * @memberof DataTable#oApi
5797 */
5798 function _fnGetMaxLenString( settings, colIdx )
5799 {
5800 var s, max=-1, maxIdx = -1;
5801
5802 for ( var i=0, ien=settings.aoData.length ; i<ien ; i++ ) {
5803 s = _fnGetCellData( settings, i, colIdx, 'display' )+'';
5804 s = s.replace( __re_html_remove, '' );
5805 s = s.replace( /&nbsp;/g, ' ' );
5806
5807 if ( s.length > max ) {
5808 max = s.length;
5809 maxIdx = i;
5810 }
5811 }
5812
5813 return maxIdx;
5814 }
5815
5816
5817 /**
5818 * Append a CSS unit (only if required) to a string
5819 * @param {string} value to css-ify
5820 * @returns {string} value with css unit
5821 * @memberof DataTable#oApi
5822 */
5823 function _fnStringToCss( s )
5824 {
5825 if ( s === null ) {
5826 return '0px';
5827 }
5828
5829 if ( typeof s == 'number' ) {
5830 return s < 0 ?
5831 '0px' :
5832 s+'px';
5833 }
5834
5835 // Check it has a unit character already
5836 return s.match(/\d$/) ?
5837 s+'px' :
5838 s;
5839 }
5840
5841
5842
5843 function _fnSortFlatten ( settings )
5844 {
5845 var
5846 i, iLen, k, kLen,
5847 aSort = [],
5848 aiOrig = [],
5849 aoColumns = settings.aoColumns,
5850 aDataSort, iCol, sType, srcCol,
5851 fixed = settings.aaSortingFixed,
5852 fixedObj = $.isPlainObject( fixed ),
5853 nestedSort = [],
5854 add = function ( a ) {
5855 if ( a.length && ! $.isArray( a[0] ) ) {
5856 // 1D array
5857 nestedSort.push( a );
5858 }
5859 else {
5860 // 2D array
5861 $.merge( nestedSort, a );
5862 }
5863 };
5864
5865 // Build the sort array, with pre-fix and post-fix options if they have been
5866 // specified
5867 if ( $.isArray( fixed ) ) {
5868 add( fixed );
5869 }
5870
5871 if ( fixedObj && fixed.pre ) {
5872 add( fixed.pre );
5873 }
5874
5875 add( settings.aaSorting );
5876
5877 if (fixedObj && fixed.post ) {
5878 add( fixed.post );
5879 }
5880
5881 for ( i=0 ; i<nestedSort.length ; i++ )
5882 {
5883 srcCol = nestedSort[i][0];
5884 aDataSort = aoColumns[ srcCol ].aDataSort;
5885
5886 for ( k=0, kLen=aDataSort.length ; k<kLen ; k++ )
5887 {
5888 iCol = aDataSort[k];
5889 sType = aoColumns[ iCol ].sType || 'string';
5890
5891 if ( nestedSort[i]._idx === undefined ) {
5892 nestedSort[i]._idx = $.inArray( nestedSort[i][1], aoColumns[iCol].asSorting );
5893 }
5894
5895 aSort.push( {
5896 src: srcCol,
5897 col: iCol,
5898 dir: nestedSort[i][1],
5899 index: nestedSort[i]._idx,
5900 type: sType,
5901 formatter: DataTable.ext.type.order[ sType+"-pre" ]
5902 } );
5903 }
5904 }
5905
5906 return aSort;
5907 }
5908
5909 /**
5910 * Change the order of the table
5911 * @param {object} oSettings dataTables settings object
5912 * @memberof DataTable#oApi
5913 * @todo This really needs split up!
5914 */
5915 function _fnSort ( oSettings )
5916 {
5917 var
5918 i, ien, iLen, j, jLen, k, kLen,
5919 sDataType, nTh,
5920 aiOrig = [],
5921 oExtSort = DataTable.ext.type.order,
5922 aoData = oSettings.aoData,
5923 aoColumns = oSettings.aoColumns,
5924 aDataSort, data, iCol, sType, oSort,
5925 formatters = 0,
5926 sortCol,
5927 displayMaster = oSettings.aiDisplayMaster,
5928 aSort;
5929
5930 // Resolve any column types that are unknown due to addition or invalidation
5931 // @todo Can this be moved into a 'data-ready' handler which is called when
5932 // data is going to be used in the table?
5933 _fnColumnTypes( oSettings );
5934
5935 aSort = _fnSortFlatten( oSettings );
5936
5937 for ( i=0, ien=aSort.length ; i<ien ; i++ ) {
5938 sortCol = aSort[i];
5939
5940 // Track if we can use the fast sort algorithm
5941 if ( sortCol.formatter ) {
5942 formatters++;
5943 }
5944
5945 // Load the data needed for the sort, for each cell
5946 _fnSortData( oSettings, sortCol.col );
5947 }
5948
5949 /* No sorting required if server-side or no sorting array */
5950 if ( _fnDataSource( oSettings ) != 'ssp' && aSort.length !== 0 )
5951 {
5952 // Create a value - key array of the current row positions such that we can use their
5953 // current position during the sort, if values match, in order to perform stable sorting
5954 for ( i=0, iLen=displayMaster.length ; i<iLen ; i++ ) {
5955 aiOrig[ displayMaster[i] ] = i;
5956 }
5957
5958 /* Do the sort - here we want multi-column sorting based on a given data source (column)
5959 * and sorting function (from oSort) in a certain direction. It's reasonably complex to
5960 * follow on it's own, but this is what we want (example two column sorting):
5961 * fnLocalSorting = function(a,b){
5962 * var iTest;
5963 * iTest = oSort['string-asc']('data11', 'data12');
5964 * if (iTest !== 0)
5965 * return iTest;
5966 * iTest = oSort['numeric-desc']('data21', 'data22');
5967 * if (iTest !== 0)
5968 * return iTest;
5969 * return oSort['numeric-asc']( aiOrig[a], aiOrig[b] );
5970 * }
5971 * Basically we have a test for each sorting column, if the data in that column is equal,
5972 * test the next column. If all columns match, then we use a numeric sort on the row
5973 * positions in the original data array to provide a stable sort.
5974 *
5975 * Note - I know it seems excessive to have two sorting methods, but the first is around
5976 * 15% faster, so the second is only maintained for backwards compatibility with sorting
5977 * methods which do not have a pre-sort formatting function.
5978 */
5979 if ( formatters === aSort.length ) {
5980 // All sort types have formatting functions
5981 displayMaster.sort( function ( a, b ) {
5982 var
5983 x, y, k, test, sort,
5984 len=aSort.length,
5985 dataA = aoData[a]._aSortData,
5986 dataB = aoData[b]._aSortData;
5987
5988 for ( k=0 ; k<len ; k++ ) {
5989 sort = aSort[k];
5990
5991 x = dataA[ sort.col ];
5992 y = dataB[ sort.col ];
5993
5994 test = x<y ? -1 : x>y ? 1 : 0;
5995 if ( test !== 0 ) {
5996 return sort.dir === 'asc' ? test : -test;
5997 }
5998 }
5999
6000 x = aiOrig[a];
6001 y = aiOrig[b];
6002 return x<y ? -1 : x>y ? 1 : 0;
6003 } );
6004 }
6005 else {
6006 // Depreciated - remove in 1.11 (providing a plug-in option)
6007 // Not all sort types have formatting methods, so we have to call their sorting
6008 // methods.
6009 displayMaster.sort( function ( a, b ) {
6010 var
6011 x, y, k, l, test, sort, fn,
6012 len=aSort.length,
6013 dataA = aoData[a]._aSortData,
6014 dataB = aoData[b]._aSortData;
6015
6016 for ( k=0 ; k<len ; k++ ) {
6017 sort = aSort[k];
6018
6019 x = dataA[ sort.col ];
6020 y = dataB[ sort.col ];
6021
6022 fn = oExtSort[ sort.type+"-"+sort.dir ] || oExtSort[ "string-"+sort.dir ];
6023 test = fn( x, y );
6024 if ( test !== 0 ) {
6025 return test;
6026 }
6027 }
6028
6029 x = aiOrig[a];
6030 y = aiOrig[b];
6031 return x<y ? -1 : x>y ? 1 : 0;
6032 } );
6033 }
6034 }
6035
6036 /* Tell the draw function that we have sorted the data */
6037 oSettings.bSorted = true;
6038 }
6039
6040
6041 function _fnSortAria ( settings )
6042 {
6043 var label;
6044 var nextSort;
6045 var columns = settings.aoColumns;
6046 var aSort = _fnSortFlatten( settings );
6047 var oAria = settings.oLanguage.oAria;
6048
6049 // ARIA attributes - need to loop all columns, to update all (removing old
6050 // attributes as needed)
6051 for ( var i=0, iLen=columns.length ; i<iLen ; i++ )
6052 {
6053 var col = columns[i];
6054 var asSorting = col.asSorting;
6055 var sTitle = col.sTitle.replace( /<.*?>/g, "" );
6056 var th = col.nTh;
6057
6058 // IE7 is throwing an error when setting these properties with jQuery's
6059 // attr() and removeAttr() methods...
6060 th.removeAttribute('aria-sort');
6061
6062 /* In ARIA only the first sorting column can be marked as sorting - no multi-sort option */
6063 if ( col.bSortable ) {
6064 if ( aSort.length > 0 && aSort[0].col == i ) {
6065 th.setAttribute('aria-sort', aSort[0].dir=="asc" ? "ascending" : "descending" );
6066 nextSort = asSorting[ aSort[0].index+1 ] || asSorting[0];
6067 }
6068 else {
6069 nextSort = asSorting[0];
6070 }
6071
6072 label = sTitle + ( nextSort === "asc" ?
6073 oAria.sSortAscending :
6074 oAria.sSortDescending
6075 );
6076 }
6077 else {
6078 label = sTitle;
6079 }
6080
6081 th.setAttribute('aria-label', label);
6082 }
6083 }
6084
6085
6086 /**
6087 * Function to run on user sort request
6088 * @param {object} settings dataTables settings object
6089 * @param {node} attachTo node to attach the handler to
6090 * @param {int} colIdx column sorting index
6091 * @param {boolean} [append=false] Append the requested sort to the existing
6092 * sort if true (i.e. multi-column sort)
6093 * @param {function} [callback] callback function
6094 * @memberof DataTable#oApi
6095 */
6096 function _fnSortListener ( settings, colIdx, append, callback )
6097 {
6098 var col = settings.aoColumns[ colIdx ];
6099 var sorting = settings.aaSorting;
6100 var asSorting = col.asSorting;
6101 var nextSortIdx;
6102 var next = function ( a, overflow ) {
6103 var idx = a._idx;
6104 if ( idx === undefined ) {
6105 idx = $.inArray( a[1], asSorting );
6106 }
6107
6108 return idx+1 < asSorting.length ?
6109 idx+1 :
6110 overflow ?
6111 null :
6112 0;
6113 };
6114
6115 // Convert to 2D array if needed
6116 if ( typeof sorting[0] === 'number' ) {
6117 sorting = settings.aaSorting = [ sorting ];
6118 }
6119
6120 // If appending the sort then we are multi-column sorting
6121 if ( append && settings.oFeatures.bSortMulti ) {
6122 // Are we already doing some kind of sort on this column?
6123 var sortIdx = $.inArray( colIdx, _pluck(sorting, '0') );
6124
6125 if ( sortIdx !== -1 ) {
6126 // Yes, modify the sort
6127 nextSortIdx = next( sorting[sortIdx], true );
6128
6129 if ( nextSortIdx === null && sorting.length === 1 ) {
6130 nextSortIdx = 0; // can't remove sorting completely
6131 }
6132
6133 if ( nextSortIdx === null ) {
6134 sorting.splice( sortIdx, 1 );
6135 }
6136 else {
6137 sorting[sortIdx][1] = asSorting[ nextSortIdx ];
6138 sorting[sortIdx]._idx = nextSortIdx;
6139 }
6140 }
6141 else {
6142 // No sort on this column yet
6143 sorting.push( [ colIdx, asSorting[0], 0 ] );
6144 sorting[sorting.length-1]._idx = 0;
6145 }
6146 }
6147 else if ( sorting.length && sorting[0][0] == colIdx ) {
6148 // Single column - already sorting on this column, modify the sort
6149 nextSortIdx = next( sorting[0] );
6150
6151 sorting.length = 1;
6152 sorting[0][1] = asSorting[ nextSortIdx ];
6153 sorting[0]._idx = nextSortIdx;
6154 }
6155 else {
6156 // Single column - sort only on this column
6157 sorting.length = 0;
6158 sorting.push( [ colIdx, asSorting[0] ] );
6159 sorting[0]._idx = 0;
6160 }
6161
6162 // Run the sort by calling a full redraw
6163 _fnReDraw( settings );
6164
6165 // callback used for async user interaction
6166 if ( typeof callback == 'function' ) {
6167 callback( settings );
6168 }
6169 }
6170
6171
6172 /**
6173 * Attach a sort handler (click) to a node
6174 * @param {object} settings dataTables settings object
6175 * @param {node} attachTo node to attach the handler to
6176 * @param {int} colIdx column sorting index
6177 * @param {function} [callback] callback function
6178 * @memberof DataTable#oApi
6179 */
6180 function _fnSortAttachListener ( settings, attachTo, colIdx, callback )
6181 {
6182 var col = settings.aoColumns[ colIdx ];
6183
6184 _fnBindAction( attachTo, {}, function (e) {
6185 /* If the column is not sortable - don't to anything */
6186 if ( col.bSortable === false ) {
6187 return;
6188 }
6189
6190 // If processing is enabled use a timeout to allow the processing
6191 // display to be shown - otherwise to it synchronously
6192 if ( settings.oFeatures.bProcessing ) {
6193 _fnProcessingDisplay( settings, true );
6194
6195 setTimeout( function() {
6196 _fnSortListener( settings, colIdx, e.shiftKey, callback );
6197
6198 // In server-side processing, the draw callback will remove the
6199 // processing display
6200 if ( _fnDataSource( settings ) !== 'ssp' ) {
6201 _fnProcessingDisplay( settings, false );
6202 }
6203 }, 0 );
6204 }
6205 else {
6206 _fnSortListener( settings, colIdx, e.shiftKey, callback );
6207 }
6208 } );
6209 }
6210
6211
6212 /**
6213 * Set the sorting classes on table's body, Note: it is safe to call this function
6214 * when bSort and bSortClasses are false
6215 * @param {object} oSettings dataTables settings object
6216 * @memberof DataTable#oApi
6217 */
6218 function _fnSortingClasses( settings )
6219 {
6220 var oldSort = settings.aLastSort;
6221 var sortClass = settings.oClasses.sSortColumn;
6222 var sort = _fnSortFlatten( settings );
6223 var features = settings.oFeatures;
6224 var i, ien, colIdx;
6225
6226 if ( features.bSort && features.bSortClasses ) {
6227 // Remove old sorting classes
6228 for ( i=0, ien=oldSort.length ; i<ien ; i++ ) {
6229 colIdx = oldSort[i].src;
6230
6231 // Remove column sorting
6232 $( _pluck( settings.aoData, 'anCells', colIdx ) )
6233 .removeClass( sortClass + (i<2 ? i+1 : 3) );
6234 }
6235
6236 // Add new column sorting
6237 for ( i=0, ien=sort.length ; i<ien ; i++ ) {
6238 colIdx = sort[i].src;
6239
6240 $( _pluck( settings.aoData, 'anCells', colIdx ) )
6241 .addClass( sortClass + (i<2 ? i+1 : 3) );
6242 }
6243 }
6244
6245 settings.aLastSort = sort;
6246 }
6247
6248
6249 // Get the data to sort a column, be it from cache, fresh (populating the
6250 // cache), or from a sort formatter
6251 function _fnSortData( settings, idx )
6252 {
6253 // Custom sorting function - provided by the sort data type
6254 var column = settings.aoColumns[ idx ];
6255 var customSort = DataTable.ext.order[ column.sSortDataType ];
6256 var customData;
6257
6258 if ( customSort ) {
6259 customData = customSort.call( settings.oInstance, settings, idx,
6260 _fnColumnIndexToVisible( settings, idx )
6261 );
6262 }
6263
6264 // Use / populate cache
6265 var row, cellData;
6266 var formatter = DataTable.ext.type.order[ column.sType+"-pre" ];
6267
6268 for ( var i=0, ien=settings.aoData.length ; i<ien ; i++ ) {
6269 row = settings.aoData[i];
6270
6271 if ( ! row._aSortData ) {
6272 row._aSortData = [];
6273 }
6274
6275 if ( ! row._aSortData[idx] || customSort ) {
6276 cellData = customSort ?
6277 customData[i] : // If there was a custom sort function, use data from there
6278 _fnGetCellData( settings, i, idx, 'sort' );
6279
6280 row._aSortData[ idx ] = formatter ?
6281 formatter( cellData ) :
6282 cellData;
6283 }
6284 }
6285 }
6286
6287
6288
6289 /**
6290 * Save the state of a table
6291 * @param {object} oSettings dataTables settings object
6292 * @memberof DataTable#oApi
6293 */
6294 function _fnSaveState ( settings )
6295 {
6296 if ( !settings.oFeatures.bStateSave || settings.bDestroying )
6297 {
6298 return;
6299 }
6300
6301 /* Store the interesting variables */
6302 var state = {
6303 time: +new Date(),
6304 start: settings._iDisplayStart,
6305 length: settings._iDisplayLength,
6306 order: $.extend( true, [], settings.aaSorting ),
6307 search: _fnSearchToCamel( settings.oPreviousSearch ),
6308 columns: $.map( settings.aoColumns, function ( col, i ) {
6309 return {
6310 visible: col.bVisible,
6311 search: _fnSearchToCamel( settings.aoPreSearchCols[i] )
6312 };
6313 } )
6314 };
6315
6316 _fnCallbackFire( settings, "aoStateSaveParams", 'stateSaveParams', [settings, state] );
6317
6318 settings.oSavedState = state;
6319 settings.fnStateSaveCallback.call( settings.oInstance, settings, state );
6320 }
6321
6322
6323 /**
6324 * Attempt to load a saved table state
6325 * @param {object} oSettings dataTables settings object
6326 * @param {object} oInit DataTables init object so we can override settings
6327 * @param {function} callback Callback to execute when the state has been loaded
6328 * @memberof DataTable#oApi
6329 */
6330 function _fnLoadState ( settings, oInit, callback )
6331 {
6332 var i, ien;
6333 var columns = settings.aoColumns;
6334 var loaded = function ( s ) {
6335 if ( ! s || ! s.time ) {
6336 callback();
6337 return;
6338 }
6339
6340 // Allow custom and plug-in manipulation functions to alter the saved data set and
6341 // cancelling of loading by returning false
6342 var abStateLoad = _fnCallbackFire( settings, 'aoStateLoadParams', 'stateLoadParams', [settings, s] );
6343 if ( $.inArray( false, abStateLoad ) !== -1 ) {
6344 callback();
6345 return;
6346 }
6347
6348 // Reject old data
6349 var duration = settings.iStateDuration;
6350 if ( duration > 0 && s.time < +new Date() - (duration*1000) ) {
6351 callback();
6352 return;
6353 }
6354
6355 // Number of columns have changed - all bets are off, no restore of settings
6356 if ( s.columns && columns.length !== s.columns.length ) {
6357 callback();
6358 return;
6359 }
6360
6361 // Store the saved state so it might be accessed at any time
6362 settings.oLoadedState = $.extend( true, {}, s );
6363
6364 // Restore key features - todo - for 1.11 this needs to be done by
6365 // subscribed events
6366 if ( s.start !== undefined ) {
6367 settings._iDisplayStart = s.start;
6368 settings.iInitDisplayStart = s.start;
6369 }
6370 if ( s.length !== undefined ) {
6371 settings._iDisplayLength = s.length;
6372 }
6373
6374 // Order
6375 if ( s.order !== undefined ) {
6376 settings.aaSorting = [];
6377 $.each( s.order, function ( i, col ) {
6378 settings.aaSorting.push( col[0] >= columns.length ?
6379 [ 0, col[1] ] :
6380 col
6381 );
6382 } );
6383 }
6384
6385 // Search
6386 if ( s.search !== undefined ) {
6387 $.extend( settings.oPreviousSearch, _fnSearchToHung( s.search ) );
6388 }
6389
6390 // Columns
6391 //
6392 if ( s.columns ) {
6393 for ( i=0, ien=s.columns.length ; i<ien ; i++ ) {
6394 var col = s.columns[i];
6395
6396 // Visibility
6397 if ( col.visible !== undefined ) {
6398 columns[i].bVisible = col.visible;
6399 }
6400
6401 // Search
6402 if ( col.search !== undefined ) {
6403 $.extend( settings.aoPreSearchCols[i], _fnSearchToHung( col.search ) );
6404 }
6405 }
6406 }
6407
6408 _fnCallbackFire( settings, 'aoStateLoaded', 'stateLoaded', [settings, s] );
6409 callback();
6410 }
6411
6412 if ( ! settings.oFeatures.bStateSave ) {
6413 callback();
6414 return;
6415 }
6416
6417 var state = settings.fnStateLoadCallback.call( settings.oInstance, settings, loaded );
6418
6419 if ( state !== undefined ) {
6420 loaded( state );
6421 }
6422 // otherwise, wait for the loaded callback to be executed
6423 }
6424
6425
6426 /**
6427 * Return the settings object for a particular table
6428 * @param {node} table table we are using as a dataTable
6429 * @returns {object} Settings object - or null if not found
6430 * @memberof DataTable#oApi
6431 */
6432 function _fnSettingsFromNode ( table )
6433 {
6434 var settings = DataTable.settings;
6435 var idx = $.inArray( table, _pluck( settings, 'nTable' ) );
6436
6437 return idx !== -1 ?
6438 settings[ idx ] :
6439 null;
6440 }
6441
6442
6443 /**
6444 * Log an error message
6445 * @param {object} settings dataTables settings object
6446 * @param {int} level log error messages, or display them to the user
6447 * @param {string} msg error message
6448 * @param {int} tn Technical note id to get more information about the error.
6449 * @memberof DataTable#oApi
6450 */
6451 function _fnLog( settings, level, msg, tn )
6452 {
6453 msg = 'DataTables warning: '+
6454 (settings ? 'table id='+settings.sTableId+' - ' : '')+msg;
6455
6456 if ( tn ) {
6457 msg += '. For more information about this error, please see '+
6458 'http://datatables.net/tn/'+tn;
6459 }
6460
6461 if ( ! level ) {
6462 // Backwards compatibility pre 1.10
6463 var ext = DataTable.ext;
6464 var type = ext.sErrMode || ext.errMode;
6465
6466 if ( settings ) {
6467 _fnCallbackFire( settings, null, 'error', [ settings, tn, msg ] );
6468 }
6469
6470 if ( type == 'alert' ) {
6471 alert( msg );
6472 }
6473 else if ( type == 'throw' ) {
6474 throw new Error(msg);
6475 }
6476 else if ( typeof type == 'function' ) {
6477 type( settings, tn, msg );
6478 }
6479 }
6480 else if ( window.console && console.log ) {
6481 console.log( msg );
6482 }
6483 }
6484
6485
6486 /**
6487 * See if a property is defined on one object, if so assign it to the other object
6488 * @param {object} ret target object
6489 * @param {object} src source object
6490 * @param {string} name property
6491 * @param {string} [mappedName] name to map too - optional, name used if not given
6492 * @memberof DataTable#oApi
6493 */
6494 function _fnMap( ret, src, name, mappedName )
6495 {
6496 if ( $.isArray( name ) ) {
6497 $.each( name, function (i, val) {
6498 if ( $.isArray( val ) ) {
6499 _fnMap( ret, src, val[0], val[1] );
6500 }
6501 else {
6502 _fnMap( ret, src, val );
6503 }
6504 } );
6505
6506 return;
6507 }
6508
6509 if ( mappedName === undefined ) {
6510 mappedName = name;
6511 }
6512
6513 if ( src[name] !== undefined ) {
6514 ret[mappedName] = src[name];
6515 }
6516 }
6517
6518
6519 /**
6520 * Extend objects - very similar to jQuery.extend, but deep copy objects, and
6521 * shallow copy arrays. The reason we need to do this, is that we don't want to
6522 * deep copy array init values (such as aaSorting) since the dev wouldn't be
6523 * able to override them, but we do want to deep copy arrays.
6524 * @param {object} out Object to extend
6525 * @param {object} extender Object from which the properties will be applied to
6526 * out
6527 * @param {boolean} breakRefs If true, then arrays will be sliced to take an
6528 * independent copy with the exception of the `data` or `aaData` parameters
6529 * if they are present. This is so you can pass in a collection to
6530 * DataTables and have that used as your data source without breaking the
6531 * references
6532 * @returns {object} out Reference, just for convenience - out === the return.
6533 * @memberof DataTable#oApi
6534 * @todo This doesn't take account of arrays inside the deep copied objects.
6535 */
6536 function _fnExtend( out, extender, breakRefs )
6537 {
6538 var val;
6539
6540 for ( var prop in extender ) {
6541 if ( extender.hasOwnProperty(prop) ) {
6542 val = extender[prop];
6543
6544 if ( $.isPlainObject( val ) ) {
6545 if ( ! $.isPlainObject( out[prop] ) ) {
6546 out[prop] = {};
6547 }
6548 $.extend( true, out[prop], val );
6549 }
6550 else if ( breakRefs && prop !== 'data' && prop !== 'aaData' && $.isArray(val) ) {
6551 out[prop] = val.slice();
6552 }
6553 else {
6554 out[prop] = val;
6555 }
6556 }
6557 }
6558
6559 return out;
6560 }
6561
6562
6563 /**
6564 * Bind an event handers to allow a click or return key to activate the callback.
6565 * This is good for accessibility since a return on the keyboard will have the
6566 * same effect as a click, if the element has focus.
6567 * @param {element} n Element to bind the action to
6568 * @param {object} oData Data object to pass to the triggered function
6569 * @param {function} fn Callback function for when the event is triggered
6570 * @memberof DataTable#oApi
6571 */
6572 function _fnBindAction( n, oData, fn )
6573 {
6574 $(n)
6575 .on( 'click.DT', oData, function (e) {
6576 n.blur(); // Remove focus outline for mouse users
6577 fn(e);
6578 } )
6579 .on( 'keypress.DT', oData, function (e){
6580 if ( e.which === 13 ) {
6581 e.preventDefault();
6582 fn(e);
6583 }
6584 } )
6585 .on( 'selectstart.DT', function () {
6586 /* Take the brutal approach to cancelling text selection */
6587 return false;
6588 } );
6589 }
6590
6591
6592 /**
6593 * Register a callback function. Easily allows a callback function to be added to
6594 * an array store of callback functions that can then all be called together.
6595 * @param {object} oSettings dataTables settings object
6596 * @param {string} sStore Name of the array storage for the callbacks in oSettings
6597 * @param {function} fn Function to be called back
6598 * @param {string} sName Identifying name for the callback (i.e. a label)
6599 * @memberof DataTable#oApi
6600 */
6601 function _fnCallbackReg( oSettings, sStore, fn, sName )
6602 {
6603 if ( fn )
6604 {
6605 oSettings[sStore].push( {
6606 "fn": fn,
6607 "sName": sName
6608 } );
6609 }
6610 }
6611
6612
6613 /**
6614 * Fire callback functions and trigger events. Note that the loop over the
6615 * callback array store is done backwards! Further note that you do not want to
6616 * fire off triggers in time sensitive applications (for example cell creation)
6617 * as its slow.
6618 * @param {object} settings dataTables settings object
6619 * @param {string} callbackArr Name of the array storage for the callbacks in
6620 * oSettings
6621 * @param {string} eventName Name of the jQuery custom event to trigger. If
6622 * null no trigger is fired
6623 * @param {array} args Array of arguments to pass to the callback function /
6624 * trigger
6625 * @memberof DataTable#oApi
6626 */
6627 function _fnCallbackFire( settings, callbackArr, eventName, args )
6628 {
6629 var ret = [];
6630
6631 if ( callbackArr ) {
6632 ret = $.map( settings[callbackArr].slice().reverse(), function (val, i) {
6633 return val.fn.apply( settings.oInstance, args );
6634 } );
6635 }
6636
6637 if ( eventName !== null ) {
6638 var e = $.Event( eventName+'.dt' );
6639
6640 $(settings.nTable).trigger( e, args );
6641
6642 ret.push( e.result );
6643 }
6644
6645 return ret;
6646 }
6647
6648
6649 function _fnLengthOverflow ( settings )
6650 {
6651 var
6652 start = settings._iDisplayStart,
6653 end = settings.fnDisplayEnd(),
6654 len = settings._iDisplayLength;
6655
6656 /* If we have space to show extra rows (backing up from the end point - then do so */
6657 if ( start >= end )
6658 {
6659 start = end - len;
6660 }
6661
6662 // Keep the start record on the current page
6663 start -= (start % len);
6664
6665 if ( len === -1 || start < 0 )
6666 {
6667 start = 0;
6668 }
6669
6670 settings._iDisplayStart = start;
6671 }
6672
6673
6674 function _fnRenderer( settings, type )
6675 {
6676 var renderer = settings.renderer;
6677 var host = DataTable.ext.renderer[type];
6678
6679 if ( $.isPlainObject( renderer ) && renderer[type] ) {
6680 // Specific renderer for this type. If available use it, otherwise use
6681 // the default.
6682 return host[renderer[type]] || host._;
6683 }
6684 else if ( typeof renderer === 'string' ) {
6685 // Common renderer - if there is one available for this type use it,
6686 // otherwise use the default
6687 return host[renderer] || host._;
6688 }
6689
6690 // Use the default
6691 return host._;
6692 }
6693
6694
6695 /**
6696 * Detect the data source being used for the table. Used to simplify the code
6697 * a little (ajax) and to make it compress a little smaller.
6698 *
6699 * @param {object} settings dataTables settings object
6700 * @returns {string} Data source
6701 * @memberof DataTable#oApi
6702 */
6703 function _fnDataSource ( settings )
6704 {
6705 if ( settings.oFeatures.bServerSide ) {
6706 return 'ssp';
6707 }
6708 else if ( settings.ajax || settings.sAjaxSource ) {
6709 return 'ajax';
6710 }
6711 return 'dom';
6712 }
6713
6714
6715
6716
6717 /**
6718 * Computed structure of the DataTables API, defined by the options passed to
6719 * `DataTable.Api.register()` when building the API.
6720 *
6721 * The structure is built in order to speed creation and extension of the Api
6722 * objects since the extensions are effectively pre-parsed.
6723 *
6724 * The array is an array of objects with the following structure, where this
6725 * base array represents the Api prototype base:
6726 *
6727 * [
6728 * {
6729 * name: 'data' -- string - Property name
6730 * val: function () {}, -- function - Api method (or undefined if just an object
6731 * methodExt: [ ... ], -- array - Array of Api object definitions to extend the method result
6732 * propExt: [ ... ] -- array - Array of Api object definitions to extend the property
6733 * },
6734 * {
6735 * name: 'row'
6736 * val: {},
6737 * methodExt: [ ... ],
6738 * propExt: [
6739 * {
6740 * name: 'data'
6741 * val: function () {},
6742 * methodExt: [ ... ],
6743 * propExt: [ ... ]
6744 * },
6745 * ...
6746 * ]
6747 * }
6748 * ]
6749 *
6750 * @type {Array}
6751 * @ignore
6752 */
6753 var __apiStruct = [];
6754
6755
6756 /**
6757 * `Array.prototype` reference.
6758 *
6759 * @type object
6760 * @ignore
6761 */
6762 var __arrayProto = Array.prototype;
6763
6764
6765 /**
6766 * Abstraction for `context` parameter of the `Api` constructor to allow it to
6767 * take several different forms for ease of use.
6768 *
6769 * Each of the input parameter types will be converted to a DataTables settings
6770 * object where possible.
6771 *
6772 * @param {string|node|jQuery|object} mixed DataTable identifier. Can be one
6773 * of:
6774 *
6775 * * `string` - jQuery selector. Any DataTables' matching the given selector
6776 * with be found and used.
6777 * * `node` - `TABLE` node which has already been formed into a DataTable.
6778 * * `jQuery` - A jQuery object of `TABLE` nodes.
6779 * * `object` - DataTables settings object
6780 * * `DataTables.Api` - API instance
6781 * @return {array|null} Matching DataTables settings objects. `null` or
6782 * `undefined` is returned if no matching DataTable is found.
6783 * @ignore
6784 */
6785 var _toSettings = function ( mixed )
6786 {
6787 var idx, jq;
6788 var settings = DataTable.settings;
6789 var tables = $.map( settings, function (el, i) {
6790 return el.nTable;
6791 } );
6792
6793 if ( ! mixed ) {
6794 return [];
6795 }
6796 else if ( mixed.nTable && mixed.oApi ) {
6797 // DataTables settings object
6798 return [ mixed ];
6799 }
6800 else if ( mixed.nodeName && mixed.nodeName.toLowerCase() === 'table' ) {
6801 // Table node
6802 idx = $.inArray( mixed, tables );
6803 return idx !== -1 ? [ settings[idx] ] : null;
6804 }
6805 else if ( mixed && typeof mixed.settings === 'function' ) {
6806 return mixed.settings().toArray();
6807 }
6808 else if ( typeof mixed === 'string' ) {
6809 // jQuery selector
6810 jq = $(mixed);
6811 }
6812 else if ( mixed instanceof $ ) {
6813 // jQuery object (also DataTables instance)
6814 jq = mixed;
6815 }
6816
6817 if ( jq ) {
6818 return jq.map( function(i) {
6819 idx = $.inArray( this, tables );
6820 return idx !== -1 ? settings[idx] : null;
6821 } ).toArray();
6822 }
6823 };
6824
6825
6826 /**
6827 * DataTables API class - used to control and interface with one or more
6828 * DataTables enhanced tables.
6829 *
6830 * The API class is heavily based on jQuery, presenting a chainable interface
6831 * that you can use to interact with tables. Each instance of the API class has
6832 * a "context" - i.e. the tables that it will operate on. This could be a single
6833 * table, all tables on a page or a sub-set thereof.
6834 *
6835 * Additionally the API is designed to allow you to easily work with the data in
6836 * the tables, retrieving and manipulating it as required. This is done by
6837 * presenting the API class as an array like interface. The contents of the
6838 * array depend upon the actions requested by each method (for example
6839 * `rows().nodes()` will return an array of nodes, while `rows().data()` will
6840 * return an array of objects or arrays depending upon your table's
6841 * configuration). The API object has a number of array like methods (`push`,
6842 * `pop`, `reverse` etc) as well as additional helper methods (`each`, `pluck`,
6843 * `unique` etc) to assist your working with the data held in a table.
6844 *
6845 * Most methods (those which return an Api instance) are chainable, which means
6846 * the return from a method call also has all of the methods available that the
6847 * top level object had. For example, these two calls are equivalent:
6848 *
6849 * // Not chained
6850 * api.row.add( {...} );
6851 * api.draw();
6852 *
6853 * // Chained
6854 * api.row.add( {...} ).draw();
6855 *
6856 * @class DataTable.Api
6857 * @param {array|object|string|jQuery} context DataTable identifier. This is
6858 * used to define which DataTables enhanced tables this API will operate on.
6859 * Can be one of:
6860 *
6861 * * `string` - jQuery selector. Any DataTables' matching the given selector
6862 * with be found and used.
6863 * * `node` - `TABLE` node which has already been formed into a DataTable.
6864 * * `jQuery` - A jQuery object of `TABLE` nodes.
6865 * * `object` - DataTables settings object
6866 * @param {array} [data] Data to initialise the Api instance with.
6867 *
6868 * @example
6869 * // Direct initialisation during DataTables construction
6870 * var api = $('#example').DataTable();
6871 *
6872 * @example
6873 * // Initialisation using a DataTables jQuery object
6874 * var api = $('#example').dataTable().api();
6875 *
6876 * @example
6877 * // Initialisation as a constructor
6878 * var api = new $.fn.DataTable.Api( 'table.dataTable' );
6879 */
6880 _Api = function ( context, data )
6881 {
6882 if ( ! (this instanceof _Api) ) {
6883 return new _Api( context, data );
6884 }
6885
6886 var settings = [];
6887 var ctxSettings = function ( o ) {
6888 var a = _toSettings( o );
6889 if ( a ) {
6890 settings = settings.concat( a );
6891 }
6892 };
6893
6894 if ( $.isArray( context ) ) {
6895 for ( var i=0, ien=context.length ; i<ien ; i++ ) {
6896 ctxSettings( context[i] );
6897 }
6898 }
6899 else {
6900 ctxSettings( context );
6901 }
6902
6903 // Remove duplicates
6904 this.context = _unique( settings );
6905
6906 // Initial data
6907 if ( data ) {
6908 $.merge( this, data );
6909 }
6910
6911 // selector
6912 this.selector = {
6913 rows: null,
6914 cols: null,
6915 opts: null
6916 };
6917
6918 _Api.extend( this, this, __apiStruct );
6919 };
6920
6921 DataTable.Api = _Api;
6922
6923 // Don't destroy the existing prototype, just extend it. Required for jQuery 2's
6924 // isPlainObject.
6925 $.extend( _Api.prototype, {
6926 any: function ()
6927 {
6928 return this.count() !== 0;
6929 },
6930
6931
6932 concat: __arrayProto.concat,
6933
6934
6935 context: [], // array of table settings objects
6936
6937
6938 count: function ()
6939 {
6940 return this.flatten().length;
6941 },
6942
6943
6944 each: function ( fn )
6945 {
6946 for ( var i=0, ien=this.length ; i<ien; i++ ) {
6947 fn.call( this, this[i], i, this );
6948 }
6949
6950 return this;
6951 },
6952
6953
6954 eq: function ( idx )
6955 {
6956 var ctx = this.context;
6957
6958 return ctx.length > idx ?
6959 new _Api( ctx[idx], this[idx] ) :
6960 null;
6961 },
6962
6963
6964 filter: function ( fn )
6965 {
6966 var a = [];
6967
6968 if ( __arrayProto.filter ) {
6969 a = __arrayProto.filter.call( this, fn, this );
6970 }
6971 else {
6972 // Compatibility for browsers without EMCA-252-5 (JS 1.6)
6973 for ( var i=0, ien=this.length ; i<ien ; i++ ) {
6974 if ( fn.call( this, this[i], i, this ) ) {
6975 a.push( this[i] );
6976 }
6977 }
6978 }
6979
6980 return new _Api( this.context, a );
6981 },
6982
6983
6984 flatten: function ()
6985 {
6986 var a = [];
6987 return new _Api( this.context, a.concat.apply( a, this.toArray() ) );
6988 },
6989
6990
6991 join: __arrayProto.join,
6992
6993
6994 indexOf: __arrayProto.indexOf || function (obj, start)
6995 {
6996 for ( var i=(start || 0), ien=this.length ; i<ien ; i++ ) {
6997 if ( this[i] === obj ) {
6998 return i;
6999 }
7000 }
7001 return -1;
7002 },
7003
7004 iterator: function ( flatten, type, fn, alwaysNew ) {
7005 var
7006 a = [], ret,
7007 i, ien, j, jen,
7008 context = this.context,
7009 rows, items, item,
7010 selector = this.selector;
7011
7012 // Argument shifting
7013 if ( typeof flatten === 'string' ) {
7014 alwaysNew = fn;
7015 fn = type;
7016 type = flatten;
7017 flatten = false;
7018 }
7019
7020 for ( i=0, ien=context.length ; i<ien ; i++ ) {
7021 var apiInst = new _Api( context[i] );
7022
7023 if ( type === 'table' ) {
7024 ret = fn.call( apiInst, context[i], i );
7025
7026 if ( ret !== undefined ) {
7027 a.push( ret );
7028 }
7029 }
7030 else if ( type === 'columns' || type === 'rows' ) {
7031 // this has same length as context - one entry for each table
7032 ret = fn.call( apiInst, context[i], this[i], i );
7033
7034 if ( ret !== undefined ) {
7035 a.push( ret );
7036 }
7037 }
7038 else if ( type === 'column' || type === 'column-rows' || type === 'row' || type === 'cell' ) {
7039 // columns and rows share the same structure.
7040 // 'this' is an array of column indexes for each context
7041 items = this[i];
7042
7043 if ( type === 'column-rows' ) {
7044 rows = _selector_row_indexes( context[i], selector.opts );
7045 }
7046
7047 for ( j=0, jen=items.length ; j<jen ; j++ ) {
7048 item = items[j];
7049
7050 if ( type === 'cell' ) {
7051 ret = fn.call( apiInst, context[i], item.row, item.column, i, j );
7052 }
7053 else {
7054 ret = fn.call( apiInst, context[i], item, i, j, rows );
7055 }
7056
7057 if ( ret !== undefined ) {
7058 a.push( ret );
7059 }
7060 }
7061 }
7062 }
7063
7064 if ( a.length || alwaysNew ) {
7065 var api = new _Api( context, flatten ? a.concat.apply( [], a ) : a );
7066 var apiSelector = api.selector;
7067 apiSelector.rows = selector.rows;
7068 apiSelector.cols = selector.cols;
7069 apiSelector.opts = selector.opts;
7070 return api;
7071 }
7072 return this;
7073 },
7074
7075
7076 lastIndexOf: __arrayProto.lastIndexOf || function (obj, start)
7077 {
7078 // Bit cheeky...
7079 return this.indexOf.apply( this.toArray.reverse(), arguments );
7080 },
7081
7082
7083 length: 0,
7084
7085
7086 map: function ( fn )
7087 {
7088 var a = [];
7089
7090 if ( __arrayProto.map ) {
7091 a = __arrayProto.map.call( this, fn, this );
7092 }
7093 else {
7094 // Compatibility for browsers without EMCA-252-5 (JS 1.6)
7095 for ( var i=0, ien=this.length ; i<ien ; i++ ) {
7096 a.push( fn.call( this, this[i], i ) );
7097 }
7098 }
7099
7100 return new _Api( this.context, a );
7101 },
7102
7103
7104 pluck: function ( prop )
7105 {
7106 return this.map( function ( el ) {
7107 return el[ prop ];
7108 } );
7109 },
7110
7111 pop: __arrayProto.pop,
7112
7113
7114 push: __arrayProto.push,
7115
7116
7117 // Does not return an API instance
7118 reduce: __arrayProto.reduce || function ( fn, init )
7119 {
7120 return _fnReduce( this, fn, init, 0, this.length, 1 );
7121 },
7122
7123
7124 reduceRight: __arrayProto.reduceRight || function ( fn, init )
7125 {
7126 return _fnReduce( this, fn, init, this.length-1, -1, -1 );
7127 },
7128
7129
7130 reverse: __arrayProto.reverse,
7131
7132
7133 // Object with rows, columns and opts
7134 selector: null,
7135
7136
7137 shift: __arrayProto.shift,
7138
7139
7140 slice: function () {
7141 return new _Api( this.context, this );
7142 },
7143
7144
7145 sort: __arrayProto.sort, // ? name - order?
7146
7147
7148 splice: __arrayProto.splice,
7149
7150
7151 toArray: function ()
7152 {
7153 return __arrayProto.slice.call( this );
7154 },
7155
7156
7157 to$: function ()
7158 {
7159 return $( this );
7160 },
7161
7162
7163 toJQuery: function ()
7164 {
7165 return $( this );
7166 },
7167
7168
7169 unique: function ()
7170 {
7171 return new _Api( this.context, _unique(this) );
7172 },
7173
7174
7175 unshift: __arrayProto.unshift
7176 } );
7177
7178
7179 _Api.extend = function ( scope, obj, ext )
7180 {
7181 // Only extend API instances and static properties of the API
7182 if ( ! ext.length || ! obj || ( ! (obj instanceof _Api) && ! obj.__dt_wrapper ) ) {
7183 return;
7184 }
7185
7186 var
7187 i, ien,
7188 j, jen,
7189 struct, inner,
7190 methodScoping = function ( scope, fn, struc ) {
7191 return function () {
7192 var ret = fn.apply( scope, arguments );
7193
7194 // Method extension
7195 _Api.extend( ret, ret, struc.methodExt );
7196 return ret;
7197 };
7198 };
7199
7200 for ( i=0, ien=ext.length ; i<ien ; i++ ) {
7201 struct = ext[i];
7202
7203 // Value
7204 obj[ struct.name ] = typeof struct.val === 'function' ?
7205 methodScoping( scope, struct.val, struct ) :
7206 $.isPlainObject( struct.val ) ?
7207 {} :
7208 struct.val;
7209
7210 obj[ struct.name ].__dt_wrapper = true;
7211
7212 // Property extension
7213 _Api.extend( scope, obj[ struct.name ], struct.propExt );
7214 }
7215 };
7216
7217
7218 // @todo - Is there need for an augment function?
7219 // _Api.augment = function ( inst, name )
7220 // {
7221 // // Find src object in the structure from the name
7222 // var parts = name.split('.');
7223
7224 // _Api.extend( inst, obj );
7225 // };
7226
7227
7228 // [
7229 // {
7230 // name: 'data' -- string - Property name
7231 // val: function () {}, -- function - Api method (or undefined if just an object
7232 // methodExt: [ ... ], -- array - Array of Api object definitions to extend the method result
7233 // propExt: [ ... ] -- array - Array of Api object definitions to extend the property
7234 // },
7235 // {
7236 // name: 'row'
7237 // val: {},
7238 // methodExt: [ ... ],
7239 // propExt: [
7240 // {
7241 // name: 'data'
7242 // val: function () {},
7243 // methodExt: [ ... ],
7244 // propExt: [ ... ]
7245 // },
7246 // ...
7247 // ]
7248 // }
7249 // ]
7250
7251 _Api.register = _api_register = function ( name, val )
7252 {
7253 if ( $.isArray( name ) ) {
7254 for ( var j=0, jen=name.length ; j<jen ; j++ ) {
7255 _Api.register( name[j], val );
7256 }
7257 return;
7258 }
7259
7260 var
7261 i, ien,
7262 heir = name.split('.'),
7263 struct = __apiStruct,
7264 key, method;
7265
7266 var find = function ( src, name ) {
7267 for ( var i=0, ien=src.length ; i<ien ; i++ ) {
7268 if ( src[i].name === name ) {
7269 return src[i];
7270 }
7271 }
7272 return null;
7273 };
7274
7275 for ( i=0, ien=heir.length ; i<ien ; i++ ) {
7276 method = heir[i].indexOf('()') !== -1;
7277 key = method ?
7278 heir[i].replace('()', '') :
7279 heir[i];
7280
7281 var src = find( struct, key );
7282 if ( ! src ) {
7283 src = {
7284 name: key,
7285 val: {},
7286 methodExt: [],
7287 propExt: []
7288 };
7289 struct.push( src );
7290 }
7291
7292 if ( i === ien-1 ) {
7293 src.val = val;
7294 }
7295 else {
7296 struct = method ?
7297 src.methodExt :
7298 src.propExt;
7299 }
7300 }
7301 };
7302
7303
7304 _Api.registerPlural = _api_registerPlural = function ( pluralName, singularName, val ) {
7305 _Api.register( pluralName, val );
7306
7307 _Api.register( singularName, function () {
7308 var ret = val.apply( this, arguments );
7309
7310 if ( ret === this ) {
7311 // Returned item is the API instance that was passed in, return it
7312 return this;
7313 }
7314 else if ( ret instanceof _Api ) {
7315 // New API instance returned, want the value from the first item
7316 // in the returned array for the singular result.
7317 return ret.length ?
7318 $.isArray( ret[0] ) ?
7319 new _Api( ret.context, ret[0] ) : // Array results are 'enhanced'
7320 ret[0] :
7321 undefined;
7322 }
7323
7324 // Non-API return - just fire it back
7325 return ret;
7326 } );
7327 };
7328
7329
7330 /**
7331 * Selector for HTML tables. Apply the given selector to the give array of
7332 * DataTables settings objects.
7333 *
7334 * @param {string|integer} [selector] jQuery selector string or integer
7335 * @param {array} Array of DataTables settings objects to be filtered
7336 * @return {array}
7337 * @ignore
7338 */
7339 var __table_selector = function ( selector, a )
7340 {
7341 // Integer is used to pick out a table by index
7342 if ( typeof selector === 'number' ) {
7343 return [ a[ selector ] ];
7344 }
7345
7346 // Perform a jQuery selector on the table nodes
7347 var nodes = $.map( a, function (el, i) {
7348 return el.nTable;
7349 } );
7350
7351 return $(nodes)
7352 .filter( selector )
7353 .map( function (i) {
7354 // Need to translate back from the table node to the settings
7355 var idx = $.inArray( this, nodes );
7356 return a[ idx ];
7357 } )
7358 .toArray();
7359 };
7360
7361
7362
7363 /**
7364 * Context selector for the API's context (i.e. the tables the API instance
7365 * refers to.
7366 *
7367 * @name DataTable.Api#tables
7368 * @param {string|integer} [selector] Selector to pick which tables the iterator
7369 * should operate on. If not given, all tables in the current context are
7370 * used. This can be given as a jQuery selector (for example `':gt(0)'`) to
7371 * select multiple tables or as an integer to select a single table.
7372 * @returns {DataTable.Api} Returns a new API instance if a selector is given.
7373 */
7374 _api_register( 'tables()', function ( selector ) {
7375 // A new instance is created if there was a selector specified
7376 return selector ?
7377 new _Api( __table_selector( selector, this.context ) ) :
7378 this;
7379 } );
7380
7381
7382 _api_register( 'table()', function ( selector ) {
7383 var tables = this.tables( selector );
7384 var ctx = tables.context;
7385
7386 // Truncate to the first matched table
7387 return ctx.length ?
7388 new _Api( ctx[0] ) :
7389 tables;
7390 } );
7391
7392
7393 _api_registerPlural( 'tables().nodes()', 'table().node()' , function () {
7394 return this.iterator( 'table', function ( ctx ) {
7395 return ctx.nTable;
7396 }, 1 );
7397 } );
7398
7399
7400 _api_registerPlural( 'tables().body()', 'table().body()' , function () {
7401 return this.iterator( 'table', function ( ctx ) {
7402 return ctx.nTBody;
7403 }, 1 );
7404 } );
7405
7406
7407 _api_registerPlural( 'tables().header()', 'table().header()' , function () {
7408 return this.iterator( 'table', function ( ctx ) {
7409 return ctx.nTHead;
7410 }, 1 );
7411 } );
7412
7413
7414 _api_registerPlural( 'tables().footer()', 'table().footer()' , function () {
7415 return this.iterator( 'table', function ( ctx ) {
7416 return ctx.nTFoot;
7417 }, 1 );
7418 } );
7419
7420
7421 _api_registerPlural( 'tables().containers()', 'table().container()' , function () {
7422 return this.iterator( 'table', function ( ctx ) {
7423 return ctx.nTableWrapper;
7424 }, 1 );
7425 } );
7426
7427
7428
7429 /**
7430 * Redraw the tables in the current context.
7431 */
7432 _api_register( 'draw()', function ( paging ) {
7433 return this.iterator( 'table', function ( settings ) {
7434 if ( paging === 'page' ) {
7435 _fnDraw( settings );
7436 }
7437 else {
7438 if ( typeof paging === 'string' ) {
7439 paging = paging === 'full-hold' ?
7440 false :
7441 true;
7442 }
7443
7444 _fnReDraw( settings, paging===false );
7445 }
7446 } );
7447 } );
7448
7449
7450
7451 /**
7452 * Get the current page index.
7453 *
7454 * @return {integer} Current page index (zero based)
7455 *//**
7456 * Set the current page.
7457 *
7458 * Note that if you attempt to show a page which does not exist, DataTables will
7459 * not throw an error, but rather reset the paging.
7460 *
7461 * @param {integer|string} action The paging action to take. This can be one of:
7462 * * `integer` - The page index to jump to
7463 * * `string` - An action to take:
7464 * * `first` - Jump to first page.
7465 * * `next` - Jump to the next page
7466 * * `previous` - Jump to previous page
7467 * * `last` - Jump to the last page.
7468 * @returns {DataTables.Api} this
7469 */
7470 _api_register( 'page()', function ( action ) {
7471 if ( action === undefined ) {
7472 return this.page.info().page; // not an expensive call
7473 }
7474
7475 // else, have an action to take on all tables
7476 return this.iterator( 'table', function ( settings ) {
7477 _fnPageChange( settings, action );
7478 } );
7479 } );
7480
7481
7482 /**
7483 * Paging information for the first table in the current context.
7484 *
7485 * If you require paging information for another table, use the `table()` method
7486 * with a suitable selector.
7487 *
7488 * @return {object} Object with the following properties set:
7489 * * `page` - Current page index (zero based - i.e. the first page is `0`)
7490 * * `pages` - Total number of pages
7491 * * `start` - Display index for the first record shown on the current page
7492 * * `end` - Display index for the last record shown on the current page
7493 * * `length` - Display length (number of records). Note that generally `start
7494 * + length = end`, but this is not always true, for example if there are
7495 * only 2 records to show on the final page, with a length of 10.
7496 * * `recordsTotal` - Full data set length
7497 * * `recordsDisplay` - Data set length once the current filtering criterion
7498 * are applied.
7499 */
7500 _api_register( 'page.info()', function ( action ) {
7501 if ( this.context.length === 0 ) {
7502 return undefined;
7503 }
7504
7505 var
7506 settings = this.context[0],
7507 start = settings._iDisplayStart,
7508 len = settings.oFeatures.bPaginate ? settings._iDisplayLength : -1,
7509 visRecords = settings.fnRecordsDisplay(),
7510 all = len === -1;
7511
7512 return {
7513 "page": all ? 0 : Math.floor( start / len ),
7514 "pages": all ? 1 : Math.ceil( visRecords / len ),
7515 "start": start,
7516 "end": settings.fnDisplayEnd(),
7517 "length": len,
7518 "recordsTotal": settings.fnRecordsTotal(),
7519 "recordsDisplay": visRecords,
7520 "serverSide": _fnDataSource( settings ) === 'ssp'
7521 };
7522 } );
7523
7524
7525 /**
7526 * Get the current page length.
7527 *
7528 * @return {integer} Current page length. Note `-1` indicates that all records
7529 * are to be shown.
7530 *//**
7531 * Set the current page length.
7532 *
7533 * @param {integer} Page length to set. Use `-1` to show all records.
7534 * @returns {DataTables.Api} this
7535 */
7536 _api_register( 'page.len()', function ( len ) {
7537 // Note that we can't call this function 'length()' because `length`
7538 // is a Javascript property of functions which defines how many arguments
7539 // the function expects.
7540 if ( len === undefined ) {
7541 return this.context.length !== 0 ?
7542 this.context[0]._iDisplayLength :
7543 undefined;
7544 }
7545
7546 // else, set the page length
7547 return this.iterator( 'table', function ( settings ) {
7548 _fnLengthChange( settings, len );
7549 } );
7550 } );
7551
7552
7553
7554 var __reload = function ( settings, holdPosition, callback ) {
7555 // Use the draw event to trigger a callback
7556 if ( callback ) {
7557 var api = new _Api( settings );
7558
7559 api.one( 'draw', function () {
7560 callback( api.ajax.json() );
7561 } );
7562 }
7563
7564 if ( _fnDataSource( settings ) == 'ssp' ) {
7565 _fnReDraw( settings, holdPosition );
7566 }
7567 else {
7568 _fnProcessingDisplay( settings, true );
7569
7570 // Cancel an existing request
7571 var xhr = settings.jqXHR;
7572 if ( xhr && xhr.readyState !== 4 ) {
7573 xhr.abort();
7574 }
7575
7576 // Trigger xhr
7577 _fnBuildAjax( settings, [], function( json ) {
7578 _fnClearTable( settings );
7579
7580 var data = _fnAjaxDataSrc( settings, json );
7581 for ( var i=0, ien=data.length ; i<ien ; i++ ) {
7582 _fnAddData( settings, data[i] );
7583 }
7584
7585 _fnReDraw( settings, holdPosition );
7586 _fnProcessingDisplay( settings, false );
7587 } );
7588 }
7589 };
7590
7591
7592 /**
7593 * Get the JSON response from the last Ajax request that DataTables made to the
7594 * server. Note that this returns the JSON from the first table in the current
7595 * context.
7596 *
7597 * @return {object} JSON received from the server.
7598 */
7599 _api_register( 'ajax.json()', function () {
7600 var ctx = this.context;
7601
7602 if ( ctx.length > 0 ) {
7603 return ctx[0].json;
7604 }
7605
7606 // else return undefined;
7607 } );
7608
7609
7610 /**
7611 * Get the data submitted in the last Ajax request
7612 */
7613 _api_register( 'ajax.params()', function () {
7614 var ctx = this.context;
7615
7616 if ( ctx.length > 0 ) {
7617 return ctx[0].oAjaxData;
7618 }
7619
7620 // else return undefined;
7621 } );
7622
7623
7624 /**
7625 * Reload tables from the Ajax data source. Note that this function will
7626 * automatically re-draw the table when the remote data has been loaded.
7627 *
7628 * @param {boolean} [reset=true] Reset (default) or hold the current paging
7629 * position. A full re-sort and re-filter is performed when this method is
7630 * called, which is why the pagination reset is the default action.
7631 * @returns {DataTables.Api} this
7632 */
7633 _api_register( 'ajax.reload()', function ( callback, resetPaging ) {
7634 return this.iterator( 'table', function (settings) {
7635 __reload( settings, resetPaging===false, callback );
7636 } );
7637 } );
7638
7639
7640 /**
7641 * Get the current Ajax URL. Note that this returns the URL from the first
7642 * table in the current context.
7643 *
7644 * @return {string} Current Ajax source URL
7645 *//**
7646 * Set the Ajax URL. Note that this will set the URL for all tables in the
7647 * current context.
7648 *
7649 * @param {string} url URL to set.
7650 * @returns {DataTables.Api} this
7651 */
7652 _api_register( 'ajax.url()', function ( url ) {
7653 var ctx = this.context;
7654
7655 if ( url === undefined ) {
7656 // get
7657 if ( ctx.length === 0 ) {
7658 return undefined;
7659 }
7660 ctx = ctx[0];
7661
7662 return ctx.ajax ?
7663 $.isPlainObject( ctx.ajax ) ?
7664 ctx.ajax.url :
7665 ctx.ajax :
7666 ctx.sAjaxSource;
7667 }
7668
7669 // set
7670 return this.iterator( 'table', function ( settings ) {
7671 if ( $.isPlainObject( settings.ajax ) ) {
7672 settings.ajax.url = url;
7673 }
7674 else {
7675 settings.ajax = url;
7676 }
7677 // No need to consider sAjaxSource here since DataTables gives priority
7678 // to `ajax` over `sAjaxSource`. So setting `ajax` here, renders any
7679 // value of `sAjaxSource` redundant.
7680 } );
7681 } );
7682
7683
7684 /**
7685 * Load data from the newly set Ajax URL. Note that this method is only
7686 * available when `ajax.url()` is used to set a URL. Additionally, this method
7687 * has the same effect as calling `ajax.reload()` but is provided for
7688 * convenience when setting a new URL. Like `ajax.reload()` it will
7689 * automatically redraw the table once the remote data has been loaded.
7690 *
7691 * @returns {DataTables.Api} this
7692 */
7693 _api_register( 'ajax.url().load()', function ( callback, resetPaging ) {
7694 // Same as a reload, but makes sense to present it for easy access after a
7695 // url change
7696 return this.iterator( 'table', function ( ctx ) {
7697 __reload( ctx, resetPaging===false, callback );
7698 } );
7699 } );
7700
7701
7702
7703
7704 var _selector_run = function ( type, selector, selectFn, settings, opts )
7705 {
7706 var
7707 out = [], res,
7708 a, i, ien, j, jen,
7709 selectorType = typeof selector;
7710
7711 // Can't just check for isArray here, as an API or jQuery instance might be
7712 // given with their array like look
7713 if ( ! selector || selectorType === 'string' || selectorType === 'function' || selector.length === undefined ) {
7714 selector = [ selector ];
7715 }
7716
7717 for ( i=0, ien=selector.length ; i<ien ; i++ ) {
7718 // Only split on simple strings - complex expressions will be jQuery selectors
7719 a = selector[i] && selector[i].split && ! selector[i].match(/[\[\(:]/) ?
7720 selector[i].split(',') :
7721 [ selector[i] ];
7722
7723 for ( j=0, jen=a.length ; j<jen ; j++ ) {
7724 res = selectFn( typeof a[j] === 'string' ? $.trim(a[j]) : a[j] );
7725
7726 if ( res && res.length ) {
7727 out = out.concat( res );
7728 }
7729 }
7730 }
7731
7732 // selector extensions
7733 var ext = _ext.selector[ type ];
7734 if ( ext.length ) {
7735 for ( i=0, ien=ext.length ; i<ien ; i++ ) {
7736 out = ext[i]( settings, opts, out );
7737 }
7738 }
7739
7740 return _unique( out );
7741 };
7742
7743
7744 var _selector_opts = function ( opts )
7745 {
7746 if ( ! opts ) {
7747 opts = {};
7748 }
7749
7750 // Backwards compatibility for 1.9- which used the terminology filter rather
7751 // than search
7752 if ( opts.filter && opts.search === undefined ) {
7753 opts.search = opts.filter;
7754 }
7755
7756 return $.extend( {
7757 search: 'none',
7758 order: 'current',
7759 page: 'all'
7760 }, opts );
7761 };
7762
7763
7764 var _selector_first = function ( inst )
7765 {
7766 // Reduce the API instance to the first item found
7767 for ( var i=0, ien=inst.length ; i<ien ; i++ ) {
7768 if ( inst[i].length > 0 ) {
7769 // Assign the first element to the first item in the instance
7770 // and truncate the instance and context
7771 inst[0] = inst[i];
7772 inst[0].length = 1;
7773 inst.length = 1;
7774 inst.context = [ inst.context[i] ];
7775
7776 return inst;
7777 }
7778 }
7779
7780 // Not found - return an empty instance
7781 inst.length = 0;
7782 return inst;
7783 };
7784
7785
7786 var _selector_row_indexes = function ( settings, opts )
7787 {
7788 var
7789 i, ien, tmp, a=[],
7790 displayFiltered = settings.aiDisplay,
7791 displayMaster = settings.aiDisplayMaster;
7792
7793 var
7794 search = opts.search, // none, applied, removed
7795 order = opts.order, // applied, current, index (original - compatibility with 1.9)
7796 page = opts.page; // all, current
7797
7798 if ( _fnDataSource( settings ) == 'ssp' ) {
7799 // In server-side processing mode, most options are irrelevant since
7800 // rows not shown don't exist and the index order is the applied order
7801 // Removed is a special case - for consistency just return an empty
7802 // array
7803 return search === 'removed' ?
7804 [] :
7805 _range( 0, displayMaster.length );
7806 }
7807 else if ( page == 'current' ) {
7808 // Current page implies that order=current and fitler=applied, since it is
7809 // fairly senseless otherwise, regardless of what order and search actually
7810 // are
7811 for ( i=settings._iDisplayStart, ien=settings.fnDisplayEnd() ; i<ien ; i++ ) {
7812 a.push( displayFiltered[i] );
7813 }
7814 }
7815 else if ( order == 'current' || order == 'applied' ) {
7816 a = search == 'none' ?
7817 displayMaster.slice() : // no search
7818 search == 'applied' ?
7819 displayFiltered.slice() : // applied search
7820 $.map( displayMaster, function (el, i) { // removed search
7821 return $.inArray( el, displayFiltered ) === -1 ? el : null;
7822 } );
7823 }
7824 else if ( order == 'index' || order == 'original' ) {
7825 for ( i=0, ien=settings.aoData.length ; i<ien ; i++ ) {
7826 if ( search == 'none' ) {
7827 a.push( i );
7828 }
7829 else { // applied | removed
7830 tmp = $.inArray( i, displayFiltered );
7831
7832 if ((tmp === -1 && search == 'removed') ||
7833 (tmp >= 0 && search == 'applied') )
7834 {
7835 a.push( i );
7836 }
7837 }
7838 }
7839 }
7840
7841 return a;
7842 };
7843
7844
7845 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
7846 * Rows
7847 *
7848 * {} - no selector - use all available rows
7849 * {integer} - row aoData index
7850 * {node} - TR node
7851 * {string} - jQuery selector to apply to the TR elements
7852 * {array} - jQuery array of nodes, or simply an array of TR nodes
7853 *
7854 */
7855
7856
7857 var __row_selector = function ( settings, selector, opts )
7858 {
7859 var rows;
7860 var run = function ( sel ) {
7861 var selInt = _intVal( sel );
7862 var i, ien;
7863
7864 // Short cut - selector is a number and no options provided (default is
7865 // all records, so no need to check if the index is in there, since it
7866 // must be - dev error if the index doesn't exist).
7867 if ( selInt !== null && ! opts ) {
7868 return [ selInt ];
7869 }
7870
7871 if ( ! rows ) {
7872 rows = _selector_row_indexes( settings, opts );
7873 }
7874
7875 if ( selInt !== null && $.inArray( selInt, rows ) !== -1 ) {
7876 // Selector - integer
7877 return [ selInt ];
7878 }
7879 else if ( sel === null || sel === undefined || sel === '' ) {
7880 // Selector - none
7881 return rows;
7882 }
7883
7884 // Selector - function
7885 if ( typeof sel === 'function' ) {
7886 return $.map( rows, function (idx) {
7887 var row = settings.aoData[ idx ];
7888 return sel( idx, row._aData, row.nTr ) ? idx : null;
7889 } );
7890 }
7891
7892 // Get nodes in the order from the `rows` array with null values removed
7893 var nodes = _removeEmpty(
7894 _pluck_order( settings.aoData, rows, 'nTr' )
7895 );
7896
7897 // Selector - node
7898 if ( sel.nodeName ) {
7899 if ( sel._DT_RowIndex !== undefined ) {
7900 return [ sel._DT_RowIndex ]; // Property added by DT for fast lookup
7901 }
7902 else if ( sel._DT_CellIndex ) {
7903 return [ sel._DT_CellIndex.row ];
7904 }
7905 else {
7906 var host = $(sel).closest('*[data-dt-row]');
7907 return host.length ?
7908 [ host.data('dt-row') ] :
7909 [];
7910 }
7911 }
7912
7913 // ID selector. Want to always be able to select rows by id, regardless
7914 // of if the tr element has been created or not, so can't rely upon
7915 // jQuery here - hence a custom implementation. This does not match
7916 // Sizzle's fast selector or HTML4 - in HTML5 the ID can be anything,
7917 // but to select it using a CSS selector engine (like Sizzle or
7918 // querySelect) it would need to need to be escaped for some characters.
7919 // DataTables simplifies this for row selectors since you can select
7920 // only a row. A # indicates an id any anything that follows is the id -
7921 // unescaped.
7922 if ( typeof sel === 'string' && sel.charAt(0) === '#' ) {
7923 // get row index from id
7924 var rowObj = settings.aIds[ sel.replace( /^#/, '' ) ];
7925 if ( rowObj !== undefined ) {
7926 return [ rowObj.idx ];
7927 }
7928
7929 // need to fall through to jQuery in case there is DOM id that
7930 // matches
7931 }
7932
7933 // Selector - jQuery selector string, array of nodes or jQuery object/
7934 // As jQuery's .filter() allows jQuery objects to be passed in filter,
7935 // it also allows arrays, so this will cope with all three options
7936 return $(nodes)
7937 .filter( sel )
7938 .map( function () {
7939 return this._DT_RowIndex;
7940 } )
7941 .toArray();
7942 };
7943
7944 return _selector_run( 'row', selector, run, settings, opts );
7945 };
7946
7947
7948 _api_register( 'rows()', function ( selector, opts ) {
7949 // argument shifting
7950 if ( selector === undefined ) {
7951 selector = '';
7952 }
7953 else if ( $.isPlainObject( selector ) ) {
7954 opts = selector;
7955 selector = '';
7956 }
7957
7958 opts = _selector_opts( opts );
7959
7960 var inst = this.iterator( 'table', function ( settings ) {
7961 return __row_selector( settings, selector, opts );
7962 }, 1 );
7963
7964 // Want argument shifting here and in __row_selector?
7965 inst.selector.rows = selector;
7966 inst.selector.opts = opts;
7967
7968 return inst;
7969 } );
7970
7971 _api_register( 'rows().nodes()', function () {
7972 return this.iterator( 'row', function ( settings, row ) {
7973 return settings.aoData[ row ].nTr || undefined;
7974 }, 1 );
7975 } );
7976
7977 _api_register( 'rows().data()', function () {
7978 return this.iterator( true, 'rows', function ( settings, rows ) {
7979 return _pluck_order( settings.aoData, rows, '_aData' );
7980 }, 1 );
7981 } );
7982
7983 _api_registerPlural( 'rows().cache()', 'row().cache()', function ( type ) {
7984 return this.iterator( 'row', function ( settings, row ) {
7985 var r = settings.aoData[ row ];
7986 return type === 'search' ? r._aFilterData : r._aSortData;
7987 }, 1 );
7988 } );
7989
7990 _api_registerPlural( 'rows().invalidate()', 'row().invalidate()', function ( src ) {
7991 return this.iterator( 'row', function ( settings, row ) {
7992 _fnInvalidate( settings, row, src );
7993 } );
7994 } );
7995
7996 _api_registerPlural( 'rows().indexes()', 'row().index()', function () {
7997 return this.iterator( 'row', function ( settings, row ) {
7998 return row;
7999 }, 1 );
8000 } );
8001
8002 _api_registerPlural( 'rows().ids()', 'row().id()', function ( hash ) {
8003 var a = [];
8004 var context = this.context;
8005
8006 // `iterator` will drop undefined values, but in this case we want them
8007 for ( var i=0, ien=context.length ; i<ien ; i++ ) {
8008 for ( var j=0, jen=this[i].length ; j<jen ; j++ ) {
8009 var id = context[i].rowIdFn( context[i].aoData[ this[i][j] ]._aData );
8010 a.push( (hash === true ? '#' : '' )+ id );
8011 }
8012 }
8013
8014 return new _Api( context, a );
8015 } );
8016
8017 _api_registerPlural( 'rows().remove()', 'row().remove()', function () {
8018 var that = this;
8019
8020 this.iterator( 'row', function ( settings, row, thatIdx ) {
8021 var data = settings.aoData;
8022 var rowData = data[ row ];
8023 var i, ien, j, jen;
8024 var loopRow, loopCells;
8025
8026 data.splice( row, 1 );
8027
8028 // Update the cached indexes
8029 for ( i=0, ien=data.length ; i<ien ; i++ ) {
8030 loopRow = data[i];
8031 loopCells = loopRow.anCells;
8032
8033 // Rows
8034 if ( loopRow.nTr !== null ) {
8035 loopRow.nTr._DT_RowIndex = i;
8036 }
8037
8038 // Cells
8039 if ( loopCells !== null ) {
8040 for ( j=0, jen=loopCells.length ; j<jen ; j++ ) {
8041 loopCells[j]._DT_CellIndex.row = i;
8042 }
8043 }
8044 }
8045
8046 // Delete from the display arrays
8047 _fnDeleteIndex( settings.aiDisplayMaster, row );
8048 _fnDeleteIndex( settings.aiDisplay, row );
8049 _fnDeleteIndex( that[ thatIdx ], row, false ); // maintain local indexes
8050
8051 // For server-side processing tables - subtract the deleted row from the count
8052 if ( settings._iRecordsDisplay > 0 ) {
8053 settings._iRecordsDisplay--;
8054 }
8055
8056 // Check for an 'overflow' they case for displaying the table
8057 _fnLengthOverflow( settings );
8058
8059 // Remove the row's ID reference if there is one
8060 var id = settings.rowIdFn( rowData._aData );
8061 if ( id !== undefined ) {
8062 delete settings.aIds[ id ];
8063 }
8064 } );
8065
8066 this.iterator( 'table', function ( settings ) {
8067 for ( var i=0, ien=settings.aoData.length ; i<ien ; i++ ) {
8068 settings.aoData[i].idx = i;
8069 }
8070 } );
8071
8072 return this;
8073 } );
8074
8075
8076 _api_register( 'rows.add()', function ( rows ) {
8077 var newRows = this.iterator( 'table', function ( settings ) {
8078 var row, i, ien;
8079 var out = [];
8080
8081 for ( i=0, ien=rows.length ; i<ien ; i++ ) {
8082 row = rows[i];
8083
8084 if ( row.nodeName && row.nodeName.toUpperCase() === 'TR' ) {
8085 out.push( _fnAddTr( settings, row )[0] );
8086 }
8087 else {
8088 out.push( _fnAddData( settings, row ) );
8089 }
8090 }
8091
8092 return out;
8093 }, 1 );
8094
8095 // Return an Api.rows() extended instance, so rows().nodes() etc can be used
8096 var modRows = this.rows( -1 );
8097 modRows.pop();
8098 $.merge( modRows, newRows );
8099
8100 return modRows;
8101 } );
8102
8103
8104
8105
8106
8107 /**
8108 *
8109 */
8110 _api_register( 'row()', function ( selector, opts ) {
8111 return _selector_first( this.rows( selector, opts ) );
8112 } );
8113
8114
8115 _api_register( 'row().data()', function ( data ) {
8116 var ctx = this.context;
8117
8118 if ( data === undefined ) {
8119 // Get
8120 return ctx.length && this.length ?
8121 ctx[0].aoData[ this[0] ]._aData :
8122 undefined;
8123 }
8124
8125 // Set
8126 ctx[0].aoData[ this[0] ]._aData = data;
8127
8128 // Automatically invalidate
8129 _fnInvalidate( ctx[0], this[0], 'data' );
8130
8131 return this;
8132 } );
8133
8134
8135 _api_register( 'row().node()', function () {
8136 var ctx = this.context;
8137
8138 return ctx.length && this.length ?
8139 ctx[0].aoData[ this[0] ].nTr || null :
8140 null;
8141 } );
8142
8143
8144 _api_register( 'row.add()', function ( row ) {
8145 // Allow a jQuery object to be passed in - only a single row is added from
8146 // it though - the first element in the set
8147 if ( row instanceof $ && row.length ) {
8148 row = row[0];
8149 }
8150
8151 var rows = this.iterator( 'table', function ( settings ) {
8152 if ( row.nodeName && row.nodeName.toUpperCase() === 'TR' ) {
8153 return _fnAddTr( settings, row )[0];
8154 }
8155 return _fnAddData( settings, row );
8156 } );
8157
8158 // Return an Api.rows() extended instance, with the newly added row selected
8159 return this.row( rows[0] );
8160 } );
8161
8162
8163
8164 var __details_add = function ( ctx, row, data, klass )
8165 {
8166 // Convert to array of TR elements
8167 var rows = [];
8168 var addRow = function ( r, k ) {
8169 // Recursion to allow for arrays of jQuery objects
8170 if ( $.isArray( r ) || r instanceof $ ) {
8171 for ( var i=0, ien=r.length ; i<ien ; i++ ) {
8172 addRow( r[i], k );
8173 }
8174 return;
8175 }
8176
8177 // If we get a TR element, then just add it directly - up to the dev
8178 // to add the correct number of columns etc
8179 if ( r.nodeName && r.nodeName.toLowerCase() === 'tr' ) {
8180 rows.push( r );
8181 }
8182 else {
8183 // Otherwise create a row with a wrapper
8184 var created = $('<tr><td/></tr>').addClass( k );
8185 $('td', created)
8186 .addClass( k )
8187 .html( r )
8188 [0].colSpan = _fnVisbleColumns( ctx );
8189
8190 rows.push( created[0] );
8191 }
8192 };
8193
8194 addRow( data, klass );
8195
8196 if ( row._details ) {
8197 row._details.detach();
8198 }
8199
8200 row._details = $(rows);
8201
8202 // If the children were already shown, that state should be retained
8203 if ( row._detailsShow ) {
8204 row._details.insertAfter( row.nTr );
8205 }
8206 };
8207
8208
8209 var __details_remove = function ( api, idx )
8210 {
8211 var ctx = api.context;
8212
8213 if ( ctx.length ) {
8214 var row = ctx[0].aoData[ idx !== undefined ? idx : api[0] ];
8215
8216 if ( row && row._details ) {
8217 row._details.remove();
8218
8219 row._detailsShow = undefined;
8220 row._details = undefined;
8221 }
8222 }
8223 };
8224
8225
8226 var __details_display = function ( api, show ) {
8227 var ctx = api.context;
8228
8229 if ( ctx.length && api.length ) {
8230 var row = ctx[0].aoData[ api[0] ];
8231
8232 if ( row._details ) {
8233 row._detailsShow = show;
8234
8235 if ( show ) {
8236 row._details.insertAfter( row.nTr );
8237 }
8238 else {
8239 row._details.detach();
8240 }
8241
8242 __details_events( ctx[0] );
8243 }
8244 }
8245 };
8246
8247
8248 var __details_events = function ( settings )
8249 {
8250 var api = new _Api( settings );
8251 var namespace = '.dt.DT_details';
8252 var drawEvent = 'draw'+namespace;
8253 var colvisEvent = 'column-visibility'+namespace;
8254 var destroyEvent = 'destroy'+namespace;
8255 var data = settings.aoData;
8256
8257 api.off( drawEvent +' '+ colvisEvent +' '+ destroyEvent );
8258
8259 if ( _pluck( data, '_details' ).length > 0 ) {
8260 // On each draw, insert the required elements into the document
8261 api.on( drawEvent, function ( e, ctx ) {
8262 if ( settings !== ctx ) {
8263 return;
8264 }
8265
8266 api.rows( {page:'current'} ).eq(0).each( function (idx) {
8267 // Internal data grab
8268 var row = data[ idx ];
8269
8270 if ( row._detailsShow ) {
8271 row._details.insertAfter( row.nTr );
8272 }
8273 } );
8274 } );
8275
8276 // Column visibility change - update the colspan
8277 api.on( colvisEvent, function ( e, ctx, idx, vis ) {
8278 if ( settings !== ctx ) {
8279 return;
8280 }
8281
8282 // Update the colspan for the details rows (note, only if it already has
8283 // a colspan)
8284 var row, visible = _fnVisbleColumns( ctx );
8285
8286 for ( var i=0, ien=data.length ; i<ien ; i++ ) {
8287 row = data[i];
8288
8289 if ( row._details ) {
8290 row._details.children('td[colspan]').attr('colspan', visible );
8291 }
8292 }
8293 } );
8294
8295 // Table destroyed - nuke any child rows
8296 api.on( destroyEvent, function ( e, ctx ) {
8297 if ( settings !== ctx ) {
8298 return;
8299 }
8300
8301 for ( var i=0, ien=data.length ; i<ien ; i++ ) {
8302 if ( data[i]._details ) {
8303 __details_remove( api, i );
8304 }
8305 }
8306 } );
8307 }
8308 };
8309
8310 // Strings for the method names to help minification
8311 var _emp = '';
8312 var _child_obj = _emp+'row().child';
8313 var _child_mth = _child_obj+'()';
8314
8315 // data can be:
8316 // tr
8317 // string
8318 // jQuery or array of any of the above
8319 _api_register( _child_mth, function ( data, klass ) {
8320 var ctx = this.context;
8321
8322 if ( data === undefined ) {
8323 // get
8324 return ctx.length && this.length ?
8325 ctx[0].aoData[ this[0] ]._details :
8326 undefined;
8327 }
8328 else if ( data === true ) {
8329 // show
8330 this.child.show();
8331 }
8332 else if ( data === false ) {
8333 // remove
8334 __details_remove( this );
8335 }
8336 else if ( ctx.length && this.length ) {
8337 // set
8338 __details_add( ctx[0], ctx[0].aoData[ this[0] ], data, klass );
8339 }
8340
8341 return this;
8342 } );
8343
8344
8345 _api_register( [
8346 _child_obj+'.show()',
8347 _child_mth+'.show()' // only when `child()` was called with parameters (without
8348 ], function ( show ) { // it returns an object and this method is not executed)
8349 __details_display( this, true );
8350 return this;
8351 } );
8352
8353
8354 _api_register( [
8355 _child_obj+'.hide()',
8356 _child_mth+'.hide()' // only when `child()` was called with parameters (without
8357 ], function () { // it returns an object and this method is not executed)
8358 __details_display( this, false );
8359 return this;
8360 } );
8361
8362
8363 _api_register( [
8364 _child_obj+'.remove()',
8365 _child_mth+'.remove()' // only when `child()` was called with parameters (without
8366 ], function () { // it returns an object and this method is not executed)
8367 __details_remove( this );
8368 return this;
8369 } );
8370
8371
8372 _api_register( _child_obj+'.isShown()', function () {
8373 var ctx = this.context;
8374
8375 if ( ctx.length && this.length ) {
8376 // _detailsShown as false or undefined will fall through to return false
8377 return ctx[0].aoData[ this[0] ]._detailsShow || false;
8378 }
8379 return false;
8380 } );
8381
8382
8383
8384 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
8385 * Columns
8386 *
8387 * {integer} - column index (>=0 count from left, <0 count from right)
8388 * "{integer}:visIdx" - visible column index (i.e. translate to column index) (>=0 count from left, <0 count from right)
8389 * "{integer}:visible" - alias for {integer}:visIdx (>=0 count from left, <0 count from right)
8390 * "{string}:name" - column name
8391 * "{string}" - jQuery selector on column header nodes
8392 *
8393 */
8394
8395 // can be an array of these items, comma separated list, or an array of comma
8396 // separated lists
8397
8398 var __re_column_selector = /^([^:]+):(name|visIdx|visible)$/;
8399
8400
8401 // r1 and r2 are redundant - but it means that the parameters match for the
8402 // iterator callback in columns().data()
8403 var __columnData = function ( settings, column, r1, r2, rows ) {
8404 var a = [];
8405 for ( var row=0, ien=rows.length ; row<ien ; row++ ) {
8406 a.push( _fnGetCellData( settings, rows[row], column ) );
8407 }
8408 return a;
8409 };
8410
8411
8412 var __column_selector = function ( settings, selector, opts )
8413 {
8414 var
8415 columns = settings.aoColumns,
8416 names = _pluck( columns, 'sName' ),
8417 nodes = _pluck( columns, 'nTh' );
8418
8419 var run = function ( s ) {
8420 var selInt = _intVal( s );
8421
8422 // Selector - all
8423 if ( s === '' ) {
8424 return _range( columns.length );
8425 }
8426
8427 // Selector - index
8428 if ( selInt !== null ) {
8429 return [ selInt >= 0 ?
8430 selInt : // Count from left
8431 columns.length + selInt // Count from right (+ because its a negative value)
8432 ];
8433 }
8434
8435 // Selector = function
8436 if ( typeof s === 'function' ) {
8437 var rows = _selector_row_indexes( settings, opts );
8438
8439 return $.map( columns, function (col, idx) {
8440 return s(
8441 idx,
8442 __columnData( settings, idx, 0, 0, rows ),
8443 nodes[ idx ]
8444 ) ? idx : null;
8445 } );
8446 }
8447
8448 // jQuery or string selector
8449 var match = typeof s === 'string' ?
8450 s.match( __re_column_selector ) :
8451 '';
8452
8453 if ( match ) {
8454 switch( match[2] ) {
8455 case 'visIdx':
8456 case 'visible':
8457 var idx = parseInt( match[1], 10 );
8458 // Visible index given, convert to column index
8459 if ( idx < 0 ) {
8460 // Counting from the right
8461 var visColumns = $.map( columns, function (col,i) {
8462 return col.bVisible ? i : null;
8463 } );
8464 return [ visColumns[ visColumns.length + idx ] ];
8465 }
8466 // Counting from the left
8467 return [ _fnVisibleToColumnIndex( settings, idx ) ];
8468
8469 case 'name':
8470 // match by name. `names` is column index complete and in order
8471 return $.map( names, function (name, i) {
8472 return name === match[1] ? i : null;
8473 } );
8474
8475 default:
8476 return [];
8477 }
8478 }
8479
8480 // Cell in the table body
8481 if ( s.nodeName && s._DT_CellIndex ) {
8482 return [ s._DT_CellIndex.column ];
8483 }
8484
8485 // jQuery selector on the TH elements for the columns
8486 var jqResult = $( nodes )
8487 .filter( s )
8488 .map( function () {
8489 return $.inArray( this, nodes ); // `nodes` is column index complete and in order
8490 } )
8491 .toArray();
8492
8493 if ( jqResult.length || ! s.nodeName ) {
8494 return jqResult;
8495 }
8496
8497 // Otherwise a node which might have a `dt-column` data attribute, or be
8498 // a child or such an element
8499 var host = $(s).closest('*[data-dt-column]');
8500 return host.length ?
8501 [ host.data('dt-column') ] :
8502 [];
8503 };
8504
8505 return _selector_run( 'column', selector, run, settings, opts );
8506 };
8507
8508
8509 var __setColumnVis = function ( settings, column, vis ) {
8510 var
8511 cols = settings.aoColumns,
8512 col = cols[ column ],
8513 data = settings.aoData,
8514 row, cells, i, ien, tr;
8515
8516 // Get
8517 if ( vis === undefined ) {
8518 return col.bVisible;
8519 }
8520
8521 // Set
8522 // No change
8523 if ( col.bVisible === vis ) {
8524 return;
8525 }
8526
8527 if ( vis ) {
8528 // Insert column
8529 // Need to decide if we should use appendChild or insertBefore
8530 var insertBefore = $.inArray( true, _pluck(cols, 'bVisible'), column+1 );
8531
8532 for ( i=0, ien=data.length ; i<ien ; i++ ) {
8533 tr = data[i].nTr;
8534 cells = data[i].anCells;
8535
8536 if ( tr ) {
8537 // insertBefore can act like appendChild if 2nd arg is null
8538 tr.insertBefore( cells[ column ], cells[ insertBefore ] || null );
8539 }
8540 }
8541 }
8542 else {
8543 // Remove column
8544 $( _pluck( settings.aoData, 'anCells', column ) ).detach();
8545 }
8546
8547 // Common actions
8548 col.bVisible = vis;
8549 _fnDrawHead( settings, settings.aoHeader );
8550 _fnDrawHead( settings, settings.aoFooter );
8551
8552 _fnSaveState( settings );
8553 };
8554
8555
8556 _api_register( 'columns()', function ( selector, opts ) {
8557 // argument shifting
8558 if ( selector === undefined ) {
8559 selector = '';
8560 }
8561 else if ( $.isPlainObject( selector ) ) {
8562 opts = selector;
8563 selector = '';
8564 }
8565
8566 opts = _selector_opts( opts );
8567
8568 var inst = this.iterator( 'table', function ( settings ) {
8569 return __column_selector( settings, selector, opts );
8570 }, 1 );
8571
8572 // Want argument shifting here and in _row_selector?
8573 inst.selector.cols = selector;
8574 inst.selector.opts = opts;
8575
8576 return inst;
8577 } );
8578
8579 _api_registerPlural( 'columns().header()', 'column().header()', function ( selector, opts ) {
8580 return this.iterator( 'column', function ( settings, column ) {
8581 return settings.aoColumns[column].nTh;
8582 }, 1 );
8583 } );
8584
8585 _api_registerPlural( 'columns().footer()', 'column().footer()', function ( selector, opts ) {
8586 return this.iterator( 'column', function ( settings, column ) {
8587 return settings.aoColumns[column].nTf;
8588 }, 1 );
8589 } );
8590
8591 _api_registerPlural( 'columns().data()', 'column().data()', function () {
8592 return this.iterator( 'column-rows', __columnData, 1 );
8593 } );
8594
8595 _api_registerPlural( 'columns().dataSrc()', 'column().dataSrc()', function () {
8596 return this.iterator( 'column', function ( settings, column ) {
8597 return settings.aoColumns[column].mData;
8598 }, 1 );
8599 } );
8600
8601 _api_registerPlural( 'columns().cache()', 'column().cache()', function ( type ) {
8602 return this.iterator( 'column-rows', function ( settings, column, i, j, rows ) {
8603 return _pluck_order( settings.aoData, rows,
8604 type === 'search' ? '_aFilterData' : '_aSortData', column
8605 );
8606 }, 1 );
8607 } );
8608
8609 _api_registerPlural( 'columns().nodes()', 'column().nodes()', function () {
8610 return this.iterator( 'column-rows', function ( settings, column, i, j, rows ) {
8611 return _pluck_order( settings.aoData, rows, 'anCells', column ) ;
8612 }, 1 );
8613 } );
8614
8615 _api_registerPlural( 'columns().visible()', 'column().visible()', function ( vis, calc ) {
8616 var ret = this.iterator( 'column', function ( settings, column ) {
8617 if ( vis === undefined ) {
8618 return settings.aoColumns[ column ].bVisible;
8619 } // else
8620 __setColumnVis( settings, column, vis );
8621 } );
8622
8623 // Group the column visibility changes
8624 if ( vis !== undefined ) {
8625 // Second loop once the first is done for events
8626 this.iterator( 'column', function ( settings, column ) {
8627 _fnCallbackFire( settings, null, 'column-visibility', [settings, column, vis, calc] );
8628 } );
8629
8630 if ( calc === undefined || calc ) {
8631 this.columns.adjust();
8632 }
8633 }
8634
8635 return ret;
8636 } );
8637
8638 _api_registerPlural( 'columns().indexes()', 'column().index()', function ( type ) {
8639 return this.iterator( 'column', function ( settings, column ) {
8640 return type === 'visible' ?
8641 _fnColumnIndexToVisible( settings, column ) :
8642 column;
8643 }, 1 );
8644 } );
8645
8646 _api_register( 'columns.adjust()', function () {
8647 return this.iterator( 'table', function ( settings ) {
8648 _fnAdjustColumnSizing( settings );
8649 }, 1 );
8650 } );
8651
8652 _api_register( 'column.index()', function ( type, idx ) {
8653 if ( this.context.length !== 0 ) {
8654 var ctx = this.context[0];
8655
8656 if ( type === 'fromVisible' || type === 'toData' ) {
8657 return _fnVisibleToColumnIndex( ctx, idx );
8658 }
8659 else if ( type === 'fromData' || type === 'toVisible' ) {
8660 return _fnColumnIndexToVisible( ctx, idx );
8661 }
8662 }
8663 } );
8664
8665 _api_register( 'column()', function ( selector, opts ) {
8666 return _selector_first( this.columns( selector, opts ) );
8667 } );
8668
8669
8670
8671 var __cell_selector = function ( settings, selector, opts )
8672 {
8673 var data = settings.aoData;
8674 var rows = _selector_row_indexes( settings, opts );
8675 var cells = _removeEmpty( _pluck_order( data, rows, 'anCells' ) );
8676 var allCells = $( [].concat.apply([], cells) );
8677 var row;
8678 var columns = settings.aoColumns.length;
8679 var a, i, ien, j, o, host;
8680
8681 var run = function ( s ) {
8682 var fnSelector = typeof s === 'function';
8683
8684 if ( s === null || s === undefined || fnSelector ) {
8685 // All cells and function selectors
8686 a = [];
8687
8688 for ( i=0, ien=rows.length ; i<ien ; i++ ) {
8689 row = rows[i];
8690
8691 for ( j=0 ; j<columns ; j++ ) {
8692 o = {
8693 row: row,
8694 column: j
8695 };
8696
8697 if ( fnSelector ) {
8698 // Selector - function
8699 host = data[ row ];
8700
8701 if ( s( o, _fnGetCellData(settings, row, j), host.anCells ? host.anCells[j] : null ) ) {
8702 a.push( o );
8703 }
8704 }
8705 else {
8706 // Selector - all
8707 a.push( o );
8708 }
8709 }
8710 }
8711
8712 return a;
8713 }
8714
8715 // Selector - index
8716 if ( $.isPlainObject( s ) ) {
8717 return [s];
8718 }
8719
8720 // Selector - jQuery filtered cells
8721 var jqResult = allCells
8722 .filter( s )
8723 .map( function (i, el) {
8724 return { // use a new object, in case someone changes the values
8725 row: el._DT_CellIndex.row,
8726 column: el._DT_CellIndex.column
8727 };
8728 } )
8729 .toArray();
8730
8731 if ( jqResult.length || ! s.nodeName ) {
8732 return jqResult;
8733 }
8734
8735 // Otherwise the selector is a node, and there is one last option - the
8736 // element might be a child of an element which has dt-row and dt-column
8737 // data attributes
8738 host = $(s).closest('*[data-dt-row]');
8739 return host.length ?
8740 [ {
8741 row: host.data('dt-row'),
8742 column: host.data('dt-column')
8743 } ] :
8744 [];
8745 };
8746
8747 return _selector_run( 'cell', selector, run, settings, opts );
8748 };
8749
8750
8751
8752
8753 _api_register( 'cells()', function ( rowSelector, columnSelector, opts ) {
8754 // Argument shifting
8755 if ( $.isPlainObject( rowSelector ) ) {
8756 // Indexes
8757 if ( rowSelector.row === undefined ) {
8758 // Selector options in first parameter
8759 opts = rowSelector;
8760 rowSelector = null;
8761 }
8762 else {
8763 // Cell index objects in first parameter
8764 opts = columnSelector;
8765 columnSelector = null;
8766 }
8767 }
8768 if ( $.isPlainObject( columnSelector ) ) {
8769 opts = columnSelector;
8770 columnSelector = null;
8771 }
8772
8773 // Cell selector
8774 if ( columnSelector === null || columnSelector === undefined ) {
8775 return this.iterator( 'table', function ( settings ) {
8776 return __cell_selector( settings, rowSelector, _selector_opts( opts ) );
8777 } );
8778 }
8779
8780 // Row + column selector
8781 var columns = this.columns( columnSelector, opts );
8782 var rows = this.rows( rowSelector, opts );
8783 var a, i, ien, j, jen;
8784
8785 var cells = this.iterator( 'table', function ( settings, idx ) {
8786 a = [];
8787
8788 for ( i=0, ien=rows[idx].length ; i<ien ; i++ ) {
8789 for ( j=0, jen=columns[idx].length ; j<jen ; j++ ) {
8790 a.push( {
8791 row: rows[idx][i],
8792 column: columns[idx][j]
8793 } );
8794 }
8795 }
8796
8797 return a;
8798 }, 1 );
8799
8800 $.extend( cells.selector, {
8801 cols: columnSelector,
8802 rows: rowSelector,
8803 opts: opts
8804 } );
8805
8806 return cells;
8807 } );
8808
8809
8810 _api_registerPlural( 'cells().nodes()', 'cell().node()', function () {
8811 return this.iterator( 'cell', function ( settings, row, column ) {
8812 var data = settings.aoData[ row ];
8813
8814 return data && data.anCells ?
8815 data.anCells[ column ] :
8816 undefined;
8817 }, 1 );
8818 } );
8819
8820
8821 _api_register( 'cells().data()', function () {
8822 return this.iterator( 'cell', function ( settings, row, column ) {
8823 return _fnGetCellData( settings, row, column );
8824 }, 1 );
8825 } );
8826
8827
8828 _api_registerPlural( 'cells().cache()', 'cell().cache()', function ( type ) {
8829 type = type === 'search' ? '_aFilterData' : '_aSortData';
8830
8831 return this.iterator( 'cell', function ( settings, row, column ) {
8832 return settings.aoData[ row ][ type ][ column ];
8833 }, 1 );
8834 } );
8835
8836
8837 _api_registerPlural( 'cells().render()', 'cell().render()', function ( type ) {
8838 return this.iterator( 'cell', function ( settings, row, column ) {
8839 return _fnGetCellData( settings, row, column, type );
8840 }, 1 );
8841 } );
8842
8843
8844 _api_registerPlural( 'cells().indexes()', 'cell().index()', function () {
8845 return this.iterator( 'cell', function ( settings, row, column ) {
8846 return {
8847 row: row,
8848 column: column,
8849 columnVisible: _fnColumnIndexToVisible( settings, column )
8850 };
8851 }, 1 );
8852 } );
8853
8854
8855 _api_registerPlural( 'cells().invalidate()', 'cell().invalidate()', function ( src ) {
8856 return this.iterator( 'cell', function ( settings, row, column ) {
8857 _fnInvalidate( settings, row, src, column );
8858 } );
8859 } );
8860
8861
8862
8863 _api_register( 'cell()', function ( rowSelector, columnSelector, opts ) {
8864 return _selector_first( this.cells( rowSelector, columnSelector, opts ) );
8865 } );
8866
8867
8868 _api_register( 'cell().data()', function ( data ) {
8869 var ctx = this.context;
8870 var cell = this[0];
8871
8872 if ( data === undefined ) {
8873 // Get
8874 return ctx.length && cell.length ?
8875 _fnGetCellData( ctx[0], cell[0].row, cell[0].column ) :
8876 undefined;
8877 }
8878
8879 // Set
8880 _fnSetCellData( ctx[0], cell[0].row, cell[0].column, data );
8881 _fnInvalidate( ctx[0], cell[0].row, 'data', cell[0].column );
8882
8883 return this;
8884 } );
8885
8886
8887
8888 /**
8889 * Get current ordering (sorting) that has been applied to the table.
8890 *
8891 * @returns {array} 2D array containing the sorting information for the first
8892 * table in the current context. Each element in the parent array represents
8893 * a column being sorted upon (i.e. multi-sorting with two columns would have
8894 * 2 inner arrays). The inner arrays may have 2 or 3 elements. The first is
8895 * the column index that the sorting condition applies to, the second is the
8896 * direction of the sort (`desc` or `asc`) and, optionally, the third is the
8897 * index of the sorting order from the `column.sorting` initialisation array.
8898 *//**
8899 * Set the ordering for the table.
8900 *
8901 * @param {integer} order Column index to sort upon.
8902 * @param {string} direction Direction of the sort to be applied (`asc` or `desc`)
8903 * @returns {DataTables.Api} this
8904 *//**
8905 * Set the ordering for the table.
8906 *
8907 * @param {array} order 1D array of sorting information to be applied.
8908 * @param {array} [...] Optional additional sorting conditions
8909 * @returns {DataTables.Api} this
8910 *//**
8911 * Set the ordering for the table.
8912 *
8913 * @param {array} order 2D array of sorting information to be applied.
8914 * @returns {DataTables.Api} this
8915 */
8916 _api_register( 'order()', function ( order, dir ) {
8917 var ctx = this.context;
8918
8919 if ( order === undefined ) {
8920 // get
8921 return ctx.length !== 0 ?
8922 ctx[0].aaSorting :
8923 undefined;
8924 }
8925
8926 // set
8927 if ( typeof order === 'number' ) {
8928 // Simple column / direction passed in
8929 order = [ [ order, dir ] ];
8930 }
8931 else if ( order.length && ! $.isArray( order[0] ) ) {
8932 // Arguments passed in (list of 1D arrays)
8933 order = Array.prototype.slice.call( arguments );
8934 }
8935 // otherwise a 2D array was passed in
8936
8937 return this.iterator( 'table', function ( settings ) {
8938 settings.aaSorting = order.slice();
8939 } );
8940 } );
8941
8942
8943 /**
8944 * Attach a sort listener to an element for a given column
8945 *
8946 * @param {node|jQuery|string} node Identifier for the element(s) to attach the
8947 * listener to. This can take the form of a single DOM node, a jQuery
8948 * collection of nodes or a jQuery selector which will identify the node(s).
8949 * @param {integer} column the column that a click on this node will sort on
8950 * @param {function} [callback] callback function when sort is run
8951 * @returns {DataTables.Api} this
8952 */
8953 _api_register( 'order.listener()', function ( node, column, callback ) {
8954 return this.iterator( 'table', function ( settings ) {
8955 _fnSortAttachListener( settings, node, column, callback );
8956 } );
8957 } );
8958
8959
8960 _api_register( 'order.fixed()', function ( set ) {
8961 if ( ! set ) {
8962 var ctx = this.context;
8963 var fixed = ctx.length ?
8964 ctx[0].aaSortingFixed :
8965 undefined;
8966
8967 return $.isArray( fixed ) ?
8968 { pre: fixed } :
8969 fixed;
8970 }
8971
8972 return this.iterator( 'table', function ( settings ) {
8973 settings.aaSortingFixed = $.extend( true, {}, set );
8974 } );
8975 } );
8976
8977
8978 // Order by the selected column(s)
8979 _api_register( [
8980 'columns().order()',
8981 'column().order()'
8982 ], function ( dir ) {
8983 var that = this;
8984
8985 return this.iterator( 'table', function ( settings, i ) {
8986 var sort = [];
8987
8988 $.each( that[i], function (j, col) {
8989 sort.push( [ col, dir ] );
8990 } );
8991
8992 settings.aaSorting = sort;
8993 } );
8994 } );
8995
8996
8997
8998 _api_register( 'search()', function ( input, regex, smart, caseInsen ) {
8999 var ctx = this.context;
9000
9001 if ( input === undefined ) {
9002 // get
9003 return ctx.length !== 0 ?
9004 ctx[0].oPreviousSearch.sSearch :
9005 undefined;
9006 }
9007
9008 // set
9009 return this.iterator( 'table', function ( settings ) {
9010 if ( ! settings.oFeatures.bFilter ) {
9011 return;
9012 }
9013
9014 _fnFilterComplete( settings, $.extend( {}, settings.oPreviousSearch, {
9015 "sSearch": input+"",
9016 "bRegex": regex === null ? false : regex,
9017 "bSmart": smart === null ? true : smart,
9018 "bCaseInsensitive": caseInsen === null ? true : caseInsen
9019 } ), 1 );
9020 } );
9021 } );
9022
9023
9024 _api_registerPlural(
9025 'columns().search()',
9026 'column().search()',
9027 function ( input, regex, smart, caseInsen ) {
9028 return this.iterator( 'column', function ( settings, column ) {
9029 var preSearch = settings.aoPreSearchCols;
9030
9031 if ( input === undefined ) {
9032 // get
9033 return preSearch[ column ].sSearch;
9034 }
9035
9036 // set
9037 if ( ! settings.oFeatures.bFilter ) {
9038 return;
9039 }
9040
9041 $.extend( preSearch[ column ], {
9042 "sSearch": input+"",
9043 "bRegex": regex === null ? false : regex,
9044 "bSmart": smart === null ? true : smart,
9045 "bCaseInsensitive": caseInsen === null ? true : caseInsen
9046 } );
9047
9048 _fnFilterComplete( settings, settings.oPreviousSearch, 1 );
9049 } );
9050 }
9051 );
9052
9053 /*
9054 * State API methods
9055 */
9056
9057 _api_register( 'state()', function () {
9058 return this.context.length ?
9059 this.context[0].oSavedState :
9060 null;
9061 } );
9062
9063
9064 _api_register( 'state.clear()', function () {
9065 return this.iterator( 'table', function ( settings ) {
9066 // Save an empty object
9067 settings.fnStateSaveCallback.call( settings.oInstance, settings, {} );
9068 } );
9069 } );
9070
9071
9072 _api_register( 'state.loaded()', function () {
9073 return this.context.length ?
9074 this.context[0].oLoadedState :
9075 null;
9076 } );
9077
9078
9079 _api_register( 'state.save()', function () {
9080 return this.iterator( 'table', function ( settings ) {
9081 _fnSaveState( settings );
9082 } );
9083 } );
9084
9085
9086
9087 /**
9088 * Provide a common method for plug-ins to check the version of DataTables being
9089 * used, in order to ensure compatibility.
9090 *
9091 * @param {string} version Version string to check for, in the format "X.Y.Z".
9092 * Note that the formats "X" and "X.Y" are also acceptable.
9093 * @returns {boolean} true if this version of DataTables is greater or equal to
9094 * the required version, or false if this version of DataTales is not
9095 * suitable
9096 * @static
9097 * @dtopt API-Static
9098 *
9099 * @example
9100 * alert( $.fn.dataTable.versionCheck( '1.9.0' ) );
9101 */
9102 DataTable.versionCheck = DataTable.fnVersionCheck = function( version )
9103 {
9104 var aThis = DataTable.version.split('.');
9105 var aThat = version.split('.');
9106 var iThis, iThat;
9107
9108 for ( var i=0, iLen=aThat.length ; i<iLen ; i++ ) {
9109 iThis = parseInt( aThis[i], 10 ) || 0;
9110 iThat = parseInt( aThat[i], 10 ) || 0;
9111
9112 // Parts are the same, keep comparing
9113 if (iThis === iThat) {
9114 continue;
9115 }
9116
9117 // Parts are different, return immediately
9118 return iThis > iThat;
9119 }
9120
9121 return true;
9122 };
9123
9124
9125 /**
9126 * Check if a `<table>` node is a DataTable table already or not.
9127 *
9128 * @param {node|jquery|string} table Table node, jQuery object or jQuery
9129 * selector for the table to test. Note that if more than more than one
9130 * table is passed on, only the first will be checked
9131 * @returns {boolean} true the table given is a DataTable, or false otherwise
9132 * @static
9133 * @dtopt API-Static
9134 *
9135 * @example
9136 * if ( ! $.fn.DataTable.isDataTable( '#example' ) ) {
9137 * $('#example').dataTable();
9138 * }
9139 */
9140 DataTable.isDataTable = DataTable.fnIsDataTable = function ( table )
9141 {
9142 var t = $(table).get(0);
9143 var is = false;
9144
9145 if ( table instanceof DataTable.Api ) {
9146 return true;
9147 }
9148
9149 $.each( DataTable.settings, function (i, o) {
9150 var head = o.nScrollHead ? $('table', o.nScrollHead)[0] : null;
9151 var foot = o.nScrollFoot ? $('table', o.nScrollFoot)[0] : null;
9152
9153 if ( o.nTable === t || head === t || foot === t ) {
9154 is = true;
9155 }
9156 } );
9157
9158 return is;
9159 };
9160
9161
9162 /**
9163 * Get all DataTable tables that have been initialised - optionally you can
9164 * select to get only currently visible tables.
9165 *
9166 * @param {boolean} [visible=false] Flag to indicate if you want all (default)
9167 * or visible tables only.
9168 * @returns {array} Array of `table` nodes (not DataTable instances) which are
9169 * DataTables
9170 * @static
9171 * @dtopt API-Static
9172 *
9173 * @example
9174 * $.each( $.fn.dataTable.tables(true), function () {
9175 * $(table).DataTable().columns.adjust();
9176 * } );
9177 */
9178 DataTable.tables = DataTable.fnTables = function ( visible )
9179 {
9180 var api = false;
9181
9182 if ( $.isPlainObject( visible ) ) {
9183 api = visible.api;
9184 visible = visible.visible;
9185 }
9186
9187 var a = $.map( DataTable.settings, function (o) {
9188 if ( !visible || (visible && $(o.nTable).is(':visible')) ) {
9189 return o.nTable;
9190 }
9191 } );
9192
9193 return api ?
9194 new _Api( a ) :
9195 a;
9196 };
9197
9198
9199 /**
9200 * Convert from camel case parameters to Hungarian notation. This is made public
9201 * for the extensions to provide the same ability as DataTables core to accept
9202 * either the 1.9 style Hungarian notation, or the 1.10+ style camelCase
9203 * parameters.
9204 *
9205 * @param {object} src The model object which holds all parameters that can be
9206 * mapped.
9207 * @param {object} user The object to convert from camel case to Hungarian.
9208 * @param {boolean} force When set to `true`, properties which already have a
9209 * Hungarian value in the `user` object will be overwritten. Otherwise they
9210 * won't be.
9211 */
9212 DataTable.camelToHungarian = _fnCamelToHungarian;
9213
9214
9215
9216 /**
9217 *
9218 */
9219 _api_register( '$()', function ( selector, opts ) {
9220 var
9221 rows = this.rows( opts ).nodes(), // Get all rows
9222 jqRows = $(rows);
9223
9224 return $( [].concat(
9225 jqRows.filter( selector ).toArray(),
9226 jqRows.find( selector ).toArray()
9227 ) );
9228 } );
9229
9230
9231 // jQuery functions to operate on the tables
9232 $.each( [ 'on', 'one', 'off' ], function (i, key) {
9233 _api_register( key+'()', function ( /* event, handler */ ) {
9234 var args = Array.prototype.slice.call(arguments);
9235
9236 // Add the `dt` namespace automatically if it isn't already present
9237 args[0] = $.map( args[0].split( /\s/ ), function ( e ) {
9238 return ! e.match(/\.dt\b/) ?
9239 e+'.dt' :
9240 e;
9241 } ).join( ' ' );
9242
9243 var inst = $( this.tables().nodes() );
9244 inst[key].apply( inst, args );
9245 return this;
9246 } );
9247 } );
9248
9249
9250 _api_register( 'clear()', function () {
9251 return this.iterator( 'table', function ( settings ) {
9252 _fnClearTable( settings );
9253 } );
9254 } );
9255
9256
9257 _api_register( 'settings()', function () {
9258 return new _Api( this.context, this.context );
9259 } );
9260
9261
9262 _api_register( 'init()', function () {
9263 var ctx = this.context;
9264 return ctx.length ? ctx[0].oInit : null;
9265 } );
9266
9267
9268 _api_register( 'data()', function () {
9269 return this.iterator( 'table', function ( settings ) {
9270 return _pluck( settings.aoData, '_aData' );
9271 } ).flatten();
9272 } );
9273
9274
9275 _api_register( 'destroy()', function ( remove ) {
9276 remove = remove || false;
9277
9278 return this.iterator( 'table', function ( settings ) {
9279 var orig = settings.nTableWrapper.parentNode;
9280 var classes = settings.oClasses;
9281 var table = settings.nTable;
9282 var tbody = settings.nTBody;
9283 var thead = settings.nTHead;
9284 var tfoot = settings.nTFoot;
9285 var jqTable = $(table);
9286 var jqTbody = $(tbody);
9287 var jqWrapper = $(settings.nTableWrapper);
9288 var rows = $.map( settings.aoData, function (r) { return r.nTr; } );
9289 var i, ien;
9290
9291 // Flag to note that the table is currently being destroyed - no action
9292 // should be taken
9293 settings.bDestroying = true;
9294
9295 // Fire off the destroy callbacks for plug-ins etc
9296 _fnCallbackFire( settings, "aoDestroyCallback", "destroy", [settings] );
9297
9298 // If not being removed from the document, make all columns visible
9299 if ( ! remove ) {
9300 new _Api( settings ).columns().visible( true );
9301 }
9302
9303 // Blitz all `DT` namespaced events (these are internal events, the
9304 // lowercase, `dt` events are user subscribed and they are responsible
9305 // for removing them
9306 jqWrapper.off('.DT').find(':not(tbody *)').off('.DT');
9307 $(window).off('.DT-'+settings.sInstance);
9308
9309 // When scrolling we had to break the table up - restore it
9310 if ( table != thead.parentNode ) {
9311 jqTable.children('thead').detach();
9312 jqTable.append( thead );
9313 }
9314
9315 if ( tfoot && table != tfoot.parentNode ) {
9316 jqTable.children('tfoot').detach();
9317 jqTable.append( tfoot );
9318 }
9319
9320 settings.aaSorting = [];
9321 settings.aaSortingFixed = [];
9322 _fnSortingClasses( settings );
9323
9324 $( rows ).removeClass( settings.asStripeClasses.join(' ') );
9325
9326 $('th, td', thead).removeClass( classes.sSortable+' '+
9327 classes.sSortableAsc+' '+classes.sSortableDesc+' '+classes.sSortableNone
9328 );
9329
9330 // Add the TR elements back into the table in their original order
9331 jqTbody.children().detach();
9332 jqTbody.append( rows );
9333
9334 // Remove the DataTables generated nodes, events and classes
9335 var removedMethod = remove ? 'remove' : 'detach';
9336 jqTable[ removedMethod ]();
9337 jqWrapper[ removedMethod ]();
9338
9339 // If we need to reattach the table to the document
9340 if ( ! remove && orig ) {
9341 // insertBefore acts like appendChild if !arg[1]
9342 orig.insertBefore( table, settings.nTableReinsertBefore );
9343
9344 // Restore the width of the original table - was read from the style property,
9345 // so we can restore directly to that
9346 jqTable
9347 .css( 'width', settings.sDestroyWidth )
9348 .removeClass( classes.sTable );
9349
9350 // If the were originally stripe classes - then we add them back here.
9351 // Note this is not fool proof (for example if not all rows had stripe
9352 // classes - but it's a good effort without getting carried away
9353 ien = settings.asDestroyStripes.length;
9354
9355 if ( ien ) {
9356 jqTbody.children().each( function (i) {
9357 $(this).addClass( settings.asDestroyStripes[i % ien] );
9358 } );
9359 }
9360 }
9361
9362 /* Remove the settings object from the settings array */
9363 var idx = $.inArray( settings, DataTable.settings );
9364 if ( idx !== -1 ) {
9365 DataTable.settings.splice( idx, 1 );
9366 }
9367 } );
9368 } );
9369
9370
9371 // Add the `every()` method for rows, columns and cells in a compact form
9372 $.each( [ 'column', 'row', 'cell' ], function ( i, type ) {
9373 _api_register( type+'s().every()', function ( fn ) {
9374 var opts = this.selector.opts;
9375 var api = this;
9376
9377 return this.iterator( type, function ( settings, arg1, arg2, arg3, arg4 ) {
9378 // Rows and columns:
9379 // arg1 - index
9380 // arg2 - table counter
9381 // arg3 - loop counter
9382 // arg4 - undefined
9383 // Cells:
9384 // arg1 - row index
9385 // arg2 - column index
9386 // arg3 - table counter
9387 // arg4 - loop counter
9388 fn.call(
9389 api[ type ](
9390 arg1,
9391 type==='cell' ? arg2 : opts,
9392 type==='cell' ? opts : undefined
9393 ),
9394 arg1, arg2, arg3, arg4
9395 );
9396 } );
9397 } );
9398 } );
9399
9400
9401 // i18n method for extensions to be able to use the language object from the
9402 // DataTable
9403 _api_register( 'i18n()', function ( token, def, plural ) {
9404 var ctx = this.context[0];
9405 var resolved = _fnGetObjectDataFn( token )( ctx.oLanguage );
9406
9407 if ( resolved === undefined ) {
9408 resolved = def;
9409 }
9410
9411 if ( plural !== undefined && $.isPlainObject( resolved ) ) {
9412 resolved = resolved[ plural ] !== undefined ?
9413 resolved[ plural ] :
9414 resolved._;
9415 }
9416
9417 return resolved.replace( '%d', plural ); // nb: plural might be undefined,
9418 } );
9419
9420 /**
9421 * Version string for plug-ins to check compatibility. Allowed format is
9422 * `a.b.c-d` where: a:int, b:int, c:int, d:string(dev|beta|alpha). `d` is used
9423 * only for non-release builds. See http://semver.org/ for more information.
9424 * @member
9425 * @type string
9426 * @default Version number
9427 */
9428 DataTable.version = "1.10.16";
9429
9430 /**
9431 * Private data store, containing all of the settings objects that are
9432 * created for the tables on a given page.
9433 *
9434 * Note that the `DataTable.settings` object is aliased to
9435 * `jQuery.fn.dataTableExt` through which it may be accessed and
9436 * manipulated, or `jQuery.fn.dataTable.settings`.
9437 * @member
9438 * @type array
9439 * @default []
9440 * @private
9441 */
9442 DataTable.settings = [];
9443
9444 /**
9445 * Object models container, for the various models that DataTables has
9446 * available to it. These models define the objects that are used to hold
9447 * the active state and configuration of the table.
9448 * @namespace
9449 */
9450 DataTable.models = {};
9451
9452
9453
9454 /**
9455 * Template object for the way in which DataTables holds information about
9456 * search information for the global filter and individual column filters.
9457 * @namespace
9458 */
9459 DataTable.models.oSearch = {
9460 /**
9461 * Flag to indicate if the filtering should be case insensitive or not
9462 * @type boolean
9463 * @default true
9464 */
9465 "bCaseInsensitive": true,
9466
9467 /**
9468 * Applied search term
9469 * @type string
9470 * @default <i>Empty string</i>
9471 */
9472 "sSearch": "",
9473
9474 /**
9475 * Flag to indicate if the search term should be interpreted as a
9476 * regular expression (true) or not (false) and therefore and special
9477 * regex characters escaped.
9478 * @type boolean
9479 * @default false
9480 */
9481 "bRegex": false,
9482
9483 /**
9484 * Flag to indicate if DataTables is to use its smart filtering or not.
9485 * @type boolean
9486 * @default true
9487 */
9488 "bSmart": true
9489 };
9490
9491
9492
9493
9494 /**
9495 * Template object for the way in which DataTables holds information about
9496 * each individual row. This is the object format used for the settings
9497 * aoData array.
9498 * @namespace
9499 */
9500 DataTable.models.oRow = {
9501 /**
9502 * TR element for the row
9503 * @type node
9504 * @default null
9505 */
9506 "nTr": null,
9507
9508 /**
9509 * Array of TD elements for each row. This is null until the row has been
9510 * created.
9511 * @type array nodes
9512 * @default []
9513 */
9514 "anCells": null,
9515
9516 /**
9517 * Data object from the original data source for the row. This is either
9518 * an array if using the traditional form of DataTables, or an object if
9519 * using mData options. The exact type will depend on the passed in
9520 * data from the data source, or will be an array if using DOM a data
9521 * source.
9522 * @type array|object
9523 * @default []
9524 */
9525 "_aData": [],
9526
9527 /**
9528 * Sorting data cache - this array is ostensibly the same length as the
9529 * number of columns (although each index is generated only as it is
9530 * needed), and holds the data that is used for sorting each column in the
9531 * row. We do this cache generation at the start of the sort in order that
9532 * the formatting of the sort data need be done only once for each cell
9533 * per sort. This array should not be read from or written to by anything
9534 * other than the master sorting methods.
9535 * @type array
9536 * @default null
9537 * @private
9538 */
9539 "_aSortData": null,
9540
9541 /**
9542 * Per cell filtering data cache. As per the sort data cache, used to
9543 * increase the performance of the filtering in DataTables
9544 * @type array
9545 * @default null
9546 * @private
9547 */
9548 "_aFilterData": null,
9549
9550 /**
9551 * Filtering data cache. This is the same as the cell filtering cache, but
9552 * in this case a string rather than an array. This is easily computed with
9553 * a join on `_aFilterData`, but is provided as a cache so the join isn't
9554 * needed on every search (memory traded for performance)
9555 * @type array
9556 * @default null
9557 * @private
9558 */
9559 "_sFilterRow": null,
9560
9561 /**
9562 * Cache of the class name that DataTables has applied to the row, so we
9563 * can quickly look at this variable rather than needing to do a DOM check
9564 * on className for the nTr property.
9565 * @type string
9566 * @default <i>Empty string</i>
9567 * @private
9568 */
9569 "_sRowStripe": "",
9570
9571 /**
9572 * Denote if the original data source was from the DOM, or the data source
9573 * object. This is used for invalidating data, so DataTables can
9574 * automatically read data from the original source, unless uninstructed
9575 * otherwise.
9576 * @type string
9577 * @default null
9578 * @private
9579 */
9580 "src": null,
9581
9582 /**
9583 * Index in the aoData array. This saves an indexOf lookup when we have the
9584 * object, but want to know the index
9585 * @type integer
9586 * @default -1
9587 * @private
9588 */
9589 "idx": -1
9590 };
9591
9592
9593 /**
9594 * Template object for the column information object in DataTables. This object
9595 * is held in the settings aoColumns array and contains all the information that
9596 * DataTables needs about each individual column.
9597 *
9598 * Note that this object is related to {@link DataTable.defaults.column}
9599 * but this one is the internal data store for DataTables's cache of columns.
9600 * It should NOT be manipulated outside of DataTables. Any configuration should
9601 * be done through the initialisation options.
9602 * @namespace
9603 */
9604 DataTable.models.oColumn = {
9605 /**
9606 * Column index. This could be worked out on-the-fly with $.inArray, but it
9607 * is faster to just hold it as a variable
9608 * @type integer
9609 * @default null
9610 */
9611 "idx": null,
9612
9613 /**
9614 * A list of the columns that sorting should occur on when this column
9615 * is sorted. That this property is an array allows multi-column sorting
9616 * to be defined for a column (for example first name / last name columns
9617 * would benefit from this). The values are integers pointing to the
9618 * columns to be sorted on (typically it will be a single integer pointing
9619 * at itself, but that doesn't need to be the case).
9620 * @type array
9621 */
9622 "aDataSort": null,
9623
9624 /**
9625 * Define the sorting directions that are applied to the column, in sequence
9626 * as the column is repeatedly sorted upon - i.e. the first value is used
9627 * as the sorting direction when the column if first sorted (clicked on).
9628 * Sort it again (click again) and it will move on to the next index.
9629 * Repeat until loop.
9630 * @type array
9631 */
9632 "asSorting": null,
9633
9634 /**
9635 * Flag to indicate if the column is searchable, and thus should be included
9636 * in the filtering or not.
9637 * @type boolean
9638 */
9639 "bSearchable": null,
9640
9641 /**
9642 * Flag to indicate if the column is sortable or not.
9643 * @type boolean
9644 */
9645 "bSortable": null,
9646
9647 /**
9648 * Flag to indicate if the column is currently visible in the table or not
9649 * @type boolean
9650 */
9651 "bVisible": null,
9652
9653 /**
9654 * Store for manual type assignment using the `column.type` option. This
9655 * is held in store so we can manipulate the column's `sType` property.
9656 * @type string
9657 * @default null
9658 * @private
9659 */
9660 "_sManualType": null,
9661
9662 /**
9663 * Flag to indicate if HTML5 data attributes should be used as the data
9664 * source for filtering or sorting. True is either are.
9665 * @type boolean
9666 * @default false
9667 * @private
9668 */
9669 "_bAttrSrc": false,
9670
9671 /**
9672 * Developer definable function that is called whenever a cell is created (Ajax source,
9673 * etc) or processed for input (DOM source). This can be used as a compliment to mRender
9674 * allowing you to modify the DOM element (add background colour for example) when the
9675 * element is available.
9676 * @type function
9677 * @param {element} nTd The TD node that has been created
9678 * @param {*} sData The Data for the cell
9679 * @param {array|object} oData The data for the whole row
9680 * @param {int} iRow The row index for the aoData data store
9681 * @default null
9682 */
9683 "fnCreatedCell": null,
9684
9685 /**
9686 * Function to get data from a cell in a column. You should <b>never</b>
9687 * access data directly through _aData internally in DataTables - always use
9688 * the method attached to this property. It allows mData to function as
9689 * required. This function is automatically assigned by the column
9690 * initialisation method
9691 * @type function
9692 * @param {array|object} oData The data array/object for the array
9693 * (i.e. aoData[]._aData)
9694 * @param {string} sSpecific The specific data type you want to get -
9695 * 'display', 'type' 'filter' 'sort'
9696 * @returns {*} The data for the cell from the given row's data
9697 * @default null
9698 */
9699 "fnGetData": null,
9700
9701 /**
9702 * Function to set data for a cell in the column. You should <b>never</b>
9703 * set the data directly to _aData internally in DataTables - always use
9704 * this method. It allows mData to function as required. This function
9705 * is automatically assigned by the column initialisation method
9706 * @type function
9707 * @param {array|object} oData The data array/object for the array
9708 * (i.e. aoData[]._aData)
9709 * @param {*} sValue Value to set
9710 * @default null
9711 */
9712 "fnSetData": null,
9713
9714 /**
9715 * Property to read the value for the cells in the column from the data
9716 * source array / object. If null, then the default content is used, if a
9717 * function is given then the return from the function is used.
9718 * @type function|int|string|null
9719 * @default null
9720 */
9721 "mData": null,
9722
9723 /**
9724 * Partner property to mData which is used (only when defined) to get
9725 * the data - i.e. it is basically the same as mData, but without the
9726 * 'set' option, and also the data fed to it is the result from mData.
9727 * This is the rendering method to match the data method of mData.
9728 * @type function|int|string|null
9729 * @default null
9730 */
9731 "mRender": null,
9732
9733 /**
9734 * Unique header TH/TD element for this column - this is what the sorting
9735 * listener is attached to (if sorting is enabled.)
9736 * @type node
9737 * @default null
9738 */
9739 "nTh": null,
9740
9741 /**
9742 * Unique footer TH/TD element for this column (if there is one). Not used
9743 * in DataTables as such, but can be used for plug-ins to reference the
9744 * footer for each column.
9745 * @type node
9746 * @default null
9747 */
9748 "nTf": null,
9749
9750 /**
9751 * The class to apply to all TD elements in the table's TBODY for the column
9752 * @type string
9753 * @default null
9754 */
9755 "sClass": null,
9756
9757 /**
9758 * When DataTables calculates the column widths to assign to each column,
9759 * it finds the longest string in each column and then constructs a
9760 * temporary table and reads the widths from that. The problem with this
9761 * is that "mmm" is much wider then "iiii", but the latter is a longer
9762 * string - thus the calculation can go wrong (doing it properly and putting
9763 * it into an DOM object and measuring that is horribly(!) slow). Thus as
9764 * a "work around" we provide this option. It will append its value to the
9765 * text that is found to be the longest string for the column - i.e. padding.
9766 * @type string
9767 */
9768 "sContentPadding": null,
9769
9770 /**
9771 * Allows a default value to be given for a column's data, and will be used
9772 * whenever a null data source is encountered (this can be because mData
9773 * is set to null, or because the data source itself is null).
9774 * @type string
9775 * @default null
9776 */
9777 "sDefaultContent": null,
9778
9779 /**
9780 * Name for the column, allowing reference to the column by name as well as
9781 * by index (needs a lookup to work by name).
9782 * @type string
9783 */
9784 "sName": null,
9785
9786 /**
9787 * Custom sorting data type - defines which of the available plug-ins in
9788 * afnSortData the custom sorting will use - if any is defined.
9789 * @type string
9790 * @default std
9791 */
9792 "sSortDataType": 'std',
9793
9794 /**
9795 * Class to be applied to the header element when sorting on this column
9796 * @type string
9797 * @default null
9798 */
9799 "sSortingClass": null,
9800
9801 /**
9802 * Class to be applied to the header element when sorting on this column -
9803 * when jQuery UI theming is used.
9804 * @type string
9805 * @default null
9806 */
9807 "sSortingClassJUI": null,
9808
9809 /**
9810 * Title of the column - what is seen in the TH element (nTh).
9811 * @type string
9812 */
9813 "sTitle": null,
9814
9815 /**
9816 * Column sorting and filtering type
9817 * @type string
9818 * @default null
9819 */
9820 "sType": null,
9821
9822 /**
9823 * Width of the column
9824 * @type string
9825 * @default null
9826 */
9827 "sWidth": null,
9828
9829 /**
9830 * Width of the column when it was first "encountered"
9831 * @type string
9832 * @default null
9833 */
9834 "sWidthOrig": null
9835 };
9836
9837
9838 /*
9839 * Developer note: The properties of the object below are given in Hungarian
9840 * notation, that was used as the interface for DataTables prior to v1.10, however
9841 * from v1.10 onwards the primary interface is camel case. In order to avoid
9842 * breaking backwards compatibility utterly with this change, the Hungarian
9843 * version is still, internally the primary interface, but is is not documented
9844 * - hence the @name tags in each doc comment. This allows a Javascript function
9845 * to create a map from Hungarian notation to camel case (going the other direction
9846 * would require each property to be listed, which would at around 3K to the size
9847 * of DataTables, while this method is about a 0.5K hit.
9848 *
9849 * Ultimately this does pave the way for Hungarian notation to be dropped
9850 * completely, but that is a massive amount of work and will break current
9851 * installs (therefore is on-hold until v2).
9852 */
9853
9854 /**
9855 * Initialisation options that can be given to DataTables at initialisation
9856 * time.
9857 * @namespace
9858 */
9859 DataTable.defaults = {
9860 /**
9861 * An array of data to use for the table, passed in at initialisation which
9862 * will be used in preference to any data which is already in the DOM. This is
9863 * particularly useful for constructing tables purely in Javascript, for
9864 * example with a custom Ajax call.
9865 * @type array
9866 * @default null
9867 *
9868 * @dtopt Option
9869 * @name DataTable.defaults.data
9870 *
9871 * @example
9872 * // Using a 2D array data source
9873 * $(document).ready( function () {
9874 * $('#example').dataTable( {
9875 * "data": [
9876 * ['Trident', 'Internet Explorer 4.0', 'Win 95+', 4, 'X'],
9877 * ['Trident', 'Internet Explorer 5.0', 'Win 95+', 5, 'C'],
9878 * ],
9879 * "columns": [
9880 * { "title": "Engine" },
9881 * { "title": "Browser" },
9882 * { "title": "Platform" },
9883 * { "title": "Version" },
9884 * { "title": "Grade" }
9885 * ]
9886 * } );
9887 * } );
9888 *
9889 * @example
9890 * // Using an array of objects as a data source (`data`)
9891 * $(document).ready( function () {
9892 * $('#example').dataTable( {
9893 * "data": [
9894 * {
9895 * "engine": "Trident",
9896 * "browser": "Internet Explorer 4.0",
9897 * "platform": "Win 95+",
9898 * "version": 4,
9899 * "grade": "X"
9900 * },
9901 * {
9902 * "engine": "Trident",
9903 * "browser": "Internet Explorer 5.0",
9904 * "platform": "Win 95+",
9905 * "version": 5,
9906 * "grade": "C"
9907 * }
9908 * ],
9909 * "columns": [
9910 * { "title": "Engine", "data": "engine" },
9911 * { "title": "Browser", "data": "browser" },
9912 * { "title": "Platform", "data": "platform" },
9913 * { "title": "Version", "data": "version" },
9914 * { "title": "Grade", "data": "grade" }
9915 * ]
9916 * } );
9917 * } );
9918 */
9919 "aaData": null,
9920
9921
9922 /**
9923 * If ordering is enabled, then DataTables will perform a first pass sort on
9924 * initialisation. You can define which column(s) the sort is performed
9925 * upon, and the sorting direction, with this variable. The `sorting` array
9926 * should contain an array for each column to be sorted initially containing
9927 * the column's index and a direction string ('asc' or 'desc').
9928 * @type array
9929 * @default [[0,'asc']]
9930 *
9931 * @dtopt Option
9932 * @name DataTable.defaults.order
9933 *
9934 * @example
9935 * // Sort by 3rd column first, and then 4th column
9936 * $(document).ready( function() {
9937 * $('#example').dataTable( {
9938 * "order": [[2,'asc'], [3,'desc']]
9939 * } );
9940 * } );
9941 *
9942 * // No initial sorting
9943 * $(document).ready( function() {
9944 * $('#example').dataTable( {
9945 * "order": []
9946 * } );
9947 * } );
9948 */
9949 "aaSorting": [[0,'asc']],
9950
9951
9952 /**
9953 * This parameter is basically identical to the `sorting` parameter, but
9954 * cannot be overridden by user interaction with the table. What this means
9955 * is that you could have a column (visible or hidden) which the sorting
9956 * will always be forced on first - any sorting after that (from the user)
9957 * will then be performed as required. This can be useful for grouping rows
9958 * together.
9959 * @type array
9960 * @default null
9961 *
9962 * @dtopt Option
9963 * @name DataTable.defaults.orderFixed
9964 *
9965 * @example
9966 * $(document).ready( function() {
9967 * $('#example').dataTable( {
9968 * "orderFixed": [[0,'asc']]
9969 * } );
9970 * } )
9971 */
9972 "aaSortingFixed": [],
9973
9974
9975 /**
9976 * DataTables can be instructed to load data to display in the table from a
9977 * Ajax source. This option defines how that Ajax call is made and where to.
9978 *
9979 * The `ajax` property has three different modes of operation, depending on
9980 * how it is defined. These are:
9981 *
9982 * * `string` - Set the URL from where the data should be loaded from.
9983 * * `object` - Define properties for `jQuery.ajax`.
9984 * * `function` - Custom data get function
9985 *
9986 * `string`
9987 * --------
9988 *
9989 * As a string, the `ajax` property simply defines the URL from which
9990 * DataTables will load data.
9991 *
9992 * `object`
9993 * --------
9994 *
9995 * As an object, the parameters in the object are passed to
9996 * [jQuery.ajax](http://api.jquery.com/jQuery.ajax/) allowing fine control
9997 * of the Ajax request. DataTables has a number of default parameters which
9998 * you can override using this option. Please refer to the jQuery
9999 * documentation for a full description of the options available, although
10000 * the following parameters provide additional options in DataTables or
10001 * require special consideration:
10002 *
10003 * * `data` - As with jQuery, `data` can be provided as an object, but it
10004 * can also be used as a function to manipulate the data DataTables sends
10005 * to the server. The function takes a single parameter, an object of
10006 * parameters with the values that DataTables has readied for sending. An
10007 * object may be returned which will be merged into the DataTables
10008 * defaults, or you can add the items to the object that was passed in and
10009 * not return anything from the function. This supersedes `fnServerParams`
10010 * from DataTables 1.9-.
10011 *
10012 * * `dataSrc` - By default DataTables will look for the property `data` (or
10013 * `aaData` for compatibility with DataTables 1.9-) when obtaining data
10014 * from an Ajax source or for server-side processing - this parameter
10015 * allows that property to be changed. You can use Javascript dotted
10016 * object notation to get a data source for multiple levels of nesting, or
10017 * it my be used as a function. As a function it takes a single parameter,
10018 * the JSON returned from the server, which can be manipulated as
10019 * required, with the returned value being that used by DataTables as the
10020 * data source for the table. This supersedes `sAjaxDataProp` from
10021 * DataTables 1.9-.
10022 *
10023 * * `success` - Should not be overridden it is used internally in
10024 * DataTables. To manipulate / transform the data returned by the server
10025 * use `ajax.dataSrc`, or use `ajax` as a function (see below).
10026 *
10027 * `function`
10028 * ----------
10029 *
10030 * As a function, making the Ajax call is left up to yourself allowing
10031 * complete control of the Ajax request. Indeed, if desired, a method other
10032 * than Ajax could be used to obtain the required data, such as Web storage
10033 * or an AIR database.
10034 *
10035 * The function is given four parameters and no return is required. The
10036 * parameters are:
10037 *
10038 * 1. _object_ - Data to send to the server
10039 * 2. _function_ - Callback function that must be executed when the required
10040 * data has been obtained. That data should be passed into the callback
10041 * as the only parameter
10042 * 3. _object_ - DataTables settings object for the table
10043 *
10044 * Note that this supersedes `fnServerData` from DataTables 1.9-.
10045 *
10046 * @type string|object|function
10047 * @default null
10048 *
10049 * @dtopt Option
10050 * @name DataTable.defaults.ajax
10051 * @since 1.10.0
10052 *
10053 * @example
10054 * // Get JSON data from a file via Ajax.
10055 * // Note DataTables expects data in the form `{ data: [ ...data... ] }` by default).
10056 * $('#example').dataTable( {
10057 * "ajax": "data.json"
10058 * } );
10059 *
10060 * @example
10061 * // Get JSON data from a file via Ajax, using `dataSrc` to change
10062 * // `data` to `tableData` (i.e. `{ tableData: [ ...data... ] }`)
10063 * $('#example').dataTable( {
10064 * "ajax": {
10065 * "url": "data.json",
10066 * "dataSrc": "tableData"
10067 * }
10068 * } );
10069 *
10070 * @example
10071 * // Get JSON data from a file via Ajax, using `dataSrc` to read data
10072 * // from a plain array rather than an array in an object
10073 * $('#example').dataTable( {
10074 * "ajax": {
10075 * "url": "data.json",
10076 * "dataSrc": ""
10077 * }
10078 * } );
10079 *
10080 * @example
10081 * // Manipulate the data returned from the server - add a link to data
10082 * // (note this can, should, be done using `render` for the column - this
10083 * // is just a simple example of how the data can be manipulated).
10084 * $('#example').dataTable( {
10085 * "ajax": {
10086 * "url": "data.json",
10087 * "dataSrc": function ( json ) {
10088 * for ( var i=0, ien=json.length ; i<ien ; i++ ) {
10089 * json[i][0] = '<a href="/message/'+json[i][0]+'>View message</a>';
10090 * }
10091 * return json;
10092 * }
10093 * }
10094 * } );
10095 *
10096 * @example
10097 * // Add data to the request
10098 * $('#example').dataTable( {
10099 * "ajax": {
10100 * "url": "data.json",
10101 * "data": function ( d ) {
10102 * return {
10103 * "extra_search": $('#extra').val()
10104 * };
10105 * }
10106 * }
10107 * } );
10108 *
10109 * @example
10110 * // Send request as POST
10111 * $('#example').dataTable( {
10112 * "ajax": {
10113 * "url": "data.json",
10114 * "type": "POST"
10115 * }
10116 * } );
10117 *
10118 * @example
10119 * // Get the data from localStorage (could interface with a form for
10120 * // adding, editing and removing rows).
10121 * $('#example').dataTable( {
10122 * "ajax": function (data, callback, settings) {
10123 * callback(
10124 * JSON.parse( localStorage.getItem('dataTablesData') )
10125 * );
10126 * }
10127 * } );
10128 */
10129 "ajax": null,
10130
10131
10132 /**
10133 * This parameter allows you to readily specify the entries in the length drop
10134 * down menu that DataTables shows when pagination is enabled. It can be
10135 * either a 1D array of options which will be used for both the displayed
10136 * option and the value, or a 2D array which will use the array in the first
10137 * position as the value, and the array in the second position as the
10138 * displayed options (useful for language strings such as 'All').
10139 *
10140 * Note that the `pageLength` property will be automatically set to the
10141 * first value given in this array, unless `pageLength` is also provided.
10142 * @type array
10143 * @default [ 10, 25, 50, 100 ]
10144 *
10145 * @dtopt Option
10146 * @name DataTable.defaults.lengthMenu
10147 *
10148 * @example
10149 * $(document).ready( function() {
10150 * $('#example').dataTable( {
10151 * "lengthMenu": [[10, 25, 50, -1], [10, 25, 50, "All"]]
10152 * } );
10153 * } );
10154 */
10155 "aLengthMenu": [ 10, 25, 50, 100 ],
10156
10157
10158 /**
10159 * The `columns` option in the initialisation parameter allows you to define
10160 * details about the way individual columns behave. For a full list of
10161 * column options that can be set, please see
10162 * {@link DataTable.defaults.column}. Note that if you use `columns` to
10163 * define your columns, you must have an entry in the array for every single
10164 * column that you have in your table (these can be null if you don't which
10165 * to specify any options).
10166 * @member
10167 *
10168 * @name DataTable.defaults.column
10169 */
10170 "aoColumns": null,
10171
10172 /**
10173 * Very similar to `columns`, `columnDefs` allows you to target a specific
10174 * column, multiple columns, or all columns, using the `targets` property of
10175 * each object in the array. This allows great flexibility when creating
10176 * tables, as the `columnDefs` arrays can be of any length, targeting the
10177 * columns you specifically want. `columnDefs` may use any of the column
10178 * options available: {@link DataTable.defaults.column}, but it _must_
10179 * have `targets` defined in each object in the array. Values in the `targets`
10180 * array may be:
10181 * <ul>
10182 * <li>a string - class name will be matched on the TH for the column</li>
10183 * <li>0 or a positive integer - column index counting from the left</li>
10184 * <li>a negative integer - column index counting from the right</li>
10185 * <li>the string "_all" - all columns (i.e. assign a default)</li>
10186 * </ul>
10187 * @member
10188 *
10189 * @name DataTable.defaults.columnDefs
10190 */
10191 "aoColumnDefs": null,
10192
10193
10194 /**
10195 * Basically the same as `search`, this parameter defines the individual column
10196 * filtering state at initialisation time. The array must be of the same size
10197 * as the number of columns, and each element be an object with the parameters
10198 * `search` and `escapeRegex` (the latter is optional). 'null' is also
10199 * accepted and the default will be used.
10200 * @type array
10201 * @default []
10202 *
10203 * @dtopt Option
10204 * @name DataTable.defaults.searchCols
10205 *
10206 * @example
10207 * $(document).ready( function() {
10208 * $('#example').dataTable( {
10209 * "searchCols": [
10210 * null,
10211 * { "search": "My filter" },
10212 * null,
10213 * { "search": "^[0-9]", "escapeRegex": false }
10214 * ]
10215 * } );
10216 * } )
10217 */
10218 "aoSearchCols": [],
10219
10220
10221 /**
10222 * An array of CSS classes that should be applied to displayed rows. This
10223 * array may be of any length, and DataTables will apply each class
10224 * sequentially, looping when required.
10225 * @type array
10226 * @default null <i>Will take the values determined by the `oClasses.stripe*`
10227 * options</i>
10228 *
10229 * @dtopt Option
10230 * @name DataTable.defaults.stripeClasses
10231 *
10232 * @example
10233 * $(document).ready( function() {
10234 * $('#example').dataTable( {
10235 * "stripeClasses": [ 'strip1', 'strip2', 'strip3' ]
10236 * } );
10237 * } )
10238 */
10239 "asStripeClasses": null,
10240
10241
10242 /**
10243 * Enable or disable automatic column width calculation. This can be disabled
10244 * as an optimisation (it takes some time to calculate the widths) if the
10245 * tables widths are passed in using `columns`.
10246 * @type boolean
10247 * @default true
10248 *
10249 * @dtopt Features
10250 * @name DataTable.defaults.autoWidth
10251 *
10252 * @example
10253 * $(document).ready( function () {
10254 * $('#example').dataTable( {
10255 * "autoWidth": false
10256 * } );
10257 * } );
10258 */
10259 "bAutoWidth": true,
10260
10261
10262 /**
10263 * Deferred rendering can provide DataTables with a huge speed boost when you
10264 * are using an Ajax or JS data source for the table. This option, when set to
10265 * true, will cause DataTables to defer the creation of the table elements for
10266 * each row until they are needed for a draw - saving a significant amount of
10267 * time.
10268 * @type boolean
10269 * @default false
10270 *
10271 * @dtopt Features
10272 * @name DataTable.defaults.deferRender
10273 *
10274 * @example
10275 * $(document).ready( function() {
10276 * $('#example').dataTable( {
10277 * "ajax": "sources/arrays.txt",
10278 * "deferRender": true
10279 * } );
10280 * } );
10281 */
10282 "bDeferRender": false,
10283
10284
10285 /**
10286 * Replace a DataTable which matches the given selector and replace it with
10287 * one which has the properties of the new initialisation object passed. If no
10288 * table matches the selector, then the new DataTable will be constructed as
10289 * per normal.
10290 * @type boolean
10291 * @default false
10292 *
10293 * @dtopt Options
10294 * @name DataTable.defaults.destroy
10295 *
10296 * @example
10297 * $(document).ready( function() {
10298 * $('#example').dataTable( {
10299 * "srollY": "200px",
10300 * "paginate": false
10301 * } );
10302 *
10303 * // Some time later....
10304 * $('#example').dataTable( {
10305 * "filter": false,
10306 * "destroy": true
10307 * } );
10308 * } );
10309 */
10310 "bDestroy": false,
10311
10312
10313 /**
10314 * Enable or disable filtering of data. Filtering in DataTables is "smart" in
10315 * that it allows the end user to input multiple words (space separated) and
10316 * will match a row containing those words, even if not in the order that was
10317 * specified (this allow matching across multiple columns). Note that if you
10318 * wish to use filtering in DataTables this must remain 'true' - to remove the
10319 * default filtering input box and retain filtering abilities, please use
10320 * {@link DataTable.defaults.dom}.
10321 * @type boolean
10322 * @default true
10323 *
10324 * @dtopt Features
10325 * @name DataTable.defaults.searching
10326 *
10327 * @example
10328 * $(document).ready( function () {
10329 * $('#example').dataTable( {
10330 * "searching": false
10331 * } );
10332 * } );
10333 */
10334 "bFilter": true,
10335
10336
10337 /**
10338 * Enable or disable the table information display. This shows information
10339 * about the data that is currently visible on the page, including information
10340 * about filtered data if that action is being performed.
10341 * @type boolean
10342 * @default true
10343 *
10344 * @dtopt Features
10345 * @name DataTable.defaults.info
10346 *
10347 * @example
10348 * $(document).ready( function () {
10349 * $('#example').dataTable( {
10350 * "info": false
10351 * } );
10352 * } );
10353 */
10354 "bInfo": true,
10355
10356
10357 /**
10358 * Allows the end user to select the size of a formatted page from a select
10359 * menu (sizes are 10, 25, 50 and 100). Requires pagination (`paginate`).
10360 * @type boolean
10361 * @default true
10362 *
10363 * @dtopt Features
10364 * @name DataTable.defaults.lengthChange
10365 *
10366 * @example
10367 * $(document).ready( function () {
10368 * $('#example').dataTable( {
10369 * "lengthChange": false
10370 * } );
10371 * } );
10372 */
10373 "bLengthChange": true,
10374
10375
10376 /**
10377 * Enable or disable pagination.
10378 * @type boolean
10379 * @default true
10380 *
10381 * @dtopt Features
10382 * @name DataTable.defaults.paging
10383 *
10384 * @example
10385 * $(document).ready( function () {
10386 * $('#example').dataTable( {
10387 * "paging": false
10388 * } );
10389 * } );
10390 */
10391 "bPaginate": true,
10392
10393
10394 /**
10395 * Enable or disable the display of a 'processing' indicator when the table is
10396 * being processed (e.g. a sort). This is particularly useful for tables with
10397 * large amounts of data where it can take a noticeable amount of time to sort
10398 * the entries.
10399 * @type boolean
10400 * @default false
10401 *
10402 * @dtopt Features
10403 * @name DataTable.defaults.processing
10404 *
10405 * @example
10406 * $(document).ready( function () {
10407 * $('#example').dataTable( {
10408 * "processing": true
10409 * } );
10410 * } );
10411 */
10412 "bProcessing": false,
10413
10414
10415 /**
10416 * Retrieve the DataTables object for the given selector. Note that if the
10417 * table has already been initialised, this parameter will cause DataTables
10418 * to simply return the object that has already been set up - it will not take
10419 * account of any changes you might have made to the initialisation object
10420 * passed to DataTables (setting this parameter to true is an acknowledgement
10421 * that you understand this). `destroy` can be used to reinitialise a table if
10422 * you need.
10423 * @type boolean
10424 * @default false
10425 *
10426 * @dtopt Options
10427 * @name DataTable.defaults.retrieve
10428 *
10429 * @example
10430 * $(document).ready( function() {
10431 * initTable();
10432 * tableActions();
10433 * } );
10434 *
10435 * function initTable ()
10436 * {
10437 * return $('#example').dataTable( {
10438 * "scrollY": "200px",
10439 * "paginate": false,
10440 * "retrieve": true
10441 * } );
10442 * }
10443 *
10444 * function tableActions ()
10445 * {
10446 * var table = initTable();
10447 * // perform API operations with oTable
10448 * }
10449 */
10450 "bRetrieve": false,
10451
10452
10453 /**
10454 * When vertical (y) scrolling is enabled, DataTables will force the height of
10455 * the table's viewport to the given height at all times (useful for layout).
10456 * However, this can look odd when filtering data down to a small data set,
10457 * and the footer is left "floating" further down. This parameter (when
10458 * enabled) will cause DataTables to collapse the table's viewport down when
10459 * the result set will fit within the given Y height.
10460 * @type boolean
10461 * @default false
10462 *
10463 * @dtopt Options
10464 * @name DataTable.defaults.scrollCollapse
10465 *
10466 * @example
10467 * $(document).ready( function() {
10468 * $('#example').dataTable( {
10469 * "scrollY": "200",
10470 * "scrollCollapse": true
10471 * } );
10472 * } );
10473 */
10474 "bScrollCollapse": false,
10475
10476
10477 /**
10478 * Configure DataTables to use server-side processing. Note that the
10479 * `ajax` parameter must also be given in order to give DataTables a
10480 * source to obtain the required data for each draw.
10481 * @type boolean
10482 * @default false
10483 *
10484 * @dtopt Features
10485 * @dtopt Server-side
10486 * @name DataTable.defaults.serverSide
10487 *
10488 * @example
10489 * $(document).ready( function () {
10490 * $('#example').dataTable( {
10491 * "serverSide": true,
10492 * "ajax": "xhr.php"
10493 * } );
10494 * } );
10495 */
10496 "bServerSide": false,
10497
10498
10499 /**
10500 * Enable or disable sorting of columns. Sorting of individual columns can be
10501 * disabled by the `sortable` option for each column.
10502 * @type boolean
10503 * @default true
10504 *
10505 * @dtopt Features
10506 * @name DataTable.defaults.ordering
10507 *
10508 * @example
10509 * $(document).ready( function () {
10510 * $('#example').dataTable( {
10511 * "ordering": false
10512 * } );
10513 * } );
10514 */
10515 "bSort": true,
10516
10517
10518 /**
10519 * Enable or display DataTables' ability to sort multiple columns at the
10520 * same time (activated by shift-click by the user).
10521 * @type boolean
10522 * @default true
10523 *
10524 * @dtopt Options
10525 * @name DataTable.defaults.orderMulti
10526 *
10527 * @example
10528 * // Disable multiple column sorting ability
10529 * $(document).ready( function () {
10530 * $('#example').dataTable( {
10531 * "orderMulti": false
10532 * } );
10533 * } );
10534 */
10535 "bSortMulti": true,
10536
10537
10538 /**
10539 * Allows control over whether DataTables should use the top (true) unique
10540 * cell that is found for a single column, or the bottom (false - default).
10541 * This is useful when using complex headers.
10542 * @type boolean
10543 * @default false
10544 *
10545 * @dtopt Options
10546 * @name DataTable.defaults.orderCellsTop
10547 *
10548 * @example
10549 * $(document).ready( function() {
10550 * $('#example').dataTable( {
10551 * "orderCellsTop": true
10552 * } );
10553 * } );
10554 */
10555 "bSortCellsTop": false,
10556
10557
10558 /**
10559 * Enable or disable the addition of the classes `sorting\_1`, `sorting\_2` and
10560 * `sorting\_3` to the columns which are currently being sorted on. This is
10561 * presented as a feature switch as it can increase processing time (while
10562 * classes are removed and added) so for large data sets you might want to
10563 * turn this off.
10564 * @type boolean
10565 * @default true
10566 *
10567 * @dtopt Features
10568 * @name DataTable.defaults.orderClasses
10569 *
10570 * @example
10571 * $(document).ready( function () {
10572 * $('#example').dataTable( {
10573 * "orderClasses": false
10574 * } );
10575 * } );
10576 */
10577 "bSortClasses": true,
10578
10579
10580 /**
10581 * Enable or disable state saving. When enabled HTML5 `localStorage` will be
10582 * used to save table display information such as pagination information,
10583 * display length, filtering and sorting. As such when the end user reloads
10584 * the page the display display will match what thy had previously set up.
10585 *
10586 * Due to the use of `localStorage` the default state saving is not supported
10587 * in IE6 or 7. If state saving is required in those browsers, use
10588 * `stateSaveCallback` to provide a storage solution such as cookies.
10589 * @type boolean
10590 * @default false
10591 *
10592 * @dtopt Features
10593 * @name DataTable.defaults.stateSave
10594 *
10595 * @example
10596 * $(document).ready( function () {
10597 * $('#example').dataTable( {
10598 * "stateSave": true
10599 * } );
10600 * } );
10601 */
10602 "bStateSave": false,
10603
10604
10605 /**
10606 * This function is called when a TR element is created (and all TD child
10607 * elements have been inserted), or registered if using a DOM source, allowing
10608 * manipulation of the TR element (adding classes etc).
10609 * @type function
10610 * @param {node} row "TR" element for the current row
10611 * @param {array} data Raw data array for this row
10612 * @param {int} dataIndex The index of this row in the internal aoData array
10613 *
10614 * @dtopt Callbacks
10615 * @name DataTable.defaults.createdRow
10616 *
10617 * @example
10618 * $(document).ready( function() {
10619 * $('#example').dataTable( {
10620 * "createdRow": function( row, data, dataIndex ) {
10621 * // Bold the grade for all 'A' grade browsers
10622 * if ( data[4] == "A" )
10623 * {
10624 * $('td:eq(4)', row).html( '<b>A</b>' );
10625 * }
10626 * }
10627 * } );
10628 * } );
10629 */
10630 "fnCreatedRow": null,
10631
10632
10633 /**
10634 * This function is called on every 'draw' event, and allows you to
10635 * dynamically modify any aspect you want about the created DOM.
10636 * @type function
10637 * @param {object} settings DataTables settings object
10638 *
10639 * @dtopt Callbacks
10640 * @name DataTable.defaults.drawCallback
10641 *
10642 * @example
10643 * $(document).ready( function() {
10644 * $('#example').dataTable( {
10645 * "drawCallback": function( settings ) {
10646 * alert( 'DataTables has redrawn the table' );
10647 * }
10648 * } );
10649 * } );
10650 */
10651 "fnDrawCallback": null,
10652
10653
10654 /**
10655 * Identical to fnHeaderCallback() but for the table footer this function
10656 * allows you to modify the table footer on every 'draw' event.
10657 * @type function
10658 * @param {node} foot "TR" element for the footer
10659 * @param {array} data Full table data (as derived from the original HTML)
10660 * @param {int} start Index for the current display starting point in the
10661 * display array
10662 * @param {int} end Index for the current display ending point in the
10663 * display array
10664 * @param {array int} display Index array to translate the visual position
10665 * to the full data array
10666 *
10667 * @dtopt Callbacks
10668 * @name DataTable.defaults.footerCallback
10669 *
10670 * @example
10671 * $(document).ready( function() {
10672 * $('#example').dataTable( {
10673 * "footerCallback": function( tfoot, data, start, end, display ) {
10674 * tfoot.getElementsByTagName('th')[0].innerHTML = "Starting index is "+start;
10675 * }
10676 * } );
10677 * } )
10678 */
10679 "fnFooterCallback": null,
10680
10681
10682 /**
10683 * When rendering large numbers in the information element for the table
10684 * (i.e. "Showing 1 to 10 of 57 entries") DataTables will render large numbers
10685 * to have a comma separator for the 'thousands' units (e.g. 1 million is
10686 * rendered as "1,000,000") to help readability for the end user. This
10687 * function will override the default method DataTables uses.
10688 * @type function
10689 * @member
10690 * @param {int} toFormat number to be formatted
10691 * @returns {string} formatted string for DataTables to show the number
10692 *
10693 * @dtopt Callbacks
10694 * @name DataTable.defaults.formatNumber
10695 *
10696 * @example
10697 * // Format a number using a single quote for the separator (note that
10698 * // this can also be done with the language.thousands option)
10699 * $(document).ready( function() {
10700 * $('#example').dataTable( {
10701 * "formatNumber": function ( toFormat ) {
10702 * return toFormat.toString().replace(
10703 * /\B(?=(\d{3})+(?!\d))/g, "'"
10704 * );
10705 * };
10706 * } );
10707 * } );
10708 */
10709 "fnFormatNumber": function ( toFormat ) {
10710 return toFormat.toString().replace(
10711 /\B(?=(\d{3})+(?!\d))/g,
10712 this.oLanguage.sThousands
10713 );
10714 },
10715
10716
10717 /**
10718 * This function is called on every 'draw' event, and allows you to
10719 * dynamically modify the header row. This can be used to calculate and
10720 * display useful information about the table.
10721 * @type function
10722 * @param {node} head "TR" element for the header
10723 * @param {array} data Full table data (as derived from the original HTML)
10724 * @param {int} start Index for the current display starting point in the
10725 * display array
10726 * @param {int} end Index for the current display ending point in the
10727 * display array
10728 * @param {array int} display Index array to translate the visual position
10729 * to the full data array
10730 *
10731 * @dtopt Callbacks
10732 * @name DataTable.defaults.headerCallback
10733 *
10734 * @example
10735 * $(document).ready( function() {
10736 * $('#example').dataTable( {
10737 * "fheaderCallback": function( head, data, start, end, display ) {
10738 * head.getElementsByTagName('th')[0].innerHTML = "Displaying "+(end-start)+" records";
10739 * }
10740 * } );
10741 * } )
10742 */
10743 "fnHeaderCallback": null,
10744
10745
10746 /**
10747 * The information element can be used to convey information about the current
10748 * state of the table. Although the internationalisation options presented by
10749 * DataTables are quite capable of dealing with most customisations, there may
10750 * be times where you wish to customise the string further. This callback
10751 * allows you to do exactly that.
10752 * @type function
10753 * @param {object} oSettings DataTables settings object
10754 * @param {int} start Starting position in data for the draw
10755 * @param {int} end End position in data for the draw
10756 * @param {int} max Total number of rows in the table (regardless of
10757 * filtering)
10758 * @param {int} total Total number of rows in the data set, after filtering
10759 * @param {string} pre The string that DataTables has formatted using it's
10760 * own rules
10761 * @returns {string} The string to be displayed in the information element.
10762 *
10763 * @dtopt Callbacks
10764 * @name DataTable.defaults.infoCallback
10765 *
10766 * @example
10767 * $('#example').dataTable( {
10768 * "infoCallback": function( settings, start, end, max, total, pre ) {
10769 * return start +" to "+ end;
10770 * }
10771 * } );
10772 */
10773 "fnInfoCallback": null,
10774
10775
10776 /**
10777 * Called when the table has been initialised. Normally DataTables will
10778 * initialise sequentially and there will be no need for this function,
10779 * however, this does not hold true when using external language information
10780 * since that is obtained using an async XHR call.
10781 * @type function
10782 * @param {object} settings DataTables settings object
10783 * @param {object} json The JSON object request from the server - only
10784 * present if client-side Ajax sourced data is used
10785 *
10786 * @dtopt Callbacks
10787 * @name DataTable.defaults.initComplete
10788 *
10789 * @example
10790 * $(document).ready( function() {
10791 * $('#example').dataTable( {
10792 * "initComplete": function(settings, json) {
10793 * alert( 'DataTables has finished its initialisation.' );
10794 * }
10795 * } );
10796 * } )
10797 */
10798 "fnInitComplete": null,
10799
10800
10801 /**
10802 * Called at the very start of each table draw and can be used to cancel the
10803 * draw by returning false, any other return (including undefined) results in
10804 * the full draw occurring).
10805 * @type function
10806 * @param {object} settings DataTables settings object
10807 * @returns {boolean} False will cancel the draw, anything else (including no
10808 * return) will allow it to complete.
10809 *
10810 * @dtopt Callbacks
10811 * @name DataTable.defaults.preDrawCallback
10812 *
10813 * @example
10814 * $(document).ready( function() {
10815 * $('#example').dataTable( {
10816 * "preDrawCallback": function( settings ) {
10817 * if ( $('#test').val() == 1 ) {
10818 * return false;
10819 * }
10820 * }
10821 * } );
10822 * } );
10823 */
10824 "fnPreDrawCallback": null,
10825
10826
10827 /**
10828 * This function allows you to 'post process' each row after it have been
10829 * generated for each table draw, but before it is rendered on screen. This
10830 * function might be used for setting the row class name etc.
10831 * @type function
10832 * @param {node} row "TR" element for the current row
10833 * @param {array} data Raw data array for this row
10834 * @param {int} displayIndex The display index for the current table draw
10835 * @param {int} displayIndexFull The index of the data in the full list of
10836 * rows (after filtering)
10837 *
10838 * @dtopt Callbacks
10839 * @name DataTable.defaults.rowCallback
10840 *
10841 * @example
10842 * $(document).ready( function() {
10843 * $('#example').dataTable( {
10844 * "rowCallback": function( row, data, displayIndex, displayIndexFull ) {
10845 * // Bold the grade for all 'A' grade browsers
10846 * if ( data[4] == "A" ) {
10847 * $('td:eq(4)', row).html( '<b>A</b>' );
10848 * }
10849 * }
10850 * } );
10851 * } );
10852 */
10853 "fnRowCallback": null,
10854
10855
10856 /**
10857 * __Deprecated__ The functionality provided by this parameter has now been
10858 * superseded by that provided through `ajax`, which should be used instead.
10859 *
10860 * This parameter allows you to override the default function which obtains
10861 * the data from the server so something more suitable for your application.
10862 * For example you could use POST data, or pull information from a Gears or
10863 * AIR database.
10864 * @type function
10865 * @member
10866 * @param {string} source HTTP source to obtain the data from (`ajax`)
10867 * @param {array} data A key/value pair object containing the data to send
10868 * to the server
10869 * @param {function} callback to be called on completion of the data get
10870 * process that will draw the data on the page.
10871 * @param {object} settings DataTables settings object
10872 *
10873 * @dtopt Callbacks
10874 * @dtopt Server-side
10875 * @name DataTable.defaults.serverData
10876 *
10877 * @deprecated 1.10. Please use `ajax` for this functionality now.
10878 */
10879 "fnServerData": null,
10880
10881
10882 /**
10883 * __Deprecated__ The functionality provided by this parameter has now been
10884 * superseded by that provided through `ajax`, which should be used instead.
10885 *
10886 * It is often useful to send extra data to the server when making an Ajax
10887 * request - for example custom filtering information, and this callback
10888 * function makes it trivial to send extra information to the server. The
10889 * passed in parameter is the data set that has been constructed by
10890 * DataTables, and you can add to this or modify it as you require.
10891 * @type function
10892 * @param {array} data Data array (array of objects which are name/value
10893 * pairs) that has been constructed by DataTables and will be sent to the
10894 * server. In the case of Ajax sourced data with server-side processing
10895 * this will be an empty array, for server-side processing there will be a
10896 * significant number of parameters!
10897 * @returns {undefined} Ensure that you modify the data array passed in,
10898 * as this is passed by reference.
10899 *
10900 * @dtopt Callbacks
10901 * @dtopt Server-side
10902 * @name DataTable.defaults.serverParams
10903 *
10904 * @deprecated 1.10. Please use `ajax` for this functionality now.
10905 */
10906 "fnServerParams": null,
10907
10908
10909 /**
10910 * Load the table state. With this function you can define from where, and how, the
10911 * state of a table is loaded. By default DataTables will load from `localStorage`
10912 * but you might wish to use a server-side database or cookies.
10913 * @type function
10914 * @member
10915 * @param {object} settings DataTables settings object
10916 * @param {object} callback Callback that can be executed when done. It
10917 * should be passed the loaded state object.
10918 * @return {object} The DataTables state object to be loaded
10919 *
10920 * @dtopt Callbacks
10921 * @name DataTable.defaults.stateLoadCallback
10922 *
10923 * @example
10924 * $(document).ready( function() {
10925 * $('#example').dataTable( {
10926 * "stateSave": true,
10927 * "stateLoadCallback": function (settings, callback) {
10928 * $.ajax( {
10929 * "url": "/state_load",
10930 * "dataType": "json",
10931 * "success": function (json) {
10932 * callback( json );
10933 * }
10934 * } );
10935 * }
10936 * } );
10937 * } );
10938 */
10939 "fnStateLoadCallback": function ( settings ) {
10940 try {
10941 return JSON.parse(
10942 (settings.iStateDuration === -1 ? sessionStorage : localStorage).getItem(
10943 'DataTables_'+settings.sInstance+'_'+location.pathname
10944 )
10945 );
10946 } catch (e) {}
10947 },
10948
10949
10950 /**
10951 * Callback which allows modification of the saved state prior to loading that state.
10952 * This callback is called when the table is loading state from the stored data, but
10953 * prior to the settings object being modified by the saved state. Note that for
10954 * plug-in authors, you should use the `stateLoadParams` event to load parameters for
10955 * a plug-in.
10956 * @type function
10957 * @param {object} settings DataTables settings object
10958 * @param {object} data The state object that is to be loaded
10959 *
10960 * @dtopt Callbacks
10961 * @name DataTable.defaults.stateLoadParams
10962 *
10963 * @example
10964 * // Remove a saved filter, so filtering is never loaded
10965 * $(document).ready( function() {
10966 * $('#example').dataTable( {
10967 * "stateSave": true,
10968 * "stateLoadParams": function (settings, data) {
10969 * data.oSearch.sSearch = "";
10970 * }
10971 * } );
10972 * } );
10973 *
10974 * @example
10975 * // Disallow state loading by returning false
10976 * $(document).ready( function() {
10977 * $('#example').dataTable( {
10978 * "stateSave": true,
10979 * "stateLoadParams": function (settings, data) {
10980 * return false;
10981 * }
10982 * } );
10983 * } );
10984 */
10985 "fnStateLoadParams": null,
10986
10987
10988 /**
10989 * Callback that is called when the state has been loaded from the state saving method
10990 * and the DataTables settings object has been modified as a result of the loaded state.
10991 * @type function
10992 * @param {object} settings DataTables settings object
10993 * @param {object} data The state object that was loaded
10994 *
10995 * @dtopt Callbacks
10996 * @name DataTable.defaults.stateLoaded
10997 *
10998 * @example
10999 * // Show an alert with the filtering value that was saved
11000 * $(document).ready( function() {
11001 * $('#example').dataTable( {
11002 * "stateSave": true,
11003 * "stateLoaded": function (settings, data) {
11004 * alert( 'Saved filter was: '+data.oSearch.sSearch );
11005 * }
11006 * } );
11007 * } );
11008 */
11009 "fnStateLoaded": null,
11010
11011
11012 /**
11013 * Save the table state. This function allows you to define where and how the state
11014 * information for the table is stored By default DataTables will use `localStorage`
11015 * but you might wish to use a server-side database or cookies.
11016 * @type function
11017 * @member
11018 * @param {object} settings DataTables settings object
11019 * @param {object} data The state object to be saved
11020 *
11021 * @dtopt Callbacks
11022 * @name DataTable.defaults.stateSaveCallback
11023 *
11024 * @example
11025 * $(document).ready( function() {
11026 * $('#example').dataTable( {
11027 * "stateSave": true,
11028 * "stateSaveCallback": function (settings, data) {
11029 * // Send an Ajax request to the server with the state object
11030 * $.ajax( {
11031 * "url": "/state_save",
11032 * "data": data,
11033 * "dataType": "json",
11034 * "method": "POST"
11035 * "success": function () {}
11036 * } );
11037 * }
11038 * } );
11039 * } );
11040 */
11041 "fnStateSaveCallback": function ( settings, data ) {
11042 try {
11043 (settings.iStateDuration === -1 ? sessionStorage : localStorage).setItem(
11044 'DataTables_'+settings.sInstance+'_'+location.pathname,
11045 JSON.stringify( data )
11046 );
11047 } catch (e) {}
11048 },
11049
11050
11051 /**
11052 * Callback which allows modification of the state to be saved. Called when the table
11053 * has changed state a new state save is required. This method allows modification of
11054 * the state saving object prior to actually doing the save, including addition or
11055 * other state properties or modification. Note that for plug-in authors, you should
11056 * use the `stateSaveParams` event to save parameters for a plug-in.
11057 * @type function
11058 * @param {object} settings DataTables settings object
11059 * @param {object} data The state object to be saved
11060 *
11061 * @dtopt Callbacks
11062 * @name DataTable.defaults.stateSaveParams
11063 *
11064 * @example
11065 * // Remove a saved filter, so filtering is never saved
11066 * $(document).ready( function() {
11067 * $('#example').dataTable( {
11068 * "stateSave": true,
11069 * "stateSaveParams": function (settings, data) {
11070 * data.oSearch.sSearch = "";
11071 * }
11072 * } );
11073 * } );
11074 */
11075 "fnStateSaveParams": null,
11076
11077
11078 /**
11079 * Duration for which the saved state information is considered valid. After this period
11080 * has elapsed the state will be returned to the default.
11081 * Value is given in seconds.
11082 * @type int
11083 * @default 7200 <i>(2 hours)</i>
11084 *
11085 * @dtopt Options
11086 * @name DataTable.defaults.stateDuration
11087 *
11088 * @example
11089 * $(document).ready( function() {
11090 * $('#example').dataTable( {
11091 * "stateDuration": 60*60*24; // 1 day
11092 * } );
11093 * } )
11094 */
11095 "iStateDuration": 7200,
11096
11097
11098 /**
11099 * When enabled DataTables will not make a request to the server for the first
11100 * page draw - rather it will use the data already on the page (no sorting etc
11101 * will be applied to it), thus saving on an XHR at load time. `deferLoading`
11102 * is used to indicate that deferred loading is required, but it is also used
11103 * to tell DataTables how many records there are in the full table (allowing
11104 * the information element and pagination to be displayed correctly). In the case
11105 * where a filtering is applied to the table on initial load, this can be
11106 * indicated by giving the parameter as an array, where the first element is
11107 * the number of records available after filtering and the second element is the
11108 * number of records without filtering (allowing the table information element
11109 * to be shown correctly).
11110 * @type int | array
11111 * @default null
11112 *
11113 * @dtopt Options
11114 * @name DataTable.defaults.deferLoading
11115 *
11116 * @example
11117 * // 57 records available in the table, no filtering applied
11118 * $(document).ready( function() {
11119 * $('#example').dataTable( {
11120 * "serverSide": true,
11121 * "ajax": "scripts/server_processing.php",
11122 * "deferLoading": 57
11123 * } );
11124 * } );
11125 *
11126 * @example
11127 * // 57 records after filtering, 100 without filtering (an initial filter applied)
11128 * $(document).ready( function() {
11129 * $('#example').dataTable( {
11130 * "serverSide": true,
11131 * "ajax": "scripts/server_processing.php",
11132 * "deferLoading": [ 57, 100 ],
11133 * "search": {
11134 * "search": "my_filter"
11135 * }
11136 * } );
11137 * } );
11138 */
11139 "iDeferLoading": null,
11140
11141
11142 /**
11143 * Number of rows to display on a single page when using pagination. If
11144 * feature enabled (`lengthChange`) then the end user will be able to override
11145 * this to a custom setting using a pop-up menu.
11146 * @type int
11147 * @default 10
11148 *
11149 * @dtopt Options
11150 * @name DataTable.defaults.pageLength
11151 *
11152 * @example
11153 * $(document).ready( function() {
11154 * $('#example').dataTable( {
11155 * "pageLength": 50
11156 * } );
11157 * } )
11158 */
11159 "iDisplayLength": 10,
11160
11161
11162 /**
11163 * Define the starting point for data display when using DataTables with
11164 * pagination. Note that this parameter is the number of records, rather than
11165 * the page number, so if you have 10 records per page and want to start on
11166 * the third page, it should be "20".
11167 * @type int
11168 * @default 0
11169 *
11170 * @dtopt Options
11171 * @name DataTable.defaults.displayStart
11172 *
11173 * @example
11174 * $(document).ready( function() {
11175 * $('#example').dataTable( {
11176 * "displayStart": 20
11177 * } );
11178 * } )
11179 */
11180 "iDisplayStart": 0,
11181
11182
11183 /**
11184 * By default DataTables allows keyboard navigation of the table (sorting, paging,
11185 * and filtering) by adding a `tabindex` attribute to the required elements. This
11186 * allows you to tab through the controls and press the enter key to activate them.
11187 * The tabindex is default 0, meaning that the tab follows the flow of the document.
11188 * You can overrule this using this parameter if you wish. Use a value of -1 to
11189 * disable built-in keyboard navigation.
11190 * @type int
11191 * @default 0
11192 *
11193 * @dtopt Options
11194 * @name DataTable.defaults.tabIndex
11195 *
11196 * @example
11197 * $(document).ready( function() {
11198 * $('#example').dataTable( {
11199 * "tabIndex": 1
11200 * } );
11201 * } );
11202 */
11203 "iTabIndex": 0,
11204
11205
11206 /**
11207 * Classes that DataTables assigns to the various components and features
11208 * that it adds to the HTML table. This allows classes to be configured
11209 * during initialisation in addition to through the static
11210 * {@link DataTable.ext.oStdClasses} object).
11211 * @namespace
11212 * @name DataTable.defaults.classes
11213 */
11214 "oClasses": {},
11215
11216
11217 /**
11218 * All strings that DataTables uses in the user interface that it creates
11219 * are defined in this object, allowing you to modified them individually or
11220 * completely replace them all as required.
11221 * @namespace
11222 * @name DataTable.defaults.language
11223 */
11224 "oLanguage": {
11225 /**
11226 * Strings that are used for WAI-ARIA labels and controls only (these are not
11227 * actually visible on the page, but will be read by screenreaders, and thus
11228 * must be internationalised as well).
11229 * @namespace
11230 * @name DataTable.defaults.language.aria
11231 */
11232 "oAria": {
11233 /**
11234 * ARIA label that is added to the table headers when the column may be
11235 * sorted ascending by activing the column (click or return when focused).
11236 * Note that the column header is prefixed to this string.
11237 * @type string
11238 * @default : activate to sort column ascending
11239 *
11240 * @dtopt Language
11241 * @name DataTable.defaults.language.aria.sortAscending
11242 *
11243 * @example
11244 * $(document).ready( function() {
11245 * $('#example').dataTable( {
11246 * "language": {
11247 * "aria": {
11248 * "sortAscending": " - click/return to sort ascending"
11249 * }
11250 * }
11251 * } );
11252 * } );
11253 */
11254 "sSortAscending": ": activate to sort column ascending",
11255
11256 /**
11257 * ARIA label that is added to the table headers when the column may be
11258 * sorted descending by activing the column (click or return when focused).
11259 * Note that the column header is prefixed to this string.
11260 * @type string
11261 * @default : activate to sort column ascending
11262 *
11263 * @dtopt Language
11264 * @name DataTable.defaults.language.aria.sortDescending
11265 *
11266 * @example
11267 * $(document).ready( function() {
11268 * $('#example').dataTable( {
11269 * "language": {
11270 * "aria": {
11271 * "sortDescending": " - click/return to sort descending"
11272 * }
11273 * }
11274 * } );
11275 * } );
11276 */
11277 "sSortDescending": ": activate to sort column descending"
11278 },
11279
11280 /**
11281 * Pagination string used by DataTables for the built-in pagination
11282 * control types.
11283 * @namespace
11284 * @name DataTable.defaults.language.paginate
11285 */
11286 "oPaginate": {
11287 /**
11288 * Text to use when using the 'full_numbers' type of pagination for the
11289 * button to take the user to the first page.
11290 * @type string
11291 * @default First
11292 *
11293 * @dtopt Language
11294 * @name DataTable.defaults.language.paginate.first
11295 *
11296 * @example
11297 * $(document).ready( function() {
11298 * $('#example').dataTable( {
11299 * "language": {
11300 * "paginate": {
11301 * "first": "First page"
11302 * }
11303 * }
11304 * } );
11305 * } );
11306 */
11307 "sFirst": "First",
11308
11309
11310 /**
11311 * Text to use when using the 'full_numbers' type of pagination for the
11312 * button to take the user to the last page.
11313 * @type string
11314 * @default Last
11315 *
11316 * @dtopt Language
11317 * @name DataTable.defaults.language.paginate.last
11318 *
11319 * @example
11320 * $(document).ready( function() {
11321 * $('#example').dataTable( {
11322 * "language": {
11323 * "paginate": {
11324 * "last": "Last page"
11325 * }
11326 * }
11327 * } );
11328 * } );
11329 */
11330 "sLast": "Last",
11331
11332
11333 /**
11334 * Text to use for the 'next' pagination button (to take the user to the
11335 * next page).
11336 * @type string
11337 * @default Next
11338 *
11339 * @dtopt Language
11340 * @name DataTable.defaults.language.paginate.next
11341 *
11342 * @example
11343 * $(document).ready( function() {
11344 * $('#example').dataTable( {
11345 * "language": {
11346 * "paginate": {
11347 * "next": "Next page"
11348 * }
11349 * }
11350 * } );
11351 * } );
11352 */
11353 "sNext": "Next",
11354
11355
11356 /**
11357 * Text to use for the 'previous' pagination button (to take the user to
11358 * the previous page).
11359 * @type string
11360 * @default Previous
11361 *
11362 * @dtopt Language
11363 * @name DataTable.defaults.language.paginate.previous
11364 *
11365 * @example
11366 * $(document).ready( function() {
11367 * $('#example').dataTable( {
11368 * "language": {
11369 * "paginate": {
11370 * "previous": "Previous page"
11371 * }
11372 * }
11373 * } );
11374 * } );
11375 */
11376 "sPrevious": "Previous"
11377 },
11378
11379 /**
11380 * This string is shown in preference to `zeroRecords` when the table is
11381 * empty of data (regardless of filtering). Note that this is an optional
11382 * parameter - if it is not given, the value of `zeroRecords` will be used
11383 * instead (either the default or given value).
11384 * @type string
11385 * @default No data available in table
11386 *
11387 * @dtopt Language
11388 * @name DataTable.defaults.language.emptyTable
11389 *
11390 * @example
11391 * $(document).ready( function() {
11392 * $('#example').dataTable( {
11393 * "language": {
11394 * "emptyTable": "No data available in table"
11395 * }
11396 * } );
11397 * } );
11398 */
11399 "sEmptyTable": "No data available in table",
11400
11401
11402 /**
11403 * This string gives information to the end user about the information
11404 * that is current on display on the page. The following tokens can be
11405 * used in the string and will be dynamically replaced as the table
11406 * display updates. This tokens can be placed anywhere in the string, or
11407 * removed as needed by the language requires:
11408 *
11409 * * `\_START\_` - Display index of the first record on the current page
11410 * * `\_END\_` - Display index of the last record on the current page
11411 * * `\_TOTAL\_` - Number of records in the table after filtering
11412 * * `\_MAX\_` - Number of records in the table without filtering
11413 * * `\_PAGE\_` - Current page number
11414 * * `\_PAGES\_` - Total number of pages of data in the table
11415 *
11416 * @type string
11417 * @default Showing _START_ to _END_ of _TOTAL_ entries
11418 *
11419 * @dtopt Language
11420 * @name DataTable.defaults.language.info
11421 *
11422 * @example
11423 * $(document).ready( function() {
11424 * $('#example').dataTable( {
11425 * "language": {
11426 * "info": "Showing page _PAGE_ of _PAGES_"
11427 * }
11428 * } );
11429 * } );
11430 */
11431 "sInfo": "Showing _START_ to _END_ of _TOTAL_ entries",
11432
11433
11434 /**
11435 * Display information string for when the table is empty. Typically the
11436 * format of this string should match `info`.
11437 * @type string
11438 * @default Showing 0 to 0 of 0 entries
11439 *
11440 * @dtopt Language
11441 * @name DataTable.defaults.language.infoEmpty
11442 *
11443 * @example
11444 * $(document).ready( function() {
11445 * $('#example').dataTable( {
11446 * "language": {
11447 * "infoEmpty": "No entries to show"
11448 * }
11449 * } );
11450 * } );
11451 */
11452 "sInfoEmpty": "Showing 0 to 0 of 0 entries",
11453
11454
11455 /**
11456 * When a user filters the information in a table, this string is appended
11457 * to the information (`info`) to give an idea of how strong the filtering
11458 * is. The variable _MAX_ is dynamically updated.
11459 * @type string
11460 * @default (filtered from _MAX_ total entries)
11461 *
11462 * @dtopt Language
11463 * @name DataTable.defaults.language.infoFiltered
11464 *
11465 * @example
11466 * $(document).ready( function() {
11467 * $('#example').dataTable( {
11468 * "language": {
11469 * "infoFiltered": " - filtering from _MAX_ records"
11470 * }
11471 * } );
11472 * } );
11473 */
11474 "sInfoFiltered": "(filtered from _MAX_ total entries)",
11475
11476
11477 /**
11478 * If can be useful to append extra information to the info string at times,
11479 * and this variable does exactly that. This information will be appended to
11480 * the `info` (`infoEmpty` and `infoFiltered` in whatever combination they are
11481 * being used) at all times.
11482 * @type string
11483 * @default <i>Empty string</i>
11484 *
11485 * @dtopt Language
11486 * @name DataTable.defaults.language.infoPostFix
11487 *
11488 * @example
11489 * $(document).ready( function() {
11490 * $('#example').dataTable( {
11491 * "language": {
11492 * "infoPostFix": "All records shown are derived from real information."
11493 * }
11494 * } );
11495 * } );
11496 */
11497 "sInfoPostFix": "",
11498
11499
11500 /**
11501 * This decimal place operator is a little different from the other
11502 * language options since DataTables doesn't output floating point
11503 * numbers, so it won't ever use this for display of a number. Rather,
11504 * what this parameter does is modify the sort methods of the table so
11505 * that numbers which are in a format which has a character other than
11506 * a period (`.`) as a decimal place will be sorted numerically.
11507 *
11508 * Note that numbers with different decimal places cannot be shown in
11509 * the same table and still be sortable, the table must be consistent.
11510 * However, multiple different tables on the page can use different
11511 * decimal place characters.
11512 * @type string
11513 * @default
11514 *
11515 * @dtopt Language
11516 * @name DataTable.defaults.language.decimal
11517 *
11518 * @example
11519 * $(document).ready( function() {
11520 * $('#example').dataTable( {
11521 * "language": {
11522 * "decimal": ","
11523 * "thousands": "."
11524 * }
11525 * } );
11526 * } );
11527 */
11528 "sDecimal": "",
11529
11530
11531 /**
11532 * DataTables has a build in number formatter (`formatNumber`) which is
11533 * used to format large numbers that are used in the table information.
11534 * By default a comma is used, but this can be trivially changed to any
11535 * character you wish with this parameter.
11536 * @type string
11537 * @default ,
11538 *
11539 * @dtopt Language
11540 * @name DataTable.defaults.language.thousands
11541 *
11542 * @example
11543 * $(document).ready( function() {
11544 * $('#example').dataTable( {
11545 * "language": {
11546 * "thousands": "'"
11547 * }
11548 * } );
11549 * } );
11550 */
11551 "sThousands": ",",
11552
11553
11554 /**
11555 * Detail the action that will be taken when the drop down menu for the
11556 * pagination length option is changed. The '_MENU_' variable is replaced
11557 * with a default select list of 10, 25, 50 and 100, and can be replaced
11558 * with a custom select box if required.
11559 * @type string
11560 * @default Show _MENU_ entries
11561 *
11562 * @dtopt Language
11563 * @name DataTable.defaults.language.lengthMenu
11564 *
11565 * @example
11566 * // Language change only
11567 * $(document).ready( function() {
11568 * $('#example').dataTable( {
11569 * "language": {
11570 * "lengthMenu": "Display _MENU_ records"
11571 * }
11572 * } );
11573 * } );
11574 *
11575 * @example
11576 * // Language and options change
11577 * $(document).ready( function() {
11578 * $('#example').dataTable( {
11579 * "language": {
11580 * "lengthMenu": 'Display <select>'+
11581 * '<option value="10">10</option>'+
11582 * '<option value="20">20</option>'+
11583 * '<option value="30">30</option>'+
11584 * '<option value="40">40</option>'+
11585 * '<option value="50">50</option>'+
11586 * '<option value="-1">All</option>'+
11587 * '</select> records'
11588 * }
11589 * } );
11590 * } );
11591 */
11592 "sLengthMenu": "Show _MENU_ entries",
11593
11594
11595 /**
11596 * When using Ajax sourced data and during the first draw when DataTables is
11597 * gathering the data, this message is shown in an empty row in the table to
11598 * indicate to the end user the the data is being loaded. Note that this
11599 * parameter is not used when loading data by server-side processing, just
11600 * Ajax sourced data with client-side processing.
11601 * @type string
11602 * @default Loading...
11603 *
11604 * @dtopt Language
11605 * @name DataTable.defaults.language.loadingRecords
11606 *
11607 * @example
11608 * $(document).ready( function() {
11609 * $('#example').dataTable( {
11610 * "language": {
11611 * "loadingRecords": "Please wait - loading..."
11612 * }
11613 * } );
11614 * } );
11615 */
11616 "sLoadingRecords": "Loading...",
11617
11618
11619 /**
11620 * Text which is displayed when the table is processing a user action
11621 * (usually a sort command or similar).
11622 * @type string
11623 * @default Processing...
11624 *
11625 * @dtopt Language
11626 * @name DataTable.defaults.language.processing
11627 *
11628 * @example
11629 * $(document).ready( function() {
11630 * $('#example').dataTable( {
11631 * "language": {
11632 * "processing": "DataTables is currently busy"
11633 * }
11634 * } );
11635 * } );
11636 */
11637 "sProcessing": "Processing...",
11638
11639
11640 /**
11641 * Details the actions that will be taken when the user types into the
11642 * filtering input text box. The variable "_INPUT_", if used in the string,
11643 * is replaced with the HTML text box for the filtering input allowing
11644 * control over where it appears in the string. If "_INPUT_" is not given
11645 * then the input box is appended to the string automatically.
11646 * @type string
11647 * @default Search:
11648 *
11649 * @dtopt Language
11650 * @name DataTable.defaults.language.search
11651 *
11652 * @example
11653 * // Input text box will be appended at the end automatically
11654 * $(document).ready( function() {
11655 * $('#example').dataTable( {
11656 * "language": {
11657 * "search": "Filter records:"
11658 * }
11659 * } );
11660 * } );
11661 *
11662 * @example
11663 * // Specify where the filter should appear
11664 * $(document).ready( function() {
11665 * $('#example').dataTable( {
11666 * "language": {
11667 * "search": "Apply filter _INPUT_ to table"
11668 * }
11669 * } );
11670 * } );
11671 */
11672 "sSearch": "Search:",
11673
11674
11675 /**
11676 * Assign a `placeholder` attribute to the search `input` element
11677 * @type string
11678 * @default
11679 *
11680 * @dtopt Language
11681 * @name DataTable.defaults.language.searchPlaceholder
11682 */
11683 "sSearchPlaceholder": "",
11684
11685
11686 /**
11687 * All of the language information can be stored in a file on the
11688 * server-side, which DataTables will look up if this parameter is passed.
11689 * It must store the URL of the language file, which is in a JSON format,
11690 * and the object has the same properties as the oLanguage object in the
11691 * initialiser object (i.e. the above parameters). Please refer to one of
11692 * the example language files to see how this works in action.
11693 * @type string
11694 * @default <i>Empty string - i.e. disabled</i>
11695 *
11696 * @dtopt Language
11697 * @name DataTable.defaults.language.url
11698 *
11699 * @example
11700 * $(document).ready( function() {
11701 * $('#example').dataTable( {
11702 * "language": {
11703 * "url": "http://www.sprymedia.co.uk/dataTables/lang.txt"
11704 * }
11705 * } );
11706 * } );
11707 */
11708 "sUrl": "",
11709
11710
11711 /**
11712 * Text shown inside the table records when the is no information to be
11713 * displayed after filtering. `emptyTable` is shown when there is simply no
11714 * information in the table at all (regardless of filtering).
11715 * @type string
11716 * @default No matching records found
11717 *
11718 * @dtopt Language
11719 * @name DataTable.defaults.language.zeroRecords
11720 *
11721 * @example
11722 * $(document).ready( function() {
11723 * $('#example').dataTable( {
11724 * "language": {
11725 * "zeroRecords": "No records to display"
11726 * }
11727 * } );
11728 * } );
11729 */
11730 "sZeroRecords": "No matching records found"
11731 },
11732
11733
11734 /**
11735 * This parameter allows you to have define the global filtering state at
11736 * initialisation time. As an object the `search` parameter must be
11737 * defined, but all other parameters are optional. When `regex` is true,
11738 * the search string will be treated as a regular expression, when false
11739 * (default) it will be treated as a straight string. When `smart`
11740 * DataTables will use it's smart filtering methods (to word match at
11741 * any point in the data), when false this will not be done.
11742 * @namespace
11743 * @extends DataTable.models.oSearch
11744 *
11745 * @dtopt Options
11746 * @name DataTable.defaults.search
11747 *
11748 * @example
11749 * $(document).ready( function() {
11750 * $('#example').dataTable( {
11751 * "search": {"search": "Initial search"}
11752 * } );
11753 * } )
11754 */
11755 "oSearch": $.extend( {}, DataTable.models.oSearch ),
11756
11757
11758 /**
11759 * __Deprecated__ The functionality provided by this parameter has now been
11760 * superseded by that provided through `ajax`, which should be used instead.
11761 *
11762 * By default DataTables will look for the property `data` (or `aaData` for
11763 * compatibility with DataTables 1.9-) when obtaining data from an Ajax
11764 * source or for server-side processing - this parameter allows that
11765 * property to be changed. You can use Javascript dotted object notation to
11766 * get a data source for multiple levels of nesting.
11767 * @type string
11768 * @default data
11769 *
11770 * @dtopt Options
11771 * @dtopt Server-side
11772 * @name DataTable.defaults.ajaxDataProp
11773 *
11774 * @deprecated 1.10. Please use `ajax` for this functionality now.
11775 */
11776 "sAjaxDataProp": "data",
11777
11778
11779 /**
11780 * __Deprecated__ The functionality provided by this parameter has now been
11781 * superseded by that provided through `ajax`, which should be used instead.
11782 *
11783 * You can instruct DataTables to load data from an external
11784 * source using this parameter (use aData if you want to pass data in you
11785 * already have). Simply provide a url a JSON object can be obtained from.
11786 * @type string
11787 * @default null
11788 *
11789 * @dtopt Options
11790 * @dtopt Server-side
11791 * @name DataTable.defaults.ajaxSource
11792 *
11793 * @deprecated 1.10. Please use `ajax` for this functionality now.
11794 */
11795 "sAjaxSource": null,
11796
11797
11798 /**
11799 * This initialisation variable allows you to specify exactly where in the
11800 * DOM you want DataTables to inject the various controls it adds to the page
11801 * (for example you might want the pagination controls at the top of the
11802 * table). DIV elements (with or without a custom class) can also be added to
11803 * aid styling. The follow syntax is used:
11804 * <ul>
11805 * <li>The following options are allowed:
11806 * <ul>
11807 * <li>'l' - Length changing</li>
11808 * <li>'f' - Filtering input</li>
11809 * <li>'t' - The table!</li>
11810 * <li>'i' - Information</li>
11811 * <li>'p' - Pagination</li>
11812 * <li>'r' - pRocessing</li>
11813 * </ul>
11814 * </li>
11815 * <li>The following constants are allowed:
11816 * <ul>
11817 * <li>'H' - jQueryUI theme "header" classes ('fg-toolbar ui-widget-header ui-corner-tl ui-corner-tr ui-helper-clearfix')</li>
11818 * <li>'F' - jQueryUI theme "footer" classes ('fg-toolbar ui-widget-header ui-corner-bl ui-corner-br ui-helper-clearfix')</li>
11819 * </ul>
11820 * </li>
11821 * <li>The following syntax is expected:
11822 * <ul>
11823 * <li>'&lt;' and '&gt;' - div elements</li>
11824 * <li>'&lt;"class" and '&gt;' - div with a class</li>
11825 * <li>'&lt;"#id" and '&gt;' - div with an ID</li>
11826 * </ul>
11827 * </li>
11828 * <li>Examples:
11829 * <ul>
11830 * <li>'&lt;"wrapper"flipt&gt;'</li>
11831 * <li>'&lt;lf&lt;t&gt;ip&gt;'</li>
11832 * </ul>
11833 * </li>
11834 * </ul>
11835 * @type string
11836 * @default lfrtip <i>(when `jQueryUI` is false)</i> <b>or</b>
11837 * <"H"lfr>t<"F"ip> <i>(when `jQueryUI` is true)</i>
11838 *
11839 * @dtopt Options
11840 * @name DataTable.defaults.dom
11841 *
11842 * @example
11843 * $(document).ready( function() {
11844 * $('#example').dataTable( {
11845 * "dom": '&lt;"top"i&gt;rt&lt;"bottom"flp&gt;&lt;"clear"&gt;'
11846 * } );
11847 * } );
11848 */
11849 "sDom": "lfrtip",
11850
11851
11852 /**
11853 * Search delay option. This will throttle full table searches that use the
11854 * DataTables provided search input element (it does not effect calls to
11855 * `dt-api search()`, providing a delay before the search is made.
11856 * @type integer
11857 * @default 0
11858 *
11859 * @dtopt Options
11860 * @name DataTable.defaults.searchDelay
11861 *
11862 * @example
11863 * $(document).ready( function() {
11864 * $('#example').dataTable( {
11865 * "searchDelay": 200
11866 * } );
11867 * } )
11868 */
11869 "searchDelay": null,
11870
11871
11872 /**
11873 * DataTables features six different built-in options for the buttons to
11874 * display for pagination control:
11875 *
11876 * * `numbers` - Page number buttons only
11877 * * `simple` - 'Previous' and 'Next' buttons only
11878 * * 'simple_numbers` - 'Previous' and 'Next' buttons, plus page numbers
11879 * * `full` - 'First', 'Previous', 'Next' and 'Last' buttons
11880 * * `full_numbers` - 'First', 'Previous', 'Next' and 'Last' buttons, plus page numbers
11881 * * `first_last_numbers` - 'First' and 'Last' buttons, plus page numbers
11882 *
11883 * Further methods can be added using {@link DataTable.ext.oPagination}.
11884 * @type string
11885 * @default simple_numbers
11886 *
11887 * @dtopt Options
11888 * @name DataTable.defaults.pagingType
11889 *
11890 * @example
11891 * $(document).ready( function() {
11892 * $('#example').dataTable( {
11893 * "pagingType": "full_numbers"
11894 * } );
11895 * } )
11896 */
11897 "sPaginationType": "simple_numbers",
11898
11899
11900 /**
11901 * Enable horizontal scrolling. When a table is too wide to fit into a
11902 * certain layout, or you have a large number of columns in the table, you
11903 * can enable x-scrolling to show the table in a viewport, which can be
11904 * scrolled. This property can be `true` which will allow the table to
11905 * scroll horizontally when needed, or any CSS unit, or a number (in which
11906 * case it will be treated as a pixel measurement). Setting as simply `true`
11907 * is recommended.
11908 * @type boolean|string
11909 * @default <i>blank string - i.e. disabled</i>
11910 *
11911 * @dtopt Features
11912 * @name DataTable.defaults.scrollX
11913 *
11914 * @example
11915 * $(document).ready( function() {
11916 * $('#example').dataTable( {
11917 * "scrollX": true,
11918 * "scrollCollapse": true
11919 * } );
11920 * } );
11921 */
11922 "sScrollX": "",
11923
11924
11925 /**
11926 * This property can be used to force a DataTable to use more width than it
11927 * might otherwise do when x-scrolling is enabled. For example if you have a
11928 * table which requires to be well spaced, this parameter is useful for
11929 * "over-sizing" the table, and thus forcing scrolling. This property can by
11930 * any CSS unit, or a number (in which case it will be treated as a pixel
11931 * measurement).
11932 * @type string
11933 * @default <i>blank string - i.e. disabled</i>
11934 *
11935 * @dtopt Options
11936 * @name DataTable.defaults.scrollXInner
11937 *
11938 * @example
11939 * $(document).ready( function() {
11940 * $('#example').dataTable( {
11941 * "scrollX": "100%",
11942 * "scrollXInner": "110%"
11943 * } );
11944 * } );
11945 */
11946 "sScrollXInner": "",
11947
11948
11949 /**
11950 * Enable vertical scrolling. Vertical scrolling will constrain the DataTable
11951 * to the given height, and enable scrolling for any data which overflows the
11952 * current viewport. This can be used as an alternative to paging to display
11953 * a lot of data in a small area (although paging and scrolling can both be
11954 * enabled at the same time). This property can be any CSS unit, or a number
11955 * (in which case it will be treated as a pixel measurement).
11956 * @type string
11957 * @default <i>blank string - i.e. disabled</i>
11958 *
11959 * @dtopt Features
11960 * @name DataTable.defaults.scrollY
11961 *
11962 * @example
11963 * $(document).ready( function() {
11964 * $('#example').dataTable( {
11965 * "scrollY": "200px",
11966 * "paginate": false
11967 * } );
11968 * } );
11969 */
11970 "sScrollY": "",
11971
11972
11973 /**
11974 * __Deprecated__ The functionality provided by this parameter has now been
11975 * superseded by that provided through `ajax`, which should be used instead.
11976 *
11977 * Set the HTTP method that is used to make the Ajax call for server-side
11978 * processing or Ajax sourced data.
11979 * @type string
11980 * @default GET
11981 *
11982 * @dtopt Options
11983 * @dtopt Server-side
11984 * @name DataTable.defaults.serverMethod
11985 *
11986 * @deprecated 1.10. Please use `ajax` for this functionality now.
11987 */
11988 "sServerMethod": "GET",
11989
11990
11991 /**
11992 * DataTables makes use of renderers when displaying HTML elements for
11993 * a table. These renderers can be added or modified by plug-ins to
11994 * generate suitable mark-up for a site. For example the Bootstrap
11995 * integration plug-in for DataTables uses a paging button renderer to
11996 * display pagination buttons in the mark-up required by Bootstrap.
11997 *
11998 * For further information about the renderers available see
11999 * DataTable.ext.renderer
12000 * @type string|object
12001 * @default null
12002 *
12003 * @name DataTable.defaults.renderer
12004 *
12005 */
12006 "renderer": null,
12007
12008
12009 /**
12010 * Set the data property name that DataTables should use to get a row's id
12011 * to set as the `id` property in the node.
12012 * @type string
12013 * @default DT_RowId
12014 *
12015 * @name DataTable.defaults.rowId
12016 */
12017 "rowId": "DT_RowId"
12018 };
12019
12020 _fnHungarianMap( DataTable.defaults );
12021
12022
12023
12024 /*
12025 * Developer note - See note in model.defaults.js about the use of Hungarian
12026 * notation and camel case.
12027 */
12028
12029 /**
12030 * Column options that can be given to DataTables at initialisation time.
12031 * @namespace
12032 */
12033 DataTable.defaults.column = {
12034 /**
12035 * Define which column(s) an order will occur on for this column. This
12036 * allows a column's ordering to take multiple columns into account when
12037 * doing a sort or use the data from a different column. For example first
12038 * name / last name columns make sense to do a multi-column sort over the
12039 * two columns.
12040 * @type array|int
12041 * @default null <i>Takes the value of the column index automatically</i>
12042 *
12043 * @name DataTable.defaults.column.orderData
12044 * @dtopt Columns
12045 *
12046 * @example
12047 * // Using `columnDefs`
12048 * $(document).ready( function() {
12049 * $('#example').dataTable( {
12050 * "columnDefs": [
12051 * { "orderData": [ 0, 1 ], "targets": [ 0 ] },
12052 * { "orderData": [ 1, 0 ], "targets": [ 1 ] },
12053 * { "orderData": 2, "targets": [ 2 ] }
12054 * ]
12055 * } );
12056 * } );
12057 *
12058 * @example
12059 * // Using `columns`
12060 * $(document).ready( function() {
12061 * $('#example').dataTable( {
12062 * "columns": [
12063 * { "orderData": [ 0, 1 ] },
12064 * { "orderData": [ 1, 0 ] },
12065 * { "orderData": 2 },
12066 * null,
12067 * null
12068 * ]
12069 * } );
12070 * } );
12071 */
12072 "aDataSort": null,
12073 "iDataSort": -1,
12074
12075
12076 /**
12077 * You can control the default ordering direction, and even alter the
12078 * behaviour of the sort handler (i.e. only allow ascending ordering etc)
12079 * using this parameter.
12080 * @type array
12081 * @default [ 'asc', 'desc' ]
12082 *
12083 * @name DataTable.defaults.column.orderSequence
12084 * @dtopt Columns
12085 *
12086 * @example
12087 * // Using `columnDefs`
12088 * $(document).ready( function() {
12089 * $('#example').dataTable( {
12090 * "columnDefs": [
12091 * { "orderSequence": [ "asc" ], "targets": [ 1 ] },
12092 * { "orderSequence": [ "desc", "asc", "asc" ], "targets": [ 2 ] },
12093 * { "orderSequence": [ "desc" ], "targets": [ 3 ] }
12094 * ]
12095 * } );
12096 * } );
12097 *
12098 * @example
12099 * // Using `columns`
12100 * $(document).ready( function() {
12101 * $('#example').dataTable( {
12102 * "columns": [
12103 * null,
12104 * { "orderSequence": [ "asc" ] },
12105 * { "orderSequence": [ "desc", "asc", "asc" ] },
12106 * { "orderSequence": [ "desc" ] },
12107 * null
12108 * ]
12109 * } );
12110 * } );
12111 */
12112 "asSorting": [ 'asc', 'desc' ],
12113
12114
12115 /**
12116 * Enable or disable filtering on the data in this column.
12117 * @type boolean
12118 * @default true
12119 *
12120 * @name DataTable.defaults.column.searchable
12121 * @dtopt Columns
12122 *
12123 * @example
12124 * // Using `columnDefs`
12125 * $(document).ready( function() {
12126 * $('#example').dataTable( {
12127 * "columnDefs": [
12128 * { "searchable": false, "targets": [ 0 ] }
12129 * ] } );
12130 * } );
12131 *
12132 * @example
12133 * // Using `columns`
12134 * $(document).ready( function() {
12135 * $('#example').dataTable( {
12136 * "columns": [
12137 * { "searchable": false },
12138 * null,
12139 * null,
12140 * null,
12141 * null
12142 * ] } );
12143 * } );
12144 */
12145 "bSearchable": true,
12146
12147
12148 /**
12149 * Enable or disable ordering on this column.
12150 * @type boolean
12151 * @default true
12152 *
12153 * @name DataTable.defaults.column.orderable
12154 * @dtopt Columns
12155 *
12156 * @example
12157 * // Using `columnDefs`
12158 * $(document).ready( function() {
12159 * $('#example').dataTable( {
12160 * "columnDefs": [
12161 * { "orderable": false, "targets": [ 0 ] }
12162 * ] } );
12163 * } );
12164 *
12165 * @example
12166 * // Using `columns`
12167 * $(document).ready( function() {
12168 * $('#example').dataTable( {
12169 * "columns": [
12170 * { "orderable": false },
12171 * null,
12172 * null,
12173 * null,
12174 * null
12175 * ] } );
12176 * } );
12177 */
12178 "bSortable": true,
12179
12180
12181 /**
12182 * Enable or disable the display of this column.
12183 * @type boolean
12184 * @default true
12185 *
12186 * @name DataTable.defaults.column.visible
12187 * @dtopt Columns
12188 *
12189 * @example
12190 * // Using `columnDefs`
12191 * $(document).ready( function() {
12192 * $('#example').dataTable( {
12193 * "columnDefs": [
12194 * { "visible": false, "targets": [ 0 ] }
12195 * ] } );
12196 * } );
12197 *
12198 * @example
12199 * // Using `columns`
12200 * $(document).ready( function() {
12201 * $('#example').dataTable( {
12202 * "columns": [
12203 * { "visible": false },
12204 * null,
12205 * null,
12206 * null,
12207 * null
12208 * ] } );
12209 * } );
12210 */
12211 "bVisible": true,
12212
12213
12214 /**
12215 * Developer definable function that is called whenever a cell is created (Ajax source,
12216 * etc) or processed for input (DOM source). This can be used as a compliment to mRender
12217 * allowing you to modify the DOM element (add background colour for example) when the
12218 * element is available.
12219 * @type function
12220 * @param {element} td The TD node that has been created
12221 * @param {*} cellData The Data for the cell
12222 * @param {array|object} rowData The data for the whole row
12223 * @param {int} row The row index for the aoData data store
12224 * @param {int} col The column index for aoColumns
12225 *
12226 * @name DataTable.defaults.column.createdCell
12227 * @dtopt Columns
12228 *
12229 * @example
12230 * $(document).ready( function() {
12231 * $('#example').dataTable( {
12232 * "columnDefs": [ {
12233 * "targets": [3],
12234 * "createdCell": function (td, cellData, rowData, row, col) {
12235 * if ( cellData == "1.7" ) {
12236 * $(td).css('color', 'blue')
12237 * }
12238 * }
12239 * } ]
12240 * });
12241 * } );
12242 */
12243 "fnCreatedCell": null,
12244
12245
12246 /**
12247 * This parameter has been replaced by `data` in DataTables to ensure naming
12248 * consistency. `dataProp` can still be used, as there is backwards
12249 * compatibility in DataTables for this option, but it is strongly
12250 * recommended that you use `data` in preference to `dataProp`.
12251 * @name DataTable.defaults.column.dataProp
12252 */
12253
12254
12255 /**
12256 * This property can be used to read data from any data source property,
12257 * including deeply nested objects / properties. `data` can be given in a
12258 * number of different ways which effect its behaviour:
12259 *
12260 * * `integer` - treated as an array index for the data source. This is the
12261 * default that DataTables uses (incrementally increased for each column).
12262 * * `string` - read an object property from the data source. There are
12263 * three 'special' options that can be used in the string to alter how
12264 * DataTables reads the data from the source object:
12265 * * `.` - Dotted Javascript notation. Just as you use a `.` in
12266 * Javascript to read from nested objects, so to can the options
12267 * specified in `data`. For example: `browser.version` or
12268 * `browser.name`. If your object parameter name contains a period, use
12269 * `\\` to escape it - i.e. `first\\.name`.
12270 * * `[]` - Array notation. DataTables can automatically combine data
12271 * from and array source, joining the data with the characters provided
12272 * between the two brackets. For example: `name[, ]` would provide a
12273 * comma-space separated list from the source array. If no characters
12274 * are provided between the brackets, the original array source is
12275 * returned.
12276 * * `()` - Function notation. Adding `()` to the end of a parameter will
12277 * execute a function of the name given. For example: `browser()` for a
12278 * simple function on the data source, `browser.version()` for a
12279 * function in a nested property or even `browser().version` to get an
12280 * object property if the function called returns an object. Note that
12281 * function notation is recommended for use in `render` rather than
12282 * `data` as it is much simpler to use as a renderer.
12283 * * `null` - use the original data source for the row rather than plucking
12284 * data directly from it. This action has effects on two other
12285 * initialisation options:
12286 * * `defaultContent` - When null is given as the `data` option and
12287 * `defaultContent` is specified for the column, the value defined by
12288 * `defaultContent` will be used for the cell.
12289 * * `render` - When null is used for the `data` option and the `render`
12290 * option is specified for the column, the whole data source for the
12291 * row is used for the renderer.
12292 * * `function` - the function given will be executed whenever DataTables
12293 * needs to set or get the data for a cell in the column. The function
12294 * takes three parameters:
12295 * * Parameters:
12296 * * `{array|object}` The data source for the row
12297 * * `{string}` The type call data requested - this will be 'set' when
12298 * setting data or 'filter', 'display', 'type', 'sort' or undefined
12299 * when gathering data. Note that when `undefined` is given for the
12300 * type DataTables expects to get the raw data for the object back<
12301 * * `{*}` Data to set when the second parameter is 'set'.
12302 * * Return:
12303 * * The return value from the function is not required when 'set' is
12304 * the type of call, but otherwise the return is what will be used
12305 * for the data requested.
12306 *
12307 * Note that `data` is a getter and setter option. If you just require
12308 * formatting of data for output, you will likely want to use `render` which
12309 * is simply a getter and thus simpler to use.
12310 *
12311 * Note that prior to DataTables 1.9.2 `data` was called `mDataProp`. The
12312 * name change reflects the flexibility of this property and is consistent
12313 * with the naming of mRender. If 'mDataProp' is given, then it will still
12314 * be used by DataTables, as it automatically maps the old name to the new
12315 * if required.
12316 *
12317 * @type string|int|function|null
12318 * @default null <i>Use automatically calculated column index</i>
12319 *
12320 * @name DataTable.defaults.column.data
12321 * @dtopt Columns
12322 *
12323 * @example
12324 * // Read table data from objects
12325 * // JSON structure for each row:
12326 * // {
12327 * // "engine": {value},
12328 * // "browser": {value},
12329 * // "platform": {value},
12330 * // "version": {value},
12331 * // "grade": {value}
12332 * // }
12333 * $(document).ready( function() {
12334 * $('#example').dataTable( {
12335 * "ajaxSource": "sources/objects.txt",
12336 * "columns": [
12337 * { "data": "engine" },
12338 * { "data": "browser" },
12339 * { "data": "platform" },
12340 * { "data": "version" },
12341 * { "data": "grade" }
12342 * ]
12343 * } );
12344 * } );
12345 *
12346 * @example
12347 * // Read information from deeply nested objects
12348 * // JSON structure for each row:
12349 * // {
12350 * // "engine": {value},
12351 * // "browser": {value},
12352 * // "platform": {
12353 * // "inner": {value}
12354 * // },
12355 * // "details": [
12356 * // {value}, {value}
12357 * // ]
12358 * // }
12359 * $(document).ready( function() {
12360 * $('#example').dataTable( {
12361 * "ajaxSource": "sources/deep.txt",
12362 * "columns": [
12363 * { "data": "engine" },
12364 * { "data": "browser" },
12365 * { "data": "platform.inner" },
12366 * { "data": "platform.details.0" },
12367 * { "data": "platform.details.1" }
12368 * ]
12369 * } );
12370 * } );
12371 *
12372 * @example
12373 * // Using `data` as a function to provide different information for
12374 * // sorting, filtering and display. In this case, currency (price)
12375 * $(document).ready( function() {
12376 * $('#example').dataTable( {
12377 * "columnDefs": [ {
12378 * "targets": [ 0 ],
12379 * "data": function ( source, type, val ) {
12380 * if (type === 'set') {
12381 * source.price = val;
12382 * // Store the computed dislay and filter values for efficiency
12383 * source.price_display = val=="" ? "" : "$"+numberFormat(val);
12384 * source.price_filter = val=="" ? "" : "$"+numberFormat(val)+" "+val;
12385 * return;
12386 * }
12387 * else if (type === 'display') {
12388 * return source.price_display;
12389 * }
12390 * else if (type === 'filter') {
12391 * return source.price_filter;
12392 * }
12393 * // 'sort', 'type' and undefined all just use the integer
12394 * return source.price;
12395 * }
12396 * } ]
12397 * } );
12398 * } );
12399 *
12400 * @example
12401 * // Using default content
12402 * $(document).ready( function() {
12403 * $('#example').dataTable( {
12404 * "columnDefs": [ {
12405 * "targets": [ 0 ],
12406 * "data": null,
12407 * "defaultContent": "Click to edit"
12408 * } ]
12409 * } );
12410 * } );
12411 *
12412 * @example
12413 * // Using array notation - outputting a list from an array
12414 * $(document).ready( function() {
12415 * $('#example').dataTable( {
12416 * "columnDefs": [ {
12417 * "targets": [ 0 ],
12418 * "data": "name[, ]"
12419 * } ]
12420 * } );
12421 * } );
12422 *
12423 */
12424 "mData": null,
12425
12426
12427 /**
12428 * This property is the rendering partner to `data` and it is suggested that
12429 * when you want to manipulate data for display (including filtering,
12430 * sorting etc) without altering the underlying data for the table, use this
12431 * property. `render` can be considered to be the the read only companion to
12432 * `data` which is read / write (then as such more complex). Like `data`
12433 * this option can be given in a number of different ways to effect its
12434 * behaviour:
12435 *
12436 * * `integer` - treated as an array index for the data source. This is the
12437 * default that DataTables uses (incrementally increased for each column).
12438 * * `string` - read an object property from the data source. There are
12439 * three 'special' options that can be used in the string to alter how
12440 * DataTables reads the data from the source object:
12441 * * `.` - Dotted Javascript notation. Just as you use a `.` in
12442 * Javascript to read from nested objects, so to can the options
12443 * specified in `data`. For example: `browser.version` or
12444 * `browser.name`. If your object parameter name contains a period, use
12445 * `\\` to escape it - i.e. `first\\.name`.
12446 * * `[]` - Array notation. DataTables can automatically combine data
12447 * from and array source, joining the data with the characters provided
12448 * between the two brackets. For example: `name[, ]` would provide a
12449 * comma-space separated list from the source array. If no characters
12450 * are provided between the brackets, the original array source is
12451 * returned.
12452 * * `()` - Function notation. Adding `()` to the end of a parameter will
12453 * execute a function of the name given. For example: `browser()` for a
12454 * simple function on the data source, `browser.version()` for a
12455 * function in a nested property or even `browser().version` to get an
12456 * object property if the function called returns an object.
12457 * * `object` - use different data for the different data types requested by
12458 * DataTables ('filter', 'display', 'type' or 'sort'). The property names
12459 * of the object is the data type the property refers to and the value can
12460 * defined using an integer, string or function using the same rules as
12461 * `render` normally does. Note that an `_` option _must_ be specified.
12462 * This is the default value to use if you haven't specified a value for
12463 * the data type requested by DataTables.
12464 * * `function` - the function given will be executed whenever DataTables
12465 * needs to set or get the data for a cell in the column. The function
12466 * takes three parameters:
12467 * * Parameters:
12468 * * {array|object} The data source for the row (based on `data`)
12469 * * {string} The type call data requested - this will be 'filter',
12470 * 'display', 'type' or 'sort'.
12471 * * {array|object} The full data source for the row (not based on
12472 * `data`)
12473 * * Return:
12474 * * The return value from the function is what will be used for the
12475 * data requested.
12476 *
12477 * @type string|int|function|object|null
12478 * @default null Use the data source value.
12479 *
12480 * @name DataTable.defaults.column.render
12481 * @dtopt Columns
12482 *
12483 * @example
12484 * // Create a comma separated list from an array of objects
12485 * $(document).ready( function() {
12486 * $('#example').dataTable( {
12487 * "ajaxSource": "sources/deep.txt",
12488 * "columns": [
12489 * { "data": "engine" },
12490 * { "data": "browser" },
12491 * {
12492 * "data": "platform",
12493 * "render": "[, ].name"
12494 * }
12495 * ]
12496 * } );
12497 * } );
12498 *
12499 * @example
12500 * // Execute a function to obtain data
12501 * $(document).ready( function() {
12502 * $('#example').dataTable( {
12503 * "columnDefs": [ {
12504 * "targets": [ 0 ],
12505 * "data": null, // Use the full data source object for the renderer's source
12506 * "render": "browserName()"
12507 * } ]
12508 * } );
12509 * } );
12510 *
12511 * @example
12512 * // As an object, extracting different data for the different types
12513 * // This would be used with a data source such as:
12514 * // { "phone": 5552368, "phone_filter": "5552368 555-2368", "phone_display": "555-2368" }
12515 * // Here the `phone` integer is used for sorting and type detection, while `phone_filter`
12516 * // (which has both forms) is used for filtering for if a user inputs either format, while
12517 * // the formatted phone number is the one that is shown in the table.
12518 * $(document).ready( function() {
12519 * $('#example').dataTable( {
12520 * "columnDefs": [ {
12521 * "targets": [ 0 ],
12522 * "data": null, // Use the full data source object for the renderer's source
12523 * "render": {
12524 * "_": "phone",
12525 * "filter": "phone_filter",
12526 * "display": "phone_display"
12527 * }
12528 * } ]
12529 * } );
12530 * } );
12531 *
12532 * @example
12533 * // Use as a function to create a link from the data source
12534 * $(document).ready( function() {
12535 * $('#example').dataTable( {
12536 * "columnDefs": [ {
12537 * "targets": [ 0 ],
12538 * "data": "download_link",
12539 * "render": function ( data, type, full ) {
12540 * return '<a href="'+data+'">Download</a>';
12541 * }
12542 * } ]
12543 * } );
12544 * } );
12545 */
12546 "mRender": null,
12547
12548
12549 /**
12550 * Change the cell type created for the column - either TD cells or TH cells. This
12551 * can be useful as TH cells have semantic meaning in the table body, allowing them
12552 * to act as a header for a row (you may wish to add scope='row' to the TH elements).
12553 * @type string
12554 * @default td
12555 *
12556 * @name DataTable.defaults.column.cellType
12557 * @dtopt Columns
12558 *
12559 * @example
12560 * // Make the first column use TH cells
12561 * $(document).ready( function() {
12562 * $('#example').dataTable( {
12563 * "columnDefs": [ {
12564 * "targets": [ 0 ],
12565 * "cellType": "th"
12566 * } ]
12567 * } );
12568 * } );
12569 */
12570 "sCellType": "td",
12571
12572
12573 /**
12574 * Class to give to each cell in this column.
12575 * @type string
12576 * @default <i>Empty string</i>
12577 *
12578 * @name DataTable.defaults.column.class
12579 * @dtopt Columns
12580 *
12581 * @example
12582 * // Using `columnDefs`
12583 * $(document).ready( function() {
12584 * $('#example').dataTable( {
12585 * "columnDefs": [
12586 * { "class": "my_class", "targets": [ 0 ] }
12587 * ]
12588 * } );
12589 * } );
12590 *
12591 * @example
12592 * // Using `columns`
12593 * $(document).ready( function() {
12594 * $('#example').dataTable( {
12595 * "columns": [
12596 * { "class": "my_class" },
12597 * null,
12598 * null,
12599 * null,
12600 * null
12601 * ]
12602 * } );
12603 * } );
12604 */
12605 "sClass": "",
12606
12607 /**
12608 * When DataTables calculates the column widths to assign to each column,
12609 * it finds the longest string in each column and then constructs a
12610 * temporary table and reads the widths from that. The problem with this
12611 * is that "mmm" is much wider then "iiii", but the latter is a longer
12612 * string - thus the calculation can go wrong (doing it properly and putting
12613 * it into an DOM object and measuring that is horribly(!) slow). Thus as
12614 * a "work around" we provide this option. It will append its value to the
12615 * text that is found to be the longest string for the column - i.e. padding.
12616 * Generally you shouldn't need this!
12617 * @type string
12618 * @default <i>Empty string<i>
12619 *
12620 * @name DataTable.defaults.column.contentPadding
12621 * @dtopt Columns
12622 *
12623 * @example
12624 * // Using `columns`
12625 * $(document).ready( function() {
12626 * $('#example').dataTable( {
12627 * "columns": [
12628 * null,
12629 * null,
12630 * null,
12631 * {
12632 * "contentPadding": "mmm"
12633 * }
12634 * ]
12635 * } );
12636 * } );
12637 */
12638 "sContentPadding": "",
12639
12640
12641 /**
12642 * Allows a default value to be given for a column's data, and will be used
12643 * whenever a null data source is encountered (this can be because `data`
12644 * is set to null, or because the data source itself is null).
12645 * @type string
12646 * @default null
12647 *
12648 * @name DataTable.defaults.column.defaultContent
12649 * @dtopt Columns
12650 *
12651 * @example
12652 * // Using `columnDefs`
12653 * $(document).ready( function() {
12654 * $('#example').dataTable( {
12655 * "columnDefs": [
12656 * {
12657 * "data": null,
12658 * "defaultContent": "Edit",
12659 * "targets": [ -1 ]
12660 * }
12661 * ]
12662 * } );
12663 * } );
12664 *
12665 * @example
12666 * // Using `columns`
12667 * $(document).ready( function() {
12668 * $('#example').dataTable( {
12669 * "columns": [
12670 * null,
12671 * null,
12672 * null,
12673 * {
12674 * "data": null,
12675 * "defaultContent": "Edit"
12676 * }
12677 * ]
12678 * } );
12679 * } );
12680 */
12681 "sDefaultContent": null,
12682
12683
12684 /**
12685 * This parameter is only used in DataTables' server-side processing. It can
12686 * be exceptionally useful to know what columns are being displayed on the
12687 * client side, and to map these to database fields. When defined, the names
12688 * also allow DataTables to reorder information from the server if it comes
12689 * back in an unexpected order (i.e. if you switch your columns around on the
12690 * client-side, your server-side code does not also need updating).
12691 * @type string
12692 * @default <i>Empty string</i>
12693 *
12694 * @name DataTable.defaults.column.name
12695 * @dtopt Columns
12696 *
12697 * @example
12698 * // Using `columnDefs`
12699 * $(document).ready( function() {
12700 * $('#example').dataTable( {
12701 * "columnDefs": [
12702 * { "name": "engine", "targets": [ 0 ] },
12703 * { "name": "browser", "targets": [ 1 ] },
12704 * { "name": "platform", "targets": [ 2 ] },
12705 * { "name": "version", "targets": [ 3 ] },
12706 * { "name": "grade", "targets": [ 4 ] }
12707 * ]
12708 * } );
12709 * } );
12710 *
12711 * @example
12712 * // Using `columns`
12713 * $(document).ready( function() {
12714 * $('#example').dataTable( {
12715 * "columns": [
12716 * { "name": "engine" },
12717 * { "name": "browser" },
12718 * { "name": "platform" },
12719 * { "name": "version" },
12720 * { "name": "grade" }
12721 * ]
12722 * } );
12723 * } );
12724 */
12725 "sName": "",
12726
12727
12728 /**
12729 * Defines a data source type for the ordering which can be used to read
12730 * real-time information from the table (updating the internally cached
12731 * version) prior to ordering. This allows ordering to occur on user
12732 * editable elements such as form inputs.
12733 * @type string
12734 * @default std
12735 *
12736 * @name DataTable.defaults.column.orderDataType
12737 * @dtopt Columns
12738 *
12739 * @example
12740 * // Using `columnDefs`
12741 * $(document).ready( function() {
12742 * $('#example').dataTable( {
12743 * "columnDefs": [
12744 * { "orderDataType": "dom-text", "targets": [ 2, 3 ] },
12745 * { "type": "numeric", "targets": [ 3 ] },
12746 * { "orderDataType": "dom-select", "targets": [ 4 ] },
12747 * { "orderDataType": "dom-checkbox", "targets": [ 5 ] }
12748 * ]
12749 * } );
12750 * } );
12751 *
12752 * @example
12753 * // Using `columns`
12754 * $(document).ready( function() {
12755 * $('#example').dataTable( {
12756 * "columns": [
12757 * null,
12758 * null,
12759 * { "orderDataType": "dom-text" },
12760 * { "orderDataType": "dom-text", "type": "numeric" },
12761 * { "orderDataType": "dom-select" },
12762 * { "orderDataType": "dom-checkbox" }
12763 * ]
12764 * } );
12765 * } );
12766 */
12767 "sSortDataType": "std",
12768
12769
12770 /**
12771 * The title of this column.
12772 * @type string
12773 * @default null <i>Derived from the 'TH' value for this column in the
12774 * original HTML table.</i>
12775 *
12776 * @name DataTable.defaults.column.title
12777 * @dtopt Columns
12778 *
12779 * @example
12780 * // Using `columnDefs`
12781 * $(document).ready( function() {
12782 * $('#example').dataTable( {
12783 * "columnDefs": [
12784 * { "title": "My column title", "targets": [ 0 ] }
12785 * ]
12786 * } );
12787 * } );
12788 *
12789 * @example
12790 * // Using `columns`
12791 * $(document).ready( function() {
12792 * $('#example').dataTable( {
12793 * "columns": [
12794 * { "title": "My column title" },
12795 * null,
12796 * null,
12797 * null,
12798 * null
12799 * ]
12800 * } );
12801 * } );
12802 */
12803 "sTitle": null,
12804
12805
12806 /**
12807 * The type allows you to specify how the data for this column will be
12808 * ordered. Four types (string, numeric, date and html (which will strip
12809 * HTML tags before ordering)) are currently available. Note that only date
12810 * formats understood by Javascript's Date() object will be accepted as type
12811 * date. For example: "Mar 26, 2008 5:03 PM". May take the values: 'string',
12812 * 'numeric', 'date' or 'html' (by default). Further types can be adding
12813 * through plug-ins.
12814 * @type string
12815 * @default null <i>Auto-detected from raw data</i>
12816 *
12817 * @name DataTable.defaults.column.type
12818 * @dtopt Columns
12819 *
12820 * @example
12821 * // Using `columnDefs`
12822 * $(document).ready( function() {
12823 * $('#example').dataTable( {
12824 * "columnDefs": [
12825 * { "type": "html", "targets": [ 0 ] }
12826 * ]
12827 * } );
12828 * } );
12829 *
12830 * @example
12831 * // Using `columns`
12832 * $(document).ready( function() {
12833 * $('#example').dataTable( {
12834 * "columns": [
12835 * { "type": "html" },
12836 * null,
12837 * null,
12838 * null,
12839 * null
12840 * ]
12841 * } );
12842 * } );
12843 */
12844 "sType": null,
12845
12846
12847 /**
12848 * Defining the width of the column, this parameter may take any CSS value
12849 * (3em, 20px etc). DataTables applies 'smart' widths to columns which have not
12850 * been given a specific width through this interface ensuring that the table
12851 * remains readable.
12852 * @type string
12853 * @default null <i>Automatic</i>
12854 *
12855 * @name DataTable.defaults.column.width
12856 * @dtopt Columns
12857 *
12858 * @example
12859 * // Using `columnDefs`
12860 * $(document).ready( function() {
12861 * $('#example').dataTable( {
12862 * "columnDefs": [
12863 * { "width": "20%", "targets": [ 0 ] }
12864 * ]
12865 * } );
12866 * } );
12867 *
12868 * @example
12869 * // Using `columns`
12870 * $(document).ready( function() {
12871 * $('#example').dataTable( {
12872 * "columns": [
12873 * { "width": "20%" },
12874 * null,
12875 * null,
12876 * null,
12877 * null
12878 * ]
12879 * } );
12880 * } );
12881 */
12882 "sWidth": null
12883 };
12884
12885 _fnHungarianMap( DataTable.defaults.column );
12886
12887
12888
12889 /**
12890 * DataTables settings object - this holds all the information needed for a
12891 * given table, including configuration, data and current application of the
12892 * table options. DataTables does not have a single instance for each DataTable
12893 * with the settings attached to that instance, but rather instances of the
12894 * DataTable "class" are created on-the-fly as needed (typically by a
12895 * $().dataTable() call) and the settings object is then applied to that
12896 * instance.
12897 *
12898 * Note that this object is related to {@link DataTable.defaults} but this
12899 * one is the internal data store for DataTables's cache of columns. It should
12900 * NOT be manipulated outside of DataTables. Any configuration should be done
12901 * through the initialisation options.
12902 * @namespace
12903 * @todo Really should attach the settings object to individual instances so we
12904 * don't need to create new instances on each $().dataTable() call (if the
12905 * table already exists). It would also save passing oSettings around and
12906 * into every single function. However, this is a very significant
12907 * architecture change for DataTables and will almost certainly break
12908 * backwards compatibility with older installations. This is something that
12909 * will be done in 2.0.
12910 */
12911 DataTable.models.oSettings = {
12912 /**
12913 * Primary features of DataTables and their enablement state.
12914 * @namespace
12915 */
12916 "oFeatures": {
12917
12918 /**
12919 * Flag to say if DataTables should automatically try to calculate the
12920 * optimum table and columns widths (true) or not (false).
12921 * Note that this parameter will be set by the initialisation routine. To
12922 * set a default use {@link DataTable.defaults}.
12923 * @type boolean
12924 */
12925 "bAutoWidth": null,
12926
12927 /**
12928 * Delay the creation of TR and TD elements until they are actually
12929 * needed by a driven page draw. This can give a significant speed
12930 * increase for Ajax source and Javascript source data, but makes no
12931 * difference at all fro DOM and server-side processing tables.
12932 * Note that this parameter will be set by the initialisation routine. To
12933 * set a default use {@link DataTable.defaults}.
12934 * @type boolean
12935 */
12936 "bDeferRender": null,
12937
12938 /**
12939 * Enable filtering on the table or not. Note that if this is disabled
12940 * then there is no filtering at all on the table, including fnFilter.
12941 * To just remove the filtering input use sDom and remove the 'f' option.
12942 * Note that this parameter will be set by the initialisation routine. To
12943 * set a default use {@link DataTable.defaults}.
12944 * @type boolean
12945 */
12946 "bFilter": null,
12947
12948 /**
12949 * Table information element (the 'Showing x of y records' div) enable
12950 * flag.
12951 * Note that this parameter will be set by the initialisation routine. To
12952 * set a default use {@link DataTable.defaults}.
12953 * @type boolean
12954 */
12955 "bInfo": null,
12956
12957 /**
12958 * Present a user control allowing the end user to change the page size
12959 * when pagination is enabled.
12960 * Note that this parameter will be set by the initialisation routine. To
12961 * set a default use {@link DataTable.defaults}.
12962 * @type boolean
12963 */
12964 "bLengthChange": null,
12965
12966 /**
12967 * Pagination enabled or not. Note that if this is disabled then length
12968 * changing must also be disabled.
12969 * Note that this parameter will be set by the initialisation routine. To
12970 * set a default use {@link DataTable.defaults}.
12971 * @type boolean
12972 */
12973 "bPaginate": null,
12974
12975 /**
12976 * Processing indicator enable flag whenever DataTables is enacting a
12977 * user request - typically an Ajax request for server-side processing.
12978 * Note that this parameter will be set by the initialisation routine. To
12979 * set a default use {@link DataTable.defaults}.
12980 * @type boolean
12981 */
12982 "bProcessing": null,
12983
12984 /**
12985 * Server-side processing enabled flag - when enabled DataTables will
12986 * get all data from the server for every draw - there is no filtering,
12987 * sorting or paging done on the client-side.
12988 * Note that this parameter will be set by the initialisation routine. To
12989 * set a default use {@link DataTable.defaults}.
12990 * @type boolean
12991 */
12992 "bServerSide": null,
12993
12994 /**
12995 * Sorting enablement flag.
12996 * Note that this parameter will be set by the initialisation routine. To
12997 * set a default use {@link DataTable.defaults}.
12998 * @type boolean
12999 */
13000 "bSort": null,
13001
13002 /**
13003 * Multi-column sorting
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 "bSortMulti": null,
13009
13010 /**
13011 * Apply a class to the columns which are being sorted to provide a
13012 * visual highlight or not. This can slow things down when enabled since
13013 * there is a lot of DOM interaction.
13014 * Note that this parameter will be set by the initialisation routine. To
13015 * set a default use {@link DataTable.defaults}.
13016 * @type boolean
13017 */
13018 "bSortClasses": null,
13019
13020 /**
13021 * State saving enablement flag.
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 "bStateSave": null
13027 },
13028
13029
13030 /**
13031 * Scrolling settings for a table.
13032 * @namespace
13033 */
13034 "oScroll": {
13035 /**
13036 * When the table is shorter in height than sScrollY, collapse the
13037 * table container down to the height of the table (when true).
13038 * Note that this parameter will be set by the initialisation routine. To
13039 * set a default use {@link DataTable.defaults}.
13040 * @type boolean
13041 */
13042 "bCollapse": null,
13043
13044 /**
13045 * Width of the scrollbar for the web-browser's platform. Calculated
13046 * during table initialisation.
13047 * @type int
13048 * @default 0
13049 */
13050 "iBarWidth": 0,
13051
13052 /**
13053 * Viewport width for horizontal scrolling. Horizontal scrolling is
13054 * disabled if an empty string.
13055 * Note that this parameter will be set by the initialisation routine. To
13056 * set a default use {@link DataTable.defaults}.
13057 * @type string
13058 */
13059 "sX": null,
13060
13061 /**
13062 * Width to expand the table to when using x-scrolling. Typically you
13063 * should not need to use this.
13064 * Note that this parameter will be set by the initialisation routine. To
13065 * set a default use {@link DataTable.defaults}.
13066 * @type string
13067 * @deprecated
13068 */
13069 "sXInner": null,
13070
13071 /**
13072 * Viewport height for vertical scrolling. Vertical scrolling is disabled
13073 * if an empty string.
13074 * Note that this parameter will be set by the initialisation routine. To
13075 * set a default use {@link DataTable.defaults}.
13076 * @type string
13077 */
13078 "sY": null
13079 },
13080
13081 /**
13082 * Language information for the table.
13083 * @namespace
13084 * @extends DataTable.defaults.oLanguage
13085 */
13086 "oLanguage": {
13087 /**
13088 * Information callback function. See
13089 * {@link DataTable.defaults.fnInfoCallback}
13090 * @type function
13091 * @default null
13092 */
13093 "fnInfoCallback": null
13094 },
13095
13096 /**
13097 * Browser support parameters
13098 * @namespace
13099 */
13100 "oBrowser": {
13101 /**
13102 * Indicate if the browser incorrectly calculates width:100% inside a
13103 * scrolling element (IE6/7)
13104 * @type boolean
13105 * @default false
13106 */
13107 "bScrollOversize": false,
13108
13109 /**
13110 * Determine if the vertical scrollbar is on the right or left of the
13111 * scrolling container - needed for rtl language layout, although not
13112 * all browsers move the scrollbar (Safari).
13113 * @type boolean
13114 * @default false
13115 */
13116 "bScrollbarLeft": false,
13117
13118 /**
13119 * Flag for if `getBoundingClientRect` is fully supported or not
13120 * @type boolean
13121 * @default false
13122 */
13123 "bBounding": false,
13124
13125 /**
13126 * Browser scrollbar width
13127 * @type integer
13128 * @default 0
13129 */
13130 "barWidth": 0
13131 },
13132
13133
13134 "ajax": null,
13135
13136
13137 /**
13138 * Array referencing the nodes which are used for the features. The
13139 * parameters of this object match what is allowed by sDom - i.e.
13140 * <ul>
13141 * <li>'l' - Length changing</li>
13142 * <li>'f' - Filtering input</li>
13143 * <li>'t' - The table!</li>
13144 * <li>'i' - Information</li>
13145 * <li>'p' - Pagination</li>
13146 * <li>'r' - pRocessing</li>
13147 * </ul>
13148 * @type array
13149 * @default []
13150 */
13151 "aanFeatures": [],
13152
13153 /**
13154 * Store data information - see {@link DataTable.models.oRow} for detailed
13155 * information.
13156 * @type array
13157 * @default []
13158 */
13159 "aoData": [],
13160
13161 /**
13162 * Array of indexes which are in the current display (after filtering etc)
13163 * @type array
13164 * @default []
13165 */
13166 "aiDisplay": [],
13167
13168 /**
13169 * Array of indexes for display - no filtering
13170 * @type array
13171 * @default []
13172 */
13173 "aiDisplayMaster": [],
13174
13175 /**
13176 * Map of row ids to data indexes
13177 * @type object
13178 * @default {}
13179 */
13180 "aIds": {},
13181
13182 /**
13183 * Store information about each column that is in use
13184 * @type array
13185 * @default []
13186 */
13187 "aoColumns": [],
13188
13189 /**
13190 * Store information about the table's header
13191 * @type array
13192 * @default []
13193 */
13194 "aoHeader": [],
13195
13196 /**
13197 * Store information about the table's footer
13198 * @type array
13199 * @default []
13200 */
13201 "aoFooter": [],
13202
13203 /**
13204 * Store the applied global search information in case we want to force a
13205 * research or compare the old search to a new one.
13206 * Note that this parameter will be set by the initialisation routine. To
13207 * set a default use {@link DataTable.defaults}.
13208 * @namespace
13209 * @extends DataTable.models.oSearch
13210 */
13211 "oPreviousSearch": {},
13212
13213 /**
13214 * Store the applied search for each column - see
13215 * {@link DataTable.models.oSearch} for the format that is used for the
13216 * filtering information for each column.
13217 * @type array
13218 * @default []
13219 */
13220 "aoPreSearchCols": [],
13221
13222 /**
13223 * Sorting that is applied to the table. Note that the inner arrays are
13224 * used in the following manner:
13225 * <ul>
13226 * <li>Index 0 - column number</li>
13227 * <li>Index 1 - current sorting direction</li>
13228 * </ul>
13229 * Note that this parameter will be set by the initialisation routine. To
13230 * set a default use {@link DataTable.defaults}.
13231 * @type array
13232 * @todo These inner arrays should really be objects
13233 */
13234 "aaSorting": null,
13235
13236 /**
13237 * Sorting that is always applied to the table (i.e. prefixed in front of
13238 * aaSorting).
13239 * Note that this parameter will be set by the initialisation routine. To
13240 * set a default use {@link DataTable.defaults}.
13241 * @type array
13242 * @default []
13243 */
13244 "aaSortingFixed": [],
13245
13246 /**
13247 * Classes to use for the striping of a table.
13248 * Note that this parameter will be set by the initialisation routine. To
13249 * set a default use {@link DataTable.defaults}.
13250 * @type array
13251 * @default []
13252 */
13253 "asStripeClasses": null,
13254
13255 /**
13256 * If restoring a table - we should restore its striping classes as well
13257 * @type array
13258 * @default []
13259 */
13260 "asDestroyStripes": [],
13261
13262 /**
13263 * If restoring a table - we should restore its width
13264 * @type int
13265 * @default 0
13266 */
13267 "sDestroyWidth": 0,
13268
13269 /**
13270 * Callback functions array for every time a row is inserted (i.e. on a draw).
13271 * @type array
13272 * @default []
13273 */
13274 "aoRowCallback": [],
13275
13276 /**
13277 * Callback functions for the header on each draw.
13278 * @type array
13279 * @default []
13280 */
13281 "aoHeaderCallback": [],
13282
13283 /**
13284 * Callback function for the footer on each draw.
13285 * @type array
13286 * @default []
13287 */
13288 "aoFooterCallback": [],
13289
13290 /**
13291 * Array of callback functions for draw callback functions
13292 * @type array
13293 * @default []
13294 */
13295 "aoDrawCallback": [],
13296
13297 /**
13298 * Array of callback functions for row created function
13299 * @type array
13300 * @default []
13301 */
13302 "aoRowCreatedCallback": [],
13303
13304 /**
13305 * Callback functions for just before the table is redrawn. A return of
13306 * false will be used to cancel the draw.
13307 * @type array
13308 * @default []
13309 */
13310 "aoPreDrawCallback": [],
13311
13312 /**
13313 * Callback functions for when the table has been initialised.
13314 * @type array
13315 * @default []
13316 */
13317 "aoInitComplete": [],
13318
13319
13320 /**
13321 * Callbacks for modifying the settings to be stored for state saving, prior to
13322 * saving state.
13323 * @type array
13324 * @default []
13325 */
13326 "aoStateSaveParams": [],
13327
13328 /**
13329 * Callbacks for modifying the settings that have been stored for state saving
13330 * prior to using the stored values to restore the state.
13331 * @type array
13332 * @default []
13333 */
13334 "aoStateLoadParams": [],
13335
13336 /**
13337 * Callbacks for operating on the settings object once the saved state has been
13338 * loaded
13339 * @type array
13340 * @default []
13341 */
13342 "aoStateLoaded": [],
13343
13344 /**
13345 * Cache the table ID for quick access
13346 * @type string
13347 * @default <i>Empty string</i>
13348 */
13349 "sTableId": "",
13350
13351 /**
13352 * The TABLE node for the main table
13353 * @type node
13354 * @default null
13355 */
13356 "nTable": null,
13357
13358 /**
13359 * Permanent ref to the thead element
13360 * @type node
13361 * @default null
13362 */
13363 "nTHead": null,
13364
13365 /**
13366 * Permanent ref to the tfoot element - if it exists
13367 * @type node
13368 * @default null
13369 */
13370 "nTFoot": null,
13371
13372 /**
13373 * Permanent ref to the tbody element
13374 * @type node
13375 * @default null
13376 */
13377 "nTBody": null,
13378
13379 /**
13380 * Cache the wrapper node (contains all DataTables controlled elements)
13381 * @type node
13382 * @default null
13383 */
13384 "nTableWrapper": null,
13385
13386 /**
13387 * Indicate if when using server-side processing the loading of data
13388 * should be deferred until the second draw.
13389 * Note that this parameter will be set by the initialisation routine. To
13390 * set a default use {@link DataTable.defaults}.
13391 * @type boolean
13392 * @default false
13393 */
13394 "bDeferLoading": false,
13395
13396 /**
13397 * Indicate if all required information has been read in
13398 * @type boolean
13399 * @default false
13400 */
13401 "bInitialised": false,
13402
13403 /**
13404 * Information about open rows. Each object in the array has the parameters
13405 * 'nTr' and 'nParent'
13406 * @type array
13407 * @default []
13408 */
13409 "aoOpenRows": [],
13410
13411 /**
13412 * Dictate the positioning of DataTables' control elements - see
13413 * {@link DataTable.model.oInit.sDom}.
13414 * Note that this parameter will be set by the initialisation routine. To
13415 * set a default use {@link DataTable.defaults}.
13416 * @type string
13417 * @default null
13418 */
13419 "sDom": null,
13420
13421 /**
13422 * Search delay (in mS)
13423 * @type integer
13424 * @default null
13425 */
13426 "searchDelay": null,
13427
13428 /**
13429 * Which type of pagination should be used.
13430 * Note that this parameter will be set by the initialisation routine. To
13431 * set a default use {@link DataTable.defaults}.
13432 * @type string
13433 * @default two_button
13434 */
13435 "sPaginationType": "two_button",
13436
13437 /**
13438 * The state duration (for `stateSave`) in seconds.
13439 * Note that this parameter will be set by the initialisation routine. To
13440 * set a default use {@link DataTable.defaults}.
13441 * @type int
13442 * @default 0
13443 */
13444 "iStateDuration": 0,
13445
13446 /**
13447 * Array of callback functions for state saving. Each array element is an
13448 * object with the following parameters:
13449 * <ul>
13450 * <li>function:fn - function to call. Takes two parameters, oSettings
13451 * and the JSON string to save that has been thus far created. Returns
13452 * a JSON string to be inserted into a json object
13453 * (i.e. '"param": [ 0, 1, 2]')</li>
13454 * <li>string:sName - name of callback</li>
13455 * </ul>
13456 * @type array
13457 * @default []
13458 */
13459 "aoStateSave": [],
13460
13461 /**
13462 * Array of callback functions for state loading. Each array element is an
13463 * object with the following parameters:
13464 * <ul>
13465 * <li>function:fn - function to call. Takes two parameters, oSettings
13466 * and the object stored. May return false to cancel state loading</li>
13467 * <li>string:sName - name of callback</li>
13468 * </ul>
13469 * @type array
13470 * @default []
13471 */
13472 "aoStateLoad": [],
13473
13474 /**
13475 * State that was saved. Useful for back reference
13476 * @type object
13477 * @default null
13478 */
13479 "oSavedState": null,
13480
13481 /**
13482 * State that was loaded. Useful for back reference
13483 * @type object
13484 * @default null
13485 */
13486 "oLoadedState": null,
13487
13488 /**
13489 * Source url for AJAX data for the table.
13490 * Note that this parameter will be set by the initialisation routine. To
13491 * set a default use {@link DataTable.defaults}.
13492 * @type string
13493 * @default null
13494 */
13495 "sAjaxSource": null,
13496
13497 /**
13498 * Property from a given object from which to read the table data from. This
13499 * can be an empty string (when not server-side processing), in which case
13500 * it is assumed an an array is given directly.
13501 * Note that this parameter will be set by the initialisation routine. To
13502 * set a default use {@link DataTable.defaults}.
13503 * @type string
13504 */
13505 "sAjaxDataProp": null,
13506
13507 /**
13508 * Note if draw should be blocked while getting data
13509 * @type boolean
13510 * @default true
13511 */
13512 "bAjaxDataGet": true,
13513
13514 /**
13515 * The last jQuery XHR object that was used for server-side data gathering.
13516 * This can be used for working with the XHR information in one of the
13517 * callbacks
13518 * @type object
13519 * @default null
13520 */
13521 "jqXHR": null,
13522
13523 /**
13524 * JSON returned from the server in the last Ajax request
13525 * @type object
13526 * @default undefined
13527 */
13528 "json": undefined,
13529
13530 /**
13531 * Data submitted as part of the last Ajax request
13532 * @type object
13533 * @default undefined
13534 */
13535 "oAjaxData": undefined,
13536
13537 /**
13538 * Function to get the server-side data.
13539 * Note that this parameter will be set by the initialisation routine. To
13540 * set a default use {@link DataTable.defaults}.
13541 * @type function
13542 */
13543 "fnServerData": null,
13544
13545 /**
13546 * Functions which are called prior to sending an Ajax request so extra
13547 * parameters can easily be sent to the server
13548 * @type array
13549 * @default []
13550 */
13551 "aoServerParams": [],
13552
13553 /**
13554 * Send the XHR HTTP method - GET or POST (could be PUT or DELETE if
13555 * required).
13556 * Note that this parameter will be set by the initialisation routine. To
13557 * set a default use {@link DataTable.defaults}.
13558 * @type string
13559 */
13560 "sServerMethod": null,
13561
13562 /**
13563 * Format numbers for display.
13564 * Note that this parameter will be set by the initialisation routine. To
13565 * set a default use {@link DataTable.defaults}.
13566 * @type function
13567 */
13568 "fnFormatNumber": null,
13569
13570 /**
13571 * List of options that can be used for the user selectable length menu.
13572 * Note that this parameter will be set by the initialisation routine. To
13573 * set a default use {@link DataTable.defaults}.
13574 * @type array
13575 * @default []
13576 */
13577 "aLengthMenu": null,
13578
13579 /**
13580 * Counter for the draws that the table does. Also used as a tracker for
13581 * server-side processing
13582 * @type int
13583 * @default 0
13584 */
13585 "iDraw": 0,
13586
13587 /**
13588 * Indicate if a redraw is being done - useful for Ajax
13589 * @type boolean
13590 * @default false
13591 */
13592 "bDrawing": false,
13593
13594 /**
13595 * Draw index (iDraw) of the last error when parsing the returned data
13596 * @type int
13597 * @default -1
13598 */
13599 "iDrawError": -1,
13600
13601 /**
13602 * Paging display length
13603 * @type int
13604 * @default 10
13605 */
13606 "_iDisplayLength": 10,
13607
13608 /**
13609 * Paging start point - aiDisplay index
13610 * @type int
13611 * @default 0
13612 */
13613 "_iDisplayStart": 0,
13614
13615 /**
13616 * Server-side processing - number of records in the result set
13617 * (i.e. before filtering), Use fnRecordsTotal rather than
13618 * this property to get the value of the number of records, regardless of
13619 * the server-side processing setting.
13620 * @type int
13621 * @default 0
13622 * @private
13623 */
13624 "_iRecordsTotal": 0,
13625
13626 /**
13627 * Server-side processing - number of records in the current display set
13628 * (i.e. after filtering). Use fnRecordsDisplay rather than
13629 * this property to get the value of the number of records, regardless of
13630 * the server-side processing setting.
13631 * @type boolean
13632 * @default 0
13633 * @private
13634 */
13635 "_iRecordsDisplay": 0,
13636
13637 /**
13638 * The classes to use for the table
13639 * @type object
13640 * @default {}
13641 */
13642 "oClasses": {},
13643
13644 /**
13645 * Flag attached to the settings object so you can check in the draw
13646 * callback if filtering has been done in the draw. Deprecated in favour of
13647 * events.
13648 * @type boolean
13649 * @default false
13650 * @deprecated
13651 */
13652 "bFiltered": false,
13653
13654 /**
13655 * Flag attached to the settings object so you can check in the draw
13656 * callback if sorting has been done in the draw. Deprecated in favour of
13657 * events.
13658 * @type boolean
13659 * @default false
13660 * @deprecated
13661 */
13662 "bSorted": false,
13663
13664 /**
13665 * Indicate that if multiple rows are in the header and there is more than
13666 * one unique cell per column, if the top one (true) or bottom one (false)
13667 * should be used for sorting / title by DataTables.
13668 * Note that this parameter will be set by the initialisation routine. To
13669 * set a default use {@link DataTable.defaults}.
13670 * @type boolean
13671 */
13672 "bSortCellsTop": null,
13673
13674 /**
13675 * Initialisation object that is used for the table
13676 * @type object
13677 * @default null
13678 */
13679 "oInit": null,
13680
13681 /**
13682 * Destroy callback functions - for plug-ins to attach themselves to the
13683 * destroy so they can clean up markup and events.
13684 * @type array
13685 * @default []
13686 */
13687 "aoDestroyCallback": [],
13688
13689
13690 /**
13691 * Get the number of records in the current record set, before filtering
13692 * @type function
13693 */
13694 "fnRecordsTotal": function ()
13695 {
13696 return _fnDataSource( this ) == 'ssp' ?
13697 this._iRecordsTotal * 1 :
13698 this.aiDisplayMaster.length;
13699 },
13700
13701 /**
13702 * Get the number of records in the current record set, after filtering
13703 * @type function
13704 */
13705 "fnRecordsDisplay": function ()
13706 {
13707 return _fnDataSource( this ) == 'ssp' ?
13708 this._iRecordsDisplay * 1 :
13709 this.aiDisplay.length;
13710 },
13711
13712 /**
13713 * Get the display end point - aiDisplay index
13714 * @type function
13715 */
13716 "fnDisplayEnd": function ()
13717 {
13718 var
13719 len = this._iDisplayLength,
13720 start = this._iDisplayStart,
13721 calc = start + len,
13722 records = this.aiDisplay.length,
13723 features = this.oFeatures,
13724 paginate = features.bPaginate;
13725
13726 if ( features.bServerSide ) {
13727 return paginate === false || len === -1 ?
13728 start + records :
13729 Math.min( start+len, this._iRecordsDisplay );
13730 }
13731 else {
13732 return ! paginate || calc>records || len===-1 ?
13733 records :
13734 calc;
13735 }
13736 },
13737
13738 /**
13739 * The DataTables object for this table
13740 * @type object
13741 * @default null
13742 */
13743 "oInstance": null,
13744
13745 /**
13746 * Unique identifier for each instance of the DataTables object. If there
13747 * is an ID on the table node, then it takes that value, otherwise an
13748 * incrementing internal counter is used.
13749 * @type string
13750 * @default null
13751 */
13752 "sInstance": null,
13753
13754 /**
13755 * tabindex attribute value that is added to DataTables control elements, allowing
13756 * keyboard navigation of the table and its controls.
13757 */
13758 "iTabIndex": 0,
13759
13760 /**
13761 * DIV container for the footer scrolling table if scrolling
13762 */
13763 "nScrollHead": null,
13764
13765 /**
13766 * DIV container for the footer scrolling table if scrolling
13767 */
13768 "nScrollFoot": null,
13769
13770 /**
13771 * Last applied sort
13772 * @type array
13773 * @default []
13774 */
13775 "aLastSort": [],
13776
13777 /**
13778 * Stored plug-in instances
13779 * @type object
13780 * @default {}
13781 */
13782 "oPlugins": {},
13783
13784 /**
13785 * Function used to get a row's id from the row's data
13786 * @type function
13787 * @default null
13788 */
13789 "rowIdFn": null,
13790
13791 /**
13792 * Data location where to store a row's id
13793 * @type string
13794 * @default null
13795 */
13796 "rowId": null
13797 };
13798
13799 /**
13800 * Extension object for DataTables that is used to provide all extension
13801 * options.
13802 *
13803 * Note that the `DataTable.ext` object is available through
13804 * `jQuery.fn.dataTable.ext` where it may be accessed and manipulated. It is
13805 * also aliased to `jQuery.fn.dataTableExt` for historic reasons.
13806 * @namespace
13807 * @extends DataTable.models.ext
13808 */
13809
13810
13811 /**
13812 * DataTables extensions
13813 *
13814 * This namespace acts as a collection area for plug-ins that can be used to
13815 * extend DataTables capabilities. Indeed many of the build in methods
13816 * use this method to provide their own capabilities (sorting methods for
13817 * example).
13818 *
13819 * Note that this namespace is aliased to `jQuery.fn.dataTableExt` for legacy
13820 * reasons
13821 *
13822 * @namespace
13823 */
13824 DataTable.ext = _ext = {
13825 /**
13826 * Buttons. For use with the Buttons extension for DataTables. This is
13827 * defined here so other extensions can define buttons regardless of load
13828 * order. It is _not_ used by DataTables core.
13829 *
13830 * @type object
13831 * @default {}
13832 */
13833 buttons: {},
13834
13835
13836 /**
13837 * Element class names
13838 *
13839 * @type object
13840 * @default {}
13841 */
13842 classes: {},
13843
13844
13845 /**
13846 * DataTables build type (expanded by the download builder)
13847 *
13848 * @type string
13849 */
13850 build:"dt/dt-1.10.16",
13851
13852
13853 /**
13854 * Error reporting.
13855 *
13856 * How should DataTables report an error. Can take the value 'alert',
13857 * 'throw', 'none' or a function.
13858 *
13859 * @type string|function
13860 * @default alert
13861 */
13862 errMode: "alert",
13863
13864
13865 /**
13866 * Feature plug-ins.
13867 *
13868 * This is an array of objects which describe the feature plug-ins that are
13869 * available to DataTables. These feature plug-ins are then available for
13870 * use through the `dom` initialisation option.
13871 *
13872 * Each feature plug-in is described by an object which must have the
13873 * following properties:
13874 *
13875 * * `fnInit` - function that is used to initialise the plug-in,
13876 * * `cFeature` - a character so the feature can be enabled by the `dom`
13877 * instillation option. This is case sensitive.
13878 *
13879 * The `fnInit` function has the following input parameters:
13880 *
13881 * 1. `{object}` DataTables settings object: see
13882 * {@link DataTable.models.oSettings}
13883 *
13884 * And the following return is expected:
13885 *
13886 * * {node|null} The element which contains your feature. Note that the
13887 * return may also be void if your plug-in does not require to inject any
13888 * DOM elements into DataTables control (`dom`) - for example this might
13889 * be useful when developing a plug-in which allows table control via
13890 * keyboard entry
13891 *
13892 * @type array
13893 *
13894 * @example
13895 * $.fn.dataTable.ext.features.push( {
13896 * "fnInit": function( oSettings ) {
13897 * return new TableTools( { "oDTSettings": oSettings } );
13898 * },
13899 * "cFeature": "T"
13900 * } );
13901 */
13902 feature: [],
13903
13904
13905 /**
13906 * Row searching.
13907 *
13908 * This method of searching is complimentary to the default type based
13909 * searching, and a lot more comprehensive as it allows you complete control
13910 * over the searching logic. Each element in this array is a function
13911 * (parameters described below) that is called for every row in the table,
13912 * and your logic decides if it should be included in the searching data set
13913 * or not.
13914 *
13915 * Searching functions have the following input parameters:
13916 *
13917 * 1. `{object}` DataTables settings object: see
13918 * {@link DataTable.models.oSettings}
13919 * 2. `{array|object}` Data for the row to be processed (same as the
13920 * original format that was passed in as the data source, or an array
13921 * from a DOM data source
13922 * 3. `{int}` Row index ({@link DataTable.models.oSettings.aoData}), which
13923 * can be useful to retrieve the `TR` element if you need DOM interaction.
13924 *
13925 * And the following return is expected:
13926 *
13927 * * {boolean} Include the row in the searched result set (true) or not
13928 * (false)
13929 *
13930 * Note that as with the main search ability in DataTables, technically this
13931 * is "filtering", since it is subtractive. However, for consistency in
13932 * naming we call it searching here.
13933 *
13934 * @type array
13935 * @default []
13936 *
13937 * @example
13938 * // The following example shows custom search being applied to the
13939 * // fourth column (i.e. the data[3] index) based on two input values
13940 * // from the end-user, matching the data in a certain range.
13941 * $.fn.dataTable.ext.search.push(
13942 * function( settings, data, dataIndex ) {
13943 * var min = document.getElementById('min').value * 1;
13944 * var max = document.getElementById('max').value * 1;
13945 * var version = data[3] == "-" ? 0 : data[3]*1;
13946 *
13947 * if ( min == "" && max == "" ) {
13948 * return true;
13949 * }
13950 * else if ( min == "" && version < max ) {
13951 * return true;
13952 * }
13953 * else if ( min < version && "" == max ) {
13954 * return true;
13955 * }
13956 * else if ( min < version && version < max ) {
13957 * return true;
13958 * }
13959 * return false;
13960 * }
13961 * );
13962 */
13963 search: [],
13964
13965
13966 /**
13967 * Selector extensions
13968 *
13969 * The `selector` option can be used to extend the options available for the
13970 * selector modifier options (`selector-modifier` object data type) that
13971 * each of the three built in selector types offer (row, column and cell +
13972 * their plural counterparts). For example the Select extension uses this
13973 * mechanism to provide an option to select only rows, columns and cells
13974 * that have been marked as selected by the end user (`{selected: true}`),
13975 * which can be used in conjunction with the existing built in selector
13976 * options.
13977 *
13978 * Each property is an array to which functions can be pushed. The functions
13979 * take three attributes:
13980 *
13981 * * Settings object for the host table
13982 * * Options object (`selector-modifier` object type)
13983 * * Array of selected item indexes
13984 *
13985 * The return is an array of the resulting item indexes after the custom
13986 * selector has been applied.
13987 *
13988 * @type object
13989 */
13990 selector: {
13991 cell: [],
13992 column: [],
13993 row: []
13994 },
13995
13996
13997 /**
13998 * Internal functions, exposed for used in plug-ins.
13999 *
14000 * Please note that you should not need to use the internal methods for
14001 * anything other than a plug-in (and even then, try to avoid if possible).
14002 * The internal function may change between releases.
14003 *
14004 * @type object
14005 * @default {}
14006 */
14007 internal: {},
14008
14009
14010 /**
14011 * Legacy configuration options. Enable and disable legacy options that
14012 * are available in DataTables.
14013 *
14014 * @type object
14015 */
14016 legacy: {
14017 /**
14018 * Enable / disable DataTables 1.9 compatible server-side processing
14019 * requests
14020 *
14021 * @type boolean
14022 * @default null
14023 */
14024 ajax: null
14025 },
14026
14027
14028 /**
14029 * Pagination plug-in methods.
14030 *
14031 * Each entry in this object is a function and defines which buttons should
14032 * be shown by the pagination rendering method that is used for the table:
14033 * {@link DataTable.ext.renderer.pageButton}. The renderer addresses how the
14034 * buttons are displayed in the document, while the functions here tell it
14035 * what buttons to display. This is done by returning an array of button
14036 * descriptions (what each button will do).
14037 *
14038 * Pagination types (the four built in options and any additional plug-in
14039 * options defined here) can be used through the `paginationType`
14040 * initialisation parameter.
14041 *
14042 * The functions defined take two parameters:
14043 *
14044 * 1. `{int} page` The current page index
14045 * 2. `{int} pages` The number of pages in the table
14046 *
14047 * Each function is expected to return an array where each element of the
14048 * array can be one of:
14049 *
14050 * * `first` - Jump to first page when activated
14051 * * `last` - Jump to last page when activated
14052 * * `previous` - Show previous page when activated
14053 * * `next` - Show next page when activated
14054 * * `{int}` - Show page of the index given
14055 * * `{array}` - A nested array containing the above elements to add a
14056 * containing 'DIV' element (might be useful for styling).
14057 *
14058 * Note that DataTables v1.9- used this object slightly differently whereby
14059 * an object with two functions would be defined for each plug-in. That
14060 * ability is still supported by DataTables 1.10+ to provide backwards
14061 * compatibility, but this option of use is now decremented and no longer
14062 * documented in DataTables 1.10+.
14063 *
14064 * @type object
14065 * @default {}
14066 *
14067 * @example
14068 * // Show previous, next and current page buttons only
14069 * $.fn.dataTableExt.oPagination.current = function ( page, pages ) {
14070 * return [ 'previous', page, 'next' ];
14071 * };
14072 */
14073 pager: {},
14074
14075
14076 renderer: {
14077 pageButton: {},
14078 header: {}
14079 },
14080
14081
14082 /**
14083 * Ordering plug-ins - custom data source
14084 *
14085 * The extension options for ordering of data available here is complimentary
14086 * to the default type based ordering that DataTables typically uses. It
14087 * allows much greater control over the the data that is being used to
14088 * order a column, but is necessarily therefore more complex.
14089 *
14090 * This type of ordering is useful if you want to do ordering based on data
14091 * live from the DOM (for example the contents of an 'input' element) rather
14092 * than just the static string that DataTables knows of.
14093 *
14094 * The way these plug-ins work is that you create an array of the values you
14095 * wish to be ordering for the column in question and then return that
14096 * array. The data in the array much be in the index order of the rows in
14097 * the table (not the currently ordering order!). Which order data gathering
14098 * function is run here depends on the `dt-init columns.orderDataType`
14099 * parameter that is used for the column (if any).
14100 *
14101 * The functions defined take two parameters:
14102 *
14103 * 1. `{object}` DataTables settings object: see
14104 * {@link DataTable.models.oSettings}
14105 * 2. `{int}` Target column index
14106 *
14107 * Each function is expected to return an array:
14108 *
14109 * * `{array}` Data for the column to be ordering upon
14110 *
14111 * @type array
14112 *
14113 * @example
14114 * // Ordering using `input` node values
14115 * $.fn.dataTable.ext.order['dom-text'] = function ( settings, col )
14116 * {
14117 * return this.api().column( col, {order:'index'} ).nodes().map( function ( td, i ) {
14118 * return $('input', td).val();
14119 * } );
14120 * }
14121 */
14122 order: {},
14123
14124
14125 /**
14126 * Type based plug-ins.
14127 *
14128 * Each column in DataTables has a type assigned to it, either by automatic
14129 * detection or by direct assignment using the `type` option for the column.
14130 * The type of a column will effect how it is ordering and search (plug-ins
14131 * can also make use of the column type if required).
14132 *
14133 * @namespace
14134 */
14135 type: {
14136 /**
14137 * Type detection functions.
14138 *
14139 * The functions defined in this object are used to automatically detect
14140 * a column's type, making initialisation of DataTables super easy, even
14141 * when complex data is in the table.
14142 *
14143 * The functions defined take two parameters:
14144 *
14145 * 1. `{*}` Data from the column cell to be analysed
14146 * 2. `{settings}` DataTables settings object. This can be used to
14147 * perform context specific type detection - for example detection
14148 * based on language settings such as using a comma for a decimal
14149 * place. Generally speaking the options from the settings will not
14150 * be required
14151 *
14152 * Each function is expected to return:
14153 *
14154 * * `{string|null}` Data type detected, or null if unknown (and thus
14155 * pass it on to the other type detection functions.
14156 *
14157 * @type array
14158 *
14159 * @example
14160 * // Currency type detection plug-in:
14161 * $.fn.dataTable.ext.type.detect.push(
14162 * function ( data, settings ) {
14163 * // Check the numeric part
14164 * if ( ! $.isNumeric( data.substring(1) ) ) {
14165 * return null;
14166 * }
14167 *
14168 * // Check prefixed by currency
14169 * if ( data.charAt(0) == '$' || data.charAt(0) == '&pound;' ) {
14170 * return 'currency';
14171 * }
14172 * return null;
14173 * }
14174 * );
14175 */
14176 detect: [],
14177
14178
14179 /**
14180 * Type based search formatting.
14181 *
14182 * The type based searching functions can be used to pre-format the
14183 * data to be search on. For example, it can be used to strip HTML
14184 * tags or to de-format telephone numbers for numeric only searching.
14185 *
14186 * Note that is a search is not defined for a column of a given type,
14187 * no search formatting will be performed.
14188 *
14189 * Pre-processing of searching data plug-ins - When you assign the sType
14190 * for a column (or have it automatically detected for you by DataTables
14191 * or a type detection plug-in), you will typically be using this for
14192 * custom sorting, but it can also be used to provide custom searching
14193 * by allowing you to pre-processing the data and returning the data in
14194 * the format that should be searched upon. This is done by adding
14195 * functions this object with a parameter name which matches the sType
14196 * for that target column. This is the corollary of <i>afnSortData</i>
14197 * for searching data.
14198 *
14199 * The functions defined take a single parameter:
14200 *
14201 * 1. `{*}` Data from the column cell to be prepared for searching
14202 *
14203 * Each function is expected to return:
14204 *
14205 * * `{string|null}` Formatted string that will be used for the searching.
14206 *
14207 * @type object
14208 * @default {}
14209 *
14210 * @example
14211 * $.fn.dataTable.ext.type.search['title-numeric'] = function ( d ) {
14212 * return d.replace(/\n/g," ").replace( /<.*?>/g, "" );
14213 * }
14214 */
14215 search: {},
14216
14217
14218 /**
14219 * Type based ordering.
14220 *
14221 * The column type tells DataTables what ordering to apply to the table
14222 * when a column is sorted upon. The order for each type that is defined,
14223 * is defined by the functions available in this object.
14224 *
14225 * Each ordering option can be described by three properties added to
14226 * this object:
14227 *
14228 * * `{type}-pre` - Pre-formatting function
14229 * * `{type}-asc` - Ascending order function
14230 * * `{type}-desc` - Descending order function
14231 *
14232 * All three can be used together, only `{type}-pre` or only
14233 * `{type}-asc` and `{type}-desc` together. It is generally recommended
14234 * that only `{type}-pre` is used, as this provides the optimal
14235 * implementation in terms of speed, although the others are provided
14236 * for compatibility with existing Javascript sort functions.
14237 *
14238 * `{type}-pre`: Functions defined take a single parameter:
14239 *
14240 * 1. `{*}` Data from the column cell to be prepared for ordering
14241 *
14242 * And return:
14243 *
14244 * * `{*}` Data to be sorted upon
14245 *
14246 * `{type}-asc` and `{type}-desc`: Functions are typical Javascript sort
14247 * functions, taking two parameters:
14248 *
14249 * 1. `{*}` Data to compare to the second parameter
14250 * 2. `{*}` Data to compare to the first parameter
14251 *
14252 * And returning:
14253 *
14254 * * `{*}` Ordering match: <0 if first parameter should be sorted lower
14255 * than the second parameter, ===0 if the two parameters are equal and
14256 * >0 if the first parameter should be sorted height than the second
14257 * parameter.
14258 *
14259 * @type object
14260 * @default {}
14261 *
14262 * @example
14263 * // Numeric ordering of formatted numbers with a pre-formatter
14264 * $.extend( $.fn.dataTable.ext.type.order, {
14265 * "string-pre": function(x) {
14266 * a = (a === "-" || a === "") ? 0 : a.replace( /[^\d\-\.]/g, "" );
14267 * return parseFloat( a );
14268 * }
14269 * } );
14270 *
14271 * @example
14272 * // Case-sensitive string ordering, with no pre-formatting method
14273 * $.extend( $.fn.dataTable.ext.order, {
14274 * "string-case-asc": function(x,y) {
14275 * return ((x < y) ? -1 : ((x > y) ? 1 : 0));
14276 * },
14277 * "string-case-desc": function(x,y) {
14278 * return ((x < y) ? 1 : ((x > y) ? -1 : 0));
14279 * }
14280 * } );
14281 */
14282 order: {}
14283 },
14284
14285 /**
14286 * Unique DataTables instance counter
14287 *
14288 * @type int
14289 * @private
14290 */
14291 _unique: 0,
14292
14293
14294 //
14295 // Depreciated
14296 // The following properties are retained for backwards compatiblity only.
14297 // The should not be used in new projects and will be removed in a future
14298 // version
14299 //
14300
14301 /**
14302 * Version check function.
14303 * @type function
14304 * @depreciated Since 1.10
14305 */
14306 fnVersionCheck: DataTable.fnVersionCheck,
14307
14308
14309 /**
14310 * Index for what 'this' index API functions should use
14311 * @type int
14312 * @deprecated Since v1.10
14313 */
14314 iApiIndex: 0,
14315
14316
14317 /**
14318 * jQuery UI class container
14319 * @type object
14320 * @deprecated Since v1.10
14321 */
14322 oJUIClasses: {},
14323
14324
14325 /**
14326 * Software version
14327 * @type string
14328 * @deprecated Since v1.10
14329 */
14330 sVersion: DataTable.version
14331 };
14332
14333
14334 //
14335 // Backwards compatibility. Alias to pre 1.10 Hungarian notation counter parts
14336 //
14337 $.extend( _ext, {
14338 afnFiltering: _ext.search,
14339 aTypes: _ext.type.detect,
14340 ofnSearch: _ext.type.search,
14341 oSort: _ext.type.order,
14342 afnSortData: _ext.order,
14343 aoFeatures: _ext.feature,
14344 oApi: _ext.internal,
14345 oStdClasses: _ext.classes,
14346 oPagination: _ext.pager
14347 } );
14348
14349
14350 $.extend( DataTable.ext.classes, {
14351 "sTable": "dataTable",
14352 "sNoFooter": "no-footer",
14353
14354 /* Paging buttons */
14355 "sPageButton": "paginate_button",
14356 "sPageButtonActive": "current",
14357 "sPageButtonDisabled": "disabled",
14358
14359 /* Striping classes */
14360 "sStripeOdd": "odd",
14361 "sStripeEven": "even",
14362
14363 /* Empty row */
14364 "sRowEmpty": "dataTables_empty",
14365
14366 /* Features */
14367 "sWrapper": "dataTables_wrapper",
14368 "sFilter": "dataTables_filter",
14369 "sInfo": "dataTables_info",
14370 "sPaging": "dataTables_paginate paging_", /* Note that the type is postfixed */
14371 "sLength": "dataTables_length",
14372 "sProcessing": "dataTables_processing",
14373
14374 /* Sorting */
14375 "sSortAsc": "sorting_asc",
14376 "sSortDesc": "sorting_desc",
14377 "sSortable": "sorting", /* Sortable in both directions */
14378 "sSortableAsc": "sorting_asc_disabled",
14379 "sSortableDesc": "sorting_desc_disabled",
14380 "sSortableNone": "sorting_disabled",
14381 "sSortColumn": "sorting_", /* Note that an int is postfixed for the sorting order */
14382
14383 /* Filtering */
14384 "sFilterInput": "",
14385
14386 /* Page length */
14387 "sLengthSelect": "",
14388
14389 /* Scrolling */
14390 "sScrollWrapper": "dataTables_scroll",
14391 "sScrollHead": "dataTables_scrollHead",
14392 "sScrollHeadInner": "dataTables_scrollHeadInner",
14393 "sScrollBody": "dataTables_scrollBody",
14394 "sScrollFoot": "dataTables_scrollFoot",
14395 "sScrollFootInner": "dataTables_scrollFootInner",
14396
14397 /* Misc */
14398 "sHeaderTH": "",
14399 "sFooterTH": "",
14400
14401 // Deprecated
14402 "sSortJUIAsc": "",
14403 "sSortJUIDesc": "",
14404 "sSortJUI": "",
14405 "sSortJUIAscAllowed": "",
14406 "sSortJUIDescAllowed": "",
14407 "sSortJUIWrapper": "",
14408 "sSortIcon": "",
14409 "sJUIHeader": "",
14410 "sJUIFooter": ""
14411 } );
14412
14413
14414 var extPagination = DataTable.ext.pager;
14415
14416 function _numbers ( page, pages ) {
14417 var
14418 numbers = [],
14419 buttons = extPagination.numbers_length,
14420 half = Math.floor( buttons / 2 ),
14421 i = 1;
14422
14423 if ( pages <= buttons ) {
14424 numbers = _range( 0, pages );
14425 }
14426 else if ( page <= half ) {
14427 numbers = _range( 0, buttons-2 );
14428 numbers.push( 'ellipsis' );
14429 numbers.push( pages-1 );
14430 }
14431 else if ( page >= pages - 1 - half ) {
14432 numbers = _range( pages-(buttons-2), pages );
14433 numbers.splice( 0, 0, 'ellipsis' ); // no unshift in ie6
14434 numbers.splice( 0, 0, 0 );
14435 }
14436 else {
14437 numbers = _range( page-half+2, page+half-1 );
14438 numbers.push( 'ellipsis' );
14439 numbers.push( pages-1 );
14440 numbers.splice( 0, 0, 'ellipsis' );
14441 numbers.splice( 0, 0, 0 );
14442 }
14443
14444 numbers.DT_el = 'span';
14445 return numbers;
14446 }
14447
14448
14449 $.extend( extPagination, {
14450 simple: function ( page, pages ) {
14451 return [ 'previous', 'next' ];
14452 },
14453
14454 full: function ( page, pages ) {
14455 return [ 'first', 'previous', 'next', 'last' ];
14456 },
14457
14458 numbers: function ( page, pages ) {
14459 return [ _numbers(page, pages) ];
14460 },
14461
14462 simple_numbers: function ( page, pages ) {
14463 return [ 'previous', _numbers(page, pages), 'next' ];
14464 },
14465
14466 full_numbers: function ( page, pages ) {
14467 return [ 'first', 'previous', _numbers(page, pages), 'next', 'last' ];
14468 },
14469
14470 first_last_numbers: function (page, pages) {
14471 return ['first', _numbers(page, pages), 'last'];
14472 },
14473
14474 // For testing and plug-ins to use
14475 _numbers: _numbers,
14476
14477 // Number of number buttons (including ellipsis) to show. _Must be odd!_
14478 numbers_length: 7
14479 } );
14480
14481
14482 $.extend( true, DataTable.ext.renderer, {
14483 pageButton: {
14484 _: function ( settings, host, idx, buttons, page, pages ) {
14485 var classes = settings.oClasses;
14486 var lang = settings.oLanguage.oPaginate;
14487 var aria = settings.oLanguage.oAria.paginate || {};
14488 var btnDisplay, btnClass, counter=0;
14489
14490 var attach = function( container, buttons ) {
14491 var i, ien, node, button;
14492 var clickHandler = function ( e ) {
14493 _fnPageChange( settings, e.data.action, true );
14494 };
14495
14496 for ( i=0, ien=buttons.length ; i<ien ; i++ ) {
14497 button = buttons[i];
14498
14499 if ( $.isArray( button ) ) {
14500 var inner = $( '<'+(button.DT_el || 'div')+'/>' )
14501 .appendTo( container );
14502 attach( inner, button );
14503 }
14504 else {
14505 btnDisplay = null;
14506 btnClass = '';
14507
14508 switch ( button ) {
14509 case 'ellipsis':
14510 container.append('<span class="ellipsis">&#x2026;</span>');
14511 break;
14512
14513 case 'first':
14514 btnDisplay = lang.sFirst;
14515 btnClass = button + (page > 0 ?
14516 '' : ' '+classes.sPageButtonDisabled);
14517 break;
14518
14519 case 'previous':
14520 btnDisplay = lang.sPrevious;
14521 btnClass = button + (page > 0 ?
14522 '' : ' '+classes.sPageButtonDisabled);
14523 break;
14524
14525 case 'next':
14526 btnDisplay = lang.sNext;
14527 btnClass = button + (page < pages-1 ?
14528 '' : ' '+classes.sPageButtonDisabled);
14529 break;
14530
14531 case 'last':
14532 btnDisplay = lang.sLast;
14533 btnClass = button + (page < pages-1 ?
14534 '' : ' '+classes.sPageButtonDisabled);
14535 break;
14536
14537 default:
14538 btnDisplay = button + 1;
14539 btnClass = page === button ?
14540 classes.sPageButtonActive : '';
14541 break;
14542 }
14543
14544 if ( btnDisplay !== null ) {
14545 node = $('<a>', {
14546 'class': classes.sPageButton+' '+btnClass,
14547 'aria-controls': settings.sTableId,
14548 'aria-label': aria[ button ],
14549 'data-dt-idx': counter,
14550 'tabindex': settings.iTabIndex,
14551 'id': idx === 0 && typeof button === 'string' ?
14552 settings.sTableId +'_'+ button :
14553 null
14554 } )
14555 .html( btnDisplay )
14556 .appendTo( container );
14557
14558 _fnBindAction(
14559 node, {action: button}, clickHandler
14560 );
14561
14562 counter++;
14563 }
14564 }
14565 }
14566 };
14567
14568 // IE9 throws an 'unknown error' if document.activeElement is used
14569 // inside an iframe or frame. Try / catch the error. Not good for
14570 // accessibility, but neither are frames.
14571 var activeEl;
14572
14573 try {
14574 // Because this approach is destroying and recreating the paging
14575 // elements, focus is lost on the select button which is bad for
14576 // accessibility. So we want to restore focus once the draw has
14577 // completed
14578 activeEl = $(host).find(document.activeElement).data('dt-idx');
14579 }
14580 catch (e) {}
14581
14582 attach( $(host).empty(), buttons );
14583
14584 if ( activeEl !== undefined ) {
14585 $(host).find( '[data-dt-idx='+activeEl+']' ).focus();
14586 }
14587 }
14588 }
14589 } );
14590
14591
14592
14593 // Built in type detection. See model.ext.aTypes for information about
14594 // what is required from this methods.
14595 $.extend( DataTable.ext.type.detect, [
14596 // Plain numbers - first since V8 detects some plain numbers as dates
14597 // e.g. Date.parse('55') (but not all, e.g. Date.parse('22')...).
14598 function ( d, settings )
14599 {
14600 var decimal = settings.oLanguage.sDecimal;
14601 return _isNumber( d, decimal ) ? 'num'+decimal : null;
14602 },
14603
14604 // Dates (only those recognised by the browser's Date.parse)
14605 function ( d, settings )
14606 {
14607 // V8 tries _very_ hard to make a string passed into `Date.parse()`
14608 // valid, so we need to use a regex to restrict date formats. Use a
14609 // plug-in for anything other than ISO8601 style strings
14610 if ( d && !(d instanceof Date) && ! _re_date.test(d) ) {
14611 return null;
14612 }
14613 var parsed = Date.parse(d);
14614 return (parsed !== null && !isNaN(parsed)) || _empty(d) ? 'date' : null;
14615 },
14616
14617 // Formatted numbers
14618 function ( d, settings )
14619 {
14620 var decimal = settings.oLanguage.sDecimal;
14621 return _isNumber( d, decimal, true ) ? 'num-fmt'+decimal : null;
14622 },
14623
14624 // HTML numeric
14625 function ( d, settings )
14626 {
14627 var decimal = settings.oLanguage.sDecimal;
14628 return _htmlNumeric( d, decimal ) ? 'html-num'+decimal : null;
14629 },
14630
14631 // HTML numeric, formatted
14632 function ( d, settings )
14633 {
14634 var decimal = settings.oLanguage.sDecimal;
14635 return _htmlNumeric( d, decimal, true ) ? 'html-num-fmt'+decimal : null;
14636 },
14637
14638 // HTML (this is strict checking - there must be html)
14639 function ( d, settings )
14640 {
14641 return _empty( d ) || (typeof d === 'string' && d.indexOf('<') !== -1) ?
14642 'html' : null;
14643 }
14644 ] );
14645
14646
14647
14648 // Filter formatting functions. See model.ext.ofnSearch for information about
14649 // what is required from these methods.
14650 //
14651 // Note that additional search methods are added for the html numbers and
14652 // html formatted numbers by `_addNumericSort()` when we know what the decimal
14653 // place is
14654
14655
14656 $.extend( DataTable.ext.type.search, {
14657 html: function ( data ) {
14658 return _empty(data) ?
14659 data :
14660 typeof data === 'string' ?
14661 data
14662 .replace( _re_new_lines, " " )
14663 .replace( _re_html, "" ) :
14664 '';
14665 },
14666
14667 string: function ( data ) {
14668 return _empty(data) ?
14669 data :
14670 typeof data === 'string' ?
14671 data.replace( _re_new_lines, " " ) :
14672 data;
14673 }
14674 } );
14675
14676
14677
14678 var __numericReplace = function ( d, decimalPlace, re1, re2 ) {
14679 if ( d !== 0 && (!d || d === '-') ) {
14680 return -Infinity;
14681 }
14682
14683 // If a decimal place other than `.` is used, it needs to be given to the
14684 // function so we can detect it and replace with a `.` which is the only
14685 // decimal place Javascript recognises - it is not locale aware.
14686 if ( decimalPlace ) {
14687 d = _numToDecimal( d, decimalPlace );
14688 }
14689
14690 if ( d.replace ) {
14691 if ( re1 ) {
14692 d = d.replace( re1, '' );
14693 }
14694
14695 if ( re2 ) {
14696 d = d.replace( re2, '' );
14697 }
14698 }
14699
14700 return d * 1;
14701 };
14702
14703
14704 // Add the numeric 'deformatting' functions for sorting and search. This is done
14705 // in a function to provide an easy ability for the language options to add
14706 // additional methods if a non-period decimal place is used.
14707 function _addNumericSort ( decimalPlace ) {
14708 $.each(
14709 {
14710 // Plain numbers
14711 "num": function ( d ) {
14712 return __numericReplace( d, decimalPlace );
14713 },
14714
14715 // Formatted numbers
14716 "num-fmt": function ( d ) {
14717 return __numericReplace( d, decimalPlace, _re_formatted_numeric );
14718 },
14719
14720 // HTML numeric
14721 "html-num": function ( d ) {
14722 return __numericReplace( d, decimalPlace, _re_html );
14723 },
14724
14725 // HTML numeric, formatted
14726 "html-num-fmt": function ( d ) {
14727 return __numericReplace( d, decimalPlace, _re_html, _re_formatted_numeric );
14728 }
14729 },
14730 function ( key, fn ) {
14731 // Add the ordering method
14732 _ext.type.order[ key+decimalPlace+'-pre' ] = fn;
14733
14734 // For HTML types add a search formatter that will strip the HTML
14735 if ( key.match(/^html\-/) ) {
14736 _ext.type.search[ key+decimalPlace ] = _ext.type.search.html;
14737 }
14738 }
14739 );
14740 }
14741
14742
14743 // Default sort methods
14744 $.extend( _ext.type.order, {
14745 // Dates
14746 "date-pre": function ( d ) {
14747 return Date.parse( d ) || -Infinity;
14748 },
14749
14750 // html
14751 "html-pre": function ( a ) {
14752 return _empty(a) ?
14753 '' :
14754 a.replace ?
14755 a.replace( /<.*?>/g, "" ).toLowerCase() :
14756 a+'';
14757 },
14758
14759 // string
14760 "string-pre": function ( a ) {
14761 // This is a little complex, but faster than always calling toString,
14762 // http://jsperf.com/tostring-v-check
14763 return _empty(a) ?
14764 '' :
14765 typeof a === 'string' ?
14766 a.toLowerCase() :
14767 ! a.toString ?
14768 '' :
14769 a.toString();
14770 },
14771
14772 // string-asc and -desc are retained only for compatibility with the old
14773 // sort methods
14774 "string-asc": function ( x, y ) {
14775 return ((x < y) ? -1 : ((x > y) ? 1 : 0));
14776 },
14777
14778 "string-desc": function ( x, y ) {
14779 return ((x < y) ? 1 : ((x > y) ? -1 : 0));
14780 }
14781 } );
14782
14783
14784 // Numeric sorting types - order doesn't matter here
14785 _addNumericSort( '' );
14786
14787
14788 $.extend( true, DataTable.ext.renderer, {
14789 header: {
14790 _: function ( settings, cell, column, classes ) {
14791 // No additional mark-up required
14792 // Attach a sort listener to update on sort - note that using the
14793 // `DT` namespace will allow the event to be removed automatically
14794 // on destroy, while the `dt` namespaced event is the one we are
14795 // listening for
14796 $(settings.nTable).on( 'order.dt.DT', function ( e, ctx, sorting, columns ) {
14797 if ( settings !== ctx ) { // need to check this this is the host
14798 return; // table, not a nested one
14799 }
14800
14801 var colIdx = column.idx;
14802
14803 cell
14804 .removeClass(
14805 column.sSortingClass +' '+
14806 classes.sSortAsc +' '+
14807 classes.sSortDesc
14808 )
14809 .addClass( columns[ colIdx ] == 'asc' ?
14810 classes.sSortAsc : columns[ colIdx ] == 'desc' ?
14811 classes.sSortDesc :
14812 column.sSortingClass
14813 );
14814 } );
14815 },
14816
14817 jqueryui: function ( settings, cell, column, classes ) {
14818 $('<div/>')
14819 .addClass( classes.sSortJUIWrapper )
14820 .append( cell.contents() )
14821 .append( $('<span/>')
14822 .addClass( classes.sSortIcon+' '+column.sSortingClassJUI )
14823 )
14824 .appendTo( cell );
14825
14826 // Attach a sort listener to update on sort
14827 $(settings.nTable).on( 'order.dt.DT', function ( e, ctx, sorting, columns ) {
14828 if ( settings !== ctx ) {
14829 return;
14830 }
14831
14832 var colIdx = column.idx;
14833
14834 cell
14835 .removeClass( classes.sSortAsc +" "+classes.sSortDesc )
14836 .addClass( columns[ colIdx ] == 'asc' ?
14837 classes.sSortAsc : columns[ colIdx ] == 'desc' ?
14838 classes.sSortDesc :
14839 column.sSortingClass
14840 );
14841
14842 cell
14843 .find( 'span.'+classes.sSortIcon )
14844 .removeClass(
14845 classes.sSortJUIAsc +" "+
14846 classes.sSortJUIDesc +" "+
14847 classes.sSortJUI +" "+
14848 classes.sSortJUIAscAllowed +" "+
14849 classes.sSortJUIDescAllowed
14850 )
14851 .addClass( columns[ colIdx ] == 'asc' ?
14852 classes.sSortJUIAsc : columns[ colIdx ] == 'desc' ?
14853 classes.sSortJUIDesc :
14854 column.sSortingClassJUI
14855 );
14856 } );
14857 }
14858 }
14859 } );
14860
14861 /*
14862 * Public helper functions. These aren't used internally by DataTables, or
14863 * called by any of the options passed into DataTables, but they can be used
14864 * externally by developers working with DataTables. They are helper functions
14865 * to make working with DataTables a little bit easier.
14866 */
14867
14868 var __htmlEscapeEntities = function ( d ) {
14869 return typeof d === 'string' ?
14870 d.replace(/</g, '&lt;').replace(/>/g, '&gt;').replace(/"/g, '&quot;') :
14871 d;
14872 };
14873
14874 /**
14875 * Helpers for `columns.render`.
14876 *
14877 * The options defined here can be used with the `columns.render` initialisation
14878 * option to provide a display renderer. The following functions are defined:
14879 *
14880 * * `number` - Will format numeric data (defined by `columns.data`) for
14881 * display, retaining the original unformatted data for sorting and filtering.
14882 * It takes 5 parameters:
14883 * * `string` - Thousands grouping separator
14884 * * `string` - Decimal point indicator
14885 * * `integer` - Number of decimal points to show
14886 * * `string` (optional) - Prefix.
14887 * * `string` (optional) - Postfix (/suffix).
14888 * * `text` - Escape HTML to help prevent XSS attacks. It has no optional
14889 * parameters.
14890 *
14891 * @example
14892 * // Column definition using the number renderer
14893 * {
14894 * data: "salary",
14895 * render: $.fn.dataTable.render.number( '\'', '.', 0, '$' )
14896 * }
14897 *
14898 * @namespace
14899 */
14900 DataTable.render = {
14901 number: function ( thousands, decimal, precision, prefix, postfix ) {
14902 return {
14903 display: function ( d ) {
14904 if ( typeof d !== 'number' && typeof d !== 'string' ) {
14905 return d;
14906 }
14907
14908 var negative = d < 0 ? '-' : '';
14909 var flo = parseFloat( d );
14910
14911 // If NaN then there isn't much formatting that we can do - just
14912 // return immediately, escaping any HTML (this was supposed to
14913 // be a number after all)
14914 if ( isNaN( flo ) ) {
14915 return __htmlEscapeEntities( d );
14916 }
14917
14918 flo = flo.toFixed( precision );
14919 d = Math.abs( flo );
14920
14921 var intPart = parseInt( d, 10 );
14922 var floatPart = precision ?
14923 decimal+(d - intPart).toFixed( precision ).substring( 2 ):
14924 '';
14925
14926 return negative + (prefix||'') +
14927 intPart.toString().replace(
14928 /\B(?=(\d{3})+(?!\d))/g, thousands
14929 ) +
14930 floatPart +
14931 (postfix||'');
14932 }
14933 };
14934 },
14935
14936 text: function () {
14937 return {
14938 display: __htmlEscapeEntities
14939 };
14940 }
14941 };
14942
14943
14944 /*
14945 * This is really a good bit rubbish this method of exposing the internal methods
14946 * publicly... - To be fixed in 2.0 using methods on the prototype
14947 */
14948
14949
14950 /**
14951 * Create a wrapper function for exporting an internal functions to an external API.
14952 * @param {string} fn API function name
14953 * @returns {function} wrapped function
14954 * @memberof DataTable#internal
14955 */
14956 function _fnExternApiFunc (fn)
14957 {
14958 return function() {
14959 var args = [_fnSettingsFromNode( this[DataTable.ext.iApiIndex] )].concat(
14960 Array.prototype.slice.call(arguments)
14961 );
14962 return DataTable.ext.internal[fn].apply( this, args );
14963 };
14964 }
14965
14966
14967 /**
14968 * Reference to internal functions for use by plug-in developers. Note that
14969 * these methods are references to internal functions and are considered to be
14970 * private. If you use these methods, be aware that they are liable to change
14971 * between versions.
14972 * @namespace
14973 */
14974 $.extend( DataTable.ext.internal, {
14975 _fnExternApiFunc: _fnExternApiFunc,
14976 _fnBuildAjax: _fnBuildAjax,
14977 _fnAjaxUpdate: _fnAjaxUpdate,
14978 _fnAjaxParameters: _fnAjaxParameters,
14979 _fnAjaxUpdateDraw: _fnAjaxUpdateDraw,
14980 _fnAjaxDataSrc: _fnAjaxDataSrc,
14981 _fnAddColumn: _fnAddColumn,
14982 _fnColumnOptions: _fnColumnOptions,
14983 _fnAdjustColumnSizing: _fnAdjustColumnSizing,
14984 _fnVisibleToColumnIndex: _fnVisibleToColumnIndex,
14985 _fnColumnIndexToVisible: _fnColumnIndexToVisible,
14986 _fnVisbleColumns: _fnVisbleColumns,
14987 _fnGetColumns: _fnGetColumns,
14988 _fnColumnTypes: _fnColumnTypes,
14989 _fnApplyColumnDefs: _fnApplyColumnDefs,
14990 _fnHungarianMap: _fnHungarianMap,
14991 _fnCamelToHungarian: _fnCamelToHungarian,
14992 _fnLanguageCompat: _fnLanguageCompat,
14993 _fnBrowserDetect: _fnBrowserDetect,
14994 _fnAddData: _fnAddData,
14995 _fnAddTr: _fnAddTr,
14996 _fnNodeToDataIndex: _fnNodeToDataIndex,
14997 _fnNodeToColumnIndex: _fnNodeToColumnIndex,
14998 _fnGetCellData: _fnGetCellData,
14999 _fnSetCellData: _fnSetCellData,
15000 _fnSplitObjNotation: _fnSplitObjNotation,
15001 _fnGetObjectDataFn: _fnGetObjectDataFn,
15002 _fnSetObjectDataFn: _fnSetObjectDataFn,
15003 _fnGetDataMaster: _fnGetDataMaster,
15004 _fnClearTable: _fnClearTable,
15005 _fnDeleteIndex: _fnDeleteIndex,
15006 _fnInvalidate: _fnInvalidate,
15007 _fnGetRowElements: _fnGetRowElements,
15008 _fnCreateTr: _fnCreateTr,
15009 _fnBuildHead: _fnBuildHead,
15010 _fnDrawHead: _fnDrawHead,
15011 _fnDraw: _fnDraw,
15012 _fnReDraw: _fnReDraw,
15013 _fnAddOptionsHtml: _fnAddOptionsHtml,
15014 _fnDetectHeader: _fnDetectHeader,
15015 _fnGetUniqueThs: _fnGetUniqueThs,
15016 _fnFeatureHtmlFilter: _fnFeatureHtmlFilter,
15017 _fnFilterComplete: _fnFilterComplete,
15018 _fnFilterCustom: _fnFilterCustom,
15019 _fnFilterColumn: _fnFilterColumn,
15020 _fnFilter: _fnFilter,
15021 _fnFilterCreateSearch: _fnFilterCreateSearch,
15022 _fnEscapeRegex: _fnEscapeRegex,
15023 _fnFilterData: _fnFilterData,
15024 _fnFeatureHtmlInfo: _fnFeatureHtmlInfo,
15025 _fnUpdateInfo: _fnUpdateInfo,
15026 _fnInfoMacros: _fnInfoMacros,
15027 _fnInitialise: _fnInitialise,
15028 _fnInitComplete: _fnInitComplete,
15029 _fnLengthChange: _fnLengthChange,
15030 _fnFeatureHtmlLength: _fnFeatureHtmlLength,
15031 _fnFeatureHtmlPaginate: _fnFeatureHtmlPaginate,
15032 _fnPageChange: _fnPageChange,
15033 _fnFeatureHtmlProcessing: _fnFeatureHtmlProcessing,
15034 _fnProcessingDisplay: _fnProcessingDisplay,
15035 _fnFeatureHtmlTable: _fnFeatureHtmlTable,
15036 _fnScrollDraw: _fnScrollDraw,
15037 _fnApplyToChildren: _fnApplyToChildren,
15038 _fnCalculateColumnWidths: _fnCalculateColumnWidths,
15039 _fnThrottle: _fnThrottle,
15040 _fnConvertToWidth: _fnConvertToWidth,
15041 _fnGetWidestNode: _fnGetWidestNode,
15042 _fnGetMaxLenString: _fnGetMaxLenString,
15043 _fnStringToCss: _fnStringToCss,
15044 _fnSortFlatten: _fnSortFlatten,
15045 _fnSort: _fnSort,
15046 _fnSortAria: _fnSortAria,
15047 _fnSortListener: _fnSortListener,
15048 _fnSortAttachListener: _fnSortAttachListener,
15049 _fnSortingClasses: _fnSortingClasses,
15050 _fnSortData: _fnSortData,
15051 _fnSaveState: _fnSaveState,
15052 _fnLoadState: _fnLoadState,
15053 _fnSettingsFromNode: _fnSettingsFromNode,
15054 _fnLog: _fnLog,
15055 _fnMap: _fnMap,
15056 _fnBindAction: _fnBindAction,
15057 _fnCallbackReg: _fnCallbackReg,
15058 _fnCallbackFire: _fnCallbackFire,
15059 _fnLengthOverflow: _fnLengthOverflow,
15060 _fnRenderer: _fnRenderer,
15061 _fnDataSource: _fnDataSource,
15062 _fnRowAttributes: _fnRowAttributes,
15063 _fnCalculateEnd: function () {} // Used by a lot of plug-ins, but redundant
15064 // in 1.10, so this dead-end function is
15065 // added to prevent errors
15066 } );
15067
15068
15069 // jQuery access
15070 $.fn.dataTable = DataTable;
15071
15072 // Provide access to the host jQuery object (circular reference)
15073 DataTable.$ = $;
15074
15075 // Legacy aliases
15076 $.fn.dataTableSettings = DataTable.settings;
15077 $.fn.dataTableExt = DataTable.ext;
15078
15079 // With a capital `D` we return a DataTables API instance rather than a
15080 // jQuery object
15081 $.fn.DataTable = function ( opts ) {
15082 return $(this).dataTable( opts ).api();
15083 };
15084
15085 // All properties that are available to $.fn.dataTable should also be
15086 // available on $.fn.DataTable
15087 $.each( DataTable, function ( prop, val ) {
15088 $.fn.DataTable[ prop ] = val;
15089 } );
15090
15091
15092 // Information about events fired by DataTables - for documentation.
15093 /**
15094 * Draw event, fired whenever the table is redrawn on the page, at the same
15095 * point as fnDrawCallback. This may be useful for binding events or
15096 * performing calculations when the table is altered at all.
15097 * @name DataTable#draw.dt
15098 * @event
15099 * @param {event} e jQuery event object
15100 * @param {object} o DataTables settings object {@link DataTable.models.oSettings}
15101 */
15102
15103 /**
15104 * Search event, fired when the searching applied to the table (using the
15105 * built-in global search, or column filters) is altered.
15106 * @name DataTable#search.dt
15107 * @event
15108 * @param {event} e jQuery event object
15109 * @param {object} o DataTables settings object {@link DataTable.models.oSettings}
15110 */
15111
15112 /**
15113 * Page change event, fired when the paging of the table is altered.
15114 * @name DataTable#page.dt
15115 * @event
15116 * @param {event} e jQuery event object
15117 * @param {object} o DataTables settings object {@link DataTable.models.oSettings}
15118 */
15119
15120 /**
15121 * Order event, fired when the ordering applied to the table is altered.
15122 * @name DataTable#order.dt
15123 * @event
15124 * @param {event} e jQuery event object
15125 * @param {object} o DataTables settings object {@link DataTable.models.oSettings}
15126 */
15127
15128 /**
15129 * DataTables initialisation complete event, fired when the table is fully
15130 * drawn, including Ajax data loaded, if Ajax data is required.
15131 * @name DataTable#init.dt
15132 * @event
15133 * @param {event} e jQuery event object
15134 * @param {object} oSettings DataTables settings object
15135 * @param {object} json The JSON object request from the server - only
15136 * present if client-side Ajax sourced data is used</li></ol>
15137 */
15138
15139 /**
15140 * State save event, fired when the table has changed state a new state save
15141 * is required. This event allows modification of the state saving object
15142 * prior to actually doing the save, including addition or other state
15143 * properties (for plug-ins) or modification of a DataTables core property.
15144 * @name DataTable#stateSaveParams.dt
15145 * @event
15146 * @param {event} e jQuery event object
15147 * @param {object} oSettings DataTables settings object
15148 * @param {object} json The state information to be saved
15149 */
15150
15151 /**
15152 * State load event, fired when the table is loading state from the stored
15153 * data, but prior to the settings object being modified by the saved state
15154 * - allowing modification of the saved state is required or loading of
15155 * state for a plug-in.
15156 * @name DataTable#stateLoadParams.dt
15157 * @event
15158 * @param {event} e jQuery event object
15159 * @param {object} oSettings DataTables settings object
15160 * @param {object} json The saved state information
15161 */
15162
15163 /**
15164 * State loaded event, fired when state has been loaded from stored data and
15165 * the settings object has been modified by the loaded data.
15166 * @name DataTable#stateLoaded.dt
15167 * @event
15168 * @param {event} e jQuery event object
15169 * @param {object} oSettings DataTables settings object
15170 * @param {object} json The saved state information
15171 */
15172
15173 /**
15174 * Processing event, fired when DataTables is doing some kind of processing
15175 * (be it, order, searcg or anything else). It can be used to indicate to
15176 * the end user that there is something happening, or that something has
15177 * finished.
15178 * @name DataTable#processing.dt
15179 * @event
15180 * @param {event} e jQuery event object
15181 * @param {object} oSettings DataTables settings object
15182 * @param {boolean} bShow Flag for if DataTables is doing processing or not
15183 */
15184
15185 /**
15186 * Ajax (XHR) event, fired whenever an Ajax request is completed from a
15187 * request to made to the server for new data. This event is called before
15188 * DataTables processed the returned data, so it can also be used to pre-
15189 * process the data returned from the server, if needed.
15190 *
15191 * Note that this trigger is called in `fnServerData`, if you override
15192 * `fnServerData` and which to use this event, you need to trigger it in you
15193 * success function.
15194 * @name DataTable#xhr.dt
15195 * @event
15196 * @param {event} e jQuery event object
15197 * @param {object} o DataTables settings object {@link DataTable.models.oSettings}
15198 * @param {object} json JSON returned from the server
15199 *
15200 * @example
15201 * // Use a custom property returned from the server in another DOM element
15202 * $('#table').dataTable().on('xhr.dt', function (e, settings, json) {
15203 * $('#status').html( json.status );
15204 * } );
15205 *
15206 * @example
15207 * // Pre-process the data returned from the server
15208 * $('#table').dataTable().on('xhr.dt', function (e, settings, json) {
15209 * for ( var i=0, ien=json.aaData.length ; i<ien ; i++ ) {
15210 * json.aaData[i].sum = json.aaData[i].one + json.aaData[i].two;
15211 * }
15212 * // Note no return - manipulate the data directly in the JSON object.
15213 * } );
15214 */
15215
15216 /**
15217 * Destroy event, fired when the DataTable is destroyed by calling fnDestroy
15218 * or passing the bDestroy:true parameter in the initialisation object. This
15219 * can be used to remove bound events, added DOM nodes, etc.
15220 * @name DataTable#destroy.dt
15221 * @event
15222 * @param {event} e jQuery event object
15223 * @param {object} o DataTables settings object {@link DataTable.models.oSettings}
15224 */
15225
15226 /**
15227 * Page length change event, fired when number of records to show on each
15228 * page (the length) is changed.
15229 * @name DataTable#length.dt
15230 * @event
15231 * @param {event} e jQuery event object
15232 * @param {object} o DataTables settings object {@link DataTable.models.oSettings}
15233 * @param {integer} len New length
15234 */
15235
15236 /**
15237 * Column sizing has changed.
15238 * @name DataTable#column-sizing.dt
15239 * @event
15240 * @param {event} e jQuery event object
15241 * @param {object} o DataTables settings object {@link DataTable.models.oSettings}
15242 */
15243
15244 /**
15245 * Column visibility has changed.
15246 * @name DataTable#column-visibility.dt
15247 * @event
15248 * @param {event} e jQuery event object
15249 * @param {object} o DataTables settings object {@link DataTable.models.oSettings}
15250 * @param {int} column Column index
15251 * @param {bool} vis `false` if column now hidden, or `true` if visible
15252 */
15253
15254 return $.fn.dataTable;
15255 }));
15256
15257
15258