2 * @summary DataTables
\r
3 * @description Paginate, search and sort HTML tables
\r
5 * @file jquery.dataTables.js
\r
6 * @author Allan Jardine (www.sprymedia.co.uk)
\r
7 * @contact www.sprymedia.co.uk/contact
\r
9 * @copyright Copyright 2008-2012 Allan Jardine, all rights reserved.
\r
11 * This source file is free software, under either the GPL v2 license or a
\r
12 * BSD style license, available at:
\r
13 * http://datatables.net/license_gpl2
\r
14 * http://datatables.net/license_bsd
\r
16 * This source file is distributed in the hope that it will be useful, but
\r
17 * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
\r
18 * or FITNESS FOR A PARTICULAR PURPOSE. See the license files for details.
\r
20 * For details please refer to: http://www.datatables.net
\r
23 /*jslint evil: true, undef: true, browser: true */
\r
24 /*globals $, jQuery,define,_fnExternApiFunc,_fnInitialise,_fnInitComplete,_fnLanguageCompat,_fnAddColumn,_fnColumnOptions,_fnAddData,_fnCreateTr,_fnGatherData,_fnBuildHead,_fnDrawHead,_fnDraw,_fnReDraw,_fnAjaxUpdate,_fnAjaxParameters,_fnAjaxUpdateDraw,_fnServerParams,_fnAddOptionsHtml,_fnFeatureHtmlTable,_fnScrollDraw,_fnAdjustColumnSizing,_fnFeatureHtmlFilter,_fnFilterComplete,_fnFilterCustom,_fnFilterColumn,_fnFilter,_fnBuildSearchArray,_fnBuildSearchRow,_fnFilterCreateSearch,_fnDataToSearch,_fnSort,_fnSortAttachListener,_fnSortingClasses,_fnFeatureHtmlPaginate,_fnPageChange,_fnFeatureHtmlInfo,_fnUpdateInfo,_fnFeatureHtmlLength,_fnFeatureHtmlProcessing,_fnProcessingDisplay,_fnVisibleToColumnIndex,_fnColumnIndexToVisible,_fnNodeToDataIndex,_fnVisbleColumns,_fnCalculateEnd,_fnConvertToWidth,_fnCalculateColumnWidths,_fnScrollingWidthAdjust,_fnGetWidestNode,_fnGetMaxLenString,_fnStringToCss,_fnDetectType,_fnSettingsFromNode,_fnGetDataMaster,_fnGetTrNodes,_fnGetTdNodes,_fnEscapeRegex,_fnDeleteIndex,_fnReOrderIndex,_fnColumnOrdering,_fnLog,_fnClearTable,_fnSaveState,_fnLoadState,_fnCreateCookie,_fnReadCookie,_fnDetectHeader,_fnGetUniqueThs,_fnScrollBarWidth,_fnApplyToChildren,_fnMap,_fnGetRowData,_fnGetCellData,_fnSetCellData,_fnGetObjectDataFn,_fnSetObjectDataFn,_fnApplyColumnDefs,_fnBindAction,_fnCallbackReg,_fnCallbackFire,_fnJsonString,_fnRender,_fnNodeToColumnIndex,_fnInfoMacros,_fnBrowserDetect,_fnGetColumns*/
\r
26 (/** @lends <global> */function( window, document, undefined ) {
\r
28 (function( factory ) {
\r
31 // Define as an AMD module if possible
\r
32 if ( typeof define === 'function' && define.amd )
\r
34 define( ['jquery'], factory );
\r
36 /* Define using browser globals otherwise
\r
37 * Prevent multiple instantiations if the script is loaded twice
\r
39 else if ( jQuery && !jQuery.fn.dataTable )
\r
44 (/** @lends <global> */function( $ ) {
\r
47 * DataTables is a plug-in for the jQuery Javascript library. It is a
\r
48 * highly flexible tool, based upon the foundations of progressive
\r
49 * enhancement, which will add advanced interaction controls to any
\r
50 * HTML table. For a full list of features please refer to
\r
51 * <a href="http://datatables.net">DataTables.net</a>.
\r
53 * Note that the <i>DataTable</i> object is not a global variable but is
\r
54 * aliased to <i>jQuery.fn.DataTable</i> and <i>jQuery.fn.dataTable</i> through which
\r
55 * it may be accessed.
\r
58 * @param {object} [oInit={}] Configuration object for DataTables. Options
\r
59 * are defined by {@link DataTable.defaults}
\r
60 * @requires jQuery 1.3+
\r
63 * // Basic initialisation
\r
64 * $(document).ready( function {
\r
65 * $('#example').dataTable();
\r
69 * // Initialisation with configuration options - in this case, disable
\r
70 * // pagination and sorting.
\r
71 * $(document).ready( function {
\r
72 * $('#example').dataTable( {
\r
73 * "bPaginate": false,
\r
78 var DataTable = function( oInit )
\r
83 * Add a column to the list used for the table with default values
\r
84 * @param {object} oSettings dataTables settings object
\r
85 * @param {node} nTh The th element for this column
\r
86 * @memberof DataTable#oApi
\r
88 function _fnAddColumn( oSettings, nTh )
\r
90 var oDefaults = DataTable.defaults.columns;
\r
91 var iCol = oSettings.aoColumns.length;
\r
92 var oCol = $.extend( {}, DataTable.models.oColumn, oDefaults, {
\r
93 "sSortingClass": oSettings.oClasses.sSortable,
\r
94 "sSortingClassJUI": oSettings.oClasses.sSortJUI,
\r
95 "nTh": nTh ? nTh : document.createElement('th'),
\r
96 "sTitle": oDefaults.sTitle ? oDefaults.sTitle : nTh ? nTh.innerHTML : '',
\r
97 "aDataSort": oDefaults.aDataSort ? oDefaults.aDataSort : [iCol],
\r
98 "mData": oDefaults.mData ? oDefaults.oDefaults : iCol
\r
100 oSettings.aoColumns.push( oCol );
\r
102 /* Add a column specific filter */
\r
103 if ( oSettings.aoPreSearchCols[ iCol ] === undefined || oSettings.aoPreSearchCols[ iCol ] === null )
\r
105 oSettings.aoPreSearchCols[ iCol ] = $.extend( {}, DataTable.models.oSearch );
\r
109 var oPre = oSettings.aoPreSearchCols[ iCol ];
\r
111 /* Don't require that the user must specify bRegex, bSmart or bCaseInsensitive */
\r
112 if ( oPre.bRegex === undefined )
\r
114 oPre.bRegex = true;
\r
117 if ( oPre.bSmart === undefined )
\r
119 oPre.bSmart = true;
\r
122 if ( oPre.bCaseInsensitive === undefined )
\r
124 oPre.bCaseInsensitive = true;
\r
128 /* Use the column options function to initialise classes etc */
\r
129 _fnColumnOptions( oSettings, iCol, null );
\r
134 * Apply options for a column
\r
135 * @param {object} oSettings dataTables settings object
\r
136 * @param {int} iCol column index to consider
\r
137 * @param {object} oOptions object with sType, bVisible and bSearchable etc
\r
138 * @memberof DataTable#oApi
\r
140 function _fnColumnOptions( oSettings, iCol, oOptions )
\r
142 var oCol = oSettings.aoColumns[ iCol ];
\r
144 /* User specified column options */
\r
145 if ( oOptions !== undefined && oOptions !== null )
\r
147 /* Backwards compatibility for mDataProp */
\r
148 if ( oOptions.mDataProp && !oOptions.mData )
\r
150 oOptions.mData = oOptions.mDataProp;
\r
153 if ( oOptions.sType !== undefined )
\r
155 oCol.sType = oOptions.sType;
\r
156 oCol._bAutoType = false;
\r
159 $.extend( oCol, oOptions );
\r
160 _fnMap( oCol, oOptions, "sWidth", "sWidthOrig" );
\r
162 /* iDataSort to be applied (backwards compatibility), but aDataSort will take
\r
163 * priority if defined
\r
165 if ( oOptions.iDataSort !== undefined )
\r
167 oCol.aDataSort = [ oOptions.iDataSort ];
\r
169 _fnMap( oCol, oOptions, "aDataSort" );
\r
172 /* Cache the data get and set functions for speed */
\r
173 var mRender = oCol.mRender ? _fnGetObjectDataFn( oCol.mRender ) : null;
\r
174 var mData = _fnGetObjectDataFn( oCol.mData );
\r
176 oCol.fnGetData = function (oData, sSpecific) {
\r
177 var innerData = mData( oData, sSpecific );
\r
179 if ( oCol.mRender && (sSpecific && sSpecific !== '') )
\r
181 return mRender( innerData, sSpecific, oData );
\r
185 oCol.fnSetData = _fnSetObjectDataFn( oCol.mData );
\r
187 /* Feature sorting overrides column specific when off */
\r
188 if ( !oSettings.oFeatures.bSort )
\r
190 oCol.bSortable = false;
\r
193 /* Check that the class assignment is correct for sorting */
\r
194 if ( !oCol.bSortable ||
\r
195 ($.inArray('asc', oCol.asSorting) == -1 && $.inArray('desc', oCol.asSorting) == -1) )
\r
197 oCol.sSortingClass = oSettings.oClasses.sSortableNone;
\r
198 oCol.sSortingClassJUI = "";
\r
200 else if ( $.inArray('asc', oCol.asSorting) == -1 && $.inArray('desc', oCol.asSorting) == -1 )
\r
202 oCol.sSortingClass = oSettings.oClasses.sSortable;
\r
203 oCol.sSortingClassJUI = oSettings.oClasses.sSortJUI;
\r
205 else if ( $.inArray('asc', oCol.asSorting) != -1 && $.inArray('desc', oCol.asSorting) == -1 )
\r
207 oCol.sSortingClass = oSettings.oClasses.sSortableAsc;
\r
208 oCol.sSortingClassJUI = oSettings.oClasses.sSortJUIAscAllowed;
\r
210 else if ( $.inArray('asc', oCol.asSorting) == -1 && $.inArray('desc', oCol.asSorting) != -1 )
\r
212 oCol.sSortingClass = oSettings.oClasses.sSortableDesc;
\r
213 oCol.sSortingClassJUI = oSettings.oClasses.sSortJUIDescAllowed;
\r
219 * Adjust the table column widths for new data. Note: you would probably want to
\r
220 * do a redraw after calling this function!
\r
221 * @param {object} oSettings dataTables settings object
\r
222 * @memberof DataTable#oApi
\r
224 function _fnAdjustColumnSizing ( oSettings )
\r
226 /* Not interested in doing column width calculation if auto-width is disabled */
\r
227 if ( oSettings.oFeatures.bAutoWidth === false )
\r
232 _fnCalculateColumnWidths( oSettings );
\r
233 for ( var i=0 , iLen=oSettings.aoColumns.length ; i<iLen ; i++ )
\r
235 oSettings.aoColumns[i].nTh.style.width = oSettings.aoColumns[i].sWidth;
\r
241 * Covert the index of a visible column to the index in the data array (take account
\r
242 * of hidden columns)
\r
243 * @param {object} oSettings dataTables settings object
\r
244 * @param {int} iMatch Visible column index to lookup
\r
245 * @returns {int} i the data index
\r
246 * @memberof DataTable#oApi
\r
248 function _fnVisibleToColumnIndex( oSettings, iMatch )
\r
250 var aiVis = _fnGetColumns( oSettings, 'bVisible' );
\r
252 return typeof aiVis[iMatch] === 'number' ?
\r
259 * Covert the index of an index in the data array and convert it to the visible
\r
260 * column index (take account of hidden columns)
\r
261 * @param {int} iMatch Column index to lookup
\r
262 * @param {object} oSettings dataTables settings object
\r
263 * @returns {int} i the data index
\r
264 * @memberof DataTable#oApi
\r
266 function _fnColumnIndexToVisible( oSettings, iMatch )
\r
268 var aiVis = _fnGetColumns( oSettings, 'bVisible' );
\r
269 var iPos = $.inArray( iMatch, aiVis );
\r
271 return iPos !== -1 ? iPos : null;
\r
276 * Get the number of visible columns
\r
277 * @param {object} oSettings dataTables settings object
\r
278 * @returns {int} i the number of visible columns
\r
279 * @memberof DataTable#oApi
\r
281 function _fnVisbleColumns( oSettings )
\r
283 return _fnGetColumns( oSettings, 'bVisible' ).length;
\r
288 * Get an array of column indexes that match a given property
\r
289 * @param {object} oSettings dataTables settings object
\r
290 * @param {string} sParam Parameter in aoColumns to look for - typically
\r
291 * bVisible or bSearchable
\r
292 * @returns {array} Array of indexes with matched properties
\r
293 * @memberof DataTable#oApi
\r
295 function _fnGetColumns( oSettings, sParam )
\r
299 $.map( oSettings.aoColumns, function(val, i) {
\r
300 if ( val[sParam] ) {
\r
310 * Get the sort type based on an input string
\r
311 * @param {string} sData data we wish to know the type of
\r
312 * @returns {string} type (defaults to 'string' if no type can be detected)
\r
313 * @memberof DataTable#oApi
\r
315 function _fnDetectType( sData )
\r
317 var aTypes = DataTable.ext.aTypes;
\r
318 var iLen = aTypes.length;
\r
320 for ( var i=0 ; i<iLen ; i++ )
\r
322 var sType = aTypes[i]( sData );
\r
323 if ( sType !== null )
\r
334 * Figure out how to reorder a display list
\r
335 * @param {object} oSettings dataTables settings object
\r
336 * @returns array {int} aiReturn index list for reordering
\r
337 * @memberof DataTable#oApi
\r
339 function _fnReOrderIndex ( oSettings, sColumns )
\r
341 var aColumns = sColumns.split(',');
\r
344 for ( var i=0, iLen=oSettings.aoColumns.length ; i<iLen ; i++ )
\r
346 for ( var j=0 ; j<iLen ; j++ )
\r
348 if ( oSettings.aoColumns[i].sName == aColumns[j] )
\r
350 aiReturn.push( j );
\r
361 * Get the column ordering that DataTables expects
\r
362 * @param {object} oSettings dataTables settings object
\r
363 * @returns {string} comma separated list of names
\r
364 * @memberof DataTable#oApi
\r
366 function _fnColumnOrdering ( oSettings )
\r
369 for ( var i=0, iLen=oSettings.aoColumns.length ; i<iLen ; i++ )
\r
371 sNames += oSettings.aoColumns[i].sName+',';
\r
373 if ( sNames.length == iLen )
\r
377 return sNames.slice(0, -1);
\r
382 * Take the column definitions and static columns arrays and calculate how
\r
383 * they relate to column indexes. The callback function will then apply the
\r
384 * definition found for a column to a suitable configuration object.
\r
385 * @param {object} oSettings dataTables settings object
\r
386 * @param {array} aoColDefs The aoColumnDefs array that is to be applied
\r
387 * @param {array} aoCols The aoColumns array that defines columns individually
\r
388 * @param {function} fn Callback function - takes two parameters, the calculated
\r
389 * column index and the definition for that column.
\r
390 * @memberof DataTable#oApi
\r
392 function _fnApplyColumnDefs( oSettings, aoColDefs, aoCols, fn )
\r
394 var i, iLen, j, jLen, k, kLen;
\r
396 // Column definitions with aTargets
\r
399 /* Loop over the definitions array - loop in reverse so first instance has priority */
\r
400 for ( i=aoColDefs.length-1 ; i>=0 ; i-- )
\r
402 /* Each definition can target multiple columns, as it is an array */
\r
403 var aTargets = aoColDefs[i].aTargets;
\r
404 if ( !$.isArray( aTargets ) )
\r
406 _fnLog( oSettings, 1, 'aTargets must be an array of targets, not a '+(typeof aTargets) );
\r
409 for ( j=0, jLen=aTargets.length ; j<jLen ; j++ )
\r
411 if ( typeof aTargets[j] === 'number' && aTargets[j] >= 0 )
\r
413 /* Add columns that we don't yet know about */
\r
414 while( oSettings.aoColumns.length <= aTargets[j] )
\r
416 _fnAddColumn( oSettings );
\r
419 /* Integer, basic index */
\r
420 fn( aTargets[j], aoColDefs[i] );
\r
422 else if ( typeof aTargets[j] === 'number' && aTargets[j] < 0 )
\r
424 /* Negative integer, right to left column counting */
\r
425 fn( oSettings.aoColumns.length+aTargets[j], aoColDefs[i] );
\r
427 else if ( typeof aTargets[j] === 'string' )
\r
429 /* Class name matching on TH element */
\r
430 for ( k=0, kLen=oSettings.aoColumns.length ; k<kLen ; k++ )
\r
432 if ( aTargets[j] == "_all" ||
\r
433 $(oSettings.aoColumns[k].nTh).hasClass( aTargets[j] ) )
\r
435 fn( k, aoColDefs[i] );
\r
443 // Statically defined columns array
\r
446 for ( i=0, iLen=aoCols.length ; i<iLen ; i++ )
\r
448 fn( i, aoCols[i] );
\r
454 * Add a data array to the table, creating DOM node etc. This is the parallel to
\r
455 * _fnGatherData, but for adding rows from a Javascript source, rather than a
\r
457 * @param {object} oSettings dataTables settings object
\r
458 * @param {array} aData data array to be added
\r
459 * @returns {int} >=0 if successful (index of new aoData entry), -1 if failed
\r
460 * @memberof DataTable#oApi
\r
462 function _fnAddData ( oSettings, aDataSupplied )
\r
466 /* Take an independent copy of the data source so we can bash it about as we wish */
\r
467 var aDataIn = ($.isArray(aDataSupplied)) ?
\r
468 aDataSupplied.slice() :
\r
469 $.extend( true, {}, aDataSupplied );
\r
471 /* Create the object for storing information about this new row */
\r
472 var iRow = oSettings.aoData.length;
\r
473 var oData = $.extend( true, {}, DataTable.models.oRow );
\r
474 oData._aData = aDataIn;
\r
475 oSettings.aoData.push( oData );
\r
477 /* Create the cells */
\r
478 var nTd, sThisType;
\r
479 for ( var i=0, iLen=oSettings.aoColumns.length ; i<iLen ; i++ )
\r
481 oCol = oSettings.aoColumns[i];
\r
483 /* Use rendered data for filtering / sorting */
\r
484 if ( typeof oCol.fnRender === 'function' && oCol.bUseRendered && oCol.mData !== null )
\r
486 _fnSetCellData( oSettings, iRow, i, _fnRender(oSettings, iRow, i) );
\r
490 _fnSetCellData( oSettings, iRow, i, _fnGetCellData( oSettings, iRow, i ) );
\r
493 /* See if we should auto-detect the column type */
\r
494 if ( oCol._bAutoType && oCol.sType != 'string' )
\r
496 /* Attempt to auto detect the type - same as _fnGatherData() */
\r
497 var sVarType = _fnGetCellData( oSettings, iRow, i, 'type' );
\r
498 if ( sVarType !== null && sVarType !== '' )
\r
500 sThisType = _fnDetectType( sVarType );
\r
501 if ( oCol.sType === null )
\r
503 oCol.sType = sThisType;
\r
505 else if ( oCol.sType != sThisType && oCol.sType != "html" )
\r
507 /* String is always the 'fallback' option */
\r
508 oCol.sType = 'string';
\r
514 /* Add to the display array */
\r
515 oSettings.aiDisplayMaster.push( iRow );
\r
517 /* Create the DOM information */
\r
518 if ( !oSettings.oFeatures.bDeferRender )
\r
520 _fnCreateTr( oSettings, iRow );
\r
528 * Read in the data from the target table from the DOM
\r
529 * @param {object} oSettings dataTables settings object
\r
530 * @memberof DataTable#oApi
\r
532 function _fnGatherData( oSettings )
\r
534 var iLoop, i, iLen, j, jLen, jInner,
\r
535 nTds, nTrs, nTd, nTr, aLocalData, iThisIndex,
\r
536 iRow, iRows, iColumn, iColumns, sNodeName,
\r
540 * Process by row first
\r
541 * Add the data object for the whole table - storing the tr node. Note - no point in getting
\r
542 * DOM based data if we are going to go and replace it with Ajax source data.
\r
544 if ( oSettings.bDeferLoading || oSettings.sAjaxSource === null )
\r
546 nTr = oSettings.nTBody.firstChild;
\r
549 if ( nTr.nodeName.toUpperCase() == "TR" )
\r
551 iThisIndex = oSettings.aoData.length;
\r
552 nTr._DT_RowIndex = iThisIndex;
\r
553 oSettings.aoData.push( $.extend( true, {}, DataTable.models.oRow, {
\r
557 oSettings.aiDisplayMaster.push( iThisIndex );
\r
558 nTd = nTr.firstChild;
\r
562 sNodeName = nTd.nodeName.toUpperCase();
\r
563 if ( sNodeName == "TD" || sNodeName == "TH" )
\r
565 _fnSetCellData( oSettings, iThisIndex, jInner, $.trim(nTd.innerHTML) );
\r
568 nTd = nTd.nextSibling;
\r
571 nTr = nTr.nextSibling;
\r
575 /* Gather in the TD elements of the Table - note that this is basically the same as
\r
576 * fnGetTdNodes, but that function takes account of hidden columns, which we haven't yet
\r
579 nTrs = _fnGetTrNodes( oSettings );
\r
581 for ( i=0, iLen=nTrs.length ; i<iLen ; i++ )
\r
583 nTd = nTrs[i].firstChild;
\r
586 sNodeName = nTd.nodeName.toUpperCase();
\r
587 if ( sNodeName == "TD" || sNodeName == "TH" )
\r
591 nTd = nTd.nextSibling;
\r
595 /* Now process by column */
\r
596 for ( iColumn=0, iColumns=oSettings.aoColumns.length ; iColumn<iColumns ; iColumn++ )
\r
598 oCol = oSettings.aoColumns[iColumn];
\r
600 /* Get the title of the column - unless there is a user set one */
\r
601 if ( oCol.sTitle === null )
\r
603 oCol.sTitle = oCol.nTh.innerHTML;
\r
607 bAutoType = oCol._bAutoType,
\r
608 bRender = typeof oCol.fnRender === 'function',
\r
609 bClass = oCol.sClass !== null,
\r
610 bVisible = oCol.bVisible,
\r
611 nCell, sThisType, sRendered, sValType;
\r
613 /* A single loop to rule them all (and be more efficient) */
\r
614 if ( bAutoType || bRender || bClass || !bVisible )
\r
616 for ( iRow=0, iRows=oSettings.aoData.length ; iRow<iRows ; iRow++ )
\r
618 oData = oSettings.aoData[iRow];
\r
619 nCell = nTds[ (iRow*iColumns) + iColumn ];
\r
621 /* Type detection */
\r
622 if ( bAutoType && oCol.sType != 'string' )
\r
624 sValType = _fnGetCellData( oSettings, iRow, iColumn, 'type' );
\r
625 if ( sValType !== '' )
\r
627 sThisType = _fnDetectType( sValType );
\r
628 if ( oCol.sType === null )
\r
630 oCol.sType = sThisType;
\r
632 else if ( oCol.sType != sThisType &&
\r
633 oCol.sType != "html" )
\r
635 /* String is always the 'fallback' option */
\r
636 oCol.sType = 'string';
\r
641 if ( oCol.mRender )
\r
643 // mRender has been defined, so we need to get the value and set it
\r
644 nCell.innerHTML = _fnGetCellData( oSettings, iRow, iColumn, 'display' );
\r
646 else if ( oCol.mData !== iColumn )
\r
648 // If mData is not the same as the column number, then we need to
\r
649 // get the dev set value. If it is the column, no point in wasting
\r
650 // time setting the value that is already there!
\r
651 nCell.innerHTML = _fnGetCellData( oSettings, iRow, iColumn, 'display' );
\r
657 sRendered = _fnRender( oSettings, iRow, iColumn );
\r
658 nCell.innerHTML = sRendered;
\r
659 if ( oCol.bUseRendered )
\r
661 /* Use the rendered data for filtering / sorting */
\r
662 _fnSetCellData( oSettings, iRow, iColumn, sRendered );
\r
669 nCell.className += ' '+oCol.sClass;
\r
672 /* Column visibility */
\r
675 oData._anHidden[iColumn] = nCell;
\r
676 nCell.parentNode.removeChild( nCell );
\r
680 oData._anHidden[iColumn] = null;
\r
683 if ( oCol.fnCreatedCell )
\r
685 oCol.fnCreatedCell.call( oSettings.oInstance,
\r
686 nCell, _fnGetCellData( oSettings, iRow, iColumn, 'display' ), oData._aData, iRow, iColumn
\r
693 /* Row created callbacks */
\r
694 if ( oSettings.aoRowCreatedCallback.length !== 0 )
\r
696 for ( i=0, iLen=oSettings.aoData.length ; i<iLen ; i++ )
\r
698 oData = oSettings.aoData[i];
\r
699 _fnCallbackFire( oSettings, 'aoRowCreatedCallback', null, [oData.nTr, oData._aData, i] );
\r
706 * Take a TR element and convert it to an index in aoData
\r
707 * @param {object} oSettings dataTables settings object
\r
708 * @param {node} n the TR element to find
\r
709 * @returns {int} index if the node is found, null if not
\r
710 * @memberof DataTable#oApi
\r
712 function _fnNodeToDataIndex( oSettings, n )
\r
714 return (n._DT_RowIndex!==undefined) ? n._DT_RowIndex : null;
\r
719 * Take a TD element and convert it into a column data index (not the visible index)
\r
720 * @param {object} oSettings dataTables settings object
\r
721 * @param {int} iRow The row number the TD/TH can be found in
\r
722 * @param {node} n The TD/TH element to find
\r
723 * @returns {int} index if the node is found, -1 if not
\r
724 * @memberof DataTable#oApi
\r
726 function _fnNodeToColumnIndex( oSettings, iRow, n )
\r
728 var anCells = _fnGetTdNodes( oSettings, iRow );
\r
730 for ( var i=0, iLen=oSettings.aoColumns.length ; i<iLen ; i++ )
\r
732 if ( anCells[i] === n )
\r
742 * Get an array of data for a given row from the internal data cache
\r
743 * @param {object} oSettings dataTables settings object
\r
744 * @param {int} iRow aoData row id
\r
745 * @param {string} sSpecific data get type ('type' 'filter' 'sort')
\r
746 * @param {array} aiColumns Array of column indexes to get data from
\r
747 * @returns {array} Data array
\r
748 * @memberof DataTable#oApi
\r
750 function _fnGetRowData( oSettings, iRow, sSpecific, aiColumns )
\r
753 for ( var i=0, iLen=aiColumns.length ; i<iLen ; i++ )
\r
755 out.push( _fnGetCellData( oSettings, iRow, aiColumns[i], sSpecific ) );
\r
762 * Get the data for a given cell from the internal cache, taking into account data mapping
\r
763 * @param {object} oSettings dataTables settings object
\r
764 * @param {int} iRow aoData row id
\r
765 * @param {int} iCol Column index
\r
766 * @param {string} sSpecific data get type ('display', 'type' 'filter' 'sort')
\r
767 * @returns {*} Cell data
\r
768 * @memberof DataTable#oApi
\r
770 function _fnGetCellData( oSettings, iRow, iCol, sSpecific )
\r
773 var oCol = oSettings.aoColumns[iCol];
\r
774 var oData = oSettings.aoData[iRow]._aData;
\r
776 if ( (sData=oCol.fnGetData( oData, sSpecific )) === undefined )
\r
778 if ( oSettings.iDrawError != oSettings.iDraw && oCol.sDefaultContent === null )
\r
780 _fnLog( oSettings, 1, "Requested unknown parameter "+
\r
781 (typeof oCol.mData=='function' ? '{mData function}' : "'"+oCol.mData+"'")+
\r
782 " from the data source for row "+iRow );
\r
783 oSettings.iDrawError = oSettings.iDraw;
\r
785 return oCol.sDefaultContent;
\r
788 /* When the data source is null, we can use default column data */
\r
789 if ( sData === null && oCol.sDefaultContent !== null )
\r
791 sData = oCol.sDefaultContent;
\r
793 else if ( typeof sData === 'function' )
\r
795 /* If the data source is a function, then we run it and use the return */
\r
799 if ( sSpecific == 'display' && sData === null )
\r
808 * Set the value for a specific cell, into the internal data cache
\r
809 * @param {object} oSettings dataTables settings object
\r
810 * @param {int} iRow aoData row id
\r
811 * @param {int} iCol Column index
\r
812 * @param {*} val Value to set
\r
813 * @memberof DataTable#oApi
\r
815 function _fnSetCellData( oSettings, iRow, iCol, val )
\r
817 var oCol = oSettings.aoColumns[iCol];
\r
818 var oData = oSettings.aoData[iRow]._aData;
\r
820 oCol.fnSetData( oData, val );
\r
824 // Private variable that is used to match array syntax in the data property object
\r
825 var __reArray = /\[.*?\]$/;
\r
828 * Return a function that can be used to get data from a source object, taking
\r
829 * into account the ability to use nested objects as a source
\r
830 * @param {string|int|function} mSource The data source for the object
\r
831 * @returns {function} Data get function
\r
832 * @memberof DataTable#oApi
\r
834 function _fnGetObjectDataFn( mSource )
\r
836 if ( mSource === null )
\r
838 /* Give an empty string for rendering / sorting etc */
\r
839 return function (data, type) {
\r
843 else if ( typeof mSource === 'function' )
\r
845 return function (data, type, extra) {
\r
846 return mSource( data, type, extra );
\r
849 else if ( typeof mSource === 'string' && (mSource.indexOf('.') !== -1 || mSource.indexOf('[') !== -1) )
\r
851 /* If there is a . in the source string then the data source is in a
\r
852 * nested object so we loop over the data for each level to get the next
\r
853 * level down. On each loop we test for undefined, and if found immediately
\r
854 * return. This allows entire objects to be missing and sDefaultContent to
\r
855 * be used if defined, rather than throwing an error
\r
857 var fetchData = function (data, type, src) {
\r
858 var a = src.split('.');
\r
859 var arrayNotation, out, innerSrc;
\r
863 for ( var i=0, iLen=a.length ; i<iLen ; i++ )
\r
865 // Check if we are dealing with an array notation request
\r
866 arrayNotation = a[i].match(__reArray);
\r
868 if ( arrayNotation ) {
\r
869 a[i] = a[i].replace(__reArray, '');
\r
871 // Condition allows simply [] to be passed in
\r
872 if ( a[i] !== "" ) {
\r
873 data = data[ a[i] ];
\r
877 // Get the remainder of the nested object to get
\r
878 a.splice( 0, i+1 );
\r
879 innerSrc = a.join('.');
\r
881 // Traverse each entry in the array getting the properties requested
\r
882 for ( var j=0, jLen=data.length ; j<jLen ; j++ ) {
\r
883 out.push( fetchData( data[j], type, innerSrc ) );
\r
886 // If a string is given in between the array notation indicators, that
\r
887 // is used to join the strings together, otherwise an array is returned
\r
888 var join = arrayNotation[0].substring(1, arrayNotation[0].length-1);
\r
889 data = (join==="") ? out : out.join(join);
\r
891 // The inner call to fetchData has already traversed through the remainder
\r
892 // of the source requested, so we exit from the loop
\r
896 if ( data === null || data[ a[i] ] === undefined )
\r
900 data = data[ a[i] ];
\r
907 return function (data, type) {
\r
908 return fetchData( data, type, mSource );
\r
913 /* Array or flat object mapping */
\r
914 return function (data, type) {
\r
915 return data[mSource];
\r
922 * Return a function that can be used to set data from a source object, taking
\r
923 * into account the ability to use nested objects as a source
\r
924 * @param {string|int|function} mSource The data source for the object
\r
925 * @returns {function} Data set function
\r
926 * @memberof DataTable#oApi
\r
928 function _fnSetObjectDataFn( mSource )
\r
930 if ( mSource === null )
\r
932 /* Nothing to do when the data source is null */
\r
933 return function (data, val) {};
\r
935 else if ( typeof mSource === 'function' )
\r
937 return function (data, val) {
\r
938 mSource( data, 'set', val );
\r
941 else if ( typeof mSource === 'string' && (mSource.indexOf('.') !== -1 || mSource.indexOf('[') !== -1) )
\r
943 /* Like the get, we need to get data from a nested object */
\r
944 var setData = function (data, val, src) {
\r
945 var a = src.split('.'), b;
\r
946 var arrayNotation, o, innerSrc;
\r
948 for ( var i=0, iLen=a.length-1 ; i<iLen ; i++ )
\r
950 // Check if we are dealing with an array notation request
\r
951 arrayNotation = a[i].match(__reArray);
\r
953 if ( arrayNotation )
\r
955 a[i] = a[i].replace(__reArray, '');
\r
958 // Get the remainder of the nested object to set so we can recurse
\r
960 b.splice( 0, i+1 );
\r
961 innerSrc = b.join('.');
\r
963 // Traverse each entry in the array setting the properties requested
\r
964 for ( var j=0, jLen=val.length ; j<jLen ; j++ )
\r
967 setData( o, val[j], innerSrc );
\r
968 data[ a[i] ].push( o );
\r
971 // The inner call to setData has already traversed through the remainder
\r
972 // of the source and has set the data, thus we can exit here
\r
976 // If the nested object doesn't currently exist - since we are
\r
977 // trying to set the value - create it
\r
978 if ( data[ a[i] ] === null || data[ a[i] ] === undefined )
\r
982 data = data[ a[i] ];
\r
985 // If array notation is used, we just want to strip it and use the property name
\r
986 // and assign the value. If it isn't used, then we get the result we want anyway
\r
987 data[ a[a.length-1].replace(__reArray, '') ] = val;
\r
990 return function (data, val) {
\r
991 return setData( data, val, mSource );
\r
996 /* Array or flat object mapping */
\r
997 return function (data, val) {
\r
998 data[mSource] = val;
\r
1005 * Return an array with the full table data
\r
1006 * @param {object} oSettings dataTables settings object
\r
1007 * @returns array {array} aData Master data array
\r
1008 * @memberof DataTable#oApi
\r
1010 function _fnGetDataMaster ( oSettings )
\r
1013 var iLen = oSettings.aoData.length;
\r
1014 for ( var i=0 ; i<iLen; i++ )
\r
1016 aData.push( oSettings.aoData[i]._aData );
\r
1024 * @param {object} oSettings dataTables settings object
\r
1025 * @memberof DataTable#oApi
\r
1027 function _fnClearTable( oSettings )
\r
1029 oSettings.aoData.splice( 0, oSettings.aoData.length );
\r
1030 oSettings.aiDisplayMaster.splice( 0, oSettings.aiDisplayMaster.length );
\r
1031 oSettings.aiDisplay.splice( 0, oSettings.aiDisplay.length );
\r
1032 _fnCalculateEnd( oSettings );
\r
1037 * Take an array of integers (index array) and remove a target integer (value - not
\r
1039 * @param {array} a Index array to target
\r
1040 * @param {int} iTarget value to find
\r
1041 * @memberof DataTable#oApi
\r
1043 function _fnDeleteIndex( a, iTarget )
\r
1045 var iTargetIndex = -1;
\r
1047 for ( var i=0, iLen=a.length ; i<iLen ; i++ )
\r
1049 if ( a[i] == iTarget )
\r
1053 else if ( a[i] > iTarget )
\r
1059 if ( iTargetIndex != -1 )
\r
1061 a.splice( iTargetIndex, 1 );
\r
1067 * Call the developer defined fnRender function for a given cell (row/column) with
\r
1068 * the required parameters and return the result.
\r
1069 * @param {object} oSettings dataTables settings object
\r
1070 * @param {int} iRow aoData index for the row
\r
1071 * @param {int} iCol aoColumns index for the column
\r
1072 * @returns {*} Return of the developer's fnRender function
\r
1073 * @memberof DataTable#oApi
\r
1075 function _fnRender( oSettings, iRow, iCol )
\r
1077 var oCol = oSettings.aoColumns[iCol];
\r
1079 return oCol.fnRender( {
\r
1081 "iDataColumn": iCol,
\r
1082 "oSettings": oSettings,
\r
1083 "aData": oSettings.aoData[iRow]._aData,
\r
1084 "mDataProp": oCol.mData
\r
1085 }, _fnGetCellData(oSettings, iRow, iCol, 'display') );
\r
1088 * Create a new TR element (and it's TD children) for a row
\r
1089 * @param {object} oSettings dataTables settings object
\r
1090 * @param {int} iRow Row to consider
\r
1091 * @memberof DataTable#oApi
\r
1093 function _fnCreateTr ( oSettings, iRow )
\r
1095 var oData = oSettings.aoData[iRow];
\r
1098 if ( oData.nTr === null )
\r
1100 oData.nTr = document.createElement('tr');
\r
1102 /* Use a private property on the node to allow reserve mapping from the node
\r
1103 * to the aoData array for fast look up
\r
1105 oData.nTr._DT_RowIndex = iRow;
\r
1107 /* Special parameters can be given by the data source to be used on the row */
\r
1108 if ( oData._aData.DT_RowId )
\r
1110 oData.nTr.id = oData._aData.DT_RowId;
\r
1113 if ( oData._aData.DT_RowClass )
\r
1115 oData.nTr.className = oData._aData.DT_RowClass;
\r
1118 /* Process each column */
\r
1119 for ( var i=0, iLen=oSettings.aoColumns.length ; i<iLen ; i++ )
\r
1121 var oCol = oSettings.aoColumns[i];
\r
1122 nTd = document.createElement( oCol.sCellType );
\r
1124 /* Render if needed - if bUseRendered is true then we already have the rendered
\r
1125 * value in the data source - so can just use that
\r
1127 nTd.innerHTML = (typeof oCol.fnRender === 'function' && (!oCol.bUseRendered || oCol.mData === null)) ?
\r
1128 _fnRender( oSettings, iRow, i ) :
\r
1129 _fnGetCellData( oSettings, iRow, i, 'display' );
\r
1131 /* Add user defined class */
\r
1132 if ( oCol.sClass !== null )
\r
1134 nTd.className = oCol.sClass;
\r
1137 if ( oCol.bVisible )
\r
1139 oData.nTr.appendChild( nTd );
\r
1140 oData._anHidden[i] = null;
\r
1144 oData._anHidden[i] = nTd;
\r
1147 if ( oCol.fnCreatedCell )
\r
1149 oCol.fnCreatedCell.call( oSettings.oInstance,
\r
1150 nTd, _fnGetCellData( oSettings, iRow, i, 'display' ), oData._aData, iRow, i
\r
1155 _fnCallbackFire( oSettings, 'aoRowCreatedCallback', null, [oData.nTr, oData._aData, iRow] );
\r
1161 * Create the HTML header for the table
\r
1162 * @param {object} oSettings dataTables settings object
\r
1163 * @memberof DataTable#oApi
\r
1165 function _fnBuildHead( oSettings )
\r
1167 var i, nTh, iLen, j, jLen;
\r
1168 var iThs = $('th, td', oSettings.nTHead).length;
\r
1169 var iCorrector = 0;
\r
1172 /* If there is a header in place - then use it - otherwise it's going to get nuked... */
\r
1175 /* We've got a thead from the DOM, so remove hidden columns and apply width to vis cols */
\r
1176 for ( i=0, iLen=oSettings.aoColumns.length ; i<iLen ; i++ )
\r
1178 nTh = oSettings.aoColumns[i].nTh;
\r
1179 nTh.setAttribute('role', 'columnheader');
\r
1180 if ( oSettings.aoColumns[i].bSortable )
\r
1182 nTh.setAttribute('tabindex', oSettings.iTabIndex);
\r
1183 nTh.setAttribute('aria-controls', oSettings.sTableId);
\r
1186 if ( oSettings.aoColumns[i].sClass !== null )
\r
1188 $(nTh).addClass( oSettings.aoColumns[i].sClass );
\r
1191 /* Set the title of the column if it is user defined (not what was auto detected) */
\r
1192 if ( oSettings.aoColumns[i].sTitle != nTh.innerHTML )
\r
1194 nTh.innerHTML = oSettings.aoColumns[i].sTitle;
\r
1200 /* We don't have a header in the DOM - so we are going to have to create one */
\r
1201 var nTr = document.createElement( "tr" );
\r
1203 for ( i=0, iLen=oSettings.aoColumns.length ; i<iLen ; i++ )
\r
1205 nTh = oSettings.aoColumns[i].nTh;
\r
1206 nTh.innerHTML = oSettings.aoColumns[i].sTitle;
\r
1207 nTh.setAttribute('tabindex', '0');
\r
1209 if ( oSettings.aoColumns[i].sClass !== null )
\r
1211 $(nTh).addClass( oSettings.aoColumns[i].sClass );
\r
1214 nTr.appendChild( nTh );
\r
1216 $(oSettings.nTHead).html( '' )[0].appendChild( nTr );
\r
1217 _fnDetectHeader( oSettings.aoHeader, oSettings.nTHead );
\r
1220 /* ARIA role for the rows */
\r
1221 $(oSettings.nTHead).children('tr').attr('role', 'row');
\r
1223 /* Add the extra markup needed by jQuery UI's themes */
\r
1224 if ( oSettings.bJUI )
\r
1226 for ( i=0, iLen=oSettings.aoColumns.length ; i<iLen ; i++ )
\r
1228 nTh = oSettings.aoColumns[i].nTh;
\r
1230 var nDiv = document.createElement('div');
\r
1231 nDiv.className = oSettings.oClasses.sSortJUIWrapper;
\r
1232 $(nTh).contents().appendTo(nDiv);
\r
1234 var nSpan = document.createElement('span');
\r
1235 nSpan.className = oSettings.oClasses.sSortIcon;
\r
1236 nDiv.appendChild( nSpan );
\r
1237 nTh.appendChild( nDiv );
\r
1241 if ( oSettings.oFeatures.bSort )
\r
1243 for ( i=0 ; i<oSettings.aoColumns.length ; i++ )
\r
1245 if ( oSettings.aoColumns[i].bSortable !== false )
\r
1247 _fnSortAttachListener( oSettings, oSettings.aoColumns[i].nTh, i );
\r
1251 $(oSettings.aoColumns[i].nTh).addClass( oSettings.oClasses.sSortableNone );
\r
1256 /* Deal with the footer - add classes if required */
\r
1257 if ( oSettings.oClasses.sFooterTH !== "" )
\r
1259 $(oSettings.nTFoot).children('tr').children('th').addClass( oSettings.oClasses.sFooterTH );
\r
1262 /* Cache the footer elements */
\r
1263 if ( oSettings.nTFoot !== null )
\r
1265 var anCells = _fnGetUniqueThs( oSettings, null, oSettings.aoFooter );
\r
1266 for ( i=0, iLen=oSettings.aoColumns.length ; i<iLen ; i++ )
\r
1270 oSettings.aoColumns[i].nTf = anCells[i];
\r
1271 if ( oSettings.aoColumns[i].sClass )
\r
1273 $(anCells[i]).addClass( oSettings.aoColumns[i].sClass );
\r
1282 * Draw the header (or footer) element based on the column visibility states. The
\r
1283 * methodology here is to use the layout array from _fnDetectHeader, modified for
\r
1284 * the instantaneous column visibility, to construct the new layout. The grid is
\r
1285 * traversed over cell at a time in a rows x columns grid fashion, although each
\r
1286 * cell insert can cover multiple elements in the grid - which is tracks using the
\r
1287 * aApplied array. Cell inserts in the grid will only occur where there isn't
\r
1288 * already a cell in that position.
\r
1289 * @param {object} oSettings dataTables settings object
\r
1290 * @param array {objects} aoSource Layout array from _fnDetectHeader
\r
1291 * @param {boolean} [bIncludeHidden=false] If true then include the hidden columns in the calc,
\r
1292 * @memberof DataTable#oApi
\r
1294 function _fnDrawHead( oSettings, aoSource, bIncludeHidden )
\r
1296 var i, iLen, j, jLen, k, kLen, n, nLocalTr;
\r
1298 var aApplied = [];
\r
1299 var iColumns = oSettings.aoColumns.length;
\r
1300 var iRowspan, iColspan;
\r
1302 if ( bIncludeHidden === undefined )
\r
1304 bIncludeHidden = false;
\r
1307 /* Make a copy of the master layout array, but without the visible columns in it */
\r
1308 for ( i=0, iLen=aoSource.length ; i<iLen ; i++ )
\r
1310 aoLocal[i] = aoSource[i].slice();
\r
1311 aoLocal[i].nTr = aoSource[i].nTr;
\r
1313 /* Remove any columns which are currently hidden */
\r
1314 for ( j=iColumns-1 ; j>=0 ; j-- )
\r
1316 if ( !oSettings.aoColumns[j].bVisible && !bIncludeHidden )
\r
1318 aoLocal[i].splice( j, 1 );
\r
1322 /* Prep the applied array - it needs an element for each row */
\r
1323 aApplied.push( [] );
\r
1326 for ( i=0, iLen=aoLocal.length ; i<iLen ; i++ )
\r
1328 nLocalTr = aoLocal[i].nTr;
\r
1330 /* All cells are going to be replaced, so empty out the row */
\r
1333 while( (n = nLocalTr.firstChild) )
\r
1335 nLocalTr.removeChild( n );
\r
1339 for ( j=0, jLen=aoLocal[i].length ; j<jLen ; j++ )
\r
1344 /* Check to see if there is already a cell (row/colspan) covering our target
\r
1345 * insert point. If there is, then there is nothing to do.
\r
1347 if ( aApplied[i][j] === undefined )
\r
1349 nLocalTr.appendChild( aoLocal[i][j].cell );
\r
1350 aApplied[i][j] = 1;
\r
1352 /* Expand the cell to cover as many rows as needed */
\r
1353 while ( aoLocal[i+iRowspan] !== undefined &&
\r
1354 aoLocal[i][j].cell == aoLocal[i+iRowspan][j].cell )
\r
1356 aApplied[i+iRowspan][j] = 1;
\r
1360 /* Expand the cell to cover as many columns as needed */
\r
1361 while ( aoLocal[i][j+iColspan] !== undefined &&
\r
1362 aoLocal[i][j].cell == aoLocal[i][j+iColspan].cell )
\r
1364 /* Must update the applied array over the rows for the columns */
\r
1365 for ( k=0 ; k<iRowspan ; k++ )
\r
1367 aApplied[i+k][j+iColspan] = 1;
\r
1372 /* Do the actual expansion in the DOM */
\r
1373 aoLocal[i][j].cell.rowSpan = iRowspan;
\r
1374 aoLocal[i][j].cell.colSpan = iColspan;
\r
1382 * Insert the required TR nodes into the table for display
\r
1383 * @param {object} oSettings dataTables settings object
\r
1384 * @memberof DataTable#oApi
\r
1386 function _fnDraw( oSettings )
\r
1388 /* Provide a pre-callback function which can be used to cancel the draw is false is returned */
\r
1389 var aPreDraw = _fnCallbackFire( oSettings, 'aoPreDrawCallback', 'preDraw', [oSettings] );
\r
1390 if ( $.inArray( false, aPreDraw ) !== -1 )
\r
1392 _fnProcessingDisplay( oSettings, false );
\r
1398 var iRowCount = 0;
\r
1399 var iStripes = oSettings.asStripeClasses.length;
\r
1400 var iOpenRows = oSettings.aoOpenRows.length;
\r
1402 oSettings.bDrawing = true;
\r
1404 /* Check and see if we have an initial draw position from state saving */
\r
1405 if ( oSettings.iInitDisplayStart !== undefined && oSettings.iInitDisplayStart != -1 )
\r
1407 if ( oSettings.oFeatures.bServerSide )
\r
1409 oSettings._iDisplayStart = oSettings.iInitDisplayStart;
\r
1413 oSettings._iDisplayStart = (oSettings.iInitDisplayStart >= oSettings.fnRecordsDisplay()) ?
\r
1414 0 : oSettings.iInitDisplayStart;
\r
1416 oSettings.iInitDisplayStart = -1;
\r
1417 _fnCalculateEnd( oSettings );
\r
1420 /* Server-side processing draw intercept */
\r
1421 if ( oSettings.bDeferLoading )
\r
1423 oSettings.bDeferLoading = false;
\r
1424 oSettings.iDraw++;
\r
1426 else if ( !oSettings.oFeatures.bServerSide )
\r
1428 oSettings.iDraw++;
\r
1430 else if ( !oSettings.bDestroying && !_fnAjaxUpdate( oSettings ) )
\r
1435 if ( oSettings.aiDisplay.length !== 0 )
\r
1437 var iStart = oSettings._iDisplayStart;
\r
1438 var iEnd = oSettings._iDisplayEnd;
\r
1440 if ( oSettings.oFeatures.bServerSide )
\r
1443 iEnd = oSettings.aoData.length;
\r
1446 for ( var j=iStart ; j<iEnd ; j++ )
\r
1448 var aoData = oSettings.aoData[ oSettings.aiDisplay[j] ];
\r
1449 if ( aoData.nTr === null )
\r
1451 _fnCreateTr( oSettings, oSettings.aiDisplay[j] );
\r
1454 var nRow = aoData.nTr;
\r
1456 /* Remove the old striping classes and then add the new one */
\r
1457 if ( iStripes !== 0 )
\r
1459 var sStripe = oSettings.asStripeClasses[ iRowCount % iStripes ];
\r
1460 if ( aoData._sRowStripe != sStripe )
\r
1462 $(nRow).removeClass( aoData._sRowStripe ).addClass( sStripe );
\r
1463 aoData._sRowStripe = sStripe;
\r
1467 /* Row callback functions - might want to manipulate the row */
\r
1468 _fnCallbackFire( oSettings, 'aoRowCallback', null,
\r
1469 [nRow, oSettings.aoData[ oSettings.aiDisplay[j] ]._aData, iRowCount, j] );
\r
1471 anRows.push( nRow );
\r
1474 /* If there is an open row - and it is attached to this parent - attach it on redraw */
\r
1475 if ( iOpenRows !== 0 )
\r
1477 for ( var k=0 ; k<iOpenRows ; k++ )
\r
1479 if ( nRow == oSettings.aoOpenRows[k].nParent )
\r
1481 anRows.push( oSettings.aoOpenRows[k].nTr );
\r
1490 /* Table is empty - create a row with an empty message in it */
\r
1491 anRows[ 0 ] = document.createElement( 'tr' );
\r
1493 if ( oSettings.asStripeClasses[0] )
\r
1495 anRows[ 0 ].className = oSettings.asStripeClasses[0];
\r
1498 var oLang = oSettings.oLanguage;
\r
1499 var sZero = oLang.sZeroRecords;
\r
1500 if ( oSettings.iDraw == 1 && oSettings.sAjaxSource !== null && !oSettings.oFeatures.bServerSide )
\r
1502 sZero = oLang.sLoadingRecords;
\r
1504 else if ( oLang.sEmptyTable && oSettings.fnRecordsTotal() === 0 )
\r
1506 sZero = oLang.sEmptyTable;
\r
1509 var nTd = document.createElement( 'td' );
\r
1510 nTd.setAttribute( 'valign', "top" );
\r
1511 nTd.colSpan = _fnVisbleColumns( oSettings );
\r
1512 nTd.className = oSettings.oClasses.sRowEmpty;
\r
1513 nTd.innerHTML = _fnInfoMacros( oSettings, sZero );
\r
1515 anRows[ iRowCount ].appendChild( nTd );
\r
1518 /* Header and footer callbacks */
\r
1519 _fnCallbackFire( oSettings, 'aoHeaderCallback', 'header', [ $(oSettings.nTHead).children('tr')[0],
\r
1520 _fnGetDataMaster( oSettings ), oSettings._iDisplayStart, oSettings.fnDisplayEnd(), oSettings.aiDisplay ] );
\r
1522 _fnCallbackFire( oSettings, 'aoFooterCallback', 'footer', [ $(oSettings.nTFoot).children('tr')[0],
\r
1523 _fnGetDataMaster( oSettings ), oSettings._iDisplayStart, oSettings.fnDisplayEnd(), oSettings.aiDisplay ] );
\r
1526 * Need to remove any old row from the display - note we can't just empty the tbody using
\r
1527 * $().html('') since this will unbind the jQuery event handlers (even although the node
\r
1528 * still exists!) - equally we can't use innerHTML, since IE throws an exception.
\r
1531 nAddFrag = document.createDocumentFragment(),
\r
1532 nRemoveFrag = document.createDocumentFragment(),
\r
1535 if ( oSettings.nTBody )
\r
1537 nBodyPar = oSettings.nTBody.parentNode;
\r
1538 nRemoveFrag.appendChild( oSettings.nTBody );
\r
1540 /* When doing infinite scrolling, only remove child rows when sorting, filtering or start
\r
1541 * up. When not infinite scroll, always do it.
\r
1543 if ( !oSettings.oScroll.bInfinite || !oSettings._bInitComplete ||
\r
1544 oSettings.bSorted || oSettings.bFiltered )
\r
1546 while( (n = oSettings.nTBody.firstChild) )
\r
1548 oSettings.nTBody.removeChild( n );
\r
1552 /* Put the draw table into the dom */
\r
1553 for ( i=0, iLen=anRows.length ; i<iLen ; i++ )
\r
1555 nAddFrag.appendChild( anRows[i] );
\r
1558 oSettings.nTBody.appendChild( nAddFrag );
\r
1559 if ( nBodyPar !== null )
\r
1561 nBodyPar.appendChild( oSettings.nTBody );
\r
1565 /* Call all required callback functions for the end of a draw */
\r
1566 _fnCallbackFire( oSettings, 'aoDrawCallback', 'draw', [oSettings] );
\r
1568 /* Draw is complete, sorting and filtering must be as well */
\r
1569 oSettings.bSorted = false;
\r
1570 oSettings.bFiltered = false;
\r
1571 oSettings.bDrawing = false;
\r
1573 if ( oSettings.oFeatures.bServerSide )
\r
1575 _fnProcessingDisplay( oSettings, false );
\r
1576 if ( !oSettings._bInitComplete )
\r
1578 _fnInitComplete( oSettings );
\r
1585 * Redraw the table - taking account of the various features which are enabled
\r
1586 * @param {object} oSettings dataTables settings object
\r
1587 * @memberof DataTable#oApi
\r
1589 function _fnReDraw( oSettings )
\r
1591 if ( oSettings.oFeatures.bSort )
\r
1593 /* Sorting will refilter and draw for us */
\r
1594 _fnSort( oSettings, oSettings.oPreviousSearch );
\r
1596 else if ( oSettings.oFeatures.bFilter )
\r
1598 /* Filtering will redraw for us */
\r
1599 _fnFilterComplete( oSettings, oSettings.oPreviousSearch );
\r
1603 _fnCalculateEnd( oSettings );
\r
1604 _fnDraw( oSettings );
\r
1610 * Add the options to the page HTML for the table
\r
1611 * @param {object} oSettings dataTables settings object
\r
1612 * @memberof DataTable#oApi
\r
1614 function _fnAddOptionsHtml ( oSettings )
\r
1617 * Create a temporary, empty, div which we can later on replace with what we have generated
\r
1618 * we do it this way to rendering the 'options' html offline - speed :-)
\r
1620 var nHolding = $('<div></div>')[0];
\r
1621 oSettings.nTable.parentNode.insertBefore( nHolding, oSettings.nTable );
\r
1624 * All DataTables are wrapped in a div
\r
1626 oSettings.nTableWrapper = $('<div id="'+oSettings.sTableId+'_wrapper" class="'+oSettings.oClasses.sWrapper+'" role="grid"></div>')[0];
\r
1627 oSettings.nTableReinsertBefore = oSettings.nTable.nextSibling;
\r
1629 /* Track where we want to insert the option */
\r
1630 var nInsertNode = oSettings.nTableWrapper;
\r
1632 /* Loop over the user set positioning and place the elements as needed */
\r
1633 var aDom = oSettings.sDom.split('');
\r
1634 var nTmp, iPushFeature, cOption, nNewNode, cNext, sAttr, j;
\r
1635 for ( var i=0 ; i<aDom.length ; i++ )
\r
1638 cOption = aDom[i];
\r
1640 if ( cOption == '<' )
\r
1642 /* New container div */
\r
1643 nNewNode = $('<div></div>')[0];
\r
1645 /* Check to see if we should append an id and/or a class name to the container */
\r
1646 cNext = aDom[i+1];
\r
1647 if ( cNext == "'" || cNext == '"' )
\r
1651 while ( aDom[i+j] != cNext )
\r
1653 sAttr += aDom[i+j];
\r
1657 /* Replace jQuery UI constants */
\r
1658 if ( sAttr == "H" )
\r
1660 sAttr = oSettings.oClasses.sJUIHeader;
\r
1662 else if ( sAttr == "F" )
\r
1664 sAttr = oSettings.oClasses.sJUIFooter;
\r
1667 /* The attribute can be in the format of "#id.class", "#id" or "class" This logic
\r
1668 * breaks the string into parts and applies them as needed
\r
1670 if ( sAttr.indexOf('.') != -1 )
\r
1672 var aSplit = sAttr.split('.');
\r
1673 nNewNode.id = aSplit[0].substr(1, aSplit[0].length-1);
\r
1674 nNewNode.className = aSplit[1];
\r
1676 else if ( sAttr.charAt(0) == "#" )
\r
1678 nNewNode.id = sAttr.substr(1, sAttr.length-1);
\r
1682 nNewNode.className = sAttr;
\r
1685 i += j; /* Move along the position array */
\r
1688 nInsertNode.appendChild( nNewNode );
\r
1689 nInsertNode = nNewNode;
\r
1691 else if ( cOption == '>' )
\r
1693 /* End container div */
\r
1694 nInsertNode = nInsertNode.parentNode;
\r
1696 else if ( cOption == 'l' && oSettings.oFeatures.bPaginate && oSettings.oFeatures.bLengthChange )
\r
1699 nTmp = _fnFeatureHtmlLength( oSettings );
\r
1702 else if ( cOption == 'f' && oSettings.oFeatures.bFilter )
\r
1705 nTmp = _fnFeatureHtmlFilter( oSettings );
\r
1708 else if ( cOption == 'r' && oSettings.oFeatures.bProcessing )
\r
1711 nTmp = _fnFeatureHtmlProcessing( oSettings );
\r
1714 else if ( cOption == 't' )
\r
1717 nTmp = _fnFeatureHtmlTable( oSettings );
\r
1720 else if ( cOption == 'i' && oSettings.oFeatures.bInfo )
\r
1723 nTmp = _fnFeatureHtmlInfo( oSettings );
\r
1726 else if ( cOption == 'p' && oSettings.oFeatures.bPaginate )
\r
1729 nTmp = _fnFeatureHtmlPaginate( oSettings );
\r
1732 else if ( DataTable.ext.aoFeatures.length !== 0 )
\r
1734 /* Plug-in features */
\r
1735 var aoFeatures = DataTable.ext.aoFeatures;
\r
1736 for ( var k=0, kLen=aoFeatures.length ; k<kLen ; k++ )
\r
1738 if ( cOption == aoFeatures[k].cFeature )
\r
1740 nTmp = aoFeatures[k].fnInit( oSettings );
\r
1750 /* Add to the 2D features array */
\r
1751 if ( iPushFeature == 1 && nTmp !== null )
\r
1753 if ( typeof oSettings.aanFeatures[cOption] !== 'object' )
\r
1755 oSettings.aanFeatures[cOption] = [];
\r
1757 oSettings.aanFeatures[cOption].push( nTmp );
\r
1758 nInsertNode.appendChild( nTmp );
\r
1762 /* Built our DOM structure - replace the holding div with what we want */
\r
1763 nHolding.parentNode.replaceChild( oSettings.nTableWrapper, nHolding );
\r
1768 * Use the DOM source to create up an array of header cells. The idea here is to
\r
1769 * create a layout grid (array) of rows x columns, which contains a reference
\r
1770 * to the cell that that point in the grid (regardless of col/rowspan), such that
\r
1771 * any column / row could be removed and the new grid constructed
\r
1772 * @param array {object} aLayout Array to store the calculated layout in
\r
1773 * @param {node} nThead The header/footer element for the table
\r
1774 * @memberof DataTable#oApi
\r
1776 function _fnDetectHeader ( aLayout, nThead )
\r
1778 var nTrs = $(nThead).children('tr');
\r
1780 var i, k, l, iLen, jLen, iColShifted, iColumn, iColspan, iRowspan;
\r
1782 var fnShiftCol = function ( a, i, j ) {
\r
1790 aLayout.splice( 0, aLayout.length );
\r
1792 /* We know how many rows there are in the layout - so prep it */
\r
1793 for ( i=0, iLen=nTrs.length ; i<iLen ; i++ )
\r
1795 aLayout.push( [] );
\r
1798 /* Calculate a layout array */
\r
1799 for ( i=0, iLen=nTrs.length ; i<iLen ; i++ )
\r
1804 /* For every cell in the row... */
\r
1805 nCell = nTr.firstChild;
\r
1807 if ( nCell.nodeName.toUpperCase() == "TD" ||
\r
1808 nCell.nodeName.toUpperCase() == "TH" )
\r
1810 /* Get the col and rowspan attributes from the DOM and sanitise them */
\r
1811 iColspan = nCell.getAttribute('colspan') * 1;
\r
1812 iRowspan = nCell.getAttribute('rowspan') * 1;
\r
1813 iColspan = (!iColspan || iColspan===0 || iColspan===1) ? 1 : iColspan;
\r
1814 iRowspan = (!iRowspan || iRowspan===0 || iRowspan===1) ? 1 : iRowspan;
\r
1816 /* There might be colspan cells already in this row, so shift our target
\r
1819 iColShifted = fnShiftCol( aLayout, i, iColumn );
\r
1821 /* Cache calculation for unique columns */
\r
1822 bUnique = iColspan === 1 ? true : false;
\r
1824 /* If there is col / rowspan, copy the information into the layout grid */
\r
1825 for ( l=0 ; l<iColspan ; l++ )
\r
1827 for ( k=0 ; k<iRowspan ; k++ )
\r
1829 aLayout[i+k][iColShifted+l] = {
\r
1833 aLayout[i+k].nTr = nTr;
\r
1837 nCell = nCell.nextSibling;
\r
1844 * Get an array of unique th elements, one for each column
\r
1845 * @param {object} oSettings dataTables settings object
\r
1846 * @param {node} nHeader automatically detect the layout from this node - optional
\r
1847 * @param {array} aLayout thead/tfoot layout from _fnDetectHeader - optional
\r
1848 * @returns array {node} aReturn list of unique th's
\r
1849 * @memberof DataTable#oApi
\r
1851 function _fnGetUniqueThs ( oSettings, nHeader, aLayout )
\r
1856 aLayout = oSettings.aoHeader;
\r
1860 _fnDetectHeader( aLayout, nHeader );
\r
1864 for ( var i=0, iLen=aLayout.length ; i<iLen ; i++ )
\r
1866 for ( var j=0, jLen=aLayout[i].length ; j<jLen ; j++ )
\r
1868 if ( aLayout[i][j].unique &&
\r
1869 (!aReturn[j] || !oSettings.bSortCellsTop) )
\r
1871 aReturn[j] = aLayout[i][j].cell;
\r
1882 * Update the table using an Ajax call
\r
1883 * @param {object} oSettings dataTables settings object
\r
1884 * @returns {boolean} Block the table drawing or not
\r
1885 * @memberof DataTable#oApi
\r
1887 function _fnAjaxUpdate( oSettings )
\r
1889 if ( oSettings.bAjaxDataGet )
\r
1891 oSettings.iDraw++;
\r
1892 _fnProcessingDisplay( oSettings, true );
\r
1893 var iColumns = oSettings.aoColumns.length;
\r
1894 var aoData = _fnAjaxParameters( oSettings );
\r
1895 _fnServerParams( oSettings, aoData );
\r
1897 oSettings.fnServerData.call( oSettings.oInstance, oSettings.sAjaxSource, aoData,
\r
1899 _fnAjaxUpdateDraw( oSettings, json );
\r
1911 * Build up the parameters in an object needed for a server-side processing request
\r
1912 * @param {object} oSettings dataTables settings object
\r
1913 * @returns {bool} block the table drawing or not
\r
1914 * @memberof DataTable#oApi
\r
1916 function _fnAjaxParameters( oSettings )
\r
1918 var iColumns = oSettings.aoColumns.length;
\r
1919 var aoData = [], mDataProp, aaSort, aDataSort;
\r
1922 aoData.push( { "name": "sEcho", "value": oSettings.iDraw } );
\r
1923 aoData.push( { "name": "iColumns", "value": iColumns } );
\r
1924 aoData.push( { "name": "sColumns", "value": _fnColumnOrdering(oSettings) } );
\r
1925 aoData.push( { "name": "iDisplayStart", "value": oSettings._iDisplayStart } );
\r
1926 aoData.push( { "name": "iDisplayLength", "value": oSettings.oFeatures.bPaginate !== false ?
\r
1927 oSettings._iDisplayLength : -1 } );
\r
1929 for ( i=0 ; i<iColumns ; i++ )
\r
1931 mDataProp = oSettings.aoColumns[i].mData;
\r
1932 aoData.push( { "name": "mDataProp_"+i, "value": typeof(mDataProp)==="function" ? 'function' : mDataProp } );
\r
1936 if ( oSettings.oFeatures.bFilter !== false )
\r
1938 aoData.push( { "name": "sSearch", "value": oSettings.oPreviousSearch.sSearch } );
\r
1939 aoData.push( { "name": "bRegex", "value": oSettings.oPreviousSearch.bRegex } );
\r
1940 for ( i=0 ; i<iColumns ; i++ )
\r
1942 aoData.push( { "name": "sSearch_"+i, "value": oSettings.aoPreSearchCols[i].sSearch } );
\r
1943 aoData.push( { "name": "bRegex_"+i, "value": oSettings.aoPreSearchCols[i].bRegex } );
\r
1944 aoData.push( { "name": "bSearchable_"+i, "value": oSettings.aoColumns[i].bSearchable } );
\r
1949 if ( oSettings.oFeatures.bSort !== false )
\r
1953 aaSort = ( oSettings.aaSortingFixed !== null ) ?
\r
1954 oSettings.aaSortingFixed.concat( oSettings.aaSorting ) :
\r
1955 oSettings.aaSorting.slice();
\r
1957 for ( i=0 ; i<aaSort.length ; i++ )
\r
1959 aDataSort = oSettings.aoColumns[ aaSort[i][0] ].aDataSort;
\r
1961 for ( j=0 ; j<aDataSort.length ; j++ )
\r
1963 aoData.push( { "name": "iSortCol_"+iCounter, "value": aDataSort[j] } );
\r
1964 aoData.push( { "name": "sSortDir_"+iCounter, "value": aaSort[i][1] } );
\r
1968 aoData.push( { "name": "iSortingCols", "value": iCounter } );
\r
1970 for ( i=0 ; i<iColumns ; i++ )
\r
1972 aoData.push( { "name": "bSortable_"+i, "value": oSettings.aoColumns[i].bSortable } );
\r
1981 * Add Ajax parameters from plug-ins
\r
1982 * @param {object} oSettings dataTables settings object
\r
1983 * @param array {objects} aoData name/value pairs to send to the server
\r
1984 * @memberof DataTable#oApi
\r
1986 function _fnServerParams( oSettings, aoData )
\r
1988 _fnCallbackFire( oSettings, 'aoServerParams', 'serverParams', [aoData] );
\r
1993 * Data the data from the server (nuking the old) and redraw the table
\r
1994 * @param {object} oSettings dataTables settings object
\r
1995 * @param {object} json json data return from the server.
\r
1996 * @param {string} json.sEcho Tracking flag for DataTables to match requests
\r
1997 * @param {int} json.iTotalRecords Number of records in the data set, not accounting for filtering
\r
1998 * @param {int} json.iTotalDisplayRecords Number of records in the data set, accounting for filtering
\r
1999 * @param {array} json.aaData The data to display on this page
\r
2000 * @param {string} [json.sColumns] Column ordering (sName, comma separated)
\r
2001 * @memberof DataTable#oApi
\r
2003 function _fnAjaxUpdateDraw ( oSettings, json )
\r
2005 if ( json.sEcho !== undefined )
\r
2007 /* Protect against old returns over-writing a new one. Possible when you get
\r
2008 * very fast interaction, and later queries are completed much faster
\r
2010 if ( json.sEcho*1 < oSettings.iDraw )
\r
2016 oSettings.iDraw = json.sEcho * 1;
\r
2020 if ( !oSettings.oScroll.bInfinite ||
\r
2021 (oSettings.oScroll.bInfinite && (oSettings.bSorted || oSettings.bFiltered)) )
\r
2023 _fnClearTable( oSettings );
\r
2025 oSettings._iRecordsTotal = parseInt(json.iTotalRecords, 10);
\r
2026 oSettings._iRecordsDisplay = parseInt(json.iTotalDisplayRecords, 10);
\r
2028 /* Determine if reordering is required */
\r
2029 var sOrdering = _fnColumnOrdering(oSettings);
\r
2030 var bReOrder = (json.sColumns !== undefined && sOrdering !== "" && json.sColumns != sOrdering );
\r
2034 aiIndex = _fnReOrderIndex( oSettings, json.sColumns );
\r
2037 var aData = _fnGetObjectDataFn( oSettings.sAjaxDataProp )( json );
\r
2038 for ( var i=0, iLen=aData.length ; i<iLen ; i++ )
\r
2042 /* If we need to re-order, then create a new array with the correct order and add it */
\r
2043 var aDataSorted = [];
\r
2044 for ( var j=0, jLen=oSettings.aoColumns.length ; j<jLen ; j++ )
\r
2046 aDataSorted.push( aData[i][ aiIndex[j] ] );
\r
2048 _fnAddData( oSettings, aDataSorted );
\r
2052 /* No re-order required, sever got it "right" - just straight add */
\r
2053 _fnAddData( oSettings, aData[i] );
\r
2056 oSettings.aiDisplay = oSettings.aiDisplayMaster.slice();
\r
2058 oSettings.bAjaxDataGet = false;
\r
2059 _fnDraw( oSettings );
\r
2060 oSettings.bAjaxDataGet = true;
\r
2061 _fnProcessingDisplay( oSettings, false );
\r
2067 * Generate the node required for filtering text
\r
2068 * @returns {node} Filter control element
\r
2069 * @param {object} oSettings dataTables settings object
\r
2070 * @memberof DataTable#oApi
\r
2072 function _fnFeatureHtmlFilter ( oSettings )
\r
2074 var oPreviousSearch = oSettings.oPreviousSearch;
\r
2076 var sSearchStr = oSettings.oLanguage.sSearch;
\r
2077 sSearchStr = (sSearchStr.indexOf('_INPUT_') !== -1) ?
\r
2078 sSearchStr.replace('_INPUT_', '<input type="text" />') :
\r
2079 sSearchStr==="" ? '<input type="text" />' : sSearchStr+' <input type="text" />';
\r
2081 var nFilter = document.createElement( 'div' );
\r
2082 nFilter.className = oSettings.oClasses.sFilter;
\r
2083 nFilter.innerHTML = '<label>'+sSearchStr+'</label>';
\r
2084 if ( !oSettings.aanFeatures.f )
\r
2086 nFilter.id = oSettings.sTableId+'_filter';
\r
2089 var jqFilter = $('input[type="text"]', nFilter);
\r
2091 // Store a reference to the input element, so other input elements could be
\r
2092 // added to the filter wrapper if needed (submit button for example)
\r
2093 nFilter._DT_Input = jqFilter[0];
\r
2095 jqFilter.val( oPreviousSearch.sSearch.replace('"','"') );
\r
2096 jqFilter.bind( 'keyup.DT', function(e) {
\r
2097 /* Update all other filter input elements for the new display */
\r
2098 var n = oSettings.aanFeatures.f;
\r
2099 var val = this.value==="" ? "" : this.value; // mental IE8 fix :-(
\r
2101 for ( var i=0, iLen=n.length ; i<iLen ; i++ )
\r
2103 if ( n[i] != $(this).parents('div.dataTables_filter')[0] )
\r
2105 $(n[i]._DT_Input).val( val );
\r
2109 /* Now do the filter */
\r
2110 if ( val != oPreviousSearch.sSearch )
\r
2112 _fnFilterComplete( oSettings, {
\r
2114 "bRegex": oPreviousSearch.bRegex,
\r
2115 "bSmart": oPreviousSearch.bSmart ,
\r
2116 "bCaseInsensitive": oPreviousSearch.bCaseInsensitive
\r
2122 .attr('aria-controls', oSettings.sTableId)
\r
2123 .bind( 'keypress.DT', function(e) {
\r
2124 /* Prevent form submission */
\r
2125 if ( e.keyCode == 13 )
\r
2137 * Filter the table using both the global filter and column based filtering
\r
2138 * @param {object} oSettings dataTables settings object
\r
2139 * @param {object} oSearch search information
\r
2140 * @param {int} [iForce] force a research of the master array (1) or not (undefined or 0)
\r
2141 * @memberof DataTable#oApi
\r
2143 function _fnFilterComplete ( oSettings, oInput, iForce )
\r
2145 var oPrevSearch = oSettings.oPreviousSearch;
\r
2146 var aoPrevSearch = oSettings.aoPreSearchCols;
\r
2147 var fnSaveFilter = function ( oFilter ) {
\r
2148 /* Save the filtering values */
\r
2149 oPrevSearch.sSearch = oFilter.sSearch;
\r
2150 oPrevSearch.bRegex = oFilter.bRegex;
\r
2151 oPrevSearch.bSmart = oFilter.bSmart;
\r
2152 oPrevSearch.bCaseInsensitive = oFilter.bCaseInsensitive;
\r
2155 /* In server-side processing all filtering is done by the server, so no point hanging around here */
\r
2156 if ( !oSettings.oFeatures.bServerSide )
\r
2158 /* Global filter */
\r
2159 _fnFilter( oSettings, oInput.sSearch, iForce, oInput.bRegex, oInput.bSmart, oInput.bCaseInsensitive );
\r
2160 fnSaveFilter( oInput );
\r
2162 /* Now do the individual column filter */
\r
2163 for ( var i=0 ; i<oSettings.aoPreSearchCols.length ; i++ )
\r
2165 _fnFilterColumn( oSettings, aoPrevSearch[i].sSearch, i, aoPrevSearch[i].bRegex,
\r
2166 aoPrevSearch[i].bSmart, aoPrevSearch[i].bCaseInsensitive );
\r
2169 /* Custom filtering */
\r
2170 _fnFilterCustom( oSettings );
\r
2174 fnSaveFilter( oInput );
\r
2177 /* Tell the draw function we have been filtering */
\r
2178 oSettings.bFiltered = true;
\r
2179 $(oSettings.oInstance).trigger('filter', oSettings);
\r
2181 /* Redraw the table */
\r
2182 oSettings._iDisplayStart = 0;
\r
2183 _fnCalculateEnd( oSettings );
\r
2184 _fnDraw( oSettings );
\r
2186 /* Rebuild search array 'offline' */
\r
2187 _fnBuildSearchArray( oSettings, 0 );
\r
2192 * Apply custom filtering functions
\r
2193 * @param {object} oSettings dataTables settings object
\r
2194 * @memberof DataTable#oApi
\r
2196 function _fnFilterCustom( oSettings )
\r
2198 var afnFilters = DataTable.ext.afnFiltering;
\r
2199 var aiFilterColumns = _fnGetColumns( oSettings, 'bSearchable' );
\r
2201 for ( var i=0, iLen=afnFilters.length ; i<iLen ; i++ )
\r
2203 var iCorrector = 0;
\r
2204 for ( var j=0, jLen=oSettings.aiDisplay.length ; j<jLen ; j++ )
\r
2206 var iDisIndex = oSettings.aiDisplay[j-iCorrector];
\r
2207 var bTest = afnFilters[i](
\r
2209 _fnGetRowData( oSettings, iDisIndex, 'filter', aiFilterColumns ),
\r
2213 /* Check if we should use this row based on the filtering function */
\r
2216 oSettings.aiDisplay.splice( j-iCorrector, 1 );
\r
2225 * Filter the table on a per-column basis
\r
2226 * @param {object} oSettings dataTables settings object
\r
2227 * @param {string} sInput string to filter on
\r
2228 * @param {int} iColumn column to filter
\r
2229 * @param {bool} bRegex treat search string as a regular expression or not
\r
2230 * @param {bool} bSmart use smart filtering or not
\r
2231 * @param {bool} bCaseInsensitive Do case insenstive matching or not
\r
2232 * @memberof DataTable#oApi
\r
2234 function _fnFilterColumn ( oSettings, sInput, iColumn, bRegex, bSmart, bCaseInsensitive )
\r
2236 if ( sInput === "" )
\r
2241 var iIndexCorrector = 0;
\r
2242 var rpSearch = _fnFilterCreateSearch( sInput, bRegex, bSmart, bCaseInsensitive );
\r
2244 for ( var i=oSettings.aiDisplay.length-1 ; i>=0 ; i-- )
\r
2246 var sData = _fnDataToSearch( _fnGetCellData( oSettings, oSettings.aiDisplay[i], iColumn, 'filter' ),
\r
2247 oSettings.aoColumns[iColumn].sType );
\r
2248 if ( ! rpSearch.test( sData ) )
\r
2250 oSettings.aiDisplay.splice( i, 1 );
\r
2251 iIndexCorrector++;
\r
2258 * Filter the data table based on user input and draw the table
\r
2259 * @param {object} oSettings dataTables settings object
\r
2260 * @param {string} sInput string to filter on
\r
2261 * @param {int} iForce optional - force a research of the master array (1) or not (undefined or 0)
\r
2262 * @param {bool} bRegex treat as a regular expression or not
\r
2263 * @param {bool} bSmart perform smart filtering or not
\r
2264 * @param {bool} bCaseInsensitive Do case insenstive matching or not
\r
2265 * @memberof DataTable#oApi
\r
2267 function _fnFilter( oSettings, sInput, iForce, bRegex, bSmart, bCaseInsensitive )
\r
2270 var rpSearch = _fnFilterCreateSearch( sInput, bRegex, bSmart, bCaseInsensitive );
\r
2271 var oPrevSearch = oSettings.oPreviousSearch;
\r
2273 /* Check if we are forcing or not - optional parameter */
\r
2279 /* Need to take account of custom filtering functions - always filter */
\r
2280 if ( DataTable.ext.afnFiltering.length !== 0 )
\r
2286 * If the input is blank - we want the full data set
\r
2288 if ( sInput.length <= 0 )
\r
2290 oSettings.aiDisplay.splice( 0, oSettings.aiDisplay.length);
\r
2291 oSettings.aiDisplay = oSettings.aiDisplayMaster.slice();
\r
2296 * We are starting a new search or the new search string is smaller
\r
2297 * then the old one (i.e. delete). Search from the master array
\r
2299 if ( oSettings.aiDisplay.length == oSettings.aiDisplayMaster.length ||
\r
2300 oPrevSearch.sSearch.length > sInput.length || iForce == 1 ||
\r
2301 sInput.indexOf(oPrevSearch.sSearch) !== 0 )
\r
2303 /* Nuke the old display array - we are going to rebuild it */
\r
2304 oSettings.aiDisplay.splice( 0, oSettings.aiDisplay.length);
\r
2306 /* Force a rebuild of the search array */
\r
2307 _fnBuildSearchArray( oSettings, 1 );
\r
2309 /* Search through all records to populate the search array
\r
2310 * The the oSettings.aiDisplayMaster and asDataSearch arrays have 1 to 1
\r
2313 for ( i=0 ; i<oSettings.aiDisplayMaster.length ; i++ )
\r
2315 if ( rpSearch.test(oSettings.asDataSearch[i]) )
\r
2317 oSettings.aiDisplay.push( oSettings.aiDisplayMaster[i] );
\r
2323 /* Using old search array - refine it - do it this way for speed
\r
2324 * Don't have to search the whole master array again
\r
2326 var iIndexCorrector = 0;
\r
2328 /* Search the current results */
\r
2329 for ( i=0 ; i<oSettings.asDataSearch.length ; i++ )
\r
2331 if ( ! rpSearch.test(oSettings.asDataSearch[i]) )
\r
2333 oSettings.aiDisplay.splice( i-iIndexCorrector, 1 );
\r
2334 iIndexCorrector++;
\r
2343 * Create an array which can be quickly search through
\r
2344 * @param {object} oSettings dataTables settings object
\r
2345 * @param {int} iMaster use the master data array - optional
\r
2346 * @memberof DataTable#oApi
\r
2348 function _fnBuildSearchArray ( oSettings, iMaster )
\r
2350 if ( !oSettings.oFeatures.bServerSide )
\r
2352 /* Clear out the old data */
\r
2353 oSettings.asDataSearch = [];
\r
2355 var aiFilterColumns = _fnGetColumns( oSettings, 'bSearchable' );
\r
2356 var aiIndex = (iMaster===1) ?
\r
2357 oSettings.aiDisplayMaster :
\r
2358 oSettings.aiDisplay;
\r
2360 for ( var i=0, iLen=aiIndex.length ; i<iLen ; i++ )
\r
2362 oSettings.asDataSearch[i] = _fnBuildSearchRow(
\r
2364 _fnGetRowData( oSettings, aiIndex[i], 'filter', aiFilterColumns )
\r
2372 * Create a searchable string from a single data row
\r
2373 * @param {object} oSettings dataTables settings object
\r
2374 * @param {array} aData Row data array to use for the data to search
\r
2375 * @memberof DataTable#oApi
\r
2377 function _fnBuildSearchRow( oSettings, aData )
\r
2379 var sSearch = aData.join(' ');
\r
2381 /* If it looks like there is an HTML entity in the string, attempt to decode it */
\r
2382 if ( sSearch.indexOf('&') !== -1 )
\r
2384 sSearch = $('<div>').html(sSearch).text();
\r
2387 // Strip newline characters
\r
2388 return sSearch.replace( /[\n\r]/g, " " );
\r
2392 * Build a regular expression object suitable for searching a table
\r
2393 * @param {string} sSearch string to search for
\r
2394 * @param {bool} bRegex treat as a regular expression or not
\r
2395 * @param {bool} bSmart perform smart filtering or not
\r
2396 * @param {bool} bCaseInsensitive Do case insensitive matching or not
\r
2397 * @returns {RegExp} constructed object
\r
2398 * @memberof DataTable#oApi
\r
2400 function _fnFilterCreateSearch( sSearch, bRegex, bSmart, bCaseInsensitive )
\r
2402 var asSearch, sRegExpString;
\r
2406 /* Generate the regular expression to use. Something along the lines of:
\r
2407 * ^(?=.*?\bone\b)(?=.*?\btwo\b)(?=.*?\bthree\b).*$
\r
2409 asSearch = bRegex ? sSearch.split( ' ' ) : _fnEscapeRegex( sSearch ).split( ' ' );
\r
2410 sRegExpString = '^(?=.*?'+asSearch.join( ')(?=.*?' )+').*$';
\r
2411 return new RegExp( sRegExpString, bCaseInsensitive ? "i" : "" );
\r
2415 sSearch = bRegex ? sSearch : _fnEscapeRegex( sSearch );
\r
2416 return new RegExp( sSearch, bCaseInsensitive ? "i" : "" );
\r
2422 * Convert raw data into something that the user can search on
\r
2423 * @param {string} sData data to be modified
\r
2424 * @param {string} sType data type
\r
2425 * @returns {string} search string
\r
2426 * @memberof DataTable#oApi
\r
2428 function _fnDataToSearch ( sData, sType )
\r
2430 if ( typeof DataTable.ext.ofnSearch[sType] === "function" )
\r
2432 return DataTable.ext.ofnSearch[sType]( sData );
\r
2434 else if ( sData === null )
\r
2438 else if ( sType == "html" )
\r
2440 return sData.replace(/[\r\n]/g," ").replace( /<.*?>/g, "" );
\r
2442 else if ( typeof sData === "string" )
\r
2444 return sData.replace(/[\r\n]/g," ");
\r
2451 * scape a string such that it can be used in a regular expression
\r
2452 * @param {string} sVal string to escape
\r
2453 * @returns {string} escaped string
\r
2454 * @memberof DataTable#oApi
\r
2456 function _fnEscapeRegex ( sVal )
\r
2458 var acEscape = [ '/', '.', '*', '+', '?', '|', '(', ')', '[', ']', '{', '}', '\\', '$', '^', '-' ];
\r
2459 var reReplace = new RegExp( '(\\' + acEscape.join('|\\') + ')', 'g' );
\r
2460 return sVal.replace(reReplace, '\\$1');
\r
2465 * Generate the node required for the info display
\r
2466 * @param {object} oSettings dataTables settings object
\r
2467 * @returns {node} Information element
\r
2468 * @memberof DataTable#oApi
\r
2470 function _fnFeatureHtmlInfo ( oSettings )
\r
2472 var nInfo = document.createElement( 'div' );
\r
2473 nInfo.className = oSettings.oClasses.sInfo;
\r
2475 /* Actions that are to be taken once only for this feature */
\r
2476 if ( !oSettings.aanFeatures.i )
\r
2478 /* Add draw callback */
\r
2479 oSettings.aoDrawCallback.push( {
\r
2480 "fn": _fnUpdateInfo,
\r
2481 "sName": "information"
\r
2485 nInfo.id = oSettings.sTableId+'_info';
\r
2487 oSettings.nTable.setAttribute( 'aria-describedby', oSettings.sTableId+'_info' );
\r
2494 * Update the information elements in the display
\r
2495 * @param {object} oSettings dataTables settings object
\r
2496 * @memberof DataTable#oApi
\r
2498 function _fnUpdateInfo ( oSettings )
\r
2500 /* Show information about the table */
\r
2501 if ( !oSettings.oFeatures.bInfo || oSettings.aanFeatures.i.length === 0 )
\r
2507 oLang = oSettings.oLanguage,
\r
2508 iStart = oSettings._iDisplayStart+1,
\r
2509 iEnd = oSettings.fnDisplayEnd(),
\r
2510 iMax = oSettings.fnRecordsTotal(),
\r
2511 iTotal = oSettings.fnRecordsDisplay(),
\r
2514 if ( iTotal === 0 )
\r
2516 /* Empty record set */
\r
2517 sOut = oLang.sInfoEmpty;
\r
2520 /* Normal record set */
\r
2521 sOut = oLang.sInfo;
\r
2524 if ( iTotal != iMax )
\r
2526 /* Record set after filtering */
\r
2527 sOut += ' ' + oLang.sInfoFiltered;
\r
2530 // Convert the macros
\r
2531 sOut += oLang.sInfoPostFix;
\r
2532 sOut = _fnInfoMacros( oSettings, sOut );
\r
2534 if ( oLang.fnInfoCallback !== null )
\r
2536 sOut = oLang.fnInfoCallback.call( oSettings.oInstance,
\r
2537 oSettings, iStart, iEnd, iMax, iTotal, sOut );
\r
2540 var n = oSettings.aanFeatures.i;
\r
2541 for ( var i=0, iLen=n.length ; i<iLen ; i++ )
\r
2543 $(n[i]).html( sOut );
\r
2548 function _fnInfoMacros ( oSettings, str )
\r
2551 iStart = oSettings._iDisplayStart+1,
\r
2552 sStart = oSettings.fnFormatNumber( iStart ),
\r
2553 iEnd = oSettings.fnDisplayEnd(),
\r
2554 sEnd = oSettings.fnFormatNumber( iEnd ),
\r
2555 iTotal = oSettings.fnRecordsDisplay(),
\r
2556 sTotal = oSettings.fnFormatNumber( iTotal ),
\r
2557 iMax = oSettings.fnRecordsTotal(),
\r
2558 sMax = oSettings.fnFormatNumber( iMax );
\r
2560 // When infinite scrolling, we are always starting at 1. _iDisplayStart is used only
\r
2562 if ( oSettings.oScroll.bInfinite )
\r
2564 sStart = oSettings.fnFormatNumber( 1 );
\r
2568 replace(/_START_/g, sStart).
\r
2569 replace(/_END_/g, sEnd).
\r
2570 replace(/_TOTAL_/g, sTotal).
\r
2571 replace(/_MAX_/g, sMax);
\r
2577 * Draw the table for the first time, adding all required features
\r
2578 * @param {object} oSettings dataTables settings object
\r
2579 * @memberof DataTable#oApi
\r
2581 function _fnInitialise ( oSettings )
\r
2583 var i, iLen, iAjaxStart=oSettings.iInitDisplayStart;
\r
2585 /* Ensure that the table data is fully initialised */
\r
2586 if ( oSettings.bInitialised === false )
\r
2588 setTimeout( function(){ _fnInitialise( oSettings ); }, 200 );
\r
2592 /* Show the display HTML options */
\r
2593 _fnAddOptionsHtml( oSettings );
\r
2595 /* Build and draw the header / footer for the table */
\r
2596 _fnBuildHead( oSettings );
\r
2597 _fnDrawHead( oSettings, oSettings.aoHeader );
\r
2598 if ( oSettings.nTFoot )
\r
2600 _fnDrawHead( oSettings, oSettings.aoFooter );
\r
2603 /* Okay to show that something is going on now */
\r
2604 _fnProcessingDisplay( oSettings, true );
\r
2606 /* Calculate sizes for columns */
\r
2607 if ( oSettings.oFeatures.bAutoWidth )
\r
2609 _fnCalculateColumnWidths( oSettings );
\r
2612 for ( i=0, iLen=oSettings.aoColumns.length ; i<iLen ; i++ )
\r
2614 if ( oSettings.aoColumns[i].sWidth !== null )
\r
2616 oSettings.aoColumns[i].nTh.style.width = _fnStringToCss( oSettings.aoColumns[i].sWidth );
\r
2620 /* If there is default sorting required - let's do it. The sort function will do the
\r
2621 * drawing for us. Otherwise we draw the table regardless of the Ajax source - this allows
\r
2622 * the table to look initialised for Ajax sourcing data (show 'loading' message possibly)
\r
2624 if ( oSettings.oFeatures.bSort )
\r
2626 _fnSort( oSettings );
\r
2628 else if ( oSettings.oFeatures.bFilter )
\r
2630 _fnFilterComplete( oSettings, oSettings.oPreviousSearch );
\r
2634 oSettings.aiDisplay = oSettings.aiDisplayMaster.slice();
\r
2635 _fnCalculateEnd( oSettings );
\r
2636 _fnDraw( oSettings );
\r
2639 /* if there is an ajax source load the data */
\r
2640 if ( oSettings.sAjaxSource !== null && !oSettings.oFeatures.bServerSide )
\r
2643 _fnServerParams( oSettings, aoData );
\r
2644 oSettings.fnServerData.call( oSettings.oInstance, oSettings.sAjaxSource, aoData, function(json) {
\r
2645 var aData = (oSettings.sAjaxDataProp !== "") ?
\r
2646 _fnGetObjectDataFn( oSettings.sAjaxDataProp )(json) : json;
\r
2648 /* Got the data - add it to the table */
\r
2649 for ( i=0 ; i<aData.length ; i++ )
\r
2651 _fnAddData( oSettings, aData[i] );
\r
2654 /* Reset the init display for cookie saving. We've already done a filter, and
\r
2655 * therefore cleared it before. So we need to make it appear 'fresh'
\r
2657 oSettings.iInitDisplayStart = iAjaxStart;
\r
2659 if ( oSettings.oFeatures.bSort )
\r
2661 _fnSort( oSettings );
\r
2665 oSettings.aiDisplay = oSettings.aiDisplayMaster.slice();
\r
2666 _fnCalculateEnd( oSettings );
\r
2667 _fnDraw( oSettings );
\r
2670 _fnProcessingDisplay( oSettings, false );
\r
2671 _fnInitComplete( oSettings, json );
\r
2676 /* Server-side processing initialisation complete is done at the end of _fnDraw */
\r
2677 if ( !oSettings.oFeatures.bServerSide )
\r
2679 _fnProcessingDisplay( oSettings, false );
\r
2680 _fnInitComplete( oSettings );
\r
2686 * Draw the table for the first time, adding all required features
\r
2687 * @param {object} oSettings dataTables settings object
\r
2688 * @param {object} [json] JSON from the server that completed the table, if using Ajax source
\r
2689 * with client-side processing (optional)
\r
2690 * @memberof DataTable#oApi
\r
2692 function _fnInitComplete ( oSettings, json )
\r
2694 oSettings._bInitComplete = true;
\r
2695 _fnCallbackFire( oSettings, 'aoInitComplete', 'init', [oSettings, json] );
\r
2700 * Language compatibility - when certain options are given, and others aren't, we
\r
2701 * need to duplicate the values over, in order to provide backwards compatibility
\r
2702 * with older language files.
\r
2703 * @param {object} oSettings dataTables settings object
\r
2704 * @memberof DataTable#oApi
\r
2706 function _fnLanguageCompat( oLanguage )
\r
2708 var oDefaults = DataTable.defaults.oLanguage;
\r
2710 /* Backwards compatibility - if there is no sEmptyTable given, then use the same as
\r
2711 * sZeroRecords - assuming that is given.
\r
2713 if ( !oLanguage.sEmptyTable && oLanguage.sZeroRecords &&
\r
2714 oDefaults.sEmptyTable === "No data available in table" )
\r
2716 _fnMap( oLanguage, oLanguage, 'sZeroRecords', 'sEmptyTable' );
\r
2719 /* Likewise with loading records */
\r
2720 if ( !oLanguage.sLoadingRecords && oLanguage.sZeroRecords &&
\r
2721 oDefaults.sLoadingRecords === "Loading..." )
\r
2723 _fnMap( oLanguage, oLanguage, 'sZeroRecords', 'sLoadingRecords' );
\r
2730 * Generate the node required for user display length changing
\r
2731 * @param {object} oSettings dataTables settings object
\r
2732 * @returns {node} Display length feature node
\r
2733 * @memberof DataTable#oApi
\r
2735 function _fnFeatureHtmlLength ( oSettings )
\r
2737 if ( oSettings.oScroll.bInfinite )
\r
2742 /* This can be overruled by not using the _MENU_ var/macro in the language variable */
\r
2743 var sName = 'name="'+oSettings.sTableId+'_length"';
\r
2744 var sStdMenu = '<select size="1" '+sName+'>';
\r
2746 var aLengthMenu = oSettings.aLengthMenu;
\r
2748 if ( aLengthMenu.length == 2 && typeof aLengthMenu[0] === 'object' &&
\r
2749 typeof aLengthMenu[1] === 'object' )
\r
2751 for ( i=0, iLen=aLengthMenu[0].length ; i<iLen ; i++ )
\r
2753 sStdMenu += '<option value="'+aLengthMenu[0][i]+'">'+aLengthMenu[1][i]+'</option>';
\r
2758 for ( i=0, iLen=aLengthMenu.length ; i<iLen ; i++ )
\r
2760 sStdMenu += '<option value="'+aLengthMenu[i]+'">'+aLengthMenu[i]+'</option>';
\r
2763 sStdMenu += '</select>';
\r
2765 var nLength = document.createElement( 'div' );
\r
2766 if ( !oSettings.aanFeatures.l )
\r
2768 nLength.id = oSettings.sTableId+'_length';
\r
2770 nLength.className = oSettings.oClasses.sLength;
\r
2771 nLength.innerHTML = '<label>'+oSettings.oLanguage.sLengthMenu.replace( '_MENU_', sStdMenu )+'</label>';
\r
2774 * Set the length to the current display length - thanks to Andrea Pavlovic for this fix,
\r
2775 * and Stefan Skopnik for fixing the fix!
\r
2777 $('select option[value="'+oSettings._iDisplayLength+'"]', nLength).attr("selected", true);
\r
2779 $('select', nLength).bind( 'change.DT', function(e) {
\r
2780 var iVal = $(this).val();
\r
2782 /* Update all other length options for the new display */
\r
2783 var n = oSettings.aanFeatures.l;
\r
2784 for ( i=0, iLen=n.length ; i<iLen ; i++ )
\r
2786 if ( n[i] != this.parentNode )
\r
2788 $('select', n[i]).val( iVal );
\r
2792 /* Redraw the table */
\r
2793 oSettings._iDisplayLength = parseInt(iVal, 10);
\r
2794 _fnCalculateEnd( oSettings );
\r
2796 /* If we have space to show extra rows (backing up from the end point - then do so */
\r
2797 if ( oSettings.fnDisplayEnd() == oSettings.fnRecordsDisplay() )
\r
2799 oSettings._iDisplayStart = oSettings.fnDisplayEnd() - oSettings._iDisplayLength;
\r
2800 if ( oSettings._iDisplayStart < 0 )
\r
2802 oSettings._iDisplayStart = 0;
\r
2806 if ( oSettings._iDisplayLength == -1 )
\r
2808 oSettings._iDisplayStart = 0;
\r
2811 _fnDraw( oSettings );
\r
2815 $('select', nLength).attr('aria-controls', oSettings.sTableId);
\r
2822 * Recalculate the end point based on the start point
\r
2823 * @param {object} oSettings dataTables settings object
\r
2824 * @memberof DataTable#oApi
\r
2826 function _fnCalculateEnd( oSettings )
\r
2828 if ( oSettings.oFeatures.bPaginate === false )
\r
2830 oSettings._iDisplayEnd = oSettings.aiDisplay.length;
\r
2834 /* Set the end point of the display - based on how many elements there are
\r
2835 * still to display
\r
2837 if ( oSettings._iDisplayStart + oSettings._iDisplayLength > oSettings.aiDisplay.length ||
\r
2838 oSettings._iDisplayLength == -1 )
\r
2840 oSettings._iDisplayEnd = oSettings.aiDisplay.length;
\r
2844 oSettings._iDisplayEnd = oSettings._iDisplayStart + oSettings._iDisplayLength;
\r
2851 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
\r
2852 * Note that most of the paging logic is done in
\r
2853 * DataTable.ext.oPagination
\r
2857 * Generate the node required for default pagination
\r
2858 * @param {object} oSettings dataTables settings object
\r
2859 * @returns {node} Pagination feature node
\r
2860 * @memberof DataTable#oApi
\r
2862 function _fnFeatureHtmlPaginate ( oSettings )
\r
2864 if ( oSettings.oScroll.bInfinite )
\r
2869 var nPaginate = document.createElement( 'div' );
\r
2870 nPaginate.className = oSettings.oClasses.sPaging+oSettings.sPaginationType;
\r
2872 DataTable.ext.oPagination[ oSettings.sPaginationType ].fnInit( oSettings, nPaginate,
\r
2873 function( oSettings ) {
\r
2874 _fnCalculateEnd( oSettings );
\r
2875 _fnDraw( oSettings );
\r
2879 /* Add a draw callback for the pagination on first instance, to update the paging display */
\r
2880 if ( !oSettings.aanFeatures.p )
\r
2882 oSettings.aoDrawCallback.push( {
\r
2883 "fn": function( oSettings ) {
\r
2884 DataTable.ext.oPagination[ oSettings.sPaginationType ].fnUpdate( oSettings, function( oSettings ) {
\r
2885 _fnCalculateEnd( oSettings );
\r
2886 _fnDraw( oSettings );
\r
2889 "sName": "pagination"
\r
2897 * Alter the display settings to change the page
\r
2898 * @param {object} oSettings dataTables settings object
\r
2899 * @param {string|int} mAction Paging action to take: "first", "previous", "next" or "last"
\r
2900 * or page number to jump to (integer)
\r
2901 * @returns {bool} true page has changed, false - no change (no effect) eg 'first' on page 1
\r
2902 * @memberof DataTable#oApi
\r
2904 function _fnPageChange ( oSettings, mAction )
\r
2906 var iOldStart = oSettings._iDisplayStart;
\r
2908 if ( typeof mAction === "number" )
\r
2910 oSettings._iDisplayStart = mAction * oSettings._iDisplayLength;
\r
2911 if ( oSettings._iDisplayStart > oSettings.fnRecordsDisplay() )
\r
2913 oSettings._iDisplayStart = 0;
\r
2916 else if ( mAction == "first" )
\r
2918 oSettings._iDisplayStart = 0;
\r
2920 else if ( mAction == "previous" )
\r
2922 oSettings._iDisplayStart = oSettings._iDisplayLength>=0 ?
\r
2923 oSettings._iDisplayStart - oSettings._iDisplayLength :
\r
2926 /* Correct for under-run */
\r
2927 if ( oSettings._iDisplayStart < 0 )
\r
2929 oSettings._iDisplayStart = 0;
\r
2932 else if ( mAction == "next" )
\r
2934 if ( oSettings._iDisplayLength >= 0 )
\r
2936 /* Make sure we are not over running the display array */
\r
2937 if ( oSettings._iDisplayStart + oSettings._iDisplayLength < oSettings.fnRecordsDisplay() )
\r
2939 oSettings._iDisplayStart += oSettings._iDisplayLength;
\r
2944 oSettings._iDisplayStart = 0;
\r
2947 else if ( mAction == "last" )
\r
2949 if ( oSettings._iDisplayLength >= 0 )
\r
2951 var iPages = parseInt( (oSettings.fnRecordsDisplay()-1) / oSettings._iDisplayLength, 10 ) + 1;
\r
2952 oSettings._iDisplayStart = (iPages-1) * oSettings._iDisplayLength;
\r
2956 oSettings._iDisplayStart = 0;
\r
2961 _fnLog( oSettings, 0, "Unknown paging action: "+mAction );
\r
2963 $(oSettings.oInstance).trigger('page', oSettings);
\r
2965 return iOldStart != oSettings._iDisplayStart;
\r
2971 * Generate the node required for the processing node
\r
2972 * @param {object} oSettings dataTables settings object
\r
2973 * @returns {node} Processing element
\r
2974 * @memberof DataTable#oApi
\r
2976 function _fnFeatureHtmlProcessing ( oSettings )
\r
2978 var nProcessing = document.createElement( 'div' );
\r
2980 if ( !oSettings.aanFeatures.r )
\r
2982 nProcessing.id = oSettings.sTableId+'_processing';
\r
2984 nProcessing.innerHTML = oSettings.oLanguage.sProcessing;
\r
2985 nProcessing.className = oSettings.oClasses.sProcessing;
\r
2986 oSettings.nTable.parentNode.insertBefore( nProcessing, oSettings.nTable );
\r
2988 return nProcessing;
\r
2993 * Display or hide the processing indicator
\r
2994 * @param {object} oSettings dataTables settings object
\r
2995 * @param {bool} bShow Show the processing indicator (true) or not (false)
\r
2996 * @memberof DataTable#oApi
\r
2998 function _fnProcessingDisplay ( oSettings, bShow )
\r
3000 if ( oSettings.oFeatures.bProcessing )
\r
3002 var an = oSettings.aanFeatures.r;
\r
3003 for ( var i=0, iLen=an.length ; i<iLen ; i++ )
\r
3005 an[i].style.visibility = bShow ? "visible" : "hidden";
\r
3009 $(oSettings.oInstance).trigger('processing', [oSettings, bShow]);
\r
3013 * Add any control elements for the table - specifically scrolling
\r
3014 * @param {object} oSettings dataTables settings object
\r
3015 * @returns {node} Node to add to the DOM
\r
3016 * @memberof DataTable#oApi
\r
3018 function _fnFeatureHtmlTable ( oSettings )
\r
3020 /* Check if scrolling is enabled or not - if not then leave the DOM unaltered */
\r
3021 if ( oSettings.oScroll.sX === "" && oSettings.oScroll.sY === "" )
\r
3023 return oSettings.nTable;
\r
3027 * The HTML structure that we want to generate in this function is:
\r
3029 * div - nScrollHead
\r
3030 * div - nScrollHeadInner
\r
3031 * table - nScrollHeadTable
\r
3033 * div - nScrollBody
\r
3034 * table - oSettings.nTable
\r
3035 * thead - nTheadSize
\r
3037 * div - nScrollFoot
\r
3038 * div - nScrollFootInner
\r
3039 * table - nScrollFootTable
\r
3043 nScroller = document.createElement('div'),
\r
3044 nScrollHead = document.createElement('div'),
\r
3045 nScrollHeadInner = document.createElement('div'),
\r
3046 nScrollBody = document.createElement('div'),
\r
3047 nScrollFoot = document.createElement('div'),
\r
3048 nScrollFootInner = document.createElement('div'),
\r
3049 nScrollHeadTable = oSettings.nTable.cloneNode(false),
\r
3050 nScrollFootTable = oSettings.nTable.cloneNode(false),
\r
3051 nThead = oSettings.nTable.getElementsByTagName('thead')[0],
\r
3052 nTfoot = oSettings.nTable.getElementsByTagName('tfoot').length === 0 ? null :
\r
3053 oSettings.nTable.getElementsByTagName('tfoot')[0],
\r
3054 oClasses = oSettings.oClasses;
\r
3056 nScrollHead.appendChild( nScrollHeadInner );
\r
3057 nScrollFoot.appendChild( nScrollFootInner );
\r
3058 nScrollBody.appendChild( oSettings.nTable );
\r
3059 nScroller.appendChild( nScrollHead );
\r
3060 nScroller.appendChild( nScrollBody );
\r
3061 nScrollHeadInner.appendChild( nScrollHeadTable );
\r
3062 nScrollHeadTable.appendChild( nThead );
\r
3063 if ( nTfoot !== null )
\r
3065 nScroller.appendChild( nScrollFoot );
\r
3066 nScrollFootInner.appendChild( nScrollFootTable );
\r
3067 nScrollFootTable.appendChild( nTfoot );
\r
3070 nScroller.className = oClasses.sScrollWrapper;
\r
3071 nScrollHead.className = oClasses.sScrollHead;
\r
3072 nScrollHeadInner.className = oClasses.sScrollHeadInner;
\r
3073 nScrollBody.className = oClasses.sScrollBody;
\r
3074 nScrollFoot.className = oClasses.sScrollFoot;
\r
3075 nScrollFootInner.className = oClasses.sScrollFootInner;
\r
3077 if ( oSettings.oScroll.bAutoCss )
\r
3079 nScrollHead.style.overflow = "hidden";
\r
3080 nScrollHead.style.position = "relative";
\r
3081 nScrollFoot.style.overflow = "hidden";
\r
3082 nScrollBody.style.overflow = "auto";
\r
3085 nScrollHead.style.border = "0";
\r
3086 nScrollHead.style.width = "100%";
\r
3087 nScrollFoot.style.border = "0";
\r
3088 nScrollHeadInner.style.width = oSettings.oScroll.sXInner !== "" ?
\r
3089 oSettings.oScroll.sXInner : "100%"; /* will be overwritten */
\r
3091 /* Modify attributes to respect the clones */
\r
3092 nScrollHeadTable.removeAttribute('id');
\r
3093 nScrollHeadTable.style.marginLeft = "0";
\r
3094 oSettings.nTable.style.marginLeft = "0";
\r
3095 if ( nTfoot !== null )
\r
3097 nScrollFootTable.removeAttribute('id');
\r
3098 nScrollFootTable.style.marginLeft = "0";
\r
3101 /* Move caption elements from the body to the header, footer or leave where it is
\r
3102 * depending on the configuration. Note that the DTD says there can be only one caption */
\r
3103 var nCaption = $(oSettings.nTable).children('caption');
\r
3104 if ( nCaption.length > 0 )
\r
3106 nCaption = nCaption[0];
\r
3107 if ( nCaption._captionSide === "top" )
\r
3109 nScrollHeadTable.appendChild( nCaption );
\r
3111 else if ( nCaption._captionSide === "bottom" && nTfoot )
\r
3113 nScrollFootTable.appendChild( nCaption );
\r
3120 /* When x-scrolling add the width and a scroller to move the header with the body */
\r
3121 if ( oSettings.oScroll.sX !== "" )
\r
3123 nScrollHead.style.width = _fnStringToCss( oSettings.oScroll.sX );
\r
3124 nScrollBody.style.width = _fnStringToCss( oSettings.oScroll.sX );
\r
3126 if ( nTfoot !== null )
\r
3128 nScrollFoot.style.width = _fnStringToCss( oSettings.oScroll.sX );
\r
3131 /* When the body is scrolled, then we also want to scroll the headers */
\r
3132 $(nScrollBody).scroll( function (e) {
\r
3133 nScrollHead.scrollLeft = this.scrollLeft;
\r
3135 if ( nTfoot !== null )
\r
3137 nScrollFoot.scrollLeft = this.scrollLeft;
\r
3142 /* When yscrolling, add the height */
\r
3143 if ( oSettings.oScroll.sY !== "" )
\r
3145 nScrollBody.style.height = _fnStringToCss( oSettings.oScroll.sY );
\r
3148 /* Redraw - align columns across the tables */
\r
3149 oSettings.aoDrawCallback.push( {
\r
3150 "fn": _fnScrollDraw,
\r
3151 "sName": "scrolling"
\r
3154 /* Infinite scrolling event handlers */
\r
3155 if ( oSettings.oScroll.bInfinite )
\r
3157 $(nScrollBody).scroll( function() {
\r
3158 /* Use a blocker to stop scrolling from loading more data while other data is still loading */
\r
3159 if ( !oSettings.bDrawing && $(this).scrollTop() !== 0 )
\r
3161 /* Check if we should load the next data set */
\r
3162 if ( $(this).scrollTop() + $(this).height() >
\r
3163 $(oSettings.nTable).height() - oSettings.oScroll.iLoadGap )
\r
3165 /* Only do the redraw if we have to - we might be at the end of the data */
\r
3166 if ( oSettings.fnDisplayEnd() < oSettings.fnRecordsDisplay() )
\r
3168 _fnPageChange( oSettings, 'next' );
\r
3169 _fnCalculateEnd( oSettings );
\r
3170 _fnDraw( oSettings );
\r
3177 oSettings.nScrollHead = nScrollHead;
\r
3178 oSettings.nScrollFoot = nScrollFoot;
\r
3185 * Update the various tables for resizing. It's a bit of a pig this function, but
\r
3186 * basically the idea to:
\r
3187 * 1. Re-create the table inside the scrolling div
\r
3188 * 2. Take live measurements from the DOM
\r
3189 * 3. Apply the measurements
\r
3191 * @param {object} o dataTables settings object
\r
3192 * @returns {node} Node to add to the DOM
\r
3193 * @memberof DataTable#oApi
\r
3195 function _fnScrollDraw ( o )
\r
3198 nScrollHeadInner = o.nScrollHead.getElementsByTagName('div')[0],
\r
3199 nScrollHeadTable = nScrollHeadInner.getElementsByTagName('table')[0],
\r
3200 nScrollBody = o.nTable.parentNode,
\r
3201 i, iLen, j, jLen, anHeadToSize, anHeadSizers, anFootSizers, anFootToSize, oStyle, iVis,
\r
3202 nTheadSize, nTfootSize,
\r
3203 iWidth, aApplied=[], aAppliedFooter=[], iSanityWidth,
\r
3204 nScrollFootInner = (o.nTFoot !== null) ? o.nScrollFoot.getElementsByTagName('div')[0] : null,
\r
3205 nScrollFootTable = (o.nTFoot !== null) ? nScrollFootInner.getElementsByTagName('table')[0] : null,
\r
3206 ie67 = o.oBrowser.bScrollOversize,
\r
3207 zeroOut = function(nSizer) {
\r
3208 oStyle = nSizer.style;
\r
3209 oStyle.paddingTop = "0";
\r
3210 oStyle.paddingBottom = "0";
\r
3211 oStyle.borderTopWidth = "0";
\r
3212 oStyle.borderBottomWidth = "0";
\r
3213 oStyle.height = 0;
\r
3217 * 1. Re-create the table inside the scrolling div
\r
3220 /* Remove the old minimised thead and tfoot elements in the inner table */
\r
3221 $(o.nTable).children('thead, tfoot').remove();
\r
3223 /* Clone the current header and footer elements and then place it into the inner table */
\r
3224 nTheadSize = $(o.nTHead).clone()[0];
\r
3225 o.nTable.insertBefore( nTheadSize, o.nTable.childNodes[0] );
\r
3226 anHeadToSize = o.nTHead.getElementsByTagName('tr');
\r
3227 anHeadSizers = nTheadSize.getElementsByTagName('tr');
\r
3229 if ( o.nTFoot !== null )
\r
3231 nTfootSize = $(o.nTFoot).clone()[0];
\r
3232 o.nTable.insertBefore( nTfootSize, o.nTable.childNodes[1] );
\r
3233 anFootToSize = o.nTFoot.getElementsByTagName('tr');
\r
3234 anFootSizers = nTfootSize.getElementsByTagName('tr');
\r
3238 * 2. Take live measurements from the DOM - do not alter the DOM itself!
\r
3241 /* Remove old sizing and apply the calculated column widths
\r
3242 * Get the unique column headers in the newly created (cloned) header. We want to apply the
\r
3243 * calculated sizes to this header
\r
3245 if ( o.oScroll.sX === "" )
\r
3247 nScrollBody.style.width = '100%';
\r
3248 nScrollHeadInner.parentNode.style.width = '100%';
\r
3251 var nThs = _fnGetUniqueThs( o, nTheadSize );
\r
3252 for ( i=0, iLen=nThs.length ; i<iLen ; i++ )
\r
3254 iVis = _fnVisibleToColumnIndex( o, i );
\r
3255 nThs[i].style.width = o.aoColumns[iVis].sWidth;
\r
3258 if ( o.nTFoot !== null )
\r
3260 _fnApplyToChildren( function(n) {
\r
3261 n.style.width = "";
\r
3262 }, anFootSizers );
\r
3265 // If scroll collapse is enabled, when we put the headers back into the body for sizing, we
\r
3266 // will end up forcing the scrollbar to appear, making our measurements wrong for when we
\r
3267 // then hide it (end of this function), so add the header height to the body scroller.
\r
3268 if ( o.oScroll.bCollapse && o.oScroll.sY !== "" )
\r
3270 nScrollBody.style.height = (nScrollBody.offsetHeight + o.nTHead.offsetHeight)+"px";
\r
3273 /* Size the table as a whole */
\r
3274 iSanityWidth = $(o.nTable).outerWidth();
\r
3275 if ( o.oScroll.sX === "" )
\r
3277 /* No x scrolling */
\r
3278 o.nTable.style.width = "100%";
\r
3280 /* I know this is rubbish - but IE7 will make the width of the table when 100% include
\r
3281 * the scrollbar - which is shouldn't. When there is a scrollbar we need to take this
\r
3284 if ( ie67 && ($('tbody', nScrollBody).height() > nScrollBody.offsetHeight ||
\r
3285 $(nScrollBody).css('overflow-y') == "scroll") )
\r
3287 o.nTable.style.width = _fnStringToCss( $(o.nTable).outerWidth() - o.oScroll.iBarWidth);
\r
3292 if ( o.oScroll.sXInner !== "" )
\r
3294 /* x scroll inner has been given - use it */
\r
3295 o.nTable.style.width = _fnStringToCss(o.oScroll.sXInner);
\r
3297 else if ( iSanityWidth == $(nScrollBody).width() &&
\r
3298 $(nScrollBody).height() < $(o.nTable).height() )
\r
3300 /* There is y-scrolling - try to take account of the y scroll bar */
\r
3301 o.nTable.style.width = _fnStringToCss( iSanityWidth-o.oScroll.iBarWidth );
\r
3302 if ( $(o.nTable).outerWidth() > iSanityWidth-o.oScroll.iBarWidth )
\r
3304 /* Not possible to take account of it */
\r
3305 o.nTable.style.width = _fnStringToCss( iSanityWidth );
\r
3310 /* All else fails */
\r
3311 o.nTable.style.width = _fnStringToCss( iSanityWidth );
\r
3315 /* Recalculate the sanity width - now that we've applied the required width, before it was
\r
3316 * a temporary variable. This is required because the column width calculation is done
\r
3317 * before this table DOM is created.
\r
3319 iSanityWidth = $(o.nTable).outerWidth();
\r
3321 /* We want the hidden header to have zero height, so remove padding and borders. Then
\r
3322 * set the width based on the real headers
\r
3325 // Apply all styles in one pass. Invalidates layout only once because we don't read any
\r
3326 // DOM properties.
\r
3327 _fnApplyToChildren( zeroOut, anHeadSizers );
\r
3329 // Read all widths in next pass. Forces layout only once because we do not change
\r
3330 // any DOM properties.
\r
3331 _fnApplyToChildren( function(nSizer) {
\r
3332 aApplied.push( _fnStringToCss( $(nSizer).width() ) );
\r
3333 }, anHeadSizers );
\r
3335 // Apply all widths in final pass. Invalidates layout only once because we do not
\r
3336 // read any DOM properties.
\r
3337 _fnApplyToChildren( function(nToSize, i) {
\r
3338 nToSize.style.width = aApplied[i];
\r
3339 }, anHeadToSize );
\r
3341 $(anHeadSizers).height(0);
\r
3343 /* Same again with the footer if we have one */
\r
3344 if ( o.nTFoot !== null )
\r
3346 _fnApplyToChildren( zeroOut, anFootSizers );
\r
3348 _fnApplyToChildren( function(nSizer) {
\r
3349 aAppliedFooter.push( _fnStringToCss( $(nSizer).width() ) );
\r
3350 }, anFootSizers );
\r
3352 _fnApplyToChildren( function(nToSize, i) {
\r
3353 nToSize.style.width = aAppliedFooter[i];
\r
3354 }, anFootToSize );
\r
3356 $(anFootSizers).height(0);
\r
3360 * 3. Apply the measurements
\r
3363 /* "Hide" the header and footer that we used for the sizing. We want to also fix their width
\r
3364 * to what they currently are
\r
3366 _fnApplyToChildren( function(nSizer, i) {
\r
3367 nSizer.innerHTML = "";
\r
3368 nSizer.style.width = aApplied[i];
\r
3369 //fix column align
\r
3370 nSizer.style.minWidth =nSizer.style.width;
\r
3371 }, anHeadSizers );
\r
3373 if ( o.nTFoot !== null )
\r
3375 _fnApplyToChildren( function(nSizer, i) {
\r
3376 nSizer.innerHTML = "";
\r
3377 nSizer.style.width = aAppliedFooter[i];
\r
3378 }, anFootSizers );
\r
3381 /* Sanity check that the table is of a sensible width. If not then we are going to get
\r
3382 * misalignment - try to prevent this by not allowing the table to shrink below its min width
\r
3384 if ( $(o.nTable).outerWidth() < iSanityWidth )
\r
3386 /* The min width depends upon if we have a vertical scrollbar visible or not */
\r
3387 var iCorrection = ((nScrollBody.scrollHeight > nScrollBody.offsetHeight ||
\r
3388 $(nScrollBody).css('overflow-y') == "scroll")) ?
\r
3389 iSanityWidth+o.oScroll.iBarWidth : iSanityWidth;
\r
3391 /* IE6/7 are a law unto themselves... */
\r
3392 if ( ie67 && (nScrollBody.scrollHeight >
\r
3393 nScrollBody.offsetHeight || $(nScrollBody).css('overflow-y') == "scroll") )
\r
3395 o.nTable.style.width = _fnStringToCss( iCorrection-o.oScroll.iBarWidth );
\r
3398 /* Apply the calculated minimum width to the table wrappers */
\r
3399 nScrollBody.style.width = _fnStringToCss( iCorrection );
\r
3400 o.nScrollHead.style.width = _fnStringToCss( iCorrection );
\r
3402 if ( o.nTFoot !== null )
\r
3404 o.nScrollFoot.style.width = _fnStringToCss( iCorrection );
\r
3407 /* And give the user a warning that we've stopped the table getting too small */
\r
3408 if ( o.oScroll.sX === "" )
\r
3410 _fnLog( o, 1, "The table cannot fit into the current element which will cause column"+
\r
3411 " misalignment. The table has been drawn at its minimum possible width." );
\r
3413 else if ( o.oScroll.sXInner !== "" )
\r
3415 _fnLog( o, 1, "The table cannot fit into the current element which will cause column"+
\r
3416 " misalignment. Increase the sScrollXInner value or remove it to allow automatic"+
\r
3422 nScrollBody.style.width = _fnStringToCss( '100%' );
\r
3423 o.nScrollHead.style.width = _fnStringToCss( '100%' );
\r
3425 if ( o.nTFoot !== null )
\r
3427 o.nScrollFoot.style.width = _fnStringToCss( '100%' );
\r
3435 if ( o.oScroll.sY === "" )
\r
3437 /* IE7< puts a vertical scrollbar in place (when it shouldn't be) due to subtracting
\r
3438 * the scrollbar height from the visible display, rather than adding it on. We need to
\r
3439 * set the height in order to sort this. Don't want to do it in any other browsers.
\r
3443 nScrollBody.style.height = _fnStringToCss( o.nTable.offsetHeight+o.oScroll.iBarWidth );
\r
3447 if ( o.oScroll.sY !== "" && o.oScroll.bCollapse )
\r
3449 nScrollBody.style.height = _fnStringToCss( o.oScroll.sY );
\r
3451 var iExtra = (o.oScroll.sX !== "" && o.nTable.offsetWidth > nScrollBody.offsetWidth) ?
\r
3452 o.oScroll.iBarWidth : 0;
\r
3453 if ( o.nTable.offsetHeight < nScrollBody.offsetHeight )
\r
3455 nScrollBody.style.height = _fnStringToCss( o.nTable.offsetHeight+iExtra );
\r
3459 /* Finally set the width's of the header and footer tables */
\r
3460 var iOuterWidth = $(o.nTable).outerWidth();
\r
3461 nScrollHeadTable.style.width = _fnStringToCss( iOuterWidth );
\r
3462 nScrollHeadInner.style.width = _fnStringToCss( iOuterWidth );
\r
3464 // Figure out if there are scrollbar present - if so then we need a the header and footer to
\r
3465 // provide a bit more space to allow "overflow" scrolling (i.e. past the scrollbar)
\r
3466 var bScrolling = $(o.nTable).height() > nScrollBody.clientHeight || $(nScrollBody).css('overflow-y') == "scroll";
\r
3467 nScrollHeadInner.style.paddingRight = bScrolling ? o.oScroll.iBarWidth+"px" : "0px";
\r
3469 if ( o.nTFoot !== null )
\r
3471 nScrollFootTable.style.width = _fnStringToCss( iOuterWidth );
\r
3472 nScrollFootInner.style.width = _fnStringToCss( iOuterWidth );
\r
3473 nScrollFootInner.style.paddingRight = bScrolling ? o.oScroll.iBarWidth+"px" : "0px";
\r
3476 /* Adjust the position of the header in case we loose the y-scrollbar */
\r
3477 $(nScrollBody).scroll();
\r
3479 /* If sorting or filtering has occurred, jump the scrolling back to the top */
\r
3480 if ( o.bSorted || o.bFiltered )
\r
3482 nScrollBody.scrollTop = 0;
\r
3488 * Apply a given function to the display child nodes of an element array (typically
\r
3489 * TD children of TR rows
\r
3490 * @param {function} fn Method to apply to the objects
\r
3491 * @param array {nodes} an1 List of elements to look through for display children
\r
3492 * @param array {nodes} an2 Another list (identical structure to the first) - optional
\r
3493 * @memberof DataTable#oApi
\r
3495 function _fnApplyToChildren( fn, an1, an2 )
\r
3497 var index=0, i=0, iLen=an1.length;
\r
3498 var nNode1, nNode2;
\r
3500 while ( i < iLen )
\r
3502 nNode1 = an1[i].firstChild;
\r
3503 nNode2 = an2 ? an2[i].firstChild : null;
\r
3506 if ( nNode1.nodeType === 1 )
\r
3510 fn( nNode1, nNode2, index );
\r
3514 fn( nNode1, index );
\r
3518 nNode1 = nNode1.nextSibling;
\r
3519 nNode2 = an2 ? nNode2.nextSibling : null;
\r
3526 * Convert a CSS unit width to pixels (e.g. 2em)
\r
3527 * @param {string} sWidth width to be converted
\r
3528 * @param {node} nParent parent to get the with for (required for relative widths) - optional
\r
3529 * @returns {int} iWidth width in pixels
\r
3530 * @memberof DataTable#oApi
\r
3532 function _fnConvertToWidth ( sWidth, nParent )
\r
3534 if ( !sWidth || sWidth === null || sWidth === '' )
\r
3541 nParent = document.body;
\r
3545 var nTmp = document.createElement( "div" );
\r
3546 nTmp.style.width = _fnStringToCss( sWidth );
\r
3548 nParent.appendChild( nTmp );
\r
3549 iWidth = nTmp.offsetWidth;
\r
3550 nParent.removeChild( nTmp );
\r
3552 return ( iWidth );
\r
3557 * Calculate the width of columns for the table
\r
3558 * @param {object} oSettings dataTables settings object
\r
3559 * @memberof DataTable#oApi
\r
3561 function _fnCalculateColumnWidths ( oSettings )
\r
3563 var iTableWidth = oSettings.nTable.offsetWidth;
\r
3564 var iUserInputs = 0;
\r
3566 var iVisibleColumns = 0;
\r
3567 var iColums = oSettings.aoColumns.length;
\r
3568 var i, iIndex, iCorrector, iWidth;
\r
3569 var oHeaders = $('th', oSettings.nTHead);
\r
3570 var widthAttr = oSettings.nTable.getAttribute('width');
\r
3571 var nWrapper = oSettings.nTable.parentNode;
\r
3573 /* Convert any user input sizes into pixel sizes */
\r
3574 for ( i=0 ; i<iColums ; i++ )
\r
3576 if ( oSettings.aoColumns[i].bVisible )
\r
3578 iVisibleColumns++;
\r
3580 if ( oSettings.aoColumns[i].sWidth !== null )
\r
3582 iTmpWidth = _fnConvertToWidth( oSettings.aoColumns[i].sWidthOrig,
\r
3584 if ( iTmpWidth !== null )
\r
3586 oSettings.aoColumns[i].sWidth = _fnStringToCss( iTmpWidth );
\r
3594 /* If the number of columns in the DOM equals the number that we have to process in
\r
3595 * DataTables, then we can use the offsets that are created by the web-browser. No custom
\r
3596 * sizes can be set in order for this to happen, nor scrolling used
\r
3598 if ( iColums == oHeaders.length && iUserInputs === 0 && iVisibleColumns == iColums &&
\r
3599 oSettings.oScroll.sX === "" && oSettings.oScroll.sY === "" )
\r
3601 for ( i=0 ; i<oSettings.aoColumns.length ; i++ )
\r
3603 iTmpWidth = $(oHeaders[i]).width();
\r
3604 if ( iTmpWidth !== null )
\r
3606 oSettings.aoColumns[i].sWidth = _fnStringToCss( iTmpWidth );
\r
3612 /* Otherwise we are going to have to do some calculations to get the width of each column.
\r
3613 * Construct a 1 row table with the widest node in the data, and any user defined widths,
\r
3614 * then insert it into the DOM and allow the browser to do all the hard work of
\r
3615 * calculating table widths.
\r
3618 nCalcTmp = oSettings.nTable.cloneNode( false ),
\r
3619 nTheadClone = oSettings.nTHead.cloneNode(true),
\r
3620 nBody = document.createElement( 'tbody' ),
\r
3621 nTr = document.createElement( 'tr' ),
\r
3624 nCalcTmp.removeAttribute( "id" );
\r
3625 nCalcTmp.appendChild( nTheadClone );
\r
3626 if ( oSettings.nTFoot !== null )
\r
3628 nCalcTmp.appendChild( oSettings.nTFoot.cloneNode(true) );
\r
3629 _fnApplyToChildren( function(n) {
\r
3630 n.style.width = "";
\r
3631 }, nCalcTmp.getElementsByTagName('tr') );
\r
3634 nCalcTmp.appendChild( nBody );
\r
3635 nBody.appendChild( nTr );
\r
3637 /* Remove any sizing that was previously applied by the styles */
\r
3638 var jqColSizing = $('thead th', nCalcTmp);
\r
3639 if ( jqColSizing.length === 0 )
\r
3641 jqColSizing = $('tbody tr:eq(0)>td', nCalcTmp);
\r
3644 /* Apply custom sizing to the cloned header */
\r
3645 var nThs = _fnGetUniqueThs( oSettings, nTheadClone );
\r
3647 for ( i=0 ; i<iColums ; i++ )
\r
3649 var oColumn = oSettings.aoColumns[i];
\r
3650 if ( oColumn.bVisible && oColumn.sWidthOrig !== null && oColumn.sWidthOrig !== "" )
\r
3652 nThs[i-iCorrector].style.width = _fnStringToCss( oColumn.sWidthOrig );
\r
3654 else if ( oColumn.bVisible )
\r
3656 nThs[i-iCorrector].style.width = "";
\r
3664 /* Find the biggest td for each column and put it into the table */
\r
3665 for ( i=0 ; i<iColums ; i++ )
\r
3667 if ( oSettings.aoColumns[i].bVisible )
\r
3669 var nTd = _fnGetWidestNode( oSettings, i );
\r
3670 if ( nTd !== null )
\r
3672 nTd = nTd.cloneNode(true);
\r
3673 if ( oSettings.aoColumns[i].sContentPadding !== "" )
\r
3675 nTd.innerHTML += oSettings.aoColumns[i].sContentPadding;
\r
3677 nTr.appendChild( nTd );
\r
3682 /* Build the table and 'display' it */
\r
3683 nWrapper.appendChild( nCalcTmp );
\r
3685 /* When scrolling (X or Y) we want to set the width of the table as appropriate. However,
\r
3686 * when not scrolling leave the table width as it is. This results in slightly different,
\r
3687 * but I think correct behaviour
\r
3689 if ( oSettings.oScroll.sX !== "" && oSettings.oScroll.sXInner !== "" )
\r
3691 nCalcTmp.style.width = _fnStringToCss(oSettings.oScroll.sXInner);
\r
3693 else if ( oSettings.oScroll.sX !== "" )
\r
3695 nCalcTmp.style.width = "";
\r
3696 if ( $(nCalcTmp).width() < nWrapper.offsetWidth )
\r
3698 nCalcTmp.style.width = _fnStringToCss( nWrapper.offsetWidth );
\r
3701 else if ( oSettings.oScroll.sY !== "" )
\r
3703 nCalcTmp.style.width = _fnStringToCss( nWrapper.offsetWidth );
\r
3705 else if ( widthAttr )
\r
3707 nCalcTmp.style.width = _fnStringToCss( widthAttr );
\r
3709 nCalcTmp.style.visibility = "hidden";
\r
3711 /* Scrolling considerations */
\r
3712 _fnScrollingWidthAdjust( oSettings, nCalcTmp );
\r
3714 /* Read the width's calculated by the browser and store them for use by the caller. We
\r
3715 * first of all try to use the elements in the body, but it is possible that there are
\r
3716 * no elements there, under which circumstances we use the header elements
\r
3718 var oNodes = $("tbody tr:eq(0)", nCalcTmp).children();
\r
3719 if ( oNodes.length === 0 )
\r
3721 oNodes = _fnGetUniqueThs( oSettings, $('thead', nCalcTmp)[0] );
\r
3724 /* Browsers need a bit of a hand when a width is assigned to any columns when
\r
3725 * x-scrolling as they tend to collapse the table to the min-width, even if
\r
3726 * we sent the column widths. So we need to keep track of what the table width
\r
3727 * should be by summing the user given values, and the automatic values
\r
3729 if ( oSettings.oScroll.sX !== "" )
\r
3733 for ( i=0 ; i<oSettings.aoColumns.length ; i++ )
\r
3735 if ( oSettings.aoColumns[i].bVisible )
\r
3737 if ( oSettings.aoColumns[i].sWidthOrig === null )
\r
3739 iTotal += $(oNodes[iCorrector]).outerWidth();
\r
3743 iTotal += parseInt(oSettings.aoColumns[i].sWidth.replace('px',''), 10) +
\r
3744 ($(oNodes[iCorrector]).outerWidth() - $(oNodes[iCorrector]).width());
\r
3750 nCalcTmp.style.width = _fnStringToCss( iTotal );
\r
3751 oSettings.nTable.style.width = _fnStringToCss( iTotal );
\r
3755 for ( i=0 ; i<oSettings.aoColumns.length ; i++ )
\r
3757 if ( oSettings.aoColumns[i].bVisible )
\r
3759 iWidth = $(oNodes[iCorrector]).width();
\r
3760 if ( iWidth !== null && iWidth > 0 )
\r
3762 oSettings.aoColumns[i].sWidth = _fnStringToCss( iWidth );
\r
3768 var cssWidth = $(nCalcTmp).css('width');
\r
3769 oSettings.nTable.style.width = (cssWidth.indexOf('%') !== -1) ?
\r
3770 cssWidth : _fnStringToCss( $(nCalcTmp).outerWidth() );
\r
3771 nCalcTmp.parentNode.removeChild( nCalcTmp );
\r
3776 oSettings.nTable.style.width = _fnStringToCss( widthAttr );
\r
3782 * Adjust a table's width to take account of scrolling
\r
3783 * @param {object} oSettings dataTables settings object
\r
3784 * @param {node} n table node
\r
3785 * @memberof DataTable#oApi
\r
3787 function _fnScrollingWidthAdjust ( oSettings, n )
\r
3789 if ( oSettings.oScroll.sX === "" && oSettings.oScroll.sY !== "" )
\r
3791 /* When y-scrolling only, we want to remove the width of the scroll bar so the table
\r
3792 * + scroll bar will fit into the area avaialble.
\r
3794 var iOrigWidth = $(n).width();
\r
3795 n.style.width = _fnStringToCss( $(n).outerWidth()-oSettings.oScroll.iBarWidth );
\r
3797 else if ( oSettings.oScroll.sX !== "" )
\r
3799 /* When x-scrolling both ways, fix the table at it's current size, without adjusting */
\r
3800 n.style.width = _fnStringToCss( $(n).outerWidth() );
\r
3806 * Get the widest node
\r
3807 * @param {object} oSettings dataTables settings object
\r
3808 * @param {int} iCol column of interest
\r
3809 * @returns {node} widest table node
\r
3810 * @memberof DataTable#oApi
\r
3812 function _fnGetWidestNode( oSettings, iCol )
\r
3814 var iMaxIndex = _fnGetMaxLenString( oSettings, iCol );
\r
3815 if ( iMaxIndex < 0 )
\r
3820 if ( oSettings.aoData[iMaxIndex].nTr === null )
\r
3822 var n = document.createElement('td');
\r
3823 n.innerHTML = _fnGetCellData( oSettings, iMaxIndex, iCol, '' );
\r
3826 return _fnGetTdNodes(oSettings, iMaxIndex)[iCol];
\r
3831 * Get the maximum strlen for each data column
\r
3832 * @param {object} oSettings dataTables settings object
\r
3833 * @param {int} iCol column of interest
\r
3834 * @returns {string} max string length for each column
\r
3835 * @memberof DataTable#oApi
\r
3837 function _fnGetMaxLenString( oSettings, iCol )
\r
3840 var iMaxIndex = -1;
\r
3842 for ( var i=0 ; i<oSettings.aoData.length ; i++ )
\r
3844 var s = _fnGetCellData( oSettings, i, iCol, 'display' )+"";
\r
3845 s = s.replace( /<.*?>/g, "" );
\r
3846 if ( s.length > iMax )
\r
3858 * Append a CSS unit (only if required) to a string
\r
3859 * @param {array} aArray1 first array
\r
3860 * @param {array} aArray2 second array
\r
3861 * @returns {int} 0 if match, 1 if length is different, 2 if no match
\r
3862 * @memberof DataTable#oApi
\r
3864 function _fnStringToCss( s )
\r
3871 if ( typeof s == 'number' )
\r
3880 /* Check if the last character is not 0-9 */
\r
3881 var c = s.charCodeAt( s.length-1 );
\r
3882 if (c < 0x30 || c > 0x39)
\r
3891 * Get the width of a scroll bar in this browser being used
\r
3892 * @returns {int} width in pixels
\r
3893 * @memberof DataTable#oApi
\r
3895 function _fnScrollBarWidth ()
\r
3897 var inner = document.createElement('p');
\r
3898 var style = inner.style;
\r
3899 style.width = "100%";
\r
3900 style.height = "200px";
\r
3901 style.padding = "0px";
\r
3903 var outer = document.createElement('div');
\r
3904 style = outer.style;
\r
3905 style.position = "absolute";
\r
3906 style.top = "0px";
\r
3907 style.left = "0px";
\r
3908 style.visibility = "hidden";
\r
3909 style.width = "200px";
\r
3910 style.height = "150px";
\r
3911 style.padding = "0px";
\r
3912 style.overflow = "hidden";
\r
3913 outer.appendChild(inner);
\r
3915 document.body.appendChild(outer);
\r
3916 var w1 = inner.offsetWidth;
\r
3917 outer.style.overflow = 'scroll';
\r
3918 var w2 = inner.offsetWidth;
\r
3921 w2 = outer.clientWidth;
\r
3924 document.body.removeChild(outer);
\r
3925 return (w1 - w2);
\r
3929 * Change the order of the table
\r
3930 * @param {object} oSettings dataTables settings object
\r
3931 * @param {bool} bApplyClasses optional - should we apply classes or not
\r
3932 * @memberof DataTable#oApi
\r
3934 function _fnSort ( oSettings, bApplyClasses )
\r
3937 i, iLen, j, jLen, k, kLen,
\r
3941 oSort = DataTable.ext.oSort,
\r
3942 aoData = oSettings.aoData,
\r
3943 aoColumns = oSettings.aoColumns,
\r
3944 oAria = oSettings.oLanguage.oAria;
\r
3946 /* No sorting required if server-side or no sorting array */
\r
3947 if ( !oSettings.oFeatures.bServerSide &&
\r
3948 (oSettings.aaSorting.length !== 0 || oSettings.aaSortingFixed !== null) )
\r
3950 aaSort = ( oSettings.aaSortingFixed !== null ) ?
\r
3951 oSettings.aaSortingFixed.concat( oSettings.aaSorting ) :
\r
3952 oSettings.aaSorting.slice();
\r
3954 /* If there is a sorting data type, and a function belonging to it, then we need to
\r
3955 * get the data from the developer's function and apply it for this column
\r
3957 for ( i=0 ; i<aaSort.length ; i++ )
\r
3959 var iColumn = aaSort[i][0];
\r
3960 var iVisColumn = _fnColumnIndexToVisible( oSettings, iColumn );
\r
3961 sDataType = oSettings.aoColumns[ iColumn ].sSortDataType;
\r
3962 if ( DataTable.ext.afnSortData[sDataType] )
\r
3964 var aData = DataTable.ext.afnSortData[sDataType].call(
\r
3965 oSettings.oInstance, oSettings, iColumn, iVisColumn
\r
3967 if ( aData.length === aoData.length )
\r
3969 for ( j=0, jLen=aoData.length ; j<jLen ; j++ )
\r
3971 _fnSetCellData( oSettings, j, iColumn, aData[j] );
\r
3976 _fnLog( oSettings, 0, "Returned data sort array (col "+iColumn+") is the wrong length" );
\r
3981 /* Create a value - key array of the current row positions such that we can use their
\r
3982 * current position during the sort, if values match, in order to perform stable sorting
\r
3984 for ( i=0, iLen=oSettings.aiDisplayMaster.length ; i<iLen ; i++ )
\r
3986 aiOrig[ oSettings.aiDisplayMaster[i] ] = i;
\r
3989 /* Build an internal data array which is specific to the sort, so we can get and prep
\r
3990 * the data to be sorted only once, rather than needing to do it every time the sorting
\r
3991 * function runs. This make the sorting function a very simple comparison
\r
3993 var iSortLen = aaSort.length;
\r
3994 var fnSortFormat, aDataSort;
\r
3995 for ( i=0, iLen=aoData.length ; i<iLen ; i++ )
\r
3997 for ( j=0 ; j<iSortLen ; j++ )
\r
3999 aDataSort = aoColumns[ aaSort[j][0] ].aDataSort;
\r
4001 for ( k=0, kLen=aDataSort.length ; k<kLen ; k++ )
\r
4003 sDataType = aoColumns[ aDataSort[k] ].sType;
\r
4004 fnSortFormat = oSort[ (sDataType ? sDataType : 'string')+"-pre" ];
\r
4006 aoData[i]._aSortData[ aDataSort[k] ] = fnSortFormat ?
\r
4007 fnSortFormat( _fnGetCellData( oSettings, i, aDataSort[k], 'sort' ) ) :
\r
4008 _fnGetCellData( oSettings, i, aDataSort[k], 'sort' );
\r
4013 /* Do the sort - here we want multi-column sorting based on a given data source (column)
\r
4014 * and sorting function (from oSort) in a certain direction. It's reasonably complex to
\r
4015 * follow on it's own, but this is what we want (example two column sorting):
\r
4016 * fnLocalSorting = function(a,b){
\r
4018 * iTest = oSort['string-asc']('data11', 'data12');
\r
4019 * if (iTest !== 0)
\r
4021 * iTest = oSort['numeric-desc']('data21', 'data22');
\r
4022 * if (iTest !== 0)
\r
4024 * return oSort['numeric-asc']( aiOrig[a], aiOrig[b] );
\r
4026 * Basically we have a test for each sorting column, if the data in that column is equal,
\r
4027 * test the next column. If all columns match, then we use a numeric sort on the row
\r
4028 * positions in the original data array to provide a stable sort.
\r
4030 oSettings.aiDisplayMaster.sort( function ( a, b ) {
\r
4031 var k, l, lLen, iTest, aDataSort, sDataType;
\r
4032 for ( k=0 ; k<iSortLen ; k++ )
\r
4034 aDataSort = aoColumns[ aaSort[k][0] ].aDataSort;
\r
4036 for ( l=0, lLen=aDataSort.length ; l<lLen ; l++ )
\r
4038 sDataType = aoColumns[ aDataSort[l] ].sType;
\r
4040 iTest = oSort[ (sDataType ? sDataType : 'string')+"-"+aaSort[k][1] ](
\r
4041 aoData[a]._aSortData[ aDataSort[l] ],
\r
4042 aoData[b]._aSortData[ aDataSort[l] ]
\r
4045 if ( iTest !== 0 )
\r
4052 return oSort['numeric-asc']( aiOrig[a], aiOrig[b] );
\r
4056 /* Alter the sorting classes to take account of the changes */
\r
4057 if ( (bApplyClasses === undefined || bApplyClasses) && !oSettings.oFeatures.bDeferRender )
\r
4059 _fnSortingClasses( oSettings );
\r
4062 for ( i=0, iLen=oSettings.aoColumns.length ; i<iLen ; i++ )
\r
4064 var sTitle = aoColumns[i].sTitle.replace( /<.*?>/g, "" );
\r
4065 nTh = aoColumns[i].nTh;
\r
4066 nTh.removeAttribute('aria-sort');
\r
4067 nTh.removeAttribute('aria-label');
\r
4069 /* In ARIA only the first sorting column can be marked as sorting - no multi-sort option */
\r
4070 if ( aoColumns[i].bSortable )
\r
4072 if ( aaSort.length > 0 && aaSort[0][0] == i )
\r
4074 nTh.setAttribute('aria-sort', aaSort[0][1]=="asc" ? "ascending" : "descending" );
\r
4076 var nextSort = (aoColumns[i].asSorting[ aaSort[0][2]+1 ]) ?
\r
4077 aoColumns[i].asSorting[ aaSort[0][2]+1 ] : aoColumns[i].asSorting[0];
\r
4078 nTh.setAttribute('aria-label', sTitle+
\r
4079 (nextSort=="asc" ? oAria.sSortAscending : oAria.sSortDescending) );
\r
4083 nTh.setAttribute('aria-label', sTitle+
\r
4084 (aoColumns[i].asSorting[0]=="asc" ? oAria.sSortAscending : oAria.sSortDescending) );
\r
4089 nTh.setAttribute('aria-label', sTitle);
\r
4093 /* Tell the draw function that we have sorted the data */
\r
4094 oSettings.bSorted = true;
\r
4095 $(oSettings.oInstance).trigger('sort', oSettings);
\r
4097 /* Copy the master data into the draw array and re-draw */
\r
4098 if ( oSettings.oFeatures.bFilter )
\r
4100 /* _fnFilter() will redraw the table for us */
\r
4101 _fnFilterComplete( oSettings, oSettings.oPreviousSearch, 1 );
\r
4105 oSettings.aiDisplay = oSettings.aiDisplayMaster.slice();
\r
4106 oSettings._iDisplayStart = 0; /* reset display back to page 0 */
\r
4107 _fnCalculateEnd( oSettings );
\r
4108 _fnDraw( oSettings );
\r
4114 * Attach a sort handler (click) to a node
\r
4115 * @param {object} oSettings dataTables settings object
\r
4116 * @param {node} nNode node to attach the handler to
\r
4117 * @param {int} iDataIndex column sorting index
\r
4118 * @param {function} [fnCallback] callback function
\r
4119 * @memberof DataTable#oApi
\r
4121 function _fnSortAttachListener ( oSettings, nNode, iDataIndex, fnCallback )
\r
4123 _fnBindAction( nNode, {}, function (e) {
\r
4124 /* If the column is not sortable - don't to anything */
\r
4125 if ( oSettings.aoColumns[iDataIndex].bSortable === false )
\r
4131 * This is a little bit odd I admit... I declare a temporary function inside the scope of
\r
4132 * _fnBuildHead and the click handler in order that the code presented here can be used
\r
4133 * twice - once for when bProcessing is enabled, and another time for when it is
\r
4134 * disabled, as we need to perform slightly different actions.
\r
4135 * Basically the issue here is that the Javascript engine in modern browsers don't
\r
4136 * appear to allow the rendering engine to update the display while it is still executing
\r
4137 * it's thread (well - it does but only after long intervals). This means that the
\r
4138 * 'processing' display doesn't appear for a table sort. To break the js thread up a bit
\r
4139 * I force an execution break by using setTimeout - but this breaks the expected
\r
4140 * thread continuation for the end-developer's point of view (their code would execute
\r
4141 * too early), so we only do it when we absolutely have to.
\r
4143 var fnInnerSorting = function () {
\r
4144 var iColumn, iNextSort;
\r
4146 /* If the shift key is pressed then we are multiple column sorting */
\r
4149 /* Are we already doing some kind of sort on this column? */
\r
4150 var bFound = false;
\r
4151 for ( var i=0 ; i<oSettings.aaSorting.length ; i++ )
\r
4153 if ( oSettings.aaSorting[i][0] == iDataIndex )
\r
4156 iColumn = oSettings.aaSorting[i][0];
\r
4157 iNextSort = oSettings.aaSorting[i][2]+1;
\r
4159 if ( !oSettings.aoColumns[iColumn].asSorting[iNextSort] )
\r
4161 /* Reached the end of the sorting options, remove from multi-col sort */
\r
4162 oSettings.aaSorting.splice( i, 1 );
\r
4166 /* Move onto next sorting direction */
\r
4167 oSettings.aaSorting[i][1] = oSettings.aoColumns[iColumn].asSorting[iNextSort];
\r
4168 oSettings.aaSorting[i][2] = iNextSort;
\r
4174 /* No sort yet - add it in */
\r
4175 if ( bFound === false )
\r
4177 oSettings.aaSorting.push( [ iDataIndex,
\r
4178 oSettings.aoColumns[iDataIndex].asSorting[0], 0 ] );
\r
4183 /* If no shift key then single column sort */
\r
4184 if ( oSettings.aaSorting.length == 1 && oSettings.aaSorting[0][0] == iDataIndex )
\r
4186 iColumn = oSettings.aaSorting[0][0];
\r
4187 iNextSort = oSettings.aaSorting[0][2]+1;
\r
4188 if ( !oSettings.aoColumns[iColumn].asSorting[iNextSort] )
\r
4192 oSettings.aaSorting[0][1] = oSettings.aoColumns[iColumn].asSorting[iNextSort];
\r
4193 oSettings.aaSorting[0][2] = iNextSort;
\r
4197 oSettings.aaSorting.splice( 0, oSettings.aaSorting.length );
\r
4198 oSettings.aaSorting.push( [ iDataIndex,
\r
4199 oSettings.aoColumns[iDataIndex].asSorting[0], 0 ] );
\r
4203 /* Run the sort */
\r
4204 _fnSort( oSettings );
\r
4205 }; /* /fnInnerSorting */
\r
4207 if ( !oSettings.oFeatures.bProcessing )
\r
4213 _fnProcessingDisplay( oSettings, true );
\r
4214 setTimeout( function() {
\r
4216 if ( !oSettings.oFeatures.bServerSide )
\r
4218 _fnProcessingDisplay( oSettings, false );
\r
4223 /* Call the user specified callback function - used for async user interaction */
\r
4224 if ( typeof fnCallback == 'function' )
\r
4226 fnCallback( oSettings );
\r
4233 * Set the sorting classes on the header, Note: it is safe to call this function
\r
4234 * when bSort and bSortClasses are false
\r
4235 * @param {object} oSettings dataTables settings object
\r
4236 * @memberof DataTable#oApi
\r
4238 function _fnSortingClasses( oSettings )
\r
4240 var i, iLen, j, jLen, iFound;
\r
4241 var aaSort, sClass;
\r
4242 var iColumns = oSettings.aoColumns.length;
\r
4243 var oClasses = oSettings.oClasses;
\r
4245 for ( i=0 ; i<iColumns ; i++ )
\r
4247 if ( oSettings.aoColumns[i].bSortable )
\r
4249 $(oSettings.aoColumns[i].nTh).removeClass( oClasses.sSortAsc +" "+ oClasses.sSortDesc +
\r
4250 " "+ oSettings.aoColumns[i].sSortingClass );
\r
4254 if ( oSettings.aaSortingFixed !== null )
\r
4256 aaSort = oSettings.aaSortingFixed.concat( oSettings.aaSorting );
\r
4260 aaSort = oSettings.aaSorting.slice();
\r
4263 /* Apply the required classes to the header */
\r
4264 for ( i=0 ; i<oSettings.aoColumns.length ; i++ )
\r
4266 if ( oSettings.aoColumns[i].bSortable )
\r
4268 sClass = oSettings.aoColumns[i].sSortingClass;
\r
4270 for ( j=0 ; j<aaSort.length ; j++ )
\r
4272 if ( aaSort[j][0] == i )
\r
4274 sClass = ( aaSort[j][1] == "asc" ) ?
\r
4275 oClasses.sSortAsc : oClasses.sSortDesc;
\r
4280 $(oSettings.aoColumns[i].nTh).addClass( sClass );
\r
4282 if ( oSettings.bJUI )
\r
4284 /* jQuery UI uses extra markup */
\r
4285 var jqSpan = $("span."+oClasses.sSortIcon, oSettings.aoColumns[i].nTh);
\r
4286 jqSpan.removeClass(oClasses.sSortJUIAsc +" "+ oClasses.sSortJUIDesc +" "+
\r
4287 oClasses.sSortJUI +" "+ oClasses.sSortJUIAscAllowed +" "+ oClasses.sSortJUIDescAllowed );
\r
4290 if ( iFound == -1 )
\r
4292 sSpanClass = oSettings.aoColumns[i].sSortingClassJUI;
\r
4294 else if ( aaSort[iFound][1] == "asc" )
\r
4296 sSpanClass = oClasses.sSortJUIAsc;
\r
4300 sSpanClass = oClasses.sSortJUIDesc;
\r
4303 jqSpan.addClass( sSpanClass );
\r
4308 /* No sorting on this column, so add the base class. This will have been assigned by
\r
4311 $(oSettings.aoColumns[i].nTh).addClass( oSettings.aoColumns[i].sSortingClass );
\r
4316 * Apply the required classes to the table body
\r
4317 * Note that this is given as a feature switch since it can significantly slow down a sort
\r
4318 * on large data sets (adding and removing of classes is always slow at the best of times..)
\r
4319 * Further to this, note that this code is admittedly fairly ugly. It could be made a lot
\r
4320 * simpler using jQuery selectors and add/removeClass, but that is significantly slower
\r
4321 * (on the order of 5 times slower) - hence the direct DOM manipulation here.
\r
4322 * Note that for deferred drawing we do use jQuery - the reason being that taking the first
\r
4323 * row found to see if the whole column needs processed can miss classes since the first
\r
4324 * column might be new.
\r
4326 sClass = oClasses.sSortColumn;
\r
4328 if ( oSettings.oFeatures.bSort && oSettings.oFeatures.bSortClasses )
\r
4330 var nTds = _fnGetTdNodes( oSettings );
\r
4332 /* Determine what the sorting class for each column should be */
\r
4333 var iClass, iTargetCol;
\r
4334 var asClasses = [];
\r
4335 for (i = 0; i < iColumns; i++)
\r
4337 asClasses.push("");
\r
4339 for (i = 0, iClass = 1; i < aaSort.length; i++)
\r
4341 iTargetCol = parseInt( aaSort[i][0], 10 );
\r
4342 asClasses[iTargetCol] = sClass + iClass;
\r
4350 /* Make changes to the classes for each cell as needed */
\r
4351 var reClass = new RegExp(sClass + "[123]");
\r
4352 var sTmpClass, sCurrentClass, sNewClass;
\r
4353 for ( i=0, iLen=nTds.length; i<iLen; i++ )
\r
4355 /* Determine which column we're looking at */
\r
4356 iTargetCol = i % iColumns;
\r
4358 /* What is the full list of classes now */
\r
4359 sCurrentClass = nTds[i].className;
\r
4360 /* What sorting class should be applied? */
\r
4361 sNewClass = asClasses[iTargetCol];
\r
4362 /* What would the new full list be if we did a replacement? */
\r
4363 sTmpClass = sCurrentClass.replace(reClass, sNewClass);
\r
4365 if ( sTmpClass != sCurrentClass )
\r
4367 /* We changed something */
\r
4368 nTds[i].className = $.trim( sTmpClass );
\r
4370 else if ( sNewClass.length > 0 && sCurrentClass.indexOf(sNewClass) == -1 )
\r
4372 /* We need to add a class */
\r
4373 nTds[i].className = sCurrentClass + " " + sNewClass;
\r
4382 * Save the state of a table in a cookie such that the page can be reloaded
\r
4383 * @param {object} oSettings dataTables settings object
\r
4384 * @memberof DataTable#oApi
\r
4386 function _fnSaveState ( oSettings )
\r
4388 if ( !oSettings.oFeatures.bStateSave || oSettings.bDestroying )
\r
4393 /* Store the interesting variables */
\r
4394 var i, iLen, bInfinite=oSettings.oScroll.bInfinite;
\r
4396 "iCreate": new Date().getTime(),
\r
4397 "iStart": (bInfinite ? 0 : oSettings._iDisplayStart),
\r
4398 "iEnd": (bInfinite ? oSettings._iDisplayLength : oSettings._iDisplayEnd),
\r
4399 "iLength": oSettings._iDisplayLength,
\r
4400 "aaSorting": $.extend( true, [], oSettings.aaSorting ),
\r
4401 "oSearch": $.extend( true, {}, oSettings.oPreviousSearch ),
\r
4402 "aoSearchCols": $.extend( true, [], oSettings.aoPreSearchCols ),
\r
4406 for ( i=0, iLen=oSettings.aoColumns.length ; i<iLen ; i++ )
\r
4408 oState.abVisCols.push( oSettings.aoColumns[i].bVisible );
\r
4411 _fnCallbackFire( oSettings, "aoStateSaveParams", 'stateSaveParams', [oSettings, oState] );
\r
4413 oSettings.fnStateSave.call( oSettings.oInstance, oSettings, oState );
\r
4418 * Attempt to load a saved table state from a cookie
\r
4419 * @param {object} oSettings dataTables settings object
\r
4420 * @param {object} oInit DataTables init object so we can override settings
\r
4421 * @memberof DataTable#oApi
\r
4423 function _fnLoadState ( oSettings, oInit )
\r
4425 if ( !oSettings.oFeatures.bStateSave )
\r
4430 var oData = oSettings.fnStateLoad.call( oSettings.oInstance, oSettings );
\r
4436 /* Allow custom and plug-in manipulation functions to alter the saved data set and
\r
4437 * cancelling of loading by returning false
\r
4439 var abStateLoad = _fnCallbackFire( oSettings, 'aoStateLoadParams', 'stateLoadParams', [oSettings, oData] );
\r
4440 if ( $.inArray( false, abStateLoad ) !== -1 )
\r
4445 /* Store the saved state so it might be accessed at any time */
\r
4446 oSettings.oLoadedState = $.extend( true, {}, oData );
\r
4448 /* Restore key features */
\r
4449 oSettings._iDisplayStart = oData.iStart;
\r
4450 oSettings.iInitDisplayStart = oData.iStart;
\r
4451 oSettings._iDisplayEnd = oData.iEnd;
\r
4452 oSettings._iDisplayLength = oData.iLength;
\r
4453 oSettings.aaSorting = oData.aaSorting.slice();
\r
4454 oSettings.saved_aaSorting = oData.aaSorting.slice();
\r
4456 /* Search filtering */
\r
4457 $.extend( oSettings.oPreviousSearch, oData.oSearch );
\r
4458 $.extend( true, oSettings.aoPreSearchCols, oData.aoSearchCols );
\r
4460 /* Column visibility state
\r
4461 * Pass back visibility settings to the init handler, but to do not here override
\r
4462 * the init object that the user might have passed in
\r
4464 oInit.saved_aoColumns = [];
\r
4465 for ( var i=0 ; i<oData.abVisCols.length ; i++ )
\r
4467 oInit.saved_aoColumns[i] = {};
\r
4468 oInit.saved_aoColumns[i].bVisible = oData.abVisCols[i];
\r
4471 _fnCallbackFire( oSettings, 'aoStateLoaded', 'stateLoaded', [oSettings, oData] );
\r
4476 * Create a new cookie with a value to store the state of a table
\r
4477 * @param {string} sName name of the cookie to create
\r
4478 * @param {string} sValue the value the cookie should take
\r
4479 * @param {int} iSecs duration of the cookie
\r
4480 * @param {string} sBaseName sName is made up of the base + file name - this is the base
\r
4481 * @param {function} fnCallback User definable function to modify the cookie
\r
4482 * @memberof DataTable#oApi
\r
4484 function _fnCreateCookie ( sName, sValue, iSecs, sBaseName, fnCallback )
\r
4486 var date = new Date();
\r
4487 date.setTime( date.getTime()+(iSecs*1000) );
\r
4490 * Shocking but true - it would appear IE has major issues with having the path not having
\r
4491 * a trailing slash on it. We need the cookie to be available based on the path, so we
\r
4492 * have to append the file name to the cookie name. Appalling. Thanks to vex for adding the
\r
4493 * patch to use at least some of the path
\r
4495 var aParts = window.location.pathname.split('/');
\r
4496 var sNameFile = sName + '_' + aParts.pop().replace(/[\/:]/g,"").toLowerCase();
\r
4497 var sFullCookie, oData;
\r
4499 if ( fnCallback !== null )
\r
4501 oData = (typeof $.parseJSON === 'function') ?
\r
4502 $.parseJSON( sValue ) : eval( '('+sValue+')' );
\r
4503 sFullCookie = fnCallback( sNameFile, oData, date.toGMTString(),
\r
4504 aParts.join('/')+"/" );
\r
4508 sFullCookie = sNameFile + "=" + encodeURIComponent(sValue) +
\r
4509 "; expires=" + date.toGMTString() +"; path=" + aParts.join('/')+"/";
\r
4512 /* Are we going to go over the cookie limit of 4KiB? If so, try to delete a cookies
\r
4513 * belonging to DataTables.
\r
4516 aCookies =document.cookie.split(';'),
\r
4517 iNewCookieLen = sFullCookie.split(';')[0].length,
\r
4520 if ( iNewCookieLen+document.cookie.length+10 > 4096 ) /* Magic 10 for padding */
\r
4522 for ( var i=0, iLen=aCookies.length ; i<iLen ; i++ )
\r
4524 if ( aCookies[i].indexOf( sBaseName ) != -1 )
\r
4526 /* It's a DataTables cookie, so eval it and check the time stamp */
\r
4527 var aSplitCookie = aCookies[i].split('=');
\r
4529 oData = eval( '('+decodeURIComponent(aSplitCookie[1])+')' );
\r
4531 if ( oData && oData.iCreate )
\r
4533 aOldCookies.push( {
\r
4534 "name": aSplitCookie[0],
\r
4535 "time": oData.iCreate
\r
4543 // Make sure we delete the oldest ones first
\r
4544 aOldCookies.sort( function (a, b) {
\r
4545 return b.time - a.time;
\r
4548 // Eliminate as many old DataTables cookies as we need to
\r
4549 while ( iNewCookieLen + document.cookie.length + 10 > 4096 ) {
\r
4550 if ( aOldCookies.length === 0 ) {
\r
4551 // Deleted all DT cookies and still not enough space. Can't state save
\r
4555 var old = aOldCookies.pop();
\r
4556 document.cookie = old.name+"=; expires=Thu, 01-Jan-1970 00:00:01 GMT; path="+
\r
4557 aParts.join('/') + "/";
\r
4561 document.cookie = sFullCookie;
\r
4566 * Read an old cookie to get a cookie with an old table state
\r
4567 * @param {string} sName name of the cookie to read
\r
4568 * @returns {string} contents of the cookie - or null if no cookie with that name found
\r
4569 * @memberof DataTable#oApi
\r
4571 function _fnReadCookie ( sName )
\r
4574 aParts = window.location.pathname.split('/'),
\r
4575 sNameEQ = sName + '_' + aParts[aParts.length-1].replace(/[\/:]/g,"").toLowerCase() + '=',
\r
4576 sCookieContents = document.cookie.split(';');
\r
4578 for( var i=0 ; i<sCookieContents.length ; i++ )
\r
4580 var c = sCookieContents[i];
\r
4582 while (c.charAt(0)==' ')
\r
4584 c = c.substring(1,c.length);
\r
4587 if (c.indexOf(sNameEQ) === 0)
\r
4589 return decodeURIComponent( c.substring(sNameEQ.length,c.length) );
\r
4597 * Return the settings object for a particular table
\r
4598 * @param {node} nTable table we are using as a dataTable
\r
4599 * @returns {object} Settings object - or null if not found
\r
4600 * @memberof DataTable#oApi
\r
4602 function _fnSettingsFromNode ( nTable )
\r
4604 for ( var i=0 ; i<DataTable.settings.length ; i++ )
\r
4606 if ( DataTable.settings[i].nTable === nTable )
\r
4608 return DataTable.settings[i];
\r
4617 * Return an array with the TR nodes for the table
\r
4618 * @param {object} oSettings dataTables settings object
\r
4619 * @returns {array} TR array
\r
4620 * @memberof DataTable#oApi
\r
4622 function _fnGetTrNodes ( oSettings )
\r
4625 var aoData = oSettings.aoData;
\r
4626 for ( var i=0, iLen=aoData.length ; i<iLen ; i++ )
\r
4628 if ( aoData[i].nTr !== null )
\r
4630 aNodes.push( aoData[i].nTr );
\r
4638 * Return an flat array with all TD nodes for the table, or row
\r
4639 * @param {object} oSettings dataTables settings object
\r
4640 * @param {int} [iIndividualRow] aoData index to get the nodes for - optional
\r
4641 * if not given then the return array will contain all nodes for the table
\r
4642 * @returns {array} TD array
\r
4643 * @memberof DataTable#oApi
\r
4645 function _fnGetTdNodes ( oSettings, iIndividualRow )
\r
4647 var anReturn = [];
\r
4650 var iRow, iRows=oSettings.aoData.length,
\r
4651 iColumn, iColumns, oData, sNodeName, iStart=0, iEnd=iRows;
\r
4653 /* Allow the collection to be limited to just one row */
\r
4654 if ( iIndividualRow !== undefined )
\r
4656 iStart = iIndividualRow;
\r
4657 iEnd = iIndividualRow+1;
\r
4660 for ( iRow=iStart ; iRow<iEnd ; iRow++ )
\r
4662 oData = oSettings.aoData[iRow];
\r
4663 if ( oData.nTr !== null )
\r
4665 /* get the TD child nodes - taking into account text etc nodes */
\r
4667 nTd = oData.nTr.firstChild;
\r
4670 sNodeName = nTd.nodeName.toLowerCase();
\r
4671 if ( sNodeName == 'td' || sNodeName == 'th' )
\r
4673 anTds.push( nTd );
\r
4675 nTd = nTd.nextSibling;
\r
4679 for ( iColumn=0, iColumns=oSettings.aoColumns.length ; iColumn<iColumns ; iColumn++ )
\r
4681 if ( oSettings.aoColumns[iColumn].bVisible )
\r
4683 anReturn.push( anTds[iColumn-iCorrector] );
\r
4687 anReturn.push( oData._anHidden[iColumn] );
\r
4699 * Log an error message
\r
4700 * @param {object} oSettings dataTables settings object
\r
4701 * @param {int} iLevel log error messages, or display them to the user
\r
4702 * @param {string} sMesg error message
\r
4703 * @memberof DataTable#oApi
\r
4705 function _fnLog( oSettings, iLevel, sMesg )
\r
4707 var sAlert = (oSettings===null) ?
\r
4708 "DataTables warning: "+sMesg :
\r
4709 "DataTables warning (table id = '"+oSettings.sTableId+"'): "+sMesg;
\r
4711 if ( iLevel === 0 )
\r
4713 if ( DataTable.ext.sErrMode == 'alert' )
\r
4719 throw new Error(sAlert);
\r
4723 else if ( window.console && console.log )
\r
4725 console.log( sAlert );
\r
4731 * See if a property is defined on one object, if so assign it to the other object
\r
4732 * @param {object} oRet target object
\r
4733 * @param {object} oSrc source object
\r
4734 * @param {string} sName property
\r
4735 * @param {string} [sMappedName] name to map too - optional, sName used if not given
\r
4736 * @memberof DataTable#oApi
\r
4738 function _fnMap( oRet, oSrc, sName, sMappedName )
\r
4740 if ( sMappedName === undefined )
\r
4742 sMappedName = sName;
\r
4744 if ( oSrc[sName] !== undefined )
\r
4746 oRet[sMappedName] = oSrc[sName];
\r
4752 * Extend objects - very similar to jQuery.extend, but deep copy objects, and shallow
\r
4753 * copy arrays. The reason we need to do this, is that we don't want to deep copy array
\r
4754 * init values (such as aaSorting) since the dev wouldn't be able to override them, but
\r
4755 * we do want to deep copy arrays.
\r
4756 * @param {object} oOut Object to extend
\r
4757 * @param {object} oExtender Object from which the properties will be applied to oOut
\r
4758 * @returns {object} oOut Reference, just for convenience - oOut === the return.
\r
4759 * @memberof DataTable#oApi
\r
4760 * @todo This doesn't take account of arrays inside the deep copied objects.
\r
4762 function _fnExtend( oOut, oExtender )
\r
4766 for ( var prop in oExtender )
\r
4768 if ( oExtender.hasOwnProperty(prop) )
\r
4770 val = oExtender[prop];
\r
4772 if ( typeof oInit[prop] === 'object' && val !== null && $.isArray(val) === false )
\r
4774 $.extend( true, oOut[prop], val );
\r
4788 * Bind an event handers to allow a click or return key to activate the callback.
\r
4789 * This is good for accessibility since a return on the keyboard will have the
\r
4790 * same effect as a click, if the element has focus.
\r
4791 * @param {element} n Element to bind the action to
\r
4792 * @param {object} oData Data object to pass to the triggered function
\r
4793 * @param {function} fn Callback function for when the event is triggered
\r
4794 * @memberof DataTable#oApi
\r
4796 function _fnBindAction( n, oData, fn )
\r
4799 .bind( 'click.DT', oData, function (e) {
\r
4800 n.blur(); // Remove focus outline for mouse users
\r
4803 .bind( 'keypress.DT', oData, function (e){
\r
4804 if ( e.which === 13 ) {
\r
4807 .bind( 'selectstart.DT', function () {
\r
4808 /* Take the brutal approach to cancelling text selection */
\r
4815 * Register a callback function. Easily allows a callback function to be added to
\r
4816 * an array store of callback functions that can then all be called together.
\r
4817 * @param {object} oSettings dataTables settings object
\r
4818 * @param {string} sStore Name of the array storage for the callbacks in oSettings
\r
4819 * @param {function} fn Function to be called back
\r
4820 * @param {string} sName Identifying name for the callback (i.e. a label)
\r
4821 * @memberof DataTable#oApi
\r
4823 function _fnCallbackReg( oSettings, sStore, fn, sName )
\r
4827 oSettings[sStore].push( {
\r
4836 * Fire callback functions and trigger events. Note that the loop over the callback
\r
4837 * array store is done backwards! Further note that you do not want to fire off triggers
\r
4838 * in time sensitive applications (for example cell creation) as its slow.
\r
4839 * @param {object} oSettings dataTables settings object
\r
4840 * @param {string} sStore Name of the array storage for the callbacks in oSettings
\r
4841 * @param {string} sTrigger Name of the jQuery custom event to trigger. If null no trigger
\r
4843 * @param {array} aArgs Array of arguments to pass to the callback function / trigger
\r
4844 * @memberof DataTable#oApi
\r
4846 function _fnCallbackFire( oSettings, sStore, sTrigger, aArgs )
\r
4848 var aoStore = oSettings[sStore];
\r
4851 for ( var i=aoStore.length-1 ; i>=0 ; i-- )
\r
4853 aRet.push( aoStore[i].fn.apply( oSettings.oInstance, aArgs ) );
\r
4856 if ( sTrigger !== null )
\r
4858 $(oSettings.oInstance).trigger(sTrigger, aArgs);
\r
4866 * JSON stringify. If JSON.stringify it provided by the browser, json2.js or any other
\r
4867 * library, then we use that as it is fast, safe and accurate. If the function isn't
\r
4868 * available then we need to built it ourselves - the inspiration for this function comes
\r
4869 * from Craig Buckler ( http://www.sitepoint.com/javascript-json-serialization/ ). It is
\r
4870 * not perfect and absolutely should not be used as a replacement to json2.js - but it does
\r
4871 * do what we need, without requiring a dependency for DataTables.
\r
4872 * @param {object} o JSON object to be converted
\r
4873 * @returns {string} JSON string
\r
4874 * @memberof DataTable#oApi
\r
4876 var _fnJsonString = (window.JSON) ? JSON.stringify : function( o )
\r
4878 /* Not an object or array */
\r
4879 var sType = typeof o;
\r
4880 if (sType !== "object" || o === null)
\r
4882 // simple data type
\r
4883 if (sType === "string")
\r
4890 /* If object or array, need to recurse over it */
\r
4894 bArr = $.isArray(o);
\r
4898 mValue = o[sProp];
\r
4899 sType = typeof mValue;
\r
4901 if (sType === "string")
\r
4903 mValue = '"'+mValue+'"';
\r
4905 else if (sType === "object" && mValue !== null)
\r
4907 mValue = _fnJsonString(mValue);
\r
4910 json.push((bArr ? "" : '"'+sProp+'":') + mValue);
\r
4913 return (bArr ? "[" : "{") + json + (bArr ? "]" : "}");
\r
4918 * From some browsers (specifically IE6/7) we need special handling to work around browser
\r
4919 * bugs - this function is used to detect when these workarounds are needed.
\r
4920 * @param {object} oSettings dataTables settings object
\r
4921 * @memberof DataTable#oApi
\r
4923 function _fnBrowserDetect( oSettings )
\r
4925 /* IE6/7 will oversize a width 100% element inside a scrolling element, to include the
\r
4926 * width of the scrollbar, while other browsers ensure the inner element is contained
\r
4927 * without forcing scrolling
\r
4930 '<div style="position:absolute; top:0; left:0; height:1px; width:1px; overflow:hidden">'+
\r
4931 '<div style="position:absolute; top:1px; left:1px; width:100px; overflow:scroll;">'+
\r
4932 '<div id="DT_BrowserTest" style="width:100%; height:10px;"></div>'+
\r
4936 document.body.appendChild( n );
\r
4937 oSettings.oBrowser.bScrollOversize = $('#DT_BrowserTest', n)[0].offsetWidth === 100 ? true : false;
\r
4938 document.body.removeChild( n );
\r
4943 * Perform a jQuery selector action on the table's TR elements (from the tbody) and
\r
4944 * return the resulting jQuery object.
\r
4945 * @param {string|node|jQuery} sSelector jQuery selector or node collection to act on
\r
4946 * @param {object} [oOpts] Optional parameters for modifying the rows to be included
\r
4947 * @param {string} [oOpts.filter=none] Select TR elements that meet the current filter
\r
4948 * criterion ("applied") or all TR elements (i.e. no filter).
\r
4949 * @param {string} [oOpts.order=current] Order of the TR elements in the processed array.
\r
4950 * Can be either 'current', whereby the current sorting of the table is used, or
\r
4951 * 'original' whereby the original order the data was read into the table is used.
\r
4952 * @param {string} [oOpts.page=all] Limit the selection to the currently displayed page
\r
4953 * ("current") or not ("all"). If 'current' is given, then order is assumed to be
\r
4954 * 'current' and filter is 'applied', regardless of what they might be given as.
\r
4955 * @returns {object} jQuery object, filtered by the given selector.
\r
4959 * $(document).ready(function() {
\r
4960 * var oTable = $('#example').dataTable();
\r
4962 * // Highlight every second row
\r
4963 * oTable.$('tr:odd').css('backgroundColor', 'blue');
\r
4967 * $(document).ready(function() {
\r
4968 * var oTable = $('#example').dataTable();
\r
4970 * // Filter to rows with 'Webkit' in them, add a background colour and then
\r
4971 * // remove the filter, thus highlighting the 'Webkit' rows only.
\r
4972 * oTable.fnFilter('Webkit');
\r
4973 * oTable.$('tr', {"filter": "applied"}).css('backgroundColor', 'blue');
\r
4974 * oTable.fnFilter('');
\r
4977 this.$ = function ( sSelector, oOpts )
\r
4979 var i, iLen, a = [], tr;
\r
4980 var oSettings = _fnSettingsFromNode( this[DataTable.ext.iApiIndex] );
\r
4981 var aoData = oSettings.aoData;
\r
4982 var aiDisplay = oSettings.aiDisplay;
\r
4983 var aiDisplayMaster = oSettings.aiDisplayMaster;
\r
4990 oOpts = $.extend( {}, {
\r
4991 "filter": "none", // applied
\r
4992 "order": "current", // "original"
\r
4993 "page": "all" // current
\r
4996 // Current page implies that order=current and fitler=applied, since it is fairly
\r
4997 // senseless otherwise
\r
4998 if ( oOpts.page == 'current' )
\r
5000 for ( i=oSettings._iDisplayStart, iLen=oSettings.fnDisplayEnd() ; i<iLen ; i++ )
\r
5002 tr = aoData[ aiDisplay[i] ].nTr;
\r
5009 else if ( oOpts.order == "current" && oOpts.filter == "none" )
\r
5011 for ( i=0, iLen=aiDisplayMaster.length ; i<iLen ; i++ )
\r
5013 tr = aoData[ aiDisplayMaster[i] ].nTr;
\r
5020 else if ( oOpts.order == "current" && oOpts.filter == "applied" )
\r
5022 for ( i=0, iLen=aiDisplay.length ; i<iLen ; i++ )
\r
5024 tr = aoData[ aiDisplay[i] ].nTr;
\r
5031 else if ( oOpts.order == "original" && oOpts.filter == "none" )
\r
5033 for ( i=0, iLen=aoData.length ; i<iLen ; i++ )
\r
5035 tr = aoData[ i ].nTr ;
\r
5042 else if ( oOpts.order == "original" && oOpts.filter == "applied" )
\r
5044 for ( i=0, iLen=aoData.length ; i<iLen ; i++ )
\r
5046 tr = aoData[ i ].nTr;
\r
5047 if ( $.inArray( i, aiDisplay ) !== -1 && tr )
\r
5055 _fnLog( oSettings, 1, "Unknown selection options" );
\r
5058 /* We need to filter on the TR elements and also 'find' in their descendants
\r
5059 * to make the selector act like it would in a full table - so we need
\r
5060 * to build both results and then combine them together
\r
5063 var jqTRs = jqA.filter( sSelector );
\r
5064 var jqDescendants = jqA.find( sSelector );
\r
5066 return $( [].concat($.makeArray(jqTRs), $.makeArray(jqDescendants)) );
\r
5071 * Almost identical to $ in operation, but in this case returns the data for the matched
\r
5072 * rows - as such, the jQuery selector used should match TR row nodes or TD/TH cell nodes
\r
5073 * rather than any descendants, so the data can be obtained for the row/cell. If matching
\r
5074 * rows are found, the data returned is the original data array/object that was used to
\r
5075 * create the row (or a generated array if from a DOM source).
\r
5077 * This method is often useful in-combination with $ where both functions are given the
\r
5078 * same parameters and the array indexes will match identically.
\r
5079 * @param {string|node|jQuery} sSelector jQuery selector or node collection to act on
\r
5080 * @param {object} [oOpts] Optional parameters for modifying the rows to be included
\r
5081 * @param {string} [oOpts.filter=none] Select elements that meet the current filter
\r
5082 * criterion ("applied") or all elements (i.e. no filter).
\r
5083 * @param {string} [oOpts.order=current] Order of the data in the processed array.
\r
5084 * Can be either 'current', whereby the current sorting of the table is used, or
\r
5085 * 'original' whereby the original order the data was read into the table is used.
\r
5086 * @param {string} [oOpts.page=all] Limit the selection to the currently displayed page
\r
5087 * ("current") or not ("all"). If 'current' is given, then order is assumed to be
\r
5088 * 'current' and filter is 'applied', regardless of what they might be given as.
\r
5089 * @returns {array} Data for the matched elements. If any elements, as a result of the
\r
5090 * selector, were not TR, TD or TH elements in the DataTable, they will have a null
\r
5091 * entry in the array.
\r
5095 * $(document).ready(function() {
\r
5096 * var oTable = $('#example').dataTable();
\r
5098 * // Get the data from the first row in the table
\r
5099 * var data = oTable._('tr:first');
\r
5101 * // Do something useful with the data
\r
5102 * alert( "First cell is: "+data[0] );
\r
5106 * $(document).ready(function() {
\r
5107 * var oTable = $('#example').dataTable();
\r
5109 * // Filter to 'Webkit' and get all data for
\r
5110 * oTable.fnFilter('Webkit');
\r
5111 * var data = oTable._('tr', {"filter": "applied"});
\r
5113 * // Do something with the data
\r
5114 * alert( data.length+" rows matched the filter" );
\r
5117 this._ = function ( sSelector, oOpts )
\r
5120 var i, iLen, iIndex;
\r
5121 var aTrs = this.$( sSelector, oOpts );
\r
5123 for ( i=0, iLen=aTrs.length ; i<iLen ; i++ )
\r
5125 aOut.push( this.fnGetData(aTrs[i]) );
\r
5133 * Add a single new row or multiple rows of data to the table. Please note
\r
5134 * that this is suitable for client-side processing only - if you are using
\r
5135 * server-side processing (i.e. "bServerSide": true), then to add data, you
\r
5136 * must add it to the data source, i.e. the server-side, through an Ajax call.
\r
5137 * @param {array|object} mData The data to be added to the table. This can be:
\r
5139 * <li>1D array of data - add a single row with the data provided</li>
\r
5140 * <li>2D array of arrays - add multiple rows in a single call</li>
\r
5141 * <li>object - data object when using <i>mData</i></li>
\r
5142 * <li>array of objects - multiple data objects when using <i>mData</i></li>
\r
5144 * @param {bool} [bRedraw=true] redraw the table or not
\r
5145 * @returns {array} An array of integers, representing the list of indexes in
\r
5146 * <i>aoData</i> ({@link DataTable.models.oSettings}) that have been added to
\r
5151 * // Global var for counter
\r
5152 * var giCount = 2;
\r
5154 * $(document).ready(function() {
\r
5155 * $('#example').dataTable();
\r
5158 * function fnClickAddRow() {
\r
5159 * $('#example').dataTable().fnAddData( [
\r
5169 this.fnAddData = function( mData, bRedraw )
\r
5171 if ( mData.length === 0 )
\r
5176 var aiReturn = [];
\r
5179 /* Find settings from table node */
\r
5180 var oSettings = _fnSettingsFromNode( this[DataTable.ext.iApiIndex] );
\r
5182 /* Check if we want to add multiple rows or not */
\r
5183 if ( typeof mData[0] === "object" && mData[0] !== null )
\r
5185 for ( var i=0 ; i<mData.length ; i++ )
\r
5187 iTest = _fnAddData( oSettings, mData[i] );
\r
5188 if ( iTest == -1 )
\r
5192 aiReturn.push( iTest );
\r
5197 iTest = _fnAddData( oSettings, mData );
\r
5198 if ( iTest == -1 )
\r
5202 aiReturn.push( iTest );
\r
5205 oSettings.aiDisplay = oSettings.aiDisplayMaster.slice();
\r
5207 if ( bRedraw === undefined || bRedraw )
\r
5209 _fnReDraw( oSettings );
\r
5216 * This function will make DataTables recalculate the column sizes, based on the data
\r
5217 * contained in the table and the sizes applied to the columns (in the DOM, CSS or
\r
5218 * through the sWidth parameter). This can be useful when the width of the table's
\r
5219 * parent element changes (for example a window resize).
\r
5220 * @param {boolean} [bRedraw=true] Redraw the table or not, you will typically want to
\r
5224 * $(document).ready(function() {
\r
5225 * var oTable = $('#example').dataTable( {
\r
5226 * "sScrollY": "200px",
\r
5227 * "bPaginate": false
\r
5230 * $(window).bind('resize', function () {
\r
5231 * oTable.fnAdjustColumnSizing();
\r
5235 this.fnAdjustColumnSizing = function ( bRedraw )
\r
5237 var oSettings = _fnSettingsFromNode(this[DataTable.ext.iApiIndex]);
\r
5238 _fnAdjustColumnSizing( oSettings );
\r
5240 if ( bRedraw === undefined || bRedraw )
\r
5242 this.fnDraw( false );
\r
5244 else if ( oSettings.oScroll.sX !== "" || oSettings.oScroll.sY !== "" )
\r
5246 /* If not redrawing, but scrolling, we want to apply the new column sizes anyway */
\r
5247 this.oApi._fnScrollDraw(oSettings);
\r
5253 * Quickly and simply clear a table
\r
5254 * @param {bool} [bRedraw=true] redraw the table or not
\r
5258 * $(document).ready(function() {
\r
5259 * var oTable = $('#example').dataTable();
\r
5261 * // Immediately 'nuke' the current rows (perhaps waiting for an Ajax callback...)
\r
5262 * oTable.fnClearTable();
\r
5265 this.fnClearTable = function( bRedraw )
\r
5267 /* Find settings from table node */
\r
5268 var oSettings = _fnSettingsFromNode( this[DataTable.ext.iApiIndex] );
\r
5269 _fnClearTable( oSettings );
\r
5271 if ( bRedraw === undefined || bRedraw )
\r
5273 _fnDraw( oSettings );
\r
5279 * The exact opposite of 'opening' a row, this function will close any rows which
\r
5280 * are currently 'open'.
\r
5281 * @param {node} nTr the table row to 'close'
\r
5282 * @returns {int} 0 on success, or 1 if failed (can't find the row)
\r
5286 * $(document).ready(function() {
\r
5289 * // 'open' an information row when a row is clicked on
\r
5290 * $('#example tbody tr').click( function () {
\r
5291 * if ( oTable.fnIsOpen(this) ) {
\r
5292 * oTable.fnClose( this );
\r
5294 * oTable.fnOpen( this, "Temporary row opened", "info_row" );
\r
5298 * oTable = $('#example').dataTable();
\r
5301 this.fnClose = function( nTr )
\r
5303 /* Find settings from table node */
\r
5304 var oSettings = _fnSettingsFromNode( this[DataTable.ext.iApiIndex] );
\r
5306 for ( var i=0 ; i<oSettings.aoOpenRows.length ; i++ )
\r
5308 if ( oSettings.aoOpenRows[i].nParent == nTr )
\r
5310 var nTrParent = oSettings.aoOpenRows[i].nTr.parentNode;
\r
5313 /* Remove it if it is currently on display */
\r
5314 nTrParent.removeChild( oSettings.aoOpenRows[i].nTr );
\r
5316 oSettings.aoOpenRows.splice( i, 1 );
\r
5325 * Remove a row for the table
\r
5326 * @param {mixed} mTarget The index of the row from aoData to be deleted, or
\r
5327 * the TR element you want to delete
\r
5328 * @param {function|null} [fnCallBack] Callback function
\r
5329 * @param {bool} [bRedraw=true] Redraw the table or not
\r
5330 * @returns {array} The row that was deleted
\r
5334 * $(document).ready(function() {
\r
5335 * var oTable = $('#example').dataTable();
\r
5337 * // Immediately remove the first row
\r
5338 * oTable.fnDeleteRow( 0 );
\r
5341 this.fnDeleteRow = function( mTarget, fnCallBack, bRedraw )
\r
5343 /* Find settings from table node */
\r
5344 var oSettings = _fnSettingsFromNode( this[DataTable.ext.iApiIndex] );
\r
5345 var i, iLen, iAODataIndex;
\r
5347 iAODataIndex = (typeof mTarget === 'object') ?
\r
5348 _fnNodeToDataIndex(oSettings, mTarget) : mTarget;
\r
5350 /* Return the data array from this row */
\r
5351 var oData = oSettings.aoData.splice( iAODataIndex, 1 );
\r
5353 /* Update the _DT_RowIndex parameter */
\r
5354 for ( i=0, iLen=oSettings.aoData.length ; i<iLen ; i++ )
\r
5356 if ( oSettings.aoData[i].nTr !== null )
\r
5358 oSettings.aoData[i].nTr._DT_RowIndex = i;
\r
5362 /* Remove the target row from the search array */
\r
5363 var iDisplayIndex = $.inArray( iAODataIndex, oSettings.aiDisplay );
\r
5364 oSettings.asDataSearch.splice( iDisplayIndex, 1 );
\r
5366 /* Delete from the display arrays */
\r
5367 _fnDeleteIndex( oSettings.aiDisplayMaster, iAODataIndex );
\r
5368 _fnDeleteIndex( oSettings.aiDisplay, iAODataIndex );
\r
5370 /* If there is a user callback function - call it */
\r
5371 if ( typeof fnCallBack === "function" )
\r
5373 fnCallBack.call( this, oSettings, oData );
\r
5376 /* Check for an 'overflow' they case for displaying the table */
\r
5377 if ( oSettings._iDisplayStart >= oSettings.fnRecordsDisplay() )
\r
5379 oSettings._iDisplayStart -= oSettings._iDisplayLength;
\r
5380 if ( oSettings._iDisplayStart < 0 )
\r
5382 oSettings._iDisplayStart = 0;
\r
5386 if ( bRedraw === undefined || bRedraw )
\r
5388 _fnCalculateEnd( oSettings );
\r
5389 _fnDraw( oSettings );
\r
5397 * Restore the table to it's original state in the DOM by removing all of DataTables
\r
5398 * enhancements, alterations to the DOM structure of the table and event listeners.
\r
5399 * @param {boolean} [bRemove=false] Completely remove the table from the DOM
\r
5403 * $(document).ready(function() {
\r
5404 * // This example is fairly pointless in reality, but shows how fnDestroy can be used
\r
5405 * var oTable = $('#example').dataTable();
\r
5406 * oTable.fnDestroy();
\r
5409 this.fnDestroy = function ( bRemove )
\r
5411 var oSettings = _fnSettingsFromNode( this[DataTable.ext.iApiIndex] );
\r
5412 var nOrig = oSettings.nTableWrapper.parentNode;
\r
5413 var nBody = oSettings.nTBody;
\r
5416 bRemove = (bRemove===undefined) ? false : bRemove;
\r
5418 /* Flag to note that the table is currently being destroyed - no action should be taken */
\r
5419 oSettings.bDestroying = true;
\r
5421 /* Fire off the destroy callbacks for plug-ins etc */
\r
5422 _fnCallbackFire( oSettings, "aoDestroyCallback", "destroy", [oSettings] );
\r
5424 /* If the table is not being removed, restore the hidden columns */
\r
5427 for ( i=0, iLen=oSettings.aoColumns.length ; i<iLen ; i++ )
\r
5429 if ( oSettings.aoColumns[i].bVisible === false )
\r
5431 this.fnSetColumnVis( i, true );
\r
5436 /* Blitz all DT events */
\r
5437 $(oSettings.nTableWrapper).find('*').andSelf().unbind('.DT');
\r
5439 /* If there is an 'empty' indicator row, remove it */
\r
5440 $('tbody>tr>td.'+oSettings.oClasses.sRowEmpty, oSettings.nTable).parent().remove();
\r
5442 /* When scrolling we had to break the table up - restore it */
\r
5443 if ( oSettings.nTable != oSettings.nTHead.parentNode )
\r
5445 $(oSettings.nTable).children('thead').remove();
\r
5446 oSettings.nTable.appendChild( oSettings.nTHead );
\r
5449 if ( oSettings.nTFoot && oSettings.nTable != oSettings.nTFoot.parentNode )
\r
5451 $(oSettings.nTable).children('tfoot').remove();
\r
5452 oSettings.nTable.appendChild( oSettings.nTFoot );
\r
5455 /* Remove the DataTables generated nodes, events and classes */
\r
5456 oSettings.nTable.parentNode.removeChild( oSettings.nTable );
\r
5457 $(oSettings.nTableWrapper).remove();
\r
5459 oSettings.aaSorting = [];
\r
5460 oSettings.aaSortingFixed = [];
\r
5461 _fnSortingClasses( oSettings );
\r
5463 $(_fnGetTrNodes( oSettings )).removeClass( oSettings.asStripeClasses.join(' ') );
\r
5465 $('th, td', oSettings.nTHead).removeClass( [
\r
5466 oSettings.oClasses.sSortable,
\r
5467 oSettings.oClasses.sSortableAsc,
\r
5468 oSettings.oClasses.sSortableDesc,
\r
5469 oSettings.oClasses.sSortableNone ].join(' ')
\r
5471 if ( oSettings.bJUI )
\r
5473 $('th span.'+oSettings.oClasses.sSortIcon
\r
5474 + ', td span.'+oSettings.oClasses.sSortIcon, oSettings.nTHead).remove();
\r
5476 $('th, td', oSettings.nTHead).each( function () {
\r
5477 var jqWrapper = $('div.'+oSettings.oClasses.sSortJUIWrapper, this);
\r
5478 var kids = jqWrapper.contents();
\r
5479 $(this).append( kids );
\r
5480 jqWrapper.remove();
\r
5484 /* Add the TR elements back into the table in their original order */
\r
5485 if ( !bRemove && oSettings.nTableReinsertBefore )
\r
5487 nOrig.insertBefore( oSettings.nTable, oSettings.nTableReinsertBefore );
\r
5489 else if ( !bRemove )
\r
5491 nOrig.appendChild( oSettings.nTable );
\r
5494 for ( i=0, iLen=oSettings.aoData.length ; i<iLen ; i++ )
\r
5496 if ( oSettings.aoData[i].nTr !== null )
\r
5498 nBody.appendChild( oSettings.aoData[i].nTr );
\r
5502 /* Restore the width of the original table */
\r
5503 if ( oSettings.oFeatures.bAutoWidth === true )
\r
5505 oSettings.nTable.style.width = _fnStringToCss(oSettings.sDestroyWidth);
\r
5508 /* If the were originally stripe classes - then we add them back here. Note
\r
5509 * this is not fool proof (for example if not all rows had stripe classes - but
\r
5510 * it's a good effort without getting carried away
\r
5512 iLen = oSettings.asDestroyStripes.length;
\r
5515 var anRows = $(nBody).children('tr');
\r
5516 for ( i=0 ; i<iLen ; i++ )
\r
5518 anRows.filter(':nth-child(' + iLen + 'n + ' + i + ')').addClass( oSettings.asDestroyStripes[i] );
\r
5522 /* Remove the settings object from the settings array */
\r
5523 for ( i=0, iLen=DataTable.settings.length ; i<iLen ; i++ )
\r
5525 if ( DataTable.settings[i] == oSettings )
\r
5527 DataTable.settings.splice( i, 1 );
\r
5538 * Redraw the table
\r
5539 * @param {bool} [bComplete=true] Re-filter and resort (if enabled) the table before the draw.
\r
5543 * $(document).ready(function() {
\r
5544 * var oTable = $('#example').dataTable();
\r
5546 * // Re-draw the table - you wouldn't want to do it here, but it's an example :-)
\r
5547 * oTable.fnDraw();
\r
5550 this.fnDraw = function( bComplete )
\r
5552 var oSettings = _fnSettingsFromNode( this[DataTable.ext.iApiIndex] );
\r
5553 if ( bComplete === false )
\r
5555 _fnCalculateEnd( oSettings );
\r
5556 _fnDraw( oSettings );
\r
5560 _fnReDraw( oSettings );
\r
5566 * Filter the input based on data
\r
5567 * @param {string} sInput String to filter the table on
\r
5568 * @param {int|null} [iColumn] Column to limit filtering to
\r
5569 * @param {bool} [bRegex=false] Treat as regular expression or not
\r
5570 * @param {bool} [bSmart=true] Perform smart filtering or not
\r
5571 * @param {bool} [bShowGlobal=true] Show the input global filter in it's input box(es)
\r
5572 * @param {bool} [bCaseInsensitive=true] Do case-insensitive matching (true) or not (false)
\r
5576 * $(document).ready(function() {
\r
5577 * var oTable = $('#example').dataTable();
\r
5579 * // Sometime later - filter...
\r
5580 * oTable.fnFilter( 'test string' );
\r
5583 this.fnFilter = function( sInput, iColumn, bRegex, bSmart, bShowGlobal, bCaseInsensitive )
\r
5585 var oSettings = _fnSettingsFromNode( this[DataTable.ext.iApiIndex] );
\r
5587 if ( !oSettings.oFeatures.bFilter )
\r
5592 if ( bRegex === undefined || bRegex === null )
\r
5597 if ( bSmart === undefined || bSmart === null )
\r
5602 if ( bShowGlobal === undefined || bShowGlobal === null )
\r
5604 bShowGlobal = true;
\r
5607 if ( bCaseInsensitive === undefined || bCaseInsensitive === null )
\r
5609 bCaseInsensitive = true;
\r
5612 if ( iColumn === undefined || iColumn === null )
\r
5614 /* Global filter */
\r
5615 _fnFilterComplete( oSettings, {
\r
5616 "sSearch":sInput+"",
\r
5619 "bCaseInsensitive": bCaseInsensitive
\r
5622 if ( bShowGlobal && oSettings.aanFeatures.f )
\r
5624 var n = oSettings.aanFeatures.f;
\r
5625 for ( var i=0, iLen=n.length ; i<iLen ; i++ )
\r
5627 // IE9 throws an 'unknown error' if document.activeElement is used
\r
5628 // inside an iframe or frame...
\r
5630 if ( n[i]._DT_Input != document.activeElement )
\r
5632 $(n[i]._DT_Input).val( sInput );
\r
5636 $(n[i]._DT_Input).val( sInput );
\r
5643 /* Single column filter */
\r
5644 $.extend( oSettings.aoPreSearchCols[ iColumn ], {
\r
5645 "sSearch": sInput+"",
\r
5648 "bCaseInsensitive": bCaseInsensitive
\r
5650 _fnFilterComplete( oSettings, oSettings.oPreviousSearch, 1 );
\r
5656 * Get the data for the whole table, an individual row or an individual cell based on the
\r
5657 * provided parameters.
\r
5658 * @param {int|node} [mRow] A TR row node, TD/TH cell node or an integer. If given as
\r
5659 * a TR node then the data source for the whole row will be returned. If given as a
\r
5660 * TD/TH cell node then iCol will be automatically calculated and the data for the
\r
5661 * cell returned. If given as an integer, then this is treated as the aoData internal
\r
5662 * data index for the row (see fnGetPosition) and the data for that row used.
\r
5663 * @param {int} [iCol] Optional column index that you want the data of.
\r
5664 * @returns {array|object|string} If mRow is undefined, then the data for all rows is
\r
5665 * returned. If mRow is defined, just data for that row, and is iCol is
\r
5666 * defined, only data for the designated cell is returned.
\r
5671 * $(document).ready(function() {
\r
5672 * oTable = $('#example').dataTable();
\r
5674 * oTable.$('tr').click( function () {
\r
5675 * var data = oTable.fnGetData( this );
\r
5676 * // ... do something with the array / object of data for the row
\r
5681 * // Individual cell data
\r
5682 * $(document).ready(function() {
\r
5683 * oTable = $('#example').dataTable();
\r
5685 * oTable.$('td').click( function () {
\r
5686 * var sData = oTable.fnGetData( this );
\r
5687 * alert( 'The cell clicked on had the value of '+sData );
\r
5691 this.fnGetData = function( mRow, iCol )
\r
5693 var oSettings = _fnSettingsFromNode( this[DataTable.ext.iApiIndex] );
\r
5695 if ( mRow !== undefined )
\r
5698 if ( typeof mRow === 'object' )
\r
5700 var sNode = mRow.nodeName.toLowerCase();
\r
5701 if (sNode === "tr" )
\r
5703 iRow = _fnNodeToDataIndex(oSettings, mRow);
\r
5705 else if ( sNode === "td" )
\r
5707 iRow = _fnNodeToDataIndex(oSettings, mRow.parentNode);
\r
5708 iCol = _fnNodeToColumnIndex( oSettings, iRow, mRow );
\r
5712 if ( iCol !== undefined )
\r
5714 return _fnGetCellData( oSettings, iRow, iCol, '' );
\r
5716 return (oSettings.aoData[iRow]!==undefined) ?
\r
5717 oSettings.aoData[iRow]._aData : null;
\r
5719 return _fnGetDataMaster( oSettings );
\r
5724 * Get an array of the TR nodes that are used in the table's body. Note that you will
\r
5725 * typically want to use the '$' API method in preference to this as it is more
\r
5727 * @param {int} [iRow] Optional row index for the TR element you want
\r
5728 * @returns {array|node} If iRow is undefined, returns an array of all TR elements
\r
5729 * in the table's body, or iRow is defined, just the TR element requested.
\r
5733 * $(document).ready(function() {
\r
5734 * var oTable = $('#example').dataTable();
\r
5736 * // Get the nodes from the table
\r
5737 * var nNodes = oTable.fnGetNodes( );
\r
5740 this.fnGetNodes = function( iRow )
\r
5742 var oSettings = _fnSettingsFromNode( this[DataTable.ext.iApiIndex] );
\r
5744 if ( iRow !== undefined ) {
\r
5745 return (oSettings.aoData[iRow]!==undefined) ?
\r
5746 oSettings.aoData[iRow].nTr : null;
\r
5748 return _fnGetTrNodes( oSettings );
\r
5753 * Get the array indexes of a particular cell from it's DOM element
\r
5754 * and column index including hidden columns
\r
5755 * @param {node} nNode this can either be a TR, TD or TH in the table's body
\r
5756 * @returns {int} If nNode is given as a TR, then a single index is returned, or
\r
5757 * if given as a cell, an array of [row index, column index (visible),
\r
5758 * column index (all)] is given.
\r
5762 * $(document).ready(function() {
\r
5763 * $('#example tbody td').click( function () {
\r
5764 * // Get the position of the current data from the node
\r
5765 * var aPos = oTable.fnGetPosition( this );
\r
5767 * // Get the data array for this row
\r
5768 * var aData = oTable.fnGetData( aPos[0] );
\r
5770 * // Update the data array and return the value
\r
5771 * aData[ aPos[1] ] = 'clicked';
\r
5772 * this.innerHTML = 'clicked';
\r
5775 * // Init DataTables
\r
5776 * oTable = $('#example').dataTable();
\r
5779 this.fnGetPosition = function( nNode )
\r
5781 var oSettings = _fnSettingsFromNode( this[DataTable.ext.iApiIndex] );
\r
5782 var sNodeName = nNode.nodeName.toUpperCase();
\r
5784 if ( sNodeName == "TR" )
\r
5786 return _fnNodeToDataIndex(oSettings, nNode);
\r
5788 else if ( sNodeName == "TD" || sNodeName == "TH" )
\r
5790 var iDataIndex = _fnNodeToDataIndex( oSettings, nNode.parentNode );
\r
5791 var iColumnIndex = _fnNodeToColumnIndex( oSettings, iDataIndex, nNode );
\r
5792 return [ iDataIndex, _fnColumnIndexToVisible(oSettings, iColumnIndex ), iColumnIndex ];
\r
5799 * Check to see if a row is 'open' or not.
\r
5800 * @param {node} nTr the table row to check
\r
5801 * @returns {boolean} true if the row is currently open, false otherwise
\r
5805 * $(document).ready(function() {
\r
5808 * // 'open' an information row when a row is clicked on
\r
5809 * $('#example tbody tr').click( function () {
\r
5810 * if ( oTable.fnIsOpen(this) ) {
\r
5811 * oTable.fnClose( this );
\r
5813 * oTable.fnOpen( this, "Temporary row opened", "info_row" );
\r
5817 * oTable = $('#example').dataTable();
\r
5820 this.fnIsOpen = function( nTr )
\r
5822 var oSettings = _fnSettingsFromNode( this[DataTable.ext.iApiIndex] );
\r
5823 var aoOpenRows = oSettings.aoOpenRows;
\r
5825 for ( var i=0 ; i<oSettings.aoOpenRows.length ; i++ )
\r
5827 if ( oSettings.aoOpenRows[i].nParent == nTr )
\r
5837 * This function will place a new row directly after a row which is currently
\r
5838 * on display on the page, with the HTML contents that is passed into the
\r
5839 * function. This can be used, for example, to ask for confirmation that a
\r
5840 * particular record should be deleted.
\r
5841 * @param {node} nTr The table row to 'open'
\r
5842 * @param {string|node|jQuery} mHtml The HTML to put into the row
\r
5843 * @param {string} sClass Class to give the new TD cell
\r
5844 * @returns {node} The row opened. Note that if the table row passed in as the
\r
5845 * first parameter, is not found in the table, this method will silently
\r
5850 * $(document).ready(function() {
\r
5853 * // 'open' an information row when a row is clicked on
\r
5854 * $('#example tbody tr').click( function () {
\r
5855 * if ( oTable.fnIsOpen(this) ) {
\r
5856 * oTable.fnClose( this );
\r
5858 * oTable.fnOpen( this, "Temporary row opened", "info_row" );
\r
5862 * oTable = $('#example').dataTable();
\r
5865 this.fnOpen = function( nTr, mHtml, sClass )
\r
5867 /* Find settings from table node */
\r
5868 var oSettings = _fnSettingsFromNode( this[DataTable.ext.iApiIndex] );
\r
5870 /* Check that the row given is in the table */
\r
5871 var nTableRows = _fnGetTrNodes( oSettings );
\r
5872 if ( $.inArray(nTr, nTableRows) === -1 )
\r
5877 /* the old open one if there is one */
\r
5878 this.fnClose( nTr );
\r
5880 var nNewRow = document.createElement("tr");
\r
5881 var nNewCell = document.createElement("td");
\r
5882 nNewRow.appendChild( nNewCell );
\r
5883 nNewCell.className = sClass;
\r
5884 nNewCell.colSpan = _fnVisbleColumns( oSettings );
\r
5886 if (typeof mHtml === "string")
\r
5888 nNewCell.innerHTML = mHtml;
\r
5892 $(nNewCell).html( mHtml );
\r
5895 /* If the nTr isn't on the page at the moment - then we don't insert at the moment */
\r
5896 var nTrs = $('tr', oSettings.nTBody);
\r
5897 if ( $.inArray(nTr, nTrs) != -1 )
\r
5899 $(nNewRow).insertAfter(nTr);
\r
5902 oSettings.aoOpenRows.push( {
\r
5912 * Change the pagination - provides the internal logic for pagination in a simple API
\r
5913 * function. With this function you can have a DataTables table go to the next,
\r
5914 * previous, first or last pages.
\r
5915 * @param {string|int} mAction Paging action to take: "first", "previous", "next" or "last"
\r
5916 * or page number to jump to (integer), note that page 0 is the first page.
\r
5917 * @param {bool} [bRedraw=true] Redraw the table or not
\r
5921 * $(document).ready(function() {
\r
5922 * var oTable = $('#example').dataTable();
\r
5923 * oTable.fnPageChange( 'next' );
\r
5926 this.fnPageChange = function ( mAction, bRedraw )
\r
5928 var oSettings = _fnSettingsFromNode( this[DataTable.ext.iApiIndex] );
\r
5929 _fnPageChange( oSettings, mAction );
\r
5930 _fnCalculateEnd( oSettings );
\r
5932 if ( bRedraw === undefined || bRedraw )
\r
5934 _fnDraw( oSettings );
\r
5940 * Show a particular column
\r
5941 * @param {int} iCol The column whose display should be changed
\r
5942 * @param {bool} bShow Show (true) or hide (false) the column
\r
5943 * @param {bool} [bRedraw=true] Redraw the table or not
\r
5947 * $(document).ready(function() {
\r
5948 * var oTable = $('#example').dataTable();
\r
5950 * // Hide the second column after initialisation
\r
5951 * oTable.fnSetColumnVis( 1, false );
\r
5954 this.fnSetColumnVis = function ( iCol, bShow, bRedraw )
\r
5956 var oSettings = _fnSettingsFromNode( this[DataTable.ext.iApiIndex] );
\r
5958 var aoColumns = oSettings.aoColumns;
\r
5959 var aoData = oSettings.aoData;
\r
5960 var nTd, bAppend, iBefore;
\r
5962 /* No point in doing anything if we are requesting what is already true */
\r
5963 if ( aoColumns[iCol].bVisible == bShow )
\r
5968 /* Show the column */
\r
5972 for ( i=0 ; i<iCol ; i++ )
\r
5974 if ( aoColumns[i].bVisible )
\r
5980 /* Need to decide if we should use appendChild or insertBefore */
\r
5981 bAppend = (iInsert >= _fnVisbleColumns( oSettings ));
\r
5983 /* Which coloumn should we be inserting before? */
\r
5986 for ( i=iCol ; i<aoColumns.length ; i++ )
\r
5988 if ( aoColumns[i].bVisible )
\r
5996 for ( i=0, iLen=aoData.length ; i<iLen ; i++ )
\r
5998 if ( aoData[i].nTr !== null )
\r
6002 aoData[i].nTr.appendChild(
\r
6003 aoData[i]._anHidden[iCol]
\r
6008 aoData[i].nTr.insertBefore(
\r
6009 aoData[i]._anHidden[iCol],
\r
6010 _fnGetTdNodes( oSettings, i )[iBefore] );
\r
6017 /* Remove a column from display */
\r
6018 for ( i=0, iLen=aoData.length ; i<iLen ; i++ )
\r
6020 if ( aoData[i].nTr !== null )
\r
6022 nTd = _fnGetTdNodes( oSettings, i )[iCol];
\r
6023 aoData[i]._anHidden[iCol] = nTd;
\r
6024 nTd.parentNode.removeChild( nTd );
\r
6029 /* Clear to set the visible flag */
\r
6030 aoColumns[iCol].bVisible = bShow;
\r
6032 /* Redraw the header and footer based on the new column visibility */
\r
6033 _fnDrawHead( oSettings, oSettings.aoHeader );
\r
6034 if ( oSettings.nTFoot )
\r
6036 _fnDrawHead( oSettings, oSettings.aoFooter );
\r
6039 /* If there are any 'open' rows, then we need to alter the colspan for this col change */
\r
6040 for ( i=0, iLen=oSettings.aoOpenRows.length ; i<iLen ; i++ )
\r
6042 oSettings.aoOpenRows[i].nTr.colSpan = _fnVisbleColumns( oSettings );
\r
6045 /* Do a redraw incase anything depending on the table columns needs it
\r
6046 * (built-in: scrolling)
\r
6048 if ( bRedraw === undefined || bRedraw )
\r
6050 _fnAdjustColumnSizing( oSettings );
\r
6051 _fnDraw( oSettings );
\r
6054 _fnSaveState( oSettings );
\r
6059 * Get the settings for a particular table for external manipulation
\r
6060 * @returns {object} DataTables settings object. See
\r
6061 * {@link DataTable.models.oSettings}
\r
6065 * $(document).ready(function() {
\r
6066 * var oTable = $('#example').dataTable();
\r
6067 * var oSettings = oTable.fnSettings();
\r
6069 * // Show an example parameter from the settings
\r
6070 * alert( oSettings._iDisplayStart );
\r
6073 this.fnSettings = function()
\r
6075 return _fnSettingsFromNode( this[DataTable.ext.iApiIndex] );
\r
6080 * Sort the table by a particular column
\r
6081 * @param {int} iCol the data index to sort on. Note that this will not match the
\r
6082 * 'display index' if you have hidden data entries
\r
6086 * $(document).ready(function() {
\r
6087 * var oTable = $('#example').dataTable();
\r
6089 * // Sort immediately with columns 0 and 1
\r
6090 * oTable.fnSort( [ [0,'asc'], [1,'asc'] ] );
\r
6093 this.fnSort = function( aaSort )
\r
6095 var oSettings = _fnSettingsFromNode( this[DataTable.ext.iApiIndex] );
\r
6096 oSettings.aaSorting = aaSort;
\r
6097 _fnSort( oSettings );
\r
6102 * Attach a sort listener to an element for a given column
\r
6103 * @param {node} nNode the element to attach the sort listener to
\r
6104 * @param {int} iColumn the column that a click on this node will sort on
\r
6105 * @param {function} [fnCallback] callback function when sort is run
\r
6109 * $(document).ready(function() {
\r
6110 * var oTable = $('#example').dataTable();
\r
6112 * // Sort on column 1, when 'sorter' is clicked on
\r
6113 * oTable.fnSortListener( document.getElementById('sorter'), 1 );
\r
6116 this.fnSortListener = function( nNode, iColumn, fnCallback )
\r
6118 _fnSortAttachListener( _fnSettingsFromNode( this[DataTable.ext.iApiIndex] ), nNode, iColumn,
\r
6124 * Update a table cell or row - this method will accept either a single value to
\r
6125 * update the cell with, an array of values with one element for each column or
\r
6126 * an object in the same format as the original data source. The function is
\r
6127 * self-referencing in order to make the multi column updates easier.
\r
6128 * @param {object|array|string} mData Data to update the cell/row with
\r
6129 * @param {node|int} mRow TR element you want to update or the aoData index
\r
6130 * @param {int} [iColumn] The column to update (not used of mData is an array or object)
\r
6131 * @param {bool} [bRedraw=true] Redraw the table or not
\r
6132 * @param {bool} [bAction=true] Perform pre-draw actions or not
\r
6133 * @returns {int} 0 on success, 1 on error
\r
6137 * $(document).ready(function() {
\r
6138 * var oTable = $('#example').dataTable();
\r
6139 * oTable.fnUpdate( 'Example update', 0, 0 ); // Single cell
\r
6140 * oTable.fnUpdate( ['a', 'b', 'c', 'd', 'e'], 1, 0 ); // Row
\r
6143 this.fnUpdate = function( mData, mRow, iColumn, bRedraw, bAction )
\r
6145 var oSettings = _fnSettingsFromNode( this[DataTable.ext.iApiIndex] );
\r
6146 var i, iLen, sDisplay;
\r
6147 var iRow = (typeof mRow === 'object') ?
\r
6148 _fnNodeToDataIndex(oSettings, mRow) : mRow;
\r
6150 if ( $.isArray(mData) && iColumn === undefined )
\r
6152 /* Array update - update the whole row */
\r
6153 oSettings.aoData[iRow]._aData = mData.slice();
\r
6155 /* Flag to the function that we are recursing */
\r
6156 for ( i=0 ; i<oSettings.aoColumns.length ; i++ )
\r
6158 this.fnUpdate( _fnGetCellData( oSettings, iRow, i ), iRow, i, false, false );
\r
6161 else if ( $.isPlainObject(mData) && iColumn === undefined )
\r
6163 /* Object update - update the whole row - assume the developer gets the object right */
\r
6164 oSettings.aoData[iRow]._aData = $.extend( true, {}, mData );
\r
6166 for ( i=0 ; i<oSettings.aoColumns.length ; i++ )
\r
6168 this.fnUpdate( _fnGetCellData( oSettings, iRow, i ), iRow, i, false, false );
\r
6173 /* Individual cell update */
\r
6174 _fnSetCellData( oSettings, iRow, iColumn, mData );
\r
6175 sDisplay = _fnGetCellData( oSettings, iRow, iColumn, 'display' );
\r
6177 var oCol = oSettings.aoColumns[iColumn];
\r
6178 if ( oCol.fnRender !== null )
\r
6180 sDisplay = _fnRender( oSettings, iRow, iColumn );
\r
6181 if ( oCol.bUseRendered )
\r
6183 _fnSetCellData( oSettings, iRow, iColumn, sDisplay );
\r
6187 if ( oSettings.aoData[iRow].nTr !== null )
\r
6189 /* Do the actual HTML update */
\r
6190 _fnGetTdNodes( oSettings, iRow )[iColumn].innerHTML = sDisplay;
\r
6194 /* Modify the search index for this row (strictly this is likely not needed, since fnReDraw
\r
6195 * will rebuild the search array - however, the redraw might be disabled by the user)
\r
6197 var iDisplayIndex = $.inArray( iRow, oSettings.aiDisplay );
\r
6198 oSettings.asDataSearch[iDisplayIndex] = _fnBuildSearchRow(
\r
6200 _fnGetRowData( oSettings, iRow, 'filter', _fnGetColumns( oSettings, 'bSearchable' ) )
\r
6203 /* Perform pre-draw actions */
\r
6204 if ( bAction === undefined || bAction )
\r
6206 _fnAdjustColumnSizing( oSettings );
\r
6209 /* Redraw the table */
\r
6210 if ( bRedraw === undefined || bRedraw )
\r
6212 _fnReDraw( oSettings );
\r
6219 * Provide a common method for plug-ins to check the version of DataTables being used, in order
\r
6220 * to ensure compatibility.
\r
6221 * @param {string} sVersion Version string to check for, in the format "X.Y.Z". Note that the
\r
6222 * formats "X" and "X.Y" are also acceptable.
\r
6223 * @returns {boolean} true if this version of DataTables is greater or equal to the required
\r
6224 * version, or false if this version of DataTales is not suitable
\r
6229 * $(document).ready(function() {
\r
6230 * var oTable = $('#example').dataTable();
\r
6231 * alert( oTable.fnVersionCheck( '1.9.0' ) );
\r
6234 this.fnVersionCheck = DataTable.ext.fnVersionCheck;
\r
6238 * This is really a good bit rubbish this method of exposing the internal methods
\r
6239 * publicly... - To be fixed in 2.0 using methods on the prototype
\r
6244 * Create a wrapper function for exporting an internal functions to an external API.
\r
6245 * @param {string} sFunc API function name
\r
6246 * @returns {function} wrapped function
\r
6247 * @memberof DataTable#oApi
\r
6249 function _fnExternApiFunc (sFunc)
\r
6251 return function() {
\r
6252 var aArgs = [_fnSettingsFromNode(this[DataTable.ext.iApiIndex])].concat(
\r
6253 Array.prototype.slice.call(arguments) );
\r
6254 return DataTable.ext.oApi[sFunc].apply( this, aArgs );
\r
6260 * Reference to internal functions for use by plug-in developers. Note that these
\r
6261 * methods are references to internal functions and are considered to be private.
\r
6262 * If you use these methods, be aware that they are liable to change between versions
\r
6263 * (check the upgrade notes).
\r
6267 "_fnExternApiFunc": _fnExternApiFunc,
\r
6268 "_fnInitialise": _fnInitialise,
\r
6269 "_fnInitComplete": _fnInitComplete,
\r
6270 "_fnLanguageCompat": _fnLanguageCompat,
\r
6271 "_fnAddColumn": _fnAddColumn,
\r
6272 "_fnColumnOptions": _fnColumnOptions,
\r
6273 "_fnAddData": _fnAddData,
\r
6274 "_fnCreateTr": _fnCreateTr,
\r
6275 "_fnGatherData": _fnGatherData,
\r
6276 "_fnBuildHead": _fnBuildHead,
\r
6277 "_fnDrawHead": _fnDrawHead,
\r
6278 "_fnDraw": _fnDraw,
\r
6279 "_fnReDraw": _fnReDraw,
\r
6280 "_fnAjaxUpdate": _fnAjaxUpdate,
\r
6281 "_fnAjaxParameters": _fnAjaxParameters,
\r
6282 "_fnAjaxUpdateDraw": _fnAjaxUpdateDraw,
\r
6283 "_fnServerParams": _fnServerParams,
\r
6284 "_fnAddOptionsHtml": _fnAddOptionsHtml,
\r
6285 "_fnFeatureHtmlTable": _fnFeatureHtmlTable,
\r
6286 "_fnScrollDraw": _fnScrollDraw,
\r
6287 "_fnAdjustColumnSizing": _fnAdjustColumnSizing,
\r
6288 "_fnFeatureHtmlFilter": _fnFeatureHtmlFilter,
\r
6289 "_fnFilterComplete": _fnFilterComplete,
\r
6290 "_fnFilterCustom": _fnFilterCustom,
\r
6291 "_fnFilterColumn": _fnFilterColumn,
\r
6292 "_fnFilter": _fnFilter,
\r
6293 "_fnBuildSearchArray": _fnBuildSearchArray,
\r
6294 "_fnBuildSearchRow": _fnBuildSearchRow,
\r
6295 "_fnFilterCreateSearch": _fnFilterCreateSearch,
\r
6296 "_fnDataToSearch": _fnDataToSearch,
\r
6297 "_fnSort": _fnSort,
\r
6298 "_fnSortAttachListener": _fnSortAttachListener,
\r
6299 "_fnSortingClasses": _fnSortingClasses,
\r
6300 "_fnFeatureHtmlPaginate": _fnFeatureHtmlPaginate,
\r
6301 "_fnPageChange": _fnPageChange,
\r
6302 "_fnFeatureHtmlInfo": _fnFeatureHtmlInfo,
\r
6303 "_fnUpdateInfo": _fnUpdateInfo,
\r
6304 "_fnFeatureHtmlLength": _fnFeatureHtmlLength,
\r
6305 "_fnFeatureHtmlProcessing": _fnFeatureHtmlProcessing,
\r
6306 "_fnProcessingDisplay": _fnProcessingDisplay,
\r
6307 "_fnVisibleToColumnIndex": _fnVisibleToColumnIndex,
\r
6308 "_fnColumnIndexToVisible": _fnColumnIndexToVisible,
\r
6309 "_fnNodeToDataIndex": _fnNodeToDataIndex,
\r
6310 "_fnVisbleColumns": _fnVisbleColumns,
\r
6311 "_fnCalculateEnd": _fnCalculateEnd,
\r
6312 "_fnConvertToWidth": _fnConvertToWidth,
\r
6313 "_fnCalculateColumnWidths": _fnCalculateColumnWidths,
\r
6314 "_fnScrollingWidthAdjust": _fnScrollingWidthAdjust,
\r
6315 "_fnGetWidestNode": _fnGetWidestNode,
\r
6316 "_fnGetMaxLenString": _fnGetMaxLenString,
\r
6317 "_fnStringToCss": _fnStringToCss,
\r
6318 "_fnDetectType": _fnDetectType,
\r
6319 "_fnSettingsFromNode": _fnSettingsFromNode,
\r
6320 "_fnGetDataMaster": _fnGetDataMaster,
\r
6321 "_fnGetTrNodes": _fnGetTrNodes,
\r
6322 "_fnGetTdNodes": _fnGetTdNodes,
\r
6323 "_fnEscapeRegex": _fnEscapeRegex,
\r
6324 "_fnDeleteIndex": _fnDeleteIndex,
\r
6325 "_fnReOrderIndex": _fnReOrderIndex,
\r
6326 "_fnColumnOrdering": _fnColumnOrdering,
\r
6328 "_fnClearTable": _fnClearTable,
\r
6329 "_fnSaveState": _fnSaveState,
\r
6330 "_fnLoadState": _fnLoadState,
\r
6331 "_fnCreateCookie": _fnCreateCookie,
\r
6332 "_fnReadCookie": _fnReadCookie,
\r
6333 "_fnDetectHeader": _fnDetectHeader,
\r
6334 "_fnGetUniqueThs": _fnGetUniqueThs,
\r
6335 "_fnScrollBarWidth": _fnScrollBarWidth,
\r
6336 "_fnApplyToChildren": _fnApplyToChildren,
\r
6338 "_fnGetRowData": _fnGetRowData,
\r
6339 "_fnGetCellData": _fnGetCellData,
\r
6340 "_fnSetCellData": _fnSetCellData,
\r
6341 "_fnGetObjectDataFn": _fnGetObjectDataFn,
\r
6342 "_fnSetObjectDataFn": _fnSetObjectDataFn,
\r
6343 "_fnApplyColumnDefs": _fnApplyColumnDefs,
\r
6344 "_fnBindAction": _fnBindAction,
\r
6345 "_fnExtend": _fnExtend,
\r
6346 "_fnCallbackReg": _fnCallbackReg,
\r
6347 "_fnCallbackFire": _fnCallbackFire,
\r
6348 "_fnJsonString": _fnJsonString,
\r
6349 "_fnRender": _fnRender,
\r
6350 "_fnNodeToColumnIndex": _fnNodeToColumnIndex,
\r
6351 "_fnInfoMacros": _fnInfoMacros,
\r
6352 "_fnBrowserDetect": _fnBrowserDetect,
\r
6353 "_fnGetColumns": _fnGetColumns
\r
6356 $.extend( DataTable.ext.oApi, this.oApi );
\r
6358 for ( var sFunc in DataTable.ext.oApi )
\r
6362 this[sFunc] = _fnExternApiFunc(sFunc);
\r
6368 this.each(function() {
\r
6369 var i=0, iLen, j, jLen, k, kLen;
\r
6370 var sId = this.getAttribute( 'id' );
\r
6371 var bInitHandedOff = false;
\r
6372 var bUsePassedData = false;
\r
6375 /* Sanity check */
\r
6376 if ( this.nodeName.toLowerCase() != 'table' )
\r
6378 _fnLog( null, 0, "Attempted to initialise DataTables on a node which is not a "+
\r
6379 "table: "+this.nodeName );
\r
6383 /* Check to see if we are re-initialising a table */
\r
6384 for ( i=0, iLen=DataTable.settings.length ; i<iLen ; i++ )
\r
6386 /* Base check on table node */
\r
6387 if ( DataTable.settings[i].nTable == this )
\r
6389 if ( oInit === undefined || oInit.bRetrieve )
\r
6391 return DataTable.settings[i].oInstance;
\r
6393 else if ( oInit.bDestroy )
\r
6395 DataTable.settings[i].oInstance.fnDestroy();
\r
6400 _fnLog( DataTable.settings[i], 0, "Cannot reinitialise DataTable.\n\n"+
\r
6401 "To retrieve the DataTables object for this table, pass no arguments or see "+
\r
6402 "the docs for bRetrieve and bDestroy" );
\r
6407 /* If the element we are initialising has the same ID as a table which was previously
\r
6408 * initialised, but the table nodes don't match (from before) then we destroy the old
\r
6409 * instance by simply deleting it. This is under the assumption that the table has been
\r
6410 * destroyed by other methods. Anyone using non-id selectors will need to do this manually
\r
6412 if ( DataTable.settings[i].sTableId == this.id )
\r
6414 DataTable.settings.splice( i, 1 );
\r
6419 /* Ensure the table has an ID - required for accessibility */
\r
6420 if ( sId === null || sId === "" )
\r
6422 sId = "DataTables_Table_"+(DataTable.ext._oExternConfig.iNextUnique++);
\r
6426 /* Create the settings object for this table and set some of the default parameters */
\r
6427 var oSettings = $.extend( true, {}, DataTable.models.oSettings, {
\r
6429 "oApi": _that.oApi,
\r
6431 "sDestroyWidth": $(this).width(),
\r
6435 DataTable.settings.push( oSettings );
\r
6437 // Need to add the instance after the instance after the settings object has been added
\r
6438 // to the settings array, so we can self reference the table instance if more than one
\r
6439 oSettings.oInstance = (_that.length===1) ? _that : $(this).dataTable();
\r
6441 /* Setting up the initialisation object */
\r
6447 // Backwards compatibility, before we apply all the defaults
\r
6448 if ( oInit.oLanguage )
\r
6450 _fnLanguageCompat( oInit.oLanguage );
\r
6453 oInit = _fnExtend( $.extend(true, {}, DataTable.defaults), oInit );
\r
6455 // Map the initialisation options onto the settings object
\r
6456 _fnMap( oSettings.oFeatures, oInit, "bPaginate" );
\r
6457 _fnMap( oSettings.oFeatures, oInit, "bLengthChange" );
\r
6458 _fnMap( oSettings.oFeatures, oInit, "bFilter" );
\r
6459 _fnMap( oSettings.oFeatures, oInit, "bSort" );
\r
6460 _fnMap( oSettings.oFeatures, oInit, "bInfo" );
\r
6461 _fnMap( oSettings.oFeatures, oInit, "bProcessing" );
\r
6462 _fnMap( oSettings.oFeatures, oInit, "bAutoWidth" );
\r
6463 _fnMap( oSettings.oFeatures, oInit, "bSortClasses" );
\r
6464 _fnMap( oSettings.oFeatures, oInit, "bServerSide" );
\r
6465 _fnMap( oSettings.oFeatures, oInit, "bDeferRender" );
\r
6466 _fnMap( oSettings.oScroll, oInit, "sScrollX", "sX" );
\r
6467 _fnMap( oSettings.oScroll, oInit, "sScrollXInner", "sXInner" );
\r
6468 _fnMap( oSettings.oScroll, oInit, "sScrollY", "sY" );
\r
6469 _fnMap( oSettings.oScroll, oInit, "bScrollCollapse", "bCollapse" );
\r
6470 _fnMap( oSettings.oScroll, oInit, "bScrollInfinite", "bInfinite" );
\r
6471 _fnMap( oSettings.oScroll, oInit, "iScrollLoadGap", "iLoadGap" );
\r
6472 _fnMap( oSettings.oScroll, oInit, "bScrollAutoCss", "bAutoCss" );
\r
6473 _fnMap( oSettings, oInit, "asStripeClasses" );
\r
6474 _fnMap( oSettings, oInit, "asStripClasses", "asStripeClasses" ); // legacy
\r
6475 _fnMap( oSettings, oInit, "fnServerData" );
\r
6476 _fnMap( oSettings, oInit, "fnFormatNumber" );
\r
6477 _fnMap( oSettings, oInit, "sServerMethod" );
\r
6478 _fnMap( oSettings, oInit, "aaSorting" );
\r
6479 _fnMap( oSettings, oInit, "aaSortingFixed" );
\r
6480 _fnMap( oSettings, oInit, "aLengthMenu" );
\r
6481 _fnMap( oSettings, oInit, "sPaginationType" );
\r
6482 _fnMap( oSettings, oInit, "sAjaxSource" );
\r
6483 _fnMap( oSettings, oInit, "sAjaxDataProp" );
\r
6484 _fnMap( oSettings, oInit, "iCookieDuration" );
\r
6485 _fnMap( oSettings, oInit, "sCookiePrefix" );
\r
6486 _fnMap( oSettings, oInit, "sDom" );
\r
6487 _fnMap( oSettings, oInit, "bSortCellsTop" );
\r
6488 _fnMap( oSettings, oInit, "iTabIndex" );
\r
6489 _fnMap( oSettings, oInit, "oSearch", "oPreviousSearch" );
\r
6490 _fnMap( oSettings, oInit, "aoSearchCols", "aoPreSearchCols" );
\r
6491 _fnMap( oSettings, oInit, "iDisplayLength", "_iDisplayLength" );
\r
6492 _fnMap( oSettings, oInit, "bJQueryUI", "bJUI" );
\r
6493 _fnMap( oSettings, oInit, "fnCookieCallback" );
\r
6494 _fnMap( oSettings, oInit, "fnStateLoad" );
\r
6495 _fnMap( oSettings, oInit, "fnStateSave" );
\r
6496 _fnMap( oSettings.oLanguage, oInit, "fnInfoCallback" );
\r
6498 /* Callback functions which are array driven */
\r
6499 _fnCallbackReg( oSettings, 'aoDrawCallback', oInit.fnDrawCallback, 'user' );
\r
6500 _fnCallbackReg( oSettings, 'aoServerParams', oInit.fnServerParams, 'user' );
\r
6501 _fnCallbackReg( oSettings, 'aoStateSaveParams', oInit.fnStateSaveParams, 'user' );
\r
6502 _fnCallbackReg( oSettings, 'aoStateLoadParams', oInit.fnStateLoadParams, 'user' );
\r
6503 _fnCallbackReg( oSettings, 'aoStateLoaded', oInit.fnStateLoaded, 'user' );
\r
6504 _fnCallbackReg( oSettings, 'aoRowCallback', oInit.fnRowCallback, 'user' );
\r
6505 _fnCallbackReg( oSettings, 'aoRowCreatedCallback', oInit.fnCreatedRow, 'user' );
\r
6506 _fnCallbackReg( oSettings, 'aoHeaderCallback', oInit.fnHeaderCallback, 'user' );
\r
6507 _fnCallbackReg( oSettings, 'aoFooterCallback', oInit.fnFooterCallback, 'user' );
\r
6508 _fnCallbackReg( oSettings, 'aoInitComplete', oInit.fnInitComplete, 'user' );
\r
6509 _fnCallbackReg( oSettings, 'aoPreDrawCallback', oInit.fnPreDrawCallback, 'user' );
\r
6511 if ( oSettings.oFeatures.bServerSide && oSettings.oFeatures.bSort &&
\r
6512 oSettings.oFeatures.bSortClasses )
\r
6514 /* Enable sort classes for server-side processing. Safe to do it here, since server-side
\r
6515 * processing must be enabled by the developer
\r
6517 _fnCallbackReg( oSettings, 'aoDrawCallback', _fnSortingClasses, 'server_side_sort_classes' );
\r
6519 else if ( oSettings.oFeatures.bDeferRender )
\r
6521 _fnCallbackReg( oSettings, 'aoDrawCallback', _fnSortingClasses, 'defer_sort_classes' );
\r
6524 if ( oInit.bJQueryUI )
\r
6526 /* Use the JUI classes object for display. You could clone the oStdClasses object if
\r
6527 * you want to have multiple tables with multiple independent classes
\r
6529 $.extend( oSettings.oClasses, DataTable.ext.oJUIClasses );
\r
6531 if ( oInit.sDom === DataTable.defaults.sDom && DataTable.defaults.sDom === "lfrtip" )
\r
6533 /* Set the DOM to use a layout suitable for jQuery UI's theming */
\r
6534 oSettings.sDom = '<"H"lfr>t<"F"ip>';
\r
6539 $.extend( oSettings.oClasses, DataTable.ext.oStdClasses );
\r
6541 $(this).addClass( oSettings.oClasses.sTable );
\r
6543 /* Calculate the scroll bar width and cache it for use later on */
\r
6544 if ( oSettings.oScroll.sX !== "" || oSettings.oScroll.sY !== "" )
\r
6546 oSettings.oScroll.iBarWidth = _fnScrollBarWidth();
\r
6549 if ( oSettings.iInitDisplayStart === undefined )
\r
6551 /* Display start point, taking into account the save saving */
\r
6552 oSettings.iInitDisplayStart = oInit.iDisplayStart;
\r
6553 oSettings._iDisplayStart = oInit.iDisplayStart;
\r
6556 /* Must be done after everything which can be overridden by a cookie! */
\r
6557 if ( oInit.bStateSave )
\r
6559 oSettings.oFeatures.bStateSave = true;
\r
6560 _fnLoadState( oSettings, oInit );
\r
6561 _fnCallbackReg( oSettings, 'aoDrawCallback', _fnSaveState, 'state_save' );
\r
6564 if ( oInit.iDeferLoading !== null )
\r
6566 oSettings.bDeferLoading = true;
\r
6567 var tmp = $.isArray( oInit.iDeferLoading );
\r
6568 oSettings._iRecordsDisplay = tmp ? oInit.iDeferLoading[0] : oInit.iDeferLoading;
\r
6569 oSettings._iRecordsTotal = tmp ? oInit.iDeferLoading[1] : oInit.iDeferLoading;
\r
6572 if ( oInit.aaData !== null )
\r
6574 bUsePassedData = true;
\r
6577 /* Language definitions */
\r
6578 if ( oInit.oLanguage.sUrl !== "" )
\r
6580 /* Get the language definitions from a file - because this Ajax call makes the language
\r
6581 * get async to the remainder of this function we use bInitHandedOff to indicate that
\r
6582 * _fnInitialise will be fired by the returned Ajax handler, rather than the constructor
\r
6584 oSettings.oLanguage.sUrl = oInit.oLanguage.sUrl;
\r
6585 $.getJSON( oSettings.oLanguage.sUrl, null, function( json ) {
\r
6586 _fnLanguageCompat( json );
\r
6587 $.extend( true, oSettings.oLanguage, oInit.oLanguage, json );
\r
6588 _fnInitialise( oSettings );
\r
6590 bInitHandedOff = true;
\r
6594 $.extend( true, oSettings.oLanguage, oInit.oLanguage );
\r
6601 if ( oInit.asStripeClasses === null )
\r
6603 oSettings.asStripeClasses =[
\r
6604 oSettings.oClasses.sStripeOdd,
\r
6605 oSettings.oClasses.sStripeEven
\r
6609 /* Remove row stripe classes if they are already on the table row */
\r
6610 iLen=oSettings.asStripeClasses.length;
\r
6611 oSettings.asDestroyStripes = [];
\r
6614 var bStripeRemove = false;
\r
6615 var anRows = $(this).children('tbody').children('tr:lt(' + iLen + ')');
\r
6616 for ( i=0 ; i<iLen ; i++ )
\r
6618 if ( anRows.hasClass( oSettings.asStripeClasses[i] ) )
\r
6620 bStripeRemove = true;
\r
6622 /* Store the classes which we are about to remove so they can be re-added on destroy */
\r
6623 oSettings.asDestroyStripes.push( oSettings.asStripeClasses[i] );
\r
6627 if ( bStripeRemove )
\r
6629 anRows.removeClass( oSettings.asStripeClasses.join(' ') );
\r
6635 * See if we should load columns automatically or use defined ones
\r
6638 var aoColumnsInit;
\r
6639 var nThead = this.getElementsByTagName('thead');
\r
6640 if ( nThead.length !== 0 )
\r
6642 _fnDetectHeader( oSettings.aoHeader, nThead[0] );
\r
6643 anThs = _fnGetUniqueThs( oSettings );
\r
6646 /* If not given a column array, generate one with nulls */
\r
6647 if ( oInit.aoColumns === null )
\r
6649 aoColumnsInit = [];
\r
6650 for ( i=0, iLen=anThs.length ; i<iLen ; i++ )
\r
6652 aoColumnsInit.push( null );
\r
6657 aoColumnsInit = oInit.aoColumns;
\r
6660 /* Add the columns */
\r
6661 for ( i=0, iLen=aoColumnsInit.length ; i<iLen ; i++ )
\r
6663 /* Short cut - use the loop to check if we have column visibility state to restore */
\r
6664 if ( oInit.saved_aoColumns !== undefined && oInit.saved_aoColumns.length == iLen )
\r
6666 if ( aoColumnsInit[i] === null )
\r
6668 aoColumnsInit[i] = {};
\r
6670 aoColumnsInit[i].bVisible = oInit.saved_aoColumns[i].bVisible;
\r
6673 _fnAddColumn( oSettings, anThs ? anThs[i] : null );
\r
6676 /* Apply the column definitions */
\r
6677 _fnApplyColumnDefs( oSettings, oInit.aoColumnDefs, aoColumnsInit, function (iCol, oDef) {
\r
6678 _fnColumnOptions( oSettings, iCol, oDef );
\r
6684 * Check the aaSorting array
\r
6686 for ( i=0, iLen=oSettings.aaSorting.length ; i<iLen ; i++ )
\r
6688 if ( oSettings.aaSorting[i][0] >= oSettings.aoColumns.length )
\r
6690 oSettings.aaSorting[i][0] = 0;
\r
6692 var oColumn = oSettings.aoColumns[ oSettings.aaSorting[i][0] ];
\r
6694 /* Add a default sorting index */
\r
6695 if ( oSettings.aaSorting[i][2] === undefined )
\r
6697 oSettings.aaSorting[i][2] = 0;
\r
6700 /* If aaSorting is not defined, then we use the first indicator in asSorting */
\r
6701 if ( oInit.aaSorting === undefined && oSettings.saved_aaSorting === undefined )
\r
6703 oSettings.aaSorting[i][1] = oColumn.asSorting[0];
\r
6706 /* Set the current sorting index based on aoColumns.asSorting */
\r
6707 for ( j=0, jLen=oColumn.asSorting.length ; j<jLen ; j++ )
\r
6709 if ( oSettings.aaSorting[i][1] == oColumn.asSorting[j] )
\r
6711 oSettings.aaSorting[i][2] = j;
\r
6717 /* Do a first pass on the sorting classes (allows any size changes to be taken into
\r
6718 * account, and also will apply sorting disabled classes if disabled
\r
6720 _fnSortingClasses( oSettings );
\r
6725 * Cache the header, body and footer as required, creating them if needed
\r
6728 /* Browser support detection */
\r
6729 _fnBrowserDetect( oSettings );
\r
6731 // Work around for Webkit bug 83867 - store the caption-side before removing from doc
\r
6732 var captions = $(this).children('caption').each( function () {
\r
6733 this._captionSide = $(this).css('caption-side');
\r
6736 var thead = $(this).children('thead');
\r
6737 if ( thead.length === 0 )
\r
6739 thead = [ document.createElement( 'thead' ) ];
\r
6740 this.appendChild( thead[0] );
\r
6742 oSettings.nTHead = thead[0];
\r
6744 var tbody = $(this).children('tbody');
\r
6745 if ( tbody.length === 0 )
\r
6747 tbody = [ document.createElement( 'tbody' ) ];
\r
6748 this.appendChild( tbody[0] );
\r
6750 oSettings.nTBody = tbody[0];
\r
6751 oSettings.nTBody.setAttribute( "role", "alert" );
\r
6752 oSettings.nTBody.setAttribute( "aria-live", "polite" );
\r
6753 oSettings.nTBody.setAttribute( "aria-relevant", "all" );
\r
6755 var tfoot = $(this).children('tfoot');
\r
6756 if ( tfoot.length === 0 && captions.length > 0 && (oSettings.oScroll.sX !== "" || oSettings.oScroll.sY !== "") )
\r
6758 // If we are a scrolling table, and no footer has been given, then we need to create
\r
6759 // a tfoot element for the caption element to be appended to
\r
6760 tfoot = [ document.createElement( 'tfoot' ) ];
\r
6761 this.appendChild( tfoot[0] );
\r
6764 if ( tfoot.length > 0 )
\r
6766 oSettings.nTFoot = tfoot[0];
\r
6767 _fnDetectHeader( oSettings.aoFooter, oSettings.nTFoot );
\r
6770 /* Check if there is data passing into the constructor */
\r
6771 if ( bUsePassedData )
\r
6773 for ( i=0 ; i<oInit.aaData.length ; i++ )
\r
6775 _fnAddData( oSettings, oInit.aaData[ i ] );
\r
6780 /* Grab the data from the page */
\r
6781 _fnGatherData( oSettings );
\r
6784 /* Copy the data index array */
\r
6785 oSettings.aiDisplay = oSettings.aiDisplayMaster.slice();
\r
6787 /* Initialisation complete - table can be drawn */
\r
6788 oSettings.bInitialised = true;
\r
6790 /* Check if we need to initialise the table (it might not have been handed off to the
\r
6791 * language processor)
\r
6793 if ( bInitHandedOff === false )
\r
6795 _fnInitialise( oSettings );
\r
6805 * Provide a common method for plug-ins to check the version of DataTables being used, in order
\r
6806 * to ensure compatibility.
\r
6807 * @param {string} sVersion Version string to check for, in the format "X.Y.Z". Note that the
\r
6808 * formats "X" and "X.Y" are also acceptable.
\r
6809 * @returns {boolean} true if this version of DataTables is greater or equal to the required
\r
6810 * version, or false if this version of DataTales is not suitable
\r
6812 * @dtopt API-Static
\r
6815 * alert( $.fn.dataTable.fnVersionCheck( '1.9.0' ) );
\r
6817 DataTable.fnVersionCheck = function( sVersion )
\r
6819 /* This is cheap, but effective */
\r
6820 var fnZPad = function (Zpad, count)
\r
6822 while(Zpad.length < count) {
\r
6827 var aThis = DataTable.ext.sVersion.split('.');
\r
6828 var aThat = sVersion.split('.');
\r
6829 var sThis = '', sThat = '';
\r
6831 for ( var i=0, iLen=aThat.length ; i<iLen ; i++ )
\r
6833 sThis += fnZPad( aThis[i], 3 );
\r
6834 sThat += fnZPad( aThat[i], 3 );
\r
6837 return parseInt(sThis, 10) >= parseInt(sThat, 10);
\r
6842 * Check if a TABLE node is a DataTable table already or not.
\r
6843 * @param {node} nTable The TABLE node to check if it is a DataTable or not (note that other
\r
6844 * node types can be passed in, but will always return false).
\r
6845 * @returns {boolean} true the table given is a DataTable, or false otherwise
\r
6847 * @dtopt API-Static
\r
6850 * var ex = document.getElementById('example');
\r
6851 * if ( ! $.fn.DataTable.fnIsDataTable( ex ) ) {
\r
6852 * $(ex).dataTable();
\r
6855 DataTable.fnIsDataTable = function ( nTable )
\r
6857 var o = DataTable.settings;
\r
6859 for ( var i=0 ; i<o.length ; i++ )
\r
6861 if ( o[i].nTable === nTable || o[i].nScrollHead === nTable || o[i].nScrollFoot === nTable )
\r
6872 * Get all DataTable tables that have been initialised - optionally you can select to
\r
6873 * get only currently visible tables.
\r
6874 * @param {boolean} [bVisible=false] Flag to indicate if you want all (default) or
\r
6875 * visible tables only.
\r
6876 * @returns {array} Array of TABLE nodes (not DataTable instances) which are DataTables
\r
6878 * @dtopt API-Static
\r
6881 * var table = $.fn.dataTable.fnTables(true);
\r
6882 * if ( table.length > 0 ) {
\r
6883 * $(table).dataTable().fnAdjustColumnSizing();
\r
6886 DataTable.fnTables = function ( bVisible )
\r
6890 jQuery.each( DataTable.settings, function (i, o) {
\r
6891 if ( !bVisible || (bVisible === true && $(o.nTable).is(':visible')) )
\r
6893 out.push( o.nTable );
\r
6902 * Version string for plug-ins to check compatibility. Allowed format is
\r
6903 * a.b.c.d.e where: a:int, b:int, c:int, d:string(dev|beta), e:int. d and
\r
6907 * @default Version number
\r
6909 DataTable.version = "1.9.4";
\r
6912 * Private data store, containing all of the settings objects that are created for the
\r
6913 * tables on a given page.
\r
6915 * Note that the <i>DataTable.settings</i> object is aliased to <i>jQuery.fn.dataTableExt</i>
\r
6916 * through which it may be accessed and manipulated, or <i>jQuery.fn.dataTable.settings</i>.
\r
6922 DataTable.settings = [];
\r
6925 * Object models container, for the various models that DataTables has available
\r
6926 * to it. These models define the objects that are used to hold the active state
\r
6927 * and configuration of the table.
\r
6930 DataTable.models = {};
\r
6934 * DataTables extension options and plug-ins. This namespace acts as a collection "area"
\r
6935 * for plug-ins that can be used to extend the default DataTables behaviour - indeed many
\r
6936 * of the build in methods use this method to provide their own capabilities (sorting methods
\r
6939 * Note that this namespace is aliased to jQuery.fn.dataTableExt so it can be readily accessed
\r
6940 * and modified by plug-ins.
\r
6943 DataTable.models.ext = {
\r
6945 * Plug-in filtering functions - this method of filtering is complimentary to the default
\r
6946 * type based filtering, and a lot more comprehensive as it allows you complete control
\r
6947 * over the filtering logic. Each element in this array is a function (parameters
\r
6948 * described below) that is called for every row in the table, and your logic decides if
\r
6949 * it should be included in the filtered data set or not.
\r
6952 * Function input parameters:
\r
6954 * <li>{object} DataTables settings object: see {@link DataTable.models.oSettings}.</li>
\r
6955 * <li>{array|object} Data for the row to be processed (same as the original format
\r
6956 * that was passed in as the data source, or an array from a DOM data source</li>
\r
6957 * <li>{int} Row index in aoData ({@link DataTable.models.oSettings.aoData}), which can
\r
6958 * be useful to retrieve the TR element if you need DOM interaction.</li>
\r
6962 * Function return:
\r
6964 * <li>{boolean} Include the row in the filtered result set (true) or not (false)</li>
\r
6972 * // The following example shows custom filtering being applied to the fourth column (i.e.
\r
6973 * // the aData[3] index) based on two input values from the end-user, matching the data in
\r
6974 * // a certain range.
\r
6975 * $.fn.dataTableExt.afnFiltering.push(
\r
6976 * function( oSettings, aData, iDataIndex ) {
\r
6977 * var iMin = document.getElementById('min').value * 1;
\r
6978 * var iMax = document.getElementById('max').value * 1;
\r
6979 * var iVersion = aData[3] == "-" ? 0 : aData[3]*1;
\r
6980 * if ( iMin == "" && iMax == "" ) {
\r
6983 * else if ( iMin == "" && iVersion < iMax ) {
\r
6986 * else if ( iMin < iVersion && "" == iMax ) {
\r
6989 * else if ( iMin < iVersion && iVersion < iMax ) {
\r
6996 "afnFiltering": [],
\r
7000 * Plug-in sorting functions - this method of sorting is complimentary to the default type
\r
7001 * based sorting that DataTables does automatically, allowing much greater control over the
\r
7002 * the data that is being used to sort a column. This is useful if you want to do sorting
\r
7003 * based on live data (for example the contents of an 'input' element) rather than just the
\r
7004 * static string that DataTables knows of. The way these plug-ins work is that you create
\r
7005 * an array of the values you wish to be sorted for the column in question and then return
\r
7006 * that array. Which pre-sorting function is run here depends on the sSortDataType parameter
\r
7007 * that is used for the column (if any). This is the corollary of <i>ofnSearch</i> for sort
\r
7011 * Function input parameters:
\r
7013 * <li>{object} DataTables settings object: see {@link DataTable.models.oSettings}.</li>
\r
7014 * <li>{int} Target column index</li>
\r
7018 * Function return:
\r
7020 * <li>{array} Data for the column to be sorted upon</li>
\r
7025 * Note that as of v1.9, it is typically preferable to use <i>mData</i> to prepare data for
\r
7026 * the different uses that DataTables can put the data to. Specifically <i>mData</i> when
\r
7027 * used as a function will give you a 'type' (sorting, filtering etc) that you can use to
\r
7028 * prepare the data as required for the different types. As such, this method is deprecated.
\r
7034 * // Updating the cached sorting information with user entered values in HTML input elements
\r
7035 * jQuery.fn.dataTableExt.afnSortData['dom-text'] = function ( oSettings, iColumn )
\r
7038 * $( 'td:eq('+iColumn+') input', oSettings.oApi._fnGetTrNodes(oSettings) ).each( function () {
\r
7039 * aData.push( this.value );
\r
7044 "afnSortData": [],
\r
7048 * Feature plug-ins - This is an array of objects which describe the feature plug-ins that are
\r
7049 * available to DataTables. These feature plug-ins are accessible through the sDom initialisation
\r
7050 * option. As such, each feature plug-in must describe a function that is used to initialise
\r
7051 * itself (fnInit), a character so the feature can be enabled by sDom (cFeature) and the name
\r
7052 * of the feature (sFeature). Thus the objects attached to this method must provide:
\r
7054 * <li>{function} fnInit Initialisation of the plug-in
\r
7057 * Function input parameters:
\r
7059 * <li>{object} DataTables settings object: see {@link DataTable.models.oSettings}.</li>
\r
7063 * Function return:
\r
7065 * <li>{node|null} The element which contains your feature. Note that the return
\r
7066 * may also be void if your plug-in does not require to inject any DOM elements
\r
7067 * into DataTables control (sDom) - for example this might be useful when
\r
7068 * developing a plug-in which allows table control via keyboard entry.</li>
\r
7073 * <li>{character} cFeature Character that will be matched in sDom - case sensitive</li>
\r
7074 * <li>{string} sFeature Feature name</li>
\r
7080 * // How TableTools initialises itself.
\r
7081 * $.fn.dataTableExt.aoFeatures.push( {
\r
7082 * "fnInit": function( oSettings ) {
\r
7083 * return new TableTools( { "oDTSettings": oSettings } );
\r
7085 * "cFeature": "T",
\r
7086 * "sFeature": "TableTools"
\r
7093 * Type detection plug-in functions - DataTables utilises types to define how sorting and
\r
7094 * filtering behave, and types can be either be defined by the developer (sType for the
\r
7095 * column) or they can be automatically detected by the methods in this array. The functions
\r
7096 * defined in the array are quite simple, taking a single parameter (the data to analyse)
\r
7097 * and returning the type if it is a known type, or null otherwise.
\r
7100 * Function input parameters:
\r
7102 * <li>{*} Data from the column cell to be analysed</li>
\r
7106 * Function return:
\r
7108 * <li>{string|null} Data type detected, or null if unknown (and thus pass it
\r
7109 * on to the other type detection functions.</li>
\r
7117 * // Currency type detection plug-in:
\r
7118 * jQuery.fn.dataTableExt.aTypes.push(
\r
7119 * function ( sData ) {
\r
7120 * var sValidChars = "0123456789.-";
\r
7123 * // Check the numeric part
\r
7124 * for ( i=1 ; i<sData.length ; i++ ) {
\r
7125 * Char = sData.charAt(i);
\r
7126 * if (sValidChars.indexOf(Char) == -1) {
\r
7131 * // Check prefixed by currency
\r
7132 * if ( sData.charAt(0) == '$' || sData.charAt(0) == '£' ) {
\r
7133 * return 'currency';
\r
7143 * Provide a common method for plug-ins to check the version of DataTables being used,
\r
7144 * in order to ensure compatibility.
\r
7146 * @param {string} sVersion Version string to check for, in the format "X.Y.Z". Note
\r
7147 * that the formats "X" and "X.Y" are also acceptable.
\r
7148 * @returns {boolean} true if this version of DataTables is greater or equal to the
\r
7149 * required version, or false if this version of DataTales is not suitable
\r
7152 * $(document).ready(function() {
\r
7153 * var oTable = $('#example').dataTable();
\r
7154 * alert( oTable.fnVersionCheck( '1.9.0' ) );
\r
7157 "fnVersionCheck": DataTable.fnVersionCheck,
\r
7161 * Index for what 'this' index API functions should use
\r
7169 * Pre-processing of filtering data plug-ins - When you assign the sType for a column
\r
7170 * (or have it automatically detected for you by DataTables or a type detection plug-in),
\r
7171 * you will typically be using this for custom sorting, but it can also be used to provide
\r
7172 * custom filtering by allowing you to pre-processing the data and returning the data in
\r
7173 * the format that should be filtered upon. This is done by adding functions this object
\r
7174 * with a parameter name which matches the sType for that target column. This is the
\r
7175 * corollary of <i>afnSortData</i> for filtering data.
\r
7178 * Function input parameters:
\r
7180 * <li>{*} Data from the column cell to be prepared for filtering</li>
\r
7184 * Function return:
\r
7186 * <li>{string|null} Formatted string that will be used for the filtering.</li>
\r
7191 * Note that as of v1.9, it is typically preferable to use <i>mData</i> to prepare data for
\r
7192 * the different uses that DataTables can put the data to. Specifically <i>mData</i> when
\r
7193 * used as a function will give you a 'type' (sorting, filtering etc) that you can use to
\r
7194 * prepare the data as required for the different types. As such, this method is deprecated.
\r
7200 * $.fn.dataTableExt.ofnSearch['title-numeric'] = function ( sData ) {
\r
7201 * return sData.replace(/\n/g," ").replace( /<.*?>/g, "" );
\r
7208 * Container for all private functions in DataTables so they can be exposed externally
\r
7216 * Storage for the various classes that DataTables uses
\r
7220 "oStdClasses": {},
\r
7224 * Storage for the various classes that DataTables uses - jQuery UI suitable
\r
7228 "oJUIClasses": {},
\r
7232 * Pagination plug-in methods - The style and controls of the pagination can significantly
\r
7233 * impact on how the end user interacts with the data in your table, and DataTables allows
\r
7234 * the addition of pagination controls by extending this object, which can then be enabled
\r
7235 * through the <i>sPaginationType</i> initialisation parameter. Each pagination type that
\r
7236 * is added is an object (the property name of which is what <i>sPaginationType</i> refers
\r
7237 * to) that has two properties, both methods that are used by DataTables to update the
\r
7238 * control's state.
\r
7241 * fnInit - Initialisation of the paging controls. Called only during initialisation
\r
7242 * of the table. It is expected that this function will add the required DOM elements
\r
7243 * to the page for the paging controls to work. The element pointer
\r
7244 * 'oSettings.aanFeatures.p' array is provided by DataTables to contain the paging
\r
7245 * controls (note that this is a 2D array to allow for multiple instances of each
\r
7246 * DataTables DOM element). It is suggested that you add the controls to this element
\r
7250 * Function input parameters:
\r
7252 * <li>{object} DataTables settings object: see {@link DataTable.models.oSettings}.</li>
\r
7253 * <li>{node} Container into which the pagination controls must be inserted</li>
\r
7254 * <li>{function} Draw callback function - whenever the controls cause a page
\r
7255 * change, this method must be called to redraw the table.</li>
\r
7259 * Function return:
\r
7261 * <li>No return required</li>
\r
7267 * fnInit - This function is called whenever the paging status of the table changes and is
\r
7268 * typically used to update classes and/or text of the paging controls to reflex the new
\r
7272 * Function input parameters:
\r
7274 * <li>{object} DataTables settings object: see {@link DataTable.models.oSettings}.</li>
\r
7275 * <li>{function} Draw callback function - in case you need to redraw the table again
\r
7276 * or attach new event listeners</li>
\r
7280 * Function return:
\r
7282 * <li>No return required</li>
\r
7292 * $.fn.dataTableExt.oPagination.four_button = {
\r
7293 * "fnInit": function ( oSettings, nPaging, fnCallbackDraw ) {
\r
7294 * nFirst = document.createElement( 'span' );
\r
7295 * nPrevious = document.createElement( 'span' );
\r
7296 * nNext = document.createElement( 'span' );
\r
7297 * nLast = document.createElement( 'span' );
\r
7299 * nFirst.appendChild( document.createTextNode( oSettings.oLanguage.oPaginate.sFirst ) );
\r
7300 * nPrevious.appendChild( document.createTextNode( oSettings.oLanguage.oPaginate.sPrevious ) );
\r
7301 * nNext.appendChild( document.createTextNode( oSettings.oLanguage.oPaginate.sNext ) );
\r
7302 * nLast.appendChild( document.createTextNode( oSettings.oLanguage.oPaginate.sLast ) );
\r
7304 * nFirst.className = "paginate_button first";
\r
7305 * nPrevious.className = "paginate_button previous";
\r
7306 * nNext.className="paginate_button next";
\r
7307 * nLast.className = "paginate_button last";
\r
7309 * nPaging.appendChild( nFirst );
\r
7310 * nPaging.appendChild( nPrevious );
\r
7311 * nPaging.appendChild( nNext );
\r
7312 * nPaging.appendChild( nLast );
\r
7314 * $(nFirst).click( function () {
\r
7315 * oSettings.oApi._fnPageChange( oSettings, "first" );
\r
7316 * fnCallbackDraw( oSettings );
\r
7319 * $(nPrevious).click( function() {
\r
7320 * oSettings.oApi._fnPageChange( oSettings, "previous" );
\r
7321 * fnCallbackDraw( oSettings );
\r
7324 * $(nNext).click( function() {
\r
7325 * oSettings.oApi._fnPageChange( oSettings, "next" );
\r
7326 * fnCallbackDraw( oSettings );
\r
7329 * $(nLast).click( function() {
\r
7330 * oSettings.oApi._fnPageChange( oSettings, "last" );
\r
7331 * fnCallbackDraw( oSettings );
\r
7334 * $(nFirst).bind( 'selectstart', function () { return false; } );
\r
7335 * $(nPrevious).bind( 'selectstart', function () { return false; } );
\r
7336 * $(nNext).bind( 'selectstart', function () { return false; } );
\r
7337 * $(nLast).bind( 'selectstart', function () { return false; } );
\r
7340 * "fnUpdate": function ( oSettings, fnCallbackDraw ) {
\r
7341 * if ( !oSettings.aanFeatures.p ) {
\r
7345 * // Loop over each instance of the pager
\r
7346 * var an = oSettings.aanFeatures.p;
\r
7347 * for ( var i=0, iLen=an.length ; i<iLen ; i++ ) {
\r
7348 * var buttons = an[i].getElementsByTagName('span');
\r
7349 * if ( oSettings._iDisplayStart === 0 ) {
\r
7350 * buttons[0].className = "paginate_disabled_previous";
\r
7351 * buttons[1].className = "paginate_disabled_previous";
\r
7354 * buttons[0].className = "paginate_enabled_previous";
\r
7355 * buttons[1].className = "paginate_enabled_previous";
\r
7358 * if ( oSettings.fnDisplayEnd() == oSettings.fnRecordsDisplay() ) {
\r
7359 * buttons[2].className = "paginate_disabled_next";
\r
7360 * buttons[3].className = "paginate_disabled_next";
\r
7363 * buttons[2].className = "paginate_enabled_next";
\r
7364 * buttons[3].className = "paginate_enabled_next";
\r
7370 "oPagination": {},
\r
7374 * Sorting plug-in methods - Sorting in DataTables is based on the detected type of the
\r
7375 * data column (you can add your own type detection functions, or override automatic
\r
7376 * detection using sType). With this specific type given to the column, DataTables will
\r
7377 * apply the required sort from the functions in the object. Each sort type must provide
\r
7378 * two mandatory methods, one each for ascending and descending sorting, and can optionally
\r
7379 * provide a pre-formatting method that will help speed up sorting by allowing DataTables
\r
7380 * to pre-format the sort data only once (rather than every time the actual sort functions
\r
7381 * are run). The two sorting functions are typical Javascript sort methods:
\r
7384 * Function input parameters:
\r
7386 * <li>{*} Data to compare to the second parameter</li>
\r
7387 * <li>{*} Data to compare to the first parameter</li>
\r
7391 * Function return:
\r
7393 * <li>{int} Sorting match: <0 if first parameter should be sorted lower than
\r
7394 * the second parameter, ===0 if the two parameters are equal and >0 if
\r
7395 * the first parameter should be sorted height than the second parameter.</li>
\r
7403 * // Case-sensitive string sorting, with no pre-formatting method
\r
7404 * $.extend( $.fn.dataTableExt.oSort, {
\r
7405 * "string-case-asc": function(x,y) {
\r
7406 * return ((x < y) ? -1 : ((x > y) ? 1 : 0));
\r
7408 * "string-case-desc": function(x,y) {
\r
7409 * return ((x < y) ? 1 : ((x > y) ? -1 : 0));
\r
7414 * // Case-insensitive string sorting, with pre-formatting
\r
7415 * $.extend( $.fn.dataTableExt.oSort, {
\r
7416 * "string-pre": function(x) {
\r
7417 * return x.toLowerCase();
\r
7419 * "string-asc": function(x,y) {
\r
7420 * return ((x < y) ? -1 : ((x > y) ? 1 : 0));
\r
7422 * "string-desc": function(x,y) {
\r
7423 * return ((x < y) ? 1 : ((x > y) ? -1 : 0));
\r
7431 * Version string for plug-ins to check compatibility. Allowed format is
\r
7432 * a.b.c.d.e where: a:int, b:int, c:int, d:string(dev|beta), e:int. d and
\r
7435 * @default Version number
\r
7437 "sVersion": DataTable.version,
\r
7441 * How should DataTables report an error. Can take the value 'alert' or 'throw'
\r
7445 "sErrMode": "alert",
\r
7449 * Store information for DataTables to access globally about other instances
\r
7453 "_oExternConfig": {
\r
7454 /* int:iNextUnique - next unique number for an instance */
\r
7463 * Template object for the way in which DataTables holds information about
\r
7464 * search information for the global filter and individual column filters.
\r
7467 DataTable.models.oSearch = {
\r
7469 * Flag to indicate if the filtering should be case insensitive or not
\r
7473 "bCaseInsensitive": true,
\r
7476 * Applied search term
\r
7478 * @default <i>Empty string</i>
\r
7483 * Flag to indicate if the search term should be interpreted as a
\r
7484 * regular expression (true) or not (false) and therefore and special
\r
7485 * regex characters escaped.
\r
7492 * Flag to indicate if DataTables is to use its smart filtering or not.
\r
7503 * Template object for the way in which DataTables holds information about
\r
7504 * each individual row. This is the object format used for the settings
\r
7508 DataTable.models.oRow = {
\r
7510 * TR element for the row
\r
7517 * Data object from the original data source for the row. This is either
\r
7518 * an array if using the traditional form of DataTables, or an object if
\r
7519 * using mData options. The exact type will depend on the passed in
\r
7520 * data from the data source, or will be an array if using DOM a data
\r
7522 * @type array|object
\r
7528 * Sorting data cache - this array is ostensibly the same length as the
\r
7529 * number of columns (although each index is generated only as it is
\r
7530 * needed), and holds the data that is used for sorting each column in the
\r
7531 * row. We do this cache generation at the start of the sort in order that
\r
7532 * the formatting of the sort data need be done only once for each cell
\r
7533 * per sort. This array should not be read from or written to by anything
\r
7534 * other than the master sorting methods.
\r
7542 * Array of TD elements that are cached for hidden rows, so they can be
\r
7543 * reinserted into the table if a column is made visible again (or to act
\r
7544 * as a store if a column is made hidden). Only hidden columns have a
\r
7545 * reference in the array. For non-hidden columns the value is either
\r
7546 * undefined or null.
\r
7547 * @type array nodes
\r
7554 * Cache of the class name that DataTables has applied to the row, so we
\r
7555 * can quickly look at this variable rather than needing to do a DOM check
\r
7556 * on className for the nTr property.
\r
7558 * @default <i>Empty string</i>
\r
7567 * Template object for the column information object in DataTables. This object
\r
7568 * is held in the settings aoColumns array and contains all the information that
\r
7569 * DataTables needs about each individual column.
\r
7571 * Note that this object is related to {@link DataTable.defaults.columns}
\r
7572 * but this one is the internal data store for DataTables's cache of columns.
\r
7573 * It should NOT be manipulated outside of DataTables. Any configuration should
\r
7574 * be done through the initialisation options.
\r
7577 DataTable.models.oColumn = {
\r
7579 * A list of the columns that sorting should occur on when this column
\r
7580 * is sorted. That this property is an array allows multi-column sorting
\r
7581 * to be defined for a column (for example first name / last name columns
\r
7582 * would benefit from this). The values are integers pointing to the
\r
7583 * columns to be sorted on (typically it will be a single integer pointing
\r
7584 * at itself, but that doesn't need to be the case).
\r
7587 "aDataSort": null,
\r
7590 * Define the sorting directions that are applied to the column, in sequence
\r
7591 * as the column is repeatedly sorted upon - i.e. the first value is used
\r
7592 * as the sorting direction when the column if first sorted (clicked on).
\r
7593 * Sort it again (click again) and it will move on to the next index.
\r
7594 * Repeat until loop.
\r
7597 "asSorting": null,
\r
7600 * Flag to indicate if the column is searchable, and thus should be included
\r
7601 * in the filtering or not.
\r
7604 "bSearchable": null,
\r
7607 * Flag to indicate if the column is sortable or not.
\r
7610 "bSortable": null,
\r
7613 * <code>Deprecated</code> When using fnRender, you have two options for what
\r
7614 * to do with the data, and this property serves as the switch. Firstly, you
\r
7615 * can have the sorting and filtering use the rendered value (true - default),
\r
7616 * or you can have the sorting and filtering us the original value (false).
\r
7618 * Please note that this option has now been deprecated and will be removed
\r
7619 * in the next version of DataTables. Please use mRender / mData rather than
\r
7624 "bUseRendered": null,
\r
7627 * Flag to indicate if the column is currently visible in the table or not
\r
7633 * Flag to indicate to the type detection method if the automatic type
\r
7634 * detection should be used, or if a column type (sType) has been specified
\r
7639 "_bAutoType": true,
\r
7642 * Developer definable function that is called whenever a cell is created (Ajax source,
\r
7643 * etc) or processed for input (DOM source). This can be used as a compliment to mRender
\r
7644 * allowing you to modify the DOM element (add background colour for example) when the
\r
7645 * element is available.
\r
7647 * @param {element} nTd The TD node that has been created
\r
7648 * @param {*} sData The Data for the cell
\r
7649 * @param {array|object} oData The data for the whole row
\r
7650 * @param {int} iRow The row index for the aoData data store
\r
7653 "fnCreatedCell": null,
\r
7656 * Function to get data from a cell in a column. You should <b>never</b>
\r
7657 * access data directly through _aData internally in DataTables - always use
\r
7658 * the method attached to this property. It allows mData to function as
\r
7659 * required. This function is automatically assigned by the column
\r
7660 * initialisation method
\r
7662 * @param {array|object} oData The data array/object for the array
\r
7663 * (i.e. aoData[]._aData)
\r
7664 * @param {string} sSpecific The specific data type you want to get -
\r
7665 * 'display', 'type' 'filter' 'sort'
\r
7666 * @returns {*} The data for the cell from the given row's data
\r
7669 "fnGetData": null,
\r
7672 * <code>Deprecated</code> Custom display function that will be called for the
\r
7673 * display of each cell in this column.
\r
7675 * Please note that this option has now been deprecated and will be removed
\r
7676 * in the next version of DataTables. Please use mRender / mData rather than
\r
7679 * @param {object} o Object with the following parameters:
\r
7680 * @param {int} o.iDataRow The row in aoData
\r
7681 * @param {int} o.iDataColumn The column in question
\r
7682 * @param {array} o.aData The data for the row in question
\r
7683 * @param {object} o.oSettings The settings object for this DataTables instance
\r
7684 * @returns {string} The string you which to use in the display
\r
7691 * Function to set data for a cell in the column. You should <b>never</b>
\r
7692 * set the data directly to _aData internally in DataTables - always use
\r
7693 * this method. It allows mData to function as required. This function
\r
7694 * is automatically assigned by the column initialisation method
\r
7696 * @param {array|object} oData The data array/object for the array
\r
7697 * (i.e. aoData[]._aData)
\r
7698 * @param {*} sValue Value to set
\r
7701 "fnSetData": null,
\r
7704 * Property to read the value for the cells in the column from the data
\r
7705 * source array / object. If null, then the default content is used, if a
\r
7706 * function is given then the return from the function is used.
\r
7707 * @type function|int|string|null
\r
7713 * Partner property to mData which is used (only when defined) to get
\r
7714 * the data - i.e. it is basically the same as mData, but without the
\r
7715 * 'set' option, and also the data fed to it is the result from mData.
\r
7716 * This is the rendering method to match the data method of mData.
\r
7717 * @type function|int|string|null
\r
7723 * Unique header TH/TD element for this column - this is what the sorting
\r
7724 * listener is attached to (if sorting is enabled.)
\r
7731 * Unique footer TH/TD element for this column (if there is one). Not used
\r
7732 * in DataTables as such, but can be used for plug-ins to reference the
\r
7733 * footer for each column.
\r
7740 * The class to apply to all TD elements in the table's TBODY for the column
\r
7747 * When DataTables calculates the column widths to assign to each column,
\r
7748 * it finds the longest string in each column and then constructs a
\r
7749 * temporary table and reads the widths from that. The problem with this
\r
7750 * is that "mmm" is much wider then "iiii", but the latter is a longer
\r
7751 * string - thus the calculation can go wrong (doing it properly and putting
\r
7752 * it into an DOM object and measuring that is horribly(!) slow). Thus as
\r
7753 * a "work around" we provide this option. It will append its value to the
\r
7754 * text that is found to be the longest string for the column - i.e. padding.
\r
7757 "sContentPadding": null,
\r
7760 * Allows a default value to be given for a column's data, and will be used
\r
7761 * whenever a null data source is encountered (this can be because mData
\r
7762 * is set to null, or because the data source itself is null).
\r
7766 "sDefaultContent": null,
\r
7769 * Name for the column, allowing reference to the column by name as well as
\r
7770 * by index (needs a lookup to work by name).
\r
7776 * Custom sorting data type - defines which of the available plug-ins in
\r
7777 * afnSortData the custom sorting will use - if any is defined.
\r
7781 "sSortDataType": 'std',
\r
7784 * Class to be applied to the header element when sorting on this column
\r
7788 "sSortingClass": null,
\r
7791 * Class to be applied to the header element when sorting on this column -
\r
7792 * when jQuery UI theming is used.
\r
7796 "sSortingClassJUI": null,
\r
7799 * Title of the column - what is seen in the TH element (nTh).
\r
7805 * Column sorting and filtering type
\r
7812 * Width of the column
\r
7819 * Width of the column when it was first "encountered"
\r
7823 "sWidthOrig": null
\r
7829 * Initialisation options that can be given to DataTables at initialisation
\r
7833 DataTable.defaults = {
\r
7835 * An array of data to use for the table, passed in at initialisation which
\r
7836 * will be used in preference to any data which is already in the DOM. This is
\r
7837 * particularly useful for constructing tables purely in Javascript, for
\r
7838 * example with a custom Ajax call.
\r
7844 * // Using a 2D array data source
\r
7845 * $(document).ready( function () {
\r
7846 * $('#example').dataTable( {
\r
7848 * ['Trident', 'Internet Explorer 4.0', 'Win 95+', 4, 'X'],
\r
7849 * ['Trident', 'Internet Explorer 5.0', 'Win 95+', 5, 'C'],
\r
7852 * { "sTitle": "Engine" },
\r
7853 * { "sTitle": "Browser" },
\r
7854 * { "sTitle": "Platform" },
\r
7855 * { "sTitle": "Version" },
\r
7856 * { "sTitle": "Grade" }
\r
7862 * // Using an array of objects as a data source (mData)
\r
7863 * $(document).ready( function () {
\r
7864 * $('#example').dataTable( {
\r
7867 * "engine": "Trident",
\r
7868 * "browser": "Internet Explorer 4.0",
\r
7869 * "platform": "Win 95+",
\r
7874 * "engine": "Trident",
\r
7875 * "browser": "Internet Explorer 5.0",
\r
7876 * "platform": "Win 95+",
\r
7882 * { "sTitle": "Engine", "mData": "engine" },
\r
7883 * { "sTitle": "Browser", "mData": "browser" },
\r
7884 * { "sTitle": "Platform", "mData": "platform" },
\r
7885 * { "sTitle": "Version", "mData": "version" },
\r
7886 * { "sTitle": "Grade", "mData": "grade" }
\r
7895 * If sorting is enabled, then DataTables will perform a first pass sort on
\r
7896 * initialisation. You can define which column(s) the sort is performed upon,
\r
7897 * and the sorting direction, with this variable. The aaSorting array should
\r
7898 * contain an array for each column to be sorted initially containing the
\r
7899 * column's index and a direction string ('asc' or 'desc').
\r
7901 * @default [[0,'asc']]
\r
7905 * // Sort by 3rd column first, and then 4th column
\r
7906 * $(document).ready( function() {
\r
7907 * $('#example').dataTable( {
\r
7908 * "aaSorting": [[2,'asc'], [3,'desc']]
\r
7912 * // No initial sorting
\r
7913 * $(document).ready( function() {
\r
7914 * $('#example').dataTable( {
\r
7919 "aaSorting": [[0,'asc']],
\r
7923 * This parameter is basically identical to the aaSorting parameter, but
\r
7924 * cannot be overridden by user interaction with the table. What this means
\r
7925 * is that you could have a column (visible or hidden) which the sorting will
\r
7926 * always be forced on first - any sorting after that (from the user) will
\r
7927 * then be performed as required. This can be useful for grouping rows
\r
7934 * $(document).ready( function() {
\r
7935 * $('#example').dataTable( {
\r
7936 * "aaSortingFixed": [[0,'asc']]
\r
7940 "aaSortingFixed": null,
\r
7944 * This parameter allows you to readily specify the entries in the length drop
\r
7945 * down menu that DataTables shows when pagination is enabled. It can be
\r
7946 * either a 1D array of options which will be used for both the displayed
\r
7947 * option and the value, or a 2D array which will use the array in the first
\r
7948 * position as the value, and the array in the second position as the
\r
7949 * displayed options (useful for language strings such as 'All').
\r
7951 * @default [ 10, 25, 50, 100 ]
\r
7955 * $(document).ready( function() {
\r
7956 * $('#example').dataTable( {
\r
7957 * "aLengthMenu": [[10, 25, 50, -1], [10, 25, 50, "All"]]
\r
7962 * // Setting the default display length as well as length menu
\r
7963 * // This is likely to be wanted if you remove the '10' option which
\r
7964 * // is the iDisplayLength default.
\r
7965 * $(document).ready( function() {
\r
7966 * $('#example').dataTable( {
\r
7967 * "iDisplayLength": 25,
\r
7968 * "aLengthMenu": [[25, 50, 100, -1], [25, 50, 100, "All"]]
\r
7972 "aLengthMenu": [ 10, 25, 50, 100 ],
\r
7976 * The aoColumns option in the initialisation parameter allows you to define
\r
7977 * details about the way individual columns behave. For a full list of
\r
7978 * column options that can be set, please see
\r
7979 * {@link DataTable.defaults.columns}. Note that if you use aoColumns to
\r
7980 * define your columns, you must have an entry in the array for every single
\r
7981 * column that you have in your table (these can be null if you don't which
\r
7982 * to specify any options).
\r
7985 "aoColumns": null,
\r
7988 * Very similar to aoColumns, aoColumnDefs allows you to target a specific
\r
7989 * column, multiple columns, or all columns, using the aTargets property of
\r
7990 * each object in the array. This allows great flexibility when creating
\r
7991 * tables, as the aoColumnDefs arrays can be of any length, targeting the
\r
7992 * columns you specifically want. aoColumnDefs may use any of the column
\r
7993 * options available: {@link DataTable.defaults.columns}, but it _must_
\r
7994 * have aTargets defined in each object in the array. Values in the aTargets
\r
7997 * <li>a string - class name will be matched on the TH for the column</li>
\r
7998 * <li>0 or a positive integer - column index counting from the left</li>
\r
7999 * <li>a negative integer - column index counting from the right</li>
\r
8000 * <li>the string "_all" - all columns (i.e. assign a default)</li>
\r
8004 "aoColumnDefs": null,
\r
8008 * Basically the same as oSearch, this parameter defines the individual column
\r
8009 * filtering state at initialisation time. The array must be of the same size
\r
8010 * as the number of columns, and each element be an object with the parameters
\r
8011 * "sSearch" and "bEscapeRegex" (the latter is optional). 'null' is also
\r
8012 * accepted and the default will be used.
\r
8018 * $(document).ready( function() {
\r
8019 * $('#example').dataTable( {
\r
8020 * "aoSearchCols": [
\r
8022 * { "sSearch": "My filter" },
\r
8024 * { "sSearch": "^[0-9]", "bEscapeRegex": false }
\r
8029 "aoSearchCols": [],
\r
8033 * An array of CSS classes that should be applied to displayed rows. This
\r
8034 * array may be of any length, and DataTables will apply each class
\r
8035 * sequentially, looping when required.
\r
8037 * @default null <i>Will take the values determined by the oClasses.sStripe*
\r
8042 * $(document).ready( function() {
\r
8043 * $('#example').dataTable( {
\r
8044 * "asStripeClasses": [ 'strip1', 'strip2', 'strip3' ]
\r
8048 "asStripeClasses": null,
\r
8052 * Enable or disable automatic column width calculation. This can be disabled
\r
8053 * as an optimisation (it takes some time to calculate the widths) if the
\r
8054 * tables widths are passed in using aoColumns.
\r
8060 * $(document).ready( function () {
\r
8061 * $('#example').dataTable( {
\r
8062 * "bAutoWidth": false
\r
8066 "bAutoWidth": true,
\r
8070 * Deferred rendering can provide DataTables with a huge speed boost when you
\r
8071 * are using an Ajax or JS data source for the table. This option, when set to
\r
8072 * true, will cause DataTables to defer the creation of the table elements for
\r
8073 * each row until they are needed for a draw - saving a significant amount of
\r
8080 * $(document).ready( function() {
\r
8081 * var oTable = $('#example').dataTable( {
\r
8082 * "sAjaxSource": "sources/arrays.txt",
\r
8083 * "bDeferRender": true
\r
8087 "bDeferRender": false,
\r
8091 * Replace a DataTable which matches the given selector and replace it with
\r
8092 * one which has the properties of the new initialisation object passed. If no
\r
8093 * table matches the selector, then the new DataTable will be constructed as
\r
8100 * $(document).ready( function() {
\r
8101 * $('#example').dataTable( {
\r
8102 * "sScrollY": "200px",
\r
8103 * "bPaginate": false
\r
8106 * // Some time later....
\r
8107 * $('#example').dataTable( {
\r
8108 * "bFilter": false,
\r
8109 * "bDestroy": true
\r
8113 "bDestroy": false,
\r
8117 * Enable or disable filtering of data. Filtering in DataTables is "smart" in
\r
8118 * that it allows the end user to input multiple words (space separated) and
\r
8119 * will match a row containing those words, even if not in the order that was
\r
8120 * specified (this allow matching across multiple columns). Note that if you
\r
8121 * wish to use filtering in DataTables this must remain 'true' - to remove the
\r
8122 * default filtering input box and retain filtering abilities, please use
\r
8123 * {@link DataTable.defaults.sDom}.
\r
8129 * $(document).ready( function () {
\r
8130 * $('#example').dataTable( {
\r
8131 * "bFilter": false
\r
8139 * Enable or disable the table information display. This shows information
\r
8140 * about the data that is currently visible on the page, including information
\r
8141 * about filtered data if that action is being performed.
\r
8147 * $(document).ready( function () {
\r
8148 * $('#example').dataTable( {
\r
8157 * Enable jQuery UI ThemeRoller support (required as ThemeRoller requires some
\r
8158 * slightly different and additional mark-up from what DataTables has
\r
8159 * traditionally used).
\r
8165 * $(document).ready( function() {
\r
8166 * $('#example').dataTable( {
\r
8167 * "bJQueryUI": true
\r
8171 "bJQueryUI": false,
\r
8175 * Allows the end user to select the size of a formatted page from a select
\r
8176 * menu (sizes are 10, 25, 50 and 100). Requires pagination (bPaginate).
\r
8182 * $(document).ready( function () {
\r
8183 * $('#example').dataTable( {
\r
8184 * "bLengthChange": false
\r
8188 "bLengthChange": true,
\r
8192 * Enable or disable pagination.
\r
8198 * $(document).ready( function () {
\r
8199 * $('#example').dataTable( {
\r
8200 * "bPaginate": false
\r
8204 "bPaginate": true,
\r
8208 * Enable or disable the display of a 'processing' indicator when the table is
\r
8209 * being processed (e.g. a sort). This is particularly useful for tables with
\r
8210 * large amounts of data where it can take a noticeable amount of time to sort
\r
8217 * $(document).ready( function () {
\r
8218 * $('#example').dataTable( {
\r
8219 * "bProcessing": true
\r
8223 "bProcessing": false,
\r
8227 * Retrieve the DataTables object for the given selector. Note that if the
\r
8228 * table has already been initialised, this parameter will cause DataTables
\r
8229 * to simply return the object that has already been set up - it will not take
\r
8230 * account of any changes you might have made to the initialisation object
\r
8231 * passed to DataTables (setting this parameter to true is an acknowledgement
\r
8232 * that you understand this). bDestroy can be used to reinitialise a table if
\r
8239 * $(document).ready( function() {
\r
8244 * function initTable ()
\r
8246 * return $('#example').dataTable( {
\r
8247 * "sScrollY": "200px",
\r
8248 * "bPaginate": false,
\r
8249 * "bRetrieve": true
\r
8253 * function tableActions ()
\r
8255 * var oTable = initTable();
\r
8256 * // perform API operations with oTable
\r
8259 "bRetrieve": false,
\r
8263 * Indicate if DataTables should be allowed to set the padding / margin
\r
8264 * etc for the scrolling header elements or not. Typically you will want
\r
8271 * $(document).ready( function() {
\r
8272 * $('#example').dataTable( {
\r
8273 * "bScrollAutoCss": false,
\r
8274 * "sScrollY": "200px"
\r
8278 "bScrollAutoCss": true,
\r
8282 * When vertical (y) scrolling is enabled, DataTables will force the height of
\r
8283 * the table's viewport to the given height at all times (useful for layout).
\r
8284 * However, this can look odd when filtering data down to a small data set,
\r
8285 * and the footer is left "floating" further down. This parameter (when
\r
8286 * enabled) will cause DataTables to collapse the table's viewport down when
\r
8287 * the result set will fit within the given Y height.
\r
8293 * $(document).ready( function() {
\r
8294 * $('#example').dataTable( {
\r
8295 * "sScrollY": "200",
\r
8296 * "bScrollCollapse": true
\r
8300 "bScrollCollapse": false,
\r
8304 * Enable infinite scrolling for DataTables (to be used in combination with
\r
8305 * sScrollY). Infinite scrolling means that DataTables will continually load
\r
8306 * data as a user scrolls through a table, which is very useful for large
\r
8307 * dataset. This cannot be used with pagination, which is automatically
\r
8308 * disabled. Note - the Scroller extra for DataTables is recommended in
\r
8309 * in preference to this option.
\r
8315 * $(document).ready( function() {
\r
8316 * $('#example').dataTable( {
\r
8317 * "bScrollInfinite": true,
\r
8318 * "bScrollCollapse": true,
\r
8319 * "sScrollY": "200px"
\r
8323 "bScrollInfinite": false,
\r
8327 * Configure DataTables to use server-side processing. Note that the
\r
8328 * sAjaxSource parameter must also be given in order to give DataTables a
\r
8329 * source to obtain the required data for each draw.
\r
8333 * @dtopt Server-side
\r
8336 * $(document).ready( function () {
\r
8337 * $('#example').dataTable( {
\r
8338 * "bServerSide": true,
\r
8339 * "sAjaxSource": "xhr.php"
\r
8343 "bServerSide": false,
\r
8347 * Enable or disable sorting of columns. Sorting of individual columns can be
\r
8348 * disabled by the "bSortable" option for each column.
\r
8354 * $(document).ready( function () {
\r
8355 * $('#example').dataTable( {
\r
8364 * Allows control over whether DataTables should use the top (true) unique
\r
8365 * cell that is found for a single column, or the bottom (false - default).
\r
8366 * This is useful when using complex headers.
\r
8372 * $(document).ready( function() {
\r
8373 * $('#example').dataTable( {
\r
8374 * "bSortCellsTop": true
\r
8378 "bSortCellsTop": false,
\r
8382 * Enable or disable the addition of the classes 'sorting_1', 'sorting_2' and
\r
8383 * 'sorting_3' to the columns which are currently being sorted on. This is
\r
8384 * presented as a feature switch as it can increase processing time (while
\r
8385 * classes are removed and added) so for large data sets you might want to
\r
8392 * $(document).ready( function () {
\r
8393 * $('#example').dataTable( {
\r
8394 * "bSortClasses": false
\r
8398 "bSortClasses": true,
\r
8402 * Enable or disable state saving. When enabled a cookie will be used to save
\r
8403 * table display information such as pagination information, display length,
\r
8404 * filtering and sorting. As such when the end user reloads the page the
\r
8405 * display display will match what thy had previously set up.
\r
8411 * $(document).ready( function () {
\r
8412 * $('#example').dataTable( {
\r
8413 * "bStateSave": true
\r
8417 "bStateSave": false,
\r
8421 * Customise the cookie and / or the parameters being stored when using
\r
8422 * DataTables with state saving enabled. This function is called whenever
\r
8423 * the cookie is modified, and it expects a fully formed cookie string to be
\r
8424 * returned. Note that the data object passed in is a Javascript object which
\r
8425 * must be converted to a string (JSON.stringify for example).
\r
8427 * @param {string} sName Name of the cookie defined by DataTables
\r
8428 * @param {object} oData Data to be stored in the cookie
\r
8429 * @param {string} sExpires Cookie expires string
\r
8430 * @param {string} sPath Path of the cookie to set
\r
8431 * @returns {string} Cookie formatted string (which should be encoded by
\r
8432 * using encodeURIComponent())
\r
8433 * @dtopt Callbacks
\r
8436 * $(document).ready( function () {
\r
8437 * $('#example').dataTable( {
\r
8438 * "fnCookieCallback": function (sName, oData, sExpires, sPath) {
\r
8439 * // Customise oData or sName or whatever else here
\r
8440 * return sName + "="+JSON.stringify(oData)+"; expires=" + sExpires +"; path=" + sPath;
\r
8445 "fnCookieCallback": null,
\r
8449 * This function is called when a TR element is created (and all TD child
\r
8450 * elements have been inserted), or registered if using a DOM source, allowing
\r
8451 * manipulation of the TR element (adding classes etc).
\r
8453 * @param {node} nRow "TR" element for the current row
\r
8454 * @param {array} aData Raw data array for this row
\r
8455 * @param {int} iDataIndex The index of this row in aoData
\r
8456 * @dtopt Callbacks
\r
8459 * $(document).ready( function() {
\r
8460 * $('#example').dataTable( {
\r
8461 * "fnCreatedRow": function( nRow, aData, iDataIndex ) {
\r
8462 * // Bold the grade for all 'A' grade browsers
\r
8463 * if ( aData[4] == "A" )
\r
8465 * $('td:eq(4)', nRow).html( '<b>A</b>' );
\r
8471 "fnCreatedRow": null,
\r
8475 * This function is called on every 'draw' event, and allows you to
\r
8476 * dynamically modify any aspect you want about the created DOM.
\r
8478 * @param {object} oSettings DataTables settings object
\r
8479 * @dtopt Callbacks
\r
8482 * $(document).ready( function() {
\r
8483 * $('#example').dataTable( {
\r
8484 * "fnDrawCallback": function( oSettings ) {
\r
8485 * alert( 'DataTables has redrawn the table' );
\r
8490 "fnDrawCallback": null,
\r
8494 * Identical to fnHeaderCallback() but for the table footer this function
\r
8495 * allows you to modify the table footer on every 'draw' even.
\r
8497 * @param {node} nFoot "TR" element for the footer
\r
8498 * @param {array} aData Full table data (as derived from the original HTML)
\r
8499 * @param {int} iStart Index for the current display starting point in the
\r
8501 * @param {int} iEnd Index for the current display ending point in the
\r
8503 * @param {array int} aiDisplay Index array to translate the visual position
\r
8504 * to the full data array
\r
8505 * @dtopt Callbacks
\r
8508 * $(document).ready( function() {
\r
8509 * $('#example').dataTable( {
\r
8510 * "fnFooterCallback": function( nFoot, aData, iStart, iEnd, aiDisplay ) {
\r
8511 * nFoot.getElementsByTagName('th')[0].innerHTML = "Starting index is "+iStart;
\r
8516 "fnFooterCallback": null,
\r
8520 * When rendering large numbers in the information element for the table
\r
8521 * (i.e. "Showing 1 to 10 of 57 entries") DataTables will render large numbers
\r
8522 * to have a comma separator for the 'thousands' units (e.g. 1 million is
\r
8523 * rendered as "1,000,000") to help readability for the end user. This
\r
8524 * function will override the default method DataTables uses.
\r
8527 * @param {int} iIn number to be formatted
\r
8528 * @returns {string} formatted string for DataTables to show the number
\r
8529 * @dtopt Callbacks
\r
8532 * $(document).ready( function() {
\r
8533 * $('#example').dataTable( {
\r
8534 * "fnFormatNumber": function ( iIn ) {
\r
8535 * if ( iIn < 1000 ) {
\r
8540 * a=s.split(""), out="",
\r
8543 * for ( var i=0 ; i<iLen ; i++ ) {
\r
8544 * if ( i%3 === 0 && i !== 0 ) {
\r
8547 * out = a[iLen-i-1]+out;
\r
8555 "fnFormatNumber": function ( iIn ) {
\r
8558 // A small optimisation for what is likely to be the majority of use cases
\r
8562 var s=(iIn+""), a=s.split(""), out="", iLen=s.length;
\r
8564 for ( var i=0 ; i<iLen ; i++ )
\r
8566 if ( i%3 === 0 && i !== 0 )
\r
8568 out = this.oLanguage.sInfoThousands+out;
\r
8570 out = a[iLen-i-1]+out;
\r
8577 * This function is called on every 'draw' event, and allows you to
\r
8578 * dynamically modify the header row. This can be used to calculate and
\r
8579 * display useful information about the table.
\r
8581 * @param {node} nHead "TR" element for the header
\r
8582 * @param {array} aData Full table data (as derived from the original HTML)
\r
8583 * @param {int} iStart Index for the current display starting point in the
\r
8585 * @param {int} iEnd Index for the current display ending point in the
\r
8587 * @param {array int} aiDisplay Index array to translate the visual position
\r
8588 * to the full data array
\r
8589 * @dtopt Callbacks
\r
8592 * $(document).ready( function() {
\r
8593 * $('#example').dataTable( {
\r
8594 * "fnHeaderCallback": function( nHead, aData, iStart, iEnd, aiDisplay ) {
\r
8595 * nHead.getElementsByTagName('th')[0].innerHTML = "Displaying "+(iEnd-iStart)+" records";
\r
8600 "fnHeaderCallback": null,
\r
8604 * The information element can be used to convey information about the current
\r
8605 * state of the table. Although the internationalisation options presented by
\r
8606 * DataTables are quite capable of dealing with most customisations, there may
\r
8607 * be times where you wish to customise the string further. This callback
\r
8608 * allows you to do exactly that.
\r
8610 * @param {object} oSettings DataTables settings object
\r
8611 * @param {int} iStart Starting position in data for the draw
\r
8612 * @param {int} iEnd End position in data for the draw
\r
8613 * @param {int} iMax Total number of rows in the table (regardless of
\r
8615 * @param {int} iTotal Total number of rows in the data set, after filtering
\r
8616 * @param {string} sPre The string that DataTables has formatted using it's
\r
8618 * @returns {string} The string to be displayed in the information element.
\r
8619 * @dtopt Callbacks
\r
8622 * $('#example').dataTable( {
\r
8623 * "fnInfoCallback": function( oSettings, iStart, iEnd, iMax, iTotal, sPre ) {
\r
8624 * return iStart +" to "+ iEnd;
\r
8628 "fnInfoCallback": null,
\r
8632 * Called when the table has been initialised. Normally DataTables will
\r
8633 * initialise sequentially and there will be no need for this function,
\r
8634 * however, this does not hold true when using external language information
\r
8635 * since that is obtained using an async XHR call.
\r
8637 * @param {object} oSettings DataTables settings object
\r
8638 * @param {object} json The JSON object request from the server - only
\r
8639 * present if client-side Ajax sourced data is used
\r
8640 * @dtopt Callbacks
\r
8643 * $(document).ready( function() {
\r
8644 * $('#example').dataTable( {
\r
8645 * "fnInitComplete": function(oSettings, json) {
\r
8646 * alert( 'DataTables has finished its initialisation.' );
\r
8651 "fnInitComplete": null,
\r
8655 * Called at the very start of each table draw and can be used to cancel the
\r
8656 * draw by returning false, any other return (including undefined) results in
\r
8657 * the full draw occurring).
\r
8659 * @param {object} oSettings DataTables settings object
\r
8660 * @returns {boolean} False will cancel the draw, anything else (including no
\r
8661 * return) will allow it to complete.
\r
8662 * @dtopt Callbacks
\r
8665 * $(document).ready( function() {
\r
8666 * $('#example').dataTable( {
\r
8667 * "fnPreDrawCallback": function( oSettings ) {
\r
8668 * if ( $('#test').val() == 1 ) {
\r
8675 "fnPreDrawCallback": null,
\r
8679 * This function allows you to 'post process' each row after it have been
\r
8680 * generated for each table draw, but before it is rendered on screen. This
\r
8681 * function might be used for setting the row class name etc.
\r
8683 * @param {node} nRow "TR" element for the current row
\r
8684 * @param {array} aData Raw data array for this row
\r
8685 * @param {int} iDisplayIndex The display index for the current table draw
\r
8686 * @param {int} iDisplayIndexFull The index of the data in the full list of
\r
8687 * rows (after filtering)
\r
8688 * @dtopt Callbacks
\r
8691 * $(document).ready( function() {
\r
8692 * $('#example').dataTable( {
\r
8693 * "fnRowCallback": function( nRow, aData, iDisplayIndex, iDisplayIndexFull ) {
\r
8694 * // Bold the grade for all 'A' grade browsers
\r
8695 * if ( aData[4] == "A" )
\r
8697 * $('td:eq(4)', nRow).html( '<b>A</b>' );
\r
8703 "fnRowCallback": null,
\r
8707 * This parameter allows you to override the default function which obtains
\r
8708 * the data from the server ($.getJSON) so something more suitable for your
\r
8709 * application. For example you could use POST data, or pull information from
\r
8710 * a Gears or AIR database.
\r
8713 * @param {string} sSource HTTP source to obtain the data from (sAjaxSource)
\r
8714 * @param {array} aoData A key/value pair object containing the data to send
\r
8716 * @param {function} fnCallback to be called on completion of the data get
\r
8717 * process that will draw the data on the page.
\r
8718 * @param {object} oSettings DataTables settings object
\r
8719 * @dtopt Callbacks
\r
8720 * @dtopt Server-side
\r
8723 * // POST data to server
\r
8724 * $(document).ready( function() {
\r
8725 * $('#example').dataTable( {
\r
8726 * "bProcessing": true,
\r
8727 * "bServerSide": true,
\r
8728 * "sAjaxSource": "xhr.php",
\r
8729 * "fnServerData": function ( sSource, aoData, fnCallback, oSettings ) {
\r
8730 * oSettings.jqXHR = $.ajax( {
\r
8731 * "dataType": 'json',
\r
8732 * "type": "POST",
\r
8733 * "url": sSource,
\r
8734 * "data": aoData,
\r
8735 * "success": fnCallback
\r
8741 "fnServerData": function ( sUrl, aoData, fnCallback, oSettings ) {
\r
8742 oSettings.jqXHR = $.ajax( {
\r
8745 "success": function (json) {
\r
8746 if ( json.sError ) {
\r
8747 oSettings.oApi._fnLog( oSettings, 0, json.sError );
\r
8750 $(oSettings.oInstance).trigger('xhr', [oSettings, json]);
\r
8751 fnCallback( json );
\r
8753 "dataType": "json",
\r
8755 "type": oSettings.sServerMethod,
\r
8756 "error": function (xhr, error, thrown) {
\r
8757 if ( error == "parsererror" ) {
\r
8758 oSettings.oApi._fnLog( oSettings, 0, "DataTables warning: JSON data from "+
\r
8759 "server could not be parsed. This is caused by a JSON formatting error." );
\r
8767 * It is often useful to send extra data to the server when making an Ajax
\r
8768 * request - for example custom filtering information, and this callback
\r
8769 * function makes it trivial to send extra information to the server. The
\r
8770 * passed in parameter is the data set that has been constructed by
\r
8771 * DataTables, and you can add to this or modify it as you require.
\r
8773 * @param {array} aoData Data array (array of objects which are name/value
\r
8774 * pairs) that has been constructed by DataTables and will be sent to the
\r
8775 * server. In the case of Ajax sourced data with server-side processing
\r
8776 * this will be an empty array, for server-side processing there will be a
\r
8777 * significant number of parameters!
\r
8778 * @returns {undefined} Ensure that you modify the aoData array passed in,
\r
8779 * as this is passed by reference.
\r
8780 * @dtopt Callbacks
\r
8781 * @dtopt Server-side
\r
8784 * $(document).ready( function() {
\r
8785 * $('#example').dataTable( {
\r
8786 * "bProcessing": true,
\r
8787 * "bServerSide": true,
\r
8788 * "sAjaxSource": "scripts/server_processing.php",
\r
8789 * "fnServerParams": function ( aoData ) {
\r
8790 * aoData.push( { "name": "more_data", "value": "my_value" } );
\r
8795 "fnServerParams": null,
\r
8799 * Load the table state. With this function you can define from where, and how, the
\r
8800 * state of a table is loaded. By default DataTables will load from its state saving
\r
8801 * cookie, but you might wish to use local storage (HTML5) or a server-side database.
\r
8804 * @param {object} oSettings DataTables settings object
\r
8805 * @return {object} The DataTables state object to be loaded
\r
8806 * @dtopt Callbacks
\r
8809 * $(document).ready( function() {
\r
8810 * $('#example').dataTable( {
\r
8811 * "bStateSave": true,
\r
8812 * "fnStateLoad": function (oSettings) {
\r
8815 * // Send an Ajax request to the server to get the data. Note that
\r
8816 * // this is a synchronous request.
\r
8818 * "url": "/state_load",
\r
8820 * "dataType": "json",
\r
8821 * "success": function (json) {
\r
8831 "fnStateLoad": function ( oSettings ) {
\r
8832 var sData = this.oApi._fnReadCookie( oSettings.sCookiePrefix+oSettings.sInstance );
\r
8836 oData = (typeof $.parseJSON === 'function') ?
\r
8837 $.parseJSON(sData) : eval( '('+sData+')' );
\r
8847 * Callback which allows modification of the saved state prior to loading that state.
\r
8848 * This callback is called when the table is loading state from the stored data, but
\r
8849 * prior to the settings object being modified by the saved state. Note that for
\r
8850 * plug-in authors, you should use the 'stateLoadParams' event to load parameters for
\r
8853 * @param {object} oSettings DataTables settings object
\r
8854 * @param {object} oData The state object that is to be loaded
\r
8855 * @dtopt Callbacks
\r
8858 * // Remove a saved filter, so filtering is never loaded
\r
8859 * $(document).ready( function() {
\r
8860 * $('#example').dataTable( {
\r
8861 * "bStateSave": true,
\r
8862 * "fnStateLoadParams": function (oSettings, oData) {
\r
8863 * oData.oSearch.sSearch = "";
\r
8869 * // Disallow state loading by returning false
\r
8870 * $(document).ready( function() {
\r
8871 * $('#example').dataTable( {
\r
8872 * "bStateSave": true,
\r
8873 * "fnStateLoadParams": function (oSettings, oData) {
\r
8879 "fnStateLoadParams": null,
\r
8883 * Callback that is called when the state has been loaded from the state saving method
\r
8884 * and the DataTables settings object has been modified as a result of the loaded state.
\r
8886 * @param {object} oSettings DataTables settings object
\r
8887 * @param {object} oData The state object that was loaded
\r
8888 * @dtopt Callbacks
\r
8891 * // Show an alert with the filtering value that was saved
\r
8892 * $(document).ready( function() {
\r
8893 * $('#example').dataTable( {
\r
8894 * "bStateSave": true,
\r
8895 * "fnStateLoaded": function (oSettings, oData) {
\r
8896 * alert( 'Saved filter was: '+oData.oSearch.sSearch );
\r
8901 "fnStateLoaded": null,
\r
8905 * Save the table state. This function allows you to define where and how the state
\r
8906 * information for the table is stored - by default it will use a cookie, but you
\r
8907 * might want to use local storage (HTML5) or a server-side database.
\r
8910 * @param {object} oSettings DataTables settings object
\r
8911 * @param {object} oData The state object to be saved
\r
8912 * @dtopt Callbacks
\r
8915 * $(document).ready( function() {
\r
8916 * $('#example').dataTable( {
\r
8917 * "bStateSave": true,
\r
8918 * "fnStateSave": function (oSettings, oData) {
\r
8919 * // Send an Ajax request to the server with the state object
\r
8921 * "url": "/state_save",
\r
8923 * "dataType": "json",
\r
8924 * "method": "POST"
\r
8925 * "success": function () {}
\r
8931 "fnStateSave": function ( oSettings, oData ) {
\r
8932 this.oApi._fnCreateCookie(
\r
8933 oSettings.sCookiePrefix+oSettings.sInstance,
\r
8934 this.oApi._fnJsonString(oData),
\r
8935 oSettings.iCookieDuration,
\r
8936 oSettings.sCookiePrefix,
\r
8937 oSettings.fnCookieCallback
\r
8943 * Callback which allows modification of the state to be saved. Called when the table
\r
8944 * has changed state a new state save is required. This method allows modification of
\r
8945 * the state saving object prior to actually doing the save, including addition or
\r
8946 * other state properties or modification. Note that for plug-in authors, you should
\r
8947 * use the 'stateSaveParams' event to save parameters for a plug-in.
\r
8949 * @param {object} oSettings DataTables settings object
\r
8950 * @param {object} oData The state object to be saved
\r
8951 * @dtopt Callbacks
\r
8954 * // Remove a saved filter, so filtering is never saved
\r
8955 * $(document).ready( function() {
\r
8956 * $('#example').dataTable( {
\r
8957 * "bStateSave": true,
\r
8958 * "fnStateSaveParams": function (oSettings, oData) {
\r
8959 * oData.oSearch.sSearch = "";
\r
8964 "fnStateSaveParams": null,
\r
8968 * Duration of the cookie which is used for storing session information. This
\r
8969 * value is given in seconds.
\r
8971 * @default 7200 <i>(2 hours)</i>
\r
8975 * $(document).ready( function() {
\r
8976 * $('#example').dataTable( {
\r
8977 * "iCookieDuration": 60*60*24; // 1 day
\r
8981 "iCookieDuration": 7200,
\r
8985 * When enabled DataTables will not make a request to the server for the first
\r
8986 * page draw - rather it will use the data already on the page (no sorting etc
\r
8987 * will be applied to it), thus saving on an XHR at load time. iDeferLoading
\r
8988 * is used to indicate that deferred loading is required, but it is also used
\r
8989 * to tell DataTables how many records there are in the full table (allowing
\r
8990 * the information element and pagination to be displayed correctly). In the case
\r
8991 * where a filtering is applied to the table on initial load, this can be
\r
8992 * indicated by giving the parameter as an array, where the first element is
\r
8993 * the number of records available after filtering and the second element is the
\r
8994 * number of records without filtering (allowing the table information element
\r
8995 * to be shown correctly).
\r
8996 * @type int | array
\r
9001 * // 57 records available in the table, no filtering applied
\r
9002 * $(document).ready( function() {
\r
9003 * $('#example').dataTable( {
\r
9004 * "bServerSide": true,
\r
9005 * "sAjaxSource": "scripts/server_processing.php",
\r
9006 * "iDeferLoading": 57
\r
9011 * // 57 records after filtering, 100 without filtering (an initial filter applied)
\r
9012 * $(document).ready( function() {
\r
9013 * $('#example').dataTable( {
\r
9014 * "bServerSide": true,
\r
9015 * "sAjaxSource": "scripts/server_processing.php",
\r
9016 * "iDeferLoading": [ 57, 100 ],
\r
9018 * "sSearch": "my_filter"
\r
9023 "iDeferLoading": null,
\r
9027 * Number of rows to display on a single page when using pagination. If
\r
9028 * feature enabled (bLengthChange) then the end user will be able to override
\r
9029 * this to a custom setting using a pop-up menu.
\r
9035 * $(document).ready( function() {
\r
9036 * $('#example').dataTable( {
\r
9037 * "iDisplayLength": 50
\r
9041 "iDisplayLength": 10,
\r
9045 * Define the starting point for data display when using DataTables with
\r
9046 * pagination. Note that this parameter is the number of records, rather than
\r
9047 * the page number, so if you have 10 records per page and want to start on
\r
9048 * the third page, it should be "20".
\r
9054 * $(document).ready( function() {
\r
9055 * $('#example').dataTable( {
\r
9056 * "iDisplayStart": 20
\r
9060 "iDisplayStart": 0,
\r
9064 * The scroll gap is the amount of scrolling that is left to go before
\r
9065 * DataTables will load the next 'page' of data automatically. You typically
\r
9066 * want a gap which is big enough that the scrolling will be smooth for the
\r
9067 * user, while not so large that it will load more data than need.
\r
9073 * $(document).ready( function() {
\r
9074 * $('#example').dataTable( {
\r
9075 * "bScrollInfinite": true,
\r
9076 * "bScrollCollapse": true,
\r
9077 * "sScrollY": "200px",
\r
9078 * "iScrollLoadGap": 50
\r
9082 "iScrollLoadGap": 100,
\r
9086 * By default DataTables allows keyboard navigation of the table (sorting, paging,
\r
9087 * and filtering) by adding a tabindex attribute to the required elements. This
\r
9088 * allows you to tab through the controls and press the enter key to activate them.
\r
9089 * The tabindex is default 0, meaning that the tab follows the flow of the document.
\r
9090 * You can overrule this using this parameter if you wish. Use a value of -1 to
\r
9091 * disable built-in keyboard navigation.
\r
9097 * $(document).ready( function() {
\r
9098 * $('#example').dataTable( {
\r
9107 * All strings that DataTables uses in the user interface that it creates
\r
9108 * are defined in this object, allowing you to modified them individually or
\r
9109 * completely replace them all as required.
\r
9114 * Strings that are used for WAI-ARIA labels and controls only (these are not
\r
9115 * actually visible on the page, but will be read by screenreaders, and thus
\r
9116 * must be internationalised as well).
\r
9121 * ARIA label that is added to the table headers when the column may be
\r
9122 * sorted ascending by activing the column (click or return when focused).
\r
9123 * Note that the column header is prefixed to this string.
\r
9125 * @default : activate to sort column ascending
\r
9129 * $(document).ready( function() {
\r
9130 * $('#example').dataTable( {
\r
9133 * "sSortAscending": " - click/return to sort ascending"
\r
9139 "sSortAscending": ": activate to sort column ascending",
\r
9142 * ARIA label that is added to the table headers when the column may be
\r
9143 * sorted descending by activing the column (click or return when focused).
\r
9144 * Note that the column header is prefixed to this string.
\r
9146 * @default : activate to sort column ascending
\r
9150 * $(document).ready( function() {
\r
9151 * $('#example').dataTable( {
\r
9154 * "sSortDescending": " - click/return to sort descending"
\r
9160 "sSortDescending": ": activate to sort column descending"
\r
9164 * Pagination string used by DataTables for the two built-in pagination
\r
9165 * control types ("two_button" and "full_numbers")
\r
9170 * Text to use when using the 'full_numbers' type of pagination for the
\r
9171 * button to take the user to the first page.
\r
9177 * $(document).ready( function() {
\r
9178 * $('#example').dataTable( {
\r
9181 * "sFirst": "First page"
\r
9187 "sFirst": "First",
\r
9191 * Text to use when using the 'full_numbers' type of pagination for the
\r
9192 * button to take the user to the last page.
\r
9198 * $(document).ready( function() {
\r
9199 * $('#example').dataTable( {
\r
9202 * "sLast": "Last page"
\r
9212 * Text to use for the 'next' pagination button (to take the user to the
\r
9219 * $(document).ready( function() {
\r
9220 * $('#example').dataTable( {
\r
9223 * "sNext": "Next page"
\r
9233 * Text to use for the 'previous' pagination button (to take the user to
\r
9234 * the previous page).
\r
9236 * @default Previous
\r
9240 * $(document).ready( function() {
\r
9241 * $('#example').dataTable( {
\r
9244 * "sPrevious": "Previous page"
\r
9250 "sPrevious": "Previous"
\r
9254 * This string is shown in preference to sZeroRecords when the table is
\r
9255 * empty of data (regardless of filtering). Note that this is an optional
\r
9256 * parameter - if it is not given, the value of sZeroRecords will be used
\r
9257 * instead (either the default or given value).
\r
9259 * @default No data available in table
\r
9263 * $(document).ready( function() {
\r
9264 * $('#example').dataTable( {
\r
9266 * "sEmptyTable": "No data available in table"
\r
9271 "sEmptyTable": "No data available in table",
\r
9275 * This string gives information to the end user about the information that
\r
9276 * is current on display on the page. The _START_, _END_ and _TOTAL_
\r
9277 * variables are all dynamically replaced as the table display updates, and
\r
9278 * can be freely moved or removed as the language requirements change.
\r
9280 * @default Showing _START_ to _END_ of _TOTAL_ entries
\r
9284 * $(document).ready( function() {
\r
9285 * $('#example').dataTable( {
\r
9287 * "sInfo": "Got a total of _TOTAL_ entries to show (_START_ to _END_)"
\r
9292 "sInfo": "Showing _START_ to _END_ of _TOTAL_ entries",
\r
9296 * Display information string for when the table is empty. Typically the
\r
9297 * format of this string should match sInfo.
\r
9299 * @default Showing 0 to 0 of 0 entries
\r
9303 * $(document).ready( function() {
\r
9304 * $('#example').dataTable( {
\r
9306 * "sInfoEmpty": "No entries to show"
\r
9311 "sInfoEmpty": "Showing 0 to 0 of 0 entries",
\r
9315 * When a user filters the information in a table, this string is appended
\r
9316 * to the information (sInfo) to give an idea of how strong the filtering
\r
9317 * is. The variable _MAX_ is dynamically updated.
\r
9319 * @default (filtered from _MAX_ total entries)
\r
9323 * $(document).ready( function() {
\r
9324 * $('#example').dataTable( {
\r
9326 * "sInfoFiltered": " - filtering from _MAX_ records"
\r
9331 "sInfoFiltered": "(filtered from _MAX_ total entries)",
\r
9335 * If can be useful to append extra information to the info string at times,
\r
9336 * and this variable does exactly that. This information will be appended to
\r
9337 * the sInfo (sInfoEmpty and sInfoFiltered in whatever combination they are
\r
9338 * being used) at all times.
\r
9340 * @default <i>Empty string</i>
\r
9344 * $(document).ready( function() {
\r
9345 * $('#example').dataTable( {
\r
9347 * "sInfoPostFix": "All records shown are derived from real information."
\r
9352 "sInfoPostFix": "",
\r
9356 * DataTables has a build in number formatter (fnFormatNumber) which is used
\r
9357 * to format large numbers that are used in the table information. By
\r
9358 * default a comma is used, but this can be trivially changed to any
\r
9359 * character you wish with this parameter.
\r
9365 * $(document).ready( function() {
\r
9366 * $('#example').dataTable( {
\r
9368 * "sInfoThousands": "'"
\r
9373 "sInfoThousands": ",",
\r
9377 * Detail the action that will be taken when the drop down menu for the
\r
9378 * pagination length option is changed. The '_MENU_' variable is replaced
\r
9379 * with a default select list of 10, 25, 50 and 100, and can be replaced
\r
9380 * with a custom select box if required.
\r
9382 * @default Show _MENU_ entries
\r
9386 * // Language change only
\r
9387 * $(document).ready( function() {
\r
9388 * $('#example').dataTable( {
\r
9390 * "sLengthMenu": "Display _MENU_ records"
\r
9396 * // Language and options change
\r
9397 * $(document).ready( function() {
\r
9398 * $('#example').dataTable( {
\r
9400 * "sLengthMenu": 'Display <select>'+
\r
9401 * '<option value="10">10</option>'+
\r
9402 * '<option value="20">20</option>'+
\r
9403 * '<option value="30">30</option>'+
\r
9404 * '<option value="40">40</option>'+
\r
9405 * '<option value="50">50</option>'+
\r
9406 * '<option value="-1">All</option>'+
\r
9407 * '</select> records'
\r
9412 "sLengthMenu": "Show _MENU_ entries",
\r
9416 * When using Ajax sourced data and during the first draw when DataTables is
\r
9417 * gathering the data, this message is shown in an empty row in the table to
\r
9418 * indicate to the end user the the data is being loaded. Note that this
\r
9419 * parameter is not used when loading data by server-side processing, just
\r
9420 * Ajax sourced data with client-side processing.
\r
9422 * @default Loading...
\r
9426 * $(document).ready( function() {
\r
9427 * $('#example').dataTable( {
\r
9429 * "sLoadingRecords": "Please wait - loading..."
\r
9434 "sLoadingRecords": "Loading...",
\r
9438 * Text which is displayed when the table is processing a user action
\r
9439 * (usually a sort command or similar).
\r
9441 * @default Processing...
\r
9445 * $(document).ready( function() {
\r
9446 * $('#example').dataTable( {
\r
9448 * "sProcessing": "DataTables is currently busy"
\r
9453 "sProcessing": "Processing...",
\r
9457 * Details the actions that will be taken when the user types into the
\r
9458 * filtering input text box. The variable "_INPUT_", if used in the string,
\r
9459 * is replaced with the HTML text box for the filtering input allowing
\r
9460 * control over where it appears in the string. If "_INPUT_" is not given
\r
9461 * then the input box is appended to the string automatically.
\r
9463 * @default Search:
\r
9467 * // Input text box will be appended at the end automatically
\r
9468 * $(document).ready( function() {
\r
9469 * $('#example').dataTable( {
\r
9471 * "sSearch": "Filter records:"
\r
9477 * // Specify where the filter should appear
\r
9478 * $(document).ready( function() {
\r
9479 * $('#example').dataTable( {
\r
9481 * "sSearch": "Apply filter _INPUT_ to table"
\r
9486 "sSearch": "Search:",
\r
9490 * All of the language information can be stored in a file on the
\r
9491 * server-side, which DataTables will look up if this parameter is passed.
\r
9492 * It must store the URL of the language file, which is in a JSON format,
\r
9493 * and the object has the same properties as the oLanguage object in the
\r
9494 * initialiser object (i.e. the above parameters). Please refer to one of
\r
9495 * the example language files to see how this works in action.
\r
9497 * @default <i>Empty string - i.e. disabled</i>
\r
9501 * $(document).ready( function() {
\r
9502 * $('#example').dataTable( {
\r
9504 * "sUrl": "http://www.sprymedia.co.uk/dataTables/lang.txt"
\r
9513 * Text shown inside the table records when the is no information to be
\r
9514 * displayed after filtering. sEmptyTable is shown when there is simply no
\r
9515 * information in the table at all (regardless of filtering).
\r
9517 * @default No matching records found
\r
9521 * $(document).ready( function() {
\r
9522 * $('#example').dataTable( {
\r
9524 * "sZeroRecords": "No records to display"
\r
9529 "sZeroRecords": "No matching records found"
\r
9534 * This parameter allows you to have define the global filtering state at
\r
9535 * initialisation time. As an object the "sSearch" parameter must be
\r
9536 * defined, but all other parameters are optional. When "bRegex" is true,
\r
9537 * the search string will be treated as a regular expression, when false
\r
9538 * (default) it will be treated as a straight string. When "bSmart"
\r
9539 * DataTables will use it's smart filtering methods (to word match at
\r
9540 * any point in the data), when false this will not be done.
\r
9542 * @extends DataTable.models.oSearch
\r
9546 * $(document).ready( function() {
\r
9547 * $('#example').dataTable( {
\r
9548 * "oSearch": {"sSearch": "Initial search"}
\r
9552 "oSearch": $.extend( {}, DataTable.models.oSearch ),
\r
9556 * By default DataTables will look for the property 'aaData' when obtaining
\r
9557 * data from an Ajax source or for server-side processing - this parameter
\r
9558 * allows that property to be changed. You can use Javascript dotted object
\r
9559 * notation to get a data source for multiple levels of nesting.
\r
9563 * @dtopt Server-side
\r
9566 * // Get data from { "data": [...] }
\r
9567 * $(document).ready( function() {
\r
9568 * var oTable = $('#example').dataTable( {
\r
9569 * "sAjaxSource": "sources/data.txt",
\r
9570 * "sAjaxDataProp": "data"
\r
9575 * // Get data from { "data": { "inner": [...] } }
\r
9576 * $(document).ready( function() {
\r
9577 * var oTable = $('#example').dataTable( {
\r
9578 * "sAjaxSource": "sources/data.txt",
\r
9579 * "sAjaxDataProp": "data.inner"
\r
9583 "sAjaxDataProp": "aaData",
\r
9587 * You can instruct DataTables to load data from an external source using this
\r
9588 * parameter (use aData if you want to pass data in you already have). Simply
\r
9589 * provide a url a JSON object can be obtained from. This object must include
\r
9590 * the parameter 'aaData' which is the data source for the table.
\r
9594 * @dtopt Server-side
\r
9597 * $(document).ready( function() {
\r
9598 * $('#example').dataTable( {
\r
9599 * "sAjaxSource": "http://www.sprymedia.co.uk/dataTables/json.php"
\r
9603 "sAjaxSource": null,
\r
9607 * This parameter can be used to override the default prefix that DataTables
\r
9608 * assigns to a cookie when state saving is enabled.
\r
9610 * @default SpryMedia_DataTables_
\r
9614 * $(document).ready( function() {
\r
9615 * $('#example').dataTable( {
\r
9616 * "sCookiePrefix": "my_datatable_",
\r
9620 "sCookiePrefix": "SpryMedia_DataTables_",
\r
9624 * This initialisation variable allows you to specify exactly where in the
\r
9625 * DOM you want DataTables to inject the various controls it adds to the page
\r
9626 * (for example you might want the pagination controls at the top of the
\r
9627 * table). DIV elements (with or without a custom class) can also be added to
\r
9628 * aid styling. The follow syntax is used:
\r
9630 * <li>The following options are allowed:
\r
9632 * <li>'l' - Length changing</li
\r
9633 * <li>'f' - Filtering input</li>
\r
9634 * <li>'t' - The table!</li>
\r
9635 * <li>'i' - Information</li>
\r
9636 * <li>'p' - Pagination</li>
\r
9637 * <li>'r' - pRocessing</li>
\r
9640 * <li>The following constants are allowed:
\r
9642 * <li>'H' - jQueryUI theme "header" classes ('fg-toolbar ui-widget-header ui-corner-tl ui-corner-tr ui-helper-clearfix')</li>
\r
9643 * <li>'F' - jQueryUI theme "footer" classes ('fg-toolbar ui-widget-header ui-corner-bl ui-corner-br ui-helper-clearfix')</li>
\r
9646 * <li>The following syntax is expected:
\r
9648 * <li>'<' and '>' - div elements</li>
\r
9649 * <li>'<"class" and '>' - div with a class</li>
\r
9650 * <li>'<"#id" and '>' - div with an ID</li>
\r
9655 * <li>'<"wrapper"flipt>'</li>
\r
9656 * <li>'<lf<t>ip>'</li>
\r
9661 * @default lfrtip <i>(when bJQueryUI is false)</i> <b>or</b>
\r
9662 * <"H"lfr>t<"F"ip> <i>(when bJQueryUI is true)</i>
\r
9666 * $(document).ready( function() {
\r
9667 * $('#example').dataTable( {
\r
9668 * "sDom": '<"top"i>rt<"bottom"flp><"clear">'
\r
9676 * DataTables features two different built-in pagination interaction methods
\r
9677 * ('two_button' or 'full_numbers') which present different page controls to
\r
9678 * the end user. Further methods can be added using the API (see below).
\r
9680 * @default two_button
\r
9684 * $(document).ready( function() {
\r
9685 * $('#example').dataTable( {
\r
9686 * "sPaginationType": "full_numbers"
\r
9690 "sPaginationType": "two_button",
\r
9694 * Enable horizontal scrolling. When a table is too wide to fit into a certain
\r
9695 * layout, or you have a large number of columns in the table, you can enable
\r
9696 * x-scrolling to show the table in a viewport, which can be scrolled. This
\r
9697 * property can be any CSS unit, or a number (in which case it will be treated
\r
9698 * as a pixel measurement).
\r
9700 * @default <i>blank string - i.e. disabled</i>
\r
9704 * $(document).ready( function() {
\r
9705 * $('#example').dataTable( {
\r
9706 * "sScrollX": "100%",
\r
9707 * "bScrollCollapse": true
\r
9715 * This property can be used to force a DataTable to use more width than it
\r
9716 * might otherwise do when x-scrolling is enabled. For example if you have a
\r
9717 * table which requires to be well spaced, this parameter is useful for
\r
9718 * "over-sizing" the table, and thus forcing scrolling. This property can by
\r
9719 * any CSS unit, or a number (in which case it will be treated as a pixel
\r
9722 * @default <i>blank string - i.e. disabled</i>
\r
9726 * $(document).ready( function() {
\r
9727 * $('#example').dataTable( {
\r
9728 * "sScrollX": "100%",
\r
9729 * "sScrollXInner": "110%"
\r
9733 "sScrollXInner": "",
\r
9737 * Enable vertical scrolling. Vertical scrolling will constrain the DataTable
\r
9738 * to the given height, and enable scrolling for any data which overflows the
\r
9739 * current viewport. This can be used as an alternative to paging to display
\r
9740 * a lot of data in a small area (although paging and scrolling can both be
\r
9741 * enabled at the same time). This property can be any CSS unit, or a number
\r
9742 * (in which case it will be treated as a pixel measurement).
\r
9744 * @default <i>blank string - i.e. disabled</i>
\r
9748 * $(document).ready( function() {
\r
9749 * $('#example').dataTable( {
\r
9750 * "sScrollY": "200px",
\r
9751 * "bPaginate": false
\r
9759 * Set the HTTP method that is used to make the Ajax call for server-side
\r
9760 * processing or Ajax sourced data.
\r
9764 * @dtopt Server-side
\r
9767 * $(document).ready( function() {
\r
9768 * $('#example').dataTable( {
\r
9769 * "bServerSide": true,
\r
9770 * "sAjaxSource": "scripts/post.php",
\r
9771 * "sServerMethod": "POST"
\r
9775 "sServerMethod": "GET"
\r
9781 * Column options that can be given to DataTables at initialisation time.
\r
9784 DataTable.defaults.columns = {
\r
9786 * Allows a column's sorting to take multiple columns into account when
\r
9787 * doing a sort. For example first name / last name columns make sense to
\r
9788 * do a multi-column sort over the two columns.
\r
9790 * @default null <i>Takes the value of the column index automatically</i>
\r
9794 * // Using aoColumnDefs
\r
9795 * $(document).ready( function() {
\r
9796 * $('#example').dataTable( {
\r
9797 * "aoColumnDefs": [
\r
9798 * { "aDataSort": [ 0, 1 ], "aTargets": [ 0 ] },
\r
9799 * { "aDataSort": [ 1, 0 ], "aTargets": [ 1 ] },
\r
9800 * { "aDataSort": [ 2, 3, 4 ], "aTargets": [ 2 ] }
\r
9806 * // Using aoColumns
\r
9807 * $(document).ready( function() {
\r
9808 * $('#example').dataTable( {
\r
9810 * { "aDataSort": [ 0, 1 ] },
\r
9811 * { "aDataSort": [ 1, 0 ] },
\r
9812 * { "aDataSort": [ 2, 3, 4 ] },
\r
9819 "aDataSort": null,
\r
9823 * You can control the default sorting direction, and even alter the behaviour
\r
9824 * of the sort handler (i.e. only allow ascending sorting etc) using this
\r
9827 * @default [ 'asc', 'desc' ]
\r
9831 * // Using aoColumnDefs
\r
9832 * $(document).ready( function() {
\r
9833 * $('#example').dataTable( {
\r
9834 * "aoColumnDefs": [
\r
9835 * { "asSorting": [ "asc" ], "aTargets": [ 1 ] },
\r
9836 * { "asSorting": [ "desc", "asc", "asc" ], "aTargets": [ 2 ] },
\r
9837 * { "asSorting": [ "desc" ], "aTargets": [ 3 ] }
\r
9843 * // Using aoColumns
\r
9844 * $(document).ready( function() {
\r
9845 * $('#example').dataTable( {
\r
9848 * { "asSorting": [ "asc" ] },
\r
9849 * { "asSorting": [ "desc", "asc", "asc" ] },
\r
9850 * { "asSorting": [ "desc" ] },
\r
9856 "asSorting": [ 'asc', 'desc' ],
\r
9860 * Enable or disable filtering on the data in this column.
\r
9866 * // Using aoColumnDefs
\r
9867 * $(document).ready( function() {
\r
9868 * $('#example').dataTable( {
\r
9869 * "aoColumnDefs": [
\r
9870 * { "bSearchable": false, "aTargets": [ 0 ] }
\r
9875 * // Using aoColumns
\r
9876 * $(document).ready( function() {
\r
9877 * $('#example').dataTable( {
\r
9879 * { "bSearchable": false },
\r
9887 "bSearchable": true,
\r
9891 * Enable or disable sorting on this column.
\r
9897 * // Using aoColumnDefs
\r
9898 * $(document).ready( function() {
\r
9899 * $('#example').dataTable( {
\r
9900 * "aoColumnDefs": [
\r
9901 * { "bSortable": false, "aTargets": [ 0 ] }
\r
9906 * // Using aoColumns
\r
9907 * $(document).ready( function() {
\r
9908 * $('#example').dataTable( {
\r
9910 * { "bSortable": false },
\r
9918 "bSortable": true,
\r
9922 * <code>Deprecated</code> When using fnRender() for a column, you may wish
\r
9923 * to use the original data (before rendering) for sorting and filtering
\r
9924 * (the default is to used the rendered data that the user can see). This
\r
9925 * may be useful for dates etc.
\r
9927 * Please note that this option has now been deprecated and will be removed
\r
9928 * in the next version of DataTables. Please use mRender / mData rather than
\r
9935 "bUseRendered": true,
\r
9939 * Enable or disable the display of this column.
\r
9945 * // Using aoColumnDefs
\r
9946 * $(document).ready( function() {
\r
9947 * $('#example').dataTable( {
\r
9948 * "aoColumnDefs": [
\r
9949 * { "bVisible": false, "aTargets": [ 0 ] }
\r
9954 * // Using aoColumns
\r
9955 * $(document).ready( function() {
\r
9956 * $('#example').dataTable( {
\r
9958 * { "bVisible": false },
\r
9970 * Developer definable function that is called whenever a cell is created (Ajax source,
\r
9971 * etc) or processed for input (DOM source). This can be used as a compliment to mRender
\r
9972 * allowing you to modify the DOM element (add background colour for example) when the
\r
9973 * element is available.
\r
9975 * @param {element} nTd The TD node that has been created
\r
9976 * @param {*} sData The Data for the cell
\r
9977 * @param {array|object} oData The data for the whole row
\r
9978 * @param {int} iRow The row index for the aoData data store
\r
9979 * @param {int} iCol The column index for aoColumns
\r
9983 * $(document).ready( function() {
\r
9984 * $('#example').dataTable( {
\r
9985 * "aoColumnDefs": [ {
\r
9986 * "aTargets": [3],
\r
9987 * "fnCreatedCell": function (nTd, sData, oData, iRow, iCol) {
\r
9988 * if ( sData == "1.7" ) {
\r
9989 * $(nTd).css('color', 'blue')
\r
9996 "fnCreatedCell": null,
\r
10000 * <code>Deprecated</code> Custom display function that will be called for the
\r
10001 * display of each cell in this column.
\r
10003 * Please note that this option has now been deprecated and will be removed
\r
10004 * in the next version of DataTables. Please use mRender / mData rather than
\r
10007 * @param {object} o Object with the following parameters:
\r
10008 * @param {int} o.iDataRow The row in aoData
\r
10009 * @param {int} o.iDataColumn The column in question
\r
10010 * @param {array} o.aData The data for the row in question
\r
10011 * @param {object} o.oSettings The settings object for this DataTables instance
\r
10012 * @param {object} o.mDataProp The data property used for this column
\r
10013 * @param {*} val The current cell value
\r
10014 * @returns {string} The string you which to use in the display
\r
10018 "fnRender": null,
\r
10022 * The column index (starting from 0!) that you wish a sort to be performed
\r
10023 * upon when this column is selected for sorting. This can be used for sorting
\r
10024 * on hidden columns for example.
\r
10026 * @default -1 <i>Use automatically calculated column index</i>
\r
10030 * // Using aoColumnDefs
\r
10031 * $(document).ready( function() {
\r
10032 * $('#example').dataTable( {
\r
10033 * "aoColumnDefs": [
\r
10034 * { "iDataSort": 1, "aTargets": [ 0 ] }
\r
10040 * // Using aoColumns
\r
10041 * $(document).ready( function() {
\r
10042 * $('#example').dataTable( {
\r
10043 * "aoColumns": [
\r
10044 * { "iDataSort": 1 },
\r
10057 * This parameter has been replaced by mData in DataTables to ensure naming
\r
10058 * consistency. mDataProp can still be used, as there is backwards compatibility
\r
10059 * in DataTables for this option, but it is strongly recommended that you use
\r
10060 * mData in preference to mDataProp.
\r
10061 * @name DataTable.defaults.columns.mDataProp
\r
10066 * This property can be used to read data from any JSON data source property,
\r
10067 * including deeply nested objects / properties. mData can be given in a
\r
10068 * number of different ways which effect its behaviour:
\r
10070 * <li>integer - treated as an array index for the data source. This is the
\r
10071 * default that DataTables uses (incrementally increased for each column).</li>
\r
10072 * <li>string - read an object property from the data source. Note that you can
\r
10073 * use Javascript dotted notation to read deep properties / arrays from the
\r
10074 * data source.</li>
\r
10075 * <li>null - the sDefaultContent option will be used for the cell (null
\r
10076 * by default, so you will need to specify the default content you want -
\r
10077 * typically an empty string). This can be useful on generated columns such
\r
10078 * as edit / delete action columns.</li>
\r
10079 * <li>function - the function given will be executed whenever DataTables
\r
10080 * needs to set or get the data for a cell in the column. The function
\r
10081 * takes three parameters:
\r
10083 * <li>{array|object} The data source for the row</li>
\r
10084 * <li>{string} The type call data requested - this will be 'set' when
\r
10085 * setting data or 'filter', 'display', 'type', 'sort' or undefined when
\r
10086 * gathering data. Note that when <i>undefined</i> is given for the type
\r
10087 * DataTables expects to get the raw data for the object back</li>
\r
10088 * <li>{*} Data to set when the second parameter is 'set'.</li>
\r
10090 * The return value from the function is not required when 'set' is the type
\r
10091 * of call, but otherwise the return is what will be used for the data
\r
10092 * requested.</li>
\r
10095 * Note that prior to DataTables 1.9.2 mData was called mDataProp. The name change
\r
10096 * reflects the flexibility of this property and is consistent with the naming of
\r
10097 * mRender. If 'mDataProp' is given, then it will still be used by DataTables, as
\r
10098 * it automatically maps the old name to the new if required.
\r
10099 * @type string|int|function|null
\r
10100 * @default null <i>Use automatically calculated column index</i>
\r
10104 * // Read table data from objects
\r
10105 * $(document).ready( function() {
\r
10106 * var oTable = $('#example').dataTable( {
\r
10107 * "sAjaxSource": "sources/deep.txt",
\r
10109 * { "mData": "engine" },
\r
10110 * { "mData": "browser" },
\r
10111 * { "mData": "platform.inner" },
\r
10112 * { "mData": "platform.details.0" },
\r
10113 * { "mData": "platform.details.1" }
\r
10119 * // Using mData as a function to provide different information for
\r
10120 * // sorting, filtering and display. In this case, currency (price)
\r
10121 * $(document).ready( function() {
\r
10122 * var oTable = $('#example').dataTable( {
\r
10123 * "aoColumnDefs": [ {
\r
10124 * "aTargets": [ 0 ],
\r
10125 * "mData": function ( source, type, val ) {
\r
10126 * if (type === 'set') {
\r
10127 * source.price = val;
\r
10128 * // Store the computed dislay and filter values for efficiency
\r
10129 * source.price_display = val=="" ? "" : "$"+numberFormat(val);
\r
10130 * source.price_filter = val=="" ? "" : "$"+numberFormat(val)+" "+val;
\r
10133 * else if (type === 'display') {
\r
10134 * return source.price_display;
\r
10136 * else if (type === 'filter') {
\r
10137 * return source.price_filter;
\r
10139 * // 'sort', 'type' and undefined all just use the integer
\r
10140 * return source.price;
\r
10150 * This property is the rendering partner to mData and it is suggested that
\r
10151 * when you want to manipulate data for display (including filtering, sorting etc)
\r
10152 * but not altering the underlying data for the table, use this property. mData
\r
10153 * can actually do everything this property can and more, but this parameter is
\r
10154 * easier to use since there is no 'set' option. Like mData is can be given
\r
10155 * in a number of different ways to effect its behaviour, with the addition of
\r
10156 * supporting array syntax for easy outputting of arrays (including arrays of
\r
10159 * <li>integer - treated as an array index for the data source. This is the
\r
10160 * default that DataTables uses (incrementally increased for each column).</li>
\r
10161 * <li>string - read an object property from the data source. Note that you can
\r
10162 * use Javascript dotted notation to read deep properties / arrays from the
\r
10163 * data source and also array brackets to indicate that the data reader should
\r
10164 * loop over the data source array. When characters are given between the array
\r
10165 * brackets, these characters are used to join the data source array together.
\r
10166 * For example: "accounts[, ].name" would result in a comma separated list with
\r
10167 * the 'name' value from the 'accounts' array of objects.</li>
\r
10168 * <li>function - the function given will be executed whenever DataTables
\r
10169 * needs to set or get the data for a cell in the column. The function
\r
10170 * takes three parameters:
\r
10172 * <li>{array|object} The data source for the row (based on mData)</li>
\r
10173 * <li>{string} The type call data requested - this will be 'filter', 'display',
\r
10174 * 'type' or 'sort'.</li>
\r
10175 * <li>{array|object} The full data source for the row (not based on mData)</li>
\r
10177 * The return value from the function is what will be used for the data
\r
10178 * requested.</li>
\r
10180 * @type string|int|function|null
\r
10181 * @default null <i>Use mData</i>
\r
10185 * // Create a comma separated list from an array of objects
\r
10186 * $(document).ready( function() {
\r
10187 * var oTable = $('#example').dataTable( {
\r
10188 * "sAjaxSource": "sources/deep.txt",
\r
10190 * { "mData": "engine" },
\r
10191 * { "mData": "browser" },
\r
10193 * "mData": "platform",
\r
10194 * "mRender": "[, ].name"
\r
10201 * // Use as a function to create a link from the data source
\r
10202 * $(document).ready( function() {
\r
10203 * var oTable = $('#example').dataTable( {
\r
10204 * "aoColumnDefs": [
\r
10206 * "aTargets": [ 0 ],
\r
10207 * "mData": "download_link",
\r
10208 * "mRender": function ( data, type, full ) {
\r
10209 * return '<a href="'+data+'">Download</a>';
\r
10219 * Change the cell type created for the column - either TD cells or TH cells. This
\r
10220 * can be useful as TH cells have semantic meaning in the table body, allowing them
\r
10221 * to act as a header for a row (you may wish to add scope='row' to the TH elements).
\r
10227 * // Make the first column use TH cells
\r
10228 * $(document).ready( function() {
\r
10229 * var oTable = $('#example').dataTable( {
\r
10230 * "aoColumnDefs": [ {
\r
10231 * "aTargets": [ 0 ],
\r
10232 * "sCellType": "th"
\r
10237 "sCellType": "td",
\r
10241 * Class to give to each cell in this column.
\r
10243 * @default <i>Empty string</i>
\r
10247 * // Using aoColumnDefs
\r
10248 * $(document).ready( function() {
\r
10249 * $('#example').dataTable( {
\r
10250 * "aoColumnDefs": [
\r
10251 * { "sClass": "my_class", "aTargets": [ 0 ] }
\r
10257 * // Using aoColumns
\r
10258 * $(document).ready( function() {
\r
10259 * $('#example').dataTable( {
\r
10260 * "aoColumns": [
\r
10261 * { "sClass": "my_class" },
\r
10273 * When DataTables calculates the column widths to assign to each column,
\r
10274 * it finds the longest string in each column and then constructs a
\r
10275 * temporary table and reads the widths from that. The problem with this
\r
10276 * is that "mmm" is much wider then "iiii", but the latter is a longer
\r
10277 * string - thus the calculation can go wrong (doing it properly and putting
\r
10278 * it into an DOM object and measuring that is horribly(!) slow). Thus as
\r
10279 * a "work around" we provide this option. It will append its value to the
\r
10280 * text that is found to be the longest string for the column - i.e. padding.
\r
10281 * Generally you shouldn't need this, and it is not documented on the
\r
10282 * general DataTables.net documentation
\r
10284 * @default <i>Empty string<i>
\r
10288 * // Using aoColumns
\r
10289 * $(document).ready( function() {
\r
10290 * $('#example').dataTable( {
\r
10291 * "aoColumns": [
\r
10296 * "sContentPadding": "mmm"
\r
10302 "sContentPadding": "",
\r
10306 * Allows a default value to be given for a column's data, and will be used
\r
10307 * whenever a null data source is encountered (this can be because mData
\r
10308 * is set to null, or because the data source itself is null).
\r
10314 * // Using aoColumnDefs
\r
10315 * $(document).ready( function() {
\r
10316 * $('#example').dataTable( {
\r
10317 * "aoColumnDefs": [
\r
10320 * "sDefaultContent": "Edit",
\r
10321 * "aTargets": [ -1 ]
\r
10328 * // Using aoColumns
\r
10329 * $(document).ready( function() {
\r
10330 * $('#example').dataTable( {
\r
10331 * "aoColumns": [
\r
10337 * "sDefaultContent": "Edit"
\r
10343 "sDefaultContent": null,
\r
10347 * This parameter is only used in DataTables' server-side processing. It can
\r
10348 * be exceptionally useful to know what columns are being displayed on the
\r
10349 * client side, and to map these to database fields. When defined, the names
\r
10350 * also allow DataTables to reorder information from the server if it comes
\r
10351 * back in an unexpected order (i.e. if you switch your columns around on the
\r
10352 * client-side, your server-side code does not also need updating).
\r
10354 * @default <i>Empty string</i>
\r
10358 * // Using aoColumnDefs
\r
10359 * $(document).ready( function() {
\r
10360 * $('#example').dataTable( {
\r
10361 * "aoColumnDefs": [
\r
10362 * { "sName": "engine", "aTargets": [ 0 ] },
\r
10363 * { "sName": "browser", "aTargets": [ 1 ] },
\r
10364 * { "sName": "platform", "aTargets": [ 2 ] },
\r
10365 * { "sName": "version", "aTargets": [ 3 ] },
\r
10366 * { "sName": "grade", "aTargets": [ 4 ] }
\r
10372 * // Using aoColumns
\r
10373 * $(document).ready( function() {
\r
10374 * $('#example').dataTable( {
\r
10375 * "aoColumns": [
\r
10376 * { "sName": "engine" },
\r
10377 * { "sName": "browser" },
\r
10378 * { "sName": "platform" },
\r
10379 * { "sName": "version" },
\r
10380 * { "sName": "grade" }
\r
10389 * Defines a data source type for the sorting which can be used to read
\r
10390 * real-time information from the table (updating the internally cached
\r
10391 * version) prior to sorting. This allows sorting to occur on user editable
\r
10392 * elements such as form inputs.
\r
10398 * // Using aoColumnDefs
\r
10399 * $(document).ready( function() {
\r
10400 * $('#example').dataTable( {
\r
10401 * "aoColumnDefs": [
\r
10402 * { "sSortDataType": "dom-text", "aTargets": [ 2, 3 ] },
\r
10403 * { "sType": "numeric", "aTargets": [ 3 ] },
\r
10404 * { "sSortDataType": "dom-select", "aTargets": [ 4 ] },
\r
10405 * { "sSortDataType": "dom-checkbox", "aTargets": [ 5 ] }
\r
10411 * // Using aoColumns
\r
10412 * $(document).ready( function() {
\r
10413 * $('#example').dataTable( {
\r
10417 * { "sSortDataType": "dom-text" },
\r
10418 * { "sSortDataType": "dom-text", "sType": "numeric" },
\r
10419 * { "sSortDataType": "dom-select" },
\r
10420 * { "sSortDataType": "dom-checkbox" }
\r
10425 "sSortDataType": "std",
\r
10429 * The title of this column.
\r
10431 * @default null <i>Derived from the 'TH' value for this column in the
\r
10432 * original HTML table.</i>
\r
10436 * // Using aoColumnDefs
\r
10437 * $(document).ready( function() {
\r
10438 * $('#example').dataTable( {
\r
10439 * "aoColumnDefs": [
\r
10440 * { "sTitle": "My column title", "aTargets": [ 0 ] }
\r
10446 * // Using aoColumns
\r
10447 * $(document).ready( function() {
\r
10448 * $('#example').dataTable( {
\r
10449 * "aoColumns": [
\r
10450 * { "sTitle": "My column title" },
\r
10463 * The type allows you to specify how the data for this column will be sorted.
\r
10464 * Four types (string, numeric, date and html (which will strip HTML tags
\r
10465 * before sorting)) are currently available. Note that only date formats
\r
10466 * understood by Javascript's Date() object will be accepted as type date. For
\r
10467 * example: "Mar 26, 2008 5:03 PM". May take the values: 'string', 'numeric',
\r
10468 * 'date' or 'html' (by default). Further types can be adding through
\r
10471 * @default null <i>Auto-detected from raw data</i>
\r
10475 * // Using aoColumnDefs
\r
10476 * $(document).ready( function() {
\r
10477 * $('#example').dataTable( {
\r
10478 * "aoColumnDefs": [
\r
10479 * { "sType": "html", "aTargets": [ 0 ] }
\r
10485 * // Using aoColumns
\r
10486 * $(document).ready( function() {
\r
10487 * $('#example').dataTable( {
\r
10488 * "aoColumns": [
\r
10489 * { "sType": "html" },
\r
10502 * Defining the width of the column, this parameter may take any CSS value
\r
10503 * (3em, 20px etc). DataTables apples 'smart' widths to columns which have not
\r
10504 * been given a specific width through this interface ensuring that the table
\r
10505 * remains readable.
\r
10507 * @default null <i>Automatic</i>
\r
10511 * // Using aoColumnDefs
\r
10512 * $(document).ready( function() {
\r
10513 * $('#example').dataTable( {
\r
10514 * "aoColumnDefs": [
\r
10515 * { "sWidth": "20%", "aTargets": [ 0 ] }
\r
10521 * // Using aoColumns
\r
10522 * $(document).ready( function() {
\r
10523 * $('#example').dataTable( {
\r
10524 * "aoColumns": [
\r
10525 * { "sWidth": "20%" },
\r
10540 * DataTables settings object - this holds all the information needed for a
\r
10541 * given table, including configuration, data and current application of the
\r
10542 * table options. DataTables does not have a single instance for each DataTable
\r
10543 * with the settings attached to that instance, but rather instances of the
\r
10544 * DataTable "class" are created on-the-fly as needed (typically by a
\r
10545 * $().dataTable() call) and the settings object is then applied to that
\r
10548 * Note that this object is related to {@link DataTable.defaults} but this
\r
10549 * one is the internal data store for DataTables's cache of columns. It should
\r
10550 * NOT be manipulated outside of DataTables. Any configuration should be done
\r
10551 * through the initialisation options.
\r
10553 * @todo Really should attach the settings object to individual instances so we
\r
10554 * don't need to create new instances on each $().dataTable() call (if the
\r
10555 * table already exists). It would also save passing oSettings around and
\r
10556 * into every single function. However, this is a very significant
\r
10557 * architecture change for DataTables and will almost certainly break
\r
10558 * backwards compatibility with older installations. This is something that
\r
10559 * will be done in 2.0.
\r
10561 DataTable.models.oSettings = {
\r
10563 * Primary features of DataTables and their enablement state.
\r
10569 * Flag to say if DataTables should automatically try to calculate the
\r
10570 * optimum table and columns widths (true) or not (false).
\r
10571 * Note that this parameter will be set by the initialisation routine. To
\r
10572 * set a default use {@link DataTable.defaults}.
\r
10575 "bAutoWidth": null,
\r
10578 * Delay the creation of TR and TD elements until they are actually
\r
10579 * needed by a driven page draw. This can give a significant speed
\r
10580 * increase for Ajax source and Javascript source data, but makes no
\r
10581 * difference at all fro DOM and server-side processing tables.
\r
10582 * Note that this parameter will be set by the initialisation routine. To
\r
10583 * set a default use {@link DataTable.defaults}.
\r
10586 "bDeferRender": null,
\r
10589 * Enable filtering on the table or not. Note that if this is disabled
\r
10590 * then there is no filtering at all on the table, including fnFilter.
\r
10591 * To just remove the filtering input use sDom and remove the 'f' option.
\r
10592 * Note that this parameter will be set by the initialisation routine. To
\r
10593 * set a default use {@link DataTable.defaults}.
\r
10599 * Table information element (the 'Showing x of y records' div) enable
\r
10601 * Note that this parameter will be set by the initialisation routine. To
\r
10602 * set a default use {@link DataTable.defaults}.
\r
10608 * Present a user control allowing the end user to change the page size
\r
10609 * when pagination is enabled.
\r
10610 * Note that this parameter will be set by the initialisation routine. To
\r
10611 * set a default use {@link DataTable.defaults}.
\r
10614 "bLengthChange": null,
\r
10617 * Pagination enabled or not. Note that if this is disabled then length
\r
10618 * changing must also be disabled.
\r
10619 * Note that this parameter will be set by the initialisation routine. To
\r
10620 * set a default use {@link DataTable.defaults}.
\r
10623 "bPaginate": null,
\r
10626 * Processing indicator enable flag whenever DataTables is enacting a
\r
10627 * user request - typically an Ajax request for server-side processing.
\r
10628 * Note that this parameter will be set by the initialisation routine. To
\r
10629 * set a default use {@link DataTable.defaults}.
\r
10632 "bProcessing": null,
\r
10635 * Server-side processing enabled flag - when enabled DataTables will
\r
10636 * get all data from the server for every draw - there is no filtering,
\r
10637 * sorting or paging done on the client-side.
\r
10638 * Note that this parameter will be set by the initialisation routine. To
\r
10639 * set a default use {@link DataTable.defaults}.
\r
10642 "bServerSide": null,
\r
10645 * Sorting enablement flag.
\r
10646 * Note that this parameter will be set by the initialisation routine. To
\r
10647 * set a default use {@link DataTable.defaults}.
\r
10653 * Apply a class to the columns which are being sorted to provide a
\r
10654 * visual highlight or not. This can slow things down when enabled since
\r
10655 * there is a lot of DOM interaction.
\r
10656 * Note that this parameter will be set by the initialisation routine. To
\r
10657 * set a default use {@link DataTable.defaults}.
\r
10660 "bSortClasses": null,
\r
10663 * State saving enablement flag.
\r
10664 * Note that this parameter will be set by the initialisation routine. To
\r
10665 * set a default use {@link DataTable.defaults}.
\r
10668 "bStateSave": null
\r
10673 * Scrolling settings for a table.
\r
10678 * Indicate if DataTables should be allowed to set the padding / margin
\r
10679 * etc for the scrolling header elements or not. Typically you will want
\r
10681 * Note that this parameter will be set by the initialisation routine. To
\r
10682 * set a default use {@link DataTable.defaults}.
\r
10685 "bAutoCss": null,
\r
10688 * When the table is shorter in height than sScrollY, collapse the
\r
10689 * table container down to the height of the table (when true).
\r
10690 * Note that this parameter will be set by the initialisation routine. To
\r
10691 * set a default use {@link DataTable.defaults}.
\r
10694 "bCollapse": null,
\r
10697 * Infinite scrolling enablement flag. Now deprecated in favour of
\r
10698 * using the Scroller plug-in.
\r
10699 * Note that this parameter will be set by the initialisation routine. To
\r
10700 * set a default use {@link DataTable.defaults}.
\r
10703 "bInfinite": null,
\r
10706 * Width of the scrollbar for the web-browser's platform. Calculated
\r
10707 * during table initialisation.
\r
10714 * Space (in pixels) between the bottom of the scrolling container and
\r
10715 * the bottom of the scrolling viewport before the next page is loaded
\r
10716 * when using infinite scrolling.
\r
10717 * Note that this parameter will be set by the initialisation routine. To
\r
10718 * set a default use {@link DataTable.defaults}.
\r
10721 "iLoadGap": null,
\r
10724 * Viewport width for horizontal scrolling. Horizontal scrolling is
\r
10725 * disabled if an empty string.
\r
10726 * Note that this parameter will be set by the initialisation routine. To
\r
10727 * set a default use {@link DataTable.defaults}.
\r
10733 * Width to expand the table to when using x-scrolling. Typically you
\r
10734 * should not need to use this.
\r
10735 * Note that this parameter will be set by the initialisation routine. To
\r
10736 * set a default use {@link DataTable.defaults}.
\r
10743 * Viewport height for vertical scrolling. Vertical scrolling is disabled
\r
10744 * if an empty string.
\r
10745 * Note that this parameter will be set by the initialisation routine. To
\r
10746 * set a default use {@link DataTable.defaults}.
\r
10753 * Language information for the table.
\r
10755 * @extends DataTable.defaults.oLanguage
\r
10759 * Information callback function. See
\r
10760 * {@link DataTable.defaults.fnInfoCallback}
\r
10764 "fnInfoCallback": null
\r
10768 * Browser support parameters
\r
10773 * Indicate if the browser incorrectly calculates width:100% inside a
\r
10774 * scrolling element (IE6/7)
\r
10778 "bScrollOversize": false
\r
10782 * Array referencing the nodes which are used for the features. The
\r
10783 * parameters of this object match what is allowed by sDom - i.e.
\r
10785 * <li>'l' - Length changing</li>
\r
10786 * <li>'f' - Filtering input</li>
\r
10787 * <li>'t' - The table!</li>
\r
10788 * <li>'i' - Information</li>
\r
10789 * <li>'p' - Pagination</li>
\r
10790 * <li>'r' - pRocessing</li>
\r
10795 "aanFeatures": [],
\r
10798 * Store data information - see {@link DataTable.models.oRow} for detailed
\r
10806 * Array of indexes which are in the current display (after filtering etc)
\r
10813 * Array of indexes for display - no filtering
\r
10817 "aiDisplayMaster": [],
\r
10820 * Store information about each column that is in use
\r
10827 * Store information about the table's header
\r
10834 * Store information about the table's footer
\r
10841 * Search data array for regular expression searching
\r
10845 "asDataSearch": [],
\r
10848 * Store the applied global search information in case we want to force a
\r
10849 * research or compare the old search to a new one.
\r
10850 * Note that this parameter will be set by the initialisation routine. To
\r
10851 * set a default use {@link DataTable.defaults}.
\r
10853 * @extends DataTable.models.oSearch
\r
10855 "oPreviousSearch": {},
\r
10858 * Store the applied search for each column - see
\r
10859 * {@link DataTable.models.oSearch} for the format that is used for the
\r
10860 * filtering information for each column.
\r
10864 "aoPreSearchCols": [],
\r
10867 * Sorting that is applied to the table. Note that the inner arrays are
\r
10868 * used in the following manner:
\r
10870 * <li>Index 0 - column number</li>
\r
10871 * <li>Index 1 - current sorting direction</li>
\r
10872 * <li>Index 2 - index of asSorting for this column</li>
\r
10874 * Note that this parameter will be set by the initialisation routine. To
\r
10875 * set a default use {@link DataTable.defaults}.
\r
10877 * @todo These inner arrays should really be objects
\r
10879 "aaSorting": null,
\r
10882 * Sorting that is always applied to the table (i.e. prefixed in front of
\r
10884 * Note that this parameter will be set by the initialisation routine. To
\r
10885 * set a default use {@link DataTable.defaults}.
\r
10886 * @type array|null
\r
10889 "aaSortingFixed": null,
\r
10892 * Classes to use for the striping of a table.
\r
10893 * Note that this parameter will be set by the initialisation routine. To
\r
10894 * set a default use {@link DataTable.defaults}.
\r
10898 "asStripeClasses": null,
\r
10901 * If restoring a table - we should restore its striping classes as well
\r
10905 "asDestroyStripes": [],
\r
10908 * If restoring a table - we should restore its width
\r
10912 "sDestroyWidth": 0,
\r
10915 * Callback functions array for every time a row is inserted (i.e. on a draw).
\r
10919 "aoRowCallback": [],
\r
10922 * Callback functions for the header on each draw.
\r
10926 "aoHeaderCallback": [],
\r
10929 * Callback function for the footer on each draw.
\r
10933 "aoFooterCallback": [],
\r
10936 * Array of callback functions for draw callback functions
\r
10940 "aoDrawCallback": [],
\r
10943 * Array of callback functions for row created function
\r
10947 "aoRowCreatedCallback": [],
\r
10950 * Callback functions for just before the table is redrawn. A return of
\r
10951 * false will be used to cancel the draw.
\r
10955 "aoPreDrawCallback": [],
\r
10958 * Callback functions for when the table has been initialised.
\r
10962 "aoInitComplete": [],
\r
10966 * Callbacks for modifying the settings to be stored for state saving, prior to
\r
10971 "aoStateSaveParams": [],
\r
10974 * Callbacks for modifying the settings that have been stored for state saving
\r
10975 * prior to using the stored values to restore the state.
\r
10979 "aoStateLoadParams": [],
\r
10982 * Callbacks for operating on the settings object once the saved state has been
\r
10987 "aoStateLoaded": [],
\r
10990 * Cache the table ID for quick access
\r
10992 * @default <i>Empty string</i>
\r
10997 * The TABLE node for the main table
\r
11004 * Permanent ref to the thead element
\r
11011 * Permanent ref to the tfoot element - if it exists
\r
11018 * Permanent ref to the tbody element
\r
11025 * Cache the wrapper node (contains all DataTables controlled elements)
\r
11029 "nTableWrapper": null,
\r
11032 * Indicate if when using server-side processing the loading of data
\r
11033 * should be deferred until the second draw.
\r
11034 * Note that this parameter will be set by the initialisation routine. To
\r
11035 * set a default use {@link DataTable.defaults}.
\r
11039 "bDeferLoading": false,
\r
11042 * Indicate if all required information has been read in
\r
11046 "bInitialised": false,
\r
11049 * Information about open rows. Each object in the array has the parameters
\r
11050 * 'nTr' and 'nParent'
\r
11054 "aoOpenRows": [],
\r
11057 * Dictate the positioning of DataTables' control elements - see
\r
11058 * {@link DataTable.model.oInit.sDom}.
\r
11059 * Note that this parameter will be set by the initialisation routine. To
\r
11060 * set a default use {@link DataTable.defaults}.
\r
11067 * Which type of pagination should be used.
\r
11068 * Note that this parameter will be set by the initialisation routine. To
\r
11069 * set a default use {@link DataTable.defaults}.
\r
11071 * @default two_button
\r
11073 "sPaginationType": "two_button",
\r
11076 * The cookie duration (for bStateSave) in seconds.
\r
11077 * Note that this parameter will be set by the initialisation routine. To
\r
11078 * set a default use {@link DataTable.defaults}.
\r
11082 "iCookieDuration": 0,
\r
11085 * The cookie name prefix.
\r
11086 * Note that this parameter will be set by the initialisation routine. To
\r
11087 * set a default use {@link DataTable.defaults}.
\r
11089 * @default <i>Empty string</i>
\r
11091 "sCookiePrefix": "",
\r
11094 * Callback function for cookie creation.
\r
11095 * Note that this parameter will be set by the initialisation routine. To
\r
11096 * set a default use {@link DataTable.defaults}.
\r
11100 "fnCookieCallback": null,
\r
11103 * Array of callback functions for state saving. Each array element is an
\r
11104 * object with the following parameters:
\r
11106 * <li>function:fn - function to call. Takes two parameters, oSettings
\r
11107 * and the JSON string to save that has been thus far created. Returns
\r
11108 * a JSON string to be inserted into a json object
\r
11109 * (i.e. '"param": [ 0, 1, 2]')</li>
\r
11110 * <li>string:sName - name of callback</li>
\r
11115 "aoStateSave": [],
\r
11118 * Array of callback functions for state loading. Each array element is an
\r
11119 * object with the following parameters:
\r
11121 * <li>function:fn - function to call. Takes two parameters, oSettings
\r
11122 * and the object stored. May return false to cancel state loading</li>
\r
11123 * <li>string:sName - name of callback</li>
\r
11128 "aoStateLoad": [],
\r
11131 * State that was loaded from the cookie. Useful for back reference
\r
11135 "oLoadedState": null,
\r
11138 * Source url for AJAX data for the table.
\r
11139 * Note that this parameter will be set by the initialisation routine. To
\r
11140 * set a default use {@link DataTable.defaults}.
\r
11144 "sAjaxSource": null,
\r
11147 * Property from a given object from which to read the table data from. This
\r
11148 * can be an empty string (when not server-side processing), in which case
\r
11149 * it is assumed an an array is given directly.
\r
11150 * Note that this parameter will be set by the initialisation routine. To
\r
11151 * set a default use {@link DataTable.defaults}.
\r
11154 "sAjaxDataProp": null,
\r
11157 * Note if draw should be blocked while getting data
\r
11161 "bAjaxDataGet": true,
\r
11164 * The last jQuery XHR object that was used for server-side data gathering.
\r
11165 * This can be used for working with the XHR information in one of the
\r
11173 * Function to get the server-side data.
\r
11174 * Note that this parameter will be set by the initialisation routine. To
\r
11175 * set a default use {@link DataTable.defaults}.
\r
11178 "fnServerData": null,
\r
11181 * Functions which are called prior to sending an Ajax request so extra
\r
11182 * parameters can easily be sent to the server
\r
11186 "aoServerParams": [],
\r
11189 * Send the XHR HTTP method - GET or POST (could be PUT or DELETE if
\r
11191 * Note that this parameter will be set by the initialisation routine. To
\r
11192 * set a default use {@link DataTable.defaults}.
\r
11195 "sServerMethod": null,
\r
11198 * Format numbers for display.
\r
11199 * Note that this parameter will be set by the initialisation routine. To
\r
11200 * set a default use {@link DataTable.defaults}.
\r
11203 "fnFormatNumber": null,
\r
11206 * List of options that can be used for the user selectable length menu.
\r
11207 * Note that this parameter will be set by the initialisation routine. To
\r
11208 * set a default use {@link DataTable.defaults}.
\r
11212 "aLengthMenu": null,
\r
11215 * Counter for the draws that the table does. Also used as a tracker for
\r
11216 * server-side processing
\r
11223 * Indicate if a redraw is being done - useful for Ajax
\r
11227 "bDrawing": false,
\r
11230 * Draw index (iDraw) of the last error when parsing the returned data
\r
11234 "iDrawError": -1,
\r
11237 * Paging display length
\r
11241 "_iDisplayLength": 10,
\r
11244 * Paging start point - aiDisplay index
\r
11248 "_iDisplayStart": 0,
\r
11251 * Paging end point - aiDisplay index. Use fnDisplayEnd rather than
\r
11252 * this property to get the end point
\r
11257 "_iDisplayEnd": 10,
\r
11260 * Server-side processing - number of records in the result set
\r
11261 * (i.e. before filtering), Use fnRecordsTotal rather than
\r
11262 * this property to get the value of the number of records, regardless of
\r
11263 * the server-side processing setting.
\r
11268 "_iRecordsTotal": 0,
\r
11271 * Server-side processing - number of records in the current display set
\r
11272 * (i.e. after filtering). Use fnRecordsDisplay rather than
\r
11273 * this property to get the value of the number of records, regardless of
\r
11274 * the server-side processing setting.
\r
11279 "_iRecordsDisplay": 0,
\r
11282 * Flag to indicate if jQuery UI marking and classes should be used.
\r
11283 * Note that this parameter will be set by the initialisation routine. To
\r
11284 * set a default use {@link DataTable.defaults}.
\r
11290 * The classes to use for the table
\r
11297 * Flag attached to the settings object so you can check in the draw
\r
11298 * callback if filtering has been done in the draw. Deprecated in favour of
\r
11304 "bFiltered": false,
\r
11307 * Flag attached to the settings object so you can check in the draw
\r
11308 * callback if sorting has been done in the draw. Deprecated in favour of
\r
11314 "bSorted": false,
\r
11317 * Indicate that if multiple rows are in the header and there is more than
\r
11318 * one unique cell per column, if the top one (true) or bottom one (false)
\r
11319 * should be used for sorting / title by DataTables.
\r
11320 * Note that this parameter will be set by the initialisation routine. To
\r
11321 * set a default use {@link DataTable.defaults}.
\r
11324 "bSortCellsTop": null,
\r
11327 * Initialisation object that is used for the table
\r
11334 * Destroy callback functions - for plug-ins to attach themselves to the
\r
11335 * destroy so they can clean up markup and events.
\r
11339 "aoDestroyCallback": [],
\r
11343 * Get the number of records in the current record set, before filtering
\r
11346 "fnRecordsTotal": function ()
\r
11348 if ( this.oFeatures.bServerSide ) {
\r
11349 return parseInt(this._iRecordsTotal, 10);
\r
11351 return this.aiDisplayMaster.length;
\r
11356 * Get the number of records in the current record set, after filtering
\r
11359 "fnRecordsDisplay": function ()
\r
11361 if ( this.oFeatures.bServerSide ) {
\r
11362 return parseInt(this._iRecordsDisplay, 10);
\r
11364 return this.aiDisplay.length;
\r
11369 * Set the display end point - aiDisplay index
\r
11371 * @todo Should do away with _iDisplayEnd and calculate it on-the-fly here
\r
11373 "fnDisplayEnd": function ()
\r
11375 if ( this.oFeatures.bServerSide ) {
\r
11376 if ( this.oFeatures.bPaginate === false || this._iDisplayLength == -1 ) {
\r
11377 return this._iDisplayStart+this.aiDisplay.length;
\r
11379 return Math.min( this._iDisplayStart+this._iDisplayLength,
\r
11380 this._iRecordsDisplay );
\r
11383 return this._iDisplayEnd;
\r
11388 * The DataTables object for this table
\r
11392 "oInstance": null,
\r
11395 * Unique identifier for each instance of the DataTables object. If there
\r
11396 * is an ID on the table node, then it takes that value, otherwise an
\r
11397 * incrementing internal counter is used.
\r
11401 "sInstance": null,
\r
11404 * tabindex attribute value that is added to DataTables control elements, allowing
\r
11405 * keyboard navigation of the table and its controls.
\r
11410 * DIV container for the footer scrolling table if scrolling
\r
11412 "nScrollHead": null,
\r
11415 * DIV container for the footer scrolling table if scrolling
\r
11417 "nScrollFoot": null
\r
11421 * Extension object for DataTables that is used to provide all extension options.
\r
11423 * Note that the <i>DataTable.ext</i> object is available through
\r
11424 * <i>jQuery.fn.dataTable.ext</i> where it may be accessed and manipulated. It is
\r
11425 * also aliased to <i>jQuery.fn.dataTableExt</i> for historic reasons.
\r
11427 * @extends DataTable.models.ext
\r
11429 DataTable.ext = $.extend( true, {}, DataTable.models.ext );
\r
11431 $.extend( DataTable.ext.oStdClasses, {
\r
11432 "sTable": "dataTable",
\r
11434 /* Two buttons buttons */
\r
11435 "sPagePrevEnabled": "paginate_enabled_previous",
\r
11436 "sPagePrevDisabled": "paginate_disabled_previous",
\r
11437 "sPageNextEnabled": "paginate_enabled_next",
\r
11438 "sPageNextDisabled": "paginate_disabled_next",
\r
11439 "sPageJUINext": "",
\r
11440 "sPageJUIPrev": "",
\r
11442 /* Full numbers paging buttons */
\r
11443 "sPageButton": "paginate_button",
\r
11444 "sPageButtonActive": "paginate_active",
\r
11445 "sPageButtonStaticDisabled": "paginate_button paginate_button_disabled",
\r
11446 "sPageFirst": "first",
\r
11447 "sPagePrevious": "previous",
\r
11448 "sPageNext": "next",
\r
11449 "sPageLast": "last",
\r
11451 /* Striping classes */
\r
11452 "sStripeOdd": "odd",
\r
11453 "sStripeEven": "even",
\r
11456 "sRowEmpty": "dataTables_empty",
\r
11459 "sWrapper": "dataTables_wrapper",
\r
11460 "sFilter": "dataTables_filter",
\r
11461 "sInfo": "dataTables_info",
\r
11462 "sPaging": "dataTables_paginate paging_", /* Note that the type is postfixed */
\r
11463 "sLength": "dataTables_length",
\r
11464 "sProcessing": "dataTables_processing",
\r
11467 "sSortAsc": "sorting_asc",
\r
11468 "sSortDesc": "sorting_desc",
\r
11469 "sSortable": "sorting", /* Sortable in both directions */
\r
11470 "sSortableAsc": "sorting_asc_disabled",
\r
11471 "sSortableDesc": "sorting_desc_disabled",
\r
11472 "sSortableNone": "sorting_disabled",
\r
11473 "sSortColumn": "sorting_", /* Note that an int is postfixed for the sorting order */
\r
11474 "sSortJUIAsc": "",
\r
11475 "sSortJUIDesc": "",
\r
11477 "sSortJUIAscAllowed": "",
\r
11478 "sSortJUIDescAllowed": "",
\r
11479 "sSortJUIWrapper": "",
\r
11483 "sScrollWrapper": "dataTables_scroll",
\r
11484 "sScrollHead": "dataTables_scrollHead",
\r
11485 "sScrollHeadInner": "dataTables_scrollHeadInner",
\r
11486 "sScrollBody": "dataTables_scrollBody",
\r
11487 "sScrollFoot": "dataTables_scrollFoot",
\r
11488 "sScrollFootInner": "dataTables_scrollFootInner",
\r
11492 "sJUIHeader": "",
\r
11497 $.extend( DataTable.ext.oJUIClasses, DataTable.ext.oStdClasses, {
\r
11498 /* Two buttons buttons */
\r
11499 "sPagePrevEnabled": "fg-button ui-button ui-state-default ui-corner-left",
\r
11500 "sPagePrevDisabled": "fg-button ui-button ui-state-default ui-corner-left ui-state-disabled",
\r
11501 "sPageNextEnabled": "fg-button ui-button ui-state-default ui-corner-right",
\r
11502 "sPageNextDisabled": "fg-button ui-button ui-state-default ui-corner-right ui-state-disabled",
\r
11503 "sPageJUINext": "ui-icon ui-icon-circle-arrow-e",
\r
11504 "sPageJUIPrev": "ui-icon ui-icon-circle-arrow-w",
\r
11506 /* Full numbers paging buttons */
\r
11507 "sPageButton": "fg-button ui-button ui-state-default",
\r
11508 "sPageButtonActive": "fg-button ui-button ui-state-default ui-state-disabled",
\r
11509 "sPageButtonStaticDisabled": "fg-button ui-button ui-state-default ui-state-disabled",
\r
11510 "sPageFirst": "first ui-corner-tl ui-corner-bl",
\r
11511 "sPageLast": "last ui-corner-tr ui-corner-br",
\r
11514 "sPaging": "dataTables_paginate fg-buttonset ui-buttonset fg-buttonset-multi "+
\r
11515 "ui-buttonset-multi paging_", /* Note that the type is postfixed */
\r
11518 "sSortAsc": "ui-state-default",
\r
11519 "sSortDesc": "ui-state-default",
\r
11520 "sSortable": "ui-state-default",
\r
11521 "sSortableAsc": "ui-state-default",
\r
11522 "sSortableDesc": "ui-state-default",
\r
11523 "sSortableNone": "ui-state-default",
\r
11524 "sSortJUIAsc": "css_right ui-icon ui-icon-triangle-1-n",
\r
11525 "sSortJUIDesc": "css_right ui-icon ui-icon-triangle-1-s",
\r
11526 "sSortJUI": "css_right ui-icon ui-icon-carat-2-n-s",
\r
11527 "sSortJUIAscAllowed": "css_right ui-icon ui-icon-carat-1-n",
\r
11528 "sSortJUIDescAllowed": "css_right ui-icon ui-icon-carat-1-s",
\r
11529 "sSortJUIWrapper": "DataTables_sort_wrapper",
\r
11530 "sSortIcon": "DataTables_sort_icon",
\r
11533 "sScrollHead": "dataTables_scrollHead ui-state-default",
\r
11534 "sScrollFoot": "dataTables_scrollFoot ui-state-default",
\r
11537 "sFooterTH": "ui-state-default",
\r
11538 "sJUIHeader": "fg-toolbar ui-toolbar ui-widget-header ui-corner-tl ui-corner-tr ui-helper-clearfix",
\r
11539 "sJUIFooter": "fg-toolbar ui-toolbar ui-widget-header ui-corner-bl ui-corner-br ui-helper-clearfix"
\r
11543 * Variable: oPagination
\r
11545 * Scope: jQuery.fn.dataTableExt
\r
11547 $.extend( DataTable.ext.oPagination, {
\r
11549 * Variable: two_button
\r
11550 * Purpose: Standard two button (forward/back) pagination
\r
11551 * Scope: jQuery.fn.dataTableExt.oPagination
\r
11555 * Function: oPagination.two_button.fnInit
\r
11556 * Purpose: Initialise dom elements required for pagination with forward/back buttons only
\r
11558 * Inputs: object:oSettings - dataTables settings object
\r
11559 * node:nPaging - the DIV which contains this pagination control
\r
11560 * function:fnCallbackDraw - draw function which must be called on update
\r
11562 "fnInit": function ( oSettings, nPaging, fnCallbackDraw )
\r
11564 var oLang = oSettings.oLanguage.oPaginate;
\r
11565 var oClasses = oSettings.oClasses;
\r
11566 var fnClickHandler = function ( e ) {
\r
11567 if ( oSettings.oApi._fnPageChange( oSettings, e.data.action ) )
\r
11569 fnCallbackDraw( oSettings );
\r
11573 var sAppend = (!oSettings.bJUI) ?
\r
11574 '<a class="'+oSettings.oClasses.sPagePrevDisabled+'" tabindex="'+oSettings.iTabIndex+'" role="button">'+oLang.sPrevious+'</a>'+
\r
11575 '<a class="'+oSettings.oClasses.sPageNextDisabled+'" tabindex="'+oSettings.iTabIndex+'" role="button">'+oLang.sNext+'</a>'
\r
11577 '<a class="'+oSettings.oClasses.sPagePrevDisabled+'" tabindex="'+oSettings.iTabIndex+'" role="button"><span class="'+oSettings.oClasses.sPageJUIPrev+'"></span></a>'+
\r
11578 '<a class="'+oSettings.oClasses.sPageNextDisabled+'" tabindex="'+oSettings.iTabIndex+'" role="button"><span class="'+oSettings.oClasses.sPageJUINext+'"></span></a>';
\r
11579 $(nPaging).append( sAppend );
\r
11581 var els = $('a', nPaging);
\r
11582 var nPrevious = els[0],
\r
11585 oSettings.oApi._fnBindAction( nPrevious, {action: "previous"}, fnClickHandler );
\r
11586 oSettings.oApi._fnBindAction( nNext, {action: "next"}, fnClickHandler );
\r
11588 /* ID the first elements only */
\r
11589 if ( !oSettings.aanFeatures.p )
\r
11591 nPaging.id = oSettings.sTableId+'_paginate';
\r
11592 nPrevious.id = oSettings.sTableId+'_previous';
\r
11593 nNext.id = oSettings.sTableId+'_next';
\r
11595 nPrevious.setAttribute('aria-controls', oSettings.sTableId);
\r
11596 nNext.setAttribute('aria-controls', oSettings.sTableId);
\r
11601 * Function: oPagination.two_button.fnUpdate
\r
11602 * Purpose: Update the two button pagination at the end of the draw
\r
11604 * Inputs: object:oSettings - dataTables settings object
\r
11605 * function:fnCallbackDraw - draw function to call on page change
\r
11607 "fnUpdate": function ( oSettings, fnCallbackDraw )
\r
11609 if ( !oSettings.aanFeatures.p )
\r
11614 var oClasses = oSettings.oClasses;
\r
11615 var an = oSettings.aanFeatures.p;
\r
11618 /* Loop over each instance of the pager */
\r
11619 for ( var i=0, iLen=an.length ; i<iLen ; i++ )
\r
11621 nNode = an[i].firstChild;
\r
11624 /* Previous page */
\r
11625 nNode.className = ( oSettings._iDisplayStart === 0 ) ?
\r
11626 oClasses.sPagePrevDisabled : oClasses.sPagePrevEnabled;
\r
11629 nNode = nNode.nextSibling;
\r
11630 nNode.className = ( oSettings.fnDisplayEnd() == oSettings.fnRecordsDisplay() ) ?
\r
11631 oClasses.sPageNextDisabled : oClasses.sPageNextEnabled;
\r
11639 * Variable: iFullNumbersShowPages
\r
11640 * Purpose: Change the number of pages which can be seen
\r
11641 * Scope: jQuery.fn.dataTableExt.oPagination
\r
11643 "iFullNumbersShowPages": 5,
\r
11646 * Variable: full_numbers
\r
11647 * Purpose: Full numbers pagination
\r
11648 * Scope: jQuery.fn.dataTableExt.oPagination
\r
11650 "full_numbers": {
\r
11652 * Function: oPagination.full_numbers.fnInit
\r
11653 * Purpose: Initialise dom elements required for pagination with a list of the pages
\r
11655 * Inputs: object:oSettings - dataTables settings object
\r
11656 * node:nPaging - the DIV which contains this pagination control
\r
11657 * function:fnCallbackDraw - draw function which must be called on update
\r
11659 "fnInit": function ( oSettings, nPaging, fnCallbackDraw )
\r
11661 var oLang = oSettings.oLanguage.oPaginate;
\r
11662 var oClasses = oSettings.oClasses;
\r
11663 var fnClickHandler = function ( e ) {
\r
11664 if ( oSettings.oApi._fnPageChange( oSettings, e.data.action ) )
\r
11666 fnCallbackDraw( oSettings );
\r
11670 $(nPaging).append(
\r
11671 '<a tabindex="'+oSettings.iTabIndex+'" class="'+oClasses.sPageButton+" "+oClasses.sPageFirst+'">'+oLang.sFirst+'</a>'+
\r
11672 '<a tabindex="'+oSettings.iTabIndex+'" class="'+oClasses.sPageButton+" "+oClasses.sPagePrevious+'">'+oLang.sPrevious+'</a>'+
\r
11674 '<a tabindex="'+oSettings.iTabIndex+'" class="'+oClasses.sPageButton+" "+oClasses.sPageNext+'">'+oLang.sNext+'</a>'+
\r
11675 '<a tabindex="'+oSettings.iTabIndex+'" class="'+oClasses.sPageButton+" "+oClasses.sPageLast+'">'+oLang.sLast+'</a>'
\r
11677 var els = $('a', nPaging);
\r
11678 var nFirst = els[0],
\r
11683 oSettings.oApi._fnBindAction( nFirst, {action: "first"}, fnClickHandler );
\r
11684 oSettings.oApi._fnBindAction( nPrev, {action: "previous"}, fnClickHandler );
\r
11685 oSettings.oApi._fnBindAction( nNext, {action: "next"}, fnClickHandler );
\r
11686 oSettings.oApi._fnBindAction( nLast, {action: "last"}, fnClickHandler );
\r
11688 /* ID the first elements only */
\r
11689 if ( !oSettings.aanFeatures.p )
\r
11691 nPaging.id = oSettings.sTableId+'_paginate';
\r
11692 nFirst.id =oSettings.sTableId+'_first';
\r
11693 nPrev.id =oSettings.sTableId+'_previous';
\r
11694 nNext.id =oSettings.sTableId+'_next';
\r
11695 nLast.id =oSettings.sTableId+'_last';
\r
11700 * Function: oPagination.full_numbers.fnUpdate
\r
11701 * Purpose: Update the list of page buttons shows
\r
11703 * Inputs: object:oSettings - dataTables settings object
\r
11704 * function:fnCallbackDraw - draw function to call on page change
\r
11706 "fnUpdate": function ( oSettings, fnCallbackDraw )
\r
11708 if ( !oSettings.aanFeatures.p )
\r
11713 var iPageCount = DataTable.ext.oPagination.iFullNumbersShowPages;
\r
11714 var iPageCountHalf = Math.floor(iPageCount / 2);
\r
11715 var iPages = Math.ceil((oSettings.fnRecordsDisplay()) / oSettings._iDisplayLength);
\r
11716 var iCurrentPage = Math.ceil(oSettings._iDisplayStart / oSettings._iDisplayLength) + 1;
\r
11718 var iStartButton, iEndButton, i, iLen;
\r
11719 var oClasses = oSettings.oClasses;
\r
11720 var anButtons, anStatic, nPaginateList, nNode;
\r
11721 var an = oSettings.aanFeatures.p;
\r
11722 var fnBind = function (j) {
\r
11723 oSettings.oApi._fnBindAction( this, {"page": j+iStartButton-1}, function(e) {
\r
11724 /* Use the information in the element to jump to the required page */
\r
11725 oSettings.oApi._fnPageChange( oSettings, e.data.page );
\r
11726 fnCallbackDraw( oSettings );
\r
11727 e.preventDefault();
\r
11731 /* Pages calculation */
\r
11732 if ( oSettings._iDisplayLength === -1 )
\r
11734 iStartButton = 1;
\r
11736 iCurrentPage = 1;
\r
11738 else if (iPages < iPageCount)
\r
11740 iStartButton = 1;
\r
11741 iEndButton = iPages;
\r
11743 else if (iCurrentPage <= iPageCountHalf)
\r
11745 iStartButton = 1;
\r
11746 iEndButton = iPageCount;
\r
11748 else if (iCurrentPage >= (iPages - iPageCountHalf))
\r
11750 iStartButton = iPages - iPageCount + 1;
\r
11751 iEndButton = iPages;
\r
11755 iStartButton = iCurrentPage - Math.ceil(iPageCount / 2) + 1;
\r
11756 iEndButton = iStartButton + iPageCount - 1;
\r
11760 /* Build the dynamic list */
\r
11761 for ( i=iStartButton ; i<=iEndButton ; i++ )
\r
11763 sList += (iCurrentPage !== i) ?
\r
11764 '<a tabindex="'+oSettings.iTabIndex+'" class="'+oClasses.sPageButton+'">'+oSettings.fnFormatNumber(i)+'</a>' :
\r
11765 '<a tabindex="'+oSettings.iTabIndex+'" class="'+oClasses.sPageButtonActive+'">'+oSettings.fnFormatNumber(i)+'</a>';
\r
11768 /* Loop over each instance of the pager */
\r
11769 for ( i=0, iLen=an.length ; i<iLen ; i++ )
\r
11772 if ( !nNode.hasChildNodes() )
\r
11777 /* Build up the dynamic list first - html and listeners */
\r
11778 $('span:eq(0)', nNode)
\r
11780 .children('a').each( fnBind );
\r
11782 /* Update the permanent button's classes */
\r
11783 anButtons = nNode.getElementsByTagName('a');
\r
11785 anButtons[0], anButtons[1],
\r
11786 anButtons[anButtons.length-2], anButtons[anButtons.length-1]
\r
11789 $(anStatic).removeClass( oClasses.sPageButton+" "+oClasses.sPageButtonActive+" "+oClasses.sPageButtonStaticDisabled );
\r
11790 $([anStatic[0], anStatic[1]]).addClass(
\r
11791 (iCurrentPage==1) ?
\r
11792 oClasses.sPageButtonStaticDisabled :
\r
11793 oClasses.sPageButton
\r
11795 $([anStatic[2], anStatic[3]]).addClass(
\r
11796 (iPages===0 || iCurrentPage===iPages || oSettings._iDisplayLength===-1) ?
\r
11797 oClasses.sPageButtonStaticDisabled :
\r
11798 oClasses.sPageButton
\r
11805 $.extend( DataTable.ext.oSort, {
\r
11809 "string-pre": function ( a )
\r
11811 if ( typeof a != 'string' ) {
\r
11812 a = (a !== null && a.toString) ? a.toString() : '';
\r
11814 return a.toLowerCase();
\r
11817 "string-asc": function ( x, y )
\r
11819 return ((x < y) ? -1 : ((x > y) ? 1 : 0));
\r
11822 "string-desc": function ( x, y )
\r
11824 return ((x < y) ? 1 : ((x > y) ? -1 : 0));
\r
11829 * html sorting (ignore html tags)
\r
11831 "html-pre": function ( a )
\r
11833 return a.replace( /<.*?>/g, "" ).toLowerCase();
\r
11836 "html-asc": function ( x, y )
\r
11838 return ((x < y) ? -1 : ((x > y) ? 1 : 0));
\r
11841 "html-desc": function ( x, y )
\r
11843 return ((x < y) ? 1 : ((x > y) ? -1 : 0));
\r
11850 "date-pre": function ( a )
\r
11852 var x = Date.parse( a );
\r
11854 if ( isNaN(x) || x==="" )
\r
11856 x = Date.parse( "01/01/1970 00:00:00" );
\r
11861 "date-asc": function ( x, y )
\r
11866 "date-desc": function ( x, y )
\r
11873 * numerical sorting
\r
11875 "numeric-pre": function ( a )
\r
11877 return (a=="-" || a==="") ? 0 : a*1;
\r
11880 "numeric-asc": function ( x, y )
\r
11885 "numeric-desc": function ( x, y )
\r
11892 $.extend( DataTable.ext.aTypes, [
\r
11895 * Purpose: Check to see if a string is numeric
\r
11896 * Returns: string:'numeric' or null
\r
11897 * Inputs: mixed:sText - string to check
\r
11899 function ( sData )
\r
11901 /* Allow zero length strings as a number */
\r
11902 if ( typeof sData === 'number' )
\r
11904 return 'numeric';
\r
11906 else if ( typeof sData !== 'string' )
\r
11911 var sValidFirstChars = "0123456789-";
\r
11912 var sValidChars = "0123456789.";
\r
11914 var bDecimal = false;
\r
11916 /* Check for a valid first char (no period and allow negatives) */
\r
11917 Char = sData.charAt(0);
\r
11918 if (sValidFirstChars.indexOf(Char) == -1)
\r
11923 /* Check all the other characters are valid */
\r
11924 for ( var i=1 ; i<sData.length ; i++ )
\r
11926 Char = sData.charAt(i);
\r
11927 if (sValidChars.indexOf(Char) == -1)
\r
11932 /* Only allowed one decimal place... */
\r
11933 if ( Char == "." )
\r
11943 return 'numeric';
\r
11948 * Purpose: Check to see if a string is actually a formatted date
\r
11949 * Returns: string:'date' or null
\r
11950 * Inputs: string:sText - string to check
\r
11952 function ( sData )
\r
11954 var iParse = Date.parse(sData);
\r
11955 if ( (iParse !== null && !isNaN(iParse)) || (typeof sData === 'string' && sData.length === 0) )
\r
11964 * Purpose: Check to see if a string should be treated as an HTML string
\r
11965 * Returns: string:'html' or null
\r
11966 * Inputs: string:sText - string to check
\r
11968 function ( sData )
\r
11970 if ( typeof sData === 'string' && sData.indexOf('<') != -1 && sData.indexOf('>') != -1 )
\r
11979 // jQuery aliases
\r
11980 $.fn.DataTable = DataTable;
\r
11981 $.fn.dataTable = DataTable;
\r
11982 $.fn.dataTableSettings = DataTable.settings;
\r
11983 $.fn.dataTableExt = DataTable.ext;
\r
11986 // Information about events fired by DataTables - for documentation.
\r
11988 * Draw event, fired whenever the table is redrawn on the page, at the same point as
\r
11989 * fnDrawCallback. This may be useful for binding events or performing calculations when
\r
11990 * the table is altered at all.
\r
11991 * @name DataTable#draw
\r
11993 * @param {event} e jQuery event object
\r
11994 * @param {object} o DataTables settings object {@link DataTable.models.oSettings}
\r
11998 * Filter event, fired when the filtering applied to the table (using the build in global
\r
11999 * global filter, or column filters) is altered.
\r
12000 * @name DataTable#filter
\r
12002 * @param {event} e jQuery event object
\r
12003 * @param {object} o DataTables settings object {@link DataTable.models.oSettings}
\r
12007 * Page change event, fired when the paging of the table is altered.
\r
12008 * @name DataTable#page
\r
12010 * @param {event} e jQuery event object
\r
12011 * @param {object} o DataTables settings object {@link DataTable.models.oSettings}
\r
12015 * Sort event, fired when the sorting applied to the table is altered.
\r
12016 * @name DataTable#sort
\r
12018 * @param {event} e jQuery event object
\r
12019 * @param {object} o DataTables settings object {@link DataTable.models.oSettings}
\r
12023 * DataTables initialisation complete event, fired when the table is fully drawn,
\r
12024 * including Ajax data loaded, if Ajax data is required.
\r
12025 * @name DataTable#init
\r
12027 * @param {event} e jQuery event object
\r
12028 * @param {object} oSettings DataTables settings object
\r
12029 * @param {object} json The JSON object request from the server - only
\r
12030 * present if client-side Ajax sourced data is used</li></ol>
\r
12034 * State save event, fired when the table has changed state a new state save is required.
\r
12035 * This method allows modification of the state saving object prior to actually doing the
\r
12036 * save, including addition or other state properties (for plug-ins) or modification
\r
12037 * of a DataTables core property.
\r
12038 * @name DataTable#stateSaveParams
\r
12040 * @param {event} e jQuery event object
\r
12041 * @param {object} oSettings DataTables settings object
\r
12042 * @param {object} json The state information to be saved
\r
12046 * State load event, fired when the table is loading state from the stored data, but
\r
12047 * prior to the settings object being modified by the saved state - allowing modification
\r
12048 * of the saved state is required or loading of state for a plug-in.
\r
12049 * @name DataTable#stateLoadParams
\r
12051 * @param {event} e jQuery event object
\r
12052 * @param {object} oSettings DataTables settings object
\r
12053 * @param {object} json The saved state information
\r
12057 * State loaded event, fired when state has been loaded from stored data and the settings
\r
12058 * object has been modified by the loaded data.
\r
12059 * @name DataTable#stateLoaded
\r
12061 * @param {event} e jQuery event object
\r
12062 * @param {object} oSettings DataTables settings object
\r
12063 * @param {object} json The saved state information
\r
12067 * Processing event, fired when DataTables is doing some kind of processing (be it,
\r
12068 * sort, filter or anything else). Can be used to indicate to the end user that
\r
12069 * there is something happening, or that something has finished.
\r
12070 * @name DataTable#processing
\r
12072 * @param {event} e jQuery event object
\r
12073 * @param {object} oSettings DataTables settings object
\r
12074 * @param {boolean} bShow Flag for if DataTables is doing processing or not
\r
12078 * Ajax (XHR) event, fired whenever an Ajax request is completed from a request to
\r
12079 * made to the server for new data (note that this trigger is called in fnServerData,
\r
12080 * if you override fnServerData and which to use this event, you need to trigger it in
\r
12081 * you success function).
\r
12082 * @name DataTable#xhr
\r
12084 * @param {event} e jQuery event object
\r
12085 * @param {object} o DataTables settings object {@link DataTable.models.oSettings}
\r
12086 * @param {object} json JSON returned from the server
\r
12090 * Destroy event, fired when the DataTable is destroyed by calling fnDestroy or passing
\r
12091 * the bDestroy:true parameter in the initialisation object. This can be used to remove
\r
12092 * bound events, added DOM nodes, etc.
\r
12093 * @name DataTable#destroy
\r
12095 * @param {event} e jQuery event object
\r
12096 * @param {object} o DataTables settings object {@link DataTable.models.oSettings}
\r
12100 }(window, document));
\r