2 * ©2008-2017 SpryMedia Ltd - datatables.net/license
7 * @description Paginate, search and order HTML tables
9 * @file jquery.dataTables.js
10 * @author SpryMedia Ltd
11 * @contact www.datatables.net
12 * @copyright Copyright 2008-2017 SpryMedia Ltd.
14 * This source file is free software, available under the following license:
15 * MIT license - http://datatables.net/license
17 * This source file is distributed in the hope that it will be useful, but
18 * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
19 * or FITNESS FOR A PARTICULAR PURPOSE. See the license files for details.
21 * For details please refer to: http://www.datatables.net
24 /*jslint evil: true, undef: true, browser: true */
25 /*globals $,require,jQuery,define,_selector_run,_selector_opts,_selector_first,_selector_row_indexes,_ext,_Api,_api_register,_api_registerPlural,_re_new_lines,_re_html,_re_formatted_numeric,_re_escape_regex,_empty,_intVal,_numToDecimal,_isNumber,_isHtml,_htmlNumeric,_pluck,_pluck_order,_range,_stripHtml,_unique,_fnBuildAjax,_fnAjaxUpdate,_fnAjaxParameters,_fnAjaxUpdateDraw,_fnAjaxDataSrc,_fnAddColumn,_fnColumnOptions,_fnAdjustColumnSizing,_fnVisibleToColumnIndex,_fnColumnIndexToVisible,_fnVisbleColumns,_fnGetColumns,_fnColumnTypes,_fnApplyColumnDefs,_fnHungarianMap,_fnCamelToHungarian,_fnLanguageCompat,_fnBrowserDetect,_fnAddData,_fnAddTr,_fnNodeToDataIndex,_fnNodeToColumnIndex,_fnGetCellData,_fnSetCellData,_fnSplitObjNotation,_fnGetObjectDataFn,_fnSetObjectDataFn,_fnGetDataMaster,_fnClearTable,_fnDeleteIndex,_fnInvalidate,_fnGetRowElements,_fnCreateTr,_fnBuildHead,_fnDrawHead,_fnDraw,_fnReDraw,_fnAddOptionsHtml,_fnDetectHeader,_fnGetUniqueThs,_fnFeatureHtmlFilter,_fnFilterComplete,_fnFilterCustom,_fnFilterColumn,_fnFilter,_fnFilterCreateSearch,_fnEscapeRegex,_fnFilterData,_fnFeatureHtmlInfo,_fnUpdateInfo,_fnInfoMacros,_fnInitialise,_fnInitComplete,_fnLengthChange,_fnFeatureHtmlLength,_fnFeatureHtmlPaginate,_fnPageChange,_fnFeatureHtmlProcessing,_fnProcessingDisplay,_fnFeatureHtmlTable,_fnScrollDraw,_fnApplyToChildren,_fnCalculateColumnWidths,_fnThrottle,_fnConvertToWidth,_fnGetWidestNode,_fnGetMaxLenString,_fnStringToCss,_fnSortFlatten,_fnSort,_fnSortAria,_fnSortListener,_fnSortAttachListener,_fnSortingClasses,_fnSortData,_fnSaveState,_fnLoadState,_fnSettingsFromNode,_fnLog,_fnMap,_fnBindAction,_fnCallbackReg,_fnCallbackFire,_fnLengthOverflow,_fnRenderer,_fnDataSource,_fnRowAttributes*/
27 (function( factory ) {
30 if ( typeof define === 'function' && define.amd ) {
32 define( ['jquery'], function ( $ ) {
33 return factory( $, window, document );
36 else if ( typeof exports === 'object' ) {
38 module.exports = function (root, $) {
40 // CommonJS environments without a window global must pass a
41 // root. This will give an error otherwise
46 $ = typeof window !== 'undefined' ? // jQuery's factory checks for a global window
48 require('jquery')( root );
51 return factory( $, root, root.document );
56 factory( jQuery, window, document );
59 (function( $, window, document, undefined ) {
63 * DataTables is a plug-in for the jQuery Javascript library. It is a highly
64 * flexible tool, based upon the foundations of progressive enhancement,
65 * which will add advanced interaction controls to any HTML table. For a
66 * full list of features please refer to
67 * [DataTables.net](href="http://datatables.net).
69 * Note that the `DataTable` object is not a global variable but is aliased
70 * to `jQuery.fn.DataTable` and `jQuery.fn.dataTable` through which it may
74 * @param {object} [init={}] Configuration object for DataTables. Options
75 * are defined by {@link DataTable.defaults}
76 * @requires jQuery 1.7+
79 * // Basic initialisation
80 * $(document).ready( function {
81 * $('#example').dataTable();
85 * // Initialisation with configuration options - in this case, disable
86 * // pagination and sorting.
87 * $(document).ready( function {
88 * $('#example').dataTable( {
94 var DataTable = function ( options )
97 * Perform a jQuery selector action on the table's TR elements (from the tbody) and
98 * return the resulting jQuery object.
99 * @param {string|node|jQuery} sSelector jQuery selector or node collection to act on
100 * @param {object} [oOpts] Optional parameters for modifying the rows to be included
101 * @param {string} [oOpts.filter=none] Select TR elements that meet the current filter
102 * criterion ("applied") or all TR elements (i.e. no filter).
103 * @param {string} [oOpts.order=current] Order of the TR elements in the processed array.
104 * Can be either 'current', whereby the current sorting of the table is used, or
105 * 'original' whereby the original order the data was read into the table is used.
106 * @param {string} [oOpts.page=all] Limit the selection to the currently displayed page
107 * ("current") or not ("all"). If 'current' is given, then order is assumed to be
108 * 'current' and filter is 'applied', regardless of what they might be given as.
109 * @returns {object} jQuery object, filtered by the given selector.
111 * @deprecated Since v1.10
114 * $(document).ready(function() {
115 * var oTable = $('#example').dataTable();
117 * // Highlight every second row
118 * oTable.$('tr:odd').css('backgroundColor', 'blue');
122 * $(document).ready(function() {
123 * var oTable = $('#example').dataTable();
125 * // Filter to rows with 'Webkit' in them, add a background colour and then
126 * // remove the filter, thus highlighting the 'Webkit' rows only.
127 * oTable.fnFilter('Webkit');
128 * oTable.$('tr', {"search": "applied"}).css('backgroundColor', 'blue');
129 * oTable.fnFilter('');
132 this.$ = function ( sSelector, oOpts )
134 return this.api(true).$( sSelector, oOpts );
139 * Almost identical to $ in operation, but in this case returns the data for the matched
140 * rows - as such, the jQuery selector used should match TR row nodes or TD/TH cell nodes
141 * rather than any descendants, so the data can be obtained for the row/cell. If matching
142 * rows are found, the data returned is the original data array/object that was used to
143 * create the row (or a generated array if from a DOM source).
145 * This method is often useful in-combination with $ where both functions are given the
146 * same parameters and the array indexes will match identically.
147 * @param {string|node|jQuery} sSelector jQuery selector or node collection to act on
148 * @param {object} [oOpts] Optional parameters for modifying the rows to be included
149 * @param {string} [oOpts.filter=none] Select elements that meet the current filter
150 * criterion ("applied") or all elements (i.e. no filter).
151 * @param {string} [oOpts.order=current] Order of the data in the processed array.
152 * Can be either 'current', whereby the current sorting of the table is used, or
153 * 'original' whereby the original order the data was read into the table is used.
154 * @param {string} [oOpts.page=all] Limit the selection to the currently displayed page
155 * ("current") or not ("all"). If 'current' is given, then order is assumed to be
156 * 'current' and filter is 'applied', regardless of what they might be given as.
157 * @returns {array} Data for the matched elements. If any elements, as a result of the
158 * selector, were not TR, TD or TH elements in the DataTable, they will have a null
159 * entry in the array.
161 * @deprecated Since v1.10
164 * $(document).ready(function() {
165 * var oTable = $('#example').dataTable();
167 * // Get the data from the first row in the table
168 * var data = oTable._('tr:first');
170 * // Do something useful with the data
171 * alert( "First cell is: "+data[0] );
175 * $(document).ready(function() {
176 * var oTable = $('#example').dataTable();
178 * // Filter to 'Webkit' and get all data for
179 * oTable.fnFilter('Webkit');
180 * var data = oTable._('tr', {"search": "applied"});
182 * // Do something with the data
183 * alert( data.length+" rows matched the search" );
186 this._ = function ( sSelector, oOpts )
188 return this.api(true).rows( sSelector, oOpts ).data();
193 * Create a DataTables Api instance, with the currently selected tables for
195 * @param {boolean} [traditional=false] Set the API instance's context to be
196 * only the table referred to by the `DataTable.ext.iApiIndex` option, as was
197 * used in the API presented by DataTables 1.9- (i.e. the traditional mode),
198 * or if all tables captured in the jQuery object should be used.
199 * @return {DataTables.Api}
201 this.api = function ( traditional )
205 _fnSettingsFromNode( this[ _ext.iApiIndex ] )
212 * Add a single new row or multiple rows of data to the table. Please note
213 * that this is suitable for client-side processing only - if you are using
214 * server-side processing (i.e. "bServerSide": true), then to add data, you
215 * must add it to the data source, i.e. the server-side, through an Ajax call.
216 * @param {array|object} data The data to be added to the table. This can be:
218 * <li>1D array of data - add a single row with the data provided</li>
219 * <li>2D array of arrays - add multiple rows in a single call</li>
220 * <li>object - data object when using <i>mData</i></li>
221 * <li>array of objects - multiple data objects when using <i>mData</i></li>
223 * @param {bool} [redraw=true] redraw the table or not
224 * @returns {array} An array of integers, representing the list of indexes in
225 * <i>aoData</i> ({@link DataTable.models.oSettings}) that have been added to
228 * @deprecated Since v1.10
231 * // Global var for counter
234 * $(document).ready(function() {
235 * $('#example').dataTable();
238 * function fnClickAddRow() {
239 * $('#example').dataTable().fnAddData( [
249 this.fnAddData = function( data, redraw )
251 var api = this.api( true );
253 /* Check if we want to add multiple rows or not */
254 var rows = $.isArray(data) && ( $.isArray(data[0]) || $.isPlainObject(data[0]) ) ?
255 api.rows.add( data ) :
258 if ( redraw === undefined || redraw ) {
262 return rows.flatten().toArray();
267 * This function will make DataTables recalculate the column sizes, based on the data
268 * contained in the table and the sizes applied to the columns (in the DOM, CSS or
269 * through the sWidth parameter). This can be useful when the width of the table's
270 * parent element changes (for example a window resize).
271 * @param {boolean} [bRedraw=true] Redraw the table or not, you will typically want to
273 * @deprecated Since v1.10
276 * $(document).ready(function() {
277 * var oTable = $('#example').dataTable( {
278 * "sScrollY": "200px",
282 * $(window).on('resize', function () {
283 * oTable.fnAdjustColumnSizing();
287 this.fnAdjustColumnSizing = function ( bRedraw )
289 var api = this.api( true ).columns.adjust();
290 var settings = api.settings()[0];
291 var scroll = settings.oScroll;
293 if ( bRedraw === undefined || bRedraw ) {
296 else if ( scroll.sX !== "" || scroll.sY !== "" ) {
297 /* If not redrawing, but scrolling, we want to apply the new column sizes anyway */
298 _fnScrollDraw( settings );
304 * Quickly and simply clear a table
305 * @param {bool} [bRedraw=true] redraw the table or not
307 * @deprecated Since v1.10
310 * $(document).ready(function() {
311 * var oTable = $('#example').dataTable();
313 * // Immediately 'nuke' the current rows (perhaps waiting for an Ajax callback...)
314 * oTable.fnClearTable();
317 this.fnClearTable = function( bRedraw )
319 var api = this.api( true ).clear();
321 if ( bRedraw === undefined || bRedraw ) {
328 * The exact opposite of 'opening' a row, this function will close any rows which
329 * are currently 'open'.
330 * @param {node} nTr the table row to 'close'
331 * @returns {int} 0 on success, or 1 if failed (can't find the row)
333 * @deprecated Since v1.10
336 * $(document).ready(function() {
339 * // 'open' an information row when a row is clicked on
340 * $('#example tbody tr').click( function () {
341 * if ( oTable.fnIsOpen(this) ) {
342 * oTable.fnClose( this );
344 * oTable.fnOpen( this, "Temporary row opened", "info_row" );
348 * oTable = $('#example').dataTable();
351 this.fnClose = function( nTr )
353 this.api( true ).row( nTr ).child.hide();
358 * Remove a row for the table
359 * @param {mixed} target The index of the row from aoData to be deleted, or
360 * the TR element you want to delete
361 * @param {function|null} [callBack] Callback function
362 * @param {bool} [redraw=true] Redraw the table or not
363 * @returns {array} The row that was deleted
365 * @deprecated Since v1.10
368 * $(document).ready(function() {
369 * var oTable = $('#example').dataTable();
371 * // Immediately remove the first row
372 * oTable.fnDeleteRow( 0 );
375 this.fnDeleteRow = function( target, callback, redraw )
377 var api = this.api( true );
378 var rows = api.rows( target );
379 var settings = rows.settings()[0];
380 var data = settings.aoData[ rows[0][0] ];
385 callback.call( this, settings, data );
388 if ( redraw === undefined || redraw ) {
397 * Restore the table to it's original state in the DOM by removing all of DataTables
398 * enhancements, alterations to the DOM structure of the table and event listeners.
399 * @param {boolean} [remove=false] Completely remove the table from the DOM
401 * @deprecated Since v1.10
404 * $(document).ready(function() {
405 * // This example is fairly pointless in reality, but shows how fnDestroy can be used
406 * var oTable = $('#example').dataTable();
407 * oTable.fnDestroy();
410 this.fnDestroy = function ( remove )
412 this.api( true ).destroy( remove );
418 * @param {bool} [complete=true] Re-filter and resort (if enabled) the table before the draw.
420 * @deprecated Since v1.10
423 * $(document).ready(function() {
424 * var oTable = $('#example').dataTable();
426 * // Re-draw the table - you wouldn't want to do it here, but it's an example :-)
430 this.fnDraw = function( complete )
432 // Note that this isn't an exact match to the old call to _fnDraw - it takes
433 // into account the new data, but can hold position.
434 this.api( true ).draw( complete );
439 * Filter the input based on data
440 * @param {string} sInput String to filter the table on
441 * @param {int|null} [iColumn] Column to limit filtering to
442 * @param {bool} [bRegex=false] Treat as regular expression or not
443 * @param {bool} [bSmart=true] Perform smart filtering or not
444 * @param {bool} [bShowGlobal=true] Show the input global filter in it's input box(es)
445 * @param {bool} [bCaseInsensitive=true] Do case-insensitive matching (true) or not (false)
447 * @deprecated Since v1.10
450 * $(document).ready(function() {
451 * var oTable = $('#example').dataTable();
453 * // Sometime later - filter...
454 * oTable.fnFilter( 'test string' );
457 this.fnFilter = function( sInput, iColumn, bRegex, bSmart, bShowGlobal, bCaseInsensitive )
459 var api = this.api( true );
461 if ( iColumn === null || iColumn === undefined ) {
462 api.search( sInput, bRegex, bSmart, bCaseInsensitive );
465 api.column( iColumn ).search( sInput, bRegex, bSmart, bCaseInsensitive );
473 * Get the data for the whole table, an individual row or an individual cell based on the
474 * provided parameters.
475 * @param {int|node} [src] A TR row node, TD/TH cell node or an integer. If given as
476 * a TR node then the data source for the whole row will be returned. If given as a
477 * TD/TH cell node then iCol will be automatically calculated and the data for the
478 * cell returned. If given as an integer, then this is treated as the aoData internal
479 * data index for the row (see fnGetPosition) and the data for that row used.
480 * @param {int} [col] Optional column index that you want the data of.
481 * @returns {array|object|string} If mRow is undefined, then the data for all rows is
482 * returned. If mRow is defined, just data for that row, and is iCol is
483 * defined, only data for the designated cell is returned.
485 * @deprecated Since v1.10
489 * $(document).ready(function() {
490 * oTable = $('#example').dataTable();
492 * oTable.$('tr').click( function () {
493 * var data = oTable.fnGetData( this );
494 * // ... do something with the array / object of data for the row
499 * // Individual cell data
500 * $(document).ready(function() {
501 * oTable = $('#example').dataTable();
503 * oTable.$('td').click( function () {
504 * var sData = oTable.fnGetData( this );
505 * alert( 'The cell clicked on had the value of '+sData );
509 this.fnGetData = function( src, col )
511 var api = this.api( true );
513 if ( src !== undefined ) {
514 var type = src.nodeName ? src.nodeName.toLowerCase() : '';
516 return col !== undefined || type == 'td' || type == 'th' ?
517 api.cell( src, col ).data() :
518 api.row( src ).data() || null;
521 return api.data().toArray();
526 * Get an array of the TR nodes that are used in the table's body. Note that you will
527 * typically want to use the '$' API method in preference to this as it is more
529 * @param {int} [iRow] Optional row index for the TR element you want
530 * @returns {array|node} If iRow is undefined, returns an array of all TR elements
531 * in the table's body, or iRow is defined, just the TR element requested.
533 * @deprecated Since v1.10
536 * $(document).ready(function() {
537 * var oTable = $('#example').dataTable();
539 * // Get the nodes from the table
540 * var nNodes = oTable.fnGetNodes( );
543 this.fnGetNodes = function( iRow )
545 var api = this.api( true );
547 return iRow !== undefined ?
548 api.row( iRow ).node() :
549 api.rows().nodes().flatten().toArray();
554 * Get the array indexes of a particular cell from it's DOM element
555 * and column index including hidden columns
556 * @param {node} node this can either be a TR, TD or TH in the table's body
557 * @returns {int} If nNode is given as a TR, then a single index is returned, or
558 * if given as a cell, an array of [row index, column index (visible),
559 * column index (all)] is given.
561 * @deprecated Since v1.10
564 * $(document).ready(function() {
565 * $('#example tbody td').click( function () {
566 * // Get the position of the current data from the node
567 * var aPos = oTable.fnGetPosition( this );
569 * // Get the data array for this row
570 * var aData = oTable.fnGetData( aPos[0] );
572 * // Update the data array and return the value
573 * aData[ aPos[1] ] = 'clicked';
574 * this.innerHTML = 'clicked';
578 * oTable = $('#example').dataTable();
581 this.fnGetPosition = function( node )
583 var api = this.api( true );
584 var nodeName = node.nodeName.toUpperCase();
586 if ( nodeName == 'TR' ) {
587 return api.row( node ).index();
589 else if ( nodeName == 'TD' || nodeName == 'TH' ) {
590 var cell = api.cell( node ).index();
603 * Check to see if a row is 'open' or not.
604 * @param {node} nTr the table row to check
605 * @returns {boolean} true if the row is currently open, false otherwise
607 * @deprecated Since v1.10
610 * $(document).ready(function() {
613 * // 'open' an information row when a row is clicked on
614 * $('#example tbody tr').click( function () {
615 * if ( oTable.fnIsOpen(this) ) {
616 * oTable.fnClose( this );
618 * oTable.fnOpen( this, "Temporary row opened", "info_row" );
622 * oTable = $('#example').dataTable();
625 this.fnIsOpen = function( nTr )
627 return this.api( true ).row( nTr ).child.isShown();
632 * This function will place a new row directly after a row which is currently
633 * on display on the page, with the HTML contents that is passed into the
634 * function. This can be used, for example, to ask for confirmation that a
635 * particular record should be deleted.
636 * @param {node} nTr The table row to 'open'
637 * @param {string|node|jQuery} mHtml The HTML to put into the row
638 * @param {string} sClass Class to give the new TD cell
639 * @returns {node} The row opened. Note that if the table row passed in as the
640 * first parameter, is not found in the table, this method will silently
643 * @deprecated Since v1.10
646 * $(document).ready(function() {
649 * // 'open' an information row when a row is clicked on
650 * $('#example tbody tr').click( function () {
651 * if ( oTable.fnIsOpen(this) ) {
652 * oTable.fnClose( this );
654 * oTable.fnOpen( this, "Temporary row opened", "info_row" );
658 * oTable = $('#example').dataTable();
661 this.fnOpen = function( nTr, mHtml, sClass )
663 return this.api( true )
665 .child( mHtml, sClass )
672 * Change the pagination - provides the internal logic for pagination in a simple API
673 * function. With this function you can have a DataTables table go to the next,
674 * previous, first or last pages.
675 * @param {string|int} mAction Paging action to take: "first", "previous", "next" or "last"
676 * or page number to jump to (integer), note that page 0 is the first page.
677 * @param {bool} [bRedraw=true] Redraw the table or not
679 * @deprecated Since v1.10
682 * $(document).ready(function() {
683 * var oTable = $('#example').dataTable();
684 * oTable.fnPageChange( 'next' );
687 this.fnPageChange = function ( mAction, bRedraw )
689 var api = this.api( true ).page( mAction );
691 if ( bRedraw === undefined || bRedraw ) {
698 * Show a particular column
699 * @param {int} iCol The column whose display should be changed
700 * @param {bool} bShow Show (true) or hide (false) the column
701 * @param {bool} [bRedraw=true] Redraw the table or not
703 * @deprecated Since v1.10
706 * $(document).ready(function() {
707 * var oTable = $('#example').dataTable();
709 * // Hide the second column after initialisation
710 * oTable.fnSetColumnVis( 1, false );
713 this.fnSetColumnVis = function ( iCol, bShow, bRedraw )
715 var api = this.api( true ).column( iCol ).visible( bShow );
717 if ( bRedraw === undefined || bRedraw ) {
718 api.columns.adjust().draw();
724 * Get the settings for a particular table for external manipulation
725 * @returns {object} DataTables settings object. See
726 * {@link DataTable.models.oSettings}
728 * @deprecated Since v1.10
731 * $(document).ready(function() {
732 * var oTable = $('#example').dataTable();
733 * var oSettings = oTable.fnSettings();
735 * // Show an example parameter from the settings
736 * alert( oSettings._iDisplayStart );
739 this.fnSettings = function()
741 return _fnSettingsFromNode( this[_ext.iApiIndex] );
746 * Sort the table by a particular column
747 * @param {int} iCol the data index to sort on. Note that this will not match the
748 * 'display index' if you have hidden data entries
750 * @deprecated Since v1.10
753 * $(document).ready(function() {
754 * var oTable = $('#example').dataTable();
756 * // Sort immediately with columns 0 and 1
757 * oTable.fnSort( [ [0,'asc'], [1,'asc'] ] );
760 this.fnSort = function( aaSort )
762 this.api( true ).order( aaSort ).draw();
767 * Attach a sort listener to an element for a given column
768 * @param {node} nNode the element to attach the sort listener to
769 * @param {int} iColumn the column that a click on this node will sort on
770 * @param {function} [fnCallback] callback function when sort is run
772 * @deprecated Since v1.10
775 * $(document).ready(function() {
776 * var oTable = $('#example').dataTable();
778 * // Sort on column 1, when 'sorter' is clicked on
779 * oTable.fnSortListener( document.getElementById('sorter'), 1 );
782 this.fnSortListener = function( nNode, iColumn, fnCallback )
784 this.api( true ).order.listener( nNode, iColumn, fnCallback );
789 * Update a table cell or row - this method will accept either a single value to
790 * update the cell with, an array of values with one element for each column or
791 * an object in the same format as the original data source. The function is
792 * self-referencing in order to make the multi column updates easier.
793 * @param {object|array|string} mData Data to update the cell/row with
794 * @param {node|int} mRow TR element you want to update or the aoData index
795 * @param {int} [iColumn] The column to update, give as null or undefined to
796 * update a whole row.
797 * @param {bool} [bRedraw=true] Redraw the table or not
798 * @param {bool} [bAction=true] Perform pre-draw actions or not
799 * @returns {int} 0 on success, 1 on error
801 * @deprecated Since v1.10
804 * $(document).ready(function() {
805 * var oTable = $('#example').dataTable();
806 * oTable.fnUpdate( 'Example update', 0, 0 ); // Single cell
807 * oTable.fnUpdate( ['a', 'b', 'c', 'd', 'e'], $('tbody tr')[0] ); // Row
810 this.fnUpdate = function( mData, mRow, iColumn, bRedraw, bAction )
812 var api = this.api( true );
814 if ( iColumn === undefined || iColumn === null ) {
815 api.row( mRow ).data( mData );
818 api.cell( mRow, iColumn ).data( mData );
821 if ( bAction === undefined || bAction ) {
822 api.columns.adjust();
825 if ( bRedraw === undefined || bRedraw ) {
833 * Provide a common method for plug-ins to check the version of DataTables being used, in order
834 * to ensure compatibility.
835 * @param {string} sVersion Version string to check for, in the format "X.Y.Z". Note that the
836 * formats "X" and "X.Y" are also acceptable.
837 * @returns {boolean} true if this version of DataTables is greater or equal to the required
838 * version, or false if this version of DataTales is not suitable
841 * @deprecated Since v1.10
844 * $(document).ready(function() {
845 * var oTable = $('#example').dataTable();
846 * alert( oTable.fnVersionCheck( '1.9.0' ) );
849 this.fnVersionCheck = _ext.fnVersionCheck;
853 var emptyInit = options === undefined;
854 var len = this.length;
860 this.oApi = this.internal = _ext.internal;
862 // Extend with old style plug-in API methods
863 for ( var fn in DataTable.ext.internal ) {
865 this[fn] = _fnExternApiFunc(fn);
869 this.each(function() {
870 // For each initialisation we want to give it a clean initialisation
871 // object that can be bashed around
873 var oInit = len > 1 ? // optimisation for single table case
874 _fnExtend( o, options, true ) :
877 /*global oInit,_that,emptyInit*/
878 var i=0, iLen, j, jLen, k, kLen;
879 var sId = this.getAttribute( 'id' );
880 var bInitHandedOff = false;
881 var defaults = DataTable.defaults;
886 if ( this.nodeName.toLowerCase() != 'table' )
888 _fnLog( null, 0, 'Non-table node initialisation ('+this.nodeName+')', 2 );
892 /* Backwards compatibility for the defaults */
893 _fnCompatOpts( defaults );
894 _fnCompatCols( defaults.column );
896 /* Convert the camel-case defaults to Hungarian */
897 _fnCamelToHungarian( defaults, defaults, true );
898 _fnCamelToHungarian( defaults.column, defaults.column, true );
900 /* Setting up the initialisation object */
901 _fnCamelToHungarian( defaults, $.extend( oInit, $this.data() ) );
905 /* Check to see if we are re-initialising a table */
906 var allSettings = DataTable.settings;
907 for ( i=0, iLen=allSettings.length ; i<iLen ; i++ )
909 var s = allSettings[i];
911 /* Base check on table node */
912 if ( s.nTable == this || s.nTHead.parentNode == this || (s.nTFoot && s.nTFoot.parentNode == this) )
914 var bRetrieve = oInit.bRetrieve !== undefined ? oInit.bRetrieve : defaults.bRetrieve;
915 var bDestroy = oInit.bDestroy !== undefined ? oInit.bDestroy : defaults.bDestroy;
917 if ( emptyInit || bRetrieve )
923 s.oInstance.fnDestroy();
928 _fnLog( s, 0, 'Cannot reinitialise DataTable', 3 );
933 /* If the element we are initialising has the same ID as a table which was previously
934 * initialised, but the table nodes don't match (from before) then we destroy the old
935 * instance by simply deleting it. This is under the assumption that the table has been
936 * destroyed by other methods. Anyone using non-id selectors will need to do this manually
938 if ( s.sTableId == this.id )
940 allSettings.splice( i, 1 );
945 /* Ensure the table has an ID - required for accessibility */
946 if ( sId === null || sId === "" )
948 sId = "DataTables_Table_"+(DataTable.ext._unique++);
952 /* Create the settings object for this table and set some of the default parameters */
953 var oSettings = $.extend( true, {}, DataTable.models.oSettings, {
954 "sDestroyWidth": $this[0].style.width,
958 oSettings.nTable = this;
959 oSettings.oApi = _that.internal;
960 oSettings.oInit = oInit;
962 allSettings.push( oSettings );
964 // Need to add the instance after the instance after the settings object has been added
965 // to the settings array, so we can self reference the table instance if more than one
966 oSettings.oInstance = (_that.length===1) ? _that : $this.dataTable();
968 // Backwards compatibility, before we apply all the defaults
969 _fnCompatOpts( oInit );
971 if ( oInit.oLanguage )
973 _fnLanguageCompat( oInit.oLanguage );
976 // If the length menu is given, but the init display length is not, use the length menu
977 if ( oInit.aLengthMenu && ! oInit.iDisplayLength )
979 oInit.iDisplayLength = $.isArray( oInit.aLengthMenu[0] ) ?
980 oInit.aLengthMenu[0][0] : oInit.aLengthMenu[0];
983 // Apply the defaults and init options to make a single init object will all
984 // options defined from defaults and instance options.
985 oInit = _fnExtend( $.extend( true, {}, defaults ), oInit );
988 // Map the initialisation options onto the settings object
989 _fnMap( oSettings.oFeatures, oInit, [
1002 _fnMap( oSettings, oInit, [
1018 "fnStateLoadCallback",
1019 "fnStateSaveCallback",
1023 [ "iCookieDuration", "iStateDuration" ], // backwards compat
1024 [ "oSearch", "oPreviousSearch" ],
1025 [ "aoSearchCols", "aoPreSearchCols" ],
1026 [ "iDisplayLength", "_iDisplayLength" ],
1027 [ "bJQueryUI", "bJUI" ]
1029 _fnMap( oSettings.oScroll, oInit, [
1030 [ "sScrollX", "sX" ],
1031 [ "sScrollXInner", "sXInner" ],
1032 [ "sScrollY", "sY" ],
1033 [ "bScrollCollapse", "bCollapse" ]
1035 _fnMap( oSettings.oLanguage, oInit, "fnInfoCallback" );
1037 /* Callback functions which are array driven */
1038 _fnCallbackReg( oSettings, 'aoDrawCallback', oInit.fnDrawCallback, 'user' );
1039 _fnCallbackReg( oSettings, 'aoServerParams', oInit.fnServerParams, 'user' );
1040 _fnCallbackReg( oSettings, 'aoStateSaveParams', oInit.fnStateSaveParams, 'user' );
1041 _fnCallbackReg( oSettings, 'aoStateLoadParams', oInit.fnStateLoadParams, 'user' );
1042 _fnCallbackReg( oSettings, 'aoStateLoaded', oInit.fnStateLoaded, 'user' );
1043 _fnCallbackReg( oSettings, 'aoRowCallback', oInit.fnRowCallback, 'user' );
1044 _fnCallbackReg( oSettings, 'aoRowCreatedCallback', oInit.fnCreatedRow, 'user' );
1045 _fnCallbackReg( oSettings, 'aoHeaderCallback', oInit.fnHeaderCallback, 'user' );
1046 _fnCallbackReg( oSettings, 'aoFooterCallback', oInit.fnFooterCallback, 'user' );
1047 _fnCallbackReg( oSettings, 'aoInitComplete', oInit.fnInitComplete, 'user' );
1048 _fnCallbackReg( oSettings, 'aoPreDrawCallback', oInit.fnPreDrawCallback, 'user' );
1050 oSettings.rowIdFn = _fnGetObjectDataFn( oInit.rowId );
1052 /* Browser support detection */
1053 _fnBrowserDetect( oSettings );
1055 var oClasses = oSettings.oClasses;
1057 // @todo Remove in 1.11
1058 if ( oInit.bJQueryUI )
1060 /* Use the JUI classes object for display. You could clone the oStdClasses object if
1061 * you want to have multiple tables with multiple independent classes
1063 $.extend( oClasses, DataTable.ext.oJUIClasses, oInit.oClasses );
1065 if ( oInit.sDom === defaults.sDom && defaults.sDom === "lfrtip" )
1067 /* Set the DOM to use a layout suitable for jQuery UI's theming */
1068 oSettings.sDom = '<"H"lfr>t<"F"ip>';
1071 if ( ! oSettings.renderer ) {
1072 oSettings.renderer = 'jqueryui';
1074 else if ( $.isPlainObject( oSettings.renderer ) && ! oSettings.renderer.header ) {
1075 oSettings.renderer.header = 'jqueryui';
1080 $.extend( oClasses, DataTable.ext.classes, oInit.oClasses );
1082 $this.addClass( oClasses.sTable );
1085 if ( oSettings.iInitDisplayStart === undefined )
1087 /* Display start point, taking into account the save saving */
1088 oSettings.iInitDisplayStart = oInit.iDisplayStart;
1089 oSettings._iDisplayStart = oInit.iDisplayStart;
1092 if ( oInit.iDeferLoading !== null )
1094 oSettings.bDeferLoading = true;
1095 var tmp = $.isArray( oInit.iDeferLoading );
1096 oSettings._iRecordsDisplay = tmp ? oInit.iDeferLoading[0] : oInit.iDeferLoading;
1097 oSettings._iRecordsTotal = tmp ? oInit.iDeferLoading[1] : oInit.iDeferLoading;
1100 /* Language definitions */
1101 var oLanguage = oSettings.oLanguage;
1102 $.extend( true, oLanguage, oInit.oLanguage );
1104 if ( oLanguage.sUrl )
1106 /* Get the language definitions from a file - because this Ajax call makes the language
1107 * get async to the remainder of this function we use bInitHandedOff to indicate that
1108 * _fnInitialise will be fired by the returned Ajax handler, rather than the constructor
1112 url: oLanguage.sUrl,
1113 success: function ( json ) {
1114 _fnLanguageCompat( json );
1115 _fnCamelToHungarian( defaults.oLanguage, json );
1116 $.extend( true, oLanguage, json );
1117 _fnInitialise( oSettings );
1119 error: function () {
1120 // Error occurred loading language file, continue on as best we can
1121 _fnInitialise( oSettings );
1124 bInitHandedOff = true;
1130 if ( oInit.asStripeClasses === null )
1132 oSettings.asStripeClasses =[
1133 oClasses.sStripeOdd,
1134 oClasses.sStripeEven
1138 /* Remove row stripe classes if they are already on the table row */
1139 var stripeClasses = oSettings.asStripeClasses;
1140 var rowOne = $this.children('tbody').find('tr').eq(0);
1141 if ( $.inArray( true, $.map( stripeClasses, function(el, i) {
1142 return rowOne.hasClass(el);
1144 $('tbody tr', this).removeClass( stripeClasses.join(' ') );
1145 oSettings.asDestroyStripes = stripeClasses.slice();
1150 * See if we should load columns automatically or use defined ones
1154 var nThead = this.getElementsByTagName('thead');
1155 if ( nThead.length !== 0 )
1157 _fnDetectHeader( oSettings.aoHeader, nThead[0] );
1158 anThs = _fnGetUniqueThs( oSettings );
1161 /* If not given a column array, generate one with nulls */
1162 if ( oInit.aoColumns === null )
1165 for ( i=0, iLen=anThs.length ; i<iLen ; i++ )
1167 aoColumnsInit.push( null );
1172 aoColumnsInit = oInit.aoColumns;
1175 /* Add the columns */
1176 for ( i=0, iLen=aoColumnsInit.length ; i<iLen ; i++ )
1178 _fnAddColumn( oSettings, anThs ? anThs[i] : null );
1181 /* Apply the column definitions */
1182 _fnApplyColumnDefs( oSettings, oInit.aoColumnDefs, aoColumnsInit, function (iCol, oDef) {
1183 _fnColumnOptions( oSettings, iCol, oDef );
1186 /* HTML5 attribute detection - build an mData object automatically if the
1187 * attributes are found
1189 if ( rowOne.length ) {
1190 var a = function ( cell, name ) {
1191 return cell.getAttribute( 'data-'+name ) !== null ? name : null;
1194 $( rowOne[0] ).children('th, td').each( function (i, cell) {
1195 var col = oSettings.aoColumns[i];
1197 if ( col.mData === i ) {
1198 var sort = a( cell, 'sort' ) || a( cell, 'order' );
1199 var filter = a( cell, 'filter' ) || a( cell, 'search' );
1201 if ( sort !== null || filter !== null ) {
1204 sort: sort !== null ? i+'.@data-'+sort : undefined,
1205 type: sort !== null ? i+'.@data-'+sort : undefined,
1206 filter: filter !== null ? i+'.@data-'+filter : undefined
1209 _fnColumnOptions( oSettings, i );
1215 var features = oSettings.oFeatures;
1216 var loadedInit = function () {
1219 * @todo For modularisation (1.11) this needs to do into a sort start up handler
1222 // If aaSorting is not defined, then we use the first indicator in asSorting
1223 // in case that has been altered, so the default sort reflects that option
1224 if ( oInit.aaSorting === undefined ) {
1225 var sorting = oSettings.aaSorting;
1226 for ( i=0, iLen=sorting.length ; i<iLen ; i++ ) {
1227 sorting[i][1] = oSettings.aoColumns[ i ].asSorting[0];
1231 /* Do a first pass on the sorting classes (allows any size changes to be taken into
1232 * account, and also will apply sorting disabled classes if disabled
1234 _fnSortingClasses( oSettings );
1236 if ( features.bSort ) {
1237 _fnCallbackReg( oSettings, 'aoDrawCallback', function () {
1238 if ( oSettings.bSorted ) {
1239 var aSort = _fnSortFlatten( oSettings );
1240 var sortedColumns = {};
1242 $.each( aSort, function (i, val) {
1243 sortedColumns[ val.src ] = val.dir;
1246 _fnCallbackFire( oSettings, null, 'order', [oSettings, aSort, sortedColumns] );
1247 _fnSortAria( oSettings );
1252 _fnCallbackReg( oSettings, 'aoDrawCallback', function () {
1253 if ( oSettings.bSorted || _fnDataSource( oSettings ) === 'ssp' || features.bDeferRender ) {
1254 _fnSortingClasses( oSettings );
1261 * Cache the header, body and footer as required, creating them if needed
1264 // Work around for Webkit bug 83867 - store the caption-side before removing from doc
1265 var captions = $this.children('caption').each( function () {
1266 this._captionSide = $(this).css('caption-side');
1269 var thead = $this.children('thead');
1270 if ( thead.length === 0 ) {
1271 thead = $('<thead/>').appendTo($this);
1273 oSettings.nTHead = thead[0];
1275 var tbody = $this.children('tbody');
1276 if ( tbody.length === 0 ) {
1277 tbody = $('<tbody/>').appendTo($this);
1279 oSettings.nTBody = tbody[0];
1281 var tfoot = $this.children('tfoot');
1282 if ( tfoot.length === 0 && captions.length > 0 && (oSettings.oScroll.sX !== "" || oSettings.oScroll.sY !== "") ) {
1283 // If we are a scrolling table, and no footer has been given, then we need to create
1284 // a tfoot element for the caption element to be appended to
1285 tfoot = $('<tfoot/>').appendTo($this);
1288 if ( tfoot.length === 0 || tfoot.children().length === 0 ) {
1289 $this.addClass( oClasses.sNoFooter );
1291 else if ( tfoot.length > 0 ) {
1292 oSettings.nTFoot = tfoot[0];
1293 _fnDetectHeader( oSettings.aoFooter, oSettings.nTFoot );
1296 /* Check if there is data passing into the constructor */
1297 if ( oInit.aaData ) {
1298 for ( i=0 ; i<oInit.aaData.length ; i++ ) {
1299 _fnAddData( oSettings, oInit.aaData[ i ] );
1302 else if ( oSettings.bDeferLoading || _fnDataSource( oSettings ) == 'dom' ) {
1303 /* Grab the data from the page - only do this when deferred loading or no Ajax
1304 * source since there is no point in reading the DOM data if we are then going
1305 * to replace it with Ajax data
1307 _fnAddTr( oSettings, $(oSettings.nTBody).children('tr') );
1310 /* Copy the data index array */
1311 oSettings.aiDisplay = oSettings.aiDisplayMaster.slice();
1313 /* Initialisation complete - table can be drawn */
1314 oSettings.bInitialised = true;
1316 /* Check if we need to initialise the table (it might not have been handed off to the
1317 * language processor)
1319 if ( bInitHandedOff === false ) {
1320 _fnInitialise( oSettings );
1324 /* Must be done after everything which can be overridden by the state saving! */
1325 if ( oInit.bStateSave )
1327 features.bStateSave = true;
1328 _fnCallbackReg( oSettings, 'aoDrawCallback', _fnSaveState, 'state_save' );
1329 _fnLoadState( oSettings, oInit, loadedInit );
1342 * It is useful to have variables which are scoped locally so only the
1343 * DataTables functions can access them and they don't leak into global space.
1344 * At the same time these functions are often useful over multiple files in the
1345 * core and API, so we list, or at least document, all variables which are used
1346 * by DataTables as private variables here. This also ensures that there is no
1347 * clashing of variable names and that they can easily referenced for reuse.
1351 // Defined else where
1355 // _selector_row_indexes
1357 var _ext; // DataTable.ext
1358 var _Api; // DataTable.Api
1359 var _api_register; // DataTable.Api.register
1360 var _api_registerPlural; // DataTable.Api.registerPlural
1363 var _re_new_lines = /[\r\n]/g;
1364 var _re_html = /<.*?>/g;
1366 // This is not strict ISO8601 - Date.parse() is quite lax, although
1367 // implementations differ between browsers.
1368 var _re_date = /^\d{2,4}[\.\/\-]\d{1,2}[\.\/\-]\d{1,2}([T ]{1}\d{1,2}[:\.]\d{2}([\.:]\d{2})?)?$/;
1370 // Escape regular expression special characters
1371 var _re_escape_regex = new RegExp( '(\\' + [ '/', '.', '*', '+', '?', '|', '(', ')', '[', ']', '{', '}', '\\', '$', '^', '-' ].join('|\\') + ')', 'g' );
1373 // http://en.wikipedia.org/wiki/Foreign_exchange_market
1374 // - \u20BD - Russian ruble.
1375 // - \u20a9 - South Korean Won
1376 // - \u20BA - Turkish Lira
1377 // - \u20B9 - Indian Rupee
1378 // - R - Brazil (R$) and South Africa
1379 // - fr - Swiss Franc
1380 // - kr - Swedish krona, Norwegian krone and Danish krone
1381 // - \u2009 is thin space and \u202F is narrow no-break space, both used in many
1382 // standards as thousands separators.
1383 var _re_formatted_numeric = /[',$£€¥%\u2009\u202F\u20BD\u20a9\u20BArfk]/gi;
1386 var _empty = function ( d ) {
1387 return !d || d === true || d === '-' ? true : false;
1391 var _intVal = function ( s ) {
1392 var integer = parseInt( s, 10 );
1393 return !isNaN(integer) && isFinite(s) ? integer : null;
1396 // Convert from a formatted number with characters other than `.` as the
1397 // decimal place, to a Javascript number
1398 var _numToDecimal = function ( num, decimalPoint ) {
1399 // Cache created regular expressions for speed as this function is called often
1400 if ( ! _re_dic[ decimalPoint ] ) {
1401 _re_dic[ decimalPoint ] = new RegExp( _fnEscapeRegex( decimalPoint ), 'g' );
1403 return typeof num === 'string' && decimalPoint !== '.' ?
1404 num.replace( /\./g, '' ).replace( _re_dic[ decimalPoint ], '.' ) :
1409 var _isNumber = function ( d, decimalPoint, formatted ) {
1410 var strType = typeof d === 'string';
1412 // If empty return immediately so there must be a number if it is a
1413 // formatted string (this stops the string "k", or "kr", etc being detected
1414 // as a formatted number for currency
1415 if ( _empty( d ) ) {
1419 if ( decimalPoint && strType ) {
1420 d = _numToDecimal( d, decimalPoint );
1423 if ( formatted && strType ) {
1424 d = d.replace( _re_formatted_numeric, '' );
1427 return !isNaN( parseFloat(d) ) && isFinite( d );
1431 // A string without HTML in it can be considered to be HTML still
1432 var _isHtml = function ( d ) {
1433 return _empty( d ) || typeof d === 'string';
1437 var _htmlNumeric = function ( d, decimalPoint, formatted ) {
1438 if ( _empty( d ) ) {
1442 var html = _isHtml( d );
1445 _isNumber( _stripHtml( d ), decimalPoint, formatted ) ?
1451 var _pluck = function ( a, prop, prop2 ) {
1453 var i=0, ien=a.length;
1455 // Could have the test in the loop for slightly smaller code, but speed
1456 // is essential here
1457 if ( prop2 !== undefined ) {
1458 for ( ; i<ien ; i++ ) {
1459 if ( a[i] && a[i][ prop ] ) {
1460 out.push( a[i][ prop ][ prop2 ] );
1465 for ( ; i<ien ; i++ ) {
1467 out.push( a[i][ prop ] );
1476 // Basically the same as _pluck, but rather than looping over `a` we use `order`
1477 // as the indexes to pick from `a`
1478 var _pluck_order = function ( a, order, prop, prop2 )
1481 var i=0, ien=order.length;
1483 // Could have the test in the loop for slightly smaller code, but speed
1484 // is essential here
1485 if ( prop2 !== undefined ) {
1486 for ( ; i<ien ; i++ ) {
1487 if ( a[ order[i] ][ prop ] ) {
1488 out.push( a[ order[i] ][ prop ][ prop2 ] );
1493 for ( ; i<ien ; i++ ) {
1494 out.push( a[ order[i] ][ prop ] );
1502 var _range = function ( len, start )
1507 if ( start === undefined ) {
1516 for ( var i=start ; i<end ; i++ ) {
1524 var _removeEmpty = function ( a )
1528 for ( var i=0, ien=a.length ; i<ien ; i++ ) {
1529 if ( a[i] ) { // careful - will remove all falsy values!
1538 var _stripHtml = function ( d ) {
1539 return d.replace( _re_html, '' );
1544 * Determine if all values in the array are unique. This means we can short
1545 * cut the _unique method at the cost of a single loop. A sorted array is used
1546 * to easily check the values.
1548 * @param {array} src Source array
1549 * @return {boolean} true if all unique, false otherwise
1552 var _areAllUnique = function ( src ) {
1553 if ( src.length < 2 ) {
1557 var sorted = src.slice().sort();
1558 var last = sorted[0];
1560 for ( var i=1, ien=sorted.length ; i<ien ; i++ ) {
1561 if ( sorted[i] === last ) {
1573 * Find the unique elements in a source array.
1575 * @param {array} src Source array
1576 * @return {array} Array of unique items
1579 var _unique = function ( src )
1581 if ( _areAllUnique( src ) ) {
1585 // A faster unique method is to use object keys to identify used values,
1586 // but this doesn't work with arrays or objects, which we must also
1587 // consider. See jsperf.com/compare-array-unique-versions/4 for more
1595 again: for ( i=0 ; i<ien ; i++ ) {
1598 for ( j=0 ; j<k ; j++ ) {
1599 if ( out[j] === val ) {
1613 * DataTables utility methods
1615 * This namespace provides helper methods that DataTables uses internally to
1616 * create a DataTable, but which are not exclusively used only for DataTables.
1617 * These methods can be used by extension authors to save the duplication of
1624 * Throttle the calls to a function. Arguments and context are maintained
1625 * for the throttled function.
1627 * @param {function} fn Function to be called
1628 * @param {integer} freq Call frequency in mS
1629 * @return {function} Wrapped function
1631 throttle: function ( fn, freq ) {
1633 frequency = freq !== undefined ? freq : 200,
1637 return function () {
1643 if ( last && now < last + frequency ) {
1644 clearTimeout( timer );
1646 timer = setTimeout( function () {
1648 fn.apply( that, args );
1653 fn.apply( that, args );
1660 * Escape a string such that it can be used in a regular expression
1662 * @param {string} val string to escape
1663 * @returns {string} escaped string
1665 escapeRegex: function ( val ) {
1666 return val.replace( _re_escape_regex, '\\$1' );
1673 * Create a mapping object that allows camel case parameters to be looked up
1674 * for their Hungarian counterparts. The mapping is stored in a private
1675 * parameter called `_hungarianMap` which can be accessed on the source object.
1677 * @memberof DataTable#oApi
1679 function _fnHungarianMap ( o )
1682 hungarian = 'a aa ai ao as b fn i m o s ',
1687 $.each( o, function (key, val) {
1688 match = key.match(/^([^A-Z]+?)([A-Z])/);
1690 if ( match && hungarian.indexOf(match[1]+' ') !== -1 )
1692 newKey = key.replace( match[0], match[2].toLowerCase() );
1693 map[ newKey ] = key;
1695 if ( match[1] === 'o' )
1697 _fnHungarianMap( o[key] );
1702 o._hungarianMap = map;
1707 * Convert from camel case parameters to Hungarian, based on a Hungarian map
1708 * created by _fnHungarianMap.
1709 * @param {object} src The model object which holds all parameters that can be
1711 * @param {object} user The object to convert from camel case to Hungarian.
1712 * @param {boolean} force When set to `true`, properties which already have a
1713 * Hungarian value in the `user` object will be overwritten. Otherwise they
1715 * @memberof DataTable#oApi
1717 function _fnCamelToHungarian ( src, user, force )
1719 if ( ! src._hungarianMap ) {
1720 _fnHungarianMap( src );
1725 $.each( user, function (key, val) {
1726 hungarianKey = src._hungarianMap[ key ];
1728 if ( hungarianKey !== undefined && (force || user[hungarianKey] === undefined) )
1730 // For objects, we need to buzz down into the object to copy parameters
1731 if ( hungarianKey.charAt(0) === 'o' )
1733 // Copy the camelCase options over to the hungarian
1734 if ( ! user[ hungarianKey ] ) {
1735 user[ hungarianKey ] = {};
1737 $.extend( true, user[hungarianKey], user[key] );
1739 _fnCamelToHungarian( src[hungarianKey], user[hungarianKey], force );
1742 user[hungarianKey] = user[ key ];
1750 * Language compatibility - when certain options are given, and others aren't, we
1751 * need to duplicate the values over, in order to provide backwards compatibility
1752 * with older language files.
1753 * @param {object} oSettings dataTables settings object
1754 * @memberof DataTable#oApi
1756 function _fnLanguageCompat( lang )
1758 var defaults = DataTable.defaults.oLanguage;
1759 var zeroRecords = lang.sZeroRecords;
1761 /* Backwards compatibility - if there is no sEmptyTable given, then use the same as
1762 * sZeroRecords - assuming that is given.
1764 if ( ! lang.sEmptyTable && zeroRecords &&
1765 defaults.sEmptyTable === "No data available in table" )
1767 _fnMap( lang, lang, 'sZeroRecords', 'sEmptyTable' );
1770 /* Likewise with loading records */
1771 if ( ! lang.sLoadingRecords && zeroRecords &&
1772 defaults.sLoadingRecords === "Loading..." )
1774 _fnMap( lang, lang, 'sZeroRecords', 'sLoadingRecords' );
1777 // Old parameter name of the thousands separator mapped onto the new
1778 if ( lang.sInfoThousands ) {
1779 lang.sThousands = lang.sInfoThousands;
1782 var decimal = lang.sDecimal;
1784 _addNumericSort( decimal );
1790 * Map one parameter onto another
1791 * @param {object} o Object to map
1792 * @param {*} knew The new parameter name
1793 * @param {*} old The old parameter name
1795 var _fnCompatMap = function ( o, knew, old ) {
1796 if ( o[ knew ] !== undefined ) {
1797 o[ old ] = o[ knew ];
1803 * Provide backwards compatibility for the main DT options. Note that the new
1804 * options are mapped onto the old parameters, so this is an external interface
1806 * @param {object} init Object to map
1808 function _fnCompatOpts ( init )
1810 _fnCompatMap( init, 'ordering', 'bSort' );
1811 _fnCompatMap( init, 'orderMulti', 'bSortMulti' );
1812 _fnCompatMap( init, 'orderClasses', 'bSortClasses' );
1813 _fnCompatMap( init, 'orderCellsTop', 'bSortCellsTop' );
1814 _fnCompatMap( init, 'order', 'aaSorting' );
1815 _fnCompatMap( init, 'orderFixed', 'aaSortingFixed' );
1816 _fnCompatMap( init, 'paging', 'bPaginate' );
1817 _fnCompatMap( init, 'pagingType', 'sPaginationType' );
1818 _fnCompatMap( init, 'pageLength', 'iDisplayLength' );
1819 _fnCompatMap( init, 'searching', 'bFilter' );
1821 // Boolean initialisation of x-scrolling
1822 if ( typeof init.sScrollX === 'boolean' ) {
1823 init.sScrollX = init.sScrollX ? '100%' : '';
1825 if ( typeof init.scrollX === 'boolean' ) {
1826 init.scrollX = init.scrollX ? '100%' : '';
1829 // Column search objects are in an array, so it needs to be converted
1830 // element by element
1831 var searchCols = init.aoSearchCols;
1834 for ( var i=0, ien=searchCols.length ; i<ien ; i++ ) {
1835 if ( searchCols[i] ) {
1836 _fnCamelToHungarian( DataTable.models.oSearch, searchCols[i] );
1844 * Provide backwards compatibility for column options. Note that the new options
1845 * are mapped onto the old parameters, so this is an external interface change
1847 * @param {object} init Object to map
1849 function _fnCompatCols ( init )
1851 _fnCompatMap( init, 'orderable', 'bSortable' );
1852 _fnCompatMap( init, 'orderData', 'aDataSort' );
1853 _fnCompatMap( init, 'orderSequence', 'asSorting' );
1854 _fnCompatMap( init, 'orderDataType', 'sortDataType' );
1856 // orderData can be given as an integer
1857 var dataSort = init.aDataSort;
1858 if ( typeof dataSort === 'number' && ! $.isArray( dataSort ) ) {
1859 init.aDataSort = [ dataSort ];
1865 * Browser feature detection for capabilities, quirks
1866 * @param {object} settings dataTables settings object
1867 * @memberof DataTable#oApi
1869 function _fnBrowserDetect( settings )
1871 // We don't need to do this every time DataTables is constructed, the values
1872 // calculated are specific to the browser and OS configuration which we
1873 // don't expect to change between initialisations
1874 if ( ! DataTable.__browser ) {
1876 DataTable.__browser = browser;
1878 // Scrolling feature / quirks detection
1883 left: $(window).scrollLeft()*-1, // allow for scrolling
1891 position: 'absolute',
1905 .appendTo( 'body' );
1907 var outer = n.children();
1908 var inner = outer.children();
1910 // Numbers below, in order, are:
1911 // inner.offsetWidth, inner.clientWidth, outer.offsetWidth, outer.clientWidth
1913 // IE6 XP: 100 100 100 83
1914 // IE7 Vista: 100 100 100 83
1915 // IE 8+ Windows: 83 83 100 83
1916 // Evergreen Windows: 83 83 100 83
1917 // Evergreen Mac with scrollbars: 85 85 100 85
1918 // Evergreen Mac without scrollbars: 100 100 100 100
1920 // Get scrollbar width
1921 browser.barWidth = outer[0].offsetWidth - outer[0].clientWidth;
1923 // IE6/7 will oversize a width 100% element inside a scrolling element, to
1924 // include the width of the scrollbar, while other browsers ensure the inner
1925 // element is contained without forcing scrolling
1926 browser.bScrollOversize = inner[0].offsetWidth === 100 && outer[0].clientWidth !== 100;
1928 // In rtl text layout, some browsers (most, but not all) will place the
1929 // scrollbar on the left, rather than the right.
1930 browser.bScrollbarLeft = Math.round( inner.offset().left ) !== 1;
1932 // IE8- don't provide height and width for getBoundingClientRect
1933 browser.bBounding = n[0].getBoundingClientRect().width ? true : false;
1938 $.extend( settings.oBrowser, DataTable.__browser );
1939 settings.oScroll.iBarWidth = DataTable.__browser.barWidth;
1944 * Array.prototype reduce[Right] method, used for browsers which don't support
1945 * JS 1.6. Done this way to reduce code size, since we iterate either way
1946 * @param {object} settings dataTables settings object
1947 * @memberof DataTable#oApi
1949 function _fnReduce ( that, fn, init, start, end, inc )
1956 if ( init !== undefined ) {
1961 while ( i !== end ) {
1962 if ( ! that.hasOwnProperty(i) ) {
1967 fn( value, that[i], i, that ) :
1978 * Add a column to the list used for the table with default values
1979 * @param {object} oSettings dataTables settings object
1980 * @param {node} nTh The th element for this column
1981 * @memberof DataTable#oApi
1983 function _fnAddColumn( oSettings, nTh )
1985 // Add column to aoColumns array
1986 var oDefaults = DataTable.defaults.column;
1987 var iCol = oSettings.aoColumns.length;
1988 var oCol = $.extend( {}, DataTable.models.oColumn, oDefaults, {
1989 "nTh": nTh ? nTh : document.createElement('th'),
1990 "sTitle": oDefaults.sTitle ? oDefaults.sTitle : nTh ? nTh.innerHTML : '',
1991 "aDataSort": oDefaults.aDataSort ? oDefaults.aDataSort : [iCol],
1992 "mData": oDefaults.mData ? oDefaults.mData : iCol,
1995 oSettings.aoColumns.push( oCol );
1997 // Add search object for column specific search. Note that the `searchCols[ iCol ]`
1998 // passed into extend can be undefined. This allows the user to give a default
1999 // with only some of the parameters defined, and also not give a default
2000 var searchCols = oSettings.aoPreSearchCols;
2001 searchCols[ iCol ] = $.extend( {}, DataTable.models.oSearch, searchCols[ iCol ] );
2003 // Use the default column options function to initialise classes etc
2004 _fnColumnOptions( oSettings, iCol, $(nTh).data() );
2009 * Apply options for a column
2010 * @param {object} oSettings dataTables settings object
2011 * @param {int} iCol column index to consider
2012 * @param {object} oOptions object with sType, bVisible and bSearchable etc
2013 * @memberof DataTable#oApi
2015 function _fnColumnOptions( oSettings, iCol, oOptions )
2017 var oCol = oSettings.aoColumns[ iCol ];
2018 var oClasses = oSettings.oClasses;
2019 var th = $(oCol.nTh);
2021 // Try to get width information from the DOM. We can't get it from CSS
2022 // as we'd need to parse the CSS stylesheet. `width` option can override
2023 if ( ! oCol.sWidthOrig ) {
2025 oCol.sWidthOrig = th.attr('width') || null;
2028 var t = (th.attr('style') || '').match(/width:\s*(\d+[pxem%]+)/);
2030 oCol.sWidthOrig = t[1];
2034 /* User specified column options */
2035 if ( oOptions !== undefined && oOptions !== null )
2037 // Backwards compatibility
2038 _fnCompatCols( oOptions );
2040 // Map camel case parameters to their Hungarian counterparts
2041 _fnCamelToHungarian( DataTable.defaults.column, oOptions );
2043 /* Backwards compatibility for mDataProp */
2044 if ( oOptions.mDataProp !== undefined && !oOptions.mData )
2046 oOptions.mData = oOptions.mDataProp;
2049 if ( oOptions.sType )
2051 oCol._sManualType = oOptions.sType;
2054 // `class` is a reserved word in Javascript, so we need to provide
2055 // the ability to use a valid name for the camel case input
2056 if ( oOptions.className && ! oOptions.sClass )
2058 oOptions.sClass = oOptions.className;
2061 $.extend( oCol, oOptions );
2062 _fnMap( oCol, oOptions, "sWidth", "sWidthOrig" );
2064 /* iDataSort to be applied (backwards compatibility), but aDataSort will take
2065 * priority if defined
2067 if ( oOptions.iDataSort !== undefined )
2069 oCol.aDataSort = [ oOptions.iDataSort ];
2071 _fnMap( oCol, oOptions, "aDataSort" );
2074 /* Cache the data get and set functions for speed */
2075 var mDataSrc = oCol.mData;
2076 var mData = _fnGetObjectDataFn( mDataSrc );
2077 var mRender = oCol.mRender ? _fnGetObjectDataFn( oCol.mRender ) : null;
2079 var attrTest = function( src ) {
2080 return typeof src === 'string' && src.indexOf('@') !== -1;
2082 oCol._bAttrSrc = $.isPlainObject( mDataSrc ) && (
2083 attrTest(mDataSrc.sort) || attrTest(mDataSrc.type) || attrTest(mDataSrc.filter)
2085 oCol._setter = null;
2087 oCol.fnGetData = function (rowData, type, meta) {
2088 var innerData = mData( rowData, type, undefined, meta );
2090 return mRender && type ?
2091 mRender( innerData, type, rowData, meta ) :
2094 oCol.fnSetData = function ( rowData, val, meta ) {
2095 return _fnSetObjectDataFn( mDataSrc )( rowData, val, meta );
2098 // Indicate if DataTables should read DOM data as an object or array
2099 // Used in _fnGetRowElements
2100 if ( typeof mDataSrc !== 'number' ) {
2101 oSettings._rowReadObject = true;
2104 /* Feature sorting overrides column specific when off */
2105 if ( !oSettings.oFeatures.bSort )
2107 oCol.bSortable = false;
2108 th.addClass( oClasses.sSortableNone ); // Have to add class here as order event isn't called
2111 /* Check that the class assignment is correct for sorting */
2112 var bAsc = $.inArray('asc', oCol.asSorting) !== -1;
2113 var bDesc = $.inArray('desc', oCol.asSorting) !== -1;
2114 if ( !oCol.bSortable || (!bAsc && !bDesc) )
2116 oCol.sSortingClass = oClasses.sSortableNone;
2117 oCol.sSortingClassJUI = "";
2119 else if ( bAsc && !bDesc )
2121 oCol.sSortingClass = oClasses.sSortableAsc;
2122 oCol.sSortingClassJUI = oClasses.sSortJUIAscAllowed;
2124 else if ( !bAsc && bDesc )
2126 oCol.sSortingClass = oClasses.sSortableDesc;
2127 oCol.sSortingClassJUI = oClasses.sSortJUIDescAllowed;
2131 oCol.sSortingClass = oClasses.sSortable;
2132 oCol.sSortingClassJUI = oClasses.sSortJUI;
2138 * Adjust the table column widths for new data. Note: you would probably want to
2139 * do a redraw after calling this function!
2140 * @param {object} settings dataTables settings object
2141 * @memberof DataTable#oApi
2143 function _fnAdjustColumnSizing ( settings )
2145 /* Not interested in doing column width calculation if auto-width is disabled */
2146 if ( settings.oFeatures.bAutoWidth !== false )
2148 var columns = settings.aoColumns;
2150 _fnCalculateColumnWidths( settings );
2151 for ( var i=0 , iLen=columns.length ; i<iLen ; i++ )
2153 columns[i].nTh.style.width = columns[i].sWidth;
2157 var scroll = settings.oScroll;
2158 if ( scroll.sY !== '' || scroll.sX !== '')
2160 _fnScrollDraw( settings );
2163 _fnCallbackFire( settings, null, 'column-sizing', [settings] );
2168 * Covert the index of a visible column to the index in the data array (take account
2169 * of hidden columns)
2170 * @param {object} oSettings dataTables settings object
2171 * @param {int} iMatch Visible column index to lookup
2172 * @returns {int} i the data index
2173 * @memberof DataTable#oApi
2175 function _fnVisibleToColumnIndex( oSettings, iMatch )
2177 var aiVis = _fnGetColumns( oSettings, 'bVisible' );
2179 return typeof aiVis[iMatch] === 'number' ?
2186 * Covert the index of an index in the data array and convert it to the visible
2187 * column index (take account of hidden columns)
2188 * @param {int} iMatch Column index to lookup
2189 * @param {object} oSettings dataTables settings object
2190 * @returns {int} i the data index
2191 * @memberof DataTable#oApi
2193 function _fnColumnIndexToVisible( oSettings, iMatch )
2195 var aiVis = _fnGetColumns( oSettings, 'bVisible' );
2196 var iPos = $.inArray( iMatch, aiVis );
2198 return iPos !== -1 ? iPos : null;
2203 * Get the number of visible columns
2204 * @param {object} oSettings dataTables settings object
2205 * @returns {int} i the number of visible columns
2206 * @memberof DataTable#oApi
2208 function _fnVisbleColumns( oSettings )
2212 // No reduce in IE8, use a loop for now
2213 $.each( oSettings.aoColumns, function ( i, col ) {
2214 if ( col.bVisible && $(col.nTh).css('display') !== 'none' ) {
2224 * Get an array of column indexes that match a given property
2225 * @param {object} oSettings dataTables settings object
2226 * @param {string} sParam Parameter in aoColumns to look for - typically
2227 * bVisible or bSearchable
2228 * @returns {array} Array of indexes with matched properties
2229 * @memberof DataTable#oApi
2231 function _fnGetColumns( oSettings, sParam )
2235 $.map( oSettings.aoColumns, function(val, i) {
2236 if ( val[sParam] ) {
2246 * Calculate the 'type' of a column
2247 * @param {object} settings dataTables settings object
2248 * @memberof DataTable#oApi
2250 function _fnColumnTypes ( settings )
2252 var columns = settings.aoColumns;
2253 var data = settings.aoData;
2254 var types = DataTable.ext.type.detect;
2255 var i, ien, j, jen, k, ken;
2256 var col, cell, detectedType, cache;
2258 // For each column, spin over the
2259 for ( i=0, ien=columns.length ; i<ien ; i++ ) {
2263 if ( ! col.sType && col._sManualType ) {
2264 col.sType = col._sManualType;
2266 else if ( ! col.sType ) {
2267 for ( j=0, jen=types.length ; j<jen ; j++ ) {
2268 for ( k=0, ken=data.length ; k<ken ; k++ ) {
2269 // Use a cache array so we only need to get the type data
2270 // from the formatter once (when using multiple detectors)
2271 if ( cache[k] === undefined ) {
2272 cache[k] = _fnGetCellData( settings, k, i, 'type' );
2275 detectedType = types[j]( cache[k], settings );
2277 // If null, then this type can't apply to this column, so
2278 // rather than testing all cells, break out. There is an
2279 // exception for the last type which is `html`. We need to
2280 // scan all rows since it is possible to mix string and HTML
2282 if ( ! detectedType && j !== types.length-1 ) {
2286 // Only a single match is needed for html type since it is
2287 // bottom of the pile and very similar to string
2288 if ( detectedType === 'html' ) {
2293 // Type is valid for all data points in the column - use this
2295 if ( detectedType ) {
2296 col.sType = detectedType;
2301 // Fall back - if no type was detected, always use string
2302 if ( ! col.sType ) {
2303 col.sType = 'string';
2311 * Take the column definitions and static columns arrays and calculate how
2312 * they relate to column indexes. The callback function will then apply the
2313 * definition found for a column to a suitable configuration object.
2314 * @param {object} oSettings dataTables settings object
2315 * @param {array} aoColDefs The aoColumnDefs array that is to be applied
2316 * @param {array} aoCols The aoColumns array that defines columns individually
2317 * @param {function} fn Callback function - takes two parameters, the calculated
2318 * column index and the definition for that column.
2319 * @memberof DataTable#oApi
2321 function _fnApplyColumnDefs( oSettings, aoColDefs, aoCols, fn )
2323 var i, iLen, j, jLen, k, kLen, def;
2324 var columns = oSettings.aoColumns;
2326 // Column definitions with aTargets
2329 /* Loop over the definitions array - loop in reverse so first instance has priority */
2330 for ( i=aoColDefs.length-1 ; i>=0 ; i-- )
2334 /* Each definition can target multiple columns, as it is an array */
2335 var aTargets = def.targets !== undefined ?
2339 if ( ! $.isArray( aTargets ) )
2341 aTargets = [ aTargets ];
2344 for ( j=0, jLen=aTargets.length ; j<jLen ; j++ )
2346 if ( typeof aTargets[j] === 'number' && aTargets[j] >= 0 )
2348 /* Add columns that we don't yet know about */
2349 while( columns.length <= aTargets[j] )
2351 _fnAddColumn( oSettings );
2354 /* Integer, basic index */
2355 fn( aTargets[j], def );
2357 else if ( typeof aTargets[j] === 'number' && aTargets[j] < 0 )
2359 /* Negative integer, right to left column counting */
2360 fn( columns.length+aTargets[j], def );
2362 else if ( typeof aTargets[j] === 'string' )
2364 /* Class name matching on TH element */
2365 for ( k=0, kLen=columns.length ; k<kLen ; k++ )
2367 if ( aTargets[j] == "_all" ||
2368 $(columns[k].nTh).hasClass( aTargets[j] ) )
2378 // Statically defined columns array
2381 for ( i=0, iLen=aoCols.length ; i<iLen ; i++ )
2389 * Add a data array to the table, creating DOM node etc. This is the parallel to
2390 * _fnGatherData, but for adding rows from a Javascript source, rather than a
2392 * @param {object} oSettings dataTables settings object
2393 * @param {array} aData data array to be added
2394 * @param {node} [nTr] TR element to add to the table - optional. If not given,
2395 * DataTables will create a row automatically
2396 * @param {array} [anTds] Array of TD|TH elements for the row - must be given
2398 * @returns {int} >=0 if successful (index of new aoData entry), -1 if failed
2399 * @memberof DataTable#oApi
2401 function _fnAddData ( oSettings, aDataIn, nTr, anTds )
2403 /* Create the object for storing information about this new row */
2404 var iRow = oSettings.aoData.length;
2405 var oData = $.extend( true, {}, DataTable.models.oRow, {
2406 src: nTr ? 'dom' : 'data',
2410 oData._aData = aDataIn;
2411 oSettings.aoData.push( oData );
2413 /* Create the cells */
2415 var columns = oSettings.aoColumns;
2417 // Invalidate the column types as the new data needs to be revalidated
2418 for ( var i=0, iLen=columns.length ; i<iLen ; i++ )
2420 columns[i].sType = null;
2423 /* Add to the display array */
2424 oSettings.aiDisplayMaster.push( iRow );
2426 var id = oSettings.rowIdFn( aDataIn );
2427 if ( id !== undefined ) {
2428 oSettings.aIds[ id ] = oData;
2431 /* Create the DOM information, or register it if already present */
2432 if ( nTr || ! oSettings.oFeatures.bDeferRender )
2434 _fnCreateTr( oSettings, iRow, nTr, anTds );
2442 * Add one or more TR elements to the table. Generally we'd expect to
2443 * use this for reading data from a DOM sourced table, but it could be
2444 * used for an TR element. Note that if a TR is given, it is used (i.e.
2445 * it is not cloned).
2446 * @param {object} settings dataTables settings object
2447 * @param {array|node|jQuery} trs The TR element(s) to add to the table
2448 * @returns {array} Array of indexes for the added rows
2449 * @memberof DataTable#oApi
2451 function _fnAddTr( settings, trs )
2455 // Allow an individual node to be passed in
2456 if ( ! (trs instanceof $) ) {
2460 return trs.map( function (i, el) {
2461 row = _fnGetRowElements( settings, el );
2462 return _fnAddData( settings, row.data, el, row.cells );
2468 * Take a TR element and convert it to an index in aoData
2469 * @param {object} oSettings dataTables settings object
2470 * @param {node} n the TR element to find
2471 * @returns {int} index if the node is found, null if not
2472 * @memberof DataTable#oApi
2474 function _fnNodeToDataIndex( oSettings, n )
2476 return (n._DT_RowIndex!==undefined) ? n._DT_RowIndex : null;
2481 * Take a TD element and convert it into a column data index (not the visible index)
2482 * @param {object} oSettings dataTables settings object
2483 * @param {int} iRow The row number the TD/TH can be found in
2484 * @param {node} n The TD/TH element to find
2485 * @returns {int} index if the node is found, -1 if not
2486 * @memberof DataTable#oApi
2488 function _fnNodeToColumnIndex( oSettings, iRow, n )
2490 return $.inArray( n, oSettings.aoData[ iRow ].anCells );
2495 * Get the data for a given cell from the internal cache, taking into account data mapping
2496 * @param {object} settings dataTables settings object
2497 * @param {int} rowIdx aoData row id
2498 * @param {int} colIdx Column index
2499 * @param {string} type data get type ('display', 'type' 'filter' 'sort')
2500 * @returns {*} Cell data
2501 * @memberof DataTable#oApi
2503 function _fnGetCellData( settings, rowIdx, colIdx, type )
2505 var draw = settings.iDraw;
2506 var col = settings.aoColumns[colIdx];
2507 var rowData = settings.aoData[rowIdx]._aData;
2508 var defaultContent = col.sDefaultContent;
2509 var cellData = col.fnGetData( rowData, type, {
2515 if ( cellData === undefined ) {
2516 if ( settings.iDrawError != draw && defaultContent === null ) {
2517 _fnLog( settings, 0, "Requested unknown parameter "+
2518 (typeof col.mData=='function' ? '{function}' : "'"+col.mData+"'")+
2519 " for row "+rowIdx+", column "+colIdx, 4 );
2520 settings.iDrawError = draw;
2522 return defaultContent;
2525 // When the data source is null and a specific data type is requested (i.e.
2526 // not the original data), we can use default column data
2527 if ( (cellData === rowData || cellData === null) && defaultContent !== null && type !== undefined ) {
2528 cellData = defaultContent;
2530 else if ( typeof cellData === 'function' ) {
2531 // If the data source is a function, then we run it and use the return,
2532 // executing in the scope of the data object (for instances)
2533 return cellData.call( rowData );
2536 if ( cellData === null && type == 'display' ) {
2544 * Set the value for a specific cell, into the internal data cache
2545 * @param {object} settings dataTables settings object
2546 * @param {int} rowIdx aoData row id
2547 * @param {int} colIdx Column index
2548 * @param {*} val Value to set
2549 * @memberof DataTable#oApi
2551 function _fnSetCellData( settings, rowIdx, colIdx, val )
2553 var col = settings.aoColumns[colIdx];
2554 var rowData = settings.aoData[rowIdx]._aData;
2556 col.fnSetData( rowData, val, {
2564 // Private variable that is used to match action syntax in the data property object
2565 var __reArray = /\[.*?\]$/;
2566 var __reFn = /\(\)$/;
2569 * Split string on periods, taking into account escaped periods
2570 * @param {string} str String to split
2571 * @return {array} Split string
2573 function _fnSplitObjNotation( str )
2575 return $.map( str.match(/(\\.|[^\.])+/g) || [''], function ( s ) {
2576 return s.replace(/\\\./g, '.');
2582 * Return a function that can be used to get data from a source object, taking
2583 * into account the ability to use nested objects as a source
2584 * @param {string|int|function} mSource The data source for the object
2585 * @returns {function} Data get function
2586 * @memberof DataTable#oApi
2588 function _fnGetObjectDataFn( mSource )
2590 if ( $.isPlainObject( mSource ) )
2592 /* Build an object of get functions, and wrap them in a single call */
2594 $.each( mSource, function (key, val) {
2596 o[key] = _fnGetObjectDataFn( val );
2600 return function (data, type, row, meta) {
2601 var t = o[type] || o._;
2602 return t !== undefined ?
2603 t(data, type, row, meta) :
2607 else if ( mSource === null )
2609 /* Give an empty string for rendering / sorting etc */
2610 return function (data) { // type, row and meta also passed, but not used
2614 else if ( typeof mSource === 'function' )
2616 return function (data, type, row, meta) {
2617 return mSource( data, type, row, meta );
2620 else if ( typeof mSource === 'string' && (mSource.indexOf('.') !== -1 ||
2621 mSource.indexOf('[') !== -1 || mSource.indexOf('(') !== -1) )
2623 /* If there is a . in the source string then the data source is in a
2624 * nested object so we loop over the data for each level to get the next
2625 * level down. On each loop we test for undefined, and if found immediately
2626 * return. This allows entire objects to be missing and sDefaultContent to
2627 * be used if defined, rather than throwing an error
2629 var fetchData = function (data, type, src) {
2630 var arrayNotation, funcNotation, out, innerSrc;
2634 var a = _fnSplitObjNotation( src );
2636 for ( var i=0, iLen=a.length ; i<iLen ; i++ )
2638 // Check if we are dealing with special notation
2639 arrayNotation = a[i].match(__reArray);
2640 funcNotation = a[i].match(__reFn);
2642 if ( arrayNotation )
2645 a[i] = a[i].replace(__reArray, '');
2647 // Condition allows simply [] to be passed in
2648 if ( a[i] !== "" ) {
2649 data = data[ a[i] ];
2653 // Get the remainder of the nested object to get
2655 innerSrc = a.join('.');
2657 // Traverse each entry in the array getting the properties requested
2658 if ( $.isArray( data ) ) {
2659 for ( var j=0, jLen=data.length ; j<jLen ; j++ ) {
2660 out.push( fetchData( data[j], type, innerSrc ) );
2664 // If a string is given in between the array notation indicators, that
2665 // is used to join the strings together, otherwise an array is returned
2666 var join = arrayNotation[0].substring(1, arrayNotation[0].length-1);
2667 data = (join==="") ? out : out.join(join);
2669 // The inner call to fetchData has already traversed through the remainder
2670 // of the source requested, so we exit from the loop
2673 else if ( funcNotation )
2676 a[i] = a[i].replace(__reFn, '');
2677 data = data[ a[i] ]();
2681 if ( data === null || data[ a[i] ] === undefined )
2685 data = data[ a[i] ];
2692 return function (data, type) { // row and meta also passed, but not used
2693 return fetchData( data, type, mSource );
2698 /* Array or flat object mapping */
2699 return function (data, type) { // row and meta also passed, but not used
2700 return data[mSource];
2707 * Return a function that can be used to set data from a source object, taking
2708 * into account the ability to use nested objects as a source
2709 * @param {string|int|function} mSource The data source for the object
2710 * @returns {function} Data set function
2711 * @memberof DataTable#oApi
2713 function _fnSetObjectDataFn( mSource )
2715 if ( $.isPlainObject( mSource ) )
2717 /* Unlike get, only the underscore (global) option is used for for
2718 * setting data since we don't know the type here. This is why an object
2719 * option is not documented for `mData` (which is read/write), but it is
2720 * for `mRender` which is read only.
2722 return _fnSetObjectDataFn( mSource._ );
2724 else if ( mSource === null )
2726 /* Nothing to do when the data source is null */
2727 return function () {};
2729 else if ( typeof mSource === 'function' )
2731 return function (data, val, meta) {
2732 mSource( data, 'set', val, meta );
2735 else if ( typeof mSource === 'string' && (mSource.indexOf('.') !== -1 ||
2736 mSource.indexOf('[') !== -1 || mSource.indexOf('(') !== -1) )
2738 /* Like the get, we need to get data from a nested object */
2739 var setData = function (data, val, src) {
2740 var a = _fnSplitObjNotation( src ), b;
2741 var aLast = a[a.length-1];
2742 var arrayNotation, funcNotation, o, innerSrc;
2744 for ( var i=0, iLen=a.length-1 ; i<iLen ; i++ )
2746 // Check if we are dealing with an array notation request
2747 arrayNotation = a[i].match(__reArray);
2748 funcNotation = a[i].match(__reFn);
2750 if ( arrayNotation )
2752 a[i] = a[i].replace(__reArray, '');
2755 // Get the remainder of the nested object to set so we can recurse
2758 innerSrc = b.join('.');
2760 // Traverse each entry in the array setting the properties requested
2761 if ( $.isArray( val ) )
2763 for ( var j=0, jLen=val.length ; j<jLen ; j++ )
2766 setData( o, val[j], innerSrc );
2767 data[ a[i] ].push( o );
2772 // We've been asked to save data to an array, but it
2773 // isn't array data to be saved. Best that can be done
2774 // is to just save the value.
2778 // The inner call to setData has already traversed through the remainder
2779 // of the source and has set the data, thus we can exit here
2782 else if ( funcNotation )
2785 a[i] = a[i].replace(__reFn, '');
2786 data = data[ a[i] ]( val );
2789 // If the nested object doesn't currently exist - since we are
2790 // trying to set the value - create it
2791 if ( data[ a[i] ] === null || data[ a[i] ] === undefined )
2795 data = data[ a[i] ];
2798 // Last item in the input - i.e, the actual set
2799 if ( aLast.match(__reFn ) )
2802 data = data[ aLast.replace(__reFn, '') ]( val );
2806 // If array notation is used, we just want to strip it and use the property name
2807 // and assign the value. If it isn't used, then we get the result we want anyway
2808 data[ aLast.replace(__reArray, '') ] = val;
2812 return function (data, val) { // meta is also passed in, but not used
2813 return setData( data, val, mSource );
2818 /* Array or flat object mapping */
2819 return function (data, val) { // meta is also passed in, but not used
2820 data[mSource] = val;
2827 * Return an array with the full table data
2828 * @param {object} oSettings dataTables settings object
2829 * @returns array {array} aData Master data array
2830 * @memberof DataTable#oApi
2832 function _fnGetDataMaster ( settings )
2834 return _pluck( settings.aoData, '_aData' );
2840 * @param {object} oSettings dataTables settings object
2841 * @memberof DataTable#oApi
2843 function _fnClearTable( settings )
2845 settings.aoData.length = 0;
2846 settings.aiDisplayMaster.length = 0;
2847 settings.aiDisplay.length = 0;
2853 * Take an array of integers (index array) and remove a target integer (value - not
2855 * @param {array} a Index array to target
2856 * @param {int} iTarget value to find
2857 * @memberof DataTable#oApi
2859 function _fnDeleteIndex( a, iTarget, splice )
2861 var iTargetIndex = -1;
2863 for ( var i=0, iLen=a.length ; i<iLen ; i++ )
2865 if ( a[i] == iTarget )
2869 else if ( a[i] > iTarget )
2875 if ( iTargetIndex != -1 && splice === undefined )
2877 a.splice( iTargetIndex, 1 );
2883 * Mark cached data as invalid such that a re-read of the data will occur when
2884 * the cached data is next requested. Also update from the data source object.
2886 * @param {object} settings DataTables settings object
2887 * @param {int} rowIdx Row index to invalidate
2888 * @param {string} [src] Source to invalidate from: undefined, 'auto', 'dom'
2890 * @param {int} [colIdx] Column index to invalidate. If undefined the whole
2891 * row will be invalidated
2892 * @memberof DataTable#oApi
2894 * @todo For the modularisation of v1.11 this will need to become a callback, so
2895 * the sort and filter methods can subscribe to it. That will required
2896 * initialisation options for sorting, which is why it is not already baked in
2898 function _fnInvalidate( settings, rowIdx, src, colIdx )
2900 var row = settings.aoData[ rowIdx ];
2902 var cellWrite = function ( cell, col ) {
2903 // This is very frustrating, but in IE if you just write directly
2904 // to innerHTML, and elements that are overwritten are GC'ed,
2905 // even if there is a reference to them elsewhere
2906 while ( cell.childNodes.length ) {
2907 cell.removeChild( cell.firstChild );
2910 cell.innerHTML = _fnGetCellData( settings, rowIdx, col, 'display' );
2913 // Are we reading last data from DOM or the data object?
2914 if ( src === 'dom' || ((! src || src === 'auto') && row.src === 'dom') ) {
2915 // Read the data from the DOM
2916 row._aData = _fnGetRowElements(
2917 settings, row, colIdx, colIdx === undefined ? undefined : row._aData
2922 // Reading from data object, update the DOM
2923 var cells = row.anCells;
2926 if ( colIdx !== undefined ) {
2927 cellWrite( cells[colIdx], colIdx );
2930 for ( i=0, ien=cells.length ; i<ien ; i++ ) {
2931 cellWrite( cells[i], i );
2937 // For both row and cell invalidation, the cached data for sorting and
2938 // filtering is nulled out
2939 row._aSortData = null;
2940 row._aFilterData = null;
2942 // Invalidate the type for a specific column (if given) or all columns since
2943 // the data might have changed
2944 var cols = settings.aoColumns;
2945 if ( colIdx !== undefined ) {
2946 cols[ colIdx ].sType = null;
2949 for ( i=0, ien=cols.length ; i<ien ; i++ ) {
2950 cols[i].sType = null;
2953 // Update DataTables special `DT_*` attributes for the row
2954 _fnRowAttributes( settings, row );
2960 * Build a data source object from an HTML row, reading the contents of the
2961 * cells that are in the row.
2963 * @param {object} settings DataTables settings object
2964 * @param {node|object} TR element from which to read data or existing row
2965 * object from which to re-read the data from the cells
2966 * @param {int} [colIdx] Optional column index
2967 * @param {array|object} [d] Data source object. If `colIdx` is given then this
2968 * parameter should also be given and will be used to write the data into.
2969 * Only the column in question will be written
2970 * @returns {object} Object with two parameters: `data` the data read, in
2971 * document order, and `cells` and array of nodes (they can be useful to the
2972 * caller, so rather than needing a second traversal to get them, just return
2974 * @memberof DataTable#oApi
2976 function _fnGetRowElements( settings, row, colIdx, d )
2980 td = row.firstChild,
2981 name, col, o, i=0, contents,
2982 columns = settings.aoColumns,
2983 objectRead = settings._rowReadObject;
2985 // Allow the data object to be passed in, or construct
2986 d = d !== undefined ?
2992 var attr = function ( str, td ) {
2993 if ( typeof str === 'string' ) {
2994 var idx = str.indexOf('@');
2997 var attr = str.substring( idx+1 );
2998 var setter = _fnSetObjectDataFn( str );
2999 setter( d, td.getAttribute( attr ) );
3004 // Read data from a cell and store into the data object
3005 var cellProcess = function ( cell ) {
3006 if ( colIdx === undefined || colIdx === i ) {
3008 contents = $.trim(cell.innerHTML);
3010 if ( col && col._bAttrSrc ) {
3011 var setter = _fnSetObjectDataFn( col.mData._ );
3012 setter( d, contents );
3014 attr( col.mData.sort, cell );
3015 attr( col.mData.type, cell );
3016 attr( col.mData.filter, cell );
3019 // Depending on the `data` option for the columns the data can
3020 // be read to either an object or an array.
3022 if ( ! col._setter ) {
3023 // Cache the setter function
3024 col._setter = _fnSetObjectDataFn( col.mData );
3026 col._setter( d, contents );
3038 // `tr` element was passed in
3040 name = td.nodeName.toUpperCase();
3042 if ( name == "TD" || name == "TH" ) {
3047 td = td.nextSibling;
3051 // Existing row object passed in
3054 for ( var j=0, jen=tds.length ; j<jen ; j++ ) {
3055 cellProcess( tds[j] );
3059 // Read the ID from the DOM if present
3060 var rowNode = row.firstChild ? row : row.nTr;
3063 var id = rowNode.getAttribute( 'id' );
3066 _fnSetObjectDataFn( settings.rowId )( d, id );
3076 * Create a new TR element (and it's TD children) for a row
3077 * @param {object} oSettings dataTables settings object
3078 * @param {int} iRow Row to consider
3079 * @param {node} [nTrIn] TR element to add to the table - optional. If not given,
3080 * DataTables will create a row automatically
3081 * @param {array} [anTds] Array of TD|TH elements for the row - must be given
3083 * @memberof DataTable#oApi
3085 function _fnCreateTr ( oSettings, iRow, nTrIn, anTds )
3088 row = oSettings.aoData[iRow],
3089 rowData = row._aData,
3094 if ( row.nTr === null )
3096 nTr = nTrIn || document.createElement('tr');
3099 row.anCells = cells;
3101 /* Use a private property on the node to allow reserve mapping from the node
3102 * to the aoData array for fast look up
3104 nTr._DT_RowIndex = iRow;
3106 /* Special parameters can be given by the data source to be used on the row */
3107 _fnRowAttributes( oSettings, row );
3109 /* Process each column */
3110 for ( i=0, iLen=oSettings.aoColumns.length ; i<iLen ; i++ )
3112 oCol = oSettings.aoColumns[i];
3114 nTd = nTrIn ? anTds[i] : document.createElement( oCol.sCellType );
3115 nTd._DT_CellIndex = {
3122 // Need to create the HTML if new, or if a rendering function is defined
3123 if ( (!nTrIn || oCol.mRender || oCol.mData !== i) &&
3124 (!$.isPlainObject(oCol.mData) || oCol.mData._ !== i+'.display')
3126 nTd.innerHTML = _fnGetCellData( oSettings, iRow, i, 'display' );
3129 /* Add user defined class */
3132 nTd.className += ' '+oCol.sClass;
3135 // Visibility - add or remove as required
3136 if ( oCol.bVisible && ! nTrIn )
3138 nTr.appendChild( nTd );
3140 else if ( ! oCol.bVisible && nTrIn )
3142 nTd.parentNode.removeChild( nTd );
3145 if ( oCol.fnCreatedCell )
3147 oCol.fnCreatedCell.call( oSettings.oInstance,
3148 nTd, _fnGetCellData( oSettings, iRow, i ), rowData, iRow, i
3153 _fnCallbackFire( oSettings, 'aoRowCreatedCallback', null, [nTr, rowData, iRow] );
3156 // Remove once webkit bug 131819 and Chromium bug 365619 have been resolved
3158 row.nTr.setAttribute( 'role', 'row' );
3163 * Add attributes to a row based on the special `DT_*` parameters in a data
3165 * @param {object} settings DataTables settings object
3166 * @param {object} DataTables row object for the row to be modified
3167 * @memberof DataTable#oApi
3169 function _fnRowAttributes( settings, row )
3172 var data = row._aData;
3175 var id = settings.rowIdFn( data );
3181 if ( data.DT_RowClass ) {
3182 // Remove any classes added by DT_RowClass before
3183 var a = data.DT_RowClass.split(' ');
3184 row.__rowc = row.__rowc ?
3185 _unique( row.__rowc.concat( a ) ) :
3189 .removeClass( row.__rowc.join(' ') )
3190 .addClass( data.DT_RowClass );
3193 if ( data.DT_RowAttr ) {
3194 $(tr).attr( data.DT_RowAttr );
3197 if ( data.DT_RowData ) {
3198 $(tr).data( data.DT_RowData );
3205 * Create the HTML header for the table
3206 * @param {object} oSettings dataTables settings object
3207 * @memberof DataTable#oApi
3209 function _fnBuildHead( oSettings )
3211 var i, ien, cell, row, column;
3212 var thead = oSettings.nTHead;
3213 var tfoot = oSettings.nTFoot;
3214 var createHeader = $('th, td', thead).length === 0;
3215 var classes = oSettings.oClasses;
3216 var columns = oSettings.aoColumns;
3218 if ( createHeader ) {
3219 row = $('<tr/>').appendTo( thead );
3222 for ( i=0, ien=columns.length ; i<ien ; i++ ) {
3223 column = columns[i];
3224 cell = $( column.nTh ).addClass( column.sClass );
3226 if ( createHeader ) {
3227 cell.appendTo( row );
3230 // 1.11 move into sorting
3231 if ( oSettings.oFeatures.bSort ) {
3232 cell.addClass( column.sSortingClass );
3234 if ( column.bSortable !== false ) {
3236 .attr( 'tabindex', oSettings.iTabIndex )
3237 .attr( 'aria-controls', oSettings.sTableId );
3239 _fnSortAttachListener( oSettings, column.nTh, i );
3243 if ( column.sTitle != cell[0].innerHTML ) {
3244 cell.html( column.sTitle );
3247 _fnRenderer( oSettings, 'header' )(
3248 oSettings, cell, column, classes
3252 if ( createHeader ) {
3253 _fnDetectHeader( oSettings.aoHeader, thead );
3256 /* ARIA role for the rows */
3257 $(thead).find('>tr').attr('role', 'row');
3259 /* Deal with the footer - add classes if required */
3260 $(thead).find('>tr>th, >tr>td').addClass( classes.sHeaderTH );
3261 $(tfoot).find('>tr>th, >tr>td').addClass( classes.sFooterTH );
3263 // Cache the footer cells. Note that we only take the cells from the first
3264 // row in the footer. If there is more than one row the user wants to
3265 // interact with, they need to use the table().foot() method. Note also this
3266 // allows cells to be used for multiple columns using colspan
3267 if ( tfoot !== null ) {
3268 var cells = oSettings.aoFooter[0];
3270 for ( i=0, ien=cells.length ; i<ien ; i++ ) {
3271 column = columns[i];
3272 column.nTf = cells[i].cell;
3274 if ( column.sClass ) {
3275 $(column.nTf).addClass( column.sClass );
3283 * Draw the header (or footer) element based on the column visibility states. The
3284 * methodology here is to use the layout array from _fnDetectHeader, modified for
3285 * the instantaneous column visibility, to construct the new layout. The grid is
3286 * traversed over cell at a time in a rows x columns grid fashion, although each
3287 * cell insert can cover multiple elements in the grid - which is tracks using the
3288 * aApplied array. Cell inserts in the grid will only occur where there isn't
3289 * already a cell in that position.
3290 * @param {object} oSettings dataTables settings object
3291 * @param array {objects} aoSource Layout array from _fnDetectHeader
3292 * @param {boolean} [bIncludeHidden=false] If true then include the hidden columns in the calc,
3293 * @memberof DataTable#oApi
3295 function _fnDrawHead( oSettings, aoSource, bIncludeHidden )
3297 var i, iLen, j, jLen, k, kLen, n, nLocalTr;
3300 var iColumns = oSettings.aoColumns.length;
3301 var iRowspan, iColspan;
3308 if ( bIncludeHidden === undefined )
3310 bIncludeHidden = false;
3313 /* Make a copy of the master layout array, but without the visible columns in it */
3314 for ( i=0, iLen=aoSource.length ; i<iLen ; i++ )
3316 aoLocal[i] = aoSource[i].slice();
3317 aoLocal[i].nTr = aoSource[i].nTr;
3319 /* Remove any columns which are currently hidden */
3320 for ( j=iColumns-1 ; j>=0 ; j-- )
3322 if ( !oSettings.aoColumns[j].bVisible && !bIncludeHidden )
3324 aoLocal[i].splice( j, 1 );
3328 /* Prep the applied array - it needs an element for each row */
3329 aApplied.push( [] );
3332 for ( i=0, iLen=aoLocal.length ; i<iLen ; i++ )
3334 nLocalTr = aoLocal[i].nTr;
3336 /* All cells are going to be replaced, so empty out the row */
3339 while( (n = nLocalTr.firstChild) )
3341 nLocalTr.removeChild( n );
3345 for ( j=0, jLen=aoLocal[i].length ; j<jLen ; j++ )
3350 /* Check to see if there is already a cell (row/colspan) covering our target
3351 * insert point. If there is, then there is nothing to do.
3353 if ( aApplied[i][j] === undefined )
3355 nLocalTr.appendChild( aoLocal[i][j].cell );
3358 /* Expand the cell to cover as many rows as needed */
3359 while ( aoLocal[i+iRowspan] !== undefined &&
3360 aoLocal[i][j].cell == aoLocal[i+iRowspan][j].cell )
3362 aApplied[i+iRowspan][j] = 1;
3366 /* Expand the cell to cover as many columns as needed */
3367 while ( aoLocal[i][j+iColspan] !== undefined &&
3368 aoLocal[i][j].cell == aoLocal[i][j+iColspan].cell )
3370 /* Must update the applied array over the rows for the columns */
3371 for ( k=0 ; k<iRowspan ; k++ )
3373 aApplied[i+k][j+iColspan] = 1;
3378 /* Do the actual expansion in the DOM */
3379 $(aoLocal[i][j].cell)
3380 .attr('rowspan', iRowspan)
3381 .attr('colspan', iColspan);
3389 * Insert the required TR nodes into the table for display
3390 * @param {object} oSettings dataTables settings object
3391 * @memberof DataTable#oApi
3393 function _fnDraw( oSettings )
3395 /* Provide a pre-callback function which can be used to cancel the draw is false is returned */
3396 var aPreDraw = _fnCallbackFire( oSettings, 'aoPreDrawCallback', 'preDraw', [oSettings] );
3397 if ( $.inArray( false, aPreDraw ) !== -1 )
3399 _fnProcessingDisplay( oSettings, false );
3406 var asStripeClasses = oSettings.asStripeClasses;
3407 var iStripes = asStripeClasses.length;
3408 var iOpenRows = oSettings.aoOpenRows.length;
3409 var oLang = oSettings.oLanguage;
3410 var iInitDisplayStart = oSettings.iInitDisplayStart;
3411 var bServerSide = _fnDataSource( oSettings ) == 'ssp';
3412 var aiDisplay = oSettings.aiDisplay;
3414 oSettings.bDrawing = true;
3416 /* Check and see if we have an initial draw position from state saving */
3417 if ( iInitDisplayStart !== undefined && iInitDisplayStart !== -1 )
3419 oSettings._iDisplayStart = bServerSide ?
3421 iInitDisplayStart >= oSettings.fnRecordsDisplay() ?
3425 oSettings.iInitDisplayStart = -1;
3428 var iDisplayStart = oSettings._iDisplayStart;
3429 var iDisplayEnd = oSettings.fnDisplayEnd();
3431 /* Server-side processing draw intercept */
3432 if ( oSettings.bDeferLoading )
3434 oSettings.bDeferLoading = false;
3436 _fnProcessingDisplay( oSettings, false );
3438 else if ( !bServerSide )
3442 else if ( !oSettings.bDestroying && !_fnAjaxUpdate( oSettings ) )
3447 if ( aiDisplay.length !== 0 )
3449 var iStart = bServerSide ? 0 : iDisplayStart;
3450 var iEnd = bServerSide ? oSettings.aoData.length : iDisplayEnd;
3452 for ( var j=iStart ; j<iEnd ; j++ )
3454 var iDataIndex = aiDisplay[j];
3455 var aoData = oSettings.aoData[ iDataIndex ];
3456 if ( aoData.nTr === null )
3458 _fnCreateTr( oSettings, iDataIndex );
3461 var nRow = aoData.nTr;
3463 /* Remove the old striping classes and then add the new one */
3464 if ( iStripes !== 0 )
3466 var sStripe = asStripeClasses[ iRowCount % iStripes ];
3467 if ( aoData._sRowStripe != sStripe )
3469 $(nRow).removeClass( aoData._sRowStripe ).addClass( sStripe );
3470 aoData._sRowStripe = sStripe;
3474 // Row callback functions - might want to manipulate the row
3475 // iRowCount and j are not currently documented. Are they at all
3477 _fnCallbackFire( oSettings, 'aoRowCallback', null,
3478 [nRow, aoData._aData, iRowCount, j] );
3480 anRows.push( nRow );
3486 /* Table is empty - create a row with an empty message in it */
3487 var sZero = oLang.sZeroRecords;
3488 if ( oSettings.iDraw == 1 && _fnDataSource( oSettings ) == 'ajax' )
3490 sZero = oLang.sLoadingRecords;
3492 else if ( oLang.sEmptyTable && oSettings.fnRecordsTotal() === 0 )
3494 sZero = oLang.sEmptyTable;
3497 anRows[ 0 ] = $( '<tr/>', { 'class': iStripes ? asStripeClasses[0] : '' } )
3498 .append( $('<td />', {
3500 'colSpan': _fnVisbleColumns( oSettings ),
3501 'class': oSettings.oClasses.sRowEmpty
3502 } ).html( sZero ) )[0];
3505 /* Header and footer callbacks */
3506 _fnCallbackFire( oSettings, 'aoHeaderCallback', 'header', [ $(oSettings.nTHead).children('tr')[0],
3507 _fnGetDataMaster( oSettings ), iDisplayStart, iDisplayEnd, aiDisplay ] );
3509 _fnCallbackFire( oSettings, 'aoFooterCallback', 'footer', [ $(oSettings.nTFoot).children('tr')[0],
3510 _fnGetDataMaster( oSettings ), iDisplayStart, iDisplayEnd, aiDisplay ] );
3512 var body = $(oSettings.nTBody);
3514 body.children().detach();
3515 body.append( $(anRows) );
3517 /* Call all required callback functions for the end of a draw */
3518 _fnCallbackFire( oSettings, 'aoDrawCallback', 'draw', [oSettings] );
3520 /* Draw is complete, sorting and filtering must be as well */
3521 oSettings.bSorted = false;
3522 oSettings.bFiltered = false;
3523 oSettings.bDrawing = false;
3528 * Redraw the table - taking account of the various features which are enabled
3529 * @param {object} oSettings dataTables settings object
3530 * @param {boolean} [holdPosition] Keep the current paging position. By default
3531 * the paging is reset to the first page
3532 * @memberof DataTable#oApi
3534 function _fnReDraw( settings, holdPosition )
3537 features = settings.oFeatures,
3538 sort = features.bSort,
3539 filter = features.bFilter;
3542 _fnSort( settings );
3546 _fnFilterComplete( settings, settings.oPreviousSearch );
3549 // No filtering, so we want to just use the display master
3550 settings.aiDisplay = settings.aiDisplayMaster.slice();
3553 if ( holdPosition !== true ) {
3554 settings._iDisplayStart = 0;
3557 // Let any modules know about the draw hold position state (used by
3558 // scrolling internally)
3559 settings._drawHold = holdPosition;
3561 _fnDraw( settings );
3563 settings._drawHold = false;
3568 * Add the options to the page HTML for the table
3569 * @param {object} oSettings dataTables settings object
3570 * @memberof DataTable#oApi
3572 function _fnAddOptionsHtml ( oSettings )
3574 var classes = oSettings.oClasses;
3575 var table = $(oSettings.nTable);
3576 var holding = $('<div/>').insertBefore( table ); // Holding element for speed
3577 var features = oSettings.oFeatures;
3579 // All DataTables are wrapped in a div
3580 var insert = $('<div/>', {
3581 id: oSettings.sTableId+'_wrapper',
3582 'class': classes.sWrapper + (oSettings.nTFoot ? '' : ' '+classes.sNoFooter)
3585 oSettings.nHolding = holding[0];
3586 oSettings.nTableWrapper = insert[0];
3587 oSettings.nTableReinsertBefore = oSettings.nTable.nextSibling;
3589 /* Loop over the user set positioning and place the elements as needed */
3590 var aDom = oSettings.sDom.split('');
3591 var featureNode, cOption, nNewNode, cNext, sAttr, j;
3592 for ( var i=0 ; i<aDom.length ; i++ )
3597 if ( cOption == '<' )
3599 /* New container div */
3600 nNewNode = $('<div/>')[0];
3602 /* Check to see if we should append an id and/or a class name to the container */
3604 if ( cNext == "'" || cNext == '"' )
3608 while ( aDom[i+j] != cNext )
3614 /* Replace jQuery UI constants @todo depreciated */
3617 sAttr = classes.sJUIHeader;
3619 else if ( sAttr == "F" )
3621 sAttr = classes.sJUIFooter;
3624 /* The attribute can be in the format of "#id.class", "#id" or "class" This logic
3625 * breaks the string into parts and applies them as needed
3627 if ( sAttr.indexOf('.') != -1 )
3629 var aSplit = sAttr.split('.');
3630 nNewNode.id = aSplit[0].substr(1, aSplit[0].length-1);
3631 nNewNode.className = aSplit[1];
3633 else if ( sAttr.charAt(0) == "#" )
3635 nNewNode.id = sAttr.substr(1, sAttr.length-1);
3639 nNewNode.className = sAttr;
3642 i += j; /* Move along the position array */
3645 insert.append( nNewNode );
3646 insert = $(nNewNode);
3648 else if ( cOption == '>' )
3650 /* End container div */
3651 insert = insert.parent();
3653 // @todo Move options into their own plugins?
3654 else if ( cOption == 'l' && features.bPaginate && features.bLengthChange )
3657 featureNode = _fnFeatureHtmlLength( oSettings );
3659 else if ( cOption == 'f' && features.bFilter )
3662 featureNode = _fnFeatureHtmlFilter( oSettings );
3664 else if ( cOption == 'r' && features.bProcessing )
3667 featureNode = _fnFeatureHtmlProcessing( oSettings );
3669 else if ( cOption == 't' )
3672 featureNode = _fnFeatureHtmlTable( oSettings );
3674 else if ( cOption == 'i' && features.bInfo )
3677 featureNode = _fnFeatureHtmlInfo( oSettings );
3679 else if ( cOption == 'p' && features.bPaginate )
3682 featureNode = _fnFeatureHtmlPaginate( oSettings );
3684 else if ( DataTable.ext.feature.length !== 0 )
3686 /* Plug-in features */
3687 var aoFeatures = DataTable.ext.feature;
3688 for ( var k=0, kLen=aoFeatures.length ; k<kLen ; k++ )
3690 if ( cOption == aoFeatures[k].cFeature )
3692 featureNode = aoFeatures[k].fnInit( oSettings );
3698 /* Add to the 2D features array */
3701 var aanFeatures = oSettings.aanFeatures;
3703 if ( ! aanFeatures[cOption] )
3705 aanFeatures[cOption] = [];
3708 aanFeatures[cOption].push( featureNode );
3709 insert.append( featureNode );
3713 /* Built our DOM structure - replace the holding div with what we want */
3714 holding.replaceWith( insert );
3715 oSettings.nHolding = null;
3720 * Use the DOM source to create up an array of header cells. The idea here is to
3721 * create a layout grid (array) of rows x columns, which contains a reference
3722 * to the cell that that point in the grid (regardless of col/rowspan), such that
3723 * any column / row could be removed and the new grid constructed
3724 * @param array {object} aLayout Array to store the calculated layout in
3725 * @param {node} nThead The header/footer element for the table
3726 * @memberof DataTable#oApi
3728 function _fnDetectHeader ( aLayout, nThead )
3730 var nTrs = $(nThead).children('tr');
3732 var i, k, l, iLen, jLen, iColShifted, iColumn, iColspan, iRowspan;
3734 var fnShiftCol = function ( a, i, j ) {
3742 aLayout.splice( 0, aLayout.length );
3744 /* We know how many rows there are in the layout - so prep it */
3745 for ( i=0, iLen=nTrs.length ; i<iLen ; i++ )
3750 /* Calculate a layout array */
3751 for ( i=0, iLen=nTrs.length ; i<iLen ; i++ )
3756 /* For every cell in the row... */
3757 nCell = nTr.firstChild;
3759 if ( nCell.nodeName.toUpperCase() == "TD" ||
3760 nCell.nodeName.toUpperCase() == "TH" )
3762 /* Get the col and rowspan attributes from the DOM and sanitise them */
3763 iColspan = nCell.getAttribute('colspan') * 1;
3764 iRowspan = nCell.getAttribute('rowspan') * 1;
3765 iColspan = (!iColspan || iColspan===0 || iColspan===1) ? 1 : iColspan;
3766 iRowspan = (!iRowspan || iRowspan===0 || iRowspan===1) ? 1 : iRowspan;
3768 /* There might be colspan cells already in this row, so shift our target
3771 iColShifted = fnShiftCol( aLayout, i, iColumn );
3773 /* Cache calculation for unique columns */
3774 bUnique = iColspan === 1 ? true : false;
3776 /* If there is col / rowspan, copy the information into the layout grid */
3777 for ( l=0 ; l<iColspan ; l++ )
3779 for ( k=0 ; k<iRowspan ; k++ )
3781 aLayout[i+k][iColShifted+l] = {
3785 aLayout[i+k].nTr = nTr;
3789 nCell = nCell.nextSibling;
3796 * Get an array of unique th elements, one for each column
3797 * @param {object} oSettings dataTables settings object
3798 * @param {node} nHeader automatically detect the layout from this node - optional
3799 * @param {array} aLayout thead/tfoot layout from _fnDetectHeader - optional
3800 * @returns array {node} aReturn list of unique th's
3801 * @memberof DataTable#oApi
3803 function _fnGetUniqueThs ( oSettings, nHeader, aLayout )
3808 aLayout = oSettings.aoHeader;
3812 _fnDetectHeader( aLayout, nHeader );
3816 for ( var i=0, iLen=aLayout.length ; i<iLen ; i++ )
3818 for ( var j=0, jLen=aLayout[i].length ; j<jLen ; j++ )
3820 if ( aLayout[i][j].unique &&
3821 (!aReturn[j] || !oSettings.bSortCellsTop) )
3823 aReturn[j] = aLayout[i][j].cell;
3832 * Create an Ajax call based on the table's settings, taking into account that
3833 * parameters can have multiple forms, and backwards compatibility.
3835 * @param {object} oSettings dataTables settings object
3836 * @param {array} data Data to send to the server, required by
3837 * DataTables - may be augmented by developer callbacks
3838 * @param {function} fn Callback function to run when data is obtained
3840 function _fnBuildAjax( oSettings, data, fn )
3842 // Compatibility with 1.9-, allow fnServerData and event to manipulate
3843 _fnCallbackFire( oSettings, 'aoServerParams', 'serverParams', [data] );
3845 // Convert to object based for 1.10+ if using the old array scheme which can
3846 // come from server-side processing or serverParams
3847 if ( data && $.isArray(data) ) {
3849 var rbracket = /(.*?)\[\]$/;
3851 $.each( data, function (key, val) {
3852 var match = val.name.match(rbracket);
3855 // Support for arrays
3856 var name = match[0];
3858 if ( ! tmp[ name ] ) {
3861 tmp[ name ].push( val.value );
3864 tmp[val.name] = val.value;
3871 var ajax = oSettings.ajax;
3872 var instance = oSettings.oInstance;
3873 var callback = function ( json ) {
3874 _fnCallbackFire( oSettings, null, 'xhr', [oSettings, json, oSettings.jqXHR] );
3878 if ( $.isPlainObject( ajax ) && ajax.data )
3880 ajaxData = ajax.data;
3882 var newData = $.isFunction( ajaxData ) ?
3883 ajaxData( data, oSettings ) : // fn can manipulate data or return
3884 ajaxData; // an object object or array to merge
3886 // If the function returned something, use that alone
3887 data = $.isFunction( ajaxData ) && newData ?
3889 $.extend( true, data, newData );
3891 // Remove the data property as we've resolved it already and don't want
3892 // jQuery to do it again (it is restored at the end of the function)
3898 "success": function (json) {
3899 var error = json.error || json.sError;
3901 _fnLog( oSettings, 0, error );
3904 oSettings.json = json;
3909 "type": oSettings.sServerMethod,
3910 "error": function (xhr, error, thrown) {
3911 var ret = _fnCallbackFire( oSettings, null, 'xhr', [oSettings, null, oSettings.jqXHR] );
3913 if ( $.inArray( true, ret ) === -1 ) {
3914 if ( error == "parsererror" ) {
3915 _fnLog( oSettings, 0, 'Invalid JSON response', 1 );
3917 else if ( xhr.readyState === 4 ) {
3918 _fnLog( oSettings, 0, 'Ajax error', 7 );
3922 _fnProcessingDisplay( oSettings, false );
3926 // Store the data submitted for the API
3927 oSettings.oAjaxData = data;
3929 // Allow plug-ins and external processes to modify the data
3930 _fnCallbackFire( oSettings, null, 'preXhr', [oSettings, data] );
3932 if ( oSettings.fnServerData )
3934 // DataTables 1.9- compatibility
3935 oSettings.fnServerData.call( instance,
3936 oSettings.sAjaxSource,
3937 $.map( data, function (val, key) { // Need to convert back to 1.9 trad format
3938 return { name: key, value: val };
3944 else if ( oSettings.sAjaxSource || typeof ajax === 'string' )
3946 // DataTables 1.9- compatibility
3947 oSettings.jqXHR = $.ajax( $.extend( baseAjax, {
3948 url: ajax || oSettings.sAjaxSource
3951 else if ( $.isFunction( ajax ) )
3953 // Is a function - let the caller define what needs to be done
3954 oSettings.jqXHR = ajax.call( instance, data, callback, oSettings );
3958 // Object to extend the base settings
3959 oSettings.jqXHR = $.ajax( $.extend( baseAjax, ajax ) );
3961 // Restore for next time around
3962 ajax.data = ajaxData;
3968 * Update the table using an Ajax call
3969 * @param {object} settings dataTables settings object
3970 * @returns {boolean} Block the table drawing or not
3971 * @memberof DataTable#oApi
3973 function _fnAjaxUpdate( settings )
3975 if ( settings.bAjaxDataGet ) {
3977 _fnProcessingDisplay( settings, true );
3981 _fnAjaxParameters( settings ),
3983 _fnAjaxUpdateDraw( settings, json );
3994 * Build up the parameters in an object needed for a server-side processing
3995 * request. Note that this is basically done twice, is different ways - a modern
3996 * method which is used by default in DataTables 1.10 which uses objects and
3997 * arrays, or the 1.9- method with is name / value pairs. 1.9 method is used if
3998 * the sAjaxSource option is used in the initialisation, or the legacyAjax
4000 * @param {object} oSettings dataTables settings object
4001 * @returns {bool} block the table drawing or not
4002 * @memberof DataTable#oApi
4004 function _fnAjaxParameters( settings )
4007 columns = settings.aoColumns,
4008 columnCount = columns.length,
4009 features = settings.oFeatures,
4010 preSearch = settings.oPreviousSearch,
4011 preColSearch = settings.aoPreSearchCols,
4012 i, data = [], dataProp, column, columnSearch,
4013 sort = _fnSortFlatten( settings ),
4014 displayStart = settings._iDisplayStart,
4015 displayLength = features.bPaginate !== false ?
4016 settings._iDisplayLength :
4019 var param = function ( name, value ) {
4020 data.push( { 'name': name, 'value': value } );
4023 // DataTables 1.9- compatible method
4024 param( 'sEcho', settings.iDraw );
4025 param( 'iColumns', columnCount );
4026 param( 'sColumns', _pluck( columns, 'sName' ).join(',') );
4027 param( 'iDisplayStart', displayStart );
4028 param( 'iDisplayLength', displayLength );
4030 // DataTables 1.10+ method
4032 draw: settings.iDraw,
4035 start: displayStart,
4036 length: displayLength,
4038 value: preSearch.sSearch,
4039 regex: preSearch.bRegex
4043 for ( i=0 ; i<columnCount ; i++ ) {
4044 column = columns[i];
4045 columnSearch = preColSearch[i];
4046 dataProp = typeof column.mData=="function" ? 'function' : column.mData ;
4051 searchable: column.bSearchable,
4052 orderable: column.bSortable,
4054 value: columnSearch.sSearch,
4055 regex: columnSearch.bRegex
4059 param( "mDataProp_"+i, dataProp );
4061 if ( features.bFilter ) {
4062 param( 'sSearch_'+i, columnSearch.sSearch );
4063 param( 'bRegex_'+i, columnSearch.bRegex );
4064 param( 'bSearchable_'+i, column.bSearchable );
4067 if ( features.bSort ) {
4068 param( 'bSortable_'+i, column.bSortable );
4072 if ( features.bFilter ) {
4073 param( 'sSearch', preSearch.sSearch );
4074 param( 'bRegex', preSearch.bRegex );
4077 if ( features.bSort ) {
4078 $.each( sort, function ( i, val ) {
4079 d.order.push( { column: val.col, dir: val.dir } );
4081 param( 'iSortCol_'+i, val.col );
4082 param( 'sSortDir_'+i, val.dir );
4085 param( 'iSortingCols', sort.length );
4088 // If the legacy.ajax parameter is null, then we automatically decide which
4089 // form to use, based on sAjaxSource
4090 var legacy = DataTable.ext.legacy.ajax;
4091 if ( legacy === null ) {
4092 return settings.sAjaxSource ? data : d;
4095 // Otherwise, if legacy has been specified then we use that to decide on the
4097 return legacy ? data : d;
4102 * Data the data from the server (nuking the old) and redraw the table
4103 * @param {object} oSettings dataTables settings object
4104 * @param {object} json json data return from the server.
4105 * @param {string} json.sEcho Tracking flag for DataTables to match requests
4106 * @param {int} json.iTotalRecords Number of records in the data set, not accounting for filtering
4107 * @param {int} json.iTotalDisplayRecords Number of records in the data set, accounting for filtering
4108 * @param {array} json.aaData The data to display on this page
4109 * @param {string} [json.sColumns] Column ordering (sName, comma separated)
4110 * @memberof DataTable#oApi
4112 function _fnAjaxUpdateDraw ( settings, json )
4114 // v1.10 uses camelCase variables, while 1.9 uses Hungarian notation.
4116 var compat = function ( old, modern ) {
4117 return json[old] !== undefined ? json[old] : json[modern];
4120 var data = _fnAjaxDataSrc( settings, json );
4121 var draw = compat( 'sEcho', 'draw' );
4122 var recordsTotal = compat( 'iTotalRecords', 'recordsTotal' );
4123 var recordsFiltered = compat( 'iTotalDisplayRecords', 'recordsFiltered' );
4126 // Protect against out of sequence returns
4127 if ( draw*1 < settings.iDraw ) {
4130 settings.iDraw = draw * 1;
4133 _fnClearTable( settings );
4134 settings._iRecordsTotal = parseInt(recordsTotal, 10);
4135 settings._iRecordsDisplay = parseInt(recordsFiltered, 10);
4137 for ( var i=0, ien=data.length ; i<ien ; i++ ) {
4138 _fnAddData( settings, data[i] );
4140 settings.aiDisplay = settings.aiDisplayMaster.slice();
4142 settings.bAjaxDataGet = false;
4143 _fnDraw( settings );
4145 if ( ! settings._bInitComplete ) {
4146 _fnInitComplete( settings, json );
4149 settings.bAjaxDataGet = true;
4150 _fnProcessingDisplay( settings, false );
4155 * Get the data from the JSON data source to use for drawing a table. Using
4156 * `_fnGetObjectDataFn` allows the data to be sourced from a property of the
4157 * source object, or from a processing function.
4158 * @param {object} oSettings dataTables settings object
4159 * @param {object} json Data source object / array from the server
4160 * @return {array} Array of data to use
4162 function _fnAjaxDataSrc ( oSettings, json )
4164 var dataSrc = $.isPlainObject( oSettings.ajax ) && oSettings.ajax.dataSrc !== undefined ?
4165 oSettings.ajax.dataSrc :
4166 oSettings.sAjaxDataProp; // Compatibility with 1.9-.
4168 // Compatibility with 1.9-. In order to read from aaData, check if the
4169 // default has been changed, if not, check for aaData
4170 if ( dataSrc === 'data' ) {
4171 return json.aaData || json[dataSrc];
4174 return dataSrc !== "" ?
4175 _fnGetObjectDataFn( dataSrc )( json ) :
4180 * Generate the node required for filtering text
4181 * @returns {node} Filter control element
4182 * @param {object} oSettings dataTables settings object
4183 * @memberof DataTable#oApi
4185 function _fnFeatureHtmlFilter ( settings )
4187 var classes = settings.oClasses;
4188 var tableId = settings.sTableId;
4189 var language = settings.oLanguage;
4190 var previousSearch = settings.oPreviousSearch;
4191 var features = settings.aanFeatures;
4192 var input = '<input type="search" class="'+classes.sFilterInput+'"/>';
4194 var str = language.sSearch;
4195 str = str.match(/_INPUT_/) ?
4196 str.replace('_INPUT_', input) :
4199 var filter = $('<div/>', {
4200 'id': ! features.f ? tableId+'_filter' : null,
4201 'class': classes.sFilter
4203 .append( $('<label/>' ).append( str ) );
4205 var searchFn = function() {
4206 /* Update all other filter input elements for the new display */
4208 var val = !this.value ? "" : this.value; // mental IE8 fix :-(
4210 /* Now do the filter */
4211 if ( val != previousSearch.sSearch ) {
4212 _fnFilterComplete( settings, {
4214 "bRegex": previousSearch.bRegex,
4215 "bSmart": previousSearch.bSmart ,
4216 "bCaseInsensitive": previousSearch.bCaseInsensitive
4219 // Need to redraw, without resorting
4220 settings._iDisplayStart = 0;
4221 _fnDraw( settings );
4225 var searchDelay = settings.searchDelay !== null ?
4226 settings.searchDelay :
4227 _fnDataSource( settings ) === 'ssp' ?
4231 var jqFilter = $('input', filter)
4232 .val( previousSearch.sSearch )
4233 .attr( 'placeholder', language.sSearchPlaceholder )
4235 'keyup.DT search.DT input.DT paste.DT cut.DT',
4237 _fnThrottle( searchFn, searchDelay ) :
4240 .on( 'keypress.DT', function(e) {
4241 /* Prevent form submission */
4242 if ( e.keyCode == 13 ) {
4246 .attr('aria-controls', tableId);
4248 // Update the input elements whenever the table is filtered
4249 $(settings.nTable).on( 'search.dt.DT', function ( ev, s ) {
4250 if ( settings === s ) {
4251 // IE9 throws an 'unknown error' if document.activeElement is used
4252 // inside an iframe or frame...
4254 if ( jqFilter[0] !== document.activeElement ) {
4255 jqFilter.val( previousSearch.sSearch );
4267 * Filter the table using both the global filter and column based filtering
4268 * @param {object} oSettings dataTables settings object
4269 * @param {object} oSearch search information
4270 * @param {int} [iForce] force a research of the master array (1) or not (undefined or 0)
4271 * @memberof DataTable#oApi
4273 function _fnFilterComplete ( oSettings, oInput, iForce )
4275 var oPrevSearch = oSettings.oPreviousSearch;
4276 var aoPrevSearch = oSettings.aoPreSearchCols;
4277 var fnSaveFilter = function ( oFilter ) {
4278 /* Save the filtering values */
4279 oPrevSearch.sSearch = oFilter.sSearch;
4280 oPrevSearch.bRegex = oFilter.bRegex;
4281 oPrevSearch.bSmart = oFilter.bSmart;
4282 oPrevSearch.bCaseInsensitive = oFilter.bCaseInsensitive;
4284 var fnRegex = function ( o ) {
4285 // Backwards compatibility with the bEscapeRegex option
4286 return o.bEscapeRegex !== undefined ? !o.bEscapeRegex : o.bRegex;
4289 // Resolve any column types that are unknown due to addition or invalidation
4290 // @todo As per sort - can this be moved into an event handler?
4291 _fnColumnTypes( oSettings );
4293 /* In server-side processing all filtering is done by the server, so no point hanging around here */
4294 if ( _fnDataSource( oSettings ) != 'ssp' )
4297 _fnFilter( oSettings, oInput.sSearch, iForce, fnRegex(oInput), oInput.bSmart, oInput.bCaseInsensitive );
4298 fnSaveFilter( oInput );
4300 /* Now do the individual column filter */
4301 for ( var i=0 ; i<aoPrevSearch.length ; i++ )
4303 _fnFilterColumn( oSettings, aoPrevSearch[i].sSearch, i, fnRegex(aoPrevSearch[i]),
4304 aoPrevSearch[i].bSmart, aoPrevSearch[i].bCaseInsensitive );
4307 /* Custom filtering */
4308 _fnFilterCustom( oSettings );
4312 fnSaveFilter( oInput );
4315 /* Tell the draw function we have been filtering */
4316 oSettings.bFiltered = true;
4317 _fnCallbackFire( oSettings, null, 'search', [oSettings] );
4322 * Apply custom filtering functions
4323 * @param {object} oSettings dataTables settings object
4324 * @memberof DataTable#oApi
4326 function _fnFilterCustom( settings )
4328 var filters = DataTable.ext.search;
4329 var displayRows = settings.aiDisplay;
4332 for ( var i=0, ien=filters.length ; i<ien ; i++ ) {
4335 // Loop over each row and see if it should be included
4336 for ( var j=0, jen=displayRows.length ; j<jen ; j++ ) {
4337 rowIdx = displayRows[ j ];
4338 row = settings.aoData[ rowIdx ];
4340 if ( filters[i]( settings, row._aFilterData, rowIdx, row._aData, j ) ) {
4341 rows.push( rowIdx );
4345 // So the array reference doesn't break set the results into the
4347 displayRows.length = 0;
4348 $.merge( displayRows, rows );
4354 * Filter the table on a per-column basis
4355 * @param {object} oSettings dataTables settings object
4356 * @param {string} sInput string to filter on
4357 * @param {int} iColumn column to filter
4358 * @param {bool} bRegex treat search string as a regular expression or not
4359 * @param {bool} bSmart use smart filtering or not
4360 * @param {bool} bCaseInsensitive Do case insenstive matching or not
4361 * @memberof DataTable#oApi
4363 function _fnFilterColumn ( settings, searchStr, colIdx, regex, smart, caseInsensitive )
4365 if ( searchStr === '' ) {
4371 var display = settings.aiDisplay;
4372 var rpSearch = _fnFilterCreateSearch( searchStr, regex, smart, caseInsensitive );
4374 for ( var i=0 ; i<display.length ; i++ ) {
4375 data = settings.aoData[ display[i] ]._aFilterData[ colIdx ];
4377 if ( rpSearch.test( data ) ) {
4378 out.push( display[i] );
4382 settings.aiDisplay = out;
4387 * Filter the data table based on user input and draw the table
4388 * @param {object} settings dataTables settings object
4389 * @param {string} input string to filter on
4390 * @param {int} force optional - force a research of the master array (1) or not (undefined or 0)
4391 * @param {bool} regex treat as a regular expression or not
4392 * @param {bool} smart perform smart filtering or not
4393 * @param {bool} caseInsensitive Do case insenstive matching or not
4394 * @memberof DataTable#oApi
4396 function _fnFilter( settings, input, force, regex, smart, caseInsensitive )
4398 var rpSearch = _fnFilterCreateSearch( input, regex, smart, caseInsensitive );
4399 var prevSearch = settings.oPreviousSearch.sSearch;
4400 var displayMaster = settings.aiDisplayMaster;
4401 var display, invalidated, i;
4404 // Need to take account of custom filtering functions - always filter
4405 if ( DataTable.ext.search.length !== 0 ) {
4409 // Check if any of the rows were invalidated
4410 invalidated = _fnFilterData( settings );
4412 // If the input is blank - we just want the full data set
4413 if ( input.length <= 0 ) {
4414 settings.aiDisplay = displayMaster.slice();
4417 // New search - start from the master array
4420 prevSearch.length > input.length ||
4421 input.indexOf(prevSearch) !== 0 ||
4422 settings.bSorted // On resort, the display master needs to be
4423 // re-filtered since indexes will have changed
4425 settings.aiDisplay = displayMaster.slice();
4428 // Search the display array
4429 display = settings.aiDisplay;
4431 for ( i=0 ; i<display.length ; i++ ) {
4432 if ( rpSearch.test( settings.aoData[ display[i] ]._sFilterRow ) ) {
4433 filtered.push( display[i] );
4437 settings.aiDisplay = filtered;
4443 * Build a regular expression object suitable for searching a table
4444 * @param {string} sSearch string to search for
4445 * @param {bool} bRegex treat as a regular expression or not
4446 * @param {bool} bSmart perform smart filtering or not
4447 * @param {bool} bCaseInsensitive Do case insensitive matching or not
4448 * @returns {RegExp} constructed object
4449 * @memberof DataTable#oApi
4451 function _fnFilterCreateSearch( search, regex, smart, caseInsensitive )
4455 _fnEscapeRegex( search );
4458 /* For smart filtering we want to allow the search to work regardless of
4459 * word order. We also want double quoted text to be preserved, so word
4460 * order is important - a la google. So this is what we want to
4463 * ^(?=.*?\bone\b)(?=.*?\btwo three\b)(?=.*?\bfour\b).*$
4465 var a = $.map( search.match( /"[^"]+"|[^ ]+/g ) || [''], function ( word ) {
4466 if ( word.charAt(0) === '"' ) {
4467 var m = word.match( /^"(.*)"$/ );
4468 word = m ? m[1] : word;
4471 return word.replace('"', '');
4474 search = '^(?=.*?'+a.join( ')(?=.*?' )+').*$';
4477 return new RegExp( search, caseInsensitive ? 'i' : '' );
4482 * Escape a string such that it can be used in a regular expression
4483 * @param {string} sVal string to escape
4484 * @returns {string} escaped string
4485 * @memberof DataTable#oApi
4487 var _fnEscapeRegex = DataTable.util.escapeRegex;
4489 var __filter_div = $('<div>')[0];
4490 var __filter_div_textContent = __filter_div.textContent !== undefined;
4492 // Update the filtering data for each row if needed (by invalidation or first run)
4493 function _fnFilterData ( settings )
4495 var columns = settings.aoColumns;
4497 var i, j, ien, jen, filterData, cellData, row;
4498 var fomatters = DataTable.ext.type.search;
4499 var wasInvalidated = false;
4501 for ( i=0, ien=settings.aoData.length ; i<ien ; i++ ) {
4502 row = settings.aoData[i];
4504 if ( ! row._aFilterData ) {
4507 for ( j=0, jen=columns.length ; j<jen ; j++ ) {
4508 column = columns[j];
4510 if ( column.bSearchable ) {
4511 cellData = _fnGetCellData( settings, i, j, 'filter' );
4513 if ( fomatters[ column.sType ] ) {
4514 cellData = fomatters[ column.sType ]( cellData );
4517 // Search in DataTables 1.10 is string based. In 1.11 this
4518 // should be altered to also allow strict type checking.
4519 if ( cellData === null ) {
4523 if ( typeof cellData !== 'string' && cellData.toString ) {
4524 cellData = cellData.toString();
4531 // If it looks like there is an HTML entity in the string,
4532 // attempt to decode it so sorting works as expected. Note that
4533 // we could use a single line of jQuery to do this, but the DOM
4534 // method used here is much faster http://jsperf.com/html-decode
4535 if ( cellData.indexOf && cellData.indexOf('&') !== -1 ) {
4536 __filter_div.innerHTML = cellData;
4537 cellData = __filter_div_textContent ?
4538 __filter_div.textContent :
4539 __filter_div.innerText;
4542 if ( cellData.replace ) {
4543 cellData = cellData.replace(/[\r\n]/g, '');
4546 filterData.push( cellData );
4549 row._aFilterData = filterData;
4550 row._sFilterRow = filterData.join(' ');
4551 wasInvalidated = true;
4555 return wasInvalidated;
4560 * Convert from the internal Hungarian notation to camelCase for external
4562 * @param {object} obj Object to convert
4563 * @returns {object} Inverted object
4564 * @memberof DataTable#oApi
4566 function _fnSearchToCamel ( obj )
4569 search: obj.sSearch,
4572 caseInsensitive: obj.bCaseInsensitive
4579 * Convert from camelCase notation to the internal Hungarian. We could use the
4580 * Hungarian convert function here, but this is cleaner
4581 * @param {object} obj Object to convert
4582 * @returns {object} Inverted object
4583 * @memberof DataTable#oApi
4585 function _fnSearchToHung ( obj )
4588 sSearch: obj.search,
4591 bCaseInsensitive: obj.caseInsensitive
4596 * Generate the node required for the info display
4597 * @param {object} oSettings dataTables settings object
4598 * @returns {node} Information element
4599 * @memberof DataTable#oApi
4601 function _fnFeatureHtmlInfo ( settings )
4604 tid = settings.sTableId,
4605 nodes = settings.aanFeatures.i,
4607 'class': settings.oClasses.sInfo,
4608 'id': ! nodes ? tid+'_info' : null
4612 // Update display on each draw
4613 settings.aoDrawCallback.push( {
4614 "fn": _fnUpdateInfo,
4615 "sName": "information"
4619 .attr( 'role', 'status' )
4620 .attr( 'aria-live', 'polite' );
4622 // Table is described by our info div
4623 $(settings.nTable).attr( 'aria-describedby', tid+'_info' );
4631 * Update the information elements in the display
4632 * @param {object} settings dataTables settings object
4633 * @memberof DataTable#oApi
4635 function _fnUpdateInfo ( settings )
4637 /* Show information about the table */
4638 var nodes = settings.aanFeatures.i;
4639 if ( nodes.length === 0 ) {
4644 lang = settings.oLanguage,
4645 start = settings._iDisplayStart+1,
4646 end = settings.fnDisplayEnd(),
4647 max = settings.fnRecordsTotal(),
4648 total = settings.fnRecordsDisplay(),
4653 if ( total !== max ) {
4654 /* Record set after filtering */
4655 out += ' ' + lang.sInfoFiltered;
4658 // Convert the macros
4659 out += lang.sInfoPostFix;
4660 out = _fnInfoMacros( settings, out );
4662 var callback = lang.fnInfoCallback;
4663 if ( callback !== null ) {
4664 out = callback.call( settings.oInstance,
4665 settings, start, end, max, total, out
4669 $(nodes).html( out );
4673 function _fnInfoMacros ( settings, str )
4675 // When infinite scrolling, we are always starting at 1. _iDisplayStart is used only
4678 formatter = settings.fnFormatNumber,
4679 start = settings._iDisplayStart+1,
4680 len = settings._iDisplayLength,
4681 vis = settings.fnRecordsDisplay(),
4685 replace(/_START_/g, formatter.call( settings, start ) ).
4686 replace(/_END_/g, formatter.call( settings, settings.fnDisplayEnd() ) ).
4687 replace(/_MAX_/g, formatter.call( settings, settings.fnRecordsTotal() ) ).
4688 replace(/_TOTAL_/g, formatter.call( settings, vis ) ).
4689 replace(/_PAGE_/g, formatter.call( settings, all ? 1 : Math.ceil( start / len ) ) ).
4690 replace(/_PAGES_/g, formatter.call( settings, all ? 1 : Math.ceil( vis / len ) ) );
4696 * Draw the table for the first time, adding all required features
4697 * @param {object} settings dataTables settings object
4698 * @memberof DataTable#oApi
4700 function _fnInitialise ( settings )
4702 var i, iLen, iAjaxStart=settings.iInitDisplayStart;
4703 var columns = settings.aoColumns, column;
4704 var features = settings.oFeatures;
4705 var deferLoading = settings.bDeferLoading; // value modified by the draw
4707 /* Ensure that the table data is fully initialised */
4708 if ( ! settings.bInitialised ) {
4709 setTimeout( function(){ _fnInitialise( settings ); }, 200 );
4713 /* Show the display HTML options */
4714 _fnAddOptionsHtml( settings );
4716 /* Build and draw the header / footer for the table */
4717 _fnBuildHead( settings );
4718 _fnDrawHead( settings, settings.aoHeader );
4719 _fnDrawHead( settings, settings.aoFooter );
4721 /* Okay to show that something is going on now */
4722 _fnProcessingDisplay( settings, true );
4724 /* Calculate sizes for columns */
4725 if ( features.bAutoWidth ) {
4726 _fnCalculateColumnWidths( settings );
4729 for ( i=0, iLen=columns.length ; i<iLen ; i++ ) {
4730 column = columns[i];
4732 if ( column.sWidth ) {
4733 column.nTh.style.width = _fnStringToCss( column.sWidth );
4737 _fnCallbackFire( settings, null, 'preInit', [settings] );
4739 // If there is default sorting required - let's do it. The sort function
4740 // will do the drawing for us. Otherwise we draw the table regardless of the
4741 // Ajax source - this allows the table to look initialised for Ajax sourcing
4742 // data (show 'loading' message possibly)
4743 _fnReDraw( settings );
4745 // Server-side processing init complete is done by _fnAjaxUpdateDraw
4746 var dataSrc = _fnDataSource( settings );
4747 if ( dataSrc != 'ssp' || deferLoading ) {
4748 // if there is an ajax source load the data
4749 if ( dataSrc == 'ajax' ) {
4750 _fnBuildAjax( settings, [], function(json) {
4751 var aData = _fnAjaxDataSrc( settings, json );
4753 // Got the data - add it to the table
4754 for ( i=0 ; i<aData.length ; i++ ) {
4755 _fnAddData( settings, aData[i] );
4758 // Reset the init display for cookie saving. We've already done
4759 // a filter, and therefore cleared it before. So we need to make
4760 // it appear 'fresh'
4761 settings.iInitDisplayStart = iAjaxStart;
4763 _fnReDraw( settings );
4765 _fnProcessingDisplay( settings, false );
4766 _fnInitComplete( settings, json );
4770 _fnProcessingDisplay( settings, false );
4771 _fnInitComplete( settings );
4778 * Draw the table for the first time, adding all required features
4779 * @param {object} oSettings dataTables settings object
4780 * @param {object} [json] JSON from the server that completed the table, if using Ajax source
4781 * with client-side processing (optional)
4782 * @memberof DataTable#oApi
4784 function _fnInitComplete ( settings, json )
4786 settings._bInitComplete = true;
4788 // When data was added after the initialisation (data or Ajax) we need to
4789 // calculate the column sizing
4790 if ( json || settings.oInit.aaData ) {
4791 _fnAdjustColumnSizing( settings );
4794 _fnCallbackFire( settings, null, 'plugin-init', [settings, json] );
4795 _fnCallbackFire( settings, 'aoInitComplete', 'init', [settings, json] );
4799 function _fnLengthChange ( settings, val )
4801 var len = parseInt( val, 10 );
4802 settings._iDisplayLength = len;
4804 _fnLengthOverflow( settings );
4806 // Fire length change event
4807 _fnCallbackFire( settings, null, 'length', [settings, len] );
4812 * Generate the node required for user display length changing
4813 * @param {object} settings dataTables settings object
4814 * @returns {node} Display length feature node
4815 * @memberof DataTable#oApi
4817 function _fnFeatureHtmlLength ( settings )
4820 classes = settings.oClasses,
4821 tableId = settings.sTableId,
4822 menu = settings.aLengthMenu,
4823 d2 = $.isArray( menu[0] ),
4824 lengths = d2 ? menu[0] : menu,
4825 language = d2 ? menu[1] : menu;
4827 var select = $('<select/>', {
4828 'name': tableId+'_length',
4829 'aria-controls': tableId,
4830 'class': classes.sLengthSelect
4833 for ( var i=0, ien=lengths.length ; i<ien ; i++ ) {
4834 select[0][ i ] = new Option( language[i], lengths[i] );
4837 var div = $('<div><label/></div>').addClass( classes.sLength );
4838 if ( ! settings.aanFeatures.l ) {
4839 div[0].id = tableId+'_length';
4842 div.children().append(
4843 settings.oLanguage.sLengthMenu.replace( '_MENU_', select[0].outerHTML )
4846 // Can't use `select` variable as user might provide their own and the
4847 // reference is broken by the use of outerHTML
4849 .val( settings._iDisplayLength )
4850 .on( 'change.DT', function(e) {
4851 _fnLengthChange( settings, $(this).val() );
4852 _fnDraw( settings );
4855 // Update node value whenever anything changes the table's length
4856 $(settings.nTable).on( 'length.dt.DT', function (e, s, len) {
4857 if ( settings === s ) {
4858 $('select', div).val( len );
4867 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
4868 * Note that most of the paging logic is done in
4869 * DataTable.ext.pager
4873 * Generate the node required for default pagination
4874 * @param {object} oSettings dataTables settings object
4875 * @returns {node} Pagination feature node
4876 * @memberof DataTable#oApi
4878 function _fnFeatureHtmlPaginate ( settings )
4881 type = settings.sPaginationType,
4882 plugin = DataTable.ext.pager[ type ],
4883 modern = typeof plugin === 'function',
4884 redraw = function( settings ) {
4885 _fnDraw( settings );
4887 node = $('<div/>').addClass( settings.oClasses.sPaging + type )[0],
4888 features = settings.aanFeatures;
4891 plugin.fnInit( settings, node, redraw );
4894 /* Add a draw callback for the pagination on first instance, to update the paging display */
4897 node.id = settings.sTableId+'_paginate';
4899 settings.aoDrawCallback.push( {
4900 "fn": function( settings ) {
4903 start = settings._iDisplayStart,
4904 len = settings._iDisplayLength,
4905 visRecords = settings.fnRecordsDisplay(),
4907 page = all ? 0 : Math.ceil( start / len ),
4908 pages = all ? 1 : Math.ceil( visRecords / len ),
4909 buttons = plugin(page, pages),
4912 for ( i=0, ien=features.p.length ; i<ien ; i++ ) {
4913 _fnRenderer( settings, 'pageButton' )(
4914 settings, features.p[i], i, buttons, page, pages
4919 plugin.fnUpdate( settings, redraw );
4922 "sName": "pagination"
4931 * Alter the display settings to change the page
4932 * @param {object} settings DataTables settings object
4933 * @param {string|int} action Paging action to take: "first", "previous",
4934 * "next" or "last" or page number to jump to (integer)
4935 * @param [bool] redraw Automatically draw the update or not
4936 * @returns {bool} true page has changed, false - no change
4937 * @memberof DataTable#oApi
4939 function _fnPageChange ( settings, action, redraw )
4942 start = settings._iDisplayStart,
4943 len = settings._iDisplayLength,
4944 records = settings.fnRecordsDisplay();
4946 if ( records === 0 || len === -1 )
4950 else if ( typeof action === "number" )
4952 start = action * len;
4954 if ( start > records )
4959 else if ( action == "first" )
4963 else if ( action == "previous" )
4974 else if ( action == "next" )
4976 if ( start + len < records )
4981 else if ( action == "last" )
4983 start = Math.floor( (records-1) / len) * len;
4987 _fnLog( settings, 0, "Unknown paging action: "+action, 5 );
4990 var changed = settings._iDisplayStart !== start;
4991 settings._iDisplayStart = start;
4994 _fnCallbackFire( settings, null, 'page', [settings] );
4997 _fnDraw( settings );
5007 * Generate the node required for the processing node
5008 * @param {object} settings dataTables settings object
5009 * @returns {node} Processing element
5010 * @memberof DataTable#oApi
5012 function _fnFeatureHtmlProcessing ( settings )
5014 return $('<div/>', {
5015 'id': ! settings.aanFeatures.r ? settings.sTableId+'_processing' : null,
5016 'class': settings.oClasses.sProcessing
5018 .html( settings.oLanguage.sProcessing )
5019 .insertBefore( settings.nTable )[0];
5024 * Display or hide the processing indicator
5025 * @param {object} settings dataTables settings object
5026 * @param {bool} show Show the processing indicator (true) or not (false)
5027 * @memberof DataTable#oApi
5029 function _fnProcessingDisplay ( settings, show )
5031 if ( settings.oFeatures.bProcessing ) {
5032 $(settings.aanFeatures.r).css( 'display', show ? 'block' : 'none' );
5035 _fnCallbackFire( settings, null, 'processing', [settings, show] );
5039 * Add any control elements for the table - specifically scrolling
5040 * @param {object} settings dataTables settings object
5041 * @returns {node} Node to add to the DOM
5042 * @memberof DataTable#oApi
5044 function _fnFeatureHtmlTable ( settings )
5046 var table = $(settings.nTable);
5048 // Add the ARIA grid role to the table
5049 table.attr( 'role', 'grid' );
5051 // Scrolling from here on in
5052 var scroll = settings.oScroll;
5054 if ( scroll.sX === '' && scroll.sY === '' ) {
5055 return settings.nTable;
5058 var scrollX = scroll.sX;
5059 var scrollY = scroll.sY;
5060 var classes = settings.oClasses;
5061 var caption = table.children('caption');
5062 var captionSide = caption.length ? caption[0]._captionSide : null;
5063 var headerClone = $( table[0].cloneNode(false) );
5064 var footerClone = $( table[0].cloneNode(false) );
5065 var footer = table.children('tfoot');
5066 var _div = '<div/>';
5067 var size = function ( s ) {
5068 return !s ? null : _fnStringToCss( s );
5071 if ( ! footer.length ) {
5076 * The HTML structure that we want to generate in this function is:
5079 * div - scroll head inner
5080 * table - scroll head table
5083 * table - table (master table)
5084 * thead - thead clone for sizing
5087 * div - scroll foot inner
5088 * table - scroll foot table
5091 var scroller = $( _div, { 'class': classes.sScrollWrapper } )
5093 $(_div, { 'class': classes.sScrollHead } )
5096 position: 'relative',
5098 width: scrollX ? size(scrollX) : '100%'
5101 $(_div, { 'class': classes.sScrollHeadInner } )
5103 'box-sizing': 'content-box',
5104 width: scroll.sXInner || '100%'
5109 .css( 'margin-left', 0 )
5110 .append( captionSide === 'top' ? caption : null )
5112 table.children('thead')
5118 $(_div, { 'class': classes.sScrollBody } )
5120 position: 'relative',
5122 width: size( scrollX )
5129 $(_div, { 'class': classes.sScrollFoot } )
5133 width: scrollX ? size(scrollX) : '100%'
5136 $(_div, { 'class': classes.sScrollFootInner } )
5140 .css( 'margin-left', 0 )
5141 .append( captionSide === 'bottom' ? caption : null )
5143 table.children('tfoot')
5150 var children = scroller.children();
5151 var scrollHead = children[0];
5152 var scrollBody = children[1];
5153 var scrollFoot = footer ? children[2] : null;
5155 // When the body is scrolled, then we also want to scroll the headers
5157 $(scrollBody).on( 'scroll.DT', function (e) {
5158 var scrollLeft = this.scrollLeft;
5160 scrollHead.scrollLeft = scrollLeft;
5163 scrollFoot.scrollLeft = scrollLeft;
5169 scrollY && scroll.bCollapse ? 'max-height' : 'height',
5173 settings.nScrollHead = scrollHead;
5174 settings.nScrollBody = scrollBody;
5175 settings.nScrollFoot = scrollFoot;
5177 // On redraw - align columns
5178 settings.aoDrawCallback.push( {
5179 "fn": _fnScrollDraw,
5180 "sName": "scrolling"
5189 * Update the header, footer and body tables for resizing - i.e. column
5192 * Welcome to the most horrible function DataTables. The process that this
5193 * function follows is basically:
5194 * 1. Re-create the table inside the scrolling div
5195 * 2. Take live measurements from the DOM
5196 * 3. Apply the measurements to align the columns
5199 * @param {object} settings dataTables settings object
5200 * @memberof DataTable#oApi
5202 function _fnScrollDraw ( settings )
5204 // Given that this is such a monster function, a lot of variables are use
5205 // to try and keep the minimised size as small as possible
5207 scroll = settings.oScroll,
5208 scrollX = scroll.sX,
5209 scrollXInner = scroll.sXInner,
5210 scrollY = scroll.sY,
5211 barWidth = scroll.iBarWidth,
5212 divHeader = $(settings.nScrollHead),
5213 divHeaderStyle = divHeader[0].style,
5214 divHeaderInner = divHeader.children('div'),
5215 divHeaderInnerStyle = divHeaderInner[0].style,
5216 divHeaderTable = divHeaderInner.children('table'),
5217 divBodyEl = settings.nScrollBody,
5218 divBody = $(divBodyEl),
5219 divBodyStyle = divBodyEl.style,
5220 divFooter = $(settings.nScrollFoot),
5221 divFooterInner = divFooter.children('div'),
5222 divFooterTable = divFooterInner.children('table'),
5223 header = $(settings.nTHead),
5224 table = $(settings.nTable),
5226 tableStyle = tableEl.style,
5227 footer = settings.nTFoot ? $(settings.nTFoot) : null,
5228 browser = settings.oBrowser,
5229 ie67 = browser.bScrollOversize,
5230 dtHeaderCells = _pluck( settings.aoColumns, 'nTh' ),
5231 headerTrgEls, footerTrgEls,
5232 headerSrcEls, footerSrcEls,
5233 headerCopy, footerCopy,
5234 headerWidths=[], footerWidths=[],
5235 headerContent=[], footerContent=[],
5236 idx, correction, sanityWidth,
5237 zeroOut = function(nSizer) {
5238 var style = nSizer.style;
5239 style.paddingTop = "0";
5240 style.paddingBottom = "0";
5241 style.borderTopWidth = "0";
5242 style.borderBottomWidth = "0";
5246 // If the scrollbar visibility has changed from the last draw, we need to
5247 // adjust the column sizes as the table width will have changed to account
5248 // for the scrollbar
5249 var scrollBarVis = divBodyEl.scrollHeight > divBodyEl.clientHeight;
5251 if ( settings.scrollBarVis !== scrollBarVis && settings.scrollBarVis !== undefined ) {
5252 settings.scrollBarVis = scrollBarVis;
5253 _fnAdjustColumnSizing( settings );
5254 return; // adjust column sizing will call this function again
5257 settings.scrollBarVis = scrollBarVis;
5261 * 1. Re-create the table inside the scrolling div
5264 // Remove the old minimised thead and tfoot elements in the inner table
5265 table.children('thead, tfoot').remove();
5268 footerCopy = footer.clone().prependTo( table );
5269 footerTrgEls = footer.find('tr'); // the original tfoot is in its own table and must be sized
5270 footerSrcEls = footerCopy.find('tr');
5273 // Clone the current header and footer elements and then place it into the inner table
5274 headerCopy = header.clone().prependTo( table );
5275 headerTrgEls = header.find('tr'); // original header is in its own table
5276 headerSrcEls = headerCopy.find('tr');
5277 headerCopy.find('th, td').removeAttr('tabindex');
5281 * 2. Take live measurements from the DOM - do not alter the DOM itself!
5284 // Remove old sizing and apply the calculated column widths
5285 // Get the unique column headers in the newly created (cloned) header. We want to apply the
5286 // calculated sizes to this header
5289 divBodyStyle.width = '100%';
5290 divHeader[0].style.width = '100%';
5293 $.each( _fnGetUniqueThs( settings, headerCopy ), function ( i, el ) {
5294 idx = _fnVisibleToColumnIndex( settings, i );
5295 el.style.width = settings.aoColumns[idx].sWidth;
5299 _fnApplyToChildren( function(n) {
5304 // Size the table as a whole
5305 sanityWidth = table.outerWidth();
5306 if ( scrollX === "" ) {
5308 tableStyle.width = "100%";
5310 // IE7 will make the width of the table when 100% include the scrollbar
5311 // - which is shouldn't. When there is a scrollbar we need to take this
5313 if ( ie67 && (table.find('tbody').height() > divBodyEl.offsetHeight ||
5314 divBody.css('overflow-y') == "scroll")
5316 tableStyle.width = _fnStringToCss( table.outerWidth() - barWidth);
5319 // Recalculate the sanity width
5320 sanityWidth = table.outerWidth();
5322 else if ( scrollXInner !== "" ) {
5323 // legacy x scroll inner has been given - use it
5324 tableStyle.width = _fnStringToCss(scrollXInner);
5326 // Recalculate the sanity width
5327 sanityWidth = table.outerWidth();
5330 // Hidden header should have zero height, so remove padding and borders. Then
5331 // set the width based on the real headers
5333 // Apply all styles in one pass
5334 _fnApplyToChildren( zeroOut, headerSrcEls );
5336 // Read all widths in next pass
5337 _fnApplyToChildren( function(nSizer) {
5338 headerContent.push( nSizer.innerHTML );
5339 headerWidths.push( _fnStringToCss( $(nSizer).css('width') ) );
5342 // Apply all widths in final pass
5343 _fnApplyToChildren( function(nToSize, i) {
5344 // Only apply widths to the DataTables detected header cells - this
5345 // prevents complex headers from having contradictory sizes applied
5346 if ( $.inArray( nToSize, dtHeaderCells ) !== -1 ) {
5347 nToSize.style.width = headerWidths[i];
5351 $(headerSrcEls).height(0);
5353 /* Same again with the footer if we have one */
5356 _fnApplyToChildren( zeroOut, footerSrcEls );
5358 _fnApplyToChildren( function(nSizer) {
5359 footerContent.push( nSizer.innerHTML );
5360 footerWidths.push( _fnStringToCss( $(nSizer).css('width') ) );
5363 _fnApplyToChildren( function(nToSize, i) {
5364 nToSize.style.width = footerWidths[i];
5367 $(footerSrcEls).height(0);
5372 * 3. Apply the measurements
5375 // "Hide" the header and footer that we used for the sizing. We need to keep
5376 // the content of the cell so that the width applied to the header and body
5377 // both match, but we want to hide it completely. We want to also fix their
5378 // width to what they currently are
5379 _fnApplyToChildren( function(nSizer, i) {
5380 nSizer.innerHTML = '<div class="dataTables_sizing" style="height:0;overflow:hidden;">'+headerContent[i]+'</div>';
5381 nSizer.style.width = headerWidths[i];
5386 _fnApplyToChildren( function(nSizer, i) {
5387 nSizer.innerHTML = '<div class="dataTables_sizing" style="height:0;overflow:hidden;">'+footerContent[i]+'</div>';
5388 nSizer.style.width = footerWidths[i];
5392 // Sanity check that the table is of a sensible width. If not then we are going to get
5393 // misalignment - try to prevent this by not allowing the table to shrink below its min width
5394 if ( table.outerWidth() < sanityWidth )
5396 // The min width depends upon if we have a vertical scrollbar visible or not */
5397 correction = ((divBodyEl.scrollHeight > divBodyEl.offsetHeight ||
5398 divBody.css('overflow-y') == "scroll")) ?
5399 sanityWidth+barWidth :
5402 // IE6/7 are a law unto themselves...
5403 if ( ie67 && (divBodyEl.scrollHeight >
5404 divBodyEl.offsetHeight || divBody.css('overflow-y') == "scroll")
5406 tableStyle.width = _fnStringToCss( correction-barWidth );
5409 // And give the user a warning that we've stopped the table getting too small
5410 if ( scrollX === "" || scrollXInner !== "" ) {
5411 _fnLog( settings, 1, 'Possible column misalignment', 6 );
5416 correction = '100%';
5419 // Apply to the container elements
5420 divBodyStyle.width = _fnStringToCss( correction );
5421 divHeaderStyle.width = _fnStringToCss( correction );
5424 settings.nScrollFoot.style.width = _fnStringToCss( correction );
5432 /* IE7< puts a vertical scrollbar in place (when it shouldn't be) due to subtracting
5433 * the scrollbar height from the visible display, rather than adding it on. We need to
5434 * set the height in order to sort this. Don't want to do it in any other browsers.
5437 divBodyStyle.height = _fnStringToCss( tableEl.offsetHeight+barWidth );
5441 /* Finally set the width's of the header and footer tables */
5442 var iOuterWidth = table.outerWidth();
5443 divHeaderTable[0].style.width = _fnStringToCss( iOuterWidth );
5444 divHeaderInnerStyle.width = _fnStringToCss( iOuterWidth );
5446 // Figure out if there are scrollbar present - if so then we need a the header and footer to
5447 // provide a bit more space to allow "overflow" scrolling (i.e. past the scrollbar)
5448 var bScrolling = table.height() > divBodyEl.clientHeight || divBody.css('overflow-y') == "scroll";
5449 var padding = 'padding' + (browser.bScrollbarLeft ? 'Left' : 'Right' );
5450 divHeaderInnerStyle[ padding ] = bScrolling ? barWidth+"px" : "0px";
5453 divFooterTable[0].style.width = _fnStringToCss( iOuterWidth );
5454 divFooterInner[0].style.width = _fnStringToCss( iOuterWidth );
5455 divFooterInner[0].style[padding] = bScrolling ? barWidth+"px" : "0px";
5458 // Correct DOM ordering for colgroup - comes before the thead
5459 table.children('colgroup').insertBefore( table.children('thead') );
5461 /* Adjust the position of the header in case we loose the y-scrollbar */
5464 // If sorting or filtering has occurred, jump the scrolling back to the top
5465 // only if we aren't holding the position
5466 if ( (settings.bSorted || settings.bFiltered) && ! settings._drawHold ) {
5467 divBodyEl.scrollTop = 0;
5474 * Apply a given function to the display child nodes of an element array (typically
5475 * TD children of TR rows
5476 * @param {function} fn Method to apply to the objects
5477 * @param array {nodes} an1 List of elements to look through for display children
5478 * @param array {nodes} an2 Another list (identical structure to the first) - optional
5479 * @memberof DataTable#oApi
5481 function _fnApplyToChildren( fn, an1, an2 )
5483 var index=0, i=0, iLen=an1.length;
5486 while ( i < iLen ) {
5487 nNode1 = an1[i].firstChild;
5488 nNode2 = an2 ? an2[i].firstChild : null;
5491 if ( nNode1.nodeType === 1 ) {
5493 fn( nNode1, nNode2, index );
5496 fn( nNode1, index );
5502 nNode1 = nNode1.nextSibling;
5503 nNode2 = an2 ? nNode2.nextSibling : null;
5512 var __re_html_remove = /<.*?>/g;
5516 * Calculate the width of columns for the table
5517 * @param {object} oSettings dataTables settings object
5518 * @memberof DataTable#oApi
5520 function _fnCalculateColumnWidths ( oSettings )
5523 table = oSettings.nTable,
5524 columns = oSettings.aoColumns,
5525 scroll = oSettings.oScroll,
5526 scrollY = scroll.sY,
5527 scrollX = scroll.sX,
5528 scrollXInner = scroll.sXInner,
5529 columnCount = columns.length,
5530 visibleColumns = _fnGetColumns( oSettings, 'bVisible' ),
5531 headerCells = $('th', oSettings.nTHead),
5532 tableWidthAttr = table.getAttribute('width'), // from DOM element
5533 tableContainer = table.parentNode,
5535 i, column, columnIdx, width, outerWidth,
5536 browser = oSettings.oBrowser,
5537 ie67 = browser.bScrollOversize;
5539 var styleWidth = table.style.width;
5540 if ( styleWidth && styleWidth.indexOf('%') !== -1 ) {
5541 tableWidthAttr = styleWidth;
5544 /* Convert any user input sizes into pixel sizes */
5545 for ( i=0 ; i<visibleColumns.length ; i++ ) {
5546 column = columns[ visibleColumns[i] ];
5548 if ( column.sWidth !== null ) {
5549 column.sWidth = _fnConvertToWidth( column.sWidthOrig, tableContainer );
5555 /* If the number of columns in the DOM equals the number that we have to
5556 * process in DataTables, then we can use the offsets that are created by
5557 * the web- browser. No custom sizes can be set in order for this to happen,
5558 * nor scrolling used
5560 if ( ie67 || ! userInputs && ! scrollX && ! scrollY &&
5561 columnCount == _fnVisbleColumns( oSettings ) &&
5562 columnCount == headerCells.length
5564 for ( i=0 ; i<columnCount ; i++ ) {
5565 var colIdx = _fnVisibleToColumnIndex( oSettings, i );
5567 if ( colIdx !== null ) {
5568 columns[ colIdx ].sWidth = _fnStringToCss( headerCells.eq(i).width() );
5574 // Otherwise construct a single row, worst case, table with the widest
5575 // node in the data, assign any user defined widths, then insert it into
5576 // the DOM and allow the browser to do all the hard work of calculating
5578 var tmpTable = $(table).clone() // don't use cloneNode - IE8 will remove events on the main table
5579 .css( 'visibility', 'hidden' )
5580 .removeAttr( 'id' );
5582 // Clean up the table body
5583 tmpTable.find('tbody tr').remove();
5584 var tr = $('<tr/>').appendTo( tmpTable.find('tbody') );
5586 // Clone the table header and footer - we can't use the header / footer
5587 // from the cloned table, since if scrolling is active, the table's
5588 // real header and footer are contained in different table tags
5589 tmpTable.find('thead, tfoot').remove();
5591 .append( $(oSettings.nTHead).clone() )
5592 .append( $(oSettings.nTFoot).clone() );
5594 // Remove any assigned widths from the footer (from scrolling)
5595 tmpTable.find('tfoot th, tfoot td').css('width', '');
5597 // Apply custom sizing to the cloned header
5598 headerCells = _fnGetUniqueThs( oSettings, tmpTable.find('thead')[0] );
5600 for ( i=0 ; i<visibleColumns.length ; i++ ) {
5601 column = columns[ visibleColumns[i] ];
5603 headerCells[i].style.width = column.sWidthOrig !== null && column.sWidthOrig !== '' ?
5604 _fnStringToCss( column.sWidthOrig ) :
5607 // For scrollX we need to force the column width otherwise the
5608 // browser will collapse it. If this width is smaller than the
5609 // width the column requires, then it will have no effect
5610 if ( column.sWidthOrig && scrollX ) {
5611 $( headerCells[i] ).append( $('<div/>').css( {
5612 width: column.sWidthOrig,
5621 // Find the widest cell for each column and put it into the table
5622 if ( oSettings.aoData.length ) {
5623 for ( i=0 ; i<visibleColumns.length ; i++ ) {
5624 columnIdx = visibleColumns[i];
5625 column = columns[ columnIdx ];
5627 $( _fnGetWidestNode( oSettings, columnIdx ) )
5629 .append( column.sContentPadding )
5634 // Tidy the temporary table - remove name attributes so there aren't
5635 // duplicated in the dom (radio elements for example)
5636 $('[name]', tmpTable).removeAttr('name');
5638 // Table has been built, attach to the document so we can work with it.
5639 // A holding element is used, positioned at the top of the container
5640 // with minimal height, so it has no effect on if the container scrolls
5641 // or not. Otherwise it might trigger scrolling when it actually isn't
5643 var holder = $('<div/>').css( scrollX || scrollY ?
5645 position: 'absolute',
5655 .appendTo( tableContainer );
5657 // When scrolling (X or Y) we want to set the width of the table as
5658 // appropriate. However, when not scrolling leave the table width as it
5659 // is. This results in slightly different, but I think correct behaviour
5660 if ( scrollX && scrollXInner ) {
5661 tmpTable.width( scrollXInner );
5663 else if ( scrollX ) {
5664 tmpTable.css( 'width', 'auto' );
5665 tmpTable.removeAttr('width');
5667 // If there is no width attribute or style, then allow the table to
5669 if ( tmpTable.width() < tableContainer.clientWidth && tableWidthAttr ) {
5670 tmpTable.width( tableContainer.clientWidth );
5673 else if ( scrollY ) {
5674 tmpTable.width( tableContainer.clientWidth );
5676 else if ( tableWidthAttr ) {
5677 tmpTable.width( tableWidthAttr );
5680 // Get the width of each column in the constructed table - we need to
5681 // know the inner width (so it can be assigned to the other table's
5682 // cells) and the outer width so we can calculate the full width of the
5683 // table. This is safe since DataTables requires a unique cell for each
5684 // column, but if ever a header can span multiple columns, this will
5685 // need to be modified.
5687 for ( i=0 ; i<visibleColumns.length ; i++ ) {
5688 var cell = $(headerCells[i]);
5689 var border = cell.outerWidth() - cell.width();
5691 // Use getBounding... where possible (not IE8-) because it can give
5692 // sub-pixel accuracy, which we then want to round up!
5693 var bounding = browser.bBounding ?
5694 Math.ceil( headerCells[i].getBoundingClientRect().width ) :
5697 // Total is tracked to remove any sub-pixel errors as the outerWidth
5698 // of the table might not equal the total given here (IE!).
5701 // Width for each column to use
5702 columns[ visibleColumns[i] ].sWidth = _fnStringToCss( bounding - border );
5705 table.style.width = _fnStringToCss( total );
5707 // Finished with the table - ditch it
5711 // If there is a width attr, we want to attach an event listener which
5712 // allows the table sizing to automatically adjust when the window is
5713 // resized. Use the width attr rather than CSS, since we can't know if the
5714 // CSS is a relative value or absolute - DOM read is always px.
5715 if ( tableWidthAttr ) {
5716 table.style.width = _fnStringToCss( tableWidthAttr );
5719 if ( (tableWidthAttr || scrollX) && ! oSettings._reszEvt ) {
5720 var bindResize = function () {
5721 $(window).on('resize.DT-'+oSettings.sInstance, _fnThrottle( function () {
5722 _fnAdjustColumnSizing( oSettings );
5726 // IE6/7 will crash if we bind a resize event handler on page load.
5727 // To be removed in 1.11 which drops IE6/7 support
5729 setTimeout( bindResize, 1000 );
5735 oSettings._reszEvt = true;
5741 * Throttle the calls to a function. Arguments and context are maintained for
5742 * the throttled function
5743 * @param {function} fn Function to be called
5744 * @param {int} [freq=200] call frequency in mS
5745 * @returns {function} wrapped function
5746 * @memberof DataTable#oApi
5748 var _fnThrottle = DataTable.util.throttle;
5752 * Convert a CSS unit width to pixels (e.g. 2em)
5753 * @param {string} width width to be converted
5754 * @param {node} parent parent to get the with for (required for relative widths) - optional
5755 * @returns {int} width in pixels
5756 * @memberof DataTable#oApi
5758 function _fnConvertToWidth ( width, parent )
5765 .css( 'width', _fnStringToCss( width ) )
5766 .appendTo( parent || document.body );
5768 var val = n[0].offsetWidth;
5776 * Get the widest node
5777 * @param {object} settings dataTables settings object
5778 * @param {int} colIdx column of interest
5779 * @returns {node} widest table node
5780 * @memberof DataTable#oApi
5782 function _fnGetWidestNode( settings, colIdx )
5784 var idx = _fnGetMaxLenString( settings, colIdx );
5789 var data = settings.aoData[ idx ];
5790 return ! data.nTr ? // Might not have been created when deferred rendering
5791 $('<td/>').html( _fnGetCellData( settings, idx, colIdx, 'display' ) )[0] :
5792 data.anCells[ colIdx ];
5797 * Get the maximum strlen for each data column
5798 * @param {object} settings dataTables settings object
5799 * @param {int} colIdx column of interest
5800 * @returns {string} max string length for each column
5801 * @memberof DataTable#oApi
5803 function _fnGetMaxLenString( settings, colIdx )
5805 var s, max=-1, maxIdx = -1;
5807 for ( var i=0, ien=settings.aoData.length ; i<ien ; i++ ) {
5808 s = _fnGetCellData( settings, i, colIdx, 'display' )+'';
5809 s = s.replace( __re_html_remove, '' );
5810 s = s.replace( / /g, ' ' );
5812 if ( s.length > max ) {
5823 * Append a CSS unit (only if required) to a string
5824 * @param {string} value to css-ify
5825 * @returns {string} value with css unit
5826 * @memberof DataTable#oApi
5828 function _fnStringToCss( s )
5834 if ( typeof s == 'number' ) {
5840 // Check it has a unit character already
5841 return s.match(/\d$/) ?
5848 function _fnSortFlatten ( settings )
5854 aoColumns = settings.aoColumns,
5855 aDataSort, iCol, sType, srcCol,
5856 fixed = settings.aaSortingFixed,
5857 fixedObj = $.isPlainObject( fixed ),
5859 add = function ( a ) {
5860 if ( a.length && ! $.isArray( a[0] ) ) {
5862 nestedSort.push( a );
5866 $.merge( nestedSort, a );
5870 // Build the sort array, with pre-fix and post-fix options if they have been
5872 if ( $.isArray( fixed ) ) {
5876 if ( fixedObj && fixed.pre ) {
5880 add( settings.aaSorting );
5882 if (fixedObj && fixed.post ) {
5886 for ( i=0 ; i<nestedSort.length ; i++ )
5888 srcCol = nestedSort[i][0];
5889 aDataSort = aoColumns[ srcCol ].aDataSort;
5891 for ( k=0, kLen=aDataSort.length ; k<kLen ; k++ )
5893 iCol = aDataSort[k];
5894 sType = aoColumns[ iCol ].sType || 'string';
5896 if ( nestedSort[i]._idx === undefined ) {
5897 nestedSort[i]._idx = $.inArray( nestedSort[i][1], aoColumns[iCol].asSorting );
5903 dir: nestedSort[i][1],
5904 index: nestedSort[i]._idx,
5906 formatter: DataTable.ext.type.order[ sType+"-pre" ]
5915 * Change the order of the table
5916 * @param {object} oSettings dataTables settings object
5917 * @memberof DataTable#oApi
5918 * @todo This really needs split up!
5920 function _fnSort ( oSettings )
5923 i, ien, iLen, j, jLen, k, kLen,
5926 oExtSort = DataTable.ext.type.order,
5927 aoData = oSettings.aoData,
5928 aoColumns = oSettings.aoColumns,
5929 aDataSort, data, iCol, sType, oSort,
5932 displayMaster = oSettings.aiDisplayMaster,
5935 // Resolve any column types that are unknown due to addition or invalidation
5936 // @todo Can this be moved into a 'data-ready' handler which is called when
5937 // data is going to be used in the table?
5938 _fnColumnTypes( oSettings );
5940 aSort = _fnSortFlatten( oSettings );
5942 for ( i=0, ien=aSort.length ; i<ien ; i++ ) {
5945 // Track if we can use the fast sort algorithm
5946 if ( sortCol.formatter ) {
5950 // Load the data needed for the sort, for each cell
5951 _fnSortData( oSettings, sortCol.col );
5954 /* No sorting required if server-side or no sorting array */
5955 if ( _fnDataSource( oSettings ) != 'ssp' && aSort.length !== 0 )
5957 // Create a value - key array of the current row positions such that we can use their
5958 // current position during the sort, if values match, in order to perform stable sorting
5959 for ( i=0, iLen=displayMaster.length ; i<iLen ; i++ ) {
5960 aiOrig[ displayMaster[i] ] = i;
5963 /* Do the sort - here we want multi-column sorting based on a given data source (column)
5964 * and sorting function (from oSort) in a certain direction. It's reasonably complex to
5965 * follow on it's own, but this is what we want (example two column sorting):
5966 * fnLocalSorting = function(a,b){
5968 * iTest = oSort['string-asc']('data11', 'data12');
5971 * iTest = oSort['numeric-desc']('data21', 'data22');
5974 * return oSort['numeric-asc']( aiOrig[a], aiOrig[b] );
5976 * Basically we have a test for each sorting column, if the data in that column is equal,
5977 * test the next column. If all columns match, then we use a numeric sort on the row
5978 * positions in the original data array to provide a stable sort.
5980 * Note - I know it seems excessive to have two sorting methods, but the first is around
5981 * 15% faster, so the second is only maintained for backwards compatibility with sorting
5982 * methods which do not have a pre-sort formatting function.
5984 if ( formatters === aSort.length ) {
5985 // All sort types have formatting functions
5986 displayMaster.sort( function ( a, b ) {
5988 x, y, k, test, sort,
5990 dataA = aoData[a]._aSortData,
5991 dataB = aoData[b]._aSortData;
5993 for ( k=0 ; k<len ; k++ ) {
5996 x = dataA[ sort.col ];
5997 y = dataB[ sort.col ];
5999 test = x<y ? -1 : x>y ? 1 : 0;
6001 return sort.dir === 'asc' ? test : -test;
6007 return x<y ? -1 : x>y ? 1 : 0;
6011 // Depreciated - remove in 1.11 (providing a plug-in option)
6012 // Not all sort types have formatting methods, so we have to call their sorting
6014 displayMaster.sort( function ( a, b ) {
6016 x, y, k, l, test, sort, fn,
6018 dataA = aoData[a]._aSortData,
6019 dataB = aoData[b]._aSortData;
6021 for ( k=0 ; k<len ; k++ ) {
6024 x = dataA[ sort.col ];
6025 y = dataB[ sort.col ];
6027 fn = oExtSort[ sort.type+"-"+sort.dir ] || oExtSort[ "string-"+sort.dir ];
6036 return x<y ? -1 : x>y ? 1 : 0;
6041 /* Tell the draw function that we have sorted the data */
6042 oSettings.bSorted = true;
6046 function _fnSortAria ( settings )
6050 var columns = settings.aoColumns;
6051 var aSort = _fnSortFlatten( settings );
6052 var oAria = settings.oLanguage.oAria;
6054 // ARIA attributes - need to loop all columns, to update all (removing old
6055 // attributes as needed)
6056 for ( var i=0, iLen=columns.length ; i<iLen ; i++ )
6058 var col = columns[i];
6059 var asSorting = col.asSorting;
6060 var sTitle = col.sTitle.replace( /<.*?>/g, "" );
6063 // IE7 is throwing an error when setting these properties with jQuery's
6064 // attr() and removeAttr() methods...
6065 th.removeAttribute('aria-sort');
6067 /* In ARIA only the first sorting column can be marked as sorting - no multi-sort option */
6068 if ( col.bSortable ) {
6069 if ( aSort.length > 0 && aSort[0].col == i ) {
6070 th.setAttribute('aria-sort', aSort[0].dir=="asc" ? "ascending" : "descending" );
6071 nextSort = asSorting[ aSort[0].index+1 ] || asSorting[0];
6074 nextSort = asSorting[0];
6077 label = sTitle + ( nextSort === "asc" ?
6078 oAria.sSortAscending :
6079 oAria.sSortDescending
6086 th.setAttribute('aria-label', label);
6092 * Function to run on user sort request
6093 * @param {object} settings dataTables settings object
6094 * @param {node} attachTo node to attach the handler to
6095 * @param {int} colIdx column sorting index
6096 * @param {boolean} [append=false] Append the requested sort to the existing
6097 * sort if true (i.e. multi-column sort)
6098 * @param {function} [callback] callback function
6099 * @memberof DataTable#oApi
6101 function _fnSortListener ( settings, colIdx, append, callback )
6103 var col = settings.aoColumns[ colIdx ];
6104 var sorting = settings.aaSorting;
6105 var asSorting = col.asSorting;
6107 var next = function ( a, overflow ) {
6109 if ( idx === undefined ) {
6110 idx = $.inArray( a[1], asSorting );
6113 return idx+1 < asSorting.length ?
6120 // Convert to 2D array if needed
6121 if ( typeof sorting[0] === 'number' ) {
6122 sorting = settings.aaSorting = [ sorting ];
6125 // If appending the sort then we are multi-column sorting
6126 if ( append && settings.oFeatures.bSortMulti ) {
6127 // Are we already doing some kind of sort on this column?
6128 var sortIdx = $.inArray( colIdx, _pluck(sorting, '0') );
6130 if ( sortIdx !== -1 ) {
6131 // Yes, modify the sort
6132 nextSortIdx = next( sorting[sortIdx], true );
6134 if ( nextSortIdx === null && sorting.length === 1 ) {
6135 nextSortIdx = 0; // can't remove sorting completely
6138 if ( nextSortIdx === null ) {
6139 sorting.splice( sortIdx, 1 );
6142 sorting[sortIdx][1] = asSorting[ nextSortIdx ];
6143 sorting[sortIdx]._idx = nextSortIdx;
6147 // No sort on this column yet
6148 sorting.push( [ colIdx, asSorting[0], 0 ] );
6149 sorting[sorting.length-1]._idx = 0;
6152 else if ( sorting.length && sorting[0][0] == colIdx ) {
6153 // Single column - already sorting on this column, modify the sort
6154 nextSortIdx = next( sorting[0] );
6157 sorting[0][1] = asSorting[ nextSortIdx ];
6158 sorting[0]._idx = nextSortIdx;
6161 // Single column - sort only on this column
6163 sorting.push( [ colIdx, asSorting[0] ] );
6164 sorting[0]._idx = 0;
6167 // Run the sort by calling a full redraw
6168 _fnReDraw( settings );
6170 // callback used for async user interaction
6171 if ( typeof callback == 'function' ) {
6172 callback( settings );
6178 * Attach a sort handler (click) to a node
6179 * @param {object} settings dataTables settings object
6180 * @param {node} attachTo node to attach the handler to
6181 * @param {int} colIdx column sorting index
6182 * @param {function} [callback] callback function
6183 * @memberof DataTable#oApi
6185 function _fnSortAttachListener ( settings, attachTo, colIdx, callback )
6187 var col = settings.aoColumns[ colIdx ];
6189 _fnBindAction( attachTo, {}, function (e) {
6190 /* If the column is not sortable - don't to anything */
6191 if ( col.bSortable === false ) {
6195 // If processing is enabled use a timeout to allow the processing
6196 // display to be shown - otherwise to it synchronously
6197 if ( settings.oFeatures.bProcessing ) {
6198 _fnProcessingDisplay( settings, true );
6200 setTimeout( function() {
6201 _fnSortListener( settings, colIdx, e.shiftKey, callback );
6203 // In server-side processing, the draw callback will remove the
6204 // processing display
6205 if ( _fnDataSource( settings ) !== 'ssp' ) {
6206 _fnProcessingDisplay( settings, false );
6211 _fnSortListener( settings, colIdx, e.shiftKey, callback );
6218 * Set the sorting classes on table's body, Note: it is safe to call this function
6219 * when bSort and bSortClasses are false
6220 * @param {object} oSettings dataTables settings object
6221 * @memberof DataTable#oApi
6223 function _fnSortingClasses( settings )
6225 var oldSort = settings.aLastSort;
6226 var sortClass = settings.oClasses.sSortColumn;
6227 var sort = _fnSortFlatten( settings );
6228 var features = settings.oFeatures;
6231 if ( features.bSort && features.bSortClasses ) {
6232 // Remove old sorting classes
6233 for ( i=0, ien=oldSort.length ; i<ien ; i++ ) {
6234 colIdx = oldSort[i].src;
6236 // Remove column sorting
6237 $( _pluck( settings.aoData, 'anCells', colIdx ) )
6238 .removeClass( sortClass + (i<2 ? i+1 : 3) );
6241 // Add new column sorting
6242 for ( i=0, ien=sort.length ; i<ien ; i++ ) {
6243 colIdx = sort[i].src;
6245 $( _pluck( settings.aoData, 'anCells', colIdx ) )
6246 .addClass( sortClass + (i<2 ? i+1 : 3) );
6250 settings.aLastSort = sort;
6254 // Get the data to sort a column, be it from cache, fresh (populating the
6255 // cache), or from a sort formatter
6256 function _fnSortData( settings, idx )
6258 // Custom sorting function - provided by the sort data type
6259 var column = settings.aoColumns[ idx ];
6260 var customSort = DataTable.ext.order[ column.sSortDataType ];
6264 customData = customSort.call( settings.oInstance, settings, idx,
6265 _fnColumnIndexToVisible( settings, idx )
6269 // Use / populate cache
6271 var formatter = DataTable.ext.type.order[ column.sType+"-pre" ];
6273 for ( var i=0, ien=settings.aoData.length ; i<ien ; i++ ) {
6274 row = settings.aoData[i];
6276 if ( ! row._aSortData ) {
6277 row._aSortData = [];
6280 if ( ! row._aSortData[idx] || customSort ) {
6281 cellData = customSort ?
6282 customData[i] : // If there was a custom sort function, use data from there
6283 _fnGetCellData( settings, i, idx, 'sort' );
6285 row._aSortData[ idx ] = formatter ?
6286 formatter( cellData ) :
6295 * Save the state of a table
6296 * @param {object} oSettings dataTables settings object
6297 * @memberof DataTable#oApi
6299 function _fnSaveState ( settings )
6301 if ( !settings.oFeatures.bStateSave || settings.bDestroying )
6306 /* Store the interesting variables */
6309 start: settings._iDisplayStart,
6310 length: settings._iDisplayLength,
6311 order: $.extend( true, [], settings.aaSorting ),
6312 search: _fnSearchToCamel( settings.oPreviousSearch ),
6313 columns: $.map( settings.aoColumns, function ( col, i ) {
6315 visible: col.bVisible,
6316 search: _fnSearchToCamel( settings.aoPreSearchCols[i] )
6321 _fnCallbackFire( settings, "aoStateSaveParams", 'stateSaveParams', [settings, state] );
6323 settings.oSavedState = state;
6324 settings.fnStateSaveCallback.call( settings.oInstance, settings, state );
6329 * Attempt to load a saved table state
6330 * @param {object} oSettings dataTables settings object
6331 * @param {object} oInit DataTables init object so we can override settings
6332 * @param {function} callback Callback to execute when the state has been loaded
6333 * @memberof DataTable#oApi
6335 function _fnLoadState ( settings, oInit, callback )
6338 var columns = settings.aoColumns;
6339 var loaded = function ( s ) {
6340 if ( ! s || ! s.time ) {
6345 // Allow custom and plug-in manipulation functions to alter the saved data set and
6346 // cancelling of loading by returning false
6347 var abStateLoad = _fnCallbackFire( settings, 'aoStateLoadParams', 'stateLoadParams', [settings, s] );
6348 if ( $.inArray( false, abStateLoad ) !== -1 ) {
6354 var duration = settings.iStateDuration;
6355 if ( duration > 0 && s.time < +new Date() - (duration*1000) ) {
6360 // Number of columns have changed - all bets are off, no restore of settings
6361 if ( s.columns && columns.length !== s.columns.length ) {
6366 // Store the saved state so it might be accessed at any time
6367 settings.oLoadedState = $.extend( true, {}, s );
6369 // Restore key features - todo - for 1.11 this needs to be done by
6370 // subscribed events
6371 if ( s.start !== undefined ) {
6372 settings._iDisplayStart = s.start;
6373 settings.iInitDisplayStart = s.start;
6375 if ( s.length !== undefined ) {
6376 settings._iDisplayLength = s.length;
6380 if ( s.order !== undefined ) {
6381 settings.aaSorting = [];
6382 $.each( s.order, function ( i, col ) {
6383 settings.aaSorting.push( col[0] >= columns.length ?
6391 if ( s.search !== undefined ) {
6392 $.extend( settings.oPreviousSearch, _fnSearchToHung( s.search ) );
6398 for ( i=0, ien=s.columns.length ; i<ien ; i++ ) {
6399 var col = s.columns[i];
6402 if ( col.visible !== undefined ) {
6403 columns[i].bVisible = col.visible;
6407 if ( col.search !== undefined ) {
6408 $.extend( settings.aoPreSearchCols[i], _fnSearchToHung( col.search ) );
6413 _fnCallbackFire( settings, 'aoStateLoaded', 'stateLoaded', [settings, s] );
6417 if ( ! settings.oFeatures.bStateSave ) {
6422 var state = settings.fnStateLoadCallback.call( settings.oInstance, settings, loaded );
6424 if ( state !== undefined ) {
6427 // otherwise, wait for the loaded callback to be executed
6432 * Return the settings object for a particular table
6433 * @param {node} table table we are using as a dataTable
6434 * @returns {object} Settings object - or null if not found
6435 * @memberof DataTable#oApi
6437 function _fnSettingsFromNode ( table )
6439 var settings = DataTable.settings;
6440 var idx = $.inArray( table, _pluck( settings, 'nTable' ) );
6449 * Log an error message
6450 * @param {object} settings dataTables settings object
6451 * @param {int} level log error messages, or display them to the user
6452 * @param {string} msg error message
6453 * @param {int} tn Technical note id to get more information about the error.
6454 * @memberof DataTable#oApi
6456 function _fnLog( settings, level, msg, tn )
6458 msg = 'DataTables warning: '+
6459 (settings ? 'table id='+settings.sTableId+' - ' : '')+msg;
6462 msg += '. For more information about this error, please see '+
6463 'http://datatables.net/tn/'+tn;
6467 // Backwards compatibility pre 1.10
6468 var ext = DataTable.ext;
6469 var type = ext.sErrMode || ext.errMode;
6472 _fnCallbackFire( settings, null, 'error', [ settings, tn, msg ] );
6475 if ( type == 'alert' ) {
6478 else if ( type == 'throw' ) {
6479 throw new Error(msg);
6481 else if ( typeof type == 'function' ) {
6482 type( settings, tn, msg );
6485 else if ( window.console && console.log ) {
6492 * See if a property is defined on one object, if so assign it to the other object
6493 * @param {object} ret target object
6494 * @param {object} src source object
6495 * @param {string} name property
6496 * @param {string} [mappedName] name to map too - optional, name used if not given
6497 * @memberof DataTable#oApi
6499 function _fnMap( ret, src, name, mappedName )
6501 if ( $.isArray( name ) ) {
6502 $.each( name, function (i, val) {
6503 if ( $.isArray( val ) ) {
6504 _fnMap( ret, src, val[0], val[1] );
6507 _fnMap( ret, src, val );
6514 if ( mappedName === undefined ) {
6518 if ( src[name] !== undefined ) {
6519 ret[mappedName] = src[name];
6525 * Extend objects - very similar to jQuery.extend, but deep copy objects, and
6526 * shallow copy arrays. The reason we need to do this, is that we don't want to
6527 * deep copy array init values (such as aaSorting) since the dev wouldn't be
6528 * able to override them, but we do want to deep copy arrays.
6529 * @param {object} out Object to extend
6530 * @param {object} extender Object from which the properties will be applied to
6532 * @param {boolean} breakRefs If true, then arrays will be sliced to take an
6533 * independent copy with the exception of the `data` or `aaData` parameters
6534 * if they are present. This is so you can pass in a collection to
6535 * DataTables and have that used as your data source without breaking the
6537 * @returns {object} out Reference, just for convenience - out === the return.
6538 * @memberof DataTable#oApi
6539 * @todo This doesn't take account of arrays inside the deep copied objects.
6541 function _fnExtend( out, extender, breakRefs )
6545 for ( var prop in extender ) {
6546 if ( extender.hasOwnProperty(prop) ) {
6547 val = extender[prop];
6549 if ( $.isPlainObject( val ) ) {
6550 if ( ! $.isPlainObject( out[prop] ) ) {
6553 $.extend( true, out[prop], val );
6555 else if ( breakRefs && prop !== 'data' && prop !== 'aaData' && $.isArray(val) ) {
6556 out[prop] = val.slice();
6569 * Bind an event handers to allow a click or return key to activate the callback.
6570 * This is good for accessibility since a return on the keyboard will have the
6571 * same effect as a click, if the element has focus.
6572 * @param {element} n Element to bind the action to
6573 * @param {object} oData Data object to pass to the triggered function
6574 * @param {function} fn Callback function for when the event is triggered
6575 * @memberof DataTable#oApi
6577 function _fnBindAction( n, oData, fn )
6580 .on( 'click.DT', oData, function (e) {
6581 n.blur(); // Remove focus outline for mouse users
6584 .on( 'keypress.DT', oData, function (e){
6585 if ( e.which === 13 ) {
6590 .on( 'selectstart.DT', function () {
6591 /* Take the brutal approach to cancelling text selection */
6598 * Register a callback function. Easily allows a callback function to be added to
6599 * an array store of callback functions that can then all be called together.
6600 * @param {object} oSettings dataTables settings object
6601 * @param {string} sStore Name of the array storage for the callbacks in oSettings
6602 * @param {function} fn Function to be called back
6603 * @param {string} sName Identifying name for the callback (i.e. a label)
6604 * @memberof DataTable#oApi
6606 function _fnCallbackReg( oSettings, sStore, fn, sName )
6610 oSettings[sStore].push( {
6619 * Fire callback functions and trigger events. Note that the loop over the
6620 * callback array store is done backwards! Further note that you do not want to
6621 * fire off triggers in time sensitive applications (for example cell creation)
6623 * @param {object} settings dataTables settings object
6624 * @param {string} callbackArr Name of the array storage for the callbacks in
6626 * @param {string} eventName Name of the jQuery custom event to trigger. If
6627 * null no trigger is fired
6628 * @param {array} args Array of arguments to pass to the callback function /
6630 * @memberof DataTable#oApi
6632 function _fnCallbackFire( settings, callbackArr, eventName, args )
6636 if ( callbackArr ) {
6637 ret = $.map( settings[callbackArr].slice().reverse(), function (val, i) {
6638 return val.fn.apply( settings.oInstance, args );
6642 if ( eventName !== null ) {
6643 var e = $.Event( eventName+'.dt' );
6645 $(settings.nTable).trigger( e, args );
6647 ret.push( e.result );
6654 function _fnLengthOverflow ( settings )
6657 start = settings._iDisplayStart,
6658 end = settings.fnDisplayEnd(),
6659 len = settings._iDisplayLength;
6661 /* If we have space to show extra rows (backing up from the end point - then do so */
6667 // Keep the start record on the current page
6668 start -= (start % len);
6670 if ( len === -1 || start < 0 )
6675 settings._iDisplayStart = start;
6679 function _fnRenderer( settings, type )
6681 var renderer = settings.renderer;
6682 var host = DataTable.ext.renderer[type];
6684 if ( $.isPlainObject( renderer ) && renderer[type] ) {
6685 // Specific renderer for this type. If available use it, otherwise use
6687 return host[renderer[type]] || host._;
6689 else if ( typeof renderer === 'string' ) {
6690 // Common renderer - if there is one available for this type use it,
6691 // otherwise use the default
6692 return host[renderer] || host._;
6701 * Detect the data source being used for the table. Used to simplify the code
6702 * a little (ajax) and to make it compress a little smaller.
6704 * @param {object} settings dataTables settings object
6705 * @returns {string} Data source
6706 * @memberof DataTable#oApi
6708 function _fnDataSource ( settings )
6710 if ( settings.oFeatures.bServerSide ) {
6713 else if ( settings.ajax || settings.sAjaxSource ) {
6723 * Computed structure of the DataTables API, defined by the options passed to
6724 * `DataTable.Api.register()` when building the API.
6726 * The structure is built in order to speed creation and extension of the Api
6727 * objects since the extensions are effectively pre-parsed.
6729 * The array is an array of objects with the following structure, where this
6730 * base array represents the Api prototype base:
6734 * name: 'data' -- string - Property name
6735 * val: function () {}, -- function - Api method (or undefined if just an object
6736 * methodExt: [ ... ], -- array - Array of Api object definitions to extend the method result
6737 * propExt: [ ... ] -- array - Array of Api object definitions to extend the property
6742 * methodExt: [ ... ],
6746 * val: function () {},
6747 * methodExt: [ ... ],
6758 var __apiStruct = [];
6762 * `Array.prototype` reference.
6767 var __arrayProto = Array.prototype;
6771 * Abstraction for `context` parameter of the `Api` constructor to allow it to
6772 * take several different forms for ease of use.
6774 * Each of the input parameter types will be converted to a DataTables settings
6775 * object where possible.
6777 * @param {string|node|jQuery|object} mixed DataTable identifier. Can be one
6780 * * `string` - jQuery selector. Any DataTables' matching the given selector
6781 * with be found and used.
6782 * * `node` - `TABLE` node which has already been formed into a DataTable.
6783 * * `jQuery` - A jQuery object of `TABLE` nodes.
6784 * * `object` - DataTables settings object
6785 * * `DataTables.Api` - API instance
6786 * @return {array|null} Matching DataTables settings objects. `null` or
6787 * `undefined` is returned if no matching DataTable is found.
6790 var _toSettings = function ( mixed )
6793 var settings = DataTable.settings;
6794 var tables = $.map( settings, function (el, i) {
6801 else if ( mixed.nTable && mixed.oApi ) {
6802 // DataTables settings object
6805 else if ( mixed.nodeName && mixed.nodeName.toLowerCase() === 'table' ) {
6807 idx = $.inArray( mixed, tables );
6808 return idx !== -1 ? [ settings[idx] ] : null;
6810 else if ( mixed && typeof mixed.settings === 'function' ) {
6811 return mixed.settings().toArray();
6813 else if ( typeof mixed === 'string' ) {
6817 else if ( mixed instanceof $ ) {
6818 // jQuery object (also DataTables instance)
6823 return jq.map( function(i) {
6824 idx = $.inArray( this, tables );
6825 return idx !== -1 ? settings[idx] : null;
6832 * DataTables API class - used to control and interface with one or more
6833 * DataTables enhanced tables.
6835 * The API class is heavily based on jQuery, presenting a chainable interface
6836 * that you can use to interact with tables. Each instance of the API class has
6837 * a "context" - i.e. the tables that it will operate on. This could be a single
6838 * table, all tables on a page or a sub-set thereof.
6840 * Additionally the API is designed to allow you to easily work with the data in
6841 * the tables, retrieving and manipulating it as required. This is done by
6842 * presenting the API class as an array like interface. The contents of the
6843 * array depend upon the actions requested by each method (for example
6844 * `rows().nodes()` will return an array of nodes, while `rows().data()` will
6845 * return an array of objects or arrays depending upon your table's
6846 * configuration). The API object has a number of array like methods (`push`,
6847 * `pop`, `reverse` etc) as well as additional helper methods (`each`, `pluck`,
6848 * `unique` etc) to assist your working with the data held in a table.
6850 * Most methods (those which return an Api instance) are chainable, which means
6851 * the return from a method call also has all of the methods available that the
6852 * top level object had. For example, these two calls are equivalent:
6855 * api.row.add( {...} );
6859 * api.row.add( {...} ).draw();
6861 * @class DataTable.Api
6862 * @param {array|object|string|jQuery} context DataTable identifier. This is
6863 * used to define which DataTables enhanced tables this API will operate on.
6866 * * `string` - jQuery selector. Any DataTables' matching the given selector
6867 * with be found and used.
6868 * * `node` - `TABLE` node which has already been formed into a DataTable.
6869 * * `jQuery` - A jQuery object of `TABLE` nodes.
6870 * * `object` - DataTables settings object
6871 * @param {array} [data] Data to initialise the Api instance with.
6874 * // Direct initialisation during DataTables construction
6875 * var api = $('#example').DataTable();
6878 * // Initialisation using a DataTables jQuery object
6879 * var api = $('#example').dataTable().api();
6882 * // Initialisation as a constructor
6883 * var api = new $.fn.DataTable.Api( 'table.dataTable' );
6885 _Api = function ( context, data )
6887 if ( ! (this instanceof _Api) ) {
6888 return new _Api( context, data );
6892 var ctxSettings = function ( o ) {
6893 var a = _toSettings( o );
6895 settings = settings.concat( a );
6899 if ( $.isArray( context ) ) {
6900 for ( var i=0, ien=context.length ; i<ien ; i++ ) {
6901 ctxSettings( context[i] );
6905 ctxSettings( context );
6908 // Remove duplicates
6909 this.context = _unique( settings );
6913 $.merge( this, data );
6923 _Api.extend( this, this, __apiStruct );
6926 DataTable.Api = _Api;
6928 // Don't destroy the existing prototype, just extend it. Required for jQuery 2's
6930 $.extend( _Api.prototype, {
6933 return this.count() !== 0;
6937 concat: __arrayProto.concat,
6940 context: [], // array of table settings objects
6945 return this.flatten().length;
6949 each: function ( fn )
6951 for ( var i=0, ien=this.length ; i<ien; i++ ) {
6952 fn.call( this, this[i], i, this );
6959 eq: function ( idx )
6961 var ctx = this.context;
6963 return ctx.length > idx ?
6964 new _Api( ctx[idx], this[idx] ) :
6969 filter: function ( fn )
6973 if ( __arrayProto.filter ) {
6974 a = __arrayProto.filter.call( this, fn, this );
6977 // Compatibility for browsers without EMCA-252-5 (JS 1.6)
6978 for ( var i=0, ien=this.length ; i<ien ; i++ ) {
6979 if ( fn.call( this, this[i], i, this ) ) {
6985 return new _Api( this.context, a );
6989 flatten: function ()
6992 return new _Api( this.context, a.concat.apply( a, this.toArray() ) );
6996 join: __arrayProto.join,
6999 indexOf: __arrayProto.indexOf || function (obj, start)
7001 for ( var i=(start || 0), ien=this.length ; i<ien ; i++ ) {
7002 if ( this[i] === obj ) {
7009 iterator: function ( flatten, type, fn, alwaysNew ) {
7013 context = this.context,
7015 selector = this.selector;
7017 // Argument shifting
7018 if ( typeof flatten === 'string' ) {
7025 for ( i=0, ien=context.length ; i<ien ; i++ ) {
7026 var apiInst = new _Api( context[i] );
7028 if ( type === 'table' ) {
7029 ret = fn.call( apiInst, context[i], i );
7031 if ( ret !== undefined ) {
7035 else if ( type === 'columns' || type === 'rows' ) {
7036 // this has same length as context - one entry for each table
7037 ret = fn.call( apiInst, context[i], this[i], i );
7039 if ( ret !== undefined ) {
7043 else if ( type === 'column' || type === 'column-rows' || type === 'row' || type === 'cell' ) {
7044 // columns and rows share the same structure.
7045 // 'this' is an array of column indexes for each context
7048 if ( type === 'column-rows' ) {
7049 rows = _selector_row_indexes( context[i], selector.opts );
7052 for ( j=0, jen=items.length ; j<jen ; j++ ) {
7055 if ( type === 'cell' ) {
7056 ret = fn.call( apiInst, context[i], item.row, item.column, i, j );
7059 ret = fn.call( apiInst, context[i], item, i, j, rows );
7062 if ( ret !== undefined ) {
7069 if ( a.length || alwaysNew ) {
7070 var api = new _Api( context, flatten ? a.concat.apply( [], a ) : a );
7071 var apiSelector = api.selector;
7072 apiSelector.rows = selector.rows;
7073 apiSelector.cols = selector.cols;
7074 apiSelector.opts = selector.opts;
7081 lastIndexOf: __arrayProto.lastIndexOf || function (obj, start)
7084 return this.indexOf.apply( this.toArray.reverse(), arguments );
7091 map: function ( fn )
7095 if ( __arrayProto.map ) {
7096 a = __arrayProto.map.call( this, fn, this );
7099 // Compatibility for browsers without EMCA-252-5 (JS 1.6)
7100 for ( var i=0, ien=this.length ; i<ien ; i++ ) {
7101 a.push( fn.call( this, this[i], i ) );
7105 return new _Api( this.context, a );
7109 pluck: function ( prop )
7111 return this.map( function ( el ) {
7116 pop: __arrayProto.pop,
7119 push: __arrayProto.push,
7122 // Does not return an API instance
7123 reduce: __arrayProto.reduce || function ( fn, init )
7125 return _fnReduce( this, fn, init, 0, this.length, 1 );
7129 reduceRight: __arrayProto.reduceRight || function ( fn, init )
7131 return _fnReduce( this, fn, init, this.length-1, -1, -1 );
7135 reverse: __arrayProto.reverse,
7138 // Object with rows, columns and opts
7142 shift: __arrayProto.shift,
7145 slice: function () {
7146 return new _Api( this.context, this );
7150 sort: __arrayProto.sort, // ? name - order?
7153 splice: __arrayProto.splice,
7156 toArray: function ()
7158 return __arrayProto.slice.call( this );
7168 toJQuery: function ()
7176 return new _Api( this.context, _unique(this) );
7180 unshift: __arrayProto.unshift
7184 _Api.extend = function ( scope, obj, ext )
7186 // Only extend API instances and static properties of the API
7187 if ( ! ext.length || ! obj || ( ! (obj instanceof _Api) && ! obj.__dt_wrapper ) ) {
7195 methodScoping = function ( scope, fn, struc ) {
7196 return function () {
7197 var ret = fn.apply( scope, arguments );
7200 _Api.extend( ret, ret, struc.methodExt );
7205 for ( i=0, ien=ext.length ; i<ien ; i++ ) {
7209 obj[ struct.name ] = typeof struct.val === 'function' ?
7210 methodScoping( scope, struct.val, struct ) :
7211 $.isPlainObject( struct.val ) ?
7215 obj[ struct.name ].__dt_wrapper = true;
7217 // Property extension
7218 _Api.extend( scope, obj[ struct.name ], struct.propExt );
7223 // @todo - Is there need for an augment function?
7224 // _Api.augment = function ( inst, name )
7226 // // Find src object in the structure from the name
7227 // var parts = name.split('.');
7229 // _Api.extend( inst, obj );
7235 // name: 'data' -- string - Property name
7236 // val: function () {}, -- function - Api method (or undefined if just an object
7237 // methodExt: [ ... ], -- array - Array of Api object definitions to extend the method result
7238 // propExt: [ ... ] -- array - Array of Api object definitions to extend the property
7243 // methodExt: [ ... ],
7247 // val: function () {},
7248 // methodExt: [ ... ],
7256 _Api.register = _api_register = function ( name, val )
7258 if ( $.isArray( name ) ) {
7259 for ( var j=0, jen=name.length ; j<jen ; j++ ) {
7260 _Api.register( name[j], val );
7267 heir = name.split('.'),
7268 struct = __apiStruct,
7271 var find = function ( src, name ) {
7272 for ( var i=0, ien=src.length ; i<ien ; i++ ) {
7273 if ( src[i].name === name ) {
7280 for ( i=0, ien=heir.length ; i<ien ; i++ ) {
7281 method = heir[i].indexOf('()') !== -1;
7283 heir[i].replace('()', '') :
7286 var src = find( struct, key );
7297 if ( i === ien-1 ) {
7309 _Api.registerPlural = _api_registerPlural = function ( pluralName, singularName, val ) {
7310 _Api.register( pluralName, val );
7312 _Api.register( singularName, function () {
7313 var ret = val.apply( this, arguments );
7315 if ( ret === this ) {
7316 // Returned item is the API instance that was passed in, return it
7319 else if ( ret instanceof _Api ) {
7320 // New API instance returned, want the value from the first item
7321 // in the returned array for the singular result.
7323 $.isArray( ret[0] ) ?
7324 new _Api( ret.context, ret[0] ) : // Array results are 'enhanced'
7329 // Non-API return - just fire it back
7336 * Selector for HTML tables. Apply the given selector to the give array of
7337 * DataTables settings objects.
7339 * @param {string|integer} [selector] jQuery selector string or integer
7340 * @param {array} Array of DataTables settings objects to be filtered
7344 var __table_selector = function ( selector, a )
7346 // Integer is used to pick out a table by index
7347 if ( typeof selector === 'number' ) {
7348 return [ a[ selector ] ];
7351 // Perform a jQuery selector on the table nodes
7352 var nodes = $.map( a, function (el, i) {
7358 .map( function (i) {
7359 // Need to translate back from the table node to the settings
7360 var idx = $.inArray( this, nodes );
7369 * Context selector for the API's context (i.e. the tables the API instance
7372 * @name DataTable.Api#tables
7373 * @param {string|integer} [selector] Selector to pick which tables the iterator
7374 * should operate on. If not given, all tables in the current context are
7375 * used. This can be given as a jQuery selector (for example `':gt(0)'`) to
7376 * select multiple tables or as an integer to select a single table.
7377 * @returns {DataTable.Api} Returns a new API instance if a selector is given.
7379 _api_register( 'tables()', function ( selector ) {
7380 // A new instance is created if there was a selector specified
7382 new _Api( __table_selector( selector, this.context ) ) :
7387 _api_register( 'table()', function ( selector ) {
7388 var tables = this.tables( selector );
7389 var ctx = tables.context;
7391 // Truncate to the first matched table
7393 new _Api( ctx[0] ) :
7398 _api_registerPlural( 'tables().nodes()', 'table().node()' , function () {
7399 return this.iterator( 'table', function ( ctx ) {
7405 _api_registerPlural( 'tables().body()', 'table().body()' , function () {
7406 return this.iterator( 'table', function ( ctx ) {
7412 _api_registerPlural( 'tables().header()', 'table().header()' , function () {
7413 return this.iterator( 'table', function ( ctx ) {
7419 _api_registerPlural( 'tables().footer()', 'table().footer()' , function () {
7420 return this.iterator( 'table', function ( ctx ) {
7426 _api_registerPlural( 'tables().containers()', 'table().container()' , function () {
7427 return this.iterator( 'table', function ( ctx ) {
7428 return ctx.nTableWrapper;
7435 * Redraw the tables in the current context.
7437 _api_register( 'draw()', function ( paging ) {
7438 return this.iterator( 'table', function ( settings ) {
7439 if ( paging === 'page' ) {
7440 _fnDraw( settings );
7443 if ( typeof paging === 'string' ) {
7444 paging = paging === 'full-hold' ?
7449 _fnReDraw( settings, paging===false );
7457 * Get the current page index.
7459 * @return {integer} Current page index (zero based)
7461 * Set the current page.
7463 * Note that if you attempt to show a page which does not exist, DataTables will
7464 * not throw an error, but rather reset the paging.
7466 * @param {integer|string} action The paging action to take. This can be one of:
7467 * * `integer` - The page index to jump to
7468 * * `string` - An action to take:
7469 * * `first` - Jump to first page.
7470 * * `next` - Jump to the next page
7471 * * `previous` - Jump to previous page
7472 * * `last` - Jump to the last page.
7473 * @returns {DataTables.Api} this
7475 _api_register( 'page()', function ( action ) {
7476 if ( action === undefined ) {
7477 return this.page.info().page; // not an expensive call
7480 // else, have an action to take on all tables
7481 return this.iterator( 'table', function ( settings ) {
7482 _fnPageChange( settings, action );
7488 * Paging information for the first table in the current context.
7490 * If you require paging information for another table, use the `table()` method
7491 * with a suitable selector.
7493 * @return {object} Object with the following properties set:
7494 * * `page` - Current page index (zero based - i.e. the first page is `0`)
7495 * * `pages` - Total number of pages
7496 * * `start` - Display index for the first record shown on the current page
7497 * * `end` - Display index for the last record shown on the current page
7498 * * `length` - Display length (number of records). Note that generally `start
7499 * + length = end`, but this is not always true, for example if there are
7500 * only 2 records to show on the final page, with a length of 10.
7501 * * `recordsTotal` - Full data set length
7502 * * `recordsDisplay` - Data set length once the current filtering criterion
7505 _api_register( 'page.info()', function ( action ) {
7506 if ( this.context.length === 0 ) {
7511 settings = this.context[0],
7512 start = settings._iDisplayStart,
7513 len = settings.oFeatures.bPaginate ? settings._iDisplayLength : -1,
7514 visRecords = settings.fnRecordsDisplay(),
7518 "page": all ? 0 : Math.floor( start / len ),
7519 "pages": all ? 1 : Math.ceil( visRecords / len ),
7521 "end": settings.fnDisplayEnd(),
7523 "recordsTotal": settings.fnRecordsTotal(),
7524 "recordsDisplay": visRecords,
7525 "serverSide": _fnDataSource( settings ) === 'ssp'
7531 * Get the current page length.
7533 * @return {integer} Current page length. Note `-1` indicates that all records
7536 * Set the current page length.
7538 * @param {integer} Page length to set. Use `-1` to show all records.
7539 * @returns {DataTables.Api} this
7541 _api_register( 'page.len()', function ( len ) {
7542 // Note that we can't call this function 'length()' because `length`
7543 // is a Javascript property of functions which defines how many arguments
7544 // the function expects.
7545 if ( len === undefined ) {
7546 return this.context.length !== 0 ?
7547 this.context[0]._iDisplayLength :
7551 // else, set the page length
7552 return this.iterator( 'table', function ( settings ) {
7553 _fnLengthChange( settings, len );
7559 var __reload = function ( settings, holdPosition, callback ) {
7560 // Use the draw event to trigger a callback
7562 var api = new _Api( settings );
7564 api.one( 'draw', function () {
7565 callback( api.ajax.json() );
7569 if ( _fnDataSource( settings ) == 'ssp' ) {
7570 _fnReDraw( settings, holdPosition );
7573 _fnProcessingDisplay( settings, true );
7575 // Cancel an existing request
7576 var xhr = settings.jqXHR;
7577 if ( xhr && xhr.readyState !== 4 ) {
7582 _fnBuildAjax( settings, [], function( json ) {
7583 _fnClearTable( settings );
7585 var data = _fnAjaxDataSrc( settings, json );
7586 for ( var i=0, ien=data.length ; i<ien ; i++ ) {
7587 _fnAddData( settings, data[i] );
7590 _fnReDraw( settings, holdPosition );
7591 _fnProcessingDisplay( settings, false );
7598 * Get the JSON response from the last Ajax request that DataTables made to the
7599 * server. Note that this returns the JSON from the first table in the current
7602 * @return {object} JSON received from the server.
7604 _api_register( 'ajax.json()', function () {
7605 var ctx = this.context;
7607 if ( ctx.length > 0 ) {
7611 // else return undefined;
7616 * Get the data submitted in the last Ajax request
7618 _api_register( 'ajax.params()', function () {
7619 var ctx = this.context;
7621 if ( ctx.length > 0 ) {
7622 return ctx[0].oAjaxData;
7625 // else return undefined;
7630 * Reload tables from the Ajax data source. Note that this function will
7631 * automatically re-draw the table when the remote data has been loaded.
7633 * @param {boolean} [reset=true] Reset (default) or hold the current paging
7634 * position. A full re-sort and re-filter is performed when this method is
7635 * called, which is why the pagination reset is the default action.
7636 * @returns {DataTables.Api} this
7638 _api_register( 'ajax.reload()', function ( callback, resetPaging ) {
7639 return this.iterator( 'table', function (settings) {
7640 __reload( settings, resetPaging===false, callback );
7646 * Get the current Ajax URL. Note that this returns the URL from the first
7647 * table in the current context.
7649 * @return {string} Current Ajax source URL
7651 * Set the Ajax URL. Note that this will set the URL for all tables in the
7654 * @param {string} url URL to set.
7655 * @returns {DataTables.Api} this
7657 _api_register( 'ajax.url()', function ( url ) {
7658 var ctx = this.context;
7660 if ( url === undefined ) {
7662 if ( ctx.length === 0 ) {
7668 $.isPlainObject( ctx.ajax ) ?
7675 return this.iterator( 'table', function ( settings ) {
7676 if ( $.isPlainObject( settings.ajax ) ) {
7677 settings.ajax.url = url;
7680 settings.ajax = url;
7682 // No need to consider sAjaxSource here since DataTables gives priority
7683 // to `ajax` over `sAjaxSource`. So setting `ajax` here, renders any
7684 // value of `sAjaxSource` redundant.
7690 * Load data from the newly set Ajax URL. Note that this method is only
7691 * available when `ajax.url()` is used to set a URL. Additionally, this method
7692 * has the same effect as calling `ajax.reload()` but is provided for
7693 * convenience when setting a new URL. Like `ajax.reload()` it will
7694 * automatically redraw the table once the remote data has been loaded.
7696 * @returns {DataTables.Api} this
7698 _api_register( 'ajax.url().load()', function ( callback, resetPaging ) {
7699 // Same as a reload, but makes sense to present it for easy access after a
7701 return this.iterator( 'table', function ( ctx ) {
7702 __reload( ctx, resetPaging===false, callback );
7709 var _selector_run = function ( type, selector, selectFn, settings, opts )
7714 selectorType = typeof selector;
7716 // Can't just check for isArray here, as an API or jQuery instance might be
7717 // given with their array like look
7718 if ( ! selector || selectorType === 'string' || selectorType === 'function' || selector.length === undefined ) {
7719 selector = [ selector ];
7722 for ( i=0, ien=selector.length ; i<ien ; i++ ) {
7723 // Only split on simple strings - complex expressions will be jQuery selectors
7724 a = selector[i] && selector[i].split && ! selector[i].match(/[\[\(:]/) ?
7725 selector[i].split(',') :
7728 for ( j=0, jen=a.length ; j<jen ; j++ ) {
7729 res = selectFn( typeof a[j] === 'string' ? $.trim(a[j]) : a[j] );
7731 if ( res && res.length ) {
7732 out = out.concat( res );
7737 // selector extensions
7738 var ext = _ext.selector[ type ];
7740 for ( i=0, ien=ext.length ; i<ien ; i++ ) {
7741 out = ext[i]( settings, opts, out );
7745 return _unique( out );
7749 var _selector_opts = function ( opts )
7755 // Backwards compatibility for 1.9- which used the terminology filter rather
7757 if ( opts.filter && opts.search === undefined ) {
7758 opts.search = opts.filter;
7769 var _selector_first = function ( inst )
7771 // Reduce the API instance to the first item found
7772 for ( var i=0, ien=inst.length ; i<ien ; i++ ) {
7773 if ( inst[i].length > 0 ) {
7774 // Assign the first element to the first item in the instance
7775 // and truncate the instance and context
7779 inst.context = [ inst.context[i] ];
7785 // Not found - return an empty instance
7791 var _selector_row_indexes = function ( settings, opts )
7795 displayFiltered = settings.aiDisplay,
7796 displayMaster = settings.aiDisplayMaster;
7799 search = opts.search, // none, applied, removed
7800 order = opts.order, // applied, current, index (original - compatibility with 1.9)
7801 page = opts.page; // all, current
7803 if ( _fnDataSource( settings ) == 'ssp' ) {
7804 // In server-side processing mode, most options are irrelevant since
7805 // rows not shown don't exist and the index order is the applied order
7806 // Removed is a special case - for consistency just return an empty
7808 return search === 'removed' ?
7810 _range( 0, displayMaster.length );
7812 else if ( page == 'current' ) {
7813 // Current page implies that order=current and fitler=applied, since it is
7814 // fairly senseless otherwise, regardless of what order and search actually
7816 for ( i=settings._iDisplayStart, ien=settings.fnDisplayEnd() ; i<ien ; i++ ) {
7817 a.push( displayFiltered[i] );
7820 else if ( order == 'current' || order == 'applied' ) {
7821 a = search == 'none' ?
7822 displayMaster.slice() : // no search
7823 search == 'applied' ?
7824 displayFiltered.slice() : // applied search
7825 $.map( displayMaster, function (el, i) { // removed search
7826 return $.inArray( el, displayFiltered ) === -1 ? el : null;
7829 else if ( order == 'index' || order == 'original' ) {
7830 for ( i=0, ien=settings.aoData.length ; i<ien ; i++ ) {
7831 if ( search == 'none' ) {
7834 else { // applied | removed
7835 tmp = $.inArray( i, displayFiltered );
7837 if ((tmp === -1 && search == 'removed') ||
7838 (tmp >= 0 && search == 'applied') )
7850 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
7853 * {} - no selector - use all available rows
7854 * {integer} - row aoData index
7856 * {string} - jQuery selector to apply to the TR elements
7857 * {array} - jQuery array of nodes, or simply an array of TR nodes
7862 var __row_selector = function ( settings, selector, opts )
7865 var run = function ( sel ) {
7866 var selInt = _intVal( sel );
7869 // Short cut - selector is a number and no options provided (default is
7870 // all records, so no need to check if the index is in there, since it
7871 // must be - dev error if the index doesn't exist).
7872 if ( selInt !== null && ! opts ) {
7877 rows = _selector_row_indexes( settings, opts );
7880 if ( selInt !== null && $.inArray( selInt, rows ) !== -1 ) {
7881 // Selector - integer
7884 else if ( sel === null || sel === undefined || sel === '' ) {
7889 // Selector - function
7890 if ( typeof sel === 'function' ) {
7891 return $.map( rows, function (idx) {
7892 var row = settings.aoData[ idx ];
7893 return sel( idx, row._aData, row.nTr ) ? idx : null;
7897 // Get nodes in the order from the `rows` array with null values removed
7898 var nodes = _removeEmpty(
7899 _pluck_order( settings.aoData, rows, 'nTr' )
7903 if ( sel.nodeName ) {
7904 if ( sel._DT_RowIndex !== undefined ) {
7905 return [ sel._DT_RowIndex ]; // Property added by DT for fast lookup
7907 else if ( sel._DT_CellIndex ) {
7908 return [ sel._DT_CellIndex.row ];
7911 var host = $(sel).closest('*[data-dt-row]');
7912 return host.length ?
7913 [ host.data('dt-row') ] :
7918 // ID selector. Want to always be able to select rows by id, regardless
7919 // of if the tr element has been created or not, so can't rely upon
7920 // jQuery here - hence a custom implementation. This does not match
7921 // Sizzle's fast selector or HTML4 - in HTML5 the ID can be anything,
7922 // but to select it using a CSS selector engine (like Sizzle or
7923 // querySelect) it would need to need to be escaped for some characters.
7924 // DataTables simplifies this for row selectors since you can select
7925 // only a row. A # indicates an id any anything that follows is the id -
7927 if ( typeof sel === 'string' && sel.charAt(0) === '#' ) {
7928 // get row index from id
7929 var rowObj = settings.aIds[ sel.replace( /^#/, '' ) ];
7930 if ( rowObj !== undefined ) {
7931 return [ rowObj.idx ];
7934 // need to fall through to jQuery in case there is DOM id that
7938 // Selector - jQuery selector string, array of nodes or jQuery object/
7939 // As jQuery's .filter() allows jQuery objects to be passed in filter,
7940 // it also allows arrays, so this will cope with all three options
7944 return this._DT_RowIndex;
7949 return _selector_run( 'row', selector, run, settings, opts );
7953 _api_register( 'rows()', function ( selector, opts ) {
7954 // argument shifting
7955 if ( selector === undefined ) {
7958 else if ( $.isPlainObject( selector ) ) {
7963 opts = _selector_opts( opts );
7965 var inst = this.iterator( 'table', function ( settings ) {
7966 return __row_selector( settings, selector, opts );
7969 // Want argument shifting here and in __row_selector?
7970 inst.selector.rows = selector;
7971 inst.selector.opts = opts;
7976 _api_register( 'rows().nodes()', function () {
7977 return this.iterator( 'row', function ( settings, row ) {
7978 return settings.aoData[ row ].nTr || undefined;
7982 _api_register( 'rows().data()', function () {
7983 return this.iterator( true, 'rows', function ( settings, rows ) {
7984 return _pluck_order( settings.aoData, rows, '_aData' );
7988 _api_registerPlural( 'rows().cache()', 'row().cache()', function ( type ) {
7989 return this.iterator( 'row', function ( settings, row ) {
7990 var r = settings.aoData[ row ];
7991 return type === 'search' ? r._aFilterData : r._aSortData;
7995 _api_registerPlural( 'rows().invalidate()', 'row().invalidate()', function ( src ) {
7996 return this.iterator( 'row', function ( settings, row ) {
7997 _fnInvalidate( settings, row, src );
8001 _api_registerPlural( 'rows().indexes()', 'row().index()', function () {
8002 return this.iterator( 'row', function ( settings, row ) {
8007 _api_registerPlural( 'rows().ids()', 'row().id()', function ( hash ) {
8009 var context = this.context;
8011 // `iterator` will drop undefined values, but in this case we want them
8012 for ( var i=0, ien=context.length ; i<ien ; i++ ) {
8013 for ( var j=0, jen=this[i].length ; j<jen ; j++ ) {
8014 var id = context[i].rowIdFn( context[i].aoData[ this[i][j] ]._aData );
8015 a.push( (hash === true ? '#' : '' )+ id );
8019 return new _Api( context, a );
8022 _api_registerPlural( 'rows().remove()', 'row().remove()', function () {
8025 this.iterator( 'row', function ( settings, row, thatIdx ) {
8026 var data = settings.aoData;
8027 var rowData = data[ row ];
8029 var loopRow, loopCells;
8031 data.splice( row, 1 );
8033 // Update the cached indexes
8034 for ( i=0, ien=data.length ; i<ien ; i++ ) {
8036 loopCells = loopRow.anCells;
8039 if ( loopRow.nTr !== null ) {
8040 loopRow.nTr._DT_RowIndex = i;
8044 if ( loopCells !== null ) {
8045 for ( j=0, jen=loopCells.length ; j<jen ; j++ ) {
8046 loopCells[j]._DT_CellIndex.row = i;
8051 // Delete from the display arrays
8052 _fnDeleteIndex( settings.aiDisplayMaster, row );
8053 _fnDeleteIndex( settings.aiDisplay, row );
8054 _fnDeleteIndex( that[ thatIdx ], row, false ); // maintain local indexes
8056 // Check for an 'overflow' they case for displaying the table
8057 _fnLengthOverflow( settings );
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 ];
8066 this.iterator( 'table', function ( settings ) {
8067 for ( var i=0, ien=settings.aoData.length ; i<ien ; i++ ) {
8068 settings.aoData[i].idx = i;
8076 _api_register( 'rows.add()', function ( rows ) {
8077 var newRows = this.iterator( 'table', function ( settings ) {
8081 for ( i=0, ien=rows.length ; i<ien ; i++ ) {
8084 if ( row.nodeName && row.nodeName.toUpperCase() === 'TR' ) {
8085 out.push( _fnAddTr( settings, row )[0] );
8088 out.push( _fnAddData( settings, row ) );
8095 // Return an Api.rows() extended instance, so rows().nodes() etc can be used
8096 var modRows = this.rows( -1 );
8098 $.merge( modRows, newRows );
8110 _api_register( 'row()', function ( selector, opts ) {
8111 return _selector_first( this.rows( selector, opts ) );
8115 _api_register( 'row().data()', function ( data ) {
8116 var ctx = this.context;
8118 if ( data === undefined ) {
8120 return ctx.length && this.length ?
8121 ctx[0].aoData[ this[0] ]._aData :
8126 ctx[0].aoData[ this[0] ]._aData = data;
8128 // Automatically invalidate
8129 _fnInvalidate( ctx[0], this[0], 'data' );
8135 _api_register( 'row().node()', function () {
8136 var ctx = this.context;
8138 return ctx.length && this.length ?
8139 ctx[0].aoData[ this[0] ].nTr || null :
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 ) {
8151 var rows = this.iterator( 'table', function ( settings ) {
8152 if ( row.nodeName && row.nodeName.toUpperCase() === 'TR' ) {
8153 return _fnAddTr( settings, row )[0];
8155 return _fnAddData( settings, row );
8158 // Return an Api.rows() extended instance, with the newly added row selected
8159 return this.row( rows[0] );
8164 var __details_add = function ( ctx, row, data, klass )
8166 // Convert to array of TR elements
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++ ) {
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' ) {
8183 // Otherwise create a row with a wrapper
8184 var created = $('<tr><td/></tr>').addClass( k );
8188 [0].colSpan = _fnVisbleColumns( ctx );
8190 rows.push( created[0] );
8194 addRow( data, klass );
8196 if ( row._details ) {
8197 row._details.detach();
8200 row._details = $(rows);
8202 // If the children were already shown, that state should be retained
8203 if ( row._detailsShow ) {
8204 row._details.insertAfter( row.nTr );
8209 var __details_remove = function ( api, idx )
8211 var ctx = api.context;
8214 var row = ctx[0].aoData[ idx !== undefined ? idx : api[0] ];
8216 if ( row && row._details ) {
8217 row._details.remove();
8219 row._detailsShow = undefined;
8220 row._details = undefined;
8226 var __details_display = function ( api, show ) {
8227 var ctx = api.context;
8229 if ( ctx.length && api.length ) {
8230 var row = ctx[0].aoData[ api[0] ];
8232 if ( row._details ) {
8233 row._detailsShow = show;
8236 row._details.insertAfter( row.nTr );
8239 row._details.detach();
8242 __details_events( ctx[0] );
8248 var __details_events = function ( settings )
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;
8257 api.off( drawEvent +' '+ colvisEvent +' '+ destroyEvent );
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 ) {
8266 api.rows( {page:'current'} ).eq(0).each( function (idx) {
8267 // Internal data grab
8268 var row = data[ idx ];
8270 if ( row._detailsShow ) {
8271 row._details.insertAfter( row.nTr );
8276 // Column visibility change - update the colspan
8277 api.on( colvisEvent, function ( e, ctx, idx, vis ) {
8278 if ( settings !== ctx ) {
8282 // Update the colspan for the details rows (note, only if it already has
8284 var row, visible = _fnVisbleColumns( ctx );
8286 for ( var i=0, ien=data.length ; i<ien ; i++ ) {
8289 if ( row._details ) {
8290 row._details.children('td[colspan]').attr('colspan', visible );
8295 // Table destroyed - nuke any child rows
8296 api.on( destroyEvent, function ( e, ctx ) {
8297 if ( settings !== ctx ) {
8301 for ( var i=0, ien=data.length ; i<ien ; i++ ) {
8302 if ( data[i]._details ) {
8303 __details_remove( api, i );
8310 // Strings for the method names to help minification
8312 var _child_obj = _emp+'row().child';
8313 var _child_mth = _child_obj+'()';
8318 // jQuery or array of any of the above
8319 _api_register( _child_mth, function ( data, klass ) {
8320 var ctx = this.context;
8322 if ( data === undefined ) {
8324 return ctx.length && this.length ?
8325 ctx[0].aoData[ this[0] ]._details :
8328 else if ( data === true ) {
8332 else if ( data === false ) {
8334 __details_remove( this );
8336 else if ( ctx.length && this.length ) {
8338 __details_add( ctx[0], ctx[0].aoData[ this[0] ], data, klass );
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 );
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 );
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 );
8372 _api_register( _child_obj+'.isShown()', function () {
8373 var ctx = this.context;
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;
8384 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
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
8395 // can be an array of these items, comma separated list, or an array of comma
8398 var __re_column_selector = /^([^:]+):(name|visIdx|visible)$/;
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 ) {
8405 for ( var row=0, ien=rows.length ; row<ien ; row++ ) {
8406 a.push( _fnGetCellData( settings, rows[row], column ) );
8412 var __column_selector = function ( settings, selector, opts )
8415 columns = settings.aoColumns,
8416 names = _pluck( columns, 'sName' ),
8417 nodes = _pluck( columns, 'nTh' );
8419 var run = function ( s ) {
8420 var selInt = _intVal( s );
8424 return _range( columns.length );
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)
8435 // Selector = function
8436 if ( typeof s === 'function' ) {
8437 var rows = _selector_row_indexes( settings, opts );
8439 return $.map( columns, function (col, idx) {
8442 __columnData( settings, idx, 0, 0, rows ),
8448 // jQuery or string selector
8449 var match = typeof s === 'string' ?
8450 s.match( __re_column_selector ) :
8454 switch( match[2] ) {
8457 var idx = parseInt( match[1], 10 );
8458 // Visible index given, convert to column index
8460 // Counting from the right
8461 var visColumns = $.map( columns, function (col,i) {
8462 return col.bVisible ? i : null;
8464 return [ visColumns[ visColumns.length + idx ] ];
8466 // Counting from the left
8467 return [ _fnVisibleToColumnIndex( settings, idx ) ];
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;
8480 // Cell in the table body
8481 if ( s.nodeName && s._DT_CellIndex ) {
8482 return [ s._DT_CellIndex.column ];
8485 // jQuery selector on the TH elements for the columns
8486 var jqResult = $( nodes )
8489 return $.inArray( this, nodes ); // `nodes` is column index complete and in order
8493 if ( jqResult.length || ! s.nodeName ) {
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') ] :
8505 return _selector_run( 'column', selector, run, settings, opts );
8509 var __setColumnVis = function ( settings, column, vis ) {
8511 cols = settings.aoColumns,
8512 col = cols[ column ],
8513 data = settings.aoData,
8514 row, cells, i, ien, tr;
8517 if ( vis === undefined ) {
8518 return col.bVisible;
8523 if ( col.bVisible === vis ) {
8529 // Need to decide if we should use appendChild or insertBefore
8530 var insertBefore = $.inArray( true, _pluck(cols, 'bVisible'), column+1 );
8532 for ( i=0, ien=data.length ; i<ien ; i++ ) {
8534 cells = data[i].anCells;
8537 // insertBefore can act like appendChild if 2nd arg is null
8538 tr.insertBefore( cells[ column ], cells[ insertBefore ] || null );
8544 $( _pluck( settings.aoData, 'anCells', column ) ).detach();
8549 _fnDrawHead( settings, settings.aoHeader );
8550 _fnDrawHead( settings, settings.aoFooter );
8552 _fnSaveState( settings );
8556 _api_register( 'columns()', function ( selector, opts ) {
8557 // argument shifting
8558 if ( selector === undefined ) {
8561 else if ( $.isPlainObject( selector ) ) {
8566 opts = _selector_opts( opts );
8568 var inst = this.iterator( 'table', function ( settings ) {
8569 return __column_selector( settings, selector, opts );
8572 // Want argument shifting here and in _row_selector?
8573 inst.selector.cols = selector;
8574 inst.selector.opts = opts;
8579 _api_registerPlural( 'columns().header()', 'column().header()', function ( selector, opts ) {
8580 return this.iterator( 'column', function ( settings, column ) {
8581 return settings.aoColumns[column].nTh;
8585 _api_registerPlural( 'columns().footer()', 'column().footer()', function ( selector, opts ) {
8586 return this.iterator( 'column', function ( settings, column ) {
8587 return settings.aoColumns[column].nTf;
8591 _api_registerPlural( 'columns().data()', 'column().data()', function () {
8592 return this.iterator( 'column-rows', __columnData, 1 );
8595 _api_registerPlural( 'columns().dataSrc()', 'column().dataSrc()', function () {
8596 return this.iterator( 'column', function ( settings, column ) {
8597 return settings.aoColumns[column].mData;
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
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 ) ;
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;
8620 __setColumnVis( settings, column, vis );
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] );
8630 if ( calc === undefined || calc ) {
8631 this.columns.adjust();
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 ) :
8646 _api_register( 'columns.adjust()', function () {
8647 return this.iterator( 'table', function ( settings ) {
8648 _fnAdjustColumnSizing( settings );
8652 _api_register( 'column.index()', function ( type, idx ) {
8653 if ( this.context.length !== 0 ) {
8654 var ctx = this.context[0];
8656 if ( type === 'fromVisible' || type === 'toData' ) {
8657 return _fnVisibleToColumnIndex( ctx, idx );
8659 else if ( type === 'fromData' || type === 'toVisible' ) {
8660 return _fnColumnIndexToVisible( ctx, idx );
8665 _api_register( 'column()', function ( selector, opts ) {
8666 return _selector_first( this.columns( selector, opts ) );
8671 var __cell_selector = function ( settings, selector, opts )
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) );
8678 var columns = settings.aoColumns.length;
8679 var a, i, ien, j, o, host;
8681 var run = function ( s ) {
8682 var fnSelector = typeof s === 'function';
8684 if ( s === null || s === undefined || fnSelector ) {
8685 // All cells and function selectors
8688 for ( i=0, ien=rows.length ; i<ien ; i++ ) {
8691 for ( j=0 ; j<columns ; j++ ) {
8698 // Selector - function
8701 if ( s( o, _fnGetCellData(settings, row, j), host.anCells ? host.anCells[j] : null ) ) {
8716 if ( $.isPlainObject( s ) ) {
8720 // Selector - jQuery filtered cells
8721 var jqResult = allCells
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
8731 if ( jqResult.length || ! s.nodeName ) {
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
8738 host = $(s).closest('*[data-dt-row]');
8739 return host.length ?
8741 row: host.data('dt-row'),
8742 column: host.data('dt-column')
8747 return _selector_run( 'cell', selector, run, settings, opts );
8753 _api_register( 'cells()', function ( rowSelector, columnSelector, opts ) {
8754 // Argument shifting
8755 if ( $.isPlainObject( rowSelector ) ) {
8757 if ( rowSelector.row === undefined ) {
8758 // Selector options in first parameter
8763 // Cell index objects in first parameter
8764 opts = columnSelector;
8765 columnSelector = null;
8768 if ( $.isPlainObject( columnSelector ) ) {
8769 opts = columnSelector;
8770 columnSelector = null;
8774 if ( columnSelector === null || columnSelector === undefined ) {
8775 return this.iterator( 'table', function ( settings ) {
8776 return __cell_selector( settings, rowSelector, _selector_opts( opts ) );
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;
8785 var cells = this.iterator( 'table', function ( settings, idx ) {
8788 for ( i=0, ien=rows[idx].length ; i<ien ; i++ ) {
8789 for ( j=0, jen=columns[idx].length ; j<jen ; j++ ) {
8792 column: columns[idx][j]
8800 $.extend( cells.selector, {
8801 cols: columnSelector,
8810 _api_registerPlural( 'cells().nodes()', 'cell().node()', function () {
8811 return this.iterator( 'cell', function ( settings, row, column ) {
8812 var data = settings.aoData[ row ];
8814 return data && data.anCells ?
8815 data.anCells[ column ] :
8821 _api_register( 'cells().data()', function () {
8822 return this.iterator( 'cell', function ( settings, row, column ) {
8823 return _fnGetCellData( settings, row, column );
8828 _api_registerPlural( 'cells().cache()', 'cell().cache()', function ( type ) {
8829 type = type === 'search' ? '_aFilterData' : '_aSortData';
8831 return this.iterator( 'cell', function ( settings, row, column ) {
8832 return settings.aoData[ row ][ type ][ column ];
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 );
8844 _api_registerPlural( 'cells().indexes()', 'cell().index()', function () {
8845 return this.iterator( 'cell', function ( settings, row, column ) {
8849 columnVisible: _fnColumnIndexToVisible( settings, column )
8855 _api_registerPlural( 'cells().invalidate()', 'cell().invalidate()', function ( src ) {
8856 return this.iterator( 'cell', function ( settings, row, column ) {
8857 _fnInvalidate( settings, row, src, column );
8863 _api_register( 'cell()', function ( rowSelector, columnSelector, opts ) {
8864 return _selector_first( this.cells( rowSelector, columnSelector, opts ) );
8868 _api_register( 'cell().data()', function ( data ) {
8869 var ctx = this.context;
8872 if ( data === undefined ) {
8874 return ctx.length && cell.length ?
8875 _fnGetCellData( ctx[0], cell[0].row, cell[0].column ) :
8880 _fnSetCellData( ctx[0], cell[0].row, cell[0].column, data );
8881 _fnInvalidate( ctx[0], cell[0].row, 'data', cell[0].column );
8889 * Get current ordering (sorting) that has been applied to the table.
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.
8899 * Set the ordering for the table.
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
8905 * Set the ordering for the table.
8907 * @param {array} order 1D array of sorting information to be applied.
8908 * @param {array} [...] Optional additional sorting conditions
8909 * @returns {DataTables.Api} this
8911 * Set the ordering for the table.
8913 * @param {array} order 2D array of sorting information to be applied.
8914 * @returns {DataTables.Api} this
8916 _api_register( 'order()', function ( order, dir ) {
8917 var ctx = this.context;
8919 if ( order === undefined ) {
8921 return ctx.length !== 0 ?
8927 if ( typeof order === 'number' ) {
8928 // Simple column / direction passed in
8929 order = [ [ order, dir ] ];
8931 else if ( order.length && ! $.isArray( order[0] ) ) {
8932 // Arguments passed in (list of 1D arrays)
8933 order = Array.prototype.slice.call( arguments );
8935 // otherwise a 2D array was passed in
8937 return this.iterator( 'table', function ( settings ) {
8938 settings.aaSorting = order.slice();
8944 * Attach a sort listener to an element for a given column
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
8953 _api_register( 'order.listener()', function ( node, column, callback ) {
8954 return this.iterator( 'table', function ( settings ) {
8955 _fnSortAttachListener( settings, node, column, callback );
8960 _api_register( 'order.fixed()', function ( set ) {
8962 var ctx = this.context;
8963 var fixed = ctx.length ?
8964 ctx[0].aaSortingFixed :
8967 return $.isArray( fixed ) ?
8972 return this.iterator( 'table', function ( settings ) {
8973 settings.aaSortingFixed = $.extend( true, {}, set );
8978 // Order by the selected column(s)
8980 'columns().order()',
8982 ], function ( dir ) {
8985 return this.iterator( 'table', function ( settings, i ) {
8988 $.each( that[i], function (j, col) {
8989 sort.push( [ col, dir ] );
8992 settings.aaSorting = sort;
8998 _api_register( 'search()', function ( input, regex, smart, caseInsen ) {
8999 var ctx = this.context;
9001 if ( input === undefined ) {
9003 return ctx.length !== 0 ?
9004 ctx[0].oPreviousSearch.sSearch :
9009 return this.iterator( 'table', function ( settings ) {
9010 if ( ! settings.oFeatures.bFilter ) {
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
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;
9031 if ( input === undefined ) {
9033 return preSearch[ column ].sSearch;
9037 if ( ! settings.oFeatures.bFilter ) {
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
9048 _fnFilterComplete( settings, settings.oPreviousSearch, 1 );
9057 _api_register( 'state()', function () {
9058 return this.context.length ?
9059 this.context[0].oSavedState :
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, {} );
9072 _api_register( 'state.loaded()', function () {
9073 return this.context.length ?
9074 this.context[0].oLoadedState :
9079 _api_register( 'state.save()', function () {
9080 return this.iterator( 'table', function ( settings ) {
9081 _fnSaveState( settings );
9088 * Provide a common method for plug-ins to check the version of DataTables being
9089 * used, in order to ensure compatibility.
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
9100 * alert( $.fn.dataTable.versionCheck( '1.9.0' ) );
9102 DataTable.versionCheck = DataTable.fnVersionCheck = function( version )
9104 var aThis = DataTable.version.split('.');
9105 var aThat = version.split('.');
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;
9112 // Parts are the same, keep comparing
9113 if (iThis === iThat) {
9117 // Parts are different, return immediately
9118 return iThis > iThat;
9126 * Check if a `<table>` node is a DataTable table already or not.
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
9136 * if ( ! $.fn.DataTable.isDataTable( '#example' ) ) {
9137 * $('#example').dataTable();
9140 DataTable.isDataTable = DataTable.fnIsDataTable = function ( table )
9142 var t = $(table).get(0);
9145 if ( table instanceof DataTable.Api ) {
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;
9153 if ( o.nTable === t || head === t || foot === t ) {
9163 * Get all DataTable tables that have been initialised - optionally you can
9164 * select to get only currently visible tables.
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
9174 * $.each( $.fn.dataTable.tables(true), function () {
9175 * $(table).DataTable().columns.adjust();
9178 DataTable.tables = DataTable.fnTables = function ( visible )
9182 if ( $.isPlainObject( visible ) ) {
9184 visible = visible.visible;
9187 var a = $.map( DataTable.settings, function (o) {
9188 if ( !visible || (visible && $(o.nTable).is(':visible')) ) {
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
9205 * @param {object} src The model object which holds all parameters that can be
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
9212 DataTable.camelToHungarian = _fnCamelToHungarian;
9219 _api_register( '$()', function ( selector, opts ) {
9221 rows = this.rows( opts ).nodes(), // Get all rows
9224 return $( [].concat(
9225 jqRows.filter( selector ).toArray(),
9226 jqRows.find( selector ).toArray()
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);
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/) ?
9243 var inst = $( this.tables().nodes() );
9244 inst[key].apply( inst, args );
9250 _api_register( 'clear()', function () {
9251 return this.iterator( 'table', function ( settings ) {
9252 _fnClearTable( settings );
9257 _api_register( 'settings()', function () {
9258 return new _Api( this.context, this.context );
9262 _api_register( 'init()', function () {
9263 var ctx = this.context;
9264 return ctx.length ? ctx[0].oInit : null;
9268 _api_register( 'data()', function () {
9269 return this.iterator( 'table', function ( settings ) {
9270 return _pluck( settings.aoData, '_aData' );
9275 _api_register( 'destroy()', function ( remove ) {
9276 remove = remove || false;
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; } );
9291 // Flag to note that the table is currently being destroyed - no action
9293 settings.bDestroying = true;
9295 // Fire off the destroy callbacks for plug-ins etc
9296 _fnCallbackFire( settings, "aoDestroyCallback", "destroy", [settings] );
9298 // If not being removed from the document, make all columns visible
9300 new _Api( settings ).columns().visible( true );
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);
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 );
9315 if ( tfoot && table != tfoot.parentNode ) {
9316 jqTable.children('tfoot').detach();
9317 jqTable.append( tfoot );
9320 settings.aaSorting = [];
9321 settings.aaSortingFixed = [];
9322 _fnSortingClasses( settings );
9324 $( rows ).removeClass( settings.asStripeClasses.join(' ') );
9326 $('th, td', thead).removeClass( classes.sSortable+' '+
9327 classes.sSortableAsc+' '+classes.sSortableDesc+' '+classes.sSortableNone
9330 if ( settings.bJUI ) {
9331 $('th span.'+classes.sSortIcon+ ', td span.'+classes.sSortIcon, thead).detach();
9332 $('th, td', thead).each( function () {
9333 var wrapper = $('div.'+classes.sSortJUIWrapper, this);
9334 $(this).append( wrapper.contents() );
9339 // Add the TR elements back into the table in their original order
9340 jqTbody.children().detach();
9341 jqTbody.append( rows );
9343 // Remove the DataTables generated nodes, events and classes
9344 var removedMethod = remove ? 'remove' : 'detach';
9345 jqTable[ removedMethod ]();
9346 jqWrapper[ removedMethod ]();
9348 // If we need to reattach the table to the document
9349 if ( ! remove && orig ) {
9350 // insertBefore acts like appendChild if !arg[1]
9351 orig.insertBefore( table, settings.nTableReinsertBefore );
9353 // Restore the width of the original table - was read from the style property,
9354 // so we can restore directly to that
9356 .css( 'width', settings.sDestroyWidth )
9357 .removeClass( classes.sTable );
9359 // If the were originally stripe classes - then we add them back here.
9360 // Note this is not fool proof (for example if not all rows had stripe
9361 // classes - but it's a good effort without getting carried away
9362 ien = settings.asDestroyStripes.length;
9365 jqTbody.children().each( function (i) {
9366 $(this).addClass( settings.asDestroyStripes[i % ien] );
9371 /* Remove the settings object from the settings array */
9372 var idx = $.inArray( settings, DataTable.settings );
9374 DataTable.settings.splice( idx, 1 );
9380 // Add the `every()` method for rows, columns and cells in a compact form
9381 $.each( [ 'column', 'row', 'cell' ], function ( i, type ) {
9382 _api_register( type+'s().every()', function ( fn ) {
9383 var opts = this.selector.opts;
9386 return this.iterator( type, function ( settings, arg1, arg2, arg3, arg4 ) {
9387 // Rows and columns:
9389 // arg2 - table counter
9390 // arg3 - loop counter
9394 // arg2 - column index
9395 // arg3 - table counter
9396 // arg4 - loop counter
9400 type==='cell' ? arg2 : opts,
9401 type==='cell' ? opts : undefined
9403 arg1, arg2, arg3, arg4
9410 // i18n method for extensions to be able to use the language object from the
9412 _api_register( 'i18n()', function ( token, def, plural ) {
9413 var ctx = this.context[0];
9414 var resolved = _fnGetObjectDataFn( token )( ctx.oLanguage );
9416 if ( resolved === undefined ) {
9420 if ( plural !== undefined && $.isPlainObject( resolved ) ) {
9421 resolved = resolved[ plural ] !== undefined ?
9422 resolved[ plural ] :
9426 return resolved.replace( '%d', plural ); // nb: plural might be undefined,
9430 * Version string for plug-ins to check compatibility. Allowed format is
9431 * `a.b.c-d` where: a:int, b:int, c:int, d:string(dev|beta|alpha). `d` is used
9432 * only for non-release builds. See http://semver.org/ for more information.
9435 * @default Version number
9437 DataTable.version = "1.10.15";
9440 * Private data store, containing all of the settings objects that are
9441 * created for the tables on a given page.
9443 * Note that the `DataTable.settings` object is aliased to
9444 * `jQuery.fn.dataTableExt` through which it may be accessed and
9445 * manipulated, or `jQuery.fn.dataTable.settings`.
9451 DataTable.settings = [];
9454 * Object models container, for the various models that DataTables has
9455 * available to it. These models define the objects that are used to hold
9456 * the active state and configuration of the table.
9459 DataTable.models = {};
9464 * Template object for the way in which DataTables holds information about
9465 * search information for the global filter and individual column filters.
9468 DataTable.models.oSearch = {
9470 * Flag to indicate if the filtering should be case insensitive or not
9474 "bCaseInsensitive": true,
9477 * Applied search term
9479 * @default <i>Empty string</i>
9484 * Flag to indicate if the search term should be interpreted as a
9485 * regular expression (true) or not (false) and therefore and special
9486 * regex characters escaped.
9493 * Flag to indicate if DataTables is to use its smart filtering or not.
9504 * Template object for the way in which DataTables holds information about
9505 * each individual row. This is the object format used for the settings
9509 DataTable.models.oRow = {
9511 * TR element for the row
9518 * Array of TD elements for each row. This is null until the row has been
9526 * Data object from the original data source for the row. This is either
9527 * an array if using the traditional form of DataTables, or an object if
9528 * using mData options. The exact type will depend on the passed in
9529 * data from the data source, or will be an array if using DOM a data
9531 * @type array|object
9537 * Sorting data cache - this array is ostensibly the same length as the
9538 * number of columns (although each index is generated only as it is
9539 * needed), and holds the data that is used for sorting each column in the
9540 * row. We do this cache generation at the start of the sort in order that
9541 * the formatting of the sort data need be done only once for each cell
9542 * per sort. This array should not be read from or written to by anything
9543 * other than the master sorting methods.
9551 * Per cell filtering data cache. As per the sort data cache, used to
9552 * increase the performance of the filtering in DataTables
9557 "_aFilterData": null,
9560 * Filtering data cache. This is the same as the cell filtering cache, but
9561 * in this case a string rather than an array. This is easily computed with
9562 * a join on `_aFilterData`, but is provided as a cache so the join isn't
9563 * needed on every search (memory traded for performance)
9568 "_sFilterRow": null,
9571 * Cache of the class name that DataTables has applied to the row, so we
9572 * can quickly look at this variable rather than needing to do a DOM check
9573 * on className for the nTr property.
9575 * @default <i>Empty string</i>
9581 * Denote if the original data source was from the DOM, or the data source
9582 * object. This is used for invalidating data, so DataTables can
9583 * automatically read data from the original source, unless uninstructed
9592 * Index in the aoData array. This saves an indexOf lookup when we have the
9593 * object, but want to know the index
9603 * Template object for the column information object in DataTables. This object
9604 * is held in the settings aoColumns array and contains all the information that
9605 * DataTables needs about each individual column.
9607 * Note that this object is related to {@link DataTable.defaults.column}
9608 * but this one is the internal data store for DataTables's cache of columns.
9609 * It should NOT be manipulated outside of DataTables. Any configuration should
9610 * be done through the initialisation options.
9613 DataTable.models.oColumn = {
9615 * Column index. This could be worked out on-the-fly with $.inArray, but it
9616 * is faster to just hold it as a variable
9623 * A list of the columns that sorting should occur on when this column
9624 * is sorted. That this property is an array allows multi-column sorting
9625 * to be defined for a column (for example first name / last name columns
9626 * would benefit from this). The values are integers pointing to the
9627 * columns to be sorted on (typically it will be a single integer pointing
9628 * at itself, but that doesn't need to be the case).
9634 * Define the sorting directions that are applied to the column, in sequence
9635 * as the column is repeatedly sorted upon - i.e. the first value is used
9636 * as the sorting direction when the column if first sorted (clicked on).
9637 * Sort it again (click again) and it will move on to the next index.
9638 * Repeat until loop.
9644 * Flag to indicate if the column is searchable, and thus should be included
9645 * in the filtering or not.
9648 "bSearchable": null,
9651 * Flag to indicate if the column is sortable or not.
9657 * Flag to indicate if the column is currently visible in the table or not
9663 * Store for manual type assignment using the `column.type` option. This
9664 * is held in store so we can manipulate the column's `sType` property.
9669 "_sManualType": null,
9672 * Flag to indicate if HTML5 data attributes should be used as the data
9673 * source for filtering or sorting. True is either are.
9681 * Developer definable function that is called whenever a cell is created (Ajax source,
9682 * etc) or processed for input (DOM source). This can be used as a compliment to mRender
9683 * allowing you to modify the DOM element (add background colour for example) when the
9684 * element is available.
9686 * @param {element} nTd The TD node that has been created
9687 * @param {*} sData The Data for the cell
9688 * @param {array|object} oData The data for the whole row
9689 * @param {int} iRow The row index for the aoData data store
9692 "fnCreatedCell": null,
9695 * Function to get data from a cell in a column. You should <b>never</b>
9696 * access data directly through _aData internally in DataTables - always use
9697 * the method attached to this property. It allows mData to function as
9698 * required. This function is automatically assigned by the column
9699 * initialisation method
9701 * @param {array|object} oData The data array/object for the array
9702 * (i.e. aoData[]._aData)
9703 * @param {string} sSpecific The specific data type you want to get -
9704 * 'display', 'type' 'filter' 'sort'
9705 * @returns {*} The data for the cell from the given row's data
9711 * Function to set data for a cell in the column. You should <b>never</b>
9712 * set the data directly to _aData internally in DataTables - always use
9713 * this method. It allows mData to function as required. This function
9714 * is automatically assigned by the column initialisation method
9716 * @param {array|object} oData The data array/object for the array
9717 * (i.e. aoData[]._aData)
9718 * @param {*} sValue Value to set
9724 * Property to read the value for the cells in the column from the data
9725 * source array / object. If null, then the default content is used, if a
9726 * function is given then the return from the function is used.
9727 * @type function|int|string|null
9733 * Partner property to mData which is used (only when defined) to get
9734 * the data - i.e. it is basically the same as mData, but without the
9735 * 'set' option, and also the data fed to it is the result from mData.
9736 * This is the rendering method to match the data method of mData.
9737 * @type function|int|string|null
9743 * Unique header TH/TD element for this column - this is what the sorting
9744 * listener is attached to (if sorting is enabled.)
9751 * Unique footer TH/TD element for this column (if there is one). Not used
9752 * in DataTables as such, but can be used for plug-ins to reference the
9753 * footer for each column.
9760 * The class to apply to all TD elements in the table's TBODY for the column
9767 * When DataTables calculates the column widths to assign to each column,
9768 * it finds the longest string in each column and then constructs a
9769 * temporary table and reads the widths from that. The problem with this
9770 * is that "mmm" is much wider then "iiii", but the latter is a longer
9771 * string - thus the calculation can go wrong (doing it properly and putting
9772 * it into an DOM object and measuring that is horribly(!) slow). Thus as
9773 * a "work around" we provide this option. It will append its value to the
9774 * text that is found to be the longest string for the column - i.e. padding.
9777 "sContentPadding": null,
9780 * Allows a default value to be given for a column's data, and will be used
9781 * whenever a null data source is encountered (this can be because mData
9782 * is set to null, or because the data source itself is null).
9786 "sDefaultContent": null,
9789 * Name for the column, allowing reference to the column by name as well as
9790 * by index (needs a lookup to work by name).
9796 * Custom sorting data type - defines which of the available plug-ins in
9797 * afnSortData the custom sorting will use - if any is defined.
9801 "sSortDataType": 'std',
9804 * Class to be applied to the header element when sorting on this column
9808 "sSortingClass": null,
9811 * Class to be applied to the header element when sorting on this column -
9812 * when jQuery UI theming is used.
9816 "sSortingClassJUI": null,
9819 * Title of the column - what is seen in the TH element (nTh).
9825 * Column sorting and filtering type
9832 * Width of the column
9839 * Width of the column when it was first "encountered"
9848 * Developer note: The properties of the object below are given in Hungarian
9849 * notation, that was used as the interface for DataTables prior to v1.10, however
9850 * from v1.10 onwards the primary interface is camel case. In order to avoid
9851 * breaking backwards compatibility utterly with this change, the Hungarian
9852 * version is still, internally the primary interface, but is is not documented
9853 * - hence the @name tags in each doc comment. This allows a Javascript function
9854 * to create a map from Hungarian notation to camel case (going the other direction
9855 * would require each property to be listed, which would at around 3K to the size
9856 * of DataTables, while this method is about a 0.5K hit.
9858 * Ultimately this does pave the way for Hungarian notation to be dropped
9859 * completely, but that is a massive amount of work and will break current
9860 * installs (therefore is on-hold until v2).
9864 * Initialisation options that can be given to DataTables at initialisation
9868 DataTable.defaults = {
9870 * An array of data to use for the table, passed in at initialisation which
9871 * will be used in preference to any data which is already in the DOM. This is
9872 * particularly useful for constructing tables purely in Javascript, for
9873 * example with a custom Ajax call.
9878 * @name DataTable.defaults.data
9881 * // Using a 2D array data source
9882 * $(document).ready( function () {
9883 * $('#example').dataTable( {
9885 * ['Trident', 'Internet Explorer 4.0', 'Win 95+', 4, 'X'],
9886 * ['Trident', 'Internet Explorer 5.0', 'Win 95+', 5, 'C'],
9889 * { "title": "Engine" },
9890 * { "title": "Browser" },
9891 * { "title": "Platform" },
9892 * { "title": "Version" },
9893 * { "title": "Grade" }
9899 * // Using an array of objects as a data source (`data`)
9900 * $(document).ready( function () {
9901 * $('#example').dataTable( {
9904 * "engine": "Trident",
9905 * "browser": "Internet Explorer 4.0",
9906 * "platform": "Win 95+",
9911 * "engine": "Trident",
9912 * "browser": "Internet Explorer 5.0",
9913 * "platform": "Win 95+",
9919 * { "title": "Engine", "data": "engine" },
9920 * { "title": "Browser", "data": "browser" },
9921 * { "title": "Platform", "data": "platform" },
9922 * { "title": "Version", "data": "version" },
9923 * { "title": "Grade", "data": "grade" }
9932 * If ordering is enabled, then DataTables will perform a first pass sort on
9933 * initialisation. You can define which column(s) the sort is performed
9934 * upon, and the sorting direction, with this variable. The `sorting` array
9935 * should contain an array for each column to be sorted initially containing
9936 * the column's index and a direction string ('asc' or 'desc').
9938 * @default [[0,'asc']]
9941 * @name DataTable.defaults.order
9944 * // Sort by 3rd column first, and then 4th column
9945 * $(document).ready( function() {
9946 * $('#example').dataTable( {
9947 * "order": [[2,'asc'], [3,'desc']]
9951 * // No initial sorting
9952 * $(document).ready( function() {
9953 * $('#example').dataTable( {
9958 "aaSorting": [[0,'asc']],
9962 * This parameter is basically identical to the `sorting` parameter, but
9963 * cannot be overridden by user interaction with the table. What this means
9964 * is that you could have a column (visible or hidden) which the sorting
9965 * will always be forced on first - any sorting after that (from the user)
9966 * will then be performed as required. This can be useful for grouping rows
9972 * @name DataTable.defaults.orderFixed
9975 * $(document).ready( function() {
9976 * $('#example').dataTable( {
9977 * "orderFixed": [[0,'asc']]
9981 "aaSortingFixed": [],
9985 * DataTables can be instructed to load data to display in the table from a
9986 * Ajax source. This option defines how that Ajax call is made and where to.
9988 * The `ajax` property has three different modes of operation, depending on
9989 * how it is defined. These are:
9991 * * `string` - Set the URL from where the data should be loaded from.
9992 * * `object` - Define properties for `jQuery.ajax`.
9993 * * `function` - Custom data get function
9998 * As a string, the `ajax` property simply defines the URL from which
9999 * DataTables will load data.
10004 * As an object, the parameters in the object are passed to
10005 * [jQuery.ajax](http://api.jquery.com/jQuery.ajax/) allowing fine control
10006 * of the Ajax request. DataTables has a number of default parameters which
10007 * you can override using this option. Please refer to the jQuery
10008 * documentation for a full description of the options available, although
10009 * the following parameters provide additional options in DataTables or
10010 * require special consideration:
10012 * * `data` - As with jQuery, `data` can be provided as an object, but it
10013 * can also be used as a function to manipulate the data DataTables sends
10014 * to the server. The function takes a single parameter, an object of
10015 * parameters with the values that DataTables has readied for sending. An
10016 * object may be returned which will be merged into the DataTables
10017 * defaults, or you can add the items to the object that was passed in and
10018 * not return anything from the function. This supersedes `fnServerParams`
10019 * from DataTables 1.9-.
10021 * * `dataSrc` - By default DataTables will look for the property `data` (or
10022 * `aaData` for compatibility with DataTables 1.9-) when obtaining data
10023 * from an Ajax source or for server-side processing - this parameter
10024 * allows that property to be changed. You can use Javascript dotted
10025 * object notation to get a data source for multiple levels of nesting, or
10026 * it my be used as a function. As a function it takes a single parameter,
10027 * the JSON returned from the server, which can be manipulated as
10028 * required, with the returned value being that used by DataTables as the
10029 * data source for the table. This supersedes `sAjaxDataProp` from
10032 * * `success` - Should not be overridden it is used internally in
10033 * DataTables. To manipulate / transform the data returned by the server
10034 * use `ajax.dataSrc`, or use `ajax` as a function (see below).
10039 * As a function, making the Ajax call is left up to yourself allowing
10040 * complete control of the Ajax request. Indeed, if desired, a method other
10041 * than Ajax could be used to obtain the required data, such as Web storage
10042 * or an AIR database.
10044 * The function is given four parameters and no return is required. The
10047 * 1. _object_ - Data to send to the server
10048 * 2. _function_ - Callback function that must be executed when the required
10049 * data has been obtained. That data should be passed into the callback
10050 * as the only parameter
10051 * 3. _object_ - DataTables settings object for the table
10053 * Note that this supersedes `fnServerData` from DataTables 1.9-.
10055 * @type string|object|function
10059 * @name DataTable.defaults.ajax
10063 * // Get JSON data from a file via Ajax.
10064 * // Note DataTables expects data in the form `{ data: [ ...data... ] }` by default).
10065 * $('#example').dataTable( {
10066 * "ajax": "data.json"
10070 * // Get JSON data from a file via Ajax, using `dataSrc` to change
10071 * // `data` to `tableData` (i.e. `{ tableData: [ ...data... ] }`)
10072 * $('#example').dataTable( {
10074 * "url": "data.json",
10075 * "dataSrc": "tableData"
10080 * // Get JSON data from a file via Ajax, using `dataSrc` to read data
10081 * // from a plain array rather than an array in an object
10082 * $('#example').dataTable( {
10084 * "url": "data.json",
10090 * // Manipulate the data returned from the server - add a link to data
10091 * // (note this can, should, be done using `render` for the column - this
10092 * // is just a simple example of how the data can be manipulated).
10093 * $('#example').dataTable( {
10095 * "url": "data.json",
10096 * "dataSrc": function ( json ) {
10097 * for ( var i=0, ien=json.length ; i<ien ; i++ ) {
10098 * json[i][0] = '<a href="/message/'+json[i][0]+'>View message</a>';
10106 * // Add data to the request
10107 * $('#example').dataTable( {
10109 * "url": "data.json",
10110 * "data": function ( d ) {
10112 * "extra_search": $('#extra').val()
10119 * // Send request as POST
10120 * $('#example').dataTable( {
10122 * "url": "data.json",
10128 * // Get the data from localStorage (could interface with a form for
10129 * // adding, editing and removing rows).
10130 * $('#example').dataTable( {
10131 * "ajax": function (data, callback, settings) {
10133 * JSON.parse( localStorage.getItem('dataTablesData') )
10142 * This parameter allows you to readily specify the entries in the length drop
10143 * down menu that DataTables shows when pagination is enabled. It can be
10144 * either a 1D array of options which will be used for both the displayed
10145 * option and the value, or a 2D array which will use the array in the first
10146 * position as the value, and the array in the second position as the
10147 * displayed options (useful for language strings such as 'All').
10149 * Note that the `pageLength` property will be automatically set to the
10150 * first value given in this array, unless `pageLength` is also provided.
10152 * @default [ 10, 25, 50, 100 ]
10155 * @name DataTable.defaults.lengthMenu
10158 * $(document).ready( function() {
10159 * $('#example').dataTable( {
10160 * "lengthMenu": [[10, 25, 50, -1], [10, 25, 50, "All"]]
10164 "aLengthMenu": [ 10, 25, 50, 100 ],
10168 * The `columns` option in the initialisation parameter allows you to define
10169 * details about the way individual columns behave. For a full list of
10170 * column options that can be set, please see
10171 * {@link DataTable.defaults.column}. Note that if you use `columns` to
10172 * define your columns, you must have an entry in the array for every single
10173 * column that you have in your table (these can be null if you don't which
10174 * to specify any options).
10177 * @name DataTable.defaults.column
10182 * Very similar to `columns`, `columnDefs` allows you to target a specific
10183 * column, multiple columns, or all columns, using the `targets` property of
10184 * each object in the array. This allows great flexibility when creating
10185 * tables, as the `columnDefs` arrays can be of any length, targeting the
10186 * columns you specifically want. `columnDefs` may use any of the column
10187 * options available: {@link DataTable.defaults.column}, but it _must_
10188 * have `targets` defined in each object in the array. Values in the `targets`
10191 * <li>a string - class name will be matched on the TH for the column</li>
10192 * <li>0 or a positive integer - column index counting from the left</li>
10193 * <li>a negative integer - column index counting from the right</li>
10194 * <li>the string "_all" - all columns (i.e. assign a default)</li>
10198 * @name DataTable.defaults.columnDefs
10200 "aoColumnDefs": null,
10204 * Basically the same as `search`, this parameter defines the individual column
10205 * filtering state at initialisation time. The array must be of the same size
10206 * as the number of columns, and each element be an object with the parameters
10207 * `search` and `escapeRegex` (the latter is optional). 'null' is also
10208 * accepted and the default will be used.
10213 * @name DataTable.defaults.searchCols
10216 * $(document).ready( function() {
10217 * $('#example').dataTable( {
10220 * { "search": "My filter" },
10222 * { "search": "^[0-9]", "escapeRegex": false }
10227 "aoSearchCols": [],
10231 * An array of CSS classes that should be applied to displayed rows. This
10232 * array may be of any length, and DataTables will apply each class
10233 * sequentially, looping when required.
10235 * @default null <i>Will take the values determined by the `oClasses.stripe*`
10239 * @name DataTable.defaults.stripeClasses
10242 * $(document).ready( function() {
10243 * $('#example').dataTable( {
10244 * "stripeClasses": [ 'strip1', 'strip2', 'strip3' ]
10248 "asStripeClasses": null,
10252 * Enable or disable automatic column width calculation. This can be disabled
10253 * as an optimisation (it takes some time to calculate the widths) if the
10254 * tables widths are passed in using `columns`.
10259 * @name DataTable.defaults.autoWidth
10262 * $(document).ready( function () {
10263 * $('#example').dataTable( {
10264 * "autoWidth": false
10268 "bAutoWidth": true,
10272 * Deferred rendering can provide DataTables with a huge speed boost when you
10273 * are using an Ajax or JS data source for the table. This option, when set to
10274 * true, will cause DataTables to defer the creation of the table elements for
10275 * each row until they are needed for a draw - saving a significant amount of
10281 * @name DataTable.defaults.deferRender
10284 * $(document).ready( function() {
10285 * $('#example').dataTable( {
10286 * "ajax": "sources/arrays.txt",
10287 * "deferRender": true
10291 "bDeferRender": false,
10295 * Replace a DataTable which matches the given selector and replace it with
10296 * one which has the properties of the new initialisation object passed. If no
10297 * table matches the selector, then the new DataTable will be constructed as
10303 * @name DataTable.defaults.destroy
10306 * $(document).ready( function() {
10307 * $('#example').dataTable( {
10308 * "srollY": "200px",
10309 * "paginate": false
10312 * // Some time later....
10313 * $('#example').dataTable( {
10323 * Enable or disable filtering of data. Filtering in DataTables is "smart" in
10324 * that it allows the end user to input multiple words (space separated) and
10325 * will match a row containing those words, even if not in the order that was
10326 * specified (this allow matching across multiple columns). Note that if you
10327 * wish to use filtering in DataTables this must remain 'true' - to remove the
10328 * default filtering input box and retain filtering abilities, please use
10329 * {@link DataTable.defaults.dom}.
10334 * @name DataTable.defaults.searching
10337 * $(document).ready( function () {
10338 * $('#example').dataTable( {
10339 * "searching": false
10347 * Enable or disable the table information display. This shows information
10348 * about the data that is currently visible on the page, including information
10349 * about filtered data if that action is being performed.
10354 * @name DataTable.defaults.info
10357 * $(document).ready( function () {
10358 * $('#example').dataTable( {
10367 * Enable jQuery UI ThemeRoller support (required as ThemeRoller requires some
10368 * slightly different and additional mark-up from what DataTables has
10369 * traditionally used).
10374 * @name DataTable.defaults.jQueryUI
10377 * $(document).ready( function() {
10378 * $('#example').dataTable( {
10383 "bJQueryUI": false,
10387 * Allows the end user to select the size of a formatted page from a select
10388 * menu (sizes are 10, 25, 50 and 100). Requires pagination (`paginate`).
10393 * @name DataTable.defaults.lengthChange
10396 * $(document).ready( function () {
10397 * $('#example').dataTable( {
10398 * "lengthChange": false
10402 "bLengthChange": true,
10406 * Enable or disable pagination.
10411 * @name DataTable.defaults.paging
10414 * $(document).ready( function () {
10415 * $('#example').dataTable( {
10424 * Enable or disable the display of a 'processing' indicator when the table is
10425 * being processed (e.g. a sort). This is particularly useful for tables with
10426 * large amounts of data where it can take a noticeable amount of time to sort
10432 * @name DataTable.defaults.processing
10435 * $(document).ready( function () {
10436 * $('#example').dataTable( {
10437 * "processing": true
10441 "bProcessing": false,
10445 * Retrieve the DataTables object for the given selector. Note that if the
10446 * table has already been initialised, this parameter will cause DataTables
10447 * to simply return the object that has already been set up - it will not take
10448 * account of any changes you might have made to the initialisation object
10449 * passed to DataTables (setting this parameter to true is an acknowledgement
10450 * that you understand this). `destroy` can be used to reinitialise a table if
10456 * @name DataTable.defaults.retrieve
10459 * $(document).ready( function() {
10464 * function initTable ()
10466 * return $('#example').dataTable( {
10467 * "scrollY": "200px",
10468 * "paginate": false,
10473 * function tableActions ()
10475 * var table = initTable();
10476 * // perform API operations with oTable
10479 "bRetrieve": false,
10483 * When vertical (y) scrolling is enabled, DataTables will force the height of
10484 * the table's viewport to the given height at all times (useful for layout).
10485 * However, this can look odd when filtering data down to a small data set,
10486 * and the footer is left "floating" further down. This parameter (when
10487 * enabled) will cause DataTables to collapse the table's viewport down when
10488 * the result set will fit within the given Y height.
10493 * @name DataTable.defaults.scrollCollapse
10496 * $(document).ready( function() {
10497 * $('#example').dataTable( {
10498 * "scrollY": "200",
10499 * "scrollCollapse": true
10503 "bScrollCollapse": false,
10507 * Configure DataTables to use server-side processing. Note that the
10508 * `ajax` parameter must also be given in order to give DataTables a
10509 * source to obtain the required data for each draw.
10514 * @dtopt Server-side
10515 * @name DataTable.defaults.serverSide
10518 * $(document).ready( function () {
10519 * $('#example').dataTable( {
10520 * "serverSide": true,
10521 * "ajax": "xhr.php"
10525 "bServerSide": false,
10529 * Enable or disable sorting of columns. Sorting of individual columns can be
10530 * disabled by the `sortable` option for each column.
10535 * @name DataTable.defaults.ordering
10538 * $(document).ready( function () {
10539 * $('#example').dataTable( {
10540 * "ordering": false
10548 * Enable or display DataTables' ability to sort multiple columns at the
10549 * same time (activated by shift-click by the user).
10554 * @name DataTable.defaults.orderMulti
10557 * // Disable multiple column sorting ability
10558 * $(document).ready( function () {
10559 * $('#example').dataTable( {
10560 * "orderMulti": false
10564 "bSortMulti": true,
10568 * Allows control over whether DataTables should use the top (true) unique
10569 * cell that is found for a single column, or the bottom (false - default).
10570 * This is useful when using complex headers.
10575 * @name DataTable.defaults.orderCellsTop
10578 * $(document).ready( function() {
10579 * $('#example').dataTable( {
10580 * "orderCellsTop": true
10584 "bSortCellsTop": false,
10588 * Enable or disable the addition of the classes `sorting\_1`, `sorting\_2` and
10589 * `sorting\_3` to the columns which are currently being sorted on. This is
10590 * presented as a feature switch as it can increase processing time (while
10591 * classes are removed and added) so for large data sets you might want to
10597 * @name DataTable.defaults.orderClasses
10600 * $(document).ready( function () {
10601 * $('#example').dataTable( {
10602 * "orderClasses": false
10606 "bSortClasses": true,
10610 * Enable or disable state saving. When enabled HTML5 `localStorage` will be
10611 * used to save table display information such as pagination information,
10612 * display length, filtering and sorting. As such when the end user reloads
10613 * the page the display display will match what thy had previously set up.
10615 * Due to the use of `localStorage` the default state saving is not supported
10616 * in IE6 or 7. If state saving is required in those browsers, use
10617 * `stateSaveCallback` to provide a storage solution such as cookies.
10622 * @name DataTable.defaults.stateSave
10625 * $(document).ready( function () {
10626 * $('#example').dataTable( {
10627 * "stateSave": true
10631 "bStateSave": false,
10635 * This function is called when a TR element is created (and all TD child
10636 * elements have been inserted), or registered if using a DOM source, allowing
10637 * manipulation of the TR element (adding classes etc).
10639 * @param {node} row "TR" element for the current row
10640 * @param {array} data Raw data array for this row
10641 * @param {int} dataIndex The index of this row in the internal aoData array
10644 * @name DataTable.defaults.createdRow
10647 * $(document).ready( function() {
10648 * $('#example').dataTable( {
10649 * "createdRow": function( row, data, dataIndex ) {
10650 * // Bold the grade for all 'A' grade browsers
10651 * if ( data[4] == "A" )
10653 * $('td:eq(4)', row).html( '<b>A</b>' );
10659 "fnCreatedRow": null,
10663 * This function is called on every 'draw' event, and allows you to
10664 * dynamically modify any aspect you want about the created DOM.
10666 * @param {object} settings DataTables settings object
10669 * @name DataTable.defaults.drawCallback
10672 * $(document).ready( function() {
10673 * $('#example').dataTable( {
10674 * "drawCallback": function( settings ) {
10675 * alert( 'DataTables has redrawn the table' );
10680 "fnDrawCallback": null,
10684 * Identical to fnHeaderCallback() but for the table footer this function
10685 * allows you to modify the table footer on every 'draw' event.
10687 * @param {node} foot "TR" element for the footer
10688 * @param {array} data Full table data (as derived from the original HTML)
10689 * @param {int} start Index for the current display starting point in the
10691 * @param {int} end Index for the current display ending point in the
10693 * @param {array int} display Index array to translate the visual position
10694 * to the full data array
10697 * @name DataTable.defaults.footerCallback
10700 * $(document).ready( function() {
10701 * $('#example').dataTable( {
10702 * "footerCallback": function( tfoot, data, start, end, display ) {
10703 * tfoot.getElementsByTagName('th')[0].innerHTML = "Starting index is "+start;
10708 "fnFooterCallback": null,
10712 * When rendering large numbers in the information element for the table
10713 * (i.e. "Showing 1 to 10 of 57 entries") DataTables will render large numbers
10714 * to have a comma separator for the 'thousands' units (e.g. 1 million is
10715 * rendered as "1,000,000") to help readability for the end user. This
10716 * function will override the default method DataTables uses.
10719 * @param {int} toFormat number to be formatted
10720 * @returns {string} formatted string for DataTables to show the number
10723 * @name DataTable.defaults.formatNumber
10726 * // Format a number using a single quote for the separator (note that
10727 * // this can also be done with the language.thousands option)
10728 * $(document).ready( function() {
10729 * $('#example').dataTable( {
10730 * "formatNumber": function ( toFormat ) {
10731 * return toFormat.toString().replace(
10732 * /\B(?=(\d{3})+(?!\d))/g, "'"
10738 "fnFormatNumber": function ( toFormat ) {
10739 return toFormat.toString().replace(
10740 /\B(?=(\d{3})+(?!\d))/g,
10741 this.oLanguage.sThousands
10747 * This function is called on every 'draw' event, and allows you to
10748 * dynamically modify the header row. This can be used to calculate and
10749 * display useful information about the table.
10751 * @param {node} head "TR" element for the header
10752 * @param {array} data Full table data (as derived from the original HTML)
10753 * @param {int} start Index for the current display starting point in the
10755 * @param {int} end Index for the current display ending point in the
10757 * @param {array int} display Index array to translate the visual position
10758 * to the full data array
10761 * @name DataTable.defaults.headerCallback
10764 * $(document).ready( function() {
10765 * $('#example').dataTable( {
10766 * "fheaderCallback": function( head, data, start, end, display ) {
10767 * head.getElementsByTagName('th')[0].innerHTML = "Displaying "+(end-start)+" records";
10772 "fnHeaderCallback": null,
10776 * The information element can be used to convey information about the current
10777 * state of the table. Although the internationalisation options presented by
10778 * DataTables are quite capable of dealing with most customisations, there may
10779 * be times where you wish to customise the string further. This callback
10780 * allows you to do exactly that.
10782 * @param {object} oSettings DataTables settings object
10783 * @param {int} start Starting position in data for the draw
10784 * @param {int} end End position in data for the draw
10785 * @param {int} max Total number of rows in the table (regardless of
10787 * @param {int} total Total number of rows in the data set, after filtering
10788 * @param {string} pre The string that DataTables has formatted using it's
10790 * @returns {string} The string to be displayed in the information element.
10793 * @name DataTable.defaults.infoCallback
10796 * $('#example').dataTable( {
10797 * "infoCallback": function( settings, start, end, max, total, pre ) {
10798 * return start +" to "+ end;
10802 "fnInfoCallback": null,
10806 * Called when the table has been initialised. Normally DataTables will
10807 * initialise sequentially and there will be no need for this function,
10808 * however, this does not hold true when using external language information
10809 * since that is obtained using an async XHR call.
10811 * @param {object} settings DataTables settings object
10812 * @param {object} json The JSON object request from the server - only
10813 * present if client-side Ajax sourced data is used
10816 * @name DataTable.defaults.initComplete
10819 * $(document).ready( function() {
10820 * $('#example').dataTable( {
10821 * "initComplete": function(settings, json) {
10822 * alert( 'DataTables has finished its initialisation.' );
10827 "fnInitComplete": null,
10831 * Called at the very start of each table draw and can be used to cancel the
10832 * draw by returning false, any other return (including undefined) results in
10833 * the full draw occurring).
10835 * @param {object} settings DataTables settings object
10836 * @returns {boolean} False will cancel the draw, anything else (including no
10837 * return) will allow it to complete.
10840 * @name DataTable.defaults.preDrawCallback
10843 * $(document).ready( function() {
10844 * $('#example').dataTable( {
10845 * "preDrawCallback": function( settings ) {
10846 * if ( $('#test').val() == 1 ) {
10853 "fnPreDrawCallback": null,
10857 * This function allows you to 'post process' each row after it have been
10858 * generated for each table draw, but before it is rendered on screen. This
10859 * function might be used for setting the row class name etc.
10861 * @param {node} row "TR" element for the current row
10862 * @param {array} data Raw data array for this row
10863 * @param {int} displayIndex The display index for the current table draw
10864 * @param {int} displayIndexFull The index of the data in the full list of
10865 * rows (after filtering)
10868 * @name DataTable.defaults.rowCallback
10871 * $(document).ready( function() {
10872 * $('#example').dataTable( {
10873 * "rowCallback": function( row, data, displayIndex, displayIndexFull ) {
10874 * // Bold the grade for all 'A' grade browsers
10875 * if ( data[4] == "A" ) {
10876 * $('td:eq(4)', row).html( '<b>A</b>' );
10882 "fnRowCallback": null,
10886 * __Deprecated__ The functionality provided by this parameter has now been
10887 * superseded by that provided through `ajax`, which should be used instead.
10889 * This parameter allows you to override the default function which obtains
10890 * the data from the server so something more suitable for your application.
10891 * For example you could use POST data, or pull information from a Gears or
10895 * @param {string} source HTTP source to obtain the data from (`ajax`)
10896 * @param {array} data A key/value pair object containing the data to send
10898 * @param {function} callback to be called on completion of the data get
10899 * process that will draw the data on the page.
10900 * @param {object} settings DataTables settings object
10903 * @dtopt Server-side
10904 * @name DataTable.defaults.serverData
10906 * @deprecated 1.10. Please use `ajax` for this functionality now.
10908 "fnServerData": null,
10912 * __Deprecated__ The functionality provided by this parameter has now been
10913 * superseded by that provided through `ajax`, which should be used instead.
10915 * It is often useful to send extra data to the server when making an Ajax
10916 * request - for example custom filtering information, and this callback
10917 * function makes it trivial to send extra information to the server. The
10918 * passed in parameter is the data set that has been constructed by
10919 * DataTables, and you can add to this or modify it as you require.
10921 * @param {array} data Data array (array of objects which are name/value
10922 * pairs) that has been constructed by DataTables and will be sent to the
10923 * server. In the case of Ajax sourced data with server-side processing
10924 * this will be an empty array, for server-side processing there will be a
10925 * significant number of parameters!
10926 * @returns {undefined} Ensure that you modify the data array passed in,
10927 * as this is passed by reference.
10930 * @dtopt Server-side
10931 * @name DataTable.defaults.serverParams
10933 * @deprecated 1.10. Please use `ajax` for this functionality now.
10935 "fnServerParams": null,
10939 * Load the table state. With this function you can define from where, and how, the
10940 * state of a table is loaded. By default DataTables will load from `localStorage`
10941 * but you might wish to use a server-side database or cookies.
10944 * @param {object} settings DataTables settings object
10945 * @param {object} callback Callback that can be executed when done. It
10946 * should be passed the loaded state object.
10947 * @return {object} The DataTables state object to be loaded
10950 * @name DataTable.defaults.stateLoadCallback
10953 * $(document).ready( function() {
10954 * $('#example').dataTable( {
10955 * "stateSave": true,
10956 * "stateLoadCallback": function (settings, callback) {
10958 * "url": "/state_load",
10959 * "dataType": "json",
10960 * "success": function (json) {
10961 * callback( json );
10968 "fnStateLoadCallback": function ( settings ) {
10971 (settings.iStateDuration === -1 ? sessionStorage : localStorage).getItem(
10972 'DataTables_'+settings.sInstance+'_'+location.pathname
10980 * Callback which allows modification of the saved state prior to loading that state.
10981 * This callback is called when the table is loading state from the stored data, but
10982 * prior to the settings object being modified by the saved state. Note that for
10983 * plug-in authors, you should use the `stateLoadParams` event to load parameters for
10986 * @param {object} settings DataTables settings object
10987 * @param {object} data The state object that is to be loaded
10990 * @name DataTable.defaults.stateLoadParams
10993 * // Remove a saved filter, so filtering is never loaded
10994 * $(document).ready( function() {
10995 * $('#example').dataTable( {
10996 * "stateSave": true,
10997 * "stateLoadParams": function (settings, data) {
10998 * data.oSearch.sSearch = "";
11004 * // Disallow state loading by returning false
11005 * $(document).ready( function() {
11006 * $('#example').dataTable( {
11007 * "stateSave": true,
11008 * "stateLoadParams": function (settings, data) {
11014 "fnStateLoadParams": null,
11018 * Callback that is called when the state has been loaded from the state saving method
11019 * and the DataTables settings object has been modified as a result of the loaded state.
11021 * @param {object} settings DataTables settings object
11022 * @param {object} data The state object that was loaded
11025 * @name DataTable.defaults.stateLoaded
11028 * // Show an alert with the filtering value that was saved
11029 * $(document).ready( function() {
11030 * $('#example').dataTable( {
11031 * "stateSave": true,
11032 * "stateLoaded": function (settings, data) {
11033 * alert( 'Saved filter was: '+data.oSearch.sSearch );
11038 "fnStateLoaded": null,
11042 * Save the table state. This function allows you to define where and how the state
11043 * information for the table is stored By default DataTables will use `localStorage`
11044 * but you might wish to use a server-side database or cookies.
11047 * @param {object} settings DataTables settings object
11048 * @param {object} data The state object to be saved
11051 * @name DataTable.defaults.stateSaveCallback
11054 * $(document).ready( function() {
11055 * $('#example').dataTable( {
11056 * "stateSave": true,
11057 * "stateSaveCallback": function (settings, data) {
11058 * // Send an Ajax request to the server with the state object
11060 * "url": "/state_save",
11062 * "dataType": "json",
11064 * "success": function () {}
11070 "fnStateSaveCallback": function ( settings, data ) {
11072 (settings.iStateDuration === -1 ? sessionStorage : localStorage).setItem(
11073 'DataTables_'+settings.sInstance+'_'+location.pathname,
11074 JSON.stringify( data )
11081 * Callback which allows modification of the state to be saved. Called when the table
11082 * has changed state a new state save is required. This method allows modification of
11083 * the state saving object prior to actually doing the save, including addition or
11084 * other state properties or modification. Note that for plug-in authors, you should
11085 * use the `stateSaveParams` event to save parameters for a plug-in.
11087 * @param {object} settings DataTables settings object
11088 * @param {object} data The state object to be saved
11091 * @name DataTable.defaults.stateSaveParams
11094 * // Remove a saved filter, so filtering is never saved
11095 * $(document).ready( function() {
11096 * $('#example').dataTable( {
11097 * "stateSave": true,
11098 * "stateSaveParams": function (settings, data) {
11099 * data.oSearch.sSearch = "";
11104 "fnStateSaveParams": null,
11108 * Duration for which the saved state information is considered valid. After this period
11109 * has elapsed the state will be returned to the default.
11110 * Value is given in seconds.
11112 * @default 7200 <i>(2 hours)</i>
11115 * @name DataTable.defaults.stateDuration
11118 * $(document).ready( function() {
11119 * $('#example').dataTable( {
11120 * "stateDuration": 60*60*24; // 1 day
11124 "iStateDuration": 7200,
11128 * When enabled DataTables will not make a request to the server for the first
11129 * page draw - rather it will use the data already on the page (no sorting etc
11130 * will be applied to it), thus saving on an XHR at load time. `deferLoading`
11131 * is used to indicate that deferred loading is required, but it is also used
11132 * to tell DataTables how many records there are in the full table (allowing
11133 * the information element and pagination to be displayed correctly). In the case
11134 * where a filtering is applied to the table on initial load, this can be
11135 * indicated by giving the parameter as an array, where the first element is
11136 * the number of records available after filtering and the second element is the
11137 * number of records without filtering (allowing the table information element
11138 * to be shown correctly).
11139 * @type int | array
11143 * @name DataTable.defaults.deferLoading
11146 * // 57 records available in the table, no filtering applied
11147 * $(document).ready( function() {
11148 * $('#example').dataTable( {
11149 * "serverSide": true,
11150 * "ajax": "scripts/server_processing.php",
11151 * "deferLoading": 57
11156 * // 57 records after filtering, 100 without filtering (an initial filter applied)
11157 * $(document).ready( function() {
11158 * $('#example').dataTable( {
11159 * "serverSide": true,
11160 * "ajax": "scripts/server_processing.php",
11161 * "deferLoading": [ 57, 100 ],
11163 * "search": "my_filter"
11168 "iDeferLoading": null,
11172 * Number of rows to display on a single page when using pagination. If
11173 * feature enabled (`lengthChange`) then the end user will be able to override
11174 * this to a custom setting using a pop-up menu.
11179 * @name DataTable.defaults.pageLength
11182 * $(document).ready( function() {
11183 * $('#example').dataTable( {
11188 "iDisplayLength": 10,
11192 * Define the starting point for data display when using DataTables with
11193 * pagination. Note that this parameter is the number of records, rather than
11194 * the page number, so if you have 10 records per page and want to start on
11195 * the third page, it should be "20".
11200 * @name DataTable.defaults.displayStart
11203 * $(document).ready( function() {
11204 * $('#example').dataTable( {
11205 * "displayStart": 20
11209 "iDisplayStart": 0,
11213 * By default DataTables allows keyboard navigation of the table (sorting, paging,
11214 * and filtering) by adding a `tabindex` attribute to the required elements. This
11215 * allows you to tab through the controls and press the enter key to activate them.
11216 * The tabindex is default 0, meaning that the tab follows the flow of the document.
11217 * You can overrule this using this parameter if you wish. Use a value of -1 to
11218 * disable built-in keyboard navigation.
11223 * @name DataTable.defaults.tabIndex
11226 * $(document).ready( function() {
11227 * $('#example').dataTable( {
11236 * Classes that DataTables assigns to the various components and features
11237 * that it adds to the HTML table. This allows classes to be configured
11238 * during initialisation in addition to through the static
11239 * {@link DataTable.ext.oStdClasses} object).
11241 * @name DataTable.defaults.classes
11247 * All strings that DataTables uses in the user interface that it creates
11248 * are defined in this object, allowing you to modified them individually or
11249 * completely replace them all as required.
11251 * @name DataTable.defaults.language
11255 * Strings that are used for WAI-ARIA labels and controls only (these are not
11256 * actually visible on the page, but will be read by screenreaders, and thus
11257 * must be internationalised as well).
11259 * @name DataTable.defaults.language.aria
11263 * ARIA label that is added to the table headers when the column may be
11264 * sorted ascending by activing the column (click or return when focused).
11265 * Note that the column header is prefixed to this string.
11267 * @default : activate to sort column ascending
11270 * @name DataTable.defaults.language.aria.sortAscending
11273 * $(document).ready( function() {
11274 * $('#example').dataTable( {
11277 * "sortAscending": " - click/return to sort ascending"
11283 "sSortAscending": ": activate to sort column ascending",
11286 * ARIA label that is added to the table headers when the column may be
11287 * sorted descending by activing the column (click or return when focused).
11288 * Note that the column header is prefixed to this string.
11290 * @default : activate to sort column ascending
11293 * @name DataTable.defaults.language.aria.sortDescending
11296 * $(document).ready( function() {
11297 * $('#example').dataTable( {
11300 * "sortDescending": " - click/return to sort descending"
11306 "sSortDescending": ": activate to sort column descending"
11310 * Pagination string used by DataTables for the built-in pagination
11313 * @name DataTable.defaults.language.paginate
11317 * Text to use when using the 'full_numbers' type of pagination for the
11318 * button to take the user to the first page.
11323 * @name DataTable.defaults.language.paginate.first
11326 * $(document).ready( function() {
11327 * $('#example').dataTable( {
11330 * "first": "First page"
11340 * Text to use when using the 'full_numbers' type of pagination for the
11341 * button to take the user to the last page.
11346 * @name DataTable.defaults.language.paginate.last
11349 * $(document).ready( function() {
11350 * $('#example').dataTable( {
11353 * "last": "Last page"
11363 * Text to use for the 'next' pagination button (to take the user to the
11369 * @name DataTable.defaults.language.paginate.next
11372 * $(document).ready( function() {
11373 * $('#example').dataTable( {
11376 * "next": "Next page"
11386 * Text to use for the 'previous' pagination button (to take the user to
11387 * the previous page).
11389 * @default Previous
11392 * @name DataTable.defaults.language.paginate.previous
11395 * $(document).ready( function() {
11396 * $('#example').dataTable( {
11399 * "previous": "Previous page"
11405 "sPrevious": "Previous"
11409 * This string is shown in preference to `zeroRecords` when the table is
11410 * empty of data (regardless of filtering). Note that this is an optional
11411 * parameter - if it is not given, the value of `zeroRecords` will be used
11412 * instead (either the default or given value).
11414 * @default No data available in table
11417 * @name DataTable.defaults.language.emptyTable
11420 * $(document).ready( function() {
11421 * $('#example').dataTable( {
11423 * "emptyTable": "No data available in table"
11428 "sEmptyTable": "No data available in table",
11432 * This string gives information to the end user about the information
11433 * that is current on display on the page. The following tokens can be
11434 * used in the string and will be dynamically replaced as the table
11435 * display updates. This tokens can be placed anywhere in the string, or
11436 * removed as needed by the language requires:
11438 * * `\_START\_` - Display index of the first record on the current page
11439 * * `\_END\_` - Display index of the last record on the current page
11440 * * `\_TOTAL\_` - Number of records in the table after filtering
11441 * * `\_MAX\_` - Number of records in the table without filtering
11442 * * `\_PAGE\_` - Current page number
11443 * * `\_PAGES\_` - Total number of pages of data in the table
11446 * @default Showing _START_ to _END_ of _TOTAL_ entries
11449 * @name DataTable.defaults.language.info
11452 * $(document).ready( function() {
11453 * $('#example').dataTable( {
11455 * "info": "Showing page _PAGE_ of _PAGES_"
11460 "sInfo": "Showing _START_ to _END_ of _TOTAL_ entries",
11464 * Display information string for when the table is empty. Typically the
11465 * format of this string should match `info`.
11467 * @default Showing 0 to 0 of 0 entries
11470 * @name DataTable.defaults.language.infoEmpty
11473 * $(document).ready( function() {
11474 * $('#example').dataTable( {
11476 * "infoEmpty": "No entries to show"
11481 "sInfoEmpty": "Showing 0 to 0 of 0 entries",
11485 * When a user filters the information in a table, this string is appended
11486 * to the information (`info`) to give an idea of how strong the filtering
11487 * is. The variable _MAX_ is dynamically updated.
11489 * @default (filtered from _MAX_ total entries)
11492 * @name DataTable.defaults.language.infoFiltered
11495 * $(document).ready( function() {
11496 * $('#example').dataTable( {
11498 * "infoFiltered": " - filtering from _MAX_ records"
11503 "sInfoFiltered": "(filtered from _MAX_ total entries)",
11507 * If can be useful to append extra information to the info string at times,
11508 * and this variable does exactly that. This information will be appended to
11509 * the `info` (`infoEmpty` and `infoFiltered` in whatever combination they are
11510 * being used) at all times.
11512 * @default <i>Empty string</i>
11515 * @name DataTable.defaults.language.infoPostFix
11518 * $(document).ready( function() {
11519 * $('#example').dataTable( {
11521 * "infoPostFix": "All records shown are derived from real information."
11526 "sInfoPostFix": "",
11530 * This decimal place operator is a little different from the other
11531 * language options since DataTables doesn't output floating point
11532 * numbers, so it won't ever use this for display of a number. Rather,
11533 * what this parameter does is modify the sort methods of the table so
11534 * that numbers which are in a format which has a character other than
11535 * a period (`.`) as a decimal place will be sorted numerically.
11537 * Note that numbers with different decimal places cannot be shown in
11538 * the same table and still be sortable, the table must be consistent.
11539 * However, multiple different tables on the page can use different
11540 * decimal place characters.
11545 * @name DataTable.defaults.language.decimal
11548 * $(document).ready( function() {
11549 * $('#example').dataTable( {
11561 * DataTables has a build in number formatter (`formatNumber`) which is
11562 * used to format large numbers that are used in the table information.
11563 * By default a comma is used, but this can be trivially changed to any
11564 * character you wish with this parameter.
11569 * @name DataTable.defaults.language.thousands
11572 * $(document).ready( function() {
11573 * $('#example').dataTable( {
11584 * Detail the action that will be taken when the drop down menu for the
11585 * pagination length option is changed. The '_MENU_' variable is replaced
11586 * with a default select list of 10, 25, 50 and 100, and can be replaced
11587 * with a custom select box if required.
11589 * @default Show _MENU_ entries
11592 * @name DataTable.defaults.language.lengthMenu
11595 * // Language change only
11596 * $(document).ready( function() {
11597 * $('#example').dataTable( {
11599 * "lengthMenu": "Display _MENU_ records"
11605 * // Language and options change
11606 * $(document).ready( function() {
11607 * $('#example').dataTable( {
11609 * "lengthMenu": 'Display <select>'+
11610 * '<option value="10">10</option>'+
11611 * '<option value="20">20</option>'+
11612 * '<option value="30">30</option>'+
11613 * '<option value="40">40</option>'+
11614 * '<option value="50">50</option>'+
11615 * '<option value="-1">All</option>'+
11616 * '</select> records'
11621 "sLengthMenu": "Show _MENU_ entries",
11625 * When using Ajax sourced data and during the first draw when DataTables is
11626 * gathering the data, this message is shown in an empty row in the table to
11627 * indicate to the end user the the data is being loaded. Note that this
11628 * parameter is not used when loading data by server-side processing, just
11629 * Ajax sourced data with client-side processing.
11631 * @default Loading...
11634 * @name DataTable.defaults.language.loadingRecords
11637 * $(document).ready( function() {
11638 * $('#example').dataTable( {
11640 * "loadingRecords": "Please wait - loading..."
11645 "sLoadingRecords": "Loading...",
11649 * Text which is displayed when the table is processing a user action
11650 * (usually a sort command or similar).
11652 * @default Processing...
11655 * @name DataTable.defaults.language.processing
11658 * $(document).ready( function() {
11659 * $('#example').dataTable( {
11661 * "processing": "DataTables is currently busy"
11666 "sProcessing": "Processing...",
11670 * Details the actions that will be taken when the user types into the
11671 * filtering input text box. The variable "_INPUT_", if used in the string,
11672 * is replaced with the HTML text box for the filtering input allowing
11673 * control over where it appears in the string. If "_INPUT_" is not given
11674 * then the input box is appended to the string automatically.
11679 * @name DataTable.defaults.language.search
11682 * // Input text box will be appended at the end automatically
11683 * $(document).ready( function() {
11684 * $('#example').dataTable( {
11686 * "search": "Filter records:"
11692 * // Specify where the filter should appear
11693 * $(document).ready( function() {
11694 * $('#example').dataTable( {
11696 * "search": "Apply filter _INPUT_ to table"
11701 "sSearch": "Search:",
11705 * Assign a `placeholder` attribute to the search `input` element
11710 * @name DataTable.defaults.language.searchPlaceholder
11712 "sSearchPlaceholder": "",
11716 * All of the language information can be stored in a file on the
11717 * server-side, which DataTables will look up if this parameter is passed.
11718 * It must store the URL of the language file, which is in a JSON format,
11719 * and the object has the same properties as the oLanguage object in the
11720 * initialiser object (i.e. the above parameters). Please refer to one of
11721 * the example language files to see how this works in action.
11723 * @default <i>Empty string - i.e. disabled</i>
11726 * @name DataTable.defaults.language.url
11729 * $(document).ready( function() {
11730 * $('#example').dataTable( {
11732 * "url": "http://www.sprymedia.co.uk/dataTables/lang.txt"
11741 * Text shown inside the table records when the is no information to be
11742 * displayed after filtering. `emptyTable` is shown when there is simply no
11743 * information in the table at all (regardless of filtering).
11745 * @default No matching records found
11748 * @name DataTable.defaults.language.zeroRecords
11751 * $(document).ready( function() {
11752 * $('#example').dataTable( {
11754 * "zeroRecords": "No records to display"
11759 "sZeroRecords": "No matching records found"
11764 * This parameter allows you to have define the global filtering state at
11765 * initialisation time. As an object the `search` parameter must be
11766 * defined, but all other parameters are optional. When `regex` is true,
11767 * the search string will be treated as a regular expression, when false
11768 * (default) it will be treated as a straight string. When `smart`
11769 * DataTables will use it's smart filtering methods (to word match at
11770 * any point in the data), when false this will not be done.
11772 * @extends DataTable.models.oSearch
11775 * @name DataTable.defaults.search
11778 * $(document).ready( function() {
11779 * $('#example').dataTable( {
11780 * "search": {"search": "Initial search"}
11784 "oSearch": $.extend( {}, DataTable.models.oSearch ),
11788 * __Deprecated__ The functionality provided by this parameter has now been
11789 * superseded by that provided through `ajax`, which should be used instead.
11791 * By default DataTables will look for the property `data` (or `aaData` for
11792 * compatibility with DataTables 1.9-) when obtaining data from an Ajax
11793 * source or for server-side processing - this parameter allows that
11794 * property to be changed. You can use Javascript dotted object notation to
11795 * get a data source for multiple levels of nesting.
11800 * @dtopt Server-side
11801 * @name DataTable.defaults.ajaxDataProp
11803 * @deprecated 1.10. Please use `ajax` for this functionality now.
11805 "sAjaxDataProp": "data",
11809 * __Deprecated__ The functionality provided by this parameter has now been
11810 * superseded by that provided through `ajax`, which should be used instead.
11812 * You can instruct DataTables to load data from an external
11813 * source using this parameter (use aData if you want to pass data in you
11814 * already have). Simply provide a url a JSON object can be obtained from.
11819 * @dtopt Server-side
11820 * @name DataTable.defaults.ajaxSource
11822 * @deprecated 1.10. Please use `ajax` for this functionality now.
11824 "sAjaxSource": null,
11828 * This initialisation variable allows you to specify exactly where in the
11829 * DOM you want DataTables to inject the various controls it adds to the page
11830 * (for example you might want the pagination controls at the top of the
11831 * table). DIV elements (with or without a custom class) can also be added to
11832 * aid styling. The follow syntax is used:
11834 * <li>The following options are allowed:
11836 * <li>'l' - Length changing</li>
11837 * <li>'f' - Filtering input</li>
11838 * <li>'t' - The table!</li>
11839 * <li>'i' - Information</li>
11840 * <li>'p' - Pagination</li>
11841 * <li>'r' - pRocessing</li>
11844 * <li>The following constants are allowed:
11846 * <li>'H' - jQueryUI theme "header" classes ('fg-toolbar ui-widget-header ui-corner-tl ui-corner-tr ui-helper-clearfix')</li>
11847 * <li>'F' - jQueryUI theme "footer" classes ('fg-toolbar ui-widget-header ui-corner-bl ui-corner-br ui-helper-clearfix')</li>
11850 * <li>The following syntax is expected:
11852 * <li>'<' and '>' - div elements</li>
11853 * <li>'<"class" and '>' - div with a class</li>
11854 * <li>'<"#id" and '>' - div with an ID</li>
11859 * <li>'<"wrapper"flipt>'</li>
11860 * <li>'<lf<t>ip>'</li>
11865 * @default lfrtip <i>(when `jQueryUI` is false)</i> <b>or</b>
11866 * <"H"lfr>t<"F"ip> <i>(when `jQueryUI` is true)</i>
11869 * @name DataTable.defaults.dom
11872 * $(document).ready( function() {
11873 * $('#example').dataTable( {
11874 * "dom": '<"top"i>rt<"bottom"flp><"clear">'
11882 * Search delay option. This will throttle full table searches that use the
11883 * DataTables provided search input element (it does not effect calls to
11884 * `dt-api search()`, providing a delay before the search is made.
11889 * @name DataTable.defaults.searchDelay
11892 * $(document).ready( function() {
11893 * $('#example').dataTable( {
11894 * "searchDelay": 200
11898 "searchDelay": null,
11902 * DataTables features six different built-in options for the buttons to
11903 * display for pagination control:
11905 * * `numbers` - Page number buttons only
11906 * * `simple` - 'Previous' and 'Next' buttons only
11907 * * 'simple_numbers` - 'Previous' and 'Next' buttons, plus page numbers
11908 * * `full` - 'First', 'Previous', 'Next' and 'Last' buttons
11909 * * `full_numbers` - 'First', 'Previous', 'Next' and 'Last' buttons, plus page numbers
11910 * * `first_last_numbers` - 'First' and 'Last' buttons, plus page numbers
11912 * Further methods can be added using {@link DataTable.ext.oPagination}.
11914 * @default simple_numbers
11917 * @name DataTable.defaults.pagingType
11920 * $(document).ready( function() {
11921 * $('#example').dataTable( {
11922 * "pagingType": "full_numbers"
11926 "sPaginationType": "simple_numbers",
11930 * Enable horizontal scrolling. When a table is too wide to fit into a
11931 * certain layout, or you have a large number of columns in the table, you
11932 * can enable x-scrolling to show the table in a viewport, which can be
11933 * scrolled. This property can be `true` which will allow the table to
11934 * scroll horizontally when needed, or any CSS unit, or a number (in which
11935 * case it will be treated as a pixel measurement). Setting as simply `true`
11937 * @type boolean|string
11938 * @default <i>blank string - i.e. disabled</i>
11941 * @name DataTable.defaults.scrollX
11944 * $(document).ready( function() {
11945 * $('#example').dataTable( {
11947 * "scrollCollapse": true
11955 * This property can be used to force a DataTable to use more width than it
11956 * might otherwise do when x-scrolling is enabled. For example if you have a
11957 * table which requires to be well spaced, this parameter is useful for
11958 * "over-sizing" the table, and thus forcing scrolling. This property can by
11959 * any CSS unit, or a number (in which case it will be treated as a pixel
11962 * @default <i>blank string - i.e. disabled</i>
11965 * @name DataTable.defaults.scrollXInner
11968 * $(document).ready( function() {
11969 * $('#example').dataTable( {
11970 * "scrollX": "100%",
11971 * "scrollXInner": "110%"
11975 "sScrollXInner": "",
11979 * Enable vertical scrolling. Vertical scrolling will constrain the DataTable
11980 * to the given height, and enable scrolling for any data which overflows the
11981 * current viewport. This can be used as an alternative to paging to display
11982 * a lot of data in a small area (although paging and scrolling can both be
11983 * enabled at the same time). This property can be any CSS unit, or a number
11984 * (in which case it will be treated as a pixel measurement).
11986 * @default <i>blank string - i.e. disabled</i>
11989 * @name DataTable.defaults.scrollY
11992 * $(document).ready( function() {
11993 * $('#example').dataTable( {
11994 * "scrollY": "200px",
11995 * "paginate": false
12003 * __Deprecated__ The functionality provided by this parameter has now been
12004 * superseded by that provided through `ajax`, which should be used instead.
12006 * Set the HTTP method that is used to make the Ajax call for server-side
12007 * processing or Ajax sourced data.
12012 * @dtopt Server-side
12013 * @name DataTable.defaults.serverMethod
12015 * @deprecated 1.10. Please use `ajax` for this functionality now.
12017 "sServerMethod": "GET",
12021 * DataTables makes use of renderers when displaying HTML elements for
12022 * a table. These renderers can be added or modified by plug-ins to
12023 * generate suitable mark-up for a site. For example the Bootstrap
12024 * integration plug-in for DataTables uses a paging button renderer to
12025 * display pagination buttons in the mark-up required by Bootstrap.
12027 * For further information about the renderers available see
12028 * DataTable.ext.renderer
12029 * @type string|object
12032 * @name DataTable.defaults.renderer
12039 * Set the data property name that DataTables should use to get a row's id
12040 * to set as the `id` property in the node.
12042 * @default DT_RowId
12044 * @name DataTable.defaults.rowId
12046 "rowId": "DT_RowId"
12049 _fnHungarianMap( DataTable.defaults );
12054 * Developer note - See note in model.defaults.js about the use of Hungarian
12055 * notation and camel case.
12059 * Column options that can be given to DataTables at initialisation time.
12062 DataTable.defaults.column = {
12064 * Define which column(s) an order will occur on for this column. This
12065 * allows a column's ordering to take multiple columns into account when
12066 * doing a sort or use the data from a different column. For example first
12067 * name / last name columns make sense to do a multi-column sort over the
12070 * @default null <i>Takes the value of the column index automatically</i>
12072 * @name DataTable.defaults.column.orderData
12076 * // Using `columnDefs`
12077 * $(document).ready( function() {
12078 * $('#example').dataTable( {
12080 * { "orderData": [ 0, 1 ], "targets": [ 0 ] },
12081 * { "orderData": [ 1, 0 ], "targets": [ 1 ] },
12082 * { "orderData": 2, "targets": [ 2 ] }
12088 * // Using `columns`
12089 * $(document).ready( function() {
12090 * $('#example').dataTable( {
12092 * { "orderData": [ 0, 1 ] },
12093 * { "orderData": [ 1, 0 ] },
12094 * { "orderData": 2 },
12106 * You can control the default ordering direction, and even alter the
12107 * behaviour of the sort handler (i.e. only allow ascending ordering etc)
12108 * using this parameter.
12110 * @default [ 'asc', 'desc' ]
12112 * @name DataTable.defaults.column.orderSequence
12116 * // Using `columnDefs`
12117 * $(document).ready( function() {
12118 * $('#example').dataTable( {
12120 * { "orderSequence": [ "asc" ], "targets": [ 1 ] },
12121 * { "orderSequence": [ "desc", "asc", "asc" ], "targets": [ 2 ] },
12122 * { "orderSequence": [ "desc" ], "targets": [ 3 ] }
12128 * // Using `columns`
12129 * $(document).ready( function() {
12130 * $('#example').dataTable( {
12133 * { "orderSequence": [ "asc" ] },
12134 * { "orderSequence": [ "desc", "asc", "asc" ] },
12135 * { "orderSequence": [ "desc" ] },
12141 "asSorting": [ 'asc', 'desc' ],
12145 * Enable or disable filtering on the data in this column.
12149 * @name DataTable.defaults.column.searchable
12153 * // Using `columnDefs`
12154 * $(document).ready( function() {
12155 * $('#example').dataTable( {
12157 * { "searchable": false, "targets": [ 0 ] }
12162 * // Using `columns`
12163 * $(document).ready( function() {
12164 * $('#example').dataTable( {
12166 * { "searchable": false },
12174 "bSearchable": true,
12178 * Enable or disable ordering on this column.
12182 * @name DataTable.defaults.column.orderable
12186 * // Using `columnDefs`
12187 * $(document).ready( function() {
12188 * $('#example').dataTable( {
12190 * { "orderable": false, "targets": [ 0 ] }
12195 * // Using `columns`
12196 * $(document).ready( function() {
12197 * $('#example').dataTable( {
12199 * { "orderable": false },
12211 * Enable or disable the display of this column.
12215 * @name DataTable.defaults.column.visible
12219 * // Using `columnDefs`
12220 * $(document).ready( function() {
12221 * $('#example').dataTable( {
12223 * { "visible": false, "targets": [ 0 ] }
12228 * // Using `columns`
12229 * $(document).ready( function() {
12230 * $('#example').dataTable( {
12232 * { "visible": false },
12244 * Developer definable function that is called whenever a cell is created (Ajax source,
12245 * etc) or processed for input (DOM source). This can be used as a compliment to mRender
12246 * allowing you to modify the DOM element (add background colour for example) when the
12247 * element is available.
12249 * @param {element} td The TD node that has been created
12250 * @param {*} cellData The Data for the cell
12251 * @param {array|object} rowData The data for the whole row
12252 * @param {int} row The row index for the aoData data store
12253 * @param {int} col The column index for aoColumns
12255 * @name DataTable.defaults.column.createdCell
12259 * $(document).ready( function() {
12260 * $('#example').dataTable( {
12261 * "columnDefs": [ {
12263 * "createdCell": function (td, cellData, rowData, row, col) {
12264 * if ( cellData == "1.7" ) {
12265 * $(td).css('color', 'blue')
12272 "fnCreatedCell": null,
12276 * This parameter has been replaced by `data` in DataTables to ensure naming
12277 * consistency. `dataProp` can still be used, as there is backwards
12278 * compatibility in DataTables for this option, but it is strongly
12279 * recommended that you use `data` in preference to `dataProp`.
12280 * @name DataTable.defaults.column.dataProp
12285 * This property can be used to read data from any data source property,
12286 * including deeply nested objects / properties. `data` can be given in a
12287 * number of different ways which effect its behaviour:
12289 * * `integer` - treated as an array index for the data source. This is the
12290 * default that DataTables uses (incrementally increased for each column).
12291 * * `string` - read an object property from the data source. There are
12292 * three 'special' options that can be used in the string to alter how
12293 * DataTables reads the data from the source object:
12294 * * `.` - Dotted Javascript notation. Just as you use a `.` in
12295 * Javascript to read from nested objects, so to can the options
12296 * specified in `data`. For example: `browser.version` or
12297 * `browser.name`. If your object parameter name contains a period, use
12298 * `\\` to escape it - i.e. `first\\.name`.
12299 * * `[]` - Array notation. DataTables can automatically combine data
12300 * from and array source, joining the data with the characters provided
12301 * between the two brackets. For example: `name[, ]` would provide a
12302 * comma-space separated list from the source array. If no characters
12303 * are provided between the brackets, the original array source is
12305 * * `()` - Function notation. Adding `()` to the end of a parameter will
12306 * execute a function of the name given. For example: `browser()` for a
12307 * simple function on the data source, `browser.version()` for a
12308 * function in a nested property or even `browser().version` to get an
12309 * object property if the function called returns an object. Note that
12310 * function notation is recommended for use in `render` rather than
12311 * `data` as it is much simpler to use as a renderer.
12312 * * `null` - use the original data source for the row rather than plucking
12313 * data directly from it. This action has effects on two other
12314 * initialisation options:
12315 * * `defaultContent` - When null is given as the `data` option and
12316 * `defaultContent` is specified for the column, the value defined by
12317 * `defaultContent` will be used for the cell.
12318 * * `render` - When null is used for the `data` option and the `render`
12319 * option is specified for the column, the whole data source for the
12320 * row is used for the renderer.
12321 * * `function` - the function given will be executed whenever DataTables
12322 * needs to set or get the data for a cell in the column. The function
12323 * takes three parameters:
12325 * * `{array|object}` The data source for the row
12326 * * `{string}` The type call data requested - this will be 'set' when
12327 * setting data or 'filter', 'display', 'type', 'sort' or undefined
12328 * when gathering data. Note that when `undefined` is given for the
12329 * type DataTables expects to get the raw data for the object back<
12330 * * `{*}` Data to set when the second parameter is 'set'.
12332 * * The return value from the function is not required when 'set' is
12333 * the type of call, but otherwise the return is what will be used
12334 * for the data requested.
12336 * Note that `data` is a getter and setter option. If you just require
12337 * formatting of data for output, you will likely want to use `render` which
12338 * is simply a getter and thus simpler to use.
12340 * Note that prior to DataTables 1.9.2 `data` was called `mDataProp`. The
12341 * name change reflects the flexibility of this property and is consistent
12342 * with the naming of mRender. If 'mDataProp' is given, then it will still
12343 * be used by DataTables, as it automatically maps the old name to the new
12346 * @type string|int|function|null
12347 * @default null <i>Use automatically calculated column index</i>
12349 * @name DataTable.defaults.column.data
12353 * // Read table data from objects
12354 * // JSON structure for each row:
12356 * // "engine": {value},
12357 * // "browser": {value},
12358 * // "platform": {value},
12359 * // "version": {value},
12360 * // "grade": {value}
12362 * $(document).ready( function() {
12363 * $('#example').dataTable( {
12364 * "ajaxSource": "sources/objects.txt",
12366 * { "data": "engine" },
12367 * { "data": "browser" },
12368 * { "data": "platform" },
12369 * { "data": "version" },
12370 * { "data": "grade" }
12376 * // Read information from deeply nested objects
12377 * // JSON structure for each row:
12379 * // "engine": {value},
12380 * // "browser": {value},
12382 * // "inner": {value}
12385 * // {value}, {value}
12388 * $(document).ready( function() {
12389 * $('#example').dataTable( {
12390 * "ajaxSource": "sources/deep.txt",
12392 * { "data": "engine" },
12393 * { "data": "browser" },
12394 * { "data": "platform.inner" },
12395 * { "data": "platform.details.0" },
12396 * { "data": "platform.details.1" }
12402 * // Using `data` as a function to provide different information for
12403 * // sorting, filtering and display. In this case, currency (price)
12404 * $(document).ready( function() {
12405 * $('#example').dataTable( {
12406 * "columnDefs": [ {
12407 * "targets": [ 0 ],
12408 * "data": function ( source, type, val ) {
12409 * if (type === 'set') {
12410 * source.price = val;
12411 * // Store the computed dislay and filter values for efficiency
12412 * source.price_display = val=="" ? "" : "$"+numberFormat(val);
12413 * source.price_filter = val=="" ? "" : "$"+numberFormat(val)+" "+val;
12416 * else if (type === 'display') {
12417 * return source.price_display;
12419 * else if (type === 'filter') {
12420 * return source.price_filter;
12422 * // 'sort', 'type' and undefined all just use the integer
12423 * return source.price;
12430 * // Using default content
12431 * $(document).ready( function() {
12432 * $('#example').dataTable( {
12433 * "columnDefs": [ {
12434 * "targets": [ 0 ],
12436 * "defaultContent": "Click to edit"
12442 * // Using array notation - outputting a list from an array
12443 * $(document).ready( function() {
12444 * $('#example').dataTable( {
12445 * "columnDefs": [ {
12446 * "targets": [ 0 ],
12447 * "data": "name[, ]"
12457 * This property is the rendering partner to `data` and it is suggested that
12458 * when you want to manipulate data for display (including filtering,
12459 * sorting etc) without altering the underlying data for the table, use this
12460 * property. `render` can be considered to be the the read only companion to
12461 * `data` which is read / write (then as such more complex). Like `data`
12462 * this option can be given in a number of different ways to effect its
12465 * * `integer` - treated as an array index for the data source. This is the
12466 * default that DataTables uses (incrementally increased for each column).
12467 * * `string` - read an object property from the data source. There are
12468 * three 'special' options that can be used in the string to alter how
12469 * DataTables reads the data from the source object:
12470 * * `.` - Dotted Javascript notation. Just as you use a `.` in
12471 * Javascript to read from nested objects, so to can the options
12472 * specified in `data`. For example: `browser.version` or
12473 * `browser.name`. If your object parameter name contains a period, use
12474 * `\\` to escape it - i.e. `first\\.name`.
12475 * * `[]` - Array notation. DataTables can automatically combine data
12476 * from and array source, joining the data with the characters provided
12477 * between the two brackets. For example: `name[, ]` would provide a
12478 * comma-space separated list from the source array. If no characters
12479 * are provided between the brackets, the original array source is
12481 * * `()` - Function notation. Adding `()` to the end of a parameter will
12482 * execute a function of the name given. For example: `browser()` for a
12483 * simple function on the data source, `browser.version()` for a
12484 * function in a nested property or even `browser().version` to get an
12485 * object property if the function called returns an object.
12486 * * `object` - use different data for the different data types requested by
12487 * DataTables ('filter', 'display', 'type' or 'sort'). The property names
12488 * of the object is the data type the property refers to and the value can
12489 * defined using an integer, string or function using the same rules as
12490 * `render` normally does. Note that an `_` option _must_ be specified.
12491 * This is the default value to use if you haven't specified a value for
12492 * the data type requested by DataTables.
12493 * * `function` - the function given will be executed whenever DataTables
12494 * needs to set or get the data for a cell in the column. The function
12495 * takes three parameters:
12497 * * {array|object} The data source for the row (based on `data`)
12498 * * {string} The type call data requested - this will be 'filter',
12499 * 'display', 'type' or 'sort'.
12500 * * {array|object} The full data source for the row (not based on
12503 * * The return value from the function is what will be used for the
12506 * @type string|int|function|object|null
12507 * @default null Use the data source value.
12509 * @name DataTable.defaults.column.render
12513 * // Create a comma separated list from an array of objects
12514 * $(document).ready( function() {
12515 * $('#example').dataTable( {
12516 * "ajaxSource": "sources/deep.txt",
12518 * { "data": "engine" },
12519 * { "data": "browser" },
12521 * "data": "platform",
12522 * "render": "[, ].name"
12529 * // Execute a function to obtain data
12530 * $(document).ready( function() {
12531 * $('#example').dataTable( {
12532 * "columnDefs": [ {
12533 * "targets": [ 0 ],
12534 * "data": null, // Use the full data source object for the renderer's source
12535 * "render": "browserName()"
12541 * // As an object, extracting different data for the different types
12542 * // This would be used with a data source such as:
12543 * // { "phone": 5552368, "phone_filter": "5552368 555-2368", "phone_display": "555-2368" }
12544 * // Here the `phone` integer is used for sorting and type detection, while `phone_filter`
12545 * // (which has both forms) is used for filtering for if a user inputs either format, while
12546 * // the formatted phone number is the one that is shown in the table.
12547 * $(document).ready( function() {
12548 * $('#example').dataTable( {
12549 * "columnDefs": [ {
12550 * "targets": [ 0 ],
12551 * "data": null, // Use the full data source object for the renderer's source
12554 * "filter": "phone_filter",
12555 * "display": "phone_display"
12562 * // Use as a function to create a link from the data source
12563 * $(document).ready( function() {
12564 * $('#example').dataTable( {
12565 * "columnDefs": [ {
12566 * "targets": [ 0 ],
12567 * "data": "download_link",
12568 * "render": function ( data, type, full ) {
12569 * return '<a href="'+data+'">Download</a>';
12579 * Change the cell type created for the column - either TD cells or TH cells. This
12580 * can be useful as TH cells have semantic meaning in the table body, allowing them
12581 * to act as a header for a row (you may wish to add scope='row' to the TH elements).
12585 * @name DataTable.defaults.column.cellType
12589 * // Make the first column use TH cells
12590 * $(document).ready( function() {
12591 * $('#example').dataTable( {
12592 * "columnDefs": [ {
12593 * "targets": [ 0 ],
12603 * Class to give to each cell in this column.
12605 * @default <i>Empty string</i>
12607 * @name DataTable.defaults.column.class
12611 * // Using `columnDefs`
12612 * $(document).ready( function() {
12613 * $('#example').dataTable( {
12615 * { "class": "my_class", "targets": [ 0 ] }
12621 * // Using `columns`
12622 * $(document).ready( function() {
12623 * $('#example').dataTable( {
12625 * { "class": "my_class" },
12637 * When DataTables calculates the column widths to assign to each column,
12638 * it finds the longest string in each column and then constructs a
12639 * temporary table and reads the widths from that. The problem with this
12640 * is that "mmm" is much wider then "iiii", but the latter is a longer
12641 * string - thus the calculation can go wrong (doing it properly and putting
12642 * it into an DOM object and measuring that is horribly(!) slow). Thus as
12643 * a "work around" we provide this option. It will append its value to the
12644 * text that is found to be the longest string for the column - i.e. padding.
12645 * Generally you shouldn't need this!
12647 * @default <i>Empty string<i>
12649 * @name DataTable.defaults.column.contentPadding
12653 * // Using `columns`
12654 * $(document).ready( function() {
12655 * $('#example').dataTable( {
12661 * "contentPadding": "mmm"
12667 "sContentPadding": "",
12671 * Allows a default value to be given for a column's data, and will be used
12672 * whenever a null data source is encountered (this can be because `data`
12673 * is set to null, or because the data source itself is null).
12677 * @name DataTable.defaults.column.defaultContent
12681 * // Using `columnDefs`
12682 * $(document).ready( function() {
12683 * $('#example').dataTable( {
12687 * "defaultContent": "Edit",
12688 * "targets": [ -1 ]
12695 * // Using `columns`
12696 * $(document).ready( function() {
12697 * $('#example').dataTable( {
12704 * "defaultContent": "Edit"
12710 "sDefaultContent": null,
12714 * This parameter is only used in DataTables' server-side processing. It can
12715 * be exceptionally useful to know what columns are being displayed on the
12716 * client side, and to map these to database fields. When defined, the names
12717 * also allow DataTables to reorder information from the server if it comes
12718 * back in an unexpected order (i.e. if you switch your columns around on the
12719 * client-side, your server-side code does not also need updating).
12721 * @default <i>Empty string</i>
12723 * @name DataTable.defaults.column.name
12727 * // Using `columnDefs`
12728 * $(document).ready( function() {
12729 * $('#example').dataTable( {
12731 * { "name": "engine", "targets": [ 0 ] },
12732 * { "name": "browser", "targets": [ 1 ] },
12733 * { "name": "platform", "targets": [ 2 ] },
12734 * { "name": "version", "targets": [ 3 ] },
12735 * { "name": "grade", "targets": [ 4 ] }
12741 * // Using `columns`
12742 * $(document).ready( function() {
12743 * $('#example').dataTable( {
12745 * { "name": "engine" },
12746 * { "name": "browser" },
12747 * { "name": "platform" },
12748 * { "name": "version" },
12749 * { "name": "grade" }
12758 * Defines a data source type for the ordering which can be used to read
12759 * real-time information from the table (updating the internally cached
12760 * version) prior to ordering. This allows ordering to occur on user
12761 * editable elements such as form inputs.
12765 * @name DataTable.defaults.column.orderDataType
12769 * // Using `columnDefs`
12770 * $(document).ready( function() {
12771 * $('#example').dataTable( {
12773 * { "orderDataType": "dom-text", "targets": [ 2, 3 ] },
12774 * { "type": "numeric", "targets": [ 3 ] },
12775 * { "orderDataType": "dom-select", "targets": [ 4 ] },
12776 * { "orderDataType": "dom-checkbox", "targets": [ 5 ] }
12782 * // Using `columns`
12783 * $(document).ready( function() {
12784 * $('#example').dataTable( {
12788 * { "orderDataType": "dom-text" },
12789 * { "orderDataType": "dom-text", "type": "numeric" },
12790 * { "orderDataType": "dom-select" },
12791 * { "orderDataType": "dom-checkbox" }
12796 "sSortDataType": "std",
12800 * The title of this column.
12802 * @default null <i>Derived from the 'TH' value for this column in the
12803 * original HTML table.</i>
12805 * @name DataTable.defaults.column.title
12809 * // Using `columnDefs`
12810 * $(document).ready( function() {
12811 * $('#example').dataTable( {
12813 * { "title": "My column title", "targets": [ 0 ] }
12819 * // Using `columns`
12820 * $(document).ready( function() {
12821 * $('#example').dataTable( {
12823 * { "title": "My column title" },
12836 * The type allows you to specify how the data for this column will be
12837 * ordered. Four types (string, numeric, date and html (which will strip
12838 * HTML tags before ordering)) are currently available. Note that only date
12839 * formats understood by Javascript's Date() object will be accepted as type
12840 * date. For example: "Mar 26, 2008 5:03 PM". May take the values: 'string',
12841 * 'numeric', 'date' or 'html' (by default). Further types can be adding
12842 * through plug-ins.
12844 * @default null <i>Auto-detected from raw data</i>
12846 * @name DataTable.defaults.column.type
12850 * // Using `columnDefs`
12851 * $(document).ready( function() {
12852 * $('#example').dataTable( {
12854 * { "type": "html", "targets": [ 0 ] }
12860 * // Using `columns`
12861 * $(document).ready( function() {
12862 * $('#example').dataTable( {
12864 * { "type": "html" },
12877 * Defining the width of the column, this parameter may take any CSS value
12878 * (3em, 20px etc). DataTables applies 'smart' widths to columns which have not
12879 * been given a specific width through this interface ensuring that the table
12880 * remains readable.
12882 * @default null <i>Automatic</i>
12884 * @name DataTable.defaults.column.width
12888 * // Using `columnDefs`
12889 * $(document).ready( function() {
12890 * $('#example').dataTable( {
12892 * { "width": "20%", "targets": [ 0 ] }
12898 * // Using `columns`
12899 * $(document).ready( function() {
12900 * $('#example').dataTable( {
12902 * { "width": "20%" },
12914 _fnHungarianMap( DataTable.defaults.column );
12919 * DataTables settings object - this holds all the information needed for a
12920 * given table, including configuration, data and current application of the
12921 * table options. DataTables does not have a single instance for each DataTable
12922 * with the settings attached to that instance, but rather instances of the
12923 * DataTable "class" are created on-the-fly as needed (typically by a
12924 * $().dataTable() call) and the settings object is then applied to that
12927 * Note that this object is related to {@link DataTable.defaults} but this
12928 * one is the internal data store for DataTables's cache of columns. It should
12929 * NOT be manipulated outside of DataTables. Any configuration should be done
12930 * through the initialisation options.
12932 * @todo Really should attach the settings object to individual instances so we
12933 * don't need to create new instances on each $().dataTable() call (if the
12934 * table already exists). It would also save passing oSettings around and
12935 * into every single function. However, this is a very significant
12936 * architecture change for DataTables and will almost certainly break
12937 * backwards compatibility with older installations. This is something that
12938 * will be done in 2.0.
12940 DataTable.models.oSettings = {
12942 * Primary features of DataTables and their enablement state.
12948 * Flag to say if DataTables should automatically try to calculate the
12949 * optimum table and columns widths (true) or not (false).
12950 * Note that this parameter will be set by the initialisation routine. To
12951 * set a default use {@link DataTable.defaults}.
12954 "bAutoWidth": null,
12957 * Delay the creation of TR and TD elements until they are actually
12958 * needed by a driven page draw. This can give a significant speed
12959 * increase for Ajax source and Javascript source data, but makes no
12960 * difference at all fro DOM and server-side processing tables.
12961 * Note that this parameter will be set by the initialisation routine. To
12962 * set a default use {@link DataTable.defaults}.
12965 "bDeferRender": null,
12968 * Enable filtering on the table or not. Note that if this is disabled
12969 * then there is no filtering at all on the table, including fnFilter.
12970 * To just remove the filtering input use sDom and remove the 'f' option.
12971 * Note that this parameter will be set by the initialisation routine. To
12972 * set a default use {@link DataTable.defaults}.
12978 * Table information element (the 'Showing x of y records' div) enable
12980 * Note that this parameter will be set by the initialisation routine. To
12981 * set a default use {@link DataTable.defaults}.
12987 * Present a user control allowing the end user to change the page size
12988 * when pagination is enabled.
12989 * Note that this parameter will be set by the initialisation routine. To
12990 * set a default use {@link DataTable.defaults}.
12993 "bLengthChange": null,
12996 * Pagination enabled or not. Note that if this is disabled then length
12997 * changing must also be disabled.
12998 * Note that this parameter will be set by the initialisation routine. To
12999 * set a default use {@link DataTable.defaults}.
13005 * Processing indicator enable flag whenever DataTables is enacting a
13006 * user request - typically an Ajax request for server-side processing.
13007 * Note that this parameter will be set by the initialisation routine. To
13008 * set a default use {@link DataTable.defaults}.
13011 "bProcessing": null,
13014 * Server-side processing enabled flag - when enabled DataTables will
13015 * get all data from the server for every draw - there is no filtering,
13016 * sorting or paging done on the client-side.
13017 * Note that this parameter will be set by the initialisation routine. To
13018 * set a default use {@link DataTable.defaults}.
13021 "bServerSide": null,
13024 * Sorting enablement flag.
13025 * Note that this parameter will be set by the initialisation routine. To
13026 * set a default use {@link DataTable.defaults}.
13032 * Multi-column sorting
13033 * Note that this parameter will be set by the initialisation routine. To
13034 * set a default use {@link DataTable.defaults}.
13037 "bSortMulti": null,
13040 * Apply a class to the columns which are being sorted to provide a
13041 * visual highlight or not. This can slow things down when enabled since
13042 * there is a lot of DOM interaction.
13043 * Note that this parameter will be set by the initialisation routine. To
13044 * set a default use {@link DataTable.defaults}.
13047 "bSortClasses": null,
13050 * State saving enablement flag.
13051 * Note that this parameter will be set by the initialisation routine. To
13052 * set a default use {@link DataTable.defaults}.
13060 * Scrolling settings for a table.
13065 * When the table is shorter in height than sScrollY, collapse the
13066 * table container down to the height of the table (when true).
13067 * Note that this parameter will be set by the initialisation routine. To
13068 * set a default use {@link DataTable.defaults}.
13074 * Width of the scrollbar for the web-browser's platform. Calculated
13075 * during table initialisation.
13082 * Viewport width for horizontal scrolling. Horizontal scrolling is
13083 * disabled if an empty string.
13084 * Note that this parameter will be set by the initialisation routine. To
13085 * set a default use {@link DataTable.defaults}.
13091 * Width to expand the table to when using x-scrolling. Typically you
13092 * should not need to use this.
13093 * Note that this parameter will be set by the initialisation routine. To
13094 * set a default use {@link DataTable.defaults}.
13101 * Viewport height for vertical scrolling. Vertical scrolling is disabled
13102 * if an empty string.
13103 * Note that this parameter will be set by the initialisation routine. To
13104 * set a default use {@link DataTable.defaults}.
13111 * Language information for the table.
13113 * @extends DataTable.defaults.oLanguage
13117 * Information callback function. See
13118 * {@link DataTable.defaults.fnInfoCallback}
13122 "fnInfoCallback": null
13126 * Browser support parameters
13131 * Indicate if the browser incorrectly calculates width:100% inside a
13132 * scrolling element (IE6/7)
13136 "bScrollOversize": false,
13139 * Determine if the vertical scrollbar is on the right or left of the
13140 * scrolling container - needed for rtl language layout, although not
13141 * all browsers move the scrollbar (Safari).
13145 "bScrollbarLeft": false,
13148 * Flag for if `getBoundingClientRect` is fully supported or not
13152 "bBounding": false,
13155 * Browser scrollbar width
13167 * Array referencing the nodes which are used for the features. The
13168 * parameters of this object match what is allowed by sDom - i.e.
13170 * <li>'l' - Length changing</li>
13171 * <li>'f' - Filtering input</li>
13172 * <li>'t' - The table!</li>
13173 * <li>'i' - Information</li>
13174 * <li>'p' - Pagination</li>
13175 * <li>'r' - pRocessing</li>
13183 * Store data information - see {@link DataTable.models.oRow} for detailed
13191 * Array of indexes which are in the current display (after filtering etc)
13198 * Array of indexes for display - no filtering
13202 "aiDisplayMaster": [],
13205 * Map of row ids to data indexes
13212 * Store information about each column that is in use
13219 * Store information about the table's header
13226 * Store information about the table's footer
13233 * Store the applied global search information in case we want to force a
13234 * research or compare the old search to a new one.
13235 * Note that this parameter will be set by the initialisation routine. To
13236 * set a default use {@link DataTable.defaults}.
13238 * @extends DataTable.models.oSearch
13240 "oPreviousSearch": {},
13243 * Store the applied search for each column - see
13244 * {@link DataTable.models.oSearch} for the format that is used for the
13245 * filtering information for each column.
13249 "aoPreSearchCols": [],
13252 * Sorting that is applied to the table. Note that the inner arrays are
13253 * used in the following manner:
13255 * <li>Index 0 - column number</li>
13256 * <li>Index 1 - current sorting direction</li>
13258 * Note that this parameter will be set by the initialisation routine. To
13259 * set a default use {@link DataTable.defaults}.
13261 * @todo These inner arrays should really be objects
13266 * Sorting that is always applied to the table (i.e. prefixed in front of
13268 * Note that this parameter will be set by the initialisation routine. To
13269 * set a default use {@link DataTable.defaults}.
13273 "aaSortingFixed": [],
13276 * Classes to use for the striping of a table.
13277 * Note that this parameter will be set by the initialisation routine. To
13278 * set a default use {@link DataTable.defaults}.
13282 "asStripeClasses": null,
13285 * If restoring a table - we should restore its striping classes as well
13289 "asDestroyStripes": [],
13292 * If restoring a table - we should restore its width
13296 "sDestroyWidth": 0,
13299 * Callback functions array for every time a row is inserted (i.e. on a draw).
13303 "aoRowCallback": [],
13306 * Callback functions for the header on each draw.
13310 "aoHeaderCallback": [],
13313 * Callback function for the footer on each draw.
13317 "aoFooterCallback": [],
13320 * Array of callback functions for draw callback functions
13324 "aoDrawCallback": [],
13327 * Array of callback functions for row created function
13331 "aoRowCreatedCallback": [],
13334 * Callback functions for just before the table is redrawn. A return of
13335 * false will be used to cancel the draw.
13339 "aoPreDrawCallback": [],
13342 * Callback functions for when the table has been initialised.
13346 "aoInitComplete": [],
13350 * Callbacks for modifying the settings to be stored for state saving, prior to
13355 "aoStateSaveParams": [],
13358 * Callbacks for modifying the settings that have been stored for state saving
13359 * prior to using the stored values to restore the state.
13363 "aoStateLoadParams": [],
13366 * Callbacks for operating on the settings object once the saved state has been
13371 "aoStateLoaded": [],
13374 * Cache the table ID for quick access
13376 * @default <i>Empty string</i>
13381 * The TABLE node for the main table
13388 * Permanent ref to the thead element
13395 * Permanent ref to the tfoot element - if it exists
13402 * Permanent ref to the tbody element
13409 * Cache the wrapper node (contains all DataTables controlled elements)
13413 "nTableWrapper": null,
13416 * Indicate if when using server-side processing the loading of data
13417 * should be deferred until the second draw.
13418 * Note that this parameter will be set by the initialisation routine. To
13419 * set a default use {@link DataTable.defaults}.
13423 "bDeferLoading": false,
13426 * Indicate if all required information has been read in
13430 "bInitialised": false,
13433 * Information about open rows. Each object in the array has the parameters
13434 * 'nTr' and 'nParent'
13441 * Dictate the positioning of DataTables' control elements - see
13442 * {@link DataTable.model.oInit.sDom}.
13443 * Note that this parameter will be set by the initialisation routine. To
13444 * set a default use {@link DataTable.defaults}.
13451 * Search delay (in mS)
13455 "searchDelay": null,
13458 * Which type of pagination should be used.
13459 * Note that this parameter will be set by the initialisation routine. To
13460 * set a default use {@link DataTable.defaults}.
13462 * @default two_button
13464 "sPaginationType": "two_button",
13467 * The state duration (for `stateSave`) in seconds.
13468 * Note that this parameter will be set by the initialisation routine. To
13469 * set a default use {@link DataTable.defaults}.
13473 "iStateDuration": 0,
13476 * Array of callback functions for state saving. Each array element is an
13477 * object with the following parameters:
13479 * <li>function:fn - function to call. Takes two parameters, oSettings
13480 * and the JSON string to save that has been thus far created. Returns
13481 * a JSON string to be inserted into a json object
13482 * (i.e. '"param": [ 0, 1, 2]')</li>
13483 * <li>string:sName - name of callback</li>
13491 * Array of callback functions for state loading. Each array element is an
13492 * object with the following parameters:
13494 * <li>function:fn - function to call. Takes two parameters, oSettings
13495 * and the object stored. May return false to cancel state loading</li>
13496 * <li>string:sName - name of callback</li>
13504 * State that was saved. Useful for back reference
13508 "oSavedState": null,
13511 * State that was loaded. Useful for back reference
13515 "oLoadedState": null,
13518 * Source url for AJAX data for the table.
13519 * Note that this parameter will be set by the initialisation routine. To
13520 * set a default use {@link DataTable.defaults}.
13524 "sAjaxSource": null,
13527 * Property from a given object from which to read the table data from. This
13528 * can be an empty string (when not server-side processing), in which case
13529 * it is assumed an an array is given directly.
13530 * Note that this parameter will be set by the initialisation routine. To
13531 * set a default use {@link DataTable.defaults}.
13534 "sAjaxDataProp": null,
13537 * Note if draw should be blocked while getting data
13541 "bAjaxDataGet": true,
13544 * The last jQuery XHR object that was used for server-side data gathering.
13545 * This can be used for working with the XHR information in one of the
13553 * JSON returned from the server in the last Ajax request
13555 * @default undefined
13560 * Data submitted as part of the last Ajax request
13562 * @default undefined
13564 "oAjaxData": undefined,
13567 * Function to get the server-side data.
13568 * Note that this parameter will be set by the initialisation routine. To
13569 * set a default use {@link DataTable.defaults}.
13572 "fnServerData": null,
13575 * Functions which are called prior to sending an Ajax request so extra
13576 * parameters can easily be sent to the server
13580 "aoServerParams": [],
13583 * Send the XHR HTTP method - GET or POST (could be PUT or DELETE if
13585 * Note that this parameter will be set by the initialisation routine. To
13586 * set a default use {@link DataTable.defaults}.
13589 "sServerMethod": null,
13592 * Format numbers for display.
13593 * Note that this parameter will be set by the initialisation routine. To
13594 * set a default use {@link DataTable.defaults}.
13597 "fnFormatNumber": null,
13600 * List of options that can be used for the user selectable length menu.
13601 * Note that this parameter will be set by the initialisation routine. To
13602 * set a default use {@link DataTable.defaults}.
13606 "aLengthMenu": null,
13609 * Counter for the draws that the table does. Also used as a tracker for
13610 * server-side processing
13617 * Indicate if a redraw is being done - useful for Ajax
13624 * Draw index (iDraw) of the last error when parsing the returned data
13631 * Paging display length
13635 "_iDisplayLength": 10,
13638 * Paging start point - aiDisplay index
13642 "_iDisplayStart": 0,
13645 * Server-side processing - number of records in the result set
13646 * (i.e. before filtering), Use fnRecordsTotal rather than
13647 * this property to get the value of the number of records, regardless of
13648 * the server-side processing setting.
13653 "_iRecordsTotal": 0,
13656 * Server-side processing - number of records in the current display set
13657 * (i.e. after filtering). Use fnRecordsDisplay rather than
13658 * this property to get the value of the number of records, regardless of
13659 * the server-side processing setting.
13664 "_iRecordsDisplay": 0,
13667 * Flag to indicate if jQuery UI marking and classes should be used.
13668 * Note that this parameter will be set by the initialisation routine. To
13669 * set a default use {@link DataTable.defaults}.
13675 * The classes to use for the table
13682 * Flag attached to the settings object so you can check in the draw
13683 * callback if filtering has been done in the draw. Deprecated in favour of
13689 "bFiltered": false,
13692 * Flag attached to the settings object so you can check in the draw
13693 * callback if sorting has been done in the draw. Deprecated in favour of
13702 * Indicate that if multiple rows are in the header and there is more than
13703 * one unique cell per column, if the top one (true) or bottom one (false)
13704 * should be used for sorting / title by DataTables.
13705 * Note that this parameter will be set by the initialisation routine. To
13706 * set a default use {@link DataTable.defaults}.
13709 "bSortCellsTop": null,
13712 * Initialisation object that is used for the table
13719 * Destroy callback functions - for plug-ins to attach themselves to the
13720 * destroy so they can clean up markup and events.
13724 "aoDestroyCallback": [],
13728 * Get the number of records in the current record set, before filtering
13731 "fnRecordsTotal": function ()
13733 return _fnDataSource( this ) == 'ssp' ?
13734 this._iRecordsTotal * 1 :
13735 this.aiDisplayMaster.length;
13739 * Get the number of records in the current record set, after filtering
13742 "fnRecordsDisplay": function ()
13744 return _fnDataSource( this ) == 'ssp' ?
13745 this._iRecordsDisplay * 1 :
13746 this.aiDisplay.length;
13750 * Get the display end point - aiDisplay index
13753 "fnDisplayEnd": function ()
13756 len = this._iDisplayLength,
13757 start = this._iDisplayStart,
13758 calc = start + len,
13759 records = this.aiDisplay.length,
13760 features = this.oFeatures,
13761 paginate = features.bPaginate;
13763 if ( features.bServerSide ) {
13764 return paginate === false || len === -1 ?
13766 Math.min( start+len, this._iRecordsDisplay );
13769 return ! paginate || calc>records || len===-1 ?
13776 * The DataTables object for this table
13783 * Unique identifier for each instance of the DataTables object. If there
13784 * is an ID on the table node, then it takes that value, otherwise an
13785 * incrementing internal counter is used.
13792 * tabindex attribute value that is added to DataTables control elements, allowing
13793 * keyboard navigation of the table and its controls.
13798 * DIV container for the footer scrolling table if scrolling
13800 "nScrollHead": null,
13803 * DIV container for the footer scrolling table if scrolling
13805 "nScrollFoot": null,
13808 * Last applied sort
13815 * Stored plug-in instances
13822 * Function used to get a row's id from the row's data
13829 * Data location where to store a row's id
13837 * Extension object for DataTables that is used to provide all extension
13840 * Note that the `DataTable.ext` object is available through
13841 * `jQuery.fn.dataTable.ext` where it may be accessed and manipulated. It is
13842 * also aliased to `jQuery.fn.dataTableExt` for historic reasons.
13844 * @extends DataTable.models.ext
13849 * DataTables extensions
13851 * This namespace acts as a collection area for plug-ins that can be used to
13852 * extend DataTables capabilities. Indeed many of the build in methods
13853 * use this method to provide their own capabilities (sorting methods for
13856 * Note that this namespace is aliased to `jQuery.fn.dataTableExt` for legacy
13861 DataTable.ext = _ext = {
13863 * Buttons. For use with the Buttons extension for DataTables. This is
13864 * defined here so other extensions can define buttons regardless of load
13865 * order. It is _not_ used by DataTables core.
13874 * Element class names
13883 * DataTables build type (expanded by the download builder)
13887 builder: "-source-",
13893 * How should DataTables report an error. Can take the value 'alert',
13894 * 'throw', 'none' or a function.
13896 * @type string|function
13903 * Feature plug-ins.
13905 * This is an array of objects which describe the feature plug-ins that are
13906 * available to DataTables. These feature plug-ins are then available for
13907 * use through the `dom` initialisation option.
13909 * Each feature plug-in is described by an object which must have the
13910 * following properties:
13912 * * `fnInit` - function that is used to initialise the plug-in,
13913 * * `cFeature` - a character so the feature can be enabled by the `dom`
13914 * instillation option. This is case sensitive.
13916 * The `fnInit` function has the following input parameters:
13918 * 1. `{object}` DataTables settings object: see
13919 * {@link DataTable.models.oSettings}
13921 * And the following return is expected:
13923 * * {node|null} The element which contains your feature. Note that the
13924 * return may also be void if your plug-in does not require to inject any
13925 * DOM elements into DataTables control (`dom`) - for example this might
13926 * be useful when developing a plug-in which allows table control via
13932 * $.fn.dataTable.ext.features.push( {
13933 * "fnInit": function( oSettings ) {
13934 * return new TableTools( { "oDTSettings": oSettings } );
13945 * This method of searching is complimentary to the default type based
13946 * searching, and a lot more comprehensive as it allows you complete control
13947 * over the searching logic. Each element in this array is a function
13948 * (parameters described below) that is called for every row in the table,
13949 * and your logic decides if it should be included in the searching data set
13952 * Searching functions have the following input parameters:
13954 * 1. `{object}` DataTables settings object: see
13955 * {@link DataTable.models.oSettings}
13956 * 2. `{array|object}` Data for the row to be processed (same as the
13957 * original format that was passed in as the data source, or an array
13958 * from a DOM data source
13959 * 3. `{int}` Row index ({@link DataTable.models.oSettings.aoData}), which
13960 * can be useful to retrieve the `TR` element if you need DOM interaction.
13962 * And the following return is expected:
13964 * * {boolean} Include the row in the searched result set (true) or not
13967 * Note that as with the main search ability in DataTables, technically this
13968 * is "filtering", since it is subtractive. However, for consistency in
13969 * naming we call it searching here.
13975 * // The following example shows custom search being applied to the
13976 * // fourth column (i.e. the data[3] index) based on two input values
13977 * // from the end-user, matching the data in a certain range.
13978 * $.fn.dataTable.ext.search.push(
13979 * function( settings, data, dataIndex ) {
13980 * var min = document.getElementById('min').value * 1;
13981 * var max = document.getElementById('max').value * 1;
13982 * var version = data[3] == "-" ? 0 : data[3]*1;
13984 * if ( min == "" && max == "" ) {
13987 * else if ( min == "" && version < max ) {
13990 * else if ( min < version && "" == max ) {
13993 * else if ( min < version && version < max ) {
14004 * Selector extensions
14006 * The `selector` option can be used to extend the options available for the
14007 * selector modifier options (`selector-modifier` object data type) that
14008 * each of the three built in selector types offer (row, column and cell +
14009 * their plural counterparts). For example the Select extension uses this
14010 * mechanism to provide an option to select only rows, columns and cells
14011 * that have been marked as selected by the end user (`{selected: true}`),
14012 * which can be used in conjunction with the existing built in selector
14015 * Each property is an array to which functions can be pushed. The functions
14016 * take three attributes:
14018 * * Settings object for the host table
14019 * * Options object (`selector-modifier` object type)
14020 * * Array of selected item indexes
14022 * The return is an array of the resulting item indexes after the custom
14023 * selector has been applied.
14035 * Internal functions, exposed for used in plug-ins.
14037 * Please note that you should not need to use the internal methods for
14038 * anything other than a plug-in (and even then, try to avoid if possible).
14039 * The internal function may change between releases.
14048 * Legacy configuration options. Enable and disable legacy options that
14049 * are available in DataTables.
14055 * Enable / disable DataTables 1.9 compatible server-side processing
14066 * Pagination plug-in methods.
14068 * Each entry in this object is a function and defines which buttons should
14069 * be shown by the pagination rendering method that is used for the table:
14070 * {@link DataTable.ext.renderer.pageButton}. The renderer addresses how the
14071 * buttons are displayed in the document, while the functions here tell it
14072 * what buttons to display. This is done by returning an array of button
14073 * descriptions (what each button will do).
14075 * Pagination types (the four built in options and any additional plug-in
14076 * options defined here) can be used through the `paginationType`
14077 * initialisation parameter.
14079 * The functions defined take two parameters:
14081 * 1. `{int} page` The current page index
14082 * 2. `{int} pages` The number of pages in the table
14084 * Each function is expected to return an array where each element of the
14085 * array can be one of:
14087 * * `first` - Jump to first page when activated
14088 * * `last` - Jump to last page when activated
14089 * * `previous` - Show previous page when activated
14090 * * `next` - Show next page when activated
14091 * * `{int}` - Show page of the index given
14092 * * `{array}` - A nested array containing the above elements to add a
14093 * containing 'DIV' element (might be useful for styling).
14095 * Note that DataTables v1.9- used this object slightly differently whereby
14096 * an object with two functions would be defined for each plug-in. That
14097 * ability is still supported by DataTables 1.10+ to provide backwards
14098 * compatibility, but this option of use is now decremented and no longer
14099 * documented in DataTables 1.10+.
14105 * // Show previous, next and current page buttons only
14106 * $.fn.dataTableExt.oPagination.current = function ( page, pages ) {
14107 * return [ 'previous', page, 'next' ];
14120 * Ordering plug-ins - custom data source
14122 * The extension options for ordering of data available here is complimentary
14123 * to the default type based ordering that DataTables typically uses. It
14124 * allows much greater control over the the data that is being used to
14125 * order a column, but is necessarily therefore more complex.
14127 * This type of ordering is useful if you want to do ordering based on data
14128 * live from the DOM (for example the contents of an 'input' element) rather
14129 * than just the static string that DataTables knows of.
14131 * The way these plug-ins work is that you create an array of the values you
14132 * wish to be ordering for the column in question and then return that
14133 * array. The data in the array much be in the index order of the rows in
14134 * the table (not the currently ordering order!). Which order data gathering
14135 * function is run here depends on the `dt-init columns.orderDataType`
14136 * parameter that is used for the column (if any).
14138 * The functions defined take two parameters:
14140 * 1. `{object}` DataTables settings object: see
14141 * {@link DataTable.models.oSettings}
14142 * 2. `{int}` Target column index
14144 * Each function is expected to return an array:
14146 * * `{array}` Data for the column to be ordering upon
14151 * // Ordering using `input` node values
14152 * $.fn.dataTable.ext.order['dom-text'] = function ( settings, col )
14154 * return this.api().column( col, {order:'index'} ).nodes().map( function ( td, i ) {
14155 * return $('input', td).val();
14163 * Type based plug-ins.
14165 * Each column in DataTables has a type assigned to it, either by automatic
14166 * detection or by direct assignment using the `type` option for the column.
14167 * The type of a column will effect how it is ordering and search (plug-ins
14168 * can also make use of the column type if required).
14174 * Type detection functions.
14176 * The functions defined in this object are used to automatically detect
14177 * a column's type, making initialisation of DataTables super easy, even
14178 * when complex data is in the table.
14180 * The functions defined take two parameters:
14182 * 1. `{*}` Data from the column cell to be analysed
14183 * 2. `{settings}` DataTables settings object. This can be used to
14184 * perform context specific type detection - for example detection
14185 * based on language settings such as using a comma for a decimal
14186 * place. Generally speaking the options from the settings will not
14189 * Each function is expected to return:
14191 * * `{string|null}` Data type detected, or null if unknown (and thus
14192 * pass it on to the other type detection functions.
14197 * // Currency type detection plug-in:
14198 * $.fn.dataTable.ext.type.detect.push(
14199 * function ( data, settings ) {
14200 * // Check the numeric part
14201 * if ( ! $.isNumeric( data.substring(1) ) ) {
14205 * // Check prefixed by currency
14206 * if ( data.charAt(0) == '$' || data.charAt(0) == '£' ) {
14207 * return 'currency';
14217 * Type based search formatting.
14219 * The type based searching functions can be used to pre-format the
14220 * data to be search on. For example, it can be used to strip HTML
14221 * tags or to de-format telephone numbers for numeric only searching.
14223 * Note that is a search is not defined for a column of a given type,
14224 * no search formatting will be performed.
14226 * Pre-processing of searching data plug-ins - When you assign the sType
14227 * for a column (or have it automatically detected for you by DataTables
14228 * or a type detection plug-in), you will typically be using this for
14229 * custom sorting, but it can also be used to provide custom searching
14230 * by allowing you to pre-processing the data and returning the data in
14231 * the format that should be searched upon. This is done by adding
14232 * functions this object with a parameter name which matches the sType
14233 * for that target column. This is the corollary of <i>afnSortData</i>
14234 * for searching data.
14236 * The functions defined take a single parameter:
14238 * 1. `{*}` Data from the column cell to be prepared for searching
14240 * Each function is expected to return:
14242 * * `{string|null}` Formatted string that will be used for the searching.
14248 * $.fn.dataTable.ext.type.search['title-numeric'] = function ( d ) {
14249 * return d.replace(/\n/g," ").replace( /<.*?>/g, "" );
14256 * Type based ordering.
14258 * The column type tells DataTables what ordering to apply to the table
14259 * when a column is sorted upon. The order for each type that is defined,
14260 * is defined by the functions available in this object.
14262 * Each ordering option can be described by three properties added to
14265 * * `{type}-pre` - Pre-formatting function
14266 * * `{type}-asc` - Ascending order function
14267 * * `{type}-desc` - Descending order function
14269 * All three can be used together, only `{type}-pre` or only
14270 * `{type}-asc` and `{type}-desc` together. It is generally recommended
14271 * that only `{type}-pre` is used, as this provides the optimal
14272 * implementation in terms of speed, although the others are provided
14273 * for compatibility with existing Javascript sort functions.
14275 * `{type}-pre`: Functions defined take a single parameter:
14277 * 1. `{*}` Data from the column cell to be prepared for ordering
14281 * * `{*}` Data to be sorted upon
14283 * `{type}-asc` and `{type}-desc`: Functions are typical Javascript sort
14284 * functions, taking two parameters:
14286 * 1. `{*}` Data to compare to the second parameter
14287 * 2. `{*}` Data to compare to the first parameter
14291 * * `{*}` Ordering match: <0 if first parameter should be sorted lower
14292 * than the second parameter, ===0 if the two parameters are equal and
14293 * >0 if the first parameter should be sorted height than the second
14300 * // Numeric ordering of formatted numbers with a pre-formatter
14301 * $.extend( $.fn.dataTable.ext.type.order, {
14302 * "string-pre": function(x) {
14303 * a = (a === "-" || a === "") ? 0 : a.replace( /[^\d\-\.]/g, "" );
14304 * return parseFloat( a );
14309 * // Case-sensitive string ordering, with no pre-formatting method
14310 * $.extend( $.fn.dataTable.ext.order, {
14311 * "string-case-asc": function(x,y) {
14312 * return ((x < y) ? -1 : ((x > y) ? 1 : 0));
14314 * "string-case-desc": function(x,y) {
14315 * return ((x < y) ? 1 : ((x > y) ? -1 : 0));
14323 * Unique DataTables instance counter
14333 // The following properties are retained for backwards compatiblity only.
14334 // The should not be used in new projects and will be removed in a future
14339 * Version check function.
14341 * @depreciated Since 1.10
14343 fnVersionCheck: DataTable.fnVersionCheck,
14347 * Index for what 'this' index API functions should use
14349 * @deprecated Since v1.10
14355 * jQuery UI class container
14357 * @deprecated Since v1.10
14365 * @deprecated Since v1.10
14367 sVersion: DataTable.version
14372 // Backwards compatibility. Alias to pre 1.10 Hungarian notation counter parts
14375 afnFiltering: _ext.search,
14376 aTypes: _ext.type.detect,
14377 ofnSearch: _ext.type.search,
14378 oSort: _ext.type.order,
14379 afnSortData: _ext.order,
14380 aoFeatures: _ext.feature,
14381 oApi: _ext.internal,
14382 oStdClasses: _ext.classes,
14383 oPagination: _ext.pager
14387 $.extend( DataTable.ext.classes, {
14388 "sTable": "dataTable",
14389 "sNoFooter": "no-footer",
14391 /* Paging buttons */
14392 "sPageButton": "paginate_button",
14393 "sPageButtonActive": "current",
14394 "sPageButtonDisabled": "disabled",
14396 /* Striping classes */
14397 "sStripeOdd": "odd",
14398 "sStripeEven": "even",
14401 "sRowEmpty": "dataTables_empty",
14404 "sWrapper": "dataTables_wrapper",
14405 "sFilter": "dataTables_filter",
14406 "sInfo": "dataTables_info",
14407 "sPaging": "dataTables_paginate paging_", /* Note that the type is postfixed */
14408 "sLength": "dataTables_length",
14409 "sProcessing": "dataTables_processing",
14412 "sSortAsc": "sorting_asc",
14413 "sSortDesc": "sorting_desc",
14414 "sSortable": "sorting", /* Sortable in both directions */
14415 "sSortableAsc": "sorting_asc_disabled",
14416 "sSortableDesc": "sorting_desc_disabled",
14417 "sSortableNone": "sorting_disabled",
14418 "sSortColumn": "sorting_", /* Note that an int is postfixed for the sorting order */
14421 "sFilterInput": "",
14424 "sLengthSelect": "",
14427 "sScrollWrapper": "dataTables_scroll",
14428 "sScrollHead": "dataTables_scrollHead",
14429 "sScrollHeadInner": "dataTables_scrollHeadInner",
14430 "sScrollBody": "dataTables_scrollBody",
14431 "sScrollFoot": "dataTables_scrollFoot",
14432 "sScrollFootInner": "dataTables_scrollFootInner",
14440 "sSortJUIDesc": "",
14442 "sSortJUIAscAllowed": "",
14443 "sSortJUIDescAllowed": "",
14444 "sSortJUIWrapper": "",
14453 // Reused strings for better compression. Closure compiler appears to have a
14454 // weird edge case where it is trying to expand strings rather than use the
14455 // variable version. This results in about 200 bytes being added, for very
14456 // little preference benefit since it this run on script load only.
14460 var _stateDefault = _empty + 'ui-state-default';
14461 var _sortIcon = _empty + 'css_right ui-icon ui-icon-';
14462 var _headerFooter = _empty + 'fg-toolbar ui-toolbar ui-widget-header ui-helper-clearfix';
14464 $.extend( DataTable.ext.oJUIClasses, DataTable.ext.classes, {
14465 /* Full numbers paging buttons */
14466 "sPageButton": "fg-button ui-button "+_stateDefault,
14467 "sPageButtonActive": "ui-state-disabled",
14468 "sPageButtonDisabled": "ui-state-disabled",
14471 "sPaging": "dataTables_paginate fg-buttonset ui-buttonset fg-buttonset-multi "+
14472 "ui-buttonset-multi paging_", /* Note that the type is postfixed */
14475 "sSortAsc": _stateDefault+" sorting_asc",
14476 "sSortDesc": _stateDefault+" sorting_desc",
14477 "sSortable": _stateDefault+" sorting",
14478 "sSortableAsc": _stateDefault+" sorting_asc_disabled",
14479 "sSortableDesc": _stateDefault+" sorting_desc_disabled",
14480 "sSortableNone": _stateDefault+" sorting_disabled",
14481 "sSortJUIAsc": _sortIcon+"triangle-1-n",
14482 "sSortJUIDesc": _sortIcon+"triangle-1-s",
14483 "sSortJUI": _sortIcon+"carat-2-n-s",
14484 "sSortJUIAscAllowed": _sortIcon+"carat-1-n",
14485 "sSortJUIDescAllowed": _sortIcon+"carat-1-s",
14486 "sSortJUIWrapper": "DataTables_sort_wrapper",
14487 "sSortIcon": "DataTables_sort_icon",
14490 "sScrollHead": "dataTables_scrollHead "+_stateDefault,
14491 "sScrollFoot": "dataTables_scrollFoot "+_stateDefault,
14494 "sHeaderTH": _stateDefault,
14495 "sFooterTH": _stateDefault,
14496 "sJUIHeader": _headerFooter+" ui-corner-tl ui-corner-tr",
14497 "sJUIFooter": _headerFooter+" ui-corner-bl ui-corner-br"
14504 var extPagination = DataTable.ext.pager;
14506 function _numbers ( page, pages ) {
14509 buttons = extPagination.numbers_length,
14510 half = Math.floor( buttons / 2 ),
14513 if ( pages <= buttons ) {
14514 numbers = _range( 0, pages );
14516 else if ( page <= half ) {
14517 numbers = _range( 0, buttons-2 );
14518 numbers.push( 'ellipsis' );
14519 numbers.push( pages-1 );
14521 else if ( page >= pages - 1 - half ) {
14522 numbers = _range( pages-(buttons-2), pages );
14523 numbers.splice( 0, 0, 'ellipsis' ); // no unshift in ie6
14524 numbers.splice( 0, 0, 0 );
14527 numbers = _range( page-half+2, page+half-1 );
14528 numbers.push( 'ellipsis' );
14529 numbers.push( pages-1 );
14530 numbers.splice( 0, 0, 'ellipsis' );
14531 numbers.splice( 0, 0, 0 );
14534 numbers.DT_el = 'span';
14539 $.extend( extPagination, {
14540 simple: function ( page, pages ) {
14541 return [ 'previous', 'next' ];
14544 full: function ( page, pages ) {
14545 return [ 'first', 'previous', 'next', 'last' ];
14548 numbers: function ( page, pages ) {
14549 return [ _numbers(page, pages) ];
14552 simple_numbers: function ( page, pages ) {
14553 return [ 'previous', _numbers(page, pages), 'next' ];
14556 full_numbers: function ( page, pages ) {
14557 return [ 'first', 'previous', _numbers(page, pages), 'next', 'last' ];
14560 first_last_numbers: function (page, pages) {
14561 return ['first', _numbers(page, pages), 'last'];
14564 // For testing and plug-ins to use
14565 _numbers: _numbers,
14567 // Number of number buttons (including ellipsis) to show. _Must be odd!_
14572 $.extend( true, DataTable.ext.renderer, {
14574 _: function ( settings, host, idx, buttons, page, pages ) {
14575 var classes = settings.oClasses;
14576 var lang = settings.oLanguage.oPaginate;
14577 var aria = settings.oLanguage.oAria.paginate || {};
14578 var btnDisplay, btnClass, counter=0;
14580 var attach = function( container, buttons ) {
14581 var i, ien, node, button;
14582 var clickHandler = function ( e ) {
14583 _fnPageChange( settings, e.data.action, true );
14586 for ( i=0, ien=buttons.length ; i<ien ; i++ ) {
14587 button = buttons[i];
14589 if ( $.isArray( button ) ) {
14590 var inner = $( '<'+(button.DT_el || 'div')+'/>' )
14591 .appendTo( container );
14592 attach( inner, button );
14598 switch ( button ) {
14600 container.append('<span class="ellipsis">…</span>');
14604 btnDisplay = lang.sFirst;
14605 btnClass = button + (page > 0 ?
14606 '' : ' '+classes.sPageButtonDisabled);
14610 btnDisplay = lang.sPrevious;
14611 btnClass = button + (page > 0 ?
14612 '' : ' '+classes.sPageButtonDisabled);
14616 btnDisplay = lang.sNext;
14617 btnClass = button + (page < pages-1 ?
14618 '' : ' '+classes.sPageButtonDisabled);
14622 btnDisplay = lang.sLast;
14623 btnClass = button + (page < pages-1 ?
14624 '' : ' '+classes.sPageButtonDisabled);
14628 btnDisplay = button + 1;
14629 btnClass = page === button ?
14630 classes.sPageButtonActive : '';
14634 if ( btnDisplay !== null ) {
14636 'class': classes.sPageButton+' '+btnClass,
14637 'aria-controls': settings.sTableId,
14638 'aria-label': aria[ button ],
14639 'data-dt-idx': counter,
14640 'tabindex': settings.iTabIndex,
14641 'id': idx === 0 && typeof button === 'string' ?
14642 settings.sTableId +'_'+ button :
14645 .html( btnDisplay )
14646 .appendTo( container );
14649 node, {action: button}, clickHandler
14658 // IE9 throws an 'unknown error' if document.activeElement is used
14659 // inside an iframe or frame. Try / catch the error. Not good for
14660 // accessibility, but neither are frames.
14664 // Because this approach is destroying and recreating the paging
14665 // elements, focus is lost on the select button which is bad for
14666 // accessibility. So we want to restore focus once the draw has
14668 activeEl = $(host).find(document.activeElement).data('dt-idx');
14672 attach( $(host).empty(), buttons );
14674 if ( activeEl !== undefined ) {
14675 $(host).find( '[data-dt-idx='+activeEl+']' ).focus();
14683 // Built in type detection. See model.ext.aTypes for information about
14684 // what is required from this methods.
14685 $.extend( DataTable.ext.type.detect, [
14686 // Plain numbers - first since V8 detects some plain numbers as dates
14687 // e.g. Date.parse('55') (but not all, e.g. Date.parse('22')...).
14688 function ( d, settings )
14690 var decimal = settings.oLanguage.sDecimal;
14691 return _isNumber( d, decimal ) ? 'num'+decimal : null;
14694 // Dates (only those recognised by the browser's Date.parse)
14695 function ( d, settings )
14697 // V8 tries _very_ hard to make a string passed into `Date.parse()`
14698 // valid, so we need to use a regex to restrict date formats. Use a
14699 // plug-in for anything other than ISO8601 style strings
14700 if ( d && !(d instanceof Date) && ! _re_date.test(d) ) {
14703 var parsed = Date.parse(d);
14704 return (parsed !== null && !isNaN(parsed)) || _empty(d) ? 'date' : null;
14707 // Formatted numbers
14708 function ( d, settings )
14710 var decimal = settings.oLanguage.sDecimal;
14711 return _isNumber( d, decimal, true ) ? 'num-fmt'+decimal : null;
14715 function ( d, settings )
14717 var decimal = settings.oLanguage.sDecimal;
14718 return _htmlNumeric( d, decimal ) ? 'html-num'+decimal : null;
14721 // HTML numeric, formatted
14722 function ( d, settings )
14724 var decimal = settings.oLanguage.sDecimal;
14725 return _htmlNumeric( d, decimal, true ) ? 'html-num-fmt'+decimal : null;
14728 // HTML (this is strict checking - there must be html)
14729 function ( d, settings )
14731 return _empty( d ) || (typeof d === 'string' && d.indexOf('<') !== -1) ?
14738 // Filter formatting functions. See model.ext.ofnSearch for information about
14739 // what is required from these methods.
14741 // Note that additional search methods are added for the html numbers and
14742 // html formatted numbers by `_addNumericSort()` when we know what the decimal
14746 $.extend( DataTable.ext.type.search, {
14747 html: function ( data ) {
14748 return _empty(data) ?
14750 typeof data === 'string' ?
14752 .replace( _re_new_lines, " " )
14753 .replace( _re_html, "" ) :
14757 string: function ( data ) {
14758 return _empty(data) ?
14760 typeof data === 'string' ?
14761 data.replace( _re_new_lines, " " ) :
14768 var __numericReplace = function ( d, decimalPlace, re1, re2 ) {
14769 if ( d !== 0 && (!d || d === '-') ) {
14773 // If a decimal place other than `.` is used, it needs to be given to the
14774 // function so we can detect it and replace with a `.` which is the only
14775 // decimal place Javascript recognises - it is not locale aware.
14776 if ( decimalPlace ) {
14777 d = _numToDecimal( d, decimalPlace );
14782 d = d.replace( re1, '' );
14786 d = d.replace( re2, '' );
14794 // Add the numeric 'deformatting' functions for sorting and search. This is done
14795 // in a function to provide an easy ability for the language options to add
14796 // additional methods if a non-period decimal place is used.
14797 function _addNumericSort ( decimalPlace ) {
14801 "num": function ( d ) {
14802 return __numericReplace( d, decimalPlace );
14805 // Formatted numbers
14806 "num-fmt": function ( d ) {
14807 return __numericReplace( d, decimalPlace, _re_formatted_numeric );
14811 "html-num": function ( d ) {
14812 return __numericReplace( d, decimalPlace, _re_html );
14815 // HTML numeric, formatted
14816 "html-num-fmt": function ( d ) {
14817 return __numericReplace( d, decimalPlace, _re_html, _re_formatted_numeric );
14820 function ( key, fn ) {
14821 // Add the ordering method
14822 _ext.type.order[ key+decimalPlace+'-pre' ] = fn;
14824 // For HTML types add a search formatter that will strip the HTML
14825 if ( key.match(/^html\-/) ) {
14826 _ext.type.search[ key+decimalPlace ] = _ext.type.search.html;
14833 // Default sort methods
14834 $.extend( _ext.type.order, {
14836 "date-pre": function ( d ) {
14837 return Date.parse( d ) || -Infinity;
14841 "html-pre": function ( a ) {
14845 a.replace( /<.*?>/g, "" ).toLowerCase() :
14850 "string-pre": function ( a ) {
14851 // This is a little complex, but faster than always calling toString,
14852 // http://jsperf.com/tostring-v-check
14855 typeof a === 'string' ?
14862 // string-asc and -desc are retained only for compatibility with the old
14864 "string-asc": function ( x, y ) {
14865 return ((x < y) ? -1 : ((x > y) ? 1 : 0));
14868 "string-desc": function ( x, y ) {
14869 return ((x < y) ? 1 : ((x > y) ? -1 : 0));
14874 // Numeric sorting types - order doesn't matter here
14875 _addNumericSort( '' );
14878 $.extend( true, DataTable.ext.renderer, {
14880 _: function ( settings, cell, column, classes ) {
14881 // No additional mark-up required
14882 // Attach a sort listener to update on sort - note that using the
14883 // `DT` namespace will allow the event to be removed automatically
14884 // on destroy, while the `dt` namespaced event is the one we are
14886 $(settings.nTable).on( 'order.dt.DT', function ( e, ctx, sorting, columns ) {
14887 if ( settings !== ctx ) { // need to check this this is the host
14888 return; // table, not a nested one
14891 var colIdx = column.idx;
14895 column.sSortingClass +' '+
14896 classes.sSortAsc +' '+
14899 .addClass( columns[ colIdx ] == 'asc' ?
14900 classes.sSortAsc : columns[ colIdx ] == 'desc' ?
14901 classes.sSortDesc :
14902 column.sSortingClass
14907 jqueryui: function ( settings, cell, column, classes ) {
14909 .addClass( classes.sSortJUIWrapper )
14910 .append( cell.contents() )
14911 .append( $('<span/>')
14912 .addClass( classes.sSortIcon+' '+column.sSortingClassJUI )
14916 // Attach a sort listener to update on sort
14917 $(settings.nTable).on( 'order.dt.DT', function ( e, ctx, sorting, columns ) {
14918 if ( settings !== ctx ) {
14922 var colIdx = column.idx;
14925 .removeClass( classes.sSortAsc +" "+classes.sSortDesc )
14926 .addClass( columns[ colIdx ] == 'asc' ?
14927 classes.sSortAsc : columns[ colIdx ] == 'desc' ?
14928 classes.sSortDesc :
14929 column.sSortingClass
14933 .find( 'span.'+classes.sSortIcon )
14935 classes.sSortJUIAsc +" "+
14936 classes.sSortJUIDesc +" "+
14937 classes.sSortJUI +" "+
14938 classes.sSortJUIAscAllowed +" "+
14939 classes.sSortJUIDescAllowed
14941 .addClass( columns[ colIdx ] == 'asc' ?
14942 classes.sSortJUIAsc : columns[ colIdx ] == 'desc' ?
14943 classes.sSortJUIDesc :
14944 column.sSortingClassJUI
14952 * Public helper functions. These aren't used internally by DataTables, or
14953 * called by any of the options passed into DataTables, but they can be used
14954 * externally by developers working with DataTables. They are helper functions
14955 * to make working with DataTables a little bit easier.
14958 var __htmlEscapeEntities = function ( d ) {
14959 return typeof d === 'string' ?
14960 d.replace(/</g, '<').replace(/>/g, '>').replace(/"/g, '"') :
14965 * Helpers for `columns.render`.
14967 * The options defined here can be used with the `columns.render` initialisation
14968 * option to provide a display renderer. The following functions are defined:
14970 * * `number` - Will format numeric data (defined by `columns.data`) for
14971 * display, retaining the original unformatted data for sorting and filtering.
14972 * It takes 5 parameters:
14973 * * `string` - Thousands grouping separator
14974 * * `string` - Decimal point indicator
14975 * * `integer` - Number of decimal points to show
14976 * * `string` (optional) - Prefix.
14977 * * `string` (optional) - Postfix (/suffix).
14978 * * `text` - Escape HTML to help prevent XSS attacks. It has no optional
14982 * // Column definition using the number renderer
14985 * render: $.fn.dataTable.render.number( '\'', '.', 0, '$' )
14990 DataTable.render = {
14991 number: function ( thousands, decimal, precision, prefix, postfix ) {
14993 display: function ( d ) {
14994 if ( typeof d !== 'number' && typeof d !== 'string' ) {
14998 var negative = d < 0 ? '-' : '';
14999 var flo = parseFloat( d );
15001 // If NaN then there isn't much formatting that we can do - just
15002 // return immediately, escaping any HTML (this was supposed to
15003 // be a number after all)
15004 if ( isNaN( flo ) ) {
15005 return __htmlEscapeEntities( d );
15008 flo = flo.toFixed( precision );
15009 d = Math.abs( flo );
15011 var intPart = parseInt( d, 10 );
15012 var floatPart = precision ?
15013 decimal+(d - intPart).toFixed( precision ).substring( 2 ):
15016 return negative + (prefix||'') +
15017 intPart.toString().replace(
15018 /\B(?=(\d{3})+(?!\d))/g, thousands
15026 text: function () {
15028 display: __htmlEscapeEntities
15035 * This is really a good bit rubbish this method of exposing the internal methods
15036 * publicly... - To be fixed in 2.0 using methods on the prototype
15041 * Create a wrapper function for exporting an internal functions to an external API.
15042 * @param {string} fn API function name
15043 * @returns {function} wrapped function
15044 * @memberof DataTable#internal
15046 function _fnExternApiFunc (fn)
15048 return function() {
15049 var args = [_fnSettingsFromNode( this[DataTable.ext.iApiIndex] )].concat(
15050 Array.prototype.slice.call(arguments)
15052 return DataTable.ext.internal[fn].apply( this, args );
15058 * Reference to internal functions for use by plug-in developers. Note that
15059 * these methods are references to internal functions and are considered to be
15060 * private. If you use these methods, be aware that they are liable to change
15061 * between versions.
15064 $.extend( DataTable.ext.internal, {
15065 _fnExternApiFunc: _fnExternApiFunc,
15066 _fnBuildAjax: _fnBuildAjax,
15067 _fnAjaxUpdate: _fnAjaxUpdate,
15068 _fnAjaxParameters: _fnAjaxParameters,
15069 _fnAjaxUpdateDraw: _fnAjaxUpdateDraw,
15070 _fnAjaxDataSrc: _fnAjaxDataSrc,
15071 _fnAddColumn: _fnAddColumn,
15072 _fnColumnOptions: _fnColumnOptions,
15073 _fnAdjustColumnSizing: _fnAdjustColumnSizing,
15074 _fnVisibleToColumnIndex: _fnVisibleToColumnIndex,
15075 _fnColumnIndexToVisible: _fnColumnIndexToVisible,
15076 _fnVisbleColumns: _fnVisbleColumns,
15077 _fnGetColumns: _fnGetColumns,
15078 _fnColumnTypes: _fnColumnTypes,
15079 _fnApplyColumnDefs: _fnApplyColumnDefs,
15080 _fnHungarianMap: _fnHungarianMap,
15081 _fnCamelToHungarian: _fnCamelToHungarian,
15082 _fnLanguageCompat: _fnLanguageCompat,
15083 _fnBrowserDetect: _fnBrowserDetect,
15084 _fnAddData: _fnAddData,
15085 _fnAddTr: _fnAddTr,
15086 _fnNodeToDataIndex: _fnNodeToDataIndex,
15087 _fnNodeToColumnIndex: _fnNodeToColumnIndex,
15088 _fnGetCellData: _fnGetCellData,
15089 _fnSetCellData: _fnSetCellData,
15090 _fnSplitObjNotation: _fnSplitObjNotation,
15091 _fnGetObjectDataFn: _fnGetObjectDataFn,
15092 _fnSetObjectDataFn: _fnSetObjectDataFn,
15093 _fnGetDataMaster: _fnGetDataMaster,
15094 _fnClearTable: _fnClearTable,
15095 _fnDeleteIndex: _fnDeleteIndex,
15096 _fnInvalidate: _fnInvalidate,
15097 _fnGetRowElements: _fnGetRowElements,
15098 _fnCreateTr: _fnCreateTr,
15099 _fnBuildHead: _fnBuildHead,
15100 _fnDrawHead: _fnDrawHead,
15102 _fnReDraw: _fnReDraw,
15103 _fnAddOptionsHtml: _fnAddOptionsHtml,
15104 _fnDetectHeader: _fnDetectHeader,
15105 _fnGetUniqueThs: _fnGetUniqueThs,
15106 _fnFeatureHtmlFilter: _fnFeatureHtmlFilter,
15107 _fnFilterComplete: _fnFilterComplete,
15108 _fnFilterCustom: _fnFilterCustom,
15109 _fnFilterColumn: _fnFilterColumn,
15110 _fnFilter: _fnFilter,
15111 _fnFilterCreateSearch: _fnFilterCreateSearch,
15112 _fnEscapeRegex: _fnEscapeRegex,
15113 _fnFilterData: _fnFilterData,
15114 _fnFeatureHtmlInfo: _fnFeatureHtmlInfo,
15115 _fnUpdateInfo: _fnUpdateInfo,
15116 _fnInfoMacros: _fnInfoMacros,
15117 _fnInitialise: _fnInitialise,
15118 _fnInitComplete: _fnInitComplete,
15119 _fnLengthChange: _fnLengthChange,
15120 _fnFeatureHtmlLength: _fnFeatureHtmlLength,
15121 _fnFeatureHtmlPaginate: _fnFeatureHtmlPaginate,
15122 _fnPageChange: _fnPageChange,
15123 _fnFeatureHtmlProcessing: _fnFeatureHtmlProcessing,
15124 _fnProcessingDisplay: _fnProcessingDisplay,
15125 _fnFeatureHtmlTable: _fnFeatureHtmlTable,
15126 _fnScrollDraw: _fnScrollDraw,
15127 _fnApplyToChildren: _fnApplyToChildren,
15128 _fnCalculateColumnWidths: _fnCalculateColumnWidths,
15129 _fnThrottle: _fnThrottle,
15130 _fnConvertToWidth: _fnConvertToWidth,
15131 _fnGetWidestNode: _fnGetWidestNode,
15132 _fnGetMaxLenString: _fnGetMaxLenString,
15133 _fnStringToCss: _fnStringToCss,
15134 _fnSortFlatten: _fnSortFlatten,
15136 _fnSortAria: _fnSortAria,
15137 _fnSortListener: _fnSortListener,
15138 _fnSortAttachListener: _fnSortAttachListener,
15139 _fnSortingClasses: _fnSortingClasses,
15140 _fnSortData: _fnSortData,
15141 _fnSaveState: _fnSaveState,
15142 _fnLoadState: _fnLoadState,
15143 _fnSettingsFromNode: _fnSettingsFromNode,
15146 _fnBindAction: _fnBindAction,
15147 _fnCallbackReg: _fnCallbackReg,
15148 _fnCallbackFire: _fnCallbackFire,
15149 _fnLengthOverflow: _fnLengthOverflow,
15150 _fnRenderer: _fnRenderer,
15151 _fnDataSource: _fnDataSource,
15152 _fnRowAttributes: _fnRowAttributes,
15153 _fnCalculateEnd: function () {} // Used by a lot of plug-ins, but redundant
15154 // in 1.10, so this dead-end function is
15155 // added to prevent errors
15160 $.fn.dataTable = DataTable;
15162 // Provide access to the host jQuery object (circular reference)
15166 $.fn.dataTableSettings = DataTable.settings;
15167 $.fn.dataTableExt = DataTable.ext;
15169 // With a capital `D` we return a DataTables API instance rather than a
15171 $.fn.DataTable = function ( opts ) {
15172 return $(this).dataTable( opts ).api();
15175 // All properties that are available to $.fn.dataTable should also be
15176 // available on $.fn.DataTable
15177 $.each( DataTable, function ( prop, val ) {
15178 $.fn.DataTable[ prop ] = val;
15182 // Information about events fired by DataTables - for documentation.
15184 * Draw event, fired whenever the table is redrawn on the page, at the same
15185 * point as fnDrawCallback. This may be useful for binding events or
15186 * performing calculations when the table is altered at all.
15187 * @name DataTable#draw.dt
15189 * @param {event} e jQuery event object
15190 * @param {object} o DataTables settings object {@link DataTable.models.oSettings}
15194 * Search event, fired when the searching applied to the table (using the
15195 * built-in global search, or column filters) is altered.
15196 * @name DataTable#search.dt
15198 * @param {event} e jQuery event object
15199 * @param {object} o DataTables settings object {@link DataTable.models.oSettings}
15203 * Page change event, fired when the paging of the table is altered.
15204 * @name DataTable#page.dt
15206 * @param {event} e jQuery event object
15207 * @param {object} o DataTables settings object {@link DataTable.models.oSettings}
15211 * Order event, fired when the ordering applied to the table is altered.
15212 * @name DataTable#order.dt
15214 * @param {event} e jQuery event object
15215 * @param {object} o DataTables settings object {@link DataTable.models.oSettings}
15219 * DataTables initialisation complete event, fired when the table is fully
15220 * drawn, including Ajax data loaded, if Ajax data is required.
15221 * @name DataTable#init.dt
15223 * @param {event} e jQuery event object
15224 * @param {object} oSettings DataTables settings object
15225 * @param {object} json The JSON object request from the server - only
15226 * present if client-side Ajax sourced data is used</li></ol>
15230 * State save event, fired when the table has changed state a new state save
15231 * is required. This event allows modification of the state saving object
15232 * prior to actually doing the save, including addition or other state
15233 * properties (for plug-ins) or modification of a DataTables core property.
15234 * @name DataTable#stateSaveParams.dt
15236 * @param {event} e jQuery event object
15237 * @param {object} oSettings DataTables settings object
15238 * @param {object} json The state information to be saved
15242 * State load event, fired when the table is loading state from the stored
15243 * data, but prior to the settings object being modified by the saved state
15244 * - allowing modification of the saved state is required or loading of
15245 * state for a plug-in.
15246 * @name DataTable#stateLoadParams.dt
15248 * @param {event} e jQuery event object
15249 * @param {object} oSettings DataTables settings object
15250 * @param {object} json The saved state information
15254 * State loaded event, fired when state has been loaded from stored data and
15255 * the settings object has been modified by the loaded data.
15256 * @name DataTable#stateLoaded.dt
15258 * @param {event} e jQuery event object
15259 * @param {object} oSettings DataTables settings object
15260 * @param {object} json The saved state information
15264 * Processing event, fired when DataTables is doing some kind of processing
15265 * (be it, order, searcg or anything else). It can be used to indicate to
15266 * the end user that there is something happening, or that something has
15268 * @name DataTable#processing.dt
15270 * @param {event} e jQuery event object
15271 * @param {object} oSettings DataTables settings object
15272 * @param {boolean} bShow Flag for if DataTables is doing processing or not
15276 * Ajax (XHR) event, fired whenever an Ajax request is completed from a
15277 * request to made to the server for new data. This event is called before
15278 * DataTables processed the returned data, so it can also be used to pre-
15279 * process the data returned from the server, if needed.
15281 * Note that this trigger is called in `fnServerData`, if you override
15282 * `fnServerData` and which to use this event, you need to trigger it in you
15283 * success function.
15284 * @name DataTable#xhr.dt
15286 * @param {event} e jQuery event object
15287 * @param {object} o DataTables settings object {@link DataTable.models.oSettings}
15288 * @param {object} json JSON returned from the server
15291 * // Use a custom property returned from the server in another DOM element
15292 * $('#table').dataTable().on('xhr.dt', function (e, settings, json) {
15293 * $('#status').html( json.status );
15297 * // Pre-process the data returned from the server
15298 * $('#table').dataTable().on('xhr.dt', function (e, settings, json) {
15299 * for ( var i=0, ien=json.aaData.length ; i<ien ; i++ ) {
15300 * json.aaData[i].sum = json.aaData[i].one + json.aaData[i].two;
15302 * // Note no return - manipulate the data directly in the JSON object.
15307 * Destroy event, fired when the DataTable is destroyed by calling fnDestroy
15308 * or passing the bDestroy:true parameter in the initialisation object. This
15309 * can be used to remove bound events, added DOM nodes, etc.
15310 * @name DataTable#destroy.dt
15312 * @param {event} e jQuery event object
15313 * @param {object} o DataTables settings object {@link DataTable.models.oSettings}
15317 * Page length change event, fired when number of records to show on each
15318 * page (the length) is changed.
15319 * @name DataTable#length.dt
15321 * @param {event} e jQuery event object
15322 * @param {object} o DataTables settings object {@link DataTable.models.oSettings}
15323 * @param {integer} len New length
15327 * Column sizing has changed.
15328 * @name DataTable#column-sizing.dt
15330 * @param {event} e jQuery event object
15331 * @param {object} o DataTables settings object {@link DataTable.models.oSettings}
15335 * Column visibility has changed.
15336 * @name DataTable#column-visibility.dt
15338 * @param {event} e jQuery event object
15339 * @param {object} o DataTables settings object {@link DataTable.models.oSettings}
15340 * @param {int} column Column index
15341 * @param {bool} vis `false` if column now hidden, or `true` if visible
15344 return $.fn.dataTable;