CLIENT GUI Framework
[vnfsdk/refrepo.git] / openo-portal / portal-common / src / main / webapp / common / thirdparty / data-tables / jquery.dataTables-1.9.4.js
1 /**\r
2  * @summary     DataTables\r
3  * @description Paginate, search and sort HTML tables\r
4  * @version     1.9.4\r
5  * @file        jquery.dataTables.js\r
6  * @author      Allan Jardine (www.sprymedia.co.uk)\r
7  * @contact     www.sprymedia.co.uk/contact\r
8  *\r
9  * @copyright Copyright 2008-2012 Allan Jardine, all rights reserved.\r
10  *\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
15  * \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
19  * \r
20  * For details please refer to: http://www.datatables.net\r
21  */\r
22 \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
25 \r
26 (/** @lends <global> */function( window, document, undefined ) {\r
27 \r
28 (function( factory ) {\r
29         "use strict";\r
30 \r
31         // Define as an AMD module if possible\r
32         if ( typeof define === 'function' && define.amd )\r
33         {\r
34                 define( ['jquery'], factory );\r
35         }\r
36         /* Define using browser globals otherwise\r
37          * Prevent multiple instantiations if the script is loaded twice\r
38          */\r
39         else if ( jQuery && !jQuery.fn.dataTable )\r
40         {\r
41                 factory( jQuery );\r
42         }\r
43 }\r
44 (/** @lends <global> */function( $ ) {\r
45         "use strict";\r
46         /** \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
52          *\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
56          *\r
57          *  @class\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
61          * \r
62          *  @example\r
63          *    // Basic initialisation\r
64          *    $(document).ready( function {\r
65          *      $('#example').dataTable();\r
66          *    } );\r
67          *  \r
68          *  @example\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
74          *        "bSort": false \r
75          *      } );\r
76          *    } );\r
77          */\r
78         var DataTable = function( oInit )\r
79         {\r
80                 \r
81                 \r
82                 /**\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
87                  */\r
88                 function _fnAddColumn( oSettings, nTh )\r
89                 {\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
99                         } );\r
100                         oSettings.aoColumns.push( oCol );\r
101                         \r
102                         /* Add a column specific filter */\r
103                         if ( oSettings.aoPreSearchCols[ iCol ] === undefined || oSettings.aoPreSearchCols[ iCol ] === null )\r
104                         {\r
105                                 oSettings.aoPreSearchCols[ iCol ] = $.extend( {}, DataTable.models.oSearch );\r
106                         }\r
107                         else\r
108                         {\r
109                                 var oPre = oSettings.aoPreSearchCols[ iCol ];\r
110                                 \r
111                                 /* Don't require that the user must specify bRegex, bSmart or bCaseInsensitive */\r
112                                 if ( oPre.bRegex === undefined )\r
113                                 {\r
114                                         oPre.bRegex = true;\r
115                                 }\r
116                                 \r
117                                 if ( oPre.bSmart === undefined )\r
118                                 {\r
119                                         oPre.bSmart = true;\r
120                                 }\r
121                                 \r
122                                 if ( oPre.bCaseInsensitive === undefined )\r
123                                 {\r
124                                         oPre.bCaseInsensitive = true;\r
125                                 }\r
126                         }\r
127                         \r
128                         /* Use the column options function to initialise classes etc */\r
129                         _fnColumnOptions( oSettings, iCol, null );\r
130                 }\r
131                 \r
132                 \r
133                 /**\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
139                  */\r
140                 function _fnColumnOptions( oSettings, iCol, oOptions )\r
141                 {\r
142                         var oCol = oSettings.aoColumns[ iCol ];\r
143                         \r
144                         /* User specified column options */\r
145                         if ( oOptions !== undefined && oOptions !== null )\r
146                         {\r
147                                 /* Backwards compatibility for mDataProp */\r
148                                 if ( oOptions.mDataProp && !oOptions.mData )\r
149                                 {\r
150                                         oOptions.mData = oOptions.mDataProp;\r
151                                 }\r
152                 \r
153                                 if ( oOptions.sType !== undefined )\r
154                                 {\r
155                                         oCol.sType = oOptions.sType;\r
156                                         oCol._bAutoType = false;\r
157                                 }\r
158                                 \r
159                                 $.extend( oCol, oOptions );\r
160                                 _fnMap( oCol, oOptions, "sWidth", "sWidthOrig" );\r
161                 \r
162                                 /* iDataSort to be applied (backwards compatibility), but aDataSort will take\r
163                                  * priority if defined\r
164                                  */\r
165                                 if ( oOptions.iDataSort !== undefined )\r
166                                 {\r
167                                         oCol.aDataSort = [ oOptions.iDataSort ];\r
168                                 }\r
169                                 _fnMap( oCol, oOptions, "aDataSort" );\r
170                         }\r
171                 \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
175                 \r
176                         oCol.fnGetData = function (oData, sSpecific) {\r
177                                 var innerData = mData( oData, sSpecific );\r
178                 \r
179                                 if ( oCol.mRender && (sSpecific && sSpecific !== '') )\r
180                                 {\r
181                                         return mRender( innerData, sSpecific, oData );\r
182                                 }\r
183                                 return innerData;\r
184                         };\r
185                         oCol.fnSetData = _fnSetObjectDataFn( oCol.mData );\r
186                         \r
187                         /* Feature sorting overrides column specific when off */\r
188                         if ( !oSettings.oFeatures.bSort )\r
189                         {\r
190                                 oCol.bSortable = false;\r
191                         }\r
192                         \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
196                         {\r
197                                 oCol.sSortingClass = oSettings.oClasses.sSortableNone;\r
198                                 oCol.sSortingClassJUI = "";\r
199                         }\r
200                         else if ( $.inArray('asc', oCol.asSorting) == -1 && $.inArray('desc', oCol.asSorting) == -1 )\r
201                         {\r
202                                 oCol.sSortingClass = oSettings.oClasses.sSortable;\r
203                                 oCol.sSortingClassJUI = oSettings.oClasses.sSortJUI;\r
204                         }\r
205                         else if ( $.inArray('asc', oCol.asSorting) != -1 && $.inArray('desc', oCol.asSorting) == -1 )\r
206                         {\r
207                                 oCol.sSortingClass = oSettings.oClasses.sSortableAsc;\r
208                                 oCol.sSortingClassJUI = oSettings.oClasses.sSortJUIAscAllowed;\r
209                         }\r
210                         else if ( $.inArray('asc', oCol.asSorting) == -1 && $.inArray('desc', oCol.asSorting) != -1 )\r
211                         {\r
212                                 oCol.sSortingClass = oSettings.oClasses.sSortableDesc;\r
213                                 oCol.sSortingClassJUI = oSettings.oClasses.sSortJUIDescAllowed;\r
214                         }\r
215                 }\r
216                 \r
217                 \r
218                 /**\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
223                  */\r
224                 function _fnAdjustColumnSizing ( oSettings )\r
225                 {\r
226                         /* Not interested in doing column width calculation if auto-width is disabled */\r
227                         if ( oSettings.oFeatures.bAutoWidth === false )\r
228                         {\r
229                                 return false;\r
230                         }\r
231                         \r
232                         _fnCalculateColumnWidths( oSettings );\r
233                         for ( var i=0 , iLen=oSettings.aoColumns.length ; i<iLen ; i++ )\r
234                         {\r
235                                 oSettings.aoColumns[i].nTh.style.width = oSettings.aoColumns[i].sWidth;\r
236                         }\r
237                 }\r
238                 \r
239                 \r
240                 /**\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
247                  */\r
248                 function _fnVisibleToColumnIndex( oSettings, iMatch )\r
249                 {\r
250                         var aiVis = _fnGetColumns( oSettings, 'bVisible' );\r
251                 \r
252                         return typeof aiVis[iMatch] === 'number' ?\r
253                                 aiVis[iMatch] :\r
254                                 null;\r
255                 }\r
256                 \r
257                 \r
258                 /**\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
265                  */\r
266                 function _fnColumnIndexToVisible( oSettings, iMatch )\r
267                 {\r
268                         var aiVis = _fnGetColumns( oSettings, 'bVisible' );\r
269                         var iPos = $.inArray( iMatch, aiVis );\r
270                 \r
271                         return iPos !== -1 ? iPos : null;\r
272                 }\r
273                 \r
274                 \r
275                 /**\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
280                  */\r
281                 function _fnVisbleColumns( oSettings )\r
282                 {\r
283                         return _fnGetColumns( oSettings, 'bVisible' ).length;\r
284                 }\r
285                 \r
286                 \r
287                 /**\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
294                  */\r
295                 function _fnGetColumns( oSettings, sParam )\r
296                 {\r
297                         var a = [];\r
298                 \r
299                         $.map( oSettings.aoColumns, function(val, i) {\r
300                                 if ( val[sParam] ) {\r
301                                         a.push( i );\r
302                                 }\r
303                         } );\r
304                 \r
305                         return a;\r
306                 }\r
307                 \r
308                 \r
309                 /**\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
314                  */\r
315                 function _fnDetectType( sData )\r
316                 {\r
317                         var aTypes = DataTable.ext.aTypes;\r
318                         var iLen = aTypes.length;\r
319                         \r
320                         for ( var i=0 ; i<iLen ; i++ )\r
321                         {\r
322                                 var sType = aTypes[i]( sData );\r
323                                 if ( sType !== null )\r
324                                 {\r
325                                         return sType;\r
326                                 }\r
327                         }\r
328                         \r
329                         return 'string';\r
330                 }\r
331                 \r
332                 \r
333                 /**\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
338                  */\r
339                 function _fnReOrderIndex ( oSettings, sColumns )\r
340                 {\r
341                         var aColumns = sColumns.split(',');\r
342                         var aiReturn = [];\r
343                         \r
344                         for ( var i=0, iLen=oSettings.aoColumns.length ; i<iLen ; i++ )\r
345                         {\r
346                                 for ( var j=0 ; j<iLen ; j++ )\r
347                                 {\r
348                                         if ( oSettings.aoColumns[i].sName == aColumns[j] )\r
349                                         {\r
350                                                 aiReturn.push( j );\r
351                                                 break;\r
352                                         }\r
353                                 }\r
354                         }\r
355                         \r
356                         return aiReturn;\r
357                 }\r
358                 \r
359                 \r
360                 /**\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
365                  */\r
366                 function _fnColumnOrdering ( oSettings )\r
367                 {\r
368                         var sNames = '';\r
369                         for ( var i=0, iLen=oSettings.aoColumns.length ; i<iLen ; i++ )\r
370                         {\r
371                                 sNames += oSettings.aoColumns[i].sName+',';\r
372                         }\r
373                         if ( sNames.length == iLen )\r
374                         {\r
375                                 return "";\r
376                         }\r
377                         return sNames.slice(0, -1);\r
378                 }\r
379                 \r
380                 \r
381                 /**\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
391                  */\r
392                 function _fnApplyColumnDefs( oSettings, aoColDefs, aoCols, fn )\r
393                 {\r
394                         var i, iLen, j, jLen, k, kLen;\r
395                 \r
396                         // Column definitions with aTargets\r
397                         if ( aoColDefs )\r
398                         {\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
401                                 {\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
405                                         {\r
406                                                 _fnLog( oSettings, 1, 'aTargets must be an array of targets, not a '+(typeof aTargets) );\r
407                                         }\r
408                 \r
409                                         for ( j=0, jLen=aTargets.length ; j<jLen ; j++ )\r
410                                         {\r
411                                                 if ( typeof aTargets[j] === 'number' && aTargets[j] >= 0 )\r
412                                                 {\r
413                                                         /* Add columns that we don't yet know about */\r
414                                                         while( oSettings.aoColumns.length <= aTargets[j] )\r
415                                                         {\r
416                                                                 _fnAddColumn( oSettings );\r
417                                                         }\r
418                 \r
419                                                         /* Integer, basic index */\r
420                                                         fn( aTargets[j], aoColDefs[i] );\r
421                                                 }\r
422                                                 else if ( typeof aTargets[j] === 'number' && aTargets[j] < 0 )\r
423                                                 {\r
424                                                         /* Negative integer, right to left column counting */\r
425                                                         fn( oSettings.aoColumns.length+aTargets[j], aoColDefs[i] );\r
426                                                 }\r
427                                                 else if ( typeof aTargets[j] === 'string' )\r
428                                                 {\r
429                                                         /* Class name matching on TH element */\r
430                                                         for ( k=0, kLen=oSettings.aoColumns.length ; k<kLen ; k++ )\r
431                                                         {\r
432                                                                 if ( aTargets[j] == "_all" ||\r
433                                                                      $(oSettings.aoColumns[k].nTh).hasClass( aTargets[j] ) )\r
434                                                                 {\r
435                                                                         fn( k, aoColDefs[i] );\r
436                                                                 }\r
437                                                         }\r
438                                                 }\r
439                                         }\r
440                                 }\r
441                         }\r
442                 \r
443                         // Statically defined columns array\r
444                         if ( aoCols )\r
445                         {\r
446                                 for ( i=0, iLen=aoCols.length ; i<iLen ; i++ )\r
447                                 {\r
448                                         fn( i, aoCols[i] );\r
449                                 }\r
450                         }\r
451                 }\r
452                 \r
453                 /**\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
456                  * DOM source.\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
461                  */\r
462                 function _fnAddData ( oSettings, aDataSupplied )\r
463                 {\r
464                         var oCol;\r
465                         \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
470                         \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
476                 \r
477                         /* Create the cells */\r
478                         var nTd, sThisType;\r
479                         for ( var i=0, iLen=oSettings.aoColumns.length ; i<iLen ; i++ )\r
480                         {\r
481                                 oCol = oSettings.aoColumns[i];\r
482                 \r
483                                 /* Use rendered data for filtering / sorting */\r
484                                 if ( typeof oCol.fnRender === 'function' && oCol.bUseRendered && oCol.mData !== null )\r
485                                 {\r
486                                         _fnSetCellData( oSettings, iRow, i, _fnRender(oSettings, iRow, i) );\r
487                                 }\r
488                                 else\r
489                                 {\r
490                                         _fnSetCellData( oSettings, iRow, i, _fnGetCellData( oSettings, iRow, i ) );\r
491                                 }\r
492                                 \r
493                                 /* See if we should auto-detect the column type */\r
494                                 if ( oCol._bAutoType && oCol.sType != 'string' )\r
495                                 {\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
499                                         {\r
500                                                 sThisType = _fnDetectType( sVarType );\r
501                                                 if ( oCol.sType === null )\r
502                                                 {\r
503                                                         oCol.sType = sThisType;\r
504                                                 }\r
505                                                 else if ( oCol.sType != sThisType && oCol.sType != "html" )\r
506                                                 {\r
507                                                         /* String is always the 'fallback' option */\r
508                                                         oCol.sType = 'string';\r
509                                                 }\r
510                                         }\r
511                                 }\r
512                         }\r
513                         \r
514                         /* Add to the display array */\r
515                         oSettings.aiDisplayMaster.push( iRow );\r
516                 \r
517                         /* Create the DOM information */\r
518                         if ( !oSettings.oFeatures.bDeferRender )\r
519                         {\r
520                                 _fnCreateTr( oSettings, iRow );\r
521                         }\r
522                 \r
523                         return iRow;\r
524                 }\r
525                 \r
526                 \r
527                 /**\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
531                  */\r
532                 function _fnGatherData( oSettings )\r
533                 {\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
537                                 oCol, oData;\r
538                         \r
539                         /*\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
543                          */\r
544                         if ( oSettings.bDeferLoading || oSettings.sAjaxSource === null )\r
545                         {\r
546                                 nTr = oSettings.nTBody.firstChild;\r
547                                 while ( nTr )\r
548                                 {\r
549                                         if ( nTr.nodeName.toUpperCase() == "TR" )\r
550                                         {\r
551                                                 iThisIndex = oSettings.aoData.length;\r
552                                                 nTr._DT_RowIndex = iThisIndex;\r
553                                                 oSettings.aoData.push( $.extend( true, {}, DataTable.models.oRow, {\r
554                                                         "nTr": nTr\r
555                                                 } ) );\r
556                 \r
557                                                 oSettings.aiDisplayMaster.push( iThisIndex );\r
558                                                 nTd = nTr.firstChild;\r
559                                                 jInner = 0;\r
560                                                 while ( nTd )\r
561                                                 {\r
562                                                         sNodeName = nTd.nodeName.toUpperCase();\r
563                                                         if ( sNodeName == "TD" || sNodeName == "TH" )\r
564                                                         {\r
565                                                                 _fnSetCellData( oSettings, iThisIndex, jInner, $.trim(nTd.innerHTML) );\r
566                                                                 jInner++;\r
567                                                         }\r
568                                                         nTd = nTd.nextSibling;\r
569                                                 }\r
570                                         }\r
571                                         nTr = nTr.nextSibling;\r
572                                 }\r
573                         }\r
574                         \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
577                          * setup!\r
578                          */\r
579                         nTrs = _fnGetTrNodes( oSettings );\r
580                         nTds = [];\r
581                         for ( i=0, iLen=nTrs.length ; i<iLen ; i++ )\r
582                         {\r
583                                 nTd = nTrs[i].firstChild;\r
584                                 while ( nTd )\r
585                                 {\r
586                                         sNodeName = nTd.nodeName.toUpperCase();\r
587                                         if ( sNodeName == "TD" || sNodeName == "TH" )\r
588                                         {\r
589                                                 nTds.push( nTd );\r
590                                         }\r
591                                         nTd = nTd.nextSibling;\r
592                                 }\r
593                         }\r
594                         \r
595                         /* Now process by column */\r
596                         for ( iColumn=0, iColumns=oSettings.aoColumns.length ; iColumn<iColumns ; iColumn++ )\r
597                         {\r
598                                 oCol = oSettings.aoColumns[iColumn];\r
599                 \r
600                                 /* Get the title of the column - unless there is a user set one */\r
601                                 if ( oCol.sTitle === null )\r
602                                 {\r
603                                         oCol.sTitle = oCol.nTh.innerHTML;\r
604                                 }\r
605                                 \r
606                                 var\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
612                                 \r
613                                 /* A single loop to rule them all (and be more efficient) */\r
614                                 if ( bAutoType || bRender || bClass || !bVisible )\r
615                                 {\r
616                                         for ( iRow=0, iRows=oSettings.aoData.length ; iRow<iRows ; iRow++ )\r
617                                         {\r
618                                                 oData = oSettings.aoData[iRow];\r
619                                                 nCell = nTds[ (iRow*iColumns) + iColumn ];\r
620                                                 \r
621                                                 /* Type detection */\r
622                                                 if ( bAutoType && oCol.sType != 'string' )\r
623                                                 {\r
624                                                         sValType = _fnGetCellData( oSettings, iRow, iColumn, 'type' );\r
625                                                         if ( sValType !== '' )\r
626                                                         {\r
627                                                                 sThisType = _fnDetectType( sValType );\r
628                                                                 if ( oCol.sType === null )\r
629                                                                 {\r
630                                                                         oCol.sType = sThisType;\r
631                                                                 }\r
632                                                                 else if ( oCol.sType != sThisType && \r
633                                                                           oCol.sType != "html" )\r
634                                                                 {\r
635                                                                         /* String is always the 'fallback' option */\r
636                                                                         oCol.sType = 'string';\r
637                                                                 }\r
638                                                         }\r
639                                                 }\r
640                 \r
641                                                 if ( oCol.mRender )\r
642                                                 {\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
645                                                 }\r
646                                                 else if ( oCol.mData !== iColumn )\r
647                                                 {\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
652                                                 }\r
653                                                 \r
654                                                 /* Rendering */\r
655                                                 if ( bRender )\r
656                                                 {\r
657                                                         sRendered = _fnRender( oSettings, iRow, iColumn );\r
658                                                         nCell.innerHTML = sRendered;\r
659                                                         if ( oCol.bUseRendered )\r
660                                                         {\r
661                                                                 /* Use the rendered data for filtering / sorting */\r
662                                                                 _fnSetCellData( oSettings, iRow, iColumn, sRendered );\r
663                                                         }\r
664                                                 }\r
665                                                 \r
666                                                 /* Classes */\r
667                                                 if ( bClass )\r
668                                                 {\r
669                                                         nCell.className += ' '+oCol.sClass;\r
670                                                 }\r
671                                                 \r
672                                                 /* Column visibility */\r
673                                                 if ( !bVisible )\r
674                                                 {\r
675                                                         oData._anHidden[iColumn] = nCell;\r
676                                                         nCell.parentNode.removeChild( nCell );\r
677                                                 }\r
678                                                 else\r
679                                                 {\r
680                                                         oData._anHidden[iColumn] = null;\r
681                                                 }\r
682                 \r
683                                                 if ( oCol.fnCreatedCell )\r
684                                                 {\r
685                                                         oCol.fnCreatedCell.call( oSettings.oInstance,\r
686                                                                 nCell, _fnGetCellData( oSettings, iRow, iColumn, 'display' ), oData._aData, iRow, iColumn\r
687                                                         );\r
688                                                 }\r
689                                         }\r
690                                 }\r
691                         }\r
692                 \r
693                         /* Row created callbacks */\r
694                         if ( oSettings.aoRowCreatedCallback.length !== 0 )\r
695                         {\r
696                                 for ( i=0, iLen=oSettings.aoData.length ; i<iLen ; i++ )\r
697                                 {\r
698                                         oData = oSettings.aoData[i];\r
699                                         _fnCallbackFire( oSettings, 'aoRowCreatedCallback', null, [oData.nTr, oData._aData, i] );\r
700                                 }\r
701                         }\r
702                 }\r
703                 \r
704                 \r
705                 /**\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
711                  */\r
712                 function _fnNodeToDataIndex( oSettings, n )\r
713                 {\r
714                         return (n._DT_RowIndex!==undefined) ? n._DT_RowIndex : null;\r
715                 }\r
716                 \r
717                 \r
718                 /**\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
725                  */\r
726                 function _fnNodeToColumnIndex( oSettings, iRow, n )\r
727                 {\r
728                         var anCells = _fnGetTdNodes( oSettings, iRow );\r
729                 \r
730                         for ( var i=0, iLen=oSettings.aoColumns.length ; i<iLen ; i++ )\r
731                         {\r
732                                 if ( anCells[i] === n )\r
733                                 {\r
734                                         return i;\r
735                                 }\r
736                         }\r
737                         return -1;\r
738                 }\r
739                 \r
740                 \r
741                 /**\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
749                  */\r
750                 function _fnGetRowData( oSettings, iRow, sSpecific, aiColumns )\r
751                 {\r
752                         var out = [];\r
753                         for ( var i=0, iLen=aiColumns.length ; i<iLen ; i++ )\r
754                         {\r
755                                 out.push( _fnGetCellData( oSettings, iRow, aiColumns[i], sSpecific ) );\r
756                         }\r
757                         return out;\r
758                 }\r
759                 \r
760                 \r
761                 /**\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
769                  */\r
770                 function _fnGetCellData( oSettings, iRow, iCol, sSpecific )\r
771                 {\r
772                         var sData;\r
773                         var oCol = oSettings.aoColumns[iCol];\r
774                         var oData = oSettings.aoData[iRow]._aData;\r
775                 \r
776                         if ( (sData=oCol.fnGetData( oData, sSpecific )) === undefined )\r
777                         {\r
778                                 if ( oSettings.iDrawError != oSettings.iDraw && oCol.sDefaultContent === null )\r
779                                 {\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
784                                 }\r
785                                 return oCol.sDefaultContent;\r
786                         }\r
787                 \r
788                         /* When the data source is null, we can use default column data */\r
789                         if ( sData === null && oCol.sDefaultContent !== null )\r
790                         {\r
791                                 sData = oCol.sDefaultContent;\r
792                         }\r
793                         else if ( typeof sData === 'function' )\r
794                         {\r
795                                 /* If the data source is a function, then we run it and use the return */\r
796                                 return sData();\r
797                         }\r
798                 \r
799                         if ( sSpecific == 'display' && sData === null )\r
800                         {\r
801                                 return '';\r
802                         }\r
803                         return sData;\r
804                 }\r
805                 \r
806                 \r
807                 /**\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
814                  */\r
815                 function _fnSetCellData( oSettings, iRow, iCol, val )\r
816                 {\r
817                         var oCol = oSettings.aoColumns[iCol];\r
818                         var oData = oSettings.aoData[iRow]._aData;\r
819                 \r
820                         oCol.fnSetData( oData, val );\r
821                 }\r
822                 \r
823                 \r
824                 // Private variable that is used to match array syntax in the data property object\r
825                 var __reArray = /\[.*?\]$/;\r
826                 \r
827                 /**\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
833                  */\r
834                 function _fnGetObjectDataFn( mSource )\r
835                 {\r
836                         if ( mSource === null )\r
837                         {\r
838                                 /* Give an empty string for rendering / sorting etc */\r
839                                 return function (data, type) {\r
840                                         return null;\r
841                                 };\r
842                         }\r
843                         else if ( typeof mSource === 'function' )\r
844                         {\r
845                                 return function (data, type, extra) {\r
846                                         return mSource( data, type, extra );\r
847                                 };\r
848                         }\r
849                         else if ( typeof mSource === 'string' && (mSource.indexOf('.') !== -1 || mSource.indexOf('[') !== -1) )\r
850                         {\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
856                                  */\r
857                                 var fetchData = function (data, type, src) {\r
858                                         var a = src.split('.');\r
859                                         var arrayNotation, out, innerSrc;\r
860                 \r
861                                         if ( src !== "" )\r
862                                         {\r
863                                                 for ( var i=0, iLen=a.length ; i<iLen ; i++ )\r
864                                                 {\r
865                                                         // Check if we are dealing with an array notation request\r
866                                                         arrayNotation = a[i].match(__reArray);\r
867                 \r
868                                                         if ( arrayNotation ) {\r
869                                                                 a[i] = a[i].replace(__reArray, '');\r
870                 \r
871                                                                 // Condition allows simply [] to be passed in\r
872                                                                 if ( a[i] !== "" ) {\r
873                                                                         data = data[ a[i] ];\r
874                                                                 }\r
875                                                                 out = [];\r
876                                                                 \r
877                                                                 // Get the remainder of the nested object to get\r
878                                                                 a.splice( 0, i+1 );\r
879                                                                 innerSrc = a.join('.');\r
880                 \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
884                                                                 }\r
885                 \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
890                 \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
893                                                                 break;\r
894                                                         }\r
895                 \r
896                                                         if ( data === null || data[ a[i] ] === undefined )\r
897                                                         {\r
898                                                                 return undefined;\r
899                                                         }\r
900                                                         data = data[ a[i] ];\r
901                                                 }\r
902                                         }\r
903                 \r
904                                         return data;\r
905                                 };\r
906                 \r
907                                 return function (data, type) {\r
908                                         return fetchData( data, type, mSource );\r
909                                 };\r
910                         }\r
911                         else\r
912                         {\r
913                                 /* Array or flat object mapping */\r
914                                 return function (data, type) {\r
915                                         return data[mSource];   \r
916                                 };\r
917                         }\r
918                 }\r
919                 \r
920                 \r
921                 /**\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
927                  */\r
928                 function _fnSetObjectDataFn( mSource )\r
929                 {\r
930                         if ( mSource === null )\r
931                         {\r
932                                 /* Nothing to do when the data source is null */\r
933                                 return function (data, val) {};\r
934                         }\r
935                         else if ( typeof mSource === 'function' )\r
936                         {\r
937                                 return function (data, val) {\r
938                                         mSource( data, 'set', val );\r
939                                 };\r
940                         }\r
941                         else if ( typeof mSource === 'string' && (mSource.indexOf('.') !== -1 || mSource.indexOf('[') !== -1) )\r
942                         {\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
947                 \r
948                                         for ( var i=0, iLen=a.length-1 ; i<iLen ; i++ )\r
949                                         {\r
950                                                 // Check if we are dealing with an array notation request\r
951                                                 arrayNotation = a[i].match(__reArray);\r
952                 \r
953                                                 if ( arrayNotation )\r
954                                                 {\r
955                                                         a[i] = a[i].replace(__reArray, '');\r
956                                                         data[ a[i] ] = [];\r
957                                                         \r
958                                                         // Get the remainder of the nested object to set so we can recurse\r
959                                                         b = a.slice();\r
960                                                         b.splice( 0, i+1 );\r
961                                                         innerSrc = b.join('.');\r
962                 \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
965                                                         {\r
966                                                                 o = {};\r
967                                                                 setData( o, val[j], innerSrc );\r
968                                                                 data[ a[i] ].push( o );\r
969                                                         }\r
970                 \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
973                                                         return;\r
974                                                 }\r
975                 \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
979                                                 {\r
980                                                         data[ a[i] ] = {};\r
981                                                 }\r
982                                                 data = data[ a[i] ];\r
983                                         }\r
984                 \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
988                                 };\r
989                 \r
990                                 return function (data, val) {\r
991                                         return setData( data, val, mSource );\r
992                                 };\r
993                         }\r
994                         else\r
995                         {\r
996                                 /* Array or flat object mapping */\r
997                                 return function (data, val) {\r
998                                         data[mSource] = val;    \r
999                                 };\r
1000                         }\r
1001                 }\r
1002                 \r
1003                 \r
1004                 /**\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
1009                  */\r
1010                 function _fnGetDataMaster ( oSettings )\r
1011                 {\r
1012                         var aData = [];\r
1013                         var iLen = oSettings.aoData.length;\r
1014                         for ( var i=0 ; i<iLen; i++ )\r
1015                         {\r
1016                                 aData.push( oSettings.aoData[i]._aData );\r
1017                         }\r
1018                         return aData;\r
1019                 }\r
1020                 \r
1021                 \r
1022                 /**\r
1023                  * Nuke the table\r
1024                  *  @param {object} oSettings dataTables settings object\r
1025                  *  @memberof DataTable#oApi\r
1026                  */\r
1027                 function _fnClearTable( oSettings )\r
1028                 {\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
1033                 }\r
1034                 \r
1035                 \r
1036                  /**\r
1037                  * Take an array of integers (index array) and remove a target integer (value - not \r
1038                  * the key!)\r
1039                  *  @param {array} a Index array to target\r
1040                  *  @param {int} iTarget value to find\r
1041                  *  @memberof DataTable#oApi\r
1042                  */\r
1043                 function _fnDeleteIndex( a, iTarget )\r
1044                 {\r
1045                         var iTargetIndex = -1;\r
1046                         \r
1047                         for ( var i=0, iLen=a.length ; i<iLen ; i++ )\r
1048                         {\r
1049                                 if ( a[i] == iTarget )\r
1050                                 {\r
1051                                         iTargetIndex = i;\r
1052                                 }\r
1053                                 else if ( a[i] > iTarget )\r
1054                                 {\r
1055                                         a[i]--;\r
1056                                 }\r
1057                         }\r
1058                         \r
1059                         if ( iTargetIndex != -1 )\r
1060                         {\r
1061                                 a.splice( iTargetIndex, 1 );\r
1062                         }\r
1063                 }\r
1064                 \r
1065                 \r
1066                  /**\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
1074                  */\r
1075                 function _fnRender( oSettings, iRow, iCol )\r
1076                 {\r
1077                         var oCol = oSettings.aoColumns[iCol];\r
1078                 \r
1079                         return oCol.fnRender( {\r
1080                                 "iDataRow":    iRow,\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
1086                 }\r
1087                 /**\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
1092                  */\r
1093                 function _fnCreateTr ( oSettings, iRow )\r
1094                 {\r
1095                         var oData = oSettings.aoData[iRow];\r
1096                         var nTd;\r
1097                 \r
1098                         if ( oData.nTr === null )\r
1099                         {\r
1100                                 oData.nTr = document.createElement('tr');\r
1101                 \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
1104                                  */\r
1105                                 oData.nTr._DT_RowIndex = iRow;\r
1106                 \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
1109                                 {\r
1110                                         oData.nTr.id = oData._aData.DT_RowId;\r
1111                                 }\r
1112                 \r
1113                                 if ( oData._aData.DT_RowClass )\r
1114                                 {\r
1115                                         oData.nTr.className = oData._aData.DT_RowClass;\r
1116                                 }\r
1117                 \r
1118                                 /* Process each column */\r
1119                                 for ( var i=0, iLen=oSettings.aoColumns.length ; i<iLen ; i++ )\r
1120                                 {\r
1121                                         var oCol = oSettings.aoColumns[i];\r
1122                                         nTd = document.createElement( oCol.sCellType );\r
1123                 \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
1126                                          */\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
1130                                 \r
1131                                         /* Add user defined class */\r
1132                                         if ( oCol.sClass !== null )\r
1133                                         {\r
1134                                                 nTd.className = oCol.sClass;\r
1135                                         }\r
1136                                         \r
1137                                         if ( oCol.bVisible )\r
1138                                         {\r
1139                                                 oData.nTr.appendChild( nTd );\r
1140                                                 oData._anHidden[i] = null;\r
1141                                         }\r
1142                                         else\r
1143                                         {\r
1144                                                 oData._anHidden[i] = nTd;\r
1145                                         }\r
1146                 \r
1147                                         if ( oCol.fnCreatedCell )\r
1148                                         {\r
1149                                                 oCol.fnCreatedCell.call( oSettings.oInstance,\r
1150                                                         nTd, _fnGetCellData( oSettings, iRow, i, 'display' ), oData._aData, iRow, i\r
1151                                                 );\r
1152                                         }\r
1153                                 }\r
1154                 \r
1155                                 _fnCallbackFire( oSettings, 'aoRowCreatedCallback', null, [oData.nTr, oData._aData, iRow] );\r
1156                         }\r
1157                 }\r
1158                 \r
1159                 \r
1160                 /**\r
1161                  * Create the HTML header for the table\r
1162                  *  @param {object} oSettings dataTables settings object\r
1163                  *  @memberof DataTable#oApi\r
1164                  */\r
1165                 function _fnBuildHead( oSettings )\r
1166                 {\r
1167                         var i, nTh, iLen, j, jLen;\r
1168                         var iThs = $('th, td', oSettings.nTHead).length;\r
1169                         var iCorrector = 0;\r
1170                         var jqChildren;\r
1171                         \r
1172                         /* If there is a header in place - then use it - otherwise it's going to get nuked... */\r
1173                         if ( iThs !== 0 )\r
1174                         {\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
1177                                 {\r
1178                                         nTh = oSettings.aoColumns[i].nTh;\r
1179                                         nTh.setAttribute('role', 'columnheader');\r
1180                                         if ( oSettings.aoColumns[i].bSortable )\r
1181                                         {\r
1182                                                 nTh.setAttribute('tabindex', oSettings.iTabIndex);\r
1183                                                 nTh.setAttribute('aria-controls', oSettings.sTableId);\r
1184                                         }\r
1185                 \r
1186                                         if ( oSettings.aoColumns[i].sClass !== null )\r
1187                                         {\r
1188                                                 $(nTh).addClass( oSettings.aoColumns[i].sClass );\r
1189                                         }\r
1190                                         \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
1193                                         {\r
1194                                                 nTh.innerHTML = oSettings.aoColumns[i].sTitle;\r
1195                                         }\r
1196                                 }\r
1197                         }\r
1198                         else\r
1199                         {\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
1202                                 \r
1203                                 for ( i=0, iLen=oSettings.aoColumns.length ; i<iLen ; i++ )\r
1204                                 {\r
1205                                         nTh = oSettings.aoColumns[i].nTh;\r
1206                                         nTh.innerHTML = oSettings.aoColumns[i].sTitle;\r
1207                                         nTh.setAttribute('tabindex', '0');\r
1208                                         \r
1209                                         if ( oSettings.aoColumns[i].sClass !== null )\r
1210                                         {\r
1211                                                 $(nTh).addClass( oSettings.aoColumns[i].sClass );\r
1212                                         }\r
1213                                         \r
1214                                         nTr.appendChild( nTh );\r
1215                                 }\r
1216                                 $(oSettings.nTHead).html( '' )[0].appendChild( nTr );\r
1217                                 _fnDetectHeader( oSettings.aoHeader, oSettings.nTHead );\r
1218                         }\r
1219                         \r
1220                         /* ARIA role for the rows */    \r
1221                         $(oSettings.nTHead).children('tr').attr('role', 'row');\r
1222                         \r
1223                         /* Add the extra markup needed by jQuery UI's themes */\r
1224                         if ( oSettings.bJUI )\r
1225                         {\r
1226                                 for ( i=0, iLen=oSettings.aoColumns.length ; i<iLen ; i++ )\r
1227                                 {\r
1228                                         nTh = oSettings.aoColumns[i].nTh;\r
1229                                         \r
1230                                         var nDiv = document.createElement('div');\r
1231                                         nDiv.className = oSettings.oClasses.sSortJUIWrapper;\r
1232                                         $(nTh).contents().appendTo(nDiv);\r
1233                                         \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
1238                                 }\r
1239                         }\r
1240                         \r
1241                         if ( oSettings.oFeatures.bSort )\r
1242                         {\r
1243                                 for ( i=0 ; i<oSettings.aoColumns.length ; i++ )\r
1244                                 {\r
1245                                         if ( oSettings.aoColumns[i].bSortable !== false )\r
1246                                         {\r
1247                                                 _fnSortAttachListener( oSettings, oSettings.aoColumns[i].nTh, i );\r
1248                                         }\r
1249                                         else\r
1250                                         {\r
1251                                                 $(oSettings.aoColumns[i].nTh).addClass( oSettings.oClasses.sSortableNone );\r
1252                                         }\r
1253                                 }\r
1254                         }\r
1255                         \r
1256                         /* Deal with the footer - add classes if required */\r
1257                         if ( oSettings.oClasses.sFooterTH !== "" )\r
1258                         {\r
1259                                 $(oSettings.nTFoot).children('tr').children('th').addClass( oSettings.oClasses.sFooterTH );\r
1260                         }\r
1261                         \r
1262                         /* Cache the footer elements */\r
1263                         if ( oSettings.nTFoot !== null )\r
1264                         {\r
1265                                 var anCells = _fnGetUniqueThs( oSettings, null, oSettings.aoFooter );\r
1266                                 for ( i=0, iLen=oSettings.aoColumns.length ; i<iLen ; i++ )\r
1267                                 {\r
1268                                         if ( anCells[i] )\r
1269                                         {\r
1270                                                 oSettings.aoColumns[i].nTf = anCells[i];\r
1271                                                 if ( oSettings.aoColumns[i].sClass )\r
1272                                                 {\r
1273                                                         $(anCells[i]).addClass( oSettings.aoColumns[i].sClass );\r
1274                                                 }\r
1275                                         }\r
1276                                 }\r
1277                         }\r
1278                 }\r
1279                 \r
1280                 \r
1281                 /**\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
1293                  */\r
1294                 function _fnDrawHead( oSettings, aoSource, bIncludeHidden )\r
1295                 {\r
1296                         var i, iLen, j, jLen, k, kLen, n, nLocalTr;\r
1297                         var aoLocal = [];\r
1298                         var aApplied = [];\r
1299                         var iColumns = oSettings.aoColumns.length;\r
1300                         var iRowspan, iColspan;\r
1301                 \r
1302                         if (  bIncludeHidden === undefined )\r
1303                         {\r
1304                                 bIncludeHidden = false;\r
1305                         }\r
1306                 \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
1309                         {\r
1310                                 aoLocal[i] = aoSource[i].slice();\r
1311                                 aoLocal[i].nTr = aoSource[i].nTr;\r
1312                 \r
1313                                 /* Remove any columns which are currently hidden */\r
1314                                 for ( j=iColumns-1 ; j>=0 ; j-- )\r
1315                                 {\r
1316                                         if ( !oSettings.aoColumns[j].bVisible && !bIncludeHidden )\r
1317                                         {\r
1318                                                 aoLocal[i].splice( j, 1 );\r
1319                                         }\r
1320                                 }\r
1321                 \r
1322                                 /* Prep the applied array - it needs an element for each row */\r
1323                                 aApplied.push( [] );\r
1324                         }\r
1325                 \r
1326                         for ( i=0, iLen=aoLocal.length ; i<iLen ; i++ )\r
1327                         {\r
1328                                 nLocalTr = aoLocal[i].nTr;\r
1329                                 \r
1330                                 /* All cells are going to be replaced, so empty out the row */\r
1331                                 if ( nLocalTr )\r
1332                                 {\r
1333                                         while( (n = nLocalTr.firstChild) )\r
1334                                         {\r
1335                                                 nLocalTr.removeChild( n );\r
1336                                         }\r
1337                                 }\r
1338                 \r
1339                                 for ( j=0, jLen=aoLocal[i].length ; j<jLen ; j++ )\r
1340                                 {\r
1341                                         iRowspan = 1;\r
1342                                         iColspan = 1;\r
1343                 \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
1346                                          */\r
1347                                         if ( aApplied[i][j] === undefined )\r
1348                                         {\r
1349                                                 nLocalTr.appendChild( aoLocal[i][j].cell );\r
1350                                                 aApplied[i][j] = 1;\r
1351                 \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
1355                                                 {\r
1356                                                         aApplied[i+iRowspan][j] = 1;\r
1357                                                         iRowspan++;\r
1358                                                 }\r
1359                 \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
1363                                                 {\r
1364                                                         /* Must update the applied array over the rows for the columns */\r
1365                                                         for ( k=0 ; k<iRowspan ; k++ )\r
1366                                                         {\r
1367                                                                 aApplied[i+k][j+iColspan] = 1;\r
1368                                                         }\r
1369                                                         iColspan++;\r
1370                                                 }\r
1371                 \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
1375                                         }\r
1376                                 }\r
1377                         }\r
1378                 }\r
1379                 \r
1380                 \r
1381                 /**\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
1385                  */\r
1386                 function _fnDraw( oSettings )\r
1387                 {\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
1391                         {\r
1392                                 _fnProcessingDisplay( oSettings, false );\r
1393                                 return;\r
1394                         }\r
1395                         \r
1396                         var i, iLen, n;\r
1397                         var anRows = [];\r
1398                         var iRowCount = 0;\r
1399                         var iStripes = oSettings.asStripeClasses.length;\r
1400                         var iOpenRows = oSettings.aoOpenRows.length;\r
1401                         \r
1402                         oSettings.bDrawing = true;\r
1403                         \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
1406                         {\r
1407                                 if ( oSettings.oFeatures.bServerSide )\r
1408                                 {\r
1409                                         oSettings._iDisplayStart = oSettings.iInitDisplayStart;\r
1410                                 }\r
1411                                 else\r
1412                                 {\r
1413                                         oSettings._iDisplayStart = (oSettings.iInitDisplayStart >= oSettings.fnRecordsDisplay()) ?\r
1414                                                 0 : oSettings.iInitDisplayStart;\r
1415                                 }\r
1416                                 oSettings.iInitDisplayStart = -1;\r
1417                                 _fnCalculateEnd( oSettings );\r
1418                         }\r
1419                         \r
1420                         /* Server-side processing draw intercept */\r
1421                         if ( oSettings.bDeferLoading )\r
1422                         {\r
1423                                 oSettings.bDeferLoading = false;\r
1424                                 oSettings.iDraw++;\r
1425                         }\r
1426                         else if ( !oSettings.oFeatures.bServerSide )\r
1427                         {\r
1428                                 oSettings.iDraw++;\r
1429                         }\r
1430                         else if ( !oSettings.bDestroying && !_fnAjaxUpdate( oSettings ) )\r
1431                         {\r
1432                                 return;\r
1433                         }\r
1434                         \r
1435                         if ( oSettings.aiDisplay.length !== 0 )\r
1436                         {\r
1437                                 var iStart = oSettings._iDisplayStart;\r
1438                                 var iEnd = oSettings._iDisplayEnd;\r
1439                                 \r
1440                                 if ( oSettings.oFeatures.bServerSide )\r
1441                                 {\r
1442                                         iStart = 0;\r
1443                                         iEnd = oSettings.aoData.length;\r
1444                                 }\r
1445                                 \r
1446                                 for ( var j=iStart ; j<iEnd ; j++ )\r
1447                                 {\r
1448                                         var aoData = oSettings.aoData[ oSettings.aiDisplay[j] ];\r
1449                                         if ( aoData.nTr === null )\r
1450                                         {\r
1451                                                 _fnCreateTr( oSettings, oSettings.aiDisplay[j] );\r
1452                                         }\r
1453                 \r
1454                                         var nRow = aoData.nTr;\r
1455                                         \r
1456                                         /* Remove the old striping classes and then add the new one */\r
1457                                         if ( iStripes !== 0 )\r
1458                                         {\r
1459                                                 var sStripe = oSettings.asStripeClasses[ iRowCount % iStripes ];\r
1460                                                 if ( aoData._sRowStripe != sStripe )\r
1461                                                 {\r
1462                                                         $(nRow).removeClass( aoData._sRowStripe ).addClass( sStripe );\r
1463                                                         aoData._sRowStripe = sStripe;\r
1464                                                 }\r
1465                                         }\r
1466                                         \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
1470                                         \r
1471                                         anRows.push( nRow );\r
1472                                         iRowCount++;\r
1473                                         \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
1476                                         {\r
1477                                                 for ( var k=0 ; k<iOpenRows ; k++ )\r
1478                                                 {\r
1479                                                         if ( nRow == oSettings.aoOpenRows[k].nParent )\r
1480                                                         {\r
1481                                                                 anRows.push( oSettings.aoOpenRows[k].nTr );\r
1482                                                                 break;\r
1483                                                         }\r
1484                                                 }\r
1485                                         }\r
1486                                 }\r
1487                         }\r
1488                         else\r
1489                         {\r
1490                                 /* Table is empty - create a row with an empty message in it */\r
1491                                 anRows[ 0 ] = document.createElement( 'tr' );\r
1492                                 \r
1493                                 if ( oSettings.asStripeClasses[0] )\r
1494                                 {\r
1495                                         anRows[ 0 ].className = oSettings.asStripeClasses[0];\r
1496                                 }\r
1497                 \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
1501                                 {\r
1502                                         sZero = oLang.sLoadingRecords;\r
1503                                 }\r
1504                                 else if ( oLang.sEmptyTable && oSettings.fnRecordsTotal() === 0 )\r
1505                                 {\r
1506                                         sZero = oLang.sEmptyTable;\r
1507                                 }\r
1508                 \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
1514                                 \r
1515                                 anRows[ iRowCount ].appendChild( nTd );\r
1516                         }\r
1517                         \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
1521                         \r
1522                         _fnCallbackFire( oSettings, 'aoFooterCallback', 'footer', [ $(oSettings.nTFoot).children('tr')[0], \r
1523                                 _fnGetDataMaster( oSettings ), oSettings._iDisplayStart, oSettings.fnDisplayEnd(), oSettings.aiDisplay ] );\r
1524                         \r
1525                         /* \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
1529                          */\r
1530                         var\r
1531                                 nAddFrag = document.createDocumentFragment(),\r
1532                                 nRemoveFrag = document.createDocumentFragment(),\r
1533                                 nBodyPar, nTrs;\r
1534                         \r
1535                         if ( oSettings.nTBody )\r
1536                         {\r
1537                                 nBodyPar = oSettings.nTBody.parentNode;\r
1538                                 nRemoveFrag.appendChild( oSettings.nTBody );\r
1539                                 \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
1542                                  */\r
1543                                 if ( !oSettings.oScroll.bInfinite || !oSettings._bInitComplete ||\r
1544                                         oSettings.bSorted || oSettings.bFiltered )\r
1545                                 {\r
1546                                         while( (n = oSettings.nTBody.firstChild) )\r
1547                                         {\r
1548                                                 oSettings.nTBody.removeChild( n );\r
1549                                         }\r
1550                                 }\r
1551                                 \r
1552                                 /* Put the draw table into the dom */\r
1553                                 for ( i=0, iLen=anRows.length ; i<iLen ; i++ )\r
1554                                 {\r
1555                                         nAddFrag.appendChild( anRows[i] );\r
1556                                 }\r
1557                                 \r
1558                                 oSettings.nTBody.appendChild( nAddFrag );\r
1559                                 if ( nBodyPar !== null )\r
1560                                 {\r
1561                                         nBodyPar.appendChild( oSettings.nTBody );\r
1562                                 }\r
1563                         }\r
1564                         \r
1565                         /* Call all required callback functions for the end of a draw */\r
1566                         _fnCallbackFire( oSettings, 'aoDrawCallback', 'draw', [oSettings] );\r
1567                         \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
1572                         \r
1573                         if ( oSettings.oFeatures.bServerSide )\r
1574                         {\r
1575                                 _fnProcessingDisplay( oSettings, false );\r
1576                                 if ( !oSettings._bInitComplete )\r
1577                                 {\r
1578                                         _fnInitComplete( oSettings );\r
1579                                 }\r
1580                         }\r
1581                 }\r
1582                 \r
1583                 \r
1584                 /**\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
1588                  */\r
1589                 function _fnReDraw( oSettings )\r
1590                 {\r
1591                         if ( oSettings.oFeatures.bSort )\r
1592                         {\r
1593                                 /* Sorting will refilter and draw for us */\r
1594                                 _fnSort( oSettings, oSettings.oPreviousSearch );\r
1595                         }\r
1596                         else if ( oSettings.oFeatures.bFilter )\r
1597                         {\r
1598                                 /* Filtering will redraw for us */\r
1599                                 _fnFilterComplete( oSettings, oSettings.oPreviousSearch );\r
1600                         }\r
1601                         else\r
1602                         {\r
1603                                 _fnCalculateEnd( oSettings );\r
1604                                 _fnDraw( oSettings );\r
1605                         }\r
1606                 }\r
1607                 \r
1608                 \r
1609                 /**\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
1613                  */\r
1614                 function _fnAddOptionsHtml ( oSettings )\r
1615                 {\r
1616                         /*\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
1619                          */\r
1620                         var nHolding = $('<div></div>')[0];\r
1621                         oSettings.nTable.parentNode.insertBefore( nHolding, oSettings.nTable );\r
1622                         \r
1623                         /* \r
1624                          * All DataTables are wrapped in a div\r
1625                          */\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
1628                 \r
1629                         /* Track where we want to insert the option */\r
1630                         var nInsertNode = oSettings.nTableWrapper;\r
1631                         \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
1636                         {\r
1637                                 iPushFeature = 0;\r
1638                                 cOption = aDom[i];\r
1639                                 \r
1640                                 if ( cOption == '<' )\r
1641                                 {\r
1642                                         /* New container div */\r
1643                                         nNewNode = $('<div></div>')[0];\r
1644                                         \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
1648                                         {\r
1649                                                 sAttr = "";\r
1650                                                 j = 2;\r
1651                                                 while ( aDom[i+j] != cNext )\r
1652                                                 {\r
1653                                                         sAttr += aDom[i+j];\r
1654                                                         j++;\r
1655                                                 }\r
1656                                                 \r
1657                                                 /* Replace jQuery UI constants */\r
1658                                                 if ( sAttr == "H" )\r
1659                                                 {\r
1660                                                         sAttr = oSettings.oClasses.sJUIHeader;\r
1661                                                 }\r
1662                                                 else if ( sAttr == "F" )\r
1663                                                 {\r
1664                                                         sAttr = oSettings.oClasses.sJUIFooter;\r
1665                                                 }\r
1666                                                 \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
1669                                                  */\r
1670                                                 if ( sAttr.indexOf('.') != -1 )\r
1671                                                 {\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
1675                                                 }\r
1676                                                 else if ( sAttr.charAt(0) == "#" )\r
1677                                                 {\r
1678                                                         nNewNode.id = sAttr.substr(1, sAttr.length-1);\r
1679                                                 }\r
1680                                                 else\r
1681                                                 {\r
1682                                                         nNewNode.className = sAttr;\r
1683                                                 }\r
1684                                                 \r
1685                                                 i += j; /* Move along the position array */\r
1686                                         }\r
1687                                         \r
1688                                         nInsertNode.appendChild( nNewNode );\r
1689                                         nInsertNode = nNewNode;\r
1690                                 }\r
1691                                 else if ( cOption == '>' )\r
1692                                 {\r
1693                                         /* End container div */\r
1694                                         nInsertNode = nInsertNode.parentNode;\r
1695                                 }\r
1696                                 else if ( cOption == 'l' && oSettings.oFeatures.bPaginate && oSettings.oFeatures.bLengthChange )\r
1697                                 {\r
1698                                         /* Length */\r
1699                                         nTmp = _fnFeatureHtmlLength( oSettings );\r
1700                                         iPushFeature = 1;\r
1701                                 }\r
1702                                 else if ( cOption == 'f' && oSettings.oFeatures.bFilter )\r
1703                                 {\r
1704                                         /* Filter */\r
1705                                         nTmp = _fnFeatureHtmlFilter( oSettings );\r
1706                                         iPushFeature = 1;\r
1707                                 }\r
1708                                 else if ( cOption == 'r' && oSettings.oFeatures.bProcessing )\r
1709                                 {\r
1710                                         /* pRocessing */\r
1711                                         nTmp = _fnFeatureHtmlProcessing( oSettings );\r
1712                                         iPushFeature = 1;\r
1713                                 }\r
1714                                 else if ( cOption == 't' )\r
1715                                 {\r
1716                                         /* Table */\r
1717                                         nTmp = _fnFeatureHtmlTable( oSettings );\r
1718                                         iPushFeature = 1;\r
1719                                 }\r
1720                                 else if ( cOption ==  'i' && oSettings.oFeatures.bInfo )\r
1721                                 {\r
1722                                         /* Info */\r
1723                                         nTmp = _fnFeatureHtmlInfo( oSettings );\r
1724                                         iPushFeature = 1;\r
1725                                 }\r
1726                                 else if ( cOption == 'p' && oSettings.oFeatures.bPaginate )\r
1727                                 {\r
1728                                         /* Pagination */\r
1729                                         nTmp = _fnFeatureHtmlPaginate( oSettings );\r
1730                                         iPushFeature = 1;\r
1731                                 }\r
1732                                 else if ( DataTable.ext.aoFeatures.length !== 0 )\r
1733                                 {\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
1737                                         {\r
1738                                                 if ( cOption == aoFeatures[k].cFeature )\r
1739                                                 {\r
1740                                                         nTmp = aoFeatures[k].fnInit( oSettings );\r
1741                                                         if ( nTmp )\r
1742                                                         {\r
1743                                                                 iPushFeature = 1;\r
1744                                                         }\r
1745                                                         break;\r
1746                                                 }\r
1747                                         }\r
1748                                 }\r
1749                                 \r
1750                                 /* Add to the 2D features array */\r
1751                                 if ( iPushFeature == 1 && nTmp !== null )\r
1752                                 {\r
1753                                         if ( typeof oSettings.aanFeatures[cOption] !== 'object' )\r
1754                                         {\r
1755                                                 oSettings.aanFeatures[cOption] = [];\r
1756                                         }\r
1757                                         oSettings.aanFeatures[cOption].push( nTmp );\r
1758                                         nInsertNode.appendChild( nTmp );\r
1759                                 }\r
1760                         }\r
1761                         \r
1762                         /* Built our DOM structure - replace the holding div with what we want */\r
1763                         nHolding.parentNode.replaceChild( oSettings.nTableWrapper, nHolding );\r
1764                 }\r
1765                 \r
1766                 \r
1767                 /**\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
1775                  */\r
1776                 function _fnDetectHeader ( aLayout, nThead )\r
1777                 {\r
1778                         var nTrs = $(nThead).children('tr');\r
1779                         var nTr, nCell;\r
1780                         var i, k, l, iLen, jLen, iColShifted, iColumn, iColspan, iRowspan;\r
1781                         var bUnique;\r
1782                         var fnShiftCol = function ( a, i, j ) {\r
1783                                 var k = a[i];\r
1784                                 while ( k[j] ) {\r
1785                                         j++;\r
1786                                 }\r
1787                                 return j;\r
1788                         };\r
1789                 \r
1790                         aLayout.splice( 0, aLayout.length );\r
1791                         \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
1794                         {\r
1795                                 aLayout.push( [] );\r
1796                         }\r
1797                         \r
1798                         /* Calculate a layout array */\r
1799                         for ( i=0, iLen=nTrs.length ; i<iLen ; i++ )\r
1800                         {\r
1801                                 nTr = nTrs[i];\r
1802                                 iColumn = 0;\r
1803                                 \r
1804                                 /* For every cell in the row... */\r
1805                                 nCell = nTr.firstChild;\r
1806                                 while ( nCell ) {\r
1807                                         if ( nCell.nodeName.toUpperCase() == "TD" ||\r
1808                                              nCell.nodeName.toUpperCase() == "TH" )\r
1809                                         {\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
1815                 \r
1816                                                 /* There might be colspan cells already in this row, so shift our target \r
1817                                                  * accordingly\r
1818                                                  */\r
1819                                                 iColShifted = fnShiftCol( aLayout, i, iColumn );\r
1820                                                 \r
1821                                                 /* Cache calculation for unique columns */\r
1822                                                 bUnique = iColspan === 1 ? true : false;\r
1823                                                 \r
1824                                                 /* If there is col / rowspan, copy the information into the layout grid */\r
1825                                                 for ( l=0 ; l<iColspan ; l++ )\r
1826                                                 {\r
1827                                                         for ( k=0 ; k<iRowspan ; k++ )\r
1828                                                         {\r
1829                                                                 aLayout[i+k][iColShifted+l] = {\r
1830                                                                         "cell": nCell,\r
1831                                                                         "unique": bUnique\r
1832                                                                 };\r
1833                                                                 aLayout[i+k].nTr = nTr;\r
1834                                                         }\r
1835                                                 }\r
1836                                         }\r
1837                                         nCell = nCell.nextSibling;\r
1838                                 }\r
1839                         }\r
1840                 }\r
1841                 \r
1842                 \r
1843                 /**\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
1850                  */\r
1851                 function _fnGetUniqueThs ( oSettings, nHeader, aLayout )\r
1852                 {\r
1853                         var aReturn = [];\r
1854                         if ( !aLayout )\r
1855                         {\r
1856                                 aLayout = oSettings.aoHeader;\r
1857                                 if ( nHeader )\r
1858                                 {\r
1859                                         aLayout = [];\r
1860                                         _fnDetectHeader( aLayout, nHeader );\r
1861                                 }\r
1862                         }\r
1863                 \r
1864                         for ( var i=0, iLen=aLayout.length ; i<iLen ; i++ )\r
1865                         {\r
1866                                 for ( var j=0, jLen=aLayout[i].length ; j<jLen ; j++ )\r
1867                                 {\r
1868                                         if ( aLayout[i][j].unique && \r
1869                                                  (!aReturn[j] || !oSettings.bSortCellsTop) )\r
1870                                         {\r
1871                                                 aReturn[j] = aLayout[i][j].cell;\r
1872                                         }\r
1873                                 }\r
1874                         }\r
1875                         \r
1876                         return aReturn;\r
1877                 }\r
1878                 \r
1879                 \r
1880                 \r
1881                 /**\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
1886                  */\r
1887                 function _fnAjaxUpdate( oSettings )\r
1888                 {\r
1889                         if ( oSettings.bAjaxDataGet )\r
1890                         {\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
1896                                 \r
1897                                 oSettings.fnServerData.call( oSettings.oInstance, oSettings.sAjaxSource, aoData,\r
1898                                         function(json) {\r
1899                                                 _fnAjaxUpdateDraw( oSettings, json );\r
1900                                         }, oSettings );\r
1901                                 return false;\r
1902                         }\r
1903                         else\r
1904                         {\r
1905                                 return true;\r
1906                         }\r
1907                 }\r
1908                 \r
1909                 \r
1910                 /**\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
1915                  */\r
1916                 function _fnAjaxParameters( oSettings )\r
1917                 {\r
1918                         var iColumns = oSettings.aoColumns.length;\r
1919                         var aoData = [], mDataProp, aaSort, aDataSort;\r
1920                         var i, j;\r
1921                         \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
1928                                 \r
1929                         for ( i=0 ; i<iColumns ; i++ )\r
1930                         {\r
1931                           mDataProp = oSettings.aoColumns[i].mData;\r
1932                                 aoData.push( { "name": "mDataProp_"+i, "value": typeof(mDataProp)==="function" ? 'function' : mDataProp } );\r
1933                         }\r
1934                         \r
1935                         /* Filtering */\r
1936                         if ( oSettings.oFeatures.bFilter !== false )\r
1937                         {\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
1941                                 {\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
1945                                 }\r
1946                         }\r
1947                         \r
1948                         /* Sorting */\r
1949                         if ( oSettings.oFeatures.bSort !== false )\r
1950                         {\r
1951                                 var iCounter = 0;\r
1952                 \r
1953                                 aaSort = ( oSettings.aaSortingFixed !== null ) ?\r
1954                                         oSettings.aaSortingFixed.concat( oSettings.aaSorting ) :\r
1955                                         oSettings.aaSorting.slice();\r
1956                                 \r
1957                                 for ( i=0 ; i<aaSort.length ; i++ )\r
1958                                 {\r
1959                                         aDataSort = oSettings.aoColumns[ aaSort[i][0] ].aDataSort;\r
1960                                         \r
1961                                         for ( j=0 ; j<aDataSort.length ; j++ )\r
1962                                         {\r
1963                                                 aoData.push( { "name": "iSortCol_"+iCounter,  "value": aDataSort[j] } );\r
1964                                                 aoData.push( { "name": "sSortDir_"+iCounter,  "value": aaSort[i][1] } );\r
1965                                                 iCounter++;\r
1966                                         }\r
1967                                 }\r
1968                                 aoData.push( { "name": "iSortingCols",   "value": iCounter } );\r
1969                                 \r
1970                                 for ( i=0 ; i<iColumns ; i++ )\r
1971                                 {\r
1972                                         aoData.push( { "name": "bSortable_"+i,  "value": oSettings.aoColumns[i].bSortable } );\r
1973                                 }\r
1974                         }\r
1975                         \r
1976                         return aoData;\r
1977                 }\r
1978                 \r
1979                 \r
1980                 /**\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
1985                  */\r
1986                 function _fnServerParams( oSettings, aoData )\r
1987                 {\r
1988                         _fnCallbackFire( oSettings, 'aoServerParams', 'serverParams', [aoData] );\r
1989                 }\r
1990                 \r
1991                 \r
1992                 /**\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
2002                  */\r
2003                 function _fnAjaxUpdateDraw ( oSettings, json )\r
2004                 {\r
2005                         if ( json.sEcho !== undefined )\r
2006                         {\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
2009                                  */\r
2010                                 if ( json.sEcho*1 < oSettings.iDraw )\r
2011                                 {\r
2012                                         return;\r
2013                                 }\r
2014                                 else\r
2015                                 {\r
2016                                         oSettings.iDraw = json.sEcho * 1;\r
2017                                 }\r
2018                         }\r
2019                         \r
2020                         if ( !oSettings.oScroll.bInfinite ||\r
2021                                    (oSettings.oScroll.bInfinite && (oSettings.bSorted || oSettings.bFiltered)) )\r
2022                         {\r
2023                                 _fnClearTable( oSettings );\r
2024                         }\r
2025                         oSettings._iRecordsTotal = parseInt(json.iTotalRecords, 10);\r
2026                         oSettings._iRecordsDisplay = parseInt(json.iTotalDisplayRecords, 10);\r
2027                         \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
2031                         var aiIndex;\r
2032                         if ( bReOrder )\r
2033                         {\r
2034                                 aiIndex = _fnReOrderIndex( oSettings, json.sColumns );\r
2035                         }\r
2036                         \r
2037                         var aData = _fnGetObjectDataFn( oSettings.sAjaxDataProp )( json );\r
2038                         for ( var i=0, iLen=aData.length ; i<iLen ; i++ )\r
2039                         {\r
2040                                 if ( bReOrder )\r
2041                                 {\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
2045                                         {\r
2046                                                 aDataSorted.push( aData[i][ aiIndex[j] ] );\r
2047                                         }\r
2048                                         _fnAddData( oSettings, aDataSorted );\r
2049                                 }\r
2050                                 else\r
2051                                 {\r
2052                                         /* No re-order required, sever got it "right" - just straight add */\r
2053                                         _fnAddData( oSettings, aData[i] );\r
2054                                 }\r
2055                         }\r
2056                         oSettings.aiDisplay = oSettings.aiDisplayMaster.slice();\r
2057                         \r
2058                         oSettings.bAjaxDataGet = false;\r
2059                         _fnDraw( oSettings );\r
2060                         oSettings.bAjaxDataGet = true;\r
2061                         _fnProcessingDisplay( oSettings, false );\r
2062                 }\r
2063                 \r
2064                 \r
2065                 \r
2066                 /**\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
2071                  */\r
2072                 function _fnFeatureHtmlFilter ( oSettings )\r
2073                 {\r
2074                         var oPreviousSearch = oSettings.oPreviousSearch;\r
2075                         \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
2080                         \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
2085                         {\r
2086                                 nFilter.id = oSettings.sTableId+'_filter';\r
2087                         }\r
2088                         \r
2089                         var jqFilter = $('input[type="text"]', nFilter);\r
2090                 \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
2094                 \r
2095                         jqFilter.val( oPreviousSearch.sSearch.replace('"','&quot;') );\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
2100                 \r
2101                                 for ( var i=0, iLen=n.length ; i<iLen ; i++ )\r
2102                                 {\r
2103                                         if ( n[i] != $(this).parents('div.dataTables_filter')[0] )\r
2104                                         {\r
2105                                                 $(n[i]._DT_Input).val( val );\r
2106                                         }\r
2107                                 }\r
2108                                 \r
2109                                 /* Now do the filter */\r
2110                                 if ( val != oPreviousSearch.sSearch )\r
2111                                 {\r
2112                                         _fnFilterComplete( oSettings, { \r
2113                                                 "sSearch": val, \r
2114                                                 "bRegex": oPreviousSearch.bRegex,\r
2115                                                 "bSmart": oPreviousSearch.bSmart ,\r
2116                                                 "bCaseInsensitive": oPreviousSearch.bCaseInsensitive \r
2117                                         } );\r
2118                                 }\r
2119                         } );\r
2120                 \r
2121                         jqFilter\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
2126                                         {\r
2127                                                 return false;\r
2128                                         }\r
2129                                 }\r
2130                         );\r
2131                         \r
2132                         return nFilter;\r
2133                 }\r
2134                 \r
2135                 \r
2136                 /**\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
2142                  */\r
2143                 function _fnFilterComplete ( oSettings, oInput, iForce )\r
2144                 {\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
2153                         };\r
2154                 \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
2157                         {\r
2158                                 /* Global filter */\r
2159                                 _fnFilter( oSettings, oInput.sSearch, iForce, oInput.bRegex, oInput.bSmart, oInput.bCaseInsensitive );\r
2160                                 fnSaveFilter( oInput );\r
2161                 \r
2162                                 /* Now do the individual column filter */\r
2163                                 for ( var i=0 ; i<oSettings.aoPreSearchCols.length ; i++ )\r
2164                                 {\r
2165                                         _fnFilterColumn( oSettings, aoPrevSearch[i].sSearch, i, aoPrevSearch[i].bRegex, \r
2166                                                 aoPrevSearch[i].bSmart, aoPrevSearch[i].bCaseInsensitive );\r
2167                                 }\r
2168                                 \r
2169                                 /* Custom filtering */\r
2170                                 _fnFilterCustom( oSettings );\r
2171                         }\r
2172                         else\r
2173                         {\r
2174                                 fnSaveFilter( oInput );\r
2175                         }\r
2176                         \r
2177                         /* Tell the draw function we have been filtering */\r
2178                         oSettings.bFiltered = true;\r
2179                         $(oSettings.oInstance).trigger('filter', oSettings);\r
2180                         \r
2181                         /* Redraw the table */\r
2182                         oSettings._iDisplayStart = 0;\r
2183                         _fnCalculateEnd( oSettings );\r
2184                         _fnDraw( oSettings );\r
2185                         \r
2186                         /* Rebuild search array 'offline' */\r
2187                         _fnBuildSearchArray( oSettings, 0 );\r
2188                 }\r
2189                 \r
2190                 \r
2191                 /**\r
2192                  * Apply custom filtering functions\r
2193                  *  @param {object} oSettings dataTables settings object\r
2194                  *  @memberof DataTable#oApi\r
2195                  */\r
2196                 function _fnFilterCustom( oSettings )\r
2197                 {\r
2198                         var afnFilters = DataTable.ext.afnFiltering;\r
2199                         var aiFilterColumns = _fnGetColumns( oSettings, 'bSearchable' );\r
2200                 \r
2201                         for ( var i=0, iLen=afnFilters.length ; i<iLen ; i++ )\r
2202                         {\r
2203                                 var iCorrector = 0;\r
2204                                 for ( var j=0, jLen=oSettings.aiDisplay.length ; j<jLen ; j++ )\r
2205                                 {\r
2206                                         var iDisIndex = oSettings.aiDisplay[j-iCorrector];\r
2207                                         var bTest = afnFilters[i](\r
2208                                                 oSettings,\r
2209                                                 _fnGetRowData( oSettings, iDisIndex, 'filter', aiFilterColumns ),\r
2210                                                 iDisIndex\r
2211                                         );\r
2212                                         \r
2213                                         /* Check if we should use this row based on the filtering function */\r
2214                                         if ( !bTest )\r
2215                                         {\r
2216                                                 oSettings.aiDisplay.splice( j-iCorrector, 1 );\r
2217                                                 iCorrector++;\r
2218                                         }\r
2219                                 }\r
2220                         }\r
2221                 }\r
2222                 \r
2223                 \r
2224                 /**\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
2233                  */\r
2234                 function _fnFilterColumn ( oSettings, sInput, iColumn, bRegex, bSmart, bCaseInsensitive )\r
2235                 {\r
2236                         if ( sInput === "" )\r
2237                         {\r
2238                                 return;\r
2239                         }\r
2240                         \r
2241                         var iIndexCorrector = 0;\r
2242                         var rpSearch = _fnFilterCreateSearch( sInput, bRegex, bSmart, bCaseInsensitive );\r
2243                         \r
2244                         for ( var i=oSettings.aiDisplay.length-1 ; i>=0 ; i-- )\r
2245                         {\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
2249                                 {\r
2250                                         oSettings.aiDisplay.splice( i, 1 );\r
2251                                         iIndexCorrector++;\r
2252                                 }\r
2253                         }\r
2254                 }\r
2255                 \r
2256                 \r
2257                 /**\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
2266                  */\r
2267                 function _fnFilter( oSettings, sInput, iForce, bRegex, bSmart, bCaseInsensitive )\r
2268                 {\r
2269                         var i;\r
2270                         var rpSearch = _fnFilterCreateSearch( sInput, bRegex, bSmart, bCaseInsensitive );\r
2271                         var oPrevSearch = oSettings.oPreviousSearch;\r
2272                         \r
2273                         /* Check if we are forcing or not - optional parameter */\r
2274                         if ( !iForce )\r
2275                         {\r
2276                                 iForce = 0;\r
2277                         }\r
2278                         \r
2279                         /* Need to take account of custom filtering functions - always filter */\r
2280                         if ( DataTable.ext.afnFiltering.length !== 0 )\r
2281                         {\r
2282                                 iForce = 1;\r
2283                         }\r
2284                         \r
2285                         /*\r
2286                          * If the input is blank - we want the full data set\r
2287                          */\r
2288                         if ( sInput.length <= 0 )\r
2289                         {\r
2290                                 oSettings.aiDisplay.splice( 0, oSettings.aiDisplay.length);\r
2291                                 oSettings.aiDisplay = oSettings.aiDisplayMaster.slice();\r
2292                         }\r
2293                         else\r
2294                         {\r
2295                                 /*\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
2298                                  */\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
2302                                 {\r
2303                                         /* Nuke the old display array - we are going to rebuild it */\r
2304                                         oSettings.aiDisplay.splice( 0, oSettings.aiDisplay.length);\r
2305                                         \r
2306                                         /* Force a rebuild of the search array */\r
2307                                         _fnBuildSearchArray( oSettings, 1 );\r
2308                                         \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
2311                                          * mapping\r
2312                                          */\r
2313                                         for ( i=0 ; i<oSettings.aiDisplayMaster.length ; i++ )\r
2314                                         {\r
2315                                                 if ( rpSearch.test(oSettings.asDataSearch[i]) )\r
2316                                                 {\r
2317                                                         oSettings.aiDisplay.push( oSettings.aiDisplayMaster[i] );\r
2318                                                 }\r
2319                                         }\r
2320                           }\r
2321                           else\r
2322                                 {\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
2325                                          */\r
2326                                 var iIndexCorrector = 0;\r
2327                                 \r
2328                                 /* Search the current results */\r
2329                                 for ( i=0 ; i<oSettings.asDataSearch.length ; i++ )\r
2330                                         {\r
2331                                         if ( ! rpSearch.test(oSettings.asDataSearch[i]) )\r
2332                                                 {\r
2333                                                 oSettings.aiDisplay.splice( i-iIndexCorrector, 1 );\r
2334                                                 iIndexCorrector++;\r
2335                                         }\r
2336                                 }\r
2337                           }\r
2338                         }\r
2339                 }\r
2340                 \r
2341                 \r
2342                 /**\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
2347                  */\r
2348                 function _fnBuildSearchArray ( oSettings, iMaster )\r
2349                 {\r
2350                         if ( !oSettings.oFeatures.bServerSide )\r
2351                         {\r
2352                                 /* Clear out the old data */\r
2353                                 oSettings.asDataSearch = [];\r
2354                 \r
2355                                 var aiFilterColumns = _fnGetColumns( oSettings, 'bSearchable' );\r
2356                                 var aiIndex = (iMaster===1) ?\r
2357                                         oSettings.aiDisplayMaster :\r
2358                                         oSettings.aiDisplay;\r
2359                                 \r
2360                                 for ( var i=0, iLen=aiIndex.length ; i<iLen ; i++ )\r
2361                                 {\r
2362                                         oSettings.asDataSearch[i] = _fnBuildSearchRow(\r
2363                                                 oSettings,\r
2364                                                 _fnGetRowData( oSettings, aiIndex[i], 'filter', aiFilterColumns )\r
2365                                         );\r
2366                                 }\r
2367                         }\r
2368                 }\r
2369                 \r
2370                 \r
2371                 /**\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
2376                  */\r
2377                 function _fnBuildSearchRow( oSettings, aData )\r
2378                 {\r
2379                         var sSearch = aData.join('  ');\r
2380                         \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
2383                         {\r
2384                                 sSearch = $('<div>').html(sSearch).text();\r
2385                         }\r
2386                         \r
2387                         // Strip newline characters\r
2388                         return sSearch.replace( /[\n\r]/g, " " );\r
2389                 }\r
2390                 \r
2391                 /**\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
2399                  */\r
2400                 function _fnFilterCreateSearch( sSearch, bRegex, bSmart, bCaseInsensitive )\r
2401                 {\r
2402                         var asSearch, sRegExpString;\r
2403                         \r
2404                         if ( bSmart )\r
2405                         {\r
2406                                 /* Generate the regular expression to use. Something along the lines of:\r
2407                                  * ^(?=.*?\bone\b)(?=.*?\btwo\b)(?=.*?\bthree\b).*$\r
2408                                  */\r
2409                                 asSearch = bRegex ? sSearch.split( ' ' ) : _fnEscapeRegex( sSearch ).split( ' ' );\r
2410                                 sRegExpString = '^(?=.*?'+asSearch.join( ')(?=.*?' )+').*$';\r
2411                                 return new RegExp( sRegExpString, bCaseInsensitive ? "i" : "" );\r
2412                         }\r
2413                         else\r
2414                         {\r
2415                                 sSearch = bRegex ? sSearch : _fnEscapeRegex( sSearch );\r
2416                                 return new RegExp( sSearch, bCaseInsensitive ? "i" : "" );\r
2417                         }\r
2418                 }\r
2419                 \r
2420                 \r
2421                 /**\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
2427                  */\r
2428                 function _fnDataToSearch ( sData, sType )\r
2429                 {\r
2430                         if ( typeof DataTable.ext.ofnSearch[sType] === "function" )\r
2431                         {\r
2432                                 return DataTable.ext.ofnSearch[sType]( sData );\r
2433                         }\r
2434                         else if ( sData === null )\r
2435                         {\r
2436                                 return '';\r
2437                         }\r
2438                         else if ( sType == "html" )\r
2439                         {\r
2440                                 return sData.replace(/[\r\n]/g," ").replace( /<.*?>/g, "" );\r
2441                         }\r
2442                         else if ( typeof sData === "string" )\r
2443                         {\r
2444                                 return sData.replace(/[\r\n]/g," ");\r
2445                         }\r
2446                         return sData;\r
2447                 }\r
2448                 \r
2449                 \r
2450                 /**\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
2455                  */\r
2456                 function _fnEscapeRegex ( sVal )\r
2457                 {\r
2458                         var acEscape = [ '/', '.', '*', '+', '?', '|', '(', ')', '[', ']', '{', '}', '\\', '$', '^', '-' ];\r
2459                         var reReplace = new RegExp( '(\\' + acEscape.join('|\\') + ')', 'g' );\r
2460                         return sVal.replace(reReplace, '\\$1');\r
2461                 }\r
2462                 \r
2463                 \r
2464                 /**\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
2469                  */\r
2470                 function _fnFeatureHtmlInfo ( oSettings )\r
2471                 {\r
2472                         var nInfo = document.createElement( 'div' );\r
2473                         nInfo.className = oSettings.oClasses.sInfo;\r
2474                         \r
2475                         /* Actions that are to be taken once only for this feature */\r
2476                         if ( !oSettings.aanFeatures.i )\r
2477                         {\r
2478                                 /* Add draw callback */\r
2479                                 oSettings.aoDrawCallback.push( {\r
2480                                         "fn": _fnUpdateInfo,\r
2481                                         "sName": "information"\r
2482                                 } );\r
2483                                 \r
2484                                 /* Add id */\r
2485                                 nInfo.id = oSettings.sTableId+'_info';\r
2486                         }\r
2487                         oSettings.nTable.setAttribute( 'aria-describedby', oSettings.sTableId+'_info' );\r
2488                         \r
2489                         return nInfo;\r
2490                 }\r
2491                 \r
2492                 \r
2493                 /**\r
2494                  * Update the information elements in the display\r
2495                  *  @param {object} oSettings dataTables settings object\r
2496                  *  @memberof DataTable#oApi\r
2497                  */\r
2498                 function _fnUpdateInfo ( oSettings )\r
2499                 {\r
2500                         /* Show information about the table */\r
2501                         if ( !oSettings.oFeatures.bInfo || oSettings.aanFeatures.i.length === 0 )\r
2502                         {\r
2503                                 return;\r
2504                         }\r
2505                         \r
2506                         var\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
2512                                 sOut;\r
2513                         \r
2514                         if ( iTotal === 0 )\r
2515                         {\r
2516                                 /* Empty record set */\r
2517                                 sOut = oLang.sInfoEmpty;\r
2518                         }\r
2519                         else {\r
2520                                 /* Normal record set */\r
2521                                 sOut = oLang.sInfo;\r
2522                         }\r
2523                 \r
2524                         if ( iTotal != iMax )\r
2525                         {\r
2526                                 /* Record set after filtering */\r
2527                                 sOut += ' ' + oLang.sInfoFiltered;\r
2528                         }\r
2529                 \r
2530                         // Convert the macros\r
2531                         sOut += oLang.sInfoPostFix;\r
2532                         sOut = _fnInfoMacros( oSettings, sOut );\r
2533                         \r
2534                         if ( oLang.fnInfoCallback !== null )\r
2535                         {\r
2536                                 sOut = oLang.fnInfoCallback.call( oSettings.oInstance, \r
2537                                         oSettings, iStart, iEnd, iMax, iTotal, sOut );\r
2538                         }\r
2539                         \r
2540                         var n = oSettings.aanFeatures.i;\r
2541                         for ( var i=0, iLen=n.length ; i<iLen ; i++ )\r
2542                         {\r
2543                                 $(n[i]).html( sOut );\r
2544                         }\r
2545                 }\r
2546                 \r
2547                 \r
2548                 function _fnInfoMacros ( oSettings, str )\r
2549                 {\r
2550                         var\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
2559                 \r
2560                         // When infinite scrolling, we are always starting at 1. _iDisplayStart is used only\r
2561                         // internally\r
2562                         if ( oSettings.oScroll.bInfinite )\r
2563                         {\r
2564                                 sStart = oSettings.fnFormatNumber( 1 );\r
2565                         }\r
2566                 \r
2567                         return str.\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
2572                 }\r
2573                 \r
2574                 \r
2575                 \r
2576                 /**\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
2580                  */\r
2581                 function _fnInitialise ( oSettings )\r
2582                 {\r
2583                         var i, iLen, iAjaxStart=oSettings.iInitDisplayStart;\r
2584                         \r
2585                         /* Ensure that the table data is fully initialised */\r
2586                         if ( oSettings.bInitialised === false )\r
2587                         {\r
2588                                 setTimeout( function(){ _fnInitialise( oSettings ); }, 200 );\r
2589                                 return;\r
2590                         }\r
2591                         \r
2592                         /* Show the display HTML options */\r
2593                         _fnAddOptionsHtml( oSettings );\r
2594                         \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
2599                         {\r
2600                                 _fnDrawHead( oSettings, oSettings.aoFooter );\r
2601                         }\r
2602                 \r
2603                         /* Okay to show that something is going on now */\r
2604                         _fnProcessingDisplay( oSettings, true );\r
2605                         \r
2606                         /* Calculate sizes for columns */\r
2607                         if ( oSettings.oFeatures.bAutoWidth )\r
2608                         {\r
2609                                 _fnCalculateColumnWidths( oSettings );\r
2610                         }\r
2611                         \r
2612                         for ( i=0, iLen=oSettings.aoColumns.length ; i<iLen ; i++ )\r
2613                         {\r
2614                                 if ( oSettings.aoColumns[i].sWidth !== null )\r
2615                                 {\r
2616                                         oSettings.aoColumns[i].nTh.style.width = _fnStringToCss( oSettings.aoColumns[i].sWidth );\r
2617                                 }\r
2618                         }\r
2619                         \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
2623                          */\r
2624                         if ( oSettings.oFeatures.bSort )\r
2625                         {\r
2626                                 _fnSort( oSettings );\r
2627                         }\r
2628                         else if ( oSettings.oFeatures.bFilter )\r
2629                         {\r
2630                                 _fnFilterComplete( oSettings, oSettings.oPreviousSearch );\r
2631                         }\r
2632                         else\r
2633                         {\r
2634                                 oSettings.aiDisplay = oSettings.aiDisplayMaster.slice();\r
2635                                 _fnCalculateEnd( oSettings );\r
2636                                 _fnDraw( oSettings );\r
2637                         }\r
2638                         \r
2639                         /* if there is an ajax source load the data */\r
2640                         if ( oSettings.sAjaxSource !== null && !oSettings.oFeatures.bServerSide )\r
2641                         {\r
2642                                 var aoData = [];\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
2647                 \r
2648                                         /* Got the data - add it to the table */\r
2649                                         for ( i=0 ; i<aData.length ; i++ )\r
2650                                         {\r
2651                                                 _fnAddData( oSettings, aData[i] );\r
2652                                         }\r
2653                                         \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
2656                                          */\r
2657                                         oSettings.iInitDisplayStart = iAjaxStart;\r
2658                                         \r
2659                                         if ( oSettings.oFeatures.bSort )\r
2660                                         {\r
2661                                                 _fnSort( oSettings );\r
2662                                         }\r
2663                                         else\r
2664                                         {\r
2665                                                 oSettings.aiDisplay = oSettings.aiDisplayMaster.slice();\r
2666                                                 _fnCalculateEnd( oSettings );\r
2667                                                 _fnDraw( oSettings );\r
2668                                         }\r
2669                                         \r
2670                                         _fnProcessingDisplay( oSettings, false );\r
2671                                         _fnInitComplete( oSettings, json );\r
2672                                 }, oSettings );\r
2673                                 return;\r
2674                         }\r
2675                         \r
2676                         /* Server-side processing initialisation complete is done at the end of _fnDraw */\r
2677                         if ( !oSettings.oFeatures.bServerSide )\r
2678                         {\r
2679                                 _fnProcessingDisplay( oSettings, false );\r
2680                                 _fnInitComplete( oSettings );\r
2681                         }\r
2682                 }\r
2683                 \r
2684                 \r
2685                 /**\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
2691                  */\r
2692                 function _fnInitComplete ( oSettings, json )\r
2693                 {\r
2694                         oSettings._bInitComplete = true;\r
2695                         _fnCallbackFire( oSettings, 'aoInitComplete', 'init', [oSettings, json] );\r
2696                 }\r
2697                 \r
2698                 \r
2699                 /**\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
2705                  */\r
2706                 function _fnLanguageCompat( oLanguage )\r
2707                 {\r
2708                         var oDefaults = DataTable.defaults.oLanguage;\r
2709                 \r
2710                         /* Backwards compatibility - if there is no sEmptyTable given, then use the same as\r
2711                          * sZeroRecords - assuming that is given.\r
2712                          */\r
2713                         if ( !oLanguage.sEmptyTable && oLanguage.sZeroRecords &&\r
2714                                 oDefaults.sEmptyTable === "No data available in table" )\r
2715                         {\r
2716                                 _fnMap( oLanguage, oLanguage, 'sZeroRecords', 'sEmptyTable' );\r
2717                         }\r
2718                 \r
2719                         /* Likewise with loading records */\r
2720                         if ( !oLanguage.sLoadingRecords && oLanguage.sZeroRecords &&\r
2721                                 oDefaults.sLoadingRecords === "Loading..." )\r
2722                         {\r
2723                                 _fnMap( oLanguage, oLanguage, 'sZeroRecords', 'sLoadingRecords' );\r
2724                         }\r
2725                 }\r
2726                 \r
2727                 \r
2728                 \r
2729                 /**\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
2734                  */\r
2735                 function _fnFeatureHtmlLength ( oSettings )\r
2736                 {\r
2737                         if ( oSettings.oScroll.bInfinite )\r
2738                         {\r
2739                                 return null;\r
2740                         }\r
2741                         \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
2745                         var i, iLen;\r
2746                         var aLengthMenu = oSettings.aLengthMenu;\r
2747                         \r
2748                         if ( aLengthMenu.length == 2 && typeof aLengthMenu[0] === 'object' && \r
2749                                         typeof aLengthMenu[1] === 'object' )\r
2750                         {\r
2751                                 for ( i=0, iLen=aLengthMenu[0].length ; i<iLen ; i++ )\r
2752                                 {\r
2753                                         sStdMenu += '<option value="'+aLengthMenu[0][i]+'">'+aLengthMenu[1][i]+'</option>';\r
2754                                 }\r
2755                         }\r
2756                         else\r
2757                         {\r
2758                                 for ( i=0, iLen=aLengthMenu.length ; i<iLen ; i++ )\r
2759                                 {\r
2760                                         sStdMenu += '<option value="'+aLengthMenu[i]+'">'+aLengthMenu[i]+'</option>';\r
2761                                 }\r
2762                         }\r
2763                         sStdMenu += '</select>';\r
2764                         \r
2765                         var nLength = document.createElement( 'div' );\r
2766                         if ( !oSettings.aanFeatures.l )\r
2767                         {\r
2768                                 nLength.id = oSettings.sTableId+'_length';\r
2769                         }\r
2770                         nLength.className = oSettings.oClasses.sLength;\r
2771                         nLength.innerHTML = '<label>'+oSettings.oLanguage.sLengthMenu.replace( '_MENU_', sStdMenu )+'</label>';\r
2772                         \r
2773                         /*\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
2776                          */\r
2777                         $('select option[value="'+oSettings._iDisplayLength+'"]', nLength).attr("selected", true);\r
2778                         \r
2779                         $('select', nLength).bind( 'change.DT', function(e) {\r
2780                                 var iVal = $(this).val();\r
2781                                 \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
2785                                 {\r
2786                                         if ( n[i] != this.parentNode )\r
2787                                         {\r
2788                                                 $('select', n[i]).val( iVal );\r
2789                                         }\r
2790                                 }\r
2791                                 \r
2792                                 /* Redraw the table */\r
2793                                 oSettings._iDisplayLength = parseInt(iVal, 10);\r
2794                                 _fnCalculateEnd( oSettings );\r
2795                                 \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
2798                                 {\r
2799                                         oSettings._iDisplayStart = oSettings.fnDisplayEnd() - oSettings._iDisplayLength;\r
2800                                         if ( oSettings._iDisplayStart < 0 )\r
2801                                         {\r
2802                                                 oSettings._iDisplayStart = 0;\r
2803                                         }\r
2804                                 }\r
2805                                 \r
2806                                 if ( oSettings._iDisplayLength == -1 )\r
2807                                 {\r
2808                                         oSettings._iDisplayStart = 0;\r
2809                                 }\r
2810                                 \r
2811                                 _fnDraw( oSettings );\r
2812                         } );\r
2813                 \r
2814                 \r
2815                         $('select', nLength).attr('aria-controls', oSettings.sTableId);\r
2816                         \r
2817                         return nLength;\r
2818                 }\r
2819                 \r
2820                 \r
2821                 /**\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
2825                  */\r
2826                 function _fnCalculateEnd( oSettings )\r
2827                 {\r
2828                         if ( oSettings.oFeatures.bPaginate === false )\r
2829                         {\r
2830                                 oSettings._iDisplayEnd = oSettings.aiDisplay.length;\r
2831                         }\r
2832                         else\r
2833                         {\r
2834                                 /* Set the end point of the display - based on how many elements there are\r
2835                                  * still to display\r
2836                                  */\r
2837                                 if ( oSettings._iDisplayStart + oSettings._iDisplayLength > oSettings.aiDisplay.length ||\r
2838                                            oSettings._iDisplayLength == -1 )\r
2839                                 {\r
2840                                         oSettings._iDisplayEnd = oSettings.aiDisplay.length;\r
2841                                 }\r
2842                                 else\r
2843                                 {\r
2844                                         oSettings._iDisplayEnd = oSettings._iDisplayStart + oSettings._iDisplayLength;\r
2845                                 }\r
2846                         }\r
2847                 }\r
2848                 \r
2849                 \r
2850                 \r
2851                 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *\r
2852                  * Note that most of the paging logic is done in \r
2853                  * DataTable.ext.oPagination\r
2854                  */\r
2855                 \r
2856                 /**\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
2861                  */\r
2862                 function _fnFeatureHtmlPaginate ( oSettings )\r
2863                 {\r
2864                         if ( oSettings.oScroll.bInfinite )\r
2865                         {\r
2866                                 return null;\r
2867                         }\r
2868                         \r
2869                         var nPaginate = document.createElement( 'div' );\r
2870                         nPaginate.className = oSettings.oClasses.sPaging+oSettings.sPaginationType;\r
2871                         \r
2872                         DataTable.ext.oPagination[ oSettings.sPaginationType ].fnInit( oSettings, nPaginate, \r
2873                                 function( oSettings ) {\r
2874                                         _fnCalculateEnd( oSettings );\r
2875                                         _fnDraw( oSettings );\r
2876                                 }\r
2877                         );\r
2878                         \r
2879                         /* Add a draw callback for the pagination on first instance, to update the paging display */\r
2880                         if ( !oSettings.aanFeatures.p )\r
2881                         {\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
2887                                                 } );\r
2888                                         },\r
2889                                         "sName": "pagination"\r
2890                                 } );\r
2891                         }\r
2892                         return nPaginate;\r
2893                 }\r
2894                 \r
2895                 \r
2896                 /**\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
2903                  */\r
2904                 function _fnPageChange ( oSettings, mAction )\r
2905                 {\r
2906                         var iOldStart = oSettings._iDisplayStart;\r
2907                         \r
2908                         if ( typeof mAction === "number" )\r
2909                         {\r
2910                                 oSettings._iDisplayStart = mAction * oSettings._iDisplayLength;\r
2911                                 if ( oSettings._iDisplayStart > oSettings.fnRecordsDisplay() )\r
2912                                 {\r
2913                                         oSettings._iDisplayStart = 0;\r
2914                                 }\r
2915                         }\r
2916                         else if ( mAction == "first" )\r
2917                         {\r
2918                                 oSettings._iDisplayStart = 0;\r
2919                         }\r
2920                         else if ( mAction == "previous" )\r
2921                         {\r
2922                                 oSettings._iDisplayStart = oSettings._iDisplayLength>=0 ?\r
2923                                         oSettings._iDisplayStart - oSettings._iDisplayLength :\r
2924                                         0;\r
2925                                 \r
2926                                 /* Correct for under-run */\r
2927                                 if ( oSettings._iDisplayStart < 0 )\r
2928                                 {\r
2929                                   oSettings._iDisplayStart = 0;\r
2930                                 }\r
2931                         }\r
2932                         else if ( mAction == "next" )\r
2933                         {\r
2934                                 if ( oSettings._iDisplayLength >= 0 )\r
2935                                 {\r
2936                                         /* Make sure we are not over running the display array */\r
2937                                         if ( oSettings._iDisplayStart + oSettings._iDisplayLength < oSettings.fnRecordsDisplay() )\r
2938                                         {\r
2939                                                 oSettings._iDisplayStart += oSettings._iDisplayLength;\r
2940                                         }\r
2941                                 }\r
2942                                 else\r
2943                                 {\r
2944                                         oSettings._iDisplayStart = 0;\r
2945                                 }\r
2946                         }\r
2947                         else if ( mAction == "last" )\r
2948                         {\r
2949                                 if ( oSettings._iDisplayLength >= 0 )\r
2950                                 {\r
2951                                         var iPages = parseInt( (oSettings.fnRecordsDisplay()-1) / oSettings._iDisplayLength, 10 ) + 1;\r
2952                                         oSettings._iDisplayStart = (iPages-1) * oSettings._iDisplayLength;\r
2953                                 }\r
2954                                 else\r
2955                                 {\r
2956                                         oSettings._iDisplayStart = 0;\r
2957                                 }\r
2958                         }\r
2959                         else\r
2960                         {\r
2961                                 _fnLog( oSettings, 0, "Unknown paging action: "+mAction );\r
2962                         }\r
2963                         $(oSettings.oInstance).trigger('page', oSettings);\r
2964                         \r
2965                         return iOldStart != oSettings._iDisplayStart;\r
2966                 }\r
2967                 \r
2968                 \r
2969                 \r
2970                 /**\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
2975                  */\r
2976                 function _fnFeatureHtmlProcessing ( oSettings )\r
2977                 {\r
2978                         var nProcessing = document.createElement( 'div' );\r
2979                         \r
2980                         if ( !oSettings.aanFeatures.r )\r
2981                         {\r
2982                                 nProcessing.id = oSettings.sTableId+'_processing';\r
2983                         }\r
2984                         nProcessing.innerHTML = oSettings.oLanguage.sProcessing;\r
2985                         nProcessing.className = oSettings.oClasses.sProcessing;\r
2986                         oSettings.nTable.parentNode.insertBefore( nProcessing, oSettings.nTable );\r
2987                         \r
2988                         return nProcessing;\r
2989                 }\r
2990                 \r
2991                 \r
2992                 /**\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
2997                  */\r
2998                 function _fnProcessingDisplay ( oSettings, bShow )\r
2999                 {\r
3000                         if ( oSettings.oFeatures.bProcessing )\r
3001                         {\r
3002                                 var an = oSettings.aanFeatures.r;\r
3003                                 for ( var i=0, iLen=an.length ; i<iLen ; i++ )\r
3004                                 {\r
3005                                         an[i].style.visibility = bShow ? "visible" : "hidden";\r
3006                                 }\r
3007                         }\r
3008                 \r
3009                         $(oSettings.oInstance).trigger('processing', [oSettings, bShow]);\r
3010                 }\r
3011                 \r
3012                 /**\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
3017                  */\r
3018                 function _fnFeatureHtmlTable ( oSettings )\r
3019                 {\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
3022                         {\r
3023                                 return oSettings.nTable;\r
3024                         }\r
3025                         \r
3026                         /*\r
3027                          * The HTML structure that we want to generate in this function is:\r
3028                          *  div - nScroller\r
3029                          *    div - nScrollHead\r
3030                          *      div - nScrollHeadInner\r
3031                          *        table - nScrollHeadTable\r
3032                          *          thead - nThead\r
3033                          *    div - nScrollBody\r
3034                          *      table - oSettings.nTable\r
3035                          *        thead - nTheadSize\r
3036                          *        tbody - nTbody\r
3037                          *    div - nScrollFoot\r
3038                          *      div - nScrollFootInner\r
3039                          *        table - nScrollFootTable\r
3040                          *          tfoot - nTfoot\r
3041                          */\r
3042                         var\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
3055                         \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
3064                         {\r
3065                                 nScroller.appendChild( nScrollFoot );\r
3066                                 nScrollFootInner.appendChild( nScrollFootTable );\r
3067                                 nScrollFootTable.appendChild( nTfoot );\r
3068                         }\r
3069                         \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
3076                         \r
3077                         if ( oSettings.oScroll.bAutoCss )\r
3078                         {\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
3083                         }\r
3084                         \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
3090                         \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
3096                         {\r
3097                                 nScrollFootTable.removeAttribute('id');\r
3098                                 nScrollFootTable.style.marginLeft = "0";\r
3099                         }\r
3100                         \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
3105                         {\r
3106                                 nCaption = nCaption[0];\r
3107                                 if ( nCaption._captionSide === "top" )\r
3108                                 {\r
3109                                         nScrollHeadTable.appendChild( nCaption );\r
3110                                 }\r
3111                                 else if ( nCaption._captionSide === "bottom" && nTfoot )\r
3112                                 {\r
3113                                         nScrollFootTable.appendChild( nCaption );\r
3114                                 }\r
3115                         }\r
3116                         \r
3117                         /*\r
3118                          * Sizing\r
3119                          */\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
3122                         {\r
3123                                 nScrollHead.style.width = _fnStringToCss( oSettings.oScroll.sX );\r
3124                                 nScrollBody.style.width = _fnStringToCss( oSettings.oScroll.sX );\r
3125                                 \r
3126                                 if ( nTfoot !== null )\r
3127                                 {\r
3128                                         nScrollFoot.style.width = _fnStringToCss( oSettings.oScroll.sX );       \r
3129                                 }\r
3130                                 \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
3134                                         \r
3135                                         if ( nTfoot !== null )\r
3136                                         {\r
3137                                                 nScrollFoot.scrollLeft = this.scrollLeft;\r
3138                                         }\r
3139                                 } );\r
3140                         }\r
3141                         \r
3142                         /* When yscrolling, add the height */\r
3143                         if ( oSettings.oScroll.sY !== "" )\r
3144                         {\r
3145                                 nScrollBody.style.height = _fnStringToCss( oSettings.oScroll.sY );\r
3146                         }\r
3147                         \r
3148                         /* Redraw - align columns across the tables */\r
3149                         oSettings.aoDrawCallback.push( {\r
3150                                 "fn": _fnScrollDraw,\r
3151                                 "sName": "scrolling"\r
3152                         } );\r
3153                         \r
3154                         /* Infinite scrolling event handlers */\r
3155                         if ( oSettings.oScroll.bInfinite )\r
3156                         {\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
3160                                         {\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
3164                                                 {\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
3167                                                         {\r
3168                                                                 _fnPageChange( oSettings, 'next' );\r
3169                                                                 _fnCalculateEnd( oSettings );\r
3170                                                                 _fnDraw( oSettings );\r
3171                                                         }\r
3172                                                 }\r
3173                                         }\r
3174                                 } );\r
3175                         }\r
3176                         \r
3177                         oSettings.nScrollHead = nScrollHead;\r
3178                         oSettings.nScrollFoot = nScrollFoot;\r
3179                         \r
3180                         return nScroller;\r
3181                 }\r
3182                 \r
3183                 \r
3184                 /**\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
3190                  *   4. Clean up\r
3191                  *  @param {object} o dataTables settings object\r
3192                  *  @returns {node} Node to add to the DOM\r
3193                  *  @memberof DataTable#oApi\r
3194                  */\r
3195                 function _fnScrollDraw ( o )\r
3196                 {\r
3197                         var\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
3214                                 };\r
3215                         \r
3216                         /*\r
3217                          * 1. Re-create the table inside the scrolling div\r
3218                          */\r
3219                         \r
3220                         /* Remove the old minimised thead and tfoot elements in the inner table */\r
3221                         $(o.nTable).children('thead, tfoot').remove();\r
3222                 \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
3228                         \r
3229                         if ( o.nTFoot !== null )\r
3230                         {\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
3235                         }\r
3236                         \r
3237                         /*\r
3238                          * 2. Take live measurements from the DOM - do not alter the DOM itself!\r
3239                          */\r
3240                         \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
3244                          */\r
3245                         if ( o.oScroll.sX === "" )\r
3246                         {\r
3247                                 nScrollBody.style.width = '100%';\r
3248                                 nScrollHeadInner.parentNode.style.width = '100%';\r
3249                         }\r
3250                         \r
3251                         var nThs = _fnGetUniqueThs( o, nTheadSize );\r
3252                         for ( i=0, iLen=nThs.length ; i<iLen ; i++ )\r
3253                         {\r
3254                                 iVis = _fnVisibleToColumnIndex( o, i );\r
3255                                 nThs[i].style.width = o.aoColumns[iVis].sWidth;\r
3256                         }\r
3257                         \r
3258                         if ( o.nTFoot !== null )\r
3259                         {\r
3260                                 _fnApplyToChildren( function(n) {\r
3261                                         n.style.width = "";\r
3262                                 }, anFootSizers );\r
3263                         }\r
3264                 \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
3269                         {\r
3270                                 nScrollBody.style.height = (nScrollBody.offsetHeight + o.nTHead.offsetHeight)+"px";\r
3271                         }\r
3272                         \r
3273                         /* Size the table as a whole */\r
3274                         iSanityWidth = $(o.nTable).outerWidth();\r
3275                         if ( o.oScroll.sX === "" )\r
3276                         {\r
3277                                 /* No x scrolling */\r
3278                                 o.nTable.style.width = "100%";\r
3279                                 \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
3282                                  * into account.\r
3283                                  */\r
3284                                 if ( ie67 && ($('tbody', nScrollBody).height() > nScrollBody.offsetHeight || \r
3285                                         $(nScrollBody).css('overflow-y') == "scroll")  )\r
3286                                 {\r
3287                                         o.nTable.style.width = _fnStringToCss( $(o.nTable).outerWidth() - o.oScroll.iBarWidth);\r
3288                                 }\r
3289                         }\r
3290                         else\r
3291                         {\r
3292                                 if ( o.oScroll.sXInner !== "" )\r
3293                                 {\r
3294                                         /* x scroll inner has been given - use it */\r
3295                                         o.nTable.style.width = _fnStringToCss(o.oScroll.sXInner);\r
3296                                 }\r
3297                                 else if ( iSanityWidth == $(nScrollBody).width() &&\r
3298                                    $(nScrollBody).height() < $(o.nTable).height() )\r
3299                                 {\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
3303                                         {\r
3304                                                 /* Not possible to take account of it */\r
3305                                                 o.nTable.style.width = _fnStringToCss( iSanityWidth );\r
3306                                         }\r
3307                                 }\r
3308                                 else\r
3309                                 {\r
3310                                         /* All else fails */\r
3311                                         o.nTable.style.width = _fnStringToCss( iSanityWidth );\r
3312                                 }\r
3313                         }\r
3314                         \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
3318                          */\r
3319                         iSanityWidth = $(o.nTable).outerWidth();\r
3320                         \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
3323                          */\r
3324                         \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
3328                          \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
3334                          \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
3340                 \r
3341                         $(anHeadSizers).height(0);\r
3342                         \r
3343                         /* Same again with the footer if we have one */\r
3344                         if ( o.nTFoot !== null )\r
3345                         {\r
3346                                 _fnApplyToChildren( zeroOut, anFootSizers );\r
3347                                  \r
3348                                 _fnApplyToChildren( function(nSizer) {\r
3349                                         aAppliedFooter.push( _fnStringToCss( $(nSizer).width() ) );\r
3350                                 }, anFootSizers );\r
3351                                  \r
3352                                 _fnApplyToChildren( function(nToSize, i) {\r
3353                                         nToSize.style.width = aAppliedFooter[i];\r
3354                                 }, anFootToSize );\r
3355                 \r
3356                                 $(anFootSizers).height(0);\r
3357                         }\r
3358                         \r
3359                         /*\r
3360                          * 3. Apply the measurements\r
3361                          */\r
3362                         \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
3365                          */\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
3372                         \r
3373                         if ( o.nTFoot !== null )\r
3374                         {\r
3375                                 _fnApplyToChildren( function(nSizer, i) {\r
3376                                         nSizer.innerHTML = "";\r
3377                                         nSizer.style.width = aAppliedFooter[i];\r
3378                                 }, anFootSizers );\r
3379                         }\r
3380                         \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
3383                          */\r
3384                         if ( $(o.nTable).outerWidth() < iSanityWidth )\r
3385                         {\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
3390                                 \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
3394                                 {\r
3395                                         o.nTable.style.width = _fnStringToCss( iCorrection-o.oScroll.iBarWidth );\r
3396                                 }\r
3397                                 \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
3401                                 \r
3402                                 if ( o.nTFoot !== null )\r
3403                                 {\r
3404                                         o.nScrollFoot.style.width = _fnStringToCss( iCorrection );\r
3405                                 }\r
3406                                 \r
3407                                 /* And give the user a warning that we've stopped the table getting too small */\r
3408                                 if ( o.oScroll.sX === "" )\r
3409                                 {\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
3412                                 }\r
3413                                 else if ( o.oScroll.sXInner !== "" )\r
3414                                 {\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
3417                                                 " calculation" );\r
3418                                 }\r
3419                         }\r
3420                         else\r
3421                         {\r
3422                                 nScrollBody.style.width = _fnStringToCss( '100%' );\r
3423                                 o.nScrollHead.style.width = _fnStringToCss( '100%' );\r
3424                                 \r
3425                                 if ( o.nTFoot !== null )\r
3426                                 {\r
3427                                         o.nScrollFoot.style.width = _fnStringToCss( '100%' );\r
3428                                 }\r
3429                         }\r
3430                         \r
3431                         \r
3432                         /*\r
3433                          * 4. Clean up\r
3434                          */\r
3435                         if ( o.oScroll.sY === "" )\r
3436                         {\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
3440                                  */\r
3441                                 if ( ie67 )\r
3442                                 {\r
3443                                         nScrollBody.style.height = _fnStringToCss( o.nTable.offsetHeight+o.oScroll.iBarWidth );\r
3444                                 }\r
3445                         }\r
3446                         \r
3447                         if ( o.oScroll.sY !== "" && o.oScroll.bCollapse )\r
3448                         {\r
3449                                 nScrollBody.style.height = _fnStringToCss( o.oScroll.sY );\r
3450                                 \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
3454                                 {\r
3455                                         nScrollBody.style.height = _fnStringToCss( o.nTable.offsetHeight+iExtra );\r
3456                                 }\r
3457                         }\r
3458                         \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
3463                 \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
3468                         \r
3469                         if ( o.nTFoot !== null )\r
3470                         {\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
3474                         }\r
3475                 \r
3476                         /* Adjust the position of the header in case we loose the y-scrollbar */\r
3477                         $(nScrollBody).scroll();\r
3478                         \r
3479                         /* If sorting or filtering has occurred, jump the scrolling back to the top */\r
3480                         if ( o.bSorted || o.bFiltered )\r
3481                         {\r
3482                                 nScrollBody.scrollTop = 0;\r
3483                         }\r
3484                 }\r
3485                 \r
3486                 \r
3487                 /**\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
3494                  */\r
3495                 function _fnApplyToChildren( fn, an1, an2 )\r
3496                 {\r
3497                         var index=0, i=0, iLen=an1.length;\r
3498                         var nNode1, nNode2;\r
3499                 \r
3500                         while ( i < iLen )\r
3501                         {\r
3502                                 nNode1 = an1[i].firstChild;\r
3503                                 nNode2 = an2 ? an2[i].firstChild : null;\r
3504                                 while ( nNode1 )\r
3505                                 {\r
3506                                         if ( nNode1.nodeType === 1 )\r
3507                                         {\r
3508                                                 if ( an2 )\r
3509                                                 {\r
3510                                                         fn( nNode1, nNode2, index );\r
3511                                                 }\r
3512                                                 else\r
3513                                                 {\r
3514                                                         fn( nNode1, index );\r
3515                                                 }\r
3516                                                 index++;\r
3517                                         }\r
3518                                         nNode1 = nNode1.nextSibling;\r
3519                                         nNode2 = an2 ? nNode2.nextSibling : null;\r
3520                                 }\r
3521                                 i++;\r
3522                         }\r
3523                 }\r
3524                 \r
3525                 /**\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
3531                  */\r
3532                 function _fnConvertToWidth ( sWidth, nParent )\r
3533                 {\r
3534                         if ( !sWidth || sWidth === null || sWidth === '' )\r
3535                         {\r
3536                                 return 0;\r
3537                         }\r
3538                         \r
3539                         if ( !nParent )\r
3540                         {\r
3541                                 nParent = document.body;\r
3542                         }\r
3543                         \r
3544                         var iWidth;\r
3545                         var nTmp = document.createElement( "div" );\r
3546                         nTmp.style.width = _fnStringToCss( sWidth );\r
3547                         \r
3548                         nParent.appendChild( nTmp );\r
3549                         iWidth = nTmp.offsetWidth;\r
3550                         nParent.removeChild( nTmp );\r
3551                         \r
3552                         return ( iWidth );\r
3553                 }\r
3554                 \r
3555                 \r
3556                 /**\r
3557                  * Calculate the width of columns for the table\r
3558                  *  @param {object} oSettings dataTables settings object\r
3559                  *  @memberof DataTable#oApi\r
3560                  */\r
3561                 function _fnCalculateColumnWidths ( oSettings )\r
3562                 {\r
3563                         var iTableWidth = oSettings.nTable.offsetWidth;\r
3564                         var iUserInputs = 0;\r
3565                         var iTmpWidth;\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
3572                         \r
3573                         /* Convert any user input sizes into pixel sizes */\r
3574                         for ( i=0 ; i<iColums ; i++ )\r
3575                         {\r
3576                                 if ( oSettings.aoColumns[i].bVisible )\r
3577                                 {\r
3578                                         iVisibleColumns++;\r
3579                                         \r
3580                                         if ( oSettings.aoColumns[i].sWidth !== null )\r
3581                                         {\r
3582                                                 iTmpWidth = _fnConvertToWidth( oSettings.aoColumns[i].sWidthOrig, \r
3583                                                         nWrapper );\r
3584                                                 if ( iTmpWidth !== null )\r
3585                                                 {\r
3586                                                         oSettings.aoColumns[i].sWidth = _fnStringToCss( iTmpWidth );\r
3587                                                 }\r
3588                                                         \r
3589                                                 iUserInputs++;\r
3590                                         }\r
3591                                 }\r
3592                         }\r
3593                         \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
3597                          */\r
3598                         if ( iColums == oHeaders.length && iUserInputs === 0 && iVisibleColumns == iColums &&\r
3599                                 oSettings.oScroll.sX === "" && oSettings.oScroll.sY === "" )\r
3600                         {\r
3601                                 for ( i=0 ; i<oSettings.aoColumns.length ; i++ )\r
3602                                 {\r
3603                                         iTmpWidth = $(oHeaders[i]).width();\r
3604                                         if ( iTmpWidth !== null )\r
3605                                         {\r
3606                                                 oSettings.aoColumns[i].sWidth = _fnStringToCss( iTmpWidth );\r
3607                                         }\r
3608                                 }\r
3609                         }\r
3610                         else\r
3611                         {\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
3616                                  */\r
3617                                 var\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
3622                                         nDivSizing;\r
3623                                 \r
3624                                 nCalcTmp.removeAttribute( "id" );\r
3625                                 nCalcTmp.appendChild( nTheadClone );\r
3626                                 if ( oSettings.nTFoot !== null )\r
3627                                 {\r
3628                                         nCalcTmp.appendChild( oSettings.nTFoot.cloneNode(true) );\r
3629                                         _fnApplyToChildren( function(n) {\r
3630                                                 n.style.width = "";\r
3631                                         }, nCalcTmp.getElementsByTagName('tr') );\r
3632                                 }\r
3633                                 \r
3634                                 nCalcTmp.appendChild( nBody );\r
3635                                 nBody.appendChild( nTr );\r
3636                                 \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
3640                                 {\r
3641                                         jqColSizing = $('tbody tr:eq(0)>td', nCalcTmp);\r
3642                                 }\r
3643                 \r
3644                                 /* Apply custom sizing to the cloned header */\r
3645                                 var nThs = _fnGetUniqueThs( oSettings, nTheadClone );\r
3646                                 iCorrector = 0;\r
3647                                 for ( i=0 ; i<iColums ; i++ )\r
3648                                 {\r
3649                                         var oColumn = oSettings.aoColumns[i];\r
3650                                         if ( oColumn.bVisible && oColumn.sWidthOrig !== null && oColumn.sWidthOrig !== "" )\r
3651                                         {\r
3652                                                 nThs[i-iCorrector].style.width = _fnStringToCss( oColumn.sWidthOrig );\r
3653                                         }\r
3654                                         else if ( oColumn.bVisible )\r
3655                                         {\r
3656                                                 nThs[i-iCorrector].style.width = "";\r
3657                                         }\r
3658                                         else\r
3659                                         {\r
3660                                                 iCorrector++;\r
3661                                         }\r
3662                                 }\r
3663                 \r
3664                                 /* Find the biggest td for each column and put it into the table */\r
3665                                 for ( i=0 ; i<iColums ; i++ )\r
3666                                 {\r
3667                                         if ( oSettings.aoColumns[i].bVisible )\r
3668                                         {\r
3669                                                 var nTd = _fnGetWidestNode( oSettings, i );\r
3670                                                 if ( nTd !== null )\r
3671                                                 {\r
3672                                                         nTd = nTd.cloneNode(true);\r
3673                                                         if ( oSettings.aoColumns[i].sContentPadding !== "" )\r
3674                                                         {\r
3675                                                                 nTd.innerHTML += oSettings.aoColumns[i].sContentPadding;\r
3676                                                         }\r
3677                                                         nTr.appendChild( nTd );\r
3678                                                 }\r
3679                                         }\r
3680                                 }\r
3681                                 \r
3682                                 /* Build the table and 'display' it */\r
3683                                 nWrapper.appendChild( nCalcTmp );\r
3684                                 \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
3688                                  */\r
3689                                 if ( oSettings.oScroll.sX !== "" && oSettings.oScroll.sXInner !== "" )\r
3690                                 {\r
3691                                         nCalcTmp.style.width = _fnStringToCss(oSettings.oScroll.sXInner);\r
3692                                 }\r
3693                                 else if ( oSettings.oScroll.sX !== "" )\r
3694                                 {\r
3695                                         nCalcTmp.style.width = "";\r
3696                                         if ( $(nCalcTmp).width() < nWrapper.offsetWidth )\r
3697                                         {\r
3698                                                 nCalcTmp.style.width = _fnStringToCss( nWrapper.offsetWidth );\r
3699                                         }\r
3700                                 }\r
3701                                 else if ( oSettings.oScroll.sY !== "" )\r
3702                                 {\r
3703                                         nCalcTmp.style.width = _fnStringToCss( nWrapper.offsetWidth );\r
3704                                 }\r
3705                                 else if ( widthAttr )\r
3706                                 {\r
3707                                         nCalcTmp.style.width = _fnStringToCss( widthAttr );\r
3708                                 }\r
3709                                 nCalcTmp.style.visibility = "hidden";\r
3710                                 \r
3711                                 /* Scrolling considerations */\r
3712                                 _fnScrollingWidthAdjust( oSettings, nCalcTmp );\r
3713                                 \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
3717                                  */\r
3718                                 var oNodes = $("tbody tr:eq(0)", nCalcTmp).children();\r
3719                                 if ( oNodes.length === 0 )\r
3720                                 {\r
3721                                         oNodes = _fnGetUniqueThs( oSettings, $('thead', nCalcTmp)[0] );\r
3722                                 }\r
3723                 \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
3728                                  */\r
3729                                 if ( oSettings.oScroll.sX !== "" )\r
3730                                 {\r
3731                                         var iTotal = 0;\r
3732                                         iCorrector = 0;\r
3733                                         for ( i=0 ; i<oSettings.aoColumns.length ; i++ )\r
3734                                         {\r
3735                                                 if ( oSettings.aoColumns[i].bVisible )\r
3736                                                 {\r
3737                                                         if ( oSettings.aoColumns[i].sWidthOrig === null )\r
3738                                                         {\r
3739                                                                 iTotal += $(oNodes[iCorrector]).outerWidth();\r
3740                                                         }\r
3741                                                         else\r
3742                                                         {\r
3743                                                                 iTotal += parseInt(oSettings.aoColumns[i].sWidth.replace('px',''), 10) +\r
3744                                                                         ($(oNodes[iCorrector]).outerWidth() - $(oNodes[iCorrector]).width());\r
3745                                                         }\r
3746                                                         iCorrector++;\r
3747                                                 }\r
3748                                         }\r
3749                                         \r
3750                                         nCalcTmp.style.width = _fnStringToCss( iTotal );\r
3751                                         oSettings.nTable.style.width = _fnStringToCss( iTotal );\r
3752                                 }\r
3753                 \r
3754                                 iCorrector = 0;\r
3755                                 for ( i=0 ; i<oSettings.aoColumns.length ; i++ )\r
3756                                 {\r
3757                                         if ( oSettings.aoColumns[i].bVisible )\r
3758                                         {\r
3759                                                 iWidth = $(oNodes[iCorrector]).width();\r
3760                                                 if ( iWidth !== null && iWidth > 0 )\r
3761                                                 {\r
3762                                                         oSettings.aoColumns[i].sWidth = _fnStringToCss( iWidth );\r
3763                                                 }\r
3764                                                 iCorrector++;\r
3765                                         }\r
3766                                 }\r
3767                 \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
3772                         }\r
3773                 \r
3774                         if ( widthAttr )\r
3775                         {\r
3776                                 oSettings.nTable.style.width = _fnStringToCss( widthAttr );\r
3777                         }\r
3778                 }\r
3779                 \r
3780                 \r
3781                 /**\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
3786                  */\r
3787                 function _fnScrollingWidthAdjust ( oSettings, n )\r
3788                 {\r
3789                         if ( oSettings.oScroll.sX === "" && oSettings.oScroll.sY !== "" )\r
3790                         {\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
3793                                  */\r
3794                                 var iOrigWidth = $(n).width();\r
3795                                 n.style.width = _fnStringToCss( $(n).outerWidth()-oSettings.oScroll.iBarWidth );\r
3796                         }\r
3797                         else if ( oSettings.oScroll.sX !== "" )\r
3798                         {\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
3801                         }\r
3802                 }\r
3803                 \r
3804                 \r
3805                 /**\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
3811                  */\r
3812                 function _fnGetWidestNode( oSettings, iCol )\r
3813                 {\r
3814                         var iMaxIndex = _fnGetMaxLenString( oSettings, iCol );\r
3815                         if ( iMaxIndex < 0 )\r
3816                         {\r
3817                                 return null;\r
3818                         }\r
3819                 \r
3820                         if ( oSettings.aoData[iMaxIndex].nTr === null )\r
3821                         {\r
3822                                 var n = document.createElement('td');\r
3823                                 n.innerHTML = _fnGetCellData( oSettings, iMaxIndex, iCol, '' );\r
3824                                 return n;\r
3825                         }\r
3826                         return _fnGetTdNodes(oSettings, iMaxIndex)[iCol];\r
3827                 }\r
3828                 \r
3829                 \r
3830                 /**\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
3836                  */\r
3837                 function _fnGetMaxLenString( oSettings, iCol )\r
3838                 {\r
3839                         var iMax = -1;\r
3840                         var iMaxIndex = -1;\r
3841                         \r
3842                         for ( var i=0 ; i<oSettings.aoData.length ; i++ )\r
3843                         {\r
3844                                 var s = _fnGetCellData( oSettings, i, iCol, 'display' )+"";\r
3845                                 s = s.replace( /<.*?>/g, "" );\r
3846                                 if ( s.length > iMax )\r
3847                                 {\r
3848                                         iMax = s.length;\r
3849                                         iMaxIndex = i;\r
3850                                 }\r
3851                         }\r
3852                         \r
3853                         return iMaxIndex;\r
3854                 }\r
3855                 \r
3856                 \r
3857                 /**\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
3863                  */\r
3864                 function _fnStringToCss( s )\r
3865                 {\r
3866                         if ( s === null )\r
3867                         {\r
3868                                 return "0px";\r
3869                         }\r
3870                         \r
3871                         if ( typeof s == 'number' )\r
3872                         {\r
3873                                 if ( s < 0 )\r
3874                                 {\r
3875                                         return "0px";\r
3876                                 }\r
3877                                 return s+"px";\r
3878                         }\r
3879                         \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
3883                         {\r
3884                                 return s;\r
3885                         }\r
3886                         return s+"px";\r
3887                 }\r
3888                 \r
3889                 \r
3890                 /**\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
3894                  */\r
3895                 function _fnScrollBarWidth ()\r
3896                 {  \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
3902                         \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
3914                         \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
3919                         if ( w1 == w2 )\r
3920                         {\r
3921                                 w2 = outer.clientWidth;\r
3922                         }\r
3923                         \r
3924                         document.body.removeChild(outer);\r
3925                         return (w1 - w2);  \r
3926                 }\r
3927                 \r
3928                 /**\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
3933                  */\r
3934                 function _fnSort ( oSettings, bApplyClasses )\r
3935                 {\r
3936                         var\r
3937                                 i, iLen, j, jLen, k, kLen,\r
3938                                 sDataType, nTh,\r
3939                                 aaSort = [],\r
3940                                 aiOrig = [],\r
3941                                 oSort = DataTable.ext.oSort,\r
3942                                 aoData = oSettings.aoData,\r
3943                                 aoColumns = oSettings.aoColumns,\r
3944                                 oAria = oSettings.oLanguage.oAria;\r
3945                         \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
3949                         {\r
3950                                 aaSort = ( oSettings.aaSortingFixed !== null ) ?\r
3951                                         oSettings.aaSortingFixed.concat( oSettings.aaSorting ) :\r
3952                                         oSettings.aaSorting.slice();\r
3953                                 \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
3956                                  */\r
3957                                 for ( i=0 ; i<aaSort.length ; i++ )\r
3958                                 {\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
3963                                         {\r
3964                                                 var aData = DataTable.ext.afnSortData[sDataType].call( \r
3965                                                         oSettings.oInstance, oSettings, iColumn, iVisColumn\r
3966                                                 );\r
3967                                                 if ( aData.length === aoData.length )\r
3968                                                 {\r
3969                                                         for ( j=0, jLen=aoData.length ; j<jLen ; j++ )\r
3970                                                         {\r
3971                                                                 _fnSetCellData( oSettings, j, iColumn, aData[j] );\r
3972                                                         }\r
3973                                                 }\r
3974                                                 else\r
3975                                                 {\r
3976                                                         _fnLog( oSettings, 0, "Returned data sort array (col "+iColumn+") is the wrong length" );\r
3977                                                 }\r
3978                                         }\r
3979                                 }\r
3980                                 \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
3983                                  */\r
3984                                 for ( i=0, iLen=oSettings.aiDisplayMaster.length ; i<iLen ; i++ )\r
3985                                 {\r
3986                                         aiOrig[ oSettings.aiDisplayMaster[i] ] = i;\r
3987                                 }\r
3988                 \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
3992                                  */\r
3993                                 var iSortLen = aaSort.length;\r
3994                                 var fnSortFormat, aDataSort;\r
3995                                 for ( i=0, iLen=aoData.length ; i<iLen ; i++ )\r
3996                                 {\r
3997                                         for ( j=0 ; j<iSortLen ; j++ )\r
3998                                         {\r
3999                                                 aDataSort = aoColumns[ aaSort[j][0] ].aDataSort;\r
4000                 \r
4001                                                 for ( k=0, kLen=aDataSort.length ; k<kLen ; k++ )\r
4002                                                 {\r
4003                                                         sDataType = aoColumns[ aDataSort[k] ].sType;\r
4004                                                         fnSortFormat = oSort[ (sDataType ? sDataType : 'string')+"-pre" ];\r
4005                                                         \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
4009                                                 }\r
4010                                         }\r
4011                                 }\r
4012                                 \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
4017                                  *      var iTest;\r
4018                                  *      iTest = oSort['string-asc']('data11', 'data12');\r
4019                                  *      if (iTest !== 0)\r
4020                                  *              return iTest;\r
4021                                  *    iTest = oSort['numeric-desc']('data21', 'data22');\r
4022                                  *    if (iTest !== 0)\r
4023                                  *              return iTest;\r
4024                                  *      return oSort['numeric-asc']( aiOrig[a], aiOrig[b] );\r
4025                                  *  }\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
4029                                  */\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
4033                                         {\r
4034                                                 aDataSort = aoColumns[ aaSort[k][0] ].aDataSort;\r
4035                 \r
4036                                                 for ( l=0, lLen=aDataSort.length ; l<lLen ; l++ )\r
4037                                                 {\r
4038                                                         sDataType = aoColumns[ aDataSort[l] ].sType;\r
4039                                                         \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
4043                                                         );\r
4044                                                 \r
4045                                                         if ( iTest !== 0 )\r
4046                                                         {\r
4047                                                                 return iTest;\r
4048                                                         }\r
4049                                                 }\r
4050                                         }\r
4051                                         \r
4052                                         return oSort['numeric-asc']( aiOrig[a], aiOrig[b] );\r
4053                                 } );\r
4054                         }\r
4055                         \r
4056                         /* Alter the sorting classes to take account of the changes */\r
4057                         if ( (bApplyClasses === undefined || bApplyClasses) && !oSettings.oFeatures.bDeferRender )\r
4058                         {\r
4059                                 _fnSortingClasses( oSettings );\r
4060                         }\r
4061                 \r
4062                         for ( i=0, iLen=oSettings.aoColumns.length ; i<iLen ; i++ )\r
4063                         {\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
4068                                 \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
4071                                 {\r
4072                                         if ( aaSort.length > 0 && aaSort[0][0] == i )\r
4073                                         {\r
4074                                                 nTh.setAttribute('aria-sort', aaSort[0][1]=="asc" ? "ascending" : "descending" );\r
4075                                                 \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
4080                                         }\r
4081                                         else\r
4082                                         {\r
4083                                                 nTh.setAttribute('aria-label', sTitle+\r
4084                                                         (aoColumns[i].asSorting[0]=="asc" ? oAria.sSortAscending : oAria.sSortDescending) );\r
4085                                         }\r
4086                                 }\r
4087                                 else\r
4088                                 {\r
4089                                         nTh.setAttribute('aria-label', sTitle);\r
4090                                 }\r
4091                         }\r
4092                         \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
4096                         \r
4097                         /* Copy the master data into the draw array and re-draw */\r
4098                         if ( oSettings.oFeatures.bFilter )\r
4099                         {\r
4100                                 /* _fnFilter() will redraw the table for us */\r
4101                                 _fnFilterComplete( oSettings, oSettings.oPreviousSearch, 1 );\r
4102                         }\r
4103                         else\r
4104                         {\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
4109                         }\r
4110                 }\r
4111                 \r
4112                 \r
4113                 /**\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
4120                  */\r
4121                 function _fnSortAttachListener ( oSettings, nNode, iDataIndex, fnCallback )\r
4122                 {\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
4126                                 {\r
4127                                         return;\r
4128                                 }\r
4129                                 \r
4130                                 /*\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
4142                                  */\r
4143                                 var fnInnerSorting = function () {\r
4144                                         var iColumn, iNextSort;\r
4145                                         \r
4146                                         /* If the shift key is pressed then we are multiple column sorting */\r
4147                                         if ( e.shiftKey )\r
4148                                         {\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
4152                                                 {\r
4153                                                         if ( oSettings.aaSorting[i][0] == iDataIndex )\r
4154                                                         {\r
4155                                                                 bFound = true;\r
4156                                                                 iColumn = oSettings.aaSorting[i][0];\r
4157                                                                 iNextSort = oSettings.aaSorting[i][2]+1;\r
4158                                                                 \r
4159                                                                 if ( !oSettings.aoColumns[iColumn].asSorting[iNextSort] )\r
4160                                                                 {\r
4161                                                                         /* Reached the end of the sorting options, remove from multi-col sort */\r
4162                                                                         oSettings.aaSorting.splice( i, 1 );\r
4163                                                                 }\r
4164                                                                 else\r
4165                                                                 {\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
4169                                                                 }\r
4170                                                                 break;\r
4171                                                         }\r
4172                                                 }\r
4173                                                 \r
4174                                                 /* No sort yet - add it in */\r
4175                                                 if ( bFound === false )\r
4176                                                 {\r
4177                                                         oSettings.aaSorting.push( [ iDataIndex, \r
4178                                                                 oSettings.aoColumns[iDataIndex].asSorting[0], 0 ] );\r
4179                                                 }\r
4180                                         }\r
4181                                         else\r
4182                                         {\r
4183                                                 /* If no shift key then single column sort */\r
4184                                                 if ( oSettings.aaSorting.length == 1 && oSettings.aaSorting[0][0] == iDataIndex )\r
4185                                                 {\r
4186                                                         iColumn = oSettings.aaSorting[0][0];\r
4187                                                         iNextSort = oSettings.aaSorting[0][2]+1;\r
4188                                                         if ( !oSettings.aoColumns[iColumn].asSorting[iNextSort] )\r
4189                                                         {\r
4190                                                                 iNextSort = 0;\r
4191                                                         }\r
4192                                                         oSettings.aaSorting[0][1] = oSettings.aoColumns[iColumn].asSorting[iNextSort];\r
4193                                                         oSettings.aaSorting[0][2] = iNextSort;\r
4194                                                 }\r
4195                                                 else\r
4196                                                 {\r
4197                                                         oSettings.aaSorting.splice( 0, oSettings.aaSorting.length );\r
4198                                                         oSettings.aaSorting.push( [ iDataIndex, \r
4199                                                                 oSettings.aoColumns[iDataIndex].asSorting[0], 0 ] );\r
4200                                                 }\r
4201                                         }\r
4202                                         \r
4203                                         /* Run the sort */\r
4204                                         _fnSort( oSettings );\r
4205                                 }; /* /fnInnerSorting */\r
4206                                 \r
4207                                 if ( !oSettings.oFeatures.bProcessing )\r
4208                                 {\r
4209                                         fnInnerSorting();\r
4210                                 }\r
4211                                 else\r
4212                                 {\r
4213                                         _fnProcessingDisplay( oSettings, true );\r
4214                                         setTimeout( function() {\r
4215                                                 fnInnerSorting();\r
4216                                                 if ( !oSettings.oFeatures.bServerSide )\r
4217                                                 {\r
4218                                                         _fnProcessingDisplay( oSettings, false );\r
4219                                                 }\r
4220                                         }, 0 );\r
4221                                 }\r
4222                                 \r
4223                                 /* Call the user specified callback function - used for async user interaction */\r
4224                                 if ( typeof fnCallback == 'function' )\r
4225                                 {\r
4226                                         fnCallback( oSettings );\r
4227                                 }\r
4228                         } );\r
4229                 }\r
4230                 \r
4231                 \r
4232                 /**\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
4237                  */\r
4238                 function _fnSortingClasses( oSettings )\r
4239                 {\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
4244                         \r
4245                         for ( i=0 ; i<iColumns ; i++ )\r
4246                         {\r
4247                                 if ( oSettings.aoColumns[i].bSortable )\r
4248                                 {\r
4249                                         $(oSettings.aoColumns[i].nTh).removeClass( oClasses.sSortAsc +" "+ oClasses.sSortDesc +\r
4250                                                 " "+ oSettings.aoColumns[i].sSortingClass );\r
4251                                 }\r
4252                         }\r
4253                         \r
4254                         if ( oSettings.aaSortingFixed !== null )\r
4255                         {\r
4256                                 aaSort = oSettings.aaSortingFixed.concat( oSettings.aaSorting );\r
4257                         }\r
4258                         else\r
4259                         {\r
4260                                 aaSort = oSettings.aaSorting.slice();\r
4261                         }\r
4262                         \r
4263                         /* Apply the required classes to the header */\r
4264                         for ( i=0 ; i<oSettings.aoColumns.length ; i++ )\r
4265                         {\r
4266                                 if ( oSettings.aoColumns[i].bSortable )\r
4267                                 {\r
4268                                         sClass = oSettings.aoColumns[i].sSortingClass;\r
4269                                         iFound = -1;\r
4270                                         for ( j=0 ; j<aaSort.length ; j++ )\r
4271                                         {\r
4272                                                 if ( aaSort[j][0] == i )\r
4273                                                 {\r
4274                                                         sClass = ( aaSort[j][1] == "asc" ) ?\r
4275                                                                 oClasses.sSortAsc : oClasses.sSortDesc;\r
4276                                                         iFound = j;\r
4277                                                         break;\r
4278                                                 }\r
4279                                         }\r
4280                                         $(oSettings.aoColumns[i].nTh).addClass( sClass );\r
4281                                         \r
4282                                         if ( oSettings.bJUI )\r
4283                                         {\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
4288                                                 \r
4289                                                 var sSpanClass;\r
4290                                                 if ( iFound == -1 )\r
4291                                                 {\r
4292                                                         sSpanClass = oSettings.aoColumns[i].sSortingClassJUI;\r
4293                                                 }\r
4294                                                 else if ( aaSort[iFound][1] == "asc" )\r
4295                                                 {\r
4296                                                         sSpanClass = oClasses.sSortJUIAsc;\r
4297                                                 }\r
4298                                                 else\r
4299                                                 {\r
4300                                                         sSpanClass = oClasses.sSortJUIDesc;\r
4301                                                 }\r
4302                                                 \r
4303                                                 jqSpan.addClass( sSpanClass );\r
4304                                         }\r
4305                                 }\r
4306                                 else\r
4307                                 {\r
4308                                         /* No sorting on this column, so add the base class. This will have been assigned by\r
4309                                          * _fnAddColumn\r
4310                                          */\r
4311                                         $(oSettings.aoColumns[i].nTh).addClass( oSettings.aoColumns[i].sSortingClass );\r
4312                                 }\r
4313                         }\r
4314                         \r
4315                         /* \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
4325                          */\r
4326                         sClass = oClasses.sSortColumn;\r
4327                         \r
4328                         if ( oSettings.oFeatures.bSort && oSettings.oFeatures.bSortClasses )\r
4329                         {\r
4330                                 var nTds = _fnGetTdNodes( oSettings );\r
4331                                 \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
4336                                 {\r
4337                                         asClasses.push("");\r
4338                                 }\r
4339                                 for (i = 0, iClass = 1; i < aaSort.length; i++)\r
4340                                 {\r
4341                                         iTargetCol = parseInt( aaSort[i][0], 10 );\r
4342                                         asClasses[iTargetCol] = sClass + iClass;\r
4343                                         \r
4344                                         if ( iClass < 3 )\r
4345                                         {\r
4346                                                 iClass++;\r
4347                                         }\r
4348                                 }\r
4349                                 \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
4354                                 {\r
4355                                         /* Determine which column we're looking at */\r
4356                                         iTargetCol = i % iColumns;\r
4357                                         \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
4364                                         \r
4365                                         if ( sTmpClass != sCurrentClass )\r
4366                                         {\r
4367                                                 /* We changed something */\r
4368                                                 nTds[i].className = $.trim( sTmpClass );\r
4369                                         }\r
4370                                         else if ( sNewClass.length > 0 && sCurrentClass.indexOf(sNewClass) == -1 )\r
4371                                         {\r
4372                                                 /* We need to add a class */\r
4373                                                 nTds[i].className = sCurrentClass + " " + sNewClass;\r
4374                                         }\r
4375                                 }\r
4376                         }\r
4377                 }\r
4378                 \r
4379                 \r
4380                 \r
4381                 /**\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
4385                  */\r
4386                 function _fnSaveState ( oSettings )\r
4387                 {\r
4388                         if ( !oSettings.oFeatures.bStateSave || oSettings.bDestroying )\r
4389                         {\r
4390                                 return;\r
4391                         }\r
4392                 \r
4393                         /* Store the interesting variables */\r
4394                         var i, iLen, bInfinite=oSettings.oScroll.bInfinite;\r
4395                         var oState = {\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
4403                                 "abVisCols":    []\r
4404                         };\r
4405                 \r
4406                         for ( i=0, iLen=oSettings.aoColumns.length ; i<iLen ; i++ )\r
4407                         {\r
4408                                 oState.abVisCols.push( oSettings.aoColumns[i].bVisible );\r
4409                         }\r
4410                 \r
4411                         _fnCallbackFire( oSettings, "aoStateSaveParams", 'stateSaveParams', [oSettings, oState] );\r
4412                         \r
4413                         oSettings.fnStateSave.call( oSettings.oInstance, oSettings, oState );\r
4414                 }\r
4415                 \r
4416                 \r
4417                 /**\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
4422                  */\r
4423                 function _fnLoadState ( oSettings, oInit )\r
4424                 {\r
4425                         if ( !oSettings.oFeatures.bStateSave )\r
4426                         {\r
4427                                 return;\r
4428                         }\r
4429                 \r
4430                         var oData = oSettings.fnStateLoad.call( oSettings.oInstance, oSettings );\r
4431                         if ( !oData )\r
4432                         {\r
4433                                 return;\r
4434                         }\r
4435                         \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
4438                          */\r
4439                         var abStateLoad = _fnCallbackFire( oSettings, 'aoStateLoadParams', 'stateLoadParams', [oSettings, oData] );\r
4440                         if ( $.inArray( false, abStateLoad ) !== -1 )\r
4441                         {\r
4442                                 return;\r
4443                         }\r
4444                         \r
4445                         /* Store the saved state so it might be accessed at any time */\r
4446                         oSettings.oLoadedState = $.extend( true, {}, oData );\r
4447                         \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
4455                         \r
4456                         /* Search filtering  */\r
4457                         $.extend( oSettings.oPreviousSearch, oData.oSearch );\r
4458                         $.extend( true, oSettings.aoPreSearchCols, oData.aoSearchCols );\r
4459                         \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
4463                          */\r
4464                         oInit.saved_aoColumns = [];\r
4465                         for ( var i=0 ; i<oData.abVisCols.length ; i++ )\r
4466                         {\r
4467                                 oInit.saved_aoColumns[i] = {};\r
4468                                 oInit.saved_aoColumns[i].bVisible = oData.abVisCols[i];\r
4469                         }\r
4470                 \r
4471                         _fnCallbackFire( oSettings, 'aoStateLoaded', 'stateLoaded', [oSettings, oData] );\r
4472                 }\r
4473                 \r
4474                 \r
4475                 /**\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
4483                  */\r
4484                 function _fnCreateCookie ( sName, sValue, iSecs, sBaseName, fnCallback )\r
4485                 {\r
4486                         var date = new Date();\r
4487                         date.setTime( date.getTime()+(iSecs*1000) );\r
4488                         \r
4489                         /* \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
4494                          */\r
4495                         var aParts = window.location.pathname.split('/');\r
4496                         var sNameFile = sName + '_' + aParts.pop().replace(/[\/:]/g,"").toLowerCase();\r
4497                         var sFullCookie, oData;\r
4498                         \r
4499                         if ( fnCallback !== null )\r
4500                         {\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
4505                         }\r
4506                         else\r
4507                         {\r
4508                                 sFullCookie = sNameFile + "=" + encodeURIComponent(sValue) +\r
4509                                         "; expires=" + date.toGMTString() +"; path=" + aParts.join('/')+"/";\r
4510                         }\r
4511                         \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
4514                          */\r
4515                         var\r
4516                                 aCookies =document.cookie.split(';'),\r
4517                                 iNewCookieLen = sFullCookie.split(';')[0].length,\r
4518                                 aOldCookies = [];\r
4519                         \r
4520                         if ( iNewCookieLen+document.cookie.length+10 > 4096 ) /* Magic 10 for padding */\r
4521                         {\r
4522                                 for ( var i=0, iLen=aCookies.length ; i<iLen ; i++ )\r
4523                                 {\r
4524                                         if ( aCookies[i].indexOf( sBaseName ) != -1 )\r
4525                                         {\r
4526                                                 /* It's a DataTables cookie, so eval it and check the time stamp */\r
4527                                                 var aSplitCookie = aCookies[i].split('=');\r
4528                                                 try {\r
4529                                                         oData = eval( '('+decodeURIComponent(aSplitCookie[1])+')' );\r
4530                 \r
4531                                                         if ( oData && oData.iCreate )\r
4532                                                         {\r
4533                                                                 aOldCookies.push( {\r
4534                                                                         "name": aSplitCookie[0],\r
4535                                                                         "time": oData.iCreate\r
4536                                                                 } );\r
4537                                                         }\r
4538                                                 }\r
4539                                                 catch( e ) {}\r
4540                                         }\r
4541                                 }\r
4542                 \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
4546                                 } );\r
4547                 \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
4552                                                 return;\r
4553                                         }\r
4554                                         \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
4558                                 }\r
4559                         }\r
4560                         \r
4561                         document.cookie = sFullCookie;\r
4562                 }\r
4563                 \r
4564                 \r
4565                 /**\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
4570                  */\r
4571                 function _fnReadCookie ( sName )\r
4572                 {\r
4573                         var\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
4577                         \r
4578                         for( var i=0 ; i<sCookieContents.length ; i++ )\r
4579                         {\r
4580                                 var c = sCookieContents[i];\r
4581                                 \r
4582                                 while (c.charAt(0)==' ')\r
4583                                 {\r
4584                                         c = c.substring(1,c.length);\r
4585                                 }\r
4586                                 \r
4587                                 if (c.indexOf(sNameEQ) === 0)\r
4588                                 {\r
4589                                         return decodeURIComponent( c.substring(sNameEQ.length,c.length) );\r
4590                                 }\r
4591                         }\r
4592                         return null;\r
4593                 }\r
4594                 \r
4595                 \r
4596                 /**\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
4601                  */\r
4602                 function _fnSettingsFromNode ( nTable )\r
4603                 {\r
4604                         for ( var i=0 ; i<DataTable.settings.length ; i++ )\r
4605                         {\r
4606                                 if ( DataTable.settings[i].nTable === nTable )\r
4607                                 {\r
4608                                         return DataTable.settings[i];\r
4609                                 }\r
4610                         }\r
4611                         \r
4612                         return null;\r
4613                 }\r
4614                 \r
4615                 \r
4616                 /**\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
4621                  */\r
4622                 function _fnGetTrNodes ( oSettings )\r
4623                 {\r
4624                         var aNodes = [];\r
4625                         var aoData = oSettings.aoData;\r
4626                         for ( var i=0, iLen=aoData.length ; i<iLen ; i++ )\r
4627                         {\r
4628                                 if ( aoData[i].nTr !== null )\r
4629                                 {\r
4630                                         aNodes.push( aoData[i].nTr );\r
4631                                 }\r
4632                         }\r
4633                         return aNodes;\r
4634                 }\r
4635                 \r
4636                 \r
4637                 /**\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
4644                  */\r
4645                 function _fnGetTdNodes ( oSettings, iIndividualRow )\r
4646                 {\r
4647                         var anReturn = [];\r
4648                         var iCorrector;\r
4649                         var anTds, nTd;\r
4650                         var iRow, iRows=oSettings.aoData.length,\r
4651                                 iColumn, iColumns, oData, sNodeName, iStart=0, iEnd=iRows;\r
4652                         \r
4653                         /* Allow the collection to be limited to just one row */\r
4654                         if ( iIndividualRow !== undefined )\r
4655                         {\r
4656                                 iStart = iIndividualRow;\r
4657                                 iEnd = iIndividualRow+1;\r
4658                         }\r
4659                 \r
4660                         for ( iRow=iStart ; iRow<iEnd ; iRow++ )\r
4661                         {\r
4662                                 oData = oSettings.aoData[iRow];\r
4663                                 if ( oData.nTr !== null )\r
4664                                 {\r
4665                                         /* get the TD child nodes - taking into account text etc nodes */\r
4666                                         anTds = [];\r
4667                                         nTd = oData.nTr.firstChild;\r
4668                                         while ( nTd )\r
4669                                         {\r
4670                                                 sNodeName = nTd.nodeName.toLowerCase();\r
4671                                                 if ( sNodeName == 'td' || sNodeName == 'th' )\r
4672                                                 {\r
4673                                                         anTds.push( nTd );\r
4674                                                 }\r
4675                                                 nTd = nTd.nextSibling;\r
4676                                         }\r
4677                 \r
4678                                         iCorrector = 0;\r
4679                                         for ( iColumn=0, iColumns=oSettings.aoColumns.length ; iColumn<iColumns ; iColumn++ )\r
4680                                         {\r
4681                                                 if ( oSettings.aoColumns[iColumn].bVisible )\r
4682                                                 {\r
4683                                                         anReturn.push( anTds[iColumn-iCorrector] );\r
4684                                                 }\r
4685                                                 else\r
4686                                                 {\r
4687                                                         anReturn.push( oData._anHidden[iColumn] );\r
4688                                                         iCorrector++;\r
4689                                                 }\r
4690                                         }\r
4691                                 }\r
4692                         }\r
4693                 \r
4694                         return anReturn;\r
4695                 }\r
4696                 \r
4697                 \r
4698                 /**\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
4704                  */\r
4705                 function _fnLog( oSettings, iLevel, sMesg )\r
4706                 {\r
4707                         var sAlert = (oSettings===null) ?\r
4708                                 "DataTables warning: "+sMesg :\r
4709                                 "DataTables warning (table id = '"+oSettings.sTableId+"'): "+sMesg;\r
4710                         \r
4711                         if ( iLevel === 0 )\r
4712                         {\r
4713                                 if ( DataTable.ext.sErrMode == 'alert' )\r
4714                                 {\r
4715                                         alert( sAlert );\r
4716                                 }\r
4717                                 else\r
4718                                 {\r
4719                                         throw new Error(sAlert);\r
4720                                 }\r
4721                                 return;\r
4722                         }\r
4723                         else if ( window.console && console.log )\r
4724                         {\r
4725                                 console.log( sAlert );\r
4726                         }\r
4727                 }\r
4728                 \r
4729                 \r
4730                 /**\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
4737                  */\r
4738                 function _fnMap( oRet, oSrc, sName, sMappedName )\r
4739                 {\r
4740                         if ( sMappedName === undefined )\r
4741                         {\r
4742                                 sMappedName = sName;\r
4743                         }\r
4744                         if ( oSrc[sName] !== undefined )\r
4745                         {\r
4746                                 oRet[sMappedName] = oSrc[sName];\r
4747                         }\r
4748                 }\r
4749                 \r
4750                 \r
4751                 /**\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
4761                  */\r
4762                 function _fnExtend( oOut, oExtender )\r
4763                 {\r
4764                         var val;\r
4765                         \r
4766                         for ( var prop in oExtender )\r
4767                         {\r
4768                                 if ( oExtender.hasOwnProperty(prop) )\r
4769                                 {\r
4770                                         val = oExtender[prop];\r
4771                 \r
4772                                         if ( typeof oInit[prop] === 'object' && val !== null && $.isArray(val) === false )\r
4773                                         {\r
4774                                                 $.extend( true, oOut[prop], val );\r
4775                                         }\r
4776                                         else\r
4777                                         {\r
4778                                                 oOut[prop] = val;\r
4779                                         }\r
4780                                 }\r
4781                         }\r
4782                 \r
4783                         return oOut;\r
4784                 }\r
4785                 \r
4786                 \r
4787                 /**\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
4795                  */\r
4796                 function _fnBindAction( n, oData, fn )\r
4797                 {\r
4798                         $(n)\r
4799                                 .bind( 'click.DT', oData, function (e) {\r
4800                                                 n.blur(); // Remove focus outline for mouse users\r
4801                                                 fn(e);\r
4802                                         } )\r
4803                                 .bind( 'keypress.DT', oData, function (e){\r
4804                                         if ( e.which === 13 ) {\r
4805                                                 fn(e);\r
4806                                         } } )\r
4807                                 .bind( 'selectstart.DT', function () {\r
4808                                         /* Take the brutal approach to cancelling text selection */\r
4809                                         return false;\r
4810                                         } );\r
4811                 }\r
4812                 \r
4813                 \r
4814                 /**\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
4822                  */\r
4823                 function _fnCallbackReg( oSettings, sStore, fn, sName )\r
4824                 {\r
4825                         if ( fn )\r
4826                         {\r
4827                                 oSettings[sStore].push( {\r
4828                                         "fn": fn,\r
4829                                         "sName": sName\r
4830                                 } );\r
4831                         }\r
4832                 }\r
4833                 \r
4834                 \r
4835                 /**\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
4842                  *    is fired\r
4843                  *  @param {array} aArgs Array of arguments to pass to the callback function / trigger\r
4844                  *  @memberof DataTable#oApi\r
4845                  */\r
4846                 function _fnCallbackFire( oSettings, sStore, sTrigger, aArgs )\r
4847                 {\r
4848                         var aoStore = oSettings[sStore];\r
4849                         var aRet =[];\r
4850                 \r
4851                         for ( var i=aoStore.length-1 ; i>=0 ; i-- )\r
4852                         {\r
4853                                 aRet.push( aoStore[i].fn.apply( oSettings.oInstance, aArgs ) );\r
4854                         }\r
4855                 \r
4856                         if ( sTrigger !== null )\r
4857                         {\r
4858                                 $(oSettings.oInstance).trigger(sTrigger, aArgs);\r
4859                         }\r
4860                 \r
4861                         return aRet;\r
4862                 }\r
4863                 \r
4864                 \r
4865                 /**\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
4875                  */\r
4876                 var _fnJsonString = (window.JSON) ? JSON.stringify : function( o )\r
4877                 {\r
4878                         /* Not an object or array */\r
4879                         var sType = typeof o;\r
4880                         if (sType !== "object" || o === null)\r
4881                         {\r
4882                                 // simple data type\r
4883                                 if (sType === "string")\r
4884                                 {\r
4885                                         o = '"'+o+'"';\r
4886                                 }\r
4887                                 return o+"";\r
4888                         }\r
4889                 \r
4890                         /* If object or array, need to recurse over it */\r
4891                         var\r
4892                                 sProp, mValue,\r
4893                                 json = [],\r
4894                                 bArr = $.isArray(o);\r
4895                         \r
4896                         for (sProp in o)\r
4897                         {\r
4898                                 mValue = o[sProp];\r
4899                                 sType = typeof mValue;\r
4900                 \r
4901                                 if (sType === "string")\r
4902                                 {\r
4903                                         mValue = '"'+mValue+'"';\r
4904                                 }\r
4905                                 else if (sType === "object" && mValue !== null)\r
4906                                 {\r
4907                                         mValue = _fnJsonString(mValue);\r
4908                                 }\r
4909                 \r
4910                                 json.push((bArr ? "" : '"'+sProp+'":') + mValue);\r
4911                         }\r
4912                 \r
4913                         return (bArr ? "[" : "{") + json + (bArr ? "]" : "}");\r
4914                 };\r
4915                 \r
4916                 \r
4917                 /**\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
4922                  */\r
4923                 function _fnBrowserDetect( oSettings )\r
4924                 {\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
4928                          */\r
4929                         var n = $(\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
4933                                         '</div>'+\r
4934                                 '</div>')[0];\r
4935                 \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
4939                 }\r
4940                 \r
4941 \r
4942                 /**\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
4956                  *  @dtopt API\r
4957                  *\r
4958                  *  @example\r
4959                  *    $(document).ready(function() {\r
4960                  *      var oTable = $('#example').dataTable();\r
4961                  *\r
4962                  *      // Highlight every second row\r
4963                  *      oTable.$('tr:odd').css('backgroundColor', 'blue');\r
4964                  *    } );\r
4965                  *\r
4966                  *  @example\r
4967                  *    $(document).ready(function() {\r
4968                  *      var oTable = $('#example').dataTable();\r
4969                  *\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
4975                  *    } );\r
4976                  */\r
4977                 this.$ = function ( sSelector, oOpts )\r
4978                 {\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
4984                 \r
4985                         if ( !oOpts )\r
4986                         {\r
4987                                 oOpts = {};\r
4988                         }\r
4989                 \r
4990                         oOpts = $.extend( {}, {\r
4991                                 "filter": "none", // applied\r
4992                                 "order": "current", // "original"\r
4993                                 "page": "all" // current\r
4994                         }, oOpts );\r
4995                 \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
4999                         {\r
5000                                 for ( i=oSettings._iDisplayStart, iLen=oSettings.fnDisplayEnd() ; i<iLen ; i++ )\r
5001                                 {\r
5002                                         tr = aoData[ aiDisplay[i] ].nTr;\r
5003                                         if ( tr )\r
5004                                         {\r
5005                                                 a.push( tr );\r
5006                                         }\r
5007                                 }\r
5008                         }\r
5009                         else if ( oOpts.order == "current" && oOpts.filter == "none" )\r
5010                         {\r
5011                                 for ( i=0, iLen=aiDisplayMaster.length ; i<iLen ; i++ )\r
5012                                 {\r
5013                                         tr = aoData[ aiDisplayMaster[i] ].nTr;\r
5014                                         if ( tr )\r
5015                                         {\r
5016                                                 a.push( tr );\r
5017                                         }\r
5018                                 }\r
5019                         }\r
5020                         else if ( oOpts.order == "current" && oOpts.filter == "applied" )\r
5021                         {\r
5022                                 for ( i=0, iLen=aiDisplay.length ; i<iLen ; i++ )\r
5023                                 {\r
5024                                         tr = aoData[ aiDisplay[i] ].nTr;\r
5025                                         if ( tr )\r
5026                                         {\r
5027                                                 a.push( tr );\r
5028                                         }\r
5029                                 }\r
5030                         }\r
5031                         else if ( oOpts.order == "original" && oOpts.filter == "none" )\r
5032                         {\r
5033                                 for ( i=0, iLen=aoData.length ; i<iLen ; i++ )\r
5034                                 {\r
5035                                         tr = aoData[ i ].nTr ;\r
5036                                         if ( tr )\r
5037                                         {\r
5038                                                 a.push( tr );\r
5039                                         }\r
5040                                 }\r
5041                         }\r
5042                         else if ( oOpts.order == "original" && oOpts.filter == "applied" )\r
5043                         {\r
5044                                 for ( i=0, iLen=aoData.length ; i<iLen ; i++ )\r
5045                                 {\r
5046                                         tr = aoData[ i ].nTr;\r
5047                                         if ( $.inArray( i, aiDisplay ) !== -1 && tr )\r
5048                                         {\r
5049                                                 a.push( tr );\r
5050                                         }\r
5051                                 }\r
5052                         }\r
5053                         else\r
5054                         {\r
5055                                 _fnLog( oSettings, 1, "Unknown selection options" );\r
5056                         }\r
5057                 \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
5061                          */\r
5062                         var jqA = $(a);\r
5063                         var jqTRs = jqA.filter( sSelector );\r
5064                         var jqDescendants = jqA.find( sSelector );\r
5065                 \r
5066                         return $( [].concat($.makeArray(jqTRs), $.makeArray(jqDescendants)) );\r
5067                 };\r
5068                 \r
5069                 \r
5070                 /**\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
5076                  *\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
5092                  *  @dtopt API\r
5093                  *\r
5094                  *  @example\r
5095                  *    $(document).ready(function() {\r
5096                  *      var oTable = $('#example').dataTable();\r
5097                  *\r
5098                  *      // Get the data from the first row in the table\r
5099                  *      var data = oTable._('tr:first');\r
5100                  *\r
5101                  *      // Do something useful with the data\r
5102                  *      alert( "First cell is: "+data[0] );\r
5103                  *    } );\r
5104                  *\r
5105                  *  @example\r
5106                  *    $(document).ready(function() {\r
5107                  *      var oTable = $('#example').dataTable();\r
5108                  *\r
5109                  *      // Filter to 'Webkit' and get all data for \r
5110                  *      oTable.fnFilter('Webkit');\r
5111                  *      var data = oTable._('tr', {"filter": "applied"});\r
5112                  *      \r
5113                  *      // Do something with the data\r
5114                  *      alert( data.length+" rows matched the filter" );\r
5115                  *    } );\r
5116                  */\r
5117                 this._ = function ( sSelector, oOpts )\r
5118                 {\r
5119                         var aOut = [];\r
5120                         var i, iLen, iIndex;\r
5121                         var aTrs = this.$( sSelector, oOpts );\r
5122                 \r
5123                         for ( i=0, iLen=aTrs.length ; i<iLen ; i++ )\r
5124                         {\r
5125                                 aOut.push( this.fnGetData(aTrs[i]) );\r
5126                         }\r
5127                 \r
5128                         return aOut;\r
5129                 };\r
5130                 \r
5131                 \r
5132                 /**\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
5138                  *    <ul>\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
5143                  *    </ul>\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
5147                  *    the table.\r
5148                  *  @dtopt API\r
5149                  *\r
5150                  *  @example\r
5151                  *    // Global var for counter\r
5152                  *    var giCount = 2;\r
5153                  *    \r
5154                  *    $(document).ready(function() {\r
5155                  *      $('#example').dataTable();\r
5156                  *    } );\r
5157                  *    \r
5158                  *    function fnClickAddRow() {\r
5159                  *      $('#example').dataTable().fnAddData( [\r
5160                  *        giCount+".1",\r
5161                  *        giCount+".2",\r
5162                  *        giCount+".3",\r
5163                  *        giCount+".4" ]\r
5164                  *      );\r
5165                  *        \r
5166                  *      giCount++;\r
5167                  *    }\r
5168                  */\r
5169                 this.fnAddData = function( mData, bRedraw )\r
5170                 {\r
5171                         if ( mData.length === 0 )\r
5172                         {\r
5173                                 return [];\r
5174                         }\r
5175                         \r
5176                         var aiReturn = [];\r
5177                         var iTest;\r
5178                         \r
5179                         /* Find settings from table node */\r
5180                         var oSettings = _fnSettingsFromNode( this[DataTable.ext.iApiIndex] );\r
5181                         \r
5182                         /* Check if we want to add multiple rows or not */\r
5183                         if ( typeof mData[0] === "object" && mData[0] !== null )\r
5184                         {\r
5185                                 for ( var i=0 ; i<mData.length ; i++ )\r
5186                                 {\r
5187                                         iTest = _fnAddData( oSettings, mData[i] );\r
5188                                         if ( iTest == -1 )\r
5189                                         {\r
5190                                                 return aiReturn;\r
5191                                         }\r
5192                                         aiReturn.push( iTest );\r
5193                                 }\r
5194                         }\r
5195                         else\r
5196                         {\r
5197                                 iTest = _fnAddData( oSettings, mData );\r
5198                                 if ( iTest == -1 )\r
5199                                 {\r
5200                                         return aiReturn;\r
5201                                 }\r
5202                                 aiReturn.push( iTest );\r
5203                         }\r
5204                         \r
5205                         oSettings.aiDisplay = oSettings.aiDisplayMaster.slice();\r
5206                         \r
5207                         if ( bRedraw === undefined || bRedraw )\r
5208                         {\r
5209                                 _fnReDraw( oSettings );\r
5210                         }\r
5211                         return aiReturn;\r
5212                 };\r
5213                 \r
5214                 \r
5215                 /**\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
5221                  *  @dtopt API\r
5222                  *\r
5223                  *  @example\r
5224                  *    $(document).ready(function() {\r
5225                  *      var oTable = $('#example').dataTable( {\r
5226                  *        "sScrollY": "200px",\r
5227                  *        "bPaginate": false\r
5228                  *      } );\r
5229                  *      \r
5230                  *      $(window).bind('resize', function () {\r
5231                  *        oTable.fnAdjustColumnSizing();\r
5232                  *      } );\r
5233                  *    } );\r
5234                  */\r
5235                 this.fnAdjustColumnSizing = function ( bRedraw )\r
5236                 {\r
5237                         var oSettings = _fnSettingsFromNode(this[DataTable.ext.iApiIndex]);\r
5238                         _fnAdjustColumnSizing( oSettings );\r
5239                         \r
5240                         if ( bRedraw === undefined || bRedraw )\r
5241                         {\r
5242                                 this.fnDraw( false );\r
5243                         }\r
5244                         else if ( oSettings.oScroll.sX !== "" || oSettings.oScroll.sY !== "" )\r
5245                         {\r
5246                                 /* If not redrawing, but scrolling, we want to apply the new column sizes anyway */\r
5247                                 this.oApi._fnScrollDraw(oSettings);\r
5248                         }\r
5249                 };\r
5250                 \r
5251                 \r
5252                 /**\r
5253                  * Quickly and simply clear a table\r
5254                  *  @param {bool} [bRedraw=true] redraw the table or not\r
5255                  *  @dtopt API\r
5256                  *\r
5257                  *  @example\r
5258                  *    $(document).ready(function() {\r
5259                  *      var oTable = $('#example').dataTable();\r
5260                  *      \r
5261                  *      // Immediately 'nuke' the current rows (perhaps waiting for an Ajax callback...)\r
5262                  *      oTable.fnClearTable();\r
5263                  *    } );\r
5264                  */\r
5265                 this.fnClearTable = function( bRedraw )\r
5266                 {\r
5267                         /* Find settings from table node */\r
5268                         var oSettings = _fnSettingsFromNode( this[DataTable.ext.iApiIndex] );\r
5269                         _fnClearTable( oSettings );\r
5270                         \r
5271                         if ( bRedraw === undefined || bRedraw )\r
5272                         {\r
5273                                 _fnDraw( oSettings );\r
5274                         }\r
5275                 };\r
5276                 \r
5277                 \r
5278                 /**\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
5283                  *  @dtopt API\r
5284                  *\r
5285                  *  @example\r
5286                  *    $(document).ready(function() {\r
5287                  *      var oTable;\r
5288                  *      \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
5293                  *        } else {\r
5294                  *          oTable.fnOpen( this, "Temporary row opened", "info_row" );\r
5295                  *        }\r
5296                  *      } );\r
5297                  *      \r
5298                  *      oTable = $('#example').dataTable();\r
5299                  *    } );\r
5300                  */\r
5301                 this.fnClose = function( nTr )\r
5302                 {\r
5303                         /* Find settings from table node */\r
5304                         var oSettings = _fnSettingsFromNode( this[DataTable.ext.iApiIndex] );\r
5305                         \r
5306                         for ( var i=0 ; i<oSettings.aoOpenRows.length ; i++ )\r
5307                         {\r
5308                                 if ( oSettings.aoOpenRows[i].nParent == nTr )\r
5309                                 {\r
5310                                         var nTrParent = oSettings.aoOpenRows[i].nTr.parentNode;\r
5311                                         if ( nTrParent )\r
5312                                         {\r
5313                                                 /* Remove it if it is currently on display */\r
5314                                                 nTrParent.removeChild( oSettings.aoOpenRows[i].nTr );\r
5315                                         }\r
5316                                         oSettings.aoOpenRows.splice( i, 1 );\r
5317                                         return 0;\r
5318                                 }\r
5319                         }\r
5320                         return 1;\r
5321                 };\r
5322                 \r
5323                 \r
5324                 /**\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
5331                  *  @dtopt API\r
5332                  *\r
5333                  *  @example\r
5334                  *    $(document).ready(function() {\r
5335                  *      var oTable = $('#example').dataTable();\r
5336                  *      \r
5337                  *      // Immediately remove the first row\r
5338                  *      oTable.fnDeleteRow( 0 );\r
5339                  *    } );\r
5340                  */\r
5341                 this.fnDeleteRow = function( mTarget, fnCallBack, bRedraw )\r
5342                 {\r
5343                         /* Find settings from table node */\r
5344                         var oSettings = _fnSettingsFromNode( this[DataTable.ext.iApiIndex] );\r
5345                         var i, iLen, iAODataIndex;\r
5346                         \r
5347                         iAODataIndex = (typeof mTarget === 'object') ? \r
5348                                 _fnNodeToDataIndex(oSettings, mTarget) : mTarget;\r
5349                         \r
5350                         /* Return the data array from this row */\r
5351                         var oData = oSettings.aoData.splice( iAODataIndex, 1 );\r
5352                 \r
5353                         /* Update the _DT_RowIndex parameter */\r
5354                         for ( i=0, iLen=oSettings.aoData.length ; i<iLen ; i++ )\r
5355                         {\r
5356                                 if ( oSettings.aoData[i].nTr !== null )\r
5357                                 {\r
5358                                         oSettings.aoData[i].nTr._DT_RowIndex = i;\r
5359                                 }\r
5360                         }\r
5361                         \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
5365                         \r
5366                         /* Delete from the display arrays */\r
5367                         _fnDeleteIndex( oSettings.aiDisplayMaster, iAODataIndex );\r
5368                         _fnDeleteIndex( oSettings.aiDisplay, iAODataIndex );\r
5369                         \r
5370                         /* If there is a user callback function - call it */\r
5371                         if ( typeof fnCallBack === "function" )\r
5372                         {\r
5373                                 fnCallBack.call( this, oSettings, oData );\r
5374                         }\r
5375                         \r
5376                         /* Check for an 'overflow' they case for displaying the table */\r
5377                         if ( oSettings._iDisplayStart >= oSettings.fnRecordsDisplay() )\r
5378                         {\r
5379                                 oSettings._iDisplayStart -= oSettings._iDisplayLength;\r
5380                                 if ( oSettings._iDisplayStart < 0 )\r
5381                                 {\r
5382                                         oSettings._iDisplayStart = 0;\r
5383                                 }\r
5384                         }\r
5385                         \r
5386                         if ( bRedraw === undefined || bRedraw )\r
5387                         {\r
5388                                 _fnCalculateEnd( oSettings );\r
5389                                 _fnDraw( oSettings );\r
5390                         }\r
5391                         \r
5392                         return oData;\r
5393                 };\r
5394                 \r
5395                 \r
5396                 /**\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
5400                  *  @dtopt API\r
5401                  *\r
5402                  *  @example\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
5407                  *    } );\r
5408                  */\r
5409                 this.fnDestroy = function ( bRemove )\r
5410                 {\r
5411                         var oSettings = _fnSettingsFromNode( this[DataTable.ext.iApiIndex] );\r
5412                         var nOrig = oSettings.nTableWrapper.parentNode;\r
5413                         var nBody = oSettings.nTBody;\r
5414                         var i, iLen;\r
5415                 \r
5416                         bRemove = (bRemove===undefined) ? false : bRemove;\r
5417                         \r
5418                         /* Flag to note that the table is currently being destroyed - no action should be taken */\r
5419                         oSettings.bDestroying = true;\r
5420                         \r
5421                         /* Fire off the destroy callbacks for plug-ins etc */\r
5422                         _fnCallbackFire( oSettings, "aoDestroyCallback", "destroy", [oSettings] );\r
5423                 \r
5424                         /* If the table is not being removed, restore the hidden columns */\r
5425                         if ( !bRemove )\r
5426                         {\r
5427                                 for ( i=0, iLen=oSettings.aoColumns.length ; i<iLen ; i++ )\r
5428                                 {\r
5429                                         if ( oSettings.aoColumns[i].bVisible === false )\r
5430                                         {\r
5431                                                 this.fnSetColumnVis( i, true );\r
5432                                         }\r
5433                                 }\r
5434                         }\r
5435                         \r
5436                         /* Blitz all DT events */\r
5437                         $(oSettings.nTableWrapper).find('*').andSelf().unbind('.DT');\r
5438                         \r
5439                         /* If there is an 'empty' indicator row, remove it */\r
5440                         $('tbody>tr>td.'+oSettings.oClasses.sRowEmpty, oSettings.nTable).parent().remove();\r
5441                         \r
5442                         /* When scrolling we had to break the table up - restore it */\r
5443                         if ( oSettings.nTable != oSettings.nTHead.parentNode )\r
5444                         {\r
5445                                 $(oSettings.nTable).children('thead').remove();\r
5446                                 oSettings.nTable.appendChild( oSettings.nTHead );\r
5447                         }\r
5448                         \r
5449                         if ( oSettings.nTFoot && oSettings.nTable != oSettings.nTFoot.parentNode )\r
5450                         {\r
5451                                 $(oSettings.nTable).children('tfoot').remove();\r
5452                                 oSettings.nTable.appendChild( oSettings.nTFoot );\r
5453                         }\r
5454                         \r
5455                         /* Remove the DataTables generated nodes, events and classes */\r
5456                         oSettings.nTable.parentNode.removeChild( oSettings.nTable );\r
5457                         $(oSettings.nTableWrapper).remove();\r
5458                         \r
5459                         oSettings.aaSorting = [];\r
5460                         oSettings.aaSortingFixed = [];\r
5461                         _fnSortingClasses( oSettings );\r
5462                         \r
5463                         $(_fnGetTrNodes( oSettings )).removeClass( oSettings.asStripeClasses.join(' ') );\r
5464                         \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
5470                         );\r
5471                         if ( oSettings.bJUI )\r
5472                         {\r
5473                                 $('th span.'+oSettings.oClasses.sSortIcon\r
5474                                         + ', td span.'+oSettings.oClasses.sSortIcon, oSettings.nTHead).remove();\r
5475                 \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
5481                                 } );\r
5482                         }\r
5483                         \r
5484                         /* Add the TR elements back into the table in their original order */\r
5485                         if ( !bRemove && oSettings.nTableReinsertBefore )\r
5486                         {\r
5487                                 nOrig.insertBefore( oSettings.nTable, oSettings.nTableReinsertBefore );\r
5488                         }\r
5489                         else if ( !bRemove )\r
5490                         {\r
5491                                 nOrig.appendChild( oSettings.nTable );\r
5492                         }\r
5493                 \r
5494                         for ( i=0, iLen=oSettings.aoData.length ; i<iLen ; i++ )\r
5495                         {\r
5496                                 if ( oSettings.aoData[i].nTr !== null )\r
5497                                 {\r
5498                                         nBody.appendChild( oSettings.aoData[i].nTr );\r
5499                                 }\r
5500                         }\r
5501                         \r
5502                         /* Restore the width of the original table */\r
5503                         if ( oSettings.oFeatures.bAutoWidth === true )\r
5504                         {\r
5505                           oSettings.nTable.style.width = _fnStringToCss(oSettings.sDestroyWidth);\r
5506                         }\r
5507                         \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
5511                          */\r
5512                         iLen = oSettings.asDestroyStripes.length;\r
5513                         if (iLen)\r
5514                         {\r
5515                                 var anRows = $(nBody).children('tr');\r
5516                                 for ( i=0 ; i<iLen ; i++ )\r
5517                                 {\r
5518                                         anRows.filter(':nth-child(' + iLen + 'n + ' + i + ')').addClass( oSettings.asDestroyStripes[i] );\r
5519                                 }\r
5520                         }\r
5521                         \r
5522                         /* Remove the settings object from the settings array */\r
5523                         for ( i=0, iLen=DataTable.settings.length ; i<iLen ; i++ )\r
5524                         {\r
5525                                 if ( DataTable.settings[i] == oSettings )\r
5526                                 {\r
5527                                         DataTable.settings.splice( i, 1 );\r
5528                                 }\r
5529                         }\r
5530                         \r
5531                         /* End it all */\r
5532                         oSettings = null;\r
5533                         oInit = null;\r
5534                 };\r
5535                 \r
5536                 \r
5537                 /**\r
5538                  * Redraw the table\r
5539                  *  @param {bool} [bComplete=true] Re-filter and resort (if enabled) the table before the draw.\r
5540                  *  @dtopt API\r
5541                  *\r
5542                  *  @example\r
5543                  *    $(document).ready(function() {\r
5544                  *      var oTable = $('#example').dataTable();\r
5545                  *      \r
5546                  *      // Re-draw the table - you wouldn't want to do it here, but it's an example :-)\r
5547                  *      oTable.fnDraw();\r
5548                  *    } );\r
5549                  */\r
5550                 this.fnDraw = function( bComplete )\r
5551                 {\r
5552                         var oSettings = _fnSettingsFromNode( this[DataTable.ext.iApiIndex] );\r
5553                         if ( bComplete === false )\r
5554                         {\r
5555                                 _fnCalculateEnd( oSettings );\r
5556                                 _fnDraw( oSettings );\r
5557                         }\r
5558                         else\r
5559                         {\r
5560                                 _fnReDraw( oSettings );\r
5561                         }\r
5562                 };\r
5563                 \r
5564                 \r
5565                 /**\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
5573                  *  @dtopt API\r
5574                  *\r
5575                  *  @example\r
5576                  *    $(document).ready(function() {\r
5577                  *      var oTable = $('#example').dataTable();\r
5578                  *      \r
5579                  *      // Sometime later - filter...\r
5580                  *      oTable.fnFilter( 'test string' );\r
5581                  *    } );\r
5582                  */\r
5583                 this.fnFilter = function( sInput, iColumn, bRegex, bSmart, bShowGlobal, bCaseInsensitive )\r
5584                 {\r
5585                         var oSettings = _fnSettingsFromNode( this[DataTable.ext.iApiIndex] );\r
5586                         \r
5587                         if ( !oSettings.oFeatures.bFilter )\r
5588                         {\r
5589                                 return;\r
5590                         }\r
5591                         \r
5592                         if ( bRegex === undefined || bRegex === null )\r
5593                         {\r
5594                                 bRegex = false;\r
5595                         }\r
5596                         \r
5597                         if ( bSmart === undefined || bSmart === null )\r
5598                         {\r
5599                                 bSmart = true;\r
5600                         }\r
5601                         \r
5602                         if ( bShowGlobal === undefined || bShowGlobal === null )\r
5603                         {\r
5604                                 bShowGlobal = true;\r
5605                         }\r
5606                         \r
5607                         if ( bCaseInsensitive === undefined || bCaseInsensitive === null )\r
5608                         {\r
5609                                 bCaseInsensitive = true;\r
5610                         }\r
5611                         \r
5612                         if ( iColumn === undefined || iColumn === null )\r
5613                         {\r
5614                                 /* Global filter */\r
5615                                 _fnFilterComplete( oSettings, {\r
5616                                         "sSearch":sInput+"",\r
5617                                         "bRegex": bRegex,\r
5618                                         "bSmart": bSmart,\r
5619                                         "bCaseInsensitive": bCaseInsensitive\r
5620                                 }, 1 );\r
5621                                 \r
5622                                 if ( bShowGlobal && oSettings.aanFeatures.f )\r
5623                                 {\r
5624                                         var n = oSettings.aanFeatures.f;\r
5625                                         for ( var i=0, iLen=n.length ; i<iLen ; i++ )\r
5626                                         {\r
5627                                                 // IE9 throws an 'unknown error' if document.activeElement is used\r
5628                                                 // inside an iframe or frame...\r
5629                                                 try {\r
5630                                                         if ( n[i]._DT_Input != document.activeElement )\r
5631                                                         {\r
5632                                                                 $(n[i]._DT_Input).val( sInput );\r
5633                                                         }\r
5634                                                 }\r
5635                                                 catch ( e ) {\r
5636                                                         $(n[i]._DT_Input).val( sInput );\r
5637                                                 }\r
5638                                         }\r
5639                                 }\r
5640                         }\r
5641                         else\r
5642                         {\r
5643                                 /* Single column filter */\r
5644                                 $.extend( oSettings.aoPreSearchCols[ iColumn ], {\r
5645                                         "sSearch": sInput+"",\r
5646                                         "bRegex": bRegex,\r
5647                                         "bSmart": bSmart,\r
5648                                         "bCaseInsensitive": bCaseInsensitive\r
5649                                 } );\r
5650                                 _fnFilterComplete( oSettings, oSettings.oPreviousSearch, 1 );\r
5651                         }\r
5652                 };\r
5653                 \r
5654                 \r
5655                 /**\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
5667                  *  @dtopt API\r
5668                  *\r
5669                  *  @example\r
5670                  *    // Row data\r
5671                  *    $(document).ready(function() {\r
5672                  *      oTable = $('#example').dataTable();\r
5673                  *\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
5677                  *      } );\r
5678                  *    } );\r
5679                  *\r
5680                  *  @example\r
5681                  *    // Individual cell data\r
5682                  *    $(document).ready(function() {\r
5683                  *      oTable = $('#example').dataTable();\r
5684                  *\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
5688                  *      } );\r
5689                  *    } );\r
5690                  */\r
5691                 this.fnGetData = function( mRow, iCol )\r
5692                 {\r
5693                         var oSettings = _fnSettingsFromNode( this[DataTable.ext.iApiIndex] );\r
5694                         \r
5695                         if ( mRow !== undefined )\r
5696                         {\r
5697                                 var iRow = mRow;\r
5698                                 if ( typeof mRow === 'object' )\r
5699                                 {\r
5700                                         var sNode = mRow.nodeName.toLowerCase();\r
5701                                         if (sNode === "tr" )\r
5702                                         {\r
5703                                                 iRow = _fnNodeToDataIndex(oSettings, mRow);\r
5704                                         }\r
5705                                         else if ( sNode === "td" )\r
5706                                         {\r
5707                                                 iRow = _fnNodeToDataIndex(oSettings, mRow.parentNode);\r
5708                                                 iCol = _fnNodeToColumnIndex( oSettings, iRow, mRow );\r
5709                                         }\r
5710                                 }\r
5711                 \r
5712                                 if ( iCol !== undefined )\r
5713                                 {\r
5714                                         return _fnGetCellData( oSettings, iRow, iCol, '' );\r
5715                                 }\r
5716                                 return (oSettings.aoData[iRow]!==undefined) ?\r
5717                                         oSettings.aoData[iRow]._aData : null;\r
5718                         }\r
5719                         return _fnGetDataMaster( oSettings );\r
5720                 };\r
5721                 \r
5722                 \r
5723                 /**\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
5726                  * flexible.\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
5730                  *  @dtopt API\r
5731                  *\r
5732                  *  @example\r
5733                  *    $(document).ready(function() {\r
5734                  *      var oTable = $('#example').dataTable();\r
5735                  *      \r
5736                  *      // Get the nodes from the table\r
5737                  *      var nNodes = oTable.fnGetNodes( );\r
5738                  *    } );\r
5739                  */\r
5740                 this.fnGetNodes = function( iRow )\r
5741                 {\r
5742                         var oSettings = _fnSettingsFromNode( this[DataTable.ext.iApiIndex] );\r
5743                         \r
5744                         if ( iRow !== undefined ) {\r
5745                                 return (oSettings.aoData[iRow]!==undefined) ?\r
5746                                         oSettings.aoData[iRow].nTr : null;\r
5747                         }\r
5748                         return _fnGetTrNodes( oSettings );\r
5749                 };\r
5750                 \r
5751                 \r
5752                 /**\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
5759                  *  @dtopt API\r
5760                  *\r
5761                  *  @example\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
5766                  *        \r
5767                  *        // Get the data array for this row\r
5768                  *        var aData = oTable.fnGetData( aPos[0] );\r
5769                  *        \r
5770                  *        // Update the data array and return the value\r
5771                  *        aData[ aPos[1] ] = 'clicked';\r
5772                  *        this.innerHTML = 'clicked';\r
5773                  *      } );\r
5774                  *      \r
5775                  *      // Init DataTables\r
5776                  *      oTable = $('#example').dataTable();\r
5777                  *    } );\r
5778                  */\r
5779                 this.fnGetPosition = function( nNode )\r
5780                 {\r
5781                         var oSettings = _fnSettingsFromNode( this[DataTable.ext.iApiIndex] );\r
5782                         var sNodeName = nNode.nodeName.toUpperCase();\r
5783                         \r
5784                         if ( sNodeName == "TR" )\r
5785                         {\r
5786                                 return _fnNodeToDataIndex(oSettings, nNode);\r
5787                         }\r
5788                         else if ( sNodeName == "TD" || sNodeName == "TH" )\r
5789                         {\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
5793                         }\r
5794                         return null;\r
5795                 };\r
5796                 \r
5797                 \r
5798                 /**\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
5802                  *  @dtopt API\r
5803                  *\r
5804                  *  @example\r
5805                  *    $(document).ready(function() {\r
5806                  *      var oTable;\r
5807                  *      \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
5812                  *        } else {\r
5813                  *          oTable.fnOpen( this, "Temporary row opened", "info_row" );\r
5814                  *        }\r
5815                  *      } );\r
5816                  *      \r
5817                  *      oTable = $('#example').dataTable();\r
5818                  *    } );\r
5819                  */\r
5820                 this.fnIsOpen = function( nTr )\r
5821                 {\r
5822                         var oSettings = _fnSettingsFromNode( this[DataTable.ext.iApiIndex] );\r
5823                         var aoOpenRows = oSettings.aoOpenRows;\r
5824                         \r
5825                         for ( var i=0 ; i<oSettings.aoOpenRows.length ; i++ )\r
5826                         {\r
5827                                 if ( oSettings.aoOpenRows[i].nParent == nTr )\r
5828                                 {\r
5829                                         return true;\r
5830                                 }\r
5831                         }\r
5832                         return false;\r
5833                 };\r
5834                 \r
5835                 \r
5836                 /**\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
5846                  *    return.\r
5847                  *  @dtopt API\r
5848                  *\r
5849                  *  @example\r
5850                  *    $(document).ready(function() {\r
5851                  *      var oTable;\r
5852                  *      \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
5857                  *        } else {\r
5858                  *          oTable.fnOpen( this, "Temporary row opened", "info_row" );\r
5859                  *        }\r
5860                  *      } );\r
5861                  *      \r
5862                  *      oTable = $('#example').dataTable();\r
5863                  *    } );\r
5864                  */\r
5865                 this.fnOpen = function( nTr, mHtml, sClass )\r
5866                 {\r
5867                         /* Find settings from table node */\r
5868                         var oSettings = _fnSettingsFromNode( this[DataTable.ext.iApiIndex] );\r
5869                 \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
5873                         {\r
5874                                 return;\r
5875                         }\r
5876                         \r
5877                         /* the old open one if there is one */\r
5878                         this.fnClose( nTr );\r
5879                         \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
5885                 \r
5886                         if (typeof mHtml === "string")\r
5887                         {\r
5888                                 nNewCell.innerHTML = mHtml;\r
5889                         }\r
5890                         else\r
5891                         {\r
5892                                 $(nNewCell).html( mHtml );\r
5893                         }\r
5894                 \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
5898                         {\r
5899                                 $(nNewRow).insertAfter(nTr);\r
5900                         }\r
5901                         \r
5902                         oSettings.aoOpenRows.push( {\r
5903                                 "nTr": nNewRow,\r
5904                                 "nParent": nTr\r
5905                         } );\r
5906                         \r
5907                         return nNewRow;\r
5908                 };\r
5909                 \r
5910                 \r
5911                 /**\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
5918                  *  @dtopt API\r
5919                  *\r
5920                  *  @example\r
5921                  *    $(document).ready(function() {\r
5922                  *      var oTable = $('#example').dataTable();\r
5923                  *      oTable.fnPageChange( 'next' );\r
5924                  *    } );\r
5925                  */\r
5926                 this.fnPageChange = function ( mAction, bRedraw )\r
5927                 {\r
5928                         var oSettings = _fnSettingsFromNode( this[DataTable.ext.iApiIndex] );\r
5929                         _fnPageChange( oSettings, mAction );\r
5930                         _fnCalculateEnd( oSettings );\r
5931                         \r
5932                         if ( bRedraw === undefined || bRedraw )\r
5933                         {\r
5934                                 _fnDraw( oSettings );\r
5935                         }\r
5936                 };\r
5937                 \r
5938                 \r
5939                 /**\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
5944                  *  @dtopt API\r
5945                  *\r
5946                  *  @example\r
5947                  *    $(document).ready(function() {\r
5948                  *      var oTable = $('#example').dataTable();\r
5949                  *      \r
5950                  *      // Hide the second column after initialisation\r
5951                  *      oTable.fnSetColumnVis( 1, false );\r
5952                  *    } );\r
5953                  */\r
5954                 this.fnSetColumnVis = function ( iCol, bShow, bRedraw )\r
5955                 {\r
5956                         var oSettings = _fnSettingsFromNode( this[DataTable.ext.iApiIndex] );\r
5957                         var i, iLen;\r
5958                         var aoColumns = oSettings.aoColumns;\r
5959                         var aoData = oSettings.aoData;\r
5960                         var nTd, bAppend, iBefore;\r
5961                         \r
5962                         /* No point in doing anything if we are requesting what is already true */\r
5963                         if ( aoColumns[iCol].bVisible == bShow )\r
5964                         {\r
5965                                 return;\r
5966                         }\r
5967                         \r
5968                         /* Show the column */\r
5969                         if ( bShow )\r
5970                         {\r
5971                                 var iInsert = 0;\r
5972                                 for ( i=0 ; i<iCol ; i++ )\r
5973                                 {\r
5974                                         if ( aoColumns[i].bVisible )\r
5975                                         {\r
5976                                                 iInsert++;\r
5977                                         }\r
5978                                 }\r
5979                                 \r
5980                                 /* Need to decide if we should use appendChild or insertBefore */\r
5981                                 bAppend = (iInsert >= _fnVisbleColumns( oSettings ));\r
5982                 \r
5983                                 /* Which coloumn should we be inserting before? */\r
5984                                 if ( !bAppend )\r
5985                                 {\r
5986                                         for ( i=iCol ; i<aoColumns.length ; i++ )\r
5987                                         {\r
5988                                                 if ( aoColumns[i].bVisible )\r
5989                                                 {\r
5990                                                         iBefore = i;\r
5991                                                         break;\r
5992                                                 }\r
5993                                         }\r
5994                                 }\r
5995                 \r
5996                                 for ( i=0, iLen=aoData.length ; i<iLen ; i++ )\r
5997                                 {\r
5998                                         if ( aoData[i].nTr !== null )\r
5999                                         {\r
6000                                                 if ( bAppend )\r
6001                                                 {\r
6002                                                         aoData[i].nTr.appendChild( \r
6003                                                                 aoData[i]._anHidden[iCol]\r
6004                                                         );\r
6005                                                 }\r
6006                                                 else\r
6007                                                 {\r
6008                                                         aoData[i].nTr.insertBefore(\r
6009                                                                 aoData[i]._anHidden[iCol], \r
6010                                                                 _fnGetTdNodes( oSettings, i )[iBefore] );\r
6011                                                 }\r
6012                                         }\r
6013                                 }\r
6014                         }\r
6015                         else\r
6016                         {\r
6017                                 /* Remove a column from display */\r
6018                                 for ( i=0, iLen=aoData.length ; i<iLen ; i++ )\r
6019                                 {\r
6020                                         if ( aoData[i].nTr !== null )\r
6021                                         {\r
6022                                                 nTd = _fnGetTdNodes( oSettings, i )[iCol];\r
6023                                                 aoData[i]._anHidden[iCol] = nTd;\r
6024                                                 nTd.parentNode.removeChild( nTd );\r
6025                                         }\r
6026                                 }\r
6027                         }\r
6028                 \r
6029                         /* Clear to set the visible flag */\r
6030                         aoColumns[iCol].bVisible = bShow;\r
6031                 \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
6035                         {\r
6036                                 _fnDrawHead( oSettings, oSettings.aoFooter );\r
6037                         }\r
6038                         \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
6041                         {\r
6042                                 oSettings.aoOpenRows[i].nTr.colSpan = _fnVisbleColumns( oSettings );\r
6043                         }\r
6044                         \r
6045                         /* Do a redraw incase anything depending on the table columns needs it \r
6046                          * (built-in: scrolling) \r
6047                          */\r
6048                         if ( bRedraw === undefined || bRedraw )\r
6049                         {\r
6050                                 _fnAdjustColumnSizing( oSettings );\r
6051                                 _fnDraw( oSettings );\r
6052                         }\r
6053                         \r
6054                         _fnSaveState( oSettings );\r
6055                 };\r
6056                 \r
6057                 \r
6058                 /**\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
6062                  *  @dtopt API\r
6063                  *\r
6064                  *  @example\r
6065                  *    $(document).ready(function() {\r
6066                  *      var oTable = $('#example').dataTable();\r
6067                  *      var oSettings = oTable.fnSettings();\r
6068                  *      \r
6069                  *      // Show an example parameter from the settings\r
6070                  *      alert( oSettings._iDisplayStart );\r
6071                  *    } );\r
6072                  */\r
6073                 this.fnSettings = function()\r
6074                 {\r
6075                         return _fnSettingsFromNode( this[DataTable.ext.iApiIndex] );\r
6076                 };\r
6077                 \r
6078                 \r
6079                 /**\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
6083                  *  @dtopt API\r
6084                  *\r
6085                  *  @example\r
6086                  *    $(document).ready(function() {\r
6087                  *      var oTable = $('#example').dataTable();\r
6088                  *      \r
6089                  *      // Sort immediately with columns 0 and 1\r
6090                  *      oTable.fnSort( [ [0,'asc'], [1,'asc'] ] );\r
6091                  *    } );\r
6092                  */\r
6093                 this.fnSort = function( aaSort )\r
6094                 {\r
6095                         var oSettings = _fnSettingsFromNode( this[DataTable.ext.iApiIndex] );\r
6096                         oSettings.aaSorting = aaSort;\r
6097                         _fnSort( oSettings );\r
6098                 };\r
6099                 \r
6100                 \r
6101                 /**\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
6106                  *  @dtopt API\r
6107                  *\r
6108                  *  @example\r
6109                  *    $(document).ready(function() {\r
6110                  *      var oTable = $('#example').dataTable();\r
6111                  *      \r
6112                  *      // Sort on column 1, when 'sorter' is clicked on\r
6113                  *      oTable.fnSortListener( document.getElementById('sorter'), 1 );\r
6114                  *    } );\r
6115                  */\r
6116                 this.fnSortListener = function( nNode, iColumn, fnCallback )\r
6117                 {\r
6118                         _fnSortAttachListener( _fnSettingsFromNode( this[DataTable.ext.iApiIndex] ), nNode, iColumn,\r
6119                                 fnCallback );\r
6120                 };\r
6121                 \r
6122                 \r
6123                 /**\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
6134                  *  @dtopt API\r
6135                  *\r
6136                  *  @example\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
6141                  *    } );\r
6142                  */\r
6143                 this.fnUpdate = function( mData, mRow, iColumn, bRedraw, bAction )\r
6144                 {\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
6149                         \r
6150                         if ( $.isArray(mData) && iColumn === undefined )\r
6151                         {\r
6152                                 /* Array update - update the whole row */\r
6153                                 oSettings.aoData[iRow]._aData = mData.slice();\r
6154                                 \r
6155                                 /* Flag to the function that we are recursing */\r
6156                                 for ( i=0 ; i<oSettings.aoColumns.length ; i++ )\r
6157                                 {\r
6158                                         this.fnUpdate( _fnGetCellData( oSettings, iRow, i ), iRow, i, false, false );\r
6159                                 }\r
6160                         }\r
6161                         else if ( $.isPlainObject(mData) && iColumn === undefined )\r
6162                         {\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
6165                 \r
6166                                 for ( i=0 ; i<oSettings.aoColumns.length ; i++ )\r
6167                                 {\r
6168                                         this.fnUpdate( _fnGetCellData( oSettings, iRow, i ), iRow, i, false, false );\r
6169                                 }\r
6170                         }\r
6171                         else\r
6172                         {\r
6173                                 /* Individual cell update */\r
6174                                 _fnSetCellData( oSettings, iRow, iColumn, mData );\r
6175                                 sDisplay = _fnGetCellData( oSettings, iRow, iColumn, 'display' );\r
6176                                 \r
6177                                 var oCol = oSettings.aoColumns[iColumn];\r
6178                                 if ( oCol.fnRender !== null )\r
6179                                 {\r
6180                                         sDisplay = _fnRender( oSettings, iRow, iColumn );\r
6181                                         if ( oCol.bUseRendered )\r
6182                                         {\r
6183                                                 _fnSetCellData( oSettings, iRow, iColumn, sDisplay );\r
6184                                         }\r
6185                                 }\r
6186                                 \r
6187                                 if ( oSettings.aoData[iRow].nTr !== null )\r
6188                                 {\r
6189                                         /* Do the actual HTML update */\r
6190                                         _fnGetTdNodes( oSettings, iRow )[iColumn].innerHTML = sDisplay;\r
6191                                 }\r
6192                         }\r
6193                         \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
6196                          */\r
6197                         var iDisplayIndex = $.inArray( iRow, oSettings.aiDisplay );\r
6198                         oSettings.asDataSearch[iDisplayIndex] = _fnBuildSearchRow(\r
6199                                 oSettings, \r
6200                                 _fnGetRowData( oSettings, iRow, 'filter', _fnGetColumns( oSettings, 'bSearchable' ) )\r
6201                         );\r
6202                         \r
6203                         /* Perform pre-draw actions */\r
6204                         if ( bAction === undefined || bAction )\r
6205                         {\r
6206                                 _fnAdjustColumnSizing( oSettings );\r
6207                         }\r
6208                         \r
6209                         /* Redraw the table */\r
6210                         if ( bRedraw === undefined || bRedraw )\r
6211                         {\r
6212                                 _fnReDraw( oSettings );\r
6213                         }\r
6214                         return 0;\r
6215                 };\r
6216                 \r
6217                 \r
6218                 /**\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
6225                  *  @method\r
6226                  *  @dtopt API\r
6227                  *\r
6228                  *  @example\r
6229                  *    $(document).ready(function() {\r
6230                  *      var oTable = $('#example').dataTable();\r
6231                  *      alert( oTable.fnVersionCheck( '1.9.0' ) );\r
6232                  *    } );\r
6233                  */\r
6234                 this.fnVersionCheck = DataTable.ext.fnVersionCheck;\r
6235                 \r
6236                 \r
6237                 /*\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
6240                  */\r
6241                 \r
6242                 \r
6243                 /**\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
6248                  */\r
6249                 function _fnExternApiFunc (sFunc)\r
6250                 {\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
6255                         };\r
6256                 }\r
6257                 \r
6258                 \r
6259                 /**\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
6264                  *  @namespace\r
6265                  */\r
6266                 this.oApi = {\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
6327                         "_fnLog": _fnLog,\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
6337                         "_fnMap": _fnMap,\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
6354                 };\r
6355                 \r
6356                 $.extend( DataTable.ext.oApi, this.oApi );\r
6357                 \r
6358                 for ( var sFunc in DataTable.ext.oApi )\r
6359                 {\r
6360                         if ( sFunc )\r
6361                         {\r
6362                                 this[sFunc] = _fnExternApiFunc(sFunc);\r
6363                         }\r
6364                 }\r
6365                 \r
6366                 \r
6367                 var _that = this;\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
6373                         \r
6374                         \r
6375                         /* Sanity check */\r
6376                         if ( this.nodeName.toLowerCase() != 'table' )\r
6377                         {\r
6378                                 _fnLog( null, 0, "Attempted to initialise DataTables on a node which is not a "+\r
6379                                         "table: "+this.nodeName );\r
6380                                 return;\r
6381                         }\r
6382                         \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
6385                         {\r
6386                                 /* Base check on table node */\r
6387                                 if ( DataTable.settings[i].nTable == this )\r
6388                                 {\r
6389                                         if ( oInit === undefined || oInit.bRetrieve )\r
6390                                         {\r
6391                                                 return DataTable.settings[i].oInstance;\r
6392                                         }\r
6393                                         else if ( oInit.bDestroy )\r
6394                                         {\r
6395                                                 DataTable.settings[i].oInstance.fnDestroy();\r
6396                                                 break;\r
6397                                         }\r
6398                                         else\r
6399                                         {\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
6403                                                 return;\r
6404                                         }\r
6405                                 }\r
6406                                 \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
6411                                  */\r
6412                                 if ( DataTable.settings[i].sTableId == this.id )\r
6413                                 {\r
6414                                         DataTable.settings.splice( i, 1 );\r
6415                                         break;\r
6416                                 }\r
6417                         }\r
6418                         \r
6419                         /* Ensure the table has an ID - required for accessibility */\r
6420                         if ( sId === null || sId === "" )\r
6421                         {\r
6422                                 sId = "DataTables_Table_"+(DataTable.ext._oExternConfig.iNextUnique++);\r
6423                                 this.id = sId;\r
6424                         }\r
6425                         \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
6428                                 "nTable":        this,\r
6429                                 "oApi":          _that.oApi,\r
6430                                 "oInit":         oInit,\r
6431                                 "sDestroyWidth": $(this).width(),\r
6432                                 "sInstance":     sId,\r
6433                                 "sTableId":      sId\r
6434                         } );\r
6435                         DataTable.settings.push( oSettings );\r
6436                         \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
6440                         \r
6441                         /* Setting up the initialisation object */\r
6442                         if ( !oInit )\r
6443                         {\r
6444                                 oInit = {};\r
6445                         }\r
6446                         \r
6447                         // Backwards compatibility, before we apply all the defaults\r
6448                         if ( oInit.oLanguage )\r
6449                         {\r
6450                                 _fnLanguageCompat( oInit.oLanguage );\r
6451                         }\r
6452                         \r
6453                         oInit = _fnExtend( $.extend(true, {}, DataTable.defaults), oInit );\r
6454                         \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
6497                         \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
6510                         \r
6511                         if ( oSettings.oFeatures.bServerSide && oSettings.oFeatures.bSort &&\r
6512                                    oSettings.oFeatures.bSortClasses )\r
6513                         {\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
6516                                  */\r
6517                                 _fnCallbackReg( oSettings, 'aoDrawCallback', _fnSortingClasses, 'server_side_sort_classes' );\r
6518                         }\r
6519                         else if ( oSettings.oFeatures.bDeferRender )\r
6520                         {\r
6521                                 _fnCallbackReg( oSettings, 'aoDrawCallback', _fnSortingClasses, 'defer_sort_classes' );\r
6522                         }\r
6523                         \r
6524                         if ( oInit.bJQueryUI )\r
6525                         {\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
6528                                  */\r
6529                                 $.extend( oSettings.oClasses, DataTable.ext.oJUIClasses );\r
6530                                 \r
6531                                 if ( oInit.sDom === DataTable.defaults.sDom && DataTable.defaults.sDom === "lfrtip" )\r
6532                                 {\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
6535                                 }\r
6536                         }\r
6537                         else\r
6538                         {\r
6539                                 $.extend( oSettings.oClasses, DataTable.ext.oStdClasses );\r
6540                         }\r
6541                         $(this).addClass( oSettings.oClasses.sTable );\r
6542                         \r
6543                         /* Calculate the scroll bar width and cache it for use later on */\r
6544                         if ( oSettings.oScroll.sX !== "" || oSettings.oScroll.sY !== "" )\r
6545                         {\r
6546                                 oSettings.oScroll.iBarWidth = _fnScrollBarWidth();\r
6547                         }\r
6548                         \r
6549                         if ( oSettings.iInitDisplayStart === undefined )\r
6550                         {\r
6551                                 /* Display start point, taking into account the save saving */\r
6552                                 oSettings.iInitDisplayStart = oInit.iDisplayStart;\r
6553                                 oSettings._iDisplayStart = oInit.iDisplayStart;\r
6554                         }\r
6555                         \r
6556                         /* Must be done after everything which can be overridden by a cookie! */\r
6557                         if ( oInit.bStateSave )\r
6558                         {\r
6559                                 oSettings.oFeatures.bStateSave = true;\r
6560                                 _fnLoadState( oSettings, oInit );\r
6561                                 _fnCallbackReg( oSettings, 'aoDrawCallback', _fnSaveState, 'state_save' );\r
6562                         }\r
6563                         \r
6564                         if ( oInit.iDeferLoading !== null )\r
6565                         {\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
6570                         }\r
6571                         \r
6572                         if ( oInit.aaData !== null )\r
6573                         {\r
6574                                 bUsePassedData = true;\r
6575                         }\r
6576                         \r
6577                         /* Language definitions */\r
6578                         if ( oInit.oLanguage.sUrl !== "" )\r
6579                         {\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
6583                                  */\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
6589                                 } );\r
6590                                 bInitHandedOff = true;\r
6591                         }\r
6592                         else\r
6593                         {\r
6594                                 $.extend( true, oSettings.oLanguage, oInit.oLanguage );\r
6595                         }\r
6596                         \r
6597                         \r
6598                         /*\r
6599                          * Stripes\r
6600                          */\r
6601                         if ( oInit.asStripeClasses === null )\r
6602                         {\r
6603                                 oSettings.asStripeClasses =[\r
6604                                         oSettings.oClasses.sStripeOdd,\r
6605                                         oSettings.oClasses.sStripeEven\r
6606                                 ];\r
6607                         }\r
6608                         \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
6612                         if (iLen)\r
6613                         {\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
6617                                 {\r
6618                                         if ( anRows.hasClass( oSettings.asStripeClasses[i] ) )\r
6619                                         {\r
6620                                                 bStripeRemove = true;\r
6621                                                 \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
6624                                         }\r
6625                                 }\r
6626                                 \r
6627                                 if ( bStripeRemove )\r
6628                                 {\r
6629                                         anRows.removeClass( oSettings.asStripeClasses.join(' ') );\r
6630                                 }\r
6631                         }\r
6632                         \r
6633                         /*\r
6634                          * Columns\r
6635                          * See if we should load columns automatically or use defined ones\r
6636                          */\r
6637                         var anThs = [];\r
6638                         var aoColumnsInit;\r
6639                         var nThead = this.getElementsByTagName('thead');\r
6640                         if ( nThead.length !== 0 )\r
6641                         {\r
6642                                 _fnDetectHeader( oSettings.aoHeader, nThead[0] );\r
6643                                 anThs = _fnGetUniqueThs( oSettings );\r
6644                         }\r
6645                         \r
6646                         /* If not given a column array, generate one with nulls */\r
6647                         if ( oInit.aoColumns === null )\r
6648                         {\r
6649                                 aoColumnsInit = [];\r
6650                                 for ( i=0, iLen=anThs.length ; i<iLen ; i++ )\r
6651                                 {\r
6652                                         aoColumnsInit.push( null );\r
6653                                 }\r
6654                         }\r
6655                         else\r
6656                         {\r
6657                                 aoColumnsInit = oInit.aoColumns;\r
6658                         }\r
6659                         \r
6660                         /* Add the columns */\r
6661                         for ( i=0, iLen=aoColumnsInit.length ; i<iLen ; i++ )\r
6662                         {\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
6665                                 {\r
6666                                         if ( aoColumnsInit[i] === null )\r
6667                                         {\r
6668                                                 aoColumnsInit[i] = {};\r
6669                                         }\r
6670                                         aoColumnsInit[i].bVisible = oInit.saved_aoColumns[i].bVisible;\r
6671                                 }\r
6672                                 \r
6673                                 _fnAddColumn( oSettings, anThs ? anThs[i] : null );\r
6674                         }\r
6675                         \r
6676                         /* Apply the column definitions */\r
6677                         _fnApplyColumnDefs( oSettings, oInit.aoColumnDefs, aoColumnsInit, function (iCol, oDef) {\r
6678                                 _fnColumnOptions( oSettings, iCol, oDef );\r
6679                         } );\r
6680                         \r
6681                         \r
6682                         /*\r
6683                          * Sorting\r
6684                          * Check the aaSorting array\r
6685                          */\r
6686                         for ( i=0, iLen=oSettings.aaSorting.length ; i<iLen ; i++ )\r
6687                         {\r
6688                                 if ( oSettings.aaSorting[i][0] >= oSettings.aoColumns.length )\r
6689                                 {\r
6690                                         oSettings.aaSorting[i][0] = 0;\r
6691                                 }\r
6692                                 var oColumn = oSettings.aoColumns[ oSettings.aaSorting[i][0] ];\r
6693                                 \r
6694                                 /* Add a default sorting index */\r
6695                                 if ( oSettings.aaSorting[i][2] === undefined )\r
6696                                 {\r
6697                                         oSettings.aaSorting[i][2] = 0;\r
6698                                 }\r
6699                                 \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
6702                                 {\r
6703                                         oSettings.aaSorting[i][1] = oColumn.asSorting[0];\r
6704                                 }\r
6705                                 \r
6706                                 /* Set the current sorting index based on aoColumns.asSorting */\r
6707                                 for ( j=0, jLen=oColumn.asSorting.length ; j<jLen ; j++ )\r
6708                                 {\r
6709                                         if ( oSettings.aaSorting[i][1] == oColumn.asSorting[j] )\r
6710                                         {\r
6711                                                 oSettings.aaSorting[i][2] = j;\r
6712                                                 break;\r
6713                                         }\r
6714                                 }\r
6715                         }\r
6716                                 \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
6719                          */\r
6720                         _fnSortingClasses( oSettings );\r
6721                         \r
6722                         \r
6723                         /*\r
6724                          * Final init\r
6725                          * Cache the header, body and footer as required, creating them if needed\r
6726                          */\r
6727                         \r
6728                         /* Browser support detection */\r
6729                         _fnBrowserDetect( oSettings );\r
6730                         \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
6734                         } );\r
6735                         \r
6736                         var thead = $(this).children('thead');\r
6737                         if ( thead.length === 0 )\r
6738                         {\r
6739                                 thead = [ document.createElement( 'thead' ) ];\r
6740                                 this.appendChild( thead[0] );\r
6741                         }\r
6742                         oSettings.nTHead = thead[0];\r
6743                         \r
6744                         var tbody = $(this).children('tbody');\r
6745                         if ( tbody.length === 0 )\r
6746                         {\r
6747                                 tbody = [ document.createElement( 'tbody' ) ];\r
6748                                 this.appendChild( tbody[0] );\r
6749                         }\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
6754                         \r
6755                         var tfoot = $(this).children('tfoot');\r
6756                         if ( tfoot.length === 0 && captions.length > 0 && (oSettings.oScroll.sX !== "" || oSettings.oScroll.sY !== "") )\r
6757                         {\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
6762                         }\r
6763                         \r
6764                         if ( tfoot.length > 0 )\r
6765                         {\r
6766                                 oSettings.nTFoot = tfoot[0];\r
6767                                 _fnDetectHeader( oSettings.aoFooter, oSettings.nTFoot );\r
6768                         }\r
6769                         \r
6770                         /* Check if there is data passing into the constructor */\r
6771                         if ( bUsePassedData )\r
6772                         {\r
6773                                 for ( i=0 ; i<oInit.aaData.length ; i++ )\r
6774                                 {\r
6775                                         _fnAddData( oSettings, oInit.aaData[ i ] );\r
6776                                 }\r
6777                         }\r
6778                         else\r
6779                         {\r
6780                                 /* Grab the data from the page */\r
6781                                 _fnGatherData( oSettings );\r
6782                         }\r
6783                         \r
6784                         /* Copy the data index array */\r
6785                         oSettings.aiDisplay = oSettings.aiDisplayMaster.slice();\r
6786                         \r
6787                         /* Initialisation complete - table can be drawn */\r
6788                         oSettings.bInitialised = true;\r
6789                         \r
6790                         /* Check if we need to initialise the table (it might not have been handed off to the\r
6791                          * language processor)\r
6792                          */\r
6793                         if ( bInitHandedOff === false )\r
6794                         {\r
6795                                 _fnInitialise( oSettings );\r
6796                         }\r
6797                 } );\r
6798                 _that = null;\r
6799                 return this;\r
6800         };\r
6801 \r
6802         \r
6803         \r
6804         /**\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
6811          *  @static\r
6812          *  @dtopt API-Static\r
6813          *\r
6814          *  @example\r
6815          *    alert( $.fn.dataTable.fnVersionCheck( '1.9.0' ) );\r
6816          */\r
6817         DataTable.fnVersionCheck = function( sVersion )\r
6818         {\r
6819                 /* This is cheap, but effective */\r
6820                 var fnZPad = function (Zpad, count)\r
6821                 {\r
6822                         while(Zpad.length < count) {\r
6823                                 Zpad += '0';\r
6824                         }\r
6825                         return Zpad;\r
6826                 };\r
6827                 var aThis = DataTable.ext.sVersion.split('.');\r
6828                 var aThat = sVersion.split('.');\r
6829                 var sThis = '', sThat = '';\r
6830                 \r
6831                 for ( var i=0, iLen=aThat.length ; i<iLen ; i++ )\r
6832                 {\r
6833                         sThis += fnZPad( aThis[i], 3 );\r
6834                         sThat += fnZPad( aThat[i], 3 );\r
6835                 }\r
6836                 \r
6837                 return parseInt(sThis, 10) >= parseInt(sThat, 10);\r
6838         };\r
6839         \r
6840         \r
6841         /**\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
6846          *  @static\r
6847          *  @dtopt API-Static\r
6848          *\r
6849          *  @example\r
6850          *    var ex = document.getElementById('example');\r
6851          *    if ( ! $.fn.DataTable.fnIsDataTable( ex ) ) {\r
6852          *      $(ex).dataTable();\r
6853          *    }\r
6854          */\r
6855         DataTable.fnIsDataTable = function ( nTable )\r
6856         {\r
6857                 var o = DataTable.settings;\r
6858         \r
6859                 for ( var i=0 ; i<o.length ; i++ )\r
6860                 {\r
6861                         if ( o[i].nTable === nTable || o[i].nScrollHead === nTable || o[i].nScrollFoot === nTable )\r
6862                         {\r
6863                                 return true;\r
6864                         }\r
6865                 }\r
6866         \r
6867                 return false;\r
6868         };\r
6869         \r
6870         \r
6871         /**\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
6877          *  @static\r
6878          *  @dtopt API-Static\r
6879          *\r
6880          *  @example\r
6881          *    var table = $.fn.dataTable.fnTables(true);\r
6882          *    if ( table.length > 0 ) {\r
6883          *      $(table).dataTable().fnAdjustColumnSizing();\r
6884          *    }\r
6885          */\r
6886         DataTable.fnTables = function ( bVisible )\r
6887         {\r
6888                 var out = [];\r
6889         \r
6890                 jQuery.each( DataTable.settings, function (i, o) {\r
6891                         if ( !bVisible || (bVisible === true && $(o.nTable).is(':visible')) )\r
6892                         {\r
6893                                 out.push( o.nTable );\r
6894                         }\r
6895                 } );\r
6896         \r
6897                 return out;\r
6898         };\r
6899         \r
6900 \r
6901         /**\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
6904          * e are optional\r
6905          *  @member\r
6906          *  @type string\r
6907          *  @default Version number\r
6908          */\r
6909         DataTable.version = "1.9.4";\r
6910 \r
6911         /**\r
6912          * Private data store, containing all of the settings objects that are created for the\r
6913          * tables on a given page.\r
6914          * \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
6917          *  @member\r
6918          *  @type array\r
6919          *  @default []\r
6920          *  @private\r
6921          */\r
6922         DataTable.settings = [];\r
6923 \r
6924         /**\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
6928          *  @namespace\r
6929          */\r
6930         DataTable.models = {};\r
6931         \r
6932         \r
6933         /**\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
6937          * for example).\r
6938          * \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
6941          *  @namespace\r
6942          */\r
6943         DataTable.models.ext = {\r
6944                 /**\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
6950                  *   <ul>\r
6951                  *     <li>\r
6952                  *       Function input parameters:\r
6953                  *       <ul>\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
6959                  *       </ul>\r
6960                  *     </li>\r
6961                  *     <li>\r
6962                  *       Function return:\r
6963                  *       <ul>\r
6964                  *         <li>{boolean} Include the row in the filtered result set (true) or not (false)</li>\r
6965                  *       </ul>\r
6966                  *     </il>\r
6967                  *   </ul>\r
6968                  *  @type array\r
6969                  *  @default []\r
6970                  *\r
6971                  *  @example\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
6981                  *          return true;\r
6982                  *        }\r
6983                  *        else if ( iMin == "" && iVersion < iMax ) {\r
6984                  *          return true;\r
6985                  *        }\r
6986                  *        else if ( iMin < iVersion && "" == iMax ) {\r
6987                  *          return true;\r
6988                  *        }\r
6989                  *        else if ( iMin < iVersion && iVersion < iMax ) {\r
6990                  *          return true;\r
6991                  *        }\r
6992                  *        return false;\r
6993                  *      }\r
6994                  *    );\r
6995                  */\r
6996                 "afnFiltering": [],\r
6997         \r
6998         \r
6999                 /**\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
7008                  * data.\r
7009                  *   <ul>\r
7010              *     <li>\r
7011              *       Function input parameters:\r
7012              *       <ul>\r
7013                  *         <li>{object} DataTables settings object: see {@link DataTable.models.oSettings}.</li>\r
7014              *         <li>{int} Target column index</li>\r
7015              *       </ul>\r
7016              *     </li>\r
7017                  *     <li>\r
7018                  *       Function return:\r
7019                  *       <ul>\r
7020                  *         <li>{array} Data for the column to be sorted upon</li>\r
7021                  *       </ul>\r
7022                  *     </il>\r
7023                  *   </ul>\r
7024                  *  \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
7029                  *  @type array\r
7030                  *  @default []\r
7031                  *  @deprecated\r
7032                  *\r
7033                  *  @example\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
7036                  *    {\r
7037                  *      var aData = [];\r
7038                  *      $( 'td:eq('+iColumn+') input', oSettings.oApi._fnGetTrNodes(oSettings) ).each( function () {\r
7039                  *        aData.push( this.value );\r
7040                  *      } );\r
7041                  *      return aData;\r
7042                  *    }\r
7043                  */\r
7044                 "afnSortData": [],\r
7045         \r
7046         \r
7047                 /**\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
7053                  *   <ul>\r
7054                  *     <li>{function} fnInit Initialisation of the plug-in\r
7055                  *       <ul>\r
7056              *         <li>\r
7057              *           Function input parameters:\r
7058              *           <ul>\r
7059                  *             <li>{object} DataTables settings object: see {@link DataTable.models.oSettings}.</li>\r
7060              *           </ul>\r
7061              *         </li>\r
7062                  *         <li>\r
7063                  *           Function return:\r
7064                  *           <ul>\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
7069                  *           </ul>\r
7070                  *         </il>\r
7071                  *       </ul>\r
7072                  *     </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
7075                  *   </ul>\r
7076                  *  @type array\r
7077                  *  @default []\r
7078                  * \r
7079                  *  @example\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
7084                  *      },\r
7085                  *      "cFeature": "T",\r
7086                  *      "sFeature": "TableTools"\r
7087                  *    } );\r
7088                  */\r
7089                 "aoFeatures": [],\r
7090         \r
7091         \r
7092                 /**\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
7098                  *   <ul>\r
7099              *     <li>\r
7100              *       Function input parameters:\r
7101              *       <ul>\r
7102                  *         <li>{*} Data from the column cell to be analysed</li>\r
7103              *       </ul>\r
7104              *     </li>\r
7105                  *     <li>\r
7106                  *       Function return:\r
7107                  *       <ul>\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
7110                  *       </ul>\r
7111                  *     </il>\r
7112                  *   </ul>\r
7113                  *  @type array\r
7114                  *  @default []\r
7115                  *  \r
7116                  *  @example\r
7117                  *    // Currency type detection plug-in:\r
7118                  *    jQuery.fn.dataTableExt.aTypes.push(\r
7119                  *      function ( sData ) {\r
7120                  *        var sValidChars = "0123456789.-";\r
7121                  *        var Char;\r
7122                  *        \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
7127                  *            return null;\r
7128                  *          }\r
7129                  *        }\r
7130                  *        \r
7131                  *        // Check prefixed by currency\r
7132                  *        if ( sData.charAt(0) == '$' || sData.charAt(0) == '&pound;' ) {\r
7133                  *          return 'currency';\r
7134                  *        }\r
7135                  *        return null;\r
7136                  *      }\r
7137                  *    );\r
7138                  */\r
7139                 "aTypes": [],\r
7140         \r
7141         \r
7142                 /**\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
7145                  *  @type function\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
7150                  *\r
7151                  *  @example\r
7152                  *    $(document).ready(function() {\r
7153                  *      var oTable = $('#example').dataTable();\r
7154                  *      alert( oTable.fnVersionCheck( '1.9.0' ) );\r
7155                  *    } );\r
7156                  */\r
7157                 "fnVersionCheck": DataTable.fnVersionCheck,\r
7158         \r
7159         \r
7160                 /**\r
7161                  * Index for what 'this' index API functions should use\r
7162                  *  @type int\r
7163                  *  @default 0\r
7164                  */\r
7165                 "iApiIndex": 0,\r
7166         \r
7167         \r
7168                 /**\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
7176                  *   <ul>\r
7177              *     <li>\r
7178              *       Function input parameters:\r
7179              *       <ul>\r
7180                  *         <li>{*} Data from the column cell to be prepared for filtering</li>\r
7181              *       </ul>\r
7182              *     </li>\r
7183                  *     <li>\r
7184                  *       Function return:\r
7185                  *       <ul>\r
7186                  *         <li>{string|null} Formatted string that will be used for the filtering.</li>\r
7187                  *       </ul>\r
7188                  *     </il>\r
7189                  *   </ul>\r
7190                  * \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
7195                  *  @type object\r
7196                  *  @default {}\r
7197                  *  @deprecated\r
7198                  *\r
7199                  *  @example\r
7200                  *    $.fn.dataTableExt.ofnSearch['title-numeric'] = function ( sData ) {\r
7201                  *      return sData.replace(/\n/g," ").replace( /<.*?>/g, "" );\r
7202                  *    }\r
7203                  */\r
7204                 "ofnSearch": {},\r
7205         \r
7206         \r
7207                 /**\r
7208                  * Container for all private functions in DataTables so they can be exposed externally\r
7209                  *  @type object\r
7210                  *  @default {}\r
7211                  */\r
7212                 "oApi": {},\r
7213         \r
7214         \r
7215                 /**\r
7216                  * Storage for the various classes that DataTables uses\r
7217                  *  @type object\r
7218                  *  @default {}\r
7219                  */\r
7220                 "oStdClasses": {},\r
7221                 \r
7222         \r
7223                 /**\r
7224                  * Storage for the various classes that DataTables uses - jQuery UI suitable\r
7225                  *  @type object\r
7226                  *  @default {}\r
7227                  */\r
7228                 "oJUIClasses": {},\r
7229         \r
7230         \r
7231                 /**\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
7239                  *   <ul>\r
7240                  *     <li>\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
7247                  *         as children\r
7248                  *       <ul>\r
7249              *         <li>\r
7250              *           Function input parameters:\r
7251              *           <ul>\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
7256              *           </ul>\r
7257              *         </li>\r
7258                  *         <li>\r
7259                  *           Function return:\r
7260                  *           <ul>\r
7261                  *             <li>No return required</li>\r
7262                  *           </ul>\r
7263                  *         </il>\r
7264                  *       </ul>\r
7265                  *     </il>\r
7266                  *     <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
7269                  *         status.\r
7270                  *       <ul>\r
7271              *         <li>\r
7272              *           Function input parameters:\r
7273              *           <ul>\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
7277              *           </ul>\r
7278              *         </li>\r
7279                  *         <li>\r
7280                  *           Function return:\r
7281                  *           <ul>\r
7282                  *             <li>No return required</li>\r
7283                  *           </ul>\r
7284                  *         </il>\r
7285                  *       </ul>\r
7286                  *     </il>\r
7287                  *   </ul>\r
7288                  *  @type object\r
7289                  *  @default {}\r
7290                  *\r
7291                  *  @example\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
7298                  *        \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
7303                  *        \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
7308                  *        \r
7309                  *        nPaging.appendChild( nFirst );\r
7310                  *        nPaging.appendChild( nPrevious );\r
7311                  *        nPaging.appendChild( nNext );\r
7312                  *        nPaging.appendChild( nLast );\r
7313                  *        \r
7314                  *        $(nFirst).click( function () {\r
7315                  *          oSettings.oApi._fnPageChange( oSettings, "first" );\r
7316                  *          fnCallbackDraw( oSettings );\r
7317                  *        } );\r
7318                  *        \r
7319                  *        $(nPrevious).click( function() {\r
7320                  *          oSettings.oApi._fnPageChange( oSettings, "previous" );\r
7321                  *          fnCallbackDraw( oSettings );\r
7322                  *        } );\r
7323                  *        \r
7324                  *        $(nNext).click( function() {\r
7325                  *          oSettings.oApi._fnPageChange( oSettings, "next" );\r
7326                  *          fnCallbackDraw( oSettings );\r
7327                  *        } );\r
7328                  *        \r
7329                  *        $(nLast).click( function() {\r
7330                  *          oSettings.oApi._fnPageChange( oSettings, "last" );\r
7331                  *          fnCallbackDraw( oSettings );\r
7332                  *        } );\r
7333                  *        \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
7338                  *      },\r
7339                  *      \r
7340                  *      "fnUpdate": function ( oSettings, fnCallbackDraw ) {\r
7341                  *        if ( !oSettings.aanFeatures.p ) {\r
7342                  *          return;\r
7343                  *        }\r
7344                  *        \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
7352                  *          }\r
7353                  *          else {\r
7354                  *            buttons[0].className = "paginate_enabled_previous";\r
7355                  *            buttons[1].className = "paginate_enabled_previous";\r
7356                  *          }\r
7357                  *          \r
7358                  *          if ( oSettings.fnDisplayEnd() == oSettings.fnRecordsDisplay() ) {\r
7359                  *            buttons[2].className = "paginate_disabled_next";\r
7360                  *            buttons[3].className = "paginate_disabled_next";\r
7361                  *          }\r
7362                  *          else {\r
7363                  *            buttons[2].className = "paginate_enabled_next";\r
7364                  *            buttons[3].className = "paginate_enabled_next";\r
7365                  *          }\r
7366                  *        }\r
7367                  *      }\r
7368                  *    };\r
7369                  */\r
7370                 "oPagination": {},\r
7371         \r
7372         \r
7373                 /**\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
7382                  *   <ul>\r
7383              *     <li>\r
7384              *       Function input parameters:\r
7385              *       <ul>\r
7386                  *         <li>{*} Data to compare to the second parameter</li>\r
7387                  *         <li>{*} Data to compare to the first parameter</li>\r
7388              *       </ul>\r
7389              *     </li>\r
7390                  *     <li>\r
7391                  *       Function return:\r
7392                  *       <ul>\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
7396                  *       </ul>\r
7397                  *     </il>\r
7398                  *   </ul>\r
7399                  *  @type object\r
7400                  *  @default {}\r
7401                  *\r
7402                  *  @example\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
7407                  *      },\r
7408                  *      "string-case-desc": function(x,y) {\r
7409                  *        return ((x < y) ? 1 : ((x > y) ? -1 : 0));\r
7410                  *      }\r
7411                  *    } );\r
7412                  *\r
7413                  *  @example\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
7418                  *      },\r
7419                  *      "string-asc": function(x,y) {\r
7420                  *        return ((x < y) ? -1 : ((x > y) ? 1 : 0));\r
7421                  *      },\r
7422                  *      "string-desc": function(x,y) {\r
7423                  *        return ((x < y) ? 1 : ((x > y) ? -1 : 0));\r
7424                  *      }\r
7425                  *    } );\r
7426                  */\r
7427                 "oSort": {},\r
7428         \r
7429         \r
7430                 /**\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
7433                  * e are optional\r
7434                  *  @type string\r
7435                  *  @default Version number\r
7436                  */\r
7437                 "sVersion": DataTable.version,\r
7438         \r
7439         \r
7440                 /**\r
7441                  * How should DataTables report an error. Can take the value 'alert' or 'throw'\r
7442                  *  @type string\r
7443                  *  @default alert\r
7444                  */\r
7445                 "sErrMode": "alert",\r
7446         \r
7447         \r
7448                 /**\r
7449                  * Store information for DataTables to access globally about other instances\r
7450                  *  @namespace\r
7451                  *  @private\r
7452                  */\r
7453                 "_oExternConfig": {\r
7454                         /* int:iNextUnique - next unique number for an instance */\r
7455                         "iNextUnique": 0\r
7456                 }\r
7457         };\r
7458         \r
7459         \r
7460         \r
7461         \r
7462         /**\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
7465          *  @namespace\r
7466          */\r
7467         DataTable.models.oSearch = {\r
7468                 /**\r
7469                  * Flag to indicate if the filtering should be case insensitive or not\r
7470                  *  @type boolean\r
7471                  *  @default true\r
7472                  */\r
7473                 "bCaseInsensitive": true,\r
7474         \r
7475                 /**\r
7476                  * Applied search term\r
7477                  *  @type string\r
7478                  *  @default <i>Empty string</i>\r
7479                  */\r
7480                 "sSearch": "",\r
7481         \r
7482                 /**\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
7486                  *  @type boolean\r
7487                  *  @default false\r
7488                  */\r
7489                 "bRegex": false,\r
7490         \r
7491                 /**\r
7492                  * Flag to indicate if DataTables is to use its smart filtering or not.\r
7493                  *  @type boolean\r
7494                  *  @default true\r
7495                  */\r
7496                 "bSmart": true\r
7497         };\r
7498         \r
7499         \r
7500         \r
7501         \r
7502         /**\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
7505          * aoData array.\r
7506          *  @namespace\r
7507          */\r
7508         DataTable.models.oRow = {\r
7509                 /**\r
7510                  * TR element for the row\r
7511                  *  @type node\r
7512                  *  @default null\r
7513                  */\r
7514                 "nTr": null,\r
7515         \r
7516                 /**\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
7521                  * source.\r
7522                  *  @type array|object\r
7523                  *  @default []\r
7524                  */\r
7525                 "_aData": [],\r
7526         \r
7527                 /**\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
7535                  *  @type array\r
7536                  *  @default []\r
7537                  *  @private\r
7538                  */\r
7539                 "_aSortData": [],\r
7540         \r
7541                 /**\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
7548                  *  @default []\r
7549                  *  @private\r
7550                  */\r
7551                 "_anHidden": [],\r
7552         \r
7553                 /**\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
7557                  *  @type string\r
7558                  *  @default <i>Empty string</i>\r
7559                  *  @private\r
7560                  */\r
7561                 "_sRowStripe": ""\r
7562         };\r
7563         \r
7564         \r
7565         \r
7566         /**\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
7570          * \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
7575          *  @namespace\r
7576          */\r
7577         DataTable.models.oColumn = {\r
7578                 /**\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
7585                  *  @type array\r
7586                  */\r
7587                 "aDataSort": null,\r
7588         \r
7589                 /**\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
7595                  *  @type array\r
7596                  */\r
7597                 "asSorting": null,\r
7598                 \r
7599                 /**\r
7600                  * Flag to indicate if the column is searchable, and thus should be included\r
7601                  * in the filtering or not.\r
7602                  *  @type boolean\r
7603                  */\r
7604                 "bSearchable": null,\r
7605                 \r
7606                 /**\r
7607                  * Flag to indicate if the column is sortable or not.\r
7608                  *  @type boolean\r
7609                  */\r
7610                 "bSortable": null,\r
7611                 \r
7612                 /**\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
7617                  *\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
7620                  * fnRender.\r
7621                  *  @type boolean\r
7622                  *  @deprecated\r
7623                  */\r
7624                 "bUseRendered": null,\r
7625                 \r
7626                 /**\r
7627                  * Flag to indicate if the column is currently visible in the table or not\r
7628                  *  @type boolean\r
7629                  */\r
7630                 "bVisible": null,\r
7631                 \r
7632                 /**\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
7635                  *  @type boolean\r
7636                  *  @default true\r
7637                  *  @private\r
7638                  */\r
7639                 "_bAutoType": true,\r
7640                 \r
7641                 /**\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
7646                  *  @type function\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
7651                  *  @default null\r
7652                  */\r
7653                 "fnCreatedCell": null,\r
7654                 \r
7655                 /**\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
7661                  *  @type function\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
7667                  *  @default null\r
7668                  */\r
7669                 "fnGetData": null,\r
7670                 \r
7671                 /**\r
7672                  * <code>Deprecated</code> Custom display function that will be called for the \r
7673                  * display of each cell in this column.\r
7674                  *\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
7677                  * fnRender.\r
7678                  *  @type function\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
7685                  *  @default null\r
7686                  *  @deprecated\r
7687                  */\r
7688                 "fnRender": null,\r
7689                 \r
7690                 /**\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
7695                  *  @type function\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
7699                  *  @default null\r
7700                  */\r
7701                 "fnSetData": null,\r
7702                 \r
7703                 /**\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
7708                  *  @default null\r
7709                  */\r
7710                 "mData": null,\r
7711                 \r
7712                 /**\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
7718                  *  @default null\r
7719                  */\r
7720                 "mRender": null,\r
7721                 \r
7722                 /**\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
7725                  *  @type node\r
7726                  *  @default null\r
7727                  */\r
7728                 "nTh": null,\r
7729                 \r
7730                 /**\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
7734                  *  @type node\r
7735                  *  @default null\r
7736                  */\r
7737                 "nTf": null,\r
7738                 \r
7739                 /**\r
7740                  * The class to apply to all TD elements in the table's TBODY for the column\r
7741                  *  @type string\r
7742                  *  @default null\r
7743                  */\r
7744                 "sClass": null,\r
7745                 \r
7746                 /**\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
7755                  *  @type string\r
7756                  */\r
7757                 "sContentPadding": null,\r
7758                 \r
7759                 /**\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
7763                  *  @type string\r
7764                  *  @default null\r
7765                  */\r
7766                 "sDefaultContent": null,\r
7767                 \r
7768                 /**\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
7771                  *  @type string\r
7772                  */\r
7773                 "sName": null,\r
7774                 \r
7775                 /**\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
7778                  *  @type string\r
7779                  *  @default std\r
7780                  */\r
7781                 "sSortDataType": 'std',\r
7782                 \r
7783                 /**\r
7784                  * Class to be applied to the header element when sorting on this column\r
7785                  *  @type string\r
7786                  *  @default null\r
7787                  */\r
7788                 "sSortingClass": null,\r
7789                 \r
7790                 /**\r
7791                  * Class to be applied to the header element when sorting on this column -\r
7792                  * when jQuery UI theming is used.\r
7793                  *  @type string\r
7794                  *  @default null\r
7795                  */\r
7796                 "sSortingClassJUI": null,\r
7797                 \r
7798                 /**\r
7799                  * Title of the column - what is seen in the TH element (nTh).\r
7800                  *  @type string\r
7801                  */\r
7802                 "sTitle": null,\r
7803                 \r
7804                 /**\r
7805                  * Column sorting and filtering type\r
7806                  *  @type string\r
7807                  *  @default null\r
7808                  */\r
7809                 "sType": null,\r
7810                 \r
7811                 /**\r
7812                  * Width of the column\r
7813                  *  @type string\r
7814                  *  @default null\r
7815                  */\r
7816                 "sWidth": null,\r
7817                 \r
7818                 /**\r
7819                  * Width of the column when it was first "encountered"\r
7820                  *  @type string\r
7821                  *  @default null\r
7822                  */\r
7823                 "sWidthOrig": null\r
7824         };\r
7825         \r
7826         \r
7827         \r
7828         /**\r
7829          * Initialisation options that can be given to DataTables at initialisation \r
7830          * time.\r
7831          *  @namespace\r
7832          */\r
7833         DataTable.defaults = {\r
7834                 /**\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
7839                  *  @type array\r
7840                  *  @default null\r
7841                  *  @dtopt Option\r
7842                  * \r
7843                  *  @example\r
7844                  *    // Using a 2D array data source\r
7845                  *    $(document).ready( function () {\r
7846                  *      $('#example').dataTable( {\r
7847                  *        "aaData": [\r
7848                  *          ['Trident', 'Internet Explorer 4.0', 'Win 95+', 4, 'X'],\r
7849                  *          ['Trident', 'Internet Explorer 5.0', 'Win 95+', 5, 'C'],\r
7850                  *        ],\r
7851                  *        "aoColumns": [\r
7852                  *          { "sTitle": "Engine" },\r
7853                  *          { "sTitle": "Browser" },\r
7854                  *          { "sTitle": "Platform" },\r
7855                  *          { "sTitle": "Version" },\r
7856                  *          { "sTitle": "Grade" }\r
7857                  *        ]\r
7858                  *      } );\r
7859                  *    } );\r
7860                  *    \r
7861                  *  @example\r
7862                  *    // Using an array of objects as a data source (mData)\r
7863                  *    $(document).ready( function () {\r
7864                  *      $('#example').dataTable( {\r
7865                  *        "aaData": [\r
7866                  *          {\r
7867                  *            "engine":   "Trident",\r
7868                  *            "browser":  "Internet Explorer 4.0",\r
7869                  *            "platform": "Win 95+",\r
7870                  *            "version":  4,\r
7871                  *            "grade":    "X"\r
7872                  *          },\r
7873                  *          {\r
7874                  *            "engine":   "Trident",\r
7875                  *            "browser":  "Internet Explorer 5.0",\r
7876                  *            "platform": "Win 95+",\r
7877                  *            "version":  5,\r
7878                  *            "grade":    "C"\r
7879                  *          }\r
7880                  *        ],\r
7881                  *        "aoColumns": [\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
7887                  *        ]\r
7888                  *      } );\r
7889                  *    } );\r
7890                  */\r
7891                 "aaData": null,\r
7892         \r
7893         \r
7894                 /**\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
7900                  *  @type array\r
7901                  *  @default [[0,'asc']]\r
7902                  *  @dtopt Option\r
7903                  * \r
7904                  *  @example\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
7909                  *      } );\r
7910                  *    } );\r
7911                  *    \r
7912                  *    // No initial sorting\r
7913                  *    $(document).ready( function() {\r
7914                  *      $('#example').dataTable( {\r
7915                  *        "aaSorting": []\r
7916                  *      } );\r
7917                  *    } );\r
7918                  */\r
7919                 "aaSorting": [[0,'asc']],\r
7920         \r
7921         \r
7922                 /**\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
7928                  * together.\r
7929                  *  @type array\r
7930                  *  @default null\r
7931                  *  @dtopt Option\r
7932                  * \r
7933                  *  @example\r
7934                  *    $(document).ready( function() {\r
7935                  *      $('#example').dataTable( {\r
7936                  *        "aaSortingFixed": [[0,'asc']]\r
7937                  *      } );\r
7938                  *    } )\r
7939                  */\r
7940                 "aaSortingFixed": null,\r
7941         \r
7942         \r
7943                 /**\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
7950                  *  @type array\r
7951                  *  @default [ 10, 25, 50, 100 ]\r
7952                  *  @dtopt Option\r
7953                  * \r
7954                  *  @example\r
7955                  *    $(document).ready( function() {\r
7956                  *      $('#example').dataTable( {\r
7957                  *        "aLengthMenu": [[10, 25, 50, -1], [10, 25, 50, "All"]]\r
7958                  *      } );\r
7959                  *    } );\r
7960                  *  \r
7961                  *  @example\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
7969                  *      } );\r
7970                  *    } );\r
7971                  */\r
7972                 "aLengthMenu": [ 10, 25, 50, 100 ],\r
7973         \r
7974         \r
7975                 /**\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
7983                  *  @member\r
7984                  */\r
7985                 "aoColumns": null,\r
7986         \r
7987                 /**\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
7995                  * array may be:\r
7996                  *   <ul>\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
8001                  *   </ul>\r
8002                  *  @member\r
8003                  */\r
8004                 "aoColumnDefs": null,\r
8005         \r
8006         \r
8007                 /**\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
8013                  *  @type array\r
8014                  *  @default []\r
8015                  *  @dtopt Option\r
8016                  * \r
8017                  *  @example\r
8018                  *    $(document).ready( function() {\r
8019                  *      $('#example').dataTable( {\r
8020                  *        "aoSearchCols": [\r
8021                  *          null,\r
8022                  *          { "sSearch": "My filter" },\r
8023                  *          null,\r
8024                  *          { "sSearch": "^[0-9]", "bEscapeRegex": false }\r
8025                  *        ]\r
8026                  *      } );\r
8027                  *    } )\r
8028                  */\r
8029                 "aoSearchCols": [],\r
8030         \r
8031         \r
8032                 /**\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
8036                  *  @type array\r
8037                  *  @default null <i>Will take the values determined by the oClasses.sStripe*\r
8038                  *    options</i>\r
8039                  *  @dtopt Option\r
8040                  * \r
8041                  *  @example\r
8042                  *    $(document).ready( function() {\r
8043                  *      $('#example').dataTable( {\r
8044                  *        "asStripeClasses": [ 'strip1', 'strip2', 'strip3' ]\r
8045                  *      } );\r
8046                  *    } )\r
8047                  */\r
8048                 "asStripeClasses": null,\r
8049         \r
8050         \r
8051                 /**\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
8055                  *  @type boolean\r
8056                  *  @default true\r
8057                  *  @dtopt Features\r
8058                  * \r
8059                  *  @example\r
8060                  *    $(document).ready( function () {\r
8061                  *      $('#example').dataTable( {\r
8062                  *        "bAutoWidth": false\r
8063                  *      } );\r
8064                  *    } );\r
8065                  */\r
8066                 "bAutoWidth": true,\r
8067         \r
8068         \r
8069                 /**\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
8074                  * time.\r
8075                  *  @type boolean\r
8076                  *  @default false\r
8077                  *  @dtopt Features\r
8078                  * \r
8079                  *  @example\r
8080                  *    $(document).ready( function() {\r
8081                  *      var oTable = $('#example').dataTable( {\r
8082                  *        "sAjaxSource": "sources/arrays.txt",\r
8083                  *        "bDeferRender": true\r
8084                  *      } );\r
8085                  *    } );\r
8086                  */\r
8087                 "bDeferRender": false,\r
8088         \r
8089         \r
8090                 /**\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
8094                  * per normal.\r
8095                  *  @type boolean\r
8096                  *  @default false\r
8097                  *  @dtopt Options\r
8098                  * \r
8099                  *  @example\r
8100                  *    $(document).ready( function() {\r
8101                  *      $('#example').dataTable( {\r
8102                  *        "sScrollY": "200px",\r
8103                  *        "bPaginate": false\r
8104                  *      } );\r
8105                  *      \r
8106                  *      // Some time later....\r
8107                  *      $('#example').dataTable( {\r
8108                  *        "bFilter": false,\r
8109                  *        "bDestroy": true\r
8110                  *      } );\r
8111                  *    } );\r
8112                  */\r
8113                 "bDestroy": false,\r
8114         \r
8115         \r
8116                 /**\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
8124                  *  @type boolean\r
8125                  *  @default true\r
8126                  *  @dtopt Features\r
8127                  * \r
8128                  *  @example\r
8129                  *    $(document).ready( function () {\r
8130                  *      $('#example').dataTable( {\r
8131                  *        "bFilter": false\r
8132                  *      } );\r
8133                  *    } );\r
8134                  */\r
8135                 "bFilter": true,\r
8136         \r
8137         \r
8138                 /**\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
8142                  *  @type boolean\r
8143                  *  @default true\r
8144                  *  @dtopt Features\r
8145                  * \r
8146                  *  @example\r
8147                  *    $(document).ready( function () {\r
8148                  *      $('#example').dataTable( {\r
8149                  *        "bInfo": false\r
8150                  *      } );\r
8151                  *    } );\r
8152                  */\r
8153                 "bInfo": true,\r
8154         \r
8155         \r
8156                 /**\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
8160                  *  @type boolean\r
8161                  *  @default false\r
8162                  *  @dtopt Features\r
8163                  * \r
8164                  *  @example\r
8165                  *    $(document).ready( function() {\r
8166                  *      $('#example').dataTable( {\r
8167                  *        "bJQueryUI": true\r
8168                  *      } );\r
8169                  *    } );\r
8170                  */\r
8171                 "bJQueryUI": false,\r
8172         \r
8173         \r
8174                 /**\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
8177                  *  @type boolean\r
8178                  *  @default true\r
8179                  *  @dtopt Features\r
8180                  * \r
8181                  *  @example\r
8182                  *    $(document).ready( function () {\r
8183                  *      $('#example').dataTable( {\r
8184                  *        "bLengthChange": false\r
8185                  *      } );\r
8186                  *    } );\r
8187                  */\r
8188                 "bLengthChange": true,\r
8189         \r
8190         \r
8191                 /**\r
8192                  * Enable or disable pagination.\r
8193                  *  @type boolean\r
8194                  *  @default true\r
8195                  *  @dtopt Features\r
8196                  * \r
8197                  *  @example\r
8198                  *    $(document).ready( function () {\r
8199                  *      $('#example').dataTable( {\r
8200                  *        "bPaginate": false\r
8201                  *      } );\r
8202                  *    } );\r
8203                  */\r
8204                 "bPaginate": true,\r
8205         \r
8206         \r
8207                 /**\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
8211                  * the entries.\r
8212                  *  @type boolean\r
8213                  *  @default false\r
8214                  *  @dtopt Features\r
8215                  * \r
8216                  *  @example\r
8217                  *    $(document).ready( function () {\r
8218                  *      $('#example').dataTable( {\r
8219                  *        "bProcessing": true\r
8220                  *      } );\r
8221                  *    } );\r
8222                  */\r
8223                 "bProcessing": false,\r
8224         \r
8225         \r
8226                 /**\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
8233                  * you need.\r
8234                  *  @type boolean\r
8235                  *  @default false\r
8236                  *  @dtopt Options\r
8237                  * \r
8238                  *  @example\r
8239                  *    $(document).ready( function() {\r
8240                  *      initTable();\r
8241                  *      tableActions();\r
8242                  *    } );\r
8243                  *    \r
8244                  *    function initTable ()\r
8245                  *    {\r
8246                  *      return $('#example').dataTable( {\r
8247                  *        "sScrollY": "200px",\r
8248                  *        "bPaginate": false,\r
8249                  *        "bRetrieve": true\r
8250                  *      } );\r
8251                  *    }\r
8252                  *    \r
8253                  *    function tableActions ()\r
8254                  *    {\r
8255                  *      var oTable = initTable();\r
8256                  *      // perform API operations with oTable \r
8257                  *    }\r
8258                  */\r
8259                 "bRetrieve": false,\r
8260         \r
8261         \r
8262                 /**\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
8265                  * this.\r
8266                  *  @type boolean\r
8267                  *  @default true\r
8268                  *  @dtopt Options\r
8269                  * \r
8270                  *  @example\r
8271                  *    $(document).ready( function() {\r
8272                  *      $('#example').dataTable( {\r
8273                  *        "bScrollAutoCss": false,\r
8274                  *        "sScrollY": "200px"\r
8275                  *      } );\r
8276                  *    } );\r
8277                  */\r
8278                 "bScrollAutoCss": true,\r
8279         \r
8280         \r
8281                 /**\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
8288                  *  @type boolean\r
8289                  *  @default false\r
8290                  *  @dtopt Options\r
8291                  * \r
8292                  *  @example\r
8293                  *    $(document).ready( function() {\r
8294                  *      $('#example').dataTable( {\r
8295                  *        "sScrollY": "200",\r
8296                  *        "bScrollCollapse": true\r
8297                  *      } );\r
8298                  *    } );\r
8299                  */\r
8300                 "bScrollCollapse": false,\r
8301         \r
8302         \r
8303                 /**\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
8310                  *  @type boolean\r
8311                  *  @default false\r
8312                  *  @dtopt Features\r
8313                  * \r
8314                  *  @example\r
8315                  *    $(document).ready( function() {\r
8316                  *      $('#example').dataTable( {\r
8317                  *        "bScrollInfinite": true,\r
8318                  *        "bScrollCollapse": true,\r
8319                  *        "sScrollY": "200px"\r
8320                  *      } );\r
8321                  *    } );\r
8322                  */\r
8323                 "bScrollInfinite": false,\r
8324         \r
8325         \r
8326                 /**\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
8330                  *  @type boolean\r
8331                  *  @default false\r
8332                  *  @dtopt Features\r
8333                  *  @dtopt Server-side\r
8334                  * \r
8335                  *  @example\r
8336                  *    $(document).ready( function () {\r
8337                  *      $('#example').dataTable( {\r
8338                  *        "bServerSide": true,\r
8339                  *        "sAjaxSource": "xhr.php"\r
8340                  *      } );\r
8341                  *    } );\r
8342                  */\r
8343                 "bServerSide": false,\r
8344         \r
8345         \r
8346                 /**\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
8349                  *  @type boolean\r
8350                  *  @default true\r
8351                  *  @dtopt Features\r
8352                  * \r
8353                  *  @example\r
8354                  *    $(document).ready( function () {\r
8355                  *      $('#example').dataTable( {\r
8356                  *        "bSort": false\r
8357                  *      } );\r
8358                  *    } );\r
8359                  */\r
8360                 "bSort": true,\r
8361         \r
8362         \r
8363                 /**\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
8367                  *  @type boolean\r
8368                  *  @default false\r
8369                  *  @dtopt Options\r
8370                  * \r
8371                  *  @example\r
8372                  *    $(document).ready( function() {\r
8373                  *      $('#example').dataTable( {\r
8374                  *        "bSortCellsTop": true\r
8375                  *      } );\r
8376                  *    } );\r
8377                  */\r
8378                 "bSortCellsTop": false,\r
8379         \r
8380         \r
8381                 /**\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
8386                  * turn this off.\r
8387                  *  @type boolean\r
8388                  *  @default true\r
8389                  *  @dtopt Features\r
8390                  * \r
8391                  *  @example\r
8392                  *    $(document).ready( function () {\r
8393                  *      $('#example').dataTable( {\r
8394                  *        "bSortClasses": false\r
8395                  *      } );\r
8396                  *    } );\r
8397                  */\r
8398                 "bSortClasses": true,\r
8399         \r
8400         \r
8401                 /**\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
8406                  *  @type boolean\r
8407                  *  @default false\r
8408                  *  @dtopt Features\r
8409                  * \r
8410                  *  @example\r
8411                  *    $(document).ready( function () {\r
8412                  *      $('#example').dataTable( {\r
8413                  *        "bStateSave": true\r
8414                  *      } );\r
8415                  *    } );\r
8416                  */\r
8417                 "bStateSave": false,\r
8418         \r
8419         \r
8420                 /**\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
8426                  *  @type function\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
8434                  * \r
8435                  *  @example\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
8441                  *        }\r
8442                  *      } );\r
8443                  *    } );\r
8444                  */\r
8445                 "fnCookieCallback": null,\r
8446         \r
8447         \r
8448                 /**\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
8452                  *  @type function\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
8457                  * \r
8458                  *  @example\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
8464                  *          {\r
8465                  *            $('td:eq(4)', nRow).html( '<b>A</b>' );\r
8466                  *          }\r
8467                  *        }\r
8468                  *      } );\r
8469                  *    } );\r
8470                  */\r
8471                 "fnCreatedRow": null,\r
8472         \r
8473         \r
8474                 /**\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
8477                  *  @type function\r
8478                  *  @param {object} oSettings DataTables settings object\r
8479                  *  @dtopt Callbacks\r
8480                  * \r
8481                  *  @example\r
8482                  *    $(document).ready( function() {\r
8483                  *      $('#example').dataTable( {\r
8484                  *        "fnDrawCallback": function( oSettings ) {\r
8485                  *          alert( 'DataTables has redrawn the table' );\r
8486                  *        }\r
8487                  *      } );\r
8488                  *    } );\r
8489                  */\r
8490                 "fnDrawCallback": null,\r
8491         \r
8492         \r
8493                 /**\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
8496                  *  @type function\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
8500                  *    display array\r
8501                  *  @param {int} iEnd Index for the current display ending point in the \r
8502                  *    display array\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
8506                  * \r
8507                  *  @example\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
8512                  *        }\r
8513                  *      } );\r
8514                  *    } )\r
8515                  */\r
8516                 "fnFooterCallback": null,\r
8517         \r
8518         \r
8519                 /**\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
8525                  *  @type function\r
8526                  *  @member\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
8530                  * \r
8531                  *  @example\r
8532                  *    $(document).ready( function() {\r
8533                  *      $('#example').dataTable( {\r
8534                  *        "fnFormatNumber": function ( iIn ) {\r
8535                  *          if ( iIn &lt; 1000 ) {\r
8536                  *            return iIn;\r
8537                  *          } else {\r
8538                  *            var \r
8539                  *              s=(iIn+""), \r
8540                  *              a=s.split(""), out="", \r
8541                  *              iLen=s.length;\r
8542                  *            \r
8543                  *            for ( var i=0 ; i&lt;iLen ; i++ ) {\r
8544                  *              if ( i%3 === 0 &amp;&amp; i !== 0 ) {\r
8545                  *                out = "'"+out;\r
8546                  *              }\r
8547                  *              out = a[iLen-i-1]+out;\r
8548                  *            }\r
8549                  *          }\r
8550                  *          return out;\r
8551                  *        };\r
8552                  *      } );\r
8553                  *    } );\r
8554                  */\r
8555                 "fnFormatNumber": function ( iIn ) {\r
8556                         if ( iIn < 1000 )\r
8557                         {\r
8558                                 // A small optimisation for what is likely to be the majority of use cases\r
8559                                 return iIn;\r
8560                         }\r
8561         \r
8562                         var s=(iIn+""), a=s.split(""), out="", iLen=s.length;\r
8563                         \r
8564                         for ( var i=0 ; i<iLen ; i++ )\r
8565                         {\r
8566                                 if ( i%3 === 0 && i !== 0 )\r
8567                                 {\r
8568                                         out = this.oLanguage.sInfoThousands+out;\r
8569                                 }\r
8570                                 out = a[iLen-i-1]+out;\r
8571                         }\r
8572                         return out;\r
8573                 },\r
8574         \r
8575         \r
8576                 /**\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
8580                  *  @type function\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
8584                  *    display array\r
8585                  *  @param {int} iEnd Index for the current display ending point in the\r
8586                  *    display array\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
8590                  * \r
8591                  *  @example\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
8596                  *        }\r
8597                  *      } );\r
8598                  *    } )\r
8599                  */\r
8600                 "fnHeaderCallback": null,\r
8601         \r
8602         \r
8603                 /**\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
8609                  *  @type function\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
8614                  *    filtering)\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
8617                  *    own rules\r
8618                  *  @returns {string} The string to be displayed in the information element.\r
8619                  *  @dtopt Callbacks\r
8620                  * \r
8621                  *  @example\r
8622                  *    $('#example').dataTable( {\r
8623                  *      "fnInfoCallback": function( oSettings, iStart, iEnd, iMax, iTotal, sPre ) {\r
8624                  *        return iStart +" to "+ iEnd;\r
8625                  *      }\r
8626                  *    } );\r
8627                  */\r
8628                 "fnInfoCallback": null,\r
8629         \r
8630         \r
8631                 /**\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
8636                  *  @type function\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
8641                  * \r
8642                  *  @example\r
8643                  *    $(document).ready( function() {\r
8644                  *      $('#example').dataTable( {\r
8645                  *        "fnInitComplete": function(oSettings, json) {\r
8646                  *          alert( 'DataTables has finished its initialisation.' );\r
8647                  *        }\r
8648                  *      } );\r
8649                  *    } )\r
8650                  */\r
8651                 "fnInitComplete": null,\r
8652         \r
8653         \r
8654                 /**\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
8658                  *  @type function\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
8663                  * \r
8664                  *  @example\r
8665                  *    $(document).ready( function() {\r
8666                  *      $('#example').dataTable( {\r
8667                  *        "fnPreDrawCallback": function( oSettings ) {\r
8668                  *          if ( $('#test').val() == 1 ) {\r
8669                  *            return false;\r
8670                  *          }\r
8671                  *        }\r
8672                  *      } );\r
8673                  *    } );\r
8674                  */\r
8675                 "fnPreDrawCallback": null,\r
8676         \r
8677         \r
8678                 /**\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
8682                  *  @type function\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
8689                  * \r
8690                  *  @example\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
8696                  *          {\r
8697                  *            $('td:eq(4)', nRow).html( '<b>A</b>' );\r
8698                  *          }\r
8699                  *        }\r
8700                  *      } );\r
8701                  *    } );\r
8702                  */\r
8703                 "fnRowCallback": null,\r
8704         \r
8705         \r
8706                 /**\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
8711                  *  @type function\r
8712                  *  @member\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
8715                  *    to the server\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
8721                  * \r
8722                  *  @example\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
8736                  *          } );\r
8737                  *        }\r
8738                  *      } );\r
8739                  *    } );\r
8740                  */\r
8741                 "fnServerData": function ( sUrl, aoData, fnCallback, oSettings ) {\r
8742                         oSettings.jqXHR = $.ajax( {\r
8743                                 "url":  sUrl,\r
8744                                 "data": aoData,\r
8745                                 "success": function (json) {\r
8746                                         if ( json.sError ) {\r
8747                                                 oSettings.oApi._fnLog( oSettings, 0, json.sError );\r
8748                                         }\r
8749                                         \r
8750                                         $(oSettings.oInstance).trigger('xhr', [oSettings, json]);\r
8751                                         fnCallback( json );\r
8752                                 },\r
8753                                 "dataType": "json",\r
8754                                 "cache": false,\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
8760                                         }\r
8761                                 }\r
8762                         } );\r
8763                 },\r
8764         \r
8765         \r
8766                 /**\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
8772                  *  @type function\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
8782                  * \r
8783                  *  @example\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
8791                  *        }\r
8792                  *      } );\r
8793                  *    } );\r
8794                  */\r
8795                 "fnServerParams": null,\r
8796         \r
8797         \r
8798                 /**\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
8802                  *  @type function\r
8803                  *  @member\r
8804                  *  @param {object} oSettings DataTables settings object\r
8805                  *  @return {object} The DataTables state object to be loaded\r
8806                  *  @dtopt Callbacks\r
8807                  * \r
8808                  *  @example\r
8809                  *    $(document).ready( function() {\r
8810                  *      $('#example').dataTable( {\r
8811                  *        "bStateSave": true,\r
8812                  *        "fnStateLoad": function (oSettings) {\r
8813                  *          var o;\r
8814                  *          \r
8815                  *          // Send an Ajax request to the server to get the data. Note that\r
8816                  *          // this is a synchronous request.\r
8817                  *          $.ajax( {\r
8818                  *            "url": "/state_load",\r
8819                  *            "async": false,\r
8820                  *            "dataType": "json",\r
8821                  *            "success": function (json) {\r
8822                  *              o = json;\r
8823                  *            }\r
8824                  *          } );\r
8825                  *          \r
8826                  *          return o;\r
8827                  *        }\r
8828                  *      } );\r
8829                  *    } );\r
8830                  */\r
8831                 "fnStateLoad": function ( oSettings ) {\r
8832                         var sData = this.oApi._fnReadCookie( oSettings.sCookiePrefix+oSettings.sInstance );\r
8833                         var oData;\r
8834         \r
8835                         try {\r
8836                                 oData = (typeof $.parseJSON === 'function') ? \r
8837                                         $.parseJSON(sData) : eval( '('+sData+')' );\r
8838                         } catch (e) {\r
8839                                 oData = null;\r
8840                         }\r
8841         \r
8842                         return oData;\r
8843                 },\r
8844         \r
8845         \r
8846                 /**\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
8851                  * a plug-in.\r
8852                  *  @type function\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
8856                  * \r
8857                  *  @example\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
8864                  *        }\r
8865                  *      } );\r
8866                  *    } );\r
8867                  * \r
8868                  *  @example\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
8874                  *          return false;\r
8875                  *        }\r
8876                  *      } );\r
8877                  *    } );\r
8878                  */\r
8879                 "fnStateLoadParams": null,\r
8880         \r
8881         \r
8882                 /**\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
8885                  *  @type function\r
8886                  *  @param {object} oSettings DataTables settings object\r
8887                  *  @param {object} oData The state object that was loaded\r
8888                  *  @dtopt Callbacks\r
8889                  * \r
8890                  *  @example\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
8897                  *        }\r
8898                  *      } );\r
8899                  *    } );\r
8900                  */\r
8901                 "fnStateLoaded": null,\r
8902         \r
8903         \r
8904                 /**\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
8908                  *  @type function\r
8909                  *  @member\r
8910                  *  @param {object} oSettings DataTables settings object\r
8911                  *  @param {object} oData The state object to be saved\r
8912                  *  @dtopt Callbacks\r
8913                  * \r
8914                  *  @example\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
8920                  *          $.ajax( {\r
8921                  *            "url": "/state_save",\r
8922                  *            "data": oData,\r
8923                  *            "dataType": "json",\r
8924                  *            "method": "POST"\r
8925                  *            "success": function () {}\r
8926                  *          } );\r
8927                  *        }\r
8928                  *      } );\r
8929                  *    } );\r
8930                  */\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
8938                         );\r
8939                 },\r
8940         \r
8941         \r
8942                 /**\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
8948                  *  @type function\r
8949                  *  @param {object} oSettings DataTables settings object\r
8950                  *  @param {object} oData The state object to be saved\r
8951                  *  @dtopt Callbacks\r
8952                  * \r
8953                  *  @example\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
8960                  *        }\r
8961                  *      } );\r
8962                  *    } );\r
8963                  */\r
8964                 "fnStateSaveParams": null,\r
8965         \r
8966         \r
8967                 /**\r
8968                  * Duration of the cookie which is used for storing session information. This\r
8969                  * value is given in seconds.\r
8970                  *  @type int\r
8971                  *  @default 7200 <i>(2 hours)</i>\r
8972                  *  @dtopt Options\r
8973                  * \r
8974                  *  @example\r
8975                  *    $(document).ready( function() {\r
8976                  *      $('#example').dataTable( {\r
8977                  *        "iCookieDuration": 60*60*24; // 1 day\r
8978                  *      } );\r
8979                  *    } )\r
8980                  */\r
8981                 "iCookieDuration": 7200,\r
8982         \r
8983         \r
8984                 /**\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
8997                  *  @default null\r
8998                  *  @dtopt Options\r
8999                  * \r
9000                  *  @example\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
9007                  *      } );\r
9008                  *    } );\r
9009                  * \r
9010                  *  @example\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
9017                  *        "oSearch": {\r
9018                  *          "sSearch": "my_filter"\r
9019                  *        }\r
9020                  *      } );\r
9021                  *    } );\r
9022                  */\r
9023                 "iDeferLoading": null,\r
9024         \r
9025         \r
9026                 /**\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
9030                  *  @type int\r
9031                  *  @default 10\r
9032                  *  @dtopt Options\r
9033                  * \r
9034                  *  @example\r
9035                  *    $(document).ready( function() {\r
9036                  *      $('#example').dataTable( {\r
9037                  *        "iDisplayLength": 50\r
9038                  *      } );\r
9039                  *    } )\r
9040                  */\r
9041                 "iDisplayLength": 10,\r
9042         \r
9043         \r
9044                 /**\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
9049                  *  @type int\r
9050                  *  @default 0\r
9051                  *  @dtopt Options\r
9052                  * \r
9053                  *  @example\r
9054                  *    $(document).ready( function() {\r
9055                  *      $('#example').dataTable( {\r
9056                  *        "iDisplayStart": 20\r
9057                  *      } );\r
9058                  *    } )\r
9059                  */\r
9060                 "iDisplayStart": 0,\r
9061         \r
9062         \r
9063                 /**\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
9068                  *  @type int\r
9069                  *  @default 100\r
9070                  *  @dtopt Options\r
9071                  * \r
9072                  *  @example\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
9079                  *      } );\r
9080                  *    } );\r
9081                  */\r
9082                 "iScrollLoadGap": 100,\r
9083         \r
9084         \r
9085                 /**\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
9092                  *  @type int\r
9093                  *  @default 0\r
9094                  *  @dtopt Options\r
9095                  * \r
9096                  *  @example\r
9097                  *    $(document).ready( function() {\r
9098                  *      $('#example').dataTable( {\r
9099                  *        "iTabIndex": 1\r
9100                  *      } );\r
9101                  *    } );\r
9102                  */\r
9103                 "iTabIndex": 0,\r
9104         \r
9105         \r
9106                 /**\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
9110                  *  @namespace\r
9111                  */\r
9112                 "oLanguage": {\r
9113                         /**\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
9117                          *  @namespace\r
9118                          */\r
9119                         "oAria": {\r
9120                                 /**\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
9124                                  *  @type string\r
9125                                  *  @default : activate to sort column ascending\r
9126                                  *  @dtopt Language\r
9127                                  * \r
9128                                  *  @example\r
9129                                  *    $(document).ready( function() {\r
9130                                  *      $('#example').dataTable( {\r
9131                                  *        "oLanguage": {\r
9132                                  *          "oAria": {\r
9133                                  *            "sSortAscending": " - click/return to sort ascending"\r
9134                                  *          }\r
9135                                  *        }\r
9136                                  *      } );\r
9137                                  *    } );\r
9138                                  */\r
9139                                 "sSortAscending": ": activate to sort column ascending",\r
9140         \r
9141                                 /**\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
9145                                  *  @type string\r
9146                                  *  @default : activate to sort column ascending\r
9147                                  *  @dtopt Language\r
9148                                  * \r
9149                                  *  @example\r
9150                                  *    $(document).ready( function() {\r
9151                                  *      $('#example').dataTable( {\r
9152                                  *        "oLanguage": {\r
9153                                  *          "oAria": {\r
9154                                  *            "sSortDescending": " - click/return to sort descending"\r
9155                                  *          }\r
9156                                  *        }\r
9157                                  *      } );\r
9158                                  *    } );\r
9159                                  */\r
9160                                 "sSortDescending": ": activate to sort column descending"\r
9161                         },\r
9162         \r
9163                         /**\r
9164                          * Pagination string used by DataTables for the two built-in pagination\r
9165                          * control types ("two_button" and "full_numbers")\r
9166                          *  @namespace\r
9167                          */\r
9168                         "oPaginate": {\r
9169                                 /**\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
9172                                  *  @type string\r
9173                                  *  @default First\r
9174                                  *  @dtopt Language\r
9175                                  * \r
9176                                  *  @example\r
9177                                  *    $(document).ready( function() {\r
9178                                  *      $('#example').dataTable( {\r
9179                                  *        "oLanguage": {\r
9180                                  *          "oPaginate": {\r
9181                                  *            "sFirst": "First page"\r
9182                                  *          }\r
9183                                  *        }\r
9184                                  *      } );\r
9185                                  *    } );\r
9186                                  */\r
9187                                 "sFirst": "First",\r
9188                         \r
9189                         \r
9190                                 /**\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
9193                                  *  @type string\r
9194                                  *  @default Last\r
9195                                  *  @dtopt Language\r
9196                                  * \r
9197                                  *  @example\r
9198                                  *    $(document).ready( function() {\r
9199                                  *      $('#example').dataTable( {\r
9200                                  *        "oLanguage": {\r
9201                                  *          "oPaginate": {\r
9202                                  *            "sLast": "Last page"\r
9203                                  *          }\r
9204                                  *        }\r
9205                                  *      } );\r
9206                                  *    } );\r
9207                                  */\r
9208                                 "sLast": "Last",\r
9209                         \r
9210                         \r
9211                                 /**\r
9212                                  * Text to use for the 'next' pagination button (to take the user to the \r
9213                                  * next page).\r
9214                                  *  @type string\r
9215                                  *  @default Next\r
9216                                  *  @dtopt Language\r
9217                                  * \r
9218                                  *  @example\r
9219                                  *    $(document).ready( function() {\r
9220                                  *      $('#example').dataTable( {\r
9221                                  *        "oLanguage": {\r
9222                                  *          "oPaginate": {\r
9223                                  *            "sNext": "Next page"\r
9224                                  *          }\r
9225                                  *        }\r
9226                                  *      } );\r
9227                                  *    } );\r
9228                                  */\r
9229                                 "sNext": "Next",\r
9230                         \r
9231                         \r
9232                                 /**\r
9233                                  * Text to use for the 'previous' pagination button (to take the user to  \r
9234                                  * the previous page).\r
9235                                  *  @type string\r
9236                                  *  @default Previous\r
9237                                  *  @dtopt Language\r
9238                                  * \r
9239                                  *  @example\r
9240                                  *    $(document).ready( function() {\r
9241                                  *      $('#example').dataTable( {\r
9242                                  *        "oLanguage": {\r
9243                                  *          "oPaginate": {\r
9244                                  *            "sPrevious": "Previous page"\r
9245                                  *          }\r
9246                                  *        }\r
9247                                  *      } );\r
9248                                  *    } );\r
9249                                  */\r
9250                                 "sPrevious": "Previous"\r
9251                         },\r
9252                 \r
9253                         /**\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
9258                          *  @type string\r
9259                          *  @default No data available in table\r
9260                          *  @dtopt Language\r
9261                          * \r
9262                          *  @example\r
9263                          *    $(document).ready( function() {\r
9264                          *      $('#example').dataTable( {\r
9265                          *        "oLanguage": {\r
9266                          *          "sEmptyTable": "No data available in table"\r
9267                          *        }\r
9268                          *      } );\r
9269                          *    } );\r
9270                          */\r
9271                         "sEmptyTable": "No data available in table",\r
9272                 \r
9273                 \r
9274                         /**\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
9279                          *  @type string\r
9280                          *  @default Showing _START_ to _END_ of _TOTAL_ entries\r
9281                          *  @dtopt Language\r
9282                          * \r
9283                          *  @example\r
9284                          *    $(document).ready( function() {\r
9285                          *      $('#example').dataTable( {\r
9286                          *        "oLanguage": {\r
9287                          *          "sInfo": "Got a total of _TOTAL_ entries to show (_START_ to _END_)"\r
9288                          *        }\r
9289                          *      } );\r
9290                          *    } );\r
9291                          */\r
9292                         "sInfo": "Showing _START_ to _END_ of _TOTAL_ entries",\r
9293                 \r
9294                 \r
9295                         /**\r
9296                          * Display information string for when the table is empty. Typically the \r
9297                          * format of this string should match sInfo.\r
9298                          *  @type string\r
9299                          *  @default Showing 0 to 0 of 0 entries\r
9300                          *  @dtopt Language\r
9301                          * \r
9302                          *  @example\r
9303                          *    $(document).ready( function() {\r
9304                          *      $('#example').dataTable( {\r
9305                          *        "oLanguage": {\r
9306                          *          "sInfoEmpty": "No entries to show"\r
9307                          *        }\r
9308                          *      } );\r
9309                          *    } );\r
9310                          */\r
9311                         "sInfoEmpty": "Showing 0 to 0 of 0 entries",\r
9312                 \r
9313                 \r
9314                         /**\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
9318                          *  @type string\r
9319                          *  @default (filtered from _MAX_ total entries)\r
9320                          *  @dtopt Language\r
9321                          * \r
9322                          *  @example\r
9323                          *    $(document).ready( function() {\r
9324                          *      $('#example').dataTable( {\r
9325                          *        "oLanguage": {\r
9326                          *          "sInfoFiltered": " - filtering from _MAX_ records"\r
9327                          *        }\r
9328                          *      } );\r
9329                          *    } );\r
9330                          */\r
9331                         "sInfoFiltered": "(filtered from _MAX_ total entries)",\r
9332                 \r
9333                 \r
9334                         /**\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
9339                          *  @type string\r
9340                          *  @default <i>Empty string</i>\r
9341                          *  @dtopt Language\r
9342                          * \r
9343                          *  @example\r
9344                          *    $(document).ready( function() {\r
9345                          *      $('#example').dataTable( {\r
9346                          *        "oLanguage": {\r
9347                          *          "sInfoPostFix": "All records shown are derived from real information."\r
9348                          *        }\r
9349                          *      } );\r
9350                          *    } );\r
9351                          */\r
9352                         "sInfoPostFix": "",\r
9353                 \r
9354                 \r
9355                         /**\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
9360                          *  @type string\r
9361                          *  @default ,\r
9362                          *  @dtopt Language\r
9363                          * \r
9364                          *  @example\r
9365                          *    $(document).ready( function() {\r
9366                          *      $('#example').dataTable( {\r
9367                          *        "oLanguage": {\r
9368                          *          "sInfoThousands": "'"\r
9369                          *        }\r
9370                          *      } );\r
9371                          *    } );\r
9372                          */\r
9373                         "sInfoThousands": ",",\r
9374                 \r
9375                 \r
9376                         /**\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
9381                          *  @type string\r
9382                          *  @default Show _MENU_ entries\r
9383                          *  @dtopt Language\r
9384                          * \r
9385                          *  @example\r
9386                          *    // Language change only\r
9387                          *    $(document).ready( function() {\r
9388                          *      $('#example').dataTable( {\r
9389                          *        "oLanguage": {\r
9390                          *          "sLengthMenu": "Display _MENU_ records"\r
9391                          *        }\r
9392                          *      } );\r
9393                          *    } );\r
9394                          *    \r
9395                          *  @example\r
9396                          *    // Language and options change\r
9397                          *    $(document).ready( function() {\r
9398                          *      $('#example').dataTable( {\r
9399                          *        "oLanguage": {\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
9408                          *        }\r
9409                          *      } );\r
9410                          *    } );\r
9411                          */\r
9412                         "sLengthMenu": "Show _MENU_ entries",\r
9413                 \r
9414                 \r
9415                         /**\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
9421                          *  @type string\r
9422                          *  @default Loading...\r
9423                          *  @dtopt Language\r
9424                          * \r
9425                          *  @example\r
9426                          *    $(document).ready( function() {\r
9427                          *      $('#example').dataTable( {\r
9428                          *        "oLanguage": {\r
9429                          *          "sLoadingRecords": "Please wait - loading..."\r
9430                          *        }\r
9431                          *      } );\r
9432                          *    } );\r
9433                          */\r
9434                         "sLoadingRecords": "Loading...",\r
9435                 \r
9436                 \r
9437                         /**\r
9438                          * Text which is displayed when the table is processing a user action\r
9439                          * (usually a sort command or similar).\r
9440                          *  @type string\r
9441                          *  @default Processing...\r
9442                          *  @dtopt Language\r
9443                          * \r
9444                          *  @example\r
9445                          *    $(document).ready( function() {\r
9446                          *      $('#example').dataTable( {\r
9447                          *        "oLanguage": {\r
9448                          *          "sProcessing": "DataTables is currently busy"\r
9449                          *        }\r
9450                          *      } );\r
9451                          *    } );\r
9452                          */\r
9453                         "sProcessing": "Processing...",\r
9454                 \r
9455                 \r
9456                         /**\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
9462                          *  @type string\r
9463                          *  @default Search:\r
9464                          *  @dtopt Language\r
9465                          * \r
9466                          *  @example\r
9467                          *    // Input text box will be appended at the end automatically\r
9468                          *    $(document).ready( function() {\r
9469                          *      $('#example').dataTable( {\r
9470                          *        "oLanguage": {\r
9471                          *          "sSearch": "Filter records:"\r
9472                          *        }\r
9473                          *      } );\r
9474                          *    } );\r
9475                          *    \r
9476                          *  @example\r
9477                          *    // Specify where the filter should appear\r
9478                          *    $(document).ready( function() {\r
9479                          *      $('#example').dataTable( {\r
9480                          *        "oLanguage": {\r
9481                          *          "sSearch": "Apply filter _INPUT_ to table"\r
9482                          *        }\r
9483                          *      } );\r
9484                          *    } );\r
9485                          */\r
9486                         "sSearch": "Search:",\r
9487                 \r
9488                 \r
9489                         /**\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
9496                          *  @type string\r
9497                          *  @default <i>Empty string - i.e. disabled</i>\r
9498                          *  @dtopt Language\r
9499                          * \r
9500                          *  @example\r
9501                          *    $(document).ready( function() {\r
9502                          *      $('#example').dataTable( {\r
9503                          *        "oLanguage": {\r
9504                          *          "sUrl": "http://www.sprymedia.co.uk/dataTables/lang.txt"\r
9505                          *        }\r
9506                          *      } );\r
9507                          *    } );\r
9508                          */\r
9509                         "sUrl": "",\r
9510                 \r
9511                 \r
9512                         /**\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
9516                          *  @type string\r
9517                          *  @default No matching records found\r
9518                          *  @dtopt Language\r
9519                          * \r
9520                          *  @example\r
9521                          *    $(document).ready( function() {\r
9522                          *      $('#example').dataTable( {\r
9523                          *        "oLanguage": {\r
9524                          *          "sZeroRecords": "No records to display"\r
9525                          *        }\r
9526                          *      } );\r
9527                          *    } );\r
9528                          */\r
9529                         "sZeroRecords": "No matching records found"\r
9530                 },\r
9531         \r
9532         \r
9533                 /**\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
9541                  *  @namespace\r
9542                  *  @extends DataTable.models.oSearch\r
9543                  *  @dtopt Options\r
9544                  * \r
9545                  *  @example\r
9546                  *    $(document).ready( function() {\r
9547                  *      $('#example').dataTable( {\r
9548                  *        "oSearch": {"sSearch": "Initial search"}\r
9549                  *      } );\r
9550                  *    } )\r
9551                  */\r
9552                 "oSearch": $.extend( {}, DataTable.models.oSearch ),\r
9553         \r
9554         \r
9555                 /**\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
9560                  *  @type string\r
9561                  *  @default aaData\r
9562                  *  @dtopt Options\r
9563                  *  @dtopt Server-side\r
9564                  * \r
9565                  *  @example\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
9571                  *      } );\r
9572                  *    } );\r
9573                  *    \r
9574                  *  @example\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
9580                  *      } );\r
9581                  *    } );\r
9582                  */\r
9583                 "sAjaxDataProp": "aaData",\r
9584         \r
9585         \r
9586                 /**\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
9591                  *  @type string\r
9592                  *  @default null\r
9593                  *  @dtopt Options\r
9594                  *  @dtopt Server-side\r
9595                  * \r
9596                  *  @example\r
9597                  *    $(document).ready( function() {\r
9598                  *      $('#example').dataTable( {\r
9599                  *        "sAjaxSource": "http://www.sprymedia.co.uk/dataTables/json.php"\r
9600                  *      } );\r
9601                  *    } )\r
9602                  */\r
9603                 "sAjaxSource": null,\r
9604         \r
9605         \r
9606                 /**\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
9609                  *  @type string\r
9610                  *  @default SpryMedia_DataTables_\r
9611                  *  @dtopt Options\r
9612                  * \r
9613                  *  @example\r
9614                  *    $(document).ready( function() {\r
9615                  *      $('#example').dataTable( {\r
9616                  *        "sCookiePrefix": "my_datatable_",\r
9617                  *      } );\r
9618                  *    } );\r
9619                  */\r
9620                 "sCookiePrefix": "SpryMedia_DataTables_",\r
9621         \r
9622         \r
9623                 /**\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
9629                  *   <ul>\r
9630                  *     <li>The following options are allowed:   \r
9631                  *       <ul>\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
9638                  *       </ul>\r
9639                  *     </li>\r
9640                  *     <li>The following constants are allowed:\r
9641                  *       <ul>\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
9644                  *       </ul>\r
9645                  *     </li>\r
9646                  *     <li>The following syntax is expected:\r
9647                  *       <ul>\r
9648                  *         <li>'&lt;' and '&gt;' - div elements</li>\r
9649                  *         <li>'&lt;"class" and '&gt;' - div with a class</li>\r
9650                  *         <li>'&lt;"#id" and '&gt;' - div with an ID</li>\r
9651                  *       </ul>\r
9652                  *     </li>\r
9653                  *     <li>Examples:\r
9654                  *       <ul>\r
9655                  *         <li>'&lt;"wrapper"flipt&gt;'</li>\r
9656                  *         <li>'&lt;lf&lt;t&gt;ip&gt;'</li>\r
9657                  *       </ul>\r
9658                  *     </li>\r
9659                  *   </ul>\r
9660                  *  @type string\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
9663                  *  @dtopt Options\r
9664                  * \r
9665                  *  @example\r
9666                  *    $(document).ready( function() {\r
9667                  *      $('#example').dataTable( {\r
9668                  *        "sDom": '&lt;"top"i&gt;rt&lt;"bottom"flp&gt;&lt;"clear"&gt;'\r
9669                  *      } );\r
9670                  *    } );\r
9671                  */\r
9672                 "sDom": "lfrtip",\r
9673         \r
9674         \r
9675                 /**\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
9679                  *  @type string\r
9680                  *  @default two_button\r
9681                  *  @dtopt Options\r
9682                  * \r
9683                  *  @example\r
9684                  *    $(document).ready( function() {\r
9685                  *      $('#example').dataTable( {\r
9686                  *        "sPaginationType": "full_numbers"\r
9687                  *      } );\r
9688                  *    } )\r
9689                  */\r
9690                 "sPaginationType": "two_button",\r
9691         \r
9692         \r
9693                 /**\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
9699                  *  @type string\r
9700                  *  @default <i>blank string - i.e. disabled</i>\r
9701                  *  @dtopt Features\r
9702                  * \r
9703                  *  @example\r
9704                  *    $(document).ready( function() {\r
9705                  *      $('#example').dataTable( {\r
9706                  *        "sScrollX": "100%",\r
9707                  *        "bScrollCollapse": true\r
9708                  *      } );\r
9709                  *    } );\r
9710                  */\r
9711                 "sScrollX": "",\r
9712         \r
9713         \r
9714                 /**\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
9720                  * measurement).\r
9721                  *  @type string\r
9722                  *  @default <i>blank string - i.e. disabled</i>\r
9723                  *  @dtopt Options\r
9724                  * \r
9725                  *  @example\r
9726                  *    $(document).ready( function() {\r
9727                  *      $('#example').dataTable( {\r
9728                  *        "sScrollX": "100%",\r
9729                  *        "sScrollXInner": "110%"\r
9730                  *      } );\r
9731                  *    } );\r
9732                  */\r
9733                 "sScrollXInner": "",\r
9734         \r
9735         \r
9736                 /**\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
9743                  *  @type string\r
9744                  *  @default <i>blank string - i.e. disabled</i>\r
9745                  *  @dtopt Features\r
9746                  * \r
9747                  *  @example\r
9748                  *    $(document).ready( function() {\r
9749                  *      $('#example').dataTable( {\r
9750                  *        "sScrollY": "200px",\r
9751                  *        "bPaginate": false\r
9752                  *      } );\r
9753                  *    } );\r
9754                  */\r
9755                 "sScrollY": "",\r
9756         \r
9757         \r
9758                 /**\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
9761                  *  @type string\r
9762                  *  @default GET\r
9763                  *  @dtopt Options\r
9764                  *  @dtopt Server-side\r
9765                  * \r
9766                  *  @example\r
9767                  *    $(document).ready( function() {\r
9768                  *      $('#example').dataTable( {\r
9769                  *        "bServerSide": true,\r
9770                  *        "sAjaxSource": "scripts/post.php",\r
9771                  *        "sServerMethod": "POST"\r
9772                  *      } );\r
9773                  *    } );\r
9774                  */\r
9775                 "sServerMethod": "GET"\r
9776         };\r
9777         \r
9778         \r
9779         \r
9780         /**\r
9781          * Column options that can be given to DataTables at initialisation time.\r
9782          *  @namespace\r
9783          */\r
9784         DataTable.defaults.columns = {\r
9785                 /**\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
9789                  *  @type array\r
9790                  *  @default null <i>Takes the value of the column index automatically</i>\r
9791                  *  @dtopt Columns\r
9792                  * \r
9793                  *  @example\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
9801                  *        ]\r
9802                  *      } );\r
9803                  *    } );\r
9804                  *    \r
9805                  *  @example\r
9806                  *    // Using aoColumns\r
9807                  *    $(document).ready( function() {\r
9808                  *      $('#example').dataTable( {\r
9809                  *        "aoColumns": [\r
9810                  *          { "aDataSort": [ 0, 1 ] },\r
9811                  *          { "aDataSort": [ 1, 0 ] },\r
9812                  *          { "aDataSort": [ 2, 3, 4 ] },\r
9813                  *          null,\r
9814                  *          null\r
9815                  *        ]\r
9816                  *      } );\r
9817                  *    } );\r
9818                  */\r
9819                 "aDataSort": null,\r
9820         \r
9821         \r
9822                 /**\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
9825                  * parameter.\r
9826                  *  @type array\r
9827                  *  @default [ 'asc', 'desc' ]\r
9828                  *  @dtopt Columns\r
9829                  * \r
9830                  *  @example\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
9838                  *        ]\r
9839                  *      } );\r
9840                  *    } );\r
9841                  *    \r
9842                  *  @example\r
9843                  *    // Using aoColumns\r
9844                  *    $(document).ready( function() {\r
9845                  *      $('#example').dataTable( {\r
9846                  *        "aoColumns": [\r
9847                  *          null,\r
9848                  *          { "asSorting": [ "asc" ] },\r
9849                  *          { "asSorting": [ "desc", "asc", "asc" ] },\r
9850                  *          { "asSorting": [ "desc" ] },\r
9851                  *          null\r
9852                  *        ]\r
9853                  *      } );\r
9854                  *    } );\r
9855                  */\r
9856                 "asSorting": [ 'asc', 'desc' ],\r
9857         \r
9858         \r
9859                 /**\r
9860                  * Enable or disable filtering on the data in this column.\r
9861                  *  @type boolean\r
9862                  *  @default true\r
9863                  *  @dtopt Columns\r
9864                  * \r
9865                  *  @example\r
9866                  *    // Using aoColumnDefs\r
9867                  *    $(document).ready( function() {\r
9868                  *      $('#example').dataTable( {\r
9869                  *        "aoColumnDefs": [ \r
9870                  *          { "bSearchable": false, "aTargets": [ 0 ] }\r
9871                  *        ] } );\r
9872                  *    } );\r
9873                  *    \r
9874                  *  @example\r
9875                  *    // Using aoColumns\r
9876                  *    $(document).ready( function() {\r
9877                  *      $('#example').dataTable( {\r
9878                  *        "aoColumns": [ \r
9879                  *          { "bSearchable": false },\r
9880                  *          null,\r
9881                  *          null,\r
9882                  *          null,\r
9883                  *          null\r
9884                  *        ] } );\r
9885                  *    } );\r
9886                  */\r
9887                 "bSearchable": true,\r
9888         \r
9889         \r
9890                 /**\r
9891                  * Enable or disable sorting on this column.\r
9892                  *  @type boolean\r
9893                  *  @default true\r
9894                  *  @dtopt Columns\r
9895                  * \r
9896                  *  @example\r
9897                  *    // Using aoColumnDefs\r
9898                  *    $(document).ready( function() {\r
9899                  *      $('#example').dataTable( {\r
9900                  *        "aoColumnDefs": [ \r
9901                  *          { "bSortable": false, "aTargets": [ 0 ] }\r
9902                  *        ] } );\r
9903                  *    } );\r
9904                  *    \r
9905                  *  @example\r
9906                  *    // Using aoColumns\r
9907                  *    $(document).ready( function() {\r
9908                  *      $('#example').dataTable( {\r
9909                  *        "aoColumns": [ \r
9910                  *          { "bSortable": false },\r
9911                  *          null,\r
9912                  *          null,\r
9913                  *          null,\r
9914                  *          null\r
9915                  *        ] } );\r
9916                  *    } );\r
9917                  */\r
9918                 "bSortable": true,\r
9919         \r
9920         \r
9921                 /**\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
9926                  * \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
9929                  * fnRender.\r
9930                  *  @type boolean\r
9931                  *  @default true\r
9932                  *  @dtopt Columns\r
9933                  *  @deprecated\r
9934                  */\r
9935                 "bUseRendered": true,\r
9936         \r
9937         \r
9938                 /**\r
9939                  * Enable or disable the display of this column.\r
9940                  *  @type boolean\r
9941                  *  @default true\r
9942                  *  @dtopt Columns\r
9943                  * \r
9944                  *  @example\r
9945                  *    // Using aoColumnDefs\r
9946                  *    $(document).ready( function() {\r
9947                  *      $('#example').dataTable( {\r
9948                  *        "aoColumnDefs": [ \r
9949                  *          { "bVisible": false, "aTargets": [ 0 ] }\r
9950                  *        ] } );\r
9951                  *    } );\r
9952                  *    \r
9953                  *  @example\r
9954                  *    // Using aoColumns\r
9955                  *    $(document).ready( function() {\r
9956                  *      $('#example').dataTable( {\r
9957                  *        "aoColumns": [ \r
9958                  *          { "bVisible": false },\r
9959                  *          null,\r
9960                  *          null,\r
9961                  *          null,\r
9962                  *          null\r
9963                  *        ] } );\r
9964                  *    } );\r
9965                  */\r
9966                 "bVisible": true,\r
9967                 \r
9968                 \r
9969                 /**\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
9974                  *  @type function\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
9980                  *  @dtopt Columns\r
9981                  * \r
9982                  *  @example\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
9990                  *            }\r
9991                  *          }\r
9992                  *        } ]\r
9993                  *      });\r
9994                  *    } );\r
9995                  */\r
9996                 "fnCreatedCell": null,\r
9997         \r
9998         \r
9999                 /**\r
10000                  * <code>Deprecated</code> Custom display function that will be called for the \r
10001                  * display of each cell in this column.\r
10002                  *\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
10005                  * fnRender.\r
10006                  *  @type function\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
10015                  *  @dtopt Columns\r
10016                  *  @deprecated\r
10017                  */\r
10018                 "fnRender": null,\r
10019         \r
10020         \r
10021                 /**\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
10025                  *  @type int\r
10026                  *  @default -1 <i>Use automatically calculated column index</i>\r
10027                  *  @dtopt Columns\r
10028                  * \r
10029                  *  @example\r
10030                  *    // Using aoColumnDefs\r
10031                  *    $(document).ready( function() {\r
10032                  *      $('#example').dataTable( {\r
10033                  *        "aoColumnDefs": [ \r
10034                  *          { "iDataSort": 1, "aTargets": [ 0 ] }\r
10035                  *        ]\r
10036                  *      } );\r
10037                  *    } );\r
10038                  *    \r
10039                  *  @example\r
10040                  *    // Using aoColumns\r
10041                  *    $(document).ready( function() {\r
10042                  *      $('#example').dataTable( {\r
10043                  *        "aoColumns": [ \r
10044                  *          { "iDataSort": 1 },\r
10045                  *          null,\r
10046                  *          null,\r
10047                  *          null,\r
10048                  *          null\r
10049                  *        ]\r
10050                  *      } );\r
10051                  *    } );\r
10052                  */\r
10053                 "iDataSort": -1,\r
10054         \r
10055         \r
10056                 /**\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
10062                  */\r
10063         \r
10064         \r
10065                 /**\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
10069                  *   <ul>\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
10082                  *       <ul>\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
10089                  *       </ul>\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
10093                  *    </ul>\r
10094                  *\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
10101                  *  @dtopt Columns\r
10102                  * \r
10103                  *  @example\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
10108                  *        "aoColumns": [\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
10114                  *        ]\r
10115                  *      } );\r
10116                  *    } );\r
10117                  * \r
10118                  *  @example\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
10131                  *              return;\r
10132                  *            }\r
10133                  *            else if (type === 'display') {\r
10134                  *              return source.price_display;\r
10135                  *            }\r
10136                  *            else if (type === 'filter') {\r
10137                  *              return source.price_filter;\r
10138                  *            }\r
10139                  *            // 'sort', 'type' and undefined all just use the integer\r
10140                  *            return source.price;\r
10141                  *          }\r
10142                  *        } ]\r
10143                  *      } );\r
10144                  *    } );\r
10145                  */\r
10146                 "mData": null,\r
10147         \r
10148         \r
10149                 /**\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
10157                  * objects):\r
10158                  *   <ul>\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
10171                  *       <ul>\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
10176                  *       </ul>\r
10177                  *       The return value from the function is what will be used for the data\r
10178                  *       requested.</li>\r
10179                  *    </ul>\r
10180                  *  @type string|int|function|null\r
10181                  *  @default null <i>Use mData</i>\r
10182                  *  @dtopt Columns\r
10183                  * \r
10184                  *  @example\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
10189                  *        "aoColumns": [\r
10190                  *          { "mData": "engine" },\r
10191                  *          { "mData": "browser" },\r
10192                  *          {\r
10193                  *            "mData": "platform",\r
10194                  *            "mRender": "[, ].name"\r
10195                  *          }\r
10196                  *        ]\r
10197                  *      } );\r
10198                  *    } );\r
10199                  * \r
10200                  *  @example\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
10205                  *        {\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
10210                  *          }\r
10211                  *        ]\r
10212                  *      } );\r
10213                  *    } );\r
10214                  */\r
10215                 "mRender": null,\r
10216         \r
10217         \r
10218                 /**\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
10222                  *  @type string\r
10223                  *  @default td\r
10224                  *  @dtopt Columns\r
10225                  * \r
10226                  *  @example\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
10233                  *        } ]\r
10234                  *      } );\r
10235                  *    } );\r
10236                  */\r
10237                 "sCellType": "td",\r
10238         \r
10239         \r
10240                 /**\r
10241                  * Class to give to each cell in this column.\r
10242                  *  @type string\r
10243                  *  @default <i>Empty string</i>\r
10244                  *  @dtopt Columns\r
10245                  * \r
10246                  *  @example\r
10247                  *    // Using aoColumnDefs\r
10248                  *    $(document).ready( function() {\r
10249                  *      $('#example').dataTable( {\r
10250                  *        "aoColumnDefs": [ \r
10251                  *          { "sClass": "my_class", "aTargets": [ 0 ] }\r
10252                  *        ]\r
10253                  *      } );\r
10254                  *    } );\r
10255                  *    \r
10256                  *  @example\r
10257                  *    // Using aoColumns\r
10258                  *    $(document).ready( function() {\r
10259                  *      $('#example').dataTable( {\r
10260                  *        "aoColumns": [ \r
10261                  *          { "sClass": "my_class" },\r
10262                  *          null,\r
10263                  *          null,\r
10264                  *          null,\r
10265                  *          null\r
10266                  *        ]\r
10267                  *      } );\r
10268                  *    } );\r
10269                  */\r
10270                 "sClass": "",\r
10271                 \r
10272                 /**\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
10283                  *  @type string\r
10284                  *  @default <i>Empty string<i>\r
10285                  *  @dtopt Columns\r
10286                  *    \r
10287                  *  @example\r
10288                  *    // Using aoColumns\r
10289                  *    $(document).ready( function() {\r
10290                  *      $('#example').dataTable( {\r
10291                  *        "aoColumns": [ \r
10292                  *          null,\r
10293                  *          null,\r
10294                  *          null,\r
10295                  *          {\r
10296                  *            "sContentPadding": "mmm"\r
10297                  *          }\r
10298                  *        ]\r
10299                  *      } );\r
10300                  *    } );\r
10301                  */\r
10302                 "sContentPadding": "",\r
10303         \r
10304         \r
10305                 /**\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
10309                  *  @type string\r
10310                  *  @default null\r
10311                  *  @dtopt Columns\r
10312                  * \r
10313                  *  @example\r
10314                  *    // Using aoColumnDefs\r
10315                  *    $(document).ready( function() {\r
10316                  *      $('#example').dataTable( {\r
10317                  *        "aoColumnDefs": [ \r
10318                  *          {\r
10319                  *            "mData": null,\r
10320                  *            "sDefaultContent": "Edit",\r
10321                  *            "aTargets": [ -1 ]\r
10322                  *          }\r
10323                  *        ]\r
10324                  *      } );\r
10325                  *    } );\r
10326                  *    \r
10327                  *  @example\r
10328                  *    // Using aoColumns\r
10329                  *    $(document).ready( function() {\r
10330                  *      $('#example').dataTable( {\r
10331                  *        "aoColumns": [ \r
10332                  *          null,\r
10333                  *          null,\r
10334                  *          null,\r
10335                  *          {\r
10336                  *            "mData": null,\r
10337                  *            "sDefaultContent": "Edit"\r
10338                  *          }\r
10339                  *        ]\r
10340                  *      } );\r
10341                  *    } );\r
10342                  */\r
10343                 "sDefaultContent": null,\r
10344         \r
10345         \r
10346                 /**\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
10353                  *  @type string\r
10354                  *  @default <i>Empty string</i>\r
10355                  *  @dtopt Columns\r
10356                  * \r
10357                  *  @example\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
10367                  *        ]\r
10368                  *      } );\r
10369                  *    } );\r
10370                  *    \r
10371                  *  @example\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
10381                  *        ]\r
10382                  *      } );\r
10383                  *    } );\r
10384                  */\r
10385                 "sName": "",\r
10386         \r
10387         \r
10388                 /**\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
10393                  *  @type string\r
10394                  *  @default std\r
10395                  *  @dtopt Columns\r
10396                  * \r
10397                  *  @example\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
10406                  *        ]\r
10407                  *      } );\r
10408                  *    } );\r
10409                  *    \r
10410                  *  @example\r
10411                  *    // Using aoColumns\r
10412                  *    $(document).ready( function() {\r
10413                  *      $('#example').dataTable( {\r
10414                  *        "aoColumns": [\r
10415                  *          null,\r
10416                  *          null,\r
10417                  *          { "sSortDataType": "dom-text" },\r
10418                  *          { "sSortDataType": "dom-text", "sType": "numeric" },\r
10419                  *          { "sSortDataType": "dom-select" },\r
10420                  *          { "sSortDataType": "dom-checkbox" }\r
10421                  *        ]\r
10422                  *      } );\r
10423                  *    } );\r
10424                  */\r
10425                 "sSortDataType": "std",\r
10426         \r
10427         \r
10428                 /**\r
10429                  * The title of this column.\r
10430                  *  @type string\r
10431                  *  @default null <i>Derived from the 'TH' value for this column in the \r
10432                  *    original HTML table.</i>\r
10433                  *  @dtopt Columns\r
10434                  * \r
10435                  *  @example\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
10441                  *        ]\r
10442                  *      } );\r
10443                  *    } );\r
10444                  *    \r
10445                  *  @example\r
10446                  *    // Using aoColumns\r
10447                  *    $(document).ready( function() {\r
10448                  *      $('#example').dataTable( {\r
10449                  *        "aoColumns": [ \r
10450                  *          { "sTitle": "My column title" },\r
10451                  *          null,\r
10452                  *          null,\r
10453                  *          null,\r
10454                  *          null\r
10455                  *        ]\r
10456                  *      } );\r
10457                  *    } );\r
10458                  */\r
10459                 "sTitle": null,\r
10460         \r
10461         \r
10462                 /**\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
10469                  * plug-ins.\r
10470                  *  @type string\r
10471                  *  @default null <i>Auto-detected from raw data</i>\r
10472                  *  @dtopt Columns\r
10473                  * \r
10474                  *  @example\r
10475                  *    // Using aoColumnDefs\r
10476                  *    $(document).ready( function() {\r
10477                  *      $('#example').dataTable( {\r
10478                  *        "aoColumnDefs": [ \r
10479                  *          { "sType": "html", "aTargets": [ 0 ] }\r
10480                  *        ]\r
10481                  *      } );\r
10482                  *    } );\r
10483                  *    \r
10484                  *  @example\r
10485                  *    // Using aoColumns\r
10486                  *    $(document).ready( function() {\r
10487                  *      $('#example').dataTable( {\r
10488                  *        "aoColumns": [ \r
10489                  *          { "sType": "html" },\r
10490                  *          null,\r
10491                  *          null,\r
10492                  *          null,\r
10493                  *          null\r
10494                  *        ]\r
10495                  *      } );\r
10496                  *    } );\r
10497                  */\r
10498                 "sType": null,\r
10499         \r
10500         \r
10501                 /**\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
10506                  *  @type string\r
10507                  *  @default null <i>Automatic</i>\r
10508                  *  @dtopt Columns\r
10509                  * \r
10510                  *  @example\r
10511                  *    // Using aoColumnDefs\r
10512                  *    $(document).ready( function() {\r
10513                  *      $('#example').dataTable( {\r
10514                  *        "aoColumnDefs": [ \r
10515                  *          { "sWidth": "20%", "aTargets": [ 0 ] }\r
10516                  *        ]\r
10517                  *      } );\r
10518                  *    } );\r
10519                  *    \r
10520                  *  @example\r
10521                  *    // Using aoColumns\r
10522                  *    $(document).ready( function() {\r
10523                  *      $('#example').dataTable( {\r
10524                  *        "aoColumns": [ \r
10525                  *          { "sWidth": "20%" },\r
10526                  *          null,\r
10527                  *          null,\r
10528                  *          null,\r
10529                  *          null\r
10530                  *        ]\r
10531                  *      } );\r
10532                  *    } );\r
10533                  */\r
10534                 "sWidth": null\r
10535         };\r
10536         \r
10537         \r
10538         \r
10539         /**\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
10546          * instance.\r
10547          * \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
10552          *  @namespace\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
10560          */\r
10561         DataTable.models.oSettings = {\r
10562                 /**\r
10563                  * Primary features of DataTables and their enablement state.\r
10564                  *  @namespace\r
10565                  */\r
10566                 "oFeatures": {\r
10567                         \r
10568                         /**\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
10573                          *  @type boolean\r
10574                          */\r
10575                         "bAutoWidth": null,\r
10576         \r
10577                         /**\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
10584                          *  @type boolean\r
10585                          */\r
10586                         "bDeferRender": null,\r
10587                         \r
10588                         /**\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
10594                          *  @type boolean\r
10595                          */\r
10596                         "bFilter": null,\r
10597                         \r
10598                         /**\r
10599                          * Table information element (the 'Showing x of y records' div) enable\r
10600                          * flag.\r
10601                          * Note that this parameter will be set by the initialisation routine. To\r
10602                          * set a default use {@link DataTable.defaults}.\r
10603                          *  @type boolean\r
10604                          */\r
10605                         "bInfo": null,\r
10606                         \r
10607                         /**\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
10612                          *  @type boolean\r
10613                          */\r
10614                         "bLengthChange": null,\r
10615         \r
10616                         /**\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
10621                          *  @type boolean\r
10622                          */\r
10623                         "bPaginate": null,\r
10624                         \r
10625                         /**\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
10630                          *  @type boolean\r
10631                          */\r
10632                         "bProcessing": null,\r
10633                         \r
10634                         /**\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
10640                          *  @type boolean\r
10641                          */\r
10642                         "bServerSide": null,\r
10643                         \r
10644                         /**\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
10648                          *  @type boolean\r
10649                          */\r
10650                         "bSort": null,\r
10651                         \r
10652                         /**\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
10658                          *  @type boolean\r
10659                          */\r
10660                         "bSortClasses": null,\r
10661                         \r
10662                         /**\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
10666                          *  @type boolean\r
10667                          */\r
10668                         "bStateSave": null\r
10669                 },\r
10670                 \r
10671         \r
10672                 /**\r
10673                  * Scrolling settings for a table.\r
10674                  *  @namespace\r
10675                  */\r
10676                 "oScroll": {\r
10677                         /**\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
10680                          * this.\r
10681                          * Note that this parameter will be set by the initialisation routine. To\r
10682                          * set a default use {@link DataTable.defaults}.\r
10683                          *  @type boolean\r
10684                          */\r
10685                         "bAutoCss": null,\r
10686                         \r
10687                         /**\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
10692                          *  @type boolean\r
10693                          */\r
10694                         "bCollapse": null,\r
10695                         \r
10696                         /**\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
10701                          *  @type boolean\r
10702                          */\r
10703                         "bInfinite": null,\r
10704                         \r
10705                         /**\r
10706                          * Width of the scrollbar for the web-browser's platform. Calculated\r
10707                          * during table initialisation.\r
10708                          *  @type int\r
10709                          *  @default 0\r
10710                          */\r
10711                         "iBarWidth": 0,\r
10712                         \r
10713                         /**\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
10719                          *  @type int\r
10720                          */\r
10721                         "iLoadGap": null,\r
10722                         \r
10723                         /**\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
10728                          *  @type string\r
10729                          */\r
10730                         "sX": null,\r
10731                         \r
10732                         /**\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
10737                          *  @type string\r
10738                          *  @deprecated\r
10739                          */\r
10740                         "sXInner": null,\r
10741                         \r
10742                         /**\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
10747                          *  @type string\r
10748                          */\r
10749                         "sY": null\r
10750                 },\r
10751                 \r
10752                 /**\r
10753                  * Language information for the table.\r
10754                  *  @namespace\r
10755                  *  @extends DataTable.defaults.oLanguage\r
10756                  */\r
10757                 "oLanguage": {\r
10758                         /**\r
10759                          * Information callback function. See \r
10760                          * {@link DataTable.defaults.fnInfoCallback}\r
10761                          *  @type function\r
10762                          *  @default null\r
10763                          */\r
10764                         "fnInfoCallback": null\r
10765                 },\r
10766                 \r
10767                 /**\r
10768                  * Browser support parameters\r
10769                  *  @namespace\r
10770                  */\r
10771                 "oBrowser": {\r
10772                         /**\r
10773                          * Indicate if the browser incorrectly calculates width:100% inside a\r
10774                          * scrolling element (IE6/7)\r
10775                          *  @type boolean\r
10776                          *  @default false\r
10777                          */\r
10778                         "bScrollOversize": false\r
10779                 },\r
10780                 \r
10781                 /**\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
10784                  *   <ul>\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
10791                  *   </ul>\r
10792                  *  @type array\r
10793                  *  @default []\r
10794                  */\r
10795                 "aanFeatures": [],\r
10796                 \r
10797                 /**\r
10798                  * Store data information - see {@link DataTable.models.oRow} for detailed\r
10799                  * information.\r
10800                  *  @type array\r
10801                  *  @default []\r
10802                  */\r
10803                 "aoData": [],\r
10804                 \r
10805                 /**\r
10806                  * Array of indexes which are in the current display (after filtering etc)\r
10807                  *  @type array\r
10808                  *  @default []\r
10809                  */\r
10810                 "aiDisplay": [],\r
10811                 \r
10812                 /**\r
10813                  * Array of indexes for display - no filtering\r
10814                  *  @type array\r
10815                  *  @default []\r
10816                  */\r
10817                 "aiDisplayMaster": [],\r
10818                 \r
10819                 /**\r
10820                  * Store information about each column that is in use\r
10821                  *  @type array\r
10822                  *  @default []\r
10823                  */\r
10824                 "aoColumns": [],\r
10825                 \r
10826                 /**\r
10827                  * Store information about the table's header\r
10828                  *  @type array\r
10829                  *  @default []\r
10830                  */\r
10831                 "aoHeader": [],\r
10832                 \r
10833                 /**\r
10834                  * Store information about the table's footer\r
10835                  *  @type array\r
10836                  *  @default []\r
10837                  */\r
10838                 "aoFooter": [],\r
10839                 \r
10840                 /**\r
10841                  * Search data array for regular expression searching\r
10842                  *  @type array\r
10843                  *  @default []\r
10844                  */\r
10845                 "asDataSearch": [],\r
10846                 \r
10847                 /**\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
10852                  *  @namespace\r
10853                  *  @extends DataTable.models.oSearch\r
10854                  */\r
10855                 "oPreviousSearch": {},\r
10856                 \r
10857                 /**\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
10861                  *  @type array\r
10862                  *  @default []\r
10863                  */\r
10864                 "aoPreSearchCols": [],\r
10865                 \r
10866                 /**\r
10867                  * Sorting that is applied to the table. Note that the inner arrays are\r
10868                  * used in the following manner:\r
10869                  * <ul>\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
10873                  * </ul>\r
10874                  * Note that this parameter will be set by the initialisation routine. To\r
10875                  * set a default use {@link DataTable.defaults}.\r
10876                  *  @type array\r
10877                  *  @todo These inner arrays should really be objects\r
10878                  */\r
10879                 "aaSorting": null,\r
10880                 \r
10881                 /**\r
10882                  * Sorting that is always applied to the table (i.e. prefixed in front of\r
10883                  * aaSorting).\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
10887                  *  @default null\r
10888                  */\r
10889                 "aaSortingFixed": null,\r
10890                 \r
10891                 /**\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
10895                  *  @type array\r
10896                  *  @default []\r
10897                  */\r
10898                 "asStripeClasses": null,\r
10899                 \r
10900                 /**\r
10901                  * If restoring a table - we should restore its striping classes as well\r
10902                  *  @type array\r
10903                  *  @default []\r
10904                  */\r
10905                 "asDestroyStripes": [],\r
10906                 \r
10907                 /**\r
10908                  * If restoring a table - we should restore its width \r
10909                  *  @type int\r
10910                  *  @default 0\r
10911                  */\r
10912                 "sDestroyWidth": 0,\r
10913                 \r
10914                 /**\r
10915                  * Callback functions array for every time a row is inserted (i.e. on a draw).\r
10916                  *  @type array\r
10917                  *  @default []\r
10918                  */\r
10919                 "aoRowCallback": [],\r
10920                 \r
10921                 /**\r
10922                  * Callback functions for the header on each draw.\r
10923                  *  @type array\r
10924                  *  @default []\r
10925                  */\r
10926                 "aoHeaderCallback": [],\r
10927                 \r
10928                 /**\r
10929                  * Callback function for the footer on each draw.\r
10930                  *  @type array\r
10931                  *  @default []\r
10932                  */\r
10933                 "aoFooterCallback": [],\r
10934                 \r
10935                 /**\r
10936                  * Array of callback functions for draw callback functions\r
10937                  *  @type array\r
10938                  *  @default []\r
10939                  */\r
10940                 "aoDrawCallback": [],\r
10941                 \r
10942                 /**\r
10943                  * Array of callback functions for row created function\r
10944                  *  @type array\r
10945                  *  @default []\r
10946                  */\r
10947                 "aoRowCreatedCallback": [],\r
10948                 \r
10949                 /**\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
10952                  *  @type array\r
10953                  *  @default []\r
10954                  */\r
10955                 "aoPreDrawCallback": [],\r
10956                 \r
10957                 /**\r
10958                  * Callback functions for when the table has been initialised.\r
10959                  *  @type array\r
10960                  *  @default []\r
10961                  */\r
10962                 "aoInitComplete": [],\r
10963         \r
10964                 \r
10965                 /**\r
10966                  * Callbacks for modifying the settings to be stored for state saving, prior to\r
10967                  * saving state.\r
10968                  *  @type array\r
10969                  *  @default []\r
10970                  */\r
10971                 "aoStateSaveParams": [],\r
10972                 \r
10973                 /**\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
10976                  *  @type array\r
10977                  *  @default []\r
10978                  */\r
10979                 "aoStateLoadParams": [],\r
10980                 \r
10981                 /**\r
10982                  * Callbacks for operating on the settings object once the saved state has been\r
10983                  * loaded\r
10984                  *  @type array\r
10985                  *  @default []\r
10986                  */\r
10987                 "aoStateLoaded": [],\r
10988                 \r
10989                 /**\r
10990                  * Cache the table ID for quick access\r
10991                  *  @type string\r
10992                  *  @default <i>Empty string</i>\r
10993                  */\r
10994                 "sTableId": "",\r
10995                 \r
10996                 /**\r
10997                  * The TABLE node for the main table\r
10998                  *  @type node\r
10999                  *  @default null\r
11000                  */\r
11001                 "nTable": null,\r
11002                 \r
11003                 /**\r
11004                  * Permanent ref to the thead element\r
11005                  *  @type node\r
11006                  *  @default null\r
11007                  */\r
11008                 "nTHead": null,\r
11009                 \r
11010                 /**\r
11011                  * Permanent ref to the tfoot element - if it exists\r
11012                  *  @type node\r
11013                  *  @default null\r
11014                  */\r
11015                 "nTFoot": null,\r
11016                 \r
11017                 /**\r
11018                  * Permanent ref to the tbody element\r
11019                  *  @type node\r
11020                  *  @default null\r
11021                  */\r
11022                 "nTBody": null,\r
11023                 \r
11024                 /**\r
11025                  * Cache the wrapper node (contains all DataTables controlled elements)\r
11026                  *  @type node\r
11027                  *  @default null\r
11028                  */\r
11029                 "nTableWrapper": null,\r
11030                 \r
11031                 /**\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
11036                  *  @type boolean\r
11037                  *  @default false\r
11038                  */\r
11039                 "bDeferLoading": false,\r
11040                 \r
11041                 /**\r
11042                  * Indicate if all required information has been read in\r
11043                  *  @type boolean\r
11044                  *  @default false\r
11045                  */\r
11046                 "bInitialised": false,\r
11047                 \r
11048                 /**\r
11049                  * Information about open rows. Each object in the array has the parameters\r
11050                  * 'nTr' and 'nParent'\r
11051                  *  @type array\r
11052                  *  @default []\r
11053                  */\r
11054                 "aoOpenRows": [],\r
11055                 \r
11056                 /**\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
11061                  *  @type string\r
11062                  *  @default null\r
11063                  */\r
11064                 "sDom": null,\r
11065                 \r
11066                 /**\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
11070                  *  @type string \r
11071                  *  @default two_button\r
11072                  */\r
11073                 "sPaginationType": "two_button",\r
11074                 \r
11075                 /**\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
11079                  *  @type int\r
11080                  *  @default 0\r
11081                  */\r
11082                 "iCookieDuration": 0,\r
11083                 \r
11084                 /**\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
11088                  *  @type string\r
11089                  *  @default <i>Empty string</i>\r
11090                  */\r
11091                 "sCookiePrefix": "",\r
11092                 \r
11093                 /**\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
11097                  *  @type function\r
11098                  *  @default null\r
11099                  */\r
11100                 "fnCookieCallback": null,\r
11101                 \r
11102                 /**\r
11103                  * Array of callback functions for state saving. Each array element is an \r
11104                  * object with the following parameters:\r
11105                  *   <ul>\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
11111                  *   </ul>\r
11112                  *  @type array\r
11113                  *  @default []\r
11114                  */\r
11115                 "aoStateSave": [],\r
11116                 \r
11117                 /**\r
11118                  * Array of callback functions for state loading. Each array element is an \r
11119                  * object with the following parameters:\r
11120                  *   <ul>\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
11124                  *   </ul>\r
11125                  *  @type array\r
11126                  *  @default []\r
11127                  */\r
11128                 "aoStateLoad": [],\r
11129                 \r
11130                 /**\r
11131                  * State that was loaded from the cookie. Useful for back reference\r
11132                  *  @type object\r
11133                  *  @default null\r
11134                  */\r
11135                 "oLoadedState": null,\r
11136                 \r
11137                 /**\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
11141                  *  @type string\r
11142                  *  @default null\r
11143                  */\r
11144                 "sAjaxSource": null,\r
11145                 \r
11146                 /**\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
11152                  *  @type string\r
11153                  */\r
11154                 "sAjaxDataProp": null,\r
11155                 \r
11156                 /**\r
11157                  * Note if draw should be blocked while getting data\r
11158                  *  @type boolean\r
11159                  *  @default true\r
11160                  */\r
11161                 "bAjaxDataGet": true,\r
11162                 \r
11163                 /**\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
11166                  * callbacks\r
11167                  *  @type object\r
11168                  *  @default null\r
11169                  */\r
11170                 "jqXHR": null,\r
11171                 \r
11172                 /**\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
11176                  *  @type function\r
11177                  */\r
11178                 "fnServerData": null,\r
11179                 \r
11180                 /**\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
11183                  *  @type array\r
11184                  *  @default []\r
11185                  */\r
11186                 "aoServerParams": [],\r
11187                 \r
11188                 /**\r
11189                  * Send the XHR HTTP method - GET or POST (could be PUT or DELETE if \r
11190                  * required).\r
11191                  * Note that this parameter will be set by the initialisation routine. To\r
11192                  * set a default use {@link DataTable.defaults}.\r
11193                  *  @type string\r
11194                  */\r
11195                 "sServerMethod": null,\r
11196                 \r
11197                 /**\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
11201                  *  @type function\r
11202                  */\r
11203                 "fnFormatNumber": null,\r
11204                 \r
11205                 /**\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
11209                  *  @type array\r
11210                  *  @default []\r
11211                  */\r
11212                 "aLengthMenu": null,\r
11213                 \r
11214                 /**\r
11215                  * Counter for the draws that the table does. Also used as a tracker for\r
11216                  * server-side processing\r
11217                  *  @type int\r
11218                  *  @default 0\r
11219                  */\r
11220                 "iDraw": 0,\r
11221                 \r
11222                 /**\r
11223                  * Indicate if a redraw is being done - useful for Ajax\r
11224                  *  @type boolean\r
11225                  *  @default false\r
11226                  */\r
11227                 "bDrawing": false,\r
11228                 \r
11229                 /**\r
11230                  * Draw index (iDraw) of the last error when parsing the returned data\r
11231                  *  @type int\r
11232                  *  @default -1\r
11233                  */\r
11234                 "iDrawError": -1,\r
11235                 \r
11236                 /**\r
11237                  * Paging display length\r
11238                  *  @type int\r
11239                  *  @default 10\r
11240                  */\r
11241                 "_iDisplayLength": 10,\r
11242         \r
11243                 /**\r
11244                  * Paging start point - aiDisplay index\r
11245                  *  @type int\r
11246                  *  @default 0\r
11247                  */\r
11248                 "_iDisplayStart": 0,\r
11249         \r
11250                 /**\r
11251                  * Paging end point - aiDisplay index. Use fnDisplayEnd rather than\r
11252                  * this property to get the end point\r
11253                  *  @type int\r
11254                  *  @default 10\r
11255                  *  @private\r
11256                  */\r
11257                 "_iDisplayEnd": 10,\r
11258                 \r
11259                 /**\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
11264                  *  @type int\r
11265                  *  @default 0\r
11266                  *  @private\r
11267                  */\r
11268                 "_iRecordsTotal": 0,\r
11269         \r
11270                 /**\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
11275                  *  @type boolean\r
11276                  *  @default 0\r
11277                  *  @private\r
11278                  */\r
11279                 "_iRecordsDisplay": 0,\r
11280                 \r
11281                 /**\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
11285                  *  @type boolean\r
11286                  */\r
11287                 "bJUI": null,\r
11288                 \r
11289                 /**\r
11290                  * The classes to use for the table\r
11291                  *  @type object\r
11292                  *  @default {}\r
11293                  */\r
11294                 "oClasses": {},\r
11295                 \r
11296                 /**\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
11299                  * events.\r
11300                  *  @type boolean\r
11301                  *  @default false\r
11302                  *  @deprecated\r
11303                  */\r
11304                 "bFiltered": false,\r
11305                 \r
11306                 /**\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
11309                  * events.\r
11310                  *  @type boolean\r
11311                  *  @default false\r
11312                  *  @deprecated\r
11313                  */\r
11314                 "bSorted": false,\r
11315                 \r
11316                 /**\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
11322                  *  @type boolean\r
11323                  */\r
11324                 "bSortCellsTop": null,\r
11325                 \r
11326                 /**\r
11327                  * Initialisation object that is used for the table\r
11328                  *  @type object\r
11329                  *  @default null\r
11330                  */\r
11331                 "oInit": null,\r
11332                 \r
11333                 /**\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
11336                  *  @type array\r
11337                  *  @default []\r
11338                  */\r
11339                 "aoDestroyCallback": [],\r
11340         \r
11341                 \r
11342                 /**\r
11343                  * Get the number of records in the current record set, before filtering\r
11344                  *  @type function\r
11345                  */\r
11346                 "fnRecordsTotal": function ()\r
11347                 {\r
11348                         if ( this.oFeatures.bServerSide ) {\r
11349                                 return parseInt(this._iRecordsTotal, 10);\r
11350                         } else {\r
11351                                 return this.aiDisplayMaster.length;\r
11352                         }\r
11353                 },\r
11354                 \r
11355                 /**\r
11356                  * Get the number of records in the current record set, after filtering\r
11357                  *  @type function\r
11358                  */\r
11359                 "fnRecordsDisplay": function ()\r
11360                 {\r
11361                         if ( this.oFeatures.bServerSide ) {\r
11362                                 return parseInt(this._iRecordsDisplay, 10);\r
11363                         } else {\r
11364                                 return this.aiDisplay.length;\r
11365                         }\r
11366                 },\r
11367                 \r
11368                 /**\r
11369                  * Set the display end point - aiDisplay index\r
11370                  *  @type function\r
11371                  *  @todo Should do away with _iDisplayEnd and calculate it on-the-fly here\r
11372                  */\r
11373                 "fnDisplayEnd": function ()\r
11374                 {\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
11378                                 } else {\r
11379                                         return Math.min( this._iDisplayStart+this._iDisplayLength, \r
11380                                                 this._iRecordsDisplay );\r
11381                                 }\r
11382                         } else {\r
11383                                 return this._iDisplayEnd;\r
11384                         }\r
11385                 },\r
11386                 \r
11387                 /**\r
11388                  * The DataTables object for this table\r
11389                  *  @type object\r
11390                  *  @default null\r
11391                  */\r
11392                 "oInstance": null,\r
11393                 \r
11394                 /**\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
11398                  *  @type string\r
11399                  *  @default null\r
11400                  */\r
11401                 "sInstance": null,\r
11402         \r
11403                 /**\r
11404                  * tabindex attribute value that is added to DataTables control elements, allowing\r
11405                  * keyboard navigation of the table and its controls.\r
11406                  */\r
11407                 "iTabIndex": 0,\r
11408         \r
11409                 /**\r
11410                  * DIV container for the footer scrolling table if scrolling\r
11411                  */\r
11412                 "nScrollHead": null,\r
11413         \r
11414                 /**\r
11415                  * DIV container for the footer scrolling table if scrolling\r
11416                  */\r
11417                 "nScrollFoot": null\r
11418         };\r
11419 \r
11420         /**\r
11421          * Extension object for DataTables that is used to provide all extension options.\r
11422          * \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
11426          *  @namespace\r
11427          *  @extends DataTable.models.ext\r
11428          */\r
11429         DataTable.ext = $.extend( true, {}, DataTable.models.ext );\r
11430         \r
11431         $.extend( DataTable.ext.oStdClasses, {\r
11432                 "sTable": "dataTable",\r
11433         \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
11441                 \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
11450                 \r
11451                 /* Striping classes */\r
11452                 "sStripeOdd": "odd",\r
11453                 "sStripeEven": "even",\r
11454                 \r
11455                 /* Empty row */\r
11456                 "sRowEmpty": "dataTables_empty",\r
11457                 \r
11458                 /* Features */\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
11465                 \r
11466                 /* Sorting */\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
11476                 "sSortJUI": "",\r
11477                 "sSortJUIAscAllowed": "",\r
11478                 "sSortJUIDescAllowed": "",\r
11479                 "sSortJUIWrapper": "",\r
11480                 "sSortIcon": "",\r
11481                 \r
11482                 /* Scrolling */\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
11489                 \r
11490                 /* Misc */\r
11491                 "sFooterTH": "",\r
11492                 "sJUIHeader": "",\r
11493                 "sJUIFooter": ""\r
11494         } );\r
11495         \r
11496         \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
11505                 \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
11512                 \r
11513                 /* Features */\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
11516                 \r
11517                 /* Sorting */\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
11531                 \r
11532                 /* Scrolling */\r
11533                 "sScrollHead": "dataTables_scrollHead ui-state-default",\r
11534                 "sScrollFoot": "dataTables_scrollFoot ui-state-default",\r
11535                 \r
11536                 /* Misc */\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
11540         } );\r
11541         \r
11542         /*\r
11543          * Variable: oPagination\r
11544          * Purpose:  \r
11545          * Scope:    jQuery.fn.dataTableExt\r
11546          */\r
11547         $.extend( DataTable.ext.oPagination, {\r
11548                 /*\r
11549                  * Variable: two_button\r
11550                  * Purpose:  Standard two button (forward/back) pagination\r
11551                  * Scope:    jQuery.fn.dataTableExt.oPagination\r
11552                  */\r
11553                 "two_button": {\r
11554                         /*\r
11555                          * Function: oPagination.two_button.fnInit\r
11556                          * Purpose:  Initialise dom elements required for pagination with forward/back buttons only\r
11557                          * Returns:  -\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
11561                          */\r
11562                         "fnInit": function ( oSettings, nPaging, fnCallbackDraw )\r
11563                         {\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
11568                                         {\r
11569                                                 fnCallbackDraw( oSettings );\r
11570                                         }\r
11571                                 };\r
11572         \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
11576                                         :\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
11580                                 \r
11581                                 var els = $('a', nPaging);\r
11582                                 var nPrevious = els[0],\r
11583                                         nNext = els[1];\r
11584                                 \r
11585                                 oSettings.oApi._fnBindAction( nPrevious, {action: "previous"}, fnClickHandler );\r
11586                                 oSettings.oApi._fnBindAction( nNext,     {action: "next"},     fnClickHandler );\r
11587                                 \r
11588                                 /* ID the first elements only */\r
11589                                 if ( !oSettings.aanFeatures.p )\r
11590                                 {\r
11591                                         nPaging.id = oSettings.sTableId+'_paginate';\r
11592                                         nPrevious.id = oSettings.sTableId+'_previous';\r
11593                                         nNext.id = oSettings.sTableId+'_next';\r
11594         \r
11595                                         nPrevious.setAttribute('aria-controls', oSettings.sTableId);\r
11596                                         nNext.setAttribute('aria-controls', oSettings.sTableId);\r
11597                                 }\r
11598                         },\r
11599                         \r
11600                         /*\r
11601                          * Function: oPagination.two_button.fnUpdate\r
11602                          * Purpose:  Update the two button pagination at the end of the draw\r
11603                          * Returns:  -\r
11604                          * Inputs:   object:oSettings - dataTables settings object\r
11605                          *           function:fnCallbackDraw - draw function to call on page change\r
11606                          */\r
11607                         "fnUpdate": function ( oSettings, fnCallbackDraw )\r
11608                         {\r
11609                                 if ( !oSettings.aanFeatures.p )\r
11610                                 {\r
11611                                         return;\r
11612                                 }\r
11613                                 \r
11614                                 var oClasses = oSettings.oClasses;\r
11615                                 var an = oSettings.aanFeatures.p;\r
11616                                 var nNode;\r
11617         \r
11618                                 /* Loop over each instance of the pager */\r
11619                                 for ( var i=0, iLen=an.length ; i<iLen ; i++ )\r
11620                                 {\r
11621                                         nNode = an[i].firstChild;\r
11622                                         if ( nNode )\r
11623                                         {\r
11624                                                 /* Previous page */\r
11625                                                 nNode.className = ( oSettings._iDisplayStart === 0 ) ?\r
11626                                                     oClasses.sPagePrevDisabled : oClasses.sPagePrevEnabled;\r
11627                                                     \r
11628                                                 /* Next page */\r
11629                                                 nNode = nNode.nextSibling;\r
11630                                                 nNode.className = ( oSettings.fnDisplayEnd() == oSettings.fnRecordsDisplay() ) ?\r
11631                                                     oClasses.sPageNextDisabled : oClasses.sPageNextEnabled;\r
11632                                         }\r
11633                                 }\r
11634                         }\r
11635                 },\r
11636                 \r
11637                 \r
11638                 /*\r
11639                  * Variable: iFullNumbersShowPages\r
11640                  * Purpose:  Change the number of pages which can be seen\r
11641                  * Scope:    jQuery.fn.dataTableExt.oPagination\r
11642                  */\r
11643                 "iFullNumbersShowPages": 5,\r
11644                 \r
11645                 /*\r
11646                  * Variable: full_numbers\r
11647                  * Purpose:  Full numbers pagination\r
11648                  * Scope:    jQuery.fn.dataTableExt.oPagination\r
11649                  */\r
11650                 "full_numbers": {\r
11651                         /*\r
11652                          * Function: oPagination.full_numbers.fnInit\r
11653                          * Purpose:  Initialise dom elements required for pagination with a list of the pages\r
11654                          * Returns:  -\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
11658                          */\r
11659                         "fnInit": function ( oSettings, nPaging, fnCallbackDraw )\r
11660                         {\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
11665                                         {\r
11666                                                 fnCallbackDraw( oSettings );\r
11667                                         }\r
11668                                 };\r
11669         \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
11673                                         '<span></span>'+\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
11676                                 );\r
11677                                 var els = $('a', nPaging);\r
11678                                 var nFirst = els[0],\r
11679                                         nPrev = els[1],\r
11680                                         nNext = els[2],\r
11681                                         nLast = els[3];\r
11682                                 \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
11687                                 \r
11688                                 /* ID the first elements only */\r
11689                                 if ( !oSettings.aanFeatures.p )\r
11690                                 {\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
11696                                 }\r
11697                         },\r
11698                         \r
11699                         /*\r
11700                          * Function: oPagination.full_numbers.fnUpdate\r
11701                          * Purpose:  Update the list of page buttons shows\r
11702                          * Returns:  -\r
11703                          * Inputs:   object:oSettings - dataTables settings object\r
11704                          *           function:fnCallbackDraw - draw function to call on page change\r
11705                          */\r
11706                         "fnUpdate": function ( oSettings, fnCallbackDraw )\r
11707                         {\r
11708                                 if ( !oSettings.aanFeatures.p )\r
11709                                 {\r
11710                                         return;\r
11711                                 }\r
11712                                 \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
11717                                 var sList = "";\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
11728                                         } );\r
11729                                 };\r
11730                                 \r
11731                                 /* Pages calculation */\r
11732                                 if ( oSettings._iDisplayLength === -1 )\r
11733                                 {\r
11734                                         iStartButton = 1;\r
11735                                         iEndButton = 1;\r
11736                                         iCurrentPage = 1;\r
11737                                 }\r
11738                                 else if (iPages < iPageCount)\r
11739                                 {\r
11740                                         iStartButton = 1;\r
11741                                         iEndButton = iPages;\r
11742                                 }\r
11743                                 else if (iCurrentPage <= iPageCountHalf)\r
11744                                 {\r
11745                                         iStartButton = 1;\r
11746                                         iEndButton = iPageCount;\r
11747                                 }\r
11748                                 else if (iCurrentPage >= (iPages - iPageCountHalf))\r
11749                                 {\r
11750                                         iStartButton = iPages - iPageCount + 1;\r
11751                                         iEndButton = iPages;\r
11752                                 }\r
11753                                 else\r
11754                                 {\r
11755                                         iStartButton = iCurrentPage - Math.ceil(iPageCount / 2) + 1;\r
11756                                         iEndButton = iStartButton + iPageCount - 1;\r
11757                                 }\r
11758         \r
11759                                 \r
11760                                 /* Build the dynamic list */\r
11761                                 for ( i=iStartButton ; i<=iEndButton ; i++ )\r
11762                                 {\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
11766                                 }\r
11767                                 \r
11768                                 /* Loop over each instance of the pager */\r
11769                                 for ( i=0, iLen=an.length ; i<iLen ; i++ )\r
11770                                 {\r
11771                                         nNode = an[i];\r
11772                                         if ( !nNode.hasChildNodes() )\r
11773                                         {\r
11774                                                 continue;\r
11775                                         }\r
11776                                         \r
11777                                         /* Build up the dynamic list first - html and listeners */\r
11778                                         $('span:eq(0)', nNode)\r
11779                                                 .html( sList )\r
11780                                                 .children('a').each( fnBind );\r
11781                                         \r
11782                                         /* Update the permanent button's classes */\r
11783                                         anButtons = nNode.getElementsByTagName('a');\r
11784                                         anStatic = [\r
11785                                                 anButtons[0], anButtons[1], \r
11786                                                 anButtons[anButtons.length-2], anButtons[anButtons.length-1]\r
11787                                         ];\r
11788         \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
11794                                         );\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
11799                                         );\r
11800                                 }\r
11801                         }\r
11802                 }\r
11803         } );\r
11804         \r
11805         $.extend( DataTable.ext.oSort, {\r
11806                 /*\r
11807                  * text sorting\r
11808                  */\r
11809                 "string-pre": function ( a )\r
11810                 {\r
11811                         if ( typeof a != 'string' ) {\r
11812                                 a = (a !== null && a.toString) ? a.toString() : '';\r
11813                         }\r
11814                         return a.toLowerCase();\r
11815                 },\r
11816         \r
11817                 "string-asc": function ( x, y )\r
11818                 {\r
11819                         return ((x < y) ? -1 : ((x > y) ? 1 : 0));\r
11820                 },\r
11821                 \r
11822                 "string-desc": function ( x, y )\r
11823                 {\r
11824                         return ((x < y) ? 1 : ((x > y) ? -1 : 0));\r
11825                 },\r
11826                 \r
11827                 \r
11828                 /*\r
11829                  * html sorting (ignore html tags)\r
11830                  */\r
11831                 "html-pre": function ( a )\r
11832                 {\r
11833                         return a.replace( /<.*?>/g, "" ).toLowerCase();\r
11834                 },\r
11835                 \r
11836                 "html-asc": function ( x, y )\r
11837                 {\r
11838                         return ((x < y) ? -1 : ((x > y) ? 1 : 0));\r
11839                 },\r
11840                 \r
11841                 "html-desc": function ( x, y )\r
11842                 {\r
11843                         return ((x < y) ? 1 : ((x > y) ? -1 : 0));\r
11844                 },\r
11845                 \r
11846                 \r
11847                 /*\r
11848                  * date sorting\r
11849                  */\r
11850                 "date-pre": function ( a )\r
11851                 {\r
11852                         var x = Date.parse( a );\r
11853                         \r
11854                         if ( isNaN(x) || x==="" )\r
11855                         {\r
11856                                 x = Date.parse( "01/01/1970 00:00:00" );\r
11857                         }\r
11858                         return x;\r
11859                 },\r
11860         \r
11861                 "date-asc": function ( x, y )\r
11862                 {\r
11863                         return x - y;\r
11864                 },\r
11865                 \r
11866                 "date-desc": function ( x, y )\r
11867                 {\r
11868                         return y - x;\r
11869                 },\r
11870                 \r
11871                 \r
11872                 /*\r
11873                  * numerical sorting\r
11874                  */\r
11875                 "numeric-pre": function ( a )\r
11876                 {\r
11877                         return (a=="-" || a==="") ? 0 : a*1;\r
11878                 },\r
11879         \r
11880                 "numeric-asc": function ( x, y )\r
11881                 {\r
11882                         return x - y;\r
11883                 },\r
11884                 \r
11885                 "numeric-desc": function ( x, y )\r
11886                 {\r
11887                         return y - x;\r
11888                 }\r
11889         } );\r
11890         \r
11891         \r
11892         $.extend( DataTable.ext.aTypes, [\r
11893                 /*\r
11894                  * Function: -\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
11898                  */\r
11899                 function ( sData )\r
11900                 {\r
11901                         /* Allow zero length strings as a number */\r
11902                         if ( typeof sData === 'number' )\r
11903                         {\r
11904                                 return 'numeric';\r
11905                         }\r
11906                         else if ( typeof sData !== 'string' )\r
11907                         {\r
11908                                 return null;\r
11909                         }\r
11910                         \r
11911                         var sValidFirstChars = "0123456789-";\r
11912                         var sValidChars = "0123456789.";\r
11913                         var Char;\r
11914                         var bDecimal = false;\r
11915                         \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
11919                         {\r
11920                                 return null;\r
11921                         }\r
11922                         \r
11923                         /* Check all the other characters are valid */\r
11924                         for ( var i=1 ; i<sData.length ; i++ ) \r
11925                         {\r
11926                                 Char = sData.charAt(i); \r
11927                                 if (sValidChars.indexOf(Char) == -1) \r
11928                                 {\r
11929                                         return null;\r
11930                                 }\r
11931                                 \r
11932                                 /* Only allowed one decimal place... */\r
11933                                 if ( Char == "." )\r
11934                                 {\r
11935                                         if ( bDecimal )\r
11936                                         {\r
11937                                                 return null;\r
11938                                         }\r
11939                                         bDecimal = true;\r
11940                                 }\r
11941                         }\r
11942                         \r
11943                         return 'numeric';\r
11944                 },\r
11945                 \r
11946                 /*\r
11947                  * Function: -\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
11951                  */\r
11952                 function ( sData )\r
11953                 {\r
11954                         var iParse = Date.parse(sData);\r
11955                         if ( (iParse !== null && !isNaN(iParse)) || (typeof sData === 'string' && sData.length === 0) )\r
11956                         {\r
11957                                 return 'date';\r
11958                         }\r
11959                         return null;\r
11960                 },\r
11961                 \r
11962                 /*\r
11963                  * Function: -\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
11967                  */\r
11968                 function ( sData )\r
11969                 {\r
11970                         if ( typeof sData === 'string' && sData.indexOf('<') != -1 && sData.indexOf('>') != -1 )\r
11971                         {\r
11972                                 return 'html';\r
11973                         }\r
11974                         return null;\r
11975                 }\r
11976         ] );\r
11977         \r
11978 \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
11984 \r
11985 \r
11986         // Information about events fired by DataTables - for documentation.\r
11987         /**\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
11992          *  @event\r
11993          *  @param {event} e jQuery event object\r
11994          *  @param {object} o DataTables settings object {@link DataTable.models.oSettings}\r
11995          */\r
11996 \r
11997         /**\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
12001          *  @event\r
12002          *  @param {event} e jQuery event object\r
12003          *  @param {object} o DataTables settings object {@link DataTable.models.oSettings}\r
12004          */\r
12005 \r
12006         /**\r
12007          * Page change event, fired when the paging of the table is altered.\r
12008          *  @name DataTable#page\r
12009          *  @event\r
12010          *  @param {event} e jQuery event object\r
12011          *  @param {object} o DataTables settings object {@link DataTable.models.oSettings}\r
12012          */\r
12013 \r
12014         /**\r
12015          * Sort event, fired when the sorting applied to the table is altered.\r
12016          *  @name DataTable#sort\r
12017          *  @event\r
12018          *  @param {event} e jQuery event object\r
12019          *  @param {object} o DataTables settings object {@link DataTable.models.oSettings}\r
12020          */\r
12021 \r
12022         /**\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
12026          *  @event\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
12031          */\r
12032 \r
12033         /**\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
12039          *  @event\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
12043          */\r
12044 \r
12045         /**\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
12050          *  @event\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
12054          */\r
12055 \r
12056         /**\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
12060          *  @event\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
12064          */\r
12065 \r
12066         /**\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
12071          *  @event\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
12075          */\r
12076 \r
12077         /**\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
12083          *  @event\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
12087          */\r
12088 \r
12089         /**\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
12094          *  @event\r
12095          *  @param {event} e jQuery event object\r
12096          *  @param {object} o DataTables settings object {@link DataTable.models.oSettings}\r
12097          */\r
12098 }));\r
12099 \r
12100 }(window, document));\r
12101 \r