1 /*! DataTables 1.10.11
\r
2 * ©2008-2015 SpryMedia Ltd - datatables.net/license
\r
6 * @summary DataTables
\r
7 * @description Paginate, search and order HTML tables
\r
9 * @file jquery.dataTables.js
\r
10 * @author SpryMedia Ltd (www.sprymedia.co.uk)
\r
11 * @contact www.sprymedia.co.uk/contact
\r
12 * @copyright Copyright 2008-2015 SpryMedia Ltd.
\r
14 * This source file is free software, available under the following license:
\r
15 * MIT license - http://datatables.net/license
\r
17 * This source file is distributed in the hope that it will be useful, but
\r
18 * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
\r
19 * or FITNESS FOR A PARTICULAR PURPOSE. See the license files for details.
\r
21 * For details please refer to: http://www.datatables.net
\r
24 /*jslint evil: true, undef: true, browser: true */
\r
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*/
\r
27 (function( factory ) {
\r
30 if ( typeof define === 'function' && define.amd ) {
\r
32 define( ['jquery'], function ( $ ) {
\r
33 return factory( $, window, document );
\r
36 else if ( typeof exports === 'object' ) {
\r
38 module.exports = function (root, $) {
\r
40 // CommonJS environments without a window global must pass a
\r
41 // root. This will give an error otherwise
\r
46 $ = typeof window !== 'undefined' ? // jQuery's factory checks for a global window
\r
48 require('jquery')( root );
\r
51 return factory( $, root, root.document );
\r
56 factory( jQuery, window, document );
\r
59 (function( $, window, document, undefined ) {
\r
63 * DataTables is a plug-in for the jQuery Javascript library. It is a highly
\r
64 * flexible tool, based upon the foundations of progressive enhancement,
\r
65 * which will add advanced interaction controls to any HTML table. For a
\r
66 * full list of features please refer to
\r
67 * [DataTables.net](href="http://datatables.net).
\r
69 * Note that the `DataTable` object is not a global variable but is aliased
\r
70 * to `jQuery.fn.DataTable` and `jQuery.fn.dataTable` through which it may
\r
74 * @param {object} [init={}] Configuration object for DataTables. Options
\r
75 * are defined by {@link DataTable.defaults}
\r
76 * @requires jQuery 1.7+
\r
79 * // Basic initialisation
\r
80 * $(document).ready( function {
\r
81 * $('#example').dataTable();
\r
85 * // Initialisation with configuration options - in this case, disable
\r
86 * // pagination and sorting.
\r
87 * $(document).ready( function {
\r
88 * $('#example').dataTable( {
\r
89 * "paginate": false,
\r
98 * It is useful to have variables which are scoped locally so only the
\r
99 * DataTables functions can access them and they don't leak into global space.
\r
100 * At the same time these functions are often useful over multiple files in the
\r
101 * core and API, so we list, or at least document, all variables which are used
\r
102 * by DataTables as private variables here. This also ensures that there is no
\r
103 * clashing of variable names and that they can easily referenced for reuse.
\r
107 // Defined else where
\r
111 // _selector_row_indexes
\r
113 var _ext; // DataTable.ext
\r
114 var _Api; // DataTable.Api
\r
115 var _api_register; // DataTable.Api.register
\r
116 var _api_registerPlural; // DataTable.Api.registerPlural
\r
119 var _re_new_lines = /[\r\n]/g;
\r
120 var _re_html = /<.*?>/g;
\r
121 var _re_date_start = /^[\w\+\-]/;
\r
122 var _re_date_end = /[\w\+\-]$/;
\r
124 // Escape regular expression special characters
\r
125 var _re_escape_regex = new RegExp( '(\\' + [ '/', '.', '*', '+', '?', '|', '(', ')', '[', ']', '{', '}', '\\', '$', '^', '-' ].join('|\\') + ')', 'g' );
\r
127 // http://en.wikipedia.org/wiki/Foreign_exchange_market
\r
128 // - \u20BD - Russian ruble.
\r
129 // - \u20a9 - South Korean Won
\r
130 // - \u20BA - Turkish Lira
\r
131 // - \u20B9 - Indian Rupee
\r
132 // - R - Brazil (R$) and South Africa
\r
133 // - fr - Swiss Franc
\r
134 // - kr - Swedish krona, Norwegian krone and Danish krone
\r
135 // - \u2009 is thin space and \u202F is narrow no-break space, both used in many
\r
136 // standards as thousands separators.
\r
137 var _re_formatted_numeric = /[',$£€¥%\u2009\u202F\u20BD\u20a9\u20BArfk]/gi;
\r
140 var _empty = function ( d ) {
\r
141 return !d || d === true || d === '-' ? true : false;
\r
145 var _intVal = function ( s ) {
\r
146 var integer = parseInt( s, 10 );
\r
147 return !isNaN(integer) && isFinite(s) ? integer : null;
\r
150 // Convert from a formatted number with characters other than `.` as the
\r
151 // decimal place, to a Javascript number
\r
152 var _numToDecimal = function ( num, decimalPoint ) {
\r
153 // Cache created regular expressions for speed as this function is called often
\r
154 if ( ! _re_dic[ decimalPoint ] ) {
\r
155 _re_dic[ decimalPoint ] = new RegExp( _fnEscapeRegex( decimalPoint ), 'g' );
\r
157 return typeof num === 'string' && decimalPoint !== '.' ?
\r
158 num.replace( /\./g, '' ).replace( _re_dic[ decimalPoint ], '.' ) :
\r
163 var _isNumber = function ( d, decimalPoint, formatted ) {
\r
164 var strType = typeof d === 'string';
\r
166 // If empty return immediately so there must be a number if it is a
\r
167 // formatted string (this stops the string "k", or "kr", etc being detected
\r
168 // as a formatted number for currency
\r
169 if ( _empty( d ) ) {
\r
173 if ( decimalPoint && strType ) {
\r
174 d = _numToDecimal( d, decimalPoint );
\r
177 if ( formatted && strType ) {
\r
178 d = d.replace( _re_formatted_numeric, '' );
\r
181 return !isNaN( parseFloat(d) ) && isFinite( d );
\r
185 // A string without HTML in it can be considered to be HTML still
\r
186 var _isHtml = function ( d ) {
\r
187 return _empty( d ) || typeof d === 'string';
\r
191 var _htmlNumeric = function ( d, decimalPoint, formatted ) {
\r
192 if ( _empty( d ) ) {
\r
196 var html = _isHtml( d );
\r
199 _isNumber( _stripHtml( d ), decimalPoint, formatted ) ?
\r
205 var _pluck = function ( a, prop, prop2 ) {
\r
207 var i=0, ien=a.length;
\r
209 // Could have the test in the loop for slightly smaller code, but speed
\r
210 // is essential here
\r
211 if ( prop2 !== undefined ) {
\r
212 for ( ; i<ien ; i++ ) {
\r
213 if ( a[i] && a[i][ prop ] ) {
\r
214 out.push( a[i][ prop ][ prop2 ] );
\r
219 for ( ; i<ien ; i++ ) {
\r
221 out.push( a[i][ prop ] );
\r
230 // Basically the same as _pluck, but rather than looping over `a` we use `order`
\r
231 // as the indexes to pick from `a`
\r
232 var _pluck_order = function ( a, order, prop, prop2 )
\r
235 var i=0, ien=order.length;
\r
237 // Could have the test in the loop for slightly smaller code, but speed
\r
238 // is essential here
\r
239 if ( prop2 !== undefined ) {
\r
240 for ( ; i<ien ; i++ ) {
\r
241 if ( a[ order[i] ][ prop ] ) {
\r
242 out.push( a[ order[i] ][ prop ][ prop2 ] );
\r
247 for ( ; i<ien ; i++ ) {
\r
248 out.push( a[ order[i] ][ prop ] );
\r
256 var _range = function ( len, start )
\r
261 if ( start === undefined ) {
\r
270 for ( var i=start ; i<end ; i++ ) {
\r
278 var _removeEmpty = function ( a )
\r
282 for ( var i=0, ien=a.length ; i<ien ; i++ ) {
\r
283 if ( a[i] ) { // careful - will remove all falsy values!
\r
292 var _stripHtml = function ( d ) {
\r
293 return d.replace( _re_html, '' );
\r
298 * Find the unique elements in a source array.
\r
300 * @param {array} src Source array
\r
301 * @return {array} Array of unique items
\r
304 var _unique = function ( src )
\r
306 // A faster unique method is to use object keys to identify used values,
\r
307 // but this doesn't work with arrays or objects, which we must also
\r
308 // consider. See jsperf.com/compare-array-unique-versions/4 for more
\r
316 again: for ( i=0 ; i<ien ; i++ ) {
\r
319 for ( j=0 ; j<k ; j++ ) {
\r
320 if ( out[j] === val ) {
\r
335 * Create a mapping object that allows camel case parameters to be looked up
\r
336 * for their Hungarian counterparts. The mapping is stored in a private
\r
337 * parameter called `_hungarianMap` which can be accessed on the source object.
\r
338 * @param {object} o
\r
339 * @memberof DataTable#oApi
\r
341 function _fnHungarianMap ( o )
\r
344 hungarian = 'a aa ai ao as b fn i m o s ',
\r
349 $.each( o, function (key, val) {
\r
350 match = key.match(/^([^A-Z]+?)([A-Z])/);
\r
352 if ( match && hungarian.indexOf(match[1]+' ') !== -1 )
\r
354 newKey = key.replace( match[0], match[2].toLowerCase() );
\r
355 map[ newKey ] = key;
\r
357 if ( match[1] === 'o' )
\r
359 _fnHungarianMap( o[key] );
\r
364 o._hungarianMap = map;
\r
369 * Convert from camel case parameters to Hungarian, based on a Hungarian map
\r
370 * created by _fnHungarianMap.
\r
371 * @param {object} src The model object which holds all parameters that can be
\r
373 * @param {object} user The object to convert from camel case to Hungarian.
\r
374 * @param {boolean} force When set to `true`, properties which already have a
\r
375 * Hungarian value in the `user` object will be overwritten. Otherwise they
\r
377 * @memberof DataTable#oApi
\r
379 function _fnCamelToHungarian ( src, user, force )
\r
381 if ( ! src._hungarianMap ) {
\r
382 _fnHungarianMap( src );
\r
387 $.each( user, function (key, val) {
\r
388 hungarianKey = src._hungarianMap[ key ];
\r
390 if ( hungarianKey !== undefined && (force || user[hungarianKey] === undefined) )
\r
392 // For objects, we need to buzz down into the object to copy parameters
\r
393 if ( hungarianKey.charAt(0) === 'o' )
\r
395 // Copy the camelCase options over to the hungarian
\r
396 if ( ! user[ hungarianKey ] ) {
\r
397 user[ hungarianKey ] = {};
\r
399 $.extend( true, user[hungarianKey], user[key] );
\r
401 _fnCamelToHungarian( src[hungarianKey], user[hungarianKey], force );
\r
404 user[hungarianKey] = user[ key ];
\r
412 * Language compatibility - when certain options are given, and others aren't, we
\r
413 * need to duplicate the values over, in order to provide backwards compatibility
\r
414 * with older language files.
\r
415 * @param {object} oSettings dataTables settings object
\r
416 * @memberof DataTable#oApi
\r
418 function _fnLanguageCompat( lang )
\r
420 var defaults = DataTable.defaults.oLanguage;
\r
421 var zeroRecords = lang.sZeroRecords;
\r
423 /* Backwards compatibility - if there is no sEmptyTable given, then use the same as
\r
424 * sZeroRecords - assuming that is given.
\r
426 if ( ! lang.sEmptyTable && zeroRecords &&
\r
427 defaults.sEmptyTable === "No data available in table" )
\r
429 _fnMap( lang, lang, 'sZeroRecords', 'sEmptyTable' );
\r
432 /* Likewise with loading records */
\r
433 if ( ! lang.sLoadingRecords && zeroRecords &&
\r
434 defaults.sLoadingRecords === "Loading..." )
\r
436 _fnMap( lang, lang, 'sZeroRecords', 'sLoadingRecords' );
\r
439 // Old parameter name of the thousands separator mapped onto the new
\r
440 if ( lang.sInfoThousands ) {
\r
441 lang.sThousands = lang.sInfoThousands;
\r
444 var decimal = lang.sDecimal;
\r
446 _addNumericSort( decimal );
\r
452 * Map one parameter onto another
\r
453 * @param {object} o Object to map
\r
454 * @param {*} knew The new parameter name
\r
455 * @param {*} old The old parameter name
\r
457 var _fnCompatMap = function ( o, knew, old ) {
\r
458 if ( o[ knew ] !== undefined ) {
\r
459 o[ old ] = o[ knew ];
\r
465 * Provide backwards compatibility for the main DT options. Note that the new
\r
466 * options are mapped onto the old parameters, so this is an external interface
\r
468 * @param {object} init Object to map
\r
470 function _fnCompatOpts ( init )
\r
472 _fnCompatMap( init, 'ordering', 'bSort' );
\r
473 _fnCompatMap( init, 'orderMulti', 'bSortMulti' );
\r
474 _fnCompatMap( init, 'orderClasses', 'bSortClasses' );
\r
475 _fnCompatMap( init, 'orderCellsTop', 'bSortCellsTop' );
\r
476 _fnCompatMap( init, 'order', 'aaSorting' );
\r
477 _fnCompatMap( init, 'orderFixed', 'aaSortingFixed' );
\r
478 _fnCompatMap( init, 'paging', 'bPaginate' );
\r
479 _fnCompatMap( init, 'pagingType', 'sPaginationType' );
\r
480 _fnCompatMap( init, 'pageLength', 'iDisplayLength' );
\r
481 _fnCompatMap( init, 'searching', 'bFilter' );
\r
483 // Boolean initialisation of x-scrolling
\r
484 if ( typeof init.sScrollX === 'boolean' ) {
\r
485 init.sScrollX = init.sScrollX ? '100%' : '';
\r
487 if ( typeof init.scrollX === 'boolean' ) {
\r
488 init.scrollX = init.scrollX ? '100%' : '';
\r
491 // Column search objects are in an array, so it needs to be converted
\r
492 // element by element
\r
493 var searchCols = init.aoSearchCols;
\r
495 if ( searchCols ) {
\r
496 for ( var i=0, ien=searchCols.length ; i<ien ; i++ ) {
\r
497 if ( searchCols[i] ) {
\r
498 _fnCamelToHungarian( DataTable.models.oSearch, searchCols[i] );
\r
506 * Provide backwards compatibility for column options. Note that the new options
\r
507 * are mapped onto the old parameters, so this is an external interface change
\r
509 * @param {object} init Object to map
\r
511 function _fnCompatCols ( init )
\r
513 _fnCompatMap( init, 'orderable', 'bSortable' );
\r
514 _fnCompatMap( init, 'orderData', 'aDataSort' );
\r
515 _fnCompatMap( init, 'orderSequence', 'asSorting' );
\r
516 _fnCompatMap( init, 'orderDataType', 'sortDataType' );
\r
518 // orderData can be given as an integer
\r
519 var dataSort = init.aDataSort;
\r
520 if ( dataSort && ! $.isArray( dataSort ) ) {
\r
521 init.aDataSort = [ dataSort ];
\r
527 * Browser feature detection for capabilities, quirks
\r
528 * @param {object} settings dataTables settings object
\r
529 * @memberof DataTable#oApi
\r
531 function _fnBrowserDetect( settings )
\r
533 // We don't need to do this every time DataTables is constructed, the values
\r
534 // calculated are specific to the browser and OS configuration which we
\r
535 // don't expect to change between initialisations
\r
536 if ( ! DataTable.__browser ) {
\r
538 DataTable.__browser = browser;
\r
540 // Scrolling feature / quirks detection
\r
541 var n = $('<div/>')
\r
553 position: 'absolute',
\r
567 .appendTo( 'body' );
\r
569 var outer = n.children();
\r
570 var inner = outer.children();
\r
572 // Numbers below, in order, are:
\r
573 // inner.offsetWidth, inner.clientWidth, outer.offsetWidth, outer.clientWidth
\r
575 // IE6 XP: 100 100 100 83
\r
576 // IE7 Vista: 100 100 100 83
\r
577 // IE 8+ Windows: 83 83 100 83
\r
578 // Evergreen Windows: 83 83 100 83
\r
579 // Evergreen Mac with scrollbars: 85 85 100 85
\r
580 // Evergreen Mac without scrollbars: 100 100 100 100
\r
582 // Get scrollbar width
\r
583 browser.barWidth = outer[0].offsetWidth - outer[0].clientWidth;
\r
585 // IE6/7 will oversize a width 100% element inside a scrolling element, to
\r
586 // include the width of the scrollbar, while other browsers ensure the inner
\r
587 // element is contained without forcing scrolling
\r
588 browser.bScrollOversize = inner[0].offsetWidth === 100 && outer[0].clientWidth !== 100;
\r
590 // In rtl text layout, some browsers (most, but not all) will place the
\r
591 // scrollbar on the left, rather than the right.
\r
592 browser.bScrollbarLeft = Math.round( inner.offset().left ) !== 1;
\r
594 // IE8- don't provide height and width for getBoundingClientRect
\r
595 browser.bBounding = n[0].getBoundingClientRect().width ? true : false;
\r
600 $.extend( settings.oBrowser, DataTable.__browser );
\r
601 settings.oScroll.iBarWidth = DataTable.__browser.barWidth;
\r
606 * Array.prototype reduce[Right] method, used for browsers which don't support
\r
607 * JS 1.6. Done this way to reduce code size, since we iterate either way
\r
608 * @param {object} settings dataTables settings object
\r
609 * @memberof DataTable#oApi
\r
611 function _fnReduce ( that, fn, init, start, end, inc )
\r
618 if ( init !== undefined ) {
\r
623 while ( i !== end ) {
\r
624 if ( ! that.hasOwnProperty(i) ) {
\r
629 fn( value, that[i], i, that ) :
\r
640 * Add a column to the list used for the table with default values
\r
641 * @param {object} oSettings dataTables settings object
\r
642 * @param {node} nTh The th element for this column
\r
643 * @memberof DataTable#oApi
\r
645 function _fnAddColumn( oSettings, nTh )
\r
647 // Add column to aoColumns array
\r
648 var oDefaults = DataTable.defaults.column;
\r
649 var iCol = oSettings.aoColumns.length;
\r
650 var oCol = $.extend( {}, DataTable.models.oColumn, oDefaults, {
\r
651 "nTh": nTh ? nTh : document.createElement('th'),
\r
652 "sTitle": oDefaults.sTitle ? oDefaults.sTitle : nTh ? nTh.innerHTML : '',
\r
653 "aDataSort": oDefaults.aDataSort ? oDefaults.aDataSort : [iCol],
\r
654 "mData": oDefaults.mData ? oDefaults.mData : iCol,
\r
657 oSettings.aoColumns.push( oCol );
\r
659 // Add search object for column specific search. Note that the `searchCols[ iCol ]`
\r
660 // passed into extend can be undefined. This allows the user to give a default
\r
661 // with only some of the parameters defined, and also not give a default
\r
662 var searchCols = oSettings.aoPreSearchCols;
\r
663 searchCols[ iCol ] = $.extend( {}, DataTable.models.oSearch, searchCols[ iCol ] );
\r
665 // Use the default column options function to initialise classes etc
\r
666 _fnColumnOptions( oSettings, iCol, $(nTh).data() );
\r
671 * Apply options for a column
\r
672 * @param {object} oSettings dataTables settings object
\r
673 * @param {int} iCol column index to consider
\r
674 * @param {object} oOptions object with sType, bVisible and bSearchable etc
\r
675 * @memberof DataTable#oApi
\r
677 function _fnColumnOptions( oSettings, iCol, oOptions )
\r
679 var oCol = oSettings.aoColumns[ iCol ];
\r
680 var oClasses = oSettings.oClasses;
\r
681 var th = $(oCol.nTh);
\r
683 // Try to get width information from the DOM. We can't get it from CSS
\r
684 // as we'd need to parse the CSS stylesheet. `width` option can override
\r
685 if ( ! oCol.sWidthOrig ) {
\r
687 oCol.sWidthOrig = th.attr('width') || null;
\r
690 var t = (th.attr('style') || '').match(/width:\s*(\d+[pxem%]+)/);
\r
692 oCol.sWidthOrig = t[1];
\r
696 /* User specified column options */
\r
697 if ( oOptions !== undefined && oOptions !== null )
\r
699 // Backwards compatibility
\r
700 _fnCompatCols( oOptions );
\r
702 // Map camel case parameters to their Hungarian counterparts
\r
703 _fnCamelToHungarian( DataTable.defaults.column, oOptions );
\r
705 /* Backwards compatibility for mDataProp */
\r
706 if ( oOptions.mDataProp !== undefined && !oOptions.mData )
\r
708 oOptions.mData = oOptions.mDataProp;
\r
711 if ( oOptions.sType )
\r
713 oCol._sManualType = oOptions.sType;
\r
716 // `class` is a reserved word in Javascript, so we need to provide
\r
717 // the ability to use a valid name for the camel case input
\r
718 if ( oOptions.className && ! oOptions.sClass )
\r
720 oOptions.sClass = oOptions.className;
\r
723 $.extend( oCol, oOptions );
\r
724 _fnMap( oCol, oOptions, "sWidth", "sWidthOrig" );
\r
726 /* iDataSort to be applied (backwards compatibility), but aDataSort will take
\r
727 * priority if defined
\r
729 if ( oOptions.iDataSort !== undefined )
\r
731 oCol.aDataSort = [ oOptions.iDataSort ];
\r
733 _fnMap( oCol, oOptions, "aDataSort" );
\r
736 /* Cache the data get and set functions for speed */
\r
737 var mDataSrc = oCol.mData;
\r
738 var mData = _fnGetObjectDataFn( mDataSrc );
\r
739 var mRender = oCol.mRender ? _fnGetObjectDataFn( oCol.mRender ) : null;
\r
741 var attrTest = function( src ) {
\r
742 return typeof src === 'string' && src.indexOf('@') !== -1;
\r
744 oCol._bAttrSrc = $.isPlainObject( mDataSrc ) && (
\r
745 attrTest(mDataSrc.sort) || attrTest(mDataSrc.type) || attrTest(mDataSrc.filter)
\r
747 oCol._setter = null;
\r
749 oCol.fnGetData = function (rowData, type, meta) {
\r
750 var innerData = mData( rowData, type, undefined, meta );
\r
752 return mRender && type ?
\r
753 mRender( innerData, type, rowData, meta ) :
\r
756 oCol.fnSetData = function ( rowData, val, meta ) {
\r
757 return _fnSetObjectDataFn( mDataSrc )( rowData, val, meta );
\r
760 // Indicate if DataTables should read DOM data as an object or array
\r
761 // Used in _fnGetRowElements
\r
762 if ( typeof mDataSrc !== 'number' ) {
\r
763 oSettings._rowReadObject = true;
\r
766 /* Feature sorting overrides column specific when off */
\r
767 if ( !oSettings.oFeatures.bSort )
\r
769 oCol.bSortable = false;
\r
770 th.addClass( oClasses.sSortableNone ); // Have to add class here as order event isn't called
\r
773 /* Check that the class assignment is correct for sorting */
\r
774 var bAsc = $.inArray('asc', oCol.asSorting) !== -1;
\r
775 var bDesc = $.inArray('desc', oCol.asSorting) !== -1;
\r
776 if ( !oCol.bSortable || (!bAsc && !bDesc) )
\r
778 oCol.sSortingClass = oClasses.sSortableNone;
\r
779 oCol.sSortingClassJUI = "";
\r
781 else if ( bAsc && !bDesc )
\r
783 oCol.sSortingClass = oClasses.sSortableAsc;
\r
784 oCol.sSortingClassJUI = oClasses.sSortJUIAscAllowed;
\r
786 else if ( !bAsc && bDesc )
\r
788 oCol.sSortingClass = oClasses.sSortableDesc;
\r
789 oCol.sSortingClassJUI = oClasses.sSortJUIDescAllowed;
\r
793 oCol.sSortingClass = oClasses.sSortable;
\r
794 oCol.sSortingClassJUI = oClasses.sSortJUI;
\r
800 * Adjust the table column widths for new data. Note: you would probably want to
\r
801 * do a redraw after calling this function!
\r
802 * @param {object} settings dataTables settings object
\r
803 * @memberof DataTable#oApi
\r
805 function _fnAdjustColumnSizing ( settings )
\r
807 /* Not interested in doing column width calculation if auto-width is disabled */
\r
808 if ( settings.oFeatures.bAutoWidth !== false )
\r
810 var columns = settings.aoColumns;
\r
812 _fnCalculateColumnWidths( settings );
\r
813 for ( var i=0 , iLen=columns.length ; i<iLen ; i++ )
\r
815 columns[i].nTh.style.width = columns[i].sWidth;
\r
819 var scroll = settings.oScroll;
\r
820 if ( scroll.sY !== '' || scroll.sX !== '')
\r
822 _fnScrollDraw( settings );
\r
825 _fnCallbackFire( settings, null, 'column-sizing', [settings] );
\r
830 * Covert the index of a visible column to the index in the data array (take account
\r
831 * of hidden columns)
\r
832 * @param {object} oSettings dataTables settings object
\r
833 * @param {int} iMatch Visible column index to lookup
\r
834 * @returns {int} i the data index
\r
835 * @memberof DataTable#oApi
\r
837 function _fnVisibleToColumnIndex( oSettings, iMatch )
\r
839 var aiVis = _fnGetColumns( oSettings, 'bVisible' );
\r
841 return typeof aiVis[iMatch] === 'number' ?
\r
848 * Covert the index of an index in the data array and convert it to the visible
\r
849 * column index (take account of hidden columns)
\r
850 * @param {int} iMatch Column index to lookup
\r
851 * @param {object} oSettings dataTables settings object
\r
852 * @returns {int} i the data index
\r
853 * @memberof DataTable#oApi
\r
855 function _fnColumnIndexToVisible( oSettings, iMatch )
\r
857 var aiVis = _fnGetColumns( oSettings, 'bVisible' );
\r
858 var iPos = $.inArray( iMatch, aiVis );
\r
860 return iPos !== -1 ? iPos : null;
\r
865 * Get the number of visible columns
\r
866 * @param {object} oSettings dataTables settings object
\r
867 * @returns {int} i the number of visible columns
\r
868 * @memberof DataTable#oApi
\r
870 function _fnVisbleColumns( oSettings )
\r
872 return $( _pluck( oSettings.aoColumns, 'nTh' ) ).filter(':visible').length;
\r
877 * Get an array of column indexes that match a given property
\r
878 * @param {object} oSettings dataTables settings object
\r
879 * @param {string} sParam Parameter in aoColumns to look for - typically
\r
880 * bVisible or bSearchable
\r
881 * @returns {array} Array of indexes with matched properties
\r
882 * @memberof DataTable#oApi
\r
884 function _fnGetColumns( oSettings, sParam )
\r
888 $.map( oSettings.aoColumns, function(val, i) {
\r
889 if ( val[sParam] ) {
\r
899 * Calculate the 'type' of a column
\r
900 * @param {object} settings dataTables settings object
\r
901 * @memberof DataTable#oApi
\r
903 function _fnColumnTypes ( settings )
\r
905 var columns = settings.aoColumns;
\r
906 var data = settings.aoData;
\r
907 var types = DataTable.ext.type.detect;
\r
908 var i, ien, j, jen, k, ken;
\r
909 var col, cell, detectedType, cache;
\r
911 // For each column, spin over the
\r
912 for ( i=0, ien=columns.length ; i<ien ; i++ ) {
\r
916 if ( ! col.sType && col._sManualType ) {
\r
917 col.sType = col._sManualType;
\r
919 else if ( ! col.sType ) {
\r
920 for ( j=0, jen=types.length ; j<jen ; j++ ) {
\r
921 for ( k=0, ken=data.length ; k<ken ; k++ ) {
\r
922 // Use a cache array so we only need to get the type data
\r
923 // from the formatter once (when using multiple detectors)
\r
924 if ( cache[k] === undefined ) {
\r
925 cache[k] = _fnGetCellData( settings, k, i, 'type' );
\r
928 detectedType = types[j]( cache[k], settings );
\r
930 // If null, then this type can't apply to this column, so
\r
931 // rather than testing all cells, break out. There is an
\r
932 // exception for the last type which is `html`. We need to
\r
933 // scan all rows since it is possible to mix string and HTML
\r
935 if ( ! detectedType && j !== types.length-1 ) {
\r
939 // Only a single match is needed for html type since it is
\r
940 // bottom of the pile and very similar to string
\r
941 if ( detectedType === 'html' ) {
\r
946 // Type is valid for all data points in the column - use this
\r
948 if ( detectedType ) {
\r
949 col.sType = detectedType;
\r
954 // Fall back - if no type was detected, always use string
\r
955 if ( ! col.sType ) {
\r
956 col.sType = 'string';
\r
964 * Take the column definitions and static columns arrays and calculate how
\r
965 * they relate to column indexes. The callback function will then apply the
\r
966 * definition found for a column to a suitable configuration object.
\r
967 * @param {object} oSettings dataTables settings object
\r
968 * @param {array} aoColDefs The aoColumnDefs array that is to be applied
\r
969 * @param {array} aoCols The aoColumns array that defines columns individually
\r
970 * @param {function} fn Callback function - takes two parameters, the calculated
\r
971 * column index and the definition for that column.
\r
972 * @memberof DataTable#oApi
\r
974 function _fnApplyColumnDefs( oSettings, aoColDefs, aoCols, fn )
\r
976 var i, iLen, j, jLen, k, kLen, def;
\r
977 var columns = oSettings.aoColumns;
\r
979 // Column definitions with aTargets
\r
982 /* Loop over the definitions array - loop in reverse so first instance has priority */
\r
983 for ( i=aoColDefs.length-1 ; i>=0 ; i-- )
\r
985 def = aoColDefs[i];
\r
987 /* Each definition can target multiple columns, as it is an array */
\r
988 var aTargets = def.targets !== undefined ?
\r
992 if ( ! $.isArray( aTargets ) )
\r
994 aTargets = [ aTargets ];
\r
997 for ( j=0, jLen=aTargets.length ; j<jLen ; j++ )
\r
999 if ( typeof aTargets[j] === 'number' && aTargets[j] >= 0 )
\r
1001 /* Add columns that we don't yet know about */
\r
1002 while( columns.length <= aTargets[j] )
\r
1004 _fnAddColumn( oSettings );
\r
1007 /* Integer, basic index */
\r
1008 fn( aTargets[j], def );
\r
1010 else if ( typeof aTargets[j] === 'number' && aTargets[j] < 0 )
\r
1012 /* Negative integer, right to left column counting */
\r
1013 fn( columns.length+aTargets[j], def );
\r
1015 else if ( typeof aTargets[j] === 'string' )
\r
1017 /* Class name matching on TH element */
\r
1018 for ( k=0, kLen=columns.length ; k<kLen ; k++ )
\r
1020 if ( aTargets[j] == "_all" ||
\r
1021 $(columns[k].nTh).hasClass( aTargets[j] ) )
\r
1031 // Statically defined columns array
\r
1034 for ( i=0, iLen=aoCols.length ; i<iLen ; i++ )
\r
1036 fn( i, aoCols[i] );
\r
1042 * Add a data array to the table, creating DOM node etc. This is the parallel to
\r
1043 * _fnGatherData, but for adding rows from a Javascript source, rather than a
\r
1045 * @param {object} oSettings dataTables settings object
\r
1046 * @param {array} aData data array to be added
\r
1047 * @param {node} [nTr] TR element to add to the table - optional. If not given,
\r
1048 * DataTables will create a row automatically
\r
1049 * @param {array} [anTds] Array of TD|TH elements for the row - must be given
\r
1051 * @returns {int} >=0 if successful (index of new aoData entry), -1 if failed
\r
1052 * @memberof DataTable#oApi
\r
1054 function _fnAddData ( oSettings, aDataIn, nTr, anTds )
\r
1056 /* Create the object for storing information about this new row */
\r
1057 var iRow = oSettings.aoData.length;
\r
1058 var oData = $.extend( true, {}, DataTable.models.oRow, {
\r
1059 src: nTr ? 'dom' : 'data',
\r
1063 oData._aData = aDataIn;
\r
1064 oSettings.aoData.push( oData );
\r
1066 /* Create the cells */
\r
1067 var nTd, sThisType;
\r
1068 var columns = oSettings.aoColumns;
\r
1070 // Invalidate the column types as the new data needs to be revalidated
\r
1071 for ( var i=0, iLen=columns.length ; i<iLen ; i++ )
\r
1073 columns[i].sType = null;
\r
1076 /* Add to the display array */
\r
1077 oSettings.aiDisplayMaster.push( iRow );
\r
1079 var id = oSettings.rowIdFn( aDataIn );
\r
1080 if ( id !== undefined ) {
\r
1081 oSettings.aIds[ id ] = oData;
\r
1084 /* Create the DOM information, or register it if already present */
\r
1085 if ( nTr || ! oSettings.oFeatures.bDeferRender )
\r
1087 _fnCreateTr( oSettings, iRow, nTr, anTds );
\r
1095 * Add one or more TR elements to the table. Generally we'd expect to
\r
1096 * use this for reading data from a DOM sourced table, but it could be
\r
1097 * used for an TR element. Note that if a TR is given, it is used (i.e.
\r
1098 * it is not cloned).
\r
1099 * @param {object} settings dataTables settings object
\r
1100 * @param {array|node|jQuery} trs The TR element(s) to add to the table
\r
1101 * @returns {array} Array of indexes for the added rows
\r
1102 * @memberof DataTable#oApi
\r
1104 function _fnAddTr( settings, trs )
\r
1108 // Allow an individual node to be passed in
\r
1109 if ( ! (trs instanceof $) ) {
\r
1113 return trs.map( function (i, el) {
\r
1114 row = _fnGetRowElements( settings, el );
\r
1115 return _fnAddData( settings, row.data, el, row.cells );
\r
1121 * Take a TR element and convert it to an index in aoData
\r
1122 * @param {object} oSettings dataTables settings object
\r
1123 * @param {node} n the TR element to find
\r
1124 * @returns {int} index if the node is found, null if not
\r
1125 * @memberof DataTable#oApi
\r
1127 function _fnNodeToDataIndex( oSettings, n )
\r
1129 return (n._DT_RowIndex!==undefined) ? n._DT_RowIndex : null;
\r
1134 * Take a TD element and convert it into a column data index (not the visible index)
\r
1135 * @param {object} oSettings dataTables settings object
\r
1136 * @param {int} iRow The row number the TD/TH can be found in
\r
1137 * @param {node} n The TD/TH element to find
\r
1138 * @returns {int} index if the node is found, -1 if not
\r
1139 * @memberof DataTable#oApi
\r
1141 function _fnNodeToColumnIndex( oSettings, iRow, n )
\r
1143 return $.inArray( n, oSettings.aoData[ iRow ].anCells );
\r
1148 * Get the data for a given cell from the internal cache, taking into account data mapping
\r
1149 * @param {object} settings dataTables settings object
\r
1150 * @param {int} rowIdx aoData row id
\r
1151 * @param {int} colIdx Column index
\r
1152 * @param {string} type data get type ('display', 'type' 'filter' 'sort')
\r
1153 * @returns {*} Cell data
\r
1154 * @memberof DataTable#oApi
\r
1156 function _fnGetCellData( settings, rowIdx, colIdx, type )
\r
1158 var draw = settings.iDraw;
\r
1159 var col = settings.aoColumns[colIdx];
\r
1160 var rowData = settings.aoData[rowIdx]._aData;
\r
1161 var defaultContent = col.sDefaultContent;
\r
1162 var cellData = col.fnGetData( rowData, type, {
\r
1163 settings: settings,
\r
1168 if ( cellData === undefined ) {
\r
1169 if ( settings.iDrawError != draw && defaultContent === null ) {
\r
1170 _fnLog( settings, 0, "Requested unknown parameter "+
\r
1171 (typeof col.mData=='function' ? '{function}' : "'"+col.mData+"'")+
\r
1172 " for row "+rowIdx+", column "+colIdx, 4 );
\r
1173 settings.iDrawError = draw;
\r
1175 return defaultContent;
\r
1178 // When the data source is null and a specific data type is requested (i.e.
\r
1179 // not the original data), we can use default column data
\r
1180 if ( (cellData === rowData || cellData === null) && defaultContent !== null && type !== undefined ) {
\r
1181 cellData = defaultContent;
\r
1183 else if ( typeof cellData === 'function' ) {
\r
1184 // If the data source is a function, then we run it and use the return,
\r
1185 // executing in the scope of the data object (for instances)
\r
1186 return cellData.call( rowData );
\r
1189 if ( cellData === null && type == 'display' ) {
\r
1197 * Set the value for a specific cell, into the internal data cache
\r
1198 * @param {object} settings dataTables settings object
\r
1199 * @param {int} rowIdx aoData row id
\r
1200 * @param {int} colIdx Column index
\r
1201 * @param {*} val Value to set
\r
1202 * @memberof DataTable#oApi
\r
1204 function _fnSetCellData( settings, rowIdx, colIdx, val )
\r
1206 var col = settings.aoColumns[colIdx];
\r
1207 var rowData = settings.aoData[rowIdx]._aData;
\r
1209 col.fnSetData( rowData, val, {
\r
1210 settings: settings,
\r
1217 // Private variable that is used to match action syntax in the data property object
\r
1218 var __reArray = /\[.*?\]$/;
\r
1219 var __reFn = /\(\)$/;
\r
1222 * Split string on periods, taking into account escaped periods
\r
1223 * @param {string} str String to split
\r
1224 * @return {array} Split string
\r
1226 function _fnSplitObjNotation( str )
\r
1228 return $.map( str.match(/(\\.|[^\.])+/g) || [''], function ( s ) {
\r
1229 return s.replace(/\\./g, '.');
\r
1235 * Return a function that can be used to get data from a source object, taking
\r
1236 * into account the ability to use nested objects as a source
\r
1237 * @param {string|int|function} mSource The data source for the object
\r
1238 * @returns {function} Data get function
\r
1239 * @memberof DataTable#oApi
\r
1241 function _fnGetObjectDataFn( mSource )
\r
1243 if ( $.isPlainObject( mSource ) )
\r
1245 /* Build an object of get functions, and wrap them in a single call */
\r
1247 $.each( mSource, function (key, val) {
\r
1249 o[key] = _fnGetObjectDataFn( val );
\r
1253 return function (data, type, row, meta) {
\r
1254 var t = o[type] || o._;
\r
1255 return t !== undefined ?
\r
1256 t(data, type, row, meta) :
\r
1260 else if ( mSource === null )
\r
1262 /* Give an empty string for rendering / sorting etc */
\r
1263 return function (data) { // type, row and meta also passed, but not used
\r
1267 else if ( typeof mSource === 'function' )
\r
1269 return function (data, type, row, meta) {
\r
1270 return mSource( data, type, row, meta );
\r
1273 else if ( typeof mSource === 'string' && (mSource.indexOf('.') !== -1 ||
\r
1274 mSource.indexOf('[') !== -1 || mSource.indexOf('(') !== -1) )
\r
1276 /* If there is a . in the source string then the data source is in a
\r
1277 * nested object so we loop over the data for each level to get the next
\r
1278 * level down. On each loop we test for undefined, and if found immediately
\r
1279 * return. This allows entire objects to be missing and sDefaultContent to
\r
1280 * be used if defined, rather than throwing an error
\r
1282 var fetchData = function (data, type, src) {
\r
1283 var arrayNotation, funcNotation, out, innerSrc;
\r
1287 var a = _fnSplitObjNotation( src );
\r
1289 for ( var i=0, iLen=a.length ; i<iLen ; i++ )
\r
1291 // Check if we are dealing with special notation
\r
1292 arrayNotation = a[i].match(__reArray);
\r
1293 funcNotation = a[i].match(__reFn);
\r
1295 if ( arrayNotation )
\r
1298 a[i] = a[i].replace(__reArray, '');
\r
1300 // Condition allows simply [] to be passed in
\r
1301 if ( a[i] !== "" ) {
\r
1302 data = data[ a[i] ];
\r
1306 // Get the remainder of the nested object to get
\r
1307 a.splice( 0, i+1 );
\r
1308 innerSrc = a.join('.');
\r
1310 // Traverse each entry in the array getting the properties requested
\r
1311 if ( $.isArray( data ) ) {
\r
1312 for ( var j=0, jLen=data.length ; j<jLen ; j++ ) {
\r
1313 out.push( fetchData( data[j], type, innerSrc ) );
\r
1317 // If a string is given in between the array notation indicators, that
\r
1318 // is used to join the strings together, otherwise an array is returned
\r
1319 var join = arrayNotation[0].substring(1, arrayNotation[0].length-1);
\r
1320 data = (join==="") ? out : out.join(join);
\r
1322 // The inner call to fetchData has already traversed through the remainder
\r
1323 // of the source requested, so we exit from the loop
\r
1326 else if ( funcNotation )
\r
1329 a[i] = a[i].replace(__reFn, '');
\r
1330 data = data[ a[i] ]();
\r
1334 if ( data === null || data[ a[i] ] === undefined )
\r
1338 data = data[ a[i] ];
\r
1345 return function (data, type) { // row and meta also passed, but not used
\r
1346 return fetchData( data, type, mSource );
\r
1351 /* Array or flat object mapping */
\r
1352 return function (data, type) { // row and meta also passed, but not used
\r
1353 return data[mSource];
\r
1360 * Return a function that can be used to set data from a source object, taking
\r
1361 * into account the ability to use nested objects as a source
\r
1362 * @param {string|int|function} mSource The data source for the object
\r
1363 * @returns {function} Data set function
\r
1364 * @memberof DataTable#oApi
\r
1366 function _fnSetObjectDataFn( mSource )
\r
1368 if ( $.isPlainObject( mSource ) )
\r
1370 /* Unlike get, only the underscore (global) option is used for for
\r
1371 * setting data since we don't know the type here. This is why an object
\r
1372 * option is not documented for `mData` (which is read/write), but it is
\r
1373 * for `mRender` which is read only.
\r
1375 return _fnSetObjectDataFn( mSource._ );
\r
1377 else if ( mSource === null )
\r
1379 /* Nothing to do when the data source is null */
\r
1380 return function () {};
\r
1382 else if ( typeof mSource === 'function' )
\r
1384 return function (data, val, meta) {
\r
1385 mSource( data, 'set', val, meta );
\r
1388 else if ( typeof mSource === 'string' && (mSource.indexOf('.') !== -1 ||
\r
1389 mSource.indexOf('[') !== -1 || mSource.indexOf('(') !== -1) )
\r
1391 /* Like the get, we need to get data from a nested object */
\r
1392 var setData = function (data, val, src) {
\r
1393 var a = _fnSplitObjNotation( src ), b;
\r
1394 var aLast = a[a.length-1];
\r
1395 var arrayNotation, funcNotation, o, innerSrc;
\r
1397 for ( var i=0, iLen=a.length-1 ; i<iLen ; i++ )
\r
1399 // Check if we are dealing with an array notation request
\r
1400 arrayNotation = a[i].match(__reArray);
\r
1401 funcNotation = a[i].match(__reFn);
\r
1403 if ( arrayNotation )
\r
1405 a[i] = a[i].replace(__reArray, '');
\r
1406 data[ a[i] ] = [];
\r
1408 // Get the remainder of the nested object to set so we can recurse
\r
1410 b.splice( 0, i+1 );
\r
1411 innerSrc = b.join('.');
\r
1413 // Traverse each entry in the array setting the properties requested
\r
1414 if ( $.isArray( val ) )
\r
1416 for ( var j=0, jLen=val.length ; j<jLen ; j++ )
\r
1419 setData( o, val[j], innerSrc );
\r
1420 data[ a[i] ].push( o );
\r
1425 // We've been asked to save data to an array, but it
\r
1426 // isn't array data to be saved. Best that can be done
\r
1427 // is to just save the value.
\r
1428 data[ a[i] ] = val;
\r
1431 // The inner call to setData has already traversed through the remainder
\r
1432 // of the source and has set the data, thus we can exit here
\r
1435 else if ( funcNotation )
\r
1438 a[i] = a[i].replace(__reFn, '');
\r
1439 data = data[ a[i] ]( val );
\r
1442 // If the nested object doesn't currently exist - since we are
\r
1443 // trying to set the value - create it
\r
1444 if ( data[ a[i] ] === null || data[ a[i] ] === undefined )
\r
1446 data[ a[i] ] = {};
\r
1448 data = data[ a[i] ];
\r
1451 // Last item in the input - i.e, the actual set
\r
1452 if ( aLast.match(__reFn ) )
\r
1455 data = data[ aLast.replace(__reFn, '') ]( val );
\r
1459 // If array notation is used, we just want to strip it and use the property name
\r
1460 // and assign the value. If it isn't used, then we get the result we want anyway
\r
1461 data[ aLast.replace(__reArray, '') ] = val;
\r
1465 return function (data, val) { // meta is also passed in, but not used
\r
1466 return setData( data, val, mSource );
\r
1471 /* Array or flat object mapping */
\r
1472 return function (data, val) { // meta is also passed in, but not used
\r
1473 data[mSource] = val;
\r
1480 * Return an array with the full table data
\r
1481 * @param {object} oSettings dataTables settings object
\r
1482 * @returns array {array} aData Master data array
\r
1483 * @memberof DataTable#oApi
\r
1485 function _fnGetDataMaster ( settings )
\r
1487 return _pluck( settings.aoData, '_aData' );
\r
1493 * @param {object} oSettings dataTables settings object
\r
1494 * @memberof DataTable#oApi
\r
1496 function _fnClearTable( settings )
\r
1498 settings.aoData.length = 0;
\r
1499 settings.aiDisplayMaster.length = 0;
\r
1500 settings.aiDisplay.length = 0;
\r
1501 settings.aIds = {};
\r
1506 * Take an array of integers (index array) and remove a target integer (value - not
\r
1508 * @param {array} a Index array to target
\r
1509 * @param {int} iTarget value to find
\r
1510 * @memberof DataTable#oApi
\r
1512 function _fnDeleteIndex( a, iTarget, splice )
\r
1514 var iTargetIndex = -1;
\r
1516 for ( var i=0, iLen=a.length ; i<iLen ; i++ )
\r
1518 if ( a[i] == iTarget )
\r
1522 else if ( a[i] > iTarget )
\r
1528 if ( iTargetIndex != -1 && splice === undefined )
\r
1530 a.splice( iTargetIndex, 1 );
\r
1536 * Mark cached data as invalid such that a re-read of the data will occur when
\r
1537 * the cached data is next requested. Also update from the data source object.
\r
1539 * @param {object} settings DataTables settings object
\r
1540 * @param {int} rowIdx Row index to invalidate
\r
1541 * @param {string} [src] Source to invalidate from: undefined, 'auto', 'dom'
\r
1543 * @param {int} [colIdx] Column index to invalidate. If undefined the whole
\r
1544 * row will be invalidated
\r
1545 * @memberof DataTable#oApi
\r
1547 * @todo For the modularisation of v1.11 this will need to become a callback, so
\r
1548 * the sort and filter methods can subscribe to it. That will required
\r
1549 * initialisation options for sorting, which is why it is not already baked in
\r
1551 function _fnInvalidate( settings, rowIdx, src, colIdx )
\r
1553 var row = settings.aoData[ rowIdx ];
\r
1555 var cellWrite = function ( cell, col ) {
\r
1556 // This is very frustrating, but in IE if you just write directly
\r
1557 // to innerHTML, and elements that are overwritten are GC'ed,
\r
1558 // even if there is a reference to them elsewhere
\r
1559 while ( cell.childNodes.length ) {
\r
1560 cell.removeChild( cell.firstChild );
\r
1563 cell.innerHTML = _fnGetCellData( settings, rowIdx, col, 'display' );
\r
1566 // Are we reading last data from DOM or the data object?
\r
1567 if ( src === 'dom' || ((! src || src === 'auto') && row.src === 'dom') ) {
\r
1568 // Read the data from the DOM
\r
1569 row._aData = _fnGetRowElements(
\r
1570 settings, row, colIdx, colIdx === undefined ? undefined : row._aData
\r
1575 // Reading from data object, update the DOM
\r
1576 var cells = row.anCells;
\r
1579 if ( colIdx !== undefined ) {
\r
1580 cellWrite( cells[colIdx], colIdx );
\r
1583 for ( i=0, ien=cells.length ; i<ien ; i++ ) {
\r
1584 cellWrite( cells[i], i );
\r
1590 // For both row and cell invalidation, the cached data for sorting and
\r
1591 // filtering is nulled out
\r
1592 row._aSortData = null;
\r
1593 row._aFilterData = null;
\r
1595 // Invalidate the type for a specific column (if given) or all columns since
\r
1596 // the data might have changed
\r
1597 var cols = settings.aoColumns;
\r
1598 if ( colIdx !== undefined ) {
\r
1599 cols[ colIdx ].sType = null;
\r
1602 for ( i=0, ien=cols.length ; i<ien ; i++ ) {
\r
1603 cols[i].sType = null;
\r
1606 // Update DataTables special `DT_*` attributes for the row
\r
1607 _fnRowAttributes( settings, row );
\r
1613 * Build a data source object from an HTML row, reading the contents of the
\r
1614 * cells that are in the row.
\r
1616 * @param {object} settings DataTables settings object
\r
1617 * @param {node|object} TR element from which to read data or existing row
\r
1618 * object from which to re-read the data from the cells
\r
1619 * @param {int} [colIdx] Optional column index
\r
1620 * @param {array|object} [d] Data source object. If `colIdx` is given then this
\r
1621 * parameter should also be given and will be used to write the data into.
\r
1622 * Only the column in question will be written
\r
1623 * @returns {object} Object with two parameters: `data` the data read, in
\r
1624 * document order, and `cells` and array of nodes (they can be useful to the
\r
1625 * caller, so rather than needing a second traversal to get them, just return
\r
1626 * them from here).
\r
1627 * @memberof DataTable#oApi
\r
1629 function _fnGetRowElements( settings, row, colIdx, d )
\r
1633 td = row.firstChild,
\r
1634 name, col, o, i=0, contents,
\r
1635 columns = settings.aoColumns,
\r
1636 objectRead = settings._rowReadObject;
\r
1638 // Allow the data object to be passed in, or construct
\r
1639 d = d !== undefined ?
\r
1645 var attr = function ( str, td ) {
\r
1646 if ( typeof str === 'string' ) {
\r
1647 var idx = str.indexOf('@');
\r
1649 if ( idx !== -1 ) {
\r
1650 var attr = str.substring( idx+1 );
\r
1651 var setter = _fnSetObjectDataFn( str );
\r
1652 setter( d, td.getAttribute( attr ) );
\r
1657 // Read data from a cell and store into the data object
\r
1658 var cellProcess = function ( cell ) {
\r
1659 if ( colIdx === undefined || colIdx === i ) {
\r
1661 contents = $.trim(cell.innerHTML);
\r
1663 if ( col && col._bAttrSrc ) {
\r
1664 var setter = _fnSetObjectDataFn( col.mData._ );
\r
1665 setter( d, contents );
\r
1667 attr( col.mData.sort, cell );
\r
1668 attr( col.mData.type, cell );
\r
1669 attr( col.mData.filter, cell );
\r
1672 // Depending on the `data` option for the columns the data can
\r
1673 // be read to either an object or an array.
\r
1674 if ( objectRead ) {
\r
1675 if ( ! col._setter ) {
\r
1676 // Cache the setter function
\r
1677 col._setter = _fnSetObjectDataFn( col.mData );
\r
1679 col._setter( d, contents );
\r
1691 // `tr` element was passed in
\r
1693 name = td.nodeName.toUpperCase();
\r
1695 if ( name == "TD" || name == "TH" ) {
\r
1696 cellProcess( td );
\r
1700 td = td.nextSibling;
\r
1704 // Existing row object passed in
\r
1705 tds = row.anCells;
\r
1707 for ( var j=0, jen=tds.length ; j<jen ; j++ ) {
\r
1708 cellProcess( tds[j] );
\r
1712 // Read the ID from the DOM if present
\r
1713 var rowNode = row.firstChild ? row : row.nTr;
\r
1716 var id = rowNode.getAttribute( 'id' );
\r
1719 _fnSetObjectDataFn( settings.rowId )( d, id );
\r
1729 * Create a new TR element (and it's TD children) for a row
\r
1730 * @param {object} oSettings dataTables settings object
\r
1731 * @param {int} iRow Row to consider
\r
1732 * @param {node} [nTrIn] TR element to add to the table - optional. If not given,
\r
1733 * DataTables will create a row automatically
\r
1734 * @param {array} [anTds] Array of TD|TH elements for the row - must be given
\r
1736 * @memberof DataTable#oApi
\r
1738 function _fnCreateTr ( oSettings, iRow, nTrIn, anTds )
\r
1741 row = oSettings.aoData[iRow],
\r
1742 rowData = row._aData,
\r
1747 if ( row.nTr === null )
\r
1749 nTr = nTrIn || document.createElement('tr');
\r
1752 row.anCells = cells;
\r
1754 /* Use a private property on the node to allow reserve mapping from the node
\r
1755 * to the aoData array for fast look up
\r
1757 nTr._DT_RowIndex = iRow;
\r
1759 /* Special parameters can be given by the data source to be used on the row */
\r
1760 _fnRowAttributes( oSettings, row );
\r
1762 /* Process each column */
\r
1763 for ( i=0, iLen=oSettings.aoColumns.length ; i<iLen ; i++ )
\r
1765 oCol = oSettings.aoColumns[i];
\r
1767 nTd = nTrIn ? anTds[i] : document.createElement( oCol.sCellType );
\r
1768 nTd._DT_CellIndex = {
\r
1773 cells.push( nTd );
\r
1775 // Need to create the HTML if new, or if a rendering function is defined
\r
1776 if ( (!nTrIn || oCol.mRender || oCol.mData !== i) &&
\r
1777 (!$.isPlainObject(oCol.mData) || oCol.mData._ !== i+'.display')
\r
1779 nTd.innerHTML = _fnGetCellData( oSettings, iRow, i, 'display' );
\r
1782 /* Add user defined class */
\r
1783 if ( oCol.sClass )
\r
1785 nTd.className += ' '+oCol.sClass;
\r
1788 // Visibility - add or remove as required
\r
1789 if ( oCol.bVisible && ! nTrIn )
\r
1791 nTr.appendChild( nTd );
\r
1793 else if ( ! oCol.bVisible && nTrIn )
\r
1795 nTd.parentNode.removeChild( nTd );
\r
1798 if ( oCol.fnCreatedCell )
\r
1800 oCol.fnCreatedCell.call( oSettings.oInstance,
\r
1801 nTd, _fnGetCellData( oSettings, iRow, i ), rowData, iRow, i
\r
1806 _fnCallbackFire( oSettings, 'aoRowCreatedCallback', null, [nTr, rowData, iRow] );
\r
1809 // Remove once webkit bug 131819 and Chromium bug 365619 have been resolved
\r
1811 row.nTr.setAttribute( 'role', 'row' );
\r
1816 * Add attributes to a row based on the special `DT_*` parameters in a data
\r
1818 * @param {object} settings DataTables settings object
\r
1819 * @param {object} DataTables row object for the row to be modified
\r
1820 * @memberof DataTable#oApi
\r
1822 function _fnRowAttributes( settings, row )
\r
1825 var data = row._aData;
\r
1828 var id = settings.rowIdFn( data );
\r
1834 if ( data.DT_RowClass ) {
\r
1835 // Remove any classes added by DT_RowClass before
\r
1836 var a = data.DT_RowClass.split(' ');
\r
1837 row.__rowc = row.__rowc ?
\r
1838 _unique( row.__rowc.concat( a ) ) :
\r
1842 .removeClass( row.__rowc.join(' ') )
\r
1843 .addClass( data.DT_RowClass );
\r
1846 if ( data.DT_RowAttr ) {
\r
1847 $(tr).attr( data.DT_RowAttr );
\r
1850 if ( data.DT_RowData ) {
\r
1851 $(tr).data( data.DT_RowData );
\r
1858 * Create the HTML header for the table
\r
1859 * @param {object} oSettings dataTables settings object
\r
1860 * @memberof DataTable#oApi
\r
1862 function _fnBuildHead( oSettings )
\r
1864 var i, ien, cell, row, column;
\r
1865 var thead = oSettings.nTHead;
\r
1866 var tfoot = oSettings.nTFoot;
\r
1867 var createHeader = $('th, td', thead).length === 0;
\r
1868 var classes = oSettings.oClasses;
\r
1869 var columns = oSettings.aoColumns;
\r
1871 if ( createHeader ) {
\r
1872 row = $('<tr/>').appendTo( thead );
\r
1875 for ( i=0, ien=columns.length ; i<ien ; i++ ) {
\r
1876 column = columns[i];
\r
1877 cell = $( column.nTh ).addClass( column.sClass );
\r
1879 if ( createHeader ) {
\r
1880 cell.appendTo( row );
\r
1883 // 1.11 move into sorting
\r
1884 if ( oSettings.oFeatures.bSort ) {
\r
1885 cell.addClass( column.sSortingClass );
\r
1887 if ( column.bSortable !== false ) {
\r
1889 .attr( 'tabindex', oSettings.iTabIndex )
\r
1890 .attr( 'aria-controls', oSettings.sTableId );
\r
1892 _fnSortAttachListener( oSettings, column.nTh, i );
\r
1896 if ( column.sTitle != cell[0].innerHTML ) {
\r
1897 cell.html( column.sTitle );
\r
1900 _fnRenderer( oSettings, 'header' )(
\r
1901 oSettings, cell, column, classes
\r
1905 if ( createHeader ) {
\r
1906 _fnDetectHeader( oSettings.aoHeader, thead );
\r
1909 /* ARIA role for the rows */
\r
1910 $(thead).find('>tr').attr('role', 'row');
\r
1912 /* Deal with the footer - add classes if required */
\r
1913 $(thead).find('>tr>th, >tr>td').addClass( classes.sHeaderTH );
\r
1914 $(tfoot).find('>tr>th, >tr>td').addClass( classes.sFooterTH );
\r
1916 // Cache the footer cells. Note that we only take the cells from the first
\r
1917 // row in the footer. If there is more than one row the user wants to
\r
1918 // interact with, they need to use the table().foot() method. Note also this
\r
1919 // allows cells to be used for multiple columns using colspan
\r
1920 if ( tfoot !== null ) {
\r
1921 var cells = oSettings.aoFooter[0];
\r
1923 for ( i=0, ien=cells.length ; i<ien ; i++ ) {
\r
1924 column = columns[i];
\r
1925 column.nTf = cells[i].cell;
\r
1927 if ( column.sClass ) {
\r
1928 $(column.nTf).addClass( column.sClass );
\r
1936 * Draw the header (or footer) element based on the column visibility states. The
\r
1937 * methodology here is to use the layout array from _fnDetectHeader, modified for
\r
1938 * the instantaneous column visibility, to construct the new layout. The grid is
\r
1939 * traversed over cell at a time in a rows x columns grid fashion, although each
\r
1940 * cell insert can cover multiple elements in the grid - which is tracks using the
\r
1941 * aApplied array. Cell inserts in the grid will only occur where there isn't
\r
1942 * already a cell in that position.
\r
1943 * @param {object} oSettings dataTables settings object
\r
1944 * @param array {objects} aoSource Layout array from _fnDetectHeader
\r
1945 * @param {boolean} [bIncludeHidden=false] If true then include the hidden columns in the calc,
\r
1946 * @memberof DataTable#oApi
\r
1948 function _fnDrawHead( oSettings, aoSource, bIncludeHidden )
\r
1950 var i, iLen, j, jLen, k, kLen, n, nLocalTr;
\r
1952 var aApplied = [];
\r
1953 var iColumns = oSettings.aoColumns.length;
\r
1954 var iRowspan, iColspan;
\r
1961 if ( bIncludeHidden === undefined )
\r
1963 bIncludeHidden = false;
\r
1966 /* Make a copy of the master layout array, but without the visible columns in it */
\r
1967 for ( i=0, iLen=aoSource.length ; i<iLen ; i++ )
\r
1969 aoLocal[i] = aoSource[i].slice();
\r
1970 aoLocal[i].nTr = aoSource[i].nTr;
\r
1972 /* Remove any columns which are currently hidden */
\r
1973 for ( j=iColumns-1 ; j>=0 ; j-- )
\r
1975 if ( !oSettings.aoColumns[j].bVisible && !bIncludeHidden )
\r
1977 aoLocal[i].splice( j, 1 );
\r
1981 /* Prep the applied array - it needs an element for each row */
\r
1982 aApplied.push( [] );
\r
1985 for ( i=0, iLen=aoLocal.length ; i<iLen ; i++ )
\r
1987 nLocalTr = aoLocal[i].nTr;
\r
1989 /* All cells are going to be replaced, so empty out the row */
\r
1992 while( (n = nLocalTr.firstChild) )
\r
1994 nLocalTr.removeChild( n );
\r
1998 for ( j=0, jLen=aoLocal[i].length ; j<jLen ; j++ )
\r
2003 /* Check to see if there is already a cell (row/colspan) covering our target
\r
2004 * insert point. If there is, then there is nothing to do.
\r
2006 if ( aApplied[i][j] === undefined )
\r
2008 nLocalTr.appendChild( aoLocal[i][j].cell );
\r
2009 aApplied[i][j] = 1;
\r
2011 /* Expand the cell to cover as many rows as needed */
\r
2012 while ( aoLocal[i+iRowspan] !== undefined &&
\r
2013 aoLocal[i][j].cell == aoLocal[i+iRowspan][j].cell )
\r
2015 aApplied[i+iRowspan][j] = 1;
\r
2019 /* Expand the cell to cover as many columns as needed */
\r
2020 while ( aoLocal[i][j+iColspan] !== undefined &&
\r
2021 aoLocal[i][j].cell == aoLocal[i][j+iColspan].cell )
\r
2023 /* Must update the applied array over the rows for the columns */
\r
2024 for ( k=0 ; k<iRowspan ; k++ )
\r
2026 aApplied[i+k][j+iColspan] = 1;
\r
2031 /* Do the actual expansion in the DOM */
\r
2032 $(aoLocal[i][j].cell)
\r
2033 .attr('rowspan', iRowspan)
\r
2034 .attr('colspan', iColspan);
\r
2042 * Insert the required TR nodes into the table for display
\r
2043 * @param {object} oSettings dataTables settings object
\r
2044 * @memberof DataTable#oApi
\r
2046 function _fnDraw( oSettings )
\r
2048 /* Provide a pre-callback function which can be used to cancel the draw is false is returned */
\r
2049 var aPreDraw = _fnCallbackFire( oSettings, 'aoPreDrawCallback', 'preDraw', [oSettings] );
\r
2050 if ( $.inArray( false, aPreDraw ) !== -1 )
\r
2052 _fnProcessingDisplay( oSettings, false );
\r
2058 var iRowCount = 0;
\r
2059 var asStripeClasses = oSettings.asStripeClasses;
\r
2060 var iStripes = asStripeClasses.length;
\r
2061 var iOpenRows = oSettings.aoOpenRows.length;
\r
2062 var oLang = oSettings.oLanguage;
\r
2063 var iInitDisplayStart = oSettings.iInitDisplayStart;
\r
2064 var bServerSide = _fnDataSource( oSettings ) == 'ssp';
\r
2065 var aiDisplay = oSettings.aiDisplay;
\r
2067 oSettings.bDrawing = true;
\r
2069 /* Check and see if we have an initial draw position from state saving */
\r
2070 if ( iInitDisplayStart !== undefined && iInitDisplayStart !== -1 )
\r
2072 oSettings._iDisplayStart = bServerSide ?
\r
2073 iInitDisplayStart :
\r
2074 iInitDisplayStart >= oSettings.fnRecordsDisplay() ?
\r
2076 iInitDisplayStart;
\r
2078 oSettings.iInitDisplayStart = -1;
\r
2081 var iDisplayStart = oSettings._iDisplayStart;
\r
2082 var iDisplayEnd = oSettings.fnDisplayEnd();
\r
2084 /* Server-side processing draw intercept */
\r
2085 if ( oSettings.bDeferLoading )
\r
2087 oSettings.bDeferLoading = false;
\r
2088 oSettings.iDraw++;
\r
2089 _fnProcessingDisplay( oSettings, false );
\r
2091 else if ( !bServerSide )
\r
2093 oSettings.iDraw++;
\r
2095 else if ( !oSettings.bDestroying && !_fnAjaxUpdate( oSettings ) )
\r
2100 if ( aiDisplay.length !== 0 )
\r
2102 var iStart = bServerSide ? 0 : iDisplayStart;
\r
2103 var iEnd = bServerSide ? oSettings.aoData.length : iDisplayEnd;
\r
2105 for ( var j=iStart ; j<iEnd ; j++ )
\r
2107 var iDataIndex = aiDisplay[j];
\r
2108 var aoData = oSettings.aoData[ iDataIndex ];
\r
2109 if ( aoData.nTr === null )
\r
2111 _fnCreateTr( oSettings, iDataIndex );
\r
2114 var nRow = aoData.nTr;
\r
2116 /* Remove the old striping classes and then add the new one */
\r
2117 if ( iStripes !== 0 )
\r
2119 var sStripe = asStripeClasses[ iRowCount % iStripes ];
\r
2120 if ( aoData._sRowStripe != sStripe )
\r
2122 $(nRow).removeClass( aoData._sRowStripe ).addClass( sStripe );
\r
2123 aoData._sRowStripe = sStripe;
\r
2127 // Row callback functions - might want to manipulate the row
\r
2128 // iRowCount and j are not currently documented. Are they at all
\r
2130 _fnCallbackFire( oSettings, 'aoRowCallback', null,
\r
2131 [nRow, aoData._aData, iRowCount, j] );
\r
2133 anRows.push( nRow );
\r
2139 /* Table is empty - create a row with an empty message in it */
\r
2140 var sZero = oLang.sZeroRecords;
\r
2141 if ( oSettings.iDraw == 1 && _fnDataSource( oSettings ) == 'ajax' )
\r
2143 sZero = oLang.sLoadingRecords;
\r
2145 else if ( oLang.sEmptyTable && oSettings.fnRecordsTotal() === 0 )
\r
2147 sZero = oLang.sEmptyTable;
\r
2150 anRows[ 0 ] = $( '<tr/>', { 'class': iStripes ? asStripeClasses[0] : '' } )
\r
2151 .append( $('<td />', {
\r
2153 'colSpan': _fnVisbleColumns( oSettings ),
\r
2154 'class': oSettings.oClasses.sRowEmpty
\r
2155 } ).html( sZero ) )[0];
\r
2158 /* Header and footer callbacks */
\r
2159 _fnCallbackFire( oSettings, 'aoHeaderCallback', 'header', [ $(oSettings.nTHead).children('tr')[0],
\r
2160 _fnGetDataMaster( oSettings ), iDisplayStart, iDisplayEnd, aiDisplay ] );
\r
2162 _fnCallbackFire( oSettings, 'aoFooterCallback', 'footer', [ $(oSettings.nTFoot).children('tr')[0],
\r
2163 _fnGetDataMaster( oSettings ), iDisplayStart, iDisplayEnd, aiDisplay ] );
\r
2165 var body = $(oSettings.nTBody);
\r
2167 body.children().detach();
\r
2168 body.append( $(anRows) );
\r
2170 /* Call all required callback functions for the end of a draw */
\r
2171 _fnCallbackFire( oSettings, 'aoDrawCallback', 'draw', [oSettings] );
\r
2173 /* Draw is complete, sorting and filtering must be as well */
\r
2174 oSettings.bSorted = false;
\r
2175 oSettings.bFiltered = false;
\r
2176 oSettings.bDrawing = false;
\r
2181 * Redraw the table - taking account of the various features which are enabled
\r
2182 * @param {object} oSettings dataTables settings object
\r
2183 * @param {boolean} [holdPosition] Keep the current paging position. By default
\r
2184 * the paging is reset to the first page
\r
2185 * @memberof DataTable#oApi
\r
2187 function _fnReDraw( settings, holdPosition )
\r
2190 features = settings.oFeatures,
\r
2191 sort = features.bSort,
\r
2192 filter = features.bFilter;
\r
2195 _fnSort( settings );
\r
2199 _fnFilterComplete( settings, settings.oPreviousSearch );
\r
2202 // No filtering, so we want to just use the display master
\r
2203 settings.aiDisplay = settings.aiDisplayMaster.slice();
\r
2206 if ( holdPosition !== true ) {
\r
2207 settings._iDisplayStart = 0;
\r
2210 // Let any modules know about the draw hold position state (used by
\r
2211 // scrolling internally)
\r
2212 settings._drawHold = holdPosition;
\r
2214 _fnDraw( settings );
\r
2216 settings._drawHold = false;
\r
2221 * Add the options to the page HTML for the table
\r
2222 * @param {object} oSettings dataTables settings object
\r
2223 * @memberof DataTable#oApi
\r
2225 function _fnAddOptionsHtml ( oSettings )
\r
2227 var classes = oSettings.oClasses;
\r
2228 var table = $(oSettings.nTable);
\r
2229 var holding = $('<div/>').insertBefore( table ); // Holding element for speed
\r
2230 var features = oSettings.oFeatures;
\r
2232 // All DataTables are wrapped in a div
\r
2233 var insert = $('<div/>', {
\r
2234 id: oSettings.sTableId+'_wrapper',
\r
2235 'class': classes.sWrapper + (oSettings.nTFoot ? '' : ' '+classes.sNoFooter)
\r
2238 oSettings.nHolding = holding[0];
\r
2239 oSettings.nTableWrapper = insert[0];
\r
2240 oSettings.nTableReinsertBefore = oSettings.nTable.nextSibling;
\r
2242 /* Loop over the user set positioning and place the elements as needed */
\r
2243 var aDom = oSettings.sDom.split('');
\r
2244 var featureNode, cOption, nNewNode, cNext, sAttr, j;
\r
2245 for ( var i=0 ; i<aDom.length ; i++ )
\r
2247 featureNode = null;
\r
2248 cOption = aDom[i];
\r
2250 if ( cOption == '<' )
\r
2252 /* New container div */
\r
2253 nNewNode = $('<div/>')[0];
\r
2255 /* Check to see if we should append an id and/or a class name to the container */
\r
2256 cNext = aDom[i+1];
\r
2257 if ( cNext == "'" || cNext == '"' )
\r
2261 while ( aDom[i+j] != cNext )
\r
2263 sAttr += aDom[i+j];
\r
2267 /* Replace jQuery UI constants @todo depreciated */
\r
2268 if ( sAttr == "H" )
\r
2270 sAttr = classes.sJUIHeader;
\r
2272 else if ( sAttr == "F" )
\r
2274 sAttr = classes.sJUIFooter;
\r
2277 /* The attribute can be in the format of "#id.class", "#id" or "class" This logic
\r
2278 * breaks the string into parts and applies them as needed
\r
2280 if ( sAttr.indexOf('.') != -1 )
\r
2282 var aSplit = sAttr.split('.');
\r
2283 nNewNode.id = aSplit[0].substr(1, aSplit[0].length-1);
\r
2284 nNewNode.className = aSplit[1];
\r
2286 else if ( sAttr.charAt(0) == "#" )
\r
2288 nNewNode.id = sAttr.substr(1, sAttr.length-1);
\r
2292 nNewNode.className = sAttr;
\r
2295 i += j; /* Move along the position array */
\r
2298 insert.append( nNewNode );
\r
2299 insert = $(nNewNode);
\r
2301 else if ( cOption == '>' )
\r
2303 /* End container div */
\r
2304 insert = insert.parent();
\r
2306 // @todo Move options into their own plugins?
\r
2307 else if ( cOption == 'l' && features.bPaginate && features.bLengthChange )
\r
2310 featureNode = _fnFeatureHtmlLength( oSettings );
\r
2312 else if ( cOption == 'f' && features.bFilter )
\r
2315 featureNode = _fnFeatureHtmlFilter( oSettings );
\r
2317 else if ( cOption == 'r' && features.bProcessing )
\r
2320 featureNode = _fnFeatureHtmlProcessing( oSettings );
\r
2322 else if ( cOption == 't' )
\r
2325 featureNode = _fnFeatureHtmlTable( oSettings );
\r
2327 else if ( cOption == 'i' && features.bInfo )
\r
2330 featureNode = _fnFeatureHtmlInfo( oSettings );
\r
2332 else if ( cOption == 'p' && features.bPaginate )
\r
2335 featureNode = _fnFeatureHtmlPaginate( oSettings );
\r
2337 else if ( DataTable.ext.feature.length !== 0 )
\r
2339 /* Plug-in features */
\r
2340 var aoFeatures = DataTable.ext.feature;
\r
2341 for ( var k=0, kLen=aoFeatures.length ; k<kLen ; k++ )
\r
2343 if ( cOption == aoFeatures[k].cFeature )
\r
2345 featureNode = aoFeatures[k].fnInit( oSettings );
\r
2351 /* Add to the 2D features array */
\r
2352 if ( featureNode )
\r
2354 var aanFeatures = oSettings.aanFeatures;
\r
2356 if ( ! aanFeatures[cOption] )
\r
2358 aanFeatures[cOption] = [];
\r
2361 aanFeatures[cOption].push( featureNode );
\r
2362 insert.append( featureNode );
\r
2366 /* Built our DOM structure - replace the holding div with what we want */
\r
2367 holding.replaceWith( insert );
\r
2368 oSettings.nHolding = null;
\r
2373 * Use the DOM source to create up an array of header cells. The idea here is to
\r
2374 * create a layout grid (array) of rows x columns, which contains a reference
\r
2375 * to the cell that that point in the grid (regardless of col/rowspan), such that
\r
2376 * any column / row could be removed and the new grid constructed
\r
2377 * @param array {object} aLayout Array to store the calculated layout in
\r
2378 * @param {node} nThead The header/footer element for the table
\r
2379 * @memberof DataTable#oApi
\r
2381 function _fnDetectHeader ( aLayout, nThead )
\r
2383 var nTrs = $(nThead).children('tr');
\r
2385 var i, k, l, iLen, jLen, iColShifted, iColumn, iColspan, iRowspan;
\r
2387 var fnShiftCol = function ( a, i, j ) {
\r
2395 aLayout.splice( 0, aLayout.length );
\r
2397 /* We know how many rows there are in the layout - so prep it */
\r
2398 for ( i=0, iLen=nTrs.length ; i<iLen ; i++ )
\r
2400 aLayout.push( [] );
\r
2403 /* Calculate a layout array */
\r
2404 for ( i=0, iLen=nTrs.length ; i<iLen ; i++ )
\r
2409 /* For every cell in the row... */
\r
2410 nCell = nTr.firstChild;
\r
2412 if ( nCell.nodeName.toUpperCase() == "TD" ||
\r
2413 nCell.nodeName.toUpperCase() == "TH" )
\r
2415 /* Get the col and rowspan attributes from the DOM and sanitise them */
\r
2416 iColspan = nCell.getAttribute('colspan') * 1;
\r
2417 iRowspan = nCell.getAttribute('rowspan') * 1;
\r
2418 iColspan = (!iColspan || iColspan===0 || iColspan===1) ? 1 : iColspan;
\r
2419 iRowspan = (!iRowspan || iRowspan===0 || iRowspan===1) ? 1 : iRowspan;
\r
2421 /* There might be colspan cells already in this row, so shift our target
\r
2424 iColShifted = fnShiftCol( aLayout, i, iColumn );
\r
2426 /* Cache calculation for unique columns */
\r
2427 bUnique = iColspan === 1 ? true : false;
\r
2429 /* If there is col / rowspan, copy the information into the layout grid */
\r
2430 for ( l=0 ; l<iColspan ; l++ )
\r
2432 for ( k=0 ; k<iRowspan ; k++ )
\r
2434 aLayout[i+k][iColShifted+l] = {
\r
2438 aLayout[i+k].nTr = nTr;
\r
2442 nCell = nCell.nextSibling;
\r
2449 * Get an array of unique th elements, one for each column
\r
2450 * @param {object} oSettings dataTables settings object
\r
2451 * @param {node} nHeader automatically detect the layout from this node - optional
\r
2452 * @param {array} aLayout thead/tfoot layout from _fnDetectHeader - optional
\r
2453 * @returns array {node} aReturn list of unique th's
\r
2454 * @memberof DataTable#oApi
\r
2456 function _fnGetUniqueThs ( oSettings, nHeader, aLayout )
\r
2461 aLayout = oSettings.aoHeader;
\r
2465 _fnDetectHeader( aLayout, nHeader );
\r
2469 for ( var i=0, iLen=aLayout.length ; i<iLen ; i++ )
\r
2471 for ( var j=0, jLen=aLayout[i].length ; j<jLen ; j++ )
\r
2473 if ( aLayout[i][j].unique &&
\r
2474 (!aReturn[j] || !oSettings.bSortCellsTop) )
\r
2476 aReturn[j] = aLayout[i][j].cell;
\r
2485 * Create an Ajax call based on the table's settings, taking into account that
\r
2486 * parameters can have multiple forms, and backwards compatibility.
\r
2488 * @param {object} oSettings dataTables settings object
\r
2489 * @param {array} data Data to send to the server, required by
\r
2490 * DataTables - may be augmented by developer callbacks
\r
2491 * @param {function} fn Callback function to run when data is obtained
\r
2493 function _fnBuildAjax( oSettings, data, fn )
\r
2495 // Compatibility with 1.9-, allow fnServerData and event to manipulate
\r
2496 _fnCallbackFire( oSettings, 'aoServerParams', 'serverParams', [data] );
\r
2498 // Convert to object based for 1.10+ if using the old array scheme which can
\r
2499 // come from server-side processing or serverParams
\r
2500 if ( data && $.isArray(data) ) {
\r
2502 var rbracket = /(.*?)\[\]$/;
\r
2504 $.each( data, function (key, val) {
\r
2505 var match = val.name.match(rbracket);
\r
2508 // Support for arrays
\r
2509 var name = match[0];
\r
2511 if ( ! tmp[ name ] ) {
\r
2514 tmp[ name ].push( val.value );
\r
2517 tmp[val.name] = val.value;
\r
2524 var ajax = oSettings.ajax;
\r
2525 var instance = oSettings.oInstance;
\r
2526 var callback = function ( json ) {
\r
2527 _fnCallbackFire( oSettings, null, 'xhr', [oSettings, json, oSettings.jqXHR] );
\r
2531 if ( $.isPlainObject( ajax ) && ajax.data )
\r
2533 ajaxData = ajax.data;
\r
2535 var newData = $.isFunction( ajaxData ) ?
\r
2536 ajaxData( data, oSettings ) : // fn can manipulate data or return
\r
2537 ajaxData; // an object object or array to merge
\r
2539 // If the function returned something, use that alone
\r
2540 data = $.isFunction( ajaxData ) && newData ?
\r
2542 $.extend( true, data, newData );
\r
2544 // Remove the data property as we've resolved it already and don't want
\r
2545 // jQuery to do it again (it is restored at the end of the function)
\r
2551 "success": function (json) {
\r
2552 var error = json.error || json.sError;
\r
2554 _fnLog( oSettings, 0, error );
\r
2557 oSettings.json = json;
\r
2560 "dataType": "json",
\r
2562 "type": oSettings.sServerMethod,
\r
2563 "error": function (xhr, error, thrown) {
\r
2564 var ret = _fnCallbackFire( oSettings, null, 'xhr', [oSettings, null, oSettings.jqXHR] );
\r
2566 if ( $.inArray( true, ret ) === -1 ) {
\r
2567 if ( error == "parsererror" ) {
\r
2568 _fnLog( oSettings, 0, 'Invalid JSON response', 1 );
\r
2570 else if ( xhr.readyState === 4 ) {
\r
2571 _fnLog( oSettings, 0, 'Ajax error', 7 );
\r
2575 _fnProcessingDisplay( oSettings, false );
\r
2579 // Store the data submitted for the API
\r
2580 oSettings.oAjaxData = data;
\r
2582 // Allow plug-ins and external processes to modify the data
\r
2583 _fnCallbackFire( oSettings, null, 'preXhr', [oSettings, data] );
\r
2585 if ( oSettings.fnServerData )
\r
2587 // DataTables 1.9- compatibility
\r
2588 oSettings.fnServerData.call( instance,
\r
2589 oSettings.sAjaxSource,
\r
2590 $.map( data, function (val, key) { // Need to convert back to 1.9 trad format
\r
2591 return { name: key, value: val };
\r
2597 else if ( oSettings.sAjaxSource || typeof ajax === 'string' )
\r
2599 // DataTables 1.9- compatibility
\r
2600 oSettings.jqXHR = $.ajax( $.extend( baseAjax, {
\r
2601 url: ajax || oSettings.sAjaxSource
\r
2604 else if ( $.isFunction( ajax ) )
\r
2606 // Is a function - let the caller define what needs to be done
\r
2607 oSettings.jqXHR = ajax.call( instance, data, callback, oSettings );
\r
2611 // Object to extend the base settings
\r
2612 oSettings.jqXHR = $.ajax( $.extend( baseAjax, ajax ) );
\r
2614 // Restore for next time around
\r
2615 ajax.data = ajaxData;
\r
2621 * Update the table using an Ajax call
\r
2622 * @param {object} settings dataTables settings object
\r
2623 * @returns {boolean} Block the table drawing or not
\r
2624 * @memberof DataTable#oApi
\r
2626 function _fnAjaxUpdate( settings )
\r
2628 if ( settings.bAjaxDataGet ) {
\r
2630 _fnProcessingDisplay( settings, true );
\r
2634 _fnAjaxParameters( settings ),
\r
2636 _fnAjaxUpdateDraw( settings, json );
\r
2647 * Build up the parameters in an object needed for a server-side processing
\r
2648 * request. Note that this is basically done twice, is different ways - a modern
\r
2649 * method which is used by default in DataTables 1.10 which uses objects and
\r
2650 * arrays, or the 1.9- method with is name / value pairs. 1.9 method is used if
\r
2651 * the sAjaxSource option is used in the initialisation, or the legacyAjax
\r
2653 * @param {object} oSettings dataTables settings object
\r
2654 * @returns {bool} block the table drawing or not
\r
2655 * @memberof DataTable#oApi
\r
2657 function _fnAjaxParameters( settings )
\r
2660 columns = settings.aoColumns,
\r
2661 columnCount = columns.length,
\r
2662 features = settings.oFeatures,
\r
2663 preSearch = settings.oPreviousSearch,
\r
2664 preColSearch = settings.aoPreSearchCols,
\r
2665 i, data = [], dataProp, column, columnSearch,
\r
2666 sort = _fnSortFlatten( settings ),
\r
2667 displayStart = settings._iDisplayStart,
\r
2668 displayLength = features.bPaginate !== false ?
\r
2669 settings._iDisplayLength :
\r
2672 var param = function ( name, value ) {
\r
2673 data.push( { 'name': name, 'value': value } );
\r
2676 // DataTables 1.9- compatible method
\r
2677 param( 'sEcho', settings.iDraw );
\r
2678 param( 'iColumns', columnCount );
\r
2679 param( 'sColumns', _pluck( columns, 'sName' ).join(',') );
\r
2680 param( 'iDisplayStart', displayStart );
\r
2681 param( 'iDisplayLength', displayLength );
\r
2683 // DataTables 1.10+ method
\r
2685 draw: settings.iDraw,
\r
2688 start: displayStart,
\r
2689 length: displayLength,
\r
2691 value: preSearch.sSearch,
\r
2692 regex: preSearch.bRegex
\r
2696 for ( i=0 ; i<columnCount ; i++ ) {
\r
2697 column = columns[i];
\r
2698 columnSearch = preColSearch[i];
\r
2699 dataProp = typeof column.mData=="function" ? 'function' : column.mData ;
\r
2703 name: column.sName,
\r
2704 searchable: column.bSearchable,
\r
2705 orderable: column.bSortable,
\r
2707 value: columnSearch.sSearch,
\r
2708 regex: columnSearch.bRegex
\r
2712 param( "mDataProp_"+i, dataProp );
\r
2714 if ( features.bFilter ) {
\r
2715 param( 'sSearch_'+i, columnSearch.sSearch );
\r
2716 param( 'bRegex_'+i, columnSearch.bRegex );
\r
2717 param( 'bSearchable_'+i, column.bSearchable );
\r
2720 if ( features.bSort ) {
\r
2721 param( 'bSortable_'+i, column.bSortable );
\r
2725 if ( features.bFilter ) {
\r
2726 param( 'sSearch', preSearch.sSearch );
\r
2727 param( 'bRegex', preSearch.bRegex );
\r
2730 if ( features.bSort ) {
\r
2731 $.each( sort, function ( i, val ) {
\r
2732 d.order.push( { column: val.col, dir: val.dir } );
\r
2734 param( 'iSortCol_'+i, val.col );
\r
2735 param( 'sSortDir_'+i, val.dir );
\r
2738 param( 'iSortingCols', sort.length );
\r
2741 // If the legacy.ajax parameter is null, then we automatically decide which
\r
2742 // form to use, based on sAjaxSource
\r
2743 var legacy = DataTable.ext.legacy.ajax;
\r
2744 if ( legacy === null ) {
\r
2745 return settings.sAjaxSource ? data : d;
\r
2748 // Otherwise, if legacy has been specified then we use that to decide on the
\r
2750 return legacy ? data : d;
\r
2755 * Data the data from the server (nuking the old) and redraw the table
\r
2756 * @param {object} oSettings dataTables settings object
\r
2757 * @param {object} json json data return from the server.
\r
2758 * @param {string} json.sEcho Tracking flag for DataTables to match requests
\r
2759 * @param {int} json.iTotalRecords Number of records in the data set, not accounting for filtering
\r
2760 * @param {int} json.iTotalDisplayRecords Number of records in the data set, accounting for filtering
\r
2761 * @param {array} json.aaData The data to display on this page
\r
2762 * @param {string} [json.sColumns] Column ordering (sName, comma separated)
\r
2763 * @memberof DataTable#oApi
\r
2765 function _fnAjaxUpdateDraw ( settings, json )
\r
2767 // v1.10 uses camelCase variables, while 1.9 uses Hungarian notation.
\r
2769 var compat = function ( old, modern ) {
\r
2770 return json[old] !== undefined ? json[old] : json[modern];
\r
2773 var data = _fnAjaxDataSrc( settings, json );
\r
2774 var draw = compat( 'sEcho', 'draw' );
\r
2775 var recordsTotal = compat( 'iTotalRecords', 'recordsTotal' );
\r
2776 var recordsFiltered = compat( 'iTotalDisplayRecords', 'recordsFiltered' );
\r
2779 // Protect against out of sequence returns
\r
2780 if ( draw*1 < settings.iDraw ) {
\r
2783 settings.iDraw = draw * 1;
\r
2786 _fnClearTable( settings );
\r
2787 settings._iRecordsTotal = parseInt(recordsTotal, 10);
\r
2788 settings._iRecordsDisplay = parseInt(recordsFiltered, 10);
\r
2790 for ( var i=0, ien=data.length ; i<ien ; i++ ) {
\r
2791 _fnAddData( settings, data[i] );
\r
2793 settings.aiDisplay = settings.aiDisplayMaster.slice();
\r
2795 settings.bAjaxDataGet = false;
\r
2796 _fnDraw( settings );
\r
2798 if ( ! settings._bInitComplete ) {
\r
2799 _fnInitComplete( settings, json );
\r
2802 settings.bAjaxDataGet = true;
\r
2803 _fnProcessingDisplay( settings, false );
\r
2808 * Get the data from the JSON data source to use for drawing a table. Using
\r
2809 * `_fnGetObjectDataFn` allows the data to be sourced from a property of the
\r
2810 * source object, or from a processing function.
\r
2811 * @param {object} oSettings dataTables settings object
\r
2812 * @param {object} json Data source object / array from the server
\r
2813 * @return {array} Array of data to use
\r
2815 function _fnAjaxDataSrc ( oSettings, json )
\r
2817 var dataSrc = $.isPlainObject( oSettings.ajax ) && oSettings.ajax.dataSrc !== undefined ?
\r
2818 oSettings.ajax.dataSrc :
\r
2819 oSettings.sAjaxDataProp; // Compatibility with 1.9-.
\r
2821 // Compatibility with 1.9-. In order to read from aaData, check if the
\r
2822 // default has been changed, if not, check for aaData
\r
2823 if ( dataSrc === 'data' ) {
\r
2824 return json.aaData || json[dataSrc];
\r
2827 return dataSrc !== "" ?
\r
2828 _fnGetObjectDataFn( dataSrc )( json ) :
\r
2833 * Generate the node required for filtering text
\r
2834 * @returns {node} Filter control element
\r
2835 * @param {object} oSettings dataTables settings object
\r
2836 * @memberof DataTable#oApi
\r
2838 function _fnFeatureHtmlFilter ( settings )
\r
2840 var classes = settings.oClasses;
\r
2841 var tableId = settings.sTableId;
\r
2842 var language = settings.oLanguage;
\r
2843 var previousSearch = settings.oPreviousSearch;
\r
2844 var features = settings.aanFeatures;
\r
2845 var input = '<input type="search" class="'+classes.sFilterInput+'"/>';
\r
2847 var str = language.sSearch;
\r
2848 str = str.match(/_INPUT_/) ?
\r
2849 str.replace('_INPUT_', input) :
\r
2852 var filter = $('<div/>', {
\r
2853 'id': ! features.f ? tableId+'_filter' : null,
\r
2854 'class': classes.sFilter
\r
2856 .append( $('<label/>' ).append( str ) );
\r
2858 var searchFn = function() {
\r
2859 /* Update all other filter input elements for the new display */
\r
2860 var n = features.f;
\r
2861 var val = !this.value ? "" : this.value; // mental IE8 fix :-(
\r
2863 /* Now do the filter */
\r
2864 if ( val != previousSearch.sSearch ) {
\r
2865 _fnFilterComplete( settings, {
\r
2867 "bRegex": previousSearch.bRegex,
\r
2868 "bSmart": previousSearch.bSmart ,
\r
2869 "bCaseInsensitive": previousSearch.bCaseInsensitive
\r
2872 // Need to redraw, without resorting
\r
2873 settings._iDisplayStart = 0;
\r
2874 _fnDraw( settings );
\r
2878 var searchDelay = settings.searchDelay !== null ?
\r
2879 settings.searchDelay :
\r
2880 _fnDataSource( settings ) === 'ssp' ?
\r
2884 var jqFilter = $('input', filter)
\r
2885 .val( previousSearch.sSearch )
\r
2886 .attr( 'placeholder', language.sSearchPlaceholder )
\r
2888 'keyup.DT search.DT input.DT paste.DT cut.DT',
\r
2890 _fnThrottle( searchFn, searchDelay ) :
\r
2893 .bind( 'keypress.DT', function(e) {
\r
2894 /* Prevent form submission */
\r
2895 if ( e.keyCode == 13 ) {
\r
2899 .attr('aria-controls', tableId);
\r
2901 // Update the input elements whenever the table is filtered
\r
2902 $(settings.nTable).on( 'search.dt.DT', function ( ev, s ) {
\r
2903 if ( settings === s ) {
\r
2904 // IE9 throws an 'unknown error' if document.activeElement is used
\r
2905 // inside an iframe or frame...
\r
2907 if ( jqFilter[0] !== document.activeElement ) {
\r
2908 jqFilter.val( previousSearch.sSearch );
\r
2920 * Filter the table using both the global filter and column based filtering
\r
2921 * @param {object} oSettings dataTables settings object
\r
2922 * @param {object} oSearch search information
\r
2923 * @param {int} [iForce] force a research of the master array (1) or not (undefined or 0)
\r
2924 * @memberof DataTable#oApi
\r
2926 function _fnFilterComplete ( oSettings, oInput, iForce )
\r
2928 var oPrevSearch = oSettings.oPreviousSearch;
\r
2929 var aoPrevSearch = oSettings.aoPreSearchCols;
\r
2930 var fnSaveFilter = function ( oFilter ) {
\r
2931 /* Save the filtering values */
\r
2932 oPrevSearch.sSearch = oFilter.sSearch;
\r
2933 oPrevSearch.bRegex = oFilter.bRegex;
\r
2934 oPrevSearch.bSmart = oFilter.bSmart;
\r
2935 oPrevSearch.bCaseInsensitive = oFilter.bCaseInsensitive;
\r
2937 var fnRegex = function ( o ) {
\r
2938 // Backwards compatibility with the bEscapeRegex option
\r
2939 return o.bEscapeRegex !== undefined ? !o.bEscapeRegex : o.bRegex;
\r
2942 // Resolve any column types that are unknown due to addition or invalidation
\r
2943 // @todo As per sort - can this be moved into an event handler?
\r
2944 _fnColumnTypes( oSettings );
\r
2946 /* In server-side processing all filtering is done by the server, so no point hanging around here */
\r
2947 if ( _fnDataSource( oSettings ) != 'ssp' )
\r
2949 /* Global filter */
\r
2950 _fnFilter( oSettings, oInput.sSearch, iForce, fnRegex(oInput), oInput.bSmart, oInput.bCaseInsensitive );
\r
2951 fnSaveFilter( oInput );
\r
2953 /* Now do the individual column filter */
\r
2954 for ( var i=0 ; i<aoPrevSearch.length ; i++ )
\r
2956 _fnFilterColumn( oSettings, aoPrevSearch[i].sSearch, i, fnRegex(aoPrevSearch[i]),
\r
2957 aoPrevSearch[i].bSmart, aoPrevSearch[i].bCaseInsensitive );
\r
2960 /* Custom filtering */
\r
2961 _fnFilterCustom( oSettings );
\r
2965 fnSaveFilter( oInput );
\r
2968 /* Tell the draw function we have been filtering */
\r
2969 oSettings.bFiltered = true;
\r
2970 _fnCallbackFire( oSettings, null, 'search', [oSettings] );
\r
2975 * Apply custom filtering functions
\r
2976 * @param {object} oSettings dataTables settings object
\r
2977 * @memberof DataTable#oApi
\r
2979 function _fnFilterCustom( settings )
\r
2981 var filters = DataTable.ext.search;
\r
2982 var displayRows = settings.aiDisplay;
\r
2985 for ( var i=0, ien=filters.length ; i<ien ; i++ ) {
\r
2988 // Loop over each row and see if it should be included
\r
2989 for ( var j=0, jen=displayRows.length ; j<jen ; j++ ) {
\r
2990 rowIdx = displayRows[ j ];
\r
2991 row = settings.aoData[ rowIdx ];
\r
2993 if ( filters[i]( settings, row._aFilterData, rowIdx, row._aData, j ) ) {
\r
2994 rows.push( rowIdx );
\r
2998 // So the array reference doesn't break set the results into the
\r
3000 displayRows.length = 0;
\r
3001 $.merge( displayRows, rows );
\r
3007 * Filter the table on a per-column basis
\r
3008 * @param {object} oSettings dataTables settings object
\r
3009 * @param {string} sInput string to filter on
\r
3010 * @param {int} iColumn column to filter
\r
3011 * @param {bool} bRegex treat search string as a regular expression or not
\r
3012 * @param {bool} bSmart use smart filtering or not
\r
3013 * @param {bool} bCaseInsensitive Do case insenstive matching or not
\r
3014 * @memberof DataTable#oApi
\r
3016 function _fnFilterColumn ( settings, searchStr, colIdx, regex, smart, caseInsensitive )
\r
3018 if ( searchStr === '' ) {
\r
3023 var display = settings.aiDisplay;
\r
3024 var rpSearch = _fnFilterCreateSearch( searchStr, regex, smart, caseInsensitive );
\r
3026 for ( var i=display.length-1 ; i>=0 ; i-- ) {
\r
3027 data = settings.aoData[ display[i] ]._aFilterData[ colIdx ];
\r
3029 if ( ! rpSearch.test( data ) ) {
\r
3030 display.splice( i, 1 );
\r
3037 * Filter the data table based on user input and draw the table
\r
3038 * @param {object} settings dataTables settings object
\r
3039 * @param {string} input string to filter on
\r
3040 * @param {int} force optional - force a research of the master array (1) or not (undefined or 0)
\r
3041 * @param {bool} regex treat as a regular expression or not
\r
3042 * @param {bool} smart perform smart filtering or not
\r
3043 * @param {bool} caseInsensitive Do case insenstive matching or not
\r
3044 * @memberof DataTable#oApi
\r
3046 function _fnFilter( settings, input, force, regex, smart, caseInsensitive )
\r
3048 var rpSearch = _fnFilterCreateSearch( input, regex, smart, caseInsensitive );
\r
3049 var prevSearch = settings.oPreviousSearch.sSearch;
\r
3050 var displayMaster = settings.aiDisplayMaster;
\r
3051 var display, invalidated, i;
\r
3053 // Need to take account of custom filtering functions - always filter
\r
3054 if ( DataTable.ext.search.length !== 0 ) {
\r
3058 // Check if any of the rows were invalidated
\r
3059 invalidated = _fnFilterData( settings );
\r
3061 // If the input is blank - we just want the full data set
\r
3062 if ( input.length <= 0 ) {
\r
3063 settings.aiDisplay = displayMaster.slice();
\r
3066 // New search - start from the master array
\r
3067 if ( invalidated ||
\r
3069 prevSearch.length > input.length ||
\r
3070 input.indexOf(prevSearch) !== 0 ||
\r
3071 settings.bSorted // On resort, the display master needs to be
\r
3072 // re-filtered since indexes will have changed
\r
3074 settings.aiDisplay = displayMaster.slice();
\r
3077 // Search the display array
\r
3078 display = settings.aiDisplay;
\r
3080 for ( i=display.length-1 ; i>=0 ; i-- ) {
\r
3081 if ( ! rpSearch.test( settings.aoData[ display[i] ]._sFilterRow ) ) {
\r
3082 display.splice( i, 1 );
\r
3090 * Build a regular expression object suitable for searching a table
\r
3091 * @param {string} sSearch string to search for
\r
3092 * @param {bool} bRegex treat as a regular expression or not
\r
3093 * @param {bool} bSmart perform smart filtering or not
\r
3094 * @param {bool} bCaseInsensitive Do case insensitive matching or not
\r
3095 * @returns {RegExp} constructed object
\r
3096 * @memberof DataTable#oApi
\r
3098 function _fnFilterCreateSearch( search, regex, smart, caseInsensitive )
\r
3102 _fnEscapeRegex( search );
\r
3105 /* For smart filtering we want to allow the search to work regardless of
\r
3106 * word order. We also want double quoted text to be preserved, so word
\r
3107 * order is important - a la google. So this is what we want to
\r
3110 * ^(?=.*?\bone\b)(?=.*?\btwo three\b)(?=.*?\bfour\b).*$
\r
3112 var a = $.map( search.match( /"[^"]+"|[^ ]+/g ) || [''], function ( word ) {
\r
3113 if ( word.charAt(0) === '"' ) {
\r
3114 var m = word.match( /^"(.*)"$/ );
\r
3115 word = m ? m[1] : word;
\r
3118 return word.replace('"', '');
\r
3121 search = '^(?=.*?'+a.join( ')(?=.*?' )+').*$';
\r
3124 return new RegExp( search, caseInsensitive ? 'i' : '' );
\r
3129 * Escape a string such that it can be used in a regular expression
\r
3130 * @param {string} sVal string to escape
\r
3131 * @returns {string} escaped string
\r
3132 * @memberof DataTable#oApi
\r
3134 function _fnEscapeRegex ( sVal )
\r
3136 return sVal.replace( _re_escape_regex, '\\$1' );
\r
3141 var __filter_div = $('<div>')[0];
\r
3142 var __filter_div_textContent = __filter_div.textContent !== undefined;
\r
3144 // Update the filtering data for each row if needed (by invalidation or first run)
\r
3145 function _fnFilterData ( settings )
\r
3147 var columns = settings.aoColumns;
\r
3149 var i, j, ien, jen, filterData, cellData, row;
\r
3150 var fomatters = DataTable.ext.type.search;
\r
3151 var wasInvalidated = false;
\r
3153 for ( i=0, ien=settings.aoData.length ; i<ien ; i++ ) {
\r
3154 row = settings.aoData[i];
\r
3156 if ( ! row._aFilterData ) {
\r
3159 for ( j=0, jen=columns.length ; j<jen ; j++ ) {
\r
3160 column = columns[j];
\r
3162 if ( column.bSearchable ) {
\r
3163 cellData = _fnGetCellData( settings, i, j, 'filter' );
\r
3165 if ( fomatters[ column.sType ] ) {
\r
3166 cellData = fomatters[ column.sType ]( cellData );
\r
3169 // Search in DataTables 1.10 is string based. In 1.11 this
\r
3170 // should be altered to also allow strict type checking.
\r
3171 if ( cellData === null ) {
\r
3175 if ( typeof cellData !== 'string' && cellData.toString ) {
\r
3176 cellData = cellData.toString();
\r
3183 // If it looks like there is an HTML entity in the string,
\r
3184 // attempt to decode it so sorting works as expected. Note that
\r
3185 // we could use a single line of jQuery to do this, but the DOM
\r
3186 // method used here is much faster http://jsperf.com/html-decode
\r
3187 if ( cellData.indexOf && cellData.indexOf('&') !== -1 ) {
\r
3188 __filter_div.innerHTML = cellData;
\r
3189 cellData = __filter_div_textContent ?
\r
3190 __filter_div.textContent :
\r
3191 __filter_div.innerText;
\r
3194 if ( cellData.replace ) {
\r
3195 cellData = cellData.replace(/[\r\n]/g, '');
\r
3198 filterData.push( cellData );
\r
3201 row._aFilterData = filterData;
\r
3202 row._sFilterRow = filterData.join(' ');
\r
3203 wasInvalidated = true;
\r
3207 return wasInvalidated;
\r
3212 * Convert from the internal Hungarian notation to camelCase for external
\r
3214 * @param {object} obj Object to convert
\r
3215 * @returns {object} Inverted object
\r
3216 * @memberof DataTable#oApi
\r
3218 function _fnSearchToCamel ( obj )
\r
3221 search: obj.sSearch,
\r
3222 smart: obj.bSmart,
\r
3223 regex: obj.bRegex,
\r
3224 caseInsensitive: obj.bCaseInsensitive
\r
3231 * Convert from camelCase notation to the internal Hungarian. We could use the
\r
3232 * Hungarian convert function here, but this is cleaner
\r
3233 * @param {object} obj Object to convert
\r
3234 * @returns {object} Inverted object
\r
3235 * @memberof DataTable#oApi
\r
3237 function _fnSearchToHung ( obj )
\r
3240 sSearch: obj.search,
\r
3241 bSmart: obj.smart,
\r
3242 bRegex: obj.regex,
\r
3243 bCaseInsensitive: obj.caseInsensitive
\r
3248 * Generate the node required for the info display
\r
3249 * @param {object} oSettings dataTables settings object
\r
3250 * @returns {node} Information element
\r
3251 * @memberof DataTable#oApi
\r
3253 function _fnFeatureHtmlInfo ( settings )
\r
3256 tid = settings.sTableId,
\r
3257 nodes = settings.aanFeatures.i,
\r
3259 'class': settings.oClasses.sInfo,
\r
3260 'id': ! nodes ? tid+'_info' : null
\r
3264 // Update display on each draw
\r
3265 settings.aoDrawCallback.push( {
\r
3266 "fn": _fnUpdateInfo,
\r
3267 "sName": "information"
\r
3271 .attr( 'role', 'status' )
\r
3272 .attr( 'aria-live', 'polite' );
\r
3274 // Table is described by our info div
\r
3275 $(settings.nTable).attr( 'aria-describedby', tid+'_info' );
\r
3283 * Update the information elements in the display
\r
3284 * @param {object} settings dataTables settings object
\r
3285 * @memberof DataTable#oApi
\r
3287 function _fnUpdateInfo ( settings )
\r
3289 /* Show information about the table */
\r
3290 var nodes = settings.aanFeatures.i;
\r
3291 if ( nodes.length === 0 ) {
\r
3296 lang = settings.oLanguage,
\r
3297 start = settings._iDisplayStart+1,
\r
3298 end = settings.fnDisplayEnd(),
\r
3299 max = settings.fnRecordsTotal(),
\r
3300 total = settings.fnRecordsDisplay(),
\r
3305 if ( total !== max ) {
\r
3306 /* Record set after filtering */
\r
3307 out += ' ' + lang.sInfoFiltered;
\r
3310 // Convert the macros
\r
3311 out += lang.sInfoPostFix;
\r
3312 out = _fnInfoMacros( settings, out );
\r
3314 var callback = lang.fnInfoCallback;
\r
3315 if ( callback !== null ) {
\r
3316 out = callback.call( settings.oInstance,
\r
3317 settings, start, end, max, total, out
\r
3321 $(nodes).html( out );
\r
3325 function _fnInfoMacros ( settings, str )
\r
3327 // When infinite scrolling, we are always starting at 1. _iDisplayStart is used only
\r
3330 formatter = settings.fnFormatNumber,
\r
3331 start = settings._iDisplayStart+1,
\r
3332 len = settings._iDisplayLength,
\r
3333 vis = settings.fnRecordsDisplay(),
\r
3337 replace(/_START_/g, formatter.call( settings, start ) ).
\r
3338 replace(/_END_/g, formatter.call( settings, settings.fnDisplayEnd() ) ).
\r
3339 replace(/_MAX_/g, formatter.call( settings, settings.fnRecordsTotal() ) ).
\r
3340 replace(/_TOTAL_/g, formatter.call( settings, vis ) ).
\r
3341 replace(/_PAGE_/g, formatter.call( settings, all ? 1 : Math.ceil( start / len ) ) ).
\r
3342 replace(/_PAGES_/g, formatter.call( settings, all ? 1 : Math.ceil( vis / len ) ) );
\r
3348 * Draw the table for the first time, adding all required features
\r
3349 * @param {object} settings dataTables settings object
\r
3350 * @memberof DataTable#oApi
\r
3352 function _fnInitialise ( settings )
\r
3354 var i, iLen, iAjaxStart=settings.iInitDisplayStart;
\r
3355 var columns = settings.aoColumns, column;
\r
3356 var features = settings.oFeatures;
\r
3357 var deferLoading = settings.bDeferLoading; // value modified by the draw
\r
3359 /* Ensure that the table data is fully initialised */
\r
3360 if ( ! settings.bInitialised ) {
\r
3361 setTimeout( function(){ _fnInitialise( settings ); }, 200 );
\r
3365 /* Show the display HTML options */
\r
3366 _fnAddOptionsHtml( settings );
\r
3368 /* Build and draw the header / footer for the table */
\r
3369 _fnBuildHead( settings );
\r
3370 _fnDrawHead( settings, settings.aoHeader );
\r
3371 _fnDrawHead( settings, settings.aoFooter );
\r
3373 /* Okay to show that something is going on now */
\r
3374 _fnProcessingDisplay( settings, true );
\r
3376 /* Calculate sizes for columns */
\r
3377 if ( features.bAutoWidth ) {
\r
3378 _fnCalculateColumnWidths( settings );
\r
3381 for ( i=0, iLen=columns.length ; i<iLen ; i++ ) {
\r
3382 column = columns[i];
\r
3384 if ( column.sWidth ) {
\r
3385 column.nTh.style.width = _fnStringToCss( column.sWidth );
\r
3389 _fnCallbackFire( settings, null, 'preInit', [settings] );
\r
3391 // If there is default sorting required - let's do it. The sort function
\r
3392 // will do the drawing for us. Otherwise we draw the table regardless of the
\r
3393 // Ajax source - this allows the table to look initialised for Ajax sourcing
\r
3394 // data (show 'loading' message possibly)
\r
3395 _fnReDraw( settings );
\r
3397 // Server-side processing init complete is done by _fnAjaxUpdateDraw
\r
3398 var dataSrc = _fnDataSource( settings );
\r
3399 if ( dataSrc != 'ssp' || deferLoading ) {
\r
3400 // if there is an ajax source load the data
\r
3401 if ( dataSrc == 'ajax' ) {
\r
3402 _fnBuildAjax( settings, [], function(json) {
\r
3403 var aData = _fnAjaxDataSrc( settings, json );
\r
3405 // Got the data - add it to the table
\r
3406 for ( i=0 ; i<aData.length ; i++ ) {
\r
3407 _fnAddData( settings, aData[i] );
\r
3410 // Reset the init display for cookie saving. We've already done
\r
3411 // a filter, and therefore cleared it before. So we need to make
\r
3412 // it appear 'fresh'
\r
3413 settings.iInitDisplayStart = iAjaxStart;
\r
3415 _fnReDraw( settings );
\r
3417 _fnProcessingDisplay( settings, false );
\r
3418 _fnInitComplete( settings, json );
\r
3422 _fnProcessingDisplay( settings, false );
\r
3423 _fnInitComplete( settings );
\r
3430 * Draw the table for the first time, adding all required features
\r
3431 * @param {object} oSettings dataTables settings object
\r
3432 * @param {object} [json] JSON from the server that completed the table, if using Ajax source
\r
3433 * with client-side processing (optional)
\r
3434 * @memberof DataTable#oApi
\r
3436 function _fnInitComplete ( settings, json )
\r
3438 settings._bInitComplete = true;
\r
3440 // When data was added after the initialisation (data or Ajax) we need to
\r
3441 // calculate the column sizing
\r
3442 if ( json || settings.oInit.aaData ) {
\r
3443 _fnAdjustColumnSizing( settings );
\r
3446 _fnCallbackFire( settings, null, 'plugin-init', [settings, json] );
\r
3447 _fnCallbackFire( settings, 'aoInitComplete', 'init', [settings, json] );
\r
3451 function _fnLengthChange ( settings, val )
\r
3453 var len = parseInt( val, 10 );
\r
3454 settings._iDisplayLength = len;
\r
3456 _fnLengthOverflow( settings );
\r
3458 // Fire length change event
\r
3459 _fnCallbackFire( settings, null, 'length', [settings, len] );
\r
3464 * Generate the node required for user display length changing
\r
3465 * @param {object} settings dataTables settings object
\r
3466 * @returns {node} Display length feature node
\r
3467 * @memberof DataTable#oApi
\r
3469 function _fnFeatureHtmlLength ( settings )
\r
3472 classes = settings.oClasses,
\r
3473 tableId = settings.sTableId,
\r
3474 menu = settings.aLengthMenu,
\r
3475 d2 = $.isArray( menu[0] ),
\r
3476 lengths = d2 ? menu[0] : menu,
\r
3477 language = d2 ? menu[1] : menu;
\r
3479 var select = $('<select/>', {
\r
3480 'name': tableId+'_length',
\r
3481 'aria-controls': tableId,
\r
3482 'class': classes.sLengthSelect
\r
3485 for ( var i=0, ien=lengths.length ; i<ien ; i++ ) {
\r
3486 select[0][ i ] = new Option( language[i], lengths[i] );
\r
3489 var div = $('<div><label/></div>').addClass( classes.sLength );
\r
3490 if ( ! settings.aanFeatures.l ) {
\r
3491 div[0].id = tableId+'_length';
\r
3494 div.children().append(
\r
3495 settings.oLanguage.sLengthMenu.replace( '_MENU_', select[0].outerHTML )
\r
3498 // Can't use `select` variable as user might provide their own and the
\r
3499 // reference is broken by the use of outerHTML
\r
3501 .val( settings._iDisplayLength )
\r
3502 .bind( 'change.DT', function(e) {
\r
3503 _fnLengthChange( settings, $(this).val() );
\r
3504 _fnDraw( settings );
\r
3507 // Update node value whenever anything changes the table's length
\r
3508 $(settings.nTable).bind( 'length.dt.DT', function (e, s, len) {
\r
3509 if ( settings === s ) {
\r
3510 $('select', div).val( len );
\r
3519 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
\r
3520 * Note that most of the paging logic is done in
\r
3521 * DataTable.ext.pager
\r
3525 * Generate the node required for default pagination
\r
3526 * @param {object} oSettings dataTables settings object
\r
3527 * @returns {node} Pagination feature node
\r
3528 * @memberof DataTable#oApi
\r
3530 function _fnFeatureHtmlPaginate ( settings )
\r
3533 type = settings.sPaginationType,
\r
3534 plugin = DataTable.ext.pager[ type ],
\r
3535 modern = typeof plugin === 'function',
\r
3536 redraw = function( settings ) {
\r
3537 _fnDraw( settings );
\r
3539 node = $('<div/>').addClass( settings.oClasses.sPaging + type )[0],
\r
3540 features = settings.aanFeatures;
\r
3543 plugin.fnInit( settings, node, redraw );
\r
3546 /* Add a draw callback for the pagination on first instance, to update the paging display */
\r
3547 if ( ! features.p )
\r
3549 node.id = settings.sTableId+'_paginate';
\r
3551 settings.aoDrawCallback.push( {
\r
3552 "fn": function( settings ) {
\r
3555 start = settings._iDisplayStart,
\r
3556 len = settings._iDisplayLength,
\r
3557 visRecords = settings.fnRecordsDisplay(),
\r
3559 page = all ? 0 : Math.ceil( start / len ),
\r
3560 pages = all ? 1 : Math.ceil( visRecords / len ),
\r
3561 buttons = plugin(page, pages),
\r
3564 for ( i=0, ien=features.p.length ; i<ien ; i++ ) {
\r
3565 _fnRenderer( settings, 'pageButton' )(
\r
3566 settings, features.p[i], i, buttons, page, pages
\r
3571 plugin.fnUpdate( settings, redraw );
\r
3574 "sName": "pagination"
\r
3583 * Alter the display settings to change the page
\r
3584 * @param {object} settings DataTables settings object
\r
3585 * @param {string|int} action Paging action to take: "first", "previous",
\r
3586 * "next" or "last" or page number to jump to (integer)
\r
3587 * @param [bool] redraw Automatically draw the update or not
\r
3588 * @returns {bool} true page has changed, false - no change
\r
3589 * @memberof DataTable#oApi
\r
3591 function _fnPageChange ( settings, action, redraw )
\r
3594 start = settings._iDisplayStart,
\r
3595 len = settings._iDisplayLength,
\r
3596 records = settings.fnRecordsDisplay();
\r
3598 if ( records === 0 || len === -1 )
\r
3602 else if ( typeof action === "number" )
\r
3604 start = action * len;
\r
3606 if ( start > records )
\r
3611 else if ( action == "first" )
\r
3615 else if ( action == "previous" )
\r
3617 start = len >= 0 ?
\r
3626 else if ( action == "next" )
\r
3628 if ( start + len < records )
\r
3633 else if ( action == "last" )
\r
3635 start = Math.floor( (records-1) / len) * len;
\r
3639 _fnLog( settings, 0, "Unknown paging action: "+action, 5 );
\r
3642 var changed = settings._iDisplayStart !== start;
\r
3643 settings._iDisplayStart = start;
\r
3646 _fnCallbackFire( settings, null, 'page', [settings] );
\r
3649 _fnDraw( settings );
\r
3659 * Generate the node required for the processing node
\r
3660 * @param {object} settings dataTables settings object
\r
3661 * @returns {node} Processing element
\r
3662 * @memberof DataTable#oApi
\r
3664 function _fnFeatureHtmlProcessing ( settings )
\r
3666 return $('<div/>', {
\r
3667 'id': ! settings.aanFeatures.r ? settings.sTableId+'_processing' : null,
\r
3668 'class': settings.oClasses.sProcessing
\r
3670 .html( settings.oLanguage.sProcessing )
\r
3671 .insertBefore( settings.nTable )[0];
\r
3676 * Display or hide the processing indicator
\r
3677 * @param {object} settings dataTables settings object
\r
3678 * @param {bool} show Show the processing indicator (true) or not (false)
\r
3679 * @memberof DataTable#oApi
\r
3681 function _fnProcessingDisplay ( settings, show )
\r
3683 if ( settings.oFeatures.bProcessing ) {
\r
3684 $(settings.aanFeatures.r).css( 'display', show ? 'block' : 'none' );
\r
3687 _fnCallbackFire( settings, null, 'processing', [settings, show] );
\r
3691 * Add any control elements for the table - specifically scrolling
\r
3692 * @param {object} settings dataTables settings object
\r
3693 * @returns {node} Node to add to the DOM
\r
3694 * @memberof DataTable#oApi
\r
3696 function _fnFeatureHtmlTable ( settings )
\r
3698 var table = $(settings.nTable);
\r
3700 // Add the ARIA grid role to the table
\r
3701 table.attr( 'role', 'grid' );
\r
3703 // Scrolling from here on in
\r
3704 var scroll = settings.oScroll;
\r
3706 if ( scroll.sX === '' && scroll.sY === '' ) {
\r
3707 return settings.nTable;
\r
3710 var scrollX = scroll.sX;
\r
3711 var scrollY = scroll.sY;
\r
3712 var classes = settings.oClasses;
\r
3713 var caption = table.children('caption');
\r
3714 var captionSide = caption.length ? caption[0]._captionSide : null;
\r
3715 var headerClone = $( table[0].cloneNode(false) );
\r
3716 var footerClone = $( table[0].cloneNode(false) );
\r
3717 var footer = table.children('tfoot');
\r
3718 var _div = '<div/>';
\r
3719 var size = function ( s ) {
\r
3720 return !s ? null : _fnStringToCss( s );
\r
3723 if ( ! footer.length ) {
\r
3728 * The HTML structure that we want to generate in this function is:
\r
3730 * div - scroll head
\r
3731 * div - scroll head inner
\r
3732 * table - scroll head table
\r
3734 * div - scroll body
\r
3735 * table - table (master table)
\r
3736 * thead - thead clone for sizing
\r
3738 * div - scroll foot
\r
3739 * div - scroll foot inner
\r
3740 * table - scroll foot table
\r
3743 var scroller = $( _div, { 'class': classes.sScrollWrapper } )
\r
3745 $(_div, { 'class': classes.sScrollHead } )
\r
3747 overflow: 'hidden',
\r
3748 position: 'relative',
\r
3750 width: scrollX ? size(scrollX) : '100%'
\r
3753 $(_div, { 'class': classes.sScrollHeadInner } )
\r
3755 'box-sizing': 'content-box',
\r
3756 width: scroll.sXInner || '100%'
\r
3761 .css( 'margin-left', 0 )
\r
3762 .append( captionSide === 'top' ? caption : null )
\r
3764 table.children('thead')
\r
3770 $(_div, { 'class': classes.sScrollBody } )
\r
3772 position: 'relative',
\r
3774 width: size( scrollX )
\r
3781 $(_div, { 'class': classes.sScrollFoot } )
\r
3783 overflow: 'hidden',
\r
3785 width: scrollX ? size(scrollX) : '100%'
\r
3788 $(_div, { 'class': classes.sScrollFootInner } )
\r
3792 .css( 'margin-left', 0 )
\r
3793 .append( captionSide === 'bottom' ? caption : null )
\r
3795 table.children('tfoot')
\r
3802 var children = scroller.children();
\r
3803 var scrollHead = children[0];
\r
3804 var scrollBody = children[1];
\r
3805 var scrollFoot = footer ? children[2] : null;
\r
3807 // When the body is scrolled, then we also want to scroll the headers
\r
3809 $(scrollBody).on( 'scroll.DT', function (e) {
\r
3810 var scrollLeft = this.scrollLeft;
\r
3812 scrollHead.scrollLeft = scrollLeft;
\r
3815 scrollFoot.scrollLeft = scrollLeft;
\r
3820 $(scrollBody).css(
\r
3821 scrollY && scroll.bCollapse ? 'max-height' : 'height',
\r
3825 settings.nScrollHead = scrollHead;
\r
3826 settings.nScrollBody = scrollBody;
\r
3827 settings.nScrollFoot = scrollFoot;
\r
3829 // On redraw - align columns
\r
3830 settings.aoDrawCallback.push( {
\r
3831 "fn": _fnScrollDraw,
\r
3832 "sName": "scrolling"
\r
3835 return scroller[0];
\r
3841 * Update the header, footer and body tables for resizing - i.e. column
\r
3844 * Welcome to the most horrible function DataTables. The process that this
\r
3845 * function follows is basically:
\r
3846 * 1. Re-create the table inside the scrolling div
\r
3847 * 2. Take live measurements from the DOM
\r
3848 * 3. Apply the measurements to align the columns
\r
3851 * @param {object} settings dataTables settings object
\r
3852 * @memberof DataTable#oApi
\r
3854 function _fnScrollDraw ( settings )
\r
3856 // Given that this is such a monster function, a lot of variables are use
\r
3857 // to try and keep the minimised size as small as possible
\r
3859 scroll = settings.oScroll,
\r
3860 scrollX = scroll.sX,
\r
3861 scrollXInner = scroll.sXInner,
\r
3862 scrollY = scroll.sY,
\r
3863 barWidth = scroll.iBarWidth,
\r
3864 divHeader = $(settings.nScrollHead),
\r
3865 divHeaderStyle = divHeader[0].style,
\r
3866 divHeaderInner = divHeader.children('div'),
\r
3867 divHeaderInnerStyle = divHeaderInner[0].style,
\r
3868 divHeaderTable = divHeaderInner.children('table'),
\r
3869 divBodyEl = settings.nScrollBody,
\r
3870 divBody = $(divBodyEl),
\r
3871 divBodyStyle = divBodyEl.style,
\r
3872 divFooter = $(settings.nScrollFoot),
\r
3873 divFooterInner = divFooter.children('div'),
\r
3874 divFooterTable = divFooterInner.children('table'),
\r
3875 header = $(settings.nTHead),
\r
3876 table = $(settings.nTable),
\r
3877 tableEl = table[0],
\r
3878 tableStyle = tableEl.style,
\r
3879 footer = settings.nTFoot ? $(settings.nTFoot) : null,
\r
3880 browser = settings.oBrowser,
\r
3881 ie67 = browser.bScrollOversize,
\r
3882 dtHeaderCells = _pluck( settings.aoColumns, 'nTh' ),
\r
3883 headerTrgEls, footerTrgEls,
\r
3884 headerSrcEls, footerSrcEls,
\r
3885 headerCopy, footerCopy,
\r
3886 headerWidths=[], footerWidths=[],
\r
3887 headerContent=[], footerContent=[],
\r
3888 idx, correction, sanityWidth,
\r
3889 zeroOut = function(nSizer) {
\r
3890 var style = nSizer.style;
\r
3891 style.paddingTop = "0";
\r
3892 style.paddingBottom = "0";
\r
3893 style.borderTopWidth = "0";
\r
3894 style.borderBottomWidth = "0";
\r
3898 // If the scrollbar visibility has changed from the last draw, we need to
\r
3899 // adjust the column sizes as the table width will have changed to account
\r
3900 // for the scrollbar
\r
3901 var scrollBarVis = divBodyEl.scrollHeight > divBodyEl.clientHeight;
\r
3903 if ( settings.scrollBarVis !== scrollBarVis && settings.scrollBarVis !== undefined ) {
\r
3904 settings.scrollBarVis = scrollBarVis;
\r
3905 _fnAdjustColumnSizing( settings );
\r
3906 return; // adjust column sizing will call this function again
\r
3909 settings.scrollBarVis = scrollBarVis;
\r
3913 * 1. Re-create the table inside the scrolling div
\r
3916 // Remove the old minimised thead and tfoot elements in the inner table
\r
3917 table.children('thead, tfoot').remove();
\r
3920 footerCopy = footer.clone().prependTo( table );
\r
3921 footerTrgEls = footer.find('tr'); // the original tfoot is in its own table and must be sized
\r
3922 footerSrcEls = footerCopy.find('tr');
\r
3925 // Clone the current header and footer elements and then place it into the inner table
\r
3926 headerCopy = header.clone().prependTo( table );
\r
3927 headerTrgEls = header.find('tr'); // original header is in its own table
\r
3928 headerSrcEls = headerCopy.find('tr');
\r
3929 headerCopy.find('th, td').removeAttr('tabindex');
\r
3933 * 2. Take live measurements from the DOM - do not alter the DOM itself!
\r
3936 // Remove old sizing and apply the calculated column widths
\r
3937 // Get the unique column headers in the newly created (cloned) header. We want to apply the
\r
3938 // calculated sizes to this header
\r
3941 divBodyStyle.width = '100%';
\r
3942 divHeader[0].style.width = '100%';
\r
3945 $.each( _fnGetUniqueThs( settings, headerCopy ), function ( i, el ) {
\r
3946 idx = _fnVisibleToColumnIndex( settings, i );
\r
3947 el.style.width = settings.aoColumns[idx].sWidth;
\r
3951 _fnApplyToChildren( function(n) {
\r
3952 n.style.width = "";
\r
3953 }, footerSrcEls );
\r
3956 // Size the table as a whole
\r
3957 sanityWidth = table.outerWidth();
\r
3958 if ( scrollX === "" ) {
\r
3960 tableStyle.width = "100%";
\r
3962 // IE7 will make the width of the table when 100% include the scrollbar
\r
3963 // - which is shouldn't. When there is a scrollbar we need to take this
\r
3965 if ( ie67 && (table.find('tbody').height() > divBodyEl.offsetHeight ||
\r
3966 divBody.css('overflow-y') == "scroll")
\r
3968 tableStyle.width = _fnStringToCss( table.outerWidth() - barWidth);
\r
3971 // Recalculate the sanity width
\r
3972 sanityWidth = table.outerWidth();
\r
3974 else if ( scrollXInner !== "" ) {
\r
3975 // legacy x scroll inner has been given - use it
\r
3976 tableStyle.width = _fnStringToCss(scrollXInner);
\r
3978 // Recalculate the sanity width
\r
3979 sanityWidth = table.outerWidth();
\r
3982 // Hidden header should have zero height, so remove padding and borders. Then
\r
3983 // set the width based on the real headers
\r
3985 // Apply all styles in one pass
\r
3986 _fnApplyToChildren( zeroOut, headerSrcEls );
\r
3988 // Read all widths in next pass
\r
3989 _fnApplyToChildren( function(nSizer) {
\r
3990 headerContent.push( nSizer.innerHTML );
\r
3991 headerWidths.push( _fnStringToCss( $(nSizer).css('width') ) );
\r
3992 }, headerSrcEls );
\r
3994 // Apply all widths in final pass
\r
3995 _fnApplyToChildren( function(nToSize, i) {
\r
3996 // Only apply widths to the DataTables detected header cells - this
\r
3997 // prevents complex headers from having contradictory sizes applied
\r
3998 if ( $.inArray( nToSize, dtHeaderCells ) !== -1 ) {
\r
3999 nToSize.style.width = headerWidths[i];
\r
4001 }, headerTrgEls );
\r
4003 $(headerSrcEls).height(0);
\r
4005 /* Same again with the footer if we have one */
\r
4008 _fnApplyToChildren( zeroOut, footerSrcEls );
\r
4010 _fnApplyToChildren( function(nSizer) {
\r
4011 footerContent.push( nSizer.innerHTML );
\r
4012 footerWidths.push( _fnStringToCss( $(nSizer).css('width') ) );
\r
4013 }, footerSrcEls );
\r
4015 _fnApplyToChildren( function(nToSize, i) {
\r
4016 nToSize.style.width = footerWidths[i];
\r
4017 }, footerTrgEls );
\r
4019 $(footerSrcEls).height(0);
\r
4024 * 3. Apply the measurements
\r
4027 // "Hide" the header and footer that we used for the sizing. We need to keep
\r
4028 // the content of the cell so that the width applied to the header and body
\r
4029 // both match, but we want to hide it completely. We want to also fix their
\r
4030 // width to what they currently are
\r
4031 _fnApplyToChildren( function(nSizer, i) {
\r
4032 nSizer.innerHTML = '<div class="dataTables_sizing" style="height:0;overflow:hidden;">'+headerContent[i]+'</div>';
\r
4033 nSizer.style.width = headerWidths[i];
\r
4034 }, headerSrcEls );
\r
4038 _fnApplyToChildren( function(nSizer, i) {
\r
4039 nSizer.innerHTML = '<div class="dataTables_sizing" style="height:0;overflow:hidden;">'+footerContent[i]+'</div>';
\r
4040 nSizer.style.width = footerWidths[i];
\r
4041 }, footerSrcEls );
\r
4044 // Sanity check that the table is of a sensible width. If not then we are going to get
\r
4045 // misalignment - try to prevent this by not allowing the table to shrink below its min width
\r
4046 if ( table.outerWidth() < sanityWidth )
\r
4048 // The min width depends upon if we have a vertical scrollbar visible or not */
\r
4049 correction = ((divBodyEl.scrollHeight > divBodyEl.offsetHeight ||
\r
4050 divBody.css('overflow-y') == "scroll")) ?
\r
4051 sanityWidth+barWidth :
\r
4054 // IE6/7 are a law unto themselves...
\r
4055 if ( ie67 && (divBodyEl.scrollHeight >
\r
4056 divBodyEl.offsetHeight || divBody.css('overflow-y') == "scroll")
\r
4058 tableStyle.width = _fnStringToCss( correction-barWidth );
\r
4061 // And give the user a warning that we've stopped the table getting too small
\r
4062 if ( scrollX === "" || scrollXInner !== "" ) {
\r
4063 _fnLog( settings, 1, 'Possible column misalignment', 6 );
\r
4068 correction = '100%';
\r
4071 // Apply to the container elements
\r
4072 divBodyStyle.width = _fnStringToCss( correction );
\r
4073 divHeaderStyle.width = _fnStringToCss( correction );
\r
4076 settings.nScrollFoot.style.width = _fnStringToCss( correction );
\r
4083 if ( ! scrollY ) {
\r
4084 /* IE7< puts a vertical scrollbar in place (when it shouldn't be) due to subtracting
\r
4085 * the scrollbar height from the visible display, rather than adding it on. We need to
\r
4086 * set the height in order to sort this. Don't want to do it in any other browsers.
\r
4089 divBodyStyle.height = _fnStringToCss( tableEl.offsetHeight+barWidth );
\r
4093 /* Finally set the width's of the header and footer tables */
\r
4094 var iOuterWidth = table.outerWidth();
\r
4095 divHeaderTable[0].style.width = _fnStringToCss( iOuterWidth );
\r
4096 divHeaderInnerStyle.width = _fnStringToCss( iOuterWidth );
\r
4098 // Figure out if there are scrollbar present - if so then we need a the header and footer to
\r
4099 // provide a bit more space to allow "overflow" scrolling (i.e. past the scrollbar)
\r
4100 var bScrolling = table.height() > divBodyEl.clientHeight || divBody.css('overflow-y') == "scroll";
\r
4101 var padding = 'padding' + (browser.bScrollbarLeft ? 'Left' : 'Right' );
\r
4102 divHeaderInnerStyle[ padding ] = bScrolling ? barWidth+"px" : "0px";
\r
4105 divFooterTable[0].style.width = _fnStringToCss( iOuterWidth );
\r
4106 divFooterInner[0].style.width = _fnStringToCss( iOuterWidth );
\r
4107 divFooterInner[0].style[padding] = bScrolling ? barWidth+"px" : "0px";
\r
4110 // Correct DOM ordering for colgroup - comes before the thead
\r
4111 table.children('colgroup').insertBefore( table.children('thead') );
\r
4113 /* Adjust the position of the header in case we loose the y-scrollbar */
\r
4116 // If sorting or filtering has occurred, jump the scrolling back to the top
\r
4117 // only if we aren't holding the position
\r
4118 if ( (settings.bSorted || settings.bFiltered) && ! settings._drawHold ) {
\r
4119 divBodyEl.scrollTop = 0;
\r
4126 * Apply a given function to the display child nodes of an element array (typically
\r
4127 * TD children of TR rows
\r
4128 * @param {function} fn Method to apply to the objects
\r
4129 * @param array {nodes} an1 List of elements to look through for display children
\r
4130 * @param array {nodes} an2 Another list (identical structure to the first) - optional
\r
4131 * @memberof DataTable#oApi
\r
4133 function _fnApplyToChildren( fn, an1, an2 )
\r
4135 var index=0, i=0, iLen=an1.length;
\r
4136 var nNode1, nNode2;
\r
4138 while ( i < iLen ) {
\r
4139 nNode1 = an1[i].firstChild;
\r
4140 nNode2 = an2 ? an2[i].firstChild : null;
\r
4142 while ( nNode1 ) {
\r
4143 if ( nNode1.nodeType === 1 ) {
\r
4145 fn( nNode1, nNode2, index );
\r
4148 fn( nNode1, index );
\r
4154 nNode1 = nNode1.nextSibling;
\r
4155 nNode2 = an2 ? nNode2.nextSibling : null;
\r
4164 var __re_html_remove = /<.*?>/g;
\r
4168 * Calculate the width of columns for the table
\r
4169 * @param {object} oSettings dataTables settings object
\r
4170 * @memberof DataTable#oApi
\r
4172 function _fnCalculateColumnWidths ( oSettings )
\r
4175 table = oSettings.nTable,
\r
4176 columns = oSettings.aoColumns,
\r
4177 scroll = oSettings.oScroll,
\r
4178 scrollY = scroll.sY,
\r
4179 scrollX = scroll.sX,
\r
4180 scrollXInner = scroll.sXInner,
\r
4181 columnCount = columns.length,
\r
4182 visibleColumns = _fnGetColumns( oSettings, 'bVisible' ),
\r
4183 headerCells = $('th', oSettings.nTHead),
\r
4184 tableWidthAttr = table.getAttribute('width'), // from DOM element
\r
4185 tableContainer = table.parentNode,
\r
4186 userInputs = false,
\r
4187 i, column, columnIdx, width, outerWidth,
\r
4188 browser = oSettings.oBrowser,
\r
4189 ie67 = browser.bScrollOversize;
\r
4191 var styleWidth = table.style.width;
\r
4192 if ( styleWidth && styleWidth.indexOf('%') !== -1 ) {
\r
4193 tableWidthAttr = styleWidth;
\r
4196 /* Convert any user input sizes into pixel sizes */
\r
4197 for ( i=0 ; i<visibleColumns.length ; i++ ) {
\r
4198 column = columns[ visibleColumns[i] ];
\r
4200 if ( column.sWidth !== null ) {
\r
4201 column.sWidth = _fnConvertToWidth( column.sWidthOrig, tableContainer );
\r
4203 userInputs = true;
\r
4207 /* If the number of columns in the DOM equals the number that we have to
\r
4208 * process in DataTables, then we can use the offsets that are created by
\r
4209 * the web- browser. No custom sizes can be set in order for this to happen,
\r
4210 * nor scrolling used
\r
4212 if ( ie67 || ! userInputs && ! scrollX && ! scrollY &&
\r
4213 columnCount == _fnVisbleColumns( oSettings ) &&
\r
4214 columnCount == headerCells.length
\r
4216 for ( i=0 ; i<columnCount ; i++ ) {
\r
4217 var colIdx = _fnVisibleToColumnIndex( oSettings, i );
\r
4219 if ( colIdx !== null ) {
\r
4220 columns[ colIdx ].sWidth = _fnStringToCss( headerCells.eq(i).width() );
\r
4226 // Otherwise construct a single row, worst case, table with the widest
\r
4227 // node in the data, assign any user defined widths, then insert it into
\r
4228 // the DOM and allow the browser to do all the hard work of calculating
\r
4230 var tmpTable = $(table).clone() // don't use cloneNode - IE8 will remove events on the main table
\r
4231 .css( 'visibility', 'hidden' )
\r
4232 .removeAttr( 'id' );
\r
4234 // Clean up the table body
\r
4235 tmpTable.find('tbody tr').remove();
\r
4236 var tr = $('<tr/>').appendTo( tmpTable.find('tbody') );
\r
4238 // Clone the table header and footer - we can't use the header / footer
\r
4239 // from the cloned table, since if scrolling is active, the table's
\r
4240 // real header and footer are contained in different table tags
\r
4241 tmpTable.find('thead, tfoot').remove();
\r
4243 .append( $(oSettings.nTHead).clone() )
\r
4244 .append( $(oSettings.nTFoot).clone() );
\r
4246 // Remove any assigned widths from the footer (from scrolling)
\r
4247 tmpTable.find('tfoot th, tfoot td').css('width', '');
\r
4249 // Apply custom sizing to the cloned header
\r
4250 headerCells = _fnGetUniqueThs( oSettings, tmpTable.find('thead')[0] );
\r
4252 for ( i=0 ; i<visibleColumns.length ; i++ ) {
\r
4253 column = columns[ visibleColumns[i] ];
\r
4255 headerCells[i].style.width = column.sWidthOrig !== null && column.sWidthOrig !== '' ?
\r
4256 _fnStringToCss( column.sWidthOrig ) :
\r
4259 // For scrollX we need to force the column width otherwise the
\r
4260 // browser will collapse it. If this width is smaller than the
\r
4261 // width the column requires, then it will have no effect
\r
4262 if ( column.sWidthOrig && scrollX ) {
\r
4263 $( headerCells[i] ).append( $('<div/>').css( {
\r
4264 width: column.sWidthOrig,
\r
4273 // Find the widest cell for each column and put it into the table
\r
4274 if ( oSettings.aoData.length ) {
\r
4275 for ( i=0 ; i<visibleColumns.length ; i++ ) {
\r
4276 columnIdx = visibleColumns[i];
\r
4277 column = columns[ columnIdx ];
\r
4279 $( _fnGetWidestNode( oSettings, columnIdx ) )
\r
4281 .append( column.sContentPadding )
\r
4286 // Tidy the temporary table - remove name attributes so there aren't
\r
4287 // duplicated in the dom (radio elements for example)
\r
4288 $('[name]', tmpTable).removeAttr('name');
\r
4290 // Table has been built, attach to the document so we can work with it.
\r
4291 // A holding element is used, positioned at the top of the container
\r
4292 // with minimal height, so it has no effect on if the container scrolls
\r
4293 // or not. Otherwise it might trigger scrolling when it actually isn't
\r
4295 var holder = $('<div/>').css( scrollX || scrollY ?
\r
4297 position: 'absolute',
\r
4302 overflow: 'hidden'
\r
4306 .append( tmpTable )
\r
4307 .appendTo( tableContainer );
\r
4309 // When scrolling (X or Y) we want to set the width of the table as
\r
4310 // appropriate. However, when not scrolling leave the table width as it
\r
4311 // is. This results in slightly different, but I think correct behaviour
\r
4312 if ( scrollX && scrollXInner ) {
\r
4313 tmpTable.width( scrollXInner );
\r
4315 else if ( scrollX ) {
\r
4316 tmpTable.css( 'width', 'auto' );
\r
4317 tmpTable.removeAttr('width');
\r
4319 // If there is no width attribute or style, then allow the table to
\r
4321 if ( tmpTable.width() < tableContainer.clientWidth && tableWidthAttr ) {
\r
4322 tmpTable.width( tableContainer.clientWidth );
\r
4325 else if ( scrollY ) {
\r
4326 tmpTable.width( tableContainer.clientWidth );
\r
4328 else if ( tableWidthAttr ) {
\r
4329 tmpTable.width( tableWidthAttr );
\r
4332 // Get the width of each column in the constructed table - we need to
\r
4333 // know the inner width (so it can be assigned to the other table's
\r
4334 // cells) and the outer width so we can calculate the full width of the
\r
4335 // table. This is safe since DataTables requires a unique cell for each
\r
4336 // column, but if ever a header can span multiple columns, this will
\r
4337 // need to be modified.
\r
4339 for ( i=0 ; i<visibleColumns.length ; i++ ) {
\r
4340 var cell = $(headerCells[i]);
\r
4341 var border = cell.outerWidth() - cell.width();
\r
4343 // Use getBounding... where possible (not IE8-) because it can give
\r
4344 // sub-pixel accuracy, which we then want to round up!
\r
4345 var bounding = browser.bBounding ?
\r
4346 Math.ceil( headerCells[i].getBoundingClientRect().width ) :
\r
4347 cell.outerWidth();
\r
4349 // Total is tracked to remove any sub-pixel errors as the outerWidth
\r
4350 // of the table might not equal the total given here (IE!).
\r
4351 total += bounding;
\r
4353 // Width for each column to use
\r
4354 columns[ visibleColumns[i] ].sWidth = _fnStringToCss( bounding - border );
\r
4357 table.style.width = _fnStringToCss( total );
\r
4359 // Finished with the table - ditch it
\r
4363 // If there is a width attr, we want to attach an event listener which
\r
4364 // allows the table sizing to automatically adjust when the window is
\r
4365 // resized. Use the width attr rather than CSS, since we can't know if the
\r
4366 // CSS is a relative value or absolute - DOM read is always px.
\r
4367 if ( tableWidthAttr ) {
\r
4368 table.style.width = _fnStringToCss( tableWidthAttr );
\r
4371 if ( (tableWidthAttr || scrollX) && ! oSettings._reszEvt ) {
\r
4372 var bindResize = function () {
\r
4373 $(window).bind('resize.DT-'+oSettings.sInstance, _fnThrottle( function () {
\r
4374 _fnAdjustColumnSizing( oSettings );
\r
4378 // IE6/7 will crash if we bind a resize event handler on page load.
\r
4379 // To be removed in 1.11 which drops IE6/7 support
\r
4381 setTimeout( bindResize, 1000 );
\r
4387 oSettings._reszEvt = true;
\r
4393 * Throttle the calls to a function. Arguments and context are maintained for
\r
4394 * the throttled function
\r
4395 * @param {function} fn Function to be called
\r
4396 * @param {int} [freq=200] call frequency in mS
\r
4397 * @returns {function} wrapped function
\r
4398 * @memberof DataTable#oApi
\r
4400 function _fnThrottle( fn, freq ) {
\r
4402 frequency = freq !== undefined ? freq : 200,
\r
4406 return function () {
\r
4409 now = +new Date(),
\r
4412 if ( last && now < last + frequency ) {
\r
4413 clearTimeout( timer );
\r
4415 timer = setTimeout( function () {
\r
4417 fn.apply( that, args );
\r
4422 fn.apply( that, args );
\r
4429 * Convert a CSS unit width to pixels (e.g. 2em)
\r
4430 * @param {string} width width to be converted
\r
4431 * @param {node} parent parent to get the with for (required for relative widths) - optional
\r
4432 * @returns {int} width in pixels
\r
4433 * @memberof DataTable#oApi
\r
4435 function _fnConvertToWidth ( width, parent )
\r
4441 var n = $('<div/>')
\r
4442 .css( 'width', _fnStringToCss( width ) )
\r
4443 .appendTo( parent || document.body );
\r
4445 var val = n[0].offsetWidth;
\r
4453 * Get the widest node
\r
4454 * @param {object} settings dataTables settings object
\r
4455 * @param {int} colIdx column of interest
\r
4456 * @returns {node} widest table node
\r
4457 * @memberof DataTable#oApi
\r
4459 function _fnGetWidestNode( settings, colIdx )
\r
4461 var idx = _fnGetMaxLenString( settings, colIdx );
\r
4466 var data = settings.aoData[ idx ];
\r
4467 return ! data.nTr ? // Might not have been created when deferred rendering
\r
4468 $('<td/>').html( _fnGetCellData( settings, idx, colIdx, 'display' ) )[0] :
\r
4469 data.anCells[ colIdx ];
\r
4474 * Get the maximum strlen for each data column
\r
4475 * @param {object} settings dataTables settings object
\r
4476 * @param {int} colIdx column of interest
\r
4477 * @returns {string} max string length for each column
\r
4478 * @memberof DataTable#oApi
\r
4480 function _fnGetMaxLenString( settings, colIdx )
\r
4482 var s, max=-1, maxIdx = -1;
\r
4484 for ( var i=0, ien=settings.aoData.length ; i<ien ; i++ ) {
\r
4485 s = _fnGetCellData( settings, i, colIdx, 'display' )+'';
\r
4486 s = s.replace( __re_html_remove, '' );
\r
4487 s = s.replace( / /g, ' ' );
\r
4489 if ( s.length > max ) {
\r
4500 * Append a CSS unit (only if required) to a string
\r
4501 * @param {string} value to css-ify
\r
4502 * @returns {string} value with css unit
\r
4503 * @memberof DataTable#oApi
\r
4505 function _fnStringToCss( s )
\r
4507 if ( s === null ) {
\r
4511 if ( typeof s == 'number' ) {
\r
4517 // Check it has a unit character already
\r
4518 return s.match(/\d$/) ?
\r
4525 function _fnSortFlatten ( settings )
\r
4531 aoColumns = settings.aoColumns,
\r
4532 aDataSort, iCol, sType, srcCol,
\r
4533 fixed = settings.aaSortingFixed,
\r
4534 fixedObj = $.isPlainObject( fixed ),
\r
4536 add = function ( a ) {
\r
4537 if ( a.length && ! $.isArray( a[0] ) ) {
\r
4539 nestedSort.push( a );
\r
4543 $.merge( nestedSort, a );
\r
4547 // Build the sort array, with pre-fix and post-fix options if they have been
\r
4549 if ( $.isArray( fixed ) ) {
\r
4553 if ( fixedObj && fixed.pre ) {
\r
4557 add( settings.aaSorting );
\r
4559 if (fixedObj && fixed.post ) {
\r
4560 add( fixed.post );
\r
4563 for ( i=0 ; i<nestedSort.length ; i++ )
\r
4565 srcCol = nestedSort[i][0];
\r
4566 aDataSort = aoColumns[ srcCol ].aDataSort;
\r
4568 for ( k=0, kLen=aDataSort.length ; k<kLen ; k++ )
\r
4570 iCol = aDataSort[k];
\r
4571 sType = aoColumns[ iCol ].sType || 'string';
\r
4573 if ( nestedSort[i]._idx === undefined ) {
\r
4574 nestedSort[i]._idx = $.inArray( nestedSort[i][1], aoColumns[iCol].asSorting );
\r
4580 dir: nestedSort[i][1],
\r
4581 index: nestedSort[i]._idx,
\r
4583 formatter: DataTable.ext.type.order[ sType+"-pre" ]
\r
4592 * Change the order of the table
\r
4593 * @param {object} oSettings dataTables settings object
\r
4594 * @memberof DataTable#oApi
\r
4595 * @todo This really needs split up!
\r
4597 function _fnSort ( oSettings )
\r
4600 i, ien, iLen, j, jLen, k, kLen,
\r
4603 oExtSort = DataTable.ext.type.order,
\r
4604 aoData = oSettings.aoData,
\r
4605 aoColumns = oSettings.aoColumns,
\r
4606 aDataSort, data, iCol, sType, oSort,
\r
4609 displayMaster = oSettings.aiDisplayMaster,
\r
4612 // Resolve any column types that are unknown due to addition or invalidation
\r
4613 // @todo Can this be moved into a 'data-ready' handler which is called when
\r
4614 // data is going to be used in the table?
\r
4615 _fnColumnTypes( oSettings );
\r
4617 aSort = _fnSortFlatten( oSettings );
\r
4619 for ( i=0, ien=aSort.length ; i<ien ; i++ ) {
\r
4620 sortCol = aSort[i];
\r
4622 // Track if we can use the fast sort algorithm
\r
4623 if ( sortCol.formatter ) {
\r
4627 // Load the data needed for the sort, for each cell
\r
4628 _fnSortData( oSettings, sortCol.col );
\r
4631 /* No sorting required if server-side or no sorting array */
\r
4632 if ( _fnDataSource( oSettings ) != 'ssp' && aSort.length !== 0 )
\r
4634 // Create a value - key array of the current row positions such that we can use their
\r
4635 // current position during the sort, if values match, in order to perform stable sorting
\r
4636 for ( i=0, iLen=displayMaster.length ; i<iLen ; i++ ) {
\r
4637 aiOrig[ displayMaster[i] ] = i;
\r
4640 /* Do the sort - here we want multi-column sorting based on a given data source (column)
\r
4641 * and sorting function (from oSort) in a certain direction. It's reasonably complex to
\r
4642 * follow on it's own, but this is what we want (example two column sorting):
\r
4643 * fnLocalSorting = function(a,b){
\r
4645 * iTest = oSort['string-asc']('data11', 'data12');
\r
4646 * if (iTest !== 0)
\r
4648 * iTest = oSort['numeric-desc']('data21', 'data22');
\r
4649 * if (iTest !== 0)
\r
4651 * return oSort['numeric-asc']( aiOrig[a], aiOrig[b] );
\r
4653 * Basically we have a test for each sorting column, if the data in that column is equal,
\r
4654 * test the next column. If all columns match, then we use a numeric sort on the row
\r
4655 * positions in the original data array to provide a stable sort.
\r
4657 * Note - I know it seems excessive to have two sorting methods, but the first is around
\r
4658 * 15% faster, so the second is only maintained for backwards compatibility with sorting
\r
4659 * methods which do not have a pre-sort formatting function.
\r
4661 if ( formatters === aSort.length ) {
\r
4662 // All sort types have formatting functions
\r
4663 displayMaster.sort( function ( a, b ) {
\r
4665 x, y, k, test, sort,
\r
4667 dataA = aoData[a]._aSortData,
\r
4668 dataB = aoData[b]._aSortData;
\r
4670 for ( k=0 ; k<len ; k++ ) {
\r
4673 x = dataA[ sort.col ];
\r
4674 y = dataB[ sort.col ];
\r
4676 test = x<y ? -1 : x>y ? 1 : 0;
\r
4677 if ( test !== 0 ) {
\r
4678 return sort.dir === 'asc' ? test : -test;
\r
4684 return x<y ? -1 : x>y ? 1 : 0;
\r
4688 // Depreciated - remove in 1.11 (providing a plug-in option)
\r
4689 // Not all sort types have formatting methods, so we have to call their sorting
\r
4691 displayMaster.sort( function ( a, b ) {
\r
4693 x, y, k, l, test, sort, fn,
\r
4695 dataA = aoData[a]._aSortData,
\r
4696 dataB = aoData[b]._aSortData;
\r
4698 for ( k=0 ; k<len ; k++ ) {
\r
4701 x = dataA[ sort.col ];
\r
4702 y = dataB[ sort.col ];
\r
4704 fn = oExtSort[ sort.type+"-"+sort.dir ] || oExtSort[ "string-"+sort.dir ];
\r
4705 test = fn( x, y );
\r
4706 if ( test !== 0 ) {
\r
4713 return x<y ? -1 : x>y ? 1 : 0;
\r
4718 /* Tell the draw function that we have sorted the data */
\r
4719 oSettings.bSorted = true;
\r
4723 function _fnSortAria ( settings )
\r
4727 var columns = settings.aoColumns;
\r
4728 var aSort = _fnSortFlatten( settings );
\r
4729 var oAria = settings.oLanguage.oAria;
\r
4731 // ARIA attributes - need to loop all columns, to update all (removing old
\r
4732 // attributes as needed)
\r
4733 for ( var i=0, iLen=columns.length ; i<iLen ; i++ )
\r
4735 var col = columns[i];
\r
4736 var asSorting = col.asSorting;
\r
4737 var sTitle = col.sTitle.replace( /<.*?>/g, "" );
\r
4740 // IE7 is throwing an error when setting these properties with jQuery's
\r
4741 // attr() and removeAttr() methods...
\r
4742 th.removeAttribute('aria-sort');
\r
4744 /* In ARIA only the first sorting column can be marked as sorting - no multi-sort option */
\r
4745 if ( col.bSortable ) {
\r
4746 if ( aSort.length > 0 && aSort[0].col == i ) {
\r
4747 th.setAttribute('aria-sort', aSort[0].dir=="asc" ? "ascending" : "descending" );
\r
4748 nextSort = asSorting[ aSort[0].index+1 ] || asSorting[0];
\r
4751 nextSort = asSorting[0];
\r
4754 label = sTitle + ( nextSort === "asc" ?
\r
4755 oAria.sSortAscending :
\r
4756 oAria.sSortDescending
\r
4763 th.setAttribute('aria-label', label);
\r
4769 * Function to run on user sort request
\r
4770 * @param {object} settings dataTables settings object
\r
4771 * @param {node} attachTo node to attach the handler to
\r
4772 * @param {int} colIdx column sorting index
\r
4773 * @param {boolean} [append=false] Append the requested sort to the existing
\r
4774 * sort if true (i.e. multi-column sort)
\r
4775 * @param {function} [callback] callback function
\r
4776 * @memberof DataTable#oApi
\r
4778 function _fnSortListener ( settings, colIdx, append, callback )
\r
4780 var col = settings.aoColumns[ colIdx ];
\r
4781 var sorting = settings.aaSorting;
\r
4782 var asSorting = col.asSorting;
\r
4784 var next = function ( a, overflow ) {
\r
4786 if ( idx === undefined ) {
\r
4787 idx = $.inArray( a[1], asSorting );
\r
4790 return idx+1 < asSorting.length ?
\r
4797 // Convert to 2D array if needed
\r
4798 if ( typeof sorting[0] === 'number' ) {
\r
4799 sorting = settings.aaSorting = [ sorting ];
\r
4802 // If appending the sort then we are multi-column sorting
\r
4803 if ( append && settings.oFeatures.bSortMulti ) {
\r
4804 // Are we already doing some kind of sort on this column?
\r
4805 var sortIdx = $.inArray( colIdx, _pluck(sorting, '0') );
\r
4807 if ( sortIdx !== -1 ) {
\r
4808 // Yes, modify the sort
\r
4809 nextSortIdx = next( sorting[sortIdx], true );
\r
4811 if ( nextSortIdx === null && sorting.length === 1 ) {
\r
4812 nextSortIdx = 0; // can't remove sorting completely
\r
4815 if ( nextSortIdx === null ) {
\r
4816 sorting.splice( sortIdx, 1 );
\r
4819 sorting[sortIdx][1] = asSorting[ nextSortIdx ];
\r
4820 sorting[sortIdx]._idx = nextSortIdx;
\r
4824 // No sort on this column yet
\r
4825 sorting.push( [ colIdx, asSorting[0], 0 ] );
\r
4826 sorting[sorting.length-1]._idx = 0;
\r
4829 else if ( sorting.length && sorting[0][0] == colIdx ) {
\r
4830 // Single column - already sorting on this column, modify the sort
\r
4831 nextSortIdx = next( sorting[0] );
\r
4833 sorting.length = 1;
\r
4834 sorting[0][1] = asSorting[ nextSortIdx ];
\r
4835 sorting[0]._idx = nextSortIdx;
\r
4838 // Single column - sort only on this column
\r
4839 sorting.length = 0;
\r
4840 sorting.push( [ colIdx, asSorting[0] ] );
\r
4841 sorting[0]._idx = 0;
\r
4844 // Run the sort by calling a full redraw
\r
4845 _fnReDraw( settings );
\r
4847 // callback used for async user interaction
\r
4848 if ( typeof callback == 'function' ) {
\r
4849 callback( settings );
\r
4855 * Attach a sort handler (click) to a node
\r
4856 * @param {object} settings dataTables settings object
\r
4857 * @param {node} attachTo node to attach the handler to
\r
4858 * @param {int} colIdx column sorting index
\r
4859 * @param {function} [callback] callback function
\r
4860 * @memberof DataTable#oApi
\r
4862 function _fnSortAttachListener ( settings, attachTo, colIdx, callback )
\r
4864 var col = settings.aoColumns[ colIdx ];
\r
4866 _fnBindAction( attachTo, {}, function (e) {
\r
4867 /* If the column is not sortable - don't to anything */
\r
4868 if ( col.bSortable === false ) {
\r
4872 // If processing is enabled use a timeout to allow the processing
\r
4873 // display to be shown - otherwise to it synchronously
\r
4874 if ( settings.oFeatures.bProcessing ) {
\r
4875 _fnProcessingDisplay( settings, true );
\r
4877 setTimeout( function() {
\r
4878 _fnSortListener( settings, colIdx, e.shiftKey, callback );
\r
4880 // In server-side processing, the draw callback will remove the
\r
4881 // processing display
\r
4882 if ( _fnDataSource( settings ) !== 'ssp' ) {
\r
4883 _fnProcessingDisplay( settings, false );
\r
4888 _fnSortListener( settings, colIdx, e.shiftKey, callback );
\r
4895 * Set the sorting classes on table's body, Note: it is safe to call this function
\r
4896 * when bSort and bSortClasses are false
\r
4897 * @param {object} oSettings dataTables settings object
\r
4898 * @memberof DataTable#oApi
\r
4900 function _fnSortingClasses( settings )
\r
4902 var oldSort = settings.aLastSort;
\r
4903 var sortClass = settings.oClasses.sSortColumn;
\r
4904 var sort = _fnSortFlatten( settings );
\r
4905 var features = settings.oFeatures;
\r
4906 var i, ien, colIdx;
\r
4908 if ( features.bSort && features.bSortClasses ) {
\r
4909 // Remove old sorting classes
\r
4910 for ( i=0, ien=oldSort.length ; i<ien ; i++ ) {
\r
4911 colIdx = oldSort[i].src;
\r
4913 // Remove column sorting
\r
4914 $( _pluck( settings.aoData, 'anCells', colIdx ) )
\r
4915 .removeClass( sortClass + (i<2 ? i+1 : 3) );
\r
4918 // Add new column sorting
\r
4919 for ( i=0, ien=sort.length ; i<ien ; i++ ) {
\r
4920 colIdx = sort[i].src;
\r
4922 $( _pluck( settings.aoData, 'anCells', colIdx ) )
\r
4923 .addClass( sortClass + (i<2 ? i+1 : 3) );
\r
4927 settings.aLastSort = sort;
\r
4931 // Get the data to sort a column, be it from cache, fresh (populating the
\r
4932 // cache), or from a sort formatter
\r
4933 function _fnSortData( settings, idx )
\r
4935 // Custom sorting function - provided by the sort data type
\r
4936 var column = settings.aoColumns[ idx ];
\r
4937 var customSort = DataTable.ext.order[ column.sSortDataType ];
\r
4940 if ( customSort ) {
\r
4941 customData = customSort.call( settings.oInstance, settings, idx,
\r
4942 _fnColumnIndexToVisible( settings, idx )
\r
4946 // Use / populate cache
\r
4947 var row, cellData;
\r
4948 var formatter = DataTable.ext.type.order[ column.sType+"-pre" ];
\r
4950 for ( var i=0, ien=settings.aoData.length ; i<ien ; i++ ) {
\r
4951 row = settings.aoData[i];
\r
4953 if ( ! row._aSortData ) {
\r
4954 row._aSortData = [];
\r
4957 if ( ! row._aSortData[idx] || customSort ) {
\r
4958 cellData = customSort ?
\r
4959 customData[i] : // If there was a custom sort function, use data from there
\r
4960 _fnGetCellData( settings, i, idx, 'sort' );
\r
4962 row._aSortData[ idx ] = formatter ?
\r
4963 formatter( cellData ) :
\r
4972 * Save the state of a table
\r
4973 * @param {object} oSettings dataTables settings object
\r
4974 * @memberof DataTable#oApi
\r
4976 function _fnSaveState ( settings )
\r
4978 if ( !settings.oFeatures.bStateSave || settings.bDestroying )
\r
4983 /* Store the interesting variables */
\r
4985 time: +new Date(),
\r
4986 start: settings._iDisplayStart,
\r
4987 length: settings._iDisplayLength,
\r
4988 order: $.extend( true, [], settings.aaSorting ),
\r
4989 search: _fnSearchToCamel( settings.oPreviousSearch ),
\r
4990 columns: $.map( settings.aoColumns, function ( col, i ) {
\r
4992 visible: col.bVisible,
\r
4993 search: _fnSearchToCamel( settings.aoPreSearchCols[i] )
\r
4998 _fnCallbackFire( settings, "aoStateSaveParams", 'stateSaveParams', [settings, state] );
\r
5000 settings.oSavedState = state;
\r
5001 settings.fnStateSaveCallback.call( settings.oInstance, settings, state );
\r
5006 * Attempt to load a saved table state
\r
5007 * @param {object} oSettings dataTables settings object
\r
5008 * @param {object} oInit DataTables init object so we can override settings
\r
5009 * @memberof DataTable#oApi
\r
5011 function _fnLoadState ( settings, oInit )
\r
5014 var columns = settings.aoColumns;
\r
5016 if ( ! settings.oFeatures.bStateSave ) {
\r
5020 var state = settings.fnStateLoadCallback.call( settings.oInstance, settings );
\r
5021 if ( ! state || ! state.time ) {
\r
5025 /* Allow custom and plug-in manipulation functions to alter the saved data set and
\r
5026 * cancelling of loading by returning false
\r
5028 var abStateLoad = _fnCallbackFire( settings, 'aoStateLoadParams', 'stateLoadParams', [settings, state] );
\r
5029 if ( $.inArray( false, abStateLoad ) !== -1 ) {
\r
5033 /* Reject old data */
\r
5034 var duration = settings.iStateDuration;
\r
5035 if ( duration > 0 && state.time < +new Date() - (duration*1000) ) {
\r
5039 // Number of columns have changed - all bets are off, no restore of settings
\r
5040 if ( columns.length !== state.columns.length ) {
\r
5044 // Store the saved state so it might be accessed at any time
\r
5045 settings.oLoadedState = $.extend( true, {}, state );
\r
5047 // Restore key features - todo - for 1.11 this needs to be done by
\r
5048 // subscribed events
\r
5049 if ( state.start !== undefined ) {
\r
5050 settings._iDisplayStart = state.start;
\r
5051 settings.iInitDisplayStart = state.start;
\r
5053 if ( state.length !== undefined ) {
\r
5054 settings._iDisplayLength = state.length;
\r
5058 if ( state.order !== undefined ) {
\r
5059 settings.aaSorting = [];
\r
5060 $.each( state.order, function ( i, col ) {
\r
5061 settings.aaSorting.push( col[0] >= columns.length ?
\r
5069 if ( state.search !== undefined ) {
\r
5070 $.extend( settings.oPreviousSearch, _fnSearchToHung( state.search ) );
\r
5074 for ( i=0, ien=state.columns.length ; i<ien ; i++ ) {
\r
5075 var col = state.columns[i];
\r
5078 if ( col.visible !== undefined ) {
\r
5079 columns[i].bVisible = col.visible;
\r
5083 if ( col.search !== undefined ) {
\r
5084 $.extend( settings.aoPreSearchCols[i], _fnSearchToHung( col.search ) );
\r
5088 _fnCallbackFire( settings, 'aoStateLoaded', 'stateLoaded', [settings, state] );
\r
5093 * Return the settings object for a particular table
\r
5094 * @param {node} table table we are using as a dataTable
\r
5095 * @returns {object} Settings object - or null if not found
\r
5096 * @memberof DataTable#oApi
\r
5098 function _fnSettingsFromNode ( table )
\r
5100 var settings = DataTable.settings;
\r
5101 var idx = $.inArray( table, _pluck( settings, 'nTable' ) );
\r
5103 return idx !== -1 ?
\r
5110 * Log an error message
\r
5111 * @param {object} settings dataTables settings object
\r
5112 * @param {int} level log error messages, or display them to the user
\r
5113 * @param {string} msg error message
\r
5114 * @param {int} tn Technical note id to get more information about the error.
\r
5115 * @memberof DataTable#oApi
\r
5117 function _fnLog( settings, level, msg, tn )
\r
5119 msg = 'DataTables warning: '+
\r
5120 (settings ? 'table id='+settings.sTableId+' - ' : '')+msg;
\r
5123 msg += '. For more information about this error, please see '+
\r
5124 'http://datatables.net/tn/'+tn;
\r
5128 // Backwards compatibility pre 1.10
\r
5129 var ext = DataTable.ext;
\r
5130 var type = ext.sErrMode || ext.errMode;
\r
5133 _fnCallbackFire( settings, null, 'error', [ settings, tn, msg ] );
\r
5136 if ( type == 'alert' ) {
\r
5139 else if ( type == 'throw' ) {
\r
5140 throw new Error(msg);
\r
5142 else if ( typeof type == 'function' ) {
\r
5143 type( settings, tn, msg );
\r
5146 else if ( window.console && console.log ) {
\r
5147 console.log( msg );
\r
5153 * See if a property is defined on one object, if so assign it to the other object
\r
5154 * @param {object} ret target object
\r
5155 * @param {object} src source object
\r
5156 * @param {string} name property
\r
5157 * @param {string} [mappedName] name to map too - optional, name used if not given
\r
5158 * @memberof DataTable#oApi
\r
5160 function _fnMap( ret, src, name, mappedName )
\r
5162 if ( $.isArray( name ) ) {
\r
5163 $.each( name, function (i, val) {
\r
5164 if ( $.isArray( val ) ) {
\r
5165 _fnMap( ret, src, val[0], val[1] );
\r
5168 _fnMap( ret, src, val );
\r
5175 if ( mappedName === undefined ) {
\r
5176 mappedName = name;
\r
5179 if ( src[name] !== undefined ) {
\r
5180 ret[mappedName] = src[name];
\r
5186 * Extend objects - very similar to jQuery.extend, but deep copy objects, and
\r
5187 * shallow copy arrays. The reason we need to do this, is that we don't want to
\r
5188 * deep copy array init values (such as aaSorting) since the dev wouldn't be
\r
5189 * able to override them, but we do want to deep copy arrays.
\r
5190 * @param {object} out Object to extend
\r
5191 * @param {object} extender Object from which the properties will be applied to
\r
5193 * @param {boolean} breakRefs If true, then arrays will be sliced to take an
\r
5194 * independent copy with the exception of the `data` or `aaData` parameters
\r
5195 * if they are present. This is so you can pass in a collection to
\r
5196 * DataTables and have that used as your data source without breaking the
\r
5198 * @returns {object} out Reference, just for convenience - out === the return.
\r
5199 * @memberof DataTable#oApi
\r
5200 * @todo This doesn't take account of arrays inside the deep copied objects.
\r
5202 function _fnExtend( out, extender, breakRefs )
\r
5206 for ( var prop in extender ) {
\r
5207 if ( extender.hasOwnProperty(prop) ) {
\r
5208 val = extender[prop];
\r
5210 if ( $.isPlainObject( val ) ) {
\r
5211 if ( ! $.isPlainObject( out[prop] ) ) {
\r
5214 $.extend( true, out[prop], val );
\r
5216 else if ( breakRefs && prop !== 'data' && prop !== 'aaData' && $.isArray(val) ) {
\r
5217 out[prop] = val.slice();
\r
5230 * Bind an event handers to allow a click or return key to activate the callback.
\r
5231 * This is good for accessibility since a return on the keyboard will have the
\r
5232 * same effect as a click, if the element has focus.
\r
5233 * @param {element} n Element to bind the action to
\r
5234 * @param {object} oData Data object to pass to the triggered function
\r
5235 * @param {function} fn Callback function for when the event is triggered
\r
5236 * @memberof DataTable#oApi
\r
5238 function _fnBindAction( n, oData, fn )
\r
5241 .bind( 'click.DT', oData, function (e) {
\r
5242 n.blur(); // Remove focus outline for mouse users
\r
5245 .bind( 'keypress.DT', oData, function (e){
\r
5246 if ( e.which === 13 ) {
\r
5247 e.preventDefault();
\r
5251 .bind( 'selectstart.DT', function () {
\r
5252 /* Take the brutal approach to cancelling text selection */
\r
5259 * Register a callback function. Easily allows a callback function to be added to
\r
5260 * an array store of callback functions that can then all be called together.
\r
5261 * @param {object} oSettings dataTables settings object
\r
5262 * @param {string} sStore Name of the array storage for the callbacks in oSettings
\r
5263 * @param {function} fn Function to be called back
\r
5264 * @param {string} sName Identifying name for the callback (i.e. a label)
\r
5265 * @memberof DataTable#oApi
\r
5267 function _fnCallbackReg( oSettings, sStore, fn, sName )
\r
5271 oSettings[sStore].push( {
\r
5280 * Fire callback functions and trigger events. Note that the loop over the
\r
5281 * callback array store is done backwards! Further note that you do not want to
\r
5282 * fire off triggers in time sensitive applications (for example cell creation)
\r
5284 * @param {object} settings dataTables settings object
\r
5285 * @param {string} callbackArr Name of the array storage for the callbacks in
\r
5287 * @param {string} eventName Name of the jQuery custom event to trigger. If
\r
5288 * null no trigger is fired
\r
5289 * @param {array} args Array of arguments to pass to the callback function /
\r
5291 * @memberof DataTable#oApi
\r
5293 function _fnCallbackFire( settings, callbackArr, eventName, args )
\r
5297 if ( callbackArr ) {
\r
5298 ret = $.map( settings[callbackArr].slice().reverse(), function (val, i) {
\r
5299 return val.fn.apply( settings.oInstance, args );
\r
5303 if ( eventName !== null ) {
\r
5304 var e = $.Event( eventName+'.dt' );
\r
5306 $(settings.nTable).trigger( e, args );
\r
5308 ret.push( e.result );
\r
5315 function _fnLengthOverflow ( settings )
\r
5318 start = settings._iDisplayStart,
\r
5319 end = settings.fnDisplayEnd(),
\r
5320 len = settings._iDisplayLength;
\r
5322 /* If we have space to show extra rows (backing up from the end point - then do so */
\r
5323 if ( start >= end )
\r
5325 start = end - len;
\r
5328 // Keep the start record on the current page
\r
5329 start -= (start % len);
\r
5331 if ( len === -1 || start < 0 )
\r
5336 settings._iDisplayStart = start;
\r
5340 function _fnRenderer( settings, type )
\r
5342 var renderer = settings.renderer;
\r
5343 var host = DataTable.ext.renderer[type];
\r
5345 if ( $.isPlainObject( renderer ) && renderer[type] ) {
\r
5346 // Specific renderer for this type. If available use it, otherwise use
\r
5348 return host[renderer[type]] || host._;
\r
5350 else if ( typeof renderer === 'string' ) {
\r
5351 // Common renderer - if there is one available for this type use it,
\r
5352 // otherwise use the default
\r
5353 return host[renderer] || host._;
\r
5356 // Use the default
\r
5362 * Detect the data source being used for the table. Used to simplify the code
\r
5363 * a little (ajax) and to make it compress a little smaller.
\r
5365 * @param {object} settings dataTables settings object
\r
5366 * @returns {string} Data source
\r
5367 * @memberof DataTable#oApi
\r
5369 function _fnDataSource ( settings )
\r
5371 if ( settings.oFeatures.bServerSide ) {
\r
5374 else if ( settings.ajax || settings.sAjaxSource ) {
\r
5381 DataTable = function( options )
\r
5384 * Perform a jQuery selector action on the table's TR elements (from the tbody) and
\r
5385 * return the resulting jQuery object.
\r
5386 * @param {string|node|jQuery} sSelector jQuery selector or node collection to act on
\r
5387 * @param {object} [oOpts] Optional parameters for modifying the rows to be included
\r
5388 * @param {string} [oOpts.filter=none] Select TR elements that meet the current filter
\r
5389 * criterion ("applied") or all TR elements (i.e. no filter).
\r
5390 * @param {string} [oOpts.order=current] Order of the TR elements in the processed array.
\r
5391 * Can be either 'current', whereby the current sorting of the table is used, or
\r
5392 * 'original' whereby the original order the data was read into the table is used.
\r
5393 * @param {string} [oOpts.page=all] Limit the selection to the currently displayed page
\r
5394 * ("current") or not ("all"). If 'current' is given, then order is assumed to be
\r
5395 * 'current' and filter is 'applied', regardless of what they might be given as.
\r
5396 * @returns {object} jQuery object, filtered by the given selector.
\r
5398 * @deprecated Since v1.10
\r
5401 * $(document).ready(function() {
\r
5402 * var oTable = $('#example').dataTable();
\r
5404 * // Highlight every second row
\r
5405 * oTable.$('tr:odd').css('backgroundColor', 'blue');
\r
5409 * $(document).ready(function() {
\r
5410 * var oTable = $('#example').dataTable();
\r
5412 * // Filter to rows with 'Webkit' in them, add a background colour and then
\r
5413 * // remove the filter, thus highlighting the 'Webkit' rows only.
\r
5414 * oTable.fnFilter('Webkit');
\r
5415 * oTable.$('tr', {"search": "applied"}).css('backgroundColor', 'blue');
\r
5416 * oTable.fnFilter('');
\r
5419 this.$ = function ( sSelector, oOpts )
\r
5421 return this.api(true).$( sSelector, oOpts );
\r
5426 * Almost identical to $ in operation, but in this case returns the data for the matched
\r
5427 * rows - as such, the jQuery selector used should match TR row nodes or TD/TH cell nodes
\r
5428 * rather than any descendants, so the data can be obtained for the row/cell. If matching
\r
5429 * rows are found, the data returned is the original data array/object that was used to
\r
5430 * create the row (or a generated array if from a DOM source).
\r
5432 * This method is often useful in-combination with $ where both functions are given the
\r
5433 * same parameters and the array indexes will match identically.
\r
5434 * @param {string|node|jQuery} sSelector jQuery selector or node collection to act on
\r
5435 * @param {object} [oOpts] Optional parameters for modifying the rows to be included
\r
5436 * @param {string} [oOpts.filter=none] Select elements that meet the current filter
\r
5437 * criterion ("applied") or all elements (i.e. no filter).
\r
5438 * @param {string} [oOpts.order=current] Order of the data in the processed array.
\r
5439 * Can be either 'current', whereby the current sorting of the table is used, or
\r
5440 * 'original' whereby the original order the data was read into the table is used.
\r
5441 * @param {string} [oOpts.page=all] Limit the selection to the currently displayed page
\r
5442 * ("current") or not ("all"). If 'current' is given, then order is assumed to be
\r
5443 * 'current' and filter is 'applied', regardless of what they might be given as.
\r
5444 * @returns {array} Data for the matched elements. If any elements, as a result of the
\r
5445 * selector, were not TR, TD or TH elements in the DataTable, they will have a null
\r
5446 * entry in the array.
\r
5448 * @deprecated Since v1.10
\r
5451 * $(document).ready(function() {
\r
5452 * var oTable = $('#example').dataTable();
\r
5454 * // Get the data from the first row in the table
\r
5455 * var data = oTable._('tr:first');
\r
5457 * // Do something useful with the data
\r
5458 * alert( "First cell is: "+data[0] );
\r
5462 * $(document).ready(function() {
\r
5463 * var oTable = $('#example').dataTable();
\r
5465 * // Filter to 'Webkit' and get all data for
\r
5466 * oTable.fnFilter('Webkit');
\r
5467 * var data = oTable._('tr', {"search": "applied"});
\r
5469 * // Do something with the data
\r
5470 * alert( data.length+" rows matched the search" );
\r
5473 this._ = function ( sSelector, oOpts )
\r
5475 return this.api(true).rows( sSelector, oOpts ).data();
\r
5480 * Create a DataTables Api instance, with the currently selected tables for
\r
5481 * the Api's context.
\r
5482 * @param {boolean} [traditional=false] Set the API instance's context to be
\r
5483 * only the table referred to by the `DataTable.ext.iApiIndex` option, as was
\r
5484 * used in the API presented by DataTables 1.9- (i.e. the traditional mode),
\r
5485 * or if all tables captured in the jQuery object should be used.
\r
5486 * @return {DataTables.Api}
\r
5488 this.api = function ( traditional )
\r
5490 return traditional ?
\r
5492 _fnSettingsFromNode( this[ _ext.iApiIndex ] )
\r
5499 * Add a single new row or multiple rows of data to the table. Please note
\r
5500 * that this is suitable for client-side processing only - if you are using
\r
5501 * server-side processing (i.e. "bServerSide": true), then to add data, you
\r
5502 * must add it to the data source, i.e. the server-side, through an Ajax call.
\r
5503 * @param {array|object} data The data to be added to the table. This can be:
\r
5505 * <li>1D array of data - add a single row with the data provided</li>
\r
5506 * <li>2D array of arrays - add multiple rows in a single call</li>
\r
5507 * <li>object - data object when using <i>mData</i></li>
\r
5508 * <li>array of objects - multiple data objects when using <i>mData</i></li>
\r
5510 * @param {bool} [redraw=true] redraw the table or not
\r
5511 * @returns {array} An array of integers, representing the list of indexes in
\r
5512 * <i>aoData</i> ({@link DataTable.models.oSettings}) that have been added to
\r
5515 * @deprecated Since v1.10
\r
5518 * // Global var for counter
\r
5519 * var giCount = 2;
\r
5521 * $(document).ready(function() {
\r
5522 * $('#example').dataTable();
\r
5525 * function fnClickAddRow() {
\r
5526 * $('#example').dataTable().fnAddData( [
\r
5536 this.fnAddData = function( data, redraw )
\r
5538 var api = this.api( true );
\r
5540 /* Check if we want to add multiple rows or not */
\r
5541 var rows = $.isArray(data) && ( $.isArray(data[0]) || $.isPlainObject(data[0]) ) ?
\r
5542 api.rows.add( data ) :
\r
5543 api.row.add( data );
\r
5545 if ( redraw === undefined || redraw ) {
\r
5549 return rows.flatten().toArray();
\r
5554 * This function will make DataTables recalculate the column sizes, based on the data
\r
5555 * contained in the table and the sizes applied to the columns (in the DOM, CSS or
\r
5556 * through the sWidth parameter). This can be useful when the width of the table's
\r
5557 * parent element changes (for example a window resize).
\r
5558 * @param {boolean} [bRedraw=true] Redraw the table or not, you will typically want to
\r
5560 * @deprecated Since v1.10
\r
5563 * $(document).ready(function() {
\r
5564 * var oTable = $('#example').dataTable( {
\r
5565 * "sScrollY": "200px",
\r
5566 * "bPaginate": false
\r
5569 * $(window).bind('resize', function () {
\r
5570 * oTable.fnAdjustColumnSizing();
\r
5574 this.fnAdjustColumnSizing = function ( bRedraw )
\r
5576 var api = this.api( true ).columns.adjust();
\r
5577 var settings = api.settings()[0];
\r
5578 var scroll = settings.oScroll;
\r
5580 if ( bRedraw === undefined || bRedraw ) {
\r
5581 api.draw( false );
\r
5583 else if ( scroll.sX !== "" || scroll.sY !== "" ) {
\r
5584 /* If not redrawing, but scrolling, we want to apply the new column sizes anyway */
\r
5585 _fnScrollDraw( settings );
\r
5591 * Quickly and simply clear a table
\r
5592 * @param {bool} [bRedraw=true] redraw the table or not
\r
5594 * @deprecated Since v1.10
\r
5597 * $(document).ready(function() {
\r
5598 * var oTable = $('#example').dataTable();
\r
5600 * // Immediately 'nuke' the current rows (perhaps waiting for an Ajax callback...)
\r
5601 * oTable.fnClearTable();
\r
5604 this.fnClearTable = function( bRedraw )
\r
5606 var api = this.api( true ).clear();
\r
5608 if ( bRedraw === undefined || bRedraw ) {
\r
5615 * The exact opposite of 'opening' a row, this function will close any rows which
\r
5616 * are currently 'open'.
\r
5617 * @param {node} nTr the table row to 'close'
\r
5618 * @returns {int} 0 on success, or 1 if failed (can't find the row)
\r
5620 * @deprecated Since v1.10
\r
5623 * $(document).ready(function() {
\r
5626 * // 'open' an information row when a row is clicked on
\r
5627 * $('#example tbody tr').click( function () {
\r
5628 * if ( oTable.fnIsOpen(this) ) {
\r
5629 * oTable.fnClose( this );
\r
5631 * oTable.fnOpen( this, "Temporary row opened", "info_row" );
\r
5635 * oTable = $('#example').dataTable();
\r
5638 this.fnClose = function( nTr )
\r
5640 this.api( true ).row( nTr ).child.hide();
\r
5645 * Remove a row for the table
\r
5646 * @param {mixed} target The index of the row from aoData to be deleted, or
\r
5647 * the TR element you want to delete
\r
5648 * @param {function|null} [callBack] Callback function
\r
5649 * @param {bool} [redraw=true] Redraw the table or not
\r
5650 * @returns {array} The row that was deleted
\r
5652 * @deprecated Since v1.10
\r
5655 * $(document).ready(function() {
\r
5656 * var oTable = $('#example').dataTable();
\r
5658 * // Immediately remove the first row
\r
5659 * oTable.fnDeleteRow( 0 );
\r
5662 this.fnDeleteRow = function( target, callback, redraw )
\r
5664 var api = this.api( true );
\r
5665 var rows = api.rows( target );
\r
5666 var settings = rows.settings()[0];
\r
5667 var data = settings.aoData[ rows[0][0] ];
\r
5672 callback.call( this, settings, data );
\r
5675 if ( redraw === undefined || redraw ) {
\r
5684 * Restore the table to it's original state in the DOM by removing all of DataTables
\r
5685 * enhancements, alterations to the DOM structure of the table and event listeners.
\r
5686 * @param {boolean} [remove=false] Completely remove the table from the DOM
\r
5688 * @deprecated Since v1.10
\r
5691 * $(document).ready(function() {
\r
5692 * // This example is fairly pointless in reality, but shows how fnDestroy can be used
\r
5693 * var oTable = $('#example').dataTable();
\r
5694 * oTable.fnDestroy();
\r
5697 this.fnDestroy = function ( remove )
\r
5699 this.api( true ).destroy( remove );
\r
5704 * Redraw the table
\r
5705 * @param {bool} [complete=true] Re-filter and resort (if enabled) the table before the draw.
\r
5707 * @deprecated Since v1.10
\r
5710 * $(document).ready(function() {
\r
5711 * var oTable = $('#example').dataTable();
\r
5713 * // Re-draw the table - you wouldn't want to do it here, but it's an example :-)
\r
5714 * oTable.fnDraw();
\r
5717 this.fnDraw = function( complete )
\r
5719 // Note that this isn't an exact match to the old call to _fnDraw - it takes
\r
5720 // into account the new data, but can hold position.
\r
5721 this.api( true ).draw( complete );
\r
5726 * Filter the input based on data
\r
5727 * @param {string} sInput String to filter the table on
\r
5728 * @param {int|null} [iColumn] Column to limit filtering to
\r
5729 * @param {bool} [bRegex=false] Treat as regular expression or not
\r
5730 * @param {bool} [bSmart=true] Perform smart filtering or not
\r
5731 * @param {bool} [bShowGlobal=true] Show the input global filter in it's input box(es)
\r
5732 * @param {bool} [bCaseInsensitive=true] Do case-insensitive matching (true) or not (false)
\r
5734 * @deprecated Since v1.10
\r
5737 * $(document).ready(function() {
\r
5738 * var oTable = $('#example').dataTable();
\r
5740 * // Sometime later - filter...
\r
5741 * oTable.fnFilter( 'test string' );
\r
5744 this.fnFilter = function( sInput, iColumn, bRegex, bSmart, bShowGlobal, bCaseInsensitive )
\r
5746 var api = this.api( true );
\r
5748 if ( iColumn === null || iColumn === undefined ) {
\r
5749 api.search( sInput, bRegex, bSmart, bCaseInsensitive );
\r
5752 api.column( iColumn ).search( sInput, bRegex, bSmart, bCaseInsensitive );
\r
5760 * Get the data for the whole table, an individual row or an individual cell based on the
\r
5761 * provided parameters.
\r
5762 * @param {int|node} [src] A TR row node, TD/TH cell node or an integer. If given as
\r
5763 * a TR node then the data source for the whole row will be returned. If given as a
\r
5764 * TD/TH cell node then iCol will be automatically calculated and the data for the
\r
5765 * cell returned. If given as an integer, then this is treated as the aoData internal
\r
5766 * data index for the row (see fnGetPosition) and the data for that row used.
\r
5767 * @param {int} [col] Optional column index that you want the data of.
\r
5768 * @returns {array|object|string} If mRow is undefined, then the data for all rows is
\r
5769 * returned. If mRow is defined, just data for that row, and is iCol is
\r
5770 * defined, only data for the designated cell is returned.
\r
5772 * @deprecated Since v1.10
\r
5776 * $(document).ready(function() {
\r
5777 * oTable = $('#example').dataTable();
\r
5779 * oTable.$('tr').click( function () {
\r
5780 * var data = oTable.fnGetData( this );
\r
5781 * // ... do something with the array / object of data for the row
\r
5786 * // Individual cell data
\r
5787 * $(document).ready(function() {
\r
5788 * oTable = $('#example').dataTable();
\r
5790 * oTable.$('td').click( function () {
\r
5791 * var sData = oTable.fnGetData( this );
\r
5792 * alert( 'The cell clicked on had the value of '+sData );
\r
5796 this.fnGetData = function( src, col )
\r
5798 var api = this.api( true );
\r
5800 if ( src !== undefined ) {
\r
5801 var type = src.nodeName ? src.nodeName.toLowerCase() : '';
\r
5803 return col !== undefined || type == 'td' || type == 'th' ?
\r
5804 api.cell( src, col ).data() :
\r
5805 api.row( src ).data() || null;
\r
5808 return api.data().toArray();
\r
5813 * Get an array of the TR nodes that are used in the table's body. Note that you will
\r
5814 * typically want to use the '$' API method in preference to this as it is more
\r
5816 * @param {int} [iRow] Optional row index for the TR element you want
\r
5817 * @returns {array|node} If iRow is undefined, returns an array of all TR elements
\r
5818 * in the table's body, or iRow is defined, just the TR element requested.
\r
5820 * @deprecated Since v1.10
\r
5823 * $(document).ready(function() {
\r
5824 * var oTable = $('#example').dataTable();
\r
5826 * // Get the nodes from the table
\r
5827 * var nNodes = oTable.fnGetNodes( );
\r
5830 this.fnGetNodes = function( iRow )
\r
5832 var api = this.api( true );
\r
5834 return iRow !== undefined ?
\r
5835 api.row( iRow ).node() :
\r
5836 api.rows().nodes().flatten().toArray();
\r
5841 * Get the array indexes of a particular cell from it's DOM element
\r
5842 * and column index including hidden columns
\r
5843 * @param {node} node this can either be a TR, TD or TH in the table's body
\r
5844 * @returns {int} If nNode is given as a TR, then a single index is returned, or
\r
5845 * if given as a cell, an array of [row index, column index (visible),
\r
5846 * column index (all)] is given.
\r
5848 * @deprecated Since v1.10
\r
5851 * $(document).ready(function() {
\r
5852 * $('#example tbody td').click( function () {
\r
5853 * // Get the position of the current data from the node
\r
5854 * var aPos = oTable.fnGetPosition( this );
\r
5856 * // Get the data array for this row
\r
5857 * var aData = oTable.fnGetData( aPos[0] );
\r
5859 * // Update the data array and return the value
\r
5860 * aData[ aPos[1] ] = 'clicked';
\r
5861 * this.innerHTML = 'clicked';
\r
5864 * // Init DataTables
\r
5865 * oTable = $('#example').dataTable();
\r
5868 this.fnGetPosition = function( node )
\r
5870 var api = this.api( true );
\r
5871 var nodeName = node.nodeName.toUpperCase();
\r
5873 if ( nodeName == 'TR' ) {
\r
5874 return api.row( node ).index();
\r
5876 else if ( nodeName == 'TD' || nodeName == 'TH' ) {
\r
5877 var cell = api.cell( node ).index();
\r
5881 cell.columnVisible,
\r
5890 * Check to see if a row is 'open' or not.
\r
5891 * @param {node} nTr the table row to check
\r
5892 * @returns {boolean} true if the row is currently open, false otherwise
\r
5894 * @deprecated Since v1.10
\r
5897 * $(document).ready(function() {
\r
5900 * // 'open' an information row when a row is clicked on
\r
5901 * $('#example tbody tr').click( function () {
\r
5902 * if ( oTable.fnIsOpen(this) ) {
\r
5903 * oTable.fnClose( this );
\r
5905 * oTable.fnOpen( this, "Temporary row opened", "info_row" );
\r
5909 * oTable = $('#example').dataTable();
\r
5912 this.fnIsOpen = function( nTr )
\r
5914 return this.api( true ).row( nTr ).child.isShown();
\r
5919 * This function will place a new row directly after a row which is currently
\r
5920 * on display on the page, with the HTML contents that is passed into the
\r
5921 * function. This can be used, for example, to ask for confirmation that a
\r
5922 * particular record should be deleted.
\r
5923 * @param {node} nTr The table row to 'open'
\r
5924 * @param {string|node|jQuery} mHtml The HTML to put into the row
\r
5925 * @param {string} sClass Class to give the new TD cell
\r
5926 * @returns {node} The row opened. Note that if the table row passed in as the
\r
5927 * first parameter, is not found in the table, this method will silently
\r
5930 * @deprecated Since v1.10
\r
5933 * $(document).ready(function() {
\r
5936 * // 'open' an information row when a row is clicked on
\r
5937 * $('#example tbody tr').click( function () {
\r
5938 * if ( oTable.fnIsOpen(this) ) {
\r
5939 * oTable.fnClose( this );
\r
5941 * oTable.fnOpen( this, "Temporary row opened", "info_row" );
\r
5945 * oTable = $('#example').dataTable();
\r
5948 this.fnOpen = function( nTr, mHtml, sClass )
\r
5950 return this.api( true )
\r
5952 .child( mHtml, sClass )
\r
5959 * Change the pagination - provides the internal logic for pagination in a simple API
\r
5960 * function. With this function you can have a DataTables table go to the next,
\r
5961 * previous, first or last pages.
\r
5962 * @param {string|int} mAction Paging action to take: "first", "previous", "next" or "last"
\r
5963 * or page number to jump to (integer), note that page 0 is the first page.
\r
5964 * @param {bool} [bRedraw=true] Redraw the table or not
\r
5966 * @deprecated Since v1.10
\r
5969 * $(document).ready(function() {
\r
5970 * var oTable = $('#example').dataTable();
\r
5971 * oTable.fnPageChange( 'next' );
\r
5974 this.fnPageChange = function ( mAction, bRedraw )
\r
5976 var api = this.api( true ).page( mAction );
\r
5978 if ( bRedraw === undefined || bRedraw ) {
\r
5985 * Show a particular column
\r
5986 * @param {int} iCol The column whose display should be changed
\r
5987 * @param {bool} bShow Show (true) or hide (false) the column
\r
5988 * @param {bool} [bRedraw=true] Redraw the table or not
\r
5990 * @deprecated Since v1.10
\r
5993 * $(document).ready(function() {
\r
5994 * var oTable = $('#example').dataTable();
\r
5996 * // Hide the second column after initialisation
\r
5997 * oTable.fnSetColumnVis( 1, false );
\r
6000 this.fnSetColumnVis = function ( iCol, bShow, bRedraw )
\r
6002 var api = this.api( true ).column( iCol ).visible( bShow );
\r
6004 if ( bRedraw === undefined || bRedraw ) {
\r
6005 api.columns.adjust().draw();
\r
6011 * Get the settings for a particular table for external manipulation
\r
6012 * @returns {object} DataTables settings object. See
\r
6013 * {@link DataTable.models.oSettings}
\r
6015 * @deprecated Since v1.10
\r
6018 * $(document).ready(function() {
\r
6019 * var oTable = $('#example').dataTable();
\r
6020 * var oSettings = oTable.fnSettings();
\r
6022 * // Show an example parameter from the settings
\r
6023 * alert( oSettings._iDisplayStart );
\r
6026 this.fnSettings = function()
\r
6028 return _fnSettingsFromNode( this[_ext.iApiIndex] );
\r
6033 * Sort the table by a particular column
\r
6034 * @param {int} iCol the data index to sort on. Note that this will not match the
\r
6035 * 'display index' if you have hidden data entries
\r
6037 * @deprecated Since v1.10
\r
6040 * $(document).ready(function() {
\r
6041 * var oTable = $('#example').dataTable();
\r
6043 * // Sort immediately with columns 0 and 1
\r
6044 * oTable.fnSort( [ [0,'asc'], [1,'asc'] ] );
\r
6047 this.fnSort = function( aaSort )
\r
6049 this.api( true ).order( aaSort ).draw();
\r
6054 * Attach a sort listener to an element for a given column
\r
6055 * @param {node} nNode the element to attach the sort listener to
\r
6056 * @param {int} iColumn the column that a click on this node will sort on
\r
6057 * @param {function} [fnCallback] callback function when sort is run
\r
6059 * @deprecated Since v1.10
\r
6062 * $(document).ready(function() {
\r
6063 * var oTable = $('#example').dataTable();
\r
6065 * // Sort on column 1, when 'sorter' is clicked on
\r
6066 * oTable.fnSortListener( document.getElementById('sorter'), 1 );
\r
6069 this.fnSortListener = function( nNode, iColumn, fnCallback )
\r
6071 this.api( true ).order.listener( nNode, iColumn, fnCallback );
\r
6076 * Update a table cell or row - this method will accept either a single value to
\r
6077 * update the cell with, an array of values with one element for each column or
\r
6078 * an object in the same format as the original data source. The function is
\r
6079 * self-referencing in order to make the multi column updates easier.
\r
6080 * @param {object|array|string} mData Data to update the cell/row with
\r
6081 * @param {node|int} mRow TR element you want to update or the aoData index
\r
6082 * @param {int} [iColumn] The column to update, give as null or undefined to
\r
6083 * update a whole row.
\r
6084 * @param {bool} [bRedraw=true] Redraw the table or not
\r
6085 * @param {bool} [bAction=true] Perform pre-draw actions or not
\r
6086 * @returns {int} 0 on success, 1 on error
\r
6088 * @deprecated Since v1.10
\r
6091 * $(document).ready(function() {
\r
6092 * var oTable = $('#example').dataTable();
\r
6093 * oTable.fnUpdate( 'Example update', 0, 0 ); // Single cell
\r
6094 * oTable.fnUpdate( ['a', 'b', 'c', 'd', 'e'], $('tbody tr')[0] ); // Row
\r
6097 this.fnUpdate = function( mData, mRow, iColumn, bRedraw, bAction )
\r
6099 var api = this.api( true );
\r
6101 if ( iColumn === undefined || iColumn === null ) {
\r
6102 api.row( mRow ).data( mData );
\r
6105 api.cell( mRow, iColumn ).data( mData );
\r
6108 if ( bAction === undefined || bAction ) {
\r
6109 api.columns.adjust();
\r
6112 if ( bRedraw === undefined || bRedraw ) {
\r
6120 * Provide a common method for plug-ins to check the version of DataTables being used, in order
\r
6121 * to ensure compatibility.
\r
6122 * @param {string} sVersion Version string to check for, in the format "X.Y.Z". Note that the
\r
6123 * formats "X" and "X.Y" are also acceptable.
\r
6124 * @returns {boolean} true if this version of DataTables is greater or equal to the required
\r
6125 * version, or false if this version of DataTales is not suitable
\r
6128 * @deprecated Since v1.10
\r
6131 * $(document).ready(function() {
\r
6132 * var oTable = $('#example').dataTable();
\r
6133 * alert( oTable.fnVersionCheck( '1.9.0' ) );
\r
6136 this.fnVersionCheck = _ext.fnVersionCheck;
\r
6140 var emptyInit = options === undefined;
\r
6141 var len = this.length;
\r
6143 if ( emptyInit ) {
\r
6147 this.oApi = this.internal = _ext.internal;
\r
6149 // Extend with old style plug-in API methods
\r
6150 for ( var fn in DataTable.ext.internal ) {
\r
6152 this[fn] = _fnExternApiFunc(fn);
\r
6156 this.each(function() {
\r
6157 // For each initialisation we want to give it a clean initialisation
\r
6158 // object that can be bashed around
\r
6160 var oInit = len > 1 ? // optimisation for single table case
\r
6161 _fnExtend( o, options, true ) :
\r
6164 /*global oInit,_that,emptyInit*/
\r
6165 var i=0, iLen, j, jLen, k, kLen;
\r
6166 var sId = this.getAttribute( 'id' );
\r
6167 var bInitHandedOff = false;
\r
6168 var defaults = DataTable.defaults;
\r
6169 var $this = $(this);
\r
6172 /* Sanity check */
\r
6173 if ( this.nodeName.toLowerCase() != 'table' )
\r
6175 _fnLog( null, 0, 'Non-table node initialisation ('+this.nodeName+')', 2 );
\r
6179 /* Backwards compatibility for the defaults */
\r
6180 _fnCompatOpts( defaults );
\r
6181 _fnCompatCols( defaults.column );
\r
6183 /* Convert the camel-case defaults to Hungarian */
\r
6184 _fnCamelToHungarian( defaults, defaults, true );
\r
6185 _fnCamelToHungarian( defaults.column, defaults.column, true );
\r
6187 /* Setting up the initialisation object */
\r
6188 _fnCamelToHungarian( defaults, $.extend( oInit, $this.data() ) );
\r
6192 /* Check to see if we are re-initialising a table */
\r
6193 var allSettings = DataTable.settings;
\r
6194 for ( i=0, iLen=allSettings.length ; i<iLen ; i++ )
\r
6196 var s = allSettings[i];
\r
6198 /* Base check on table node */
\r
6199 if ( s.nTable == this || s.nTHead.parentNode == this || (s.nTFoot && s.nTFoot.parentNode == this) )
\r
6201 var bRetrieve = oInit.bRetrieve !== undefined ? oInit.bRetrieve : defaults.bRetrieve;
\r
6202 var bDestroy = oInit.bDestroy !== undefined ? oInit.bDestroy : defaults.bDestroy;
\r
6204 if ( emptyInit || bRetrieve )
\r
6206 return s.oInstance;
\r
6208 else if ( bDestroy )
\r
6210 s.oInstance.fnDestroy();
\r
6215 _fnLog( s, 0, 'Cannot reinitialise DataTable', 3 );
\r
6220 /* If the element we are initialising has the same ID as a table which was previously
\r
6221 * initialised, but the table nodes don't match (from before) then we destroy the old
\r
6222 * instance by simply deleting it. This is under the assumption that the table has been
\r
6223 * destroyed by other methods. Anyone using non-id selectors will need to do this manually
\r
6225 if ( s.sTableId == this.id )
\r
6227 allSettings.splice( i, 1 );
\r
6232 /* Ensure the table has an ID - required for accessibility */
\r
6233 if ( sId === null || sId === "" )
\r
6235 sId = "DataTables_Table_"+(DataTable.ext._unique++);
\r
6239 /* Create the settings object for this table and set some of the default parameters */
\r
6240 var oSettings = $.extend( true, {}, DataTable.models.oSettings, {
\r
6241 "sDestroyWidth": $this[0].style.width,
\r
6245 oSettings.nTable = this;
\r
6246 oSettings.oApi = _that.internal;
\r
6247 oSettings.oInit = oInit;
\r
6249 allSettings.push( oSettings );
\r
6251 // Need to add the instance after the instance after the settings object has been added
\r
6252 // to the settings array, so we can self reference the table instance if more than one
\r
6253 oSettings.oInstance = (_that.length===1) ? _that : $this.dataTable();
\r
6255 // Backwards compatibility, before we apply all the defaults
\r
6256 _fnCompatOpts( oInit );
\r
6258 if ( oInit.oLanguage )
\r
6260 _fnLanguageCompat( oInit.oLanguage );
\r
6263 // If the length menu is given, but the init display length is not, use the length menu
\r
6264 if ( oInit.aLengthMenu && ! oInit.iDisplayLength )
\r
6266 oInit.iDisplayLength = $.isArray( oInit.aLengthMenu[0] ) ?
\r
6267 oInit.aLengthMenu[0][0] : oInit.aLengthMenu[0];
\r
6270 // Apply the defaults and init options to make a single init object will all
\r
6271 // options defined from defaults and instance options.
\r
6272 oInit = _fnExtend( $.extend( true, {}, defaults ), oInit );
\r
6275 // Map the initialisation options onto the settings object
\r
6276 _fnMap( oSettings.oFeatures, oInit, [
\r
6289 _fnMap( oSettings, oInit, [
\r
6290 "asStripeClasses",
\r
6298 "sPaginationType",
\r
6305 "fnStateLoadCallback",
\r
6306 "fnStateSaveCallback",
\r
6310 [ "iCookieDuration", "iStateDuration" ], // backwards compat
\r
6311 [ "oSearch", "oPreviousSearch" ],
\r
6312 [ "aoSearchCols", "aoPreSearchCols" ],
\r
6313 [ "iDisplayLength", "_iDisplayLength" ],
\r
6314 [ "bJQueryUI", "bJUI" ]
\r
6316 _fnMap( oSettings.oScroll, oInit, [
\r
6317 [ "sScrollX", "sX" ],
\r
6318 [ "sScrollXInner", "sXInner" ],
\r
6319 [ "sScrollY", "sY" ],
\r
6320 [ "bScrollCollapse", "bCollapse" ]
\r
6322 _fnMap( oSettings.oLanguage, oInit, "fnInfoCallback" );
\r
6324 /* Callback functions which are array driven */
\r
6325 _fnCallbackReg( oSettings, 'aoDrawCallback', oInit.fnDrawCallback, 'user' );
\r
6326 _fnCallbackReg( oSettings, 'aoServerParams', oInit.fnServerParams, 'user' );
\r
6327 _fnCallbackReg( oSettings, 'aoStateSaveParams', oInit.fnStateSaveParams, 'user' );
\r
6328 _fnCallbackReg( oSettings, 'aoStateLoadParams', oInit.fnStateLoadParams, 'user' );
\r
6329 _fnCallbackReg( oSettings, 'aoStateLoaded', oInit.fnStateLoaded, 'user' );
\r
6330 _fnCallbackReg( oSettings, 'aoRowCallback', oInit.fnRowCallback, 'user' );
\r
6331 _fnCallbackReg( oSettings, 'aoRowCreatedCallback', oInit.fnCreatedRow, 'user' );
\r
6332 _fnCallbackReg( oSettings, 'aoHeaderCallback', oInit.fnHeaderCallback, 'user' );
\r
6333 _fnCallbackReg( oSettings, 'aoFooterCallback', oInit.fnFooterCallback, 'user' );
\r
6334 _fnCallbackReg( oSettings, 'aoInitComplete', oInit.fnInitComplete, 'user' );
\r
6335 _fnCallbackReg( oSettings, 'aoPreDrawCallback', oInit.fnPreDrawCallback, 'user' );
\r
6337 oSettings.rowIdFn = _fnGetObjectDataFn( oInit.rowId );
\r
6339 /* Browser support detection */
\r
6340 _fnBrowserDetect( oSettings );
\r
6342 var oClasses = oSettings.oClasses;
\r
6344 // @todo Remove in 1.11
\r
6345 if ( oInit.bJQueryUI )
\r
6347 /* Use the JUI classes object for display. You could clone the oStdClasses object if
\r
6348 * you want to have multiple tables with multiple independent classes
\r
6350 $.extend( oClasses, DataTable.ext.oJUIClasses, oInit.oClasses );
\r
6352 if ( oInit.sDom === defaults.sDom && defaults.sDom === "lfrtip" )
\r
6354 /* Set the DOM to use a layout suitable for jQuery UI's theming */
\r
6355 oSettings.sDom = '<"H"lfr>t<"F"ip>';
\r
6358 if ( ! oSettings.renderer ) {
\r
6359 oSettings.renderer = 'jqueryui';
\r
6361 else if ( $.isPlainObject( oSettings.renderer ) && ! oSettings.renderer.header ) {
\r
6362 oSettings.renderer.header = 'jqueryui';
\r
6367 $.extend( oClasses, DataTable.ext.classes, oInit.oClasses );
\r
6369 $this.addClass( oClasses.sTable );
\r
6372 if ( oSettings.iInitDisplayStart === undefined )
\r
6374 /* Display start point, taking into account the save saving */
\r
6375 oSettings.iInitDisplayStart = oInit.iDisplayStart;
\r
6376 oSettings._iDisplayStart = oInit.iDisplayStart;
\r
6379 if ( oInit.iDeferLoading !== null )
\r
6381 oSettings.bDeferLoading = true;
\r
6382 var tmp = $.isArray( oInit.iDeferLoading );
\r
6383 oSettings._iRecordsDisplay = tmp ? oInit.iDeferLoading[0] : oInit.iDeferLoading;
\r
6384 oSettings._iRecordsTotal = tmp ? oInit.iDeferLoading[1] : oInit.iDeferLoading;
\r
6387 /* Language definitions */
\r
6388 var oLanguage = oSettings.oLanguage;
\r
6389 $.extend( true, oLanguage, oInit.oLanguage );
\r
6391 if ( oLanguage.sUrl !== "" )
\r
6393 /* Get the language definitions from a file - because this Ajax call makes the language
\r
6394 * get async to the remainder of this function we use bInitHandedOff to indicate that
\r
6395 * _fnInitialise will be fired by the returned Ajax handler, rather than the constructor
\r
6399 url: oLanguage.sUrl,
\r
6400 success: function ( json ) {
\r
6401 _fnLanguageCompat( json );
\r
6402 _fnCamelToHungarian( defaults.oLanguage, json );
\r
6403 $.extend( true, oLanguage, json );
\r
6404 _fnInitialise( oSettings );
\r
6406 error: function () {
\r
6407 // Error occurred loading language file, continue on as best we can
\r
6408 _fnInitialise( oSettings );
\r
6411 bInitHandedOff = true;
\r
6417 if ( oInit.asStripeClasses === null )
\r
6419 oSettings.asStripeClasses =[
\r
6420 oClasses.sStripeOdd,
\r
6421 oClasses.sStripeEven
\r
6425 /* Remove row stripe classes if they are already on the table row */
\r
6426 var stripeClasses = oSettings.asStripeClasses;
\r
6427 var rowOne = $this.children('tbody').find('tr').eq(0);
\r
6428 if ( $.inArray( true, $.map( stripeClasses, function(el, i) {
\r
6429 return rowOne.hasClass(el);
\r
6431 $('tbody tr', this).removeClass( stripeClasses.join(' ') );
\r
6432 oSettings.asDestroyStripes = stripeClasses.slice();
\r
6437 * See if we should load columns automatically or use defined ones
\r
6440 var aoColumnsInit;
\r
6441 var nThead = this.getElementsByTagName('thead');
\r
6442 if ( nThead.length !== 0 )
\r
6444 _fnDetectHeader( oSettings.aoHeader, nThead[0] );
\r
6445 anThs = _fnGetUniqueThs( oSettings );
\r
6448 /* If not given a column array, generate one with nulls */
\r
6449 if ( oInit.aoColumns === null )
\r
6451 aoColumnsInit = [];
\r
6452 for ( i=0, iLen=anThs.length ; i<iLen ; i++ )
\r
6454 aoColumnsInit.push( null );
\r
6459 aoColumnsInit = oInit.aoColumns;
\r
6462 /* Add the columns */
\r
6463 for ( i=0, iLen=aoColumnsInit.length ; i<iLen ; i++ )
\r
6465 _fnAddColumn( oSettings, anThs ? anThs[i] : null );
\r
6468 /* Apply the column definitions */
\r
6469 _fnApplyColumnDefs( oSettings, oInit.aoColumnDefs, aoColumnsInit, function (iCol, oDef) {
\r
6470 _fnColumnOptions( oSettings, iCol, oDef );
\r
6473 /* HTML5 attribute detection - build an mData object automatically if the
\r
6474 * attributes are found
\r
6476 if ( rowOne.length ) {
\r
6477 var a = function ( cell, name ) {
\r
6478 return cell.getAttribute( 'data-'+name ) !== null ? name : null;
\r
6481 $( rowOne[0] ).children('th, td').each( function (i, cell) {
\r
6482 var col = oSettings.aoColumns[i];
\r
6484 if ( col.mData === i ) {
\r
6485 var sort = a( cell, 'sort' ) || a( cell, 'order' );
\r
6486 var filter = a( cell, 'filter' ) || a( cell, 'search' );
\r
6488 if ( sort !== null || filter !== null ) {
\r
6491 sort: sort !== null ? i+'.@data-'+sort : undefined,
\r
6492 type: sort !== null ? i+'.@data-'+sort : undefined,
\r
6493 filter: filter !== null ? i+'.@data-'+filter : undefined
\r
6496 _fnColumnOptions( oSettings, i );
\r
6502 var features = oSettings.oFeatures;
\r
6504 /* Must be done after everything which can be overridden by the state saving! */
\r
6505 if ( oInit.bStateSave )
\r
6507 features.bStateSave = true;
\r
6508 _fnLoadState( oSettings, oInit );
\r
6509 _fnCallbackReg( oSettings, 'aoDrawCallback', _fnSaveState, 'state_save' );
\r
6515 * @todo For modularisation (1.11) this needs to do into a sort start up handler
\r
6518 // If aaSorting is not defined, then we use the first indicator in asSorting
\r
6519 // in case that has been altered, so the default sort reflects that option
\r
6520 if ( oInit.aaSorting === undefined )
\r
6522 var sorting = oSettings.aaSorting;
\r
6523 for ( i=0, iLen=sorting.length ; i<iLen ; i++ )
\r
6525 sorting[i][1] = oSettings.aoColumns[ i ].asSorting[0];
\r
6529 /* Do a first pass on the sorting classes (allows any size changes to be taken into
\r
6530 * account, and also will apply sorting disabled classes if disabled
\r
6532 _fnSortingClasses( oSettings );
\r
6534 if ( features.bSort )
\r
6536 _fnCallbackReg( oSettings, 'aoDrawCallback', function () {
\r
6537 if ( oSettings.bSorted ) {
\r
6538 var aSort = _fnSortFlatten( oSettings );
\r
6539 var sortedColumns = {};
\r
6541 $.each( aSort, function (i, val) {
\r
6542 sortedColumns[ val.src ] = val.dir;
\r
6545 _fnCallbackFire( oSettings, null, 'order', [oSettings, aSort, sortedColumns] );
\r
6546 _fnSortAria( oSettings );
\r
6551 _fnCallbackReg( oSettings, 'aoDrawCallback', function () {
\r
6552 if ( oSettings.bSorted || _fnDataSource( oSettings ) === 'ssp' || features.bDeferRender ) {
\r
6553 _fnSortingClasses( oSettings );
\r
6560 * Cache the header, body and footer as required, creating them if needed
\r
6563 // Work around for Webkit bug 83867 - store the caption-side before removing from doc
\r
6564 var captions = $this.children('caption').each( function () {
\r
6565 this._captionSide = $this.css('caption-side');
\r
6568 var thead = $this.children('thead');
\r
6569 if ( thead.length === 0 )
\r
6571 thead = $('<thead/>').appendTo(this);
\r
6573 oSettings.nTHead = thead[0];
\r
6575 var tbody = $this.children('tbody');
\r
6576 if ( tbody.length === 0 )
\r
6578 tbody = $('<tbody/>').appendTo(this);
\r
6580 oSettings.nTBody = tbody[0];
\r
6582 var tfoot = $this.children('tfoot');
\r
6583 if ( tfoot.length === 0 && captions.length > 0 && (oSettings.oScroll.sX !== "" || oSettings.oScroll.sY !== "") )
\r
6585 // If we are a scrolling table, and no footer has been given, then we need to create
\r
6586 // a tfoot element for the caption element to be appended to
\r
6587 tfoot = $('<tfoot/>').appendTo(this);
\r
6590 if ( tfoot.length === 0 || tfoot.children().length === 0 ) {
\r
6591 $this.addClass( oClasses.sNoFooter );
\r
6593 else if ( tfoot.length > 0 ) {
\r
6594 oSettings.nTFoot = tfoot[0];
\r
6595 _fnDetectHeader( oSettings.aoFooter, oSettings.nTFoot );
\r
6598 /* Check if there is data passing into the constructor */
\r
6599 if ( oInit.aaData )
\r
6601 for ( i=0 ; i<oInit.aaData.length ; i++ )
\r
6603 _fnAddData( oSettings, oInit.aaData[ i ] );
\r
6606 else if ( oSettings.bDeferLoading || _fnDataSource( oSettings ) == 'dom' )
\r
6608 /* Grab the data from the page - only do this when deferred loading or no Ajax
\r
6609 * source since there is no point in reading the DOM data if we are then going
\r
6610 * to replace it with Ajax data
\r
6612 _fnAddTr( oSettings, $(oSettings.nTBody).children('tr') );
\r
6615 /* Copy the data index array */
\r
6616 oSettings.aiDisplay = oSettings.aiDisplayMaster.slice();
\r
6618 /* Initialisation complete - table can be drawn */
\r
6619 oSettings.bInitialised = true;
\r
6621 /* Check if we need to initialise the table (it might not have been handed off to the
\r
6622 * language processor)
\r
6624 if ( bInitHandedOff === false )
\r
6626 _fnInitialise( oSettings );
\r
6636 * Computed structure of the DataTables API, defined by the options passed to
\r
6637 * `DataTable.Api.register()` when building the API.
\r
6639 * The structure is built in order to speed creation and extension of the Api
\r
6640 * objects since the extensions are effectively pre-parsed.
\r
6642 * The array is an array of objects with the following structure, where this
\r
6643 * base array represents the Api prototype base:
\r
6647 * name: 'data' -- string - Property name
\r
6648 * val: function () {}, -- function - Api method (or undefined if just an object
\r
6649 * methodExt: [ ... ], -- array - Array of Api object definitions to extend the method result
\r
6650 * propExt: [ ... ] -- array - Array of Api object definitions to extend the property
\r
6655 * methodExt: [ ... ],
\r
6659 * val: function () {},
\r
6660 * methodExt: [ ... ],
\r
6661 * propExt: [ ... ]
\r
6671 var __apiStruct = [];
\r
6675 * `Array.prototype` reference.
\r
6680 var __arrayProto = Array.prototype;
\r
6684 * Abstraction for `context` parameter of the `Api` constructor to allow it to
\r
6685 * take several different forms for ease of use.
\r
6687 * Each of the input parameter types will be converted to a DataTables settings
\r
6688 * object where possible.
\r
6690 * @param {string|node|jQuery|object} mixed DataTable identifier. Can be one
\r
6693 * * `string` - jQuery selector. Any DataTables' matching the given selector
\r
6694 * with be found and used.
\r
6695 * * `node` - `TABLE` node which has already been formed into a DataTable.
\r
6696 * * `jQuery` - A jQuery object of `TABLE` nodes.
\r
6697 * * `object` - DataTables settings object
\r
6698 * * `DataTables.Api` - API instance
\r
6699 * @return {array|null} Matching DataTables settings objects. `null` or
\r
6700 * `undefined` is returned if no matching DataTable is found.
\r
6703 var _toSettings = function ( mixed )
\r
6706 var settings = DataTable.settings;
\r
6707 var tables = $.map( settings, function (el, i) {
\r
6714 else if ( mixed.nTable && mixed.oApi ) {
\r
6715 // DataTables settings object
\r
6718 else if ( mixed.nodeName && mixed.nodeName.toLowerCase() === 'table' ) {
\r
6720 idx = $.inArray( mixed, tables );
\r
6721 return idx !== -1 ? [ settings[idx] ] : null;
\r
6723 else if ( mixed && typeof mixed.settings === 'function' ) {
\r
6724 return mixed.settings().toArray();
\r
6726 else if ( typeof mixed === 'string' ) {
\r
6727 // jQuery selector
\r
6730 else if ( mixed instanceof $ ) {
\r
6731 // jQuery object (also DataTables instance)
\r
6736 return jq.map( function(i) {
\r
6737 idx = $.inArray( this, tables );
\r
6738 return idx !== -1 ? settings[idx] : null;
\r
6745 * DataTables API class - used to control and interface with one or more
\r
6746 * DataTables enhanced tables.
\r
6748 * The API class is heavily based on jQuery, presenting a chainable interface
\r
6749 * that you can use to interact with tables. Each instance of the API class has
\r
6750 * a "context" - i.e. the tables that it will operate on. This could be a single
\r
6751 * table, all tables on a page or a sub-set thereof.
\r
6753 * Additionally the API is designed to allow you to easily work with the data in
\r
6754 * the tables, retrieving and manipulating it as required. This is done by
\r
6755 * presenting the API class as an array like interface. The contents of the
\r
6756 * array depend upon the actions requested by each method (for example
\r
6757 * `rows().nodes()` will return an array of nodes, while `rows().data()` will
\r
6758 * return an array of objects or arrays depending upon your table's
\r
6759 * configuration). The API object has a number of array like methods (`push`,
\r
6760 * `pop`, `reverse` etc) as well as additional helper methods (`each`, `pluck`,
\r
6761 * `unique` etc) to assist your working with the data held in a table.
\r
6763 * Most methods (those which return an Api instance) are chainable, which means
\r
6764 * the return from a method call also has all of the methods available that the
\r
6765 * top level object had. For example, these two calls are equivalent:
\r
6768 * api.row.add( {...} );
\r
6772 * api.row.add( {...} ).draw();
\r
6774 * @class DataTable.Api
\r
6775 * @param {array|object|string|jQuery} context DataTable identifier. This is
\r
6776 * used to define which DataTables enhanced tables this API will operate on.
\r
6779 * * `string` - jQuery selector. Any DataTables' matching the given selector
\r
6780 * with be found and used.
\r
6781 * * `node` - `TABLE` node which has already been formed into a DataTable.
\r
6782 * * `jQuery` - A jQuery object of `TABLE` nodes.
\r
6783 * * `object` - DataTables settings object
\r
6784 * @param {array} [data] Data to initialise the Api instance with.
\r
6787 * // Direct initialisation during DataTables construction
\r
6788 * var api = $('#example').DataTable();
\r
6791 * // Initialisation using a DataTables jQuery object
\r
6792 * var api = $('#example').dataTable().api();
\r
6795 * // Initialisation as a constructor
\r
6796 * var api = new $.fn.DataTable.Api( 'table.dataTable' );
\r
6798 _Api = function ( context, data )
\r
6800 if ( ! (this instanceof _Api) ) {
\r
6801 return new _Api( context, data );
\r
6804 var settings = [];
\r
6805 var ctxSettings = function ( o ) {
\r
6806 var a = _toSettings( o );
\r
6808 settings = settings.concat( a );
\r
6812 if ( $.isArray( context ) ) {
\r
6813 for ( var i=0, ien=context.length ; i<ien ; i++ ) {
\r
6814 ctxSettings( context[i] );
\r
6818 ctxSettings( context );
\r
6821 // Remove duplicates
\r
6822 this.context = _unique( settings );
\r
6826 $.merge( this, data );
\r
6836 _Api.extend( this, this, __apiStruct );
\r
6839 DataTable.Api = _Api;
\r
6841 // Don't destroy the existing prototype, just extend it. Required for jQuery 2's
\r
6843 $.extend( _Api.prototype, {
\r
6846 return this.count() !== 0;
\r
6850 concat: __arrayProto.concat,
\r
6853 context: [], // array of table settings objects
\r
6856 count: function ()
\r
6858 return this.flatten().length;
\r
6862 each: function ( fn )
\r
6864 for ( var i=0, ien=this.length ; i<ien; i++ ) {
\r
6865 fn.call( this, this[i], i, this );
\r
6872 eq: function ( idx )
\r
6874 var ctx = this.context;
\r
6876 return ctx.length > idx ?
\r
6877 new _Api( ctx[idx], this[idx] ) :
\r
6882 filter: function ( fn )
\r
6886 if ( __arrayProto.filter ) {
\r
6887 a = __arrayProto.filter.call( this, fn, this );
\r
6890 // Compatibility for browsers without EMCA-252-5 (JS 1.6)
\r
6891 for ( var i=0, ien=this.length ; i<ien ; i++ ) {
\r
6892 if ( fn.call( this, this[i], i, this ) ) {
\r
6893 a.push( this[i] );
\r
6898 return new _Api( this.context, a );
\r
6902 flatten: function ()
\r
6905 return new _Api( this.context, a.concat.apply( a, this.toArray() ) );
\r
6909 join: __arrayProto.join,
\r
6912 indexOf: __arrayProto.indexOf || function (obj, start)
\r
6914 for ( var i=(start || 0), ien=this.length ; i<ien ; i++ ) {
\r
6915 if ( this[i] === obj ) {
\r
6922 iterator: function ( flatten, type, fn, alwaysNew ) {
\r
6926 context = this.context,
\r
6927 rows, items, item,
\r
6928 selector = this.selector;
\r
6930 // Argument shifting
\r
6931 if ( typeof flatten === 'string' ) {
\r
6938 for ( i=0, ien=context.length ; i<ien ; i++ ) {
\r
6939 var apiInst = new _Api( context[i] );
\r
6941 if ( type === 'table' ) {
\r
6942 ret = fn.call( apiInst, context[i], i );
\r
6944 if ( ret !== undefined ) {
\r
6948 else if ( type === 'columns' || type === 'rows' ) {
\r
6949 // this has same length as context - one entry for each table
\r
6950 ret = fn.call( apiInst, context[i], this[i], i );
\r
6952 if ( ret !== undefined ) {
\r
6956 else if ( type === 'column' || type === 'column-rows' || type === 'row' || type === 'cell' ) {
\r
6957 // columns and rows share the same structure.
\r
6958 // 'this' is an array of column indexes for each context
\r
6961 if ( type === 'column-rows' ) {
\r
6962 rows = _selector_row_indexes( context[i], selector.opts );
\r
6965 for ( j=0, jen=items.length ; j<jen ; j++ ) {
\r
6968 if ( type === 'cell' ) {
\r
6969 ret = fn.call( apiInst, context[i], item.row, item.column, i, j );
\r
6972 ret = fn.call( apiInst, context[i], item, i, j, rows );
\r
6975 if ( ret !== undefined ) {
\r
6982 if ( a.length || alwaysNew ) {
\r
6983 var api = new _Api( context, flatten ? a.concat.apply( [], a ) : a );
\r
6984 var apiSelector = api.selector;
\r
6985 apiSelector.rows = selector.rows;
\r
6986 apiSelector.cols = selector.cols;
\r
6987 apiSelector.opts = selector.opts;
\r
6994 lastIndexOf: __arrayProto.lastIndexOf || function (obj, start)
\r
6997 return this.indexOf.apply( this.toArray.reverse(), arguments );
\r
7004 map: function ( fn )
\r
7008 if ( __arrayProto.map ) {
\r
7009 a = __arrayProto.map.call( this, fn, this );
\r
7012 // Compatibility for browsers without EMCA-252-5 (JS 1.6)
\r
7013 for ( var i=0, ien=this.length ; i<ien ; i++ ) {
\r
7014 a.push( fn.call( this, this[i], i ) );
\r
7018 return new _Api( this.context, a );
\r
7022 pluck: function ( prop )
\r
7024 return this.map( function ( el ) {
\r
7025 return el[ prop ];
\r
7029 pop: __arrayProto.pop,
\r
7032 push: __arrayProto.push,
\r
7035 // Does not return an API instance
\r
7036 reduce: __arrayProto.reduce || function ( fn, init )
\r
7038 return _fnReduce( this, fn, init, 0, this.length, 1 );
\r
7042 reduceRight: __arrayProto.reduceRight || function ( fn, init )
\r
7044 return _fnReduce( this, fn, init, this.length-1, -1, -1 );
\r
7048 reverse: __arrayProto.reverse,
\r
7051 // Object with rows, columns and opts
\r
7055 shift: __arrayProto.shift,
\r
7058 sort: __arrayProto.sort, // ? name - order?
\r
7061 splice: __arrayProto.splice,
\r
7064 toArray: function ()
\r
7066 return __arrayProto.slice.call( this );
\r
7076 toJQuery: function ()
\r
7082 unique: function ()
\r
7084 return new _Api( this.context, _unique(this) );
\r
7088 unshift: __arrayProto.unshift
\r
7092 _Api.extend = function ( scope, obj, ext )
\r
7094 // Only extend API instances and static properties of the API
\r
7095 if ( ! ext.length || ! obj || ( ! (obj instanceof _Api) && ! obj.__dt_wrapper ) ) {
\r
7103 methodScoping = function ( scope, fn, struc ) {
\r
7104 return function () {
\r
7105 var ret = fn.apply( scope, arguments );
\r
7107 // Method extension
\r
7108 _Api.extend( ret, ret, struc.methodExt );
\r
7113 for ( i=0, ien=ext.length ; i<ien ; i++ ) {
\r
7117 obj[ struct.name ] = typeof struct.val === 'function' ?
\r
7118 methodScoping( scope, struct.val, struct ) :
\r
7119 $.isPlainObject( struct.val ) ?
\r
7123 obj[ struct.name ].__dt_wrapper = true;
\r
7125 // Property extension
\r
7126 _Api.extend( scope, obj[ struct.name ], struct.propExt );
\r
7131 // @todo - Is there need for an augment function?
\r
7132 // _Api.augment = function ( inst, name )
\r
7134 // // Find src object in the structure from the name
\r
7135 // var parts = name.split('.');
\r
7137 // _Api.extend( inst, obj );
\r
7143 // name: 'data' -- string - Property name
\r
7144 // val: function () {}, -- function - Api method (or undefined if just an object
\r
7145 // methodExt: [ ... ], -- array - Array of Api object definitions to extend the method result
\r
7146 // propExt: [ ... ] -- array - Array of Api object definitions to extend the property
\r
7151 // methodExt: [ ... ],
\r
7155 // val: function () {},
\r
7156 // methodExt: [ ... ],
\r
7157 // propExt: [ ... ]
\r
7164 _Api.register = _api_register = function ( name, val )
\r
7166 if ( $.isArray( name ) ) {
\r
7167 for ( var j=0, jen=name.length ; j<jen ; j++ ) {
\r
7168 _Api.register( name[j], val );
\r
7175 heir = name.split('.'),
\r
7176 struct = __apiStruct,
\r
7179 var find = function ( src, name ) {
\r
7180 for ( var i=0, ien=src.length ; i<ien ; i++ ) {
\r
7181 if ( src[i].name === name ) {
\r
7188 for ( i=0, ien=heir.length ; i<ien ; i++ ) {
\r
7189 method = heir[i].indexOf('()') !== -1;
\r
7191 heir[i].replace('()', '') :
\r
7194 var src = find( struct, key );
\r
7202 struct.push( src );
\r
7205 if ( i === ien-1 ) {
\r
7217 _Api.registerPlural = _api_registerPlural = function ( pluralName, singularName, val ) {
\r
7218 _Api.register( pluralName, val );
\r
7220 _Api.register( singularName, function () {
\r
7221 var ret = val.apply( this, arguments );
\r
7223 if ( ret === this ) {
\r
7224 // Returned item is the API instance that was passed in, return it
\r
7227 else if ( ret instanceof _Api ) {
\r
7228 // New API instance returned, want the value from the first item
\r
7229 // in the returned array for the singular result.
\r
7230 return ret.length ?
\r
7231 $.isArray( ret[0] ) ?
\r
7232 new _Api( ret.context, ret[0] ) : // Array results are 'enhanced'
\r
7237 // Non-API return - just fire it back
\r
7244 * Selector for HTML tables. Apply the given selector to the give array of
\r
7245 * DataTables settings objects.
\r
7247 * @param {string|integer} [selector] jQuery selector string or integer
\r
7248 * @param {array} Array of DataTables settings objects to be filtered
\r
7252 var __table_selector = function ( selector, a )
\r
7254 // Integer is used to pick out a table by index
\r
7255 if ( typeof selector === 'number' ) {
\r
7256 return [ a[ selector ] ];
\r
7259 // Perform a jQuery selector on the table nodes
\r
7260 var nodes = $.map( a, function (el, i) {
\r
7265 .filter( selector )
\r
7266 .map( function (i) {
\r
7267 // Need to translate back from the table node to the settings
\r
7268 var idx = $.inArray( this, nodes );
\r
7277 * Context selector for the API's context (i.e. the tables the API instance
\r
7280 * @name DataTable.Api#tables
\r
7281 * @param {string|integer} [selector] Selector to pick which tables the iterator
\r
7282 * should operate on. If not given, all tables in the current context are
\r
7283 * used. This can be given as a jQuery selector (for example `':gt(0)'`) to
\r
7284 * select multiple tables or as an integer to select a single table.
\r
7285 * @returns {DataTable.Api} Returns a new API instance if a selector is given.
\r
7287 _api_register( 'tables()', function ( selector ) {
\r
7288 // A new instance is created if there was a selector specified
\r
7290 new _Api( __table_selector( selector, this.context ) ) :
\r
7295 _api_register( 'table()', function ( selector ) {
\r
7296 var tables = this.tables( selector );
\r
7297 var ctx = tables.context;
\r
7299 // Truncate to the first matched table
\r
7300 return ctx.length ?
\r
7301 new _Api( ctx[0] ) :
\r
7306 _api_registerPlural( 'tables().nodes()', 'table().node()' , function () {
\r
7307 return this.iterator( 'table', function ( ctx ) {
\r
7308 return ctx.nTable;
\r
7313 _api_registerPlural( 'tables().body()', 'table().body()' , function () {
\r
7314 return this.iterator( 'table', function ( ctx ) {
\r
7315 return ctx.nTBody;
\r
7320 _api_registerPlural( 'tables().header()', 'table().header()' , function () {
\r
7321 return this.iterator( 'table', function ( ctx ) {
\r
7322 return ctx.nTHead;
\r
7327 _api_registerPlural( 'tables().footer()', 'table().footer()' , function () {
\r
7328 return this.iterator( 'table', function ( ctx ) {
\r
7329 return ctx.nTFoot;
\r
7334 _api_registerPlural( 'tables().containers()', 'table().container()' , function () {
\r
7335 return this.iterator( 'table', function ( ctx ) {
\r
7336 return ctx.nTableWrapper;
\r
7343 * Redraw the tables in the current context.
\r
7345 _api_register( 'draw()', function ( paging ) {
\r
7346 return this.iterator( 'table', function ( settings ) {
\r
7347 if ( paging === 'page' ) {
\r
7348 _fnDraw( settings );
\r
7351 if ( typeof paging === 'string' ) {
\r
7352 paging = paging === 'full-hold' ?
\r
7357 _fnReDraw( settings, paging===false );
\r
7365 * Get the current page index.
\r
7367 * @return {integer} Current page index (zero based)
\r
7369 * Set the current page.
\r
7371 * Note that if you attempt to show a page which does not exist, DataTables will
\r
7372 * not throw an error, but rather reset the paging.
\r
7374 * @param {integer|string} action The paging action to take. This can be one of:
\r
7375 * * `integer` - The page index to jump to
\r
7376 * * `string` - An action to take:
\r
7377 * * `first` - Jump to first page.
\r
7378 * * `next` - Jump to the next page
\r
7379 * * `previous` - Jump to previous page
\r
7380 * * `last` - Jump to the last page.
\r
7381 * @returns {DataTables.Api} this
\r
7383 _api_register( 'page()', function ( action ) {
\r
7384 if ( action === undefined ) {
\r
7385 return this.page.info().page; // not an expensive call
\r
7388 // else, have an action to take on all tables
\r
7389 return this.iterator( 'table', function ( settings ) {
\r
7390 _fnPageChange( settings, action );
\r
7396 * Paging information for the first table in the current context.
\r
7398 * If you require paging information for another table, use the `table()` method
\r
7399 * with a suitable selector.
\r
7401 * @return {object} Object with the following properties set:
\r
7402 * * `page` - Current page index (zero based - i.e. the first page is `0`)
\r
7403 * * `pages` - Total number of pages
\r
7404 * * `start` - Display index for the first record shown on the current page
\r
7405 * * `end` - Display index for the last record shown on the current page
\r
7406 * * `length` - Display length (number of records). Note that generally `start
\r
7407 * + length = end`, but this is not always true, for example if there are
\r
7408 * only 2 records to show on the final page, with a length of 10.
\r
7409 * * `recordsTotal` - Full data set length
\r
7410 * * `recordsDisplay` - Data set length once the current filtering criterion
\r
7413 _api_register( 'page.info()', function ( action ) {
\r
7414 if ( this.context.length === 0 ) {
\r
7419 settings = this.context[0],
\r
7420 start = settings._iDisplayStart,
\r
7421 len = settings.oFeatures.bPaginate ? settings._iDisplayLength : -1,
\r
7422 visRecords = settings.fnRecordsDisplay(),
\r
7426 "page": all ? 0 : Math.floor( start / len ),
\r
7427 "pages": all ? 1 : Math.ceil( visRecords / len ),
\r
7429 "end": settings.fnDisplayEnd(),
\r
7431 "recordsTotal": settings.fnRecordsTotal(),
\r
7432 "recordsDisplay": visRecords,
\r
7433 "serverSide": _fnDataSource( settings ) === 'ssp'
\r
7439 * Get the current page length.
\r
7441 * @return {integer} Current page length. Note `-1` indicates that all records
\r
7442 * are to be shown.
\r
7444 * Set the current page length.
\r
7446 * @param {integer} Page length to set. Use `-1` to show all records.
\r
7447 * @returns {DataTables.Api} this
\r
7449 _api_register( 'page.len()', function ( len ) {
\r
7450 // Note that we can't call this function 'length()' because `length`
\r
7451 // is a Javascript property of functions which defines how many arguments
\r
7452 // the function expects.
\r
7453 if ( len === undefined ) {
\r
7454 return this.context.length !== 0 ?
\r
7455 this.context[0]._iDisplayLength :
\r
7459 // else, set the page length
\r
7460 return this.iterator( 'table', function ( settings ) {
\r
7461 _fnLengthChange( settings, len );
\r
7467 var __reload = function ( settings, holdPosition, callback ) {
\r
7468 // Use the draw event to trigger a callback
\r
7470 var api = new _Api( settings );
\r
7472 api.one( 'draw', function () {
\r
7473 callback( api.ajax.json() );
\r
7477 if ( _fnDataSource( settings ) == 'ssp' ) {
\r
7478 _fnReDraw( settings, holdPosition );
\r
7481 _fnProcessingDisplay( settings, true );
\r
7483 // Cancel an existing request
\r
7484 var xhr = settings.jqXHR;
\r
7485 if ( xhr && xhr.readyState !== 4 ) {
\r
7490 _fnBuildAjax( settings, [], function( json ) {
\r
7491 _fnClearTable( settings );
\r
7493 var data = _fnAjaxDataSrc( settings, json );
\r
7494 for ( var i=0, ien=data.length ; i<ien ; i++ ) {
\r
7495 _fnAddData( settings, data[i] );
\r
7498 _fnReDraw( settings, holdPosition );
\r
7499 _fnProcessingDisplay( settings, false );
\r
7506 * Get the JSON response from the last Ajax request that DataTables made to the
\r
7507 * server. Note that this returns the JSON from the first table in the current
\r
7510 * @return {object} JSON received from the server.
\r
7512 _api_register( 'ajax.json()', function () {
\r
7513 var ctx = this.context;
\r
7515 if ( ctx.length > 0 ) {
\r
7516 return ctx[0].json;
\r
7519 // else return undefined;
\r
7524 * Get the data submitted in the last Ajax request
\r
7526 _api_register( 'ajax.params()', function () {
\r
7527 var ctx = this.context;
\r
7529 if ( ctx.length > 0 ) {
\r
7530 return ctx[0].oAjaxData;
\r
7533 // else return undefined;
\r
7538 * Reload tables from the Ajax data source. Note that this function will
\r
7539 * automatically re-draw the table when the remote data has been loaded.
\r
7541 * @param {boolean} [reset=true] Reset (default) or hold the current paging
\r
7542 * position. A full re-sort and re-filter is performed when this method is
\r
7543 * called, which is why the pagination reset is the default action.
\r
7544 * @returns {DataTables.Api} this
\r
7546 _api_register( 'ajax.reload()', function ( callback, resetPaging ) {
\r
7547 return this.iterator( 'table', function (settings) {
\r
7548 __reload( settings, resetPaging===false, callback );
\r
7554 * Get the current Ajax URL. Note that this returns the URL from the first
\r
7555 * table in the current context.
\r
7557 * @return {string} Current Ajax source URL
\r
7559 * Set the Ajax URL. Note that this will set the URL for all tables in the
\r
7560 * current context.
\r
7562 * @param {string} url URL to set.
\r
7563 * @returns {DataTables.Api} this
\r
7565 _api_register( 'ajax.url()', function ( url ) {
\r
7566 var ctx = this.context;
\r
7568 if ( url === undefined ) {
\r
7570 if ( ctx.length === 0 ) {
\r
7576 $.isPlainObject( ctx.ajax ) ?
\r
7583 return this.iterator( 'table', function ( settings ) {
\r
7584 if ( $.isPlainObject( settings.ajax ) ) {
\r
7585 settings.ajax.url = url;
\r
7588 settings.ajax = url;
\r
7590 // No need to consider sAjaxSource here since DataTables gives priority
\r
7591 // to `ajax` over `sAjaxSource`. So setting `ajax` here, renders any
\r
7592 // value of `sAjaxSource` redundant.
\r
7598 * Load data from the newly set Ajax URL. Note that this method is only
\r
7599 * available when `ajax.url()` is used to set a URL. Additionally, this method
\r
7600 * has the same effect as calling `ajax.reload()` but is provided for
\r
7601 * convenience when setting a new URL. Like `ajax.reload()` it will
\r
7602 * automatically redraw the table once the remote data has been loaded.
\r
7604 * @returns {DataTables.Api} this
\r
7606 _api_register( 'ajax.url().load()', function ( callback, resetPaging ) {
\r
7607 // Same as a reload, but makes sense to present it for easy access after a
\r
7609 return this.iterator( 'table', function ( ctx ) {
\r
7610 __reload( ctx, resetPaging===false, callback );
\r
7617 var _selector_run = function ( type, selector, selectFn, settings, opts )
\r
7621 a, i, ien, j, jen,
\r
7622 selectorType = typeof selector;
\r
7624 // Can't just check for isArray here, as an API or jQuery instance might be
\r
7625 // given with their array like look
\r
7626 if ( ! selector || selectorType === 'string' || selectorType === 'function' || selector.length === undefined ) {
\r
7627 selector = [ selector ];
\r
7630 for ( i=0, ien=selector.length ; i<ien ; i++ ) {
\r
7631 a = selector[i] && selector[i].split ?
\r
7632 selector[i].split(',') :
\r
7635 for ( j=0, jen=a.length ; j<jen ; j++ ) {
\r
7636 res = selectFn( typeof a[j] === 'string' ? $.trim(a[j]) : a[j] );
\r
7638 if ( res && res.length ) {
\r
7639 out = out.concat( res );
\r
7644 // selector extensions
\r
7645 var ext = _ext.selector[ type ];
\r
7646 if ( ext.length ) {
\r
7647 for ( i=0, ien=ext.length ; i<ien ; i++ ) {
\r
7648 out = ext[i]( settings, opts, out );
\r
7652 return _unique( out );
\r
7656 var _selector_opts = function ( opts )
\r
7662 // Backwards compatibility for 1.9- which used the terminology filter rather
\r
7664 if ( opts.filter && opts.search === undefined ) {
\r
7665 opts.search = opts.filter;
\r
7668 return $.extend( {
\r
7676 var _selector_first = function ( inst )
\r
7678 // Reduce the API instance to the first item found
\r
7679 for ( var i=0, ien=inst.length ; i<ien ; i++ ) {
\r
7680 if ( inst[i].length > 0 ) {
\r
7681 // Assign the first element to the first item in the instance
\r
7682 // and truncate the instance and context
\r
7683 inst[0] = inst[i];
\r
7684 inst[0].length = 1;
\r
7686 inst.context = [ inst.context[i] ];
\r
7692 // Not found - return an empty instance
\r
7698 var _selector_row_indexes = function ( settings, opts )
\r
7701 i, ien, tmp, a=[],
\r
7702 displayFiltered = settings.aiDisplay,
\r
7703 displayMaster = settings.aiDisplayMaster;
\r
7706 search = opts.search, // none, applied, removed
\r
7707 order = opts.order, // applied, current, index (original - compatibility with 1.9)
\r
7708 page = opts.page; // all, current
\r
7710 if ( _fnDataSource( settings ) == 'ssp' ) {
\r
7711 // In server-side processing mode, most options are irrelevant since
\r
7712 // rows not shown don't exist and the index order is the applied order
\r
7713 // Removed is a special case - for consistency just return an empty
\r
7715 return search === 'removed' ?
\r
7717 _range( 0, displayMaster.length );
\r
7719 else if ( page == 'current' ) {
\r
7720 // Current page implies that order=current and fitler=applied, since it is
\r
7721 // fairly senseless otherwise, regardless of what order and search actually
\r
7723 for ( i=settings._iDisplayStart, ien=settings.fnDisplayEnd() ; i<ien ; i++ ) {
\r
7724 a.push( displayFiltered[i] );
\r
7727 else if ( order == 'current' || order == 'applied' ) {
\r
7728 a = search == 'none' ?
\r
7729 displayMaster.slice() : // no search
\r
7730 search == 'applied' ?
\r
7731 displayFiltered.slice() : // applied search
\r
7732 $.map( displayMaster, function (el, i) { // removed search
\r
7733 return $.inArray( el, displayFiltered ) === -1 ? el : null;
\r
7736 else if ( order == 'index' || order == 'original' ) {
\r
7737 for ( i=0, ien=settings.aoData.length ; i<ien ; i++ ) {
\r
7738 if ( search == 'none' ) {
\r
7741 else { // applied | removed
\r
7742 tmp = $.inArray( i, displayFiltered );
\r
7744 if ((tmp === -1 && search == 'removed') ||
\r
7745 (tmp >= 0 && search == 'applied') )
\r
7757 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
\r
7760 * {} - no selector - use all available rows
\r
7761 * {integer} - row aoData index
\r
7762 * {node} - TR node
\r
7763 * {string} - jQuery selector to apply to the TR elements
\r
7764 * {array} - jQuery array of nodes, or simply an array of TR nodes
\r
7769 var __row_selector = function ( settings, selector, opts )
\r
7771 var run = function ( sel ) {
\r
7772 var selInt = _intVal( sel );
\r
7775 // Short cut - selector is a number and no options provided (default is
\r
7776 // all records, so no need to check if the index is in there, since it
\r
7777 // must be - dev error if the index doesn't exist).
\r
7778 if ( selInt !== null && ! opts ) {
\r
7779 return [ selInt ];
\r
7782 var rows = _selector_row_indexes( settings, opts );
\r
7784 if ( selInt !== null && $.inArray( selInt, rows ) !== -1 ) {
\r
7785 // Selector - integer
\r
7786 return [ selInt ];
\r
7788 else if ( ! sel ) {
\r
7789 // Selector - none
\r
7793 // Selector - function
\r
7794 if ( typeof sel === 'function' ) {
\r
7795 return $.map( rows, function (idx) {
\r
7796 var row = settings.aoData[ idx ];
\r
7797 return sel( idx, row._aData, row.nTr ) ? idx : null;
\r
7801 // Get nodes in the order from the `rows` array with null values removed
\r
7802 var nodes = _removeEmpty(
\r
7803 _pluck_order( settings.aoData, rows, 'nTr' )
\r
7806 // Selector - node
\r
7807 if ( sel.nodeName ) {
\r
7808 if ( sel._DT_RowIndex !== undefined ) {
\r
7809 return [ sel._DT_RowIndex ]; // Property added by DT for fast lookup
\r
7811 else if ( sel._DT_CellIndex ) {
\r
7812 return [ sel._DT_CellIndex.row ];
\r
7815 var host = $(sel).closest('*[data-dt-row]');
\r
7816 return host.length ?
\r
7817 [ host.data('dt-row') ] :
\r
7822 // ID selector. Want to always be able to select rows by id, regardless
\r
7823 // of if the tr element has been created or not, so can't rely upon
\r
7824 // jQuery here - hence a custom implementation. This does not match
\r
7825 // Sizzle's fast selector or HTML4 - in HTML5 the ID can be anything,
\r
7826 // but to select it using a CSS selector engine (like Sizzle or
\r
7827 // querySelect) it would need to need to be escaped for some characters.
\r
7828 // DataTables simplifies this for row selectors since you can select
\r
7829 // only a row. A # indicates an id any anything that follows is the id -
\r
7831 if ( typeof sel === 'string' && sel.charAt(0) === '#' ) {
\r
7832 // get row index from id
\r
7833 var rowObj = settings.aIds[ sel.replace( /^#/, '' ) ];
\r
7834 if ( rowObj !== undefined ) {
\r
7835 return [ rowObj.idx ];
\r
7838 // need to fall through to jQuery in case there is DOM id that
\r
7842 // Selector - jQuery selector string, array of nodes or jQuery object/
\r
7843 // As jQuery's .filter() allows jQuery objects to be passed in filter,
\r
7844 // it also allows arrays, so this will cope with all three options
\r
7847 .map( function () {
\r
7848 return this._DT_RowIndex;
\r
7853 return _selector_run( 'row', selector, run, settings, opts );
\r
7857 _api_register( 'rows()', function ( selector, opts ) {
\r
7858 // argument shifting
\r
7859 if ( selector === undefined ) {
\r
7862 else if ( $.isPlainObject( selector ) ) {
\r
7867 opts = _selector_opts( opts );
\r
7869 var inst = this.iterator( 'table', function ( settings ) {
\r
7870 return __row_selector( settings, selector, opts );
\r
7873 // Want argument shifting here and in __row_selector?
\r
7874 inst.selector.rows = selector;
\r
7875 inst.selector.opts = opts;
\r
7880 _api_register( 'rows().nodes()', function () {
\r
7881 return this.iterator( 'row', function ( settings, row ) {
\r
7882 return settings.aoData[ row ].nTr || undefined;
\r
7886 _api_register( 'rows().data()', function () {
\r
7887 return this.iterator( true, 'rows', function ( settings, rows ) {
\r
7888 return _pluck_order( settings.aoData, rows, '_aData' );
\r
7892 _api_registerPlural( 'rows().cache()', 'row().cache()', function ( type ) {
\r
7893 return this.iterator( 'row', function ( settings, row ) {
\r
7894 var r = settings.aoData[ row ];
\r
7895 return type === 'search' ? r._aFilterData : r._aSortData;
\r
7899 _api_registerPlural( 'rows().invalidate()', 'row().invalidate()', function ( src ) {
\r
7900 return this.iterator( 'row', function ( settings, row ) {
\r
7901 _fnInvalidate( settings, row, src );
\r
7905 _api_registerPlural( 'rows().indexes()', 'row().index()', function () {
\r
7906 return this.iterator( 'row', function ( settings, row ) {
\r
7911 _api_registerPlural( 'rows().ids()', 'row().id()', function ( hash ) {
\r
7913 var context = this.context;
\r
7915 // `iterator` will drop undefined values, but in this case we want them
\r
7916 for ( var i=0, ien=context.length ; i<ien ; i++ ) {
\r
7917 for ( var j=0, jen=this[i].length ; j<jen ; j++ ) {
\r
7918 var id = context[i].rowIdFn( context[i].aoData[ this[i][j] ]._aData );
\r
7919 a.push( (hash === true ? '#' : '' )+ id );
\r
7923 return new _Api( context, a );
\r
7926 _api_registerPlural( 'rows().remove()', 'row().remove()', function () {
\r
7929 this.iterator( 'row', function ( settings, row, thatIdx ) {
\r
7930 var data = settings.aoData;
\r
7931 var rowData = data[ row ];
\r
7932 var i, ien, j, jen;
\r
7933 var loopRow, loopCells;
\r
7935 data.splice( row, 1 );
\r
7937 // Update the cached indexes
\r
7938 for ( i=0, ien=data.length ; i<ien ; i++ ) {
\r
7939 loopRow = data[i];
\r
7940 loopCells = loopRow.anCells;
\r
7943 if ( loopRow.nTr !== null ) {
\r
7944 loopRow.nTr._DT_RowIndex = i;
\r
7948 if ( loopCells !== null ) {
\r
7949 for ( j=0, jen=loopCells.length ; j<jen ; j++ ) {
\r
7950 loopCells[j]._DT_CellIndex.row = i;
\r
7955 // Delete from the display arrays
\r
7956 _fnDeleteIndex( settings.aiDisplayMaster, row );
\r
7957 _fnDeleteIndex( settings.aiDisplay, row );
\r
7958 _fnDeleteIndex( that[ thatIdx ], row, false ); // maintain local indexes
\r
7960 // Check for an 'overflow' they case for displaying the table
\r
7961 _fnLengthOverflow( settings );
\r
7963 // Remove the row's ID reference if there is one
\r
7964 var id = settings.rowIdFn( rowData._aData );
\r
7965 if ( id !== undefined ) {
\r
7966 delete settings.aIds[ id ];
\r
7970 this.iterator( 'table', function ( settings ) {
\r
7971 for ( var i=0, ien=settings.aoData.length ; i<ien ; i++ ) {
\r
7972 settings.aoData[i].idx = i;
\r
7980 _api_register( 'rows.add()', function ( rows ) {
\r
7981 var newRows = this.iterator( 'table', function ( settings ) {
\r
7985 for ( i=0, ien=rows.length ; i<ien ; i++ ) {
\r
7988 if ( row.nodeName && row.nodeName.toUpperCase() === 'TR' ) {
\r
7989 out.push( _fnAddTr( settings, row )[0] );
\r
7992 out.push( _fnAddData( settings, row ) );
\r
7999 // Return an Api.rows() extended instance, so rows().nodes() etc can be used
\r
8000 var modRows = this.rows( -1 );
\r
8002 $.merge( modRows, newRows );
\r
8014 _api_register( 'row()', function ( selector, opts ) {
\r
8015 return _selector_first( this.rows( selector, opts ) );
\r
8019 _api_register( 'row().data()', function ( data ) {
\r
8020 var ctx = this.context;
\r
8022 if ( data === undefined ) {
\r
8024 return ctx.length && this.length ?
\r
8025 ctx[0].aoData[ this[0] ]._aData :
\r
8030 ctx[0].aoData[ this[0] ]._aData = data;
\r
8032 // Automatically invalidate
\r
8033 _fnInvalidate( ctx[0], this[0], 'data' );
\r
8039 _api_register( 'row().node()', function () {
\r
8040 var ctx = this.context;
\r
8042 return ctx.length && this.length ?
\r
8043 ctx[0].aoData[ this[0] ].nTr || null :
\r
8048 _api_register( 'row.add()', function ( row ) {
\r
8049 // Allow a jQuery object to be passed in - only a single row is added from
\r
8050 // it though - the first element in the set
\r
8051 if ( row instanceof $ && row.length ) {
\r
8055 var rows = this.iterator( 'table', function ( settings ) {
\r
8056 if ( row.nodeName && row.nodeName.toUpperCase() === 'TR' ) {
\r
8057 return _fnAddTr( settings, row )[0];
\r
8059 return _fnAddData( settings, row );
\r
8062 // Return an Api.rows() extended instance, with the newly added row selected
\r
8063 return this.row( rows[0] );
\r
8068 var __details_add = function ( ctx, row, data, klass )
\r
8070 // Convert to array of TR elements
\r
8072 var addRow = function ( r, k ) {
\r
8073 // Recursion to allow for arrays of jQuery objects
\r
8074 if ( $.isArray( r ) || r instanceof $ ) {
\r
8075 for ( var i=0, ien=r.length ; i<ien ; i++ ) {
\r
8076 addRow( r[i], k );
\r
8081 // If we get a TR element, then just add it directly - up to the dev
\r
8082 // to add the correct number of columns etc
\r
8083 if ( r.nodeName && r.nodeName.toLowerCase() === 'tr' ) {
\r
8087 // Otherwise create a row with a wrapper
\r
8088 var created = $('<tr><td/></tr>').addClass( k );
\r
8092 [0].colSpan = _fnVisbleColumns( ctx );
\r
8094 rows.push( created[0] );
\r
8098 addRow( data, klass );
\r
8100 if ( row._details ) {
\r
8101 row._details.remove();
\r
8104 row._details = $(rows);
\r
8106 // If the children were already shown, that state should be retained
\r
8107 if ( row._detailsShow ) {
\r
8108 row._details.insertAfter( row.nTr );
\r
8113 var __details_remove = function ( api, idx )
\r
8115 var ctx = api.context;
\r
8117 if ( ctx.length ) {
\r
8118 var row = ctx[0].aoData[ idx !== undefined ? idx : api[0] ];
\r
8120 if ( row && row._details ) {
\r
8121 row._details.remove();
\r
8123 row._detailsShow = undefined;
\r
8124 row._details = undefined;
\r
8130 var __details_display = function ( api, show ) {
\r
8131 var ctx = api.context;
\r
8133 if ( ctx.length && api.length ) {
\r
8134 var row = ctx[0].aoData[ api[0] ];
\r
8136 if ( row._details ) {
\r
8137 row._detailsShow = show;
\r
8140 row._details.insertAfter( row.nTr );
\r
8143 row._details.detach();
\r
8146 __details_events( ctx[0] );
\r
8152 var __details_events = function ( settings )
\r
8154 var api = new _Api( settings );
\r
8155 var namespace = '.dt.DT_details';
\r
8156 var drawEvent = 'draw'+namespace;
\r
8157 var colvisEvent = 'column-visibility'+namespace;
\r
8158 var destroyEvent = 'destroy'+namespace;
\r
8159 var data = settings.aoData;
\r
8161 api.off( drawEvent +' '+ colvisEvent +' '+ destroyEvent );
\r
8163 if ( _pluck( data, '_details' ).length > 0 ) {
\r
8164 // On each draw, insert the required elements into the document
\r
8165 api.on( drawEvent, function ( e, ctx ) {
\r
8166 if ( settings !== ctx ) {
\r
8170 api.rows( {page:'current'} ).eq(0).each( function (idx) {
\r
8171 // Internal data grab
\r
8172 var row = data[ idx ];
\r
8174 if ( row._detailsShow ) {
\r
8175 row._details.insertAfter( row.nTr );
\r
8180 // Column visibility change - update the colspan
\r
8181 api.on( colvisEvent, function ( e, ctx, idx, vis ) {
\r
8182 if ( settings !== ctx ) {
\r
8186 // Update the colspan for the details rows (note, only if it already has
\r
8188 var row, visible = _fnVisbleColumns( ctx );
\r
8190 for ( var i=0, ien=data.length ; i<ien ; i++ ) {
\r
8193 if ( row._details ) {
\r
8194 row._details.children('td[colspan]').attr('colspan', visible );
\r
8199 // Table destroyed - nuke any child rows
\r
8200 api.on( destroyEvent, function ( e, ctx ) {
\r
8201 if ( settings !== ctx ) {
\r
8205 for ( var i=0, ien=data.length ; i<ien ; i++ ) {
\r
8206 if ( data[i]._details ) {
\r
8207 __details_remove( api, i );
\r
8214 // Strings for the method names to help minification
\r
8216 var _child_obj = _emp+'row().child';
\r
8217 var _child_mth = _child_obj+'()';
\r
8222 // jQuery or array of any of the above
\r
8223 _api_register( _child_mth, function ( data, klass ) {
\r
8224 var ctx = this.context;
\r
8226 if ( data === undefined ) {
\r
8228 return ctx.length && this.length ?
\r
8229 ctx[0].aoData[ this[0] ]._details :
\r
8232 else if ( data === true ) {
\r
8234 this.child.show();
\r
8236 else if ( data === false ) {
\r
8238 __details_remove( this );
\r
8240 else if ( ctx.length && this.length ) {
\r
8242 __details_add( ctx[0], ctx[0].aoData[ this[0] ], data, klass );
\r
8250 _child_obj+'.show()',
\r
8251 _child_mth+'.show()' // only when `child()` was called with parameters (without
\r
8252 ], function ( show ) { // it returns an object and this method is not executed)
\r
8253 __details_display( this, true );
\r
8259 _child_obj+'.hide()',
\r
8260 _child_mth+'.hide()' // only when `child()` was called with parameters (without
\r
8261 ], function () { // it returns an object and this method is not executed)
\r
8262 __details_display( this, false );
\r
8268 _child_obj+'.remove()',
\r
8269 _child_mth+'.remove()' // only when `child()` was called with parameters (without
\r
8270 ], function () { // it returns an object and this method is not executed)
\r
8271 __details_remove( this );
\r
8276 _api_register( _child_obj+'.isShown()', function () {
\r
8277 var ctx = this.context;
\r
8279 if ( ctx.length && this.length ) {
\r
8280 // _detailsShown as false or undefined will fall through to return false
\r
8281 return ctx[0].aoData[ this[0] ]._detailsShow || false;
\r
8288 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
\r
8291 * {integer} - column index (>=0 count from left, <0 count from right)
\r
8292 * "{integer}:visIdx" - visible column index (i.e. translate to column index) (>=0 count from left, <0 count from right)
\r
8293 * "{integer}:visible" - alias for {integer}:visIdx (>=0 count from left, <0 count from right)
\r
8294 * "{string}:name" - column name
\r
8295 * "{string}" - jQuery selector on column header nodes
\r
8299 // can be an array of these items, comma separated list, or an array of comma
\r
8300 // separated lists
\r
8302 var __re_column_selector = /^(.+):(name|visIdx|visible)$/;
\r
8305 // r1 and r2 are redundant - but it means that the parameters match for the
\r
8306 // iterator callback in columns().data()
\r
8307 var __columnData = function ( settings, column, r1, r2, rows ) {
\r
8309 for ( var row=0, ien=rows.length ; row<ien ; row++ ) {
\r
8310 a.push( _fnGetCellData( settings, rows[row], column ) );
\r
8316 var __column_selector = function ( settings, selector, opts )
\r
8319 columns = settings.aoColumns,
\r
8320 names = _pluck( columns, 'sName' ),
\r
8321 nodes = _pluck( columns, 'nTh' );
\r
8323 var run = function ( s ) {
\r
8324 var selInt = _intVal( s );
\r
8328 return _range( columns.length );
\r
8331 // Selector - index
\r
8332 if ( selInt !== null ) {
\r
8333 return [ selInt >= 0 ?
\r
8334 selInt : // Count from left
\r
8335 columns.length + selInt // Count from right (+ because its a negative value)
\r
8339 // Selector = function
\r
8340 if ( typeof s === 'function' ) {
\r
8341 var rows = _selector_row_indexes( settings, opts );
\r
8343 return $.map( columns, function (col, idx) {
\r
8346 __columnData( settings, idx, 0, 0, rows ),
\r
8352 // jQuery or string selector
\r
8353 var match = typeof s === 'string' ?
\r
8354 s.match( __re_column_selector ) :
\r
8358 switch( match[2] ) {
\r
8361 var idx = parseInt( match[1], 10 );
\r
8362 // Visible index given, convert to column index
\r
8364 // Counting from the right
\r
8365 var visColumns = $.map( columns, function (col,i) {
\r
8366 return col.bVisible ? i : null;
\r
8368 return [ visColumns[ visColumns.length + idx ] ];
\r
8370 // Counting from the left
\r
8371 return [ _fnVisibleToColumnIndex( settings, idx ) ];
\r
8374 // match by name. `names` is column index complete and in order
\r
8375 return $.map( names, function (name, i) {
\r
8376 return name === match[1] ? i : null;
\r
8384 // Cell in the table body
\r
8385 if ( s.nodeName && s._DT_CellIndex ) {
\r
8386 return [ s._DT_CellIndex.column ];
\r
8389 // jQuery selector on the TH elements for the columns
\r
8390 var jqResult = $( nodes )
\r
8392 .map( function () {
\r
8393 return $.inArray( this, nodes ); // `nodes` is column index complete and in order
\r
8397 if ( jqResult.length || ! s.nodeName ) {
\r
8401 // Otherwise a node which might have a `dt-column` data attribute, or be
\r
8402 // a child or such an element
\r
8403 var host = $(s).closest('*[data-dt-column]');
\r
8404 return host.length ?
\r
8405 [ host.data('dt-column') ] :
\r
8409 return _selector_run( 'column', selector, run, settings, opts );
\r
8413 var __setColumnVis = function ( settings, column, vis, recalc ) {
\r
8415 cols = settings.aoColumns,
\r
8416 col = cols[ column ],
\r
8417 data = settings.aoData,
\r
8418 row, cells, i, ien, tr;
\r
8421 if ( vis === undefined ) {
\r
8422 return col.bVisible;
\r
8427 if ( col.bVisible === vis ) {
\r
8433 // Need to decide if we should use appendChild or insertBefore
\r
8434 var insertBefore = $.inArray( true, _pluck(cols, 'bVisible'), column+1 );
\r
8436 for ( i=0, ien=data.length ; i<ien ; i++ ) {
\r
8438 cells = data[i].anCells;
\r
8441 // insertBefore can act like appendChild if 2nd arg is null
\r
8442 tr.insertBefore( cells[ column ], cells[ insertBefore ] || null );
\r
8448 $( _pluck( settings.aoData, 'anCells', column ) ).detach();
\r
8452 col.bVisible = vis;
\r
8453 _fnDrawHead( settings, settings.aoHeader );
\r
8454 _fnDrawHead( settings, settings.aoFooter );
\r
8456 if ( recalc === undefined || recalc ) {
\r
8457 // Automatically adjust column sizing
\r
8458 _fnAdjustColumnSizing( settings );
\r
8461 _fnCallbackFire( settings, null, 'column-visibility', [settings, column, vis, recalc] );
\r
8463 _fnSaveState( settings );
\r
8467 _api_register( 'columns()', function ( selector, opts ) {
\r
8468 // argument shifting
\r
8469 if ( selector === undefined ) {
\r
8472 else if ( $.isPlainObject( selector ) ) {
\r
8477 opts = _selector_opts( opts );
\r
8479 var inst = this.iterator( 'table', function ( settings ) {
\r
8480 return __column_selector( settings, selector, opts );
\r
8483 // Want argument shifting here and in _row_selector?
\r
8484 inst.selector.cols = selector;
\r
8485 inst.selector.opts = opts;
\r
8490 _api_registerPlural( 'columns().header()', 'column().header()', function ( selector, opts ) {
\r
8491 return this.iterator( 'column', function ( settings, column ) {
\r
8492 return settings.aoColumns[column].nTh;
\r
8496 _api_registerPlural( 'columns().footer()', 'column().footer()', function ( selector, opts ) {
\r
8497 return this.iterator( 'column', function ( settings, column ) {
\r
8498 return settings.aoColumns[column].nTf;
\r
8502 _api_registerPlural( 'columns().data()', 'column().data()', function () {
\r
8503 return this.iterator( 'column-rows', __columnData, 1 );
\r
8506 _api_registerPlural( 'columns().dataSrc()', 'column().dataSrc()', function () {
\r
8507 return this.iterator( 'column', function ( settings, column ) {
\r
8508 return settings.aoColumns[column].mData;
\r
8512 _api_registerPlural( 'columns().cache()', 'column().cache()', function ( type ) {
\r
8513 return this.iterator( 'column-rows', function ( settings, column, i, j, rows ) {
\r
8514 return _pluck_order( settings.aoData, rows,
\r
8515 type === 'search' ? '_aFilterData' : '_aSortData', column
\r
8520 _api_registerPlural( 'columns().nodes()', 'column().nodes()', function () {
\r
8521 return this.iterator( 'column-rows', function ( settings, column, i, j, rows ) {
\r
8522 return _pluck_order( settings.aoData, rows, 'anCells', column ) ;
\r
8526 _api_registerPlural( 'columns().visible()', 'column().visible()', function ( vis, calc ) {
\r
8527 return this.iterator( 'column', function ( settings, column ) {
\r
8528 if ( vis === undefined ) {
\r
8529 return settings.aoColumns[ column ].bVisible;
\r
8531 __setColumnVis( settings, column, vis, calc );
\r
8535 _api_registerPlural( 'columns().indexes()', 'column().index()', function ( type ) {
\r
8536 return this.iterator( 'column', function ( settings, column ) {
\r
8537 return type === 'visible' ?
\r
8538 _fnColumnIndexToVisible( settings, column ) :
\r
8543 _api_register( 'columns.adjust()', function () {
\r
8544 return this.iterator( 'table', function ( settings ) {
\r
8545 _fnAdjustColumnSizing( settings );
\r
8549 _api_register( 'column.index()', function ( type, idx ) {
\r
8550 if ( this.context.length !== 0 ) {
\r
8551 var ctx = this.context[0];
\r
8553 if ( type === 'fromVisible' || type === 'toData' ) {
\r
8554 return _fnVisibleToColumnIndex( ctx, idx );
\r
8556 else if ( type === 'fromData' || type === 'toVisible' ) {
\r
8557 return _fnColumnIndexToVisible( ctx, idx );
\r
8562 _api_register( 'column()', function ( selector, opts ) {
\r
8563 return _selector_first( this.columns( selector, opts ) );
\r
8569 var __cell_selector = function ( settings, selector, opts )
\r
8571 var data = settings.aoData;
\r
8572 var rows = _selector_row_indexes( settings, opts );
\r
8573 var cells = _removeEmpty( _pluck_order( data, rows, 'anCells' ) );
\r
8574 var allCells = $( [].concat.apply([], cells) );
\r
8576 var columns = settings.aoColumns.length;
\r
8577 var a, i, ien, j, o, host;
\r
8579 var run = function ( s ) {
\r
8580 var fnSelector = typeof s === 'function';
\r
8582 if ( s === null || s === undefined || fnSelector ) {
\r
8583 // All cells and function selectors
\r
8586 for ( i=0, ien=rows.length ; i<ien ; i++ ) {
\r
8589 for ( j=0 ; j<columns ; j++ ) {
\r
8595 if ( fnSelector ) {
\r
8596 // Selector - function
\r
8597 host = data[ row ];
\r
8599 if ( s( o, _fnGetCellData(settings, row, j), host.anCells ? host.anCells[j] : null ) ) {
\r
8613 // Selector - index
\r
8614 if ( $.isPlainObject( s ) ) {
\r
8618 // Selector - jQuery filtered cells
\r
8619 var jqResult = allCells
\r
8621 .map( function (i, el) {
\r
8622 return { // use a new object, in case someone changes the values
\r
8623 row: el._DT_CellIndex.row,
\r
8624 column: el._DT_CellIndex.column
\r
8629 if ( jqResult.length || ! s.nodeName ) {
\r
8633 // Otherwise the selector is a node, and there is one last option - the
\r
8634 // element might be a child of an element which has dt-row and dt-column
\r
8635 // data attributes
\r
8636 host = $(s).closest('*[data-dt-row]');
\r
8637 return host.length ?
\r
8639 row: host.data('dt-row'),
\r
8640 column: host.data('dt-column')
\r
8645 return _selector_run( 'cell', selector, run, settings, opts );
\r
8651 _api_register( 'cells()', function ( rowSelector, columnSelector, opts ) {
\r
8652 // Argument shifting
\r
8653 if ( $.isPlainObject( rowSelector ) ) {
\r
8655 if ( rowSelector.row === undefined ) {
\r
8656 // Selector options in first parameter
\r
8657 opts = rowSelector;
\r
8658 rowSelector = null;
\r
8661 // Cell index objects in first parameter
\r
8662 opts = columnSelector;
\r
8663 columnSelector = null;
\r
8666 if ( $.isPlainObject( columnSelector ) ) {
\r
8667 opts = columnSelector;
\r
8668 columnSelector = null;
\r
8672 if ( columnSelector === null || columnSelector === undefined ) {
\r
8673 return this.iterator( 'table', function ( settings ) {
\r
8674 return __cell_selector( settings, rowSelector, _selector_opts( opts ) );
\r
8678 // Row + column selector
\r
8679 var columns = this.columns( columnSelector, opts );
\r
8680 var rows = this.rows( rowSelector, opts );
\r
8681 var a, i, ien, j, jen;
\r
8683 var cells = this.iterator( 'table', function ( settings, idx ) {
\r
8686 for ( i=0, ien=rows[idx].length ; i<ien ; i++ ) {
\r
8687 for ( j=0, jen=columns[idx].length ; j<jen ; j++ ) {
\r
8689 row: rows[idx][i],
\r
8690 column: columns[idx][j]
\r
8698 $.extend( cells.selector, {
\r
8699 cols: columnSelector,
\r
8700 rows: rowSelector,
\r
8708 _api_registerPlural( 'cells().nodes()', 'cell().node()', function () {
\r
8709 return this.iterator( 'cell', function ( settings, row, column ) {
\r
8710 var data = settings.aoData[ row ];
\r
8712 return data && data.anCells ?
\r
8713 data.anCells[ column ] :
\r
8719 _api_register( 'cells().data()', function () {
\r
8720 return this.iterator( 'cell', function ( settings, row, column ) {
\r
8721 return _fnGetCellData( settings, row, column );
\r
8726 _api_registerPlural( 'cells().cache()', 'cell().cache()', function ( type ) {
\r
8727 type = type === 'search' ? '_aFilterData' : '_aSortData';
\r
8729 return this.iterator( 'cell', function ( settings, row, column ) {
\r
8730 return settings.aoData[ row ][ type ][ column ];
\r
8735 _api_registerPlural( 'cells().render()', 'cell().render()', function ( type ) {
\r
8736 return this.iterator( 'cell', function ( settings, row, column ) {
\r
8737 return _fnGetCellData( settings, row, column, type );
\r
8742 _api_registerPlural( 'cells().indexes()', 'cell().index()', function () {
\r
8743 return this.iterator( 'cell', function ( settings, row, column ) {
\r
8747 columnVisible: _fnColumnIndexToVisible( settings, column )
\r
8753 _api_registerPlural( 'cells().invalidate()', 'cell().invalidate()', function ( src ) {
\r
8754 return this.iterator( 'cell', function ( settings, row, column ) {
\r
8755 _fnInvalidate( settings, row, src, column );
\r
8761 _api_register( 'cell()', function ( rowSelector, columnSelector, opts ) {
\r
8762 return _selector_first( this.cells( rowSelector, columnSelector, opts ) );
\r
8766 _api_register( 'cell().data()', function ( data ) {
\r
8767 var ctx = this.context;
\r
8768 var cell = this[0];
\r
8770 if ( data === undefined ) {
\r
8772 return ctx.length && cell.length ?
\r
8773 _fnGetCellData( ctx[0], cell[0].row, cell[0].column ) :
\r
8778 _fnSetCellData( ctx[0], cell[0].row, cell[0].column, data );
\r
8779 _fnInvalidate( ctx[0], cell[0].row, 'data', cell[0].column );
\r
8787 * Get current ordering (sorting) that has been applied to the table.
\r
8789 * @returns {array} 2D array containing the sorting information for the first
\r
8790 * table in the current context. Each element in the parent array represents
\r
8791 * a column being sorted upon (i.e. multi-sorting with two columns would have
\r
8792 * 2 inner arrays). The inner arrays may have 2 or 3 elements. The first is
\r
8793 * the column index that the sorting condition applies to, the second is the
\r
8794 * direction of the sort (`desc` or `asc`) and, optionally, the third is the
\r
8795 * index of the sorting order from the `column.sorting` initialisation array.
\r
8797 * Set the ordering for the table.
\r
8799 * @param {integer} order Column index to sort upon.
\r
8800 * @param {string} direction Direction of the sort to be applied (`asc` or `desc`)
\r
8801 * @returns {DataTables.Api} this
\r
8803 * Set the ordering for the table.
\r
8805 * @param {array} order 1D array of sorting information to be applied.
\r
8806 * @param {array} [...] Optional additional sorting conditions
\r
8807 * @returns {DataTables.Api} this
\r
8809 * Set the ordering for the table.
\r
8811 * @param {array} order 2D array of sorting information to be applied.
\r
8812 * @returns {DataTables.Api} this
\r
8814 _api_register( 'order()', function ( order, dir ) {
\r
8815 var ctx = this.context;
\r
8817 if ( order === undefined ) {
\r
8819 return ctx.length !== 0 ?
\r
8820 ctx[0].aaSorting :
\r
8825 if ( typeof order === 'number' ) {
\r
8826 // Simple column / direction passed in
\r
8827 order = [ [ order, dir ] ];
\r
8829 else if ( ! $.isArray( order[0] ) ) {
\r
8830 // Arguments passed in (list of 1D arrays)
\r
8831 order = Array.prototype.slice.call( arguments );
\r
8833 // otherwise a 2D array was passed in
\r
8835 return this.iterator( 'table', function ( settings ) {
\r
8836 settings.aaSorting = order.slice();
\r
8842 * Attach a sort listener to an element for a given column
\r
8844 * @param {node|jQuery|string} node Identifier for the element(s) to attach the
\r
8845 * listener to. This can take the form of a single DOM node, a jQuery
\r
8846 * collection of nodes or a jQuery selector which will identify the node(s).
\r
8847 * @param {integer} column the column that a click on this node will sort on
\r
8848 * @param {function} [callback] callback function when sort is run
\r
8849 * @returns {DataTables.Api} this
\r
8851 _api_register( 'order.listener()', function ( node, column, callback ) {
\r
8852 return this.iterator( 'table', function ( settings ) {
\r
8853 _fnSortAttachListener( settings, node, column, callback );
\r
8858 _api_register( 'order.fixed()', function ( set ) {
\r
8860 var ctx = this.context;
\r
8861 var fixed = ctx.length ?
\r
8862 ctx[0].aaSortingFixed :
\r
8865 return $.isArray( fixed ) ?
\r
8870 return this.iterator( 'table', function ( settings ) {
\r
8871 settings.aaSortingFixed = $.extend( true, {}, set );
\r
8876 // Order by the selected column(s)
\r
8878 'columns().order()',
\r
8879 'column().order()'
\r
8880 ], function ( dir ) {
\r
8883 return this.iterator( 'table', function ( settings, i ) {
\r
8886 $.each( that[i], function (j, col) {
\r
8887 sort.push( [ col, dir ] );
\r
8890 settings.aaSorting = sort;
\r
8896 _api_register( 'search()', function ( input, regex, smart, caseInsen ) {
\r
8897 var ctx = this.context;
\r
8899 if ( input === undefined ) {
\r
8901 return ctx.length !== 0 ?
\r
8902 ctx[0].oPreviousSearch.sSearch :
\r
8907 return this.iterator( 'table', function ( settings ) {
\r
8908 if ( ! settings.oFeatures.bFilter ) {
\r
8912 _fnFilterComplete( settings, $.extend( {}, settings.oPreviousSearch, {
\r
8913 "sSearch": input+"",
\r
8914 "bRegex": regex === null ? false : regex,
\r
8915 "bSmart": smart === null ? true : smart,
\r
8916 "bCaseInsensitive": caseInsen === null ? true : caseInsen
\r
8922 _api_registerPlural(
\r
8923 'columns().search()',
\r
8924 'column().search()',
\r
8925 function ( input, regex, smart, caseInsen ) {
\r
8926 return this.iterator( 'column', function ( settings, column ) {
\r
8927 var preSearch = settings.aoPreSearchCols;
\r
8929 if ( input === undefined ) {
\r
8931 return preSearch[ column ].sSearch;
\r
8935 if ( ! settings.oFeatures.bFilter ) {
\r
8939 $.extend( preSearch[ column ], {
\r
8940 "sSearch": input+"",
\r
8941 "bRegex": regex === null ? false : regex,
\r
8942 "bSmart": smart === null ? true : smart,
\r
8943 "bCaseInsensitive": caseInsen === null ? true : caseInsen
\r
8946 _fnFilterComplete( settings, settings.oPreviousSearch, 1 );
\r
8952 * State API methods
\r
8955 _api_register( 'state()', function () {
\r
8956 return this.context.length ?
\r
8957 this.context[0].oSavedState :
\r
8962 _api_register( 'state.clear()', function () {
\r
8963 return this.iterator( 'table', function ( settings ) {
\r
8964 // Save an empty object
\r
8965 settings.fnStateSaveCallback.call( settings.oInstance, settings, {} );
\r
8970 _api_register( 'state.loaded()', function () {
\r
8971 return this.context.length ?
\r
8972 this.context[0].oLoadedState :
\r
8977 _api_register( 'state.save()', function () {
\r
8978 return this.iterator( 'table', function ( settings ) {
\r
8979 _fnSaveState( settings );
\r
8986 * Provide a common method for plug-ins to check the version of DataTables being
\r
8987 * used, in order to ensure compatibility.
\r
8989 * @param {string} version Version string to check for, in the format "X.Y.Z".
\r
8990 * Note that the formats "X" and "X.Y" are also acceptable.
\r
8991 * @returns {boolean} true if this version of DataTables is greater or equal to
\r
8992 * the required version, or false if this version of DataTales is not
\r
8995 * @dtopt API-Static
\r
8998 * alert( $.fn.dataTable.versionCheck( '1.9.0' ) );
\r
9000 DataTable.versionCheck = DataTable.fnVersionCheck = function( version )
\r
9002 var aThis = DataTable.version.split('.');
\r
9003 var aThat = version.split('.');
\r
9006 for ( var i=0, iLen=aThat.length ; i<iLen ; i++ ) {
\r
9007 iThis = parseInt( aThis[i], 10 ) || 0;
\r
9008 iThat = parseInt( aThat[i], 10 ) || 0;
\r
9010 // Parts are the same, keep comparing
\r
9011 if (iThis === iThat) {
\r
9015 // Parts are different, return immediately
\r
9016 return iThis > iThat;
\r
9024 * Check if a `<table>` node is a DataTable table already or not.
\r
9026 * @param {node|jquery|string} table Table node, jQuery object or jQuery
\r
9027 * selector for the table to test. Note that if more than more than one
\r
9028 * table is passed on, only the first will be checked
\r
9029 * @returns {boolean} true the table given is a DataTable, or false otherwise
\r
9031 * @dtopt API-Static
\r
9034 * if ( ! $.fn.DataTable.isDataTable( '#example' ) ) {
\r
9035 * $('#example').dataTable();
\r
9038 DataTable.isDataTable = DataTable.fnIsDataTable = function ( table )
\r
9040 var t = $(table).get(0);
\r
9043 $.each( DataTable.settings, function (i, o) {
\r
9044 var head = o.nScrollHead ? $('table', o.nScrollHead)[0] : null;
\r
9045 var foot = o.nScrollFoot ? $('table', o.nScrollFoot)[0] : null;
\r
9047 if ( o.nTable === t || head === t || foot === t ) {
\r
9057 * Get all DataTable tables that have been initialised - optionally you can
\r
9058 * select to get only currently visible tables.
\r
9060 * @param {boolean} [visible=false] Flag to indicate if you want all (default)
\r
9061 * or visible tables only.
\r
9062 * @returns {array} Array of `table` nodes (not DataTable instances) which are
\r
9065 * @dtopt API-Static
\r
9068 * $.each( $.fn.dataTable.tables(true), function () {
\r
9069 * $(table).DataTable().columns.adjust();
\r
9072 DataTable.tables = DataTable.fnTables = function ( visible )
\r
9076 if ( $.isPlainObject( visible ) ) {
\r
9077 api = visible.api;
\r
9078 visible = visible.visible;
\r
9081 var a = $.map( DataTable.settings, function (o) {
\r
9082 if ( !visible || (visible && $(o.nTable).is(':visible')) ) {
\r
9094 * DataTables utility methods
\r
9096 * This namespace provides helper methods that DataTables uses internally to
\r
9097 * create a DataTable, but which are not exclusively used only for DataTables.
\r
9098 * These methods can be used by extension authors to save the duplication of
\r
9103 DataTable.util = {
\r
9105 * Throttle the calls to a function. Arguments and context are maintained
\r
9106 * for the throttled function.
\r
9108 * @param {function} fn Function to be called
\r
9109 * @param {integer} freq Call frequency in mS
\r
9110 * @return {function} Wrapped function
\r
9112 throttle: _fnThrottle,
\r
9116 * Escape a string such that it can be used in a regular expression
\r
9118 * @param {string} sVal string to escape
\r
9119 * @returns {string} escaped string
\r
9121 escapeRegex: _fnEscapeRegex
\r
9126 * Convert from camel case parameters to Hungarian notation. This is made public
\r
9127 * for the extensions to provide the same ability as DataTables core to accept
\r
9128 * either the 1.9 style Hungarian notation, or the 1.10+ style camelCase
\r
9131 * @param {object} src The model object which holds all parameters that can be
\r
9133 * @param {object} user The object to convert from camel case to Hungarian.
\r
9134 * @param {boolean} force When set to `true`, properties which already have a
\r
9135 * Hungarian value in the `user` object will be overwritten. Otherwise they
\r
9138 DataTable.camelToHungarian = _fnCamelToHungarian;
\r
9145 _api_register( '$()', function ( selector, opts ) {
\r
9147 rows = this.rows( opts ).nodes(), // Get all rows
\r
9150 return $( [].concat(
\r
9151 jqRows.filter( selector ).toArray(),
\r
9152 jqRows.find( selector ).toArray()
\r
9157 // jQuery functions to operate on the tables
\r
9158 $.each( [ 'on', 'one', 'off' ], function (i, key) {
\r
9159 _api_register( key+'()', function ( /* event, handler */ ) {
\r
9160 var args = Array.prototype.slice.call(arguments);
\r
9162 // Add the `dt` namespace automatically if it isn't already present
\r
9163 if ( ! args[0].match(/\.dt\b/) ) {
\r
9167 var inst = $( this.tables().nodes() );
\r
9168 inst[key].apply( inst, args );
\r
9174 _api_register( 'clear()', function () {
\r
9175 return this.iterator( 'table', function ( settings ) {
\r
9176 _fnClearTable( settings );
\r
9181 _api_register( 'settings()', function () {
\r
9182 return new _Api( this.context, this.context );
\r
9186 _api_register( 'init()', function () {
\r
9187 var ctx = this.context;
\r
9188 return ctx.length ? ctx[0].oInit : null;
\r
9192 _api_register( 'data()', function () {
\r
9193 return this.iterator( 'table', function ( settings ) {
\r
9194 return _pluck( settings.aoData, '_aData' );
\r
9199 _api_register( 'destroy()', function ( remove ) {
\r
9200 remove = remove || false;
\r
9202 return this.iterator( 'table', function ( settings ) {
\r
9203 var orig = settings.nTableWrapper.parentNode;
\r
9204 var classes = settings.oClasses;
\r
9205 var table = settings.nTable;
\r
9206 var tbody = settings.nTBody;
\r
9207 var thead = settings.nTHead;
\r
9208 var tfoot = settings.nTFoot;
\r
9209 var jqTable = $(table);
\r
9210 var jqTbody = $(tbody);
\r
9211 var jqWrapper = $(settings.nTableWrapper);
\r
9212 var rows = $.map( settings.aoData, function (r) { return r.nTr; } );
\r
9215 // Flag to note that the table is currently being destroyed - no action
\r
9216 // should be taken
\r
9217 settings.bDestroying = true;
\r
9219 // Fire off the destroy callbacks for plug-ins etc
\r
9220 _fnCallbackFire( settings, "aoDestroyCallback", "destroy", [settings] );
\r
9222 // If not being removed from the document, make all columns visible
\r
9224 new _Api( settings ).columns().visible( true );
\r
9227 // Blitz all `DT` namespaced events (these are internal events, the
\r
9228 // lowercase, `dt` events are user subscribed and they are responsible
\r
9229 // for removing them
\r
9230 jqWrapper.unbind('.DT').find(':not(tbody *)').unbind('.DT');
\r
9231 $(window).unbind('.DT-'+settings.sInstance);
\r
9233 // When scrolling we had to break the table up - restore it
\r
9234 if ( table != thead.parentNode ) {
\r
9235 jqTable.children('thead').detach();
\r
9236 jqTable.append( thead );
\r
9239 if ( tfoot && table != tfoot.parentNode ) {
\r
9240 jqTable.children('tfoot').detach();
\r
9241 jqTable.append( tfoot );
\r
9244 settings.aaSorting = [];
\r
9245 settings.aaSortingFixed = [];
\r
9246 _fnSortingClasses( settings );
\r
9248 $( rows ).removeClass( settings.asStripeClasses.join(' ') );
\r
9250 $('th, td', thead).removeClass( classes.sSortable+' '+
\r
9251 classes.sSortableAsc+' '+classes.sSortableDesc+' '+classes.sSortableNone
\r
9254 if ( settings.bJUI ) {
\r
9255 $('th span.'+classes.sSortIcon+ ', td span.'+classes.sSortIcon, thead).detach();
\r
9256 $('th, td', thead).each( function () {
\r
9257 var wrapper = $('div.'+classes.sSortJUIWrapper, this);
\r
9258 $(this).append( wrapper.contents() );
\r
9263 // Add the TR elements back into the table in their original order
\r
9264 jqTbody.children().detach();
\r
9265 jqTbody.append( rows );
\r
9267 // Remove the DataTables generated nodes, events and classes
\r
9268 var removedMethod = remove ? 'remove' : 'detach';
\r
9269 jqTable[ removedMethod ]();
\r
9270 jqWrapper[ removedMethod ]();
\r
9272 // If we need to reattach the table to the document
\r
9273 if ( ! remove && orig ) {
\r
9274 // insertBefore acts like appendChild if !arg[1]
\r
9275 orig.insertBefore( table, settings.nTableReinsertBefore );
\r
9277 // Restore the width of the original table - was read from the style property,
\r
9278 // so we can restore directly to that
\r
9280 .css( 'width', settings.sDestroyWidth )
\r
9281 .removeClass( classes.sTable );
\r
9283 // If the were originally stripe classes - then we add them back here.
\r
9284 // Note this is not fool proof (for example if not all rows had stripe
\r
9285 // classes - but it's a good effort without getting carried away
\r
9286 ien = settings.asDestroyStripes.length;
\r
9289 jqTbody.children().each( function (i) {
\r
9290 $(this).addClass( settings.asDestroyStripes[i % ien] );
\r
9295 /* Remove the settings object from the settings array */
\r
9296 var idx = $.inArray( settings, DataTable.settings );
\r
9297 if ( idx !== -1 ) {
\r
9298 DataTable.settings.splice( idx, 1 );
\r
9304 // Add the `every()` method for rows, columns and cells in a compact form
\r
9305 $.each( [ 'column', 'row', 'cell' ], function ( i, type ) {
\r
9306 _api_register( type+'s().every()', function ( fn ) {
\r
9307 var opts = this.selector.opts;
\r
9310 return this.iterator( type, function ( settings, arg1, arg2, arg3, arg4 ) {
\r
9311 // Rows and columns:
\r
9313 // arg2 - table counter
\r
9314 // arg3 - loop counter
\r
9315 // arg4 - undefined
\r
9317 // arg1 - row index
\r
9318 // arg2 - column index
\r
9319 // arg3 - table counter
\r
9320 // arg4 - loop counter
\r
9324 type==='cell' ? arg2 : opts,
\r
9325 type==='cell' ? opts : undefined
\r
9327 arg1, arg2, arg3, arg4
\r
9334 // i18n method for extensions to be able to use the language object from the
\r
9336 _api_register( 'i18n()', function ( token, def, plural ) {
\r
9337 var ctx = this.context[0];
\r
9338 var resolved = _fnGetObjectDataFn( token )( ctx.oLanguage );
\r
9340 if ( resolved === undefined ) {
\r
9344 if ( plural !== undefined && $.isPlainObject( resolved ) ) {
\r
9345 resolved = resolved[ plural ] !== undefined ?
\r
9346 resolved[ plural ] :
\r
9350 return resolved.replace( '%d', plural ); // nb: plural might be undefined,
\r
9354 * Version string for plug-ins to check compatibility. Allowed format is
\r
9355 * `a.b.c-d` where: a:int, b:int, c:int, d:string(dev|beta|alpha). `d` is used
\r
9356 * only for non-release builds. See http://semver.org/ for more information.
\r
9359 * @default Version number
\r
9361 DataTable.version = "1.10.11";
\r
9364 * Private data store, containing all of the settings objects that are
\r
9365 * created for the tables on a given page.
\r
9367 * Note that the `DataTable.settings` object is aliased to
\r
9368 * `jQuery.fn.dataTableExt` through which it may be accessed and
\r
9369 * manipulated, or `jQuery.fn.dataTable.settings`.
\r
9375 DataTable.settings = [];
\r
9378 * Object models container, for the various models that DataTables has
\r
9379 * available to it. These models define the objects that are used to hold
\r
9380 * the active state and configuration of the table.
\r
9383 DataTable.models = {};
\r
9388 * Template object for the way in which DataTables holds information about
\r
9389 * search information for the global filter and individual column filters.
\r
9392 DataTable.models.oSearch = {
\r
9394 * Flag to indicate if the filtering should be case insensitive or not
\r
9398 "bCaseInsensitive": true,
\r
9401 * Applied search term
\r
9403 * @default <i>Empty string</i>
\r
9408 * Flag to indicate if the search term should be interpreted as a
\r
9409 * regular expression (true) or not (false) and therefore and special
\r
9410 * regex characters escaped.
\r
9417 * Flag to indicate if DataTables is to use its smart filtering or not.
\r
9428 * Template object for the way in which DataTables holds information about
\r
9429 * each individual row. This is the object format used for the settings
\r
9433 DataTable.models.oRow = {
\r
9435 * TR element for the row
\r
9442 * Array of TD elements for each row. This is null until the row has been
\r
9444 * @type array nodes
\r
9450 * Data object from the original data source for the row. This is either
\r
9451 * an array if using the traditional form of DataTables, or an object if
\r
9452 * using mData options. The exact type will depend on the passed in
\r
9453 * data from the data source, or will be an array if using DOM a data
\r
9455 * @type array|object
\r
9461 * Sorting data cache - this array is ostensibly the same length as the
\r
9462 * number of columns (although each index is generated only as it is
\r
9463 * needed), and holds the data that is used for sorting each column in the
\r
9464 * row. We do this cache generation at the start of the sort in order that
\r
9465 * the formatting of the sort data need be done only once for each cell
\r
9466 * per sort. This array should not be read from or written to by anything
\r
9467 * other than the master sorting methods.
\r
9472 "_aSortData": null,
\r
9475 * Per cell filtering data cache. As per the sort data cache, used to
\r
9476 * increase the performance of the filtering in DataTables
\r
9481 "_aFilterData": null,
\r
9484 * Filtering data cache. This is the same as the cell filtering cache, but
\r
9485 * in this case a string rather than an array. This is easily computed with
\r
9486 * a join on `_aFilterData`, but is provided as a cache so the join isn't
\r
9487 * needed on every search (memory traded for performance)
\r
9492 "_sFilterRow": null,
\r
9495 * Cache of the class name that DataTables has applied to the row, so we
\r
9496 * can quickly look at this variable rather than needing to do a DOM check
\r
9497 * on className for the nTr property.
\r
9499 * @default <i>Empty string</i>
\r
9502 "_sRowStripe": "",
\r
9505 * Denote if the original data source was from the DOM, or the data source
\r
9506 * object. This is used for invalidating data, so DataTables can
\r
9507 * automatically read data from the original source, unless uninstructed
\r
9516 * Index in the aoData array. This saves an indexOf lookup when we have the
\r
9517 * object, but want to know the index
\r
9527 * Template object for the column information object in DataTables. This object
\r
9528 * is held in the settings aoColumns array and contains all the information that
\r
9529 * DataTables needs about each individual column.
\r
9531 * Note that this object is related to {@link DataTable.defaults.column}
\r
9532 * but this one is the internal data store for DataTables's cache of columns.
\r
9533 * It should NOT be manipulated outside of DataTables. Any configuration should
\r
9534 * be done through the initialisation options.
\r
9537 DataTable.models.oColumn = {
\r
9539 * Column index. This could be worked out on-the-fly with $.inArray, but it
\r
9540 * is faster to just hold it as a variable
\r
9547 * A list of the columns that sorting should occur on when this column
\r
9548 * is sorted. That this property is an array allows multi-column sorting
\r
9549 * to be defined for a column (for example first name / last name columns
\r
9550 * would benefit from this). The values are integers pointing to the
\r
9551 * columns to be sorted on (typically it will be a single integer pointing
\r
9552 * at itself, but that doesn't need to be the case).
\r
9555 "aDataSort": null,
\r
9558 * Define the sorting directions that are applied to the column, in sequence
\r
9559 * as the column is repeatedly sorted upon - i.e. the first value is used
\r
9560 * as the sorting direction when the column if first sorted (clicked on).
\r
9561 * Sort it again (click again) and it will move on to the next index.
\r
9562 * Repeat until loop.
\r
9565 "asSorting": null,
\r
9568 * Flag to indicate if the column is searchable, and thus should be included
\r
9569 * in the filtering or not.
\r
9572 "bSearchable": null,
\r
9575 * Flag to indicate if the column is sortable or not.
\r
9578 "bSortable": null,
\r
9581 * Flag to indicate if the column is currently visible in the table or not
\r
9587 * Store for manual type assignment using the `column.type` option. This
\r
9588 * is held in store so we can manipulate the column's `sType` property.
\r
9593 "_sManualType": null,
\r
9596 * Flag to indicate if HTML5 data attributes should be used as the data
\r
9597 * source for filtering or sorting. True is either are.
\r
9602 "_bAttrSrc": false,
\r
9605 * Developer definable function that is called whenever a cell is created (Ajax source,
\r
9606 * etc) or processed for input (DOM source). This can be used as a compliment to mRender
\r
9607 * allowing you to modify the DOM element (add background colour for example) when the
\r
9608 * element is available.
\r
9610 * @param {element} nTd The TD node that has been created
\r
9611 * @param {*} sData The Data for the cell
\r
9612 * @param {array|object} oData The data for the whole row
\r
9613 * @param {int} iRow The row index for the aoData data store
\r
9616 "fnCreatedCell": null,
\r
9619 * Function to get data from a cell in a column. You should <b>never</b>
\r
9620 * access data directly through _aData internally in DataTables - always use
\r
9621 * the method attached to this property. It allows mData to function as
\r
9622 * required. This function is automatically assigned by the column
\r
9623 * initialisation method
\r
9625 * @param {array|object} oData The data array/object for the array
\r
9626 * (i.e. aoData[]._aData)
\r
9627 * @param {string} sSpecific The specific data type you want to get -
\r
9628 * 'display', 'type' 'filter' 'sort'
\r
9629 * @returns {*} The data for the cell from the given row's data
\r
9632 "fnGetData": null,
\r
9635 * Function to set data for a cell in the column. You should <b>never</b>
\r
9636 * set the data directly to _aData internally in DataTables - always use
\r
9637 * this method. It allows mData to function as required. This function
\r
9638 * is automatically assigned by the column initialisation method
\r
9640 * @param {array|object} oData The data array/object for the array
\r
9641 * (i.e. aoData[]._aData)
\r
9642 * @param {*} sValue Value to set
\r
9645 "fnSetData": null,
\r
9648 * Property to read the value for the cells in the column from the data
\r
9649 * source array / object. If null, then the default content is used, if a
\r
9650 * function is given then the return from the function is used.
\r
9651 * @type function|int|string|null
\r
9657 * Partner property to mData which is used (only when defined) to get
\r
9658 * the data - i.e. it is basically the same as mData, but without the
\r
9659 * 'set' option, and also the data fed to it is the result from mData.
\r
9660 * This is the rendering method to match the data method of mData.
\r
9661 * @type function|int|string|null
\r
9667 * Unique header TH/TD element for this column - this is what the sorting
\r
9668 * listener is attached to (if sorting is enabled.)
\r
9675 * Unique footer TH/TD element for this column (if there is one). Not used
\r
9676 * in DataTables as such, but can be used for plug-ins to reference the
\r
9677 * footer for each column.
\r
9684 * The class to apply to all TD elements in the table's TBODY for the column
\r
9691 * When DataTables calculates the column widths to assign to each column,
\r
9692 * it finds the longest string in each column and then constructs a
\r
9693 * temporary table and reads the widths from that. The problem with this
\r
9694 * is that "mmm" is much wider then "iiii", but the latter is a longer
\r
9695 * string - thus the calculation can go wrong (doing it properly and putting
\r
9696 * it into an DOM object and measuring that is horribly(!) slow). Thus as
\r
9697 * a "work around" we provide this option. It will append its value to the
\r
9698 * text that is found to be the longest string for the column - i.e. padding.
\r
9701 "sContentPadding": null,
\r
9704 * Allows a default value to be given for a column's data, and will be used
\r
9705 * whenever a null data source is encountered (this can be because mData
\r
9706 * is set to null, or because the data source itself is null).
\r
9710 "sDefaultContent": null,
\r
9713 * Name for the column, allowing reference to the column by name as well as
\r
9714 * by index (needs a lookup to work by name).
\r
9720 * Custom sorting data type - defines which of the available plug-ins in
\r
9721 * afnSortData the custom sorting will use - if any is defined.
\r
9725 "sSortDataType": 'std',
\r
9728 * Class to be applied to the header element when sorting on this column
\r
9732 "sSortingClass": null,
\r
9735 * Class to be applied to the header element when sorting on this column -
\r
9736 * when jQuery UI theming is used.
\r
9740 "sSortingClassJUI": null,
\r
9743 * Title of the column - what is seen in the TH element (nTh).
\r
9749 * Column sorting and filtering type
\r
9756 * Width of the column
\r
9763 * Width of the column when it was first "encountered"
\r
9767 "sWidthOrig": null
\r
9772 * Developer note: The properties of the object below are given in Hungarian
\r
9773 * notation, that was used as the interface for DataTables prior to v1.10, however
\r
9774 * from v1.10 onwards the primary interface is camel case. In order to avoid
\r
9775 * breaking backwards compatibility utterly with this change, the Hungarian
\r
9776 * version is still, internally the primary interface, but is is not documented
\r
9777 * - hence the @name tags in each doc comment. This allows a Javascript function
\r
9778 * to create a map from Hungarian notation to camel case (going the other direction
\r
9779 * would require each property to be listed, which would at around 3K to the size
\r
9780 * of DataTables, while this method is about a 0.5K hit.
\r
9782 * Ultimately this does pave the way for Hungarian notation to be dropped
\r
9783 * completely, but that is a massive amount of work and will break current
\r
9784 * installs (therefore is on-hold until v2).
\r
9788 * Initialisation options that can be given to DataTables at initialisation
\r
9792 DataTable.defaults = {
\r
9794 * An array of data to use for the table, passed in at initialisation which
\r
9795 * will be used in preference to any data which is already in the DOM. This is
\r
9796 * particularly useful for constructing tables purely in Javascript, for
\r
9797 * example with a custom Ajax call.
\r
9802 * @name DataTable.defaults.data
\r
9805 * // Using a 2D array data source
\r
9806 * $(document).ready( function () {
\r
9807 * $('#example').dataTable( {
\r
9809 * ['Trident', 'Internet Explorer 4.0', 'Win 95+', 4, 'X'],
\r
9810 * ['Trident', 'Internet Explorer 5.0', 'Win 95+', 5, 'C'],
\r
9813 * { "title": "Engine" },
\r
9814 * { "title": "Browser" },
\r
9815 * { "title": "Platform" },
\r
9816 * { "title": "Version" },
\r
9817 * { "title": "Grade" }
\r
9823 * // Using an array of objects as a data source (`data`)
\r
9824 * $(document).ready( function () {
\r
9825 * $('#example').dataTable( {
\r
9828 * "engine": "Trident",
\r
9829 * "browser": "Internet Explorer 4.0",
\r
9830 * "platform": "Win 95+",
\r
9835 * "engine": "Trident",
\r
9836 * "browser": "Internet Explorer 5.0",
\r
9837 * "platform": "Win 95+",
\r
9843 * { "title": "Engine", "data": "engine" },
\r
9844 * { "title": "Browser", "data": "browser" },
\r
9845 * { "title": "Platform", "data": "platform" },
\r
9846 * { "title": "Version", "data": "version" },
\r
9847 * { "title": "Grade", "data": "grade" }
\r
9856 * If ordering is enabled, then DataTables will perform a first pass sort on
\r
9857 * initialisation. You can define which column(s) the sort is performed
\r
9858 * upon, and the sorting direction, with this variable. The `sorting` array
\r
9859 * should contain an array for each column to be sorted initially containing
\r
9860 * the column's index and a direction string ('asc' or 'desc').
\r
9862 * @default [[0,'asc']]
\r
9865 * @name DataTable.defaults.order
\r
9868 * // Sort by 3rd column first, and then 4th column
\r
9869 * $(document).ready( function() {
\r
9870 * $('#example').dataTable( {
\r
9871 * "order": [[2,'asc'], [3,'desc']]
\r
9875 * // No initial sorting
\r
9876 * $(document).ready( function() {
\r
9877 * $('#example').dataTable( {
\r
9882 "aaSorting": [[0,'asc']],
\r
9886 * This parameter is basically identical to the `sorting` parameter, but
\r
9887 * cannot be overridden by user interaction with the table. What this means
\r
9888 * is that you could have a column (visible or hidden) which the sorting
\r
9889 * will always be forced on first - any sorting after that (from the user)
\r
9890 * will then be performed as required. This can be useful for grouping rows
\r
9896 * @name DataTable.defaults.orderFixed
\r
9899 * $(document).ready( function() {
\r
9900 * $('#example').dataTable( {
\r
9901 * "orderFixed": [[0,'asc']]
\r
9905 "aaSortingFixed": [],
\r
9909 * DataTables can be instructed to load data to display in the table from a
\r
9910 * Ajax source. This option defines how that Ajax call is made and where to.
\r
9912 * The `ajax` property has three different modes of operation, depending on
\r
9913 * how it is defined. These are:
\r
9915 * * `string` - Set the URL from where the data should be loaded from.
\r
9916 * * `object` - Define properties for `jQuery.ajax`.
\r
9917 * * `function` - Custom data get function
\r
9922 * As a string, the `ajax` property simply defines the URL from which
\r
9923 * DataTables will load data.
\r
9928 * As an object, the parameters in the object are passed to
\r
9929 * [jQuery.ajax](http://api.jquery.com/jQuery.ajax/) allowing fine control
\r
9930 * of the Ajax request. DataTables has a number of default parameters which
\r
9931 * you can override using this option. Please refer to the jQuery
\r
9932 * documentation for a full description of the options available, although
\r
9933 * the following parameters provide additional options in DataTables or
\r
9934 * require special consideration:
\r
9936 * * `data` - As with jQuery, `data` can be provided as an object, but it
\r
9937 * can also be used as a function to manipulate the data DataTables sends
\r
9938 * to the server. The function takes a single parameter, an object of
\r
9939 * parameters with the values that DataTables has readied for sending. An
\r
9940 * object may be returned which will be merged into the DataTables
\r
9941 * defaults, or you can add the items to the object that was passed in and
\r
9942 * not return anything from the function. This supersedes `fnServerParams`
\r
9943 * from DataTables 1.9-.
\r
9945 * * `dataSrc` - By default DataTables will look for the property `data` (or
\r
9946 * `aaData` for compatibility with DataTables 1.9-) when obtaining data
\r
9947 * from an Ajax source or for server-side processing - this parameter
\r
9948 * allows that property to be changed. You can use Javascript dotted
\r
9949 * object notation to get a data source for multiple levels of nesting, or
\r
9950 * it my be used as a function. As a function it takes a single parameter,
\r
9951 * the JSON returned from the server, which can be manipulated as
\r
9952 * required, with the returned value being that used by DataTables as the
\r
9953 * data source for the table. This supersedes `sAjaxDataProp` from
\r
9954 * DataTables 1.9-.
\r
9956 * * `success` - Should not be overridden it is used internally in
\r
9957 * DataTables. To manipulate / transform the data returned by the server
\r
9958 * use `ajax.dataSrc`, or use `ajax` as a function (see below).
\r
9963 * As a function, making the Ajax call is left up to yourself allowing
\r
9964 * complete control of the Ajax request. Indeed, if desired, a method other
\r
9965 * than Ajax could be used to obtain the required data, such as Web storage
\r
9966 * or an AIR database.
\r
9968 * The function is given four parameters and no return is required. The
\r
9971 * 1. _object_ - Data to send to the server
\r
9972 * 2. _function_ - Callback function that must be executed when the required
\r
9973 * data has been obtained. That data should be passed into the callback
\r
9974 * as the only parameter
\r
9975 * 3. _object_ - DataTables settings object for the table
\r
9977 * Note that this supersedes `fnServerData` from DataTables 1.9-.
\r
9979 * @type string|object|function
\r
9983 * @name DataTable.defaults.ajax
\r
9987 * // Get JSON data from a file via Ajax.
\r
9988 * // Note DataTables expects data in the form `{ data: [ ...data... ] }` by default).
\r
9989 * $('#example').dataTable( {
\r
9990 * "ajax": "data.json"
\r
9994 * // Get JSON data from a file via Ajax, using `dataSrc` to change
\r
9995 * // `data` to `tableData` (i.e. `{ tableData: [ ...data... ] }`)
\r
9996 * $('#example').dataTable( {
\r
9998 * "url": "data.json",
\r
9999 * "dataSrc": "tableData"
\r
10004 * // Get JSON data from a file via Ajax, using `dataSrc` to read data
\r
10005 * // from a plain array rather than an array in an object
\r
10006 * $('#example').dataTable( {
\r
10008 * "url": "data.json",
\r
10014 * // Manipulate the data returned from the server - add a link to data
\r
10015 * // (note this can, should, be done using `render` for the column - this
\r
10016 * // is just a simple example of how the data can be manipulated).
\r
10017 * $('#example').dataTable( {
\r
10019 * "url": "data.json",
\r
10020 * "dataSrc": function ( json ) {
\r
10021 * for ( var i=0, ien=json.length ; i<ien ; i++ ) {
\r
10022 * json[i][0] = '<a href="/message/'+json[i][0]+'>View message</a>';
\r
10030 * // Add data to the request
\r
10031 * $('#example').dataTable( {
\r
10033 * "url": "data.json",
\r
10034 * "data": function ( d ) {
\r
10036 * "extra_search": $('#extra').val()
\r
10043 * // Send request as POST
\r
10044 * $('#example').dataTable( {
\r
10046 * "url": "data.json",
\r
10052 * // Get the data from localStorage (could interface with a form for
\r
10053 * // adding, editing and removing rows).
\r
10054 * $('#example').dataTable( {
\r
10055 * "ajax": function (data, callback, settings) {
\r
10057 * JSON.parse( localStorage.getItem('dataTablesData') )
\r
10066 * This parameter allows you to readily specify the entries in the length drop
\r
10067 * down menu that DataTables shows when pagination is enabled. It can be
\r
10068 * either a 1D array of options which will be used for both the displayed
\r
10069 * option and the value, or a 2D array which will use the array in the first
\r
10070 * position as the value, and the array in the second position as the
\r
10071 * displayed options (useful for language strings such as 'All').
\r
10073 * Note that the `pageLength` property will be automatically set to the
\r
10074 * first value given in this array, unless `pageLength` is also provided.
\r
10076 * @default [ 10, 25, 50, 100 ]
\r
10079 * @name DataTable.defaults.lengthMenu
\r
10082 * $(document).ready( function() {
\r
10083 * $('#example').dataTable( {
\r
10084 * "lengthMenu": [[10, 25, 50, -1], [10, 25, 50, "All"]]
\r
10088 "aLengthMenu": [ 10, 25, 50, 100 ],
\r
10092 * The `columns` option in the initialisation parameter allows you to define
\r
10093 * details about the way individual columns behave. For a full list of
\r
10094 * column options that can be set, please see
\r
10095 * {@link DataTable.defaults.column}. Note that if you use `columns` to
\r
10096 * define your columns, you must have an entry in the array for every single
\r
10097 * column that you have in your table (these can be null if you don't which
\r
10098 * to specify any options).
\r
10101 * @name DataTable.defaults.column
\r
10103 "aoColumns": null,
\r
10106 * Very similar to `columns`, `columnDefs` allows you to target a specific
\r
10107 * column, multiple columns, or all columns, using the `targets` property of
\r
10108 * each object in the array. This allows great flexibility when creating
\r
10109 * tables, as the `columnDefs` arrays can be of any length, targeting the
\r
10110 * columns you specifically want. `columnDefs` may use any of the column
\r
10111 * options available: {@link DataTable.defaults.column}, but it _must_
\r
10112 * have `targets` defined in each object in the array. Values in the `targets`
\r
10115 * <li>a string - class name will be matched on the TH for the column</li>
\r
10116 * <li>0 or a positive integer - column index counting from the left</li>
\r
10117 * <li>a negative integer - column index counting from the right</li>
\r
10118 * <li>the string "_all" - all columns (i.e. assign a default)</li>
\r
10122 * @name DataTable.defaults.columnDefs
\r
10124 "aoColumnDefs": null,
\r
10128 * Basically the same as `search`, this parameter defines the individual column
\r
10129 * filtering state at initialisation time. The array must be of the same size
\r
10130 * as the number of columns, and each element be an object with the parameters
\r
10131 * `search` and `escapeRegex` (the latter is optional). 'null' is also
\r
10132 * accepted and the default will be used.
\r
10137 * @name DataTable.defaults.searchCols
\r
10140 * $(document).ready( function() {
\r
10141 * $('#example').dataTable( {
\r
10142 * "searchCols": [
\r
10144 * { "search": "My filter" },
\r
10146 * { "search": "^[0-9]", "escapeRegex": false }
\r
10151 "aoSearchCols": [],
\r
10155 * An array of CSS classes that should be applied to displayed rows. This
\r
10156 * array may be of any length, and DataTables will apply each class
\r
10157 * sequentially, looping when required.
\r
10159 * @default null <i>Will take the values determined by the `oClasses.stripe*`
\r
10163 * @name DataTable.defaults.stripeClasses
\r
10166 * $(document).ready( function() {
\r
10167 * $('#example').dataTable( {
\r
10168 * "stripeClasses": [ 'strip1', 'strip2', 'strip3' ]
\r
10172 "asStripeClasses": null,
\r
10176 * Enable or disable automatic column width calculation. This can be disabled
\r
10177 * as an optimisation (it takes some time to calculate the widths) if the
\r
10178 * tables widths are passed in using `columns`.
\r
10182 * @dtopt Features
\r
10183 * @name DataTable.defaults.autoWidth
\r
10186 * $(document).ready( function () {
\r
10187 * $('#example').dataTable( {
\r
10188 * "autoWidth": false
\r
10192 "bAutoWidth": true,
\r
10196 * Deferred rendering can provide DataTables with a huge speed boost when you
\r
10197 * are using an Ajax or JS data source for the table. This option, when set to
\r
10198 * true, will cause DataTables to defer the creation of the table elements for
\r
10199 * each row until they are needed for a draw - saving a significant amount of
\r
10204 * @dtopt Features
\r
10205 * @name DataTable.defaults.deferRender
\r
10208 * $(document).ready( function() {
\r
10209 * $('#example').dataTable( {
\r
10210 * "ajax": "sources/arrays.txt",
\r
10211 * "deferRender": true
\r
10215 "bDeferRender": false,
\r
10219 * Replace a DataTable which matches the given selector and replace it with
\r
10220 * one which has the properties of the new initialisation object passed. If no
\r
10221 * table matches the selector, then the new DataTable will be constructed as
\r
10227 * @name DataTable.defaults.destroy
\r
10230 * $(document).ready( function() {
\r
10231 * $('#example').dataTable( {
\r
10232 * "srollY": "200px",
\r
10233 * "paginate": false
\r
10236 * // Some time later....
\r
10237 * $('#example').dataTable( {
\r
10238 * "filter": false,
\r
10239 * "destroy": true
\r
10243 "bDestroy": false,
\r
10247 * Enable or disable filtering of data. Filtering in DataTables is "smart" in
\r
10248 * that it allows the end user to input multiple words (space separated) and
\r
10249 * will match a row containing those words, even if not in the order that was
\r
10250 * specified (this allow matching across multiple columns). Note that if you
\r
10251 * wish to use filtering in DataTables this must remain 'true' - to remove the
\r
10252 * default filtering input box and retain filtering abilities, please use
\r
10253 * {@link DataTable.defaults.dom}.
\r
10257 * @dtopt Features
\r
10258 * @name DataTable.defaults.searching
\r
10261 * $(document).ready( function () {
\r
10262 * $('#example').dataTable( {
\r
10263 * "searching": false
\r
10271 * Enable or disable the table information display. This shows information
\r
10272 * about the data that is currently visible on the page, including information
\r
10273 * about filtered data if that action is being performed.
\r
10277 * @dtopt Features
\r
10278 * @name DataTable.defaults.info
\r
10281 * $(document).ready( function () {
\r
10282 * $('#example').dataTable( {
\r
10291 * Enable jQuery UI ThemeRoller support (required as ThemeRoller requires some
\r
10292 * slightly different and additional mark-up from what DataTables has
\r
10293 * traditionally used).
\r
10297 * @dtopt Features
\r
10298 * @name DataTable.defaults.jQueryUI
\r
10301 * $(document).ready( function() {
\r
10302 * $('#example').dataTable( {
\r
10303 * "jQueryUI": true
\r
10307 "bJQueryUI": false,
\r
10311 * Allows the end user to select the size of a formatted page from a select
\r
10312 * menu (sizes are 10, 25, 50 and 100). Requires pagination (`paginate`).
\r
10316 * @dtopt Features
\r
10317 * @name DataTable.defaults.lengthChange
\r
10320 * $(document).ready( function () {
\r
10321 * $('#example').dataTable( {
\r
10322 * "lengthChange": false
\r
10326 "bLengthChange": true,
\r
10330 * Enable or disable pagination.
\r
10334 * @dtopt Features
\r
10335 * @name DataTable.defaults.paging
\r
10338 * $(document).ready( function () {
\r
10339 * $('#example').dataTable( {
\r
10340 * "paging": false
\r
10344 "bPaginate": true,
\r
10348 * Enable or disable the display of a 'processing' indicator when the table is
\r
10349 * being processed (e.g. a sort). This is particularly useful for tables with
\r
10350 * large amounts of data where it can take a noticeable amount of time to sort
\r
10355 * @dtopt Features
\r
10356 * @name DataTable.defaults.processing
\r
10359 * $(document).ready( function () {
\r
10360 * $('#example').dataTable( {
\r
10361 * "processing": true
\r
10365 "bProcessing": false,
\r
10369 * Retrieve the DataTables object for the given selector. Note that if the
\r
10370 * table has already been initialised, this parameter will cause DataTables
\r
10371 * to simply return the object that has already been set up - it will not take
\r
10372 * account of any changes you might have made to the initialisation object
\r
10373 * passed to DataTables (setting this parameter to true is an acknowledgement
\r
10374 * that you understand this). `destroy` can be used to reinitialise a table if
\r
10380 * @name DataTable.defaults.retrieve
\r
10383 * $(document).ready( function() {
\r
10385 * tableActions();
\r
10388 * function initTable ()
\r
10390 * return $('#example').dataTable( {
\r
10391 * "scrollY": "200px",
\r
10392 * "paginate": false,
\r
10393 * "retrieve": true
\r
10397 * function tableActions ()
\r
10399 * var table = initTable();
\r
10400 * // perform API operations with oTable
\r
10403 "bRetrieve": false,
\r
10407 * When vertical (y) scrolling is enabled, DataTables will force the height of
\r
10408 * the table's viewport to the given height at all times (useful for layout).
\r
10409 * However, this can look odd when filtering data down to a small data set,
\r
10410 * and the footer is left "floating" further down. This parameter (when
\r
10411 * enabled) will cause DataTables to collapse the table's viewport down when
\r
10412 * the result set will fit within the given Y height.
\r
10417 * @name DataTable.defaults.scrollCollapse
\r
10420 * $(document).ready( function() {
\r
10421 * $('#example').dataTable( {
\r
10422 * "scrollY": "200",
\r
10423 * "scrollCollapse": true
\r
10427 "bScrollCollapse": false,
\r
10431 * Configure DataTables to use server-side processing. Note that the
\r
10432 * `ajax` parameter must also be given in order to give DataTables a
\r
10433 * source to obtain the required data for each draw.
\r
10437 * @dtopt Features
\r
10438 * @dtopt Server-side
\r
10439 * @name DataTable.defaults.serverSide
\r
10442 * $(document).ready( function () {
\r
10443 * $('#example').dataTable( {
\r
10444 * "serverSide": true,
\r
10445 * "ajax": "xhr.php"
\r
10449 "bServerSide": false,
\r
10453 * Enable or disable sorting of columns. Sorting of individual columns can be
\r
10454 * disabled by the `sortable` option for each column.
\r
10458 * @dtopt Features
\r
10459 * @name DataTable.defaults.ordering
\r
10462 * $(document).ready( function () {
\r
10463 * $('#example').dataTable( {
\r
10464 * "ordering": false
\r
10472 * Enable or display DataTables' ability to sort multiple columns at the
\r
10473 * same time (activated by shift-click by the user).
\r
10478 * @name DataTable.defaults.orderMulti
\r
10481 * // Disable multiple column sorting ability
\r
10482 * $(document).ready( function () {
\r
10483 * $('#example').dataTable( {
\r
10484 * "orderMulti": false
\r
10488 "bSortMulti": true,
\r
10492 * Allows control over whether DataTables should use the top (true) unique
\r
10493 * cell that is found for a single column, or the bottom (false - default).
\r
10494 * This is useful when using complex headers.
\r
10499 * @name DataTable.defaults.orderCellsTop
\r
10502 * $(document).ready( function() {
\r
10503 * $('#example').dataTable( {
\r
10504 * "orderCellsTop": true
\r
10508 "bSortCellsTop": false,
\r
10512 * Enable or disable the addition of the classes `sorting\_1`, `sorting\_2` and
\r
10513 * `sorting\_3` to the columns which are currently being sorted on. This is
\r
10514 * presented as a feature switch as it can increase processing time (while
\r
10515 * classes are removed and added) so for large data sets you might want to
\r
10520 * @dtopt Features
\r
10521 * @name DataTable.defaults.orderClasses
\r
10524 * $(document).ready( function () {
\r
10525 * $('#example').dataTable( {
\r
10526 * "orderClasses": false
\r
10530 "bSortClasses": true,
\r
10534 * Enable or disable state saving. When enabled HTML5 `localStorage` will be
\r
10535 * used to save table display information such as pagination information,
\r
10536 * display length, filtering and sorting. As such when the end user reloads
\r
10537 * the page the display display will match what thy had previously set up.
\r
10539 * Due to the use of `localStorage` the default state saving is not supported
\r
10540 * in IE6 or 7. If state saving is required in those browsers, use
\r
10541 * `stateSaveCallback` to provide a storage solution such as cookies.
\r
10545 * @dtopt Features
\r
10546 * @name DataTable.defaults.stateSave
\r
10549 * $(document).ready( function () {
\r
10550 * $('#example').dataTable( {
\r
10551 * "stateSave": true
\r
10555 "bStateSave": false,
\r
10559 * This function is called when a TR element is created (and all TD child
\r
10560 * elements have been inserted), or registered if using a DOM source, allowing
\r
10561 * manipulation of the TR element (adding classes etc).
\r
10563 * @param {node} row "TR" element for the current row
\r
10564 * @param {array} data Raw data array for this row
\r
10565 * @param {int} dataIndex The index of this row in the internal aoData array
\r
10567 * @dtopt Callbacks
\r
10568 * @name DataTable.defaults.createdRow
\r
10571 * $(document).ready( function() {
\r
10572 * $('#example').dataTable( {
\r
10573 * "createdRow": function( row, data, dataIndex ) {
\r
10574 * // Bold the grade for all 'A' grade browsers
\r
10575 * if ( data[4] == "A" )
\r
10577 * $('td:eq(4)', row).html( '<b>A</b>' );
\r
10583 "fnCreatedRow": null,
\r
10587 * This function is called on every 'draw' event, and allows you to
\r
10588 * dynamically modify any aspect you want about the created DOM.
\r
10590 * @param {object} settings DataTables settings object
\r
10592 * @dtopt Callbacks
\r
10593 * @name DataTable.defaults.drawCallback
\r
10596 * $(document).ready( function() {
\r
10597 * $('#example').dataTable( {
\r
10598 * "drawCallback": function( settings ) {
\r
10599 * alert( 'DataTables has redrawn the table' );
\r
10604 "fnDrawCallback": null,
\r
10608 * Identical to fnHeaderCallback() but for the table footer this function
\r
10609 * allows you to modify the table footer on every 'draw' event.
\r
10611 * @param {node} foot "TR" element for the footer
\r
10612 * @param {array} data Full table data (as derived from the original HTML)
\r
10613 * @param {int} start Index for the current display starting point in the
\r
10615 * @param {int} end Index for the current display ending point in the
\r
10617 * @param {array int} display Index array to translate the visual position
\r
10618 * to the full data array
\r
10620 * @dtopt Callbacks
\r
10621 * @name DataTable.defaults.footerCallback
\r
10624 * $(document).ready( function() {
\r
10625 * $('#example').dataTable( {
\r
10626 * "footerCallback": function( tfoot, data, start, end, display ) {
\r
10627 * tfoot.getElementsByTagName('th')[0].innerHTML = "Starting index is "+start;
\r
10632 "fnFooterCallback": null,
\r
10636 * When rendering large numbers in the information element for the table
\r
10637 * (i.e. "Showing 1 to 10 of 57 entries") DataTables will render large numbers
\r
10638 * to have a comma separator for the 'thousands' units (e.g. 1 million is
\r
10639 * rendered as "1,000,000") to help readability for the end user. This
\r
10640 * function will override the default method DataTables uses.
\r
10643 * @param {int} toFormat number to be formatted
\r
10644 * @returns {string} formatted string for DataTables to show the number
\r
10646 * @dtopt Callbacks
\r
10647 * @name DataTable.defaults.formatNumber
\r
10650 * // Format a number using a single quote for the separator (note that
\r
10651 * // this can also be done with the language.thousands option)
\r
10652 * $(document).ready( function() {
\r
10653 * $('#example').dataTable( {
\r
10654 * "formatNumber": function ( toFormat ) {
\r
10655 * return toFormat.toString().replace(
\r
10656 * /\B(?=(\d{3})+(?!\d))/g, "'"
\r
10662 "fnFormatNumber": function ( toFormat ) {
\r
10663 return toFormat.toString().replace(
\r
10664 /\B(?=(\d{3})+(?!\d))/g,
\r
10665 this.oLanguage.sThousands
\r
10671 * This function is called on every 'draw' event, and allows you to
\r
10672 * dynamically modify the header row. This can be used to calculate and
\r
10673 * display useful information about the table.
\r
10675 * @param {node} head "TR" element for the header
\r
10676 * @param {array} data Full table data (as derived from the original HTML)
\r
10677 * @param {int} start Index for the current display starting point in the
\r
10679 * @param {int} end Index for the current display ending point in the
\r
10681 * @param {array int} display Index array to translate the visual position
\r
10682 * to the full data array
\r
10684 * @dtopt Callbacks
\r
10685 * @name DataTable.defaults.headerCallback
\r
10688 * $(document).ready( function() {
\r
10689 * $('#example').dataTable( {
\r
10690 * "fheaderCallback": function( head, data, start, end, display ) {
\r
10691 * head.getElementsByTagName('th')[0].innerHTML = "Displaying "+(end-start)+" records";
\r
10696 "fnHeaderCallback": null,
\r
10700 * The information element can be used to convey information about the current
\r
10701 * state of the table. Although the internationalisation options presented by
\r
10702 * DataTables are quite capable of dealing with most customisations, there may
\r
10703 * be times where you wish to customise the string further. This callback
\r
10704 * allows you to do exactly that.
\r
10706 * @param {object} oSettings DataTables settings object
\r
10707 * @param {int} start Starting position in data for the draw
\r
10708 * @param {int} end End position in data for the draw
\r
10709 * @param {int} max Total number of rows in the table (regardless of
\r
10711 * @param {int} total Total number of rows in the data set, after filtering
\r
10712 * @param {string} pre The string that DataTables has formatted using it's
\r
10714 * @returns {string} The string to be displayed in the information element.
\r
10716 * @dtopt Callbacks
\r
10717 * @name DataTable.defaults.infoCallback
\r
10720 * $('#example').dataTable( {
\r
10721 * "infoCallback": function( settings, start, end, max, total, pre ) {
\r
10722 * return start +" to "+ end;
\r
10726 "fnInfoCallback": null,
\r
10730 * Called when the table has been initialised. Normally DataTables will
\r
10731 * initialise sequentially and there will be no need for this function,
\r
10732 * however, this does not hold true when using external language information
\r
10733 * since that is obtained using an async XHR call.
\r
10735 * @param {object} settings DataTables settings object
\r
10736 * @param {object} json The JSON object request from the server - only
\r
10737 * present if client-side Ajax sourced data is used
\r
10739 * @dtopt Callbacks
\r
10740 * @name DataTable.defaults.initComplete
\r
10743 * $(document).ready( function() {
\r
10744 * $('#example').dataTable( {
\r
10745 * "initComplete": function(settings, json) {
\r
10746 * alert( 'DataTables has finished its initialisation.' );
\r
10751 "fnInitComplete": null,
\r
10755 * Called at the very start of each table draw and can be used to cancel the
\r
10756 * draw by returning false, any other return (including undefined) results in
\r
10757 * the full draw occurring).
\r
10759 * @param {object} settings DataTables settings object
\r
10760 * @returns {boolean} False will cancel the draw, anything else (including no
\r
10761 * return) will allow it to complete.
\r
10763 * @dtopt Callbacks
\r
10764 * @name DataTable.defaults.preDrawCallback
\r
10767 * $(document).ready( function() {
\r
10768 * $('#example').dataTable( {
\r
10769 * "preDrawCallback": function( settings ) {
\r
10770 * if ( $('#test').val() == 1 ) {
\r
10777 "fnPreDrawCallback": null,
\r
10781 * This function allows you to 'post process' each row after it have been
\r
10782 * generated for each table draw, but before it is rendered on screen. This
\r
10783 * function might be used for setting the row class name etc.
\r
10785 * @param {node} row "TR" element for the current row
\r
10786 * @param {array} data Raw data array for this row
\r
10787 * @param {int} displayIndex The display index for the current table draw
\r
10788 * @param {int} displayIndexFull The index of the data in the full list of
\r
10789 * rows (after filtering)
\r
10791 * @dtopt Callbacks
\r
10792 * @name DataTable.defaults.rowCallback
\r
10795 * $(document).ready( function() {
\r
10796 * $('#example').dataTable( {
\r
10797 * "rowCallback": function( row, data, displayIndex, displayIndexFull ) {
\r
10798 * // Bold the grade for all 'A' grade browsers
\r
10799 * if ( data[4] == "A" ) {
\r
10800 * $('td:eq(4)', row).html( '<b>A</b>' );
\r
10806 "fnRowCallback": null,
\r
10810 * __Deprecated__ The functionality provided by this parameter has now been
\r
10811 * superseded by that provided through `ajax`, which should be used instead.
\r
10813 * This parameter allows you to override the default function which obtains
\r
10814 * the data from the server so something more suitable for your application.
\r
10815 * For example you could use POST data, or pull information from a Gears or
\r
10819 * @param {string} source HTTP source to obtain the data from (`ajax`)
\r
10820 * @param {array} data A key/value pair object containing the data to send
\r
10822 * @param {function} callback to be called on completion of the data get
\r
10823 * process that will draw the data on the page.
\r
10824 * @param {object} settings DataTables settings object
\r
10826 * @dtopt Callbacks
\r
10827 * @dtopt Server-side
\r
10828 * @name DataTable.defaults.serverData
\r
10830 * @deprecated 1.10. Please use `ajax` for this functionality now.
\r
10832 "fnServerData": null,
\r
10836 * __Deprecated__ The functionality provided by this parameter has now been
\r
10837 * superseded by that provided through `ajax`, which should be used instead.
\r
10839 * It is often useful to send extra data to the server when making an Ajax
\r
10840 * request - for example custom filtering information, and this callback
\r
10841 * function makes it trivial to send extra information to the server. The
\r
10842 * passed in parameter is the data set that has been constructed by
\r
10843 * DataTables, and you can add to this or modify it as you require.
\r
10845 * @param {array} data Data array (array of objects which are name/value
\r
10846 * pairs) that has been constructed by DataTables and will be sent to the
\r
10847 * server. In the case of Ajax sourced data with server-side processing
\r
10848 * this will be an empty array, for server-side processing there will be a
\r
10849 * significant number of parameters!
\r
10850 * @returns {undefined} Ensure that you modify the data array passed in,
\r
10851 * as this is passed by reference.
\r
10853 * @dtopt Callbacks
\r
10854 * @dtopt Server-side
\r
10855 * @name DataTable.defaults.serverParams
\r
10857 * @deprecated 1.10. Please use `ajax` for this functionality now.
\r
10859 "fnServerParams": null,
\r
10863 * Load the table state. With this function you can define from where, and how, the
\r
10864 * state of a table is loaded. By default DataTables will load from `localStorage`
\r
10865 * but you might wish to use a server-side database or cookies.
\r
10868 * @param {object} settings DataTables settings object
\r
10869 * @return {object} The DataTables state object to be loaded
\r
10871 * @dtopt Callbacks
\r
10872 * @name DataTable.defaults.stateLoadCallback
\r
10875 * $(document).ready( function() {
\r
10876 * $('#example').dataTable( {
\r
10877 * "stateSave": true,
\r
10878 * "stateLoadCallback": function (settings) {
\r
10881 * // Send an Ajax request to the server to get the data. Note that
\r
10882 * // this is a synchronous request.
\r
10884 * "url": "/state_load",
\r
10885 * "async": false,
\r
10886 * "dataType": "json",
\r
10887 * "success": function (json) {
\r
10897 "fnStateLoadCallback": function ( settings ) {
\r
10899 return JSON.parse(
\r
10900 (settings.iStateDuration === -1 ? sessionStorage : localStorage).getItem(
\r
10901 'DataTables_'+settings.sInstance+'_'+location.pathname
\r
10909 * Callback which allows modification of the saved state prior to loading that state.
\r
10910 * This callback is called when the table is loading state from the stored data, but
\r
10911 * prior to the settings object being modified by the saved state. Note that for
\r
10912 * plug-in authors, you should use the `stateLoadParams` event to load parameters for
\r
10915 * @param {object} settings DataTables settings object
\r
10916 * @param {object} data The state object that is to be loaded
\r
10918 * @dtopt Callbacks
\r
10919 * @name DataTable.defaults.stateLoadParams
\r
10922 * // Remove a saved filter, so filtering is never loaded
\r
10923 * $(document).ready( function() {
\r
10924 * $('#example').dataTable( {
\r
10925 * "stateSave": true,
\r
10926 * "stateLoadParams": function (settings, data) {
\r
10927 * data.oSearch.sSearch = "";
\r
10933 * // Disallow state loading by returning false
\r
10934 * $(document).ready( function() {
\r
10935 * $('#example').dataTable( {
\r
10936 * "stateSave": true,
\r
10937 * "stateLoadParams": function (settings, data) {
\r
10943 "fnStateLoadParams": null,
\r
10947 * Callback that is called when the state has been loaded from the state saving method
\r
10948 * and the DataTables settings object has been modified as a result of the loaded state.
\r
10950 * @param {object} settings DataTables settings object
\r
10951 * @param {object} data The state object that was loaded
\r
10953 * @dtopt Callbacks
\r
10954 * @name DataTable.defaults.stateLoaded
\r
10957 * // Show an alert with the filtering value that was saved
\r
10958 * $(document).ready( function() {
\r
10959 * $('#example').dataTable( {
\r
10960 * "stateSave": true,
\r
10961 * "stateLoaded": function (settings, data) {
\r
10962 * alert( 'Saved filter was: '+data.oSearch.sSearch );
\r
10967 "fnStateLoaded": null,
\r
10971 * Save the table state. This function allows you to define where and how the state
\r
10972 * information for the table is stored By default DataTables will use `localStorage`
\r
10973 * but you might wish to use a server-side database or cookies.
\r
10976 * @param {object} settings DataTables settings object
\r
10977 * @param {object} data The state object to be saved
\r
10979 * @dtopt Callbacks
\r
10980 * @name DataTable.defaults.stateSaveCallback
\r
10983 * $(document).ready( function() {
\r
10984 * $('#example').dataTable( {
\r
10985 * "stateSave": true,
\r
10986 * "stateSaveCallback": function (settings, data) {
\r
10987 * // Send an Ajax request to the server with the state object
\r
10989 * "url": "/state_save",
\r
10991 * "dataType": "json",
\r
10992 * "method": "POST"
\r
10993 * "success": function () {}
\r
10999 "fnStateSaveCallback": function ( settings, data ) {
\r
11001 (settings.iStateDuration === -1 ? sessionStorage : localStorage).setItem(
\r
11002 'DataTables_'+settings.sInstance+'_'+location.pathname,
\r
11003 JSON.stringify( data )
\r
11010 * Callback which allows modification of the state to be saved. Called when the table
\r
11011 * has changed state a new state save is required. This method allows modification of
\r
11012 * the state saving object prior to actually doing the save, including addition or
\r
11013 * other state properties or modification. Note that for plug-in authors, you should
\r
11014 * use the `stateSaveParams` event to save parameters for a plug-in.
\r
11016 * @param {object} settings DataTables settings object
\r
11017 * @param {object} data The state object to be saved
\r
11019 * @dtopt Callbacks
\r
11020 * @name DataTable.defaults.stateSaveParams
\r
11023 * // Remove a saved filter, so filtering is never saved
\r
11024 * $(document).ready( function() {
\r
11025 * $('#example').dataTable( {
\r
11026 * "stateSave": true,
\r
11027 * "stateSaveParams": function (settings, data) {
\r
11028 * data.oSearch.sSearch = "";
\r
11033 "fnStateSaveParams": null,
\r
11037 * Duration for which the saved state information is considered valid. After this period
\r
11038 * has elapsed the state will be returned to the default.
\r
11039 * Value is given in seconds.
\r
11041 * @default 7200 <i>(2 hours)</i>
\r
11044 * @name DataTable.defaults.stateDuration
\r
11047 * $(document).ready( function() {
\r
11048 * $('#example').dataTable( {
\r
11049 * "stateDuration": 60*60*24; // 1 day
\r
11053 "iStateDuration": 7200,
\r
11057 * When enabled DataTables will not make a request to the server for the first
\r
11058 * page draw - rather it will use the data already on the page (no sorting etc
\r
11059 * will be applied to it), thus saving on an XHR at load time. `deferLoading`
\r
11060 * is used to indicate that deferred loading is required, but it is also used
\r
11061 * to tell DataTables how many records there are in the full table (allowing
\r
11062 * the information element and pagination to be displayed correctly). In the case
\r
11063 * where a filtering is applied to the table on initial load, this can be
\r
11064 * indicated by giving the parameter as an array, where the first element is
\r
11065 * the number of records available after filtering and the second element is the
\r
11066 * number of records without filtering (allowing the table information element
\r
11067 * to be shown correctly).
\r
11068 * @type int | array
\r
11072 * @name DataTable.defaults.deferLoading
\r
11075 * // 57 records available in the table, no filtering applied
\r
11076 * $(document).ready( function() {
\r
11077 * $('#example').dataTable( {
\r
11078 * "serverSide": true,
\r
11079 * "ajax": "scripts/server_processing.php",
\r
11080 * "deferLoading": 57
\r
11085 * // 57 records after filtering, 100 without filtering (an initial filter applied)
\r
11086 * $(document).ready( function() {
\r
11087 * $('#example').dataTable( {
\r
11088 * "serverSide": true,
\r
11089 * "ajax": "scripts/server_processing.php",
\r
11090 * "deferLoading": [ 57, 100 ],
\r
11092 * "search": "my_filter"
\r
11097 "iDeferLoading": null,
\r
11101 * Number of rows to display on a single page when using pagination. If
\r
11102 * feature enabled (`lengthChange`) then the end user will be able to override
\r
11103 * this to a custom setting using a pop-up menu.
\r
11108 * @name DataTable.defaults.pageLength
\r
11111 * $(document).ready( function() {
\r
11112 * $('#example').dataTable( {
\r
11113 * "pageLength": 50
\r
11117 "iDisplayLength": 10,
\r
11121 * Define the starting point for data display when using DataTables with
\r
11122 * pagination. Note that this parameter is the number of records, rather than
\r
11123 * the page number, so if you have 10 records per page and want to start on
\r
11124 * the third page, it should be "20".
\r
11129 * @name DataTable.defaults.displayStart
\r
11132 * $(document).ready( function() {
\r
11133 * $('#example').dataTable( {
\r
11134 * "displayStart": 20
\r
11138 "iDisplayStart": 0,
\r
11142 * By default DataTables allows keyboard navigation of the table (sorting, paging,
\r
11143 * and filtering) by adding a `tabindex` attribute to the required elements. This
\r
11144 * allows you to tab through the controls and press the enter key to activate them.
\r
11145 * The tabindex is default 0, meaning that the tab follows the flow of the document.
\r
11146 * You can overrule this using this parameter if you wish. Use a value of -1 to
\r
11147 * disable built-in keyboard navigation.
\r
11152 * @name DataTable.defaults.tabIndex
\r
11155 * $(document).ready( function() {
\r
11156 * $('#example').dataTable( {
\r
11165 * Classes that DataTables assigns to the various components and features
\r
11166 * that it adds to the HTML table. This allows classes to be configured
\r
11167 * during initialisation in addition to through the static
\r
11168 * {@link DataTable.ext.oStdClasses} object).
\r
11170 * @name DataTable.defaults.classes
\r
11176 * All strings that DataTables uses in the user interface that it creates
\r
11177 * are defined in this object, allowing you to modified them individually or
\r
11178 * completely replace them all as required.
\r
11180 * @name DataTable.defaults.language
\r
11184 * Strings that are used for WAI-ARIA labels and controls only (these are not
\r
11185 * actually visible on the page, but will be read by screenreaders, and thus
\r
11186 * must be internationalised as well).
\r
11188 * @name DataTable.defaults.language.aria
\r
11192 * ARIA label that is added to the table headers when the column may be
\r
11193 * sorted ascending by activing the column (click or return when focused).
\r
11194 * Note that the column header is prefixed to this string.
\r
11196 * @default : activate to sort column ascending
\r
11198 * @dtopt Language
\r
11199 * @name DataTable.defaults.language.aria.sortAscending
\r
11202 * $(document).ready( function() {
\r
11203 * $('#example').dataTable( {
\r
11206 * "sortAscending": " - click/return to sort ascending"
\r
11212 "sSortAscending": ": activate to sort column ascending",
\r
11215 * ARIA label that is added to the table headers when the column may be
\r
11216 * sorted descending by activing the column (click or return when focused).
\r
11217 * Note that the column header is prefixed to this string.
\r
11219 * @default : activate to sort column ascending
\r
11221 * @dtopt Language
\r
11222 * @name DataTable.defaults.language.aria.sortDescending
\r
11225 * $(document).ready( function() {
\r
11226 * $('#example').dataTable( {
\r
11229 * "sortDescending": " - click/return to sort descending"
\r
11235 "sSortDescending": ": activate to sort column descending"
\r
11239 * Pagination string used by DataTables for the built-in pagination
\r
11242 * @name DataTable.defaults.language.paginate
\r
11246 * Text to use when using the 'full_numbers' type of pagination for the
\r
11247 * button to take the user to the first page.
\r
11251 * @dtopt Language
\r
11252 * @name DataTable.defaults.language.paginate.first
\r
11255 * $(document).ready( function() {
\r
11256 * $('#example').dataTable( {
\r
11259 * "first": "First page"
\r
11265 "sFirst": "First",
\r
11269 * Text to use when using the 'full_numbers' type of pagination for the
\r
11270 * button to take the user to the last page.
\r
11274 * @dtopt Language
\r
11275 * @name DataTable.defaults.language.paginate.last
\r
11278 * $(document).ready( function() {
\r
11279 * $('#example').dataTable( {
\r
11282 * "last": "Last page"
\r
11292 * Text to use for the 'next' pagination button (to take the user to the
\r
11297 * @dtopt Language
\r
11298 * @name DataTable.defaults.language.paginate.next
\r
11301 * $(document).ready( function() {
\r
11302 * $('#example').dataTable( {
\r
11305 * "next": "Next page"
\r
11315 * Text to use for the 'previous' pagination button (to take the user to
\r
11316 * the previous page).
\r
11318 * @default Previous
\r
11320 * @dtopt Language
\r
11321 * @name DataTable.defaults.language.paginate.previous
\r
11324 * $(document).ready( function() {
\r
11325 * $('#example').dataTable( {
\r
11328 * "previous": "Previous page"
\r
11334 "sPrevious": "Previous"
\r
11338 * This string is shown in preference to `zeroRecords` when the table is
\r
11339 * empty of data (regardless of filtering). Note that this is an optional
\r
11340 * parameter - if it is not given, the value of `zeroRecords` will be used
\r
11341 * instead (either the default or given value).
\r
11343 * @default No data available in table
\r
11345 * @dtopt Language
\r
11346 * @name DataTable.defaults.language.emptyTable
\r
11349 * $(document).ready( function() {
\r
11350 * $('#example').dataTable( {
\r
11352 * "emptyTable": "No data available in table"
\r
11357 "sEmptyTable": "No data available in table",
\r
11361 * This string gives information to the end user about the information
\r
11362 * that is current on display on the page. The following tokens can be
\r
11363 * used in the string and will be dynamically replaced as the table
\r
11364 * display updates. This tokens can be placed anywhere in the string, or
\r
11365 * removed as needed by the language requires:
\r
11367 * * `\_START\_` - Display index of the first record on the current page
\r
11368 * * `\_END\_` - Display index of the last record on the current page
\r
11369 * * `\_TOTAL\_` - Number of records in the table after filtering
\r
11370 * * `\_MAX\_` - Number of records in the table without filtering
\r
11371 * * `\_PAGE\_` - Current page number
\r
11372 * * `\_PAGES\_` - Total number of pages of data in the table
\r
11375 * @default Showing _START_ to _END_ of _TOTAL_ entries
\r
11377 * @dtopt Language
\r
11378 * @name DataTable.defaults.language.info
\r
11381 * $(document).ready( function() {
\r
11382 * $('#example').dataTable( {
\r
11384 * "info": "Showing page _PAGE_ of _PAGES_"
\r
11389 "sInfo": "Showing _START_ to _END_ of _TOTAL_ entries",
\r
11393 * Display information string for when the table is empty. Typically the
\r
11394 * format of this string should match `info`.
\r
11396 * @default Showing 0 to 0 of 0 entries
\r
11398 * @dtopt Language
\r
11399 * @name DataTable.defaults.language.infoEmpty
\r
11402 * $(document).ready( function() {
\r
11403 * $('#example').dataTable( {
\r
11405 * "infoEmpty": "No entries to show"
\r
11410 "sInfoEmpty": "Showing 0 to 0 of 0 entries",
\r
11414 * When a user filters the information in a table, this string is appended
\r
11415 * to the information (`info`) to give an idea of how strong the filtering
\r
11416 * is. The variable _MAX_ is dynamically updated.
\r
11418 * @default (filtered from _MAX_ total entries)
\r
11420 * @dtopt Language
\r
11421 * @name DataTable.defaults.language.infoFiltered
\r
11424 * $(document).ready( function() {
\r
11425 * $('#example').dataTable( {
\r
11427 * "infoFiltered": " - filtering from _MAX_ records"
\r
11432 "sInfoFiltered": "(filtered from _MAX_ total entries)",
\r
11436 * If can be useful to append extra information to the info string at times,
\r
11437 * and this variable does exactly that. This information will be appended to
\r
11438 * the `info` (`infoEmpty` and `infoFiltered` in whatever combination they are
\r
11439 * being used) at all times.
\r
11441 * @default <i>Empty string</i>
\r
11443 * @dtopt Language
\r
11444 * @name DataTable.defaults.language.infoPostFix
\r
11447 * $(document).ready( function() {
\r
11448 * $('#example').dataTable( {
\r
11450 * "infoPostFix": "All records shown are derived from real information."
\r
11455 "sInfoPostFix": "",
\r
11459 * This decimal place operator is a little different from the other
\r
11460 * language options since DataTables doesn't output floating point
\r
11461 * numbers, so it won't ever use this for display of a number. Rather,
\r
11462 * what this parameter does is modify the sort methods of the table so
\r
11463 * that numbers which are in a format which has a character other than
\r
11464 * a period (`.`) as a decimal place will be sorted numerically.
\r
11466 * Note that numbers with different decimal places cannot be shown in
\r
11467 * the same table and still be sortable, the table must be consistent.
\r
11468 * However, multiple different tables on the page can use different
\r
11469 * decimal place characters.
\r
11473 * @dtopt Language
\r
11474 * @name DataTable.defaults.language.decimal
\r
11477 * $(document).ready( function() {
\r
11478 * $('#example').dataTable( {
\r
11481 * "thousands": "."
\r
11490 * DataTables has a build in number formatter (`formatNumber`) which is
\r
11491 * used to format large numbers that are used in the table information.
\r
11492 * By default a comma is used, but this can be trivially changed to any
\r
11493 * character you wish with this parameter.
\r
11497 * @dtopt Language
\r
11498 * @name DataTable.defaults.language.thousands
\r
11501 * $(document).ready( function() {
\r
11502 * $('#example').dataTable( {
\r
11504 * "thousands": "'"
\r
11509 "sThousands": ",",
\r
11513 * Detail the action that will be taken when the drop down menu for the
\r
11514 * pagination length option is changed. The '_MENU_' variable is replaced
\r
11515 * with a default select list of 10, 25, 50 and 100, and can be replaced
\r
11516 * with a custom select box if required.
\r
11518 * @default Show _MENU_ entries
\r
11520 * @dtopt Language
\r
11521 * @name DataTable.defaults.language.lengthMenu
\r
11524 * // Language change only
\r
11525 * $(document).ready( function() {
\r
11526 * $('#example').dataTable( {
\r
11528 * "lengthMenu": "Display _MENU_ records"
\r
11534 * // Language and options change
\r
11535 * $(document).ready( function() {
\r
11536 * $('#example').dataTable( {
\r
11538 * "lengthMenu": 'Display <select>'+
\r
11539 * '<option value="10">10</option>'+
\r
11540 * '<option value="20">20</option>'+
\r
11541 * '<option value="30">30</option>'+
\r
11542 * '<option value="40">40</option>'+
\r
11543 * '<option value="50">50</option>'+
\r
11544 * '<option value="-1">All</option>'+
\r
11545 * '</select> records'
\r
11550 "sLengthMenu": "Show _MENU_ entries",
\r
11554 * When using Ajax sourced data and during the first draw when DataTables is
\r
11555 * gathering the data, this message is shown in an empty row in the table to
\r
11556 * indicate to the end user the the data is being loaded. Note that this
\r
11557 * parameter is not used when loading data by server-side processing, just
\r
11558 * Ajax sourced data with client-side processing.
\r
11560 * @default Loading...
\r
11562 * @dtopt Language
\r
11563 * @name DataTable.defaults.language.loadingRecords
\r
11566 * $(document).ready( function() {
\r
11567 * $('#example').dataTable( {
\r
11569 * "loadingRecords": "Please wait - loading..."
\r
11574 "sLoadingRecords": "Loading...",
\r
11578 * Text which is displayed when the table is processing a user action
\r
11579 * (usually a sort command or similar).
\r
11581 * @default Processing...
\r
11583 * @dtopt Language
\r
11584 * @name DataTable.defaults.language.processing
\r
11587 * $(document).ready( function() {
\r
11588 * $('#example').dataTable( {
\r
11590 * "processing": "DataTables is currently busy"
\r
11595 "sProcessing": "Processing...",
\r
11599 * Details the actions that will be taken when the user types into the
\r
11600 * filtering input text box. The variable "_INPUT_", if used in the string,
\r
11601 * is replaced with the HTML text box for the filtering input allowing
\r
11602 * control over where it appears in the string. If "_INPUT_" is not given
\r
11603 * then the input box is appended to the string automatically.
\r
11605 * @default Search:
\r
11607 * @dtopt Language
\r
11608 * @name DataTable.defaults.language.search
\r
11611 * // Input text box will be appended at the end automatically
\r
11612 * $(document).ready( function() {
\r
11613 * $('#example').dataTable( {
\r
11615 * "search": "Filter records:"
\r
11621 * // Specify where the filter should appear
\r
11622 * $(document).ready( function() {
\r
11623 * $('#example').dataTable( {
\r
11625 * "search": "Apply filter _INPUT_ to table"
\r
11630 "sSearch": "Search:",
\r
11634 * Assign a `placeholder` attribute to the search `input` element
\r
11638 * @dtopt Language
\r
11639 * @name DataTable.defaults.language.searchPlaceholder
\r
11641 "sSearchPlaceholder": "",
\r
11645 * All of the language information can be stored in a file on the
\r
11646 * server-side, which DataTables will look up if this parameter is passed.
\r
11647 * It must store the URL of the language file, which is in a JSON format,
\r
11648 * and the object has the same properties as the oLanguage object in the
\r
11649 * initialiser object (i.e. the above parameters). Please refer to one of
\r
11650 * the example language files to see how this works in action.
\r
11652 * @default <i>Empty string - i.e. disabled</i>
\r
11654 * @dtopt Language
\r
11655 * @name DataTable.defaults.language.url
\r
11658 * $(document).ready( function() {
\r
11659 * $('#example').dataTable( {
\r
11661 * "url": "http://www.sprymedia.co.uk/dataTables/lang.txt"
\r
11670 * Text shown inside the table records when the is no information to be
\r
11671 * displayed after filtering. `emptyTable` is shown when there is simply no
\r
11672 * information in the table at all (regardless of filtering).
\r
11674 * @default No matching records found
\r
11676 * @dtopt Language
\r
11677 * @name DataTable.defaults.language.zeroRecords
\r
11680 * $(document).ready( function() {
\r
11681 * $('#example').dataTable( {
\r
11683 * "zeroRecords": "No records to display"
\r
11688 "sZeroRecords": "No matching records found"
\r
11693 * This parameter allows you to have define the global filtering state at
\r
11694 * initialisation time. As an object the `search` parameter must be
\r
11695 * defined, but all other parameters are optional. When `regex` is true,
\r
11696 * the search string will be treated as a regular expression, when false
\r
11697 * (default) it will be treated as a straight string. When `smart`
\r
11698 * DataTables will use it's smart filtering methods (to word match at
\r
11699 * any point in the data), when false this will not be done.
\r
11701 * @extends DataTable.models.oSearch
\r
11704 * @name DataTable.defaults.search
\r
11707 * $(document).ready( function() {
\r
11708 * $('#example').dataTable( {
\r
11709 * "search": {"search": "Initial search"}
\r
11713 "oSearch": $.extend( {}, DataTable.models.oSearch ),
\r
11717 * __Deprecated__ The functionality provided by this parameter has now been
\r
11718 * superseded by that provided through `ajax`, which should be used instead.
\r
11720 * By default DataTables will look for the property `data` (or `aaData` for
\r
11721 * compatibility with DataTables 1.9-) when obtaining data from an Ajax
\r
11722 * source or for server-side processing - this parameter allows that
\r
11723 * property to be changed. You can use Javascript dotted object notation to
\r
11724 * get a data source for multiple levels of nesting.
\r
11729 * @dtopt Server-side
\r
11730 * @name DataTable.defaults.ajaxDataProp
\r
11732 * @deprecated 1.10. Please use `ajax` for this functionality now.
\r
11734 "sAjaxDataProp": "data",
\r
11738 * __Deprecated__ The functionality provided by this parameter has now been
\r
11739 * superseded by that provided through `ajax`, which should be used instead.
\r
11741 * You can instruct DataTables to load data from an external
\r
11742 * source using this parameter (use aData if you want to pass data in you
\r
11743 * already have). Simply provide a url a JSON object can be obtained from.
\r
11748 * @dtopt Server-side
\r
11749 * @name DataTable.defaults.ajaxSource
\r
11751 * @deprecated 1.10. Please use `ajax` for this functionality now.
\r
11753 "sAjaxSource": null,
\r
11757 * This initialisation variable allows you to specify exactly where in the
\r
11758 * DOM you want DataTables to inject the various controls it adds to the page
\r
11759 * (for example you might want the pagination controls at the top of the
\r
11760 * table). DIV elements (with or without a custom class) can also be added to
\r
11761 * aid styling. The follow syntax is used:
\r
11763 * <li>The following options are allowed:
\r
11765 * <li>'l' - Length changing</li>
\r
11766 * <li>'f' - Filtering input</li>
\r
11767 * <li>'t' - The table!</li>
\r
11768 * <li>'i' - Information</li>
\r
11769 * <li>'p' - Pagination</li>
\r
11770 * <li>'r' - pRocessing</li>
\r
11773 * <li>The following constants are allowed:
\r
11775 * <li>'H' - jQueryUI theme "header" classes ('fg-toolbar ui-widget-header ui-corner-tl ui-corner-tr ui-helper-clearfix')</li>
\r
11776 * <li>'F' - jQueryUI theme "footer" classes ('fg-toolbar ui-widget-header ui-corner-bl ui-corner-br ui-helper-clearfix')</li>
\r
11779 * <li>The following syntax is expected:
\r
11781 * <li>'<' and '>' - div elements</li>
\r
11782 * <li>'<"class" and '>' - div with a class</li>
\r
11783 * <li>'<"#id" and '>' - div with an ID</li>
\r
11788 * <li>'<"wrapper"flipt>'</li>
\r
11789 * <li>'<lf<t>ip>'</li>
\r
11794 * @default lfrtip <i>(when `jQueryUI` is false)</i> <b>or</b>
\r
11795 * <"H"lfr>t<"F"ip> <i>(when `jQueryUI` is true)</i>
\r
11798 * @name DataTable.defaults.dom
\r
11801 * $(document).ready( function() {
\r
11802 * $('#example').dataTable( {
\r
11803 * "dom": '<"top"i>rt<"bottom"flp><"clear">'
\r
11807 "sDom": "lfrtip",
\r
11811 * Search delay option. This will throttle full table searches that use the
\r
11812 * DataTables provided search input element (it does not effect calls to
\r
11813 * `dt-api search()`, providing a delay before the search is made.
\r
11818 * @name DataTable.defaults.searchDelay
\r
11821 * $(document).ready( function() {
\r
11822 * $('#example').dataTable( {
\r
11823 * "searchDelay": 200
\r
11827 "searchDelay": null,
\r
11831 * DataTables features four different built-in options for the buttons to
\r
11832 * display for pagination control:
\r
11834 * * `simple` - 'Previous' and 'Next' buttons only
\r
11835 * * 'simple_numbers` - 'Previous' and 'Next' buttons, plus page numbers
\r
11836 * * `full` - 'First', 'Previous', 'Next' and 'Last' buttons
\r
11837 * * `full_numbers` - 'First', 'Previous', 'Next' and 'Last' buttons, plus
\r
11840 * Further methods can be added using {@link DataTable.ext.oPagination}.
\r
11842 * @default simple_numbers
\r
11845 * @name DataTable.defaults.pagingType
\r
11848 * $(document).ready( function() {
\r
11849 * $('#example').dataTable( {
\r
11850 * "pagingType": "full_numbers"
\r
11854 "sPaginationType": "simple_numbers",
\r
11858 * Enable horizontal scrolling. When a table is too wide to fit into a
\r
11859 * certain layout, or you have a large number of columns in the table, you
\r
11860 * can enable x-scrolling to show the table in a viewport, which can be
\r
11861 * scrolled. This property can be `true` which will allow the table to
\r
11862 * scroll horizontally when needed, or any CSS unit, or a number (in which
\r
11863 * case it will be treated as a pixel measurement). Setting as simply `true`
\r
11864 * is recommended.
\r
11865 * @type boolean|string
\r
11866 * @default <i>blank string - i.e. disabled</i>
\r
11868 * @dtopt Features
\r
11869 * @name DataTable.defaults.scrollX
\r
11872 * $(document).ready( function() {
\r
11873 * $('#example').dataTable( {
\r
11874 * "scrollX": true,
\r
11875 * "scrollCollapse": true
\r
11883 * This property can be used to force a DataTable to use more width than it
\r
11884 * might otherwise do when x-scrolling is enabled. For example if you have a
\r
11885 * table which requires to be well spaced, this parameter is useful for
\r
11886 * "over-sizing" the table, and thus forcing scrolling. This property can by
\r
11887 * any CSS unit, or a number (in which case it will be treated as a pixel
\r
11890 * @default <i>blank string - i.e. disabled</i>
\r
11893 * @name DataTable.defaults.scrollXInner
\r
11896 * $(document).ready( function() {
\r
11897 * $('#example').dataTable( {
\r
11898 * "scrollX": "100%",
\r
11899 * "scrollXInner": "110%"
\r
11903 "sScrollXInner": "",
\r
11907 * Enable vertical scrolling. Vertical scrolling will constrain the DataTable
\r
11908 * to the given height, and enable scrolling for any data which overflows the
\r
11909 * current viewport. This can be used as an alternative to paging to display
\r
11910 * a lot of data in a small area (although paging and scrolling can both be
\r
11911 * enabled at the same time). This property can be any CSS unit, or a number
\r
11912 * (in which case it will be treated as a pixel measurement).
\r
11914 * @default <i>blank string - i.e. disabled</i>
\r
11916 * @dtopt Features
\r
11917 * @name DataTable.defaults.scrollY
\r
11920 * $(document).ready( function() {
\r
11921 * $('#example').dataTable( {
\r
11922 * "scrollY": "200px",
\r
11923 * "paginate": false
\r
11931 * __Deprecated__ The functionality provided by this parameter has now been
\r
11932 * superseded by that provided through `ajax`, which should be used instead.
\r
11934 * Set the HTTP method that is used to make the Ajax call for server-side
\r
11935 * processing or Ajax sourced data.
\r
11940 * @dtopt Server-side
\r
11941 * @name DataTable.defaults.serverMethod
\r
11943 * @deprecated 1.10. Please use `ajax` for this functionality now.
\r
11945 "sServerMethod": "GET",
\r
11949 * DataTables makes use of renderers when displaying HTML elements for
\r
11950 * a table. These renderers can be added or modified by plug-ins to
\r
11951 * generate suitable mark-up for a site. For example the Bootstrap
\r
11952 * integration plug-in for DataTables uses a paging button renderer to
\r
11953 * display pagination buttons in the mark-up required by Bootstrap.
\r
11955 * For further information about the renderers available see
\r
11956 * DataTable.ext.renderer
\r
11957 * @type string|object
\r
11960 * @name DataTable.defaults.renderer
\r
11963 "renderer": null,
\r
11967 * Set the data property name that DataTables should use to get a row's id
\r
11968 * to set as the `id` property in the node.
\r
11970 * @default DT_RowId
\r
11972 * @name DataTable.defaults.rowId
\r
11974 "rowId": "DT_RowId"
\r
11977 _fnHungarianMap( DataTable.defaults );
\r
11982 * Developer note - See note in model.defaults.js about the use of Hungarian
\r
11983 * notation and camel case.
\r
11987 * Column options that can be given to DataTables at initialisation time.
\r
11990 DataTable.defaults.column = {
\r
11992 * Define which column(s) an order will occur on for this column. This
\r
11993 * allows a column's ordering to take multiple columns into account when
\r
11994 * doing a sort or use the data from a different column. For example first
\r
11995 * name / last name columns make sense to do a multi-column sort over the
\r
11997 * @type array|int
\r
11998 * @default null <i>Takes the value of the column index automatically</i>
\r
12000 * @name DataTable.defaults.column.orderData
\r
12004 * // Using `columnDefs`
\r
12005 * $(document).ready( function() {
\r
12006 * $('#example').dataTable( {
\r
12007 * "columnDefs": [
\r
12008 * { "orderData": [ 0, 1 ], "targets": [ 0 ] },
\r
12009 * { "orderData": [ 1, 0 ], "targets": [ 1 ] },
\r
12010 * { "orderData": 2, "targets": [ 2 ] }
\r
12016 * // Using `columns`
\r
12017 * $(document).ready( function() {
\r
12018 * $('#example').dataTable( {
\r
12020 * { "orderData": [ 0, 1 ] },
\r
12021 * { "orderData": [ 1, 0 ] },
\r
12022 * { "orderData": 2 },
\r
12029 "aDataSort": null,
\r
12034 * You can control the default ordering direction, and even alter the
\r
12035 * behaviour of the sort handler (i.e. only allow ascending ordering etc)
\r
12036 * using this parameter.
\r
12038 * @default [ 'asc', 'desc' ]
\r
12040 * @name DataTable.defaults.column.orderSequence
\r
12044 * // Using `columnDefs`
\r
12045 * $(document).ready( function() {
\r
12046 * $('#example').dataTable( {
\r
12047 * "columnDefs": [
\r
12048 * { "orderSequence": [ "asc" ], "targets": [ 1 ] },
\r
12049 * { "orderSequence": [ "desc", "asc", "asc" ], "targets": [ 2 ] },
\r
12050 * { "orderSequence": [ "desc" ], "targets": [ 3 ] }
\r
12056 * // Using `columns`
\r
12057 * $(document).ready( function() {
\r
12058 * $('#example').dataTable( {
\r
12061 * { "orderSequence": [ "asc" ] },
\r
12062 * { "orderSequence": [ "desc", "asc", "asc" ] },
\r
12063 * { "orderSequence": [ "desc" ] },
\r
12069 "asSorting": [ 'asc', 'desc' ],
\r
12073 * Enable or disable filtering on the data in this column.
\r
12077 * @name DataTable.defaults.column.searchable
\r
12081 * // Using `columnDefs`
\r
12082 * $(document).ready( function() {
\r
12083 * $('#example').dataTable( {
\r
12084 * "columnDefs": [
\r
12085 * { "searchable": false, "targets": [ 0 ] }
\r
12090 * // Using `columns`
\r
12091 * $(document).ready( function() {
\r
12092 * $('#example').dataTable( {
\r
12094 * { "searchable": false },
\r
12102 "bSearchable": true,
\r
12106 * Enable or disable ordering on this column.
\r
12110 * @name DataTable.defaults.column.orderable
\r
12114 * // Using `columnDefs`
\r
12115 * $(document).ready( function() {
\r
12116 * $('#example').dataTable( {
\r
12117 * "columnDefs": [
\r
12118 * { "orderable": false, "targets": [ 0 ] }
\r
12123 * // Using `columns`
\r
12124 * $(document).ready( function() {
\r
12125 * $('#example').dataTable( {
\r
12127 * { "orderable": false },
\r
12135 "bSortable": true,
\r
12139 * Enable or disable the display of this column.
\r
12143 * @name DataTable.defaults.column.visible
\r
12147 * // Using `columnDefs`
\r
12148 * $(document).ready( function() {
\r
12149 * $('#example').dataTable( {
\r
12150 * "columnDefs": [
\r
12151 * { "visible": false, "targets": [ 0 ] }
\r
12156 * // Using `columns`
\r
12157 * $(document).ready( function() {
\r
12158 * $('#example').dataTable( {
\r
12160 * { "visible": false },
\r
12168 "bVisible": true,
\r
12172 * Developer definable function that is called whenever a cell is created (Ajax source,
\r
12173 * etc) or processed for input (DOM source). This can be used as a compliment to mRender
\r
12174 * allowing you to modify the DOM element (add background colour for example) when the
\r
12175 * element is available.
\r
12177 * @param {element} td The TD node that has been created
\r
12178 * @param {*} cellData The Data for the cell
\r
12179 * @param {array|object} rowData The data for the whole row
\r
12180 * @param {int} row The row index for the aoData data store
\r
12181 * @param {int} col The column index for aoColumns
\r
12183 * @name DataTable.defaults.column.createdCell
\r
12187 * $(document).ready( function() {
\r
12188 * $('#example').dataTable( {
\r
12189 * "columnDefs": [ {
\r
12190 * "targets": [3],
\r
12191 * "createdCell": function (td, cellData, rowData, row, col) {
\r
12192 * if ( cellData == "1.7" ) {
\r
12193 * $(td).css('color', 'blue')
\r
12200 "fnCreatedCell": null,
\r
12204 * This parameter has been replaced by `data` in DataTables to ensure naming
\r
12205 * consistency. `dataProp` can still be used, as there is backwards
\r
12206 * compatibility in DataTables for this option, but it is strongly
\r
12207 * recommended that you use `data` in preference to `dataProp`.
\r
12208 * @name DataTable.defaults.column.dataProp
\r
12213 * This property can be used to read data from any data source property,
\r
12214 * including deeply nested objects / properties. `data` can be given in a
\r
12215 * number of different ways which effect its behaviour:
\r
12217 * * `integer` - treated as an array index for the data source. This is the
\r
12218 * default that DataTables uses (incrementally increased for each column).
\r
12219 * * `string` - read an object property from the data source. There are
\r
12220 * three 'special' options that can be used in the string to alter how
\r
12221 * DataTables reads the data from the source object:
\r
12222 * * `.` - Dotted Javascript notation. Just as you use a `.` in
\r
12223 * Javascript to read from nested objects, so to can the options
\r
12224 * specified in `data`. For example: `browser.version` or
\r
12225 * `browser.name`. If your object parameter name contains a period, use
\r
12226 * `\\` to escape it - i.e. `first\\.name`.
\r
12227 * * `[]` - Array notation. DataTables can automatically combine data
\r
12228 * from and array source, joining the data with the characters provided
\r
12229 * between the two brackets. For example: `name[, ]` would provide a
\r
12230 * comma-space separated list from the source array. If no characters
\r
12231 * are provided between the brackets, the original array source is
\r
12233 * * `()` - Function notation. Adding `()` to the end of a parameter will
\r
12234 * execute a function of the name given. For example: `browser()` for a
\r
12235 * simple function on the data source, `browser.version()` for a
\r
12236 * function in a nested property or even `browser().version` to get an
\r
12237 * object property if the function called returns an object. Note that
\r
12238 * function notation is recommended for use in `render` rather than
\r
12239 * `data` as it is much simpler to use as a renderer.
\r
12240 * * `null` - use the original data source for the row rather than plucking
\r
12241 * data directly from it. This action has effects on two other
\r
12242 * initialisation options:
\r
12243 * * `defaultContent` - When null is given as the `data` option and
\r
12244 * `defaultContent` is specified for the column, the value defined by
\r
12245 * `defaultContent` will be used for the cell.
\r
12246 * * `render` - When null is used for the `data` option and the `render`
\r
12247 * option is specified for the column, the whole data source for the
\r
12248 * row is used for the renderer.
\r
12249 * * `function` - the function given will be executed whenever DataTables
\r
12250 * needs to set or get the data for a cell in the column. The function
\r
12251 * takes three parameters:
\r
12253 * * `{array|object}` The data source for the row
\r
12254 * * `{string}` The type call data requested - this will be 'set' when
\r
12255 * setting data or 'filter', 'display', 'type', 'sort' or undefined
\r
12256 * when gathering data. Note that when `undefined` is given for the
\r
12257 * type DataTables expects to get the raw data for the object back<
\r
12258 * * `{*}` Data to set when the second parameter is 'set'.
\r
12260 * * The return value from the function is not required when 'set' is
\r
12261 * the type of call, but otherwise the return is what will be used
\r
12262 * for the data requested.
\r
12264 * Note that `data` is a getter and setter option. If you just require
\r
12265 * formatting of data for output, you will likely want to use `render` which
\r
12266 * is simply a getter and thus simpler to use.
\r
12268 * Note that prior to DataTables 1.9.2 `data` was called `mDataProp`. The
\r
12269 * name change reflects the flexibility of this property and is consistent
\r
12270 * with the naming of mRender. If 'mDataProp' is given, then it will still
\r
12271 * be used by DataTables, as it automatically maps the old name to the new
\r
12274 * @type string|int|function|null
\r
12275 * @default null <i>Use automatically calculated column index</i>
\r
12277 * @name DataTable.defaults.column.data
\r
12281 * // Read table data from objects
\r
12282 * // JSON structure for each row:
\r
12284 * // "engine": {value},
\r
12285 * // "browser": {value},
\r
12286 * // "platform": {value},
\r
12287 * // "version": {value},
\r
12288 * // "grade": {value}
\r
12290 * $(document).ready( function() {
\r
12291 * $('#example').dataTable( {
\r
12292 * "ajaxSource": "sources/objects.txt",
\r
12294 * { "data": "engine" },
\r
12295 * { "data": "browser" },
\r
12296 * { "data": "platform" },
\r
12297 * { "data": "version" },
\r
12298 * { "data": "grade" }
\r
12304 * // Read information from deeply nested objects
\r
12305 * // JSON structure for each row:
\r
12307 * // "engine": {value},
\r
12308 * // "browser": {value},
\r
12309 * // "platform": {
\r
12310 * // "inner": {value}
\r
12312 * // "details": [
\r
12313 * // {value}, {value}
\r
12316 * $(document).ready( function() {
\r
12317 * $('#example').dataTable( {
\r
12318 * "ajaxSource": "sources/deep.txt",
\r
12320 * { "data": "engine" },
\r
12321 * { "data": "browser" },
\r
12322 * { "data": "platform.inner" },
\r
12323 * { "data": "platform.details.0" },
\r
12324 * { "data": "platform.details.1" }
\r
12330 * // Using `data` as a function to provide different information for
\r
12331 * // sorting, filtering and display. In this case, currency (price)
\r
12332 * $(document).ready( function() {
\r
12333 * $('#example').dataTable( {
\r
12334 * "columnDefs": [ {
\r
12335 * "targets": [ 0 ],
\r
12336 * "data": function ( source, type, val ) {
\r
12337 * if (type === 'set') {
\r
12338 * source.price = val;
\r
12339 * // Store the computed dislay and filter values for efficiency
\r
12340 * source.price_display = val=="" ? "" : "$"+numberFormat(val);
\r
12341 * source.price_filter = val=="" ? "" : "$"+numberFormat(val)+" "+val;
\r
12344 * else if (type === 'display') {
\r
12345 * return source.price_display;
\r
12347 * else if (type === 'filter') {
\r
12348 * return source.price_filter;
\r
12350 * // 'sort', 'type' and undefined all just use the integer
\r
12351 * return source.price;
\r
12358 * // Using default content
\r
12359 * $(document).ready( function() {
\r
12360 * $('#example').dataTable( {
\r
12361 * "columnDefs": [ {
\r
12362 * "targets": [ 0 ],
\r
12364 * "defaultContent": "Click to edit"
\r
12370 * // Using array notation - outputting a list from an array
\r
12371 * $(document).ready( function() {
\r
12372 * $('#example').dataTable( {
\r
12373 * "columnDefs": [ {
\r
12374 * "targets": [ 0 ],
\r
12375 * "data": "name[, ]"
\r
12385 * This property is the rendering partner to `data` and it is suggested that
\r
12386 * when you want to manipulate data for display (including filtering,
\r
12387 * sorting etc) without altering the underlying data for the table, use this
\r
12388 * property. `render` can be considered to be the the read only companion to
\r
12389 * `data` which is read / write (then as such more complex). Like `data`
\r
12390 * this option can be given in a number of different ways to effect its
\r
12393 * * `integer` - treated as an array index for the data source. This is the
\r
12394 * default that DataTables uses (incrementally increased for each column).
\r
12395 * * `string` - read an object property from the data source. There are
\r
12396 * three 'special' options that can be used in the string to alter how
\r
12397 * DataTables reads the data from the source object:
\r
12398 * * `.` - Dotted Javascript notation. Just as you use a `.` in
\r
12399 * Javascript to read from nested objects, so to can the options
\r
12400 * specified in `data`. For example: `browser.version` or
\r
12401 * `browser.name`. If your object parameter name contains a period, use
\r
12402 * `\\` to escape it - i.e. `first\\.name`.
\r
12403 * * `[]` - Array notation. DataTables can automatically combine data
\r
12404 * from and array source, joining the data with the characters provided
\r
12405 * between the two brackets. For example: `name[, ]` would provide a
\r
12406 * comma-space separated list from the source array. If no characters
\r
12407 * are provided between the brackets, the original array source is
\r
12409 * * `()` - Function notation. Adding `()` to the end of a parameter will
\r
12410 * execute a function of the name given. For example: `browser()` for a
\r
12411 * simple function on the data source, `browser.version()` for a
\r
12412 * function in a nested property or even `browser().version` to get an
\r
12413 * object property if the function called returns an object.
\r
12414 * * `object` - use different data for the different data types requested by
\r
12415 * DataTables ('filter', 'display', 'type' or 'sort'). The property names
\r
12416 * of the object is the data type the property refers to and the value can
\r
12417 * defined using an integer, string or function using the same rules as
\r
12418 * `render` normally does. Note that an `_` option _must_ be specified.
\r
12419 * This is the default value to use if you haven't specified a value for
\r
12420 * the data type requested by DataTables.
\r
12421 * * `function` - the function given will be executed whenever DataTables
\r
12422 * needs to set or get the data for a cell in the column. The function
\r
12423 * takes three parameters:
\r
12425 * * {array|object} The data source for the row (based on `data`)
\r
12426 * * {string} The type call data requested - this will be 'filter',
\r
12427 * 'display', 'type' or 'sort'.
\r
12428 * * {array|object} The full data source for the row (not based on
\r
12431 * * The return value from the function is what will be used for the
\r
12432 * data requested.
\r
12434 * @type string|int|function|object|null
\r
12435 * @default null Use the data source value.
\r
12437 * @name DataTable.defaults.column.render
\r
12441 * // Create a comma separated list from an array of objects
\r
12442 * $(document).ready( function() {
\r
12443 * $('#example').dataTable( {
\r
12444 * "ajaxSource": "sources/deep.txt",
\r
12446 * { "data": "engine" },
\r
12447 * { "data": "browser" },
\r
12449 * "data": "platform",
\r
12450 * "render": "[, ].name"
\r
12457 * // Execute a function to obtain data
\r
12458 * $(document).ready( function() {
\r
12459 * $('#example').dataTable( {
\r
12460 * "columnDefs": [ {
\r
12461 * "targets": [ 0 ],
\r
12462 * "data": null, // Use the full data source object for the renderer's source
\r
12463 * "render": "browserName()"
\r
12469 * // As an object, extracting different data for the different types
\r
12470 * // This would be used with a data source such as:
\r
12471 * // { "phone": 5552368, "phone_filter": "5552368 555-2368", "phone_display": "555-2368" }
\r
12472 * // Here the `phone` integer is used for sorting and type detection, while `phone_filter`
\r
12473 * // (which has both forms) is used for filtering for if a user inputs either format, while
\r
12474 * // the formatted phone number is the one that is shown in the table.
\r
12475 * $(document).ready( function() {
\r
12476 * $('#example').dataTable( {
\r
12477 * "columnDefs": [ {
\r
12478 * "targets": [ 0 ],
\r
12479 * "data": null, // Use the full data source object for the renderer's source
\r
12482 * "filter": "phone_filter",
\r
12483 * "display": "phone_display"
\r
12490 * // Use as a function to create a link from the data source
\r
12491 * $(document).ready( function() {
\r
12492 * $('#example').dataTable( {
\r
12493 * "columnDefs": [ {
\r
12494 * "targets": [ 0 ],
\r
12495 * "data": "download_link",
\r
12496 * "render": function ( data, type, full ) {
\r
12497 * return '<a href="'+data+'">Download</a>';
\r
12507 * Change the cell type created for the column - either TD cells or TH cells. This
\r
12508 * can be useful as TH cells have semantic meaning in the table body, allowing them
\r
12509 * to act as a header for a row (you may wish to add scope='row' to the TH elements).
\r
12513 * @name DataTable.defaults.column.cellType
\r
12517 * // Make the first column use TH cells
\r
12518 * $(document).ready( function() {
\r
12519 * $('#example').dataTable( {
\r
12520 * "columnDefs": [ {
\r
12521 * "targets": [ 0 ],
\r
12522 * "cellType": "th"
\r
12527 "sCellType": "td",
\r
12531 * Class to give to each cell in this column.
\r
12533 * @default <i>Empty string</i>
\r
12535 * @name DataTable.defaults.column.class
\r
12539 * // Using `columnDefs`
\r
12540 * $(document).ready( function() {
\r
12541 * $('#example').dataTable( {
\r
12542 * "columnDefs": [
\r
12543 * { "class": "my_class", "targets": [ 0 ] }
\r
12549 * // Using `columns`
\r
12550 * $(document).ready( function() {
\r
12551 * $('#example').dataTable( {
\r
12553 * { "class": "my_class" },
\r
12565 * When DataTables calculates the column widths to assign to each column,
\r
12566 * it finds the longest string in each column and then constructs a
\r
12567 * temporary table and reads the widths from that. The problem with this
\r
12568 * is that "mmm" is much wider then "iiii", but the latter is a longer
\r
12569 * string - thus the calculation can go wrong (doing it properly and putting
\r
12570 * it into an DOM object and measuring that is horribly(!) slow). Thus as
\r
12571 * a "work around" we provide this option. It will append its value to the
\r
12572 * text that is found to be the longest string for the column - i.e. padding.
\r
12573 * Generally you shouldn't need this!
\r
12575 * @default <i>Empty string<i>
\r
12577 * @name DataTable.defaults.column.contentPadding
\r
12581 * // Using `columns`
\r
12582 * $(document).ready( function() {
\r
12583 * $('#example').dataTable( {
\r
12589 * "contentPadding": "mmm"
\r
12595 "sContentPadding": "",
\r
12599 * Allows a default value to be given for a column's data, and will be used
\r
12600 * whenever a null data source is encountered (this can be because `data`
\r
12601 * is set to null, or because the data source itself is null).
\r
12605 * @name DataTable.defaults.column.defaultContent
\r
12609 * // Using `columnDefs`
\r
12610 * $(document).ready( function() {
\r
12611 * $('#example').dataTable( {
\r
12612 * "columnDefs": [
\r
12615 * "defaultContent": "Edit",
\r
12616 * "targets": [ -1 ]
\r
12623 * // Using `columns`
\r
12624 * $(document).ready( function() {
\r
12625 * $('#example').dataTable( {
\r
12632 * "defaultContent": "Edit"
\r
12638 "sDefaultContent": null,
\r
12642 * This parameter is only used in DataTables' server-side processing. It can
\r
12643 * be exceptionally useful to know what columns are being displayed on the
\r
12644 * client side, and to map these to database fields. When defined, the names
\r
12645 * also allow DataTables to reorder information from the server if it comes
\r
12646 * back in an unexpected order (i.e. if you switch your columns around on the
\r
12647 * client-side, your server-side code does not also need updating).
\r
12649 * @default <i>Empty string</i>
\r
12651 * @name DataTable.defaults.column.name
\r
12655 * // Using `columnDefs`
\r
12656 * $(document).ready( function() {
\r
12657 * $('#example').dataTable( {
\r
12658 * "columnDefs": [
\r
12659 * { "name": "engine", "targets": [ 0 ] },
\r
12660 * { "name": "browser", "targets": [ 1 ] },
\r
12661 * { "name": "platform", "targets": [ 2 ] },
\r
12662 * { "name": "version", "targets": [ 3 ] },
\r
12663 * { "name": "grade", "targets": [ 4 ] }
\r
12669 * // Using `columns`
\r
12670 * $(document).ready( function() {
\r
12671 * $('#example').dataTable( {
\r
12673 * { "name": "engine" },
\r
12674 * { "name": "browser" },
\r
12675 * { "name": "platform" },
\r
12676 * { "name": "version" },
\r
12677 * { "name": "grade" }
\r
12686 * Defines a data source type for the ordering which can be used to read
\r
12687 * real-time information from the table (updating the internally cached
\r
12688 * version) prior to ordering. This allows ordering to occur on user
\r
12689 * editable elements such as form inputs.
\r
12693 * @name DataTable.defaults.column.orderDataType
\r
12697 * // Using `columnDefs`
\r
12698 * $(document).ready( function() {
\r
12699 * $('#example').dataTable( {
\r
12700 * "columnDefs": [
\r
12701 * { "orderDataType": "dom-text", "targets": [ 2, 3 ] },
\r
12702 * { "type": "numeric", "targets": [ 3 ] },
\r
12703 * { "orderDataType": "dom-select", "targets": [ 4 ] },
\r
12704 * { "orderDataType": "dom-checkbox", "targets": [ 5 ] }
\r
12710 * // Using `columns`
\r
12711 * $(document).ready( function() {
\r
12712 * $('#example').dataTable( {
\r
12716 * { "orderDataType": "dom-text" },
\r
12717 * { "orderDataType": "dom-text", "type": "numeric" },
\r
12718 * { "orderDataType": "dom-select" },
\r
12719 * { "orderDataType": "dom-checkbox" }
\r
12724 "sSortDataType": "std",
\r
12728 * The title of this column.
\r
12730 * @default null <i>Derived from the 'TH' value for this column in the
\r
12731 * original HTML table.</i>
\r
12733 * @name DataTable.defaults.column.title
\r
12737 * // Using `columnDefs`
\r
12738 * $(document).ready( function() {
\r
12739 * $('#example').dataTable( {
\r
12740 * "columnDefs": [
\r
12741 * { "title": "My column title", "targets": [ 0 ] }
\r
12747 * // Using `columns`
\r
12748 * $(document).ready( function() {
\r
12749 * $('#example').dataTable( {
\r
12751 * { "title": "My column title" },
\r
12764 * The type allows you to specify how the data for this column will be
\r
12765 * ordered. Four types (string, numeric, date and html (which will strip
\r
12766 * HTML tags before ordering)) are currently available. Note that only date
\r
12767 * formats understood by Javascript's Date() object will be accepted as type
\r
12768 * date. For example: "Mar 26, 2008 5:03 PM". May take the values: 'string',
\r
12769 * 'numeric', 'date' or 'html' (by default). Further types can be adding
\r
12770 * through plug-ins.
\r
12772 * @default null <i>Auto-detected from raw data</i>
\r
12774 * @name DataTable.defaults.column.type
\r
12778 * // Using `columnDefs`
\r
12779 * $(document).ready( function() {
\r
12780 * $('#example').dataTable( {
\r
12781 * "columnDefs": [
\r
12782 * { "type": "html", "targets": [ 0 ] }
\r
12788 * // Using `columns`
\r
12789 * $(document).ready( function() {
\r
12790 * $('#example').dataTable( {
\r
12792 * { "type": "html" },
\r
12805 * Defining the width of the column, this parameter may take any CSS value
\r
12806 * (3em, 20px etc). DataTables applies 'smart' widths to columns which have not
\r
12807 * been given a specific width through this interface ensuring that the table
\r
12808 * remains readable.
\r
12810 * @default null <i>Automatic</i>
\r
12812 * @name DataTable.defaults.column.width
\r
12816 * // Using `columnDefs`
\r
12817 * $(document).ready( function() {
\r
12818 * $('#example').dataTable( {
\r
12819 * "columnDefs": [
\r
12820 * { "width": "20%", "targets": [ 0 ] }
\r
12826 * // Using `columns`
\r
12827 * $(document).ready( function() {
\r
12828 * $('#example').dataTable( {
\r
12830 * { "width": "20%" },
\r
12842 _fnHungarianMap( DataTable.defaults.column );
\r
12847 * DataTables settings object - this holds all the information needed for a
\r
12848 * given table, including configuration, data and current application of the
\r
12849 * table options. DataTables does not have a single instance for each DataTable
\r
12850 * with the settings attached to that instance, but rather instances of the
\r
12851 * DataTable "class" are created on-the-fly as needed (typically by a
\r
12852 * $().dataTable() call) and the settings object is then applied to that
\r
12855 * Note that this object is related to {@link DataTable.defaults} but this
\r
12856 * one is the internal data store for DataTables's cache of columns. It should
\r
12857 * NOT be manipulated outside of DataTables. Any configuration should be done
\r
12858 * through the initialisation options.
\r
12860 * @todo Really should attach the settings object to individual instances so we
\r
12861 * don't need to create new instances on each $().dataTable() call (if the
\r
12862 * table already exists). It would also save passing oSettings around and
\r
12863 * into every single function. However, this is a very significant
\r
12864 * architecture change for DataTables and will almost certainly break
\r
12865 * backwards compatibility with older installations. This is something that
\r
12866 * will be done in 2.0.
\r
12868 DataTable.models.oSettings = {
\r
12870 * Primary features of DataTables and their enablement state.
\r
12876 * Flag to say if DataTables should automatically try to calculate the
\r
12877 * optimum table and columns widths (true) or not (false).
\r
12878 * Note that this parameter will be set by the initialisation routine. To
\r
12879 * set a default use {@link DataTable.defaults}.
\r
12882 "bAutoWidth": null,
\r
12885 * Delay the creation of TR and TD elements until they are actually
\r
12886 * needed by a driven page draw. This can give a significant speed
\r
12887 * increase for Ajax source and Javascript source data, but makes no
\r
12888 * difference at all fro DOM and server-side processing tables.
\r
12889 * Note that this parameter will be set by the initialisation routine. To
\r
12890 * set a default use {@link DataTable.defaults}.
\r
12893 "bDeferRender": null,
\r
12896 * Enable filtering on the table or not. Note that if this is disabled
\r
12897 * then there is no filtering at all on the table, including fnFilter.
\r
12898 * To just remove the filtering input use sDom and remove the 'f' option.
\r
12899 * Note that this parameter will be set by the initialisation routine. To
\r
12900 * set a default use {@link DataTable.defaults}.
\r
12906 * Table information element (the 'Showing x of y records' div) enable
\r
12908 * Note that this parameter will be set by the initialisation routine. To
\r
12909 * set a default use {@link DataTable.defaults}.
\r
12915 * Present a user control allowing the end user to change the page size
\r
12916 * when pagination is enabled.
\r
12917 * Note that this parameter will be set by the initialisation routine. To
\r
12918 * set a default use {@link DataTable.defaults}.
\r
12921 "bLengthChange": null,
\r
12924 * Pagination enabled or not. Note that if this is disabled then length
\r
12925 * changing must also be disabled.
\r
12926 * Note that this parameter will be set by the initialisation routine. To
\r
12927 * set a default use {@link DataTable.defaults}.
\r
12930 "bPaginate": null,
\r
12933 * Processing indicator enable flag whenever DataTables is enacting a
\r
12934 * user request - typically an Ajax request for server-side processing.
\r
12935 * Note that this parameter will be set by the initialisation routine. To
\r
12936 * set a default use {@link DataTable.defaults}.
\r
12939 "bProcessing": null,
\r
12942 * Server-side processing enabled flag - when enabled DataTables will
\r
12943 * get all data from the server for every draw - there is no filtering,
\r
12944 * sorting or paging done on the client-side.
\r
12945 * Note that this parameter will be set by the initialisation routine. To
\r
12946 * set a default use {@link DataTable.defaults}.
\r
12949 "bServerSide": null,
\r
12952 * Sorting enablement flag.
\r
12953 * Note that this parameter will be set by the initialisation routine. To
\r
12954 * set a default use {@link DataTable.defaults}.
\r
12960 * Multi-column sorting
\r
12961 * Note that this parameter will be set by the initialisation routine. To
\r
12962 * set a default use {@link DataTable.defaults}.
\r
12965 "bSortMulti": null,
\r
12968 * Apply a class to the columns which are being sorted to provide a
\r
12969 * visual highlight or not. This can slow things down when enabled since
\r
12970 * there is a lot of DOM interaction.
\r
12971 * Note that this parameter will be set by the initialisation routine. To
\r
12972 * set a default use {@link DataTable.defaults}.
\r
12975 "bSortClasses": null,
\r
12978 * State saving enablement flag.
\r
12979 * Note that this parameter will be set by the initialisation routine. To
\r
12980 * set a default use {@link DataTable.defaults}.
\r
12983 "bStateSave": null
\r
12988 * Scrolling settings for a table.
\r
12993 * When the table is shorter in height than sScrollY, collapse the
\r
12994 * table container down to the height of the table (when true).
\r
12995 * Note that this parameter will be set by the initialisation routine. To
\r
12996 * set a default use {@link DataTable.defaults}.
\r
12999 "bCollapse": null,
\r
13002 * Width of the scrollbar for the web-browser's platform. Calculated
\r
13003 * during table initialisation.
\r
13010 * Viewport width for horizontal scrolling. Horizontal scrolling is
\r
13011 * disabled if an empty string.
\r
13012 * Note that this parameter will be set by the initialisation routine. To
\r
13013 * set a default use {@link DataTable.defaults}.
\r
13019 * Width to expand the table to when using x-scrolling. Typically you
\r
13020 * should not need to use this.
\r
13021 * Note that this parameter will be set by the initialisation routine. To
\r
13022 * set a default use {@link DataTable.defaults}.
\r
13029 * Viewport height for vertical scrolling. Vertical scrolling is disabled
\r
13030 * if an empty string.
\r
13031 * Note that this parameter will be set by the initialisation routine. To
\r
13032 * set a default use {@link DataTable.defaults}.
\r
13039 * Language information for the table.
\r
13041 * @extends DataTable.defaults.oLanguage
\r
13045 * Information callback function. See
\r
13046 * {@link DataTable.defaults.fnInfoCallback}
\r
13050 "fnInfoCallback": null
\r
13054 * Browser support parameters
\r
13059 * Indicate if the browser incorrectly calculates width:100% inside a
\r
13060 * scrolling element (IE6/7)
\r
13064 "bScrollOversize": false,
\r
13067 * Determine if the vertical scrollbar is on the right or left of the
\r
13068 * scrolling container - needed for rtl language layout, although not
\r
13069 * all browsers move the scrollbar (Safari).
\r
13073 "bScrollbarLeft": false,
\r
13076 * Flag for if `getBoundingClientRect` is fully supported or not
\r
13080 "bBounding": false,
\r
13083 * Browser scrollbar width
\r
13095 * Array referencing the nodes which are used for the features. The
\r
13096 * parameters of this object match what is allowed by sDom - i.e.
\r
13098 * <li>'l' - Length changing</li>
\r
13099 * <li>'f' - Filtering input</li>
\r
13100 * <li>'t' - The table!</li>
\r
13101 * <li>'i' - Information</li>
\r
13102 * <li>'p' - Pagination</li>
\r
13103 * <li>'r' - pRocessing</li>
\r
13108 "aanFeatures": [],
\r
13111 * Store data information - see {@link DataTable.models.oRow} for detailed
\r
13119 * Array of indexes which are in the current display (after filtering etc)
\r
13126 * Array of indexes for display - no filtering
\r
13130 "aiDisplayMaster": [],
\r
13133 * Map of row ids to data indexes
\r
13140 * Store information about each column that is in use
\r
13147 * Store information about the table's header
\r
13154 * Store information about the table's footer
\r
13161 * Store the applied global search information in case we want to force a
\r
13162 * research or compare the old search to a new one.
\r
13163 * Note that this parameter will be set by the initialisation routine. To
\r
13164 * set a default use {@link DataTable.defaults}.
\r
13166 * @extends DataTable.models.oSearch
\r
13168 "oPreviousSearch": {},
\r
13171 * Store the applied search for each column - see
\r
13172 * {@link DataTable.models.oSearch} for the format that is used for the
\r
13173 * filtering information for each column.
\r
13177 "aoPreSearchCols": [],
\r
13180 * Sorting that is applied to the table. Note that the inner arrays are
\r
13181 * used in the following manner:
\r
13183 * <li>Index 0 - column number</li>
\r
13184 * <li>Index 1 - current sorting direction</li>
\r
13186 * Note that this parameter will be set by the initialisation routine. To
\r
13187 * set a default use {@link DataTable.defaults}.
\r
13189 * @todo These inner arrays should really be objects
\r
13191 "aaSorting": null,
\r
13194 * Sorting that is always applied to the table (i.e. prefixed in front of
\r
13196 * Note that this parameter will be set by the initialisation routine. To
\r
13197 * set a default use {@link DataTable.defaults}.
\r
13201 "aaSortingFixed": [],
\r
13204 * Classes to use for the striping of a table.
\r
13205 * Note that this parameter will be set by the initialisation routine. To
\r
13206 * set a default use {@link DataTable.defaults}.
\r
13210 "asStripeClasses": null,
\r
13213 * If restoring a table - we should restore its striping classes as well
\r
13217 "asDestroyStripes": [],
\r
13220 * If restoring a table - we should restore its width
\r
13224 "sDestroyWidth": 0,
\r
13227 * Callback functions array for every time a row is inserted (i.e. on a draw).
\r
13231 "aoRowCallback": [],
\r
13234 * Callback functions for the header on each draw.
\r
13238 "aoHeaderCallback": [],
\r
13241 * Callback function for the footer on each draw.
\r
13245 "aoFooterCallback": [],
\r
13248 * Array of callback functions for draw callback functions
\r
13252 "aoDrawCallback": [],
\r
13255 * Array of callback functions for row created function
\r
13259 "aoRowCreatedCallback": [],
\r
13262 * Callback functions for just before the table is redrawn. A return of
\r
13263 * false will be used to cancel the draw.
\r
13267 "aoPreDrawCallback": [],
\r
13270 * Callback functions for when the table has been initialised.
\r
13274 "aoInitComplete": [],
\r
13278 * Callbacks for modifying the settings to be stored for state saving, prior to
\r
13283 "aoStateSaveParams": [],
\r
13286 * Callbacks for modifying the settings that have been stored for state saving
\r
13287 * prior to using the stored values to restore the state.
\r
13291 "aoStateLoadParams": [],
\r
13294 * Callbacks for operating on the settings object once the saved state has been
\r
13299 "aoStateLoaded": [],
\r
13302 * Cache the table ID for quick access
\r
13304 * @default <i>Empty string</i>
\r
13309 * The TABLE node for the main table
\r
13316 * Permanent ref to the thead element
\r
13323 * Permanent ref to the tfoot element - if it exists
\r
13330 * Permanent ref to the tbody element
\r
13337 * Cache the wrapper node (contains all DataTables controlled elements)
\r
13341 "nTableWrapper": null,
\r
13344 * Indicate if when using server-side processing the loading of data
\r
13345 * should be deferred until the second draw.
\r
13346 * Note that this parameter will be set by the initialisation routine. To
\r
13347 * set a default use {@link DataTable.defaults}.
\r
13351 "bDeferLoading": false,
\r
13354 * Indicate if all required information has been read in
\r
13358 "bInitialised": false,
\r
13361 * Information about open rows. Each object in the array has the parameters
\r
13362 * 'nTr' and 'nParent'
\r
13366 "aoOpenRows": [],
\r
13369 * Dictate the positioning of DataTables' control elements - see
\r
13370 * {@link DataTable.model.oInit.sDom}.
\r
13371 * Note that this parameter will be set by the initialisation routine. To
\r
13372 * set a default use {@link DataTable.defaults}.
\r
13379 * Search delay (in mS)
\r
13383 "searchDelay": null,
\r
13386 * Which type of pagination should be used.
\r
13387 * Note that this parameter will be set by the initialisation routine. To
\r
13388 * set a default use {@link DataTable.defaults}.
\r
13390 * @default two_button
\r
13392 "sPaginationType": "two_button",
\r
13395 * The state duration (for `stateSave`) in seconds.
\r
13396 * Note that this parameter will be set by the initialisation routine. To
\r
13397 * set a default use {@link DataTable.defaults}.
\r
13401 "iStateDuration": 0,
\r
13404 * Array of callback functions for state saving. Each array element is an
\r
13405 * object with the following parameters:
\r
13407 * <li>function:fn - function to call. Takes two parameters, oSettings
\r
13408 * and the JSON string to save that has been thus far created. Returns
\r
13409 * a JSON string to be inserted into a json object
\r
13410 * (i.e. '"param": [ 0, 1, 2]')</li>
\r
13411 * <li>string:sName - name of callback</li>
\r
13416 "aoStateSave": [],
\r
13419 * Array of callback functions for state loading. Each array element is an
\r
13420 * object with the following parameters:
\r
13422 * <li>function:fn - function to call. Takes two parameters, oSettings
\r
13423 * and the object stored. May return false to cancel state loading</li>
\r
13424 * <li>string:sName - name of callback</li>
\r
13429 "aoStateLoad": [],
\r
13432 * State that was saved. Useful for back reference
\r
13436 "oSavedState": null,
\r
13439 * State that was loaded. Useful for back reference
\r
13443 "oLoadedState": null,
\r
13446 * Source url for AJAX data for the table.
\r
13447 * Note that this parameter will be set by the initialisation routine. To
\r
13448 * set a default use {@link DataTable.defaults}.
\r
13452 "sAjaxSource": null,
\r
13455 * Property from a given object from which to read the table data from. This
\r
13456 * can be an empty string (when not server-side processing), in which case
\r
13457 * it is assumed an an array is given directly.
\r
13458 * Note that this parameter will be set by the initialisation routine. To
\r
13459 * set a default use {@link DataTable.defaults}.
\r
13462 "sAjaxDataProp": null,
\r
13465 * Note if draw should be blocked while getting data
\r
13469 "bAjaxDataGet": true,
\r
13472 * The last jQuery XHR object that was used for server-side data gathering.
\r
13473 * This can be used for working with the XHR information in one of the
\r
13481 * JSON returned from the server in the last Ajax request
\r
13483 * @default undefined
\r
13485 "json": undefined,
\r
13488 * Data submitted as part of the last Ajax request
\r
13490 * @default undefined
\r
13492 "oAjaxData": undefined,
\r
13495 * Function to get the server-side data.
\r
13496 * Note that this parameter will be set by the initialisation routine. To
\r
13497 * set a default use {@link DataTable.defaults}.
\r
13500 "fnServerData": null,
\r
13503 * Functions which are called prior to sending an Ajax request so extra
\r
13504 * parameters can easily be sent to the server
\r
13508 "aoServerParams": [],
\r
13511 * Send the XHR HTTP method - GET or POST (could be PUT or DELETE if
\r
13513 * Note that this parameter will be set by the initialisation routine. To
\r
13514 * set a default use {@link DataTable.defaults}.
\r
13517 "sServerMethod": null,
\r
13520 * Format numbers for display.
\r
13521 * Note that this parameter will be set by the initialisation routine. To
\r
13522 * set a default use {@link DataTable.defaults}.
\r
13525 "fnFormatNumber": null,
\r
13528 * List of options that can be used for the user selectable length menu.
\r
13529 * Note that this parameter will be set by the initialisation routine. To
\r
13530 * set a default use {@link DataTable.defaults}.
\r
13534 "aLengthMenu": null,
\r
13537 * Counter for the draws that the table does. Also used as a tracker for
\r
13538 * server-side processing
\r
13545 * Indicate if a redraw is being done - useful for Ajax
\r
13549 "bDrawing": false,
\r
13552 * Draw index (iDraw) of the last error when parsing the returned data
\r
13556 "iDrawError": -1,
\r
13559 * Paging display length
\r
13563 "_iDisplayLength": 10,
\r
13566 * Paging start point - aiDisplay index
\r
13570 "_iDisplayStart": 0,
\r
13573 * Server-side processing - number of records in the result set
\r
13574 * (i.e. before filtering), Use fnRecordsTotal rather than
\r
13575 * this property to get the value of the number of records, regardless of
\r
13576 * the server-side processing setting.
\r
13581 "_iRecordsTotal": 0,
\r
13584 * Server-side processing - number of records in the current display set
\r
13585 * (i.e. after filtering). Use fnRecordsDisplay rather than
\r
13586 * this property to get the value of the number of records, regardless of
\r
13587 * the server-side processing setting.
\r
13592 "_iRecordsDisplay": 0,
\r
13595 * Flag to indicate if jQuery UI marking and classes should be used.
\r
13596 * Note that this parameter will be set by the initialisation routine. To
\r
13597 * set a default use {@link DataTable.defaults}.
\r
13603 * The classes to use for the table
\r
13610 * Flag attached to the settings object so you can check in the draw
\r
13611 * callback if filtering has been done in the draw. Deprecated in favour of
\r
13617 "bFiltered": false,
\r
13620 * Flag attached to the settings object so you can check in the draw
\r
13621 * callback if sorting has been done in the draw. Deprecated in favour of
\r
13627 "bSorted": false,
\r
13630 * Indicate that if multiple rows are in the header and there is more than
\r
13631 * one unique cell per column, if the top one (true) or bottom one (false)
\r
13632 * should be used for sorting / title by DataTables.
\r
13633 * Note that this parameter will be set by the initialisation routine. To
\r
13634 * set a default use {@link DataTable.defaults}.
\r
13637 "bSortCellsTop": null,
\r
13640 * Initialisation object that is used for the table
\r
13647 * Destroy callback functions - for plug-ins to attach themselves to the
\r
13648 * destroy so they can clean up markup and events.
\r
13652 "aoDestroyCallback": [],
\r
13656 * Get the number of records in the current record set, before filtering
\r
13659 "fnRecordsTotal": function ()
\r
13661 return _fnDataSource( this ) == 'ssp' ?
\r
13662 this._iRecordsTotal * 1 :
\r
13663 this.aiDisplayMaster.length;
\r
13667 * Get the number of records in the current record set, after filtering
\r
13670 "fnRecordsDisplay": function ()
\r
13672 return _fnDataSource( this ) == 'ssp' ?
\r
13673 this._iRecordsDisplay * 1 :
\r
13674 this.aiDisplay.length;
\r
13678 * Get the display end point - aiDisplay index
\r
13681 "fnDisplayEnd": function ()
\r
13684 len = this._iDisplayLength,
\r
13685 start = this._iDisplayStart,
\r
13686 calc = start + len,
\r
13687 records = this.aiDisplay.length,
\r
13688 features = this.oFeatures,
\r
13689 paginate = features.bPaginate;
\r
13691 if ( features.bServerSide ) {
\r
13692 return paginate === false || len === -1 ?
\r
13693 start + records :
\r
13694 Math.min( start+len, this._iRecordsDisplay );
\r
13697 return ! paginate || calc>records || len===-1 ?
\r
13704 * The DataTables object for this table
\r
13708 "oInstance": null,
\r
13711 * Unique identifier for each instance of the DataTables object. If there
\r
13712 * is an ID on the table node, then it takes that value, otherwise an
\r
13713 * incrementing internal counter is used.
\r
13717 "sInstance": null,
\r
13720 * tabindex attribute value that is added to DataTables control elements, allowing
\r
13721 * keyboard navigation of the table and its controls.
\r
13726 * DIV container for the footer scrolling table if scrolling
\r
13728 "nScrollHead": null,
\r
13731 * DIV container for the footer scrolling table if scrolling
\r
13733 "nScrollFoot": null,
\r
13736 * Last applied sort
\r
13743 * Stored plug-in instances
\r
13750 * Function used to get a row's id from the row's data
\r
13757 * Data location where to store a row's id
\r
13765 * Extension object for DataTables that is used to provide all extension
\r
13768 * Note that the `DataTable.ext` object is available through
\r
13769 * `jQuery.fn.dataTable.ext` where it may be accessed and manipulated. It is
\r
13770 * also aliased to `jQuery.fn.dataTableExt` for historic reasons.
\r
13772 * @extends DataTable.models.ext
\r
13777 * DataTables extensions
\r
13779 * This namespace acts as a collection area for plug-ins that can be used to
\r
13780 * extend DataTables capabilities. Indeed many of the build in methods
\r
13781 * use this method to provide their own capabilities (sorting methods for
\r
13784 * Note that this namespace is aliased to `jQuery.fn.dataTableExt` for legacy
\r
13789 DataTable.ext = _ext = {
\r
13791 * Buttons. For use with the Buttons extension for DataTables. This is
\r
13792 * defined here so other extensions can define buttons regardless of load
\r
13793 * order. It is _not_ used by DataTables core.
\r
13802 * Element class names
\r
13811 * DataTables build type (expanded by the download builder)
\r
13815 builder: "-source-",
\r
13819 * Error reporting.
\r
13821 * How should DataTables report an error. Can take the value 'alert',
\r
13822 * 'throw', 'none' or a function.
\r
13824 * @type string|function
\r
13827 errMode: "alert",
\r
13831 * Feature plug-ins.
\r
13833 * This is an array of objects which describe the feature plug-ins that are
\r
13834 * available to DataTables. These feature plug-ins are then available for
\r
13835 * use through the `dom` initialisation option.
\r
13837 * Each feature plug-in is described by an object which must have the
\r
13838 * following properties:
\r
13840 * * `fnInit` - function that is used to initialise the plug-in,
\r
13841 * * `cFeature` - a character so the feature can be enabled by the `dom`
\r
13842 * instillation option. This is case sensitive.
\r
13844 * The `fnInit` function has the following input parameters:
\r
13846 * 1. `{object}` DataTables settings object: see
\r
13847 * {@link DataTable.models.oSettings}
\r
13849 * And the following return is expected:
\r
13851 * * {node|null} The element which contains your feature. Note that the
\r
13852 * return may also be void if your plug-in does not require to inject any
\r
13853 * DOM elements into DataTables control (`dom`) - for example this might
\r
13854 * be useful when developing a plug-in which allows table control via
\r
13860 * $.fn.dataTable.ext.features.push( {
\r
13861 * "fnInit": function( oSettings ) {
\r
13862 * return new TableTools( { "oDTSettings": oSettings } );
\r
13864 * "cFeature": "T"
\r
13873 * This method of searching is complimentary to the default type based
\r
13874 * searching, and a lot more comprehensive as it allows you complete control
\r
13875 * over the searching logic. Each element in this array is a function
\r
13876 * (parameters described below) that is called for every row in the table,
\r
13877 * and your logic decides if it should be included in the searching data set
\r
13880 * Searching functions have the following input parameters:
\r
13882 * 1. `{object}` DataTables settings object: see
\r
13883 * {@link DataTable.models.oSettings}
\r
13884 * 2. `{array|object}` Data for the row to be processed (same as the
\r
13885 * original format that was passed in as the data source, or an array
\r
13886 * from a DOM data source
\r
13887 * 3. `{int}` Row index ({@link DataTable.models.oSettings.aoData}), which
\r
13888 * can be useful to retrieve the `TR` element if you need DOM interaction.
\r
13890 * And the following return is expected:
\r
13892 * * {boolean} Include the row in the searched result set (true) or not
\r
13895 * Note that as with the main search ability in DataTables, technically this
\r
13896 * is "filtering", since it is subtractive. However, for consistency in
\r
13897 * naming we call it searching here.
\r
13903 * // The following example shows custom search being applied to the
\r
13904 * // fourth column (i.e. the data[3] index) based on two input values
\r
13905 * // from the end-user, matching the data in a certain range.
\r
13906 * $.fn.dataTable.ext.search.push(
\r
13907 * function( settings, data, dataIndex ) {
\r
13908 * var min = document.getElementById('min').value * 1;
\r
13909 * var max = document.getElementById('max').value * 1;
\r
13910 * var version = data[3] == "-" ? 0 : data[3]*1;
\r
13912 * if ( min == "" && max == "" ) {
\r
13915 * else if ( min == "" && version < max ) {
\r
13918 * else if ( min < version && "" == max ) {
\r
13921 * else if ( min < version && version < max ) {
\r
13932 * Selector extensions
\r
13934 * The `selector` option can be used to extend the options available for the
\r
13935 * selector modifier options (`selector-modifier` object data type) that
\r
13936 * each of the three built in selector types offer (row, column and cell +
\r
13937 * their plural counterparts). For example the Select extension uses this
\r
13938 * mechanism to provide an option to select only rows, columns and cells
\r
13939 * that have been marked as selected by the end user (`{selected: true}`),
\r
13940 * which can be used in conjunction with the existing built in selector
\r
13943 * Each property is an array to which functions can be pushed. The functions
\r
13944 * take three attributes:
\r
13946 * * Settings object for the host table
\r
13947 * * Options object (`selector-modifier` object type)
\r
13948 * * Array of selected item indexes
\r
13950 * The return is an array of the resulting item indexes after the custom
\r
13951 * selector has been applied.
\r
13963 * Internal functions, exposed for used in plug-ins.
\r
13965 * Please note that you should not need to use the internal methods for
\r
13966 * anything other than a plug-in (and even then, try to avoid if possible).
\r
13967 * The internal function may change between releases.
\r
13976 * Legacy configuration options. Enable and disable legacy options that
\r
13977 * are available in DataTables.
\r
13983 * Enable / disable DataTables 1.9 compatible server-side processing
\r
13994 * Pagination plug-in methods.
\r
13996 * Each entry in this object is a function and defines which buttons should
\r
13997 * be shown by the pagination rendering method that is used for the table:
\r
13998 * {@link DataTable.ext.renderer.pageButton}. The renderer addresses how the
\r
13999 * buttons are displayed in the document, while the functions here tell it
\r
14000 * what buttons to display. This is done by returning an array of button
\r
14001 * descriptions (what each button will do).
\r
14003 * Pagination types (the four built in options and any additional plug-in
\r
14004 * options defined here) can be used through the `paginationType`
\r
14005 * initialisation parameter.
\r
14007 * The functions defined take two parameters:
\r
14009 * 1. `{int} page` The current page index
\r
14010 * 2. `{int} pages` The number of pages in the table
\r
14012 * Each function is expected to return an array where each element of the
\r
14013 * array can be one of:
\r
14015 * * `first` - Jump to first page when activated
\r
14016 * * `last` - Jump to last page when activated
\r
14017 * * `previous` - Show previous page when activated
\r
14018 * * `next` - Show next page when activated
\r
14019 * * `{int}` - Show page of the index given
\r
14020 * * `{array}` - A nested array containing the above elements to add a
\r
14021 * containing 'DIV' element (might be useful for styling).
\r
14023 * Note that DataTables v1.9- used this object slightly differently whereby
\r
14024 * an object with two functions would be defined for each plug-in. That
\r
14025 * ability is still supported by DataTables 1.10+ to provide backwards
\r
14026 * compatibility, but this option of use is now decremented and no longer
\r
14027 * documented in DataTables 1.10+.
\r
14033 * // Show previous, next and current page buttons only
\r
14034 * $.fn.dataTableExt.oPagination.current = function ( page, pages ) {
\r
14035 * return [ 'previous', page, 'next' ];
\r
14048 * Ordering plug-ins - custom data source
\r
14050 * The extension options for ordering of data available here is complimentary
\r
14051 * to the default type based ordering that DataTables typically uses. It
\r
14052 * allows much greater control over the the data that is being used to
\r
14053 * order a column, but is necessarily therefore more complex.
\r
14055 * This type of ordering is useful if you want to do ordering based on data
\r
14056 * live from the DOM (for example the contents of an 'input' element) rather
\r
14057 * than just the static string that DataTables knows of.
\r
14059 * The way these plug-ins work is that you create an array of the values you
\r
14060 * wish to be ordering for the column in question and then return that
\r
14061 * array. The data in the array much be in the index order of the rows in
\r
14062 * the table (not the currently ordering order!). Which order data gathering
\r
14063 * function is run here depends on the `dt-init columns.orderDataType`
\r
14064 * parameter that is used for the column (if any).
\r
14066 * The functions defined take two parameters:
\r
14068 * 1. `{object}` DataTables settings object: see
\r
14069 * {@link DataTable.models.oSettings}
\r
14070 * 2. `{int}` Target column index
\r
14072 * Each function is expected to return an array:
\r
14074 * * `{array}` Data for the column to be ordering upon
\r
14079 * // Ordering using `input` node values
\r
14080 * $.fn.dataTable.ext.order['dom-text'] = function ( settings, col )
\r
14082 * return this.api().column( col, {order:'index'} ).nodes().map( function ( td, i ) {
\r
14083 * return $('input', td).val();
\r
14091 * Type based plug-ins.
\r
14093 * Each column in DataTables has a type assigned to it, either by automatic
\r
14094 * detection or by direct assignment using the `type` option for the column.
\r
14095 * The type of a column will effect how it is ordering and search (plug-ins
\r
14096 * can also make use of the column type if required).
\r
14102 * Type detection functions.
\r
14104 * The functions defined in this object are used to automatically detect
\r
14105 * a column's type, making initialisation of DataTables super easy, even
\r
14106 * when complex data is in the table.
\r
14108 * The functions defined take two parameters:
\r
14110 * 1. `{*}` Data from the column cell to be analysed
\r
14111 * 2. `{settings}` DataTables settings object. This can be used to
\r
14112 * perform context specific type detection - for example detection
\r
14113 * based on language settings such as using a comma for a decimal
\r
14114 * place. Generally speaking the options from the settings will not
\r
14117 * Each function is expected to return:
\r
14119 * * `{string|null}` Data type detected, or null if unknown (and thus
\r
14120 * pass it on to the other type detection functions.
\r
14125 * // Currency type detection plug-in:
\r
14126 * $.fn.dataTable.ext.type.detect.push(
\r
14127 * function ( data, settings ) {
\r
14128 * // Check the numeric part
\r
14129 * if ( ! $.isNumeric( data.substring(1) ) ) {
\r
14133 * // Check prefixed by currency
\r
14134 * if ( data.charAt(0) == '$' || data.charAt(0) == '£' ) {
\r
14135 * return 'currency';
\r
14145 * Type based search formatting.
\r
14147 * The type based searching functions can be used to pre-format the
\r
14148 * data to be search on. For example, it can be used to strip HTML
\r
14149 * tags or to de-format telephone numbers for numeric only searching.
\r
14151 * Note that is a search is not defined for a column of a given type,
\r
14152 * no search formatting will be performed.
\r
14154 * Pre-processing of searching data plug-ins - When you assign the sType
\r
14155 * for a column (or have it automatically detected for you by DataTables
\r
14156 * or a type detection plug-in), you will typically be using this for
\r
14157 * custom sorting, but it can also be used to provide custom searching
\r
14158 * by allowing you to pre-processing the data and returning the data in
\r
14159 * the format that should be searched upon. This is done by adding
\r
14160 * functions this object with a parameter name which matches the sType
\r
14161 * for that target column. This is the corollary of <i>afnSortData</i>
\r
14162 * for searching data.
\r
14164 * The functions defined take a single parameter:
\r
14166 * 1. `{*}` Data from the column cell to be prepared for searching
\r
14168 * Each function is expected to return:
\r
14170 * * `{string|null}` Formatted string that will be used for the searching.
\r
14176 * $.fn.dataTable.ext.type.search['title-numeric'] = function ( d ) {
\r
14177 * return d.replace(/\n/g," ").replace( /<.*?>/g, "" );
\r
14184 * Type based ordering.
\r
14186 * The column type tells DataTables what ordering to apply to the table
\r
14187 * when a column is sorted upon. The order for each type that is defined,
\r
14188 * is defined by the functions available in this object.
\r
14190 * Each ordering option can be described by three properties added to
\r
14193 * * `{type}-pre` - Pre-formatting function
\r
14194 * * `{type}-asc` - Ascending order function
\r
14195 * * `{type}-desc` - Descending order function
\r
14197 * All three can be used together, only `{type}-pre` or only
\r
14198 * `{type}-asc` and `{type}-desc` together. It is generally recommended
\r
14199 * that only `{type}-pre` is used, as this provides the optimal
\r
14200 * implementation in terms of speed, although the others are provided
\r
14201 * for compatibility with existing Javascript sort functions.
\r
14203 * `{type}-pre`: Functions defined take a single parameter:
\r
14205 * 1. `{*}` Data from the column cell to be prepared for ordering
\r
14209 * * `{*}` Data to be sorted upon
\r
14211 * `{type}-asc` and `{type}-desc`: Functions are typical Javascript sort
\r
14212 * functions, taking two parameters:
\r
14214 * 1. `{*}` Data to compare to the second parameter
\r
14215 * 2. `{*}` Data to compare to the first parameter
\r
14219 * * `{*}` Ordering match: <0 if first parameter should be sorted lower
\r
14220 * than the second parameter, ===0 if the two parameters are equal and
\r
14221 * >0 if the first parameter should be sorted height than the second
\r
14228 * // Numeric ordering of formatted numbers with a pre-formatter
\r
14229 * $.extend( $.fn.dataTable.ext.type.order, {
\r
14230 * "string-pre": function(x) {
\r
14231 * a = (a === "-" || a === "") ? 0 : a.replace( /[^\d\-\.]/g, "" );
\r
14232 * return parseFloat( a );
\r
14237 * // Case-sensitive string ordering, with no pre-formatting method
\r
14238 * $.extend( $.fn.dataTable.ext.order, {
\r
14239 * "string-case-asc": function(x,y) {
\r
14240 * return ((x < y) ? -1 : ((x > y) ? 1 : 0));
\r
14242 * "string-case-desc": function(x,y) {
\r
14243 * return ((x < y) ? 1 : ((x > y) ? -1 : 0));
\r
14251 * Unique DataTables instance counter
\r
14261 // The following properties are retained for backwards compatiblity only.
\r
14262 // The should not be used in new projects and will be removed in a future
\r
14267 * Version check function.
\r
14269 * @depreciated Since 1.10
\r
14271 fnVersionCheck: DataTable.fnVersionCheck,
\r
14275 * Index for what 'this' index API functions should use
\r
14277 * @deprecated Since v1.10
\r
14283 * jQuery UI class container
\r
14285 * @deprecated Since v1.10
\r
14291 * Software version
\r
14293 * @deprecated Since v1.10
\r
14295 sVersion: DataTable.version
\r
14300 // Backwards compatibility. Alias to pre 1.10 Hungarian notation counter parts
\r
14302 $.extend( _ext, {
\r
14303 afnFiltering: _ext.search,
\r
14304 aTypes: _ext.type.detect,
\r
14305 ofnSearch: _ext.type.search,
\r
14306 oSort: _ext.type.order,
\r
14307 afnSortData: _ext.order,
\r
14308 aoFeatures: _ext.feature,
\r
14309 oApi: _ext.internal,
\r
14310 oStdClasses: _ext.classes,
\r
14311 oPagination: _ext.pager
\r
14315 $.extend( DataTable.ext.classes, {
\r
14316 "sTable": "dataTable",
\r
14317 "sNoFooter": "no-footer",
\r
14319 /* Paging buttons */
\r
14320 "sPageButton": "paginate_button",
\r
14321 "sPageButtonActive": "current",
\r
14322 "sPageButtonDisabled": "disabled",
\r
14324 /* Striping classes */
\r
14325 "sStripeOdd": "odd",
\r
14326 "sStripeEven": "even",
\r
14329 "sRowEmpty": "dataTables_empty",
\r
14332 "sWrapper": "dataTables_wrapper",
\r
14333 "sFilter": "dataTables_filter",
\r
14334 "sInfo": "dataTables_info",
\r
14335 "sPaging": "dataTables_paginate paging_", /* Note that the type is postfixed */
\r
14336 "sLength": "dataTables_length",
\r
14337 "sProcessing": "dataTables_processing",
\r
14340 "sSortAsc": "sorting_asc",
\r
14341 "sSortDesc": "sorting_desc",
\r
14342 "sSortable": "sorting", /* Sortable in both directions */
\r
14343 "sSortableAsc": "sorting_asc_disabled",
\r
14344 "sSortableDesc": "sorting_desc_disabled",
\r
14345 "sSortableNone": "sorting_disabled",
\r
14346 "sSortColumn": "sorting_", /* Note that an int is postfixed for the sorting order */
\r
14349 "sFilterInput": "",
\r
14351 /* Page length */
\r
14352 "sLengthSelect": "",
\r
14355 "sScrollWrapper": "dataTables_scroll",
\r
14356 "sScrollHead": "dataTables_scrollHead",
\r
14357 "sScrollHeadInner": "dataTables_scrollHeadInner",
\r
14358 "sScrollBody": "dataTables_scrollBody",
\r
14359 "sScrollFoot": "dataTables_scrollFoot",
\r
14360 "sScrollFootInner": "dataTables_scrollFootInner",
\r
14367 "sSortJUIAsc": "",
\r
14368 "sSortJUIDesc": "",
\r
14370 "sSortJUIAscAllowed": "",
\r
14371 "sSortJUIDescAllowed": "",
\r
14372 "sSortJUIWrapper": "",
\r
14374 "sJUIHeader": "",
\r
14381 // Reused strings for better compression. Closure compiler appears to have a
\r
14382 // weird edge case where it is trying to expand strings rather than use the
\r
14383 // variable version. This results in about 200 bytes being added, for very
\r
14384 // little preference benefit since it this run on script load only.
\r
14388 var _stateDefault = _empty + 'ui-state-default';
\r
14389 var _sortIcon = _empty + 'css_right ui-icon ui-icon-';
\r
14390 var _headerFooter = _empty + 'fg-toolbar ui-toolbar ui-widget-header ui-helper-clearfix';
\r
14392 $.extend( DataTable.ext.oJUIClasses, DataTable.ext.classes, {
\r
14393 /* Full numbers paging buttons */
\r
14394 "sPageButton": "fg-button ui-button "+_stateDefault,
\r
14395 "sPageButtonActive": "ui-state-disabled",
\r
14396 "sPageButtonDisabled": "ui-state-disabled",
\r
14399 "sPaging": "dataTables_paginate fg-buttonset ui-buttonset fg-buttonset-multi "+
\r
14400 "ui-buttonset-multi paging_", /* Note that the type is postfixed */
\r
14403 "sSortAsc": _stateDefault+" sorting_asc",
\r
14404 "sSortDesc": _stateDefault+" sorting_desc",
\r
14405 "sSortable": _stateDefault+" sorting",
\r
14406 "sSortableAsc": _stateDefault+" sorting_asc_disabled",
\r
14407 "sSortableDesc": _stateDefault+" sorting_desc_disabled",
\r
14408 "sSortableNone": _stateDefault+" sorting_disabled",
\r
14409 "sSortJUIAsc": _sortIcon+"triangle-1-n",
\r
14410 "sSortJUIDesc": _sortIcon+"triangle-1-s",
\r
14411 "sSortJUI": _sortIcon+"carat-2-n-s",
\r
14412 "sSortJUIAscAllowed": _sortIcon+"carat-1-n",
\r
14413 "sSortJUIDescAllowed": _sortIcon+"carat-1-s",
\r
14414 "sSortJUIWrapper": "DataTables_sort_wrapper",
\r
14415 "sSortIcon": "DataTables_sort_icon",
\r
14418 "sScrollHead": "dataTables_scrollHead "+_stateDefault,
\r
14419 "sScrollFoot": "dataTables_scrollFoot "+_stateDefault,
\r
14422 "sHeaderTH": _stateDefault,
\r
14423 "sFooterTH": _stateDefault,
\r
14424 "sJUIHeader": _headerFooter+" ui-corner-tl ui-corner-tr",
\r
14425 "sJUIFooter": _headerFooter+" ui-corner-bl ui-corner-br"
\r
14432 var extPagination = DataTable.ext.pager;
\r
14434 function _numbers ( page, pages ) {
\r
14437 buttons = extPagination.numbers_length,
\r
14438 half = Math.floor( buttons / 2 ),
\r
14441 if ( pages <= buttons ) {
\r
14442 numbers = _range( 0, pages );
\r
14444 else if ( page <= half ) {
\r
14445 numbers = _range( 0, buttons-2 );
\r
14446 numbers.push( 'ellipsis' );
\r
14447 numbers.push( pages-1 );
\r
14449 else if ( page >= pages - 1 - half ) {
\r
14450 numbers = _range( pages-(buttons-2), pages );
\r
14451 numbers.splice( 0, 0, 'ellipsis' ); // no unshift in ie6
\r
14452 numbers.splice( 0, 0, 0 );
\r
14455 numbers = _range( page-half+2, page+half-1 );
\r
14456 numbers.push( 'ellipsis' );
\r
14457 numbers.push( pages-1 );
\r
14458 numbers.splice( 0, 0, 'ellipsis' );
\r
14459 numbers.splice( 0, 0, 0 );
\r
14462 numbers.DT_el = 'span';
\r
14467 $.extend( extPagination, {
\r
14468 simple: function ( page, pages ) {
\r
14469 return [ 'previous', 'next' ];
\r
14472 full: function ( page, pages ) {
\r
14473 return [ 'first', 'previous', 'next', 'last' ];
\r
14476 numbers: function ( page, pages ) {
\r
14477 return [ _numbers(page, pages) ];
\r
14480 simple_numbers: function ( page, pages ) {
\r
14481 return [ 'previous', _numbers(page, pages), 'next' ];
\r
14484 full_numbers: function ( page, pages ) {
\r
14485 return [ 'first', 'previous', _numbers(page, pages), 'next', 'last' ];
\r
14488 // For testing and plug-ins to use
\r
14489 _numbers: _numbers,
\r
14491 // Number of number buttons (including ellipsis) to show. _Must be odd!_
\r
14492 numbers_length: 7
\r
14496 $.extend( true, DataTable.ext.renderer, {
\r
14498 _: function ( settings, host, idx, buttons, page, pages ) {
\r
14499 var classes = settings.oClasses;
\r
14500 var lang = settings.oLanguage.oPaginate;
\r
14501 var aria = settings.oLanguage.oAria.paginate || {};
\r
14502 var btnDisplay, btnClass, counter=0;
\r
14504 var attach = function( container, buttons ) {
\r
14505 var i, ien, node, button;
\r
14506 var clickHandler = function ( e ) {
\r
14507 _fnPageChange( settings, e.data.action, true );
\r
14510 for ( i=0, ien=buttons.length ; i<ien ; i++ ) {
\r
14511 button = buttons[i];
\r
14513 if ( $.isArray( button ) ) {
\r
14514 var inner = $( '<'+(button.DT_el || 'div')+'/>' )
\r
14515 .appendTo( container );
\r
14516 attach( inner, button );
\r
14519 btnDisplay = null;
\r
14522 switch ( button ) {
\r
14524 container.append('<span class="ellipsis">…</span>');
\r
14528 btnDisplay = lang.sFirst;
\r
14529 btnClass = button + (page > 0 ?
\r
14530 '' : ' '+classes.sPageButtonDisabled);
\r
14534 btnDisplay = lang.sPrevious;
\r
14535 btnClass = button + (page > 0 ?
\r
14536 '' : ' '+classes.sPageButtonDisabled);
\r
14540 btnDisplay = lang.sNext;
\r
14541 btnClass = button + (page < pages-1 ?
\r
14542 '' : ' '+classes.sPageButtonDisabled);
\r
14546 btnDisplay = lang.sLast;
\r
14547 btnClass = button + (page < pages-1 ?
\r
14548 '' : ' '+classes.sPageButtonDisabled);
\r
14552 btnDisplay = button + 1;
\r
14553 btnClass = page === button ?
\r
14554 classes.sPageButtonActive : '';
\r
14558 if ( btnDisplay !== null ) {
\r
14559 node = $('<a>', {
\r
14560 'class': classes.sPageButton+' '+btnClass,
\r
14561 'aria-controls': settings.sTableId,
\r
14562 'aria-label': aria[ button ],
\r
14563 'data-dt-idx': counter,
\r
14564 'tabindex': settings.iTabIndex,
\r
14565 'id': idx === 0 && typeof button === 'string' ?
\r
14566 settings.sTableId +'_'+ button :
\r
14569 .html( btnDisplay )
\r
14570 .appendTo( container );
\r
14573 node, {action: button}, clickHandler
\r
14582 // IE9 throws an 'unknown error' if document.activeElement is used
\r
14583 // inside an iframe or frame. Try / catch the error. Not good for
\r
14584 // accessibility, but neither are frames.
\r
14588 // Because this approach is destroying and recreating the paging
\r
14589 // elements, focus is lost on the select button which is bad for
\r
14590 // accessibility. So we want to restore focus once the draw has
\r
14592 activeEl = $(host).find(document.activeElement).data('dt-idx');
\r
14596 attach( $(host).empty(), buttons );
\r
14598 if ( activeEl ) {
\r
14599 $(host).find( '[data-dt-idx='+activeEl+']' ).focus();
\r
14607 // Built in type detection. See model.ext.aTypes for information about
\r
14608 // what is required from this methods.
\r
14609 $.extend( DataTable.ext.type.detect, [
\r
14610 // Plain numbers - first since V8 detects some plain numbers as dates
\r
14611 // e.g. Date.parse('55') (but not all, e.g. Date.parse('22')...).
\r
14612 function ( d, settings )
\r
14614 var decimal = settings.oLanguage.sDecimal;
\r
14615 return _isNumber( d, decimal ) ? 'num'+decimal : null;
\r
14618 // Dates (only those recognised by the browser's Date.parse)
\r
14619 function ( d, settings )
\r
14621 // V8 will remove any unknown characters at the start and end of the
\r
14622 // expression, leading to false matches such as `$245.12` or `10%` being
\r
14623 // a valid date. See forum thread 18941 for detail.
\r
14624 if ( d && !(d instanceof Date) && ( ! _re_date_start.test(d) || ! _re_date_end.test(d) ) ) {
\r
14627 var parsed = Date.parse(d);
\r
14628 return (parsed !== null && !isNaN(parsed)) || _empty(d) ? 'date' : null;
\r
14631 // Formatted numbers
\r
14632 function ( d, settings )
\r
14634 var decimal = settings.oLanguage.sDecimal;
\r
14635 return _isNumber( d, decimal, true ) ? 'num-fmt'+decimal : null;
\r
14639 function ( d, settings )
\r
14641 var decimal = settings.oLanguage.sDecimal;
\r
14642 return _htmlNumeric( d, decimal ) ? 'html-num'+decimal : null;
\r
14645 // HTML numeric, formatted
\r
14646 function ( d, settings )
\r
14648 var decimal = settings.oLanguage.sDecimal;
\r
14649 return _htmlNumeric( d, decimal, true ) ? 'html-num-fmt'+decimal : null;
\r
14652 // HTML (this is strict checking - there must be html)
\r
14653 function ( d, settings )
\r
14655 return _empty( d ) || (typeof d === 'string' && d.indexOf('<') !== -1) ?
\r
14662 // Filter formatting functions. See model.ext.ofnSearch for information about
\r
14663 // what is required from these methods.
\r
14665 // Note that additional search methods are added for the html numbers and
\r
14666 // html formatted numbers by `_addNumericSort()` when we know what the decimal
\r
14670 $.extend( DataTable.ext.type.search, {
\r
14671 html: function ( data ) {
\r
14672 return _empty(data) ?
\r
14674 typeof data === 'string' ?
\r
14676 .replace( _re_new_lines, " " )
\r
14677 .replace( _re_html, "" ) :
\r
14681 string: function ( data ) {
\r
14682 return _empty(data) ?
\r
14684 typeof data === 'string' ?
\r
14685 data.replace( _re_new_lines, " " ) :
\r
14692 var __numericReplace = function ( d, decimalPlace, re1, re2 ) {
\r
14693 if ( d !== 0 && (!d || d === '-') ) {
\r
14694 return -Infinity;
\r
14697 // If a decimal place other than `.` is used, it needs to be given to the
\r
14698 // function so we can detect it and replace with a `.` which is the only
\r
14699 // decimal place Javascript recognises - it is not locale aware.
\r
14700 if ( decimalPlace ) {
\r
14701 d = _numToDecimal( d, decimalPlace );
\r
14704 if ( d.replace ) {
\r
14706 d = d.replace( re1, '' );
\r
14710 d = d.replace( re2, '' );
\r
14718 // Add the numeric 'deformatting' functions for sorting and search. This is done
\r
14719 // in a function to provide an easy ability for the language options to add
\r
14720 // additional methods if a non-period decimal place is used.
\r
14721 function _addNumericSort ( decimalPlace ) {
\r
14725 "num": function ( d ) {
\r
14726 return __numericReplace( d, decimalPlace );
\r
14729 // Formatted numbers
\r
14730 "num-fmt": function ( d ) {
\r
14731 return __numericReplace( d, decimalPlace, _re_formatted_numeric );
\r
14735 "html-num": function ( d ) {
\r
14736 return __numericReplace( d, decimalPlace, _re_html );
\r
14739 // HTML numeric, formatted
\r
14740 "html-num-fmt": function ( d ) {
\r
14741 return __numericReplace( d, decimalPlace, _re_html, _re_formatted_numeric );
\r
14744 function ( key, fn ) {
\r
14745 // Add the ordering method
\r
14746 _ext.type.order[ key+decimalPlace+'-pre' ] = fn;
\r
14748 // For HTML types add a search formatter that will strip the HTML
\r
14749 if ( key.match(/^html\-/) ) {
\r
14750 _ext.type.search[ key+decimalPlace ] = _ext.type.search.html;
\r
14757 // Default sort methods
\r
14758 $.extend( _ext.type.order, {
\r
14760 "date-pre": function ( d ) {
\r
14761 return Date.parse( d ) || 0;
\r
14765 "html-pre": function ( a ) {
\r
14766 return _empty(a) ?
\r
14769 a.replace( /<.*?>/g, "" ).toLowerCase() :
\r
14774 "string-pre": function ( a ) {
\r
14775 // This is a little complex, but faster than always calling toString,
\r
14776 // http://jsperf.com/tostring-v-check
\r
14777 return _empty(a) ?
\r
14779 typeof a === 'string' ?
\r
14780 a.toLowerCase() :
\r
14786 // string-asc and -desc are retained only for compatibility with the old
\r
14788 "string-asc": function ( x, y ) {
\r
14789 return ((x < y) ? -1 : ((x > y) ? 1 : 0));
\r
14792 "string-desc": function ( x, y ) {
\r
14793 return ((x < y) ? 1 : ((x > y) ? -1 : 0));
\r
14798 // Numeric sorting types - order doesn't matter here
\r
14799 _addNumericSort( '' );
\r
14802 $.extend( true, DataTable.ext.renderer, {
\r
14804 _: function ( settings, cell, column, classes ) {
\r
14805 // No additional mark-up required
\r
14806 // Attach a sort listener to update on sort - note that using the
\r
14807 // `DT` namespace will allow the event to be removed automatically
\r
14808 // on destroy, while the `dt` namespaced event is the one we are
\r
14810 $(settings.nTable).on( 'order.dt.DT', function ( e, ctx, sorting, columns ) {
\r
14811 if ( settings !== ctx ) { // need to check this this is the host
\r
14812 return; // table, not a nested one
\r
14815 var colIdx = column.idx;
\r
14819 column.sSortingClass +' '+
\r
14820 classes.sSortAsc +' '+
\r
14821 classes.sSortDesc
\r
14823 .addClass( columns[ colIdx ] == 'asc' ?
\r
14824 classes.sSortAsc : columns[ colIdx ] == 'desc' ?
\r
14825 classes.sSortDesc :
\r
14826 column.sSortingClass
\r
14831 jqueryui: function ( settings, cell, column, classes ) {
\r
14833 .addClass( classes.sSortJUIWrapper )
\r
14834 .append( cell.contents() )
\r
14835 .append( $('<span/>')
\r
14836 .addClass( classes.sSortIcon+' '+column.sSortingClassJUI )
\r
14838 .appendTo( cell );
\r
14840 // Attach a sort listener to update on sort
\r
14841 $(settings.nTable).on( 'order.dt.DT', function ( e, ctx, sorting, columns ) {
\r
14842 if ( settings !== ctx ) {
\r
14846 var colIdx = column.idx;
\r
14849 .removeClass( classes.sSortAsc +" "+classes.sSortDesc )
\r
14850 .addClass( columns[ colIdx ] == 'asc' ?
\r
14851 classes.sSortAsc : columns[ colIdx ] == 'desc' ?
\r
14852 classes.sSortDesc :
\r
14853 column.sSortingClass
\r
14857 .find( 'span.'+classes.sSortIcon )
\r
14859 classes.sSortJUIAsc +" "+
\r
14860 classes.sSortJUIDesc +" "+
\r
14861 classes.sSortJUI +" "+
\r
14862 classes.sSortJUIAscAllowed +" "+
\r
14863 classes.sSortJUIDescAllowed
\r
14865 .addClass( columns[ colIdx ] == 'asc' ?
\r
14866 classes.sSortJUIAsc : columns[ colIdx ] == 'desc' ?
\r
14867 classes.sSortJUIDesc :
\r
14868 column.sSortingClassJUI
\r
14876 * Public helper functions. These aren't used internally by DataTables, or
\r
14877 * called by any of the options passed into DataTables, but they can be used
\r
14878 * externally by developers working with DataTables. They are helper functions
\r
14879 * to make working with DataTables a little bit easier.
\r
14882 var __htmlEscapeEntities = function ( d ) {
\r
14883 return typeof d === 'string' ?
\r
14884 d.replace(/</g, '<').replace(/>/g, '>').replace(/"/g, '"') :
\r
14889 * Helpers for `columns.render`.
\r
14891 * The options defined here can be used with the `columns.render` initialisation
\r
14892 * option to provide a display renderer. The following functions are defined:
\r
14894 * * `number` - Will format numeric data (defined by `columns.data`) for
\r
14895 * display, retaining the original unformatted data for sorting and filtering.
\r
14896 * It takes 5 parameters:
\r
14897 * * `string` - Thousands grouping separator
\r
14898 * * `string` - Decimal point indicator
\r
14899 * * `integer` - Number of decimal points to show
\r
14900 * * `string` (optional) - Prefix.
\r
14901 * * `string` (optional) - Postfix (/suffix).
\r
14902 * * `text` - Escape HTML to help prevent XSS attacks. It has no optional
\r
14906 * // Column definition using the number renderer
\r
14908 * data: "salary",
\r
14909 * render: $.fn.dataTable.render.number( '\'', '.', 0, '$' )
\r
14914 DataTable.render = {
\r
14915 number: function ( thousands, decimal, precision, prefix, postfix ) {
\r
14917 display: function ( d ) {
\r
14918 if ( typeof d !== 'number' && typeof d !== 'string' ) {
\r
14922 var negative = d < 0 ? '-' : '';
\r
14923 var flo = parseFloat( d );
\r
14925 // If NaN then there isn't much formatting that we can do - just
\r
14926 // return immediately, escaping any HTML (this was supposed to
\r
14927 // be a number after all)
\r
14928 if ( isNaN( flo ) ) {
\r
14929 return __htmlEscapeEntities( d );
\r
14932 d = Math.abs( flo );
\r
14934 var intPart = parseInt( d, 10 );
\r
14935 var floatPart = precision ?
\r
14936 decimal+(d - intPart).toFixed( precision ).substring( 2 ):
\r
14939 return negative + (prefix||'') +
\r
14940 intPart.toString().replace(
\r
14941 /\B(?=(\d{3})+(?!\d))/g, thousands
\r
14949 text: function () {
\r
14951 display: __htmlEscapeEntities
\r
14958 * This is really a good bit rubbish this method of exposing the internal methods
\r
14959 * publicly... - To be fixed in 2.0 using methods on the prototype
\r
14964 * Create a wrapper function for exporting an internal functions to an external API.
\r
14965 * @param {string} fn API function name
\r
14966 * @returns {function} wrapped function
\r
14967 * @memberof DataTable#internal
\r
14969 function _fnExternApiFunc (fn)
\r
14971 return function() {
\r
14972 var args = [_fnSettingsFromNode( this[DataTable.ext.iApiIndex] )].concat(
\r
14973 Array.prototype.slice.call(arguments)
\r
14975 return DataTable.ext.internal[fn].apply( this, args );
\r
14981 * Reference to internal functions for use by plug-in developers. Note that
\r
14982 * these methods are references to internal functions and are considered to be
\r
14983 * private. If you use these methods, be aware that they are liable to change
\r
14984 * between versions.
\r
14987 $.extend( DataTable.ext.internal, {
\r
14988 _fnExternApiFunc: _fnExternApiFunc,
\r
14989 _fnBuildAjax: _fnBuildAjax,
\r
14990 _fnAjaxUpdate: _fnAjaxUpdate,
\r
14991 _fnAjaxParameters: _fnAjaxParameters,
\r
14992 _fnAjaxUpdateDraw: _fnAjaxUpdateDraw,
\r
14993 _fnAjaxDataSrc: _fnAjaxDataSrc,
\r
14994 _fnAddColumn: _fnAddColumn,
\r
14995 _fnColumnOptions: _fnColumnOptions,
\r
14996 _fnAdjustColumnSizing: _fnAdjustColumnSizing,
\r
14997 _fnVisibleToColumnIndex: _fnVisibleToColumnIndex,
\r
14998 _fnColumnIndexToVisible: _fnColumnIndexToVisible,
\r
14999 _fnVisbleColumns: _fnVisbleColumns,
\r
15000 _fnGetColumns: _fnGetColumns,
\r
15001 _fnColumnTypes: _fnColumnTypes,
\r
15002 _fnApplyColumnDefs: _fnApplyColumnDefs,
\r
15003 _fnHungarianMap: _fnHungarianMap,
\r
15004 _fnCamelToHungarian: _fnCamelToHungarian,
\r
15005 _fnLanguageCompat: _fnLanguageCompat,
\r
15006 _fnBrowserDetect: _fnBrowserDetect,
\r
15007 _fnAddData: _fnAddData,
\r
15008 _fnAddTr: _fnAddTr,
\r
15009 _fnNodeToDataIndex: _fnNodeToDataIndex,
\r
15010 _fnNodeToColumnIndex: _fnNodeToColumnIndex,
\r
15011 _fnGetCellData: _fnGetCellData,
\r
15012 _fnSetCellData: _fnSetCellData,
\r
15013 _fnSplitObjNotation: _fnSplitObjNotation,
\r
15014 _fnGetObjectDataFn: _fnGetObjectDataFn,
\r
15015 _fnSetObjectDataFn: _fnSetObjectDataFn,
\r
15016 _fnGetDataMaster: _fnGetDataMaster,
\r
15017 _fnClearTable: _fnClearTable,
\r
15018 _fnDeleteIndex: _fnDeleteIndex,
\r
15019 _fnInvalidate: _fnInvalidate,
\r
15020 _fnGetRowElements: _fnGetRowElements,
\r
15021 _fnCreateTr: _fnCreateTr,
\r
15022 _fnBuildHead: _fnBuildHead,
\r
15023 _fnDrawHead: _fnDrawHead,
\r
15024 _fnDraw: _fnDraw,
\r
15025 _fnReDraw: _fnReDraw,
\r
15026 _fnAddOptionsHtml: _fnAddOptionsHtml,
\r
15027 _fnDetectHeader: _fnDetectHeader,
\r
15028 _fnGetUniqueThs: _fnGetUniqueThs,
\r
15029 _fnFeatureHtmlFilter: _fnFeatureHtmlFilter,
\r
15030 _fnFilterComplete: _fnFilterComplete,
\r
15031 _fnFilterCustom: _fnFilterCustom,
\r
15032 _fnFilterColumn: _fnFilterColumn,
\r
15033 _fnFilter: _fnFilter,
\r
15034 _fnFilterCreateSearch: _fnFilterCreateSearch,
\r
15035 _fnEscapeRegex: _fnEscapeRegex,
\r
15036 _fnFilterData: _fnFilterData,
\r
15037 _fnFeatureHtmlInfo: _fnFeatureHtmlInfo,
\r
15038 _fnUpdateInfo: _fnUpdateInfo,
\r
15039 _fnInfoMacros: _fnInfoMacros,
\r
15040 _fnInitialise: _fnInitialise,
\r
15041 _fnInitComplete: _fnInitComplete,
\r
15042 _fnLengthChange: _fnLengthChange,
\r
15043 _fnFeatureHtmlLength: _fnFeatureHtmlLength,
\r
15044 _fnFeatureHtmlPaginate: _fnFeatureHtmlPaginate,
\r
15045 _fnPageChange: _fnPageChange,
\r
15046 _fnFeatureHtmlProcessing: _fnFeatureHtmlProcessing,
\r
15047 _fnProcessingDisplay: _fnProcessingDisplay,
\r
15048 _fnFeatureHtmlTable: _fnFeatureHtmlTable,
\r
15049 _fnScrollDraw: _fnScrollDraw,
\r
15050 _fnApplyToChildren: _fnApplyToChildren,
\r
15051 _fnCalculateColumnWidths: _fnCalculateColumnWidths,
\r
15052 _fnThrottle: _fnThrottle,
\r
15053 _fnConvertToWidth: _fnConvertToWidth,
\r
15054 _fnGetWidestNode: _fnGetWidestNode,
\r
15055 _fnGetMaxLenString: _fnGetMaxLenString,
\r
15056 _fnStringToCss: _fnStringToCss,
\r
15057 _fnSortFlatten: _fnSortFlatten,
\r
15058 _fnSort: _fnSort,
\r
15059 _fnSortAria: _fnSortAria,
\r
15060 _fnSortListener: _fnSortListener,
\r
15061 _fnSortAttachListener: _fnSortAttachListener,
\r
15062 _fnSortingClasses: _fnSortingClasses,
\r
15063 _fnSortData: _fnSortData,
\r
15064 _fnSaveState: _fnSaveState,
\r
15065 _fnLoadState: _fnLoadState,
\r
15066 _fnSettingsFromNode: _fnSettingsFromNode,
\r
15069 _fnBindAction: _fnBindAction,
\r
15070 _fnCallbackReg: _fnCallbackReg,
\r
15071 _fnCallbackFire: _fnCallbackFire,
\r
15072 _fnLengthOverflow: _fnLengthOverflow,
\r
15073 _fnRenderer: _fnRenderer,
\r
15074 _fnDataSource: _fnDataSource,
\r
15075 _fnRowAttributes: _fnRowAttributes,
\r
15076 _fnCalculateEnd: function () {} // Used by a lot of plug-ins, but redundant
\r
15077 // in 1.10, so this dead-end function is
\r
15078 // added to prevent errors
\r
15083 $.fn.dataTable = DataTable;
\r
15085 // Provide access to the host jQuery object (circular reference)
\r
15088 // Legacy aliases
\r
15089 $.fn.dataTableSettings = DataTable.settings;
\r
15090 $.fn.dataTableExt = DataTable.ext;
\r
15092 // With a capital `D` we return a DataTables API instance rather than a
\r
15094 $.fn.DataTable = function ( opts ) {
\r
15095 return $(this).dataTable( opts ).api();
\r
15098 // All properties that are available to $.fn.dataTable should also be
\r
15099 // available on $.fn.DataTable
\r
15100 $.each( DataTable, function ( prop, val ) {
\r
15101 $.fn.DataTable[ prop ] = val;
\r
15105 // Information about events fired by DataTables - for documentation.
\r
15107 * Draw event, fired whenever the table is redrawn on the page, at the same
\r
15108 * point as fnDrawCallback. This may be useful for binding events or
\r
15109 * performing calculations when the table is altered at all.
\r
15110 * @name DataTable#draw.dt
\r
15112 * @param {event} e jQuery event object
\r
15113 * @param {object} o DataTables settings object {@link DataTable.models.oSettings}
\r
15117 * Search event, fired when the searching applied to the table (using the
\r
15118 * built-in global search, or column filters) is altered.
\r
15119 * @name DataTable#search.dt
\r
15121 * @param {event} e jQuery event object
\r
15122 * @param {object} o DataTables settings object {@link DataTable.models.oSettings}
\r
15126 * Page change event, fired when the paging of the table is altered.
\r
15127 * @name DataTable#page.dt
\r
15129 * @param {event} e jQuery event object
\r
15130 * @param {object} o DataTables settings object {@link DataTable.models.oSettings}
\r
15134 * Order event, fired when the ordering applied to the table is altered.
\r
15135 * @name DataTable#order.dt
\r
15137 * @param {event} e jQuery event object
\r
15138 * @param {object} o DataTables settings object {@link DataTable.models.oSettings}
\r
15142 * DataTables initialisation complete event, fired when the table is fully
\r
15143 * drawn, including Ajax data loaded, if Ajax data is required.
\r
15144 * @name DataTable#init.dt
\r
15146 * @param {event} e jQuery event object
\r
15147 * @param {object} oSettings DataTables settings object
\r
15148 * @param {object} json The JSON object request from the server - only
\r
15149 * present if client-side Ajax sourced data is used</li></ol>
\r
15153 * State save event, fired when the table has changed state a new state save
\r
15154 * is required. This event allows modification of the state saving object
\r
15155 * prior to actually doing the save, including addition or other state
\r
15156 * properties (for plug-ins) or modification of a DataTables core property.
\r
15157 * @name DataTable#stateSaveParams.dt
\r
15159 * @param {event} e jQuery event object
\r
15160 * @param {object} oSettings DataTables settings object
\r
15161 * @param {object} json The state information to be saved
\r
15165 * State load event, fired when the table is loading state from the stored
\r
15166 * data, but prior to the settings object being modified by the saved state
\r
15167 * - allowing modification of the saved state is required or loading of
\r
15168 * state for a plug-in.
\r
15169 * @name DataTable#stateLoadParams.dt
\r
15171 * @param {event} e jQuery event object
\r
15172 * @param {object} oSettings DataTables settings object
\r
15173 * @param {object} json The saved state information
\r
15177 * State loaded event, fired when state has been loaded from stored data and
\r
15178 * the settings object has been modified by the loaded data.
\r
15179 * @name DataTable#stateLoaded.dt
\r
15181 * @param {event} e jQuery event object
\r
15182 * @param {object} oSettings DataTables settings object
\r
15183 * @param {object} json The saved state information
\r
15187 * Processing event, fired when DataTables is doing some kind of processing
\r
15188 * (be it, order, searcg or anything else). It can be used to indicate to
\r
15189 * the end user that there is something happening, or that something has
\r
15191 * @name DataTable#processing.dt
\r
15193 * @param {event} e jQuery event object
\r
15194 * @param {object} oSettings DataTables settings object
\r
15195 * @param {boolean} bShow Flag for if DataTables is doing processing or not
\r
15199 * Ajax (XHR) event, fired whenever an Ajax request is completed from a
\r
15200 * request to made to the server for new data. This event is called before
\r
15201 * DataTables processed the returned data, so it can also be used to pre-
\r
15202 * process the data returned from the server, if needed.
\r
15204 * Note that this trigger is called in `fnServerData`, if you override
\r
15205 * `fnServerData` and which to use this event, you need to trigger it in you
\r
15206 * success function.
\r
15207 * @name DataTable#xhr.dt
\r
15209 * @param {event} e jQuery event object
\r
15210 * @param {object} o DataTables settings object {@link DataTable.models.oSettings}
\r
15211 * @param {object} json JSON returned from the server
\r
15214 * // Use a custom property returned from the server in another DOM element
\r
15215 * $('#table').dataTable().on('xhr.dt', function (e, settings, json) {
\r
15216 * $('#status').html( json.status );
\r
15220 * // Pre-process the data returned from the server
\r
15221 * $('#table').dataTable().on('xhr.dt', function (e, settings, json) {
\r
15222 * for ( var i=0, ien=json.aaData.length ; i<ien ; i++ ) {
\r
15223 * json.aaData[i].sum = json.aaData[i].one + json.aaData[i].two;
\r
15225 * // Note no return - manipulate the data directly in the JSON object.
\r
15230 * Destroy event, fired when the DataTable is destroyed by calling fnDestroy
\r
15231 * or passing the bDestroy:true parameter in the initialisation object. This
\r
15232 * can be used to remove bound events, added DOM nodes, etc.
\r
15233 * @name DataTable#destroy.dt
\r
15235 * @param {event} e jQuery event object
\r
15236 * @param {object} o DataTables settings object {@link DataTable.models.oSettings}
\r
15240 * Page length change event, fired when number of records to show on each
\r
15241 * page (the length) is changed.
\r
15242 * @name DataTable#length.dt
\r
15244 * @param {event} e jQuery event object
\r
15245 * @param {object} o DataTables settings object {@link DataTable.models.oSettings}
\r
15246 * @param {integer} len New length
\r
15250 * Column sizing has changed.
\r
15251 * @name DataTable#column-sizing.dt
\r
15253 * @param {event} e jQuery event object
\r
15254 * @param {object} o DataTables settings object {@link DataTable.models.oSettings}
\r
15258 * Column visibility has changed.
\r
15259 * @name DataTable#column-visibility.dt
\r
15261 * @param {event} e jQuery event object
\r
15262 * @param {object} o DataTables settings object {@link DataTable.models.oSettings}
\r
15263 * @param {int} column Column index
\r
15264 * @param {bool} vis `false` if column now hidden, or `true` if visible
\r
15267 return $.fn.dataTable;
\r