Add files for DataTables library, to replace the table sorter
[mirror/userdir-ldap-cgi.git] / html / js / DataTables-1.10.20 / datatables.js
1 /*
2  * This combined file was created by the DataTables downloader builder:
3  *   https://datatables.net/download
4  *
5  * To rebuild or modify this file with the latest versions of the included
6  * software please visit:
7  *   https://datatables.net/download/#dt/dt-1.10.20/fc-3.3.0/fh-3.1.6
8  *
9  * Included libraries:
10  *   DataTables 1.10.20, FixedColumns 3.3.0, FixedHeader 3.1.6
11  */
12
13 /*! DataTables 1.10.20
14  * ©2008-2019 SpryMedia Ltd - datatables.net/license
15  */
16
17 /**
18  * @summary     DataTables
19  * @description Paginate, search and order HTML tables
20  * @version     1.10.20
21  * @file        jquery.dataTables.js
22  * @author      SpryMedia Ltd
23  * @contact     www.datatables.net
24  * @copyright   Copyright 2008-2019 SpryMedia Ltd.
25  *
26  * This source file is free software, available under the following license:
27  *   MIT license - http://datatables.net/license
28  *
29  * This source file is distributed in the hope that it will be useful, but
30  * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
31  * or FITNESS FOR A PARTICULAR PURPOSE. See the license files for details.
32  *
33  * For details please refer to: http://www.datatables.net
34  */
35
36 /*jslint evil: true, undef: true, browser: true */
37 /*globals $,require,jQuery,define,_selector_run,_selector_opts,_selector_first,_selector_row_indexes,_ext,_Api,_api_register,_api_registerPlural,_re_new_lines,_re_html,_re_formatted_numeric,_re_escape_regex,_empty,_intVal,_numToDecimal,_isNumber,_isHtml,_htmlNumeric,_pluck,_pluck_order,_range,_stripHtml,_unique,_fnBuildAjax,_fnAjaxUpdate,_fnAjaxParameters,_fnAjaxUpdateDraw,_fnAjaxDataSrc,_fnAddColumn,_fnColumnOptions,_fnAdjustColumnSizing,_fnVisibleToColumnIndex,_fnColumnIndexToVisible,_fnVisbleColumns,_fnGetColumns,_fnColumnTypes,_fnApplyColumnDefs,_fnHungarianMap,_fnCamelToHungarian,_fnLanguageCompat,_fnBrowserDetect,_fnAddData,_fnAddTr,_fnNodeToDataIndex,_fnNodeToColumnIndex,_fnGetCellData,_fnSetCellData,_fnSplitObjNotation,_fnGetObjectDataFn,_fnSetObjectDataFn,_fnGetDataMaster,_fnClearTable,_fnDeleteIndex,_fnInvalidate,_fnGetRowElements,_fnCreateTr,_fnBuildHead,_fnDrawHead,_fnDraw,_fnReDraw,_fnAddOptionsHtml,_fnDetectHeader,_fnGetUniqueThs,_fnFeatureHtmlFilter,_fnFilterComplete,_fnFilterCustom,_fnFilterColumn,_fnFilter,_fnFilterCreateSearch,_fnEscapeRegex,_fnFilterData,_fnFeatureHtmlInfo,_fnUpdateInfo,_fnInfoMacros,_fnInitialise,_fnInitComplete,_fnLengthChange,_fnFeatureHtmlLength,_fnFeatureHtmlPaginate,_fnPageChange,_fnFeatureHtmlProcessing,_fnProcessingDisplay,_fnFeatureHtmlTable,_fnScrollDraw,_fnApplyToChildren,_fnCalculateColumnWidths,_fnThrottle,_fnConvertToWidth,_fnGetWidestNode,_fnGetMaxLenString,_fnStringToCss,_fnSortFlatten,_fnSort,_fnSortAria,_fnSortListener,_fnSortAttachListener,_fnSortingClasses,_fnSortData,_fnSaveState,_fnLoadState,_fnSettingsFromNode,_fnLog,_fnMap,_fnBindAction,_fnCallbackReg,_fnCallbackFire,_fnLengthOverflow,_fnRenderer,_fnDataSource,_fnRowAttributes*/
38
39 (function( factory ) {
40         "use strict";
41
42         if ( typeof define === 'function' && define.amd ) {
43                 // AMD
44                 define( ['jquery'], function ( $ ) {
45                         return factory( $, window, document );
46                 } );
47         }
48         else if ( typeof exports === 'object' ) {
49                 // CommonJS
50                 module.exports = function (root, $) {
51                         if ( ! root ) {
52                                 // CommonJS environments without a window global must pass a
53                                 // root. This will give an error otherwise
54                                 root = window;
55                         }
56
57                         if ( ! $ ) {
58                                 $ = typeof window !== 'undefined' ? // jQuery's factory checks for a global window
59                                         require('jquery') :
60                                         require('jquery')( root );
61                         }
62
63                         return factory( $, root, root.document );
64                 };
65         }
66         else {
67                 // Browser
68                 factory( jQuery, window, document );
69         }
70 }
71 (function( $, window, document, undefined ) {
72         "use strict";
73
74         /**
75          * DataTables is a plug-in for the jQuery Javascript library. It is a highly
76          * flexible tool, based upon the foundations of progressive enhancement,
77          * which will add advanced interaction controls to any HTML table. For a
78          * full list of features please refer to
79          * [DataTables.net](href="http://datatables.net).
80          *
81          * Note that the `DataTable` object is not a global variable but is aliased
82          * to `jQuery.fn.DataTable` and `jQuery.fn.dataTable` through which it may
83          * be  accessed.
84          *
85          *  @class
86          *  @param {object} [init={}] Configuration object for DataTables. Options
87          *    are defined by {@link DataTable.defaults}
88          *  @requires jQuery 1.7+
89          *
90          *  @example
91          *    // Basic initialisation
92          *    $(document).ready( function {
93          *      $('#example').dataTable();
94          *    } );
95          *
96          *  @example
97          *    // Initialisation with configuration options - in this case, disable
98          *    // pagination and sorting.
99          *    $(document).ready( function {
100          *      $('#example').dataTable( {
101          *        "paginate": false,
102          *        "sort": false
103          *      } );
104          *    } );
105          */
106         var DataTable = function ( options )
107         {
108                 /**
109                  * Perform a jQuery selector action on the table's TR elements (from the tbody) and
110                  * return the resulting jQuery object.
111                  *  @param {string|node|jQuery} sSelector jQuery selector or node collection to act on
112                  *  @param {object} [oOpts] Optional parameters for modifying the rows to be included
113                  *  @param {string} [oOpts.filter=none] Select TR elements that meet the current filter
114                  *    criterion ("applied") or all TR elements (i.e. no filter).
115                  *  @param {string} [oOpts.order=current] Order of the TR elements in the processed array.
116                  *    Can be either 'current', whereby the current sorting of the table is used, or
117                  *    'original' whereby the original order the data was read into the table is used.
118                  *  @param {string} [oOpts.page=all] Limit the selection to the currently displayed page
119                  *    ("current") or not ("all"). If 'current' is given, then order is assumed to be
120                  *    'current' and filter is 'applied', regardless of what they might be given as.
121                  *  @returns {object} jQuery object, filtered by the given selector.
122                  *  @dtopt API
123                  *  @deprecated Since v1.10
124                  *
125                  *  @example
126                  *    $(document).ready(function() {
127                  *      var oTable = $('#example').dataTable();
128                  *
129                  *      // Highlight every second row
130                  *      oTable.$('tr:odd').css('backgroundColor', 'blue');
131                  *    } );
132                  *
133                  *  @example
134                  *    $(document).ready(function() {
135                  *      var oTable = $('#example').dataTable();
136                  *
137                  *      // Filter to rows with 'Webkit' in them, add a background colour and then
138                  *      // remove the filter, thus highlighting the 'Webkit' rows only.
139                  *      oTable.fnFilter('Webkit');
140                  *      oTable.$('tr', {"search": "applied"}).css('backgroundColor', 'blue');
141                  *      oTable.fnFilter('');
142                  *    } );
143                  */
144                 this.$ = function ( sSelector, oOpts )
145                 {
146                         return this.api(true).$( sSelector, oOpts );
147                 };
148                 
149                 
150                 /**
151                  * Almost identical to $ in operation, but in this case returns the data for the matched
152                  * rows - as such, the jQuery selector used should match TR row nodes or TD/TH cell nodes
153                  * rather than any descendants, so the data can be obtained for the row/cell. If matching
154                  * rows are found, the data returned is the original data array/object that was used to
155                  * create the row (or a generated array if from a DOM source).
156                  *
157                  * This method is often useful in-combination with $ where both functions are given the
158                  * same parameters and the array indexes will match identically.
159                  *  @param {string|node|jQuery} sSelector jQuery selector or node collection to act on
160                  *  @param {object} [oOpts] Optional parameters for modifying the rows to be included
161                  *  @param {string} [oOpts.filter=none] Select elements that meet the current filter
162                  *    criterion ("applied") or all elements (i.e. no filter).
163                  *  @param {string} [oOpts.order=current] Order of the data in the processed array.
164                  *    Can be either 'current', whereby the current sorting of the table is used, or
165                  *    'original' whereby the original order the data was read into the table is used.
166                  *  @param {string} [oOpts.page=all] Limit the selection to the currently displayed page
167                  *    ("current") or not ("all"). If 'current' is given, then order is assumed to be
168                  *    'current' and filter is 'applied', regardless of what they might be given as.
169                  *  @returns {array} Data for the matched elements. If any elements, as a result of the
170                  *    selector, were not TR, TD or TH elements in the DataTable, they will have a null
171                  *    entry in the array.
172                  *  @dtopt API
173                  *  @deprecated Since v1.10
174                  *
175                  *  @example
176                  *    $(document).ready(function() {
177                  *      var oTable = $('#example').dataTable();
178                  *
179                  *      // Get the data from the first row in the table
180                  *      var data = oTable._('tr:first');
181                  *
182                  *      // Do something useful with the data
183                  *      alert( "First cell is: "+data[0] );
184                  *    } );
185                  *
186                  *  @example
187                  *    $(document).ready(function() {
188                  *      var oTable = $('#example').dataTable();
189                  *
190                  *      // Filter to 'Webkit' and get all data for
191                  *      oTable.fnFilter('Webkit');
192                  *      var data = oTable._('tr', {"search": "applied"});
193                  *
194                  *      // Do something with the data
195                  *      alert( data.length+" rows matched the search" );
196                  *    } );
197                  */
198                 this._ = function ( sSelector, oOpts )
199                 {
200                         return this.api(true).rows( sSelector, oOpts ).data();
201                 };
202                 
203                 
204                 /**
205                  * Create a DataTables Api instance, with the currently selected tables for
206                  * the Api's context.
207                  * @param {boolean} [traditional=false] Set the API instance's context to be
208                  *   only the table referred to by the `DataTable.ext.iApiIndex` option, as was
209                  *   used in the API presented by DataTables 1.9- (i.e. the traditional mode),
210                  *   or if all tables captured in the jQuery object should be used.
211                  * @return {DataTables.Api}
212                  */
213                 this.api = function ( traditional )
214                 {
215                         return traditional ?
216                                 new _Api(
217                                         _fnSettingsFromNode( this[ _ext.iApiIndex ] )
218                                 ) :
219                                 new _Api( this );
220                 };
221                 
222                 
223                 /**
224                  * Add a single new row or multiple rows of data to the table. Please note
225                  * that this is suitable for client-side processing only - if you are using
226                  * server-side processing (i.e. "bServerSide": true), then to add data, you
227                  * must add it to the data source, i.e. the server-side, through an Ajax call.
228                  *  @param {array|object} data The data to be added to the table. This can be:
229                  *    <ul>
230                  *      <li>1D array of data - add a single row with the data provided</li>
231                  *      <li>2D array of arrays - add multiple rows in a single call</li>
232                  *      <li>object - data object when using <i>mData</i></li>
233                  *      <li>array of objects - multiple data objects when using <i>mData</i></li>
234                  *    </ul>
235                  *  @param {bool} [redraw=true] redraw the table or not
236                  *  @returns {array} An array of integers, representing the list of indexes in
237                  *    <i>aoData</i> ({@link DataTable.models.oSettings}) that have been added to
238                  *    the table.
239                  *  @dtopt API
240                  *  @deprecated Since v1.10
241                  *
242                  *  @example
243                  *    // Global var for counter
244                  *    var giCount = 2;
245                  *
246                  *    $(document).ready(function() {
247                  *      $('#example').dataTable();
248                  *    } );
249                  *
250                  *    function fnClickAddRow() {
251                  *      $('#example').dataTable().fnAddData( [
252                  *        giCount+".1",
253                  *        giCount+".2",
254                  *        giCount+".3",
255                  *        giCount+".4" ]
256                  *      );
257                  *
258                  *      giCount++;
259                  *    }
260                  */
261                 this.fnAddData = function( data, redraw )
262                 {
263                         var api = this.api( true );
264                 
265                         /* Check if we want to add multiple rows or not */
266                         var rows = $.isArray(data) && ( $.isArray(data[0]) || $.isPlainObject(data[0]) ) ?
267                                 api.rows.add( data ) :
268                                 api.row.add( data );
269                 
270                         if ( redraw === undefined || redraw ) {
271                                 api.draw();
272                         }
273                 
274                         return rows.flatten().toArray();
275                 };
276                 
277                 
278                 /**
279                  * This function will make DataTables recalculate the column sizes, based on the data
280                  * contained in the table and the sizes applied to the columns (in the DOM, CSS or
281                  * through the sWidth parameter). This can be useful when the width of the table's
282                  * parent element changes (for example a window resize).
283                  *  @param {boolean} [bRedraw=true] Redraw the table or not, you will typically want to
284                  *  @dtopt API
285                  *  @deprecated Since v1.10
286                  *
287                  *  @example
288                  *    $(document).ready(function() {
289                  *      var oTable = $('#example').dataTable( {
290                  *        "sScrollY": "200px",
291                  *        "bPaginate": false
292                  *      } );
293                  *
294                  *      $(window).on('resize', function () {
295                  *        oTable.fnAdjustColumnSizing();
296                  *      } );
297                  *    } );
298                  */
299                 this.fnAdjustColumnSizing = function ( bRedraw )
300                 {
301                         var api = this.api( true ).columns.adjust();
302                         var settings = api.settings()[0];
303                         var scroll = settings.oScroll;
304                 
305                         if ( bRedraw === undefined || bRedraw ) {
306                                 api.draw( false );
307                         }
308                         else if ( scroll.sX !== "" || scroll.sY !== "" ) {
309                                 /* If not redrawing, but scrolling, we want to apply the new column sizes anyway */
310                                 _fnScrollDraw( settings );
311                         }
312                 };
313                 
314                 
315                 /**
316                  * Quickly and simply clear a table
317                  *  @param {bool} [bRedraw=true] redraw the table or not
318                  *  @dtopt API
319                  *  @deprecated Since v1.10
320                  *
321                  *  @example
322                  *    $(document).ready(function() {
323                  *      var oTable = $('#example').dataTable();
324                  *
325                  *      // Immediately 'nuke' the current rows (perhaps waiting for an Ajax callback...)
326                  *      oTable.fnClearTable();
327                  *    } );
328                  */
329                 this.fnClearTable = function( bRedraw )
330                 {
331                         var api = this.api( true ).clear();
332                 
333                         if ( bRedraw === undefined || bRedraw ) {
334                                 api.draw();
335                         }
336                 };
337                 
338                 
339                 /**
340                  * The exact opposite of 'opening' a row, this function will close any rows which
341                  * are currently 'open'.
342                  *  @param {node} nTr the table row to 'close'
343                  *  @returns {int} 0 on success, or 1 if failed (can't find the row)
344                  *  @dtopt API
345                  *  @deprecated Since v1.10
346                  *
347                  *  @example
348                  *    $(document).ready(function() {
349                  *      var oTable;
350                  *
351                  *      // 'open' an information row when a row is clicked on
352                  *      $('#example tbody tr').click( function () {
353                  *        if ( oTable.fnIsOpen(this) ) {
354                  *          oTable.fnClose( this );
355                  *        } else {
356                  *          oTable.fnOpen( this, "Temporary row opened", "info_row" );
357                  *        }
358                  *      } );
359                  *
360                  *      oTable = $('#example').dataTable();
361                  *    } );
362                  */
363                 this.fnClose = function( nTr )
364                 {
365                         this.api( true ).row( nTr ).child.hide();
366                 };
367                 
368                 
369                 /**
370                  * Remove a row for the table
371                  *  @param {mixed} target The index of the row from aoData to be deleted, or
372                  *    the TR element you want to delete
373                  *  @param {function|null} [callBack] Callback function
374                  *  @param {bool} [redraw=true] Redraw the table or not
375                  *  @returns {array} The row that was deleted
376                  *  @dtopt API
377                  *  @deprecated Since v1.10
378                  *
379                  *  @example
380                  *    $(document).ready(function() {
381                  *      var oTable = $('#example').dataTable();
382                  *
383                  *      // Immediately remove the first row
384                  *      oTable.fnDeleteRow( 0 );
385                  *    } );
386                  */
387                 this.fnDeleteRow = function( target, callback, redraw )
388                 {
389                         var api = this.api( true );
390                         var rows = api.rows( target );
391                         var settings = rows.settings()[0];
392                         var data = settings.aoData[ rows[0][0] ];
393                 
394                         rows.remove();
395                 
396                         if ( callback ) {
397                                 callback.call( this, settings, data );
398                         }
399                 
400                         if ( redraw === undefined || redraw ) {
401                                 api.draw();
402                         }
403                 
404                         return data;
405                 };
406                 
407                 
408                 /**
409                  * Restore the table to it's original state in the DOM by removing all of DataTables
410                  * enhancements, alterations to the DOM structure of the table and event listeners.
411                  *  @param {boolean} [remove=false] Completely remove the table from the DOM
412                  *  @dtopt API
413                  *  @deprecated Since v1.10
414                  *
415                  *  @example
416                  *    $(document).ready(function() {
417                  *      // This example is fairly pointless in reality, but shows how fnDestroy can be used
418                  *      var oTable = $('#example').dataTable();
419                  *      oTable.fnDestroy();
420                  *    } );
421                  */
422                 this.fnDestroy = function ( remove )
423                 {
424                         this.api( true ).destroy( remove );
425                 };
426                 
427                 
428                 /**
429                  * Redraw the table
430                  *  @param {bool} [complete=true] Re-filter and resort (if enabled) the table before the draw.
431                  *  @dtopt API
432                  *  @deprecated Since v1.10
433                  *
434                  *  @example
435                  *    $(document).ready(function() {
436                  *      var oTable = $('#example').dataTable();
437                  *
438                  *      // Re-draw the table - you wouldn't want to do it here, but it's an example :-)
439                  *      oTable.fnDraw();
440                  *    } );
441                  */
442                 this.fnDraw = function( complete )
443                 {
444                         // Note that this isn't an exact match to the old call to _fnDraw - it takes
445                         // into account the new data, but can hold position.
446                         this.api( true ).draw( complete );
447                 };
448                 
449                 
450                 /**
451                  * Filter the input based on data
452                  *  @param {string} sInput String to filter the table on
453                  *  @param {int|null} [iColumn] Column to limit filtering to
454                  *  @param {bool} [bRegex=false] Treat as regular expression or not
455                  *  @param {bool} [bSmart=true] Perform smart filtering or not
456                  *  @param {bool} [bShowGlobal=true] Show the input global filter in it's input box(es)
457                  *  @param {bool} [bCaseInsensitive=true] Do case-insensitive matching (true) or not (false)
458                  *  @dtopt API
459                  *  @deprecated Since v1.10
460                  *
461                  *  @example
462                  *    $(document).ready(function() {
463                  *      var oTable = $('#example').dataTable();
464                  *
465                  *      // Sometime later - filter...
466                  *      oTable.fnFilter( 'test string' );
467                  *    } );
468                  */
469                 this.fnFilter = function( sInput, iColumn, bRegex, bSmart, bShowGlobal, bCaseInsensitive )
470                 {
471                         var api = this.api( true );
472                 
473                         if ( iColumn === null || iColumn === undefined ) {
474                                 api.search( sInput, bRegex, bSmart, bCaseInsensitive );
475                         }
476                         else {
477                                 api.column( iColumn ).search( sInput, bRegex, bSmart, bCaseInsensitive );
478                         }
479                 
480                         api.draw();
481                 };
482                 
483                 
484                 /**
485                  * Get the data for the whole table, an individual row or an individual cell based on the
486                  * provided parameters.
487                  *  @param {int|node} [src] A TR row node, TD/TH cell node or an integer. If given as
488                  *    a TR node then the data source for the whole row will be returned. If given as a
489                  *    TD/TH cell node then iCol will be automatically calculated and the data for the
490                  *    cell returned. If given as an integer, then this is treated as the aoData internal
491                  *    data index for the row (see fnGetPosition) and the data for that row used.
492                  *  @param {int} [col] Optional column index that you want the data of.
493                  *  @returns {array|object|string} If mRow is undefined, then the data for all rows is
494                  *    returned. If mRow is defined, just data for that row, and is iCol is
495                  *    defined, only data for the designated cell is returned.
496                  *  @dtopt API
497                  *  @deprecated Since v1.10
498                  *
499                  *  @example
500                  *    // Row data
501                  *    $(document).ready(function() {
502                  *      oTable = $('#example').dataTable();
503                  *
504                  *      oTable.$('tr').click( function () {
505                  *        var data = oTable.fnGetData( this );
506                  *        // ... do something with the array / object of data for the row
507                  *      } );
508                  *    } );
509                  *
510                  *  @example
511                  *    // Individual cell data
512                  *    $(document).ready(function() {
513                  *      oTable = $('#example').dataTable();
514                  *
515                  *      oTable.$('td').click( function () {
516                  *        var sData = oTable.fnGetData( this );
517                  *        alert( 'The cell clicked on had the value of '+sData );
518                  *      } );
519                  *    } );
520                  */
521                 this.fnGetData = function( src, col )
522                 {
523                         var api = this.api( true );
524                 
525                         if ( src !== undefined ) {
526                                 var type = src.nodeName ? src.nodeName.toLowerCase() : '';
527                 
528                                 return col !== undefined || type == 'td' || type == 'th' ?
529                                         api.cell( src, col ).data() :
530                                         api.row( src ).data() || null;
531                         }
532                 
533                         return api.data().toArray();
534                 };
535                 
536                 
537                 /**
538                  * Get an array of the TR nodes that are used in the table's body. Note that you will
539                  * typically want to use the '$' API method in preference to this as it is more
540                  * flexible.
541                  *  @param {int} [iRow] Optional row index for the TR element you want
542                  *  @returns {array|node} If iRow is undefined, returns an array of all TR elements
543                  *    in the table's body, or iRow is defined, just the TR element requested.
544                  *  @dtopt API
545                  *  @deprecated Since v1.10
546                  *
547                  *  @example
548                  *    $(document).ready(function() {
549                  *      var oTable = $('#example').dataTable();
550                  *
551                  *      // Get the nodes from the table
552                  *      var nNodes = oTable.fnGetNodes( );
553                  *    } );
554                  */
555                 this.fnGetNodes = function( iRow )
556                 {
557                         var api = this.api( true );
558                 
559                         return iRow !== undefined ?
560                                 api.row( iRow ).node() :
561                                 api.rows().nodes().flatten().toArray();
562                 };
563                 
564                 
565                 /**
566                  * Get the array indexes of a particular cell from it's DOM element
567                  * and column index including hidden columns
568                  *  @param {node} node this can either be a TR, TD or TH in the table's body
569                  *  @returns {int} If nNode is given as a TR, then a single index is returned, or
570                  *    if given as a cell, an array of [row index, column index (visible),
571                  *    column index (all)] is given.
572                  *  @dtopt API
573                  *  @deprecated Since v1.10
574                  *
575                  *  @example
576                  *    $(document).ready(function() {
577                  *      $('#example tbody td').click( function () {
578                  *        // Get the position of the current data from the node
579                  *        var aPos = oTable.fnGetPosition( this );
580                  *
581                  *        // Get the data array for this row
582                  *        var aData = oTable.fnGetData( aPos[0] );
583                  *
584                  *        // Update the data array and return the value
585                  *        aData[ aPos[1] ] = 'clicked';
586                  *        this.innerHTML = 'clicked';
587                  *      } );
588                  *
589                  *      // Init DataTables
590                  *      oTable = $('#example').dataTable();
591                  *    } );
592                  */
593                 this.fnGetPosition = function( node )
594                 {
595                         var api = this.api( true );
596                         var nodeName = node.nodeName.toUpperCase();
597                 
598                         if ( nodeName == 'TR' ) {
599                                 return api.row( node ).index();
600                         }
601                         else if ( nodeName == 'TD' || nodeName == 'TH' ) {
602                                 var cell = api.cell( node ).index();
603                 
604                                 return [
605                                         cell.row,
606                                         cell.columnVisible,
607                                         cell.column
608                                 ];
609                         }
610                         return null;
611                 };
612                 
613                 
614                 /**
615                  * Check to see if a row is 'open' or not.
616                  *  @param {node} nTr the table row to check
617                  *  @returns {boolean} true if the row is currently open, false otherwise
618                  *  @dtopt API
619                  *  @deprecated Since v1.10
620                  *
621                  *  @example
622                  *    $(document).ready(function() {
623                  *      var oTable;
624                  *
625                  *      // 'open' an information row when a row is clicked on
626                  *      $('#example tbody tr').click( function () {
627                  *        if ( oTable.fnIsOpen(this) ) {
628                  *          oTable.fnClose( this );
629                  *        } else {
630                  *          oTable.fnOpen( this, "Temporary row opened", "info_row" );
631                  *        }
632                  *      } );
633                  *
634                  *      oTable = $('#example').dataTable();
635                  *    } );
636                  */
637                 this.fnIsOpen = function( nTr )
638                 {
639                         return this.api( true ).row( nTr ).child.isShown();
640                 };
641                 
642                 
643                 /**
644                  * This function will place a new row directly after a row which is currently
645                  * on display on the page, with the HTML contents that is passed into the
646                  * function. This can be used, for example, to ask for confirmation that a
647                  * particular record should be deleted.
648                  *  @param {node} nTr The table row to 'open'
649                  *  @param {string|node|jQuery} mHtml The HTML to put into the row
650                  *  @param {string} sClass Class to give the new TD cell
651                  *  @returns {node} The row opened. Note that if the table row passed in as the
652                  *    first parameter, is not found in the table, this method will silently
653                  *    return.
654                  *  @dtopt API
655                  *  @deprecated Since v1.10
656                  *
657                  *  @example
658                  *    $(document).ready(function() {
659                  *      var oTable;
660                  *
661                  *      // 'open' an information row when a row is clicked on
662                  *      $('#example tbody tr').click( function () {
663                  *        if ( oTable.fnIsOpen(this) ) {
664                  *          oTable.fnClose( this );
665                  *        } else {
666                  *          oTable.fnOpen( this, "Temporary row opened", "info_row" );
667                  *        }
668                  *      } );
669                  *
670                  *      oTable = $('#example').dataTable();
671                  *    } );
672                  */
673                 this.fnOpen = function( nTr, mHtml, sClass )
674                 {
675                         return this.api( true )
676                                 .row( nTr )
677                                 .child( mHtml, sClass )
678                                 .show()
679                                 .child()[0];
680                 };
681                 
682                 
683                 /**
684                  * Change the pagination - provides the internal logic for pagination in a simple API
685                  * function. With this function you can have a DataTables table go to the next,
686                  * previous, first or last pages.
687                  *  @param {string|int} mAction Paging action to take: "first", "previous", "next" or "last"
688                  *    or page number to jump to (integer), note that page 0 is the first page.
689                  *  @param {bool} [bRedraw=true] Redraw the table or not
690                  *  @dtopt API
691                  *  @deprecated Since v1.10
692                  *
693                  *  @example
694                  *    $(document).ready(function() {
695                  *      var oTable = $('#example').dataTable();
696                  *      oTable.fnPageChange( 'next' );
697                  *    } );
698                  */
699                 this.fnPageChange = function ( mAction, bRedraw )
700                 {
701                         var api = this.api( true ).page( mAction );
702                 
703                         if ( bRedraw === undefined || bRedraw ) {
704                                 api.draw(false);
705                         }
706                 };
707                 
708                 
709                 /**
710                  * Show a particular column
711                  *  @param {int} iCol The column whose display should be changed
712                  *  @param {bool} bShow Show (true) or hide (false) the column
713                  *  @param {bool} [bRedraw=true] Redraw the table or not
714                  *  @dtopt API
715                  *  @deprecated Since v1.10
716                  *
717                  *  @example
718                  *    $(document).ready(function() {
719                  *      var oTable = $('#example').dataTable();
720                  *
721                  *      // Hide the second column after initialisation
722                  *      oTable.fnSetColumnVis( 1, false );
723                  *    } );
724                  */
725                 this.fnSetColumnVis = function ( iCol, bShow, bRedraw )
726                 {
727                         var api = this.api( true ).column( iCol ).visible( bShow );
728                 
729                         if ( bRedraw === undefined || bRedraw ) {
730                                 api.columns.adjust().draw();
731                         }
732                 };
733                 
734                 
735                 /**
736                  * Get the settings for a particular table for external manipulation
737                  *  @returns {object} DataTables settings object. See
738                  *    {@link DataTable.models.oSettings}
739                  *  @dtopt API
740                  *  @deprecated Since v1.10
741                  *
742                  *  @example
743                  *    $(document).ready(function() {
744                  *      var oTable = $('#example').dataTable();
745                  *      var oSettings = oTable.fnSettings();
746                  *
747                  *      // Show an example parameter from the settings
748                  *      alert( oSettings._iDisplayStart );
749                  *    } );
750                  */
751                 this.fnSettings = function()
752                 {
753                         return _fnSettingsFromNode( this[_ext.iApiIndex] );
754                 };
755                 
756                 
757                 /**
758                  * Sort the table by a particular column
759                  *  @param {int} iCol the data index to sort on. Note that this will not match the
760                  *    'display index' if you have hidden data entries
761                  *  @dtopt API
762                  *  @deprecated Since v1.10
763                  *
764                  *  @example
765                  *    $(document).ready(function() {
766                  *      var oTable = $('#example').dataTable();
767                  *
768                  *      // Sort immediately with columns 0 and 1
769                  *      oTable.fnSort( [ [0,'asc'], [1,'asc'] ] );
770                  *    } );
771                  */
772                 this.fnSort = function( aaSort )
773                 {
774                         this.api( true ).order( aaSort ).draw();
775                 };
776                 
777                 
778                 /**
779                  * Attach a sort listener to an element for a given column
780                  *  @param {node} nNode the element to attach the sort listener to
781                  *  @param {int} iColumn the column that a click on this node will sort on
782                  *  @param {function} [fnCallback] callback function when sort is run
783                  *  @dtopt API
784                  *  @deprecated Since v1.10
785                  *
786                  *  @example
787                  *    $(document).ready(function() {
788                  *      var oTable = $('#example').dataTable();
789                  *
790                  *      // Sort on column 1, when 'sorter' is clicked on
791                  *      oTable.fnSortListener( document.getElementById('sorter'), 1 );
792                  *    } );
793                  */
794                 this.fnSortListener = function( nNode, iColumn, fnCallback )
795                 {
796                         this.api( true ).order.listener( nNode, iColumn, fnCallback );
797                 };
798                 
799                 
800                 /**
801                  * Update a table cell or row - this method will accept either a single value to
802                  * update the cell with, an array of values with one element for each column or
803                  * an object in the same format as the original data source. The function is
804                  * self-referencing in order to make the multi column updates easier.
805                  *  @param {object|array|string} mData Data to update the cell/row with
806                  *  @param {node|int} mRow TR element you want to update or the aoData index
807                  *  @param {int} [iColumn] The column to update, give as null or undefined to
808                  *    update a whole row.
809                  *  @param {bool} [bRedraw=true] Redraw the table or not
810                  *  @param {bool} [bAction=true] Perform pre-draw actions or not
811                  *  @returns {int} 0 on success, 1 on error
812                  *  @dtopt API
813                  *  @deprecated Since v1.10
814                  *
815                  *  @example
816                  *    $(document).ready(function() {
817                  *      var oTable = $('#example').dataTable();
818                  *      oTable.fnUpdate( 'Example update', 0, 0 ); // Single cell
819                  *      oTable.fnUpdate( ['a', 'b', 'c', 'd', 'e'], $('tbody tr')[0] ); // Row
820                  *    } );
821                  */
822                 this.fnUpdate = function( mData, mRow, iColumn, bRedraw, bAction )
823                 {
824                         var api = this.api( true );
825                 
826                         if ( iColumn === undefined || iColumn === null ) {
827                                 api.row( mRow ).data( mData );
828                         }
829                         else {
830                                 api.cell( mRow, iColumn ).data( mData );
831                         }
832                 
833                         if ( bAction === undefined || bAction ) {
834                                 api.columns.adjust();
835                         }
836                 
837                         if ( bRedraw === undefined || bRedraw ) {
838                                 api.draw();
839                         }
840                         return 0;
841                 };
842                 
843                 
844                 /**
845                  * Provide a common method for plug-ins to check the version of DataTables being used, in order
846                  * to ensure compatibility.
847                  *  @param {string} sVersion Version string to check for, in the format "X.Y.Z". Note that the
848                  *    formats "X" and "X.Y" are also acceptable.
849                  *  @returns {boolean} true if this version of DataTables is greater or equal to the required
850                  *    version, or false if this version of DataTales is not suitable
851                  *  @method
852                  *  @dtopt API
853                  *  @deprecated Since v1.10
854                  *
855                  *  @example
856                  *    $(document).ready(function() {
857                  *      var oTable = $('#example').dataTable();
858                  *      alert( oTable.fnVersionCheck( '1.9.0' ) );
859                  *    } );
860                  */
861                 this.fnVersionCheck = _ext.fnVersionCheck;
862                 
863
864                 var _that = this;
865                 var emptyInit = options === undefined;
866                 var len = this.length;
867
868                 if ( emptyInit ) {
869                         options = {};
870                 }
871
872                 this.oApi = this.internal = _ext.internal;
873
874                 // Extend with old style plug-in API methods
875                 for ( var fn in DataTable.ext.internal ) {
876                         if ( fn ) {
877                                 this[fn] = _fnExternApiFunc(fn);
878                         }
879                 }
880
881                 this.each(function() {
882                         // For each initialisation we want to give it a clean initialisation
883                         // object that can be bashed around
884                         var o = {};
885                         var oInit = len > 1 ? // optimisation for single table case
886                                 _fnExtend( o, options, true ) :
887                                 options;
888
889                         /*global oInit,_that,emptyInit*/
890                         var i=0, iLen, j, jLen, k, kLen;
891                         var sId = this.getAttribute( 'id' );
892                         var bInitHandedOff = false;
893                         var defaults = DataTable.defaults;
894                         var $this = $(this);
895                         
896                         
897                         /* Sanity check */
898                         if ( this.nodeName.toLowerCase() != 'table' )
899                         {
900                                 _fnLog( null, 0, 'Non-table node initialisation ('+this.nodeName+')', 2 );
901                                 return;
902                         }
903                         
904                         /* Backwards compatibility for the defaults */
905                         _fnCompatOpts( defaults );
906                         _fnCompatCols( defaults.column );
907                         
908                         /* Convert the camel-case defaults to Hungarian */
909                         _fnCamelToHungarian( defaults, defaults, true );
910                         _fnCamelToHungarian( defaults.column, defaults.column, true );
911                         
912                         /* Setting up the initialisation object */
913                         _fnCamelToHungarian( defaults, $.extend( oInit, $this.data() ), true );
914                         
915                         
916                         
917                         /* Check to see if we are re-initialising a table */
918                         var allSettings = DataTable.settings;
919                         for ( i=0, iLen=allSettings.length ; i<iLen ; i++ )
920                         {
921                                 var s = allSettings[i];
922                         
923                                 /* Base check on table node */
924                                 if (
925                                         s.nTable == this ||
926                                         (s.nTHead && s.nTHead.parentNode == this) ||
927                                         (s.nTFoot && s.nTFoot.parentNode == this)
928                                 ) {
929                                         var bRetrieve = oInit.bRetrieve !== undefined ? oInit.bRetrieve : defaults.bRetrieve;
930                                         var bDestroy = oInit.bDestroy !== undefined ? oInit.bDestroy : defaults.bDestroy;
931                         
932                                         if ( emptyInit || bRetrieve )
933                                         {
934                                                 return s.oInstance;
935                                         }
936                                         else if ( bDestroy )
937                                         {
938                                                 s.oInstance.fnDestroy();
939                                                 break;
940                                         }
941                                         else
942                                         {
943                                                 _fnLog( s, 0, 'Cannot reinitialise DataTable', 3 );
944                                                 return;
945                                         }
946                                 }
947                         
948                                 /* If the element we are initialising has the same ID as a table which was previously
949                                  * initialised, but the table nodes don't match (from before) then we destroy the old
950                                  * instance by simply deleting it. This is under the assumption that the table has been
951                                  * destroyed by other methods. Anyone using non-id selectors will need to do this manually
952                                  */
953                                 if ( s.sTableId == this.id )
954                                 {
955                                         allSettings.splice( i, 1 );
956                                         break;
957                                 }
958                         }
959                         
960                         /* Ensure the table has an ID - required for accessibility */
961                         if ( sId === null || sId === "" )
962                         {
963                                 sId = "DataTables_Table_"+(DataTable.ext._unique++);
964                                 this.id = sId;
965                         }
966                         
967                         /* Create the settings object for this table and set some of the default parameters */
968                         var oSettings = $.extend( true, {}, DataTable.models.oSettings, {
969                                 "sDestroyWidth": $this[0].style.width,
970                                 "sInstance":     sId,
971                                 "sTableId":      sId
972                         } );
973                         oSettings.nTable = this;
974                         oSettings.oApi   = _that.internal;
975                         oSettings.oInit  = oInit;
976                         
977                         allSettings.push( oSettings );
978                         
979                         // Need to add the instance after the instance after the settings object has been added
980                         // to the settings array, so we can self reference the table instance if more than one
981                         oSettings.oInstance = (_that.length===1) ? _that : $this.dataTable();
982                         
983                         // Backwards compatibility, before we apply all the defaults
984                         _fnCompatOpts( oInit );
985                         _fnLanguageCompat( oInit.oLanguage );
986                         
987                         // If the length menu is given, but the init display length is not, use the length menu
988                         if ( oInit.aLengthMenu && ! oInit.iDisplayLength )
989                         {
990                                 oInit.iDisplayLength = $.isArray( oInit.aLengthMenu[0] ) ?
991                                         oInit.aLengthMenu[0][0] : oInit.aLengthMenu[0];
992                         }
993                         
994                         // Apply the defaults and init options to make a single init object will all
995                         // options defined from defaults and instance options.
996                         oInit = _fnExtend( $.extend( true, {}, defaults ), oInit );
997                         
998                         
999                         // Map the initialisation options onto the settings object
1000                         _fnMap( oSettings.oFeatures, oInit, [
1001                                 "bPaginate",
1002                                 "bLengthChange",
1003                                 "bFilter",
1004                                 "bSort",
1005                                 "bSortMulti",
1006                                 "bInfo",
1007                                 "bProcessing",
1008                                 "bAutoWidth",
1009                                 "bSortClasses",
1010                                 "bServerSide",
1011                                 "bDeferRender"
1012                         ] );
1013                         _fnMap( oSettings, oInit, [
1014                                 "asStripeClasses",
1015                                 "ajax",
1016                                 "fnServerData",
1017                                 "fnFormatNumber",
1018                                 "sServerMethod",
1019                                 "aaSorting",
1020                                 "aaSortingFixed",
1021                                 "aLengthMenu",
1022                                 "sPaginationType",
1023                                 "sAjaxSource",
1024                                 "sAjaxDataProp",
1025                                 "iStateDuration",
1026                                 "sDom",
1027                                 "bSortCellsTop",
1028                                 "iTabIndex",
1029                                 "fnStateLoadCallback",
1030                                 "fnStateSaveCallback",
1031                                 "renderer",
1032                                 "searchDelay",
1033                                 "rowId",
1034                                 [ "iCookieDuration", "iStateDuration" ], // backwards compat
1035                                 [ "oSearch", "oPreviousSearch" ],
1036                                 [ "aoSearchCols", "aoPreSearchCols" ],
1037                                 [ "iDisplayLength", "_iDisplayLength" ]
1038                         ] );
1039                         _fnMap( oSettings.oScroll, oInit, [
1040                                 [ "sScrollX", "sX" ],
1041                                 [ "sScrollXInner", "sXInner" ],
1042                                 [ "sScrollY", "sY" ],
1043                                 [ "bScrollCollapse", "bCollapse" ]
1044                         ] );
1045                         _fnMap( oSettings.oLanguage, oInit, "fnInfoCallback" );
1046                         
1047                         /* Callback functions which are array driven */
1048                         _fnCallbackReg( oSettings, 'aoDrawCallback',       oInit.fnDrawCallback,      'user' );
1049                         _fnCallbackReg( oSettings, 'aoServerParams',       oInit.fnServerParams,      'user' );
1050                         _fnCallbackReg( oSettings, 'aoStateSaveParams',    oInit.fnStateSaveParams,   'user' );
1051                         _fnCallbackReg( oSettings, 'aoStateLoadParams',    oInit.fnStateLoadParams,   'user' );
1052                         _fnCallbackReg( oSettings, 'aoStateLoaded',        oInit.fnStateLoaded,       'user' );
1053                         _fnCallbackReg( oSettings, 'aoRowCallback',        oInit.fnRowCallback,       'user' );
1054                         _fnCallbackReg( oSettings, 'aoRowCreatedCallback', oInit.fnCreatedRow,        'user' );
1055                         _fnCallbackReg( oSettings, 'aoHeaderCallback',     oInit.fnHeaderCallback,    'user' );
1056                         _fnCallbackReg( oSettings, 'aoFooterCallback',     oInit.fnFooterCallback,    'user' );
1057                         _fnCallbackReg( oSettings, 'aoInitComplete',       oInit.fnInitComplete,      'user' );
1058                         _fnCallbackReg( oSettings, 'aoPreDrawCallback',    oInit.fnPreDrawCallback,   'user' );
1059                         
1060                         oSettings.rowIdFn = _fnGetObjectDataFn( oInit.rowId );
1061                         
1062                         /* Browser support detection */
1063                         _fnBrowserDetect( oSettings );
1064                         
1065                         var oClasses = oSettings.oClasses;
1066                         
1067                         $.extend( oClasses, DataTable.ext.classes, oInit.oClasses );
1068                         $this.addClass( oClasses.sTable );
1069                         
1070                         
1071                         if ( oSettings.iInitDisplayStart === undefined )
1072                         {
1073                                 /* Display start point, taking into account the save saving */
1074                                 oSettings.iInitDisplayStart = oInit.iDisplayStart;
1075                                 oSettings._iDisplayStart = oInit.iDisplayStart;
1076                         }
1077                         
1078                         if ( oInit.iDeferLoading !== null )
1079                         {
1080                                 oSettings.bDeferLoading = true;
1081                                 var tmp = $.isArray( oInit.iDeferLoading );
1082                                 oSettings._iRecordsDisplay = tmp ? oInit.iDeferLoading[0] : oInit.iDeferLoading;
1083                                 oSettings._iRecordsTotal = tmp ? oInit.iDeferLoading[1] : oInit.iDeferLoading;
1084                         }
1085                         
1086                         /* Language definitions */
1087                         var oLanguage = oSettings.oLanguage;
1088                         $.extend( true, oLanguage, oInit.oLanguage );
1089                         
1090                         if ( oLanguage.sUrl )
1091                         {
1092                                 /* Get the language definitions from a file - because this Ajax call makes the language
1093                                  * get async to the remainder of this function we use bInitHandedOff to indicate that
1094                                  * _fnInitialise will be fired by the returned Ajax handler, rather than the constructor
1095                                  */
1096                                 $.ajax( {
1097                                         dataType: 'json',
1098                                         url: oLanguage.sUrl,
1099                                         success: function ( json ) {
1100                                                 _fnLanguageCompat( json );
1101                                                 _fnCamelToHungarian( defaults.oLanguage, json );
1102                                                 $.extend( true, oLanguage, json );
1103                                                 _fnInitialise( oSettings );
1104                                         },
1105                                         error: function () {
1106                                                 // Error occurred loading language file, continue on as best we can
1107                                                 _fnInitialise( oSettings );
1108                                         }
1109                                 } );
1110                                 bInitHandedOff = true;
1111                         }
1112                         
1113                         /*
1114                          * Stripes
1115                          */
1116                         if ( oInit.asStripeClasses === null )
1117                         {
1118                                 oSettings.asStripeClasses =[
1119                                         oClasses.sStripeOdd,
1120                                         oClasses.sStripeEven
1121                                 ];
1122                         }
1123                         
1124                         /* Remove row stripe classes if they are already on the table row */
1125                         var stripeClasses = oSettings.asStripeClasses;
1126                         var rowOne = $this.children('tbody').find('tr').eq(0);
1127                         if ( $.inArray( true, $.map( stripeClasses, function(el, i) {
1128                                 return rowOne.hasClass(el);
1129                         } ) ) !== -1 ) {
1130                                 $('tbody tr', this).removeClass( stripeClasses.join(' ') );
1131                                 oSettings.asDestroyStripes = stripeClasses.slice();
1132                         }
1133                         
1134                         /*
1135                          * Columns
1136                          * See if we should load columns automatically or use defined ones
1137                          */
1138                         var anThs = [];
1139                         var aoColumnsInit;
1140                         var nThead = this.getElementsByTagName('thead');
1141                         if ( nThead.length !== 0 )
1142                         {
1143                                 _fnDetectHeader( oSettings.aoHeader, nThead[0] );
1144                                 anThs = _fnGetUniqueThs( oSettings );
1145                         }
1146                         
1147                         /* If not given a column array, generate one with nulls */
1148                         if ( oInit.aoColumns === null )
1149                         {
1150                                 aoColumnsInit = [];
1151                                 for ( i=0, iLen=anThs.length ; i<iLen ; i++ )
1152                                 {
1153                                         aoColumnsInit.push( null );
1154                                 }
1155                         }
1156                         else
1157                         {
1158                                 aoColumnsInit = oInit.aoColumns;
1159                         }
1160                         
1161                         /* Add the columns */
1162                         for ( i=0, iLen=aoColumnsInit.length ; i<iLen ; i++ )
1163                         {
1164                                 _fnAddColumn( oSettings, anThs ? anThs[i] : null );
1165                         }
1166                         
1167                         /* Apply the column definitions */
1168                         _fnApplyColumnDefs( oSettings, oInit.aoColumnDefs, aoColumnsInit, function (iCol, oDef) {
1169                                 _fnColumnOptions( oSettings, iCol, oDef );
1170                         } );
1171                         
1172                         /* HTML5 attribute detection - build an mData object automatically if the
1173                          * attributes are found
1174                          */
1175                         if ( rowOne.length ) {
1176                                 var a = function ( cell, name ) {
1177                                         return cell.getAttribute( 'data-'+name ) !== null ? name : null;
1178                                 };
1179                         
1180                                 $( rowOne[0] ).children('th, td').each( function (i, cell) {
1181                                         var col = oSettings.aoColumns[i];
1182                         
1183                                         if ( col.mData === i ) {
1184                                                 var sort = a( cell, 'sort' ) || a( cell, 'order' );
1185                                                 var filter = a( cell, 'filter' ) || a( cell, 'search' );
1186                         
1187                                                 if ( sort !== null || filter !== null ) {
1188                                                         col.mData = {
1189                                                                 _:      i+'.display',
1190                                                                 sort:   sort !== null   ? i+'.@data-'+sort   : undefined,
1191                                                                 type:   sort !== null   ? i+'.@data-'+sort   : undefined,
1192                                                                 filter: filter !== null ? i+'.@data-'+filter : undefined
1193                                                         };
1194                         
1195                                                         _fnColumnOptions( oSettings, i );
1196                                                 }
1197                                         }
1198                                 } );
1199                         }
1200                         
1201                         var features = oSettings.oFeatures;
1202                         var loadedInit = function () {
1203                                 /*
1204                                  * Sorting
1205                                  * @todo For modularisation (1.11) this needs to do into a sort start up handler
1206                                  */
1207                         
1208                                 // If aaSorting is not defined, then we use the first indicator in asSorting
1209                                 // in case that has been altered, so the default sort reflects that option
1210                                 if ( oInit.aaSorting === undefined ) {
1211                                         var sorting = oSettings.aaSorting;
1212                                         for ( i=0, iLen=sorting.length ; i<iLen ; i++ ) {
1213                                                 sorting[i][1] = oSettings.aoColumns[ i ].asSorting[0];
1214                                         }
1215                                 }
1216                         
1217                                 /* Do a first pass on the sorting classes (allows any size changes to be taken into
1218                                  * account, and also will apply sorting disabled classes if disabled
1219                                  */
1220                                 _fnSortingClasses( oSettings );
1221                         
1222                                 if ( features.bSort ) {
1223                                         _fnCallbackReg( oSettings, 'aoDrawCallback', function () {
1224                                                 if ( oSettings.bSorted ) {
1225                                                         var aSort = _fnSortFlatten( oSettings );
1226                                                         var sortedColumns = {};
1227                         
1228                                                         $.each( aSort, function (i, val) {
1229                                                                 sortedColumns[ val.src ] = val.dir;
1230                                                         } );
1231                         
1232                                                         _fnCallbackFire( oSettings, null, 'order', [oSettings, aSort, sortedColumns] );
1233                                                         _fnSortAria( oSettings );
1234                                                 }
1235                                         } );
1236                                 }
1237                         
1238                                 _fnCallbackReg( oSettings, 'aoDrawCallback', function () {
1239                                         if ( oSettings.bSorted || _fnDataSource( oSettings ) === 'ssp' || features.bDeferRender ) {
1240                                                 _fnSortingClasses( oSettings );
1241                                         }
1242                                 }, 'sc' );
1243                         
1244                         
1245                                 /*
1246                                  * Final init
1247                                  * Cache the header, body and footer as required, creating them if needed
1248                                  */
1249                         
1250                                 // Work around for Webkit bug 83867 - store the caption-side before removing from doc
1251                                 var captions = $this.children('caption').each( function () {
1252                                         this._captionSide = $(this).css('caption-side');
1253                                 } );
1254                         
1255                                 var thead = $this.children('thead');
1256                                 if ( thead.length === 0 ) {
1257                                         thead = $('<thead/>').appendTo($this);
1258                                 }
1259                                 oSettings.nTHead = thead[0];
1260                         
1261                                 var tbody = $this.children('tbody');
1262                                 if ( tbody.length === 0 ) {
1263                                         tbody = $('<tbody/>').appendTo($this);
1264                                 }
1265                                 oSettings.nTBody = tbody[0];
1266                         
1267                                 var tfoot = $this.children('tfoot');
1268                                 if ( tfoot.length === 0 && captions.length > 0 && (oSettings.oScroll.sX !== "" || oSettings.oScroll.sY !== "") ) {
1269                                         // If we are a scrolling table, and no footer has been given, then we need to create
1270                                         // a tfoot element for the caption element to be appended to
1271                                         tfoot = $('<tfoot/>').appendTo($this);
1272                                 }
1273                         
1274                                 if ( tfoot.length === 0 || tfoot.children().length === 0 ) {
1275                                         $this.addClass( oClasses.sNoFooter );
1276                                 }
1277                                 else if ( tfoot.length > 0 ) {
1278                                         oSettings.nTFoot = tfoot[0];
1279                                         _fnDetectHeader( oSettings.aoFooter, oSettings.nTFoot );
1280                                 }
1281                         
1282                                 /* Check if there is data passing into the constructor */
1283                                 if ( oInit.aaData ) {
1284                                         for ( i=0 ; i<oInit.aaData.length ; i++ ) {
1285                                                 _fnAddData( oSettings, oInit.aaData[ i ] );
1286                                         }
1287                                 }
1288                                 else if ( oSettings.bDeferLoading || _fnDataSource( oSettings ) == 'dom' ) {
1289                                         /* Grab the data from the page - only do this when deferred loading or no Ajax
1290                                          * source since there is no point in reading the DOM data if we are then going
1291                                          * to replace it with Ajax data
1292                                          */
1293                                         _fnAddTr( oSettings, $(oSettings.nTBody).children('tr') );
1294                                 }
1295                         
1296                                 /* Copy the data index array */
1297                                 oSettings.aiDisplay = oSettings.aiDisplayMaster.slice();
1298                         
1299                                 /* Initialisation complete - table can be drawn */
1300                                 oSettings.bInitialised = true;
1301                         
1302                                 /* Check if we need to initialise the table (it might not have been handed off to the
1303                                  * language processor)
1304                                  */
1305                                 if ( bInitHandedOff === false ) {
1306                                         _fnInitialise( oSettings );
1307                                 }
1308                         };
1309                         
1310                         /* Must be done after everything which can be overridden by the state saving! */
1311                         if ( oInit.bStateSave )
1312                         {
1313                                 features.bStateSave = true;
1314                                 _fnCallbackReg( oSettings, 'aoDrawCallback', _fnSaveState, 'state_save' );
1315                                 _fnLoadState( oSettings, oInit, loadedInit );
1316                         }
1317                         else {
1318                                 loadedInit();
1319                         }
1320                         
1321                 } );
1322                 _that = null;
1323                 return this;
1324         };
1325
1326         
1327         /*
1328          * It is useful to have variables which are scoped locally so only the
1329          * DataTables functions can access them and they don't leak into global space.
1330          * At the same time these functions are often useful over multiple files in the
1331          * core and API, so we list, or at least document, all variables which are used
1332          * by DataTables as private variables here. This also ensures that there is no
1333          * clashing of variable names and that they can easily referenced for reuse.
1334          */
1335         
1336         
1337         // Defined else where
1338         //  _selector_run
1339         //  _selector_opts
1340         //  _selector_first
1341         //  _selector_row_indexes
1342         
1343         var _ext; // DataTable.ext
1344         var _Api; // DataTable.Api
1345         var _api_register; // DataTable.Api.register
1346         var _api_registerPlural; // DataTable.Api.registerPlural
1347         
1348         var _re_dic = {};
1349         var _re_new_lines = /[\r\n\u2028]/g;
1350         var _re_html = /<.*?>/g;
1351         
1352         // This is not strict ISO8601 - Date.parse() is quite lax, although
1353         // implementations differ between browsers.
1354         var _re_date = /^\d{2,4}[\.\/\-]\d{1,2}[\.\/\-]\d{1,2}([T ]{1}\d{1,2}[:\.]\d{2}([\.:]\d{2})?)?$/;
1355         
1356         // Escape regular expression special characters
1357         var _re_escape_regex = new RegExp( '(\\' + [ '/', '.', '*', '+', '?', '|', '(', ')', '[', ']', '{', '}', '\\', '$', '^', '-' ].join('|\\') + ')', 'g' );
1358         
1359         // http://en.wikipedia.org/wiki/Foreign_exchange_market
1360         // - \u20BD - Russian ruble.
1361         // - \u20a9 - South Korean Won
1362         // - \u20BA - Turkish Lira
1363         // - \u20B9 - Indian Rupee
1364         // - R - Brazil (R$) and South Africa
1365         // - fr - Swiss Franc
1366         // - kr - Swedish krona, Norwegian krone and Danish krone
1367         // - \u2009 is thin space and \u202F is narrow no-break space, both used in many
1368         // - Ƀ - Bitcoin
1369         // - Ξ - Ethereum
1370         //   standards as thousands separators.
1371         var _re_formatted_numeric = /[',$£€¥%\u2009\u202F\u20BD\u20a9\u20BArfkɃΞ]/gi;
1372         
1373         
1374         var _empty = function ( d ) {
1375                 return !d || d === true || d === '-' ? true : false;
1376         };
1377         
1378         
1379         var _intVal = function ( s ) {
1380                 var integer = parseInt( s, 10 );
1381                 return !isNaN(integer) && isFinite(s) ? integer : null;
1382         };
1383         
1384         // Convert from a formatted number with characters other than `.` as the
1385         // decimal place, to a Javascript number
1386         var _numToDecimal = function ( num, decimalPoint ) {
1387                 // Cache created regular expressions for speed as this function is called often
1388                 if ( ! _re_dic[ decimalPoint ] ) {
1389                         _re_dic[ decimalPoint ] = new RegExp( _fnEscapeRegex( decimalPoint ), 'g' );
1390                 }
1391                 return typeof num === 'string' && decimalPoint !== '.' ?
1392                         num.replace( /\./g, '' ).replace( _re_dic[ decimalPoint ], '.' ) :
1393                         num;
1394         };
1395         
1396         
1397         var _isNumber = function ( d, decimalPoint, formatted ) {
1398                 var strType = typeof d === 'string';
1399         
1400                 // If empty return immediately so there must be a number if it is a
1401                 // formatted string (this stops the string "k", or "kr", etc being detected
1402                 // as a formatted number for currency
1403                 if ( _empty( d ) ) {
1404                         return true;
1405                 }
1406         
1407                 if ( decimalPoint && strType ) {
1408                         d = _numToDecimal( d, decimalPoint );
1409                 }
1410         
1411                 if ( formatted && strType ) {
1412                         d = d.replace( _re_formatted_numeric, '' );
1413                 }
1414         
1415                 return !isNaN( parseFloat(d) ) && isFinite( d );
1416         };
1417         
1418         
1419         // A string without HTML in it can be considered to be HTML still
1420         var _isHtml = function ( d ) {
1421                 return _empty( d ) || typeof d === 'string';
1422         };
1423         
1424         
1425         var _htmlNumeric = function ( d, decimalPoint, formatted ) {
1426                 if ( _empty( d ) ) {
1427                         return true;
1428                 }
1429         
1430                 var html = _isHtml( d );
1431                 return ! html ?
1432                         null :
1433                         _isNumber( _stripHtml( d ), decimalPoint, formatted ) ?
1434                                 true :
1435                                 null;
1436         };
1437         
1438         
1439         var _pluck = function ( a, prop, prop2 ) {
1440                 var out = [];
1441                 var i=0, ien=a.length;
1442         
1443                 // Could have the test in the loop for slightly smaller code, but speed
1444                 // is essential here
1445                 if ( prop2 !== undefined ) {
1446                         for ( ; i<ien ; i++ ) {
1447                                 if ( a[i] && a[i][ prop ] ) {
1448                                         out.push( a[i][ prop ][ prop2 ] );
1449                                 }
1450                         }
1451                 }
1452                 else {
1453                         for ( ; i<ien ; i++ ) {
1454                                 if ( a[i] ) {
1455                                         out.push( a[i][ prop ] );
1456                                 }
1457                         }
1458                 }
1459         
1460                 return out;
1461         };
1462         
1463         
1464         // Basically the same as _pluck, but rather than looping over `a` we use `order`
1465         // as the indexes to pick from `a`
1466         var _pluck_order = function ( a, order, prop, prop2 )
1467         {
1468                 var out = [];
1469                 var i=0, ien=order.length;
1470         
1471                 // Could have the test in the loop for slightly smaller code, but speed
1472                 // is essential here
1473                 if ( prop2 !== undefined ) {
1474                         for ( ; i<ien ; i++ ) {
1475                                 if ( a[ order[i] ][ prop ] ) {
1476                                         out.push( a[ order[i] ][ prop ][ prop2 ] );
1477                                 }
1478                         }
1479                 }
1480                 else {
1481                         for ( ; i<ien ; i++ ) {
1482                                 out.push( a[ order[i] ][ prop ] );
1483                         }
1484                 }
1485         
1486                 return out;
1487         };
1488         
1489         
1490         var _range = function ( len, start )
1491         {
1492                 var out = [];
1493                 var end;
1494         
1495                 if ( start === undefined ) {
1496                         start = 0;
1497                         end = len;
1498                 }
1499                 else {
1500                         end = start;
1501                         start = len;
1502                 }
1503         
1504                 for ( var i=start ; i<end ; i++ ) {
1505                         out.push( i );
1506                 }
1507         
1508                 return out;
1509         };
1510         
1511         
1512         var _removeEmpty = function ( a )
1513         {
1514                 var out = [];
1515         
1516                 for ( var i=0, ien=a.length ; i<ien ; i++ ) {
1517                         if ( a[i] ) { // careful - will remove all falsy values!
1518                                 out.push( a[i] );
1519                         }
1520                 }
1521         
1522                 return out;
1523         };
1524         
1525         
1526         var _stripHtml = function ( d ) {
1527                 return d.replace( _re_html, '' );
1528         };
1529         
1530         
1531         /**
1532          * Determine if all values in the array are unique. This means we can short
1533          * cut the _unique method at the cost of a single loop. A sorted array is used
1534          * to easily check the values.
1535          *
1536          * @param  {array} src Source array
1537          * @return {boolean} true if all unique, false otherwise
1538          * @ignore
1539          */
1540         var _areAllUnique = function ( src ) {
1541                 if ( src.length < 2 ) {
1542                         return true;
1543                 }
1544         
1545                 var sorted = src.slice().sort();
1546                 var last = sorted[0];
1547         
1548                 for ( var i=1, ien=sorted.length ; i<ien ; i++ ) {
1549                         if ( sorted[i] === last ) {
1550                                 return false;
1551                         }
1552         
1553                         last = sorted[i];
1554                 }
1555         
1556                 return true;
1557         };
1558         
1559         
1560         /**
1561          * Find the unique elements in a source array.
1562          *
1563          * @param  {array} src Source array
1564          * @return {array} Array of unique items
1565          * @ignore
1566          */
1567         var _unique = function ( src )
1568         {
1569                 if ( _areAllUnique( src ) ) {
1570                         return src.slice();
1571                 }
1572         
1573                 // A faster unique method is to use object keys to identify used values,
1574                 // but this doesn't work with arrays or objects, which we must also
1575                 // consider. See jsperf.com/compare-array-unique-versions/4 for more
1576                 // information.
1577                 var
1578                         out = [],
1579                         val,
1580                         i, ien=src.length,
1581                         j, k=0;
1582         
1583                 again: for ( i=0 ; i<ien ; i++ ) {
1584                         val = src[i];
1585         
1586                         for ( j=0 ; j<k ; j++ ) {
1587                                 if ( out[j] === val ) {
1588                                         continue again;
1589                                 }
1590                         }
1591         
1592                         out.push( val );
1593                         k++;
1594                 }
1595         
1596                 return out;
1597         };
1598         
1599         
1600         /**
1601          * DataTables utility methods
1602          * 
1603          * This namespace provides helper methods that DataTables uses internally to
1604          * create a DataTable, but which are not exclusively used only for DataTables.
1605          * These methods can be used by extension authors to save the duplication of
1606          * code.
1607          *
1608          *  @namespace
1609          */
1610         DataTable.util = {
1611                 /**
1612                  * Throttle the calls to a function. Arguments and context are maintained
1613                  * for the throttled function.
1614                  *
1615                  * @param {function} fn Function to be called
1616                  * @param {integer} freq Call frequency in mS
1617                  * @return {function} Wrapped function
1618                  */
1619                 throttle: function ( fn, freq ) {
1620                         var
1621                                 frequency = freq !== undefined ? freq : 200,
1622                                 last,
1623                                 timer;
1624         
1625                         return function () {
1626                                 var
1627                                         that = this,
1628                                         now  = +new Date(),
1629                                         args = arguments;
1630         
1631                                 if ( last && now < last + frequency ) {
1632                                         clearTimeout( timer );
1633         
1634                                         timer = setTimeout( function () {
1635                                                 last = undefined;
1636                                                 fn.apply( that, args );
1637                                         }, frequency );
1638                                 }
1639                                 else {
1640                                         last = now;
1641                                         fn.apply( that, args );
1642                                 }
1643                         };
1644                 },
1645         
1646         
1647                 /**
1648                  * Escape a string such that it can be used in a regular expression
1649                  *
1650                  *  @param {string} val string to escape
1651                  *  @returns {string} escaped string
1652                  */
1653                 escapeRegex: function ( val ) {
1654                         return val.replace( _re_escape_regex, '\\$1' );
1655                 }
1656         };
1657         
1658         
1659         
1660         /**
1661          * Create a mapping object that allows camel case parameters to be looked up
1662          * for their Hungarian counterparts. The mapping is stored in a private
1663          * parameter called `_hungarianMap` which can be accessed on the source object.
1664          *  @param {object} o
1665          *  @memberof DataTable#oApi
1666          */
1667         function _fnHungarianMap ( o )
1668         {
1669                 var
1670                         hungarian = 'a aa ai ao as b fn i m o s ',
1671                         match,
1672                         newKey,
1673                         map = {};
1674         
1675                 $.each( o, function (key, val) {
1676                         match = key.match(/^([^A-Z]+?)([A-Z])/);
1677         
1678                         if ( match && hungarian.indexOf(match[1]+' ') !== -1 )
1679                         {
1680                                 newKey = key.replace( match[0], match[2].toLowerCase() );
1681                                 map[ newKey ] = key;
1682         
1683                                 if ( match[1] === 'o' )
1684                                 {
1685                                         _fnHungarianMap( o[key] );
1686                                 }
1687                         }
1688                 } );
1689         
1690                 o._hungarianMap = map;
1691         }
1692         
1693         
1694         /**
1695          * Convert from camel case parameters to Hungarian, based on a Hungarian map
1696          * created by _fnHungarianMap.
1697          *  @param {object} src The model object which holds all parameters that can be
1698          *    mapped.
1699          *  @param {object} user The object to convert from camel case to Hungarian.
1700          *  @param {boolean} force When set to `true`, properties which already have a
1701          *    Hungarian value in the `user` object will be overwritten. Otherwise they
1702          *    won't be.
1703          *  @memberof DataTable#oApi
1704          */
1705         function _fnCamelToHungarian ( src, user, force )
1706         {
1707                 if ( ! src._hungarianMap ) {
1708                         _fnHungarianMap( src );
1709                 }
1710         
1711                 var hungarianKey;
1712         
1713                 $.each( user, function (key, val) {
1714                         hungarianKey = src._hungarianMap[ key ];
1715         
1716                         if ( hungarianKey !== undefined && (force || user[hungarianKey] === undefined) )
1717                         {
1718                                 // For objects, we need to buzz down into the object to copy parameters
1719                                 if ( hungarianKey.charAt(0) === 'o' )
1720                                 {
1721                                         // Copy the camelCase options over to the hungarian
1722                                         if ( ! user[ hungarianKey ] ) {
1723                                                 user[ hungarianKey ] = {};
1724                                         }
1725                                         $.extend( true, user[hungarianKey], user[key] );
1726         
1727                                         _fnCamelToHungarian( src[hungarianKey], user[hungarianKey], force );
1728                                 }
1729                                 else {
1730                                         user[hungarianKey] = user[ key ];
1731                                 }
1732                         }
1733                 } );
1734         }
1735         
1736         
1737         /**
1738          * Language compatibility - when certain options are given, and others aren't, we
1739          * need to duplicate the values over, in order to provide backwards compatibility
1740          * with older language files.
1741          *  @param {object} oSettings dataTables settings object
1742          *  @memberof DataTable#oApi
1743          */
1744         function _fnLanguageCompat( lang )
1745         {
1746                 // Note the use of the Hungarian notation for the parameters in this method as
1747                 // this is called after the mapping of camelCase to Hungarian
1748                 var defaults = DataTable.defaults.oLanguage;
1749         
1750                 // Default mapping
1751                 var defaultDecimal = defaults.sDecimal;
1752                 if ( defaultDecimal ) {
1753                         _addNumericSort( defaultDecimal );
1754                 }
1755         
1756                 if ( lang ) {
1757                         var zeroRecords = lang.sZeroRecords;
1758         
1759                         // Backwards compatibility - if there is no sEmptyTable given, then use the same as
1760                         // sZeroRecords - assuming that is given.
1761                         if ( ! lang.sEmptyTable && zeroRecords &&
1762                                 defaults.sEmptyTable === "No data available in table" )
1763                         {
1764                                 _fnMap( lang, lang, 'sZeroRecords', 'sEmptyTable' );
1765                         }
1766         
1767                         // Likewise with loading records
1768                         if ( ! lang.sLoadingRecords && zeroRecords &&
1769                                 defaults.sLoadingRecords === "Loading..." )
1770                         {
1771                                 _fnMap( lang, lang, 'sZeroRecords', 'sLoadingRecords' );
1772                         }
1773         
1774                         // Old parameter name of the thousands separator mapped onto the new
1775                         if ( lang.sInfoThousands ) {
1776                                 lang.sThousands = lang.sInfoThousands;
1777                         }
1778         
1779                         var decimal = lang.sDecimal;
1780                         if ( decimal && defaultDecimal !== decimal ) {
1781                                 _addNumericSort( decimal );
1782                         }
1783                 }
1784         }
1785         
1786         
1787         /**
1788          * Map one parameter onto another
1789          *  @param {object} o Object to map
1790          *  @param {*} knew The new parameter name
1791          *  @param {*} old The old parameter name
1792          */
1793         var _fnCompatMap = function ( o, knew, old ) {
1794                 if ( o[ knew ] !== undefined ) {
1795                         o[ old ] = o[ knew ];
1796                 }
1797         };
1798         
1799         
1800         /**
1801          * Provide backwards compatibility for the main DT options. Note that the new
1802          * options are mapped onto the old parameters, so this is an external interface
1803          * change only.
1804          *  @param {object} init Object to map
1805          */
1806         function _fnCompatOpts ( init )
1807         {
1808                 _fnCompatMap( init, 'ordering',      'bSort' );
1809                 _fnCompatMap( init, 'orderMulti',    'bSortMulti' );
1810                 _fnCompatMap( init, 'orderClasses',  'bSortClasses' );
1811                 _fnCompatMap( init, 'orderCellsTop', 'bSortCellsTop' );
1812                 _fnCompatMap( init, 'order',         'aaSorting' );
1813                 _fnCompatMap( init, 'orderFixed',    'aaSortingFixed' );
1814                 _fnCompatMap( init, 'paging',        'bPaginate' );
1815                 _fnCompatMap( init, 'pagingType',    'sPaginationType' );
1816                 _fnCompatMap( init, 'pageLength',    'iDisplayLength' );
1817                 _fnCompatMap( init, 'searching',     'bFilter' );
1818         
1819                 // Boolean initialisation of x-scrolling
1820                 if ( typeof init.sScrollX === 'boolean' ) {
1821                         init.sScrollX = init.sScrollX ? '100%' : '';
1822                 }
1823                 if ( typeof init.scrollX === 'boolean' ) {
1824                         init.scrollX = init.scrollX ? '100%' : '';
1825                 }
1826         
1827                 // Column search objects are in an array, so it needs to be converted
1828                 // element by element
1829                 var searchCols = init.aoSearchCols;
1830         
1831                 if ( searchCols ) {
1832                         for ( var i=0, ien=searchCols.length ; i<ien ; i++ ) {
1833                                 if ( searchCols[i] ) {
1834                                         _fnCamelToHungarian( DataTable.models.oSearch, searchCols[i] );
1835                                 }
1836                         }
1837                 }
1838         }
1839         
1840         
1841         /**
1842          * Provide backwards compatibility for column options. Note that the new options
1843          * are mapped onto the old parameters, so this is an external interface change
1844          * only.
1845          *  @param {object} init Object to map
1846          */
1847         function _fnCompatCols ( init )
1848         {
1849                 _fnCompatMap( init, 'orderable',     'bSortable' );
1850                 _fnCompatMap( init, 'orderData',     'aDataSort' );
1851                 _fnCompatMap( init, 'orderSequence', 'asSorting' );
1852                 _fnCompatMap( init, 'orderDataType', 'sortDataType' );
1853         
1854                 // orderData can be given as an integer
1855                 var dataSort = init.aDataSort;
1856                 if ( typeof dataSort === 'number' && ! $.isArray( dataSort ) ) {
1857                         init.aDataSort = [ dataSort ];
1858                 }
1859         }
1860         
1861         
1862         /**
1863          * Browser feature detection for capabilities, quirks
1864          *  @param {object} settings dataTables settings object
1865          *  @memberof DataTable#oApi
1866          */
1867         function _fnBrowserDetect( settings )
1868         {
1869                 // We don't need to do this every time DataTables is constructed, the values
1870                 // calculated are specific to the browser and OS configuration which we
1871                 // don't expect to change between initialisations
1872                 if ( ! DataTable.__browser ) {
1873                         var browser = {};
1874                         DataTable.__browser = browser;
1875         
1876                         // Scrolling feature / quirks detection
1877                         var n = $('<div/>')
1878                                 .css( {
1879                                         position: 'fixed',
1880                                         top: 0,
1881                                         left: $(window).scrollLeft()*-1, // allow for scrolling
1882                                         height: 1,
1883                                         width: 1,
1884                                         overflow: 'hidden'
1885                                 } )
1886                                 .append(
1887                                         $('<div/>')
1888                                                 .css( {
1889                                                         position: 'absolute',
1890                                                         top: 1,
1891                                                         left: 1,
1892                                                         width: 100,
1893                                                         overflow: 'scroll'
1894                                                 } )
1895                                                 .append(
1896                                                         $('<div/>')
1897                                                                 .css( {
1898                                                                         width: '100%',
1899                                                                         height: 10
1900                                                                 } )
1901                                                 )
1902                                 )
1903                                 .appendTo( 'body' );
1904         
1905                         var outer = n.children();
1906                         var inner = outer.children();
1907         
1908                         // Numbers below, in order, are:
1909                         // inner.offsetWidth, inner.clientWidth, outer.offsetWidth, outer.clientWidth
1910                         //
1911                         // IE6 XP:                           100 100 100  83
1912                         // IE7 Vista:                        100 100 100  83
1913                         // IE 8+ Windows:                     83  83 100  83
1914                         // Evergreen Windows:                 83  83 100  83
1915                         // Evergreen Mac with scrollbars:     85  85 100  85
1916                         // Evergreen Mac without scrollbars: 100 100 100 100
1917         
1918                         // Get scrollbar width
1919                         browser.barWidth = outer[0].offsetWidth - outer[0].clientWidth;
1920         
1921                         // IE6/7 will oversize a width 100% element inside a scrolling element, to
1922                         // include the width of the scrollbar, while other browsers ensure the inner
1923                         // element is contained without forcing scrolling
1924                         browser.bScrollOversize = inner[0].offsetWidth === 100 && outer[0].clientWidth !== 100;
1925         
1926                         // In rtl text layout, some browsers (most, but not all) will place the
1927                         // scrollbar on the left, rather than the right.
1928                         browser.bScrollbarLeft = Math.round( inner.offset().left ) !== 1;
1929         
1930                         // IE8- don't provide height and width for getBoundingClientRect
1931                         browser.bBounding = n[0].getBoundingClientRect().width ? true : false;
1932         
1933                         n.remove();
1934                 }
1935         
1936                 $.extend( settings.oBrowser, DataTable.__browser );
1937                 settings.oScroll.iBarWidth = DataTable.__browser.barWidth;
1938         }
1939         
1940         
1941         /**
1942          * Array.prototype reduce[Right] method, used for browsers which don't support
1943          * JS 1.6. Done this way to reduce code size, since we iterate either way
1944          *  @param {object} settings dataTables settings object
1945          *  @memberof DataTable#oApi
1946          */
1947         function _fnReduce ( that, fn, init, start, end, inc )
1948         {
1949                 var
1950                         i = start,
1951                         value,
1952                         isSet = false;
1953         
1954                 if ( init !== undefined ) {
1955                         value = init;
1956                         isSet = true;
1957                 }
1958         
1959                 while ( i !== end ) {
1960                         if ( ! that.hasOwnProperty(i) ) {
1961                                 continue;
1962                         }
1963         
1964                         value = isSet ?
1965                                 fn( value, that[i], i, that ) :
1966                                 that[i];
1967         
1968                         isSet = true;
1969                         i += inc;
1970                 }
1971         
1972                 return value;
1973         }
1974         
1975         /**
1976          * Add a column to the list used for the table with default values
1977          *  @param {object} oSettings dataTables settings object
1978          *  @param {node} nTh The th element for this column
1979          *  @memberof DataTable#oApi
1980          */
1981         function _fnAddColumn( oSettings, nTh )
1982         {
1983                 // Add column to aoColumns array
1984                 var oDefaults = DataTable.defaults.column;
1985                 var iCol = oSettings.aoColumns.length;
1986                 var oCol = $.extend( {}, DataTable.models.oColumn, oDefaults, {
1987                         "nTh": nTh ? nTh : document.createElement('th'),
1988                         "sTitle":    oDefaults.sTitle    ? oDefaults.sTitle    : nTh ? nTh.innerHTML : '',
1989                         "aDataSort": oDefaults.aDataSort ? oDefaults.aDataSort : [iCol],
1990                         "mData": oDefaults.mData ? oDefaults.mData : iCol,
1991                         idx: iCol
1992                 } );
1993                 oSettings.aoColumns.push( oCol );
1994         
1995                 // Add search object for column specific search. Note that the `searchCols[ iCol ]`
1996                 // passed into extend can be undefined. This allows the user to give a default
1997                 // with only some of the parameters defined, and also not give a default
1998                 var searchCols = oSettings.aoPreSearchCols;
1999                 searchCols[ iCol ] = $.extend( {}, DataTable.models.oSearch, searchCols[ iCol ] );
2000         
2001                 // Use the default column options function to initialise classes etc
2002                 _fnColumnOptions( oSettings, iCol, $(nTh).data() );
2003         }
2004         
2005         
2006         /**
2007          * Apply options for a column
2008          *  @param {object} oSettings dataTables settings object
2009          *  @param {int} iCol column index to consider
2010          *  @param {object} oOptions object with sType, bVisible and bSearchable etc
2011          *  @memberof DataTable#oApi
2012          */
2013         function _fnColumnOptions( oSettings, iCol, oOptions )
2014         {
2015                 var oCol = oSettings.aoColumns[ iCol ];
2016                 var oClasses = oSettings.oClasses;
2017                 var th = $(oCol.nTh);
2018         
2019                 // Try to get width information from the DOM. We can't get it from CSS
2020                 // as we'd need to parse the CSS stylesheet. `width` option can override
2021                 if ( ! oCol.sWidthOrig ) {
2022                         // Width attribute
2023                         oCol.sWidthOrig = th.attr('width') || null;
2024         
2025                         // Style attribute
2026                         var t = (th.attr('style') || '').match(/width:\s*(\d+[pxem%]+)/);
2027                         if ( t ) {
2028                                 oCol.sWidthOrig = t[1];
2029                         }
2030                 }
2031         
2032                 /* User specified column options */
2033                 if ( oOptions !== undefined && oOptions !== null )
2034                 {
2035                         // Backwards compatibility
2036                         _fnCompatCols( oOptions );
2037         
2038                         // Map camel case parameters to their Hungarian counterparts
2039                         _fnCamelToHungarian( DataTable.defaults.column, oOptions, true );
2040         
2041                         /* Backwards compatibility for mDataProp */
2042                         if ( oOptions.mDataProp !== undefined && !oOptions.mData )
2043                         {
2044                                 oOptions.mData = oOptions.mDataProp;
2045                         }
2046         
2047                         if ( oOptions.sType )
2048                         {
2049                                 oCol._sManualType = oOptions.sType;
2050                         }
2051         
2052                         // `class` is a reserved word in Javascript, so we need to provide
2053                         // the ability to use a valid name for the camel case input
2054                         if ( oOptions.className && ! oOptions.sClass )
2055                         {
2056                                 oOptions.sClass = oOptions.className;
2057                         }
2058                         if ( oOptions.sClass ) {
2059                                 th.addClass( oOptions.sClass );
2060                         }
2061         
2062                         $.extend( oCol, oOptions );
2063                         _fnMap( oCol, oOptions, "sWidth", "sWidthOrig" );
2064         
2065                         /* iDataSort to be applied (backwards compatibility), but aDataSort will take
2066                          * priority if defined
2067                          */
2068                         if ( oOptions.iDataSort !== undefined )
2069                         {
2070                                 oCol.aDataSort = [ oOptions.iDataSort ];
2071                         }
2072                         _fnMap( oCol, oOptions, "aDataSort" );
2073                 }
2074         
2075                 /* Cache the data get and set functions for speed */
2076                 var mDataSrc = oCol.mData;
2077                 var mData = _fnGetObjectDataFn( mDataSrc );
2078                 var mRender = oCol.mRender ? _fnGetObjectDataFn( oCol.mRender ) : null;
2079         
2080                 var attrTest = function( src ) {
2081                         return typeof src === 'string' && src.indexOf('@') !== -1;
2082                 };
2083                 oCol._bAttrSrc = $.isPlainObject( mDataSrc ) && (
2084                         attrTest(mDataSrc.sort) || attrTest(mDataSrc.type) || attrTest(mDataSrc.filter)
2085                 );
2086                 oCol._setter = null;
2087         
2088                 oCol.fnGetData = function (rowData, type, meta) {
2089                         var innerData = mData( rowData, type, undefined, meta );
2090         
2091                         return mRender && type ?
2092                                 mRender( innerData, type, rowData, meta ) :
2093                                 innerData;
2094                 };
2095                 oCol.fnSetData = function ( rowData, val, meta ) {
2096                         return _fnSetObjectDataFn( mDataSrc )( rowData, val, meta );
2097                 };
2098         
2099                 // Indicate if DataTables should read DOM data as an object or array
2100                 // Used in _fnGetRowElements
2101                 if ( typeof mDataSrc !== 'number' ) {
2102                         oSettings._rowReadObject = true;
2103                 }
2104         
2105                 /* Feature sorting overrides column specific when off */
2106                 if ( !oSettings.oFeatures.bSort )
2107                 {
2108                         oCol.bSortable = false;
2109                         th.addClass( oClasses.sSortableNone ); // Have to add class here as order event isn't called
2110                 }
2111         
2112                 /* Check that the class assignment is correct for sorting */
2113                 var bAsc = $.inArray('asc', oCol.asSorting) !== -1;
2114                 var bDesc = $.inArray('desc', oCol.asSorting) !== -1;
2115                 if ( !oCol.bSortable || (!bAsc && !bDesc) )
2116                 {
2117                         oCol.sSortingClass = oClasses.sSortableNone;
2118                         oCol.sSortingClassJUI = "";
2119                 }
2120                 else if ( bAsc && !bDesc )
2121                 {
2122                         oCol.sSortingClass = oClasses.sSortableAsc;
2123                         oCol.sSortingClassJUI = oClasses.sSortJUIAscAllowed;
2124                 }
2125                 else if ( !bAsc && bDesc )
2126                 {
2127                         oCol.sSortingClass = oClasses.sSortableDesc;
2128                         oCol.sSortingClassJUI = oClasses.sSortJUIDescAllowed;
2129                 }
2130                 else
2131                 {
2132                         oCol.sSortingClass = oClasses.sSortable;
2133                         oCol.sSortingClassJUI = oClasses.sSortJUI;
2134                 }
2135         }
2136         
2137         
2138         /**
2139          * Adjust the table column widths for new data. Note: you would probably want to
2140          * do a redraw after calling this function!
2141          *  @param {object} settings dataTables settings object
2142          *  @memberof DataTable#oApi
2143          */
2144         function _fnAdjustColumnSizing ( settings )
2145         {
2146                 /* Not interested in doing column width calculation if auto-width is disabled */
2147                 if ( settings.oFeatures.bAutoWidth !== false )
2148                 {
2149                         var columns = settings.aoColumns;
2150         
2151                         _fnCalculateColumnWidths( settings );
2152                         for ( var i=0 , iLen=columns.length ; i<iLen ; i++ )
2153                         {
2154                                 columns[i].nTh.style.width = columns[i].sWidth;
2155                         }
2156                 }
2157         
2158                 var scroll = settings.oScroll;
2159                 if ( scroll.sY !== '' || scroll.sX !== '')
2160                 {
2161                         _fnScrollDraw( settings );
2162                 }
2163         
2164                 _fnCallbackFire( settings, null, 'column-sizing', [settings] );
2165         }
2166         
2167         
2168         /**
2169          * Covert the index of a visible column to the index in the data array (take account
2170          * of hidden columns)
2171          *  @param {object} oSettings dataTables settings object
2172          *  @param {int} iMatch Visible column index to lookup
2173          *  @returns {int} i the data index
2174          *  @memberof DataTable#oApi
2175          */
2176         function _fnVisibleToColumnIndex( oSettings, iMatch )
2177         {
2178                 var aiVis = _fnGetColumns( oSettings, 'bVisible' );
2179         
2180                 return typeof aiVis[iMatch] === 'number' ?
2181                         aiVis[iMatch] :
2182                         null;
2183         }
2184         
2185         
2186         /**
2187          * Covert the index of an index in the data array and convert it to the visible
2188          *   column index (take account of hidden columns)
2189          *  @param {int} iMatch Column index to lookup
2190          *  @param {object} oSettings dataTables settings object
2191          *  @returns {int} i the data index
2192          *  @memberof DataTable#oApi
2193          */
2194         function _fnColumnIndexToVisible( oSettings, iMatch )
2195         {
2196                 var aiVis = _fnGetColumns( oSettings, 'bVisible' );
2197                 var iPos = $.inArray( iMatch, aiVis );
2198         
2199                 return iPos !== -1 ? iPos : null;
2200         }
2201         
2202         
2203         /**
2204          * Get the number of visible columns
2205          *  @param {object} oSettings dataTables settings object
2206          *  @returns {int} i the number of visible columns
2207          *  @memberof DataTable#oApi
2208          */
2209         function _fnVisbleColumns( oSettings )
2210         {
2211                 var vis = 0;
2212         
2213                 // No reduce in IE8, use a loop for now
2214                 $.each( oSettings.aoColumns, function ( i, col ) {
2215                         if ( col.bVisible && $(col.nTh).css('display') !== 'none' ) {
2216                                 vis++;
2217                         }
2218                 } );
2219         
2220                 return vis;
2221         }
2222         
2223         
2224         /**
2225          * Get an array of column indexes that match a given property
2226          *  @param {object} oSettings dataTables settings object
2227          *  @param {string} sParam Parameter in aoColumns to look for - typically
2228          *    bVisible or bSearchable
2229          *  @returns {array} Array of indexes with matched properties
2230          *  @memberof DataTable#oApi
2231          */
2232         function _fnGetColumns( oSettings, sParam )
2233         {
2234                 var a = [];
2235         
2236                 $.map( oSettings.aoColumns, function(val, i) {
2237                         if ( val[sParam] ) {
2238                                 a.push( i );
2239                         }
2240                 } );
2241         
2242                 return a;
2243         }
2244         
2245         
2246         /**
2247          * Calculate the 'type' of a column
2248          *  @param {object} settings dataTables settings object
2249          *  @memberof DataTable#oApi
2250          */
2251         function _fnColumnTypes ( settings )
2252         {
2253                 var columns = settings.aoColumns;
2254                 var data = settings.aoData;
2255                 var types = DataTable.ext.type.detect;
2256                 var i, ien, j, jen, k, ken;
2257                 var col, cell, detectedType, cache;
2258         
2259                 // For each column, spin over the 
2260                 for ( i=0, ien=columns.length ; i<ien ; i++ ) {
2261                         col = columns[i];
2262                         cache = [];
2263         
2264                         if ( ! col.sType && col._sManualType ) {
2265                                 col.sType = col._sManualType;
2266                         }
2267                         else if ( ! col.sType ) {
2268                                 for ( j=0, jen=types.length ; j<jen ; j++ ) {
2269                                         for ( k=0, ken=data.length ; k<ken ; k++ ) {
2270                                                 // Use a cache array so we only need to get the type data
2271                                                 // from the formatter once (when using multiple detectors)
2272                                                 if ( cache[k] === undefined ) {
2273                                                         cache[k] = _fnGetCellData( settings, k, i, 'type' );
2274                                                 }
2275         
2276                                                 detectedType = types[j]( cache[k], settings );
2277         
2278                                                 // If null, then this type can't apply to this column, so
2279                                                 // rather than testing all cells, break out. There is an
2280                                                 // exception for the last type which is `html`. We need to
2281                                                 // scan all rows since it is possible to mix string and HTML
2282                                                 // types
2283                                                 if ( ! detectedType && j !== types.length-1 ) {
2284                                                         break;
2285                                                 }
2286         
2287                                                 // Only a single match is needed for html type since it is
2288                                                 // bottom of the pile and very similar to string
2289                                                 if ( detectedType === 'html' ) {
2290                                                         break;
2291                                                 }
2292                                         }
2293         
2294                                         // Type is valid for all data points in the column - use this
2295                                         // type
2296                                         if ( detectedType ) {
2297                                                 col.sType = detectedType;
2298                                                 break;
2299                                         }
2300                                 }
2301         
2302                                 // Fall back - if no type was detected, always use string
2303                                 if ( ! col.sType ) {
2304                                         col.sType = 'string';
2305                                 }
2306                         }
2307                 }
2308         }
2309         
2310         
2311         /**
2312          * Take the column definitions and static columns arrays and calculate how
2313          * they relate to column indexes. The callback function will then apply the
2314          * definition found for a column to a suitable configuration object.
2315          *  @param {object} oSettings dataTables settings object
2316          *  @param {array} aoColDefs The aoColumnDefs array that is to be applied
2317          *  @param {array} aoCols The aoColumns array that defines columns individually
2318          *  @param {function} fn Callback function - takes two parameters, the calculated
2319          *    column index and the definition for that column.
2320          *  @memberof DataTable#oApi
2321          */
2322         function _fnApplyColumnDefs( oSettings, aoColDefs, aoCols, fn )
2323         {
2324                 var i, iLen, j, jLen, k, kLen, def;
2325                 var columns = oSettings.aoColumns;
2326         
2327                 // Column definitions with aTargets
2328                 if ( aoColDefs )
2329                 {
2330                         /* Loop over the definitions array - loop in reverse so first instance has priority */
2331                         for ( i=aoColDefs.length-1 ; i>=0 ; i-- )
2332                         {
2333                                 def = aoColDefs[i];
2334         
2335                                 /* Each definition can target multiple columns, as it is an array */
2336                                 var aTargets = def.targets !== undefined ?
2337                                         def.targets :
2338                                         def.aTargets;
2339         
2340                                 if ( ! $.isArray( aTargets ) )
2341                                 {
2342                                         aTargets = [ aTargets ];
2343                                 }
2344         
2345                                 for ( j=0, jLen=aTargets.length ; j<jLen ; j++ )
2346                                 {
2347                                         if ( typeof aTargets[j] === 'number' && aTargets[j] >= 0 )
2348                                         {
2349                                                 /* Add columns that we don't yet know about */
2350                                                 while( columns.length <= aTargets[j] )
2351                                                 {
2352                                                         _fnAddColumn( oSettings );
2353                                                 }
2354         
2355                                                 /* Integer, basic index */
2356                                                 fn( aTargets[j], def );
2357                                         }
2358                                         else if ( typeof aTargets[j] === 'number' && aTargets[j] < 0 )
2359                                         {
2360                                                 /* Negative integer, right to left column counting */
2361                                                 fn( columns.length+aTargets[j], def );
2362                                         }
2363                                         else if ( typeof aTargets[j] === 'string' )
2364                                         {
2365                                                 /* Class name matching on TH element */
2366                                                 for ( k=0, kLen=columns.length ; k<kLen ; k++ )
2367                                                 {
2368                                                         if ( aTargets[j] == "_all" ||
2369                                                              $(columns[k].nTh).hasClass( aTargets[j] ) )
2370                                                         {
2371                                                                 fn( k, def );
2372                                                         }
2373                                                 }
2374                                         }
2375                                 }
2376                         }
2377                 }
2378         
2379                 // Statically defined columns array
2380                 if ( aoCols )
2381                 {
2382                         for ( i=0, iLen=aoCols.length ; i<iLen ; i++ )
2383                         {
2384                                 fn( i, aoCols[i] );
2385                         }
2386                 }
2387         }
2388         
2389         /**
2390          * Add a data array to the table, creating DOM node etc. This is the parallel to
2391          * _fnGatherData, but for adding rows from a Javascript source, rather than a
2392          * DOM source.
2393          *  @param {object} oSettings dataTables settings object
2394          *  @param {array} aData data array to be added
2395          *  @param {node} [nTr] TR element to add to the table - optional. If not given,
2396          *    DataTables will create a row automatically
2397          *  @param {array} [anTds] Array of TD|TH elements for the row - must be given
2398          *    if nTr is.
2399          *  @returns {int} >=0 if successful (index of new aoData entry), -1 if failed
2400          *  @memberof DataTable#oApi
2401          */
2402         function _fnAddData ( oSettings, aDataIn, nTr, anTds )
2403         {
2404                 /* Create the object for storing information about this new row */
2405                 var iRow = oSettings.aoData.length;
2406                 var oData = $.extend( true, {}, DataTable.models.oRow, {
2407                         src: nTr ? 'dom' : 'data',
2408                         idx: iRow
2409                 } );
2410         
2411                 oData._aData = aDataIn;
2412                 oSettings.aoData.push( oData );
2413         
2414                 /* Create the cells */
2415                 var nTd, sThisType;
2416                 var columns = oSettings.aoColumns;
2417         
2418                 // Invalidate the column types as the new data needs to be revalidated
2419                 for ( var i=0, iLen=columns.length ; i<iLen ; i++ )
2420                 {
2421                         columns[i].sType = null;
2422                 }
2423         
2424                 /* Add to the display array */
2425                 oSettings.aiDisplayMaster.push( iRow );
2426         
2427                 var id = oSettings.rowIdFn( aDataIn );
2428                 if ( id !== undefined ) {
2429                         oSettings.aIds[ id ] = oData;
2430                 }
2431         
2432                 /* Create the DOM information, or register it if already present */
2433                 if ( nTr || ! oSettings.oFeatures.bDeferRender )
2434                 {
2435                         _fnCreateTr( oSettings, iRow, nTr, anTds );
2436                 }
2437         
2438                 return iRow;
2439         }
2440         
2441         
2442         /**
2443          * Add one or more TR elements to the table. Generally we'd expect to
2444          * use this for reading data from a DOM sourced table, but it could be
2445          * used for an TR element. Note that if a TR is given, it is used (i.e.
2446          * it is not cloned).
2447          *  @param {object} settings dataTables settings object
2448          *  @param {array|node|jQuery} trs The TR element(s) to add to the table
2449          *  @returns {array} Array of indexes for the added rows
2450          *  @memberof DataTable#oApi
2451          */
2452         function _fnAddTr( settings, trs )
2453         {
2454                 var row;
2455         
2456                 // Allow an individual node to be passed in
2457                 if ( ! (trs instanceof $) ) {
2458                         trs = $(trs);
2459                 }
2460         
2461                 return trs.map( function (i, el) {
2462                         row = _fnGetRowElements( settings, el );
2463                         return _fnAddData( settings, row.data, el, row.cells );
2464                 } );
2465         }
2466         
2467         
2468         /**
2469          * Take a TR element and convert it to an index in aoData
2470          *  @param {object} oSettings dataTables settings object
2471          *  @param {node} n the TR element to find
2472          *  @returns {int} index if the node is found, null if not
2473          *  @memberof DataTable#oApi
2474          */
2475         function _fnNodeToDataIndex( oSettings, n )
2476         {
2477                 return (n._DT_RowIndex!==undefined) ? n._DT_RowIndex : null;
2478         }
2479         
2480         
2481         /**
2482          * Take a TD element and convert it into a column data index (not the visible index)
2483          *  @param {object} oSettings dataTables settings object
2484          *  @param {int} iRow The row number the TD/TH can be found in
2485          *  @param {node} n The TD/TH element to find
2486          *  @returns {int} index if the node is found, -1 if not
2487          *  @memberof DataTable#oApi
2488          */
2489         function _fnNodeToColumnIndex( oSettings, iRow, n )
2490         {
2491                 return $.inArray( n, oSettings.aoData[ iRow ].anCells );
2492         }
2493         
2494         
2495         /**
2496          * Get the data for a given cell from the internal cache, taking into account data mapping
2497          *  @param {object} settings dataTables settings object
2498          *  @param {int} rowIdx aoData row id
2499          *  @param {int} colIdx Column index
2500          *  @param {string} type data get type ('display', 'type' 'filter' 'sort')
2501          *  @returns {*} Cell data
2502          *  @memberof DataTable#oApi
2503          */
2504         function _fnGetCellData( settings, rowIdx, colIdx, type )
2505         {
2506                 var draw           = settings.iDraw;
2507                 var col            = settings.aoColumns[colIdx];
2508                 var rowData        = settings.aoData[rowIdx]._aData;
2509                 var defaultContent = col.sDefaultContent;
2510                 var cellData       = col.fnGetData( rowData, type, {
2511                         settings: settings,
2512                         row:      rowIdx,
2513                         col:      colIdx
2514                 } );
2515         
2516                 if ( cellData === undefined ) {
2517                         if ( settings.iDrawError != draw && defaultContent === null ) {
2518                                 _fnLog( settings, 0, "Requested unknown parameter "+
2519                                         (typeof col.mData=='function' ? '{function}' : "'"+col.mData+"'")+
2520                                         " for row "+rowIdx+", column "+colIdx, 4 );
2521                                 settings.iDrawError = draw;
2522                         }
2523                         return defaultContent;
2524                 }
2525         
2526                 // When the data source is null and a specific data type is requested (i.e.
2527                 // not the original data), we can use default column data
2528                 if ( (cellData === rowData || cellData === null) && defaultContent !== null && type !== undefined ) {
2529                         cellData = defaultContent;
2530                 }
2531                 else if ( typeof cellData === 'function' ) {
2532                         // If the data source is a function, then we run it and use the return,
2533                         // executing in the scope of the data object (for instances)
2534                         return cellData.call( rowData );
2535                 }
2536         
2537                 if ( cellData === null && type == 'display' ) {
2538                         return '';
2539                 }
2540                 return cellData;
2541         }
2542         
2543         
2544         /**
2545          * Set the value for a specific cell, into the internal data cache
2546          *  @param {object} settings dataTables settings object
2547          *  @param {int} rowIdx aoData row id
2548          *  @param {int} colIdx Column index
2549          *  @param {*} val Value to set
2550          *  @memberof DataTable#oApi
2551          */
2552         function _fnSetCellData( settings, rowIdx, colIdx, val )
2553         {
2554                 var col     = settings.aoColumns[colIdx];
2555                 var rowData = settings.aoData[rowIdx]._aData;
2556         
2557                 col.fnSetData( rowData, val, {
2558                         settings: settings,
2559                         row:      rowIdx,
2560                         col:      colIdx
2561                 }  );
2562         }
2563         
2564         
2565         // Private variable that is used to match action syntax in the data property object
2566         var __reArray = /\[.*?\]$/;
2567         var __reFn = /\(\)$/;
2568         
2569         /**
2570          * Split string on periods, taking into account escaped periods
2571          * @param  {string} str String to split
2572          * @return {array} Split string
2573          */
2574         function _fnSplitObjNotation( str )
2575         {
2576                 return $.map( str.match(/(\\.|[^\.])+/g) || [''], function ( s ) {
2577                         return s.replace(/\\\./g, '.');
2578                 } );
2579         }
2580         
2581         
2582         /**
2583          * Return a function that can be used to get data from a source object, taking
2584          * into account the ability to use nested objects as a source
2585          *  @param {string|int|function} mSource The data source for the object
2586          *  @returns {function} Data get function
2587          *  @memberof DataTable#oApi
2588          */
2589         function _fnGetObjectDataFn( mSource )
2590         {
2591                 if ( $.isPlainObject( mSource ) )
2592                 {
2593                         /* Build an object of get functions, and wrap them in a single call */
2594                         var o = {};
2595                         $.each( mSource, function (key, val) {
2596                                 if ( val ) {
2597                                         o[key] = _fnGetObjectDataFn( val );
2598                                 }
2599                         } );
2600         
2601                         return function (data, type, row, meta) {
2602                                 var t = o[type] || o._;
2603                                 return t !== undefined ?
2604                                         t(data, type, row, meta) :
2605                                         data;
2606                         };
2607                 }
2608                 else if ( mSource === null )
2609                 {
2610                         /* Give an empty string for rendering / sorting etc */
2611                         return function (data) { // type, row and meta also passed, but not used
2612                                 return data;
2613                         };
2614                 }
2615                 else if ( typeof mSource === 'function' )
2616                 {
2617                         return function (data, type, row, meta) {
2618                                 return mSource( data, type, row, meta );
2619                         };
2620                 }
2621                 else if ( typeof mSource === 'string' && (mSource.indexOf('.') !== -1 ||
2622                               mSource.indexOf('[') !== -1 || mSource.indexOf('(') !== -1) )
2623                 {
2624                         /* If there is a . in the source string then the data source is in a
2625                          * nested object so we loop over the data for each level to get the next
2626                          * level down. On each loop we test for undefined, and if found immediately
2627                          * return. This allows entire objects to be missing and sDefaultContent to
2628                          * be used if defined, rather than throwing an error
2629                          */
2630                         var fetchData = function (data, type, src) {
2631                                 var arrayNotation, funcNotation, out, innerSrc;
2632         
2633                                 if ( src !== "" )
2634                                 {
2635                                         var a = _fnSplitObjNotation( src );
2636         
2637                                         for ( var i=0, iLen=a.length ; i<iLen ; i++ )
2638                                         {
2639                                                 // Check if we are dealing with special notation
2640                                                 arrayNotation = a[i].match(__reArray);
2641                                                 funcNotation = a[i].match(__reFn);
2642         
2643                                                 if ( arrayNotation )
2644                                                 {
2645                                                         // Array notation
2646                                                         a[i] = a[i].replace(__reArray, '');
2647         
2648                                                         // Condition allows simply [] to be passed in
2649                                                         if ( a[i] !== "" ) {
2650                                                                 data = data[ a[i] ];
2651                                                         }
2652                                                         out = [];
2653         
2654                                                         // Get the remainder of the nested object to get
2655                                                         a.splice( 0, i+1 );
2656                                                         innerSrc = a.join('.');
2657         
2658                                                         // Traverse each entry in the array getting the properties requested
2659                                                         if ( $.isArray( data ) ) {
2660                                                                 for ( var j=0, jLen=data.length ; j<jLen ; j++ ) {
2661                                                                         out.push( fetchData( data[j], type, innerSrc ) );
2662                                                                 }
2663                                                         }
2664         
2665                                                         // If a string is given in between the array notation indicators, that
2666                                                         // is used to join the strings together, otherwise an array is returned
2667                                                         var join = arrayNotation[0].substring(1, arrayNotation[0].length-1);
2668                                                         data = (join==="") ? out : out.join(join);
2669         
2670                                                         // The inner call to fetchData has already traversed through the remainder
2671                                                         // of the source requested, so we exit from the loop
2672                                                         break;
2673                                                 }
2674                                                 else if ( funcNotation )
2675                                                 {
2676                                                         // Function call
2677                                                         a[i] = a[i].replace(__reFn, '');
2678                                                         data = data[ a[i] ]();
2679                                                         continue;
2680                                                 }
2681         
2682                                                 if ( data === null || data[ a[i] ] === undefined )
2683                                                 {
2684                                                         return undefined;
2685                                                 }
2686                                                 data = data[ a[i] ];
2687                                         }
2688                                 }
2689         
2690                                 return data;
2691                         };
2692         
2693                         return function (data, type) { // row and meta also passed, but not used
2694                                 return fetchData( data, type, mSource );
2695                         };
2696                 }
2697                 else
2698                 {
2699                         /* Array or flat object mapping */
2700                         return function (data, type) { // row and meta also passed, but not used
2701                                 return data[mSource];
2702                         };
2703                 }
2704         }
2705         
2706         
2707         /**
2708          * Return a function that can be used to set data from a source object, taking
2709          * into account the ability to use nested objects as a source
2710          *  @param {string|int|function} mSource The data source for the object
2711          *  @returns {function} Data set function
2712          *  @memberof DataTable#oApi
2713          */
2714         function _fnSetObjectDataFn( mSource )
2715         {
2716                 if ( $.isPlainObject( mSource ) )
2717                 {
2718                         /* Unlike get, only the underscore (global) option is used for for
2719                          * setting data since we don't know the type here. This is why an object
2720                          * option is not documented for `mData` (which is read/write), but it is
2721                          * for `mRender` which is read only.
2722                          */
2723                         return _fnSetObjectDataFn( mSource._ );
2724                 }
2725                 else if ( mSource === null )
2726                 {
2727                         /* Nothing to do when the data source is null */
2728                         return function () {};
2729                 }
2730                 else if ( typeof mSource === 'function' )
2731                 {
2732                         return function (data, val, meta) {
2733                                 mSource( data, 'set', val, meta );
2734                         };
2735                 }
2736                 else if ( typeof mSource === 'string' && (mSource.indexOf('.') !== -1 ||
2737                               mSource.indexOf('[') !== -1 || mSource.indexOf('(') !== -1) )
2738                 {
2739                         /* Like the get, we need to get data from a nested object */
2740                         var setData = function (data, val, src) {
2741                                 var a = _fnSplitObjNotation( src ), b;
2742                                 var aLast = a[a.length-1];
2743                                 var arrayNotation, funcNotation, o, innerSrc;
2744         
2745                                 for ( var i=0, iLen=a.length-1 ; i<iLen ; i++ )
2746                                 {
2747                                         // Check if we are dealing with an array notation request
2748                                         arrayNotation = a[i].match(__reArray);
2749                                         funcNotation = a[i].match(__reFn);
2750         
2751                                         if ( arrayNotation )
2752                                         {
2753                                                 a[i] = a[i].replace(__reArray, '');
2754                                                 data[ a[i] ] = [];
2755         
2756                                                 // Get the remainder of the nested object to set so we can recurse
2757                                                 b = a.slice();
2758                                                 b.splice( 0, i+1 );
2759                                                 innerSrc = b.join('.');
2760         
2761                                                 // Traverse each entry in the array setting the properties requested
2762                                                 if ( $.isArray( val ) )
2763                                                 {
2764                                                         for ( var j=0, jLen=val.length ; j<jLen ; j++ )
2765                                                         {
2766                                                                 o = {};
2767                                                                 setData( o, val[j], innerSrc );
2768                                                                 data[ a[i] ].push( o );
2769                                                         }
2770                                                 }
2771                                                 else
2772                                                 {
2773                                                         // We've been asked to save data to an array, but it
2774                                                         // isn't array data to be saved. Best that can be done
2775                                                         // is to just save the value.
2776                                                         data[ a[i] ] = val;
2777                                                 }
2778         
2779                                                 // The inner call to setData has already traversed through the remainder
2780                                                 // of the source and has set the data, thus we can exit here
2781                                                 return;
2782                                         }
2783                                         else if ( funcNotation )
2784                                         {
2785                                                 // Function call
2786                                                 a[i] = a[i].replace(__reFn, '');
2787                                                 data = data[ a[i] ]( val );
2788                                         }
2789         
2790                                         // If the nested object doesn't currently exist - since we are
2791                                         // trying to set the value - create it
2792                                         if ( data[ a[i] ] === null || data[ a[i] ] === undefined )
2793                                         {
2794                                                 data[ a[i] ] = {};
2795                                         }
2796                                         data = data[ a[i] ];
2797                                 }
2798         
2799                                 // Last item in the input - i.e, the actual set
2800                                 if ( aLast.match(__reFn ) )
2801                                 {
2802                                         // Function call
2803                                         data = data[ aLast.replace(__reFn, '') ]( val );
2804                                 }
2805                                 else
2806                                 {
2807                                         // If array notation is used, we just want to strip it and use the property name
2808                                         // and assign the value. If it isn't used, then we get the result we want anyway
2809                                         data[ aLast.replace(__reArray, '') ] = val;
2810                                 }
2811                         };
2812         
2813                         return function (data, val) { // meta is also passed in, but not used
2814                                 return setData( data, val, mSource );
2815                         };
2816                 }
2817                 else
2818                 {
2819                         /* Array or flat object mapping */
2820                         return function (data, val) { // meta is also passed in, but not used
2821                                 data[mSource] = val;
2822                         };
2823                 }
2824         }
2825         
2826         
2827         /**
2828          * Return an array with the full table data
2829          *  @param {object} oSettings dataTables settings object
2830          *  @returns array {array} aData Master data array
2831          *  @memberof DataTable#oApi
2832          */
2833         function _fnGetDataMaster ( settings )
2834         {
2835                 return _pluck( settings.aoData, '_aData' );
2836         }
2837         
2838         
2839         /**
2840          * Nuke the table
2841          *  @param {object} oSettings dataTables settings object
2842          *  @memberof DataTable#oApi
2843          */
2844         function _fnClearTable( settings )
2845         {
2846                 settings.aoData.length = 0;
2847                 settings.aiDisplayMaster.length = 0;
2848                 settings.aiDisplay.length = 0;
2849                 settings.aIds = {};
2850         }
2851         
2852         
2853          /**
2854          * Take an array of integers (index array) and remove a target integer (value - not
2855          * the key!)
2856          *  @param {array} a Index array to target
2857          *  @param {int} iTarget value to find
2858          *  @memberof DataTable#oApi
2859          */
2860         function _fnDeleteIndex( a, iTarget, splice )
2861         {
2862                 var iTargetIndex = -1;
2863         
2864                 for ( var i=0, iLen=a.length ; i<iLen ; i++ )
2865                 {
2866                         if ( a[i] == iTarget )
2867                         {
2868                                 iTargetIndex = i;
2869                         }
2870                         else if ( a[i] > iTarget )
2871                         {
2872                                 a[i]--;
2873                         }
2874                 }
2875         
2876                 if ( iTargetIndex != -1 && splice === undefined )
2877                 {
2878                         a.splice( iTargetIndex, 1 );
2879                 }
2880         }
2881         
2882         
2883         /**
2884          * Mark cached data as invalid such that a re-read of the data will occur when
2885          * the cached data is next requested. Also update from the data source object.
2886          *
2887          * @param {object} settings DataTables settings object
2888          * @param {int}    rowIdx   Row index to invalidate
2889          * @param {string} [src]    Source to invalidate from: undefined, 'auto', 'dom'
2890          *     or 'data'
2891          * @param {int}    [colIdx] Column index to invalidate. If undefined the whole
2892          *     row will be invalidated
2893          * @memberof DataTable#oApi
2894          *
2895          * @todo For the modularisation of v1.11 this will need to become a callback, so
2896          *   the sort and filter methods can subscribe to it. That will required
2897          *   initialisation options for sorting, which is why it is not already baked in
2898          */
2899         function _fnInvalidate( settings, rowIdx, src, colIdx )
2900         {
2901                 var row = settings.aoData[ rowIdx ];
2902                 var i, ien;
2903                 var cellWrite = function ( cell, col ) {
2904                         // This is very frustrating, but in IE if you just write directly
2905                         // to innerHTML, and elements that are overwritten are GC'ed,
2906                         // even if there is a reference to them elsewhere
2907                         while ( cell.childNodes.length ) {
2908                                 cell.removeChild( cell.firstChild );
2909                         }
2910         
2911                         cell.innerHTML = _fnGetCellData( settings, rowIdx, col, 'display' );
2912                 };
2913         
2914                 // Are we reading last data from DOM or the data object?
2915                 if ( src === 'dom' || ((! src || src === 'auto') && row.src === 'dom') ) {
2916                         // Read the data from the DOM
2917                         row._aData = _fnGetRowElements(
2918                                         settings, row, colIdx, colIdx === undefined ? undefined : row._aData
2919                                 )
2920                                 .data;
2921                 }
2922                 else {
2923                         // Reading from data object, update the DOM
2924                         var cells = row.anCells;
2925         
2926                         if ( cells ) {
2927                                 if ( colIdx !== undefined ) {
2928                                         cellWrite( cells[colIdx], colIdx );
2929                                 }
2930                                 else {
2931                                         for ( i=0, ien=cells.length ; i<ien ; i++ ) {
2932                                                 cellWrite( cells[i], i );
2933                                         }
2934                                 }
2935                         }
2936                 }
2937         
2938                 // For both row and cell invalidation, the cached data for sorting and
2939                 // filtering is nulled out
2940                 row._aSortData = null;
2941                 row._aFilterData = null;
2942         
2943                 // Invalidate the type for a specific column (if given) or all columns since
2944                 // the data might have changed
2945                 var cols = settings.aoColumns;
2946                 if ( colIdx !== undefined ) {
2947                         cols[ colIdx ].sType = null;
2948                 }
2949                 else {
2950                         for ( i=0, ien=cols.length ; i<ien ; i++ ) {
2951                                 cols[i].sType = null;
2952                         }
2953         
2954                         // Update DataTables special `DT_*` attributes for the row
2955                         _fnRowAttributes( settings, row );
2956                 }
2957         }
2958         
2959         
2960         /**
2961          * Build a data source object from an HTML row, reading the contents of the
2962          * cells that are in the row.
2963          *
2964          * @param {object} settings DataTables settings object
2965          * @param {node|object} TR element from which to read data or existing row
2966          *   object from which to re-read the data from the cells
2967          * @param {int} [colIdx] Optional column index
2968          * @param {array|object} [d] Data source object. If `colIdx` is given then this
2969          *   parameter should also be given and will be used to write the data into.
2970          *   Only the column in question will be written
2971          * @returns {object} Object with two parameters: `data` the data read, in
2972          *   document order, and `cells` and array of nodes (they can be useful to the
2973          *   caller, so rather than needing a second traversal to get them, just return
2974          *   them from here).
2975          * @memberof DataTable#oApi
2976          */
2977         function _fnGetRowElements( settings, row, colIdx, d )
2978         {
2979                 var
2980                         tds = [],
2981                         td = row.firstChild,
2982                         name, col, o, i=0, contents,
2983                         columns = settings.aoColumns,
2984                         objectRead = settings._rowReadObject;
2985         
2986                 // Allow the data object to be passed in, or construct
2987                 d = d !== undefined ?
2988                         d :
2989                         objectRead ?
2990                                 {} :
2991                                 [];
2992         
2993                 var attr = function ( str, td  ) {
2994                         if ( typeof str === 'string' ) {
2995                                 var idx = str.indexOf('@');
2996         
2997                                 if ( idx !== -1 ) {
2998                                         var attr = str.substring( idx+1 );
2999                                         var setter = _fnSetObjectDataFn( str );
3000                                         setter( d, td.getAttribute( attr ) );
3001                                 }
3002                         }
3003                 };
3004         
3005                 // Read data from a cell and store into the data object
3006                 var cellProcess = function ( cell ) {
3007                         if ( colIdx === undefined || colIdx === i ) {
3008                                 col = columns[i];
3009                                 contents = $.trim(cell.innerHTML);
3010         
3011                                 if ( col && col._bAttrSrc ) {
3012                                         var setter = _fnSetObjectDataFn( col.mData._ );
3013                                         setter( d, contents );
3014         
3015                                         attr( col.mData.sort, cell );
3016                                         attr( col.mData.type, cell );
3017                                         attr( col.mData.filter, cell );
3018                                 }
3019                                 else {
3020                                         // Depending on the `data` option for the columns the data can
3021                                         // be read to either an object or an array.
3022                                         if ( objectRead ) {
3023                                                 if ( ! col._setter ) {
3024                                                         // Cache the setter function
3025                                                         col._setter = _fnSetObjectDataFn( col.mData );
3026                                                 }
3027                                                 col._setter( d, contents );
3028                                         }
3029                                         else {
3030                                                 d[i] = contents;
3031                                         }
3032                                 }
3033                         }
3034         
3035                         i++;
3036                 };
3037         
3038                 if ( td ) {
3039                         // `tr` element was passed in
3040                         while ( td ) {
3041                                 name = td.nodeName.toUpperCase();
3042         
3043                                 if ( name == "TD" || name == "TH" ) {
3044                                         cellProcess( td );
3045                                         tds.push( td );
3046                                 }
3047         
3048                                 td = td.nextSibling;
3049                         }
3050                 }
3051                 else {
3052                         // Existing row object passed in
3053                         tds = row.anCells;
3054         
3055                         for ( var j=0, jen=tds.length ; j<jen ; j++ ) {
3056                                 cellProcess( tds[j] );
3057                         }
3058                 }
3059         
3060                 // Read the ID from the DOM if present
3061                 var rowNode = row.firstChild ? row : row.nTr;
3062         
3063                 if ( rowNode ) {
3064                         var id = rowNode.getAttribute( 'id' );
3065         
3066                         if ( id ) {
3067                                 _fnSetObjectDataFn( settings.rowId )( d, id );
3068                         }
3069                 }
3070         
3071                 return {
3072                         data: d,
3073                         cells: tds
3074                 };
3075         }
3076         /**
3077          * Create a new TR element (and it's TD children) for a row
3078          *  @param {object} oSettings dataTables settings object
3079          *  @param {int} iRow Row to consider
3080          *  @param {node} [nTrIn] TR element to add to the table - optional. If not given,
3081          *    DataTables will create a row automatically
3082          *  @param {array} [anTds] Array of TD|TH elements for the row - must be given
3083          *    if nTr is.
3084          *  @memberof DataTable#oApi
3085          */
3086         function _fnCreateTr ( oSettings, iRow, nTrIn, anTds )
3087         {
3088                 var
3089                         row = oSettings.aoData[iRow],
3090                         rowData = row._aData,
3091                         cells = [],
3092                         nTr, nTd, oCol,
3093                         i, iLen, create;
3094         
3095                 if ( row.nTr === null )
3096                 {
3097                         nTr = nTrIn || document.createElement('tr');
3098         
3099                         row.nTr = nTr;
3100                         row.anCells = cells;
3101         
3102                         /* Use a private property on the node to allow reserve mapping from the node
3103                          * to the aoData array for fast look up
3104                          */
3105                         nTr._DT_RowIndex = iRow;
3106         
3107                         /* Special parameters can be given by the data source to be used on the row */
3108                         _fnRowAttributes( oSettings, row );
3109         
3110                         /* Process each column */
3111                         for ( i=0, iLen=oSettings.aoColumns.length ; i<iLen ; i++ )
3112                         {
3113                                 oCol = oSettings.aoColumns[i];
3114                                 create = nTrIn ? false : true;
3115         
3116                                 nTd = create ? document.createElement( oCol.sCellType ) : anTds[i];
3117                                 nTd._DT_CellIndex = {
3118                                         row: iRow,
3119                                         column: i
3120                                 };
3121                                 
3122                                 cells.push( nTd );
3123         
3124                                 // Need to create the HTML if new, or if a rendering function is defined
3125                                 if ( create || ((!nTrIn || oCol.mRender || oCol.mData !== i) &&
3126                                          (!$.isPlainObject(oCol.mData) || oCol.mData._ !== i+'.display')
3127                                 )) {
3128                                         nTd.innerHTML = _fnGetCellData( oSettings, iRow, i, 'display' );
3129                                 }
3130         
3131                                 /* Add user defined class */
3132                                 if ( oCol.sClass )
3133                                 {
3134                                         nTd.className += ' '+oCol.sClass;
3135                                 }
3136         
3137                                 // Visibility - add or remove as required
3138                                 if ( oCol.bVisible && ! nTrIn )
3139                                 {
3140                                         nTr.appendChild( nTd );
3141                                 }
3142                                 else if ( ! oCol.bVisible && nTrIn )
3143                                 {
3144                                         nTd.parentNode.removeChild( nTd );
3145                                 }
3146         
3147                                 if ( oCol.fnCreatedCell )
3148                                 {
3149                                         oCol.fnCreatedCell.call( oSettings.oInstance,
3150                                                 nTd, _fnGetCellData( oSettings, iRow, i ), rowData, iRow, i
3151                                         );
3152                                 }
3153                         }
3154         
3155                         _fnCallbackFire( oSettings, 'aoRowCreatedCallback', null, [nTr, rowData, iRow, cells] );
3156                 }
3157         
3158                 // Remove once webkit bug 131819 and Chromium bug 365619 have been resolved
3159                 // and deployed
3160                 row.nTr.setAttribute( 'role', 'row' );
3161         }
3162         
3163         
3164         /**
3165          * Add attributes to a row based on the special `DT_*` parameters in a data
3166          * source object.
3167          *  @param {object} settings DataTables settings object
3168          *  @param {object} DataTables row object for the row to be modified
3169          *  @memberof DataTable#oApi
3170          */
3171         function _fnRowAttributes( settings, row )
3172         {
3173                 var tr = row.nTr;
3174                 var data = row._aData;
3175         
3176                 if ( tr ) {
3177                         var id = settings.rowIdFn( data );
3178         
3179                         if ( id ) {
3180                                 tr.id = id;
3181                         }
3182         
3183                         if ( data.DT_RowClass ) {
3184                                 // Remove any classes added by DT_RowClass before
3185                                 var a = data.DT_RowClass.split(' ');
3186                                 row.__rowc = row.__rowc ?
3187                                         _unique( row.__rowc.concat( a ) ) :
3188                                         a;
3189         
3190                                 $(tr)
3191                                         .removeClass( row.__rowc.join(' ') )
3192                                         .addClass( data.DT_RowClass );
3193                         }
3194         
3195                         if ( data.DT_RowAttr ) {
3196                                 $(tr).attr( data.DT_RowAttr );
3197                         }
3198         
3199                         if ( data.DT_RowData ) {
3200                                 $(tr).data( data.DT_RowData );
3201                         }
3202                 }
3203         }
3204         
3205         
3206         /**
3207          * Create the HTML header for the table
3208          *  @param {object} oSettings dataTables settings object
3209          *  @memberof DataTable#oApi
3210          */
3211         function _fnBuildHead( oSettings )
3212         {
3213                 var i, ien, cell, row, column;
3214                 var thead = oSettings.nTHead;
3215                 var tfoot = oSettings.nTFoot;
3216                 var createHeader = $('th, td', thead).length === 0;
3217                 var classes = oSettings.oClasses;
3218                 var columns = oSettings.aoColumns;
3219         
3220                 if ( createHeader ) {
3221                         row = $('<tr/>').appendTo( thead );
3222                 }
3223         
3224                 for ( i=0, ien=columns.length ; i<ien ; i++ ) {
3225                         column = columns[i];
3226                         cell = $( column.nTh ).addClass( column.sClass );
3227         
3228                         if ( createHeader ) {
3229                                 cell.appendTo( row );
3230                         }
3231         
3232                         // 1.11 move into sorting
3233                         if ( oSettings.oFeatures.bSort ) {
3234                                 cell.addClass( column.sSortingClass );
3235         
3236                                 if ( column.bSortable !== false ) {
3237                                         cell
3238                                                 .attr( 'tabindex', oSettings.iTabIndex )
3239                                                 .attr( 'aria-controls', oSettings.sTableId );
3240         
3241                                         _fnSortAttachListener( oSettings, column.nTh, i );
3242                                 }
3243                         }
3244         
3245                         if ( column.sTitle != cell[0].innerHTML ) {
3246                                 cell.html( column.sTitle );
3247                         }
3248         
3249                         _fnRenderer( oSettings, 'header' )(
3250                                 oSettings, cell, column, classes
3251                         );
3252                 }
3253         
3254                 if ( createHeader ) {
3255                         _fnDetectHeader( oSettings.aoHeader, thead );
3256                 }
3257                 
3258                 /* ARIA role for the rows */
3259                 $(thead).find('>tr').attr('role', 'row');
3260         
3261                 /* Deal with the footer - add classes if required */
3262                 $(thead).find('>tr>th, >tr>td').addClass( classes.sHeaderTH );
3263                 $(tfoot).find('>tr>th, >tr>td').addClass( classes.sFooterTH );
3264         
3265                 // Cache the footer cells. Note that we only take the cells from the first
3266                 // row in the footer. If there is more than one row the user wants to
3267                 // interact with, they need to use the table().foot() method. Note also this
3268                 // allows cells to be used for multiple columns using colspan
3269                 if ( tfoot !== null ) {
3270                         var cells = oSettings.aoFooter[0];
3271         
3272                         for ( i=0, ien=cells.length ; i<ien ; i++ ) {
3273                                 column = columns[i];
3274                                 column.nTf = cells[i].cell;
3275         
3276                                 if ( column.sClass ) {
3277                                         $(column.nTf).addClass( column.sClass );
3278                                 }
3279                         }
3280                 }
3281         }
3282         
3283         
3284         /**
3285          * Draw the header (or footer) element based on the column visibility states. The
3286          * methodology here is to use the layout array from _fnDetectHeader, modified for
3287          * the instantaneous column visibility, to construct the new layout. The grid is
3288          * traversed over cell at a time in a rows x columns grid fashion, although each
3289          * cell insert can cover multiple elements in the grid - which is tracks using the
3290          * aApplied array. Cell inserts in the grid will only occur where there isn't
3291          * already a cell in that position.
3292          *  @param {object} oSettings dataTables settings object
3293          *  @param array {objects} aoSource Layout array from _fnDetectHeader
3294          *  @param {boolean} [bIncludeHidden=false] If true then include the hidden columns in the calc,
3295          *  @memberof DataTable#oApi
3296          */
3297         function _fnDrawHead( oSettings, aoSource, bIncludeHidden )
3298         {
3299                 var i, iLen, j, jLen, k, kLen, n, nLocalTr;
3300                 var aoLocal = [];
3301                 var aApplied = [];
3302                 var iColumns = oSettings.aoColumns.length;
3303                 var iRowspan, iColspan;
3304         
3305                 if ( ! aoSource )
3306                 {
3307                         return;
3308                 }
3309         
3310                 if (  bIncludeHidden === undefined )
3311                 {
3312                         bIncludeHidden = false;
3313                 }
3314         
3315                 /* Make a copy of the master layout array, but without the visible columns in it */
3316                 for ( i=0, iLen=aoSource.length ; i<iLen ; i++ )
3317                 {
3318                         aoLocal[i] = aoSource[i].slice();
3319                         aoLocal[i].nTr = aoSource[i].nTr;
3320         
3321                         /* Remove any columns which are currently hidden */
3322                         for ( j=iColumns-1 ; j>=0 ; j-- )
3323                         {
3324                                 if ( !oSettings.aoColumns[j].bVisible && !bIncludeHidden )
3325                                 {
3326                                         aoLocal[i].splice( j, 1 );
3327                                 }
3328                         }
3329         
3330                         /* Prep the applied array - it needs an element for each row */
3331                         aApplied.push( [] );
3332                 }
3333         
3334                 for ( i=0, iLen=aoLocal.length ; i<iLen ; i++ )
3335                 {
3336                         nLocalTr = aoLocal[i].nTr;
3337         
3338                         /* All cells are going to be replaced, so empty out the row */
3339                         if ( nLocalTr )
3340                         {
3341                                 while( (n = nLocalTr.firstChild) )
3342                                 {
3343                                         nLocalTr.removeChild( n );
3344                                 }
3345                         }
3346         
3347                         for ( j=0, jLen=aoLocal[i].length ; j<jLen ; j++ )
3348                         {
3349                                 iRowspan = 1;
3350                                 iColspan = 1;
3351         
3352                                 /* Check to see if there is already a cell (row/colspan) covering our target
3353                                  * insert point. If there is, then there is nothing to do.
3354                                  */
3355                                 if ( aApplied[i][j] === undefined )
3356                                 {
3357                                         nLocalTr.appendChild( aoLocal[i][j].cell );
3358                                         aApplied[i][j] = 1;
3359         
3360                                         /* Expand the cell to cover as many rows as needed */
3361                                         while ( aoLocal[i+iRowspan] !== undefined &&
3362                                                 aoLocal[i][j].cell == aoLocal[i+iRowspan][j].cell )
3363                                         {
3364                                                 aApplied[i+iRowspan][j] = 1;
3365                                                 iRowspan++;
3366                                         }
3367         
3368                                         /* Expand the cell to cover as many columns as needed */
3369                                         while ( aoLocal[i][j+iColspan] !== undefined &&
3370                                                 aoLocal[i][j].cell == aoLocal[i][j+iColspan].cell )
3371                                         {
3372                                                 /* Must update the applied array over the rows for the columns */
3373                                                 for ( k=0 ; k<iRowspan ; k++ )
3374                                                 {
3375                                                         aApplied[i+k][j+iColspan] = 1;
3376                                                 }
3377                                                 iColspan++;
3378                                         }
3379         
3380                                         /* Do the actual expansion in the DOM */
3381                                         $(aoLocal[i][j].cell)
3382                                                 .attr('rowspan', iRowspan)
3383                                                 .attr('colspan', iColspan);
3384                                 }
3385                         }
3386                 }
3387         }
3388         
3389         
3390         /**
3391          * Insert the required TR nodes into the table for display
3392          *  @param {object} oSettings dataTables settings object
3393          *  @memberof DataTable#oApi
3394          */
3395         function _fnDraw( oSettings )
3396         {
3397                 /* Provide a pre-callback function which can be used to cancel the draw is false is returned */
3398                 var aPreDraw = _fnCallbackFire( oSettings, 'aoPreDrawCallback', 'preDraw', [oSettings] );
3399                 if ( $.inArray( false, aPreDraw ) !== -1 )
3400                 {
3401                         _fnProcessingDisplay( oSettings, false );
3402                         return;
3403                 }
3404         
3405                 var i, iLen, n;
3406                 var anRows = [];
3407                 var iRowCount = 0;
3408                 var asStripeClasses = oSettings.asStripeClasses;
3409                 var iStripes = asStripeClasses.length;
3410                 var iOpenRows = oSettings.aoOpenRows.length;
3411                 var oLang = oSettings.oLanguage;
3412                 var iInitDisplayStart = oSettings.iInitDisplayStart;
3413                 var bServerSide = _fnDataSource( oSettings ) == 'ssp';
3414                 var aiDisplay = oSettings.aiDisplay;
3415         
3416                 oSettings.bDrawing = true;
3417         
3418                 /* Check and see if we have an initial draw position from state saving */
3419                 if ( iInitDisplayStart !== undefined && iInitDisplayStart !== -1 )
3420                 {
3421                         oSettings._iDisplayStart = bServerSide ?
3422                                 iInitDisplayStart :
3423                                 iInitDisplayStart >= oSettings.fnRecordsDisplay() ?
3424                                         0 :
3425                                         iInitDisplayStart;
3426         
3427                         oSettings.iInitDisplayStart = -1;
3428                 }
3429         
3430                 var iDisplayStart = oSettings._iDisplayStart;
3431                 var iDisplayEnd = oSettings.fnDisplayEnd();
3432         
3433                 /* Server-side processing draw intercept */
3434                 if ( oSettings.bDeferLoading )
3435                 {
3436                         oSettings.bDeferLoading = false;
3437                         oSettings.iDraw++;
3438                         _fnProcessingDisplay( oSettings, false );
3439                 }
3440                 else if ( !bServerSide )
3441                 {
3442                         oSettings.iDraw++;
3443                 }
3444                 else if ( !oSettings.bDestroying && !_fnAjaxUpdate( oSettings ) )
3445                 {
3446                         return;
3447                 }
3448         
3449                 if ( aiDisplay.length !== 0 )
3450                 {
3451                         var iStart = bServerSide ? 0 : iDisplayStart;
3452                         var iEnd = bServerSide ? oSettings.aoData.length : iDisplayEnd;
3453         
3454                         for ( var j=iStart ; j<iEnd ; j++ )
3455                         {
3456                                 var iDataIndex = aiDisplay[j];
3457                                 var aoData = oSettings.aoData[ iDataIndex ];
3458                                 if ( aoData.nTr === null )
3459                                 {
3460                                         _fnCreateTr( oSettings, iDataIndex );
3461                                 }
3462         
3463                                 var nRow = aoData.nTr;
3464         
3465                                 /* Remove the old striping classes and then add the new one */
3466                                 if ( iStripes !== 0 )
3467                                 {
3468                                         var sStripe = asStripeClasses[ iRowCount % iStripes ];
3469                                         if ( aoData._sRowStripe != sStripe )
3470                                         {
3471                                                 $(nRow).removeClass( aoData._sRowStripe ).addClass( sStripe );
3472                                                 aoData._sRowStripe = sStripe;
3473                                         }
3474                                 }
3475         
3476                                 // Row callback functions - might want to manipulate the row
3477                                 // iRowCount and j are not currently documented. Are they at all
3478                                 // useful?
3479                                 _fnCallbackFire( oSettings, 'aoRowCallback', null,
3480                                         [nRow, aoData._aData, iRowCount, j, iDataIndex] );
3481         
3482                                 anRows.push( nRow );
3483                                 iRowCount++;
3484                         }
3485                 }
3486                 else
3487                 {
3488                         /* Table is empty - create a row with an empty message in it */
3489                         var sZero = oLang.sZeroRecords;
3490                         if ( oSettings.iDraw == 1 &&  _fnDataSource( oSettings ) == 'ajax' )
3491                         {
3492                                 sZero = oLang.sLoadingRecords;
3493                         }
3494                         else if ( oLang.sEmptyTable && oSettings.fnRecordsTotal() === 0 )
3495                         {
3496                                 sZero = oLang.sEmptyTable;
3497                         }
3498         
3499                         anRows[ 0 ] = $( '<tr/>', { 'class': iStripes ? asStripeClasses[0] : '' } )
3500                                 .append( $('<td />', {
3501                                         'valign':  'top',
3502                                         'colSpan': _fnVisbleColumns( oSettings ),
3503                                         'class':   oSettings.oClasses.sRowEmpty
3504                                 } ).html( sZero ) )[0];
3505                 }
3506         
3507                 /* Header and footer callbacks */
3508                 _fnCallbackFire( oSettings, 'aoHeaderCallback', 'header', [ $(oSettings.nTHead).children('tr')[0],
3509                         _fnGetDataMaster( oSettings ), iDisplayStart, iDisplayEnd, aiDisplay ] );
3510         
3511                 _fnCallbackFire( oSettings, 'aoFooterCallback', 'footer', [ $(oSettings.nTFoot).children('tr')[0],
3512                         _fnGetDataMaster( oSettings ), iDisplayStart, iDisplayEnd, aiDisplay ] );
3513         
3514                 var body = $(oSettings.nTBody);
3515         
3516                 body.children().detach();
3517                 body.append( $(anRows) );
3518         
3519                 /* Call all required callback functions for the end of a draw */
3520                 _fnCallbackFire( oSettings, 'aoDrawCallback', 'draw', [oSettings] );
3521         
3522                 /* Draw is complete, sorting and filtering must be as well */
3523                 oSettings.bSorted = false;
3524                 oSettings.bFiltered = false;
3525                 oSettings.bDrawing = false;
3526         }
3527         
3528         
3529         /**
3530          * Redraw the table - taking account of the various features which are enabled
3531          *  @param {object} oSettings dataTables settings object
3532          *  @param {boolean} [holdPosition] Keep the current paging position. By default
3533          *    the paging is reset to the first page
3534          *  @memberof DataTable#oApi
3535          */
3536         function _fnReDraw( settings, holdPosition )
3537         {
3538                 var
3539                         features = settings.oFeatures,
3540                         sort     = features.bSort,
3541                         filter   = features.bFilter;
3542         
3543                 if ( sort ) {
3544                         _fnSort( settings );
3545                 }
3546         
3547                 if ( filter ) {
3548                         _fnFilterComplete( settings, settings.oPreviousSearch );
3549                 }
3550                 else {
3551                         // No filtering, so we want to just use the display master
3552                         settings.aiDisplay = settings.aiDisplayMaster.slice();
3553                 }
3554         
3555                 if ( holdPosition !== true ) {
3556                         settings._iDisplayStart = 0;
3557                 }
3558         
3559                 // Let any modules know about the draw hold position state (used by
3560                 // scrolling internally)
3561                 settings._drawHold = holdPosition;
3562         
3563                 _fnDraw( settings );
3564         
3565                 settings._drawHold = false;
3566         }
3567         
3568         
3569         /**
3570          * Add the options to the page HTML for the table
3571          *  @param {object} oSettings dataTables settings object
3572          *  @memberof DataTable#oApi
3573          */
3574         function _fnAddOptionsHtml ( oSettings )
3575         {
3576                 var classes = oSettings.oClasses;
3577                 var table = $(oSettings.nTable);
3578                 var holding = $('<div/>').insertBefore( table ); // Holding element for speed
3579                 var features = oSettings.oFeatures;
3580         
3581                 // All DataTables are wrapped in a div
3582                 var insert = $('<div/>', {
3583                         id:      oSettings.sTableId+'_wrapper',
3584                         'class': classes.sWrapper + (oSettings.nTFoot ? '' : ' '+classes.sNoFooter)
3585                 } );
3586         
3587                 oSettings.nHolding = holding[0];
3588                 oSettings.nTableWrapper = insert[0];
3589                 oSettings.nTableReinsertBefore = oSettings.nTable.nextSibling;
3590         
3591                 /* Loop over the user set positioning and place the elements as needed */
3592                 var aDom = oSettings.sDom.split('');
3593                 var featureNode, cOption, nNewNode, cNext, sAttr, j;
3594                 for ( var i=0 ; i<aDom.length ; i++ )
3595                 {
3596                         featureNode = null;
3597                         cOption = aDom[i];
3598         
3599                         if ( cOption == '<' )
3600                         {
3601                                 /* New container div */
3602                                 nNewNode = $('<div/>')[0];
3603         
3604                                 /* Check to see if we should append an id and/or a class name to the container */
3605                                 cNext = aDom[i+1];
3606                                 if ( cNext == "'" || cNext == '"' )
3607                                 {
3608                                         sAttr = "";
3609                                         j = 2;
3610                                         while ( aDom[i+j] != cNext )
3611                                         {
3612                                                 sAttr += aDom[i+j];
3613                                                 j++;
3614                                         }
3615         
3616                                         /* Replace jQuery UI constants @todo depreciated */
3617                                         if ( sAttr == "H" )
3618                                         {
3619                                                 sAttr = classes.sJUIHeader;
3620                                         }
3621                                         else if ( sAttr == "F" )
3622                                         {
3623                                                 sAttr = classes.sJUIFooter;
3624                                         }
3625         
3626                                         /* The attribute can be in the format of "#id.class", "#id" or "class" This logic
3627                                          * breaks the string into parts and applies them as needed
3628                                          */
3629                                         if ( sAttr.indexOf('.') != -1 )
3630                                         {
3631                                                 var aSplit = sAttr.split('.');
3632                                                 nNewNode.id = aSplit[0].substr(1, aSplit[0].length-1);
3633                                                 nNewNode.className = aSplit[1];
3634                                         }
3635                                         else if ( sAttr.charAt(0) == "#" )
3636                                         {
3637                                                 nNewNode.id = sAttr.substr(1, sAttr.length-1);
3638                                         }
3639                                         else
3640                                         {
3641                                                 nNewNode.className = sAttr;
3642                                         }
3643         
3644                                         i += j; /* Move along the position array */
3645                                 }
3646         
3647                                 insert.append( nNewNode );
3648                                 insert = $(nNewNode);
3649                         }
3650                         else if ( cOption == '>' )
3651                         {
3652                                 /* End container div */
3653                                 insert = insert.parent();
3654                         }
3655                         // @todo Move options into their own plugins?
3656                         else if ( cOption == 'l' && features.bPaginate && features.bLengthChange )
3657                         {
3658                                 /* Length */
3659                                 featureNode = _fnFeatureHtmlLength( oSettings );
3660                         }
3661                         else if ( cOption == 'f' && features.bFilter )
3662                         {
3663                                 /* Filter */
3664                                 featureNode = _fnFeatureHtmlFilter( oSettings );
3665                         }
3666                         else if ( cOption == 'r' && features.bProcessing )
3667                         {
3668                                 /* pRocessing */
3669                                 featureNode = _fnFeatureHtmlProcessing( oSettings );
3670                         }
3671                         else if ( cOption == 't' )
3672                         {
3673                                 /* Table */
3674                                 featureNode = _fnFeatureHtmlTable( oSettings );
3675                         }
3676                         else if ( cOption ==  'i' && features.bInfo )
3677                         {
3678                                 /* Info */
3679                                 featureNode = _fnFeatureHtmlInfo( oSettings );
3680                         }
3681                         else if ( cOption == 'p' && features.bPaginate )
3682                         {
3683                                 /* Pagination */
3684                                 featureNode = _fnFeatureHtmlPaginate( oSettings );
3685                         }
3686                         else if ( DataTable.ext.feature.length !== 0 )
3687                         {
3688                                 /* Plug-in features */
3689                                 var aoFeatures = DataTable.ext.feature;
3690                                 for ( var k=0, kLen=aoFeatures.length ; k<kLen ; k++ )
3691                                 {
3692                                         if ( cOption == aoFeatures[k].cFeature )
3693                                         {
3694                                                 featureNode = aoFeatures[k].fnInit( oSettings );
3695                                                 break;
3696                                         }
3697                                 }
3698                         }
3699         
3700                         /* Add to the 2D features array */
3701                         if ( featureNode )
3702                         {
3703                                 var aanFeatures = oSettings.aanFeatures;
3704         
3705                                 if ( ! aanFeatures[cOption] )
3706                                 {
3707                                         aanFeatures[cOption] = [];
3708                                 }
3709         
3710                                 aanFeatures[cOption].push( featureNode );
3711                                 insert.append( featureNode );
3712                         }
3713                 }
3714         
3715                 /* Built our DOM structure - replace the holding div with what we want */
3716                 holding.replaceWith( insert );
3717                 oSettings.nHolding = null;
3718         }
3719         
3720         
3721         /**
3722          * Use the DOM source to create up an array of header cells. The idea here is to
3723          * create a layout grid (array) of rows x columns, which contains a reference
3724          * to the cell that that point in the grid (regardless of col/rowspan), such that
3725          * any column / row could be removed and the new grid constructed
3726          *  @param array {object} aLayout Array to store the calculated layout in
3727          *  @param {node} nThead The header/footer element for the table
3728          *  @memberof DataTable#oApi
3729          */
3730         function _fnDetectHeader ( aLayout, nThead )
3731         {
3732                 var nTrs = $(nThead).children('tr');
3733                 var nTr, nCell;
3734                 var i, k, l, iLen, jLen, iColShifted, iColumn, iColspan, iRowspan;
3735                 var bUnique;
3736                 var fnShiftCol = function ( a, i, j ) {
3737                         var k = a[i];
3738                         while ( k[j] ) {
3739                                 j++;
3740                         }
3741                         return j;
3742                 };
3743         
3744                 aLayout.splice( 0, aLayout.length );
3745         
3746                 /* We know how many rows there are in the layout - so prep it */
3747                 for ( i=0, iLen=nTrs.length ; i<iLen ; i++ )
3748                 {
3749                         aLayout.push( [] );
3750                 }
3751         
3752                 /* Calculate a layout array */
3753                 for ( i=0, iLen=nTrs.length ; i<iLen ; i++ )
3754                 {
3755                         nTr = nTrs[i];
3756                         iColumn = 0;
3757         
3758                         /* For every cell in the row... */
3759                         nCell = nTr.firstChild;
3760                         while ( nCell ) {
3761                                 if ( nCell.nodeName.toUpperCase() == "TD" ||
3762                                      nCell.nodeName.toUpperCase() == "TH" )
3763                                 {
3764                                         /* Get the col and rowspan attributes from the DOM and sanitise them */
3765                                         iColspan = nCell.getAttribute('colspan') * 1;
3766                                         iRowspan = nCell.getAttribute('rowspan') * 1;
3767                                         iColspan = (!iColspan || iColspan===0 || iColspan===1) ? 1 : iColspan;
3768                                         iRowspan = (!iRowspan || iRowspan===0 || iRowspan===1) ? 1 : iRowspan;
3769         
3770                                         /* There might be colspan cells already in this row, so shift our target
3771                                          * accordingly
3772                                          */
3773                                         iColShifted = fnShiftCol( aLayout, i, iColumn );
3774         
3775                                         /* Cache calculation for unique columns */
3776                                         bUnique = iColspan === 1 ? true : false;
3777         
3778                                         /* If there is col / rowspan, copy the information into the layout grid */
3779                                         for ( l=0 ; l<iColspan ; l++ )
3780                                         {
3781                                                 for ( k=0 ; k<iRowspan ; k++ )
3782                                                 {
3783                                                         aLayout[i+k][iColShifted+l] = {
3784                                                                 "cell": nCell,
3785                                                                 "unique": bUnique
3786                                                         };
3787                                                         aLayout[i+k].nTr = nTr;
3788                                                 }
3789                                         }
3790                                 }
3791                                 nCell = nCell.nextSibling;
3792                         }
3793                 }
3794         }
3795         
3796         
3797         /**
3798          * Get an array of unique th elements, one for each column
3799          *  @param {object} oSettings dataTables settings object
3800          *  @param {node} nHeader automatically detect the layout from this node - optional
3801          *  @param {array} aLayout thead/tfoot layout from _fnDetectHeader - optional
3802          *  @returns array {node} aReturn list of unique th's
3803          *  @memberof DataTable#oApi
3804          */
3805         function _fnGetUniqueThs ( oSettings, nHeader, aLayout )
3806         {
3807                 var aReturn = [];
3808                 if ( !aLayout )
3809                 {
3810                         aLayout = oSettings.aoHeader;
3811                         if ( nHeader )
3812                         {
3813                                 aLayout = [];
3814                                 _fnDetectHeader( aLayout, nHeader );
3815                         }
3816                 }
3817         
3818                 for ( var i=0, iLen=aLayout.length ; i<iLen ; i++ )
3819                 {
3820                         for ( var j=0, jLen=aLayout[i].length ; j<jLen ; j++ )
3821                         {
3822                                 if ( aLayout[i][j].unique &&
3823                                          (!aReturn[j] || !oSettings.bSortCellsTop) )
3824                                 {
3825                                         aReturn[j] = aLayout[i][j].cell;
3826                                 }
3827                         }
3828                 }
3829         
3830                 return aReturn;
3831         }
3832         
3833         /**
3834          * Create an Ajax call based on the table's settings, taking into account that
3835          * parameters can have multiple forms, and backwards compatibility.
3836          *
3837          * @param {object} oSettings dataTables settings object
3838          * @param {array} data Data to send to the server, required by
3839          *     DataTables - may be augmented by developer callbacks
3840          * @param {function} fn Callback function to run when data is obtained
3841          */
3842         function _fnBuildAjax( oSettings, data, fn )
3843         {
3844                 // Compatibility with 1.9-, allow fnServerData and event to manipulate
3845                 _fnCallbackFire( oSettings, 'aoServerParams', 'serverParams', [data] );
3846         
3847                 // Convert to object based for 1.10+ if using the old array scheme which can
3848                 // come from server-side processing or serverParams
3849                 if ( data && $.isArray(data) ) {
3850                         var tmp = {};
3851                         var rbracket = /(.*?)\[\]$/;
3852         
3853                         $.each( data, function (key, val) {
3854                                 var match = val.name.match(rbracket);
3855         
3856                                 if ( match ) {
3857                                         // Support for arrays
3858                                         var name = match[0];
3859         
3860                                         if ( ! tmp[ name ] ) {
3861                                                 tmp[ name ] = [];
3862                                         }
3863                                         tmp[ name ].push( val.value );
3864                                 }
3865                                 else {
3866                                         tmp[val.name] = val.value;
3867                                 }
3868                         } );
3869                         data = tmp;
3870                 }
3871         
3872                 var ajaxData;
3873                 var ajax = oSettings.ajax;
3874                 var instance = oSettings.oInstance;
3875                 var callback = function ( json ) {
3876                         _fnCallbackFire( oSettings, null, 'xhr', [oSettings, json, oSettings.jqXHR] );
3877                         fn( json );
3878                 };
3879         
3880                 if ( $.isPlainObject( ajax ) && ajax.data )
3881                 {
3882                         ajaxData = ajax.data;
3883         
3884                         var newData = typeof ajaxData === 'function' ?
3885                                 ajaxData( data, oSettings ) :  // fn can manipulate data or return
3886                                 ajaxData;                      // an object object or array to merge
3887         
3888                         // If the function returned something, use that alone
3889                         data = typeof ajaxData === 'function' && newData ?
3890                                 newData :
3891                                 $.extend( true, data, newData );
3892         
3893                         // Remove the data property as we've resolved it already and don't want
3894                         // jQuery to do it again (it is restored at the end of the function)
3895                         delete ajax.data;
3896                 }
3897         
3898                 var baseAjax = {
3899                         "data": data,
3900                         "success": function (json) {
3901                                 var error = json.error || json.sError;
3902                                 if ( error ) {
3903                                         _fnLog( oSettings, 0, error );
3904                                 }
3905         
3906                                 oSettings.json = json;
3907                                 callback( json );
3908                         },
3909                         "dataType": "json",
3910                         "cache": false,
3911                         "type": oSettings.sServerMethod,
3912                         "error": function (xhr, error, thrown) {
3913                                 var ret = _fnCallbackFire( oSettings, null, 'xhr', [oSettings, null, oSettings.jqXHR] );
3914         
3915                                 if ( $.inArray( true, ret ) === -1 ) {
3916                                         if ( error == "parsererror" ) {
3917                                                 _fnLog( oSettings, 0, 'Invalid JSON response', 1 );
3918                                         }
3919                                         else if ( xhr.readyState === 4 ) {
3920                                                 _fnLog( oSettings, 0, 'Ajax error', 7 );
3921                                         }
3922                                 }
3923         
3924                                 _fnProcessingDisplay( oSettings, false );
3925                         }
3926                 };
3927         
3928                 // Store the data submitted for the API
3929                 oSettings.oAjaxData = data;
3930         
3931                 // Allow plug-ins and external processes to modify the data
3932                 _fnCallbackFire( oSettings, null, 'preXhr', [oSettings, data] );
3933         
3934                 if ( oSettings.fnServerData )
3935                 {
3936                         // DataTables 1.9- compatibility
3937                         oSettings.fnServerData.call( instance,
3938                                 oSettings.sAjaxSource,
3939                                 $.map( data, function (val, key) { // Need to convert back to 1.9 trad format
3940                                         return { name: key, value: val };
3941                                 } ),
3942                                 callback,
3943                                 oSettings
3944                         );
3945                 }
3946                 else if ( oSettings.sAjaxSource || typeof ajax === 'string' )
3947                 {
3948                         // DataTables 1.9- compatibility
3949                         oSettings.jqXHR = $.ajax( $.extend( baseAjax, {
3950                                 url: ajax || oSettings.sAjaxSource
3951                         } ) );
3952                 }
3953                 else if ( typeof ajax === 'function' )
3954                 {
3955                         // Is a function - let the caller define what needs to be done
3956                         oSettings.jqXHR = ajax.call( instance, data, callback, oSettings );
3957                 }
3958                 else
3959                 {
3960                         // Object to extend the base settings
3961                         oSettings.jqXHR = $.ajax( $.extend( baseAjax, ajax ) );
3962         
3963                         // Restore for next time around
3964                         ajax.data = ajaxData;
3965                 }
3966         }
3967         
3968         
3969         /**
3970          * Update the table using an Ajax call
3971          *  @param {object} settings dataTables settings object
3972          *  @returns {boolean} Block the table drawing or not
3973          *  @memberof DataTable#oApi
3974          */
3975         function _fnAjaxUpdate( settings )
3976         {
3977                 if ( settings.bAjaxDataGet ) {
3978                         settings.iDraw++;
3979                         _fnProcessingDisplay( settings, true );
3980         
3981                         _fnBuildAjax(
3982                                 settings,
3983                                 _fnAjaxParameters( settings ),
3984                                 function(json) {
3985                                         _fnAjaxUpdateDraw( settings, json );
3986                                 }
3987                         );
3988         
3989                         return false;
3990                 }
3991                 return true;
3992         }
3993         
3994         
3995         /**
3996          * Build up the parameters in an object needed for a server-side processing
3997          * request. Note that this is basically done twice, is different ways - a modern
3998          * method which is used by default in DataTables 1.10 which uses objects and
3999          * arrays, or the 1.9- method with is name / value pairs. 1.9 method is used if
4000          * the sAjaxSource option is used in the initialisation, or the legacyAjax
4001          * option is set.
4002          *  @param {object} oSettings dataTables settings object
4003          *  @returns {bool} block the table drawing or not
4004          *  @memberof DataTable#oApi
4005          */
4006         function _fnAjaxParameters( settings )
4007         {
4008                 var
4009                         columns = settings.aoColumns,
4010                         columnCount = columns.length,
4011                         features = settings.oFeatures,
4012                         preSearch = settings.oPreviousSearch,
4013                         preColSearch = settings.aoPreSearchCols,
4014                         i, data = [], dataProp, column, columnSearch,
4015                         sort = _fnSortFlatten( settings ),
4016                         displayStart = settings._iDisplayStart,
4017                         displayLength = features.bPaginate !== false ?
4018                                 settings._iDisplayLength :
4019                                 -1;
4020         
4021                 var param = function ( name, value ) {
4022                         data.push( { 'name': name, 'value': value } );
4023                 };
4024         
4025                 // DataTables 1.9- compatible method
4026                 param( 'sEcho',          settings.iDraw );
4027                 param( 'iColumns',       columnCount );
4028                 param( 'sColumns',       _pluck( columns, 'sName' ).join(',') );
4029                 param( 'iDisplayStart',  displayStart );
4030                 param( 'iDisplayLength', displayLength );
4031         
4032                 // DataTables 1.10+ method
4033                 var d = {
4034                         draw:    settings.iDraw,
4035                         columns: [],
4036                         order:   [],
4037                         start:   displayStart,
4038                         length:  displayLength,
4039                         search:  {
4040                                 value: preSearch.sSearch,
4041                                 regex: preSearch.bRegex
4042                         }
4043                 };
4044         
4045                 for ( i=0 ; i<columnCount ; i++ ) {
4046                         column = columns[i];
4047                         columnSearch = preColSearch[i];
4048                         dataProp = typeof column.mData=="function" ? 'function' : column.mData ;
4049         
4050                         d.columns.push( {
4051                                 data:       dataProp,
4052                                 name:       column.sName,
4053                                 searchable: column.bSearchable,
4054                                 orderable:  column.bSortable,
4055                                 search:     {
4056                                         value: columnSearch.sSearch,
4057                                         regex: columnSearch.bRegex
4058                                 }
4059                         } );
4060         
4061                         param( "mDataProp_"+i, dataProp );
4062         
4063                         if ( features.bFilter ) {
4064                                 param( 'sSearch_'+i,     columnSearch.sSearch );
4065                                 param( 'bRegex_'+i,      columnSearch.bRegex );
4066                                 param( 'bSearchable_'+i, column.bSearchable );
4067                         }
4068         
4069                         if ( features.bSort ) {
4070                                 param( 'bSortable_'+i, column.bSortable );
4071                         }
4072                 }
4073         
4074                 if ( features.bFilter ) {
4075                         param( 'sSearch', preSearch.sSearch );
4076                         param( 'bRegex', preSearch.bRegex );
4077                 }
4078         
4079                 if ( features.bSort ) {
4080                         $.each( sort, function ( i, val ) {
4081                                 d.order.push( { column: val.col, dir: val.dir } );
4082         
4083                                 param( 'iSortCol_'+i, val.col );
4084                                 param( 'sSortDir_'+i, val.dir );
4085                         } );
4086         
4087                         param( 'iSortingCols', sort.length );
4088                 }
4089         
4090                 // If the legacy.ajax parameter is null, then we automatically decide which
4091                 // form to use, based on sAjaxSource
4092                 var legacy = DataTable.ext.legacy.ajax;
4093                 if ( legacy === null ) {
4094                         return settings.sAjaxSource ? data : d;
4095                 }
4096         
4097                 // Otherwise, if legacy has been specified then we use that to decide on the
4098                 // form
4099                 return legacy ? data : d;
4100         }
4101         
4102         
4103         /**
4104          * Data the data from the server (nuking the old) and redraw the table
4105          *  @param {object} oSettings dataTables settings object
4106          *  @param {object} json json data return from the server.
4107          *  @param {string} json.sEcho Tracking flag for DataTables to match requests
4108          *  @param {int} json.iTotalRecords Number of records in the data set, not accounting for filtering
4109          *  @param {int} json.iTotalDisplayRecords Number of records in the data set, accounting for filtering
4110          *  @param {array} json.aaData The data to display on this page
4111          *  @param {string} [json.sColumns] Column ordering (sName, comma separated)
4112          *  @memberof DataTable#oApi
4113          */
4114         function _fnAjaxUpdateDraw ( settings, json )
4115         {
4116                 // v1.10 uses camelCase variables, while 1.9 uses Hungarian notation.
4117                 // Support both
4118                 var compat = function ( old, modern ) {
4119                         return json[old] !== undefined ? json[old] : json[modern];
4120                 };
4121         
4122                 var data = _fnAjaxDataSrc( settings, json );
4123                 var draw            = compat( 'sEcho',                'draw' );
4124                 var recordsTotal    = compat( 'iTotalRecords',        'recordsTotal' );
4125                 var recordsFiltered = compat( 'iTotalDisplayRecords', 'recordsFiltered' );
4126         
4127                 if ( draw ) {
4128                         // Protect against out of sequence returns
4129                         if ( draw*1 < settings.iDraw ) {
4130                                 return;
4131                         }
4132                         settings.iDraw = draw * 1;
4133                 }
4134         
4135                 _fnClearTable( settings );
4136                 settings._iRecordsTotal   = parseInt(recordsTotal, 10);
4137                 settings._iRecordsDisplay = parseInt(recordsFiltered, 10);
4138         
4139                 for ( var i=0, ien=data.length ; i<ien ; i++ ) {
4140                         _fnAddData( settings, data[i] );
4141                 }
4142                 settings.aiDisplay = settings.aiDisplayMaster.slice();
4143         
4144                 settings.bAjaxDataGet = false;
4145                 _fnDraw( settings );
4146         
4147                 if ( ! settings._bInitComplete ) {
4148                         _fnInitComplete( settings, json );
4149                 }
4150         
4151                 settings.bAjaxDataGet = true;
4152                 _fnProcessingDisplay( settings, false );
4153         }
4154         
4155         
4156         /**
4157          * Get the data from the JSON data source to use for drawing a table. Using
4158          * `_fnGetObjectDataFn` allows the data to be sourced from a property of the
4159          * source object, or from a processing function.
4160          *  @param {object} oSettings dataTables settings object
4161          *  @param  {object} json Data source object / array from the server
4162          *  @return {array} Array of data to use
4163          */
4164         function _fnAjaxDataSrc ( oSettings, json )
4165         {
4166                 var dataSrc = $.isPlainObject( oSettings.ajax ) && oSettings.ajax.dataSrc !== undefined ?
4167                         oSettings.ajax.dataSrc :
4168                         oSettings.sAjaxDataProp; // Compatibility with 1.9-.
4169         
4170                 // Compatibility with 1.9-. In order to read from aaData, check if the
4171                 // default has been changed, if not, check for aaData
4172                 if ( dataSrc === 'data' ) {
4173                         return json.aaData || json[dataSrc];
4174                 }
4175         
4176                 return dataSrc !== "" ?
4177                         _fnGetObjectDataFn( dataSrc )( json ) :
4178                         json;
4179         }
4180         
4181         /**
4182          * Generate the node required for filtering text
4183          *  @returns {node} Filter control element
4184          *  @param {object} oSettings dataTables settings object
4185          *  @memberof DataTable#oApi
4186          */
4187         function _fnFeatureHtmlFilter ( settings )
4188         {
4189                 var classes = settings.oClasses;
4190                 var tableId = settings.sTableId;
4191                 var language = settings.oLanguage;
4192                 var previousSearch = settings.oPreviousSearch;
4193                 var features = settings.aanFeatures;
4194                 var input = '<input type="search" class="'+classes.sFilterInput+'"/>';
4195         
4196                 var str = language.sSearch;
4197                 str = str.match(/_INPUT_/) ?
4198                         str.replace('_INPUT_', input) :
4199                         str+input;
4200         
4201                 var filter = $('<div/>', {
4202                                 'id': ! features.f ? tableId+'_filter' : null,
4203                                 'class': classes.sFilter
4204                         } )
4205                         .append( $('<label/>' ).append( str ) );
4206         
4207                 var searchFn = function() {
4208                         /* Update all other filter input elements for the new display */
4209                         var n = features.f;
4210                         var val = !this.value ? "" : this.value; // mental IE8 fix :-(
4211         
4212                         /* Now do the filter */
4213                         if ( val != previousSearch.sSearch ) {
4214                                 _fnFilterComplete( settings, {
4215                                         "sSearch": val,
4216                                         "bRegex": previousSearch.bRegex,
4217                                         "bSmart": previousSearch.bSmart ,
4218                                         "bCaseInsensitive": previousSearch.bCaseInsensitive
4219                                 } );
4220         
4221                                 // Need to redraw, without resorting
4222                                 settings._iDisplayStart = 0;
4223                                 _fnDraw( settings );
4224                         }
4225                 };
4226         
4227                 var searchDelay = settings.searchDelay !== null ?
4228                         settings.searchDelay :
4229                         _fnDataSource( settings ) === 'ssp' ?
4230                                 400 :
4231                                 0;
4232         
4233                 var jqFilter = $('input', filter)
4234                         .val( previousSearch.sSearch )
4235                         .attr( 'placeholder', language.sSearchPlaceholder )
4236                         .on(
4237                                 'keyup.DT search.DT input.DT paste.DT cut.DT',
4238                                 searchDelay ?
4239                                         _fnThrottle( searchFn, searchDelay ) :
4240                                         searchFn
4241                         )
4242                         .on( 'keypress.DT', function(e) {
4243                                 /* Prevent form submission */
4244                                 if ( e.keyCode == 13 ) {
4245                                         return false;
4246                                 }
4247                         } )
4248                         .attr('aria-controls', tableId);
4249         
4250                 // Update the input elements whenever the table is filtered
4251                 $(settings.nTable).on( 'search.dt.DT', function ( ev, s ) {
4252                         if ( settings === s ) {
4253                                 // IE9 throws an 'unknown error' if document.activeElement is used
4254                                 // inside an iframe or frame...
4255                                 try {
4256                                         if ( jqFilter[0] !== document.activeElement ) {
4257                                                 jqFilter.val( previousSearch.sSearch );
4258                                         }
4259                                 }
4260                                 catch ( e ) {}
4261                         }
4262                 } );
4263         
4264                 return filter[0];
4265         }
4266         
4267         
4268         /**
4269          * Filter the table using both the global filter and column based filtering
4270          *  @param {object} oSettings dataTables settings object
4271          *  @param {object} oSearch search information
4272          *  @param {int} [iForce] force a research of the master array (1) or not (undefined or 0)
4273          *  @memberof DataTable#oApi
4274          */
4275         function _fnFilterComplete ( oSettings, oInput, iForce )
4276         {
4277                 var oPrevSearch = oSettings.oPreviousSearch;
4278                 var aoPrevSearch = oSettings.aoPreSearchCols;
4279                 var fnSaveFilter = function ( oFilter ) {
4280                         /* Save the filtering values */
4281                         oPrevSearch.sSearch = oFilter.sSearch;
4282                         oPrevSearch.bRegex = oFilter.bRegex;
4283                         oPrevSearch.bSmart = oFilter.bSmart;
4284                         oPrevSearch.bCaseInsensitive = oFilter.bCaseInsensitive;
4285                 };
4286                 var fnRegex = function ( o ) {
4287                         // Backwards compatibility with the bEscapeRegex option
4288                         return o.bEscapeRegex !== undefined ? !o.bEscapeRegex : o.bRegex;
4289                 };
4290         
4291                 // Resolve any column types that are unknown due to addition or invalidation
4292                 // @todo As per sort - can this be moved into an event handler?
4293                 _fnColumnTypes( oSettings );
4294         
4295                 /* In server-side processing all filtering is done by the server, so no point hanging around here */
4296                 if ( _fnDataSource( oSettings ) != 'ssp' )
4297                 {
4298                         /* Global filter */
4299                         _fnFilter( oSettings, oInput.sSearch, iForce, fnRegex(oInput), oInput.bSmart, oInput.bCaseInsensitive );
4300                         fnSaveFilter( oInput );
4301         
4302                         /* Now do the individual column filter */
4303                         for ( var i=0 ; i<aoPrevSearch.length ; i++ )
4304                         {
4305                                 _fnFilterColumn( oSettings, aoPrevSearch[i].sSearch, i, fnRegex(aoPrevSearch[i]),
4306                                         aoPrevSearch[i].bSmart, aoPrevSearch[i].bCaseInsensitive );
4307                         }
4308         
4309                         /* Custom filtering */
4310                         _fnFilterCustom( oSettings );
4311                 }
4312                 else
4313                 {
4314                         fnSaveFilter( oInput );
4315                 }
4316         
4317                 /* Tell the draw function we have been filtering */
4318                 oSettings.bFiltered = true;
4319                 _fnCallbackFire( oSettings, null, 'search', [oSettings] );
4320         }
4321         
4322         
4323         /**
4324          * Apply custom filtering functions
4325          *  @param {object} oSettings dataTables settings object
4326          *  @memberof DataTable#oApi
4327          */
4328         function _fnFilterCustom( settings )
4329         {
4330                 var filters = DataTable.ext.search;
4331                 var displayRows = settings.aiDisplay;
4332                 var row, rowIdx;
4333         
4334                 for ( var i=0, ien=filters.length ; i<ien ; i++ ) {
4335                         var rows = [];
4336         
4337                         // Loop over each row and see if it should be included
4338                         for ( var j=0, jen=displayRows.length ; j<jen ; j++ ) {
4339                                 rowIdx = displayRows[ j ];
4340                                 row = settings.aoData[ rowIdx ];
4341         
4342                                 if ( filters[i]( settings, row._aFilterData, rowIdx, row._aData, j ) ) {
4343                                         rows.push( rowIdx );
4344                                 }
4345                         }
4346         
4347                         // So the array reference doesn't break set the results into the
4348                         // existing array
4349                         displayRows.length = 0;
4350                         $.merge( displayRows, rows );
4351                 }
4352         }
4353         
4354         
4355         /**
4356          * Filter the table on a per-column basis
4357          *  @param {object} oSettings dataTables settings object
4358          *  @param {string} sInput string to filter on
4359          *  @param {int} iColumn column to filter
4360          *  @param {bool} bRegex treat search string as a regular expression or not
4361          *  @param {bool} bSmart use smart filtering or not
4362          *  @param {bool} bCaseInsensitive Do case insenstive matching or not
4363          *  @memberof DataTable#oApi
4364          */
4365         function _fnFilterColumn ( settings, searchStr, colIdx, regex, smart, caseInsensitive )
4366         {
4367                 if ( searchStr === '' ) {
4368                         return;
4369                 }
4370         
4371                 var data;
4372                 var out = [];
4373                 var display = settings.aiDisplay;
4374                 var rpSearch = _fnFilterCreateSearch( searchStr, regex, smart, caseInsensitive );
4375         
4376                 for ( var i=0 ; i<display.length ; i++ ) {
4377                         data = settings.aoData[ display[i] ]._aFilterData[ colIdx ];
4378         
4379                         if ( rpSearch.test( data ) ) {
4380                                 out.push( display[i] );
4381                         }
4382                 }
4383         
4384                 settings.aiDisplay = out;
4385         }
4386         
4387         
4388         /**
4389          * Filter the data table based on user input and draw the table
4390          *  @param {object} settings dataTables settings object
4391          *  @param {string} input string to filter on
4392          *  @param {int} force optional - force a research of the master array (1) or not (undefined or 0)
4393          *  @param {bool} regex treat as a regular expression or not
4394          *  @param {bool} smart perform smart filtering or not
4395          *  @param {bool} caseInsensitive Do case insenstive matching or not
4396          *  @memberof DataTable#oApi
4397          */
4398         function _fnFilter( settings, input, force, regex, smart, caseInsensitive )
4399         {
4400                 var rpSearch = _fnFilterCreateSearch( input, regex, smart, caseInsensitive );
4401                 var prevSearch = settings.oPreviousSearch.sSearch;
4402                 var displayMaster = settings.aiDisplayMaster;
4403                 var display, invalidated, i;
4404                 var filtered = [];
4405         
4406                 // Need to take account of custom filtering functions - always filter
4407                 if ( DataTable.ext.search.length !== 0 ) {
4408                         force = true;
4409                 }
4410         
4411                 // Check if any of the rows were invalidated
4412                 invalidated = _fnFilterData( settings );
4413         
4414                 // If the input is blank - we just want the full data set
4415                 if ( input.length <= 0 ) {
4416                         settings.aiDisplay = displayMaster.slice();
4417                 }
4418                 else {
4419                         // New search - start from the master array
4420                         if ( invalidated ||
4421                                  force ||
4422                                  regex ||
4423                                  prevSearch.length > input.length ||
4424                                  input.indexOf(prevSearch) !== 0 ||
4425                                  settings.bSorted // On resort, the display master needs to be
4426                                                   // re-filtered since indexes will have changed
4427                         ) {
4428                                 settings.aiDisplay = displayMaster.slice();
4429                         }
4430         
4431                         // Search the display array
4432                         display = settings.aiDisplay;
4433         
4434                         for ( i=0 ; i<display.length ; i++ ) {
4435                                 if ( rpSearch.test( settings.aoData[ display[i] ]._sFilterRow ) ) {
4436                                         filtered.push( display[i] );
4437                                 }
4438                         }
4439         
4440                         settings.aiDisplay = filtered;
4441                 }
4442         }
4443         
4444         
4445         /**
4446          * Build a regular expression object suitable for searching a table
4447          *  @param {string} sSearch string to search for
4448          *  @param {bool} bRegex treat as a regular expression or not
4449          *  @param {bool} bSmart perform smart filtering or not
4450          *  @param {bool} bCaseInsensitive Do case insensitive matching or not
4451          *  @returns {RegExp} constructed object
4452          *  @memberof DataTable#oApi
4453          */
4454         function _fnFilterCreateSearch( search, regex, smart, caseInsensitive )
4455         {
4456                 search = regex ?
4457                         search :
4458                         _fnEscapeRegex( search );
4459                 
4460                 if ( smart ) {
4461                         /* For smart filtering we want to allow the search to work regardless of
4462                          * word order. We also want double quoted text to be preserved, so word
4463                          * order is important - a la google. So this is what we want to
4464                          * generate:
4465                          * 
4466                          * ^(?=.*?\bone\b)(?=.*?\btwo three\b)(?=.*?\bfour\b).*$
4467                          */
4468                         var a = $.map( search.match( /"[^"]+"|[^ ]+/g ) || [''], function ( word ) {
4469                                 if ( word.charAt(0) === '"' ) {
4470                                         var m = word.match( /^"(.*)"$/ );
4471                                         word = m ? m[1] : word;
4472                                 }
4473         
4474                                 return word.replace('"', '');
4475                         } );
4476         
4477                         search = '^(?=.*?'+a.join( ')(?=.*?' )+').*$';
4478                 }
4479         
4480                 return new RegExp( search, caseInsensitive ? 'i' : '' );
4481         }
4482         
4483         
4484         /**
4485          * Escape a string such that it can be used in a regular expression
4486          *  @param {string} sVal string to escape
4487          *  @returns {string} escaped string
4488          *  @memberof DataTable#oApi
4489          */
4490         var _fnEscapeRegex = DataTable.util.escapeRegex;
4491         
4492         var __filter_div = $('<div>')[0];
4493         var __filter_div_textContent = __filter_div.textContent !== undefined;
4494         
4495         // Update the filtering data for each row if needed (by invalidation or first run)
4496         function _fnFilterData ( settings )
4497         {
4498                 var columns = settings.aoColumns;
4499                 var column;
4500                 var i, j, ien, jen, filterData, cellData, row;
4501                 var fomatters = DataTable.ext.type.search;
4502                 var wasInvalidated = false;
4503         
4504                 for ( i=0, ien=settings.aoData.length ; i<ien ; i++ ) {
4505                         row = settings.aoData[i];
4506         
4507                         if ( ! row._aFilterData ) {
4508                                 filterData = [];
4509         
4510                                 for ( j=0, jen=columns.length ; j<jen ; j++ ) {
4511                                         column = columns[j];
4512         
4513                                         if ( column.bSearchable ) {
4514                                                 cellData = _fnGetCellData( settings, i, j, 'filter' );
4515         
4516                                                 if ( fomatters[ column.sType ] ) {
4517                                                         cellData = fomatters[ column.sType ]( cellData );
4518                                                 }
4519         
4520                                                 // Search in DataTables 1.10 is string based. In 1.11 this
4521                                                 // should be altered to also allow strict type checking.
4522                                                 if ( cellData === null ) {
4523                                                         cellData = '';
4524                                                 }
4525         
4526                                                 if ( typeof cellData !== 'string' && cellData.toString ) {
4527                                                         cellData = cellData.toString();
4528                                                 }
4529                                         }
4530                                         else {
4531                                                 cellData = '';
4532                                         }
4533         
4534                                         // If it looks like there is an HTML entity in the string,
4535                                         // attempt to decode it so sorting works as expected. Note that
4536                                         // we could use a single line of jQuery to do this, but the DOM
4537                                         // method used here is much faster http://jsperf.com/html-decode
4538                                         if ( cellData.indexOf && cellData.indexOf('&') !== -1 ) {
4539                                                 __filter_div.innerHTML = cellData;
4540                                                 cellData = __filter_div_textContent ?
4541                                                         __filter_div.textContent :
4542                                                         __filter_div.innerText;
4543                                         }
4544         
4545                                         if ( cellData.replace ) {
4546                                                 cellData = cellData.replace(/[\r\n\u2028]/g, '');
4547                                         }
4548         
4549                                         filterData.push( cellData );
4550                                 }
4551         
4552                                 row._aFilterData = filterData;
4553                                 row._sFilterRow = filterData.join('  ');
4554                                 wasInvalidated = true;
4555                         }
4556                 }
4557         
4558                 return wasInvalidated;
4559         }
4560         
4561         
4562         /**
4563          * Convert from the internal Hungarian notation to camelCase for external
4564          * interaction
4565          *  @param {object} obj Object to convert
4566          *  @returns {object} Inverted object
4567          *  @memberof DataTable#oApi
4568          */
4569         function _fnSearchToCamel ( obj )
4570         {
4571                 return {
4572                         search:          obj.sSearch,
4573                         smart:           obj.bSmart,
4574                         regex:           obj.bRegex,
4575                         caseInsensitive: obj.bCaseInsensitive
4576                 };
4577         }
4578         
4579         
4580         
4581         /**
4582          * Convert from camelCase notation to the internal Hungarian. We could use the
4583          * Hungarian convert function here, but this is cleaner
4584          *  @param {object} obj Object to convert
4585          *  @returns {object} Inverted object
4586          *  @memberof DataTable#oApi
4587          */
4588         function _fnSearchToHung ( obj )
4589         {
4590                 return {
4591                         sSearch:          obj.search,
4592                         bSmart:           obj.smart,
4593                         bRegex:           obj.regex,
4594                         bCaseInsensitive: obj.caseInsensitive
4595                 };
4596         }
4597         
4598         /**
4599          * Generate the node required for the info display
4600          *  @param {object} oSettings dataTables settings object
4601          *  @returns {node} Information element
4602          *  @memberof DataTable#oApi
4603          */
4604         function _fnFeatureHtmlInfo ( settings )
4605         {
4606                 var
4607                         tid = settings.sTableId,
4608                         nodes = settings.aanFeatures.i,
4609                         n = $('<div/>', {
4610                                 'class': settings.oClasses.sInfo,
4611                                 'id': ! nodes ? tid+'_info' : null
4612                         } );
4613         
4614                 if ( ! nodes ) {
4615                         // Update display on each draw
4616                         settings.aoDrawCallback.push( {
4617                                 "fn": _fnUpdateInfo,
4618                                 "sName": "information"
4619                         } );
4620         
4621                         n
4622                                 .attr( 'role', 'status' )
4623                                 .attr( 'aria-live', 'polite' );
4624         
4625                         // Table is described by our info div
4626                         $(settings.nTable).attr( 'aria-describedby', tid+'_info' );
4627                 }
4628         
4629                 return n[0];
4630         }
4631         
4632         
4633         /**
4634          * Update the information elements in the display
4635          *  @param {object} settings dataTables settings object
4636          *  @memberof DataTable#oApi
4637          */
4638         function _fnUpdateInfo ( settings )
4639         {
4640                 /* Show information about the table */
4641                 var nodes = settings.aanFeatures.i;
4642                 if ( nodes.length === 0 ) {
4643                         return;
4644                 }
4645         
4646                 var
4647                         lang  = settings.oLanguage,
4648                         start = settings._iDisplayStart+1,
4649                         end   = settings.fnDisplayEnd(),
4650                         max   = settings.fnRecordsTotal(),
4651                         total = settings.fnRecordsDisplay(),
4652                         out   = total ?
4653                                 lang.sInfo :
4654                                 lang.sInfoEmpty;
4655         
4656                 if ( total !== max ) {
4657                         /* Record set after filtering */
4658                         out += ' ' + lang.sInfoFiltered;
4659                 }
4660         
4661                 // Convert the macros
4662                 out += lang.sInfoPostFix;
4663                 out = _fnInfoMacros( settings, out );
4664         
4665                 var callback = lang.fnInfoCallback;
4666                 if ( callback !== null ) {
4667                         out = callback.call( settings.oInstance,
4668                                 settings, start, end, max, total, out
4669                         );
4670                 }
4671         
4672                 $(nodes).html( out );
4673         }
4674         
4675         
4676         function _fnInfoMacros ( settings, str )
4677         {
4678                 // When infinite scrolling, we are always starting at 1. _iDisplayStart is used only
4679                 // internally
4680                 var
4681                         formatter  = settings.fnFormatNumber,
4682                         start      = settings._iDisplayStart+1,
4683                         len        = settings._iDisplayLength,
4684                         vis        = settings.fnRecordsDisplay(),
4685                         all        = len === -1;
4686         
4687                 return str.
4688                         replace(/_START_/g, formatter.call( settings, start ) ).
4689                         replace(/_END_/g,   formatter.call( settings, settings.fnDisplayEnd() ) ).
4690                         replace(/_MAX_/g,   formatter.call( settings, settings.fnRecordsTotal() ) ).
4691                         replace(/_TOTAL_/g, formatter.call( settings, vis ) ).
4692                         replace(/_PAGE_/g,  formatter.call( settings, all ? 1 : Math.ceil( start / len ) ) ).
4693                         replace(/_PAGES_/g, formatter.call( settings, all ? 1 : Math.ceil( vis / len ) ) );
4694         }
4695         
4696         
4697         
4698         /**
4699          * Draw the table for the first time, adding all required features
4700          *  @param {object} settings dataTables settings object
4701          *  @memberof DataTable#oApi
4702          */
4703         function _fnInitialise ( settings )
4704         {
4705                 var i, iLen, iAjaxStart=settings.iInitDisplayStart;
4706                 var columns = settings.aoColumns, column;
4707                 var features = settings.oFeatures;
4708                 var deferLoading = settings.bDeferLoading; // value modified by the draw
4709         
4710                 /* Ensure that the table data is fully initialised */
4711                 if ( ! settings.bInitialised ) {
4712                         setTimeout( function(){ _fnInitialise( settings ); }, 200 );
4713                         return;
4714                 }
4715         
4716                 /* Show the display HTML options */
4717                 _fnAddOptionsHtml( settings );
4718         
4719                 /* Build and draw the header / footer for the table */
4720                 _fnBuildHead( settings );
4721                 _fnDrawHead( settings, settings.aoHeader );
4722                 _fnDrawHead( settings, settings.aoFooter );
4723         
4724                 /* Okay to show that something is going on now */
4725                 _fnProcessingDisplay( settings, true );
4726         
4727                 /* Calculate sizes for columns */
4728                 if ( features.bAutoWidth ) {
4729                         _fnCalculateColumnWidths( settings );
4730                 }
4731         
4732                 for ( i=0, iLen=columns.length ; i<iLen ; i++ ) {
4733                         column = columns[i];
4734         
4735                         if ( column.sWidth ) {
4736                                 column.nTh.style.width = _fnStringToCss( column.sWidth );
4737                         }
4738                 }
4739         
4740                 _fnCallbackFire( settings, null, 'preInit', [settings] );
4741         
4742                 // If there is default sorting required - let's do it. The sort function
4743                 // will do the drawing for us. Otherwise we draw the table regardless of the
4744                 // Ajax source - this allows the table to look initialised for Ajax sourcing
4745                 // data (show 'loading' message possibly)
4746                 _fnReDraw( settings );
4747         
4748                 // Server-side processing init complete is done by _fnAjaxUpdateDraw
4749                 var dataSrc = _fnDataSource( settings );
4750                 if ( dataSrc != 'ssp' || deferLoading ) {
4751                         // if there is an ajax source load the data
4752                         if ( dataSrc == 'ajax' ) {
4753                                 _fnBuildAjax( settings, [], function(json) {
4754                                         var aData = _fnAjaxDataSrc( settings, json );
4755         
4756                                         // Got the data - add it to the table
4757                                         for ( i=0 ; i<aData.length ; i++ ) {
4758                                                 _fnAddData( settings, aData[i] );
4759                                         }
4760         
4761                                         // Reset the init display for cookie saving. We've already done
4762                                         // a filter, and therefore cleared it before. So we need to make
4763                                         // it appear 'fresh'
4764                                         settings.iInitDisplayStart = iAjaxStart;
4765         
4766                                         _fnReDraw( settings );
4767         
4768                                         _fnProcessingDisplay( settings, false );
4769                                         _fnInitComplete( settings, json );
4770                                 }, settings );
4771                         }
4772                         else {
4773                                 _fnProcessingDisplay( settings, false );
4774                                 _fnInitComplete( settings );
4775                         }
4776                 }
4777         }
4778         
4779         
4780         /**
4781          * Draw the table for the first time, adding all required features
4782          *  @param {object} oSettings dataTables settings object
4783          *  @param {object} [json] JSON from the server that completed the table, if using Ajax source
4784          *    with client-side processing (optional)
4785          *  @memberof DataTable#oApi
4786          */
4787         function _fnInitComplete ( settings, json )
4788         {
4789                 settings._bInitComplete = true;
4790         
4791                 // When data was added after the initialisation (data or Ajax) we need to
4792                 // calculate the column sizing
4793                 if ( json || settings.oInit.aaData ) {
4794                         _fnAdjustColumnSizing( settings );
4795                 }
4796         
4797                 _fnCallbackFire( settings, null, 'plugin-init', [settings, json] );
4798                 _fnCallbackFire( settings, 'aoInitComplete', 'init', [settings, json] );
4799         }
4800         
4801         
4802         function _fnLengthChange ( settings, val )
4803         {
4804                 var len = parseInt( val, 10 );
4805                 settings._iDisplayLength = len;
4806         
4807                 _fnLengthOverflow( settings );
4808         
4809                 // Fire length change event
4810                 _fnCallbackFire( settings, null, 'length', [settings, len] );
4811         }
4812         
4813         
4814         /**
4815          * Generate the node required for user display length changing
4816          *  @param {object} settings dataTables settings object
4817          *  @returns {node} Display length feature node
4818          *  @memberof DataTable#oApi
4819          */
4820         function _fnFeatureHtmlLength ( settings )
4821         {
4822                 var
4823                         classes  = settings.oClasses,
4824                         tableId  = settings.sTableId,
4825                         menu     = settings.aLengthMenu,
4826                         d2       = $.isArray( menu[0] ),
4827                         lengths  = d2 ? menu[0] : menu,
4828                         language = d2 ? menu[1] : menu;
4829         
4830                 var select = $('<select/>', {
4831                         'name':          tableId+'_length',
4832                         'aria-controls': tableId,
4833                         'class':         classes.sLengthSelect
4834                 } );
4835         
4836                 for ( var i=0, ien=lengths.length ; i<ien ; i++ ) {
4837                         select[0][ i ] = new Option(
4838                                 typeof language[i] === 'number' ?
4839                                         settings.fnFormatNumber( language[i] ) :
4840                                         language[i],
4841                                 lengths[i]
4842                         );
4843                 }
4844         
4845                 var div = $('<div><label/></div>').addClass( classes.sLength );
4846                 if ( ! settings.aanFeatures.l ) {
4847                         div[0].id = tableId+'_length';
4848                 }
4849         
4850                 div.children().append(
4851                         settings.oLanguage.sLengthMenu.replace( '_MENU_', select[0].outerHTML )
4852                 );
4853         
4854                 // Can't use `select` variable as user might provide their own and the
4855                 // reference is broken by the use of outerHTML
4856                 $('select', div)
4857                         .val( settings._iDisplayLength )
4858                         .on( 'change.DT', function(e) {
4859                                 _fnLengthChange( settings, $(this).val() );
4860                                 _fnDraw( settings );
4861                         } );
4862         
4863                 // Update node value whenever anything changes the table's length
4864                 $(settings.nTable).on( 'length.dt.DT', function (e, s, len) {
4865                         if ( settings === s ) {
4866                                 $('select', div).val( len );
4867                         }
4868                 } );
4869         
4870                 return div[0];
4871         }
4872         
4873         
4874         
4875         /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
4876          * Note that most of the paging logic is done in
4877          * DataTable.ext.pager
4878          */
4879         
4880         /**
4881          * Generate the node required for default pagination
4882          *  @param {object} oSettings dataTables settings object
4883          *  @returns {node} Pagination feature node
4884          *  @memberof DataTable#oApi
4885          */
4886         function _fnFeatureHtmlPaginate ( settings )
4887         {
4888                 var
4889                         type   = settings.sPaginationType,
4890                         plugin = DataTable.ext.pager[ type ],
4891                         modern = typeof plugin === 'function',
4892                         redraw = function( settings ) {
4893                                 _fnDraw( settings );
4894                         },
4895                         node = $('<div/>').addClass( settings.oClasses.sPaging + type )[0],
4896                         features = settings.aanFeatures;
4897         
4898                 if ( ! modern ) {
4899                         plugin.fnInit( settings, node, redraw );
4900                 }
4901         
4902                 /* Add a draw callback for the pagination on first instance, to update the paging display */
4903                 if ( ! features.p )
4904                 {
4905                         node.id = settings.sTableId+'_paginate';
4906         
4907                         settings.aoDrawCallback.push( {
4908                                 "fn": function( settings ) {
4909                                         if ( modern ) {
4910                                                 var
4911                                                         start      = settings._iDisplayStart,
4912                                                         len        = settings._iDisplayLength,
4913                                                         visRecords = settings.fnRecordsDisplay(),
4914                                                         all        = len === -1,
4915                                                         page = all ? 0 : Math.ceil( start / len ),
4916                                                         pages = all ? 1 : Math.ceil( visRecords / len ),
4917                                                         buttons = plugin(page, pages),
4918                                                         i, ien;
4919         
4920                                                 for ( i=0, ien=features.p.length ; i<ien ; i++ ) {
4921                                                         _fnRenderer( settings, 'pageButton' )(
4922                                                                 settings, features.p[i], i, buttons, page, pages
4923                                                         );
4924                                                 }
4925                                         }
4926                                         else {
4927                                                 plugin.fnUpdate( settings, redraw );
4928                                         }
4929                                 },
4930                                 "sName": "pagination"
4931                         } );
4932                 }
4933         
4934                 return node;
4935         }
4936         
4937         
4938         /**
4939          * Alter the display settings to change the page
4940          *  @param {object} settings DataTables settings object
4941          *  @param {string|int} action Paging action to take: "first", "previous",
4942          *    "next" or "last" or page number to jump to (integer)
4943          *  @param [bool] redraw Automatically draw the update or not
4944          *  @returns {bool} true page has changed, false - no change
4945          *  @memberof DataTable#oApi
4946          */
4947         function _fnPageChange ( settings, action, redraw )
4948         {
4949                 var
4950                         start     = settings._iDisplayStart,
4951                         len       = settings._iDisplayLength,
4952                         records   = settings.fnRecordsDisplay();
4953         
4954                 if ( records === 0 || len === -1 )
4955                 {
4956                         start = 0;
4957                 }
4958                 else if ( typeof action === "number" )
4959                 {
4960                         start = action * len;
4961         
4962                         if ( start > records )
4963                         {
4964                                 start = 0;
4965                         }
4966                 }
4967                 else if ( action == "first" )
4968                 {
4969                         start = 0;
4970                 }
4971                 else if ( action == "previous" )
4972                 {
4973                         start = len >= 0 ?
4974                                 start - len :
4975                                 0;
4976         
4977                         if ( start < 0 )
4978                         {
4979                           start = 0;
4980                         }
4981                 }
4982                 else if ( action == "next" )
4983                 {
4984                         if ( start + len < records )
4985                         {
4986                                 start += len;
4987                         }
4988                 }
4989                 else if ( action == "last" )
4990                 {
4991                         start = Math.floor( (records-1) / len) * len;
4992                 }
4993                 else
4994                 {
4995                         _fnLog( settings, 0, "Unknown paging action: "+action, 5 );
4996                 }
4997         
4998                 var changed = settings._iDisplayStart !== start;
4999                 settings._iDisplayStart = start;
5000         
5001                 if ( changed ) {
5002                         _fnCallbackFire( settings, null, 'page', [settings] );
5003         
5004                         if ( redraw ) {
5005                                 _fnDraw( settings );
5006                         }
5007                 }
5008         
5009                 return changed;
5010         }
5011         
5012         
5013         
5014         /**
5015          * Generate the node required for the processing node
5016          *  @param {object} settings dataTables settings object
5017          *  @returns {node} Processing element
5018          *  @memberof DataTable#oApi
5019          */
5020         function _fnFeatureHtmlProcessing ( settings )
5021         {
5022                 return $('<div/>', {
5023                                 'id': ! settings.aanFeatures.r ? settings.sTableId+'_processing' : null,
5024                                 'class': settings.oClasses.sProcessing
5025                         } )
5026                         .html( settings.oLanguage.sProcessing )
5027                         .insertBefore( settings.nTable )[0];
5028         }
5029         
5030         
5031         /**
5032          * Display or hide the processing indicator
5033          *  @param {object} settings dataTables settings object
5034          *  @param {bool} show Show the processing indicator (true) or not (false)
5035          *  @memberof DataTable#oApi
5036          */
5037         function _fnProcessingDisplay ( settings, show )
5038         {
5039                 if ( settings.oFeatures.bProcessing ) {
5040                         $(settings.aanFeatures.r).css( 'display', show ? 'block' : 'none' );
5041                 }
5042         
5043                 _fnCallbackFire( settings, null, 'processing', [settings, show] );
5044         }
5045         
5046         /**
5047          * Add any control elements for the table - specifically scrolling
5048          *  @param {object} settings dataTables settings object
5049          *  @returns {node} Node to add to the DOM
5050          *  @memberof DataTable#oApi
5051          */
5052         function _fnFeatureHtmlTable ( settings )
5053         {
5054                 var table = $(settings.nTable);
5055         
5056                 // Add the ARIA grid role to the table
5057                 table.attr( 'role', 'grid' );
5058         
5059                 // Scrolling from here on in
5060                 var scroll = settings.oScroll;
5061         
5062                 if ( scroll.sX === '' && scroll.sY === '' ) {
5063                         return settings.nTable;
5064                 }
5065         
5066                 var scrollX = scroll.sX;
5067                 var scrollY = scroll.sY;
5068                 var classes = settings.oClasses;
5069                 var caption = table.children('caption');
5070                 var captionSide = caption.length ? caption[0]._captionSide : null;
5071                 var headerClone = $( table[0].cloneNode(false) );
5072                 var footerClone = $( table[0].cloneNode(false) );
5073                 var footer = table.children('tfoot');
5074                 var _div = '<div/>';
5075                 var size = function ( s ) {
5076                         return !s ? null : _fnStringToCss( s );
5077                 };
5078         
5079                 if ( ! footer.length ) {
5080                         footer = null;
5081                 }
5082         
5083                 /*
5084                  * The HTML structure that we want to generate in this function is:
5085                  *  div - scroller
5086                  *    div - scroll head
5087                  *      div - scroll head inner
5088                  *        table - scroll head table
5089                  *          thead - thead
5090                  *    div - scroll body
5091                  *      table - table (master table)
5092                  *        thead - thead clone for sizing
5093                  *        tbody - tbody
5094                  *    div - scroll foot
5095                  *      div - scroll foot inner
5096                  *        table - scroll foot table
5097                  *          tfoot - tfoot
5098                  */
5099                 var scroller = $( _div, { 'class': classes.sScrollWrapper } )
5100                         .append(
5101                                 $(_div, { 'class': classes.sScrollHead } )
5102                                         .css( {
5103                                                 overflow: 'hidden',
5104                                                 position: 'relative',
5105                                                 border: 0,
5106                                                 width: scrollX ? size(scrollX) : '100%'
5107                                         } )
5108                                         .append(
5109                                                 $(_div, { 'class': classes.sScrollHeadInner } )
5110                                                         .css( {
5111                                                                 'box-sizing': 'content-box',
5112                                                                 width: scroll.sXInner || '100%'
5113                                                         } )
5114                                                         .append(
5115                                                                 headerClone
5116                                                                         .removeAttr('id')
5117                                                                         .css( 'margin-left', 0 )
5118                                                                         .append( captionSide === 'top' ? caption : null )
5119                                                                         .append(
5120                                                                                 table.children('thead')
5121                                                                         )
5122                                                         )
5123                                         )
5124                         )
5125                         .append(
5126                                 $(_div, { 'class': classes.sScrollBody } )
5127                                         .css( {
5128                                                 position: 'relative',
5129                                                 overflow: 'auto',
5130                                                 width: size( scrollX )
5131                                         } )
5132                                         .append( table )
5133                         );
5134         
5135                 if ( footer ) {
5136                         scroller.append(
5137                                 $(_div, { 'class': classes.sScrollFoot } )
5138                                         .css( {
5139                                                 overflow: 'hidden',
5140                                                 border: 0,
5141                                                 width: scrollX ? size(scrollX) : '100%'
5142                                         } )
5143                                         .append(
5144                                                 $(_div, { 'class': classes.sScrollFootInner } )
5145                                                         .append(
5146                                                                 footerClone
5147                                                                         .removeAttr('id')
5148                                                                         .css( 'margin-left', 0 )
5149                                                                         .append( captionSide === 'bottom' ? caption : null )
5150                                                                         .append(
5151                                                                                 table.children('tfoot')
5152                                                                         )
5153                                                         )
5154                                         )
5155                         );
5156                 }
5157         
5158                 var children = scroller.children();
5159                 var scrollHead = children[0];
5160                 var scrollBody = children[1];
5161                 var scrollFoot = footer ? children[2] : null;
5162         
5163                 // When the body is scrolled, then we also want to scroll the headers
5164                 if ( scrollX ) {
5165                         $(scrollBody).on( 'scroll.DT', function (e) {
5166                                 var scrollLeft = this.scrollLeft;
5167         
5168                                 scrollHead.scrollLeft = scrollLeft;
5169         
5170                                 if ( footer ) {
5171                                         scrollFoot.scrollLeft = scrollLeft;
5172                                 }
5173                         } );
5174                 }
5175         
5176                 $(scrollBody).css(
5177                         scrollY && scroll.bCollapse ? 'max-height' : 'height', 
5178                         scrollY
5179                 );
5180         
5181                 settings.nScrollHead = scrollHead;
5182                 settings.nScrollBody = scrollBody;
5183                 settings.nScrollFoot = scrollFoot;
5184         
5185                 // On redraw - align columns
5186                 settings.aoDrawCallback.push( {
5187                         "fn": _fnScrollDraw,
5188                         "sName": "scrolling"
5189                 } );
5190         
5191                 return scroller[0];
5192         }
5193         
5194         
5195         
5196         /**
5197          * Update the header, footer and body tables for resizing - i.e. column
5198          * alignment.
5199          *
5200          * Welcome to the most horrible function DataTables. The process that this
5201          * function follows is basically:
5202          *   1. Re-create the table inside the scrolling div
5203          *   2. Take live measurements from the DOM
5204          *   3. Apply the measurements to align the columns
5205          *   4. Clean up
5206          *
5207          *  @param {object} settings dataTables settings object
5208          *  @memberof DataTable#oApi
5209          */
5210         function _fnScrollDraw ( settings )
5211         {
5212                 // Given that this is such a monster function, a lot of variables are use
5213                 // to try and keep the minimised size as small as possible
5214                 var
5215                         scroll         = settings.oScroll,
5216                         scrollX        = scroll.sX,
5217                         scrollXInner   = scroll.sXInner,
5218                         scrollY        = scroll.sY,
5219                         barWidth       = scroll.iBarWidth,
5220                         divHeader      = $(settings.nScrollHead),
5221                         divHeaderStyle = divHeader[0].style,
5222                         divHeaderInner = divHeader.children('div'),
5223                         divHeaderInnerStyle = divHeaderInner[0].style,
5224                         divHeaderTable = divHeaderInner.children('table'),
5225                         divBodyEl      = settings.nScrollBody,
5226                         divBody        = $(divBodyEl),
5227                         divBodyStyle   = divBodyEl.style,
5228                         divFooter      = $(settings.nScrollFoot),
5229                         divFooterInner = divFooter.children('div'),
5230                         divFooterTable = divFooterInner.children('table'),
5231                         header         = $(settings.nTHead),
5232                         table          = $(settings.nTable),
5233                         tableEl        = table[0],
5234                         tableStyle     = tableEl.style,
5235                         footer         = settings.nTFoot ? $(settings.nTFoot) : null,
5236                         browser        = settings.oBrowser,
5237                         ie67           = browser.bScrollOversize,
5238                         dtHeaderCells  = _pluck( settings.aoColumns, 'nTh' ),
5239                         headerTrgEls, footerTrgEls,
5240                         headerSrcEls, footerSrcEls,
5241                         headerCopy, footerCopy,
5242                         headerWidths=[], footerWidths=[],
5243                         headerContent=[], footerContent=[],
5244                         idx, correction, sanityWidth,
5245                         zeroOut = function(nSizer) {
5246                                 var style = nSizer.style;
5247                                 style.paddingTop = "0";
5248                                 style.paddingBottom = "0";
5249                                 style.borderTopWidth = "0";
5250                                 style.borderBottomWidth = "0";
5251                                 style.height = 0;
5252                         };
5253         
5254                 // If the scrollbar visibility has changed from the last draw, we need to
5255                 // adjust the column sizes as the table width will have changed to account
5256                 // for the scrollbar
5257                 var scrollBarVis = divBodyEl.scrollHeight > divBodyEl.clientHeight;
5258                 
5259                 if ( settings.scrollBarVis !== scrollBarVis && settings.scrollBarVis !== undefined ) {
5260                         settings.scrollBarVis = scrollBarVis;
5261                         _fnAdjustColumnSizing( settings );
5262                         return; // adjust column sizing will call this function again
5263                 }
5264                 else {
5265                         settings.scrollBarVis = scrollBarVis;
5266                 }
5267         
5268                 /*
5269                  * 1. Re-create the table inside the scrolling div
5270                  */
5271         
5272                 // Remove the old minimised thead and tfoot elements in the inner table
5273                 table.children('thead, tfoot').remove();
5274         
5275                 if ( footer ) {
5276                         footerCopy = footer.clone().prependTo( table );
5277                         footerTrgEls = footer.find('tr'); // the original tfoot is in its own table and must be sized
5278                         footerSrcEls = footerCopy.find('tr');
5279                 }
5280         
5281                 // Clone the current header and footer elements and then place it into the inner table
5282                 headerCopy = header.clone().prependTo( table );
5283                 headerTrgEls = header.find('tr'); // original header is in its own table
5284                 headerSrcEls = headerCopy.find('tr');
5285                 headerCopy.find('th, td').removeAttr('tabindex');
5286         
5287         
5288                 /*
5289                  * 2. Take live measurements from the DOM - do not alter the DOM itself!
5290                  */
5291         
5292                 // Remove old sizing and apply the calculated column widths
5293                 // Get the unique column headers in the newly created (cloned) header. We want to apply the
5294                 // calculated sizes to this header
5295                 if ( ! scrollX )
5296                 {
5297                         divBodyStyle.width = '100%';
5298                         divHeader[0].style.width = '100%';
5299                 }
5300         
5301                 $.each( _fnGetUniqueThs( settings, headerCopy ), function ( i, el ) {
5302                         idx = _fnVisibleToColumnIndex( settings, i );
5303                         el.style.width = settings.aoColumns[idx].sWidth;
5304                 } );
5305         
5306                 if ( footer ) {
5307                         _fnApplyToChildren( function(n) {
5308                                 n.style.width = "";
5309                         }, footerSrcEls );
5310                 }
5311         
5312                 // Size the table as a whole
5313                 sanityWidth = table.outerWidth();
5314                 if ( scrollX === "" ) {
5315                         // No x scrolling
5316                         tableStyle.width = "100%";
5317         
5318                         // IE7 will make the width of the table when 100% include the scrollbar
5319                         // - which is shouldn't. When there is a scrollbar we need to take this
5320                         // into account.
5321                         if ( ie67 && (table.find('tbody').height() > divBodyEl.offsetHeight ||
5322                                 divBody.css('overflow-y') == "scroll")
5323                         ) {
5324                                 tableStyle.width = _fnStringToCss( table.outerWidth() - barWidth);
5325                         }
5326         
5327                         // Recalculate the sanity width
5328                         sanityWidth = table.outerWidth();
5329                 }
5330                 else if ( scrollXInner !== "" ) {
5331                         // legacy x scroll inner has been given - use it
5332                         tableStyle.width = _fnStringToCss(scrollXInner);
5333         
5334                         // Recalculate the sanity width
5335                         sanityWidth = table.outerWidth();
5336                 }
5337         
5338                 // Hidden header should have zero height, so remove padding and borders. Then
5339                 // set the width based on the real headers
5340         
5341                 // Apply all styles in one pass
5342                 _fnApplyToChildren( zeroOut, headerSrcEls );
5343         
5344                 // Read all widths in next pass
5345                 _fnApplyToChildren( function(nSizer) {
5346                         headerContent.push( nSizer.innerHTML );
5347                         headerWidths.push( _fnStringToCss( $(nSizer).css('width') ) );
5348                 }, headerSrcEls );
5349         
5350                 // Apply all widths in final pass
5351                 _fnApplyToChildren( function(nToSize, i) {
5352                         // Only apply widths to the DataTables detected header cells - this
5353                         // prevents complex headers from having contradictory sizes applied
5354                         if ( $.inArray( nToSize, dtHeaderCells ) !== -1 ) {
5355                                 nToSize.style.width = headerWidths[i];
5356                         }
5357                 }, headerTrgEls );
5358         
5359                 $(headerSrcEls).height(0);
5360         
5361                 /* Same again with the footer if we have one */
5362                 if ( footer )
5363                 {
5364                         _fnApplyToChildren( zeroOut, footerSrcEls );
5365         
5366                         _fnApplyToChildren( function(nSizer) {
5367                                 footerContent.push( nSizer.innerHTML );
5368                                 footerWidths.push( _fnStringToCss( $(nSizer).css('width') ) );
5369                         }, footerSrcEls );
5370         
5371                         _fnApplyToChildren( function(nToSize, i) {
5372                                 nToSize.style.width = footerWidths[i];
5373                         }, footerTrgEls );
5374         
5375                         $(footerSrcEls).height(0);
5376                 }
5377         
5378         
5379                 /*
5380                  * 3. Apply the measurements
5381                  */
5382         
5383                 // "Hide" the header and footer that we used for the sizing. We need to keep
5384                 // the content of the cell so that the width applied to the header and body
5385                 // both match, but we want to hide it completely. We want to also fix their
5386                 // width to what they currently are
5387                 _fnApplyToChildren( function(nSizer, i) {
5388                         nSizer.innerHTML = '<div class="dataTables_sizing">'+headerContent[i]+'</div>';
5389                         nSizer.childNodes[0].style.height = "0";
5390                         nSizer.childNodes[0].style.overflow = "hidden";
5391                         nSizer.style.width = headerWidths[i];
5392                 }, headerSrcEls );
5393         
5394                 if ( footer )
5395                 {
5396                         _fnApplyToChildren( function(nSizer, i) {
5397                                 nSizer.innerHTML = '<div class="dataTables_sizing">'+footerContent[i]+'</div>';
5398                                 nSizer.childNodes[0].style.height = "0";
5399                                 nSizer.childNodes[0].style.overflow = "hidden";
5400                                 nSizer.style.width = footerWidths[i];
5401                         }, footerSrcEls );
5402                 }
5403         
5404                 // Sanity check that the table is of a sensible width. If not then we are going to get
5405                 // misalignment - try to prevent this by not allowing the table to shrink below its min width
5406                 if ( table.outerWidth() < sanityWidth )
5407                 {
5408                         // The min width depends upon if we have a vertical scrollbar visible or not */
5409                         correction = ((divBodyEl.scrollHeight > divBodyEl.offsetHeight ||
5410                                 divBody.css('overflow-y') == "scroll")) ?
5411                                         sanityWidth+barWidth :
5412                                         sanityWidth;
5413         
5414                         // IE6/7 are a law unto themselves...
5415                         if ( ie67 && (divBodyEl.scrollHeight >
5416                                 divBodyEl.offsetHeight || divBody.css('overflow-y') == "scroll")
5417                         ) {
5418                                 tableStyle.width = _fnStringToCss( correction-barWidth );
5419                         }
5420         
5421                         // And give the user a warning that we've stopped the table getting too small
5422                         if ( scrollX === "" || scrollXInner !== "" ) {
5423                                 _fnLog( settings, 1, 'Possible column misalignment', 6 );
5424                         }
5425                 }
5426                 else
5427                 {
5428                         correction = '100%';
5429                 }
5430         
5431                 // Apply to the container elements
5432                 divBodyStyle.width = _fnStringToCss( correction );
5433                 divHeaderStyle.width = _fnStringToCss( correction );
5434         
5435                 if ( footer ) {
5436                         settings.nScrollFoot.style.width = _fnStringToCss( correction );
5437                 }
5438         
5439         
5440                 /*
5441                  * 4. Clean up
5442                  */
5443                 if ( ! scrollY ) {
5444                         /* IE7< puts a vertical scrollbar in place (when it shouldn't be) due to subtracting
5445                          * the scrollbar height from the visible display, rather than adding it on. We need to
5446                          * set the height in order to sort this. Don't want to do it in any other browsers.
5447                          */
5448                         if ( ie67 ) {
5449                                 divBodyStyle.height = _fnStringToCss( tableEl.offsetHeight+barWidth );
5450                         }
5451                 }
5452         
5453                 /* Finally set the width's of the header and footer tables */
5454                 var iOuterWidth = table.outerWidth();
5455                 divHeaderTable[0].style.width = _fnStringToCss( iOuterWidth );
5456                 divHeaderInnerStyle.width = _fnStringToCss( iOuterWidth );
5457         
5458                 // Figure out if there are scrollbar present - if so then we need a the header and footer to
5459                 // provide a bit more space to allow "overflow" scrolling (i.e. past the scrollbar)
5460                 var bScrolling = table.height() > divBodyEl.clientHeight || divBody.css('overflow-y') == "scroll";
5461                 var padding = 'padding' + (browser.bScrollbarLeft ? 'Left' : 'Right' );
5462                 divHeaderInnerStyle[ padding ] = bScrolling ? barWidth+"px" : "0px";
5463         
5464                 if ( footer ) {
5465                         divFooterTable[0].style.width = _fnStringToCss( iOuterWidth );
5466                         divFooterInner[0].style.width = _fnStringToCss( iOuterWidth );
5467                         divFooterInner[0].style[padding] = bScrolling ? barWidth+"px" : "0px";
5468                 }
5469         
5470                 // Correct DOM ordering for colgroup - comes before the thead
5471                 table.children('colgroup').insertBefore( table.children('thead') );
5472         
5473                 /* Adjust the position of the header in case we loose the y-scrollbar */
5474                 divBody.trigger('scroll');
5475         
5476                 // If sorting or filtering has occurred, jump the scrolling back to the top
5477                 // only if we aren't holding the position
5478                 if ( (settings.bSorted || settings.bFiltered) && ! settings._drawHold ) {
5479                         divBodyEl.scrollTop = 0;
5480                 }
5481         }
5482         
5483         
5484         
5485         /**
5486          * Apply a given function to the display child nodes of an element array (typically
5487          * TD children of TR rows
5488          *  @param {function} fn Method to apply to the objects
5489          *  @param array {nodes} an1 List of elements to look through for display children
5490          *  @param array {nodes} an2 Another list (identical structure to the first) - optional
5491          *  @memberof DataTable#oApi
5492          */
5493         function _fnApplyToChildren( fn, an1, an2 )
5494         {
5495                 var index=0, i=0, iLen=an1.length;
5496                 var nNode1, nNode2;
5497         
5498                 while ( i < iLen ) {
5499                         nNode1 = an1[i].firstChild;
5500                         nNode2 = an2 ? an2[i].firstChild : null;
5501         
5502                         while ( nNode1 ) {
5503                                 if ( nNode1.nodeType === 1 ) {
5504                                         if ( an2 ) {
5505                                                 fn( nNode1, nNode2, index );
5506                                         }
5507                                         else {
5508                                                 fn( nNode1, index );
5509                                         }
5510         
5511                                         index++;
5512                                 }
5513         
5514                                 nNode1 = nNode1.nextSibling;
5515                                 nNode2 = an2 ? nNode2.nextSibling : null;
5516                         }
5517         
5518                         i++;
5519                 }
5520         }
5521         
5522         
5523         
5524         var __re_html_remove = /<.*?>/g;
5525         
5526         
5527         /**
5528          * Calculate the width of columns for the table
5529          *  @param {object} oSettings dataTables settings object
5530          *  @memberof DataTable#oApi
5531          */
5532         function _fnCalculateColumnWidths ( oSettings )
5533         {
5534                 var
5535                         table = oSettings.nTable,
5536                         columns = oSettings.aoColumns,
5537                         scroll = oSettings.oScroll,
5538                         scrollY = scroll.sY,
5539                         scrollX = scroll.sX,
5540                         scrollXInner = scroll.sXInner,
5541                         columnCount = columns.length,
5542                         visibleColumns = _fnGetColumns( oSettings, 'bVisible' ),
5543                         headerCells = $('th', oSettings.nTHead),
5544                         tableWidthAttr = table.getAttribute('width'), // from DOM element
5545                         tableContainer = table.parentNode,
5546                         userInputs = false,
5547                         i, column, columnIdx, width, outerWidth,
5548                         browser = oSettings.oBrowser,
5549                         ie67 = browser.bScrollOversize;
5550         
5551                 var styleWidth = table.style.width;
5552                 if ( styleWidth && styleWidth.indexOf('%') !== -1 ) {
5553                         tableWidthAttr = styleWidth;
5554                 }
5555         
5556                 /* Convert any user input sizes into pixel sizes */
5557                 for ( i=0 ; i<visibleColumns.length ; i++ ) {
5558                         column = columns[ visibleColumns[i] ];
5559         
5560                         if ( column.sWidth !== null ) {
5561                                 column.sWidth = _fnConvertToWidth( column.sWidthOrig, tableContainer );
5562         
5563                                 userInputs = true;
5564                         }
5565                 }
5566         
5567                 /* If the number of columns in the DOM equals the number that we have to
5568                  * process in DataTables, then we can use the offsets that are created by
5569                  * the web- browser. No custom sizes can be set in order for this to happen,
5570                  * nor scrolling used
5571                  */
5572                 if ( ie67 || ! userInputs && ! scrollX && ! scrollY &&
5573                      columnCount == _fnVisbleColumns( oSettings ) &&
5574                      columnCount == headerCells.length
5575                 ) {
5576                         for ( i=0 ; i<columnCount ; i++ ) {
5577                                 var colIdx = _fnVisibleToColumnIndex( oSettings, i );
5578         
5579                                 if ( colIdx !== null ) {
5580                                         columns[ colIdx ].sWidth = _fnStringToCss( headerCells.eq(i).width() );
5581                                 }
5582                         }
5583                 }
5584                 else
5585                 {
5586                         // Otherwise construct a single row, worst case, table with the widest
5587                         // node in the data, assign any user defined widths, then insert it into
5588                         // the DOM and allow the browser to do all the hard work of calculating
5589                         // table widths
5590                         var tmpTable = $(table).clone() // don't use cloneNode - IE8 will remove events on the main table
5591                                 .css( 'visibility', 'hidden' )
5592                                 .removeAttr( 'id' );
5593         
5594                         // Clean up the table body
5595                         tmpTable.find('tbody tr').remove();
5596                         var tr = $('<tr/>').appendTo( tmpTable.find('tbody') );
5597         
5598                         // Clone the table header and footer - we can't use the header / footer
5599                         // from the cloned table, since if scrolling is active, the table's
5600                         // real header and footer are contained in different table tags
5601                         tmpTable.find('thead, tfoot').remove();
5602                         tmpTable
5603                                 .append( $(oSettings.nTHead).clone() )
5604                                 .append( $(oSettings.nTFoot).clone() );
5605         
5606                         // Remove any assigned widths from the footer (from scrolling)
5607                         tmpTable.find('tfoot th, tfoot td').css('width', '');
5608         
5609                         // Apply custom sizing to the cloned header
5610                         headerCells = _fnGetUniqueThs( oSettings, tmpTable.find('thead')[0] );
5611         
5612                         for ( i=0 ; i<visibleColumns.length ; i++ ) {
5613                                 column = columns[ visibleColumns[i] ];
5614         
5615                                 headerCells[i].style.width = column.sWidthOrig !== null && column.sWidthOrig !== '' ?
5616                                         _fnStringToCss( column.sWidthOrig ) :
5617                                         '';
5618         
5619                                 // For scrollX we need to force the column width otherwise the
5620                                 // browser will collapse it. If this width is smaller than the
5621                                 // width the column requires, then it will have no effect
5622                                 if ( column.sWidthOrig && scrollX ) {
5623                                         $( headerCells[i] ).append( $('<div/>').css( {
5624                                                 width: column.sWidthOrig,
5625                                                 margin: 0,
5626                                                 padding: 0,
5627                                                 border: 0,
5628                                                 height: 1
5629                                         } ) );
5630                                 }
5631                         }
5632         
5633                         // Find the widest cell for each column and put it into the table
5634                         if ( oSettings.aoData.length ) {
5635                                 for ( i=0 ; i<visibleColumns.length ; i++ ) {
5636                                         columnIdx = visibleColumns[i];
5637                                         column = columns[ columnIdx ];
5638         
5639                                         $( _fnGetWidestNode( oSettings, columnIdx ) )
5640                                                 .clone( false )
5641                                                 .append( column.sContentPadding )
5642                                                 .appendTo( tr );
5643                                 }
5644                         }
5645         
5646                         // Tidy the temporary table - remove name attributes so there aren't
5647                         // duplicated in the dom (radio elements for example)
5648                         $('[name]', tmpTable).removeAttr('name');
5649         
5650                         // Table has been built, attach to the document so we can work with it.
5651                         // A holding element is used, positioned at the top of the container
5652                         // with minimal height, so it has no effect on if the container scrolls
5653                         // or not. Otherwise it might trigger scrolling when it actually isn't
5654                         // needed
5655                         var holder = $('<div/>').css( scrollX || scrollY ?
5656                                         {
5657                                                 position: 'absolute',
5658                                                 top: 0,
5659                                                 left: 0,
5660                                                 height: 1,
5661                                                 right: 0,
5662                                                 overflow: 'hidden'
5663                                         } :
5664                                         {}
5665                                 )
5666                                 .append( tmpTable )
5667                                 .appendTo( tableContainer );
5668         
5669                         // When scrolling (X or Y) we want to set the width of the table as 
5670                         // appropriate. However, when not scrolling leave the table width as it
5671                         // is. This results in slightly different, but I think correct behaviour
5672                         if ( scrollX && scrollXInner ) {
5673                                 tmpTable.width( scrollXInner );
5674                         }
5675                         else if ( scrollX ) {
5676                                 tmpTable.css( 'width', 'auto' );
5677                                 tmpTable.removeAttr('width');
5678         
5679                                 // If there is no width attribute or style, then allow the table to
5680                                 // collapse
5681                                 if ( tmpTable.width() < tableContainer.clientWidth && tableWidthAttr ) {
5682                                         tmpTable.width( tableContainer.clientWidth );
5683                                 }
5684                         }
5685                         else if ( scrollY ) {
5686                                 tmpTable.width( tableContainer.clientWidth );
5687                         }
5688                         else if ( tableWidthAttr ) {
5689                                 tmpTable.width( tableWidthAttr );
5690                         }
5691         
5692                         // Get the width of each column in the constructed table - we need to
5693                         // know the inner width (so it can be assigned to the other table's
5694                         // cells) and the outer width so we can calculate the full width of the
5695                         // table. This is safe since DataTables requires a unique cell for each
5696                         // column, but if ever a header can span multiple columns, this will
5697                         // need to be modified.
5698                         var total = 0;
5699                         for ( i=0 ; i<visibleColumns.length ; i++ ) {
5700                                 var cell = $(headerCells[i]);
5701                                 var border = cell.outerWidth() - cell.width();
5702         
5703                                 // Use getBounding... where possible (not IE8-) because it can give
5704                                 // sub-pixel accuracy, which we then want to round up!
5705                                 var bounding = browser.bBounding ?
5706                                         Math.ceil( headerCells[i].getBoundingClientRect().width ) :
5707                                         cell.outerWidth();
5708         
5709                                 // Total is tracked to remove any sub-pixel errors as the outerWidth
5710                                 // of the table might not equal the total given here (IE!).
5711                                 total += bounding;
5712         
5713                                 // Width for each column to use
5714                                 columns[ visibleColumns[i] ].sWidth = _fnStringToCss( bounding - border );
5715                         }
5716         
5717                         table.style.width = _fnStringToCss( total );
5718         
5719                         // Finished with the table - ditch it
5720                         holder.remove();
5721                 }
5722         
5723                 // If there is a width attr, we want to attach an event listener which
5724                 // allows the table sizing to automatically adjust when the window is
5725                 // resized. Use the width attr rather than CSS, since we can't know if the
5726                 // CSS is a relative value or absolute - DOM read is always px.
5727                 if ( tableWidthAttr ) {
5728                         table.style.width = _fnStringToCss( tableWidthAttr );
5729                 }
5730         
5731                 if ( (tableWidthAttr || scrollX) && ! oSettings._reszEvt ) {
5732                         var bindResize = function () {
5733                                 $(window).on('resize.DT-'+oSettings.sInstance, _fnThrottle( function () {
5734                                         _fnAdjustColumnSizing( oSettings );
5735                                 } ) );
5736                         };
5737         
5738                         // IE6/7 will crash if we bind a resize event handler on page load.
5739                         // To be removed in 1.11 which drops IE6/7 support
5740                         if ( ie67 ) {
5741                                 setTimeout( bindResize, 1000 );
5742                         }
5743                         else {
5744                                 bindResize();
5745                         }
5746         
5747                         oSettings._reszEvt = true;
5748                 }
5749         }
5750         
5751         
5752         /**
5753          * Throttle the calls to a function. Arguments and context are maintained for
5754          * the throttled function
5755          *  @param {function} fn Function to be called
5756          *  @param {int} [freq=200] call frequency in mS
5757          *  @returns {function} wrapped function
5758          *  @memberof DataTable#oApi
5759          */
5760         var _fnThrottle = DataTable.util.throttle;
5761         
5762         
5763         /**
5764          * Convert a CSS unit width to pixels (e.g. 2em)
5765          *  @param {string} width width to be converted
5766          *  @param {node} parent parent to get the with for (required for relative widths) - optional
5767          *  @returns {int} width in pixels
5768          *  @memberof DataTable#oApi
5769          */
5770         function _fnConvertToWidth ( width, parent )
5771         {
5772                 if ( ! width ) {
5773                         return 0;
5774                 }
5775         
5776                 var n = $('<div/>')
5777                         .css( 'width', _fnStringToCss( width ) )
5778                         .appendTo( parent || document.body );
5779         
5780                 var val = n[0].offsetWidth;
5781                 n.remove();
5782         
5783                 return val;
5784         }
5785         
5786         
5787         /**
5788          * Get the widest node
5789          *  @param {object} settings dataTables settings object
5790          *  @param {int} colIdx column of interest
5791          *  @returns {node} widest table node
5792          *  @memberof DataTable#oApi
5793          */
5794         function _fnGetWidestNode( settings, colIdx )
5795         {
5796                 var idx = _fnGetMaxLenString( settings, colIdx );
5797                 if ( idx < 0 ) {
5798                         return null;
5799                 }
5800         
5801                 var data = settings.aoData[ idx ];
5802                 return ! data.nTr ? // Might not have been created when deferred rendering
5803                         $('<td/>').html( _fnGetCellData( settings, idx, colIdx, 'display' ) )[0] :
5804                         data.anCells[ colIdx ];
5805         }
5806         
5807         
5808         /**
5809          * Get the maximum strlen for each data column
5810          *  @param {object} settings dataTables settings object
5811          *  @param {int} colIdx column of interest
5812          *  @returns {string} max string length for each column
5813          *  @memberof DataTable#oApi
5814          */
5815         function _fnGetMaxLenString( settings, colIdx )
5816         {
5817                 var s, max=-1, maxIdx = -1;
5818         
5819                 for ( var i=0, ien=settings.aoData.length ; i<ien ; i++ ) {
5820                         s = _fnGetCellData( settings, i, colIdx, 'display' )+'';
5821                         s = s.replace( __re_html_remove, '' );
5822                         s = s.replace( /&nbsp;/g, ' ' );
5823         
5824                         if ( s.length > max ) {
5825                                 max = s.length;
5826                                 maxIdx = i;
5827                         }
5828                 }
5829         
5830                 return maxIdx;
5831         }
5832         
5833         
5834         /**
5835          * Append a CSS unit (only if required) to a string
5836          *  @param {string} value to css-ify
5837          *  @returns {string} value with css unit
5838          *  @memberof DataTable#oApi
5839          */
5840         function _fnStringToCss( s )
5841         {
5842                 if ( s === null ) {
5843                         return '0px';
5844                 }
5845         
5846                 if ( typeof s == 'number' ) {
5847                         return s < 0 ?
5848                                 '0px' :
5849                                 s+'px';
5850                 }
5851         
5852                 // Check it has a unit character already
5853                 return s.match(/\d$/) ?
5854                         s+'px' :
5855                         s;
5856         }
5857         
5858         
5859         
5860         function _fnSortFlatten ( settings )
5861         {
5862                 var
5863                         i, iLen, k, kLen,
5864                         aSort = [],
5865                         aiOrig = [],
5866                         aoColumns = settings.aoColumns,
5867                         aDataSort, iCol, sType, srcCol,
5868                         fixed = settings.aaSortingFixed,
5869                         fixedObj = $.isPlainObject( fixed ),
5870                         nestedSort = [],
5871                         add = function ( a ) {
5872                                 if ( a.length && ! $.isArray( a[0] ) ) {
5873                                         // 1D array
5874                                         nestedSort.push( a );
5875                                 }
5876                                 else {
5877                                         // 2D array
5878                                         $.merge( nestedSort, a );
5879                                 }
5880                         };
5881         
5882                 // Build the sort array, with pre-fix and post-fix options if they have been
5883                 // specified
5884                 if ( $.isArray( fixed ) ) {
5885                         add( fixed );
5886                 }
5887         
5888                 if ( fixedObj && fixed.pre ) {
5889                         add( fixed.pre );
5890                 }
5891         
5892                 add( settings.aaSorting );
5893         
5894                 if (fixedObj && fixed.post ) {
5895                         add( fixed.post );
5896                 }
5897         
5898                 for ( i=0 ; i<nestedSort.length ; i++ )
5899                 {
5900                         srcCol = nestedSort[i][0];
5901                         aDataSort = aoColumns[ srcCol ].aDataSort;
5902         
5903                         for ( k=0, kLen=aDataSort.length ; k<kLen ; k++ )
5904                         {
5905                                 iCol = aDataSort[k];
5906                                 sType = aoColumns[ iCol ].sType || 'string';
5907         
5908                                 if ( nestedSort[i]._idx === undefined ) {
5909                                         nestedSort[i]._idx = $.inArray( nestedSort[i][1], aoColumns[iCol].asSorting );
5910                                 }
5911         
5912                                 aSort.push( {
5913                                         src:       srcCol,
5914                                         col:       iCol,
5915                                         dir:       nestedSort[i][1],
5916                                         index:     nestedSort[i]._idx,
5917                                         type:      sType,
5918                                         formatter: DataTable.ext.type.order[ sType+"-pre" ]
5919                                 } );
5920                         }
5921                 }
5922         
5923                 return aSort;
5924         }
5925         
5926         /**
5927          * Change the order of the table
5928          *  @param {object} oSettings dataTables settings object
5929          *  @memberof DataTable#oApi
5930          *  @todo This really needs split up!
5931          */
5932         function _fnSort ( oSettings )
5933         {
5934                 var
5935                         i, ien, iLen, j, jLen, k, kLen,
5936                         sDataType, nTh,
5937                         aiOrig = [],
5938                         oExtSort = DataTable.ext.type.order,
5939                         aoData = oSettings.aoData,
5940                         aoColumns = oSettings.aoColumns,
5941                         aDataSort, data, iCol, sType, oSort,
5942                         formatters = 0,
5943                         sortCol,
5944                         displayMaster = oSettings.aiDisplayMaster,
5945                         aSort;
5946         
5947                 // Resolve any column types that are unknown due to addition or invalidation
5948                 // @todo Can this be moved into a 'data-ready' handler which is called when
5949                 //   data is going to be used in the table?
5950                 _fnColumnTypes( oSettings );
5951         
5952                 aSort = _fnSortFlatten( oSettings );
5953         
5954                 for ( i=0, ien=aSort.length ; i<ien ; i++ ) {
5955                         sortCol = aSort[i];
5956         
5957                         // Track if we can use the fast sort algorithm
5958                         if ( sortCol.formatter ) {
5959                                 formatters++;
5960                         }
5961         
5962                         // Load the data needed for the sort, for each cell
5963                         _fnSortData( oSettings, sortCol.col );
5964                 }
5965         
5966                 /* No sorting required if server-side or no sorting array */
5967                 if ( _fnDataSource( oSettings ) != 'ssp' && aSort.length !== 0 )
5968                 {
5969                         // Create a value - key array of the current row positions such that we can use their
5970                         // current position during the sort, if values match, in order to perform stable sorting
5971                         for ( i=0, iLen=displayMaster.length ; i<iLen ; i++ ) {
5972                                 aiOrig[ displayMaster[i] ] = i;
5973                         }
5974         
5975                         /* Do the sort - here we want multi-column sorting based on a given data source (column)
5976                          * and sorting function (from oSort) in a certain direction. It's reasonably complex to
5977                          * follow on it's own, but this is what we want (example two column sorting):
5978                          *  fnLocalSorting = function(a,b){
5979                          *    var iTest;
5980                          *    iTest = oSort['string-asc']('data11', 'data12');
5981                          *      if (iTest !== 0)
5982                          *        return iTest;
5983                          *    iTest = oSort['numeric-desc']('data21', 'data22');
5984                          *    if (iTest !== 0)
5985                          *      return iTest;
5986                          *    return oSort['numeric-asc']( aiOrig[a], aiOrig[b] );
5987                          *  }
5988                          * Basically we have a test for each sorting column, if the data in that column is equal,
5989                          * test the next column. If all columns match, then we use a numeric sort on the row
5990                          * positions in the original data array to provide a stable sort.
5991                          *
5992                          * Note - I know it seems excessive to have two sorting methods, but the first is around
5993                          * 15% faster, so the second is only maintained for backwards compatibility with sorting
5994                          * methods which do not have a pre-sort formatting function.
5995                          */
5996                         if ( formatters === aSort.length ) {
5997                                 // All sort types have formatting functions
5998                                 displayMaster.sort( function ( a, b ) {
5999                                         var
6000                                                 x, y, k, test, sort,
6001                                                 len=aSort.length,
6002                                                 dataA = aoData[a]._aSortData,
6003                                                 dataB = aoData[b]._aSortData;
6004         
6005                                         for ( k=0 ; k<len ; k++ ) {
6006                                                 sort = aSort[k];
6007         
6008                                                 x = dataA[ sort.col ];
6009                                                 y = dataB[ sort.col ];
6010         
6011                                                 test = x<y ? -1 : x>y ? 1 : 0;
6012                                                 if ( test !== 0 ) {
6013                                                         return sort.dir === 'asc' ? test : -test;
6014                                                 }
6015                                         }
6016         
6017                                         x = aiOrig[a];
6018                                         y = aiOrig[b];
6019                                         return x<y ? -1 : x>y ? 1 : 0;
6020                                 } );
6021                         }
6022                         else {
6023                                 // Depreciated - remove in 1.11 (providing a plug-in option)
6024                                 // Not all sort types have formatting methods, so we have to call their sorting
6025                                 // methods.
6026                                 displayMaster.sort( function ( a, b ) {
6027                                         var
6028                                                 x, y, k, l, test, sort, fn,
6029                                                 len=aSort.length,
6030                                                 dataA = aoData[a]._aSortData,
6031                                                 dataB = aoData[b]._aSortData;
6032         
6033                                         for ( k=0 ; k<len ; k++ ) {
6034                                                 sort = aSort[k];
6035         
6036                                                 x = dataA[ sort.col ];
6037                                                 y = dataB[ sort.col ];
6038         
6039                                                 fn = oExtSort[ sort.type+"-"+sort.dir ] || oExtSort[ "string-"+sort.dir ];
6040                                                 test = fn( x, y );
6041                                                 if ( test !== 0 ) {
6042                                                         return test;
6043                                                 }
6044                                         }
6045         
6046                                         x = aiOrig[a];
6047                                         y = aiOrig[b];
6048                                         return x<y ? -1 : x>y ? 1 : 0;
6049                                 } );
6050                         }
6051                 }
6052         
6053                 /* Tell the draw function that we have sorted the data */
6054                 oSettings.bSorted = true;
6055         }
6056         
6057         
6058         function _fnSortAria ( settings )
6059         {
6060                 var label;
6061                 var nextSort;
6062                 var columns = settings.aoColumns;
6063                 var aSort = _fnSortFlatten( settings );
6064                 var oAria = settings.oLanguage.oAria;
6065         
6066                 // ARIA attributes - need to loop all columns, to update all (removing old
6067                 // attributes as needed)
6068                 for ( var i=0, iLen=columns.length ; i<iLen ; i++ )
6069                 {
6070                         var col = columns[i];
6071                         var asSorting = col.asSorting;
6072                         var sTitle = col.sTitle.replace( /<.*?>/g, "" );
6073                         var th = col.nTh;
6074         
6075                         // IE7 is throwing an error when setting these properties with jQuery's
6076                         // attr() and removeAttr() methods...
6077                         th.removeAttribute('aria-sort');
6078         
6079                         /* In ARIA only the first sorting column can be marked as sorting - no multi-sort option */
6080                         if ( col.bSortable ) {
6081                                 if ( aSort.length > 0 && aSort[0].col == i ) {
6082                                         th.setAttribute('aria-sort', aSort[0].dir=="asc" ? "ascending" : "descending" );
6083                                         nextSort = asSorting[ aSort[0].index+1 ] || asSorting[0];
6084                                 }
6085                                 else {
6086                                         nextSort = asSorting[0];
6087                                 }
6088         
6089                                 label = sTitle + ( nextSort === "asc" ?
6090                                         oAria.sSortAscending :
6091                                         oAria.sSortDescending
6092                                 );
6093                         }
6094                         else {
6095                                 label = sTitle;
6096                         }
6097         
6098                         th.setAttribute('aria-label', label);
6099                 }
6100         }
6101         
6102         
6103         /**
6104          * Function to run on user sort request
6105          *  @param {object} settings dataTables settings object
6106          *  @param {node} attachTo node to attach the handler to
6107          *  @param {int} colIdx column sorting index
6108          *  @param {boolean} [append=false] Append the requested sort to the existing
6109          *    sort if true (i.e. multi-column sort)
6110          *  @param {function} [callback] callback function
6111          *  @memberof DataTable#oApi
6112          */
6113         function _fnSortListener ( settings, colIdx, append, callback )
6114         {
6115                 var col = settings.aoColumns[ colIdx ];
6116                 var sorting = settings.aaSorting;
6117                 var asSorting = col.asSorting;
6118                 var nextSortIdx;
6119                 var next = function ( a, overflow ) {
6120                         var idx = a._idx;
6121                         if ( idx === undefined ) {
6122                                 idx = $.inArray( a[1], asSorting );
6123                         }
6124         
6125                         return idx+1 < asSorting.length ?
6126                                 idx+1 :
6127                                 overflow ?
6128                                         null :
6129                                         0;
6130                 };
6131         
6132                 // Convert to 2D array if needed
6133                 if ( typeof sorting[0] === 'number' ) {
6134                         sorting = settings.aaSorting = [ sorting ];
6135                 }
6136         
6137                 // If appending the sort then we are multi-column sorting
6138                 if ( append && settings.oFeatures.bSortMulti ) {
6139                         // Are we already doing some kind of sort on this column?
6140                         var sortIdx = $.inArray( colIdx, _pluck(sorting, '0') );
6141         
6142                         if ( sortIdx !== -1 ) {
6143                                 // Yes, modify the sort
6144                                 nextSortIdx = next( sorting[sortIdx], true );
6145         
6146                                 if ( nextSortIdx === null && sorting.length === 1 ) {
6147                                         nextSortIdx = 0; // can't remove sorting completely
6148                                 }
6149         
6150                                 if ( nextSortIdx === null ) {
6151                                         sorting.splice( sortIdx, 1 );
6152                                 }
6153                                 else {
6154                                         sorting[sortIdx][1] = asSorting[ nextSortIdx ];
6155                                         sorting[sortIdx]._idx = nextSortIdx;
6156                                 }
6157                         }
6158                         else {
6159                                 // No sort on this column yet
6160                                 sorting.push( [ colIdx, asSorting[0], 0 ] );
6161                                 sorting[sorting.length-1]._idx = 0;
6162                         }
6163                 }
6164                 else if ( sorting.length && sorting[0][0] == colIdx ) {
6165                         // Single column - already sorting on this column, modify the sort
6166                         nextSortIdx = next( sorting[0] );
6167         
6168                         sorting.length = 1;
6169                         sorting[0][1] = asSorting[ nextSortIdx ];
6170                         sorting[0]._idx = nextSortIdx;
6171                 }
6172                 else {
6173                         // Single column - sort only on this column
6174                         sorting.length = 0;
6175                         sorting.push( [ colIdx, asSorting[0] ] );
6176                         sorting[0]._idx = 0;
6177                 }
6178         
6179                 // Run the sort by calling a full redraw
6180                 _fnReDraw( settings );
6181         
6182                 // callback used for async user interaction
6183                 if ( typeof callback == 'function' ) {
6184                         callback( settings );
6185                 }
6186         }
6187         
6188         
6189         /**
6190          * Attach a sort handler (click) to a node
6191          *  @param {object} settings dataTables settings object
6192          *  @param {node} attachTo node to attach the handler to
6193          *  @param {int} colIdx column sorting index
6194          *  @param {function} [callback] callback function
6195          *  @memberof DataTable#oApi
6196          */
6197         function _fnSortAttachListener ( settings, attachTo, colIdx, callback )
6198         {
6199                 var col = settings.aoColumns[ colIdx ];
6200         
6201                 _fnBindAction( attachTo, {}, function (e) {
6202                         /* If the column is not sortable - don't to anything */
6203                         if ( col.bSortable === false ) {
6204                                 return;
6205                         }
6206         
6207                         // If processing is enabled use a timeout to allow the processing
6208                         // display to be shown - otherwise to it synchronously
6209                         if ( settings.oFeatures.bProcessing ) {
6210                                 _fnProcessingDisplay( settings, true );
6211         
6212                                 setTimeout( function() {
6213                                         _fnSortListener( settings, colIdx, e.shiftKey, callback );
6214         
6215                                         // In server-side processing, the draw callback will remove the
6216                                         // processing display
6217                                         if ( _fnDataSource( settings ) !== 'ssp' ) {
6218                                                 _fnProcessingDisplay( settings, false );
6219                                         }
6220                                 }, 0 );
6221                         }
6222                         else {
6223                                 _fnSortListener( settings, colIdx, e.shiftKey, callback );
6224                         }
6225                 } );
6226         }
6227         
6228         
6229         /**
6230          * Set the sorting classes on table's body, Note: it is safe to call this function
6231          * when bSort and bSortClasses are false
6232          *  @param {object} oSettings dataTables settings object
6233          *  @memberof DataTable#oApi
6234          */
6235         function _fnSortingClasses( settings )
6236         {
6237                 var oldSort = settings.aLastSort;
6238                 var sortClass = settings.oClasses.sSortColumn;
6239                 var sort = _fnSortFlatten( settings );
6240                 var features = settings.oFeatures;
6241                 var i, ien, colIdx;
6242         
6243                 if ( features.bSort && features.bSortClasses ) {
6244                         // Remove old sorting classes
6245                         for ( i=0, ien=oldSort.length ; i<ien ; i++ ) {
6246                                 colIdx = oldSort[i].src;
6247         
6248                                 // Remove column sorting
6249                                 $( _pluck( settings.aoData, 'anCells', colIdx ) )
6250                                         .removeClass( sortClass + (i<2 ? i+1 : 3) );
6251                         }
6252         
6253                         // Add new column sorting
6254                         for ( i=0, ien=sort.length ; i<ien ; i++ ) {
6255                                 colIdx = sort[i].src;
6256         
6257                                 $( _pluck( settings.aoData, 'anCells', colIdx ) )
6258                                         .addClass( sortClass + (i<2 ? i+1 : 3) );
6259                         }
6260                 }
6261         
6262                 settings.aLastSort = sort;
6263         }
6264         
6265         
6266         // Get the data to sort a column, be it from cache, fresh (populating the
6267         // cache), or from a sort formatter
6268         function _fnSortData( settings, idx )
6269         {
6270                 // Custom sorting function - provided by the sort data type
6271                 var column = settings.aoColumns[ idx ];
6272                 var customSort = DataTable.ext.order[ column.sSortDataType ];
6273                 var customData;
6274         
6275                 if ( customSort ) {
6276                         customData = customSort.call( settings.oInstance, settings, idx,
6277                                 _fnColumnIndexToVisible( settings, idx )
6278                         );
6279                 }
6280         
6281                 // Use / populate cache
6282                 var row, cellData;
6283                 var formatter = DataTable.ext.type.order[ column.sType+"-pre" ];
6284         
6285                 for ( var i=0, ien=settings.aoData.length ; i<ien ; i++ ) {
6286                         row = settings.aoData[i];
6287         
6288                         if ( ! row._aSortData ) {
6289                                 row._aSortData = [];
6290                         }
6291         
6292                         if ( ! row._aSortData[idx] || customSort ) {
6293                                 cellData = customSort ?
6294                                         customData[i] : // If there was a custom sort function, use data from there
6295                                         _fnGetCellData( settings, i, idx, 'sort' );
6296         
6297                                 row._aSortData[ idx ] = formatter ?
6298                                         formatter( cellData ) :
6299                                         cellData;
6300                         }
6301                 }
6302         }
6303         
6304         
6305         
6306         /**
6307          * Save the state of a table
6308          *  @param {object} oSettings dataTables settings object
6309          *  @memberof DataTable#oApi
6310          */
6311         function _fnSaveState ( settings )
6312         {
6313                 if ( !settings.oFeatures.bStateSave || settings.bDestroying )
6314                 {
6315                         return;
6316                 }
6317         
6318                 /* Store the interesting variables */
6319                 var state = {
6320                         time:    +new Date(),
6321                         start:   settings._iDisplayStart,
6322                         length:  settings._iDisplayLength,
6323                         order:   $.extend( true, [], settings.aaSorting ),
6324                         search:  _fnSearchToCamel( settings.oPreviousSearch ),
6325                         columns: $.map( settings.aoColumns, function ( col, i ) {
6326                                 return {
6327                                         visible: col.bVisible,
6328                                         search: _fnSearchToCamel( settings.aoPreSearchCols[i] )
6329                                 };
6330                         } )
6331                 };
6332         
6333                 _fnCallbackFire( settings, "aoStateSaveParams", 'stateSaveParams', [settings, state] );
6334         
6335                 settings.oSavedState = state;
6336                 settings.fnStateSaveCallback.call( settings.oInstance, settings, state );
6337         }
6338         
6339         
6340         /**
6341          * Attempt to load a saved table state
6342          *  @param {object} oSettings dataTables settings object
6343          *  @param {object} oInit DataTables init object so we can override settings
6344          *  @param {function} callback Callback to execute when the state has been loaded
6345          *  @memberof DataTable#oApi
6346          */
6347         function _fnLoadState ( settings, oInit, callback )
6348         {
6349                 var i, ien;
6350                 var columns = settings.aoColumns;
6351                 var loaded = function ( s ) {
6352                         if ( ! s || ! s.time ) {
6353                                 callback();
6354                                 return;
6355                         }
6356         
6357                         // Allow custom and plug-in manipulation functions to alter the saved data set and
6358                         // cancelling of loading by returning false
6359                         var abStateLoad = _fnCallbackFire( settings, 'aoStateLoadParams', 'stateLoadParams', [settings, s] );
6360                         if ( $.inArray( false, abStateLoad ) !== -1 ) {
6361                                 callback();
6362                                 return;
6363                         }
6364         
6365                         // Reject old data
6366                         var duration = settings.iStateDuration;
6367                         if ( duration > 0 && s.time < +new Date() - (duration*1000) ) {
6368                                 callback();
6369                                 return;
6370                         }
6371         
6372                         // Number of columns have changed - all bets are off, no restore of settings
6373                         if ( s.columns && columns.length !== s.columns.length ) {
6374                                 callback();
6375                                 return;
6376                         }
6377         
6378                         // Store the saved state so it might be accessed at any time
6379                         settings.oLoadedState = $.extend( true, {}, s );
6380         
6381                         // Restore key features - todo - for 1.11 this needs to be done by
6382                         // subscribed events
6383                         if ( s.start !== undefined ) {
6384                                 settings._iDisplayStart    = s.start;
6385                                 settings.iInitDisplayStart = s.start;
6386                         }
6387                         if ( s.length !== undefined ) {
6388                                 settings._iDisplayLength   = s.length;
6389                         }
6390         
6391                         // Order
6392                         if ( s.order !== undefined ) {
6393                                 settings.aaSorting = [];
6394                                 $.each( s.order, function ( i, col ) {
6395                                         settings.aaSorting.push( col[0] >= columns.length ?
6396                                                 [ 0, col[1] ] :
6397                                                 col
6398                                         );
6399                                 } );
6400                         }
6401         
6402                         // Search
6403                         if ( s.search !== undefined ) {
6404                                 $.extend( settings.oPreviousSearch, _fnSearchToHung( s.search ) );
6405                         }
6406         
6407                         // Columns
6408                         //
6409                         if ( s.columns ) {
6410                                 for ( i=0, ien=s.columns.length ; i<ien ; i++ ) {
6411                                         var col = s.columns[i];
6412         
6413                                         // Visibility
6414                                         if ( col.visible !== undefined ) {
6415                                                 columns[i].bVisible = col.visible;
6416                                         }
6417         
6418                                         // Search
6419                                         if ( col.search !== undefined ) {
6420                                                 $.extend( settings.aoPreSearchCols[i], _fnSearchToHung( col.search ) );
6421                                         }
6422                                 }
6423                         }
6424         
6425                         _fnCallbackFire( settings, 'aoStateLoaded', 'stateLoaded', [settings, s] );
6426                         callback();
6427                 };
6428         
6429                 if ( ! settings.oFeatures.bStateSave ) {
6430                         callback();
6431                         return;
6432                 }
6433         
6434                 var state = settings.fnStateLoadCallback.call( settings.oInstance, settings, loaded );
6435         
6436                 if ( state !== undefined ) {
6437                         loaded( state );
6438                 }
6439                 // otherwise, wait for the loaded callback to be executed
6440         }
6441         
6442         
6443         /**
6444          * Return the settings object for a particular table
6445          *  @param {node} table table we are using as a dataTable
6446          *  @returns {object} Settings object - or null if not found
6447          *  @memberof DataTable#oApi
6448          */
6449         function _fnSettingsFromNode ( table )
6450         {
6451                 var settings = DataTable.settings;
6452                 var idx = $.inArray( table, _pluck( settings, 'nTable' ) );
6453         
6454                 return idx !== -1 ?
6455                         settings[ idx ] :
6456                         null;
6457         }
6458         
6459         
6460         /**
6461          * Log an error message
6462          *  @param {object} settings dataTables settings object
6463          *  @param {int} level log error messages, or display them to the user
6464          *  @param {string} msg error message
6465          *  @param {int} tn Technical note id to get more information about the error.
6466          *  @memberof DataTable#oApi
6467          */
6468         function _fnLog( settings, level, msg, tn )
6469         {
6470                 msg = 'DataTables warning: '+
6471                         (settings ? 'table id='+settings.sTableId+' - ' : '')+msg;
6472         
6473                 if ( tn ) {
6474                         msg += '. For more information about this error, please see '+
6475                         'http://datatables.net/tn/'+tn;
6476                 }
6477         
6478                 if ( ! level  ) {
6479                         // Backwards compatibility pre 1.10
6480                         var ext = DataTable.ext;
6481                         var type = ext.sErrMode || ext.errMode;
6482         
6483                         if ( settings ) {
6484                                 _fnCallbackFire( settings, null, 'error', [ settings, tn, msg ] );
6485                         }
6486         
6487                         if ( type == 'alert' ) {
6488                                 alert( msg );
6489                         }
6490                         else if ( type == 'throw' ) {
6491                                 throw new Error(msg);
6492                         }
6493                         else if ( typeof type == 'function' ) {
6494                                 type( settings, tn, msg );
6495                         }
6496                 }
6497                 else if ( window.console && console.log ) {
6498                         console.log( msg );
6499                 }
6500         }
6501         
6502         
6503         /**
6504          * See if a property is defined on one object, if so assign it to the other object
6505          *  @param {object} ret target object
6506          *  @param {object} src source object
6507          *  @param {string} name property
6508          *  @param {string} [mappedName] name to map too - optional, name used if not given
6509          *  @memberof DataTable#oApi
6510          */
6511         function _fnMap( ret, src, name, mappedName )
6512         {
6513                 if ( $.isArray( name ) ) {
6514                         $.each( name, function (i, val) {
6515                                 if ( $.isArray( val ) ) {
6516                                         _fnMap( ret, src, val[0], val[1] );
6517                                 }
6518                                 else {
6519                                         _fnMap( ret, src, val );
6520                                 }
6521                         } );
6522         
6523                         return;
6524                 }
6525         
6526                 if ( mappedName === undefined ) {
6527                         mappedName = name;
6528                 }
6529         
6530                 if ( src[name] !== undefined ) {
6531                         ret[mappedName] = src[name];
6532                 }
6533         }
6534         
6535         
6536         /**
6537          * Extend objects - very similar to jQuery.extend, but deep copy objects, and
6538          * shallow copy arrays. The reason we need to do this, is that we don't want to
6539          * deep copy array init values (such as aaSorting) since the dev wouldn't be
6540          * able to override them, but we do want to deep copy arrays.
6541          *  @param {object} out Object to extend
6542          *  @param {object} extender Object from which the properties will be applied to
6543          *      out
6544          *  @param {boolean} breakRefs If true, then arrays will be sliced to take an
6545          *      independent copy with the exception of the `data` or `aaData` parameters
6546          *      if they are present. This is so you can pass in a collection to
6547          *      DataTables and have that used as your data source without breaking the
6548          *      references
6549          *  @returns {object} out Reference, just for convenience - out === the return.
6550          *  @memberof DataTable#oApi
6551          *  @todo This doesn't take account of arrays inside the deep copied objects.
6552          */
6553         function _fnExtend( out, extender, breakRefs )
6554         {
6555                 var val;
6556         
6557                 for ( var prop in extender ) {
6558                         if ( extender.hasOwnProperty(prop) ) {
6559                                 val = extender[prop];
6560         
6561                                 if ( $.isPlainObject( val ) ) {
6562                                         if ( ! $.isPlainObject( out[prop] ) ) {
6563                                                 out[prop] = {};
6564                                         }
6565                                         $.extend( true, out[prop], val );
6566                                 }
6567                                 else if ( breakRefs && prop !== 'data' && prop !== 'aaData' && $.isArray(val) ) {
6568                                         out[prop] = val.slice();
6569                                 }
6570                                 else {
6571                                         out[prop] = val;
6572                                 }
6573                         }
6574                 }
6575         
6576                 return out;
6577         }
6578         
6579         
6580         /**
6581          * Bind an event handers to allow a click or return key to activate the callback.
6582          * This is good for accessibility since a return on the keyboard will have the
6583          * same effect as a click, if the element has focus.
6584          *  @param {element} n Element to bind the action to
6585          *  @param {object} oData Data object to pass to the triggered function
6586          *  @param {function} fn Callback function for when the event is triggered
6587          *  @memberof DataTable#oApi
6588          */
6589         function _fnBindAction( n, oData, fn )
6590         {
6591                 $(n)
6592                         .on( 'click.DT', oData, function (e) {
6593                                         $(n).blur(); // Remove focus outline for mouse users
6594                                         fn(e);
6595                                 } )
6596                         .on( 'keypress.DT', oData, function (e){
6597                                         if ( e.which === 13 ) {
6598                                                 e.preventDefault();
6599                                                 fn(e);
6600                                         }
6601                                 } )
6602                         .on( 'selectstart.DT', function () {
6603                                         /* Take the brutal approach to cancelling text selection */
6604                                         return false;
6605                                 } );
6606         }
6607         
6608         
6609         /**
6610          * Register a callback function. Easily allows a callback function to be added to
6611          * an array store of callback functions that can then all be called together.
6612          *  @param {object} oSettings dataTables settings object
6613          *  @param {string} sStore Name of the array storage for the callbacks in oSettings
6614          *  @param {function} fn Function to be called back
6615          *  @param {string} sName Identifying name for the callback (i.e. a label)
6616          *  @memberof DataTable#oApi
6617          */
6618         function _fnCallbackReg( oSettings, sStore, fn, sName )
6619         {
6620                 if ( fn )
6621                 {
6622                         oSettings[sStore].push( {
6623                                 "fn": fn,
6624                                 "sName": sName
6625                         } );
6626                 }
6627         }
6628         
6629         
6630         /**
6631          * Fire callback functions and trigger events. Note that the loop over the
6632          * callback array store is done backwards! Further note that you do not want to
6633          * fire off triggers in time sensitive applications (for example cell creation)
6634          * as its slow.
6635          *  @param {object} settings dataTables settings object
6636          *  @param {string} callbackArr Name of the array storage for the callbacks in
6637          *      oSettings
6638          *  @param {string} eventName Name of the jQuery custom event to trigger. If
6639          *      null no trigger is fired
6640          *  @param {array} args Array of arguments to pass to the callback function /
6641          *      trigger
6642          *  @memberof DataTable#oApi
6643          */
6644         function _fnCallbackFire( settings, callbackArr, eventName, args )
6645         {
6646                 var ret = [];
6647         
6648                 if ( callbackArr ) {
6649                         ret = $.map( settings[callbackArr].slice().reverse(), function (val, i) {
6650                                 return val.fn.apply( settings.oInstance, args );
6651                         } );
6652                 }
6653         
6654                 if ( eventName !== null ) {
6655                         var e = $.Event( eventName+'.dt' );
6656         
6657                         $(settings.nTable).trigger( e, args );
6658         
6659                         ret.push( e.result );
6660                 }
6661         
6662                 return ret;
6663         }
6664         
6665         
6666         function _fnLengthOverflow ( settings )
6667         {
6668                 var
6669                         start = settings._iDisplayStart,
6670                         end = settings.fnDisplayEnd(),
6671                         len = settings._iDisplayLength;
6672         
6673                 /* If we have space to show extra rows (backing up from the end point - then do so */
6674                 if ( start >= end )
6675                 {
6676                         start = end - len;
6677                 }
6678         
6679                 // Keep the start record on the current page
6680                 start -= (start % len);
6681         
6682                 if ( len === -1 || start < 0 )
6683                 {
6684                         start = 0;
6685                 }
6686         
6687                 settings._iDisplayStart = start;
6688         }
6689         
6690         
6691         function _fnRenderer( settings, type )
6692         {
6693                 var renderer = settings.renderer;
6694                 var host = DataTable.ext.renderer[type];
6695         
6696                 if ( $.isPlainObject( renderer ) && renderer[type] ) {
6697                         // Specific renderer for this type. If available use it, otherwise use
6698                         // the default.
6699                         return host[renderer[type]] || host._;
6700                 }
6701                 else if ( typeof renderer === 'string' ) {
6702                         // Common renderer - if there is one available for this type use it,
6703                         // otherwise use the default
6704                         return host[renderer] || host._;
6705                 }
6706         
6707                 // Use the default
6708                 return host._;
6709         }
6710         
6711         
6712         /**
6713          * Detect the data source being used for the table. Used to simplify the code
6714          * a little (ajax) and to make it compress a little smaller.
6715          *
6716          *  @param {object} settings dataTables settings object
6717          *  @returns {string} Data source
6718          *  @memberof DataTable#oApi
6719          */
6720         function _fnDataSource ( settings )
6721         {
6722                 if ( settings.oFeatures.bServerSide ) {
6723                         return 'ssp';
6724                 }
6725                 else if ( settings.ajax || settings.sAjaxSource ) {
6726                         return 'ajax';
6727                 }
6728                 return 'dom';
6729         }
6730         
6731
6732         
6733         
6734         /**
6735          * Computed structure of the DataTables API, defined by the options passed to
6736          * `DataTable.Api.register()` when building the API.
6737          *
6738          * The structure is built in order to speed creation and extension of the Api
6739          * objects since the extensions are effectively pre-parsed.
6740          *
6741          * The array is an array of objects with the following structure, where this
6742          * base array represents the Api prototype base:
6743          *
6744          *     [
6745          *       {
6746          *         name:      'data'                -- string   - Property name
6747          *         val:       function () {},       -- function - Api method (or undefined if just an object
6748          *         methodExt: [ ... ],              -- array    - Array of Api object definitions to extend the method result
6749          *         propExt:   [ ... ]               -- array    - Array of Api object definitions to extend the property
6750          *       },
6751          *       {
6752          *         name:     'row'
6753          *         val:       {},
6754          *         methodExt: [ ... ],
6755          *         propExt:   [
6756          *           {
6757          *             name:      'data'
6758          *             val:       function () {},
6759          *             methodExt: [ ... ],
6760          *             propExt:   [ ... ]
6761          *           },
6762          *           ...
6763          *         ]
6764          *       }
6765          *     ]
6766          *
6767          * @type {Array}
6768          * @ignore
6769          */
6770         var __apiStruct = [];
6771         
6772         
6773         /**
6774          * `Array.prototype` reference.
6775          *
6776          * @type object
6777          * @ignore
6778          */
6779         var __arrayProto = Array.prototype;
6780         
6781         
6782         /**
6783          * Abstraction for `context` parameter of the `Api` constructor to allow it to
6784          * take several different forms for ease of use.
6785          *
6786          * Each of the input parameter types will be converted to a DataTables settings
6787          * object where possible.
6788          *
6789          * @param  {string|node|jQuery|object} mixed DataTable identifier. Can be one
6790          *   of:
6791          *
6792          *   * `string` - jQuery selector. Any DataTables' matching the given selector
6793          *     with be found and used.
6794          *   * `node` - `TABLE` node which has already been formed into a DataTable.
6795          *   * `jQuery` - A jQuery object of `TABLE` nodes.
6796          *   * `object` - DataTables settings object
6797          *   * `DataTables.Api` - API instance
6798          * @return {array|null} Matching DataTables settings objects. `null` or
6799          *   `undefined` is returned if no matching DataTable is found.
6800          * @ignore
6801          */
6802         var _toSettings = function ( mixed )
6803         {
6804                 var idx, jq;
6805                 var settings = DataTable.settings;
6806                 var tables = $.map( settings, function (el, i) {
6807                         return el.nTable;
6808                 } );
6809         
6810                 if ( ! mixed ) {
6811                         return [];
6812                 }
6813                 else if ( mixed.nTable && mixed.oApi ) {
6814                         // DataTables settings object
6815                         return [ mixed ];
6816                 }
6817                 else if ( mixed.nodeName && mixed.nodeName.toLowerCase() === 'table' ) {
6818                         // Table node
6819                         idx = $.inArray( mixed, tables );
6820                         return idx !== -1 ? [ settings[idx] ] : null;
6821                 }
6822                 else if ( mixed && typeof mixed.settings === 'function' ) {
6823                         return mixed.settings().toArray();
6824                 }
6825                 else if ( typeof mixed === 'string' ) {
6826                         // jQuery selector
6827                         jq = $(mixed);
6828                 }
6829                 else if ( mixed instanceof $ ) {
6830                         // jQuery object (also DataTables instance)
6831                         jq = mixed;
6832                 }
6833         
6834                 if ( jq ) {
6835                         return jq.map( function(i) {
6836                                 idx = $.inArray( this, tables );
6837                                 return idx !== -1 ? settings[idx] : null;
6838                         } ).toArray();
6839                 }
6840         };
6841         
6842         
6843         /**
6844          * DataTables API class - used to control and interface with  one or more
6845          * DataTables enhanced tables.
6846          *
6847          * The API class is heavily based on jQuery, presenting a chainable interface
6848          * that you can use to interact with tables. Each instance of the API class has
6849          * a "context" - i.e. the tables that it will operate on. This could be a single
6850          * table, all tables on a page or a sub-set thereof.
6851          *
6852          * Additionally the API is designed to allow you to easily work with the data in
6853          * the tables, retrieving and manipulating it as required. This is done by
6854          * presenting the API class as an array like interface. The contents of the
6855          * array depend upon the actions requested by each method (for example
6856          * `rows().nodes()` will return an array of nodes, while `rows().data()` will
6857          * return an array of objects or arrays depending upon your table's
6858          * configuration). The API object has a number of array like methods (`push`,
6859          * `pop`, `reverse` etc) as well as additional helper methods (`each`, `pluck`,
6860          * `unique` etc) to assist your working with the data held in a table.
6861          *
6862          * Most methods (those which return an Api instance) are chainable, which means
6863          * the return from a method call also has all of the methods available that the
6864          * top level object had. For example, these two calls are equivalent:
6865          *
6866          *     // Not chained
6867          *     api.row.add( {...} );
6868          *     api.draw();
6869          *
6870          *     // Chained
6871          *     api.row.add( {...} ).draw();
6872          *
6873          * @class DataTable.Api
6874          * @param {array|object|string|jQuery} context DataTable identifier. This is
6875          *   used to define which DataTables enhanced tables this API will operate on.
6876          *   Can be one of:
6877          *
6878          *   * `string` - jQuery selector. Any DataTables' matching the given selector
6879          *     with be found and used.
6880          *   * `node` - `TABLE` node which has already been formed into a DataTable.
6881          *   * `jQuery` - A jQuery object of `TABLE` nodes.
6882          *   * `object` - DataTables settings object
6883          * @param {array} [data] Data to initialise the Api instance with.
6884          *
6885          * @example
6886          *   // Direct initialisation during DataTables construction
6887          *   var api = $('#example').DataTable();
6888          *
6889          * @example
6890          *   // Initialisation using a DataTables jQuery object
6891          *   var api = $('#example').dataTable().api();
6892          *
6893          * @example
6894          *   // Initialisation as a constructor
6895          *   var api = new $.fn.DataTable.Api( 'table.dataTable' );
6896          */
6897         _Api = function ( context, data )
6898         {
6899                 if ( ! (this instanceof _Api) ) {
6900                         return new _Api( context, data );
6901                 }
6902         
6903                 var settings = [];
6904                 var ctxSettings = function ( o ) {
6905                         var a = _toSettings( o );
6906                         if ( a ) {
6907                                 settings.push.apply( settings, a );
6908                         }
6909                 };
6910         
6911                 if ( $.isArray( context ) ) {
6912                         for ( var i=0, ien=context.length ; i<ien ; i++ ) {
6913                                 ctxSettings( context[i] );
6914                         }
6915                 }
6916                 else {
6917                         ctxSettings( context );
6918                 }
6919         
6920                 // Remove duplicates
6921                 this.context = _unique( settings );
6922         
6923                 // Initial data
6924                 if ( data ) {
6925                         $.merge( this, data );
6926                 }
6927         
6928                 // selector
6929                 this.selector = {
6930                         rows: null,
6931                         cols: null,
6932                         opts: null
6933                 };
6934         
6935                 _Api.extend( this, this, __apiStruct );
6936         };
6937         
6938         DataTable.Api = _Api;
6939         
6940         // Don't destroy the existing prototype, just extend it. Required for jQuery 2's
6941         // isPlainObject.
6942         $.extend( _Api.prototype, {
6943                 any: function ()
6944                 {
6945                         return this.count() !== 0;
6946                 },
6947         
6948         
6949                 concat:  __arrayProto.concat,
6950         
6951         
6952                 context: [], // array of table settings objects
6953         
6954         
6955                 count: function ()
6956                 {
6957                         return this.flatten().length;
6958                 },
6959         
6960         
6961                 each: function ( fn )
6962                 {
6963                         for ( var i=0, ien=this.length ; i<ien; i++ ) {
6964                                 fn.call( this, this[i], i, this );
6965                         }
6966         
6967                         return this;
6968                 },
6969         
6970         
6971                 eq: function ( idx )
6972                 {
6973                         var ctx = this.context;
6974         
6975                         return ctx.length > idx ?
6976                                 new _Api( ctx[idx], this[idx] ) :
6977                                 null;
6978                 },
6979         
6980         
6981                 filter: function ( fn )
6982                 {
6983                         var a = [];
6984         
6985                         if ( __arrayProto.filter ) {
6986                                 a = __arrayProto.filter.call( this, fn, this );
6987                         }
6988                         else {
6989                                 // Compatibility for browsers without EMCA-252-5 (JS 1.6)
6990                                 for ( var i=0, ien=this.length ; i<ien ; i++ ) {
6991                                         if ( fn.call( this, this[i], i, this ) ) {
6992                                                 a.push( this[i] );
6993                                         }
6994                                 }
6995                         }
6996         
6997                         return new _Api( this.context, a );
6998                 },
6999         
7000         
7001                 flatten: function ()
7002                 {
7003                         var a = [];
7004                         return new _Api( this.context, a.concat.apply( a, this.toArray() ) );
7005                 },
7006         
7007         
7008                 join:    __arrayProto.join,
7009         
7010         
7011                 indexOf: __arrayProto.indexOf || function (obj, start)
7012                 {
7013                         for ( var i=(start || 0), ien=this.length ; i<ien ; i++ ) {
7014                                 if ( this[i] === obj ) {
7015                                         return i;
7016                                 }
7017                         }
7018                         return -1;
7019                 },
7020         
7021                 iterator: function ( flatten, type, fn, alwaysNew ) {
7022                         var
7023                                 a = [], ret,
7024                                 i, ien, j, jen,
7025                                 context = this.context,
7026                                 rows, items, item,
7027                                 selector = this.selector;
7028         
7029                         // Argument shifting
7030                         if ( typeof flatten === 'string' ) {
7031                                 alwaysNew = fn;
7032                                 fn = type;
7033                                 type = flatten;
7034                                 flatten = false;
7035                         }
7036         
7037                         for ( i=0, ien=context.length ; i<ien ; i++ ) {
7038                                 var apiInst = new _Api( context[i] );
7039         
7040                                 if ( type === 'table' ) {
7041                                         ret = fn.call( apiInst, context[i], i );
7042         
7043                                         if ( ret !== undefined ) {
7044                                                 a.push( ret );
7045                                         }
7046                                 }
7047                                 else if ( type === 'columns' || type === 'rows' ) {
7048                                         // this has same length as context - one entry for each table
7049                                         ret = fn.call( apiInst, context[i], this[i], i );
7050         
7051                                         if ( ret !== undefined ) {
7052                                                 a.push( ret );
7053                                         }
7054                                 }
7055                                 else if ( type === 'column' || type === 'column-rows' || type === 'row' || type === 'cell' ) {
7056                                         // columns and rows share the same structure.
7057                                         // 'this' is an array of column indexes for each context
7058                                         items = this[i];
7059         
7060                                         if ( type === 'column-rows' ) {
7061                                                 rows = _selector_row_indexes( context[i], selector.opts );
7062                                         }
7063         
7064                                         for ( j=0, jen=items.length ; j<jen ; j++ ) {
7065                                                 item = items[j];
7066         
7067                                                 if ( type === 'cell' ) {
7068                                                         ret = fn.call( apiInst, context[i], item.row, item.column, i, j );
7069                                                 }
7070                                                 else {
7071                                                         ret = fn.call( apiInst, context[i], item, i, j, rows );
7072                                                 }
7073         
7074                                                 if ( ret !== undefined ) {
7075                                                         a.push( ret );
7076                                                 }
7077                                         }
7078                                 }
7079                         }
7080         
7081                         if ( a.length || alwaysNew ) {
7082                                 var api = new _Api( context, flatten ? a.concat.apply( [], a ) : a );
7083                                 var apiSelector = api.selector;
7084                                 apiSelector.rows = selector.rows;
7085                                 apiSelector.cols = selector.cols;
7086                                 apiSelector.opts = selector.opts;
7087                                 return api;
7088                         }
7089                         return this;
7090                 },
7091         
7092         
7093                 lastIndexOf: __arrayProto.lastIndexOf || function (obj, start)
7094                 {
7095                         // Bit cheeky...
7096                         return this.indexOf.apply( this.toArray.reverse(), arguments );
7097                 },
7098         
7099         
7100                 length:  0,
7101         
7102         
7103                 map: function ( fn )
7104                 {
7105                         var a = [];
7106         
7107                         if ( __arrayProto.map ) {
7108                                 a = __arrayProto.map.call( this, fn, this );
7109                         }
7110                         else {
7111                                 // Compatibility for browsers without EMCA-252-5 (JS 1.6)
7112                                 for ( var i=0, ien=this.length ; i<ien ; i++ ) {
7113                                         a.push( fn.call( this, this[i], i ) );
7114                                 }
7115                         }
7116         
7117                         return new _Api( this.context, a );
7118                 },
7119         
7120         
7121                 pluck: function ( prop )
7122                 {
7123                         return this.map( function ( el ) {
7124                                 return el[ prop ];
7125                         } );
7126                 },
7127         
7128                 pop:     __arrayProto.pop,
7129         
7130         
7131                 push:    __arrayProto.push,
7132         
7133         
7134                 // Does not return an API instance
7135                 reduce: __arrayProto.reduce || function ( fn, init )
7136                 {
7137                         return _fnReduce( this, fn, init, 0, this.length, 1 );
7138                 },
7139         
7140         
7141                 reduceRight: __arrayProto.reduceRight || function ( fn, init )
7142                 {
7143                         return _fnReduce( this, fn, init, this.length-1, -1, -1 );
7144                 },
7145         
7146         
7147                 reverse: __arrayProto.reverse,
7148         
7149         
7150                 // Object with rows, columns and opts
7151                 selector: null,
7152         
7153         
7154                 shift:   __arrayProto.shift,
7155         
7156         
7157                 slice: function () {
7158                         return new _Api( this.context, this );
7159                 },
7160         
7161         
7162                 sort:    __arrayProto.sort, // ? name - order?
7163         
7164         
7165                 splice:  __arrayProto.splice,
7166         
7167         
7168                 toArray: function ()
7169                 {
7170                         return __arrayProto.slice.call( this );
7171                 },
7172         
7173         
7174                 to$: function ()
7175                 {
7176                         return $( this );
7177                 },
7178         
7179         
7180                 toJQuery: function ()
7181                 {
7182                         return $( this );
7183                 },
7184         
7185         
7186                 unique: function ()
7187                 {
7188                         return new _Api( this.context, _unique(this) );
7189                 },
7190         
7191         
7192                 unshift: __arrayProto.unshift
7193         } );
7194         
7195         
7196         _Api.extend = function ( scope, obj, ext )
7197         {
7198                 // Only extend API instances and static properties of the API
7199                 if ( ! ext.length || ! obj || ( ! (obj instanceof _Api) && ! obj.__dt_wrapper ) ) {
7200                         return;
7201                 }
7202         
7203                 var
7204                         i, ien,
7205                         struct,
7206                         methodScoping = function ( scope, fn, struc ) {
7207                                 return function () {
7208                                         var ret = fn.apply( scope, arguments );
7209         
7210                                         // Method extension
7211                                         _Api.extend( ret, ret, struc.methodExt );
7212                                         return ret;
7213                                 };
7214                         };
7215         
7216                 for ( i=0, ien=ext.length ; i<ien ; i++ ) {
7217                         struct = ext[i];
7218         
7219                         // Value
7220                         obj[ struct.name ] = struct.type === 'function' ?
7221                                 methodScoping( scope, struct.val, struct ) :
7222                                 struct.type === 'object' ?
7223                                         {} :
7224                                         struct.val;
7225         
7226                         obj[ struct.name ].__dt_wrapper = true;
7227         
7228                         // Property extension
7229                         _Api.extend( scope, obj[ struct.name ], struct.propExt );
7230                 }
7231         };
7232         
7233         
7234         // @todo - Is there need for an augment function?
7235         // _Api.augment = function ( inst, name )
7236         // {
7237         //      // Find src object in the structure from the name
7238         //      var parts = name.split('.');
7239         
7240         //      _Api.extend( inst, obj );
7241         // };
7242         
7243         
7244         //     [
7245         //       {
7246         //         name:      'data'                -- string   - Property name
7247         //         val:       function () {},       -- function - Api method (or undefined if just an object
7248         //         methodExt: [ ... ],              -- array    - Array of Api object definitions to extend the method result
7249         //         propExt:   [ ... ]               -- array    - Array of Api object definitions to extend the property
7250         //       },
7251         //       {
7252         //         name:     'row'
7253         //         val:       {},
7254         //         methodExt: [ ... ],
7255         //         propExt:   [
7256         //           {
7257         //             name:      'data'
7258         //             val:       function () {},
7259         //             methodExt: [ ... ],
7260         //             propExt:   [ ... ]
7261         //           },
7262         //           ...
7263         //         ]
7264         //       }
7265         //     ]
7266         
7267         _Api.register = _api_register = function ( name, val )
7268         {
7269                 if ( $.isArray( name ) ) {
7270                         for ( var j=0, jen=name.length ; j<jen ; j++ ) {
7271                                 _Api.register( name[j], val );
7272                         }
7273                         return;
7274                 }
7275         
7276                 var
7277                         i, ien,
7278                         heir = name.split('.'),
7279                         struct = __apiStruct,
7280                         key, method;
7281         
7282                 var find = function ( src, name ) {
7283                         for ( var i=0, ien=src.length ; i<ien ; i++ ) {
7284                                 if ( src[i].name === name ) {
7285                                         return src[i];
7286                                 }
7287                         }
7288                         return null;
7289                 };
7290         
7291                 for ( i=0, ien=heir.length ; i<ien ; i++ ) {
7292                         method = heir[i].indexOf('()') !== -1;
7293                         key = method ?
7294                                 heir[i].replace('()', '') :
7295                                 heir[i];
7296         
7297                         var src = find( struct, key );
7298                         if ( ! src ) {
7299                                 src = {
7300                                         name:      key,
7301                                         val:       {},
7302                                         methodExt: [],
7303                                         propExt:   [],
7304                                         type:      'object'
7305                                 };
7306                                 struct.push( src );
7307                         }
7308         
7309                         if ( i === ien-1 ) {
7310                                 src.val = val;
7311                                 src.type = typeof val === 'function' ?
7312                                         'function' :
7313                                         $.isPlainObject( val ) ?
7314                                                 'object' :
7315                                                 'other';
7316                         }
7317                         else {
7318                                 struct = method ?
7319                                         src.methodExt :
7320                                         src.propExt;
7321                         }
7322                 }
7323         };
7324         
7325         _Api.registerPlural = _api_registerPlural = function ( pluralName, singularName, val ) {
7326                 _Api.register( pluralName, val );
7327         
7328                 _Api.register( singularName, function () {
7329                         var ret = val.apply( this, arguments );
7330         
7331                         if ( ret === this ) {
7332                                 // Returned item is the API instance that was passed in, return it
7333                                 return this;
7334                         }
7335                         else if ( ret instanceof _Api ) {
7336                                 // New API instance returned, want the value from the first item
7337                                 // in the returned array for the singular result.
7338                                 return ret.length ?
7339                                         $.isArray( ret[0] ) ?
7340                                                 new _Api( ret.context, ret[0] ) : // Array results are 'enhanced'
7341                                                 ret[0] :
7342                                         undefined;
7343                         }
7344         
7345                         // Non-API return - just fire it back
7346                         return ret;
7347                 } );
7348         };
7349         
7350         
7351         /**
7352          * Selector for HTML tables. Apply the given selector to the give array of
7353          * DataTables settings objects.
7354          *
7355          * @param {string|integer} [selector] jQuery selector string or integer
7356          * @param  {array} Array of DataTables settings objects to be filtered
7357          * @return {array}
7358          * @ignore
7359          */
7360         var __table_selector = function ( selector, a )
7361         {
7362                 // Integer is used to pick out a table by index
7363                 if ( typeof selector === 'number' ) {
7364                         return [ a[ selector ] ];
7365                 }
7366         
7367                 // Perform a jQuery selector on the table nodes
7368                 var nodes = $.map( a, function (el, i) {
7369                         return el.nTable;
7370                 } );
7371         
7372                 return $(nodes)
7373                         .filter( selector )
7374                         .map( function (i) {
7375                                 // Need to translate back from the table node to the settings
7376                                 var idx = $.inArray( this, nodes );
7377                                 return a[ idx ];
7378                         } )
7379                         .toArray();
7380         };
7381         
7382         
7383         
7384         /**
7385          * Context selector for the API's context (i.e. the tables the API instance
7386          * refers to.
7387          *
7388          * @name    DataTable.Api#tables
7389          * @param {string|integer} [selector] Selector to pick which tables the iterator
7390          *   should operate on. If not given, all tables in the current context are
7391          *   used. This can be given as a jQuery selector (for example `':gt(0)'`) to
7392          *   select multiple tables or as an integer to select a single table.
7393          * @returns {DataTable.Api} Returns a new API instance if a selector is given.
7394          */
7395         _api_register( 'tables()', function ( selector ) {
7396                 // A new instance is created if there was a selector specified
7397                 return selector ?
7398                         new _Api( __table_selector( selector, this.context ) ) :
7399                         this;
7400         } );
7401         
7402         
7403         _api_register( 'table()', function ( selector ) {
7404                 var tables = this.tables( selector );
7405                 var ctx = tables.context;
7406         
7407                 // Truncate to the first matched table
7408                 return ctx.length ?
7409                         new _Api( ctx[0] ) :
7410                         tables;
7411         } );
7412         
7413         
7414         _api_registerPlural( 'tables().nodes()', 'table().node()' , function () {
7415                 return this.iterator( 'table', function ( ctx ) {
7416                         return ctx.nTable;
7417                 }, 1 );
7418         } );
7419         
7420         
7421         _api_registerPlural( 'tables().body()', 'table().body()' , function () {
7422                 return this.iterator( 'table', function ( ctx ) {
7423                         return ctx.nTBody;
7424                 }, 1 );
7425         } );
7426         
7427         
7428         _api_registerPlural( 'tables().header()', 'table().header()' , function () {
7429                 return this.iterator( 'table', function ( ctx ) {
7430                         return ctx.nTHead;
7431                 }, 1 );
7432         } );
7433         
7434         
7435         _api_registerPlural( 'tables().footer()', 'table().footer()' , function () {
7436                 return this.iterator( 'table', function ( ctx ) {
7437                         return ctx.nTFoot;
7438                 }, 1 );
7439         } );
7440         
7441         
7442         _api_registerPlural( 'tables().containers()', 'table().container()' , function () {
7443                 return this.iterator( 'table', function ( ctx ) {
7444                         return ctx.nTableWrapper;
7445                 }, 1 );
7446         } );
7447         
7448         
7449         
7450         /**
7451          * Redraw the tables in the current context.
7452          */
7453         _api_register( 'draw()', function ( paging ) {
7454                 return this.iterator( 'table', function ( settings ) {
7455                         if ( paging === 'page' ) {
7456                                 _fnDraw( settings );
7457                         }
7458                         else {
7459                                 if ( typeof paging === 'string' ) {
7460                                         paging = paging === 'full-hold' ?
7461                                                 false :
7462                                                 true;
7463                                 }
7464         
7465                                 _fnReDraw( settings, paging===false );
7466                         }
7467                 } );
7468         } );
7469         
7470         
7471         
7472         /**
7473          * Get the current page index.
7474          *
7475          * @return {integer} Current page index (zero based)
7476          *//**
7477          * Set the current page.
7478          *
7479          * Note that if you attempt to show a page which does not exist, DataTables will
7480          * not throw an error, but rather reset the paging.
7481          *
7482          * @param {integer|string} action The paging action to take. This can be one of:
7483          *  * `integer` - The page index to jump to
7484          *  * `string` - An action to take:
7485          *    * `first` - Jump to first page.
7486          *    * `next` - Jump to the next page
7487          *    * `previous` - Jump to previous page
7488          *    * `last` - Jump to the last page.
7489          * @returns {DataTables.Api} this
7490          */
7491         _api_register( 'page()', function ( action ) {
7492                 if ( action === undefined ) {
7493                         return this.page.info().page; // not an expensive call
7494                 }
7495         
7496                 // else, have an action to take on all tables
7497                 return this.iterator( 'table', function ( settings ) {
7498                         _fnPageChange( settings, action );
7499                 } );
7500         } );
7501         
7502         
7503         /**
7504          * Paging information for the first table in the current context.
7505          *
7506          * If you require paging information for another table, use the `table()` method
7507          * with a suitable selector.
7508          *
7509          * @return {object} Object with the following properties set:
7510          *  * `page` - Current page index (zero based - i.e. the first page is `0`)
7511          *  * `pages` - Total number of pages
7512          *  * `start` - Display index for the first record shown on the current page
7513          *  * `end` - Display index for the last record shown on the current page
7514          *  * `length` - Display length (number of records). Note that generally `start
7515          *    + length = end`, but this is not always true, for example if there are
7516          *    only 2 records to show on the final page, with a length of 10.
7517          *  * `recordsTotal` - Full data set length
7518          *  * `recordsDisplay` - Data set length once the current filtering criterion
7519          *    are applied.
7520          */
7521         _api_register( 'page.info()', function ( action ) {
7522                 if ( this.context.length === 0 ) {
7523                         return undefined;
7524                 }
7525         
7526                 var
7527                         settings   = this.context[0],
7528                         start      = settings._iDisplayStart,
7529                         len        = settings.oFeatures.bPaginate ? settings._iDisplayLength : -1,
7530                         visRecords = settings.fnRecordsDisplay(),
7531                         all        = len === -1;
7532         
7533                 return {
7534                         "page":           all ? 0 : Math.floor( start / len ),
7535                         "pages":          all ? 1 : Math.ceil( visRecords / len ),
7536                         "start":          start,
7537                         "end":            settings.fnDisplayEnd(),
7538                         "length":         len,
7539                         "recordsTotal":   settings.fnRecordsTotal(),
7540                         "recordsDisplay": visRecords,
7541                         "serverSide":     _fnDataSource( settings ) === 'ssp'
7542                 };
7543         } );
7544         
7545         
7546         /**
7547          * Get the current page length.
7548          *
7549          * @return {integer} Current page length. Note `-1` indicates that all records
7550          *   are to be shown.
7551          *//**
7552          * Set the current page length.
7553          *
7554          * @param {integer} Page length to set. Use `-1` to show all records.
7555          * @returns {DataTables.Api} this
7556          */
7557         _api_register( 'page.len()', function ( len ) {
7558                 // Note that we can't call this function 'length()' because `length`
7559                 // is a Javascript property of functions which defines how many arguments
7560                 // the function expects.
7561                 if ( len === undefined ) {
7562                         return this.context.length !== 0 ?
7563                                 this.context[0]._iDisplayLength :
7564                                 undefined;
7565                 }
7566         
7567                 // else, set the page length
7568                 return this.iterator( 'table', function ( settings ) {
7569                         _fnLengthChange( settings, len );
7570                 } );
7571         } );
7572         
7573         
7574         
7575         var __reload = function ( settings, holdPosition, callback ) {
7576                 // Use the draw event to trigger a callback
7577                 if ( callback ) {
7578                         var api = new _Api( settings );
7579         
7580                         api.one( 'draw', function () {
7581                                 callback( api.ajax.json() );
7582                         } );
7583                 }
7584         
7585                 if ( _fnDataSource( settings ) == 'ssp' ) {
7586                         _fnReDraw( settings, holdPosition );
7587                 }
7588                 else {
7589                         _fnProcessingDisplay( settings, true );
7590         
7591                         // Cancel an existing request
7592                         var xhr = settings.jqXHR;
7593                         if ( xhr && xhr.readyState !== 4 ) {
7594                                 xhr.abort();
7595                         }
7596         
7597                         // Trigger xhr
7598                         _fnBuildAjax( settings, [], function( json ) {
7599                                 _fnClearTable( settings );
7600         
7601                                 var data = _fnAjaxDataSrc( settings, json );
7602                                 for ( var i=0, ien=data.length ; i<ien ; i++ ) {
7603                                         _fnAddData( settings, data[i] );
7604                                 }
7605         
7606                                 _fnReDraw( settings, holdPosition );
7607                                 _fnProcessingDisplay( settings, false );
7608                         } );
7609                 }
7610         };
7611         
7612         
7613         /**
7614          * Get the JSON response from the last Ajax request that DataTables made to the
7615          * server. Note that this returns the JSON from the first table in the current
7616          * context.
7617          *
7618          * @return {object} JSON received from the server.
7619          */
7620         _api_register( 'ajax.json()', function () {
7621                 var ctx = this.context;
7622         
7623                 if ( ctx.length > 0 ) {
7624                         return ctx[0].json;
7625                 }
7626         
7627                 // else return undefined;
7628         } );
7629         
7630         
7631         /**
7632          * Get the data submitted in the last Ajax request
7633          */
7634         _api_register( 'ajax.params()', function () {
7635                 var ctx = this.context;
7636         
7637                 if ( ctx.length > 0 ) {
7638                         return ctx[0].oAjaxData;
7639                 }
7640         
7641                 // else return undefined;
7642         } );
7643         
7644         
7645         /**
7646          * Reload tables from the Ajax data source. Note that this function will
7647          * automatically re-draw the table when the remote data has been loaded.
7648          *
7649          * @param {boolean} [reset=true] Reset (default) or hold the current paging
7650          *   position. A full re-sort and re-filter is performed when this method is
7651          *   called, which is why the pagination reset is the default action.
7652          * @returns {DataTables.Api} this
7653          */
7654         _api_register( 'ajax.reload()', function ( callback, resetPaging ) {
7655                 return this.iterator( 'table', function (settings) {
7656                         __reload( settings, resetPaging===false, callback );
7657                 } );
7658         } );
7659         
7660         
7661         /**
7662          * Get the current Ajax URL. Note that this returns the URL from the first
7663          * table in the current context.
7664          *
7665          * @return {string} Current Ajax source URL
7666          *//**
7667          * Set the Ajax URL. Note that this will set the URL for all tables in the
7668          * current context.
7669          *
7670          * @param {string} url URL to set.
7671          * @returns {DataTables.Api} this
7672          */
7673         _api_register( 'ajax.url()', function ( url ) {
7674                 var ctx = this.context;
7675         
7676                 if ( url === undefined ) {
7677                         // get
7678                         if ( ctx.length === 0 ) {
7679                                 return undefined;
7680                         }
7681                         ctx = ctx[0];
7682         
7683                         return ctx.ajax ?
7684                                 $.isPlainObject( ctx.ajax ) ?
7685                                         ctx.ajax.url :
7686                                         ctx.ajax :
7687                                 ctx.sAjaxSource;
7688                 }
7689         
7690                 // set
7691                 return this.iterator( 'table', function ( settings ) {
7692                         if ( $.isPlainObject( settings.ajax ) ) {
7693                                 settings.ajax.url = url;
7694                         }
7695                         else {
7696                                 settings.ajax = url;
7697                         }
7698                         // No need to consider sAjaxSource here since DataTables gives priority
7699                         // to `ajax` over `sAjaxSource`. So setting `ajax` here, renders any
7700                         // value of `sAjaxSource` redundant.
7701                 } );
7702         } );
7703         
7704         
7705         /**
7706          * Load data from the newly set Ajax URL. Note that this method is only
7707          * available when `ajax.url()` is used to set a URL. Additionally, this method
7708          * has the same effect as calling `ajax.reload()` but is provided for
7709          * convenience when setting a new URL. Like `ajax.reload()` it will
7710          * automatically redraw the table once the remote data has been loaded.
7711          *
7712          * @returns {DataTables.Api} this
7713          */
7714         _api_register( 'ajax.url().load()', function ( callback, resetPaging ) {
7715                 // Same as a reload, but makes sense to present it for easy access after a
7716                 // url change
7717                 return this.iterator( 'table', function ( ctx ) {
7718                         __reload( ctx, resetPaging===false, callback );
7719                 } );
7720         } );
7721         
7722         
7723         
7724         
7725         var _selector_run = function ( type, selector, selectFn, settings, opts )
7726         {
7727                 var
7728                         out = [], res,
7729                         a, i, ien, j, jen,
7730                         selectorType = typeof selector;
7731         
7732                 // Can't just check for isArray here, as an API or jQuery instance might be
7733                 // given with their array like look
7734                 if ( ! selector || selectorType === 'string' || selectorType === 'function' || selector.length === undefined ) {
7735                         selector = [ selector ];
7736                 }
7737         
7738                 for ( i=0, ien=selector.length ; i<ien ; i++ ) {
7739                         // Only split on simple strings - complex expressions will be jQuery selectors
7740                         a = selector[i] && selector[i].split && ! selector[i].match(/[\[\(:]/) ?
7741                                 selector[i].split(',') :
7742                                 [ selector[i] ];
7743         
7744                         for ( j=0, jen=a.length ; j<jen ; j++ ) {
7745                                 res = selectFn( typeof a[j] === 'string' ? $.trim(a[j]) : a[j] );
7746         
7747                                 if ( res && res.length ) {
7748                                         out = out.concat( res );
7749                                 }
7750                         }
7751                 }
7752         
7753                 // selector extensions
7754                 var ext = _ext.selector[ type ];
7755                 if ( ext.length ) {
7756                         for ( i=0, ien=ext.length ; i<ien ; i++ ) {
7757                                 out = ext[i]( settings, opts, out );
7758                         }
7759                 }
7760         
7761                 return _unique( out );
7762         };
7763         
7764         
7765         var _selector_opts = function ( opts )
7766         {
7767                 if ( ! opts ) {
7768                         opts = {};
7769                 }
7770         
7771                 // Backwards compatibility for 1.9- which used the terminology filter rather
7772                 // than search
7773                 if ( opts.filter && opts.search === undefined ) {
7774                         opts.search = opts.filter;
7775                 }
7776         
7777                 return $.extend( {
7778                         search: 'none',
7779                         order: 'current',
7780                         page: 'all'
7781                 }, opts );
7782         };
7783         
7784         
7785         var _selector_first = function ( inst )
7786         {
7787                 // Reduce the API instance to the first item found
7788                 for ( var i=0, ien=inst.length ; i<ien ; i++ ) {
7789                         if ( inst[i].length > 0 ) {
7790                                 // Assign the first element to the first item in the instance
7791                                 // and truncate the instance and context
7792                                 inst[0] = inst[i];
7793                                 inst[0].length = 1;
7794                                 inst.length = 1;
7795                                 inst.context = [ inst.context[i] ];
7796         
7797                                 return inst;
7798                         }
7799                 }
7800         
7801                 // Not found - return an empty instance
7802                 inst.length = 0;
7803                 return inst;
7804         };
7805         
7806         
7807         var _selector_row_indexes = function ( settings, opts )
7808         {
7809                 var
7810                         i, ien, tmp, a=[],
7811                         displayFiltered = settings.aiDisplay,
7812                         displayMaster = settings.aiDisplayMaster;
7813         
7814                 var
7815                         search = opts.search,  // none, applied, removed
7816                         order  = opts.order,   // applied, current, index (original - compatibility with 1.9)
7817                         page   = opts.page;    // all, current
7818         
7819                 if ( _fnDataSource( settings ) == 'ssp' ) {
7820                         // In server-side processing mode, most options are irrelevant since
7821                         // rows not shown don't exist and the index order is the applied order
7822                         // Removed is a special case - for consistency just return an empty
7823                         // array
7824                         return search === 'removed' ?
7825                                 [] :
7826                                 _range( 0, displayMaster.length );
7827                 }
7828                 else if ( page == 'current' ) {
7829                         // Current page implies that order=current and fitler=applied, since it is
7830                         // fairly senseless otherwise, regardless of what order and search actually
7831                         // are
7832                         for ( i=settings._iDisplayStart, ien=settings.fnDisplayEnd() ; i<ien ; i++ ) {
7833                                 a.push( displayFiltered[i] );
7834                         }
7835                 }
7836                 else if ( order == 'current' || order == 'applied' ) {
7837                         if ( search == 'none') {
7838                                 a = displayMaster.slice();
7839                         }
7840                         else if ( search == 'applied' ) {
7841                                 a = displayFiltered.slice();
7842                         }
7843                         else if ( search == 'removed' ) {
7844                                 // O(n+m) solution by creating a hash map
7845                                 var displayFilteredMap = {};
7846         
7847                                 for ( var i=0, ien=displayFiltered.length ; i<ien ; i++ ) {
7848                                         displayFilteredMap[displayFiltered[i]] = null;
7849                                 }
7850         
7851                                 a = $.map( displayMaster, function (el) {
7852                                         return ! displayFilteredMap.hasOwnProperty(el) ?
7853                                                 el :
7854                                                 null;
7855                                 } );
7856                         }
7857                 }
7858                 else if ( order == 'index' || order == 'original' ) {
7859                         for ( i=0, ien=settings.aoData.length ; i<ien ; i++ ) {
7860                                 if ( search == 'none' ) {
7861                                         a.push( i );
7862                                 }
7863                                 else { // applied | removed
7864                                         tmp = $.inArray( i, displayFiltered );
7865         
7866                                         if ((tmp === -1 && search == 'removed') ||
7867                                                 (tmp >= 0   && search == 'applied') )
7868                                         {
7869                                                 a.push( i );
7870                                         }
7871                                 }
7872                         }
7873                 }
7874         
7875                 return a;
7876         };
7877         
7878         
7879         /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
7880          * Rows
7881          *
7882          * {}          - no selector - use all available rows
7883          * {integer}   - row aoData index
7884          * {node}      - TR node
7885          * {string}    - jQuery selector to apply to the TR elements
7886          * {array}     - jQuery array of nodes, or simply an array of TR nodes
7887          *
7888          */
7889         var __row_selector = function ( settings, selector, opts )
7890         {
7891                 var rows;
7892                 var run = function ( sel ) {
7893                         var selInt = _intVal( sel );
7894                         var i, ien;
7895                         var aoData = settings.aoData;
7896         
7897                         // Short cut - selector is a number and no options provided (default is
7898                         // all records, so no need to check if the index is in there, since it
7899                         // must be - dev error if the index doesn't exist).
7900                         if ( selInt !== null && ! opts ) {
7901                                 return [ selInt ];
7902                         }
7903         
7904                         if ( ! rows ) {
7905                                 rows = _selector_row_indexes( settings, opts );
7906                         }
7907         
7908                         if ( selInt !== null && $.inArray( selInt, rows ) !== -1 ) {
7909                                 // Selector - integer
7910                                 return [ selInt ];
7911                         }
7912                         else if ( sel === null || sel === undefined || sel === '' ) {
7913                                 // Selector - none
7914                                 return rows;
7915                         }
7916         
7917                         // Selector - function
7918                         if ( typeof sel === 'function' ) {
7919                                 return $.map( rows, function (idx) {
7920                                         var row = aoData[ idx ];
7921                                         return sel( idx, row._aData, row.nTr ) ? idx : null;
7922                                 } );
7923                         }
7924         
7925                         // Selector - node
7926                         if ( sel.nodeName ) {
7927                                 var rowIdx = sel._DT_RowIndex;  // Property added by DT for fast lookup
7928                                 var cellIdx = sel._DT_CellIndex;
7929         
7930                                 if ( rowIdx !== undefined ) {
7931                                         // Make sure that the row is actually still present in the table
7932                                         return aoData[ rowIdx ] && aoData[ rowIdx ].nTr === sel ?
7933                                                 [ rowIdx ] :
7934                                                 [];
7935                                 }
7936                                 else if ( cellIdx ) {
7937                                         return aoData[ cellIdx.row ] && aoData[ cellIdx.row ].nTr === sel.parentNode ?
7938                                                 [ cellIdx.row ] :
7939                                                 [];
7940                                 }
7941                                 else {
7942                                         var host = $(sel).closest('*[data-dt-row]');
7943                                         return host.length ?
7944                                                 [ host.data('dt-row') ] :
7945                                                 [];
7946                                 }
7947                         }
7948         
7949                         // ID selector. Want to always be able to select rows by id, regardless
7950                         // of if the tr element has been created or not, so can't rely upon
7951                         // jQuery here - hence a custom implementation. This does not match
7952                         // Sizzle's fast selector or HTML4 - in HTML5 the ID can be anything,
7953                         // but to select it using a CSS selector engine (like Sizzle or
7954                         // querySelect) it would need to need to be escaped for some characters.
7955                         // DataTables simplifies this for row selectors since you can select
7956                         // only a row. A # indicates an id any anything that follows is the id -
7957                         // unescaped.
7958                         if ( typeof sel === 'string' && sel.charAt(0) === '#' ) {
7959                                 // get row index from id
7960                                 var rowObj = settings.aIds[ sel.replace( /^#/, '' ) ];
7961                                 if ( rowObj !== undefined ) {
7962                                         return [ rowObj.idx ];
7963                                 }
7964         
7965                                 // need to fall through to jQuery in case there is DOM id that
7966                                 // matches
7967                         }
7968                         
7969                         // Get nodes in the order from the `rows` array with null values removed
7970                         var nodes = _removeEmpty(
7971                                 _pluck_order( settings.aoData, rows, 'nTr' )
7972                         );
7973         
7974                         // Selector - jQuery selector string, array of nodes or jQuery object/
7975                         // As jQuery's .filter() allows jQuery objects to be passed in filter,
7976                         // it also allows arrays, so this will cope with all three options
7977                         return $(nodes)
7978                                 .filter( sel )
7979                                 .map( function () {
7980                                         return this._DT_RowIndex;
7981                                 } )
7982                                 .toArray();
7983                 };
7984         
7985                 return _selector_run( 'row', selector, run, settings, opts );
7986         };
7987         
7988         
7989         _api_register( 'rows()', function ( selector, opts ) {
7990                 // argument shifting
7991                 if ( selector === undefined ) {
7992                         selector = '';
7993                 }
7994                 else if ( $.isPlainObject( selector ) ) {
7995                         opts = selector;
7996                         selector = '';
7997                 }
7998         
7999                 opts = _selector_opts( opts );
8000         
8001                 var inst = this.iterator( 'table', function ( settings ) {
8002                         return __row_selector( settings, selector, opts );
8003                 }, 1 );
8004         
8005                 // Want argument shifting here and in __row_selector?
8006                 inst.selector.rows = selector;
8007                 inst.selector.opts = opts;
8008         
8009                 return inst;
8010         } );
8011         
8012         _api_register( 'rows().nodes()', function () {
8013                 return this.iterator( 'row', function ( settings, row ) {
8014                         return settings.aoData[ row ].nTr || undefined;
8015                 }, 1 );
8016         } );
8017         
8018         _api_register( 'rows().data()', function () {
8019                 return this.iterator( true, 'rows', function ( settings, rows ) {
8020                         return _pluck_order( settings.aoData, rows, '_aData' );
8021                 }, 1 );
8022         } );
8023         
8024         _api_registerPlural( 'rows().cache()', 'row().cache()', function ( type ) {
8025                 return this.iterator( 'row', function ( settings, row ) {
8026                         var r = settings.aoData[ row ];
8027                         return type === 'search' ? r._aFilterData : r._aSortData;
8028                 }, 1 );
8029         } );
8030         
8031         _api_registerPlural( 'rows().invalidate()', 'row().invalidate()', function ( src ) {
8032                 return this.iterator( 'row', function ( settings, row ) {
8033                         _fnInvalidate( settings, row, src );
8034                 } );
8035         } );
8036         
8037         _api_registerPlural( 'rows().indexes()', 'row().index()', function () {
8038                 return this.iterator( 'row', function ( settings, row ) {
8039                         return row;
8040                 }, 1 );
8041         } );
8042         
8043         _api_registerPlural( 'rows().ids()', 'row().id()', function ( hash ) {
8044                 var a = [];
8045                 var context = this.context;
8046         
8047                 // `iterator` will drop undefined values, but in this case we want them
8048                 for ( var i=0, ien=context.length ; i<ien ; i++ ) {
8049                         for ( var j=0, jen=this[i].length ; j<jen ; j++ ) {
8050                                 var id = context[i].rowIdFn( context[i].aoData[ this[i][j] ]._aData );
8051                                 a.push( (hash === true ? '#' : '' )+ id );
8052                         }
8053                 }
8054         
8055                 return new _Api( context, a );
8056         } );
8057         
8058         _api_registerPlural( 'rows().remove()', 'row().remove()', function () {
8059                 var that = this;
8060         
8061                 this.iterator( 'row', function ( settings, row, thatIdx ) {
8062                         var data = settings.aoData;
8063                         var rowData = data[ row ];
8064                         var i, ien, j, jen;
8065                         var loopRow, loopCells;
8066         
8067                         data.splice( row, 1 );
8068         
8069                         // Update the cached indexes
8070                         for ( i=0, ien=data.length ; i<ien ; i++ ) {
8071                                 loopRow = data[i];
8072                                 loopCells = loopRow.anCells;
8073         
8074                                 // Rows
8075                                 if ( loopRow.nTr !== null ) {
8076                                         loopRow.nTr._DT_RowIndex = i;
8077                                 }
8078         
8079                                 // Cells
8080                                 if ( loopCells !== null ) {
8081                                         for ( j=0, jen=loopCells.length ; j<jen ; j++ ) {
8082                                                 loopCells[j]._DT_CellIndex.row = i;
8083                                         }
8084                                 }
8085                         }
8086         
8087                         // Delete from the display arrays
8088                         _fnDeleteIndex( settings.aiDisplayMaster, row );
8089                         _fnDeleteIndex( settings.aiDisplay, row );
8090                         _fnDeleteIndex( that[ thatIdx ], row, false ); // maintain local indexes
8091         
8092                         // For server-side processing tables - subtract the deleted row from the count
8093                         if ( settings._iRecordsDisplay > 0 ) {
8094                                 settings._iRecordsDisplay--;
8095                         }
8096         
8097                         // Check for an 'overflow' they case for displaying the table
8098                         _fnLengthOverflow( settings );
8099         
8100                         // Remove the row's ID reference if there is one
8101                         var id = settings.rowIdFn( rowData._aData );
8102                         if ( id !== undefined ) {
8103                                 delete settings.aIds[ id ];
8104                         }
8105                 } );
8106         
8107                 this.iterator( 'table', function ( settings ) {
8108                         for ( var i=0, ien=settings.aoData.length ; i<ien ; i++ ) {
8109                                 settings.aoData[i].idx = i;
8110                         }
8111                 } );
8112         
8113                 return this;
8114         } );
8115         
8116         
8117         _api_register( 'rows.add()', function ( rows ) {
8118                 var newRows = this.iterator( 'table', function ( settings ) {
8119                                 var row, i, ien;
8120                                 var out = [];
8121         
8122                                 for ( i=0, ien=rows.length ; i<ien ; i++ ) {
8123                                         row = rows[i];
8124         
8125                                         if ( row.nodeName && row.nodeName.toUpperCase() === 'TR' ) {
8126                                                 out.push( _fnAddTr( settings, row )[0] );
8127                                         }
8128                                         else {
8129                                                 out.push( _fnAddData( settings, row ) );
8130                                         }
8131                                 }
8132         
8133                                 return out;
8134                         }, 1 );
8135         
8136                 // Return an Api.rows() extended instance, so rows().nodes() etc can be used
8137                 var modRows = this.rows( -1 );
8138                 modRows.pop();
8139                 $.merge( modRows, newRows );
8140         
8141                 return modRows;
8142         } );
8143         
8144         
8145         
8146         
8147         
8148         /**
8149          *
8150          */
8151         _api_register( 'row()', function ( selector, opts ) {
8152                 return _selector_first( this.rows( selector, opts ) );
8153         } );
8154         
8155         
8156         _api_register( 'row().data()', function ( data ) {
8157                 var ctx = this.context;
8158         
8159                 if ( data === undefined ) {
8160                         // Get
8161                         return ctx.length && this.length ?
8162                                 ctx[0].aoData[ this[0] ]._aData :
8163                                 undefined;
8164                 }
8165         
8166                 // Set
8167                 var row = ctx[0].aoData[ this[0] ];
8168                 row._aData = data;
8169         
8170                 // If the DOM has an id, and the data source is an array
8171                 if ( $.isArray( data ) && row.nTr.id ) {
8172                         _fnSetObjectDataFn( ctx[0].rowId )( data, row.nTr.id );
8173                 }
8174         
8175                 // Automatically invalidate
8176                 _fnInvalidate( ctx[0], this[0], 'data' );
8177         
8178                 return this;
8179         } );
8180         
8181         
8182         _api_register( 'row().node()', function () {
8183                 var ctx = this.context;
8184         
8185                 return ctx.length && this.length ?
8186                         ctx[0].aoData[ this[0] ].nTr || null :
8187                         null;
8188         } );
8189         
8190         
8191         _api_register( 'row.add()', function ( row ) {
8192                 // Allow a jQuery object to be passed in - only a single row is added from
8193                 // it though - the first element in the set
8194                 if ( row instanceof $ && row.length ) {
8195                         row = row[0];
8196                 }
8197         
8198                 var rows = this.iterator( 'table', function ( settings ) {
8199                         if ( row.nodeName && row.nodeName.toUpperCase() === 'TR' ) {
8200                                 return _fnAddTr( settings, row )[0];
8201                         }
8202                         return _fnAddData( settings, row );
8203                 } );
8204         
8205                 // Return an Api.rows() extended instance, with the newly added row selected
8206                 return this.row( rows[0] );
8207         } );
8208         
8209         
8210         
8211         var __details_add = function ( ctx, row, data, klass )
8212         {
8213                 // Convert to array of TR elements
8214                 var rows = [];
8215                 var addRow = function ( r, k ) {
8216                         // Recursion to allow for arrays of jQuery objects
8217                         if ( $.isArray( r ) || r instanceof $ ) {
8218                                 for ( var i=0, ien=r.length ; i<ien ; i++ ) {
8219                                         addRow( r[i], k );
8220                                 }
8221                                 return;
8222                         }
8223         
8224                         // If we get a TR element, then just add it directly - up to the dev
8225                         // to add the correct number of columns etc
8226                         if ( r.nodeName && r.nodeName.toLowerCase() === 'tr' ) {
8227                                 rows.push( r );
8228                         }
8229                         else {
8230                                 // Otherwise create a row with a wrapper
8231                                 var created = $('<tr><td/></tr>').addClass( k );
8232                                 $('td', created)
8233                                         .addClass( k )
8234                                         .html( r )
8235                                         [0].colSpan = _fnVisbleColumns( ctx );
8236         
8237                                 rows.push( created[0] );
8238                         }
8239                 };
8240         
8241                 addRow( data, klass );
8242         
8243                 if ( row._details ) {
8244                         row._details.detach();
8245                 }
8246         
8247                 row._details = $(rows);
8248         
8249                 // If the children were already shown, that state should be retained
8250                 if ( row._detailsShow ) {
8251                         row._details.insertAfter( row.nTr );
8252                 }
8253         };
8254         
8255         
8256         var __details_remove = function ( api, idx )
8257         {
8258                 var ctx = api.context;
8259         
8260                 if ( ctx.length ) {
8261                         var row = ctx[0].aoData[ idx !== undefined ? idx : api[0] ];
8262         
8263                         if ( row && row._details ) {
8264                                 row._details.remove();
8265         
8266                                 row._detailsShow = undefined;
8267                                 row._details = undefined;
8268                         }
8269                 }
8270         };
8271         
8272         
8273         var __details_display = function ( api, show ) {
8274                 var ctx = api.context;
8275         
8276                 if ( ctx.length && api.length ) {
8277                         var row = ctx[0].aoData[ api[0] ];
8278         
8279                         if ( row._details ) {
8280                                 row._detailsShow = show;
8281         
8282                                 if ( show ) {
8283                                         row._details.insertAfter( row.nTr );
8284                                 }
8285                                 else {
8286                                         row._details.detach();
8287                                 }
8288         
8289                                 __details_events( ctx[0] );
8290                         }
8291                 }
8292         };
8293         
8294         
8295         var __details_events = function ( settings )
8296         {
8297                 var api = new _Api( settings );
8298                 var namespace = '.dt.DT_details';
8299                 var drawEvent = 'draw'+namespace;
8300                 var colvisEvent = 'column-visibility'+namespace;
8301                 var destroyEvent = 'destroy'+namespace;
8302                 var data = settings.aoData;
8303         
8304                 api.off( drawEvent +' '+ colvisEvent +' '+ destroyEvent );
8305         
8306                 if ( _pluck( data, '_details' ).length > 0 ) {
8307                         // On each draw, insert the required elements into the document
8308                         api.on( drawEvent, function ( e, ctx ) {
8309                                 if ( settings !== ctx ) {
8310                                         return;
8311                                 }
8312         
8313                                 api.rows( {page:'current'} ).eq(0).each( function (idx) {
8314                                         // Internal data grab
8315                                         var row = data[ idx ];
8316         
8317                                         if ( row._detailsShow ) {
8318                                                 row._details.insertAfter( row.nTr );
8319                                         }
8320                                 } );
8321                         } );
8322         
8323                         // Column visibility change - update the colspan
8324                         api.on( colvisEvent, function ( e, ctx, idx, vis ) {
8325                                 if ( settings !== ctx ) {
8326                                         return;
8327                                 }
8328         
8329                                 // Update the colspan for the details rows (note, only if it already has
8330                                 // a colspan)
8331                                 var row, visible = _fnVisbleColumns( ctx );
8332         
8333                                 for ( var i=0, ien=data.length ; i<ien ; i++ ) {
8334                                         row = data[i];
8335         
8336                                         if ( row._details ) {
8337                                                 row._details.children('td[colspan]').attr('colspan', visible );
8338                                         }
8339                                 }
8340                         } );
8341         
8342                         // Table destroyed - nuke any child rows
8343                         api.on( destroyEvent, function ( e, ctx ) {
8344                                 if ( settings !== ctx ) {
8345                                         return;
8346                                 }
8347         
8348                                 for ( var i=0, ien=data.length ; i<ien ; i++ ) {
8349                                         if ( data[i]._details ) {
8350                                                 __details_remove( api, i );
8351                                         }
8352                                 }
8353                         } );
8354                 }
8355         };
8356         
8357         // Strings for the method names to help minification
8358         var _emp = '';
8359         var _child_obj = _emp+'row().child';
8360         var _child_mth = _child_obj+'()';
8361         
8362         // data can be:
8363         //  tr
8364         //  string
8365         //  jQuery or array of any of the above
8366         _api_register( _child_mth, function ( data, klass ) {
8367                 var ctx = this.context;
8368         
8369                 if ( data === undefined ) {
8370                         // get
8371                         return ctx.length && this.length ?
8372                                 ctx[0].aoData[ this[0] ]._details :
8373                                 undefined;
8374                 }
8375                 else if ( data === true ) {
8376                         // show
8377                         this.child.show();
8378                 }
8379                 else if ( data === false ) {
8380                         // remove
8381                         __details_remove( this );
8382                 }
8383                 else if ( ctx.length && this.length ) {
8384                         // set
8385                         __details_add( ctx[0], ctx[0].aoData[ this[0] ], data, klass );
8386                 }
8387         
8388                 return this;
8389         } );
8390         
8391         
8392         _api_register( [
8393                 _child_obj+'.show()',
8394                 _child_mth+'.show()' // only when `child()` was called with parameters (without
8395         ], function ( show ) {   // it returns an object and this method is not executed)
8396                 __details_display( this, true );
8397                 return this;
8398         } );
8399         
8400         
8401         _api_register( [
8402                 _child_obj+'.hide()',
8403                 _child_mth+'.hide()' // only when `child()` was called with parameters (without
8404         ], function () {         // it returns an object and this method is not executed)
8405                 __details_display( this, false );
8406                 return this;
8407         } );
8408         
8409         
8410         _api_register( [
8411                 _child_obj+'.remove()',
8412                 _child_mth+'.remove()' // only when `child()` was called with parameters (without
8413         ], function () {           // it returns an object and this method is not executed)
8414                 __details_remove( this );
8415                 return this;
8416         } );
8417         
8418         
8419         _api_register( _child_obj+'.isShown()', function () {
8420                 var ctx = this.context;
8421         
8422                 if ( ctx.length && this.length ) {
8423                         // _detailsShown as false or undefined will fall through to return false
8424                         return ctx[0].aoData[ this[0] ]._detailsShow || false;
8425                 }
8426                 return false;
8427         } );
8428         
8429         
8430         
8431         /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
8432          * Columns
8433          *
8434          * {integer}           - column index (>=0 count from left, <0 count from right)
8435          * "{integer}:visIdx"  - visible column index (i.e. translate to column index)  (>=0 count from left, <0 count from right)
8436          * "{integer}:visible" - alias for {integer}:visIdx  (>=0 count from left, <0 count from right)
8437          * "{string}:name"     - column name
8438          * "{string}"          - jQuery selector on column header nodes
8439          *
8440          */
8441         
8442         // can be an array of these items, comma separated list, or an array of comma
8443         // separated lists
8444         
8445         var __re_column_selector = /^([^:]+):(name|visIdx|visible)$/;
8446         
8447         
8448         // r1 and r2 are redundant - but it means that the parameters match for the
8449         // iterator callback in columns().data()
8450         var __columnData = function ( settings, column, r1, r2, rows ) {
8451                 var a = [];
8452                 for ( var row=0, ien=rows.length ; row<ien ; row++ ) {
8453                         a.push( _fnGetCellData( settings, rows[row], column ) );
8454                 }
8455                 return a;
8456         };
8457         
8458         
8459         var __column_selector = function ( settings, selector, opts )
8460         {
8461                 var
8462                         columns = settings.aoColumns,
8463                         names = _pluck( columns, 'sName' ),
8464                         nodes = _pluck( columns, 'nTh' );
8465         
8466                 var run = function ( s ) {
8467                         var selInt = _intVal( s );
8468         
8469                         // Selector - all
8470                         if ( s === '' ) {
8471                                 return _range( columns.length );
8472                         }
8473         
8474                         // Selector - index
8475                         if ( selInt !== null ) {
8476                                 return [ selInt >= 0 ?
8477                                         selInt : // Count from left
8478                                         columns.length + selInt // Count from right (+ because its a negative value)
8479                                 ];
8480                         }
8481         
8482                         // Selector = function
8483                         if ( typeof s === 'function' ) {
8484                                 var rows = _selector_row_indexes( settings, opts );
8485         
8486                                 return $.map( columns, function (col, idx) {
8487                                         return s(
8488                                                         idx,
8489                                                         __columnData( settings, idx, 0, 0, rows ),
8490                                                         nodes[ idx ]
8491                                                 ) ? idx : null;
8492                                 } );
8493                         }
8494         
8495                         // jQuery or string selector
8496                         var match = typeof s === 'string' ?
8497                                 s.match( __re_column_selector ) :
8498                                 '';
8499         
8500                         if ( match ) {
8501                                 switch( match[2] ) {
8502                                         case 'visIdx':
8503                                         case 'visible':
8504                                                 var idx = parseInt( match[1], 10 );
8505                                                 // Visible index given, convert to column index
8506                                                 if ( idx < 0 ) {
8507                                                         // Counting from the right
8508                                                         var visColumns = $.map( columns, function (col,i) {
8509                                                                 return col.bVisible ? i : null;
8510                                                         } );
8511                                                         return [ visColumns[ visColumns.length + idx ] ];
8512                                                 }
8513                                                 // Counting from the left
8514                                                 return [ _fnVisibleToColumnIndex( settings, idx ) ];
8515         
8516                                         case 'name':
8517                                                 // match by name. `names` is column index complete and in order
8518                                                 return $.map( names, function (name, i) {
8519                                                         return name === match[1] ? i : null;
8520                                                 } );
8521         
8522                                         default:
8523                                                 return [];
8524                                 }
8525                         }
8526         
8527                         // Cell in the table body
8528                         if ( s.nodeName && s._DT_CellIndex ) {
8529                                 return [ s._DT_CellIndex.column ];
8530                         }
8531         
8532                         // jQuery selector on the TH elements for the columns
8533                         var jqResult = $( nodes )
8534                                 .filter( s )
8535                                 .map( function () {
8536                                         return $.inArray( this, nodes ); // `nodes` is column index complete and in order
8537                                 } )
8538                                 .toArray();
8539         
8540                         if ( jqResult.length || ! s.nodeName ) {
8541                                 return jqResult;
8542                         }
8543         
8544                         // Otherwise a node which might have a `dt-column` data attribute, or be
8545                         // a child or such an element
8546                         var host = $(s).closest('*[data-dt-column]');
8547                         return host.length ?
8548                                 [ host.data('dt-column') ] :
8549                                 [];
8550                 };
8551         
8552                 return _selector_run( 'column', selector, run, settings, opts );
8553         };
8554         
8555         
8556         var __setColumnVis = function ( settings, column, vis ) {
8557                 var
8558                         cols = settings.aoColumns,
8559                         col  = cols[ column ],
8560                         data = settings.aoData,
8561                         row, cells, i, ien, tr;
8562         
8563                 // Get
8564                 if ( vis === undefined ) {
8565                         return col.bVisible;
8566                 }
8567         
8568                 // Set
8569                 // No change
8570                 if ( col.bVisible === vis ) {
8571                         return;
8572                 }
8573         
8574                 if ( vis ) {
8575                         // Insert column
8576                         // Need to decide if we should use appendChild or insertBefore
8577                         var insertBefore = $.inArray( true, _pluck(cols, 'bVisible'), column+1 );
8578         
8579                         for ( i=0, ien=data.length ; i<ien ; i++ ) {
8580                                 tr = data[i].nTr;
8581                                 cells = data[i].anCells;
8582         
8583                                 if ( tr ) {
8584                                         // insertBefore can act like appendChild if 2nd arg is null
8585                                         tr.insertBefore( cells[ column ], cells[ insertBefore ] || null );
8586                                 }
8587                         }
8588                 }
8589                 else {
8590                         // Remove column
8591                         $( _pluck( settings.aoData, 'anCells', column ) ).detach();
8592                 }
8593         
8594                 // Common actions
8595                 col.bVisible = vis;
8596         };
8597         
8598         
8599         _api_register( 'columns()', function ( selector, opts ) {
8600                 // argument shifting
8601                 if ( selector === undefined ) {
8602                         selector = '';
8603                 }
8604                 else if ( $.isPlainObject( selector ) ) {
8605                         opts = selector;
8606                         selector = '';
8607                 }
8608         
8609                 opts = _selector_opts( opts );
8610         
8611                 var inst = this.iterator( 'table', function ( settings ) {
8612                         return __column_selector( settings, selector, opts );
8613                 }, 1 );
8614         
8615                 // Want argument shifting here and in _row_selector?
8616                 inst.selector.cols = selector;
8617                 inst.selector.opts = opts;
8618         
8619                 return inst;
8620         } );
8621         
8622         _api_registerPlural( 'columns().header()', 'column().header()', function ( selector, opts ) {
8623                 return this.iterator( 'column', function ( settings, column ) {
8624                         return settings.aoColumns[column].nTh;
8625                 }, 1 );
8626         } );
8627         
8628         _api_registerPlural( 'columns().footer()', 'column().footer()', function ( selector, opts ) {
8629                 return this.iterator( 'column', function ( settings, column ) {
8630                         return settings.aoColumns[column].nTf;
8631                 }, 1 );
8632         } );
8633         
8634         _api_registerPlural( 'columns().data()', 'column().data()', function () {
8635                 return this.iterator( 'column-rows', __columnData, 1 );
8636         } );
8637         
8638         _api_registerPlural( 'columns().dataSrc()', 'column().dataSrc()', function () {
8639                 return this.iterator( 'column', function ( settings, column ) {
8640                         return settings.aoColumns[column].mData;
8641                 }, 1 );
8642         } );
8643         
8644         _api_registerPlural( 'columns().cache()', 'column().cache()', function ( type ) {
8645                 return this.iterator( 'column-rows', function ( settings, column, i, j, rows ) {
8646                         return _pluck_order( settings.aoData, rows,
8647                                 type === 'search' ? '_aFilterData' : '_aSortData', column
8648                         );
8649                 }, 1 );
8650         } );
8651         
8652         _api_registerPlural( 'columns().nodes()', 'column().nodes()', function () {
8653                 return this.iterator( 'column-rows', function ( settings, column, i, j, rows ) {
8654                         return _pluck_order( settings.aoData, rows, 'anCells', column ) ;
8655                 }, 1 );
8656         } );
8657         
8658         _api_registerPlural( 'columns().visible()', 'column().visible()', function ( vis, calc ) {
8659                 var that = this;
8660                 var ret = this.iterator( 'column', function ( settings, column ) {
8661                         if ( vis === undefined ) {
8662                                 return settings.aoColumns[ column ].bVisible;
8663                         } // else
8664                         __setColumnVis( settings, column, vis );
8665                 } );
8666         
8667                 // Group the column visibility changes
8668                 if ( vis !== undefined ) {
8669                         this.iterator( 'table', function ( settings ) {
8670                                 // Redraw the header after changes
8671                                 _fnDrawHead( settings, settings.aoHeader );
8672                                 _fnDrawHead( settings, settings.aoFooter );
8673                 
8674                                 // Update colspan for no records display. Child rows and extensions will use their own
8675                                 // listeners to do this - only need to update the empty table item here
8676                                 if ( ! settings.aiDisplay.length ) {
8677                                         $(settings.nTBody).find('td[colspan]').attr('colspan', _fnVisbleColumns(settings));
8678                                 }
8679                 
8680                                 _fnSaveState( settings );
8681         
8682                                 // Second loop once the first is done for events
8683                                 that.iterator( 'column', function ( settings, column ) {
8684                                         _fnCallbackFire( settings, null, 'column-visibility', [settings, column, vis, calc] );
8685                                 } );
8686         
8687                                 if ( calc === undefined || calc ) {
8688                                         that.columns.adjust();
8689                                 }
8690                         });
8691                 }
8692         
8693                 return ret;
8694         } );
8695         
8696         _api_registerPlural( 'columns().indexes()', 'column().index()', function ( type ) {
8697                 return this.iterator( 'column', function ( settings, column ) {
8698                         return type === 'visible' ?
8699                                 _fnColumnIndexToVisible( settings, column ) :
8700                                 column;
8701                 }, 1 );
8702         } );
8703         
8704         _api_register( 'columns.adjust()', function () {
8705                 return this.iterator( 'table', function ( settings ) {
8706                         _fnAdjustColumnSizing( settings );
8707                 }, 1 );
8708         } );
8709         
8710         _api_register( 'column.index()', function ( type, idx ) {
8711                 if ( this.context.length !== 0 ) {
8712                         var ctx = this.context[0];
8713         
8714                         if ( type === 'fromVisible' || type === 'toData' ) {
8715                                 return _fnVisibleToColumnIndex( ctx, idx );
8716                         }
8717                         else if ( type === 'fromData' || type === 'toVisible' ) {
8718                                 return _fnColumnIndexToVisible( ctx, idx );
8719                         }
8720                 }
8721         } );
8722         
8723         _api_register( 'column()', function ( selector, opts ) {
8724                 return _selector_first( this.columns( selector, opts ) );
8725         } );
8726         
8727         
8728         
8729         var __cell_selector = function ( settings, selector, opts )
8730         {
8731                 var data = settings.aoData;
8732                 var rows = _selector_row_indexes( settings, opts );
8733                 var cells = _removeEmpty( _pluck_order( data, rows, 'anCells' ) );
8734                 var allCells = $( [].concat.apply([], cells) );
8735                 var row;
8736                 var columns = settings.aoColumns.length;
8737                 var a, i, ien, j, o, host;
8738         
8739                 var run = function ( s ) {
8740                         var fnSelector = typeof s === 'function';
8741         
8742                         if ( s === null || s === undefined || fnSelector ) {
8743                                 // All cells and function selectors
8744                                 a = [];
8745         
8746                                 for ( i=0, ien=rows.length ; i<ien ; i++ ) {
8747                                         row = rows[i];
8748         
8749                                         for ( j=0 ; j<columns ; j++ ) {
8750                                                 o = {
8751                                                         row: row,
8752                                                         column: j
8753                                                 };
8754         
8755                                                 if ( fnSelector ) {
8756                                                         // Selector - function
8757                                                         host = data[ row ];
8758         
8759                                                         if ( s( o, _fnGetCellData(settings, row, j), host.anCells ? host.anCells[j] : null ) ) {
8760                                                                 a.push( o );
8761                                                         }
8762                                                 }
8763                                                 else {
8764                                                         // Selector - all
8765                                                         a.push( o );
8766                                                 }
8767                                         }
8768                                 }
8769         
8770                                 return a;
8771                         }
8772                         
8773                         // Selector - index
8774                         if ( $.isPlainObject( s ) ) {
8775                                 // Valid cell index and its in the array of selectable rows
8776                                 return s.column !== undefined && s.row !== undefined && $.inArray( s.row, rows ) !== -1 ?
8777                                         [s] :
8778                                         [];
8779                         }
8780         
8781                         // Selector - jQuery filtered cells
8782                         var jqResult = allCells
8783                                 .filter( s )
8784                                 .map( function (i, el) {
8785                                         return { // use a new object, in case someone changes the values
8786                                                 row:    el._DT_CellIndex.row,
8787                                                 column: el._DT_CellIndex.column
8788                                         };
8789                                 } )
8790                                 .toArray();
8791         
8792                         if ( jqResult.length || ! s.nodeName ) {
8793                                 return jqResult;
8794                         }
8795         
8796                         // Otherwise the selector is a node, and there is one last option - the
8797                         // element might be a child of an element which has dt-row and dt-column
8798                         // data attributes
8799                         host = $(s).closest('*[data-dt-row]');
8800                         return host.length ?
8801                                 [ {
8802                                         row: host.data('dt-row'),
8803                                         column: host.data('dt-column')
8804                                 } ] :
8805                                 [];
8806                 };
8807         
8808                 return _selector_run( 'cell', selector, run, settings, opts );
8809         };
8810         
8811         
8812         
8813         
8814         _api_register( 'cells()', function ( rowSelector, columnSelector, opts ) {
8815                 // Argument shifting
8816                 if ( $.isPlainObject( rowSelector ) ) {
8817                         // Indexes
8818                         if ( rowSelector.row === undefined ) {
8819                                 // Selector options in first parameter
8820                                 opts = rowSelector;
8821                                 rowSelector = null;
8822                         }
8823                         else {
8824                                 // Cell index objects in first parameter
8825                                 opts = columnSelector;
8826                                 columnSelector = null;
8827                         }
8828                 }
8829                 if ( $.isPlainObject( columnSelector ) ) {
8830                         opts = columnSelector;
8831                         columnSelector = null;
8832                 }
8833         
8834                 // Cell selector
8835                 if ( columnSelector === null || columnSelector === undefined ) {
8836                         return this.iterator( 'table', function ( settings ) {
8837                                 return __cell_selector( settings, rowSelector, _selector_opts( opts ) );
8838                         } );
8839                 }
8840         
8841                 // The default built in options need to apply to row and columns
8842                 var internalOpts = opts ? {
8843                         page: opts.page,
8844                         order: opts.order,
8845                         search: opts.search
8846                 } : {};
8847         
8848                 // Row + column selector
8849                 var columns = this.columns( columnSelector, internalOpts );
8850                 var rows = this.rows( rowSelector, internalOpts );
8851                 var i, ien, j, jen;
8852         
8853                 var cellsNoOpts = this.iterator( 'table', function ( settings, idx ) {
8854                         var a = [];
8855         
8856                         for ( i=0, ien=rows[idx].length ; i<ien ; i++ ) {
8857                                 for ( j=0, jen=columns[idx].length ; j<jen ; j++ ) {
8858                                         a.push( {
8859                                                 row:    rows[idx][i],
8860                                                 column: columns[idx][j]
8861                                         } );
8862                                 }
8863                         }
8864         
8865                         return a;
8866                 }, 1 );
8867         
8868                 // There is currently only one extension which uses a cell selector extension
8869                 // It is a _major_ performance drag to run this if it isn't needed, so this is
8870                 // an extension specific check at the moment
8871                 var cells = opts && opts.selected ?
8872                         this.cells( cellsNoOpts, opts ) :
8873                         cellsNoOpts;
8874         
8875                 $.extend( cells.selector, {
8876                         cols: columnSelector,
8877                         rows: rowSelector,
8878                         opts: opts
8879                 } );
8880         
8881                 return cells;
8882         } );
8883         
8884         
8885         _api_registerPlural( 'cells().nodes()', 'cell().node()', function () {
8886                 return this.iterator( 'cell', function ( settings, row, column ) {
8887                         var data = settings.aoData[ row ];
8888         
8889                         return data && data.anCells ?
8890                                 data.anCells[ column ] :
8891                                 undefined;
8892                 }, 1 );
8893         } );
8894         
8895         
8896         _api_register( 'cells().data()', function () {
8897                 return this.iterator( 'cell', function ( settings, row, column ) {
8898                         return _fnGetCellData( settings, row, column );
8899                 }, 1 );
8900         } );
8901         
8902         
8903         _api_registerPlural( 'cells().cache()', 'cell().cache()', function ( type ) {
8904                 type = type === 'search' ? '_aFilterData' : '_aSortData';
8905         
8906                 return this.iterator( 'cell', function ( settings, row, column ) {
8907                         return settings.aoData[ row ][ type ][ column ];
8908                 }, 1 );
8909         } );
8910         
8911         
8912         _api_registerPlural( 'cells().render()', 'cell().render()', function ( type ) {
8913                 return this.iterator( 'cell', function ( settings, row, column ) {
8914                         return _fnGetCellData( settings, row, column, type );
8915                 }, 1 );
8916         } );
8917         
8918         
8919         _api_registerPlural( 'cells().indexes()', 'cell().index()', function () {
8920                 return this.iterator( 'cell', function ( settings, row, column ) {
8921                         return {
8922                                 row: row,
8923                                 column: column,
8924                                 columnVisible: _fnColumnIndexToVisible( settings, column )
8925                         };
8926                 }, 1 );
8927         } );
8928         
8929         
8930         _api_registerPlural( 'cells().invalidate()', 'cell().invalidate()', function ( src ) {
8931                 return this.iterator( 'cell', function ( settings, row, column ) {
8932                         _fnInvalidate( settings, row, src, column );
8933                 } );
8934         } );
8935         
8936         
8937         
8938         _api_register( 'cell()', function ( rowSelector, columnSelector, opts ) {
8939                 return _selector_first( this.cells( rowSelector, columnSelector, opts ) );
8940         } );
8941         
8942         
8943         _api_register( 'cell().data()', function ( data ) {
8944                 var ctx = this.context;
8945                 var cell = this[0];
8946         
8947                 if ( data === undefined ) {
8948                         // Get
8949                         return ctx.length && cell.length ?
8950                                 _fnGetCellData( ctx[0], cell[0].row, cell[0].column ) :
8951                                 undefined;
8952                 }
8953         
8954                 // Set
8955                 _fnSetCellData( ctx[0], cell[0].row, cell[0].column, data );
8956                 _fnInvalidate( ctx[0], cell[0].row, 'data', cell[0].column );
8957         
8958                 return this;
8959         } );
8960         
8961         
8962         
8963         /**
8964          * Get current ordering (sorting) that has been applied to the table.
8965          *
8966          * @returns {array} 2D array containing the sorting information for the first
8967          *   table in the current context. Each element in the parent array represents
8968          *   a column being sorted upon (i.e. multi-sorting with two columns would have
8969          *   2 inner arrays). The inner arrays may have 2 or 3 elements. The first is
8970          *   the column index that the sorting condition applies to, the second is the
8971          *   direction of the sort (`desc` or `asc`) and, optionally, the third is the
8972          *   index of the sorting order from the `column.sorting` initialisation array.
8973          *//**
8974          * Set the ordering for the table.
8975          *
8976          * @param {integer} order Column index to sort upon.
8977          * @param {string} direction Direction of the sort to be applied (`asc` or `desc`)
8978          * @returns {DataTables.Api} this
8979          *//**
8980          * Set the ordering for the table.
8981          *
8982          * @param {array} order 1D array of sorting information to be applied.
8983          * @param {array} [...] Optional additional sorting conditions
8984          * @returns {DataTables.Api} this
8985          *//**
8986          * Set the ordering for the table.
8987          *
8988          * @param {array} order 2D array of sorting information to be applied.
8989          * @returns {DataTables.Api} this
8990          */
8991         _api_register( 'order()', function ( order, dir ) {
8992                 var ctx = this.context;
8993         
8994                 if ( order === undefined ) {
8995                         // get
8996                         return ctx.length !== 0 ?
8997                                 ctx[0].aaSorting :
8998                                 undefined;
8999                 }
9000         
9001                 // set
9002                 if ( typeof order === 'number' ) {
9003                         // Simple column / direction passed in
9004                         order = [ [ order, dir ] ];
9005                 }
9006                 else if ( order.length && ! $.isArray( order[0] ) ) {
9007                         // Arguments passed in (list of 1D arrays)
9008                         order = Array.prototype.slice.call( arguments );
9009                 }
9010                 // otherwise a 2D array was passed in
9011         
9012                 return this.iterator( 'table', function ( settings ) {
9013                         settings.aaSorting = order.slice();
9014                 } );
9015         } );
9016         
9017         
9018         /**
9019          * Attach a sort listener to an element for a given column
9020          *
9021          * @param {node|jQuery|string} node Identifier for the element(s) to attach the
9022          *   listener to. This can take the form of a single DOM node, a jQuery
9023          *   collection of nodes or a jQuery selector which will identify the node(s).
9024          * @param {integer} column the column that a click on this node will sort on
9025          * @param {function} [callback] callback function when sort is run
9026          * @returns {DataTables.Api} this
9027          */
9028         _api_register( 'order.listener()', function ( node, column, callback ) {
9029                 return this.iterator( 'table', function ( settings ) {
9030                         _fnSortAttachListener( settings, node, column, callback );
9031                 } );
9032         } );
9033         
9034         
9035         _api_register( 'order.fixed()', function ( set ) {
9036                 if ( ! set ) {
9037                         var ctx = this.context;
9038                         var fixed = ctx.length ?
9039                                 ctx[0].aaSortingFixed :
9040                                 undefined;
9041         
9042                         return $.isArray( fixed ) ?
9043                                 { pre: fixed } :
9044                                 fixed;
9045                 }
9046         
9047                 return this.iterator( 'table', function ( settings ) {
9048                         settings.aaSortingFixed = $.extend( true, {}, set );
9049                 } );
9050         } );
9051         
9052         
9053         // Order by the selected column(s)
9054         _api_register( [
9055                 'columns().order()',
9056                 'column().order()'
9057         ], function ( dir ) {
9058                 var that = this;
9059         
9060                 return this.iterator( 'table', function ( settings, i ) {
9061                         var sort = [];
9062         
9063                         $.each( that[i], function (j, col) {
9064                                 sort.push( [ col, dir ] );
9065                         } );
9066         
9067                         settings.aaSorting = sort;
9068                 } );
9069         } );
9070         
9071         
9072         
9073         _api_register( 'search()', function ( input, regex, smart, caseInsen ) {
9074                 var ctx = this.context;
9075         
9076                 if ( input === undefined ) {
9077                         // get
9078                         return ctx.length !== 0 ?
9079                                 ctx[0].oPreviousSearch.sSearch :
9080                                 undefined;
9081                 }
9082         
9083                 // set
9084                 return this.iterator( 'table', function ( settings ) {
9085                         if ( ! settings.oFeatures.bFilter ) {
9086                                 return;
9087                         }
9088         
9089                         _fnFilterComplete( settings, $.extend( {}, settings.oPreviousSearch, {
9090                                 "sSearch": input+"",
9091                                 "bRegex":  regex === null ? false : regex,
9092                                 "bSmart":  smart === null ? true  : smart,
9093                                 "bCaseInsensitive": caseInsen === null ? true : caseInsen
9094                         } ), 1 );
9095                 } );
9096         } );
9097         
9098         
9099         _api_registerPlural(
9100                 'columns().search()',
9101                 'column().search()',
9102                 function ( input, regex, smart, caseInsen ) {
9103                         return this.iterator( 'column', function ( settings, column ) {
9104                                 var preSearch = settings.aoPreSearchCols;
9105         
9106                                 if ( input === undefined ) {
9107                                         // get
9108                                         return preSearch[ column ].sSearch;
9109                                 }
9110         
9111                                 // set
9112                                 if ( ! settings.oFeatures.bFilter ) {
9113                                         return;
9114                                 }
9115         
9116                                 $.extend( preSearch[ column ], {
9117                                         "sSearch": input+"",
9118                                         "bRegex":  regex === null ? false : regex,
9119                                         "bSmart":  smart === null ? true  : smart,
9120                                         "bCaseInsensitive": caseInsen === null ? true : caseInsen
9121                                 } );
9122         
9123                                 _fnFilterComplete( settings, settings.oPreviousSearch, 1 );
9124                         } );
9125                 }
9126         );
9127         
9128         /*
9129          * State API methods
9130          */
9131         
9132         _api_register( 'state()', function () {
9133                 return this.context.length ?
9134                         this.context[0].oSavedState :
9135                         null;
9136         } );
9137         
9138         
9139         _api_register( 'state.clear()', function () {
9140                 return this.iterator( 'table', function ( settings ) {
9141                         // Save an empty object
9142                         settings.fnStateSaveCallback.call( settings.oInstance, settings, {} );
9143                 } );
9144         } );
9145         
9146         
9147         _api_register( 'state.loaded()', function () {
9148                 return this.context.length ?
9149                         this.context[0].oLoadedState :
9150                         null;
9151         } );
9152         
9153         
9154         _api_register( 'state.save()', function () {
9155                 return this.iterator( 'table', function ( settings ) {
9156                         _fnSaveState( settings );
9157                 } );
9158         } );
9159         
9160         
9161         
9162         /**
9163          * Provide a common method for plug-ins to check the version of DataTables being
9164          * used, in order to ensure compatibility.
9165          *
9166          *  @param {string} version Version string to check for, in the format "X.Y.Z".
9167          *    Note that the formats "X" and "X.Y" are also acceptable.
9168          *  @returns {boolean} true if this version of DataTables is greater or equal to
9169          *    the required version, or false if this version of DataTales is not
9170          *    suitable
9171          *  @static
9172          *  @dtopt API-Static
9173          *
9174          *  @example
9175          *    alert( $.fn.dataTable.versionCheck( '1.9.0' ) );
9176          */
9177         DataTable.versionCheck = DataTable.fnVersionCheck = function( version )
9178         {
9179                 var aThis = DataTable.version.split('.');
9180                 var aThat = version.split('.');
9181                 var iThis, iThat;
9182         
9183                 for ( var i=0, iLen=aThat.length ; i<iLen ; i++ ) {
9184                         iThis = parseInt( aThis[i], 10 ) || 0;
9185                         iThat = parseInt( aThat[i], 10 ) || 0;
9186         
9187                         // Parts are the same, keep comparing
9188                         if (iThis === iThat) {
9189                                 continue;
9190                         }
9191         
9192                         // Parts are different, return immediately
9193                         return iThis > iThat;
9194                 }
9195         
9196                 return true;
9197         };
9198         
9199         
9200         /**
9201          * Check if a `<table>` node is a DataTable table already or not.
9202          *
9203          *  @param {node|jquery|string} table Table node, jQuery object or jQuery
9204          *      selector for the table to test. Note that if more than more than one
9205          *      table is passed on, only the first will be checked
9206          *  @returns {boolean} true the table given is a DataTable, or false otherwise
9207          *  @static
9208          *  @dtopt API-Static
9209          *
9210          *  @example
9211          *    if ( ! $.fn.DataTable.isDataTable( '#example' ) ) {
9212          *      $('#example').dataTable();
9213          *    }
9214          */
9215         DataTable.isDataTable = DataTable.fnIsDataTable = function ( table )
9216         {
9217                 var t = $(table).get(0);
9218                 var is = false;
9219         
9220                 if ( table instanceof DataTable.Api ) {
9221                         return true;
9222                 }
9223         
9224                 $.each( DataTable.settings, function (i, o) {
9225                         var head = o.nScrollHead ? $('table', o.nScrollHead)[0] : null;
9226                         var foot = o.nScrollFoot ? $('table', o.nScrollFoot)[0] : null;
9227         
9228                         if ( o.nTable === t || head === t || foot === t ) {
9229                                 is = true;
9230                         }
9231                 } );
9232         
9233                 return is;
9234         };
9235         
9236         
9237         /**
9238          * Get all DataTable tables that have been initialised - optionally you can
9239          * select to get only currently visible tables.
9240          *
9241          *  @param {boolean} [visible=false] Flag to indicate if you want all (default)
9242          *    or visible tables only.
9243          *  @returns {array} Array of `table` nodes (not DataTable instances) which are
9244          *    DataTables
9245          *  @static
9246          *  @dtopt API-Static
9247          *
9248          *  @example
9249          *    $.each( $.fn.dataTable.tables(true), function () {
9250          *      $(table).DataTable().columns.adjust();
9251          *    } );
9252          */
9253         DataTable.tables = DataTable.fnTables = function ( visible )
9254         {
9255                 var api = false;
9256         
9257                 if ( $.isPlainObject( visible ) ) {
9258                         api = visible.api;
9259                         visible = visible.visible;
9260                 }
9261         
9262                 var a = $.map( DataTable.settings, function (o) {
9263                         if ( !visible || (visible && $(o.nTable).is(':visible')) ) {
9264                                 return o.nTable;
9265                         }
9266                 } );
9267         
9268                 return api ?
9269                         new _Api( a ) :
9270                         a;
9271         };
9272         
9273         
9274         /**
9275          * Convert from camel case parameters to Hungarian notation. This is made public
9276          * for the extensions to provide the same ability as DataTables core to accept
9277          * either the 1.9 style Hungarian notation, or the 1.10+ style camelCase
9278          * parameters.
9279          *
9280          *  @param {object} src The model object which holds all parameters that can be
9281          *    mapped.
9282          *  @param {object} user The object to convert from camel case to Hungarian.
9283          *  @param {boolean} force When set to `true`, properties which already have a
9284          *    Hungarian value in the `user` object will be overwritten. Otherwise they
9285          *    won't be.
9286          */
9287         DataTable.camelToHungarian = _fnCamelToHungarian;
9288         
9289         
9290         
9291         /**
9292          *
9293          */
9294         _api_register( '$()', function ( selector, opts ) {
9295                 var
9296                         rows   = this.rows( opts ).nodes(), // Get all rows
9297                         jqRows = $(rows);
9298         
9299                 return $( [].concat(
9300                         jqRows.filter( selector ).toArray(),
9301                         jqRows.find( selector ).toArray()
9302                 ) );
9303         } );
9304         
9305         
9306         // jQuery functions to operate on the tables
9307         $.each( [ 'on', 'one', 'off' ], function (i, key) {
9308                 _api_register( key+'()', function ( /* event, handler */ ) {
9309                         var args = Array.prototype.slice.call(arguments);
9310         
9311                         // Add the `dt` namespace automatically if it isn't already present
9312                         args[0] = $.map( args[0].split( /\s/ ), function ( e ) {
9313                                 return ! e.match(/\.dt\b/) ?
9314                                         e+'.dt' :
9315                                         e;
9316                                 } ).join( ' ' );
9317         
9318                         var inst = $( this.tables().nodes() );
9319                         inst[key].apply( inst, args );
9320                         return this;
9321                 } );
9322         } );
9323         
9324         
9325         _api_register( 'clear()', function () {
9326                 return this.iterator( 'table', function ( settings ) {
9327                         _fnClearTable( settings );
9328                 } );
9329         } );
9330         
9331         
9332         _api_register( 'settings()', function () {
9333                 return new _Api( this.context, this.context );
9334         } );
9335         
9336         
9337         _api_register( 'init()', function () {
9338                 var ctx = this.context;
9339                 return ctx.length ? ctx[0].oInit : null;
9340         } );
9341         
9342         
9343         _api_register( 'data()', function () {
9344                 return this.iterator( 'table', function ( settings ) {
9345                         return _pluck( settings.aoData, '_aData' );
9346                 } ).flatten();
9347         } );
9348         
9349         
9350         _api_register( 'destroy()', function ( remove ) {
9351                 remove = remove || false;
9352         
9353                 return this.iterator( 'table', function ( settings ) {
9354                         var orig      = settings.nTableWrapper.parentNode;
9355                         var classes   = settings.oClasses;
9356                         var table     = settings.nTable;
9357                         var tbody     = settings.nTBody;
9358                         var thead     = settings.nTHead;
9359                         var tfoot     = settings.nTFoot;
9360                         var jqTable   = $(table);
9361                         var jqTbody   = $(tbody);
9362                         var jqWrapper = $(settings.nTableWrapper);
9363                         var rows      = $.map( settings.aoData, function (r) { return r.nTr; } );
9364                         var i, ien;
9365         
9366                         // Flag to note that the table is currently being destroyed - no action
9367                         // should be taken
9368                         settings.bDestroying = true;
9369         
9370                         // Fire off the destroy callbacks for plug-ins etc
9371                         _fnCallbackFire( settings, "aoDestroyCallback", "destroy", [settings] );
9372         
9373                         // If not being removed from the document, make all columns visible
9374                         if ( ! remove ) {
9375                                 new _Api( settings ).columns().visible( true );
9376                         }
9377         
9378                         // Blitz all `DT` namespaced events (these are internal events, the
9379                         // lowercase, `dt` events are user subscribed and they are responsible
9380                         // for removing them
9381                         jqWrapper.off('.DT').find(':not(tbody *)').off('.DT');
9382                         $(window).off('.DT-'+settings.sInstance);
9383         
9384                         // When scrolling we had to break the table up - restore it
9385                         if ( table != thead.parentNode ) {
9386                                 jqTable.children('thead').detach();
9387                                 jqTable.append( thead );
9388                         }
9389         
9390                         if ( tfoot && table != tfoot.parentNode ) {
9391                                 jqTable.children('tfoot').detach();
9392                                 jqTable.append( tfoot );
9393                         }
9394         
9395                         settings.aaSorting = [];
9396                         settings.aaSortingFixed = [];
9397                         _fnSortingClasses( settings );
9398         
9399                         $( rows ).removeClass( settings.asStripeClasses.join(' ') );
9400         
9401                         $('th, td', thead).removeClass( classes.sSortable+' '+
9402                                 classes.sSortableAsc+' '+classes.sSortableDesc+' '+classes.sSortableNone
9403                         );
9404         
9405                         // Add the TR elements back into the table in their original order
9406                         jqTbody.children().detach();
9407                         jqTbody.append( rows );
9408         
9409                         // Remove the DataTables generated nodes, events and classes
9410                         var removedMethod = remove ? 'remove' : 'detach';
9411                         jqTable[ removedMethod ]();
9412                         jqWrapper[ removedMethod ]();
9413         
9414                         // If we need to reattach the table to the document
9415                         if ( ! remove && orig ) {
9416                                 // insertBefore acts like appendChild if !arg[1]
9417                                 orig.insertBefore( table, settings.nTableReinsertBefore );
9418         
9419                                 // Restore the width of the original table - was read from the style property,
9420                                 // so we can restore directly to that
9421                                 jqTable
9422                                         .css( 'width', settings.sDestroyWidth )
9423                                         .removeClass( classes.sTable );
9424         
9425                                 // If the were originally stripe classes - then we add them back here.
9426                                 // Note this is not fool proof (for example if not all rows had stripe
9427                                 // classes - but it's a good effort without getting carried away
9428                                 ien = settings.asDestroyStripes.length;
9429         
9430                                 if ( ien ) {
9431                                         jqTbody.children().each( function (i) {
9432                                                 $(this).addClass( settings.asDestroyStripes[i % ien] );
9433                                         } );
9434                                 }
9435                         }
9436         
9437                         /* Remove the settings object from the settings array */
9438                         var idx = $.inArray( settings, DataTable.settings );
9439                         if ( idx !== -1 ) {
9440                                 DataTable.settings.splice( idx, 1 );
9441                         }
9442                 } );
9443         } );
9444         
9445         
9446         // Add the `every()` method for rows, columns and cells in a compact form
9447         $.each( [ 'column', 'row', 'cell' ], function ( i, type ) {
9448                 _api_register( type+'s().every()', function ( fn ) {
9449                         var opts = this.selector.opts;
9450                         var api = this;
9451         
9452                         return this.iterator( type, function ( settings, arg1, arg2, arg3, arg4 ) {
9453                                 // Rows and columns:
9454                                 //  arg1 - index
9455                                 //  arg2 - table counter
9456                                 //  arg3 - loop counter
9457                                 //  arg4 - undefined
9458                                 // Cells:
9459                                 //  arg1 - row index
9460                                 //  arg2 - column index
9461                                 //  arg3 - table counter
9462                                 //  arg4 - loop counter
9463                                 fn.call(
9464                                         api[ type ](
9465                                                 arg1,
9466                                                 type==='cell' ? arg2 : opts,
9467                                                 type==='cell' ? opts : undefined
9468                                         ),
9469                                         arg1, arg2, arg3, arg4
9470                                 );
9471                         } );
9472                 } );
9473         } );
9474         
9475         
9476         // i18n method for extensions to be able to use the language object from the
9477         // DataTable
9478         _api_register( 'i18n()', function ( token, def, plural ) {
9479                 var ctx = this.context[0];
9480                 var resolved = _fnGetObjectDataFn( token )( ctx.oLanguage );
9481         
9482                 if ( resolved === undefined ) {
9483                         resolved = def;
9484                 }
9485         
9486                 if ( plural !== undefined && $.isPlainObject( resolved ) ) {
9487                         resolved = resolved[ plural ] !== undefined ?
9488                                 resolved[ plural ] :
9489                                 resolved._;
9490                 }
9491         
9492                 return resolved.replace( '%d', plural ); // nb: plural might be undefined,
9493         } );
9494         /**
9495          * Version string for plug-ins to check compatibility. Allowed format is
9496          * `a.b.c-d` where: a:int, b:int, c:int, d:string(dev|beta|alpha). `d` is used
9497          * only for non-release builds. See http://semver.org/ for more information.
9498          *  @member
9499          *  @type string
9500          *  @default Version number
9501          */
9502         DataTable.version = "1.10.20";
9503
9504         /**
9505          * Private data store, containing all of the settings objects that are
9506          * created for the tables on a given page.
9507          *
9508          * Note that the `DataTable.settings` object is aliased to
9509          * `jQuery.fn.dataTableExt` through which it may be accessed and
9510          * manipulated, or `jQuery.fn.dataTable.settings`.
9511          *  @member
9512          *  @type array
9513          *  @default []
9514          *  @private
9515          */
9516         DataTable.settings = [];
9517
9518         /**
9519          * Object models container, for the various models that DataTables has
9520          * available to it. These models define the objects that are used to hold
9521          * the active state and configuration of the table.
9522          *  @namespace
9523          */
9524         DataTable.models = {};
9525         
9526         
9527         
9528         /**
9529          * Template object for the way in which DataTables holds information about
9530          * search information for the global filter and individual column filters.
9531          *  @namespace
9532          */
9533         DataTable.models.oSearch = {
9534                 /**
9535                  * Flag to indicate if the filtering should be case insensitive or not
9536                  *  @type boolean
9537                  *  @default true
9538                  */
9539                 "bCaseInsensitive": true,
9540         
9541                 /**
9542                  * Applied search term
9543                  *  @type string
9544                  *  @default <i>Empty string</i>
9545                  */
9546                 "sSearch": "",
9547         
9548                 /**
9549                  * Flag to indicate if the search term should be interpreted as a
9550                  * regular expression (true) or not (false) and therefore and special
9551                  * regex characters escaped.
9552                  *  @type boolean
9553                  *  @default false
9554                  */
9555                 "bRegex": false,
9556         
9557                 /**
9558                  * Flag to indicate if DataTables is to use its smart filtering or not.
9559                  *  @type boolean
9560                  *  @default true
9561                  */
9562                 "bSmart": true
9563         };
9564         
9565         
9566         
9567         
9568         /**
9569          * Template object for the way in which DataTables holds information about
9570          * each individual row. This is the object format used for the settings
9571          * aoData array.
9572          *  @namespace
9573          */
9574         DataTable.models.oRow = {
9575                 /**
9576                  * TR element for the row
9577                  *  @type node
9578                  *  @default null
9579                  */
9580                 "nTr": null,
9581         
9582                 /**
9583                  * Array of TD elements for each row. This is null until the row has been
9584                  * created.
9585                  *  @type array nodes
9586                  *  @default []
9587                  */
9588                 "anCells": null,
9589         
9590                 /**
9591                  * Data object from the original data source for the row. This is either
9592                  * an array if using the traditional form of DataTables, or an object if
9593                  * using mData options. The exact type will depend on the passed in
9594                  * data from the data source, or will be an array if using DOM a data
9595                  * source.
9596                  *  @type array|object
9597                  *  @default []
9598                  */
9599                 "_aData": [],
9600         
9601                 /**
9602                  * Sorting data cache - this array is ostensibly the same length as the
9603                  * number of columns (although each index is generated only as it is
9604                  * needed), and holds the data that is used for sorting each column in the
9605                  * row. We do this cache generation at the start of the sort in order that
9606                  * the formatting of the sort data need be done only once for each cell
9607                  * per sort. This array should not be read from or written to by anything
9608                  * other than the master sorting methods.
9609                  *  @type array
9610                  *  @default null
9611                  *  @private
9612                  */
9613                 "_aSortData": null,
9614         
9615                 /**
9616                  * Per cell filtering data cache. As per the sort data cache, used to
9617                  * increase the performance of the filtering in DataTables
9618                  *  @type array
9619                  *  @default null
9620                  *  @private
9621                  */
9622                 "_aFilterData": null,
9623         
9624                 /**
9625                  * Filtering data cache. This is the same as the cell filtering cache, but
9626                  * in this case a string rather than an array. This is easily computed with
9627                  * a join on `_aFilterData`, but is provided as a cache so the join isn't
9628                  * needed on every search (memory traded for performance)
9629                  *  @type array
9630                  *  @default null
9631                  *  @private
9632                  */
9633                 "_sFilterRow": null,
9634         
9635                 /**
9636                  * Cache of the class name that DataTables has applied to the row, so we
9637                  * can quickly look at this variable rather than needing to do a DOM check
9638                  * on className for the nTr property.
9639                  *  @type string
9640                  *  @default <i>Empty string</i>
9641                  *  @private
9642                  */
9643                 "_sRowStripe": "",
9644         
9645                 /**
9646                  * Denote if the original data source was from the DOM, or the data source
9647                  * object. This is used for invalidating data, so DataTables can
9648                  * automatically read data from the original source, unless uninstructed
9649                  * otherwise.
9650                  *  @type string
9651                  *  @default null
9652                  *  @private
9653                  */
9654                 "src": null,
9655         
9656                 /**
9657                  * Index in the aoData array. This saves an indexOf lookup when we have the
9658                  * object, but want to know the index
9659                  *  @type integer
9660                  *  @default -1
9661                  *  @private
9662                  */
9663                 "idx": -1
9664         };
9665         
9666         
9667         /**
9668          * Template object for the column information object in DataTables. This object
9669          * is held in the settings aoColumns array and contains all the information that
9670          * DataTables needs about each individual column.
9671          *
9672          * Note that this object is related to {@link DataTable.defaults.column}
9673          * but this one is the internal data store for DataTables's cache of columns.
9674          * It should NOT be manipulated outside of DataTables. Any configuration should
9675          * be done through the initialisation options.
9676          *  @namespace
9677          */
9678         DataTable.models.oColumn = {
9679                 /**
9680                  * Column index. This could be worked out on-the-fly with $.inArray, but it
9681                  * is faster to just hold it as a variable
9682                  *  @type integer
9683                  *  @default null
9684                  */
9685                 "idx": null,
9686         
9687                 /**
9688                  * A list of the columns that sorting should occur on when this column
9689                  * is sorted. That this property is an array allows multi-column sorting
9690                  * to be defined for a column (for example first name / last name columns
9691                  * would benefit from this). The values are integers pointing to the
9692                  * columns to be sorted on (typically it will be a single integer pointing
9693                  * at itself, but that doesn't need to be the case).
9694                  *  @type array
9695                  */
9696                 "aDataSort": null,
9697         
9698                 /**
9699                  * Define the sorting directions that are applied to the column, in sequence
9700                  * as the column is repeatedly sorted upon - i.e. the first value is used
9701                  * as the sorting direction when the column if first sorted (clicked on).
9702                  * Sort it again (click again) and it will move on to the next index.
9703                  * Repeat until loop.
9704                  *  @type array
9705                  */
9706                 "asSorting": null,
9707         
9708                 /**
9709                  * Flag to indicate if the column is searchable, and thus should be included
9710                  * in the filtering or not.
9711                  *  @type boolean
9712                  */
9713                 "bSearchable": null,
9714         
9715                 /**
9716                  * Flag to indicate if the column is sortable or not.
9717                  *  @type boolean
9718                  */
9719                 "bSortable": null,
9720         
9721                 /**
9722                  * Flag to indicate if the column is currently visible in the table or not
9723                  *  @type boolean
9724                  */
9725                 "bVisible": null,
9726         
9727                 /**
9728                  * Store for manual type assignment using the `column.type` option. This
9729                  * is held in store so we can manipulate the column's `sType` property.
9730                  *  @type string
9731                  *  @default null
9732                  *  @private
9733                  */
9734                 "_sManualType": null,
9735         
9736                 /**
9737                  * Flag to indicate if HTML5 data attributes should be used as the data
9738                  * source for filtering or sorting. True is either are.
9739                  *  @type boolean
9740                  *  @default false
9741                  *  @private
9742                  */
9743                 "_bAttrSrc": false,
9744         
9745                 /**
9746                  * Developer definable function that is called whenever a cell is created (Ajax source,
9747                  * etc) or processed for input (DOM source). This can be used as a compliment to mRender
9748                  * allowing you to modify the DOM element (add background colour for example) when the
9749                  * element is available.
9750                  *  @type function
9751                  *  @param {element} nTd The TD node that has been created
9752                  *  @param {*} sData The Data for the cell
9753                  *  @param {array|object} oData The data for the whole row
9754                  *  @param {int} iRow The row index for the aoData data store
9755                  *  @default null
9756                  */
9757                 "fnCreatedCell": null,
9758         
9759                 /**
9760                  * Function to get data from a cell in a column. You should <b>never</b>
9761                  * access data directly through _aData internally in DataTables - always use
9762                  * the method attached to this property. It allows mData to function as
9763                  * required. This function is automatically assigned by the column
9764                  * initialisation method
9765                  *  @type function
9766                  *  @param {array|object} oData The data array/object for the array
9767                  *    (i.e. aoData[]._aData)
9768                  *  @param {string} sSpecific The specific data type you want to get -
9769                  *    'display', 'type' 'filter' 'sort'
9770                  *  @returns {*} The data for the cell from the given row's data
9771                  *  @default null
9772                  */
9773                 "fnGetData": null,
9774         
9775                 /**
9776                  * Function to set data for a cell in the column. You should <b>never</b>
9777                  * set the data directly to _aData internally in DataTables - always use
9778                  * this method. It allows mData to function as required. This function
9779                  * is automatically assigned by the column initialisation method
9780                  *  @type function
9781                  *  @param {array|object} oData The data array/object for the array
9782                  *    (i.e. aoData[]._aData)
9783                  *  @param {*} sValue Value to set
9784                  *  @default null
9785                  */
9786                 "fnSetData": null,
9787         
9788                 /**
9789                  * Property to read the value for the cells in the column from the data
9790                  * source array / object. If null, then the default content is used, if a
9791                  * function is given then the return from the function is used.
9792                  *  @type function|int|string|null
9793                  *  @default null
9794                  */
9795                 "mData": null,
9796         
9797                 /**
9798                  * Partner property to mData which is used (only when defined) to get
9799                  * the data - i.e. it is basically the same as mData, but without the
9800                  * 'set' option, and also the data fed to it is the result from mData.
9801                  * This is the rendering method to match the data method of mData.
9802                  *  @type function|int|string|null
9803                  *  @default null
9804                  */
9805                 "mRender": null,
9806         
9807                 /**
9808                  * Unique header TH/TD element for this column - this is what the sorting
9809                  * listener is attached to (if sorting is enabled.)
9810                  *  @type node
9811                  *  @default null
9812                  */
9813                 "nTh": null,
9814         
9815                 /**
9816                  * Unique footer TH/TD element for this column (if there is one). Not used
9817                  * in DataTables as such, but can be used for plug-ins to reference the
9818                  * footer for each column.
9819                  *  @type node
9820                  *  @default null
9821                  */
9822                 "nTf": null,
9823         
9824                 /**
9825                  * The class to apply to all TD elements in the table's TBODY for the column
9826                  *  @type string
9827                  *  @default null
9828                  */
9829                 "sClass": null,
9830         
9831                 /**
9832                  * When DataTables calculates the column widths to assign to each column,
9833                  * it finds the longest string in each column and then constructs a
9834                  * temporary table and reads the widths from that. The problem with this
9835                  * is that "mmm" is much wider then "iiii", but the latter is a longer
9836                  * string - thus the calculation can go wrong (doing it properly and putting
9837                  * it into an DOM object and measuring that is horribly(!) slow). Thus as
9838                  * a "work around" we provide this option. It will append its value to the
9839                  * text that is found to be the longest string for the column - i.e. padding.
9840                  *  @type string
9841                  */
9842                 "sContentPadding": null,
9843         
9844                 /**
9845                  * Allows a default value to be given for a column's data, and will be used
9846                  * whenever a null data source is encountered (this can be because mData
9847                  * is set to null, or because the data source itself is null).
9848                  *  @type string
9849                  *  @default null
9850                  */
9851                 "sDefaultContent": null,
9852         
9853                 /**
9854                  * Name for the column, allowing reference to the column by name as well as
9855                  * by index (needs a lookup to work by name).
9856                  *  @type string
9857                  */
9858                 "sName": null,
9859         
9860                 /**
9861                  * Custom sorting data type - defines which of the available plug-ins in
9862                  * afnSortData the custom sorting will use - if any is defined.
9863                  *  @type string
9864                  *  @default std
9865                  */
9866                 "sSortDataType": 'std',
9867         
9868                 /**
9869                  * Class to be applied to the header element when sorting on this column
9870                  *  @type string
9871                  *  @default null
9872                  */
9873                 "sSortingClass": null,
9874         
9875                 /**
9876                  * Class to be applied to the header element when sorting on this column -
9877                  * when jQuery UI theming is used.
9878                  *  @type string
9879                  *  @default null
9880                  */
9881                 "sSortingClassJUI": null,
9882         
9883                 /**
9884                  * Title of the column - what is seen in the TH element (nTh).
9885                  *  @type string
9886                  */
9887                 "sTitle": null,
9888         
9889                 /**
9890                  * Column sorting and filtering type
9891                  *  @type string
9892                  *  @default null
9893                  */
9894                 "sType": null,
9895         
9896                 /**
9897                  * Width of the column
9898                  *  @type string
9899                  *  @default null
9900                  */
9901                 "sWidth": null,
9902         
9903                 /**
9904                  * Width of the column when it was first "encountered"
9905                  *  @type string
9906                  *  @default null
9907                  */
9908                 "sWidthOrig": null
9909         };
9910         
9911         
9912         /*
9913          * Developer note: The properties of the object below are given in Hungarian
9914          * notation, that was used as the interface for DataTables prior to v1.10, however
9915          * from v1.10 onwards the primary interface is camel case. In order to avoid
9916          * breaking backwards compatibility utterly with this change, the Hungarian
9917          * version is still, internally the primary interface, but is is not documented
9918          * - hence the @name tags in each doc comment. This allows a Javascript function
9919          * to create a map from Hungarian notation to camel case (going the other direction
9920          * would require each property to be listed, which would at around 3K to the size
9921          * of DataTables, while this method is about a 0.5K hit.
9922          *
9923          * Ultimately this does pave the way for Hungarian notation to be dropped
9924          * completely, but that is a massive amount of work and will break current
9925          * installs (therefore is on-hold until v2).
9926          */
9927         
9928         /**
9929          * Initialisation options that can be given to DataTables at initialisation
9930          * time.
9931          *  @namespace
9932          */
9933         DataTable.defaults = {
9934                 /**
9935                  * An array of data to use for the table, passed in at initialisation which
9936                  * will be used in preference to any data which is already in the DOM. This is
9937                  * particularly useful for constructing tables purely in Javascript, for
9938                  * example with a custom Ajax call.
9939                  *  @type array
9940                  *  @default null
9941                  *
9942                  *  @dtopt Option
9943                  *  @name DataTable.defaults.data
9944                  *
9945                  *  @example
9946                  *    // Using a 2D array data source
9947                  *    $(document).ready( function () {
9948                  *      $('#example').dataTable( {
9949                  *        "data": [
9950                  *          ['Trident', 'Internet Explorer 4.0', 'Win 95+', 4, 'X'],
9951                  *          ['Trident', 'Internet Explorer 5.0', 'Win 95+', 5, 'C'],
9952                  *        ],
9953                  *        "columns": [
9954                  *          { "title": "Engine" },
9955                  *          { "title": "Browser" },
9956                  *          { "title": "Platform" },
9957                  *          { "title": "Version" },
9958                  *          { "title": "Grade" }
9959                  *        ]
9960                  *      } );
9961                  *    } );
9962                  *
9963                  *  @example
9964                  *    // Using an array of objects as a data source (`data`)
9965                  *    $(document).ready( function () {
9966                  *      $('#example').dataTable( {
9967                  *        "data": [
9968                  *          {
9969                  *            "engine":   "Trident",
9970                  *            "browser":  "Internet Explorer 4.0",
9971                  *            "platform": "Win 95+",
9972                  *            "version":  4,
9973                  *            "grade":    "X"
9974                  *          },
9975                  *          {
9976                  *            "engine":   "Trident",
9977                  *            "browser":  "Internet Explorer 5.0",
9978                  *            "platform": "Win 95+",
9979                  *            "version":  5,
9980                  *            "grade":    "C"
9981                  *          }
9982                  *        ],
9983                  *        "columns": [
9984                  *          { "title": "Engine",   "data": "engine" },
9985                  *          { "title": "Browser",  "data": "browser" },
9986                  *          { "title": "Platform", "data": "platform" },
9987                  *          { "title": "Version",  "data": "version" },
9988                  *          { "title": "Grade",    "data": "grade" }
9989                  *        ]
9990                  *      } );
9991                  *    } );
9992                  */
9993                 "aaData": null,
9994         
9995         
9996                 /**
9997                  * If ordering is enabled, then DataTables will perform a first pass sort on
9998                  * initialisation. You can define which column(s) the sort is performed
9999                  * upon, and the sorting direction, with this variable. The `sorting` array
10000                  * should contain an array for each column to be sorted initially containing
10001                  * the column's index and a direction string ('asc' or 'desc').
10002                  *  @type array
10003                  *  @default [[0,'asc']]
10004                  *
10005                  *  @dtopt Option
10006                  *  @name DataTable.defaults.order
10007                  *
10008                  *  @example
10009                  *    // Sort by 3rd column first, and then 4th column
10010                  *    $(document).ready( function() {
10011                  *      $('#example').dataTable( {
10012                  *        "order": [[2,'asc'], [3,'desc']]
10013                  *      } );
10014                  *    } );
10015                  *
10016                  *    // No initial sorting
10017                  *    $(document).ready( function() {
10018                  *      $('#example').dataTable( {
10019                  *        "order": []
10020                  *      } );
10021                  *    } );
10022                  */
10023                 "aaSorting": [[0,'asc']],
10024         
10025         
10026                 /**
10027                  * This parameter is basically identical to the `sorting` parameter, but
10028                  * cannot be overridden by user interaction with the table. What this means
10029                  * is that you could have a column (visible or hidden) which the sorting
10030                  * will always be forced on first - any sorting after that (from the user)
10031                  * will then be performed as required. This can be useful for grouping rows
10032                  * together.
10033                  *  @type array
10034                  *  @default null
10035                  *
10036                  *  @dtopt Option
10037                  *  @name DataTable.defaults.orderFixed
10038                  *
10039                  *  @example
10040                  *    $(document).ready( function() {
10041                  *      $('#example').dataTable( {
10042                  *        "orderFixed": [[0,'asc']]
10043                  *      } );
10044                  *    } )
10045                  */
10046                 "aaSortingFixed": [],
10047         
10048         
10049                 /**
10050                  * DataTables can be instructed to load data to display in the table from a
10051                  * Ajax source. This option defines how that Ajax call is made and where to.
10052                  *
10053                  * The `ajax` property has three different modes of operation, depending on
10054                  * how it is defined. These are:
10055                  *
10056                  * * `string` - Set the URL from where the data should be loaded from.
10057                  * * `object` - Define properties for `jQuery.ajax`.
10058                  * * `function` - Custom data get function
10059                  *
10060                  * `string`
10061                  * --------
10062                  *
10063                  * As a string, the `ajax` property simply defines the URL from which
10064                  * DataTables will load data.
10065                  *
10066                  * `object`
10067                  * --------
10068                  *
10069                  * As an object, the parameters in the object are passed to
10070                  * [jQuery.ajax](http://api.jquery.com/jQuery.ajax/) allowing fine control
10071                  * of the Ajax request. DataTables has a number of default parameters which
10072                  * you can override using this option. Please refer to the jQuery
10073                  * documentation for a full description of the options available, although
10074                  * the following parameters provide additional options in DataTables or
10075                  * require special consideration:
10076                  *
10077                  * * `data` - As with jQuery, `data` can be provided as an object, but it
10078                  *   can also be used as a function to manipulate the data DataTables sends
10079                  *   to the server. The function takes a single parameter, an object of
10080                  *   parameters with the values that DataTables has readied for sending. An
10081                  *   object may be returned which will be merged into the DataTables
10082                  *   defaults, or you can add the items to the object that was passed in and
10083                  *   not return anything from the function. This supersedes `fnServerParams`
10084                  *   from DataTables 1.9-.
10085                  *
10086                  * * `dataSrc` - By default DataTables will look for the property `data` (or
10087                  *   `aaData` for compatibility with DataTables 1.9-) when obtaining data
10088                  *   from an Ajax source or for server-side processing - this parameter
10089                  *   allows that property to be changed. You can use Javascript dotted
10090                  *   object notation to get a data source for multiple levels of nesting, or
10091                  *   it my be used as a function. As a function it takes a single parameter,
10092                  *   the JSON returned from the server, which can be manipulated as
10093                  *   required, with the returned value being that used by DataTables as the
10094                  *   data source for the table. This supersedes `sAjaxDataProp` from
10095                  *   DataTables 1.9-.
10096                  *
10097                  * * `success` - Should not be overridden it is used internally in
10098                  *   DataTables. To manipulate / transform the data returned by the server
10099                  *   use `ajax.dataSrc`, or use `ajax` as a function (see below).
10100                  *
10101                  * `function`
10102                  * ----------
10103                  *
10104                  * As a function, making the Ajax call is left up to yourself allowing
10105                  * complete control of the Ajax request. Indeed, if desired, a method other
10106                  * than Ajax could be used to obtain the required data, such as Web storage
10107                  * or an AIR database.
10108                  *
10109                  * The function is given four parameters and no return is required. The
10110                  * parameters are:
10111                  *
10112                  * 1. _object_ - Data to send to the server
10113                  * 2. _function_ - Callback function that must be executed when the required
10114                  *    data has been obtained. That data should be passed into the callback
10115                  *    as the only parameter
10116                  * 3. _object_ - DataTables settings object for the table
10117                  *
10118                  * Note that this supersedes `fnServerData` from DataTables 1.9-.
10119                  *
10120                  *  @type string|object|function
10121                  *  @default null
10122                  *
10123                  *  @dtopt Option
10124                  *  @name DataTable.defaults.ajax
10125                  *  @since 1.10.0
10126                  *
10127                  * @example
10128                  *   // Get JSON data from a file via Ajax.
10129                  *   // Note DataTables expects data in the form `{ data: [ ...data... ] }` by default).
10130                  *   $('#example').dataTable( {
10131                  *     "ajax": "data.json"
10132                  *   } );
10133                  *
10134                  * @example
10135                  *   // Get JSON data from a file via Ajax, using `dataSrc` to change
10136                  *   // `data` to `tableData` (i.e. `{ tableData: [ ...data... ] }`)
10137                  *   $('#example').dataTable( {
10138                  *     "ajax": {
10139                  *       "url": "data.json",
10140                  *       "dataSrc": "tableData"
10141                  *     }
10142                  *   } );
10143                  *
10144                  * @example
10145                  *   // Get JSON data from a file via Ajax, using `dataSrc` to read data
10146                  *   // from a plain array rather than an array in an object
10147                  *   $('#example').dataTable( {
10148                  *     "ajax": {
10149                  *       "url": "data.json",
10150                  *       "dataSrc": ""
10151                  *     }
10152                  *   } );
10153                  *
10154                  * @example
10155                  *   // Manipulate the data returned from the server - add a link to data
10156                  *   // (note this can, should, be done using `render` for the column - this
10157                  *   // is just a simple example of how the data can be manipulated).
10158                  *   $('#example').dataTable( {
10159                  *     "ajax": {
10160                  *       "url": "data.json",
10161                  *       "dataSrc": function ( json ) {
10162                  *         for ( var i=0, ien=json.length ; i<ien ; i++ ) {
10163                  *           json[i][0] = '<a href="/message/'+json[i][0]+'>View message</a>';
10164                  *         }
10165                  *         return json;
10166                  *       }
10167                  *     }
10168                  *   } );
10169                  *
10170                  * @example
10171                  *   // Add data to the request
10172                  *   $('#example').dataTable( {
10173                  *     "ajax": {
10174                  *       "url": "data.json",
10175                  *       "data": function ( d ) {
10176                  *         return {
10177                  *           "extra_search": $('#extra').val()
10178                  *         };
10179                  *       }
10180                  *     }
10181                  *   } );
10182                  *
10183                  * @example
10184                  *   // Send request as POST
10185                  *   $('#example').dataTable( {
10186                  *     "ajax": {
10187                  *       "url": "data.json",
10188                  *       "type": "POST"
10189                  *     }
10190                  *   } );
10191                  *
10192                  * @example
10193                  *   // Get the data from localStorage (could interface with a form for
10194                  *   // adding, editing and removing rows).
10195                  *   $('#example').dataTable( {
10196                  *     "ajax": function (data, callback, settings) {
10197                  *       callback(
10198                  *         JSON.parse( localStorage.getItem('dataTablesData') )
10199                  *       );
10200                  *     }
10201                  *   } );
10202                  */
10203                 "ajax": null,
10204         
10205         
10206                 /**
10207                  * This parameter allows you to readily specify the entries in the length drop
10208                  * down menu that DataTables shows when pagination is enabled. It can be
10209                  * either a 1D array of options which will be used for both the displayed
10210                  * option and the value, or a 2D array which will use the array in the first
10211                  * position as the value, and the array in the second position as the
10212                  * displayed options (useful for language strings such as 'All').
10213                  *
10214                  * Note that the `pageLength` property will be automatically set to the
10215                  * first value given in this array, unless `pageLength` is also provided.
10216                  *  @type array
10217                  *  @default [ 10, 25, 50, 100 ]
10218                  *
10219                  *  @dtopt Option
10220                  *  @name DataTable.defaults.lengthMenu
10221                  *
10222                  *  @example
10223                  *    $(document).ready( function() {
10224                  *      $('#example').dataTable( {
10225                  *        "lengthMenu": [[10, 25, 50, -1], [10, 25, 50, "All"]]
10226                  *      } );
10227                  *    } );
10228                  */
10229                 "aLengthMenu": [ 10, 25, 50, 100 ],
10230         
10231         
10232                 /**
10233                  * The `columns` option in the initialisation parameter allows you to define
10234                  * details about the way individual columns behave. For a full list of
10235                  * column options that can be set, please see
10236                  * {@link DataTable.defaults.column}. Note that if you use `columns` to
10237                  * define your columns, you must have an entry in the array for every single
10238                  * column that you have in your table (these can be null if you don't which
10239                  * to specify any options).
10240                  *  @member
10241                  *
10242                  *  @name DataTable.defaults.column
10243                  */
10244                 "aoColumns": null,
10245         
10246                 /**
10247                  * Very similar to `columns`, `columnDefs` allows you to target a specific
10248                  * column, multiple columns, or all columns, using the `targets` property of
10249                  * each object in the array. This allows great flexibility when creating
10250                  * tables, as the `columnDefs` arrays can be of any length, targeting the
10251                  * columns you specifically want. `columnDefs` may use any of the column
10252                  * options available: {@link DataTable.defaults.column}, but it _must_
10253                  * have `targets` defined in each object in the array. Values in the `targets`
10254                  * array may be:
10255                  *   <ul>
10256                  *     <li>a string - class name will be matched on the TH for the column</li>
10257                  *     <li>0 or a positive integer - column index counting from the left</li>
10258                  *     <li>a negative integer - column index counting from the right</li>
10259                  *     <li>the string "_all" - all columns (i.e. assign a default)</li>
10260                  *   </ul>
10261                  *  @member
10262                  *
10263                  *  @name DataTable.defaults.columnDefs
10264                  */
10265                 "aoColumnDefs": null,
10266         
10267         
10268                 /**
10269                  * Basically the same as `search`, this parameter defines the individual column
10270                  * filtering state at initialisation time. The array must be of the same size
10271                  * as the number of columns, and each element be an object with the parameters
10272                  * `search` and `escapeRegex` (the latter is optional). 'null' is also
10273                  * accepted and the default will be used.
10274                  *  @type array
10275                  *  @default []
10276                  *
10277                  *  @dtopt Option
10278                  *  @name DataTable.defaults.searchCols
10279                  *
10280                  *  @example
10281                  *    $(document).ready( function() {
10282                  *      $('#example').dataTable( {
10283                  *        "searchCols": [
10284                  *          null,
10285                  *          { "search": "My filter" },
10286                  *          null,
10287                  *          { "search": "^[0-9]", "escapeRegex": false }
10288                  *        ]
10289                  *      } );
10290                  *    } )
10291                  */
10292                 "aoSearchCols": [],
10293         
10294         
10295                 /**
10296                  * An array of CSS classes that should be applied to displayed rows. This
10297                  * array may be of any length, and DataTables will apply each class
10298                  * sequentially, looping when required.
10299                  *  @type array
10300                  *  @default null <i>Will take the values determined by the `oClasses.stripe*`
10301                  *    options</i>
10302                  *
10303                  *  @dtopt Option
10304                  *  @name DataTable.defaults.stripeClasses
10305                  *
10306                  *  @example
10307                  *    $(document).ready( function() {
10308                  *      $('#example').dataTable( {
10309                  *        "stripeClasses": [ 'strip1', 'strip2', 'strip3' ]
10310                  *      } );
10311                  *    } )
10312                  */
10313                 "asStripeClasses": null,
10314         
10315         
10316                 /**
10317                  * Enable or disable automatic column width calculation. This can be disabled
10318                  * as an optimisation (it takes some time to calculate the widths) if the
10319                  * tables widths are passed in using `columns`.
10320                  *  @type boolean
10321                  *  @default true
10322                  *
10323                  *  @dtopt Features
10324                  *  @name DataTable.defaults.autoWidth
10325                  *
10326                  *  @example
10327                  *    $(document).ready( function () {
10328                  *      $('#example').dataTable( {
10329                  *        "autoWidth": false
10330                  *      } );
10331                  *    } );
10332                  */
10333                 "bAutoWidth": true,
10334         
10335         
10336                 /**
10337                  * Deferred rendering can provide DataTables with a huge speed boost when you
10338                  * are using an Ajax or JS data source for the table. This option, when set to
10339                  * true, will cause DataTables to defer the creation of the table elements for
10340                  * each row until they are needed for a draw - saving a significant amount of
10341                  * time.
10342                  *  @type boolean
10343                  *  @default false
10344                  *
10345                  *  @dtopt Features
10346                  *  @name DataTable.defaults.deferRender
10347                  *
10348                  *  @example
10349                  *    $(document).ready( function() {
10350                  *      $('#example').dataTable( {
10351                  *        "ajax": "sources/arrays.txt",
10352                  *        "deferRender": true
10353                  *      } );
10354                  *    } );
10355                  */
10356                 "bDeferRender": false,
10357         
10358         
10359                 /**
10360                  * Replace a DataTable which matches the given selector and replace it with
10361                  * one which has the properties of the new initialisation object passed. If no
10362                  * table matches the selector, then the new DataTable will be constructed as
10363                  * per normal.
10364                  *  @type boolean
10365                  *  @default false
10366                  *
10367                  *  @dtopt Options
10368                  *  @name DataTable.defaults.destroy
10369                  *
10370                  *  @example
10371                  *    $(document).ready( function() {
10372                  *      $('#example').dataTable( {
10373                  *        "srollY": "200px",
10374                  *        "paginate": false
10375                  *      } );
10376                  *
10377                  *      // Some time later....
10378                  *      $('#example').dataTable( {
10379                  *        "filter": false,
10380                  *        "destroy": true
10381                  *      } );
10382                  *    } );
10383                  */
10384                 "bDestroy": false,
10385         
10386         
10387                 /**
10388                  * Enable or disable filtering of data. Filtering in DataTables is "smart" in
10389                  * that it allows the end user to input multiple words (space separated) and
10390                  * will match a row containing those words, even if not in the order that was
10391                  * specified (this allow matching across multiple columns). Note that if you
10392                  * wish to use filtering in DataTables this must remain 'true' - to remove the
10393                  * default filtering input box and retain filtering abilities, please use
10394                  * {@link DataTable.defaults.dom}.
10395                  *  @type boolean
10396                  *  @default true
10397                  *
10398                  *  @dtopt Features
10399                  *  @name DataTable.defaults.searching
10400                  *
10401                  *  @example
10402                  *    $(document).ready( function () {
10403                  *      $('#example').dataTable( {
10404                  *        "searching": false
10405                  *      } );
10406                  *    } );
10407                  */
10408                 "bFilter": true,
10409         
10410         
10411                 /**
10412                  * Enable or disable the table information display. This shows information
10413                  * about the data that is currently visible on the page, including information
10414                  * about filtered data if that action is being performed.
10415                  *  @type boolean
10416                  *  @default true
10417                  *
10418                  *  @dtopt Features
10419                  *  @name DataTable.defaults.info
10420                  *
10421                  *  @example
10422                  *    $(document).ready( function () {
10423                  *      $('#example').dataTable( {
10424                  *        "info": false
10425                  *      } );
10426                  *    } );
10427                  */
10428                 "bInfo": true,
10429         
10430         
10431                 /**
10432                  * Allows the end user to select the size of a formatted page from a select
10433                  * menu (sizes are 10, 25, 50 and 100). Requires pagination (`paginate`).
10434                  *  @type boolean
10435                  *  @default true
10436                  *
10437                  *  @dtopt Features
10438                  *  @name DataTable.defaults.lengthChange
10439                  *
10440                  *  @example
10441                  *    $(document).ready( function () {
10442                  *      $('#example').dataTable( {
10443                  *        "lengthChange": false
10444                  *      } );
10445                  *    } );
10446                  */
10447                 "bLengthChange": true,
10448         
10449         
10450                 /**
10451                  * Enable or disable pagination.
10452                  *  @type boolean
10453                  *  @default true
10454                  *
10455                  *  @dtopt Features
10456                  *  @name DataTable.defaults.paging
10457                  *
10458                  *  @example
10459                  *    $(document).ready( function () {
10460                  *      $('#example').dataTable( {
10461                  *        "paging": false
10462                  *      } );
10463                  *    } );
10464                  */
10465                 "bPaginate": true,
10466         
10467         
10468                 /**
10469                  * Enable or disable the display of a 'processing' indicator when the table is
10470                  * being processed (e.g. a sort). This is particularly useful for tables with
10471                  * large amounts of data where it can take a noticeable amount of time to sort
10472                  * the entries.
10473                  *  @type boolean
10474                  *  @default false
10475                  *
10476                  *  @dtopt Features
10477                  *  @name DataTable.defaults.processing
10478                  *
10479                  *  @example
10480                  *    $(document).ready( function () {
10481                  *      $('#example').dataTable( {
10482                  *        "processing": true
10483                  *      } );
10484                  *    } );
10485                  */
10486                 "bProcessing": false,
10487         
10488         
10489                 /**
10490                  * Retrieve the DataTables object for the given selector. Note that if the
10491                  * table has already been initialised, this parameter will cause DataTables
10492                  * to simply return the object that has already been set up - it will not take
10493                  * account of any changes you might have made to the initialisation object
10494                  * passed to DataTables (setting this parameter to true is an acknowledgement
10495                  * that you understand this). `destroy` can be used to reinitialise a table if
10496                  * you need.
10497                  *  @type boolean
10498                  *  @default false
10499                  *
10500                  *  @dtopt Options
10501                  *  @name DataTable.defaults.retrieve
10502                  *
10503                  *  @example
10504                  *    $(document).ready( function() {
10505                  *      initTable();
10506                  *      tableActions();
10507                  *    } );
10508                  *
10509                  *    function initTable ()
10510                  *    {
10511                  *      return $('#example').dataTable( {
10512                  *        "scrollY": "200px",
10513                  *        "paginate": false,
10514                  *        "retrieve": true
10515                  *      } );
10516                  *    }
10517                  *
10518                  *    function tableActions ()
10519                  *    {
10520                  *      var table = initTable();
10521                  *      // perform API operations with oTable
10522                  *    }
10523                  */
10524                 "bRetrieve": false,
10525         
10526         
10527                 /**
10528                  * When vertical (y) scrolling is enabled, DataTables will force the height of
10529                  * the table's viewport to the given height at all times (useful for layout).
10530                  * However, this can look odd when filtering data down to a small data set,
10531                  * and the footer is left "floating" further down. This parameter (when
10532                  * enabled) will cause DataTables to collapse the table's viewport down when
10533                  * the result set will fit within the given Y height.
10534                  *  @type boolean
10535                  *  @default false
10536                  *
10537                  *  @dtopt Options
10538                  *  @name DataTable.defaults.scrollCollapse
10539                  *
10540                  *  @example
10541                  *    $(document).ready( function() {
10542                  *      $('#example').dataTable( {
10543                  *        "scrollY": "200",
10544                  *        "scrollCollapse": true
10545                  *      } );
10546                  *    } );
10547                  */
10548                 "bScrollCollapse": false,
10549         
10550         
10551                 /**
10552                  * Configure DataTables to use server-side processing. Note that the
10553                  * `ajax` parameter must also be given in order to give DataTables a
10554                  * source to obtain the required data for each draw.
10555                  *  @type boolean
10556                  *  @default false
10557                  *
10558                  *  @dtopt Features
10559                  *  @dtopt Server-side
10560                  *  @name DataTable.defaults.serverSide
10561                  *
10562                  *  @example
10563                  *    $(document).ready( function () {
10564                  *      $('#example').dataTable( {
10565                  *        "serverSide": true,
10566                  *        "ajax": "xhr.php"
10567                  *      } );
10568                  *    } );
10569                  */
10570                 "bServerSide": false,
10571         
10572         
10573                 /**
10574                  * Enable or disable sorting of columns. Sorting of individual columns can be
10575                  * disabled by the `sortable` option for each column.
10576                  *  @type boolean
10577                  *  @default true
10578                  *
10579                  *  @dtopt Features
10580                  *  @name DataTable.defaults.ordering
10581                  *
10582                  *  @example
10583                  *    $(document).ready( function () {
10584                  *      $('#example').dataTable( {
10585                  *        "ordering": false
10586                  *      } );
10587                  *    } );
10588                  */
10589                 "bSort": true,
10590         
10591         
10592                 /**
10593                  * Enable or display DataTables' ability to sort multiple columns at the
10594                  * same time (activated by shift-click by the user).
10595                  *  @type boolean
10596                  *  @default true
10597                  *
10598                  *  @dtopt Options
10599                  *  @name DataTable.defaults.orderMulti
10600                  *
10601                  *  @example
10602                  *    // Disable multiple column sorting ability
10603                  *    $(document).ready( function () {
10604                  *      $('#example').dataTable( {
10605                  *        "orderMulti": false
10606                  *      } );
10607                  *    } );
10608                  */
10609                 "bSortMulti": true,
10610         
10611         
10612                 /**
10613                  * Allows control over whether DataTables should use the top (true) unique
10614                  * cell that is found for a single column, or the bottom (false - default).
10615                  * This is useful when using complex headers.
10616                  *  @type boolean
10617                  *  @default false
10618                  *
10619                  *  @dtopt Options
10620                  *  @name DataTable.defaults.orderCellsTop
10621                  *
10622                  *  @example
10623                  *    $(document).ready( function() {
10624                  *      $('#example').dataTable( {
10625                  *        "orderCellsTop": true
10626                  *      } );
10627                  *    } );
10628                  */
10629                 "bSortCellsTop": false,
10630         
10631         
10632                 /**
10633                  * Enable or disable the addition of the classes `sorting\_1`, `sorting\_2` and
10634                  * `sorting\_3` to the columns which are currently being sorted on. This is
10635                  * presented as a feature switch as it can increase processing time (while
10636                  * classes are removed and added) so for large data sets you might want to
10637                  * turn this off.
10638                  *  @type boolean
10639                  *  @default true
10640                  *
10641                  *  @dtopt Features
10642                  *  @name DataTable.defaults.orderClasses
10643                  *
10644                  *  @example
10645                  *    $(document).ready( function () {
10646                  *      $('#example').dataTable( {
10647                  *        "orderClasses": false
10648                  *      } );
10649                  *    } );
10650                  */
10651                 "bSortClasses": true,
10652         
10653         
10654                 /**
10655                  * Enable or disable state saving. When enabled HTML5 `localStorage` will be
10656                  * used to save table display information such as pagination information,
10657                  * display length, filtering and sorting. As such when the end user reloads
10658                  * the page the display display will match what thy had previously set up.
10659                  *
10660                  * Due to the use of `localStorage` the default state saving is not supported
10661                  * in IE6 or 7. If state saving is required in those browsers, use
10662                  * `stateSaveCallback` to provide a storage solution such as cookies.
10663                  *  @type boolean
10664                  *  @default false
10665                  *
10666                  *  @dtopt Features
10667                  *  @name DataTable.defaults.stateSave
10668                  *
10669                  *  @example
10670                  *    $(document).ready( function () {
10671                  *      $('#example').dataTable( {
10672                  *        "stateSave": true
10673                  *      } );
10674                  *    } );
10675                  */
10676                 "bStateSave": false,
10677         
10678         
10679                 /**
10680                  * This function is called when a TR element is created (and all TD child
10681                  * elements have been inserted), or registered if using a DOM source, allowing
10682                  * manipulation of the TR element (adding classes etc).
10683                  *  @type function
10684                  *  @param {node} row "TR" element for the current row
10685                  *  @param {array} data Raw data array for this row
10686                  *  @param {int} dataIndex The index of this row in the internal aoData array
10687                  *
10688                  *  @dtopt Callbacks
10689                  *  @name DataTable.defaults.createdRow
10690                  *
10691                  *  @example
10692                  *    $(document).ready( function() {
10693                  *      $('#example').dataTable( {
10694                  *        "createdRow": function( row, data, dataIndex ) {
10695                  *          // Bold the grade for all 'A' grade browsers
10696                  *          if ( data[4] == "A" )
10697                  *          {
10698                  *            $('td:eq(4)', row).html( '<b>A</b>' );
10699                  *          }
10700                  *        }
10701                  *      } );
10702                  *    } );
10703                  */
10704                 "fnCreatedRow": null,
10705         
10706         
10707                 /**
10708                  * This function is called on every 'draw' event, and allows you to
10709                  * dynamically modify any aspect you want about the created DOM.
10710                  *  @type function
10711                  *  @param {object} settings DataTables settings object
10712                  *
10713                  *  @dtopt Callbacks
10714                  *  @name DataTable.defaults.drawCallback
10715                  *
10716                  *  @example
10717                  *    $(document).ready( function() {
10718                  *      $('#example').dataTable( {
10719                  *        "drawCallback": function( settings ) {
10720                  *          alert( 'DataTables has redrawn the table' );
10721                  *        }
10722                  *      } );
10723                  *    } );
10724                  */
10725                 "fnDrawCallback": null,
10726         
10727         
10728                 /**
10729                  * Identical to fnHeaderCallback() but for the table footer this function
10730                  * allows you to modify the table footer on every 'draw' event.
10731                  *  @type function
10732                  *  @param {node} foot "TR" element for the footer
10733                  *  @param {array} data Full table data (as derived from the original HTML)
10734                  *  @param {int} start Index for the current display starting point in the
10735                  *    display array
10736                  *  @param {int} end Index for the current display ending point in the
10737                  *    display array
10738                  *  @param {array int} display Index array to translate the visual position
10739                  *    to the full data array
10740                  *
10741                  *  @dtopt Callbacks
10742                  *  @name DataTable.defaults.footerCallback
10743                  *
10744                  *  @example
10745                  *    $(document).ready( function() {
10746                  *      $('#example').dataTable( {
10747                  *        "footerCallback": function( tfoot, data, start, end, display ) {
10748                  *          tfoot.getElementsByTagName('th')[0].innerHTML = "Starting index is "+start;
10749                  *        }
10750                  *      } );
10751                  *    } )
10752                  */
10753                 "fnFooterCallback": null,
10754         
10755         
10756                 /**
10757                  * When rendering large numbers in the information element for the table
10758                  * (i.e. "Showing 1 to 10 of 57 entries") DataTables will render large numbers
10759                  * to have a comma separator for the 'thousands' units (e.g. 1 million is
10760                  * rendered as "1,000,000") to help readability for the end user. This
10761                  * function will override the default method DataTables uses.
10762                  *  @type function
10763                  *  @member
10764                  *  @param {int} toFormat number to be formatted
10765                  *  @returns {string} formatted string for DataTables to show the number
10766                  *
10767                  *  @dtopt Callbacks
10768                  *  @name DataTable.defaults.formatNumber
10769                  *
10770                  *  @example
10771                  *    // Format a number using a single quote for the separator (note that
10772                  *    // this can also be done with the language.thousands option)
10773                  *    $(document).ready( function() {
10774                  *      $('#example').dataTable( {
10775                  *        "formatNumber": function ( toFormat ) {
10776                  *          return toFormat.toString().replace(
10777                  *            /\B(?=(\d{3})+(?!\d))/g, "'"
10778                  *          );
10779                  *        };
10780                  *      } );
10781                  *    } );
10782                  */
10783                 "fnFormatNumber": function ( toFormat ) {
10784                         return toFormat.toString().replace(
10785                                 /\B(?=(\d{3})+(?!\d))/g,
10786                                 this.oLanguage.sThousands
10787                         );
10788                 },
10789         
10790         
10791                 /**
10792                  * This function is called on every 'draw' event, and allows you to
10793                  * dynamically modify the header row. This can be used to calculate and
10794                  * display useful information about the table.
10795                  *  @type function
10796                  *  @param {node} head "TR" element for the header
10797                  *  @param {array} data Full table data (as derived from the original HTML)
10798                  *  @param {int} start Index for the current display starting point in the
10799                  *    display array
10800                  *  @param {int} end Index for the current display ending point in the
10801                  *    display array
10802                  *  @param {array int} display Index array to translate the visual position
10803                  *    to the full data array
10804                  *
10805                  *  @dtopt Callbacks
10806                  *  @name DataTable.defaults.headerCallback
10807                  *
10808                  *  @example
10809                  *    $(document).ready( function() {
10810                  *      $('#example').dataTable( {
10811                  *        "fheaderCallback": function( head, data, start, end, display ) {
10812                  *          head.getElementsByTagName('th')[0].innerHTML = "Displaying "+(end-start)+" records";
10813                  *        }
10814                  *      } );
10815                  *    } )
10816                  */
10817                 "fnHeaderCallback": null,
10818         
10819         
10820                 /**
10821                  * The information element can be used to convey information about the current
10822                  * state of the table. Although the internationalisation options presented by
10823                  * DataTables are quite capable of dealing with most customisations, there may
10824                  * be times where you wish to customise the string further. This callback
10825                  * allows you to do exactly that.
10826                  *  @type function
10827                  *  @param {object} oSettings DataTables settings object
10828                  *  @param {int} start Starting position in data for the draw
10829                  *  @param {int} end End position in data for the draw
10830                  *  @param {int} max Total number of rows in the table (regardless of
10831                  *    filtering)
10832                  *  @param {int} total Total number of rows in the data set, after filtering
10833                  *  @param {string} pre The string that DataTables has formatted using it's
10834                  *    own rules
10835                  *  @returns {string} The string to be displayed in the information element.
10836                  *
10837                  *  @dtopt Callbacks
10838                  *  @name DataTable.defaults.infoCallback
10839                  *
10840                  *  @example
10841                  *    $('#example').dataTable( {
10842                  *      "infoCallback": function( settings, start, end, max, total, pre ) {
10843                  *        return start +" to "+ end;
10844                  *      }
10845                  *    } );
10846                  */
10847                 "fnInfoCallback": null,
10848         
10849         
10850                 /**
10851                  * Called when the table has been initialised. Normally DataTables will
10852                  * initialise sequentially and there will be no need for this function,
10853                  * however, this does not hold true when using external language information
10854                  * since that is obtained using an async XHR call.
10855                  *  @type function
10856                  *  @param {object} settings DataTables settings object
10857                  *  @param {object} json The JSON object request from the server - only
10858                  *    present if client-side Ajax sourced data is used
10859                  *
10860                  *  @dtopt Callbacks
10861                  *  @name DataTable.defaults.initComplete
10862                  *
10863                  *  @example
10864                  *    $(document).ready( function() {
10865                  *      $('#example').dataTable( {
10866                  *        "initComplete": function(settings, json) {
10867                  *          alert( 'DataTables has finished its initialisation.' );
10868                  *        }
10869                  *      } );
10870                  *    } )
10871                  */
10872                 "fnInitComplete": null,
10873         
10874         
10875                 /**
10876                  * Called at the very start of each table draw and can be used to cancel the
10877                  * draw by returning false, any other return (including undefined) results in
10878                  * the full draw occurring).
10879                  *  @type function
10880                  *  @param {object} settings DataTables settings object
10881                  *  @returns {boolean} False will cancel the draw, anything else (including no
10882                  *    return) will allow it to complete.
10883                  *
10884                  *  @dtopt Callbacks
10885                  *  @name DataTable.defaults.preDrawCallback
10886                  *
10887                  *  @example
10888                  *    $(document).ready( function() {
10889                  *      $('#example').dataTable( {
10890                  *        "preDrawCallback": function( settings ) {
10891                  *          if ( $('#test').val() == 1 ) {
10892                  *            return false;
10893                  *          }
10894                  *        }
10895                  *      } );
10896                  *    } );
10897                  */
10898                 "fnPreDrawCallback": null,
10899         
10900         
10901                 /**
10902                  * This function allows you to 'post process' each row after it have been
10903                  * generated for each table draw, but before it is rendered on screen. This
10904                  * function might be used for setting the row class name etc.
10905                  *  @type function
10906                  *  @param {node} row "TR" element for the current row
10907                  *  @param {array} data Raw data array for this row
10908                  *  @param {int} displayIndex The display index for the current table draw
10909                  *  @param {int} displayIndexFull The index of the data in the full list of
10910                  *    rows (after filtering)
10911                  *
10912                  *  @dtopt Callbacks
10913                  *  @name DataTable.defaults.rowCallback
10914                  *
10915                  *  @example
10916                  *    $(document).ready( function() {
10917                  *      $('#example').dataTable( {
10918                  *        "rowCallback": function( row, data, displayIndex, displayIndexFull ) {
10919                  *          // Bold the grade for all 'A' grade browsers
10920                  *          if ( data[4] == "A" ) {
10921                  *            $('td:eq(4)', row).html( '<b>A</b>' );
10922                  *          }
10923                  *        }
10924                  *      } );
10925                  *    } );
10926                  */
10927                 "fnRowCallback": null,
10928         
10929         
10930                 /**
10931                  * __Deprecated__ The functionality provided by this parameter has now been
10932                  * superseded by that provided through `ajax`, which should be used instead.
10933                  *
10934                  * This parameter allows you to override the default function which obtains
10935                  * the data from the server so something more suitable for your application.
10936                  * For example you could use POST data, or pull information from a Gears or
10937                  * AIR database.
10938                  *  @type function
10939                  *  @member
10940                  *  @param {string} source HTTP source to obtain the data from (`ajax`)
10941                  *  @param {array} data A key/value pair object containing the data to send
10942                  *    to the server
10943                  *  @param {function} callback to be called on completion of the data get
10944                  *    process that will draw the data on the page.
10945                  *  @param {object} settings DataTables settings object
10946                  *
10947                  *  @dtopt Callbacks
10948                  *  @dtopt Server-side
10949                  *  @name DataTable.defaults.serverData
10950                  *
10951                  *  @deprecated 1.10. Please use `ajax` for this functionality now.
10952                  */
10953                 "fnServerData": null,
10954         
10955         
10956                 /**
10957                  * __Deprecated__ The functionality provided by this parameter has now been
10958                  * superseded by that provided through `ajax`, which should be used instead.
10959                  *
10960                  *  It is often useful to send extra data to the server when making an Ajax
10961                  * request - for example custom filtering information, and this callback
10962                  * function makes it trivial to send extra information to the server. The
10963                  * passed in parameter is the data set that has been constructed by
10964                  * DataTables, and you can add to this or modify it as you require.
10965                  *  @type function
10966                  *  @param {array} data Data array (array of objects which are name/value
10967                  *    pairs) that has been constructed by DataTables and will be sent to the
10968                  *    server. In the case of Ajax sourced data with server-side processing
10969                  *    this will be an empty array, for server-side processing there will be a
10970                  *    significant number of parameters!
10971                  *  @returns {undefined} Ensure that you modify the data array passed in,
10972                  *    as this is passed by reference.
10973                  *
10974                  *  @dtopt Callbacks
10975                  *  @dtopt Server-side
10976                  *  @name DataTable.defaults.serverParams
10977                  *
10978                  *  @deprecated 1.10. Please use `ajax` for this functionality now.
10979                  */
10980                 "fnServerParams": null,
10981         
10982         
10983                 /**
10984                  * Load the table state. With this function you can define from where, and how, the
10985                  * state of a table is loaded. By default DataTables will load from `localStorage`
10986                  * but you might wish to use a server-side database or cookies.
10987                  *  @type function
10988                  *  @member
10989                  *  @param {object} settings DataTables settings object
10990                  *  @param {object} callback Callback that can be executed when done. It
10991                  *    should be passed the loaded state object.
10992                  *  @return {object} The DataTables state object to be loaded
10993                  *
10994                  *  @dtopt Callbacks
10995                  *  @name DataTable.defaults.stateLoadCallback
10996                  *
10997                  *  @example
10998                  *    $(document).ready( function() {
10999                  *      $('#example').dataTable( {
11000                  *        "stateSave": true,
11001                  *        "stateLoadCallback": function (settings, callback) {
11002                  *          $.ajax( {
11003                  *            "url": "/state_load",
11004                  *            "dataType": "json",
11005                  *            "success": function (json) {
11006                  *              callback( json );
11007                  *            }
11008                  *          } );
11009                  *        }
11010                  *      } );
11011                  *    } );
11012                  */
11013                 "fnStateLoadCallback": function ( settings ) {
11014                         try {
11015                                 return JSON.parse(
11016                                         (settings.iStateDuration === -1 ? sessionStorage : localStorage).getItem(
11017                                                 'DataTables_'+settings.sInstance+'_'+location.pathname
11018                                         )
11019                                 );
11020                         } catch (e) {}
11021                 },
11022         
11023         
11024                 /**
11025                  * Callback which allows modification of the saved state prior to loading that state.
11026                  * This callback is called when the table is loading state from the stored data, but
11027                  * prior to the settings object being modified by the saved state. Note that for
11028                  * plug-in authors, you should use the `stateLoadParams` event to load parameters for
11029                  * a plug-in.
11030                  *  @type function
11031                  *  @param {object} settings DataTables settings object
11032                  *  @param {object} data The state object that is to be loaded
11033                  *
11034                  *  @dtopt Callbacks
11035                  *  @name DataTable.defaults.stateLoadParams
11036                  *
11037                  *  @example
11038                  *    // Remove a saved filter, so filtering is never loaded
11039                  *    $(document).ready( function() {
11040                  *      $('#example').dataTable( {
11041                  *        "stateSave": true,
11042                  *        "stateLoadParams": function (settings, data) {
11043                  *          data.oSearch.sSearch = "";
11044                  *        }
11045                  *      } );
11046                  *    } );
11047                  *
11048                  *  @example
11049                  *    // Disallow state loading by returning false
11050                  *    $(document).ready( function() {
11051                  *      $('#example').dataTable( {
11052                  *        "stateSave": true,
11053                  *        "stateLoadParams": function (settings, data) {
11054                  *          return false;
11055                  *        }
11056                  *      } );
11057                  *    } );
11058                  */
11059                 "fnStateLoadParams": null,
11060         
11061         
11062                 /**
11063                  * Callback that is called when the state has been loaded from the state saving method
11064                  * and the DataTables settings object has been modified as a result of the loaded state.
11065                  *  @type function
11066                  *  @param {object} settings DataTables settings object
11067                  *  @param {object} data The state object that was loaded
11068                  *
11069                  *  @dtopt Callbacks
11070                  *  @name DataTable.defaults.stateLoaded
11071                  *
11072                  *  @example
11073                  *    // Show an alert with the filtering value that was saved
11074                  *    $(document).ready( function() {
11075                  *      $('#example').dataTable( {
11076                  *        "stateSave": true,
11077                  *        "stateLoaded": function (settings, data) {
11078                  *          alert( 'Saved filter was: '+data.oSearch.sSearch );
11079                  *        }
11080                  *      } );
11081                  *    } );
11082                  */
11083                 "fnStateLoaded": null,
11084         
11085         
11086                 /**
11087                  * Save the table state. This function allows you to define where and how the state
11088                  * information for the table is stored By default DataTables will use `localStorage`
11089                  * but you might wish to use a server-side database or cookies.
11090                  *  @type function
11091                  *  @member
11092                  *  @param {object} settings DataTables settings object
11093                  *  @param {object} data The state object to be saved
11094                  *
11095                  *  @dtopt Callbacks
11096                  *  @name DataTable.defaults.stateSaveCallback
11097                  *
11098                  *  @example
11099                  *    $(document).ready( function() {
11100                  *      $('#example').dataTable( {
11101                  *        "stateSave": true,
11102                  *        "stateSaveCallback": function (settings, data) {
11103                  *          // Send an Ajax request to the server with the state object
11104                  *          $.ajax( {
11105                  *            "url": "/state_save",
11106                  *            "data": data,
11107                  *            "dataType": "json",
11108                  *            "method": "POST"
11109                  *            "success": function () {}
11110                  *          } );
11111                  *        }
11112                  *      } );
11113                  *    } );
11114                  */
11115                 "fnStateSaveCallback": function ( settings, data ) {
11116                         try {
11117                                 (settings.iStateDuration === -1 ? sessionStorage : localStorage).setItem(
11118                                         'DataTables_'+settings.sInstance+'_'+location.pathname,
11119                                         JSON.stringify( data )
11120                                 );
11121                         } catch (e) {}
11122                 },
11123         
11124         
11125                 /**
11126                  * Callback which allows modification of the state to be saved. Called when the table
11127                  * has changed state a new state save is required. This method allows modification of
11128                  * the state saving object prior to actually doing the save, including addition or
11129                  * other state properties or modification. Note that for plug-in authors, you should
11130                  * use the `stateSaveParams` event to save parameters for a plug-in.
11131                  *  @type function
11132                  *  @param {object} settings DataTables settings object
11133                  *  @param {object} data The state object to be saved
11134                  *
11135                  *  @dtopt Callbacks
11136                  *  @name DataTable.defaults.stateSaveParams
11137                  *
11138                  *  @example
11139                  *    // Remove a saved filter, so filtering is never saved
11140                  *    $(document).ready( function() {
11141                  *      $('#example').dataTable( {
11142                  *        "stateSave": true,
11143                  *        "stateSaveParams": function (settings, data) {
11144                  *          data.oSearch.sSearch = "";
11145                  *        }
11146                  *      } );
11147                  *    } );
11148                  */
11149                 "fnStateSaveParams": null,
11150         
11151         
11152                 /**
11153                  * Duration for which the saved state information is considered valid. After this period
11154                  * has elapsed the state will be returned to the default.
11155                  * Value is given in seconds.
11156                  *  @type int
11157                  *  @default 7200 <i>(2 hours)</i>
11158                  *
11159                  *  @dtopt Options
11160                  *  @name DataTable.defaults.stateDuration
11161                  *
11162                  *  @example
11163                  *    $(document).ready( function() {
11164                  *      $('#example').dataTable( {
11165                  *        "stateDuration": 60*60*24; // 1 day
11166                  *      } );
11167                  *    } )
11168                  */
11169                 "iStateDuration": 7200,
11170         
11171         
11172                 /**
11173                  * When enabled DataTables will not make a request to the server for the first
11174                  * page draw - rather it will use the data already on the page (no sorting etc
11175                  * will be applied to it), thus saving on an XHR at load time. `deferLoading`
11176                  * is used to indicate that deferred loading is required, but it is also used
11177                  * to tell DataTables how many records there are in the full table (allowing
11178                  * the information element and pagination to be displayed correctly). In the case
11179                  * where a filtering is applied to the table on initial load, this can be
11180                  * indicated by giving the parameter as an array, where the first element is
11181                  * the number of records available after filtering and the second element is the
11182                  * number of records without filtering (allowing the table information element
11183                  * to be shown correctly).
11184                  *  @type int | array
11185                  *  @default null
11186                  *
11187                  *  @dtopt Options
11188                  *  @name DataTable.defaults.deferLoading
11189                  *
11190                  *  @example
11191                  *    // 57 records available in the table, no filtering applied
11192                  *    $(document).ready( function() {
11193                  *      $('#example').dataTable( {
11194                  *        "serverSide": true,
11195                  *        "ajax": "scripts/server_processing.php",
11196                  *        "deferLoading": 57
11197                  *      } );
11198                  *    } );
11199                  *
11200                  *  @example
11201                  *    // 57 records after filtering, 100 without filtering (an initial filter applied)
11202                  *    $(document).ready( function() {
11203                  *      $('#example').dataTable( {
11204                  *        "serverSide": true,
11205                  *        "ajax": "scripts/server_processing.php",
11206                  *        "deferLoading": [ 57, 100 ],
11207                  *        "search": {
11208                  *          "search": "my_filter"
11209                  *        }
11210                  *      } );
11211                  *    } );
11212                  */
11213                 "iDeferLoading": null,
11214         
11215         
11216                 /**
11217                  * Number of rows to display on a single page when using pagination. If
11218                  * feature enabled (`lengthChange`) then the end user will be able to override
11219                  * this to a custom setting using a pop-up menu.
11220                  *  @type int
11221                  *  @default 10
11222                  *
11223                  *  @dtopt Options
11224                  *  @name DataTable.defaults.pageLength
11225                  *
11226                  *  @example
11227                  *    $(document).ready( function() {
11228                  *      $('#example').dataTable( {
11229                  *        "pageLength": 50
11230                  *      } );
11231                  *    } )
11232                  */
11233                 "iDisplayLength": 10,
11234         
11235         
11236                 /**
11237                  * Define the starting point for data display when using DataTables with
11238                  * pagination. Note that this parameter is the number of records, rather than
11239                  * the page number, so if you have 10 records per page and want to start on
11240                  * the third page, it should be "20".
11241                  *  @type int
11242                  *  @default 0
11243                  *
11244                  *  @dtopt Options
11245                  *  @name DataTable.defaults.displayStart
11246                  *
11247                  *  @example
11248                  *    $(document).ready( function() {
11249                  *      $('#example').dataTable( {
11250                  *        "displayStart": 20
11251                  *      } );
11252                  *    } )
11253                  */
11254                 "iDisplayStart": 0,
11255         
11256         
11257                 /**
11258                  * By default DataTables allows keyboard navigation of the table (sorting, paging,
11259                  * and filtering) by adding a `tabindex` attribute to the required elements. This
11260                  * allows you to tab through the controls and press the enter key to activate them.
11261                  * The tabindex is default 0, meaning that the tab follows the flow of the document.
11262                  * You can overrule this using this parameter if you wish. Use a value of -1 to
11263                  * disable built-in keyboard navigation.
11264                  *  @type int
11265                  *  @default 0
11266                  *
11267                  *  @dtopt Options
11268                  *  @name DataTable.defaults.tabIndex
11269                  *
11270                  *  @example
11271                  *    $(document).ready( function() {
11272                  *      $('#example').dataTable( {
11273                  *        "tabIndex": 1
11274                  *      } );
11275                  *    } );
11276                  */
11277                 "iTabIndex": 0,
11278         
11279         
11280                 /**
11281                  * Classes that DataTables assigns to the various components and features
11282                  * that it adds to the HTML table. This allows classes to be configured
11283                  * during initialisation in addition to through the static
11284                  * {@link DataTable.ext.oStdClasses} object).
11285                  *  @namespace
11286                  *  @name DataTable.defaults.classes
11287                  */
11288                 "oClasses": {},
11289         
11290         
11291                 /**
11292                  * All strings that DataTables uses in the user interface that it creates
11293                  * are defined in this object, allowing you to modified them individually or
11294                  * completely replace them all as required.
11295                  *  @namespace
11296                  *  @name DataTable.defaults.language
11297                  */
11298                 "oLanguage": {
11299                         /**
11300                          * Strings that are used for WAI-ARIA labels and controls only (these are not
11301                          * actually visible on the page, but will be read by screenreaders, and thus
11302                          * must be internationalised as well).
11303                          *  @namespace
11304                          *  @name DataTable.defaults.language.aria
11305                          */
11306                         "oAria": {
11307                                 /**
11308                                  * ARIA label that is added to the table headers when the column may be
11309                                  * sorted ascending by activing the column (click or return when focused).
11310                                  * Note that the column header is prefixed to this string.
11311                                  *  @type string
11312                                  *  @default : activate to sort column ascending
11313                                  *
11314                                  *  @dtopt Language
11315                                  *  @name DataTable.defaults.language.aria.sortAscending
11316                                  *
11317                                  *  @example
11318                                  *    $(document).ready( function() {
11319                                  *      $('#example').dataTable( {
11320                                  *        "language": {
11321                                  *          "aria": {
11322                                  *            "sortAscending": " - click/return to sort ascending"
11323                                  *          }
11324                                  *        }
11325                                  *      } );
11326                                  *    } );
11327                                  */
11328                                 "sSortAscending": ": activate to sort column ascending",
11329         
11330                                 /**
11331                                  * ARIA label that is added to the table headers when the column may be
11332                                  * sorted descending by activing the column (click or return when focused).
11333                                  * Note that the column header is prefixed to this string.
11334                                  *  @type string
11335                                  *  @default : activate to sort column ascending
11336                                  *
11337                                  *  @dtopt Language
11338                                  *  @name DataTable.defaults.language.aria.sortDescending
11339                                  *
11340                                  *  @example
11341                                  *    $(document).ready( function() {
11342                                  *      $('#example').dataTable( {
11343                                  *        "language": {
11344                                  *          "aria": {
11345                                  *            "sortDescending": " - click/return to sort descending"
11346                                  *          }
11347                                  *        }
11348                                  *      } );
11349                                  *    } );
11350                                  */
11351                                 "sSortDescending": ": activate to sort column descending"
11352                         },
11353         
11354                         /**
11355                          * Pagination string used by DataTables for the built-in pagination
11356                          * control types.
11357                          *  @namespace
11358                          *  @name DataTable.defaults.language.paginate
11359                          */
11360                         "oPaginate": {
11361                                 /**
11362                                  * Text to use when using the 'full_numbers' type of pagination for the
11363                                  * button to take the user to the first page.
11364                                  *  @type string
11365                                  *  @default First
11366                                  *
11367                                  *  @dtopt Language
11368                                  *  @name DataTable.defaults.language.paginate.first
11369                                  *
11370                                  *  @example
11371                                  *    $(document).ready( function() {
11372                                  *      $('#example').dataTable( {
11373                                  *        "language": {
11374                                  *          "paginate": {
11375                                  *            "first": "First page"
11376                                  *          }
11377                                  *        }
11378                                  *      } );
11379                                  *    } );
11380                                  */
11381                                 "sFirst": "First",
11382         
11383         
11384                                 /**
11385                                  * Text to use when using the 'full_numbers' type of pagination for the
11386                                  * button to take the user to the last page.
11387                                  *  @type string
11388                                  *  @default Last
11389                                  *
11390                                  *  @dtopt Language
11391                                  *  @name DataTable.defaults.language.paginate.last
11392                                  *
11393                                  *  @example
11394                                  *    $(document).ready( function() {
11395                                  *      $('#example').dataTable( {
11396                                  *        "language": {
11397                                  *          "paginate": {
11398                                  *            "last": "Last page"
11399                                  *          }
11400                                  *        }
11401                                  *      } );
11402                                  *    } );
11403                                  */
11404                                 "sLast": "Last",
11405         
11406         
11407                                 /**
11408                                  * Text to use for the 'next' pagination button (to take the user to the
11409                                  * next page).
11410                                  *  @type string
11411                                  *  @default Next
11412                                  *
11413                                  *  @dtopt Language
11414                                  *  @name DataTable.defaults.language.paginate.next
11415                                  *
11416                                  *  @example
11417                                  *    $(document).ready( function() {
11418                                  *      $('#example').dataTable( {
11419                                  *        "language": {
11420                                  *          "paginate": {
11421                                  *            "next": "Next page"
11422                                  *          }
11423                                  *        }
11424                                  *      } );
11425                                  *    } );
11426                                  */
11427                                 "sNext": "Next",
11428         
11429         
11430                                 /**
11431                                  * Text to use for the 'previous' pagination button (to take the user to
11432                                  * the previous page).
11433                                  *  @type string
11434                                  *  @default Previous
11435                                  *
11436                                  *  @dtopt Language
11437                                  *  @name DataTable.defaults.language.paginate.previous
11438                                  *
11439                                  *  @example
11440                                  *    $(document).ready( function() {
11441                                  *      $('#example').dataTable( {
11442                                  *        "language": {
11443                                  *          "paginate": {
11444                                  *            "previous": "Previous page"
11445                                  *          }
11446                                  *        }
11447                                  *      } );
11448                                  *    } );
11449                                  */
11450                                 "sPrevious": "Previous"
11451                         },
11452         
11453                         /**
11454                          * This string is shown in preference to `zeroRecords` when the table is
11455                          * empty of data (regardless of filtering). Note that this is an optional
11456                          * parameter - if it is not given, the value of `zeroRecords` will be used
11457                          * instead (either the default or given value).
11458                          *  @type string
11459                          *  @default No data available in table
11460                          *
11461                          *  @dtopt Language
11462                          *  @name DataTable.defaults.language.emptyTable
11463                          *
11464                          *  @example
11465                          *    $(document).ready( function() {
11466                          *      $('#example').dataTable( {
11467                          *        "language": {
11468                          *          "emptyTable": "No data available in table"
11469                          *        }
11470                          *      } );
11471                          *    } );
11472                          */
11473                         "sEmptyTable": "No data available in table",
11474         
11475         
11476                         /**
11477                          * This string gives information to the end user about the information
11478                          * that is current on display on the page. The following tokens can be
11479                          * used in the string and will be dynamically replaced as the table
11480                          * display updates. This tokens can be placed anywhere in the string, or
11481                          * removed as needed by the language requires:
11482                          *
11483                          * * `\_START\_` - Display index of the first record on the current page
11484                          * * `\_END\_` - Display index of the last record on the current page
11485                          * * `\_TOTAL\_` - Number of records in the table after filtering
11486                          * * `\_MAX\_` - Number of records in the table without filtering
11487                          * * `\_PAGE\_` - Current page number
11488                          * * `\_PAGES\_` - Total number of pages of data in the table
11489                          *
11490                          *  @type string
11491                          *  @default Showing _START_ to _END_ of _TOTAL_ entries
11492                          *
11493                          *  @dtopt Language
11494                          *  @name DataTable.defaults.language.info
11495                          *
11496                          *  @example
11497                          *    $(document).ready( function() {
11498                          *      $('#example').dataTable( {
11499                          *        "language": {
11500                          *          "info": "Showing page _PAGE_ of _PAGES_"
11501                          *        }
11502                          *      } );
11503                          *    } );
11504                          */
11505                         "sInfo": "Showing _START_ to _END_ of _TOTAL_ entries",
11506         
11507         
11508                         /**
11509                          * Display information string for when the table is empty. Typically the
11510                          * format of this string should match `info`.
11511                          *  @type string
11512                          *  @default Showing 0 to 0 of 0 entries
11513                          *
11514                          *  @dtopt Language
11515                          *  @name DataTable.defaults.language.infoEmpty
11516                          *
11517                          *  @example
11518                          *    $(document).ready( function() {
11519                          *      $('#example').dataTable( {
11520                          *        "language": {
11521                          *          "infoEmpty": "No entries to show"
11522                          *        }
11523                          *      } );
11524                          *    } );
11525                          */
11526                         "sInfoEmpty": "Showing 0 to 0 of 0 entries",
11527         
11528         
11529                         /**
11530                          * When a user filters the information in a table, this string is appended
11531                          * to the information (`info`) to give an idea of how strong the filtering
11532                          * is. The variable _MAX_ is dynamically updated.
11533                          *  @type string
11534                          *  @default (filtered from _MAX_ total entries)
11535                          *
11536                          *  @dtopt Language
11537                          *  @name DataTable.defaults.language.infoFiltered
11538                          *
11539                          *  @example
11540                          *    $(document).ready( function() {
11541                          *      $('#example').dataTable( {
11542                          *        "language": {
11543                          *          "infoFiltered": " - filtering from _MAX_ records"
11544                          *        }
11545                          *      } );
11546                          *    } );
11547                          */
11548                         "sInfoFiltered": "(filtered from _MAX_ total entries)",
11549         
11550         
11551                         /**
11552                          * If can be useful to append extra information to the info string at times,
11553                          * and this variable does exactly that. This information will be appended to
11554                          * the `info` (`infoEmpty` and `infoFiltered` in whatever combination they are
11555                          * being used) at all times.
11556                          *  @type string
11557                          *  @default <i>Empty string</i>
11558                          *
11559                          *  @dtopt Language
11560                          *  @name DataTable.defaults.language.infoPostFix
11561                          *
11562                          *  @example
11563                          *    $(document).ready( function() {
11564                          *      $('#example').dataTable( {
11565                          *        "language": {
11566                          *          "infoPostFix": "All records shown are derived from real information."
11567                          *        }
11568                          *      } );
11569                          *    } );
11570                          */
11571                         "sInfoPostFix": "",
11572         
11573         
11574                         /**
11575                          * This decimal place operator is a little different from the other
11576                          * language options since DataTables doesn't output floating point
11577                          * numbers, so it won't ever use this for display of a number. Rather,
11578                          * what this parameter does is modify the sort methods of the table so
11579                          * that numbers which are in a format which has a character other than
11580                          * a period (`.`) as a decimal place will be sorted numerically.
11581                          *
11582                          * Note that numbers with different decimal places cannot be shown in
11583                          * the same table and still be sortable, the table must be consistent.
11584                          * However, multiple different tables on the page can use different
11585                          * decimal place characters.
11586                          *  @type string
11587                          *  @default 
11588                          *
11589                          *  @dtopt Language
11590                          *  @name DataTable.defaults.language.decimal
11591                          *
11592                          *  @example
11593                          *    $(document).ready( function() {
11594                          *      $('#example').dataTable( {
11595                          *        "language": {
11596                          *          "decimal": ","
11597                          *          "thousands": "."
11598                          *        }
11599                          *      } );
11600                          *    } );
11601                          */
11602                         "sDecimal": "",
11603         
11604         
11605                         /**
11606                          * DataTables has a build in number formatter (`formatNumber`) which is
11607                          * used to format large numbers that are used in the table information.
11608                          * By default a comma is used, but this can be trivially changed to any
11609                          * character you wish with this parameter.
11610                          *  @type string
11611                          *  @default ,
11612                          *
11613                          *  @dtopt Language
11614                          *  @name DataTable.defaults.language.thousands
11615                          *
11616                          *  @example
11617                          *    $(document).ready( function() {
11618                          *      $('#example').dataTable( {
11619                          *        "language": {
11620                          *          "thousands": "'"
11621                          *        }
11622                          *      } );
11623                          *    } );
11624                          */
11625                         "sThousands": ",",
11626         
11627         
11628                         /**
11629                          * Detail the action that will be taken when the drop down menu for the
11630                          * pagination length option is changed. The '_MENU_' variable is replaced
11631                          * with a default select list of 10, 25, 50 and 100, and can be replaced
11632                          * with a custom select box if required.
11633                          *  @type string
11634                          *  @default Show _MENU_ entries
11635                          *
11636                          *  @dtopt Language
11637                          *  @name DataTable.defaults.language.lengthMenu
11638                          *
11639                          *  @example
11640                          *    // Language change only
11641                          *    $(document).ready( function() {
11642                          *      $('#example').dataTable( {
11643                          *        "language": {
11644                          *          "lengthMenu": "Display _MENU_ records"
11645                          *        }
11646                          *      } );
11647                          *    } );
11648                          *
11649                          *  @example
11650                          *    // Language and options change
11651                          *    $(document).ready( function() {
11652                          *      $('#example').dataTable( {
11653                          *        "language": {
11654                          *          "lengthMenu": 'Display <select>'+
11655                          *            '<option value="10">10</option>'+
11656                          *            '<option value="20">20</option>'+
11657                          *            '<option value="30">30</option>'+
11658                          *            '<option value="40">40</option>'+
11659                          *            '<option value="50">50</option>'+
11660                          *            '<option value="-1">All</option>'+
11661                          *            '</select> records'
11662                          *        }
11663                          *      } );
11664                          *    } );
11665                          */
11666                         "sLengthMenu": "Show _MENU_ entries",
11667         
11668         
11669                         /**
11670                          * When using Ajax sourced data and during the first draw when DataTables is
11671                          * gathering the data, this message is shown in an empty row in the table to
11672                          * indicate to the end user the the data is being loaded. Note that this
11673                          * parameter is not used when loading data by server-side processing, just
11674                          * Ajax sourced data with client-side processing.
11675                          *  @type string
11676                          *  @default Loading...
11677                          *
11678                          *  @dtopt Language
11679                          *  @name DataTable.defaults.language.loadingRecords
11680                          *
11681                          *  @example
11682                          *    $(document).ready( function() {
11683                          *      $('#example').dataTable( {
11684                          *        "language": {
11685                          *          "loadingRecords": "Please wait - loading..."
11686                          *        }
11687                          *      } );
11688                          *    } );
11689                          */
11690                         "sLoadingRecords": "Loading...",
11691         
11692         
11693                         /**
11694                          * Text which is displayed when the table is processing a user action
11695                          * (usually a sort command or similar).
11696                          *  @type string
11697                          *  @default Processing...
11698                          *
11699                          *  @dtopt Language
11700                          *  @name DataTable.defaults.language.processing
11701                          *
11702                          *  @example
11703                          *    $(document).ready( function() {
11704                          *      $('#example').dataTable( {
11705                          *        "language": {
11706                          *          "processing": "DataTables is currently busy"
11707                          *        }
11708                          *      } );
11709                          *    } );
11710                          */
11711                         "sProcessing": "Processing...",
11712         
11713         
11714                         /**
11715                          * Details the actions that will be taken when the user types into the
11716                          * filtering input text box. The variable "_INPUT_", if used in the string,
11717                          * is replaced with the HTML text box for the filtering input allowing
11718                          * control over where it appears in the string. If "_INPUT_" is not given
11719                          * then the input box is appended to the string automatically.
11720                          *  @type string
11721                          *  @default Search:
11722                          *
11723                          *  @dtopt Language
11724                          *  @name DataTable.defaults.language.search
11725                          *
11726                          *  @example
11727                          *    // Input text box will be appended at the end automatically
11728                          *    $(document).ready( function() {
11729                          *      $('#example').dataTable( {
11730                          *        "language": {
11731                          *          "search": "Filter records:"
11732                          *        }
11733                          *      } );
11734                          *    } );
11735                          *
11736                          *  @example
11737                          *    // Specify where the filter should appear
11738                          *    $(document).ready( function() {
11739                          *      $('#example').dataTable( {
11740                          *        "language": {
11741                          *          "search": "Apply filter _INPUT_ to table"
11742                          *        }
11743                          *      } );
11744                          *    } );
11745                          */
11746                         "sSearch": "Search:",
11747         
11748         
11749                         /**
11750                          * Assign a `placeholder` attribute to the search `input` element
11751                          *  @type string
11752                          *  @default 
11753                          *
11754                          *  @dtopt Language
11755                          *  @name DataTable.defaults.language.searchPlaceholder
11756                          */
11757                         "sSearchPlaceholder": "",
11758         
11759         
11760                         /**
11761                          * All of the language information can be stored in a file on the
11762                          * server-side, which DataTables will look up if this parameter is passed.
11763                          * It must store the URL of the language file, which is in a JSON format,
11764                          * and the object has the same properties as the oLanguage object in the
11765                          * initialiser object (i.e. the above parameters). Please refer to one of
11766                          * the example language files to see how this works in action.
11767                          *  @type string
11768                          *  @default <i>Empty string - i.e. disabled</i>
11769                          *
11770                          *  @dtopt Language
11771                          *  @name DataTable.defaults.language.url
11772                          *
11773                          *  @example
11774                          *    $(document).ready( function() {
11775                          *      $('#example').dataTable( {
11776                          *        "language": {
11777                          *          "url": "http://www.sprymedia.co.uk/dataTables/lang.txt"
11778                          *        }
11779                          *      } );
11780                          *    } );
11781                          */
11782                         "sUrl": "",
11783         
11784         
11785                         /**
11786                          * Text shown inside the table records when the is no information to be
11787                          * displayed after filtering. `emptyTable` is shown when there is simply no
11788                          * information in the table at all (regardless of filtering).
11789                          *  @type string
11790                          *  @default No matching records found
11791                          *
11792                          *  @dtopt Language
11793                          *  @name DataTable.defaults.language.zeroRecords
11794                          *
11795                          *  @example
11796                          *    $(document).ready( function() {
11797                          *      $('#example').dataTable( {
11798                          *        "language": {
11799                          *          "zeroRecords": "No records to display"
11800                          *        }
11801                          *      } );
11802                          *    } );
11803                          */
11804                         "sZeroRecords": "No matching records found"
11805                 },
11806         
11807         
11808                 /**
11809                  * This parameter allows you to have define the global filtering state at
11810                  * initialisation time. As an object the `search` parameter must be
11811                  * defined, but all other parameters are optional. When `regex` is true,
11812                  * the search string will be treated as a regular expression, when false
11813                  * (default) it will be treated as a straight string. When `smart`
11814                  * DataTables will use it's smart filtering methods (to word match at
11815                  * any point in the data), when false this will not be done.
11816                  *  @namespace
11817                  *  @extends DataTable.models.oSearch
11818                  *
11819                  *  @dtopt Options
11820                  *  @name DataTable.defaults.search
11821                  *
11822                  *  @example
11823                  *    $(document).ready( function() {
11824                  *      $('#example').dataTable( {
11825                  *        "search": {"search": "Initial search"}
11826                  *      } );
11827                  *    } )
11828                  */
11829                 "oSearch": $.extend( {}, DataTable.models.oSearch ),
11830         
11831         
11832                 /**
11833                  * __Deprecated__ The functionality provided by this parameter has now been
11834                  * superseded by that provided through `ajax`, which should be used instead.
11835                  *
11836                  * By default DataTables will look for the property `data` (or `aaData` for
11837                  * compatibility with DataTables 1.9-) when obtaining data from an Ajax
11838                  * source or for server-side processing - this parameter allows that
11839                  * property to be changed. You can use Javascript dotted object notation to
11840                  * get a data source for multiple levels of nesting.
11841                  *  @type string
11842                  *  @default data
11843                  *
11844                  *  @dtopt Options
11845                  *  @dtopt Server-side
11846                  *  @name DataTable.defaults.ajaxDataProp
11847                  *
11848                  *  @deprecated 1.10. Please use `ajax` for this functionality now.
11849                  */
11850                 "sAjaxDataProp": "data",
11851         
11852         
11853                 /**
11854                  * __Deprecated__ The functionality provided by this parameter has now been
11855                  * superseded by that provided through `ajax`, which should be used instead.
11856                  *
11857                  * You can instruct DataTables to load data from an external
11858                  * source using this parameter (use aData if you want to pass data in you
11859                  * already have). Simply provide a url a JSON object can be obtained from.
11860                  *  @type string
11861                  *  @default null
11862                  *
11863                  *  @dtopt Options
11864                  *  @dtopt Server-side
11865                  *  @name DataTable.defaults.ajaxSource
11866                  *
11867                  *  @deprecated 1.10. Please use `ajax` for this functionality now.
11868                  */
11869                 "sAjaxSource": null,
11870         
11871         
11872                 /**
11873                  * This initialisation variable allows you to specify exactly where in the
11874                  * DOM you want DataTables to inject the various controls it adds to the page
11875                  * (for example you might want the pagination controls at the top of the
11876                  * table). DIV elements (with or without a custom class) can also be added to
11877                  * aid styling. The follow syntax is used:
11878                  *   <ul>
11879                  *     <li>The following options are allowed:
11880                  *       <ul>
11881                  *         <li>'l' - Length changing</li>
11882                  *         <li>'f' - Filtering input</li>
11883                  *         <li>'t' - The table!</li>
11884                  *         <li>'i' - Information</li>
11885                  *         <li>'p' - Pagination</li>
11886                  *         <li>'r' - pRocessing</li>
11887                  *       </ul>
11888                  *     </li>
11889                  *     <li>The following constants are allowed:
11890                  *       <ul>
11891                  *         <li>'H' - jQueryUI theme "header" classes ('fg-toolbar ui-widget-header ui-corner-tl ui-corner-tr ui-helper-clearfix')</li>
11892                  *         <li>'F' - jQueryUI theme "footer" classes ('fg-toolbar ui-widget-header ui-corner-bl ui-corner-br ui-helper-clearfix')</li>
11893                  *       </ul>
11894                  *     </li>
11895                  *     <li>The following syntax is expected:
11896                  *       <ul>
11897                  *         <li>'&lt;' and '&gt;' - div elements</li>
11898                  *         <li>'&lt;"class" and '&gt;' - div with a class</li>
11899                  *         <li>'&lt;"#id" and '&gt;' - div with an ID</li>
11900                  *       </ul>
11901                  *     </li>
11902                  *     <li>Examples:
11903                  *       <ul>
11904                  *         <li>'&lt;"wrapper"flipt&gt;'</li>
11905                  *         <li>'&lt;lf&lt;t&gt;ip&gt;'</li>
11906                  *       </ul>
11907                  *     </li>
11908                  *   </ul>
11909                  *  @type string
11910                  *  @default lfrtip <i>(when `jQueryUI` is false)</i> <b>or</b>
11911                  *    <"H"lfr>t<"F"ip> <i>(when `jQueryUI` is true)</i>
11912                  *
11913                  *  @dtopt Options
11914                  *  @name DataTable.defaults.dom
11915                  *
11916                  *  @example
11917                  *    $(document).ready( function() {
11918                  *      $('#example').dataTable( {
11919                  *        "dom": '&lt;"top"i&gt;rt&lt;"bottom"flp&gt;&lt;"clear"&gt;'
11920                  *      } );
11921                  *    } );
11922                  */
11923                 "sDom": "lfrtip",
11924         
11925         
11926                 /**
11927                  * Search delay option. This will throttle full table searches that use the
11928                  * DataTables provided search input element (it does not effect calls to
11929                  * `dt-api search()`, providing a delay before the search is made.
11930                  *  @type integer
11931                  *  @default 0
11932                  *
11933                  *  @dtopt Options
11934                  *  @name DataTable.defaults.searchDelay
11935                  *
11936                  *  @example
11937                  *    $(document).ready( function() {
11938                  *      $('#example').dataTable( {
11939                  *        "searchDelay": 200
11940                  *      } );
11941                  *    } )
11942                  */
11943                 "searchDelay": null,
11944         
11945         
11946                 /**
11947                  * DataTables features six different built-in options for the buttons to
11948                  * display for pagination control:
11949                  *
11950                  * * `numbers` - Page number buttons only
11951                  * * `simple` - 'Previous' and 'Next' buttons only
11952                  * * 'simple_numbers` - 'Previous' and 'Next' buttons, plus page numbers
11953                  * * `full` - 'First', 'Previous', 'Next' and 'Last' buttons
11954                  * * `full_numbers` - 'First', 'Previous', 'Next' and 'Last' buttons, plus page numbers
11955                  * * `first_last_numbers` - 'First' and 'Last' buttons, plus page numbers
11956                  *  
11957                  * Further methods can be added using {@link DataTable.ext.oPagination}.
11958                  *  @type string
11959                  *  @default simple_numbers
11960                  *
11961                  *  @dtopt Options
11962                  *  @name DataTable.defaults.pagingType
11963                  *
11964                  *  @example
11965                  *    $(document).ready( function() {
11966                  *      $('#example').dataTable( {
11967                  *        "pagingType": "full_numbers"
11968                  *      } );
11969                  *    } )
11970                  */
11971                 "sPaginationType": "simple_numbers",
11972         
11973         
11974                 /**
11975                  * Enable horizontal scrolling. When a table is too wide to fit into a
11976                  * certain layout, or you have a large number of columns in the table, you
11977                  * can enable x-scrolling to show the table in a viewport, which can be
11978                  * scrolled. This property can be `true` which will allow the table to
11979                  * scroll horizontally when needed, or any CSS unit, or a number (in which
11980                  * case it will be treated as a pixel measurement). Setting as simply `true`
11981                  * is recommended.
11982                  *  @type boolean|string
11983                  *  @default <i>blank string - i.e. disabled</i>
11984                  *
11985                  *  @dtopt Features
11986                  *  @name DataTable.defaults.scrollX
11987                  *
11988                  *  @example
11989                  *    $(document).ready( function() {
11990                  *      $('#example').dataTable( {
11991                  *        "scrollX": true,
11992                  *        "scrollCollapse": true
11993                  *      } );
11994                  *    } );
11995                  */
11996                 "sScrollX": "",
11997         
11998         
11999                 /**
12000                  * This property can be used to force a DataTable to use more width than it
12001                  * might otherwise do when x-scrolling is enabled. For example if you have a
12002                  * table which requires to be well spaced, this parameter is useful for
12003                  * "over-sizing" the table, and thus forcing scrolling. This property can by
12004                  * any CSS unit, or a number (in which case it will be treated as a pixel
12005                  * measurement).
12006                  *  @type string
12007                  *  @default <i>blank string - i.e. disabled</i>
12008                  *
12009                  *  @dtopt Options
12010                  *  @name DataTable.defaults.scrollXInner
12011                  *
12012                  *  @example
12013                  *    $(document).ready( function() {
12014                  *      $('#example').dataTable( {
12015                  *        "scrollX": "100%",
12016                  *        "scrollXInner": "110%"
12017                  *      } );
12018                  *    } );
12019                  */
12020                 "sScrollXInner": "",
12021         
12022         
12023                 /**
12024                  * Enable vertical scrolling. Vertical scrolling will constrain the DataTable
12025                  * to the given height, and enable scrolling for any data which overflows the
12026                  * current viewport. This can be used as an alternative to paging to display
12027                  * a lot of data in a small area (although paging and scrolling can both be
12028                  * enabled at the same time). This property can be any CSS unit, or a number
12029                  * (in which case it will be treated as a pixel measurement).
12030                  *  @type string
12031                  *  @default <i>blank string - i.e. disabled</i>
12032                  *
12033                  *  @dtopt Features
12034                  *  @name DataTable.defaults.scrollY
12035                  *
12036                  *  @example
12037                  *    $(document).ready( function() {
12038                  *      $('#example').dataTable( {
12039                  *        "scrollY": "200px",
12040                  *        "paginate": false
12041                  *      } );
12042                  *    } );
12043                  */
12044                 "sScrollY": "",
12045         
12046         
12047                 /**
12048                  * __Deprecated__ The functionality provided by this parameter has now been
12049                  * superseded by that provided through `ajax`, which should be used instead.
12050                  *
12051                  * Set the HTTP method that is used to make the Ajax call for server-side
12052                  * processing or Ajax sourced data.
12053                  *  @type string
12054                  *  @default GET
12055                  *
12056                  *  @dtopt Options
12057                  *  @dtopt Server-side
12058                  *  @name DataTable.defaults.serverMethod
12059                  *
12060                  *  @deprecated 1.10. Please use `ajax` for this functionality now.
12061                  */
12062                 "sServerMethod": "GET",
12063         
12064         
12065                 /**
12066                  * DataTables makes use of renderers when displaying HTML elements for
12067                  * a table. These renderers can be added or modified by plug-ins to
12068                  * generate suitable mark-up for a site. For example the Bootstrap
12069                  * integration plug-in for DataTables uses a paging button renderer to
12070                  * display pagination buttons in the mark-up required by Bootstrap.
12071                  *
12072                  * For further information about the renderers available see
12073                  * DataTable.ext.renderer
12074                  *  @type string|object
12075                  *  @default null
12076                  *
12077                  *  @name DataTable.defaults.renderer
12078                  *
12079                  */
12080                 "renderer": null,
12081         
12082         
12083                 /**
12084                  * Set the data property name that DataTables should use to get a row's id
12085                  * to set as the `id` property in the node.
12086                  *  @type string
12087                  *  @default DT_RowId
12088                  *
12089                  *  @name DataTable.defaults.rowId
12090                  */
12091                 "rowId": "DT_RowId"
12092         };
12093         
12094         _fnHungarianMap( DataTable.defaults );
12095         
12096         
12097         
12098         /*
12099          * Developer note - See note in model.defaults.js about the use of Hungarian
12100          * notation and camel case.
12101          */
12102         
12103         /**
12104          * Column options that can be given to DataTables at initialisation time.
12105          *  @namespace
12106          */
12107         DataTable.defaults.column = {
12108                 /**
12109                  * Define which column(s) an order will occur on for this column. This
12110                  * allows a column's ordering to take multiple columns into account when
12111                  * doing a sort or use the data from a different column. For example first
12112                  * name / last name columns make sense to do a multi-column sort over the
12113                  * two columns.
12114                  *  @type array|int
12115                  *  @default null <i>Takes the value of the column index automatically</i>
12116                  *
12117                  *  @name DataTable.defaults.column.orderData
12118                  *  @dtopt Columns
12119                  *
12120                  *  @example
12121                  *    // Using `columnDefs`
12122                  *    $(document).ready( function() {
12123                  *      $('#example').dataTable( {
12124                  *        "columnDefs": [
12125                  *          { "orderData": [ 0, 1 ], "targets": [ 0 ] },
12126                  *          { "orderData": [ 1, 0 ], "targets": [ 1 ] },
12127                  *          { "orderData": 2, "targets": [ 2 ] }
12128                  *        ]
12129                  *      } );
12130                  *    } );
12131                  *
12132                  *  @example
12133                  *    // Using `columns`
12134                  *    $(document).ready( function() {
12135                  *      $('#example').dataTable( {
12136                  *        "columns": [
12137                  *          { "orderData": [ 0, 1 ] },
12138                  *          { "orderData": [ 1, 0 ] },
12139                  *          { "orderData": 2 },
12140                  *          null,
12141                  *          null
12142                  *        ]
12143                  *      } );
12144                  *    } );
12145                  */
12146                 "aDataSort": null,
12147                 "iDataSort": -1,
12148         
12149         
12150                 /**
12151                  * You can control the default ordering direction, and even alter the
12152                  * behaviour of the sort handler (i.e. only allow ascending ordering etc)
12153                  * using this parameter.
12154                  *  @type array
12155                  *  @default [ 'asc', 'desc' ]
12156                  *
12157                  *  @name DataTable.defaults.column.orderSequence
12158                  *  @dtopt Columns
12159                  *
12160                  *  @example
12161                  *    // Using `columnDefs`
12162                  *    $(document).ready( function() {
12163                  *      $('#example').dataTable( {
12164                  *        "columnDefs": [
12165                  *          { "orderSequence": [ "asc" ], "targets": [ 1 ] },
12166                  *          { "orderSequence": [ "desc", "asc", "asc" ], "targets": [ 2 ] },
12167                  *          { "orderSequence": [ "desc" ], "targets": [ 3 ] }
12168                  *        ]
12169                  *      } );
12170                  *    } );
12171                  *
12172                  *  @example
12173                  *    // Using `columns`
12174                  *    $(document).ready( function() {
12175                  *      $('#example').dataTable( {
12176                  *        "columns": [
12177                  *          null,
12178                  *          { "orderSequence": [ "asc" ] },
12179                  *          { "orderSequence": [ "desc", "asc", "asc" ] },
12180                  *          { "orderSequence": [ "desc" ] },
12181                  *          null
12182                  *        ]
12183                  *      } );
12184                  *    } );
12185                  */
12186                 "asSorting": [ 'asc', 'desc' ],
12187         
12188         
12189                 /**
12190                  * Enable or disable filtering on the data in this column.
12191                  *  @type boolean
12192                  *  @default true
12193                  *
12194                  *  @name DataTable.defaults.column.searchable
12195                  *  @dtopt Columns
12196                  *
12197                  *  @example
12198                  *    // Using `columnDefs`
12199                  *    $(document).ready( function() {
12200                  *      $('#example').dataTable( {
12201                  *        "columnDefs": [
12202                  *          { "searchable": false, "targets": [ 0 ] }
12203                  *        ] } );
12204                  *    } );
12205                  *
12206                  *  @example
12207                  *    // Using `columns`
12208                  *    $(document).ready( function() {
12209                  *      $('#example').dataTable( {
12210                  *        "columns": [
12211                  *          { "searchable": false },
12212                  *          null,
12213                  *          null,
12214                  *          null,
12215                  *          null
12216                  *        ] } );
12217                  *    } );
12218                  */
12219                 "bSearchable": true,
12220         
12221         
12222                 /**
12223                  * Enable or disable ordering on this column.
12224                  *  @type boolean
12225                  *  @default true
12226                  *
12227                  *  @name DataTable.defaults.column.orderable
12228                  *  @dtopt Columns
12229                  *
12230                  *  @example
12231                  *    // Using `columnDefs`
12232                  *    $(document).ready( function() {
12233                  *      $('#example').dataTable( {
12234                  *        "columnDefs": [
12235                  *          { "orderable": false, "targets": [ 0 ] }
12236                  *        ] } );
12237                  *    } );
12238                  *
12239                  *  @example
12240                  *    // Using `columns`
12241                  *    $(document).ready( function() {
12242                  *      $('#example').dataTable( {
12243                  *        "columns": [
12244                  *          { "orderable": false },
12245                  *          null,
12246                  *          null,
12247                  *          null,
12248                  *          null
12249                  *        ] } );
12250                  *    } );
12251                  */
12252                 "bSortable": true,
12253         
12254         
12255                 /**
12256                  * Enable or disable the display of this column.
12257                  *  @type boolean
12258                  *  @default true
12259                  *
12260                  *  @name DataTable.defaults.column.visible
12261                  *  @dtopt Columns
12262                  *
12263                  *  @example
12264                  *    // Using `columnDefs`
12265                  *    $(document).ready( function() {
12266                  *      $('#example').dataTable( {
12267                  *        "columnDefs": [
12268                  *          { "visible": false, "targets": [ 0 ] }
12269                  *        ] } );
12270                  *    } );
12271                  *
12272                  *  @example
12273                  *    // Using `columns`
12274                  *    $(document).ready( function() {
12275                  *      $('#example').dataTable( {
12276                  *        "columns": [
12277                  *          { "visible": false },
12278                  *          null,
12279                  *          null,
12280                  *          null,
12281                  *          null
12282                  *        ] } );
12283                  *    } );
12284                  */
12285                 "bVisible": true,
12286         
12287         
12288                 /**
12289                  * Developer definable function that is called whenever a cell is created (Ajax source,
12290                  * etc) or processed for input (DOM source). This can be used as a compliment to mRender
12291                  * allowing you to modify the DOM element (add background colour for example) when the
12292                  * element is available.
12293                  *  @type function
12294                  *  @param {element} td The TD node that has been created
12295                  *  @param {*} cellData The Data for the cell
12296                  *  @param {array|object} rowData The data for the whole row
12297                  *  @param {int} row The row index for the aoData data store
12298                  *  @param {int} col The column index for aoColumns
12299                  *
12300                  *  @name DataTable.defaults.column.createdCell
12301                  *  @dtopt Columns
12302                  *
12303                  *  @example
12304                  *    $(document).ready( function() {
12305                  *      $('#example').dataTable( {
12306                  *        "columnDefs": [ {
12307                  *          "targets": [3],
12308                  *          "createdCell": function (td, cellData, rowData, row, col) {
12309                  *            if ( cellData == "1.7" ) {
12310                  *              $(td).css('color', 'blue')
12311                  *            }
12312                  *          }
12313                  *        } ]
12314                  *      });
12315                  *    } );
12316                  */
12317                 "fnCreatedCell": null,
12318         
12319         
12320                 /**
12321                  * This parameter has been replaced by `data` in DataTables to ensure naming
12322                  * consistency. `dataProp` can still be used, as there is backwards
12323                  * compatibility in DataTables for this option, but it is strongly
12324                  * recommended that you use `data` in preference to `dataProp`.
12325                  *  @name DataTable.defaults.column.dataProp
12326                  */
12327         
12328         
12329                 /**
12330                  * This property can be used to read data from any data source property,
12331                  * including deeply nested objects / properties. `data` can be given in a
12332                  * number of different ways which effect its behaviour:
12333                  *
12334                  * * `integer` - treated as an array index for the data source. This is the
12335                  *   default that DataTables uses (incrementally increased for each column).
12336                  * * `string` - read an object property from the data source. There are
12337                  *   three 'special' options that can be used in the string to alter how
12338                  *   DataTables reads the data from the source object:
12339                  *    * `.` - Dotted Javascript notation. Just as you use a `.` in
12340                  *      Javascript to read from nested objects, so to can the options
12341                  *      specified in `data`. For example: `browser.version` or
12342                  *      `browser.name`. If your object parameter name contains a period, use
12343                  *      `\\` to escape it - i.e. `first\\.name`.
12344                  *    * `[]` - Array notation. DataTables can automatically combine data
12345                  *      from and array source, joining the data with the characters provided
12346                  *      between the two brackets. For example: `name[, ]` would provide a
12347                  *      comma-space separated list from the source array. If no characters
12348                  *      are provided between the brackets, the original array source is
12349                  *      returned.
12350                  *    * `()` - Function notation. Adding `()` to the end of a parameter will
12351                  *      execute a function of the name given. For example: `browser()` for a
12352                  *      simple function on the data source, `browser.version()` for a
12353                  *      function in a nested property or even `browser().version` to get an
12354                  *      object property if the function called returns an object. Note that
12355                  *      function notation is recommended for use in `render` rather than
12356                  *      `data` as it is much simpler to use as a renderer.
12357                  * * `null` - use the original data source for the row rather than plucking
12358                  *   data directly from it. This action has effects on two other
12359                  *   initialisation options:
12360                  *    * `defaultContent` - When null is given as the `data` option and
12361                  *      `defaultContent` is specified for the column, the value defined by
12362                  *      `defaultContent` will be used for the cell.
12363                  *    * `render` - When null is used for the `data` option and the `render`
12364                  *      option is specified for the column, the whole data source for the
12365                  *      row is used for the renderer.
12366                  * * `function` - the function given will be executed whenever DataTables
12367                  *   needs to set or get the data for a cell in the column. The function
12368                  *   takes three parameters:
12369                  *    * Parameters:
12370                  *      * `{array|object}` The data source for the row
12371                  *      * `{string}` The type call data requested - this will be 'set' when
12372                  *        setting data or 'filter', 'display', 'type', 'sort' or undefined
12373                  *        when gathering data. Note that when `undefined` is given for the
12374                  *        type DataTables expects to get the raw data for the object back<
12375                  *      * `{*}` Data to set when the second parameter is 'set'.
12376                  *    * Return:
12377                  *      * The return value from the function is not required when 'set' is
12378                  *        the type of call, but otherwise the return is what will be used
12379                  *        for the data requested.
12380                  *
12381                  * Note that `data` is a getter and setter option. If you just require
12382                  * formatting of data for output, you will likely want to use `render` which
12383                  * is simply a getter and thus simpler to use.
12384                  *
12385                  * Note that prior to DataTables 1.9.2 `data` was called `mDataProp`. The
12386                  * name change reflects the flexibility of this property and is consistent
12387                  * with the naming of mRender. If 'mDataProp' is given, then it will still
12388                  * be used by DataTables, as it automatically maps the old name to the new
12389                  * if required.
12390                  *
12391                  *  @type string|int|function|null
12392                  *  @default null <i>Use automatically calculated column index</i>
12393                  *
12394                  *  @name DataTable.defaults.column.data
12395                  *  @dtopt Columns
12396                  *
12397                  *  @example
12398                  *    // Read table data from objects
12399                  *    // JSON structure for each row:
12400                  *    //   {
12401                  *    //      "engine": {value},
12402                  *    //      "browser": {value},
12403                  *    //      "platform": {value},
12404                  *    //      "version": {value},
12405                  *    //      "grade": {value}
12406                  *    //   }
12407                  *    $(document).ready( function() {
12408                  *      $('#example').dataTable( {
12409                  *        "ajaxSource": "sources/objects.txt",
12410                  *        "columns": [
12411                  *          { "data": "engine" },
12412                  *          { "data": "browser" },
12413                  *          { "data": "platform" },
12414                  *          { "data": "version" },
12415                  *          { "data": "grade" }
12416                  *        ]
12417                  *      } );
12418                  *    } );
12419                  *
12420                  *  @example
12421                  *    // Read information from deeply nested objects
12422                  *    // JSON structure for each row:
12423                  *    //   {
12424                  *    //      "engine": {value},
12425                  *    //      "browser": {value},
12426                  *    //      "platform": {
12427                  *    //         "inner": {value}
12428                  *    //      },
12429                  *    //      "details": [
12430                  *    //         {value}, {value}
12431                  *    //      ]
12432                  *    //   }
12433                  *    $(document).ready( function() {
12434                  *      $('#example').dataTable( {
12435                  *        "ajaxSource": "sources/deep.txt",
12436                  *        "columns": [
12437                  *          { "data": "engine" },
12438                  *          { "data": "browser" },
12439                  *          { "data": "platform.inner" },
12440                  *          { "data": "details.0" },
12441                  *          { "data": "details.1" }
12442                  *        ]
12443                  *      } );
12444                  *    } );
12445                  *
12446                  *  @example
12447                  *    // Using `data` as a function to provide different information for
12448                  *    // sorting, filtering and display. In this case, currency (price)
12449                  *    $(document).ready( function() {
12450                  *      $('#example').dataTable( {
12451                  *        "columnDefs": [ {
12452                  *          "targets": [ 0 ],
12453                  *          "data": function ( source, type, val ) {
12454                  *            if (type === 'set') {
12455                  *              source.price = val;
12456                  *              // Store the computed dislay and filter values for efficiency
12457                  *              source.price_display = val=="" ? "" : "$"+numberFormat(val);
12458                  *              source.price_filter  = val=="" ? "" : "$"+numberFormat(val)+" "+val;
12459                  *              return;
12460                  *            }
12461                  *            else if (type === 'display') {
12462                  *              return source.price_display;
12463                  *            }
12464                  *            else if (type === 'filter') {
12465                  *              return source.price_filter;
12466                  *            }
12467                  *            // 'sort', 'type' and undefined all just use the integer
12468                  *            return source.price;
12469                  *          }
12470                  *        } ]
12471                  *      } );
12472                  *    } );
12473                  *
12474                  *  @example
12475                  *    // Using default content
12476                  *    $(document).ready( function() {
12477                  *      $('#example').dataTable( {
12478                  *        "columnDefs": [ {
12479                  *          "targets": [ 0 ],
12480                  *          "data": null,
12481                  *          "defaultContent": "Click to edit"
12482                  *        } ]
12483                  *      } );
12484                  *    } );
12485                  *
12486                  *  @example
12487                  *    // Using array notation - outputting a list from an array
12488                  *    $(document).ready( function() {
12489                  *      $('#example').dataTable( {
12490                  *        "columnDefs": [ {
12491                  *          "targets": [ 0 ],
12492                  *          "data": "name[, ]"
12493                  *        } ]
12494                  *      } );
12495                  *    } );
12496                  *
12497                  */
12498                 "mData": null,
12499         
12500         
12501                 /**
12502                  * This property is the rendering partner to `data` and it is suggested that
12503                  * when you want to manipulate data for display (including filtering,
12504                  * sorting etc) without altering the underlying data for the table, use this
12505                  * property. `render` can be considered to be the the read only companion to
12506                  * `data` which is read / write (then as such more complex). Like `data`
12507                  * this option can be given in a number of different ways to effect its
12508                  * behaviour:
12509                  *
12510                  * * `integer` - treated as an array index for the data source. This is the
12511                  *   default that DataTables uses (incrementally increased for each column).
12512                  * * `string` - read an object property from the data source. There are
12513                  *   three 'special' options that can be used in the string to alter how
12514                  *   DataTables reads the data from the source object:
12515                  *    * `.` - Dotted Javascript notation. Just as you use a `.` in
12516                  *      Javascript to read from nested objects, so to can the options
12517                  *      specified in `data`. For example: `browser.version` or
12518                  *      `browser.name`. If your object parameter name contains a period, use
12519                  *      `\\` to escape it - i.e. `first\\.name`.
12520                  *    * `[]` - Array notation. DataTables can automatically combine data
12521                  *      from and array source, joining the data with the characters provided
12522                  *      between the two brackets. For example: `name[, ]` would provide a
12523                  *      comma-space separated list from the source array. If no characters
12524                  *      are provided between the brackets, the original array source is
12525                  *      returned.
12526                  *    * `()` - Function notation. Adding `()` to the end of a parameter will
12527                  *      execute a function of the name given. For example: `browser()` for a
12528                  *      simple function on the data source, `browser.version()` for a
12529                  *      function in a nested property or even `browser().version` to get an
12530                  *      object property if the function called returns an object.
12531                  * * `object` - use different data for the different data types requested by
12532                  *   DataTables ('filter', 'display', 'type' or 'sort'). The property names
12533                  *   of the object is the data type the property refers to and the value can
12534                  *   defined using an integer, string or function using the same rules as
12535                  *   `render` normally does. Note that an `_` option _must_ be specified.
12536                  *   This is the default value to use if you haven't specified a value for
12537                  *   the data type requested by DataTables.
12538                  * * `function` - the function given will be executed whenever DataTables
12539                  *   needs to set or get the data for a cell in the column. The function
12540                  *   takes three parameters:
12541                  *    * Parameters:
12542                  *      * {array|object} The data source for the row (based on `data`)
12543                  *      * {string} The type call data requested - this will be 'filter',
12544                  *        'display', 'type' or 'sort'.
12545                  *      * {array|object} The full data source for the row (not based on
12546                  *        `data`)
12547                  *    * Return:
12548                  *      * The return value from the function is what will be used for the
12549                  *        data requested.
12550                  *
12551                  *  @type string|int|function|object|null
12552                  *  @default null Use the data source value.
12553                  *
12554                  *  @name DataTable.defaults.column.render
12555                  *  @dtopt Columns
12556                  *
12557                  *  @example
12558                  *    // Create a comma separated list from an array of objects
12559                  *    $(document).ready( function() {
12560                  *      $('#example').dataTable( {
12561                  *        "ajaxSource": "sources/deep.txt",
12562                  *        "columns": [
12563                  *          { "data": "engine" },
12564                  *          { "data": "browser" },
12565                  *          {
12566                  *            "data": "platform",
12567                  *            "render": "[, ].name"
12568                  *          }
12569                  *        ]
12570                  *      } );
12571                  *    } );
12572                  *
12573                  *  @example
12574                  *    // Execute a function to obtain data
12575                  *    $(document).ready( function() {
12576                  *      $('#example').dataTable( {
12577                  *        "columnDefs": [ {
12578                  *          "targets": [ 0 ],
12579                  *          "data": null, // Use the full data source object for the renderer's source
12580                  *          "render": "browserName()"
12581                  *        } ]
12582                  *      } );
12583                  *    } );
12584                  *
12585                  *  @example
12586                  *    // As an object, extracting different data for the different types
12587                  *    // This would be used with a data source such as:
12588                  *    //   { "phone": 5552368, "phone_filter": "5552368 555-2368", "phone_display": "555-2368" }
12589                  *    // Here the `phone` integer is used for sorting and type detection, while `phone_filter`
12590                  *    // (which has both forms) is used for filtering for if a user inputs either format, while
12591                  *    // the formatted phone number is the one that is shown in the table.
12592                  *    $(document).ready( function() {
12593                  *      $('#example').dataTable( {
12594                  *        "columnDefs": [ {
12595                  *          "targets": [ 0 ],
12596                  *          "data": null, // Use the full data source object for the renderer's source
12597                  *          "render": {
12598                  *            "_": "phone",
12599                  *            "filter": "phone_filter",
12600                  *            "display": "phone_display"
12601                  *          }
12602                  *        } ]
12603                  *      } );
12604                  *    } );
12605                  *
12606                  *  @example
12607                  *    // Use as a function to create a link from the data source
12608                  *    $(document).ready( function() {
12609                  *      $('#example').dataTable( {
12610                  *        "columnDefs": [ {
12611                  *          "targets": [ 0 ],
12612                  *          "data": "download_link",
12613                  *          "render": function ( data, type, full ) {
12614                  *            return '<a href="'+data+'">Download</a>';
12615                  *          }
12616                  *        } ]
12617                  *      } );
12618                  *    } );
12619                  */
12620                 "mRender": null,
12621         
12622         
12623                 /**
12624                  * Change the cell type created for the column - either TD cells or TH cells. This
12625                  * can be useful as TH cells have semantic meaning in the table body, allowing them
12626                  * to act as a header for a row (you may wish to add scope='row' to the TH elements).
12627                  *  @type string
12628                  *  @default td
12629                  *
12630                  *  @name DataTable.defaults.column.cellType
12631                  *  @dtopt Columns
12632                  *
12633                  *  @example
12634                  *    // Make the first column use TH cells
12635                  *    $(document).ready( function() {
12636                  *      $('#example').dataTable( {
12637                  *        "columnDefs": [ {
12638                  *          "targets": [ 0 ],
12639                  *          "cellType": "th"
12640                  *        } ]
12641                  *      } );
12642                  *    } );
12643                  */
12644                 "sCellType": "td",
12645         
12646         
12647                 /**
12648                  * Class to give to each cell in this column.
12649                  *  @type string
12650                  *  @default <i>Empty string</i>
12651                  *
12652                  *  @name DataTable.defaults.column.class
12653                  *  @dtopt Columns
12654                  *
12655                  *  @example
12656                  *    // Using `columnDefs`
12657                  *    $(document).ready( function() {
12658                  *      $('#example').dataTable( {
12659                  *        "columnDefs": [
12660                  *          { "class": "my_class", "targets": [ 0 ] }
12661                  *        ]
12662                  *      } );
12663                  *    } );
12664                  *
12665                  *  @example
12666                  *    // Using `columns`
12667                  *    $(document).ready( function() {
12668                  *      $('#example').dataTable( {
12669                  *        "columns": [
12670                  *          { "class": "my_class" },
12671                  *          null,
12672                  *          null,
12673                  *          null,
12674                  *          null
12675                  *        ]
12676                  *      } );
12677                  *    } );
12678                  */
12679                 "sClass": "",
12680         
12681                 /**
12682                  * When DataTables calculates the column widths to assign to each column,
12683                  * it finds the longest string in each column and then constructs a
12684                  * temporary table and reads the widths from that. The problem with this
12685                  * is that "mmm" is much wider then "iiii", but the latter is a longer
12686                  * string - thus the calculation can go wrong (doing it properly and putting
12687                  * it into an DOM object and measuring that is horribly(!) slow). Thus as
12688                  * a "work around" we provide this option. It will append its value to the
12689                  * text that is found to be the longest string for the column - i.e. padding.
12690                  * Generally you shouldn't need this!
12691                  *  @type string
12692                  *  @default <i>Empty string<i>
12693                  *
12694                  *  @name DataTable.defaults.column.contentPadding
12695                  *  @dtopt Columns
12696                  *
12697                  *  @example
12698                  *    // Using `columns`
12699                  *    $(document).ready( function() {
12700                  *      $('#example').dataTable( {
12701                  *        "columns": [
12702                  *          null,
12703                  *          null,
12704                  *          null,
12705                  *          {
12706                  *            "contentPadding": "mmm"
12707                  *          }
12708                  *        ]
12709                  *      } );
12710                  *    } );
12711                  */
12712                 "sContentPadding": "",
12713         
12714         
12715                 /**
12716                  * Allows a default value to be given for a column's data, and will be used
12717                  * whenever a null data source is encountered (this can be because `data`
12718                  * is set to null, or because the data source itself is null).
12719                  *  @type string
12720                  *  @default null
12721                  *
12722                  *  @name DataTable.defaults.column.defaultContent
12723                  *  @dtopt Columns
12724                  *
12725                  *  @example
12726                  *    // Using `columnDefs`
12727                  *    $(document).ready( function() {
12728                  *      $('#example').dataTable( {
12729                  *        "columnDefs": [
12730                  *          {
12731                  *            "data": null,
12732                  *            "defaultContent": "Edit",
12733                  *            "targets": [ -1 ]
12734                  *          }
12735                  *        ]
12736                  *      } );
12737                  *    } );
12738                  *
12739                  *  @example
12740                  *    // Using `columns`
12741                  *    $(document).ready( function() {
12742                  *      $('#example').dataTable( {
12743                  *        "columns": [
12744                  *          null,
12745                  *          null,
12746                  *          null,
12747                  *          {
12748                  *            "data": null,
12749                  *            "defaultContent": "Edit"
12750                  *          }
12751                  *        ]
12752                  *      } );
12753                  *    } );
12754                  */
12755                 "sDefaultContent": null,
12756         
12757         
12758                 /**
12759                  * This parameter is only used in DataTables' server-side processing. It can
12760                  * be exceptionally useful to know what columns are being displayed on the
12761                  * client side, and to map these to database fields. When defined, the names
12762                  * also allow DataTables to reorder information from the server if it comes
12763                  * back in an unexpected order (i.e. if you switch your columns around on the
12764                  * client-side, your server-side code does not also need updating).
12765                  *  @type string
12766                  *  @default <i>Empty string</i>
12767                  *
12768                  *  @name DataTable.defaults.column.name
12769                  *  @dtopt Columns
12770                  *
12771                  *  @example
12772                  *    // Using `columnDefs`
12773                  *    $(document).ready( function() {
12774                  *      $('#example').dataTable( {
12775                  *        "columnDefs": [
12776                  *          { "name": "engine", "targets": [ 0 ] },
12777                  *          { "name": "browser", "targets": [ 1 ] },
12778                  *          { "name": "platform", "targets": [ 2 ] },
12779                  *          { "name": "version", "targets": [ 3 ] },
12780                  *          { "name": "grade", "targets": [ 4 ] }
12781                  *        ]
12782                  *      } );
12783                  *    } );
12784                  *
12785                  *  @example
12786                  *    // Using `columns`
12787                  *    $(document).ready( function() {
12788                  *      $('#example').dataTable( {
12789                  *        "columns": [
12790                  *          { "name": "engine" },
12791                  *          { "name": "browser" },
12792                  *          { "name": "platform" },
12793                  *          { "name": "version" },
12794                  *          { "name": "grade" }
12795                  *        ]
12796                  *      } );
12797                  *    } );
12798                  */
12799                 "sName": "",
12800         
12801         
12802                 /**
12803                  * Defines a data source type for the ordering which can be used to read
12804                  * real-time information from the table (updating the internally cached
12805                  * version) prior to ordering. This allows ordering to occur on user
12806                  * editable elements such as form inputs.
12807                  *  @type string
12808                  *  @default std
12809                  *
12810                  *  @name DataTable.defaults.column.orderDataType
12811                  *  @dtopt Columns
12812                  *
12813                  *  @example
12814                  *    // Using `columnDefs`
12815                  *    $(document).ready( function() {
12816                  *      $('#example').dataTable( {
12817                  *        "columnDefs": [
12818                  *          { "orderDataType": "dom-text", "targets": [ 2, 3 ] },
12819                  *          { "type": "numeric", "targets": [ 3 ] },
12820                  *          { "orderDataType": "dom-select", "targets": [ 4 ] },
12821                  *          { "orderDataType": "dom-checkbox", "targets": [ 5 ] }
12822                  *        ]
12823                  *      } );
12824                  *    } );
12825                  *
12826                  *  @example
12827                  *    // Using `columns`
12828                  *    $(document).ready( function() {
12829                  *      $('#example').dataTable( {
12830                  *        "columns": [
12831                  *          null,
12832                  *          null,
12833                  *          { "orderDataType": "dom-text" },
12834                  *          { "orderDataType": "dom-text", "type": "numeric" },
12835                  *          { "orderDataType": "dom-select" },
12836                  *          { "orderDataType": "dom-checkbox" }
12837                  *        ]
12838                  *      } );
12839                  *    } );
12840                  */
12841                 "sSortDataType": "std",
12842         
12843         
12844                 /**
12845                  * The title of this column.
12846                  *  @type string
12847                  *  @default null <i>Derived from the 'TH' value for this column in the
12848                  *    original HTML table.</i>
12849                  *
12850                  *  @name DataTable.defaults.column.title
12851                  *  @dtopt Columns
12852                  *
12853                  *  @example
12854                  *    // Using `columnDefs`
12855                  *    $(document).ready( function() {
12856                  *      $('#example').dataTable( {
12857                  *        "columnDefs": [
12858                  *          { "title": "My column title", "targets": [ 0 ] }
12859                  *        ]
12860                  *      } );
12861                  *    } );
12862                  *
12863                  *  @example
12864                  *    // Using `columns`
12865                  *    $(document).ready( function() {
12866                  *      $('#example').dataTable( {
12867                  *        "columns": [
12868                  *          { "title": "My column title" },
12869                  *          null,
12870                  *          null,
12871                  *          null,
12872                  *          null
12873                  *        ]
12874                  *      } );
12875                  *    } );
12876                  */
12877                 "sTitle": null,
12878         
12879         
12880                 /**
12881                  * The type allows you to specify how the data for this column will be
12882                  * ordered. Four types (string, numeric, date and html (which will strip
12883                  * HTML tags before ordering)) are currently available. Note that only date
12884                  * formats understood by Javascript's Date() object will be accepted as type
12885                  * date. For example: "Mar 26, 2008 5:03 PM". May take the values: 'string',
12886                  * 'numeric', 'date' or 'html' (by default). Further types can be adding
12887                  * through plug-ins.
12888                  *  @type string
12889                  *  @default null <i>Auto-detected from raw data</i>
12890                  *
12891                  *  @name DataTable.defaults.column.type
12892                  *  @dtopt Columns
12893                  *
12894                  *  @example
12895                  *    // Using `columnDefs`
12896                  *    $(document).ready( function() {
12897                  *      $('#example').dataTable( {
12898                  *        "columnDefs": [
12899                  *          { "type": "html", "targets": [ 0 ] }
12900                  *        ]
12901                  *      } );
12902                  *    } );
12903                  *
12904                  *  @example
12905                  *    // Using `columns`
12906                  *    $(document).ready( function() {
12907                  *      $('#example').dataTable( {
12908                  *        "columns": [
12909                  *          { "type": "html" },
12910                  *          null,
12911                  *          null,
12912                  *          null,
12913                  *          null
12914                  *        ]
12915                  *      } );
12916                  *    } );
12917                  */
12918                 "sType": null,
12919         
12920         
12921                 /**
12922                  * Defining the width of the column, this parameter may take any CSS value
12923                  * (3em, 20px etc). DataTables applies 'smart' widths to columns which have not
12924                  * been given a specific width through this interface ensuring that the table
12925                  * remains readable.
12926                  *  @type string
12927                  *  @default null <i>Automatic</i>
12928                  *
12929                  *  @name DataTable.defaults.column.width
12930                  *  @dtopt Columns
12931                  *
12932                  *  @example
12933                  *    // Using `columnDefs`
12934                  *    $(document).ready( function() {
12935                  *      $('#example').dataTable( {
12936                  *        "columnDefs": [
12937                  *          { "width": "20%", "targets": [ 0 ] }
12938                  *        ]
12939                  *      } );
12940                  *    } );
12941                  *
12942                  *  @example
12943                  *    // Using `columns`
12944                  *    $(document).ready( function() {
12945                  *      $('#example').dataTable( {
12946                  *        "columns": [
12947                  *          { "width": "20%" },
12948                  *          null,
12949                  *          null,
12950                  *          null,
12951                  *          null
12952                  *        ]
12953                  *      } );
12954                  *    } );
12955                  */
12956                 "sWidth": null
12957         };
12958         
12959         _fnHungarianMap( DataTable.defaults.column );
12960         
12961         
12962         
12963         /**
12964          * DataTables settings object - this holds all the information needed for a
12965          * given table, including configuration, data and current application of the
12966          * table options. DataTables does not have a single instance for each DataTable
12967          * with the settings attached to that instance, but rather instances of the
12968          * DataTable "class" are created on-the-fly as needed (typically by a
12969          * $().dataTable() call) and the settings object is then applied to that
12970          * instance.
12971          *
12972          * Note that this object is related to {@link DataTable.defaults} but this
12973          * one is the internal data store for DataTables's cache of columns. It should
12974          * NOT be manipulated outside of DataTables. Any configuration should be done
12975          * through the initialisation options.
12976          *  @namespace
12977          *  @todo Really should attach the settings object to individual instances so we
12978          *    don't need to create new instances on each $().dataTable() call (if the
12979          *    table already exists). It would also save passing oSettings around and
12980          *    into every single function. However, this is a very significant
12981          *    architecture change for DataTables and will almost certainly break
12982          *    backwards compatibility with older installations. This is something that
12983          *    will be done in 2.0.
12984          */
12985         DataTable.models.oSettings = {
12986                 /**
12987                  * Primary features of DataTables and their enablement state.
12988                  *  @namespace
12989                  */
12990                 "oFeatures": {
12991         
12992                         /**
12993                          * Flag to say if DataTables should automatically try to calculate the
12994                          * optimum table and columns widths (true) or not (false).
12995                          * Note that this parameter will be set by the initialisation routine. To
12996                          * set a default use {@link DataTable.defaults}.
12997                          *  @type boolean
12998                          */
12999                         "bAutoWidth": null,
13000         
13001                         /**
13002                          * Delay the creation of TR and TD elements until they are actually
13003                          * needed by a driven page draw. This can give a significant speed
13004                          * increase for Ajax source and Javascript source data, but makes no
13005                          * difference at all fro DOM and server-side processing tables.
13006                          * Note that this parameter will be set by the initialisation routine. To
13007                          * set a default use {@link DataTable.defaults}.
13008                          *  @type boolean
13009                          */
13010                         "bDeferRender": null,
13011         
13012                         /**
13013                          * Enable filtering on the table or not. Note that if this is disabled
13014                          * then there is no filtering at all on the table, including fnFilter.
13015                          * To just remove the filtering input use sDom and remove the 'f' option.
13016                          * Note that this parameter will be set by the initialisation routine. To
13017                          * set a default use {@link DataTable.defaults}.
13018                          *  @type boolean
13019                          */
13020                         "bFilter": null,
13021         
13022                         /**
13023                          * Table information element (the 'Showing x of y records' div) enable
13024                          * flag.
13025                          * Note that this parameter will be set by the initialisation routine. To
13026                          * set a default use {@link DataTable.defaults}.
13027                          *  @type boolean
13028                          */
13029                         "bInfo": null,
13030         
13031                         /**
13032                          * Present a user control allowing the end user to change the page size
13033                          * when pagination is enabled.
13034                          * Note that this parameter will be set by the initialisation routine. To
13035                          * set a default use {@link DataTable.defaults}.
13036                          *  @type boolean
13037                          */
13038                         "bLengthChange": null,
13039         
13040                         /**
13041                          * Pagination enabled or not. Note that if this is disabled then length
13042                          * changing must also be disabled.
13043                          * Note that this parameter will be set by the initialisation routine. To
13044                          * set a default use {@link DataTable.defaults}.
13045                          *  @type boolean
13046                          */
13047                         "bPaginate": null,
13048         
13049                         /**
13050                          * Processing indicator enable flag whenever DataTables is enacting a
13051                          * user request - typically an Ajax request for server-side processing.
13052                          * Note that this parameter will be set by the initialisation routine. To
13053                          * set a default use {@link DataTable.defaults}.
13054                          *  @type boolean
13055                          */
13056                         "bProcessing": null,
13057         
13058                         /**
13059                          * Server-side processing enabled flag - when enabled DataTables will
13060                          * get all data from the server for every draw - there is no filtering,
13061                          * sorting or paging done on the client-side.
13062                          * Note that this parameter will be set by the initialisation routine. To
13063                          * set a default use {@link DataTable.defaults}.
13064                          *  @type boolean
13065                          */
13066                         "bServerSide": null,
13067         
13068                         /**
13069                          * Sorting enablement flag.
13070                          * Note that this parameter will be set by the initialisation routine. To
13071                          * set a default use {@link DataTable.defaults}.
13072                          *  @type boolean
13073                          */
13074                         "bSort": null,
13075         
13076                         /**
13077                          * Multi-column sorting
13078                          * Note that this parameter will be set by the initialisation routine. To
13079                          * set a default use {@link DataTable.defaults}.
13080                          *  @type boolean
13081                          */
13082                         "bSortMulti": null,
13083         
13084                         /**
13085                          * Apply a class to the columns which are being sorted to provide a
13086                          * visual highlight or not. This can slow things down when enabled since
13087                          * there is a lot of DOM interaction.
13088                          * Note that this parameter will be set by the initialisation routine. To
13089                          * set a default use {@link DataTable.defaults}.
13090                          *  @type boolean
13091                          */
13092                         "bSortClasses": null,
13093         
13094                         /**
13095                          * State saving enablement flag.
13096                          * Note that this parameter will be set by the initialisation routine. To
13097                          * set a default use {@link DataTable.defaults}.
13098                          *  @type boolean
13099                          */
13100                         "bStateSave": null
13101                 },
13102         
13103         
13104                 /**
13105                  * Scrolling settings for a table.
13106                  *  @namespace
13107                  */
13108                 "oScroll": {
13109                         /**
13110                          * When the table is shorter in height than sScrollY, collapse the
13111                          * table container down to the height of the table (when true).
13112                          * Note that this parameter will be set by the initialisation routine. To
13113                          * set a default use {@link DataTable.defaults}.
13114                          *  @type boolean
13115                          */
13116                         "bCollapse": null,
13117         
13118                         /**
13119                          * Width of the scrollbar for the web-browser's platform. Calculated
13120                          * during table initialisation.
13121                          *  @type int
13122                          *  @default 0
13123                          */
13124                         "iBarWidth": 0,
13125         
13126                         /**
13127                          * Viewport width for horizontal scrolling. Horizontal scrolling is
13128                          * disabled if an empty string.
13129                          * Note that this parameter will be set by the initialisation routine. To
13130                          * set a default use {@link DataTable.defaults}.
13131                          *  @type string
13132                          */
13133                         "sX": null,
13134         
13135                         /**
13136                          * Width to expand the table to when using x-scrolling. Typically you
13137                          * should not need to use this.
13138                          * Note that this parameter will be set by the initialisation routine. To
13139                          * set a default use {@link DataTable.defaults}.
13140                          *  @type string
13141                          *  @deprecated
13142                          */
13143                         "sXInner": null,
13144         
13145                         /**
13146                          * Viewport height for vertical scrolling. Vertical scrolling is disabled
13147                          * if an empty string.
13148                          * Note that this parameter will be set by the initialisation routine. To
13149                          * set a default use {@link DataTable.defaults}.
13150                          *  @type string
13151                          */
13152                         "sY": null
13153                 },
13154         
13155                 /**
13156                  * Language information for the table.
13157                  *  @namespace
13158                  *  @extends DataTable.defaults.oLanguage
13159                  */
13160                 "oLanguage": {
13161                         /**
13162                          * Information callback function. See
13163                          * {@link DataTable.defaults.fnInfoCallback}
13164                          *  @type function
13165                          *  @default null
13166                          */
13167                         "fnInfoCallback": null
13168                 },
13169         
13170                 /**
13171                  * Browser support parameters
13172                  *  @namespace
13173                  */
13174                 "oBrowser": {
13175                         /**
13176                          * Indicate if the browser incorrectly calculates width:100% inside a
13177                          * scrolling element (IE6/7)
13178                          *  @type boolean
13179                          *  @default false
13180                          */
13181                         "bScrollOversize": false,
13182         
13183                         /**
13184                          * Determine if the vertical scrollbar is on the right or left of the
13185                          * scrolling container - needed for rtl language layout, although not
13186                          * all browsers move the scrollbar (Safari).
13187                          *  @type boolean
13188                          *  @default false
13189                          */
13190                         "bScrollbarLeft": false,
13191         
13192                         /**
13193                          * Flag for if `getBoundingClientRect` is fully supported or not
13194                          *  @type boolean
13195                          *  @default false
13196                          */
13197                         "bBounding": false,
13198         
13199                         /**
13200                          * Browser scrollbar width
13201                          *  @type integer
13202                          *  @default 0
13203                          */
13204                         "barWidth": 0
13205                 },
13206         
13207         
13208                 "ajax": null,
13209         
13210         
13211                 /**
13212                  * Array referencing the nodes which are used for the features. The
13213                  * parameters of this object match what is allowed by sDom - i.e.
13214                  *   <ul>
13215                  *     <li>'l' - Length changing</li>
13216                  *     <li>'f' - Filtering input</li>
13217                  *     <li>'t' - The table!</li>
13218                  *     <li>'i' - Information</li>
13219                  *     <li>'p' - Pagination</li>
13220                  *     <li>'r' - pRocessing</li>
13221                  *   </ul>
13222                  *  @type array
13223                  *  @default []
13224                  */
13225                 "aanFeatures": [],
13226         
13227                 /**
13228                  * Store data information - see {@link DataTable.models.oRow} for detailed
13229                  * information.
13230                  *  @type array
13231                  *  @default []
13232                  */
13233                 "aoData": [],
13234         
13235                 /**
13236                  * Array of indexes which are in the current display (after filtering etc)
13237                  *  @type array
13238                  *  @default []
13239                  */
13240                 "aiDisplay": [],
13241         
13242                 /**
13243                  * Array of indexes for display - no filtering
13244                  *  @type array
13245                  *  @default []
13246                  */
13247                 "aiDisplayMaster": [],
13248         
13249                 /**
13250                  * Map of row ids to data indexes
13251                  *  @type object
13252                  *  @default {}
13253                  */
13254                 "aIds": {},
13255         
13256                 /**
13257                  * Store information about each column that is in use
13258                  *  @type array
13259                  *  @default []
13260                  */
13261                 "aoColumns": [],
13262         
13263                 /**
13264                  * Store information about the table's header
13265                  *  @type array
13266                  *  @default []
13267                  */
13268                 "aoHeader": [],
13269         
13270                 /**
13271                  * Store information about the table's footer
13272                  *  @type array
13273                  *  @default []
13274                  */
13275                 "aoFooter": [],
13276         
13277                 /**
13278                  * Store the applied global search information in case we want to force a
13279                  * research or compare the old search to a new one.
13280                  * Note that this parameter will be set by the initialisation routine. To
13281                  * set a default use {@link DataTable.defaults}.
13282                  *  @namespace
13283                  *  @extends DataTable.models.oSearch
13284                  */
13285                 "oPreviousSearch": {},
13286         
13287                 /**
13288                  * Store the applied search for each column - see
13289                  * {@link DataTable.models.oSearch} for the format that is used for the
13290                  * filtering information for each column.
13291                  *  @type array
13292                  *  @default []
13293                  */
13294                 "aoPreSearchCols": [],
13295         
13296                 /**
13297                  * Sorting that is applied to the table. Note that the inner arrays are
13298                  * used in the following manner:
13299                  * <ul>
13300                  *   <li>Index 0 - column number</li>
13301                  *   <li>Index 1 - current sorting direction</li>
13302                  * </ul>
13303                  * Note that this parameter will be set by the initialisation routine. To
13304                  * set a default use {@link DataTable.defaults}.
13305                  *  @type array
13306                  *  @todo These inner arrays should really be objects
13307                  */
13308                 "aaSorting": null,
13309         
13310                 /**
13311                  * Sorting that is always applied to the table (i.e. prefixed in front of
13312                  * aaSorting).
13313                  * Note that this parameter will be set by the initialisation routine. To
13314                  * set a default use {@link DataTable.defaults}.
13315                  *  @type array
13316                  *  @default []
13317                  */
13318                 "aaSortingFixed": [],
13319         
13320                 /**
13321                  * Classes to use for the striping of a table.
13322                  * Note that this parameter will be set by the initialisation routine. To
13323                  * set a default use {@link DataTable.defaults}.
13324                  *  @type array
13325                  *  @default []
13326                  */
13327                 "asStripeClasses": null,
13328         
13329                 /**
13330                  * If restoring a table - we should restore its striping classes as well
13331                  *  @type array
13332                  *  @default []
13333                  */
13334                 "asDestroyStripes": [],
13335         
13336                 /**
13337                  * If restoring a table - we should restore its width
13338                  *  @type int
13339                  *  @default 0
13340                  */
13341                 "sDestroyWidth": 0,
13342         
13343                 /**
13344                  * Callback functions array for every time a row is inserted (i.e. on a draw).
13345                  *  @type array
13346                  *  @default []
13347                  */
13348                 "aoRowCallback": [],
13349         
13350                 /**
13351                  * Callback functions for the header on each draw.
13352                  *  @type array
13353                  *  @default []
13354                  */
13355                 "aoHeaderCallback": [],
13356         
13357                 /**
13358                  * Callback function for the footer on each draw.
13359                  *  @type array
13360                  *  @default []
13361                  */
13362                 "aoFooterCallback": [],
13363         
13364                 /**
13365                  * Array of callback functions for draw callback functions
13366                  *  @type array
13367                  *  @default []
13368                  */
13369                 "aoDrawCallback": [],
13370         
13371                 /**
13372                  * Array of callback functions for row created function
13373                  *  @type array
13374                  *  @default []
13375                  */
13376                 "aoRowCreatedCallback": [],
13377         
13378                 /**
13379                  * Callback functions for just before the table is redrawn. A return of
13380                  * false will be used to cancel the draw.
13381                  *  @type array
13382                  *  @default []
13383                  */
13384                 "aoPreDrawCallback": [],
13385         
13386                 /**
13387                  * Callback functions for when the table has been initialised.
13388                  *  @type array
13389                  *  @default []
13390                  */
13391                 "aoInitComplete": [],
13392         
13393         
13394                 /**
13395                  * Callbacks for modifying the settings to be stored for state saving, prior to
13396                  * saving state.
13397                  *  @type array
13398                  *  @default []
13399                  */
13400                 "aoStateSaveParams": [],
13401         
13402                 /**
13403                  * Callbacks for modifying the settings that have been stored for state saving
13404                  * prior to using the stored values to restore the state.
13405                  *  @type array
13406                  *  @default []
13407                  */
13408                 "aoStateLoadParams": [],
13409         
13410                 /**
13411                  * Callbacks for operating on the settings object once the saved state has been
13412                  * loaded
13413                  *  @type array
13414                  *  @default []
13415                  */
13416                 "aoStateLoaded": [],
13417         
13418                 /**
13419                  * Cache the table ID for quick access
13420                  *  @type string
13421                  *  @default <i>Empty string</i>
13422                  */
13423                 "sTableId": "",
13424         
13425                 /**
13426                  * The TABLE node for the main table
13427                  *  @type node
13428                  *  @default null
13429                  */
13430                 "nTable": null,
13431         
13432                 /**
13433                  * Permanent ref to the thead element
13434                  *  @type node
13435                  *  @default null
13436                  */
13437                 "nTHead": null,
13438         
13439                 /**
13440                  * Permanent ref to the tfoot element - if it exists
13441                  *  @type node
13442                  *  @default null
13443                  */
13444                 "nTFoot": null,
13445         
13446                 /**
13447                  * Permanent ref to the tbody element
13448                  *  @type node
13449                  *  @default null
13450                  */
13451                 "nTBody": null,
13452         
13453                 /**
13454                  * Cache the wrapper node (contains all DataTables controlled elements)
13455                  *  @type node
13456                  *  @default null
13457                  */
13458                 "nTableWrapper": null,
13459         
13460                 /**
13461                  * Indicate if when using server-side processing the loading of data
13462                  * should be deferred until the second draw.
13463                  * Note that this parameter will be set by the initialisation routine. To
13464                  * set a default use {@link DataTable.defaults}.
13465                  *  @type boolean
13466                  *  @default false
13467                  */
13468                 "bDeferLoading": false,
13469         
13470                 /**
13471                  * Indicate if all required information has been read in
13472                  *  @type boolean
13473                  *  @default false
13474                  */
13475                 "bInitialised": false,
13476         
13477                 /**
13478                  * Information about open rows. Each object in the array has the parameters
13479                  * 'nTr' and 'nParent'
13480                  *  @type array
13481                  *  @default []
13482                  */
13483                 "aoOpenRows": [],
13484         
13485                 /**
13486                  * Dictate the positioning of DataTables' control elements - see
13487                  * {@link DataTable.model.oInit.sDom}.
13488                  * Note that this parameter will be set by the initialisation routine. To
13489                  * set a default use {@link DataTable.defaults}.
13490                  *  @type string
13491                  *  @default null
13492                  */
13493                 "sDom": null,
13494         
13495                 /**
13496                  * Search delay (in mS)
13497                  *  @type integer
13498                  *  @default null
13499                  */
13500                 "searchDelay": null,
13501         
13502                 /**
13503                  * Which type of pagination should be used.
13504                  * Note that this parameter will be set by the initialisation routine. To
13505                  * set a default use {@link DataTable.defaults}.
13506                  *  @type string
13507                  *  @default two_button
13508                  */
13509                 "sPaginationType": "two_button",
13510         
13511                 /**
13512                  * The state duration (for `stateSave`) in seconds.
13513                  * Note that this parameter will be set by the initialisation routine. To
13514                  * set a default use {@link DataTable.defaults}.
13515                  *  @type int
13516                  *  @default 0
13517                  */
13518                 "iStateDuration": 0,
13519         
13520                 /**
13521                  * Array of callback functions for state saving. Each array element is an
13522                  * object with the following parameters:
13523                  *   <ul>
13524                  *     <li>function:fn - function to call. Takes two parameters, oSettings
13525                  *       and the JSON string to save that has been thus far created. Returns
13526                  *       a JSON string to be inserted into a json object
13527                  *       (i.e. '"param": [ 0, 1, 2]')</li>
13528                  *     <li>string:sName - name of callback</li>
13529                  *   </ul>
13530                  *  @type array
13531                  *  @default []
13532                  */
13533                 "aoStateSave": [],
13534         
13535                 /**
13536                  * Array of callback functions for state loading. Each array element is an
13537                  * object with the following parameters:
13538                  *   <ul>
13539                  *     <li>function:fn - function to call. Takes two parameters, oSettings
13540                  *       and the object stored. May return false to cancel state loading</li>
13541                  *     <li>string:sName - name of callback</li>
13542                  *   </ul>
13543                  *  @type array
13544                  *  @default []
13545                  */
13546                 "aoStateLoad": [],
13547         
13548                 /**
13549                  * State that was saved. Useful for back reference
13550                  *  @type object
13551                  *  @default null
13552                  */
13553                 "oSavedState": null,
13554         
13555                 /**
13556                  * State that was loaded. Useful for back reference
13557                  *  @type object
13558                  *  @default null
13559                  */
13560                 "oLoadedState": null,
13561         
13562                 /**
13563                  * Source url for AJAX data for the table.
13564                  * Note that this parameter will be set by the initialisation routine. To
13565                  * set a default use {@link DataTable.defaults}.
13566                  *  @type string
13567                  *  @default null
13568                  */
13569                 "sAjaxSource": null,
13570         
13571                 /**
13572                  * Property from a given object from which to read the table data from. This
13573                  * can be an empty string (when not server-side processing), in which case
13574                  * it is  assumed an an array is given directly.
13575                  * Note that this parameter will be set by the initialisation routine. To
13576                  * set a default use {@link DataTable.defaults}.
13577                  *  @type string
13578                  */
13579                 "sAjaxDataProp": null,
13580         
13581                 /**
13582                  * Note if draw should be blocked while getting data
13583                  *  @type boolean
13584                  *  @default true
13585                  */
13586                 "bAjaxDataGet": true,
13587         
13588                 /**
13589                  * The last jQuery XHR object that was used for server-side data gathering.
13590                  * This can be used for working with the XHR information in one of the
13591                  * callbacks
13592                  *  @type object
13593                  *  @default null
13594                  */
13595                 "jqXHR": null,
13596         
13597                 /**
13598                  * JSON returned from the server in the last Ajax request
13599                  *  @type object
13600                  *  @default undefined
13601                  */
13602                 "json": undefined,
13603         
13604                 /**
13605                  * Data submitted as part of the last Ajax request
13606                  *  @type object
13607                  *  @default undefined
13608                  */
13609                 "oAjaxData": undefined,
13610         
13611                 /**
13612                  * Function to get the server-side data.
13613                  * Note that this parameter will be set by the initialisation routine. To
13614                  * set a default use {@link DataTable.defaults}.
13615                  *  @type function
13616                  */
13617                 "fnServerData": null,
13618         
13619                 /**
13620                  * Functions which are called prior to sending an Ajax request so extra
13621                  * parameters can easily be sent to the server
13622                  *  @type array
13623                  *  @default []
13624                  */
13625                 "aoServerParams": [],
13626         
13627                 /**
13628                  * Send the XHR HTTP method - GET or POST (could be PUT or DELETE if
13629                  * required).
13630                  * Note that this parameter will be set by the initialisation routine. To
13631                  * set a default use {@link DataTable.defaults}.
13632                  *  @type string
13633                  */
13634                 "sServerMethod": null,
13635         
13636                 /**
13637                  * Format numbers for display.
13638                  * Note that this parameter will be set by the initialisation routine. To
13639                  * set a default use {@link DataTable.defaults}.
13640                  *  @type function
13641                  */
13642                 "fnFormatNumber": null,
13643         
13644                 /**
13645                  * List of options that can be used for the user selectable length menu.
13646                  * Note that this parameter will be set by the initialisation routine. To
13647                  * set a default use {@link DataTable.defaults}.
13648                  *  @type array
13649                  *  @default []
13650                  */
13651                 "aLengthMenu": null,
13652         
13653                 /**
13654                  * Counter for the draws that the table does. Also used as a tracker for
13655                  * server-side processing
13656                  *  @type int
13657                  *  @default 0
13658                  */
13659                 "iDraw": 0,
13660         
13661                 /**
13662                  * Indicate if a redraw is being done - useful for Ajax
13663                  *  @type boolean
13664                  *  @default false
13665                  */
13666                 "bDrawing": false,
13667         
13668                 /**
13669                  * Draw index (iDraw) of the last error when parsing the returned data
13670                  *  @type int
13671                  *  @default -1
13672                  */
13673                 "iDrawError": -1,
13674         
13675                 /**
13676                  * Paging display length
13677                  *  @type int
13678                  *  @default 10
13679                  */
13680                 "_iDisplayLength": 10,
13681         
13682                 /**
13683                  * Paging start point - aiDisplay index
13684                  *  @type int
13685                  *  @default 0
13686                  */
13687                 "_iDisplayStart": 0,
13688         
13689                 /**
13690                  * Server-side processing - number of records in the result set
13691                  * (i.e. before filtering), Use fnRecordsTotal rather than
13692                  * this property to get the value of the number of records, regardless of
13693                  * the server-side processing setting.
13694                  *  @type int
13695                  *  @default 0
13696                  *  @private
13697                  */
13698                 "_iRecordsTotal": 0,
13699         
13700                 /**
13701                  * Server-side processing - number of records in the current display set
13702                  * (i.e. after filtering). Use fnRecordsDisplay rather than
13703                  * this property to get the value of the number of records, regardless of
13704                  * the server-side processing setting.
13705                  *  @type boolean
13706                  *  @default 0
13707                  *  @private
13708                  */
13709                 "_iRecordsDisplay": 0,
13710         
13711                 /**
13712                  * The classes to use for the table
13713                  *  @type object
13714                  *  @default {}
13715                  */
13716                 "oClasses": {},
13717         
13718                 /**
13719                  * Flag attached to the settings object so you can check in the draw
13720                  * callback if filtering has been done in the draw. Deprecated in favour of
13721                  * events.
13722                  *  @type boolean
13723                  *  @default false
13724                  *  @deprecated
13725                  */
13726                 "bFiltered": false,
13727         
13728                 /**
13729                  * Flag attached to the settings object so you can check in the draw
13730                  * callback if sorting has been done in the draw. Deprecated in favour of
13731                  * events.
13732                  *  @type boolean
13733                  *  @default false
13734                  *  @deprecated
13735                  */
13736                 "bSorted": false,
13737         
13738                 /**
13739                  * Indicate that if multiple rows are in the header and there is more than
13740                  * one unique cell per column, if the top one (true) or bottom one (false)
13741                  * should be used for sorting / title by DataTables.
13742                  * Note that this parameter will be set by the initialisation routine. To
13743                  * set a default use {@link DataTable.defaults}.
13744                  *  @type boolean
13745                  */
13746                 "bSortCellsTop": null,
13747         
13748                 /**
13749                  * Initialisation object that is used for the table
13750                  *  @type object
13751                  *  @default null
13752                  */
13753                 "oInit": null,
13754         
13755                 /**
13756                  * Destroy callback functions - for plug-ins to attach themselves to the
13757                  * destroy so they can clean up markup and events.
13758                  *  @type array
13759                  *  @default []
13760                  */
13761                 "aoDestroyCallback": [],
13762         
13763         
13764                 /**
13765                  * Get the number of records in the current record set, before filtering
13766                  *  @type function
13767                  */
13768                 "fnRecordsTotal": function ()
13769                 {
13770                         return _fnDataSource( this ) == 'ssp' ?
13771                                 this._iRecordsTotal * 1 :
13772                                 this.aiDisplayMaster.length;
13773                 },
13774         
13775                 /**
13776                  * Get the number of records in the current record set, after filtering
13777                  *  @type function
13778                  */
13779                 "fnRecordsDisplay": function ()
13780                 {
13781                         return _fnDataSource( this ) == 'ssp' ?
13782                                 this._iRecordsDisplay * 1 :
13783                                 this.aiDisplay.length;
13784                 },
13785         
13786                 /**
13787                  * Get the display end point - aiDisplay index
13788                  *  @type function
13789                  */
13790                 "fnDisplayEnd": function ()
13791                 {
13792                         var
13793                                 len      = this._iDisplayLength,
13794                                 start    = this._iDisplayStart,
13795                                 calc     = start + len,
13796                                 records  = this.aiDisplay.length,
13797                                 features = this.oFeatures,
13798                                 paginate = features.bPaginate;
13799         
13800                         if ( features.bServerSide ) {
13801                                 return paginate === false || len === -1 ?
13802                                         start + records :
13803                                         Math.min( start+len, this._iRecordsDisplay );
13804                         }
13805                         else {
13806                                 return ! paginate || calc>records || len===-1 ?
13807                                         records :
13808                                         calc;
13809                         }
13810                 },
13811         
13812                 /**
13813                  * The DataTables object for this table
13814                  *  @type object
13815                  *  @default null
13816                  */
13817                 "oInstance": null,
13818         
13819                 /**
13820                  * Unique identifier for each instance of the DataTables object. If there
13821                  * is an ID on the table node, then it takes that value, otherwise an
13822                  * incrementing internal counter is used.
13823                  *  @type string
13824                  *  @default null
13825                  */
13826                 "sInstance": null,
13827         
13828                 /**
13829                  * tabindex attribute value that is added to DataTables control elements, allowing
13830                  * keyboard navigation of the table and its controls.
13831                  */
13832                 "iTabIndex": 0,
13833         
13834                 /**
13835                  * DIV container for the footer scrolling table if scrolling
13836                  */
13837                 "nScrollHead": null,
13838         
13839                 /**
13840                  * DIV container for the footer scrolling table if scrolling
13841                  */
13842                 "nScrollFoot": null,
13843         
13844                 /**
13845                  * Last applied sort
13846                  *  @type array
13847                  *  @default []
13848                  */
13849                 "aLastSort": [],
13850         
13851                 /**
13852                  * Stored plug-in instances
13853                  *  @type object
13854                  *  @default {}
13855                  */
13856                 "oPlugins": {},
13857         
13858                 /**
13859                  * Function used to get a row's id from the row's data
13860                  *  @type function
13861                  *  @default null
13862                  */
13863                 "rowIdFn": null,
13864         
13865                 /**
13866                  * Data location where to store a row's id
13867                  *  @type string
13868                  *  @default null
13869                  */
13870                 "rowId": null
13871         };
13872
13873         /**
13874          * Extension object for DataTables that is used to provide all extension
13875          * options.
13876          *
13877          * Note that the `DataTable.ext` object is available through
13878          * `jQuery.fn.dataTable.ext` where it may be accessed and manipulated. It is
13879          * also aliased to `jQuery.fn.dataTableExt` for historic reasons.
13880          *  @namespace
13881          *  @extends DataTable.models.ext
13882          */
13883         
13884         
13885         /**
13886          * DataTables extensions
13887          * 
13888          * This namespace acts as a collection area for plug-ins that can be used to
13889          * extend DataTables capabilities. Indeed many of the build in methods
13890          * use this method to provide their own capabilities (sorting methods for
13891          * example).
13892          *
13893          * Note that this namespace is aliased to `jQuery.fn.dataTableExt` for legacy
13894          * reasons
13895          *
13896          *  @namespace
13897          */
13898         DataTable.ext = _ext = {
13899                 /**
13900                  * Buttons. For use with the Buttons extension for DataTables. This is
13901                  * defined here so other extensions can define buttons regardless of load
13902                  * order. It is _not_ used by DataTables core.
13903                  *
13904                  *  @type object
13905                  *  @default {}
13906                  */
13907                 buttons: {},
13908         
13909         
13910                 /**
13911                  * Element class names
13912                  *
13913                  *  @type object
13914                  *  @default {}
13915                  */
13916                 classes: {},
13917         
13918         
13919                 /**
13920                  * DataTables build type (expanded by the download builder)
13921                  *
13922                  *  @type string
13923                  */
13924                 build:"dt/dt-1.10.20/fc-3.3.0/fh-3.1.6",
13925         
13926         
13927                 /**
13928                  * Error reporting.
13929                  * 
13930                  * How should DataTables report an error. Can take the value 'alert',
13931                  * 'throw', 'none' or a function.
13932                  *
13933                  *  @type string|function
13934                  *  @default alert
13935                  */
13936                 errMode: "alert",
13937         
13938         
13939                 /**
13940                  * Feature plug-ins.
13941                  * 
13942                  * This is an array of objects which describe the feature plug-ins that are
13943                  * available to DataTables. These feature plug-ins are then available for
13944                  * use through the `dom` initialisation option.
13945                  * 
13946                  * Each feature plug-in is described by an object which must have the
13947                  * following properties:
13948                  * 
13949                  * * `fnInit` - function that is used to initialise the plug-in,
13950                  * * `cFeature` - a character so the feature can be enabled by the `dom`
13951                  *   instillation option. This is case sensitive.
13952                  *
13953                  * The `fnInit` function has the following input parameters:
13954                  *
13955                  * 1. `{object}` DataTables settings object: see
13956                  *    {@link DataTable.models.oSettings}
13957                  *
13958                  * And the following return is expected:
13959                  * 
13960                  * * {node|null} The element which contains your feature. Note that the
13961                  *   return may also be void if your plug-in does not require to inject any
13962                  *   DOM elements into DataTables control (`dom`) - for example this might
13963                  *   be useful when developing a plug-in which allows table control via
13964                  *   keyboard entry
13965                  *
13966                  *  @type array
13967                  *
13968                  *  @example
13969                  *    $.fn.dataTable.ext.features.push( {
13970                  *      "fnInit": function( oSettings ) {
13971                  *        return new TableTools( { "oDTSettings": oSettings } );
13972                  *      },
13973                  *      "cFeature": "T"
13974                  *    } );
13975                  */
13976                 feature: [],
13977         
13978         
13979                 /**
13980                  * Row searching.
13981                  * 
13982                  * This method of searching is complimentary to the default type based
13983                  * searching, and a lot more comprehensive as it allows you complete control
13984                  * over the searching logic. Each element in this array is a function
13985                  * (parameters described below) that is called for every row in the table,
13986                  * and your logic decides if it should be included in the searching data set
13987                  * or not.
13988                  *
13989                  * Searching functions have the following input parameters:
13990                  *
13991                  * 1. `{object}` DataTables settings object: see
13992                  *    {@link DataTable.models.oSettings}
13993                  * 2. `{array|object}` Data for the row to be processed (same as the
13994                  *    original format that was passed in as the data source, or an array
13995                  *    from a DOM data source
13996                  * 3. `{int}` Row index ({@link DataTable.models.oSettings.aoData}), which
13997                  *    can be useful to retrieve the `TR` element if you need DOM interaction.
13998                  *
13999                  * And the following return is expected:
14000                  *
14001                  * * {boolean} Include the row in the searched result set (true) or not
14002                  *   (false)
14003                  *
14004                  * Note that as with the main search ability in DataTables, technically this
14005                  * is "filtering", since it is subtractive. However, for consistency in
14006                  * naming we call it searching here.
14007                  *
14008                  *  @type array
14009                  *  @default []
14010                  *
14011                  *  @example
14012                  *    // The following example shows custom search being applied to the
14013                  *    // fourth column (i.e. the data[3] index) based on two input values
14014                  *    // from the end-user, matching the data in a certain range.
14015                  *    $.fn.dataTable.ext.search.push(
14016                  *      function( settings, data, dataIndex ) {
14017                  *        var min = document.getElementById('min').value * 1;
14018                  *        var max = document.getElementById('max').value * 1;
14019                  *        var version = data[3] == "-" ? 0 : data[3]*1;
14020                  *
14021                  *        if ( min == "" && max == "" ) {
14022                  *          return true;
14023                  *        }
14024                  *        else if ( min == "" && version < max ) {
14025                  *          return true;
14026                  *        }
14027                  *        else if ( min < version && "" == max ) {
14028                  *          return true;
14029                  *        }
14030                  *        else if ( min < version && version < max ) {
14031                  *          return true;
14032                  *        }
14033                  *        return false;
14034                  *      }
14035                  *    );
14036                  */
14037                 search: [],
14038         
14039         
14040                 /**
14041                  * Selector extensions
14042                  *
14043                  * The `selector` option can be used to extend the options available for the
14044                  * selector modifier options (`selector-modifier` object data type) that
14045                  * each of the three built in selector types offer (row, column and cell +
14046                  * their plural counterparts). For example the Select extension uses this
14047                  * mechanism to provide an option to select only rows, columns and cells
14048                  * that have been marked as selected by the end user (`{selected: true}`),
14049                  * which can be used in conjunction with the existing built in selector
14050                  * options.
14051                  *
14052                  * Each property is an array to which functions can be pushed. The functions
14053                  * take three attributes:
14054                  *
14055                  * * Settings object for the host table
14056                  * * Options object (`selector-modifier` object type)
14057                  * * Array of selected item indexes
14058                  *
14059                  * The return is an array of the resulting item indexes after the custom
14060                  * selector has been applied.
14061                  *
14062                  *  @type object
14063                  */
14064                 selector: {
14065                         cell: [],
14066                         column: [],
14067                         row: []
14068                 },
14069         
14070         
14071                 /**
14072                  * Internal functions, exposed for used in plug-ins.
14073                  * 
14074                  * Please note that you should not need to use the internal methods for
14075                  * anything other than a plug-in (and even then, try to avoid if possible).
14076                  * The internal function may change between releases.
14077                  *
14078                  *  @type object
14079                  *  @default {}
14080                  */
14081                 internal: {},
14082         
14083         
14084                 /**
14085                  * Legacy configuration options. Enable and disable legacy options that
14086                  * are available in DataTables.
14087                  *
14088                  *  @type object
14089                  */
14090                 legacy: {
14091                         /**
14092                          * Enable / disable DataTables 1.9 compatible server-side processing
14093                          * requests
14094                          *
14095                          *  @type boolean
14096                          *  @default null
14097                          */
14098                         ajax: null
14099                 },
14100         
14101         
14102                 /**
14103                  * Pagination plug-in methods.
14104                  * 
14105                  * Each entry in this object is a function and defines which buttons should
14106                  * be shown by the pagination rendering method that is used for the table:
14107                  * {@link DataTable.ext.renderer.pageButton}. The renderer addresses how the
14108                  * buttons are displayed in the document, while the functions here tell it
14109                  * what buttons to display. This is done by returning an array of button
14110                  * descriptions (what each button will do).
14111                  *
14112                  * Pagination types (the four built in options and any additional plug-in
14113                  * options defined here) can be used through the `paginationType`
14114                  * initialisation parameter.
14115                  *
14116                  * The functions defined take two parameters:
14117                  *
14118                  * 1. `{int} page` The current page index
14119                  * 2. `{int} pages` The number of pages in the table
14120                  *
14121                  * Each function is expected to return an array where each element of the
14122                  * array can be one of:
14123                  *
14124                  * * `first` - Jump to first page when activated
14125                  * * `last` - Jump to last page when activated
14126                  * * `previous` - Show previous page when activated
14127                  * * `next` - Show next page when activated
14128                  * * `{int}` - Show page of the index given
14129                  * * `{array}` - A nested array containing the above elements to add a
14130                  *   containing 'DIV' element (might be useful for styling).
14131                  *
14132                  * Note that DataTables v1.9- used this object slightly differently whereby
14133                  * an object with two functions would be defined for each plug-in. That
14134                  * ability is still supported by DataTables 1.10+ to provide backwards
14135                  * compatibility, but this option of use is now decremented and no longer
14136                  * documented in DataTables 1.10+.
14137                  *
14138                  *  @type object
14139                  *  @default {}
14140                  *
14141                  *  @example
14142                  *    // Show previous, next and current page buttons only
14143                  *    $.fn.dataTableExt.oPagination.current = function ( page, pages ) {
14144                  *      return [ 'previous', page, 'next' ];
14145                  *    };
14146                  */
14147                 pager: {},
14148         
14149         
14150                 renderer: {
14151                         pageButton: {},
14152                         header: {}
14153                 },
14154         
14155         
14156                 /**
14157                  * Ordering plug-ins - custom data source
14158                  * 
14159                  * The extension options for ordering of data available here is complimentary
14160                  * to the default type based ordering that DataTables typically uses. It
14161                  * allows much greater control over the the data that is being used to
14162                  * order a column, but is necessarily therefore more complex.
14163                  * 
14164                  * This type of ordering is useful if you want to do ordering based on data
14165                  * live from the DOM (for example the contents of an 'input' element) rather
14166                  * than just the static string that DataTables knows of.
14167                  * 
14168                  * The way these plug-ins work is that you create an array of the values you
14169                  * wish to be ordering for the column in question and then return that
14170                  * array. The data in the array much be in the index order of the rows in
14171                  * the table (not the currently ordering order!). Which order data gathering
14172                  * function is run here depends on the `dt-init columns.orderDataType`
14173                  * parameter that is used for the column (if any).
14174                  *
14175                  * The functions defined take two parameters:
14176                  *
14177                  * 1. `{object}` DataTables settings object: see
14178                  *    {@link DataTable.models.oSettings}
14179                  * 2. `{int}` Target column index
14180                  *
14181                  * Each function is expected to return an array:
14182                  *
14183                  * * `{array}` Data for the column to be ordering upon
14184                  *
14185                  *  @type array
14186                  *
14187                  *  @example
14188                  *    // Ordering using `input` node values
14189                  *    $.fn.dataTable.ext.order['dom-text'] = function  ( settings, col )
14190                  *    {
14191                  *      return this.api().column( col, {order:'index'} ).nodes().map( function ( td, i ) {
14192                  *        return $('input', td).val();
14193                  *      } );
14194                  *    }
14195                  */
14196                 order: {},
14197         
14198         
14199                 /**
14200                  * Type based plug-ins.
14201                  *
14202                  * Each column in DataTables has a type assigned to it, either by automatic
14203                  * detection or by direct assignment using the `type` option for the column.
14204                  * The type of a column will effect how it is ordering and search (plug-ins
14205                  * can also make use of the column type if required).
14206                  *
14207                  * @namespace
14208                  */
14209                 type: {
14210                         /**
14211                          * Type detection functions.
14212                          *
14213                          * The functions defined in this object are used to automatically detect
14214                          * a column's type, making initialisation of DataTables super easy, even
14215                          * when complex data is in the table.
14216                          *
14217                          * The functions defined take two parameters:
14218                          *
14219                      *  1. `{*}` Data from the column cell to be analysed
14220                      *  2. `{settings}` DataTables settings object. This can be used to
14221                      *     perform context specific type detection - for example detection
14222                      *     based on language settings such as using a comma for a decimal
14223                      *     place. Generally speaking the options from the settings will not
14224                      *     be required
14225                          *
14226                          * Each function is expected to return:
14227                          *
14228                          * * `{string|null}` Data type detected, or null if unknown (and thus
14229                          *   pass it on to the other type detection functions.
14230                          *
14231                          *  @type array
14232                          *
14233                          *  @example
14234                          *    // Currency type detection plug-in:
14235                          *    $.fn.dataTable.ext.type.detect.push(
14236                          *      function ( data, settings ) {
14237                          *        // Check the numeric part
14238                          *        if ( ! data.substring(1).match(/[0-9]/) ) {
14239                          *          return null;
14240                          *        }
14241                          *
14242                          *        // Check prefixed by currency
14243                          *        if ( data.charAt(0) == '$' || data.charAt(0) == '&pound;' ) {
14244                          *          return 'currency';
14245                          *        }
14246                          *        return null;
14247                          *      }
14248                          *    );
14249                          */
14250                         detect: [],
14251         
14252         
14253                         /**
14254                          * Type based search formatting.
14255                          *
14256                          * The type based searching functions can be used to pre-format the
14257                          * data to be search on. For example, it can be used to strip HTML
14258                          * tags or to de-format telephone numbers for numeric only searching.
14259                          *
14260                          * Note that is a search is not defined for a column of a given type,
14261                          * no search formatting will be performed.
14262                          * 
14263                          * Pre-processing of searching data plug-ins - When you assign the sType
14264                          * for a column (or have it automatically detected for you by DataTables
14265                          * or a type detection plug-in), you will typically be using this for
14266                          * custom sorting, but it can also be used to provide custom searching
14267                          * by allowing you to pre-processing the data and returning the data in
14268                          * the format that should be searched upon. This is done by adding
14269                          * functions this object with a parameter name which matches the sType
14270                          * for that target column. This is the corollary of <i>afnSortData</i>
14271                          * for searching data.
14272                          *
14273                          * The functions defined take a single parameter:
14274                          *
14275                      *  1. `{*}` Data from the column cell to be prepared for searching
14276                          *
14277                          * Each function is expected to return:
14278                          *
14279                          * * `{string|null}` Formatted string that will be used for the searching.
14280                          *
14281                          *  @type object
14282                          *  @default {}
14283                          *
14284                          *  @example
14285                          *    $.fn.dataTable.ext.type.search['title-numeric'] = function ( d ) {
14286                          *      return d.replace(/\n/g," ").replace( /<.*?>/g, "" );
14287                          *    }
14288                          */
14289                         search: {},
14290         
14291         
14292                         /**
14293                          * Type based ordering.
14294                          *
14295                          * The column type tells DataTables what ordering to apply to the table
14296                          * when a column is sorted upon. The order for each type that is defined,
14297                          * is defined by the functions available in this object.
14298                          *
14299                          * Each ordering option can be described by three properties added to
14300                          * this object:
14301                          *
14302                          * * `{type}-pre` - Pre-formatting function
14303                          * * `{type}-asc` - Ascending order function
14304                          * * `{type}-desc` - Descending order function
14305                          *
14306                          * All three can be used together, only `{type}-pre` or only
14307                          * `{type}-asc` and `{type}-desc` together. It is generally recommended
14308                          * that only `{type}-pre` is used, as this provides the optimal
14309                          * implementation in terms of speed, although the others are provided
14310                          * for compatibility with existing Javascript sort functions.
14311                          *
14312                          * `{type}-pre`: Functions defined take a single parameter:
14313                          *
14314                      *  1. `{*}` Data from the column cell to be prepared for ordering
14315                          *
14316                          * And return:
14317                          *
14318                          * * `{*}` Data to be sorted upon
14319                          *
14320                          * `{type}-asc` and `{type}-desc`: Functions are typical Javascript sort
14321                          * functions, taking two parameters:
14322                          *
14323                      *  1. `{*}` Data to compare to the second parameter
14324                      *  2. `{*}` Data to compare to the first parameter
14325                          *
14326                          * And returning:
14327                          *
14328                          * * `{*}` Ordering match: <0 if first parameter should be sorted lower
14329                          *   than the second parameter, ===0 if the two parameters are equal and
14330                          *   >0 if the first parameter should be sorted height than the second
14331                          *   parameter.
14332                          * 
14333                          *  @type object
14334                          *  @default {}
14335                          *
14336                          *  @example
14337                          *    // Numeric ordering of formatted numbers with a pre-formatter
14338                          *    $.extend( $.fn.dataTable.ext.type.order, {
14339                          *      "string-pre": function(x) {
14340                          *        a = (a === "-" || a === "") ? 0 : a.replace( /[^\d\-\.]/g, "" );
14341                          *        return parseFloat( a );
14342                          *      }
14343                          *    } );
14344                          *
14345                          *  @example
14346                          *    // Case-sensitive string ordering, with no pre-formatting method
14347                          *    $.extend( $.fn.dataTable.ext.order, {
14348                          *      "string-case-asc": function(x,y) {
14349                          *        return ((x < y) ? -1 : ((x > y) ? 1 : 0));
14350                          *      },
14351                          *      "string-case-desc": function(x,y) {
14352                          *        return ((x < y) ? 1 : ((x > y) ? -1 : 0));
14353                          *      }
14354                          *    } );
14355                          */
14356                         order: {}
14357                 },
14358         
14359                 /**
14360                  * Unique DataTables instance counter
14361                  *
14362                  * @type int
14363                  * @private
14364                  */
14365                 _unique: 0,
14366         
14367         
14368                 //
14369                 // Depreciated
14370                 // The following properties are retained for backwards compatiblity only.
14371                 // The should not be used in new projects and will be removed in a future
14372                 // version
14373                 //
14374         
14375                 /**
14376                  * Version check function.
14377                  *  @type function
14378                  *  @depreciated Since 1.10
14379                  */
14380                 fnVersionCheck: DataTable.fnVersionCheck,
14381         
14382         
14383                 /**
14384                  * Index for what 'this' index API functions should use
14385                  *  @type int
14386                  *  @deprecated Since v1.10
14387                  */
14388                 iApiIndex: 0,
14389         
14390         
14391                 /**
14392                  * jQuery UI class container
14393                  *  @type object
14394                  *  @deprecated Since v1.10
14395                  */
14396                 oJUIClasses: {},
14397         
14398         
14399                 /**
14400                  * Software version
14401                  *  @type string
14402                  *  @deprecated Since v1.10
14403                  */
14404                 sVersion: DataTable.version
14405         };
14406         
14407         
14408         //
14409         // Backwards compatibility. Alias to pre 1.10 Hungarian notation counter parts
14410         //
14411         $.extend( _ext, {
14412                 afnFiltering: _ext.search,
14413                 aTypes:       _ext.type.detect,
14414                 ofnSearch:    _ext.type.search,
14415                 oSort:        _ext.type.order,
14416                 afnSortData:  _ext.order,
14417                 aoFeatures:   _ext.feature,
14418                 oApi:         _ext.internal,
14419                 oStdClasses:  _ext.classes,
14420                 oPagination:  _ext.pager
14421         } );
14422         
14423         
14424         $.extend( DataTable.ext.classes, {
14425                 "sTable": "dataTable",
14426                 "sNoFooter": "no-footer",
14427         
14428                 /* Paging buttons */
14429                 "sPageButton": "paginate_button",
14430                 "sPageButtonActive": "current",
14431                 "sPageButtonDisabled": "disabled",
14432         
14433                 /* Striping classes */
14434                 "sStripeOdd": "odd",
14435                 "sStripeEven": "even",
14436         
14437                 /* Empty row */
14438                 "sRowEmpty": "dataTables_empty",
14439         
14440                 /* Features */
14441                 "sWrapper": "dataTables_wrapper",
14442                 "sFilter": "dataTables_filter",
14443                 "sInfo": "dataTables_info",
14444                 "sPaging": "dataTables_paginate paging_", /* Note that the type is postfixed */
14445                 "sLength": "dataTables_length",
14446                 "sProcessing": "dataTables_processing",
14447         
14448                 /* Sorting */
14449                 "sSortAsc": "sorting_asc",
14450                 "sSortDesc": "sorting_desc",
14451                 "sSortable": "sorting", /* Sortable in both directions */
14452                 "sSortableAsc": "sorting_asc_disabled",
14453                 "sSortableDesc": "sorting_desc_disabled",
14454                 "sSortableNone": "sorting_disabled",
14455                 "sSortColumn": "sorting_", /* Note that an int is postfixed for the sorting order */
14456         
14457                 /* Filtering */
14458                 "sFilterInput": "",
14459         
14460                 /* Page length */
14461                 "sLengthSelect": "",
14462         
14463                 /* Scrolling */
14464                 "sScrollWrapper": "dataTables_scroll",
14465                 "sScrollHead": "dataTables_scrollHead",
14466                 "sScrollHeadInner": "dataTables_scrollHeadInner",
14467                 "sScrollBody": "dataTables_scrollBody",
14468                 "sScrollFoot": "dataTables_scrollFoot",
14469                 "sScrollFootInner": "dataTables_scrollFootInner",
14470         
14471                 /* Misc */
14472                 "sHeaderTH": "",
14473                 "sFooterTH": "",
14474         
14475                 // Deprecated
14476                 "sSortJUIAsc": "",
14477                 "sSortJUIDesc": "",
14478                 "sSortJUI": "",
14479                 "sSortJUIAscAllowed": "",
14480                 "sSortJUIDescAllowed": "",
14481                 "sSortJUIWrapper": "",
14482                 "sSortIcon": "",
14483                 "sJUIHeader": "",
14484                 "sJUIFooter": ""
14485         } );
14486         
14487         
14488         var extPagination = DataTable.ext.pager;
14489         
14490         function _numbers ( page, pages ) {
14491                 var
14492                         numbers = [],
14493                         buttons = extPagination.numbers_length,
14494                         half = Math.floor( buttons / 2 ),
14495                         i = 1;
14496         
14497                 if ( pages <= buttons ) {
14498                         numbers = _range( 0, pages );
14499                 }
14500                 else if ( page <= half ) {
14501                         numbers = _range( 0, buttons-2 );
14502                         numbers.push( 'ellipsis' );
14503                         numbers.push( pages-1 );
14504                 }
14505                 else if ( page >= pages - 1 - half ) {
14506                         numbers = _range( pages-(buttons-2), pages );
14507                         numbers.splice( 0, 0, 'ellipsis' ); // no unshift in ie6
14508                         numbers.splice( 0, 0, 0 );
14509                 }
14510                 else {
14511                         numbers = _range( page-half+2, page+half-1 );
14512                         numbers.push( 'ellipsis' );
14513                         numbers.push( pages-1 );
14514                         numbers.splice( 0, 0, 'ellipsis' );
14515                         numbers.splice( 0, 0, 0 );
14516                 }
14517         
14518                 numbers.DT_el = 'span';
14519                 return numbers;
14520         }
14521         
14522         
14523         $.extend( extPagination, {
14524                 simple: function ( page, pages ) {
14525                         return [ 'previous', 'next' ];
14526                 },
14527         
14528                 full: function ( page, pages ) {
14529                         return [  'first', 'previous', 'next', 'last' ];
14530                 },
14531         
14532                 numbers: function ( page, pages ) {
14533                         return [ _numbers(page, pages) ];
14534                 },
14535         
14536                 simple_numbers: function ( page, pages ) {
14537                         return [ 'previous', _numbers(page, pages), 'next' ];
14538                 },
14539         
14540                 full_numbers: function ( page, pages ) {
14541                         return [ 'first', 'previous', _numbers(page, pages), 'next', 'last' ];
14542                 },
14543                 
14544                 first_last_numbers: function (page, pages) {
14545                         return ['first', _numbers(page, pages), 'last'];
14546                 },
14547         
14548                 // For testing and plug-ins to use
14549                 _numbers: _numbers,
14550         
14551                 // Number of number buttons (including ellipsis) to show. _Must be odd!_
14552                 numbers_length: 7
14553         } );
14554         
14555         
14556         $.extend( true, DataTable.ext.renderer, {
14557                 pageButton: {
14558                         _: function ( settings, host, idx, buttons, page, pages ) {
14559                                 var classes = settings.oClasses;
14560                                 var lang = settings.oLanguage.oPaginate;
14561                                 var aria = settings.oLanguage.oAria.paginate || {};
14562                                 var btnDisplay, btnClass, counter=0;
14563         
14564                                 var attach = function( container, buttons ) {
14565                                         var i, ien, node, button, tabIndex;
14566                                         var disabledClass = classes.sPageButtonDisabled;
14567                                         var clickHandler = function ( e ) {
14568                                                 _fnPageChange( settings, e.data.action, true );
14569                                         };
14570         
14571                                         for ( i=0, ien=buttons.length ; i<ien ; i++ ) {
14572                                                 button = buttons[i];
14573         
14574                                                 if ( $.isArray( button ) ) {
14575                                                         var inner = $( '<'+(button.DT_el || 'div')+'/>' )
14576                                                                 .appendTo( container );
14577                                                         attach( inner, button );
14578                                                 }
14579                                                 else {
14580                                                         btnDisplay = null;
14581                                                         btnClass = button;
14582                                                         tabIndex = settings.iTabIndex;
14583         
14584                                                         switch ( button ) {
14585                                                                 case 'ellipsis':
14586                                                                         container.append('<span class="ellipsis">&#x2026;</span>');
14587                                                                         break;
14588         
14589                                                                 case 'first':
14590                                                                         btnDisplay = lang.sFirst;
14591         
14592                                                                         if ( page === 0 ) {
14593                                                                                 tabIndex = -1;
14594                                                                                 btnClass += ' ' + disabledClass;
14595                                                                         }
14596                                                                         break;
14597         
14598                                                                 case 'previous':
14599                                                                         btnDisplay = lang.sPrevious;
14600         
14601                                                                         if ( page === 0 ) {
14602                                                                                 tabIndex = -1;
14603                                                                                 btnClass += ' ' + disabledClass;
14604                                                                         }
14605                                                                         break;
14606         
14607                                                                 case 'next':
14608                                                                         btnDisplay = lang.sNext;
14609         
14610                                                                         if ( page === pages-1 ) {
14611                                                                                 tabIndex = -1;
14612                                                                                 btnClass += ' ' + disabledClass;
14613                                                                         }
14614                                                                         break;
14615         
14616                                                                 case 'last':
14617                                                                         btnDisplay = lang.sLast;
14618         
14619                                                                         if ( page === pages-1 ) {
14620                                                                                 tabIndex = -1;
14621                                                                                 btnClass += ' ' + disabledClass;
14622                                                                         }
14623                                                                         break;
14624         
14625                                                                 default:
14626                                                                         btnDisplay = button + 1;
14627                                                                         btnClass = page === button ?
14628                                                                                 classes.sPageButtonActive : '';
14629                                                                         break;
14630                                                         }
14631         
14632                                                         if ( btnDisplay !== null ) {
14633                                                                 node = $('<a>', {
14634                                                                                 'class': classes.sPageButton+' '+btnClass,
14635                                                                                 'aria-controls': settings.sTableId,
14636                                                                                 'aria-label': aria[ button ],
14637                                                                                 'data-dt-idx': counter,
14638                                                                                 'tabindex': tabIndex,
14639                                                                                 'id': idx === 0 && typeof button === 'string' ?
14640                                                                                         settings.sTableId +'_'+ button :
14641                                                                                         null
14642                                                                         } )
14643                                                                         .html( btnDisplay )
14644                                                                         .appendTo( container );
14645         
14646                                                                 _fnBindAction(
14647                                                                         node, {action: button}, clickHandler
14648                                                                 );
14649         
14650                                                                 counter++;
14651                                                         }
14652                                                 }
14653                                         }
14654                                 };
14655         
14656                                 // IE9 throws an 'unknown error' if document.activeElement is used
14657                                 // inside an iframe or frame. Try / catch the error. Not good for
14658                                 // accessibility, but neither are frames.
14659                                 var activeEl;
14660         
14661                                 try {
14662                                         // Because this approach is destroying and recreating the paging
14663                                         // elements, focus is lost on the select button which is bad for
14664                                         // accessibility. So we want to restore focus once the draw has
14665                                         // completed
14666                                         activeEl = $(host).find(document.activeElement).data('dt-idx');
14667                                 }
14668                                 catch (e) {}
14669         
14670                                 attach( $(host).empty(), buttons );
14671         
14672                                 if ( activeEl !== undefined ) {
14673                                         $(host).find( '[data-dt-idx='+activeEl+']' ).focus();
14674                                 }
14675                         }
14676                 }
14677         } );
14678         
14679         
14680         
14681         // Built in type detection. See model.ext.aTypes for information about
14682         // what is required from this methods.
14683         $.extend( DataTable.ext.type.detect, [
14684                 // Plain numbers - first since V8 detects some plain numbers as dates
14685                 // e.g. Date.parse('55') (but not all, e.g. Date.parse('22')...).
14686                 function ( d, settings )
14687                 {
14688                         var decimal = settings.oLanguage.sDecimal;
14689                         return _isNumber( d, decimal ) ? 'num'+decimal : null;
14690                 },
14691         
14692                 // Dates (only those recognised by the browser's Date.parse)
14693                 function ( d, settings )
14694                 {
14695                         // V8 tries _very_ hard to make a string passed into `Date.parse()`
14696                         // valid, so we need to use a regex to restrict date formats. Use a
14697                         // plug-in for anything other than ISO8601 style strings
14698                         if ( d && !(d instanceof Date) && ! _re_date.test(d) ) {
14699                                 return null;
14700                         }
14701                         var parsed = Date.parse(d);
14702                         return (parsed !== null && !isNaN(parsed)) || _empty(d) ? 'date' : null;
14703                 },
14704         
14705                 // Formatted numbers
14706                 function ( d, settings )
14707                 {
14708                         var decimal = settings.oLanguage.sDecimal;
14709                         return _isNumber( d, decimal, true ) ? 'num-fmt'+decimal : null;
14710                 },
14711         
14712                 // HTML numeric
14713                 function ( d, settings )
14714                 {
14715                         var decimal = settings.oLanguage.sDecimal;
14716                         return _htmlNumeric( d, decimal ) ? 'html-num'+decimal : null;
14717                 },
14718         
14719                 // HTML numeric, formatted
14720                 function ( d, settings )
14721                 {
14722                         var decimal = settings.oLanguage.sDecimal;
14723                         return _htmlNumeric( d, decimal, true ) ? 'html-num-fmt'+decimal : null;
14724                 },
14725         
14726                 // HTML (this is strict checking - there must be html)
14727                 function ( d, settings )
14728                 {
14729                         return _empty( d ) || (typeof d === 'string' && d.indexOf('<') !== -1) ?
14730                                 'html' : null;
14731                 }
14732         ] );
14733         
14734         
14735         
14736         // Filter formatting functions. See model.ext.ofnSearch for information about
14737         // what is required from these methods.
14738         // 
14739         // Note that additional search methods are added for the html numbers and
14740         // html formatted numbers by `_addNumericSort()` when we know what the decimal
14741         // place is
14742         
14743         
14744         $.extend( DataTable.ext.type.search, {
14745                 html: function ( data ) {
14746                         return _empty(data) ?
14747                                 data :
14748                                 typeof data === 'string' ?
14749                                         data
14750                                                 .replace( _re_new_lines, " " )
14751                                                 .replace( _re_html, "" ) :
14752                                         '';
14753                 },
14754         
14755                 string: function ( data ) {
14756                         return _empty(data) ?
14757                                 data :
14758                                 typeof data === 'string' ?
14759                                         data.replace( _re_new_lines, " " ) :
14760                                         data;
14761                 }
14762         } );
14763         
14764         
14765         
14766         var __numericReplace = function ( d, decimalPlace, re1, re2 ) {
14767                 if ( d !== 0 && (!d || d === '-') ) {
14768                         return -Infinity;
14769                 }
14770         
14771                 // If a decimal place other than `.` is used, it needs to be given to the
14772                 // function so we can detect it and replace with a `.` which is the only
14773                 // decimal place Javascript recognises - it is not locale aware.
14774                 if ( decimalPlace ) {
14775                         d = _numToDecimal( d, decimalPlace );
14776                 }
14777         
14778                 if ( d.replace ) {
14779                         if ( re1 ) {
14780                                 d = d.replace( re1, '' );
14781                         }
14782         
14783                         if ( re2 ) {
14784                                 d = d.replace( re2, '' );
14785                         }
14786                 }
14787         
14788                 return d * 1;
14789         };
14790         
14791         
14792         // Add the numeric 'deformatting' functions for sorting and search. This is done
14793         // in a function to provide an easy ability for the language options to add
14794         // additional methods if a non-period decimal place is used.
14795         function _addNumericSort ( decimalPlace ) {
14796                 $.each(
14797                         {
14798                                 // Plain numbers
14799                                 "num": function ( d ) {
14800                                         return __numericReplace( d, decimalPlace );
14801                                 },
14802         
14803                                 // Formatted numbers
14804                                 "num-fmt": function ( d ) {
14805                                         return __numericReplace( d, decimalPlace, _re_formatted_numeric );
14806                                 },
14807         
14808                                 // HTML numeric
14809                                 "html-num": function ( d ) {
14810                                         return __numericReplace( d, decimalPlace, _re_html );
14811                                 },
14812         
14813                                 // HTML numeric, formatted
14814                                 "html-num-fmt": function ( d ) {
14815                                         return __numericReplace( d, decimalPlace, _re_html, _re_formatted_numeric );
14816                                 }
14817                         },
14818                         function ( key, fn ) {
14819                                 // Add the ordering method
14820                                 _ext.type.order[ key+decimalPlace+'-pre' ] = fn;
14821         
14822                                 // For HTML types add a search formatter that will strip the HTML
14823                                 if ( key.match(/^html\-/) ) {
14824                                         _ext.type.search[ key+decimalPlace ] = _ext.type.search.html;
14825                                 }
14826                         }
14827                 );
14828         }
14829         
14830         
14831         // Default sort methods
14832         $.extend( _ext.type.order, {
14833                 // Dates
14834                 "date-pre": function ( d ) {
14835                         var ts = Date.parse( d );
14836                         return isNaN(ts) ? -Infinity : ts;
14837                 },
14838         
14839                 // html
14840                 "html-pre": function ( a ) {
14841                         return _empty(a) ?
14842                                 '' :
14843                                 a.replace ?
14844                                         a.replace( /<.*?>/g, "" ).toLowerCase() :
14845                                         a+'';
14846                 },
14847         
14848                 // string
14849                 "string-pre": function ( a ) {
14850                         // This is a little complex, but faster than always calling toString,
14851                         // http://jsperf.com/tostring-v-check
14852                         return _empty(a) ?
14853                                 '' :
14854                                 typeof a === 'string' ?
14855                                         a.toLowerCase() :
14856                                         ! a.toString ?
14857                                                 '' :
14858                                                 a.toString();
14859                 },
14860         
14861                 // string-asc and -desc are retained only for compatibility with the old
14862                 // sort methods
14863                 "string-asc": function ( x, y ) {
14864                         return ((x < y) ? -1 : ((x > y) ? 1 : 0));
14865                 },
14866         
14867                 "string-desc": function ( x, y ) {
14868                         return ((x < y) ? 1 : ((x > y) ? -1 : 0));
14869                 }
14870         } );
14871         
14872         
14873         // Numeric sorting types - order doesn't matter here
14874         _addNumericSort( '' );
14875         
14876         
14877         $.extend( true, DataTable.ext.renderer, {
14878                 header: {
14879                         _: function ( settings, cell, column, classes ) {
14880                                 // No additional mark-up required
14881                                 // Attach a sort listener to update on sort - note that using the
14882                                 // `DT` namespace will allow the event to be removed automatically
14883                                 // on destroy, while the `dt` namespaced event is the one we are
14884                                 // listening for
14885                                 $(settings.nTable).on( 'order.dt.DT', function ( e, ctx, sorting, columns ) {
14886                                         if ( settings !== ctx ) { // need to check this this is the host
14887                                                 return;               // table, not a nested one
14888                                         }
14889         
14890                                         var colIdx = column.idx;
14891         
14892                                         cell
14893                                                 .removeClass(
14894                                                         column.sSortingClass +' '+
14895                                                         classes.sSortAsc +' '+
14896                                                         classes.sSortDesc
14897                                                 )
14898                                                 .addClass( columns[ colIdx ] == 'asc' ?
14899                                                         classes.sSortAsc : columns[ colIdx ] == 'desc' ?
14900                                                                 classes.sSortDesc :
14901                                                                 column.sSortingClass
14902                                                 );
14903                                 } );
14904                         },
14905         
14906                         jqueryui: function ( settings, cell, column, classes ) {
14907                                 $('<div/>')
14908                                         .addClass( classes.sSortJUIWrapper )
14909                                         .append( cell.contents() )
14910                                         .append( $('<span/>')
14911                                                 .addClass( classes.sSortIcon+' '+column.sSortingClassJUI )
14912                                         )
14913                                         .appendTo( cell );
14914         
14915                                 // Attach a sort listener to update on sort
14916                                 $(settings.nTable).on( 'order.dt.DT', function ( e, ctx, sorting, columns ) {
14917                                         if ( settings !== ctx ) {
14918                                                 return;
14919                                         }
14920         
14921                                         var colIdx = column.idx;
14922         
14923                                         cell
14924                                                 .removeClass( classes.sSortAsc +" "+classes.sSortDesc )
14925                                                 .addClass( columns[ colIdx ] == 'asc' ?
14926                                                         classes.sSortAsc : columns[ colIdx ] == 'desc' ?
14927                                                                 classes.sSortDesc :
14928                                                                 column.sSortingClass
14929                                                 );
14930         
14931                                         cell
14932                                                 .find( 'span.'+classes.sSortIcon )
14933                                                 .removeClass(
14934                                                         classes.sSortJUIAsc +" "+
14935                                                         classes.sSortJUIDesc +" "+
14936                                                         classes.sSortJUI +" "+
14937                                                         classes.sSortJUIAscAllowed +" "+
14938                                                         classes.sSortJUIDescAllowed
14939                                                 )
14940                                                 .addClass( columns[ colIdx ] == 'asc' ?
14941                                                         classes.sSortJUIAsc : columns[ colIdx ] == 'desc' ?
14942                                                                 classes.sSortJUIDesc :
14943                                                                 column.sSortingClassJUI
14944                                                 );
14945                                 } );
14946                         }
14947                 }
14948         } );
14949         
14950         /*
14951          * Public helper functions. These aren't used internally by DataTables, or
14952          * called by any of the options passed into DataTables, but they can be used
14953          * externally by developers working with DataTables. They are helper functions
14954          * to make working with DataTables a little bit easier.
14955          */
14956         
14957         var __htmlEscapeEntities = function ( d ) {
14958                 return typeof d === 'string' ?
14959                         d.replace(/</g, '&lt;').replace(/>/g, '&gt;').replace(/"/g, '&quot;') :
14960                         d;
14961         };
14962         
14963         /**
14964          * Helpers for `columns.render`.
14965          *
14966          * The options defined here can be used with the `columns.render` initialisation
14967          * option to provide a display renderer. The following functions are defined:
14968          *
14969          * * `number` - Will format numeric data (defined by `columns.data`) for
14970          *   display, retaining the original unformatted data for sorting and filtering.
14971          *   It takes 5 parameters:
14972          *   * `string` - Thousands grouping separator
14973          *   * `string` - Decimal point indicator
14974          *   * `integer` - Number of decimal points to show
14975          *   * `string` (optional) - Prefix.
14976          *   * `string` (optional) - Postfix (/suffix).
14977          * * `text` - Escape HTML to help prevent XSS attacks. It has no optional
14978          *   parameters.
14979          *
14980          * @example
14981          *   // Column definition using the number renderer
14982          *   {
14983          *     data: "salary",
14984          *     render: $.fn.dataTable.render.number( '\'', '.', 0, '$' )
14985          *   }
14986          *
14987          * @namespace
14988          */
14989         DataTable.render = {
14990                 number: function ( thousands, decimal, precision, prefix, postfix ) {
14991                         return {
14992                                 display: function ( d ) {
14993                                         if ( typeof d !== 'number' && typeof d !== 'string' ) {
14994                                                 return d;
14995                                         }
14996         
14997                                         var negative = d < 0 ? '-' : '';
14998                                         var flo = parseFloat( d );
14999         
15000                                         // If NaN then there isn't much formatting that we can do - just
15001                                         // return immediately, escaping any HTML (this was supposed to
15002                                         // be a number after all)
15003                                         if ( isNaN( flo ) ) {
15004                                                 return __htmlEscapeEntities( d );
15005                                         }
15006         
15007                                         flo = flo.toFixed( precision );
15008                                         d = Math.abs( flo );
15009         
15010                                         var intPart = parseInt( d, 10 );
15011                                         var floatPart = precision ?
15012                                                 decimal+(d - intPart).toFixed( precision ).substring( 2 ):
15013                                                 '';
15014         
15015                                         return negative + (prefix||'') +
15016                                                 intPart.toString().replace(
15017                                                         /\B(?=(\d{3})+(?!\d))/g, thousands
15018                                                 ) +
15019                                                 floatPart +
15020                                                 (postfix||'');
15021                                 }
15022                         };
15023                 },
15024         
15025                 text: function () {
15026                         return {
15027                                 display: __htmlEscapeEntities,
15028                                 filter: __htmlEscapeEntities
15029                         };
15030                 }
15031         };
15032         
15033         
15034         /*
15035          * This is really a good bit rubbish this method of exposing the internal methods
15036          * publicly... - To be fixed in 2.0 using methods on the prototype
15037          */
15038         
15039         
15040         /**
15041          * Create a wrapper function for exporting an internal functions to an external API.
15042          *  @param {string} fn API function name
15043          *  @returns {function} wrapped function
15044          *  @memberof DataTable#internal
15045          */
15046         function _fnExternApiFunc (fn)
15047         {
15048                 return function() {
15049                         var args = [_fnSettingsFromNode( this[DataTable.ext.iApiIndex] )].concat(
15050                                 Array.prototype.slice.call(arguments)
15051                         );
15052                         return DataTable.ext.internal[fn].apply( this, args );
15053                 };
15054         }
15055         
15056         
15057         /**
15058          * Reference to internal functions for use by plug-in developers. Note that
15059          * these methods are references to internal functions and are considered to be
15060          * private. If you use these methods, be aware that they are liable to change
15061          * between versions.
15062          *  @namespace
15063          */
15064         $.extend( DataTable.ext.internal, {
15065                 _fnExternApiFunc: _fnExternApiFunc,
15066                 _fnBuildAjax: _fnBuildAjax,
15067                 _fnAjaxUpdate: _fnAjaxUpdate,
15068                 _fnAjaxParameters: _fnAjaxParameters,
15069                 _fnAjaxUpdateDraw: _fnAjaxUpdateDraw,
15070                 _fnAjaxDataSrc: _fnAjaxDataSrc,
15071                 _fnAddColumn: _fnAddColumn,
15072                 _fnColumnOptions: _fnColumnOptions,
15073                 _fnAdjustColumnSizing: _fnAdjustColumnSizing,
15074                 _fnVisibleToColumnIndex: _fnVisibleToColumnIndex,
15075                 _fnColumnIndexToVisible: _fnColumnIndexToVisible,
15076                 _fnVisbleColumns: _fnVisbleColumns,
15077                 _fnGetColumns: _fnGetColumns,
15078                 _fnColumnTypes: _fnColumnTypes,
15079                 _fnApplyColumnDefs: _fnApplyColumnDefs,
15080                 _fnHungarianMap: _fnHungarianMap,
15081                 _fnCamelToHungarian: _fnCamelToHungarian,
15082                 _fnLanguageCompat: _fnLanguageCompat,
15083                 _fnBrowserDetect: _fnBrowserDetect,
15084                 _fnAddData: _fnAddData,
15085                 _fnAddTr: _fnAddTr,
15086                 _fnNodeToDataIndex: _fnNodeToDataIndex,
15087                 _fnNodeToColumnIndex: _fnNodeToColumnIndex,
15088                 _fnGetCellData: _fnGetCellData,
15089                 _fnSetCellData: _fnSetCellData,
15090                 _fnSplitObjNotation: _fnSplitObjNotation,
15091                 _fnGetObjectDataFn: _fnGetObjectDataFn,
15092                 _fnSetObjectDataFn: _fnSetObjectDataFn,
15093                 _fnGetDataMaster: _fnGetDataMaster,
15094                 _fnClearTable: _fnClearTable,
15095                 _fnDeleteIndex: _fnDeleteIndex,
15096                 _fnInvalidate: _fnInvalidate,
15097                 _fnGetRowElements: _fnGetRowElements,
15098                 _fnCreateTr: _fnCreateTr,
15099                 _fnBuildHead: _fnBuildHead,
15100                 _fnDrawHead: _fnDrawHead,
15101                 _fnDraw: _fnDraw,
15102                 _fnReDraw: _fnReDraw,
15103                 _fnAddOptionsHtml: _fnAddOptionsHtml,
15104                 _fnDetectHeader: _fnDetectHeader,
15105                 _fnGetUniqueThs: _fnGetUniqueThs,
15106                 _fnFeatureHtmlFilter: _fnFeatureHtmlFilter,
15107                 _fnFilterComplete: _fnFilterComplete,
15108                 _fnFilterCustom: _fnFilterCustom,
15109                 _fnFilterColumn: _fnFilterColumn,
15110                 _fnFilter: _fnFilter,
15111                 _fnFilterCreateSearch: _fnFilterCreateSearch,
15112                 _fnEscapeRegex: _fnEscapeRegex,
15113                 _fnFilterData: _fnFilterData,
15114                 _fnFeatureHtmlInfo: _fnFeatureHtmlInfo,
15115                 _fnUpdateInfo: _fnUpdateInfo,
15116                 _fnInfoMacros: _fnInfoMacros,
15117                 _fnInitialise: _fnInitialise,
15118                 _fnInitComplete: _fnInitComplete,
15119                 _fnLengthChange: _fnLengthChange,
15120                 _fnFeatureHtmlLength: _fnFeatureHtmlLength,
15121                 _fnFeatureHtmlPaginate: _fnFeatureHtmlPaginate,
15122                 _fnPageChange: _fnPageChange,
15123                 _fnFeatureHtmlProcessing: _fnFeatureHtmlProcessing,
15124                 _fnProcessingDisplay: _fnProcessingDisplay,
15125                 _fnFeatureHtmlTable: _fnFeatureHtmlTable,
15126                 _fnScrollDraw: _fnScrollDraw,
15127                 _fnApplyToChildren: _fnApplyToChildren,
15128                 _fnCalculateColumnWidths: _fnCalculateColumnWidths,
15129                 _fnThrottle: _fnThrottle,
15130                 _fnConvertToWidth: _fnConvertToWidth,
15131                 _fnGetWidestNode: _fnGetWidestNode,
15132                 _fnGetMaxLenString: _fnGetMaxLenString,
15133                 _fnStringToCss: _fnStringToCss,
15134                 _fnSortFlatten: _fnSortFlatten,
15135                 _fnSort: _fnSort,
15136                 _fnSortAria: _fnSortAria,
15137                 _fnSortListener: _fnSortListener,
15138                 _fnSortAttachListener: _fnSortAttachListener,
15139                 _fnSortingClasses: _fnSortingClasses,
15140                 _fnSortData: _fnSortData,
15141                 _fnSaveState: _fnSaveState,
15142                 _fnLoadState: _fnLoadState,
15143                 _fnSettingsFromNode: _fnSettingsFromNode,
15144                 _fnLog: _fnLog,
15145                 _fnMap: _fnMap,
15146                 _fnBindAction: _fnBindAction,
15147                 _fnCallbackReg: _fnCallbackReg,
15148                 _fnCallbackFire: _fnCallbackFire,
15149                 _fnLengthOverflow: _fnLengthOverflow,
15150                 _fnRenderer: _fnRenderer,
15151                 _fnDataSource: _fnDataSource,
15152                 _fnRowAttributes: _fnRowAttributes,
15153                 _fnExtend: _fnExtend,
15154                 _fnCalculateEnd: function () {} // Used by a lot of plug-ins, but redundant
15155                                                 // in 1.10, so this dead-end function is
15156                                                 // added to prevent errors
15157         } );
15158         
15159
15160         // jQuery access
15161         $.fn.dataTable = DataTable;
15162
15163         // Provide access to the host jQuery object (circular reference)
15164         DataTable.$ = $;
15165
15166         // Legacy aliases
15167         $.fn.dataTableSettings = DataTable.settings;
15168         $.fn.dataTableExt = DataTable.ext;
15169
15170         // With a capital `D` we return a DataTables API instance rather than a
15171         // jQuery object
15172         $.fn.DataTable = function ( opts ) {
15173                 return $(this).dataTable( opts ).api();
15174         };
15175
15176         // All properties that are available to $.fn.dataTable should also be
15177         // available on $.fn.DataTable
15178         $.each( DataTable, function ( prop, val ) {
15179                 $.fn.DataTable[ prop ] = val;
15180         } );
15181
15182
15183         // Information about events fired by DataTables - for documentation.
15184         /**
15185          * Draw event, fired whenever the table is redrawn on the page, at the same
15186          * point as fnDrawCallback. This may be useful for binding events or
15187          * performing calculations when the table is altered at all.
15188          *  @name DataTable#draw.dt
15189          *  @event
15190          *  @param {event} e jQuery event object
15191          *  @param {object} o DataTables settings object {@link DataTable.models.oSettings}
15192          */
15193
15194         /**
15195          * Search event, fired when the searching applied to the table (using the
15196          * built-in global search, or column filters) is altered.
15197          *  @name DataTable#search.dt
15198          *  @event
15199          *  @param {event} e jQuery event object
15200          *  @param {object} o DataTables settings object {@link DataTable.models.oSettings}
15201          */
15202
15203         /**
15204          * Page change event, fired when the paging of the table is altered.
15205          *  @name DataTable#page.dt
15206          *  @event
15207          *  @param {event} e jQuery event object
15208          *  @param {object} o DataTables settings object {@link DataTable.models.oSettings}
15209          */
15210
15211         /**
15212          * Order event, fired when the ordering applied to the table is altered.
15213          *  @name DataTable#order.dt
15214          *  @event
15215          *  @param {event} e jQuery event object
15216          *  @param {object} o DataTables settings object {@link DataTable.models.oSettings}
15217          */
15218
15219         /**
15220          * DataTables initialisation complete event, fired when the table is fully
15221          * drawn, including Ajax data loaded, if Ajax data is required.
15222          *  @name DataTable#init.dt
15223          *  @event
15224          *  @param {event} e jQuery event object
15225          *  @param {object} oSettings DataTables settings object
15226          *  @param {object} json The JSON object request from the server - only
15227          *    present if client-side Ajax sourced data is used</li></ol>
15228          */
15229
15230         /**
15231          * State save event, fired when the table has changed state a new state save
15232          * is required. This event allows modification of the state saving object
15233          * prior to actually doing the save, including addition or other state
15234          * properties (for plug-ins) or modification of a DataTables core property.
15235          *  @name DataTable#stateSaveParams.dt
15236          *  @event
15237          *  @param {event} e jQuery event object
15238          *  @param {object} oSettings DataTables settings object
15239          *  @param {object} json The state information to be saved
15240          */
15241
15242         /**
15243          * State load event, fired when the table is loading state from the stored
15244          * data, but prior to the settings object being modified by the saved state
15245          * - allowing modification of the saved state is required or loading of
15246          * state for a plug-in.
15247          *  @name DataTable#stateLoadParams.dt
15248          *  @event
15249          *  @param {event} e jQuery event object
15250          *  @param {object} oSettings DataTables settings object
15251          *  @param {object} json The saved state information
15252          */
15253
15254         /**
15255          * State loaded event, fired when state has been loaded from stored data and
15256          * the settings object has been modified by the loaded data.
15257          *  @name DataTable#stateLoaded.dt
15258          *  @event
15259          *  @param {event} e jQuery event object
15260          *  @param {object} oSettings DataTables settings object
15261          *  @param {object} json The saved state information
15262          */
15263
15264         /**
15265          * Processing event, fired when DataTables is doing some kind of processing
15266          * (be it, order, search or anything else). It can be used to indicate to
15267          * the end user that there is something happening, or that something has
15268          * finished.
15269          *  @name DataTable#processing.dt
15270          *  @event
15271          *  @param {event} e jQuery event object
15272          *  @param {object} oSettings DataTables settings object
15273          *  @param {boolean} bShow Flag for if DataTables is doing processing or not
15274          */
15275
15276         /**
15277          * Ajax (XHR) event, fired whenever an Ajax request is completed from a
15278          * request to made to the server for new data. This event is called before
15279          * DataTables processed the returned data, so it can also be used to pre-
15280          * process the data returned from the server, if needed.
15281          *
15282          * Note that this trigger is called in `fnServerData`, if you override
15283          * `fnServerData` and which to use this event, you need to trigger it in you
15284          * success function.
15285          *  @name DataTable#xhr.dt
15286          *  @event
15287          *  @param {event} e jQuery event object
15288          *  @param {object} o DataTables settings object {@link DataTable.models.oSettings}
15289          *  @param {object} json JSON returned from the server
15290          *
15291          *  @example
15292          *     // Use a custom property returned from the server in another DOM element
15293          *     $('#table').dataTable().on('xhr.dt', function (e, settings, json) {
15294          *       $('#status').html( json.status );
15295          *     } );
15296          *
15297          *  @example
15298          *     // Pre-process the data returned from the server
15299          *     $('#table').dataTable().on('xhr.dt', function (e, settings, json) {
15300          *       for ( var i=0, ien=json.aaData.length ; i<ien ; i++ ) {
15301          *         json.aaData[i].sum = json.aaData[i].one + json.aaData[i].two;
15302          *       }
15303          *       // Note no return - manipulate the data directly in the JSON object.
15304          *     } );
15305          */
15306
15307         /**
15308          * Destroy event, fired when the DataTable is destroyed by calling fnDestroy
15309          * or passing the bDestroy:true parameter in the initialisation object. This
15310          * can be used to remove bound events, added DOM nodes, etc.
15311          *  @name DataTable#destroy.dt
15312          *  @event
15313          *  @param {event} e jQuery event object
15314          *  @param {object} o DataTables settings object {@link DataTable.models.oSettings}
15315          */
15316
15317         /**
15318          * Page length change event, fired when number of records to show on each
15319          * page (the length) is changed.
15320          *  @name DataTable#length.dt
15321          *  @event
15322          *  @param {event} e jQuery event object
15323          *  @param {object} o DataTables settings object {@link DataTable.models.oSettings}
15324          *  @param {integer} len New length
15325          */
15326
15327         /**
15328          * Column sizing has changed.
15329          *  @name DataTable#column-sizing.dt
15330          *  @event
15331          *  @param {event} e jQuery event object
15332          *  @param {object} o DataTables settings object {@link DataTable.models.oSettings}
15333          */
15334
15335         /**
15336          * Column visibility has changed.
15337          *  @name DataTable#column-visibility.dt
15338          *  @event
15339          *  @param {event} e jQuery event object
15340          *  @param {object} o DataTables settings object {@link DataTable.models.oSettings}
15341          *  @param {int} column Column index
15342          *  @param {bool} vis `false` if column now hidden, or `true` if visible
15343          */
15344
15345         return $.fn.dataTable;
15346 }));
15347
15348
15349 /*! FixedColumns 3.3.0
15350  * ©2010-2018 SpryMedia Ltd - datatables.net/license
15351  */
15352
15353 /**
15354  * @summary     FixedColumns
15355  * @description Freeze columns in place on a scrolling DataTable
15356  * @version     3.3.0
15357  * @file        dataTables.fixedColumns.js
15358  * @author      SpryMedia Ltd (www.sprymedia.co.uk)
15359  * @contact     www.sprymedia.co.uk/contact
15360  * @copyright   Copyright 2010-2018 SpryMedia Ltd.
15361  *
15362  * This source file is free software, available under the following license:
15363  *   MIT license - http://datatables.net/license/mit
15364  *
15365  * This source file is distributed in the hope that it will be useful, but
15366  * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
15367  * or FITNESS FOR A PARTICULAR PURPOSE. See the license files for details.
15368  *
15369  * For details please refer to: http://www.datatables.net
15370  */
15371 (function( factory ){
15372         if ( typeof define === 'function' && define.amd ) {
15373                 // AMD
15374                 define( ['jquery', 'datatables.net'], function ( $ ) {
15375                         return factory( $, window, document );
15376                 } );
15377         }
15378         else if ( typeof exports === 'object' ) {
15379                 // CommonJS
15380                 module.exports = function (root, $) {
15381                         if ( ! root ) {
15382                                 root = window;
15383                         }
15384
15385                         if ( ! $ || ! $.fn.dataTable ) {
15386                                 $ = require('datatables.net')(root, $).$;
15387                         }
15388
15389                         return factory( $, root, root.document );
15390                 };
15391         }
15392         else {
15393                 // Browser
15394                 factory( jQuery, window, document );
15395         }
15396 }(function( $, window, document, undefined ) {
15397 'use strict';
15398 var DataTable = $.fn.dataTable;
15399 var _firefoxScroll;
15400
15401 /**
15402  * When making use of DataTables' x-axis scrolling feature, you may wish to
15403  * fix the left most column in place. This plug-in for DataTables provides
15404  * exactly this option (note for non-scrolling tables, please use the
15405  * FixedHeader plug-in, which can fix headers and footers). Key
15406  * features include:
15407  *
15408  * * Freezes the left or right most columns to the side of the table
15409  * * Option to freeze two or more columns
15410  * * Full integration with DataTables' scrolling options
15411  * * Speed - FixedColumns is fast in its operation
15412  *
15413  *  @class
15414  *  @constructor
15415  *  @global
15416  *  @param {object} dt DataTables instance. With DataTables 1.10 this can also
15417  *    be a jQuery collection, a jQuery selector, DataTables API instance or
15418  *    settings object.
15419  *  @param {object} [init={}] Configuration object for FixedColumns. Options are
15420  *    defined by {@link FixedColumns.defaults}
15421  *
15422  *  @requires jQuery 1.7+
15423  *  @requires DataTables 1.8.0+
15424  *
15425  *  @example
15426  *      var table = $('#example').dataTable( {
15427  *        "scrollX": "100%"
15428  *      } );
15429  *      new $.fn.dataTable.fixedColumns( table );
15430  */
15431 var FixedColumns = function ( dt, init ) {
15432         var that = this;
15433
15434         /* Sanity check - you just know it will happen */
15435         if ( ! ( this instanceof FixedColumns ) ) {
15436                 alert( "FixedColumns warning: FixedColumns must be initialised with the 'new' keyword." );
15437                 return;
15438         }
15439
15440         if ( init === undefined || init === true ) {
15441                 init = {};
15442         }
15443
15444         // Use the DataTables Hungarian notation mapping method, if it exists to
15445         // provide forwards compatibility for camel case variables
15446         var camelToHungarian = $.fn.dataTable.camelToHungarian;
15447         if ( camelToHungarian ) {
15448                 camelToHungarian( FixedColumns.defaults, FixedColumns.defaults, true );
15449                 camelToHungarian( FixedColumns.defaults, init );
15450         }
15451
15452         // v1.10 allows the settings object to be got form a number of sources
15453         var dtSettings = new $.fn.dataTable.Api( dt ).settings()[0];
15454
15455         /**
15456          * Settings object which contains customisable information for FixedColumns instance
15457          * @namespace
15458          * @extends FixedColumns.defaults
15459          * @private
15460          */
15461         this.s = {
15462                 /**
15463                  * DataTables settings objects
15464                  *  @type     object
15465                  *  @default  Obtained from DataTables instance
15466                  */
15467                 "dt": dtSettings,
15468
15469                 /**
15470                  * Number of columns in the DataTable - stored for quick access
15471                  *  @type     int
15472                  *  @default  Obtained from DataTables instance
15473                  */
15474                 "iTableColumns": dtSettings.aoColumns.length,
15475
15476                 /**
15477                  * Original outer widths of the columns as rendered by DataTables - used to calculate
15478                  * the FixedColumns grid bounding box
15479                  *  @type     array.<int>
15480                  *  @default  []
15481                  */
15482                 "aiOuterWidths": [],
15483
15484                 /**
15485                  * Original inner widths of the columns as rendered by DataTables - used to apply widths
15486                  * to the columns
15487                  *  @type     array.<int>
15488                  *  @default  []
15489                  */
15490                 "aiInnerWidths": [],
15491
15492
15493                 /**
15494                  * Is the document layout right-to-left
15495                  * @type boolean
15496                  */
15497                 rtl: $(dtSettings.nTable).css('direction') === 'rtl'
15498         };
15499
15500
15501         /**
15502          * DOM elements used by the class instance
15503          * @namespace
15504          * @private
15505          *
15506          */
15507         this.dom = {
15508                 /**
15509                  * DataTables scrolling element
15510                  *  @type     node
15511                  *  @default  null
15512                  */
15513                 "scroller": null,
15514
15515                 /**
15516                  * DataTables header table
15517                  *  @type     node
15518                  *  @default  null
15519                  */
15520                 "header": null,
15521
15522                 /**
15523                  * DataTables body table
15524                  *  @type     node
15525                  *  @default  null
15526                  */
15527                 "body": null,
15528
15529                 /**
15530                  * DataTables footer table
15531                  *  @type     node
15532                  *  @default  null
15533                  */
15534                 "footer": null,
15535
15536                 /**
15537                  * Display grid elements
15538                  * @namespace
15539                  */
15540                 "grid": {
15541                         /**
15542                          * Grid wrapper. This is the container element for the 3x3 grid
15543                          *  @type     node
15544                          *  @default  null
15545                          */
15546                         "wrapper": null,
15547
15548                         /**
15549                          * DataTables scrolling element. This element is the DataTables
15550                          * component in the display grid (making up the main table - i.e.
15551                          * not the fixed columns).
15552                          *  @type     node
15553                          *  @default  null
15554                          */
15555                         "dt": null,
15556
15557                         /**
15558                          * Left fixed column grid components
15559                          * @namespace
15560                          */
15561                         "left": {
15562                                 "wrapper": null,
15563                                 "head": null,
15564                                 "body": null,
15565                                 "foot": null
15566                         },
15567
15568                         /**
15569                          * Right fixed column grid components
15570                          * @namespace
15571                          */
15572                         "right": {
15573                                 "wrapper": null,
15574                                 "head": null,
15575                                 "body": null,
15576                                 "foot": null
15577                         }
15578                 },
15579
15580                 /**
15581                  * Cloned table nodes
15582                  * @namespace
15583                  */
15584                 "clone": {
15585                         /**
15586                          * Left column cloned table nodes
15587                          * @namespace
15588                          */
15589                         "left": {
15590                                 /**
15591                                  * Cloned header table
15592                                  *  @type     node
15593                                  *  @default  null
15594                                  */
15595                                 "header": null,
15596
15597                                 /**
15598                                  * Cloned body table
15599                                  *  @type     node
15600                                  *  @default  null
15601                                  */
15602                                 "body": null,
15603
15604                                 /**
15605                                  * Cloned footer table
15606                                  *  @type     node
15607                                  *  @default  null
15608                                  */
15609                                 "footer": null
15610                         },
15611
15612                         /**
15613                          * Right column cloned table nodes
15614                          * @namespace
15615                          */
15616                         "right": {
15617                                 /**
15618                                  * Cloned header table
15619                                  *  @type     node
15620                                  *  @default  null
15621                                  */
15622                                 "header": null,
15623
15624                                 /**
15625                                  * Cloned body table
15626                                  *  @type     node
15627                                  *  @default  null
15628                                  */
15629                                 "body": null,
15630
15631                                 /**
15632                                  * Cloned footer table
15633                                  *  @type     node
15634                                  *  @default  null
15635                                  */
15636                                 "footer": null
15637                         }
15638                 }
15639         };
15640
15641         if ( dtSettings._oFixedColumns ) {
15642                 throw 'FixedColumns already initialised on this table';
15643         }
15644
15645         /* Attach the instance to the DataTables instance so it can be accessed easily */
15646         dtSettings._oFixedColumns = this;
15647
15648         /* Let's do it */
15649         if ( ! dtSettings._bInitComplete )
15650         {
15651                 dtSettings.oApi._fnCallbackReg( dtSettings, 'aoInitComplete', function () {
15652                         that._fnConstruct( init );
15653                 }, 'FixedColumns' );
15654         }
15655         else
15656         {
15657                 this._fnConstruct( init );
15658         }
15659 };
15660
15661
15662
15663 $.extend( FixedColumns.prototype , {
15664         /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
15665          * Public methods
15666          * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
15667
15668         /**
15669          * Update the fixed columns - including headers and footers. Note that FixedColumns will
15670          * automatically update the display whenever the host DataTable redraws.
15671          *  @returns {void}
15672          *  @example
15673          *      var table = $('#example').dataTable( {
15674          *          "scrollX": "100%"
15675          *      } );
15676          *      var fc = new $.fn.dataTable.fixedColumns( table );
15677          *
15678          *      // at some later point when the table has been manipulated....
15679          *      fc.fnUpdate();
15680          */
15681         "fnUpdate": function ()
15682         {
15683                 this._fnDraw( true );
15684         },
15685
15686
15687         /**
15688          * Recalculate the resizes of the 3x3 grid that FixedColumns uses for display of the table.
15689          * This is useful if you update the width of the table container. Note that FixedColumns will
15690          * perform this function automatically when the window.resize event is fired.
15691          *  @returns {void}
15692          *  @example
15693          *      var table = $('#example').dataTable( {
15694          *          "scrollX": "100%"
15695          *      } );
15696          *      var fc = new $.fn.dataTable.fixedColumns( table );
15697          *
15698          *      // Resize the table container and then have FixedColumns adjust its layout....
15699          *      $('#content').width( 1200 );
15700          *      fc.fnRedrawLayout();
15701          */
15702         "fnRedrawLayout": function ()
15703         {
15704                 this._fnColCalc();
15705                 this._fnGridLayout();
15706                 this.fnUpdate();
15707         },
15708
15709
15710         /**
15711          * Mark a row such that it's height should be recalculated when using 'semiauto' row
15712          * height matching. This function will have no effect when 'none' or 'auto' row height
15713          * matching is used.
15714          *  @param   {Node} nTr TR element that should have it's height recalculated
15715          *  @returns {void}
15716          *  @example
15717          *      var table = $('#example').dataTable( {
15718          *          "scrollX": "100%"
15719          *      } );
15720          *      var fc = new $.fn.dataTable.fixedColumns( table );
15721          *
15722          *      // manipulate the table - mark the row as needing an update then update the table
15723          *      // this allows the redraw performed by DataTables fnUpdate to recalculate the row
15724          *      // height
15725          *      fc.fnRecalculateHeight();
15726          *      table.fnUpdate( $('#example tbody tr:eq(0)')[0], ["insert date", 1, 2, 3 ... ]);
15727          */
15728         "fnRecalculateHeight": function ( nTr )
15729         {
15730                 delete nTr._DTTC_iHeight;
15731                 nTr.style.height = 'auto';
15732         },
15733
15734
15735         /**
15736          * Set the height of a given row - provides cross browser compatibility
15737          *  @param   {Node} nTarget TR element that should have it's height recalculated
15738          *  @param   {int} iHeight Height in pixels to set
15739          *  @returns {void}
15740          *  @example
15741          *      var table = $('#example').dataTable( {
15742          *          "scrollX": "100%"
15743          *      } );
15744          *      var fc = new $.fn.dataTable.fixedColumns( table );
15745          *
15746          *      // You may want to do this after manipulating a row in the fixed column
15747          *      fc.fnSetRowHeight( $('#example tbody tr:eq(0)')[0], 50 );
15748          */
15749         "fnSetRowHeight": function ( nTarget, iHeight )
15750         {
15751                 nTarget.style.height = iHeight+"px";
15752         },
15753
15754
15755         /**
15756          * Get data index information about a row or cell in the table body.
15757          * This function is functionally identical to fnGetPosition in DataTables,
15758          * taking the same parameter (TH, TD or TR node) and returning exactly the
15759          * the same information (data index information). THe difference between
15760          * the two is that this method takes into account the fixed columns in the
15761          * table, so you can pass in nodes from the master table, or the cloned
15762          * tables and get the index position for the data in the main table.
15763          *  @param {node} node TR, TH or TD element to get the information about
15764          *  @returns {int} If nNode is given as a TR, then a single index is 
15765          *    returned, or if given as a cell, an array of [row index, column index
15766          *    (visible), column index (all)] is given.
15767          */
15768         "fnGetPosition": function ( node )
15769         {
15770                 var idx;
15771                 var inst = this.s.dt.oInstance;
15772
15773                 if ( ! $(node).parents('.DTFC_Cloned').length )
15774                 {
15775                         // Not in a cloned table
15776                         return inst.fnGetPosition( node );
15777                 }
15778                 else
15779                 {
15780                         // Its in the cloned table, so need to look up position
15781                         if ( node.nodeName.toLowerCase() === 'tr' ) {
15782                                 idx = $(node).index();
15783                                 return inst.fnGetPosition( $('tr', this.s.dt.nTBody)[ idx ] );
15784                         }
15785                         else
15786                         {
15787                                 var colIdx = $(node).index();
15788                                 idx = $(node.parentNode).index();
15789                                 var row = inst.fnGetPosition( $('tr', this.s.dt.nTBody)[ idx ] );
15790
15791                                 return [
15792                                         row,
15793                                         colIdx,
15794                                         inst.oApi._fnVisibleToColumnIndex( this.s.dt, colIdx )
15795                                 ];
15796                         }
15797                 }
15798         },
15799
15800         fnToFixedNode: function ( rowIdx, colIdx )
15801         {
15802                 var found;
15803
15804                 if ( colIdx < this.s.iLeftColumns ) {
15805                         found = $(this.dom.clone.left.body).find('[data-dt-row='+rowIdx+'][data-dt-column='+colIdx+']');
15806                 }
15807                 else if ( colIdx >= this.s.iRightColumns ) {
15808                         found = $(this.dom.clone.right.body).find('[data-dt-row='+rowIdx+'][data-dt-column='+colIdx+']');
15809                 }
15810
15811                 if ( found && found.length ) {
15812                         return found[0];
15813                 }
15814
15815                 // Fallback - non-fixed node
15816                 var table = new $.fn.dataTable.Api(this.s.dt);
15817                 return table.cell(rowIdx, colIdx).node();
15818         },
15819
15820
15821         /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
15822          * Private methods (they are of course public in JS, but recommended as private)
15823          * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
15824
15825         /**
15826          * Initialisation for FixedColumns
15827          *  @param   {Object} oInit User settings for initialisation
15828          *  @returns {void}
15829          *  @private
15830          */
15831         "_fnConstruct": function ( oInit )
15832         {
15833                 var i, iLen, iWidth,
15834                         that = this;
15835
15836                 /* Sanity checking */
15837                 if ( typeof this.s.dt.oInstance.fnVersionCheck != 'function' ||
15838                      this.s.dt.oInstance.fnVersionCheck( '1.8.0' ) !== true )
15839                 {
15840                         alert( "FixedColumns "+FixedColumns.VERSION+" required DataTables 1.8.0 or later. "+
15841                                 "Please upgrade your DataTables installation" );
15842                         return;
15843                 }
15844
15845                 if ( this.s.dt.oScroll.sX === "" )
15846                 {
15847                         this.s.dt.oInstance.oApi._fnLog( this.s.dt, 1, "FixedColumns is not needed (no "+
15848                                 "x-scrolling in DataTables enabled), so no action will be taken. Use 'FixedHeader' for "+
15849                                 "column fixing when scrolling is not enabled" );
15850                         return;
15851                 }
15852
15853                 /* Apply the settings from the user / defaults */
15854                 this.s = $.extend( true, this.s, FixedColumns.defaults, oInit );
15855
15856                 /* Set up the DOM as we need it and cache nodes */
15857                 var classes = this.s.dt.oClasses;
15858                 this.dom.grid.dt = $(this.s.dt.nTable).parents('div.'+classes.sScrollWrapper)[0];
15859                 this.dom.scroller = $('div.'+classes.sScrollBody, this.dom.grid.dt )[0];
15860
15861                 /* Set up the DOM that we want for the fixed column layout grid */
15862                 this._fnColCalc();
15863                 this._fnGridSetup();
15864
15865                 /* Event handlers */
15866                 var mouseController;
15867                 var mouseDown = false;
15868
15869                 // When the mouse is down (drag scroll) the mouse controller cannot
15870                 // change, as the browser keeps the original element as the scrolling one
15871                 $(this.s.dt.nTableWrapper).on( 'mousedown.DTFC', function (e) {
15872                         if ( e.button === 0 ) {
15873                                 mouseDown = true;
15874
15875                                 $(document).one( 'mouseup', function () {
15876                                         mouseDown = false;
15877                                 } );
15878                         }
15879                 } );
15880
15881                 // When the body is scrolled - scroll the left and right columns
15882                 $(this.dom.scroller)
15883                         .on( 'mouseover.DTFC touchstart.DTFC', function () {
15884                                 if ( ! mouseDown ) {
15885                                         mouseController = 'main';
15886                                 }
15887                         } )
15888                         .on( 'scroll.DTFC', function (e) {
15889                                 if ( ! mouseController && e.originalEvent ) {
15890                                         mouseController = 'main';
15891                                 }
15892
15893                                 if ( mouseController === 'main' ) {
15894                                         if ( that.s.iLeftColumns > 0 ) {
15895                                                 that.dom.grid.left.liner.scrollTop = that.dom.scroller.scrollTop;
15896                                         }
15897                                         if ( that.s.iRightColumns > 0 ) {
15898                                                 that.dom.grid.right.liner.scrollTop = that.dom.scroller.scrollTop;
15899                                         }
15900                                 }
15901                         } );
15902
15903                 var wheelType = 'onwheel' in document.createElement('div') ?
15904                         'wheel.DTFC' :
15905                         'mousewheel.DTFC';
15906
15907                 if ( that.s.iLeftColumns > 0 ) {
15908                         // When scrolling the left column, scroll the body and right column
15909                         $(that.dom.grid.left.liner)
15910                                 .on( 'mouseover.DTFC touchstart.DTFC', function () {
15911                                         if ( ! mouseDown ) {
15912                                                 mouseController = 'left';
15913                                         }
15914                                 } )
15915                                 .on( 'scroll.DTFC', function ( e ) {
15916                                         if ( ! mouseController && e.originalEvent ) {
15917                                                 mouseController = 'left';
15918                                         }
15919
15920                                         if ( mouseController === 'left' ) {
15921                                                 that.dom.scroller.scrollTop = that.dom.grid.left.liner.scrollTop;
15922                                                 if ( that.s.iRightColumns > 0 ) {
15923                                                         that.dom.grid.right.liner.scrollTop = that.dom.grid.left.liner.scrollTop;
15924                                                 }
15925                                         }
15926                                 } )
15927                                 .on( wheelType, function(e) {
15928                                         // Pass horizontal scrolling through
15929                                         var xDelta = e.type === 'wheel' ?
15930                                                 -e.originalEvent.deltaX :
15931                                                 e.originalEvent.wheelDeltaX;
15932                                         that.dom.scroller.scrollLeft -= xDelta;
15933                                 } );
15934                 }
15935
15936                 if ( that.s.iRightColumns > 0 ) {
15937                         // When scrolling the right column, scroll the body and the left column
15938                         $(that.dom.grid.right.liner)
15939                                 .on( 'mouseover.DTFC touchstart.DTFC', function () {
15940                                         if ( ! mouseDown ) {
15941                                                 mouseController = 'right';
15942                                         }
15943                                 } )
15944                                 .on( 'scroll.DTFC', function ( e ) {
15945                                         if ( ! mouseController && e.originalEvent ) {
15946                                                 mouseController = 'right';
15947                                         }
15948
15949                                         if ( mouseController === 'right' ) {
15950                                                 that.dom.scroller.scrollTop = that.dom.grid.right.liner.scrollTop;
15951                                                 if ( that.s.iLeftColumns > 0 ) {
15952                                                         that.dom.grid.left.liner.scrollTop = that.dom.grid.right.liner.scrollTop;
15953                                                 }
15954                                         }
15955                                 } )
15956                                 .on( wheelType, function(e) {
15957                                         // Pass horizontal scrolling through
15958                                         var xDelta = e.type === 'wheel' ?
15959                                                 -e.originalEvent.deltaX :
15960                                                 e.originalEvent.wheelDeltaX;
15961                                         that.dom.scroller.scrollLeft -= xDelta;
15962                                 } );
15963                 }
15964
15965                 $(window).on( 'resize.DTFC', function () {
15966                         that._fnGridLayout.call( that );
15967                 } );
15968
15969                 var bFirstDraw = true;
15970                 var jqTable = $(this.s.dt.nTable);
15971
15972                 jqTable
15973                         .on( 'draw.dt.DTFC', function () {
15974                                 that._fnColCalc();
15975                                 that._fnDraw.call( that, bFirstDraw );
15976                                 bFirstDraw = false;
15977                         } )
15978                         .on( 'column-sizing.dt.DTFC', function () {
15979                                 that._fnColCalc();
15980                                 that._fnGridLayout( that );
15981                         } )
15982                         .on( 'column-visibility.dt.DTFC', function ( e, settings, column, vis, recalc ) {
15983                                 if ( recalc === undefined || recalc ) {
15984                                         that._fnColCalc();
15985                                         that._fnGridLayout( that );
15986                                         that._fnDraw( true );
15987                                 }
15988                         } )
15989                         .on( 'select.dt.DTFC deselect.dt.DTFC', function ( e, dt, type, indexes ) {
15990                                 if ( e.namespace === 'dt' ) {
15991                                         that._fnDraw( false );
15992                                 }
15993                         } )
15994                         .on( 'destroy.dt.DTFC', function () {
15995                                 jqTable.off( '.DTFC' );
15996
15997                                 $(that.dom.scroller).off( '.DTFC' );
15998                                 $(window).off( '.DTFC' );
15999                                 $(that.s.dt.nTableWrapper).off( '.DTFC' );
16000
16001                                 $(that.dom.grid.left.liner).off( '.DTFC '+wheelType );
16002                                 $(that.dom.grid.left.wrapper).remove();
16003
16004                                 $(that.dom.grid.right.liner).off( '.DTFC '+wheelType );
16005                                 $(that.dom.grid.right.wrapper).remove();
16006                         } );
16007
16008                 /* Get things right to start with - note that due to adjusting the columns, there must be
16009                  * another redraw of the main table. It doesn't need to be a full redraw however.
16010                  */
16011                 this._fnGridLayout();
16012                 this.s.dt.oInstance.fnDraw(false);
16013         },
16014
16015
16016         /**
16017          * Calculate the column widths for the grid layout
16018          *  @returns {void}
16019          *  @private
16020          */
16021         "_fnColCalc": function ()
16022         {
16023                 var that = this;
16024                 var iLeftWidth = 0;
16025                 var iRightWidth = 0;
16026
16027                 this.s.aiInnerWidths = [];
16028                 this.s.aiOuterWidths = [];
16029
16030                 $.each( this.s.dt.aoColumns, function (i, col) {
16031                         var th = $(col.nTh);
16032                         var border;
16033
16034                         if ( ! th.filter(':visible').length ) {
16035                                 that.s.aiInnerWidths.push( 0 );
16036                                 that.s.aiOuterWidths.push( 0 );
16037                         }
16038                         else
16039                         {
16040                                 // Inner width is used to assign widths to cells
16041                                 // Outer width is used to calculate the container
16042                                 var iWidth = th.outerWidth();
16043
16044                                 // When working with the left most-cell, need to add on the
16045                                 // table's border to the outerWidth, since we need to take
16046                                 // account of it, but it isn't in any cell
16047                                 if ( that.s.aiOuterWidths.length === 0 ) {
16048                                         border = $(that.s.dt.nTable).css('border-left-width');
16049                                         iWidth += typeof border === 'string' && border.indexOf('px') === -1 ?
16050                                                 1 :
16051                                                 parseInt( border, 10 );
16052                                 }
16053
16054                                 // Likewise with the final column on the right
16055                                 if ( that.s.aiOuterWidths.length === that.s.dt.aoColumns.length-1 ) {
16056                                         border = $(that.s.dt.nTable).css('border-right-width');
16057                                         iWidth += typeof border === 'string' && border.indexOf('px') === -1 ?
16058                                                 1 :
16059                                                 parseInt( border, 10 );
16060                                 }
16061
16062                                 that.s.aiOuterWidths.push( iWidth );
16063                                 that.s.aiInnerWidths.push( th.width() );
16064
16065                                 if ( i < that.s.iLeftColumns )
16066                                 {
16067                                         iLeftWidth += iWidth;
16068                                 }
16069
16070                                 if ( that.s.iTableColumns-that.s.iRightColumns <= i )
16071                                 {
16072                                         iRightWidth += iWidth;
16073                                 }
16074                         }
16075                 } );
16076
16077                 this.s.iLeftWidth = iLeftWidth;
16078                 this.s.iRightWidth = iRightWidth;
16079         },
16080
16081
16082         /**
16083          * Set up the DOM for the fixed column. The way the layout works is to create a 1x3 grid
16084          * for the left column, the DataTable (for which we just reuse the scrolling element DataTable
16085          * puts into the DOM) and the right column. In each of he two fixed column elements there is a
16086          * grouping wrapper element and then a head, body and footer wrapper. In each of these we then
16087          * place the cloned header, body or footer tables. This effectively gives as 3x3 grid structure.
16088          *  @returns {void}
16089          *  @private
16090          */
16091         "_fnGridSetup": function ()
16092         {
16093                 var that = this;
16094                 var oOverflow = this._fnDTOverflow();
16095                 var block;
16096
16097                 this.dom.body = this.s.dt.nTable;
16098                 this.dom.header = this.s.dt.nTHead.parentNode;
16099                 this.dom.header.parentNode.parentNode.style.position = "relative";
16100
16101                 var nSWrapper =
16102                         $('<div class="DTFC_ScrollWrapper" style="position:relative; clear:both;">'+
16103                                 '<div class="DTFC_LeftWrapper" style="position:absolute; top:0; left:0;" aria-hidden="true">'+
16104                                         '<div class="DTFC_LeftHeadWrapper" style="position:relative; top:0; left:0; overflow:hidden;"></div>'+
16105                                         '<div class="DTFC_LeftBodyWrapper" style="position:relative; top:0; left:0; height:0; overflow:hidden;">'+
16106                                                 '<div class="DTFC_LeftBodyLiner" style="position:relative; top:0; left:0; overflow-y:scroll;"></div>'+
16107                                         '</div>'+
16108                                         '<div class="DTFC_LeftFootWrapper" style="position:relative; top:0; left:0; overflow:hidden;"></div>'+
16109                                 '</div>'+
16110                                 '<div class="DTFC_RightWrapper" style="position:absolute; top:0; right:0;" aria-hidden="true">'+
16111                                         '<div class="DTFC_RightHeadWrapper" style="position:relative; top:0; left:0;">'+
16112                                                 '<div class="DTFC_RightHeadBlocker DTFC_Blocker" style="position:absolute; top:0; bottom:0;"></div>'+
16113                                         '</div>'+
16114                                         '<div class="DTFC_RightBodyWrapper" style="position:relative; top:0; left:0; height:0; overflow:hidden;">'+
16115                                                 '<div class="DTFC_RightBodyLiner" style="position:relative; top:0; left:0; overflow-y:scroll;"></div>'+
16116                                         '</div>'+
16117                                         '<div class="DTFC_RightFootWrapper" style="position:relative; top:0; left:0;">'+
16118                                                 '<div class="DTFC_RightFootBlocker DTFC_Blocker" style="position:absolute; top:0; bottom:0;"></div>'+
16119                                         '</div>'+
16120                                 '</div>'+
16121                         '</div>')[0];
16122                 var nLeft = nSWrapper.childNodes[0];
16123                 var nRight = nSWrapper.childNodes[1];
16124
16125                 this.dom.grid.dt.parentNode.insertBefore( nSWrapper, this.dom.grid.dt );
16126                 nSWrapper.appendChild( this.dom.grid.dt );
16127
16128                 this.dom.grid.wrapper = nSWrapper;
16129
16130                 if ( this.s.iLeftColumns > 0 )
16131                 {
16132                         this.dom.grid.left.wrapper = nLeft;
16133                         this.dom.grid.left.head = nLeft.childNodes[0];
16134                         this.dom.grid.left.body = nLeft.childNodes[1];
16135                         this.dom.grid.left.liner = $('div.DTFC_LeftBodyLiner', nSWrapper)[0];
16136
16137                         nSWrapper.appendChild( nLeft );
16138                 }
16139
16140                 if ( this.s.iRightColumns > 0 )
16141                 {
16142                         this.dom.grid.right.wrapper = nRight;
16143                         this.dom.grid.right.head = nRight.childNodes[0];
16144                         this.dom.grid.right.body = nRight.childNodes[1];
16145                         this.dom.grid.right.liner = $('div.DTFC_RightBodyLiner', nSWrapper)[0];
16146
16147                         nRight.style.right = oOverflow.bar+"px";
16148
16149                         block = $('div.DTFC_RightHeadBlocker', nSWrapper)[0];
16150                         block.style.width = oOverflow.bar+"px";
16151                         block.style.right = -oOverflow.bar+"px";
16152                         this.dom.grid.right.headBlock = block;
16153
16154                         block = $('div.DTFC_RightFootBlocker', nSWrapper)[0];
16155                         block.style.width = oOverflow.bar+"px";
16156                         block.style.right = -oOverflow.bar+"px";
16157                         this.dom.grid.right.footBlock = block;
16158
16159                         nSWrapper.appendChild( nRight );
16160                 }
16161
16162                 if ( this.s.dt.nTFoot )
16163                 {
16164                         this.dom.footer = this.s.dt.nTFoot.parentNode;
16165                         if ( this.s.iLeftColumns > 0 )
16166                         {
16167                                 this.dom.grid.left.foot = nLeft.childNodes[2];
16168                         }
16169                         if ( this.s.iRightColumns > 0 )
16170                         {
16171                                 this.dom.grid.right.foot = nRight.childNodes[2];
16172                         }
16173                 }
16174
16175                 // RTL support - swap the position of the left and right columns (#48)
16176                 if ( this.s.rtl ) {
16177                         $('div.DTFC_RightHeadBlocker', nSWrapper).css( {
16178                                 left: -oOverflow.bar+'px',
16179                                 right: ''
16180                         } );
16181                 }
16182         },
16183
16184
16185         /**
16186          * Style and position the grid used for the FixedColumns layout
16187          *  @returns {void}
16188          *  @private
16189          */
16190         "_fnGridLayout": function ()
16191         {
16192                 var that = this;
16193                 var oGrid = this.dom.grid;
16194                 var iWidth = $(oGrid.wrapper).width();
16195                 var iBodyHeight = this.s.dt.nTable.parentNode.offsetHeight;
16196                 var iFullHeight = this.s.dt.nTable.parentNode.parentNode.offsetHeight;
16197                 var oOverflow = this._fnDTOverflow();
16198                 var iLeftWidth = this.s.iLeftWidth;
16199                 var iRightWidth = this.s.iRightWidth;
16200                 var rtl = $(this.dom.body).css('direction') === 'rtl';
16201                 var wrapper;
16202                 var scrollbarAdjust = function ( node, width ) {
16203                         if ( ! oOverflow.bar ) {
16204                                 // If there is no scrollbar (Macs) we need to hide the auto scrollbar
16205                                 node.style.width = (width+20)+"px";
16206                                 node.style.paddingRight = "20px";
16207                                 node.style.boxSizing = "border-box";
16208                         }
16209                         else if ( that._firefoxScrollError() ) {
16210                                 // See the above function for why this is required
16211                                 if ( $(node).height() > 34 ) {
16212                                         node.style.width = (width+oOverflow.bar)+"px";
16213                                 }
16214                         }
16215                         else {
16216                                 // Otherwise just overflow by the scrollbar
16217                                 node.style.width = (width+oOverflow.bar)+"px";
16218                         }
16219                 };
16220
16221                 // When x scrolling - don't paint the fixed columns over the x scrollbar
16222                 if ( oOverflow.x )
16223                 {
16224                         iBodyHeight -= oOverflow.bar;
16225                 }
16226
16227                 oGrid.wrapper.style.height = iFullHeight+"px";
16228
16229                 if ( this.s.iLeftColumns > 0 )
16230                 {
16231                         wrapper = oGrid.left.wrapper;
16232                         wrapper.style.width = iLeftWidth+'px';
16233                         wrapper.style.height = '1px';
16234
16235                         // Swap the position of the left and right columns for rtl (#48)
16236                         // This is always up against the edge, scrollbar on the far side
16237                         if ( rtl ) {
16238                                 wrapper.style.left = '';
16239                                 wrapper.style.right = 0;
16240                         }
16241                         else {
16242                                 wrapper.style.left = 0;
16243                                 wrapper.style.right = '';
16244                         }
16245
16246                         oGrid.left.body.style.height = iBodyHeight+"px";
16247                         if ( oGrid.left.foot ) {
16248                                 oGrid.left.foot.style.top = (oOverflow.x ? oOverflow.bar : 0)+"px"; // shift footer for scrollbar
16249                         }
16250
16251                         scrollbarAdjust( oGrid.left.liner, iLeftWidth );
16252                         oGrid.left.liner.style.height = iBodyHeight+"px";
16253                         oGrid.left.liner.style.maxHeight = iBodyHeight+"px";
16254                 }
16255
16256                 if ( this.s.iRightColumns > 0 )
16257                 {
16258                         wrapper = oGrid.right.wrapper;
16259                         wrapper.style.width = iRightWidth+'px';
16260                         wrapper.style.height = '1px';
16261
16262                         // Need to take account of the vertical scrollbar
16263                         if ( this.s.rtl ) {
16264                                 wrapper.style.left = oOverflow.y ? oOverflow.bar+'px' : 0;
16265                                 wrapper.style.right = '';
16266                         }
16267                         else {
16268                                 wrapper.style.left = '';
16269                                 wrapper.style.right = oOverflow.y ? oOverflow.bar+'px' : 0;
16270                         }
16271
16272                         oGrid.right.body.style.height = iBodyHeight+"px";
16273                         if ( oGrid.right.foot ) {
16274                                 oGrid.right.foot.style.top = (oOverflow.x ? oOverflow.bar : 0)+"px";
16275                         }
16276
16277                         scrollbarAdjust( oGrid.right.liner, iRightWidth );
16278                         oGrid.right.liner.style.height = iBodyHeight+"px";
16279                         oGrid.right.liner.style.maxHeight = iBodyHeight+"px";
16280
16281                         oGrid.right.headBlock.style.display = oOverflow.y ? 'block' : 'none';
16282                         oGrid.right.footBlock.style.display = oOverflow.y ? 'block' : 'none';
16283                 }
16284         },
16285
16286
16287         /**
16288          * Get information about the DataTable's scrolling state - specifically if the table is scrolling
16289          * on either the x or y axis, and also the scrollbar width.
16290          *  @returns {object} Information about the DataTables scrolling state with the properties:
16291          *    'x', 'y' and 'bar'
16292          *  @private
16293          */
16294         "_fnDTOverflow": function ()
16295         {
16296                 var nTable = this.s.dt.nTable;
16297                 var nTableScrollBody = nTable.parentNode;
16298                 var out = {
16299                         "x": false,
16300                         "y": false,
16301                         "bar": this.s.dt.oScroll.iBarWidth
16302                 };
16303
16304                 if ( nTable.offsetWidth > nTableScrollBody.clientWidth )
16305                 {
16306                         out.x = true;
16307                 }
16308
16309                 if ( nTable.offsetHeight > nTableScrollBody.clientHeight )
16310                 {
16311                         out.y = true;
16312                 }
16313
16314                 return out;
16315         },
16316
16317
16318         /**
16319          * Clone and position the fixed columns
16320          *  @returns {void}
16321          *  @param   {Boolean} bAll Indicate if the header and footer should be updated as well (true)
16322          *  @private
16323          */
16324         "_fnDraw": function ( bAll )
16325         {
16326                 this._fnGridLayout();
16327                 this._fnCloneLeft( bAll );
16328                 this._fnCloneRight( bAll );
16329
16330                 /* Draw callback function */
16331                 if ( this.s.fnDrawCallback !== null )
16332                 {
16333                         this.s.fnDrawCallback.call( this, this.dom.clone.left, this.dom.clone.right );
16334                 }
16335
16336                 /* Event triggering */
16337                 $(this).trigger( 'draw.dtfc', {
16338                         "leftClone": this.dom.clone.left,
16339                         "rightClone": this.dom.clone.right
16340                 } );
16341         },
16342
16343
16344         /**
16345          * Clone the right columns
16346          *  @returns {void}
16347          *  @param   {Boolean} bAll Indicate if the header and footer should be updated as well (true)
16348          *  @private
16349          */
16350         "_fnCloneRight": function ( bAll )
16351         {
16352                 if ( this.s.iRightColumns <= 0 ) {
16353                         return;
16354                 }
16355
16356                 var that = this,
16357                         i, jq,
16358                         aiColumns = [];
16359
16360                 for ( i=this.s.iTableColumns-this.s.iRightColumns ; i<this.s.iTableColumns ; i++ ) {
16361                         if ( this.s.dt.aoColumns[i].bVisible ) {
16362                                 aiColumns.push( i );
16363                         }
16364                 }
16365
16366                 this._fnClone( this.dom.clone.right, this.dom.grid.right, aiColumns, bAll );
16367         },
16368
16369
16370         /**
16371          * Clone the left columns
16372          *  @returns {void}
16373          *  @param   {Boolean} bAll Indicate if the header and footer should be updated as well (true)
16374          *  @private
16375          */
16376         "_fnCloneLeft": function ( bAll )
16377         {
16378                 if ( this.s.iLeftColumns <= 0 ) {
16379                         return;
16380                 }
16381
16382                 var that = this,
16383                         i, jq,
16384                         aiColumns = [];
16385
16386                 for ( i=0 ; i<this.s.iLeftColumns ; i++ ) {
16387                         if ( this.s.dt.aoColumns[i].bVisible ) {
16388                                 aiColumns.push( i );
16389                         }
16390                 }
16391
16392                 this._fnClone( this.dom.clone.left, this.dom.grid.left, aiColumns, bAll );
16393         },
16394
16395
16396         /**
16397          * Make a copy of the layout object for a header or footer element from DataTables. Note that
16398          * this method will clone the nodes in the layout object.
16399          *  @returns {Array} Copy of the layout array
16400          *  @param   {Object} aoOriginal Layout array from DataTables (aoHeader or aoFooter)
16401          *  @param   {Object} aiColumns Columns to copy
16402          *  @param   {boolean} events Copy cell events or not
16403          *  @private
16404          */
16405         "_fnCopyLayout": function ( aoOriginal, aiColumns, events )
16406         {
16407                 var aReturn = [];
16408                 var aClones = [];
16409                 var aCloned = [];
16410
16411                 for ( var i=0, iLen=aoOriginal.length ; i<iLen ; i++ )
16412                 {
16413                         var aRow = [];
16414                         aRow.nTr = $(aoOriginal[i].nTr).clone(events, false)[0];
16415
16416                         for ( var j=0, jLen=this.s.iTableColumns ; j<jLen ; j++ )
16417                         {
16418                                 if ( $.inArray( j, aiColumns ) === -1 )
16419                                 {
16420                                         continue;
16421                                 }
16422
16423                                 var iCloned = $.inArray( aoOriginal[i][j].cell, aCloned );
16424                                 if ( iCloned === -1 )
16425                                 {
16426                                         var nClone = $(aoOriginal[i][j].cell).clone(events, false)[0];
16427                                         aClones.push( nClone );
16428                                         aCloned.push( aoOriginal[i][j].cell );
16429
16430                                         aRow.push( {
16431                                                 "cell": nClone,
16432                                                 "unique": aoOriginal[i][j].unique
16433                                         } );
16434                                 }
16435                                 else
16436                                 {
16437                                         aRow.push( {
16438                                                 "cell": aClones[ iCloned ],
16439                                                 "unique": aoOriginal[i][j].unique
16440                                         } );
16441                                 }
16442                         }
16443
16444                         aReturn.push( aRow );
16445                 }
16446
16447                 return aReturn;
16448         },
16449
16450
16451         /**
16452          * Clone the DataTable nodes and place them in the DOM (sized correctly)
16453          *  @returns {void}
16454          *  @param   {Object} oClone Object containing the header, footer and body cloned DOM elements
16455          *  @param   {Object} oGrid Grid object containing the display grid elements for the cloned
16456          *                    column (left or right)
16457          *  @param   {Array} aiColumns Column indexes which should be operated on from the DataTable
16458          *  @param   {Boolean} bAll Indicate if the header and footer should be updated as well (true)
16459          *  @private
16460          */
16461         "_fnClone": function ( oClone, oGrid, aiColumns, bAll )
16462         {
16463                 var that = this,
16464                         i, iLen, j, jLen, jq, nTarget, iColumn, nClone, iIndex, aoCloneLayout,
16465                         jqCloneThead, aoFixedHeader,
16466                         dt = this.s.dt;
16467
16468                 /*
16469                  * Header
16470                  */
16471                 if ( bAll )
16472                 {
16473                         $(oClone.header).remove();
16474
16475                         oClone.header = $(this.dom.header).clone(true, false)[0];
16476                         oClone.header.className += " DTFC_Cloned";
16477                         oClone.header.style.width = "100%";
16478                         oGrid.head.appendChild( oClone.header );
16479
16480                         /* Copy the DataTables layout cache for the header for our floating column */
16481                         aoCloneLayout = this._fnCopyLayout( dt.aoHeader, aiColumns, true );
16482                         jqCloneThead = $('>thead', oClone.header);
16483                         jqCloneThead.empty();
16484
16485                         /* Add the created cloned TR elements to the table */
16486                         for ( i=0, iLen=aoCloneLayout.length ; i<iLen ; i++ )
16487                         {
16488                                 jqCloneThead[0].appendChild( aoCloneLayout[i].nTr );
16489                         }
16490
16491                         /* Use the handy _fnDrawHead function in DataTables to do the rowspan/colspan
16492                          * calculations for us
16493                          */
16494                         dt.oApi._fnDrawHead( dt, aoCloneLayout, true );
16495                 }
16496                 else
16497                 {
16498                         /* To ensure that we copy cell classes exactly, regardless of colspan, multiple rows
16499                          * etc, we make a copy of the header from the DataTable again, but don't insert the
16500                          * cloned cells, just copy the classes across. To get the matching layout for the
16501                          * fixed component, we use the DataTables _fnDetectHeader method, allowing 1:1 mapping
16502                          */
16503                         aoCloneLayout = this._fnCopyLayout( dt.aoHeader, aiColumns, false );
16504                         aoFixedHeader=[];
16505
16506                         dt.oApi._fnDetectHeader( aoFixedHeader, $('>thead', oClone.header)[0] );
16507
16508                         for ( i=0, iLen=aoCloneLayout.length ; i<iLen ; i++ )
16509                         {
16510                                 for ( j=0, jLen=aoCloneLayout[i].length ; j<jLen ; j++ )
16511                                 {
16512                                         aoFixedHeader[i][j].cell.className = aoCloneLayout[i][j].cell.className;
16513
16514                                         // If jQuery UI theming is used we need to copy those elements as well
16515                                         $('span.DataTables_sort_icon', aoFixedHeader[i][j].cell).each( function () {
16516                                                 this.className = $('span.DataTables_sort_icon', aoCloneLayout[i][j].cell)[0].className;
16517                                         } );
16518                                 }
16519                         }
16520                 }
16521                 this._fnEqualiseHeights( 'thead', this.dom.header, oClone.header );
16522
16523                 /*
16524                  * Body
16525                  */
16526                 if ( this.s.sHeightMatch == 'auto' )
16527                 {
16528                         /* Remove any heights which have been applied already and let the browser figure it out */
16529                         $('>tbody>tr', that.dom.body).css('height', 'auto');
16530                 }
16531
16532                 if ( oClone.body !== null )
16533                 {
16534                         $(oClone.body).remove();
16535                         oClone.body = null;
16536                 }
16537
16538                 oClone.body = $(this.dom.body).clone(true)[0];
16539                 oClone.body.className += " DTFC_Cloned";
16540                 oClone.body.style.paddingBottom = dt.oScroll.iBarWidth+"px";
16541                 oClone.body.style.marginBottom = (dt.oScroll.iBarWidth*2)+"px"; /* For IE */
16542                 if ( oClone.body.getAttribute('id') !== null )
16543                 {
16544                         oClone.body.removeAttribute('id');
16545                 }
16546
16547                 $('>thead>tr', oClone.body).empty();
16548                 $('>tfoot', oClone.body).remove();
16549
16550                 var nBody = $('tbody', oClone.body)[0];
16551                 $(nBody).empty();
16552                 if ( dt.aiDisplay.length > 0 )
16553                 {
16554                         /* Copy the DataTables' header elements to force the column width in exactly the
16555                          * same way that DataTables does it - have the header element, apply the width and
16556                          * colapse it down
16557                          */
16558                         var nInnerThead = $('>thead>tr', oClone.body)[0];
16559                         for ( iIndex=0 ; iIndex<aiColumns.length ; iIndex++ )
16560                         {
16561                                 iColumn = aiColumns[iIndex];
16562
16563                                 nClone = $(dt.aoColumns[iColumn].nTh).clone(true)[0];
16564                                 nClone.innerHTML = "";
16565
16566                                 var oStyle = nClone.style;
16567                                 oStyle.paddingTop = "0";
16568                                 oStyle.paddingBottom = "0";
16569                                 oStyle.borderTopWidth = "0";
16570                                 oStyle.borderBottomWidth = "0";
16571                                 oStyle.height = 0;
16572                                 oStyle.width = that.s.aiInnerWidths[iColumn]+"px";
16573
16574                                 nInnerThead.appendChild( nClone );
16575                         }
16576
16577                         /* Add in the tbody elements, cloning form the master table */
16578                         $('>tbody>tr', that.dom.body).each( function (z) {
16579                                 var i = that.s.dt.oFeatures.bServerSide===false ?
16580                                         that.s.dt.aiDisplay[ that.s.dt._iDisplayStart+z ] : z;
16581                                 var aTds = that.s.dt.aoData[ i ].anCells || $(this).children('td, th');
16582
16583                                 var n = this.cloneNode(false);
16584                                 n.removeAttribute('id');
16585                                 n.setAttribute( 'data-dt-row', i );
16586
16587                                 for ( iIndex=0 ; iIndex<aiColumns.length ; iIndex++ )
16588                                 {
16589                                         iColumn = aiColumns[iIndex];
16590
16591                                         if ( aTds.length > 0 )
16592                                         {
16593                                                 nClone = $( aTds[iColumn] ).clone(true, true)[0];
16594                                                 nClone.removeAttribute( 'id' );
16595                                                 nClone.setAttribute( 'data-dt-row', i );
16596                                                 nClone.setAttribute( 'data-dt-column', iColumn );
16597                                                 n.appendChild( nClone );
16598                                         }
16599                                 }
16600                                 nBody.appendChild( n );
16601                         } );
16602                 }
16603                 else
16604                 {
16605                         $('>tbody>tr', that.dom.body).each( function (z) {
16606                                 nClone = this.cloneNode(true);
16607                                 nClone.className += ' DTFC_NoData';
16608                                 $('td', nClone).html('');
16609                                 nBody.appendChild( nClone );
16610                         } );
16611                 }
16612
16613                 oClone.body.style.width = "100%";
16614                 oClone.body.style.margin = "0";
16615                 oClone.body.style.padding = "0";
16616
16617                 // Interop with Scroller - need to use a height forcing element in the
16618                 // scrolling area in the same way that Scroller does in the body scroll.
16619                 if ( dt.oScroller !== undefined )
16620                 {
16621                         var scrollerForcer = dt.oScroller.dom.force;
16622
16623                         if ( ! oGrid.forcer ) {
16624                                 oGrid.forcer = scrollerForcer.cloneNode( true );
16625                                 oGrid.liner.appendChild( oGrid.forcer );
16626                         }
16627                         else {
16628                                 oGrid.forcer.style.height = scrollerForcer.style.height;
16629                         }
16630                 }
16631
16632                 oGrid.liner.appendChild( oClone.body );
16633
16634                 this._fnEqualiseHeights( 'tbody', that.dom.body, oClone.body );
16635
16636                 /*
16637                  * Footer
16638                  */
16639                 if ( dt.nTFoot !== null )
16640                 {
16641                         if ( bAll )
16642                         {
16643                                 if ( oClone.footer !== null )
16644                                 {
16645                                         oClone.footer.parentNode.removeChild( oClone.footer );
16646                                 }
16647                                 oClone.footer = $(this.dom.footer).clone(true, true)[0];
16648                                 oClone.footer.className += " DTFC_Cloned";
16649                                 oClone.footer.style.width = "100%";
16650                                 oGrid.foot.appendChild( oClone.footer );
16651
16652                                 /* Copy the footer just like we do for the header */
16653                                 aoCloneLayout = this._fnCopyLayout( dt.aoFooter, aiColumns, true );
16654                                 var jqCloneTfoot = $('>tfoot', oClone.footer);
16655                                 jqCloneTfoot.empty();
16656
16657                                 for ( i=0, iLen=aoCloneLayout.length ; i<iLen ; i++ )
16658                                 {
16659                                         jqCloneTfoot[0].appendChild( aoCloneLayout[i].nTr );
16660                                 }
16661                                 dt.oApi._fnDrawHead( dt, aoCloneLayout, true );
16662                         }
16663                         else
16664                         {
16665                                 aoCloneLayout = this._fnCopyLayout( dt.aoFooter, aiColumns, false );
16666                                 var aoCurrFooter=[];
16667
16668                                 dt.oApi._fnDetectHeader( aoCurrFooter, $('>tfoot', oClone.footer)[0] );
16669
16670                                 for ( i=0, iLen=aoCloneLayout.length ; i<iLen ; i++ )
16671                                 {
16672                                         for ( j=0, jLen=aoCloneLayout[i].length ; j<jLen ; j++ )
16673                                         {
16674                                                 aoCurrFooter[i][j].cell.className = aoCloneLayout[i][j].cell.className;
16675                                         }
16676                                 }
16677                         }
16678                         this._fnEqualiseHeights( 'tfoot', this.dom.footer, oClone.footer );
16679                 }
16680
16681                 /* Equalise the column widths between the header footer and body - body get's priority */
16682                 var anUnique = dt.oApi._fnGetUniqueThs( dt, $('>thead', oClone.header)[0] );
16683                 $(anUnique).each( function (i) {
16684                         iColumn = aiColumns[i];
16685                         this.style.width = that.s.aiInnerWidths[iColumn]+"px";
16686                 } );
16687
16688                 if ( that.s.dt.nTFoot !== null )
16689                 {
16690                         anUnique = dt.oApi._fnGetUniqueThs( dt, $('>tfoot', oClone.footer)[0] );
16691                         $(anUnique).each( function (i) {
16692                                 iColumn = aiColumns[i];
16693                                 this.style.width = that.s.aiInnerWidths[iColumn]+"px";
16694                         } );
16695                 }
16696         },
16697
16698
16699         /**
16700          * From a given table node (THEAD etc), get a list of TR direct child elements
16701          *  @param   {Node} nIn Table element to search for TR elements (THEAD, TBODY or TFOOT element)
16702          *  @returns {Array} List of TR elements found
16703          *  @private
16704          */
16705         "_fnGetTrNodes": function ( nIn )
16706         {
16707                 var aOut = [];
16708                 for ( var i=0, iLen=nIn.childNodes.length ; i<iLen ; i++ )
16709                 {
16710                         if ( nIn.childNodes[i].nodeName.toUpperCase() == "TR" )
16711                         {
16712                                 aOut.push( nIn.childNodes[i] );
16713                         }
16714                 }
16715                 return aOut;
16716         },
16717
16718
16719         /**
16720          * Equalise the heights of the rows in a given table node in a cross browser way
16721          *  @returns {void}
16722          *  @param   {String} nodeName Node type - thead, tbody or tfoot
16723          *  @param   {Node} original Original node to take the heights from
16724          *  @param   {Node} clone Copy the heights to
16725          *  @private
16726          */
16727         "_fnEqualiseHeights": function ( nodeName, original, clone )
16728         {
16729                 if ( this.s.sHeightMatch == 'none' && nodeName !== 'thead' && nodeName !== 'tfoot' )
16730                 {
16731                         return;
16732                 }
16733
16734                 var that = this,
16735                         i, iLen, iHeight, iHeight2, iHeightOriginal, iHeightClone,
16736                         rootOriginal = original.getElementsByTagName(nodeName)[0],
16737                         rootClone    = clone.getElementsByTagName(nodeName)[0],
16738                         jqBoxHack    = $('>'+nodeName+'>tr:eq(0)', original).children(':first'),
16739                         iBoxHack     = jqBoxHack.outerHeight() - jqBoxHack.height(),
16740                         anOriginal   = this._fnGetTrNodes( rootOriginal ),
16741                         anClone      = this._fnGetTrNodes( rootClone ),
16742                         heights      = [];
16743
16744                 for ( i=0, iLen=anClone.length ; i<iLen ; i++ )
16745                 {
16746                         iHeightOriginal = anOriginal[i].offsetHeight;
16747                         iHeightClone = anClone[i].offsetHeight;
16748                         iHeight = iHeightClone > iHeightOriginal ? iHeightClone : iHeightOriginal;
16749
16750                         if ( this.s.sHeightMatch == 'semiauto' )
16751                         {
16752                                 anOriginal[i]._DTTC_iHeight = iHeight;
16753                         }
16754
16755                         heights.push( iHeight );
16756                 }
16757
16758                 for ( i=0, iLen=anClone.length ; i<iLen ; i++ )
16759                 {
16760                         anClone[i].style.height = heights[i]+"px";
16761                         anOriginal[i].style.height = heights[i]+"px";
16762                 }
16763         },
16764
16765         /**
16766          * Determine if the UA suffers from Firefox's overflow:scroll scrollbars
16767          * not being shown bug.
16768          *
16769          * Firefox doesn't draw scrollbars, even if it is told to using
16770          * overflow:scroll, if the div is less than 34px height. See bugs 292284 and
16771          * 781885. Using UA detection here since this is particularly hard to detect
16772          * using objects - its a straight up rendering error in Firefox.
16773          *
16774          * @return {boolean} True if Firefox error is present, false otherwise
16775          */
16776         _firefoxScrollError: function () {
16777                 if ( _firefoxScroll === undefined ) {
16778                         var test = $('<div/>')
16779                                 .css( {
16780                                         position: 'absolute',
16781                                         top: 0,
16782                                         left: 0,
16783                                         height: 10,
16784                                         width: 50,
16785                                         overflow: 'scroll'
16786                                 } )
16787                                 .appendTo( 'body' );
16788
16789                         // Make sure this doesn't apply on Macs with 0 width scrollbars
16790                         _firefoxScroll = (
16791                                 test[0].clientWidth === test[0].offsetWidth && this._fnDTOverflow().bar !== 0
16792                         );
16793
16794                         test.remove();
16795                 }
16796
16797                 return _firefoxScroll;
16798         }
16799 } );
16800
16801
16802
16803 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
16804  * Statics
16805  * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
16806
16807 /**
16808  * FixedColumns default settings for initialisation
16809  *  @name FixedColumns.defaults
16810  *  @namespace
16811  *  @static
16812  */
16813 FixedColumns.defaults = /** @lends FixedColumns.defaults */{
16814         /**
16815          * Number of left hand columns to fix in position
16816          *  @type     int
16817          *  @default  1
16818          *  @static
16819          *  @example
16820          *      var  = $('#example').dataTable( {
16821          *          "scrollX": "100%"
16822          *      } );
16823          *      new $.fn.dataTable.fixedColumns( table, {
16824          *          "leftColumns": 2
16825          *      } );
16826          */
16827         "iLeftColumns": 1,
16828
16829         /**
16830          * Number of right hand columns to fix in position
16831          *  @type     int
16832          *  @default  0
16833          *  @static
16834          *  @example
16835          *      var table = $('#example').dataTable( {
16836          *          "scrollX": "100%"
16837          *      } );
16838          *      new $.fn.dataTable.fixedColumns( table, {
16839          *          "rightColumns": 1
16840          *      } );
16841          */
16842         "iRightColumns": 0,
16843
16844         /**
16845          * Draw callback function which is called when FixedColumns has redrawn the fixed assets
16846          *  @type     function(object, object):void
16847          *  @default  null
16848          *  @static
16849          *  @example
16850          *      var table = $('#example').dataTable( {
16851          *          "scrollX": "100%"
16852          *      } );
16853          *      new $.fn.dataTable.fixedColumns( table, {
16854          *          "drawCallback": function () {
16855          *                  alert( "FixedColumns redraw" );
16856          *              }
16857          *      } );
16858          */
16859         "fnDrawCallback": null,
16860
16861         /**
16862          * Height matching algorthim to use. This can be "none" which will result in no height
16863          * matching being applied by FixedColumns (height matching could be forced by CSS in this
16864          * case), "semiauto" whereby the height calculation will be performed once, and the result
16865          * cached to be used again (fnRecalculateHeight can be used to force recalculation), or
16866          * "auto" when height matching is performed on every draw (slowest but must accurate)
16867          *  @type     string
16868          *  @default  semiauto
16869          *  @static
16870          *  @example
16871          *      var table = $('#example').dataTable( {
16872          *          "scrollX": "100%"
16873          *      } );
16874          *      new $.fn.dataTable.fixedColumns( table, {
16875          *          "heightMatch": "auto"
16876          *      } );
16877          */
16878         "sHeightMatch": "semiauto"
16879 };
16880
16881
16882
16883
16884 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
16885  * Constants
16886  * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
16887
16888 /**
16889  * FixedColumns version
16890  *  @name      FixedColumns.version
16891  *  @type      String
16892  *  @default   See code
16893  *  @static
16894  */
16895 FixedColumns.version = "3.3.0";
16896
16897
16898
16899 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
16900  * DataTables API integration
16901  * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
16902
16903 DataTable.Api.register( 'fixedColumns()', function () {
16904         return this;
16905 } );
16906
16907 DataTable.Api.register( 'fixedColumns().update()', function () {
16908         return this.iterator( 'table', function ( ctx ) {
16909                 if ( ctx._oFixedColumns ) {
16910                         ctx._oFixedColumns.fnUpdate();
16911                 }
16912         } );
16913 } );
16914
16915 DataTable.Api.register( 'fixedColumns().relayout()', function () {
16916         return this.iterator( 'table', function ( ctx ) {
16917                 if ( ctx._oFixedColumns ) {
16918                         ctx._oFixedColumns.fnRedrawLayout();
16919                 }
16920         } );
16921 } );
16922
16923 DataTable.Api.register( 'rows().recalcHeight()', function () {
16924         return this.iterator( 'row', function ( ctx, idx ) {
16925                 if ( ctx._oFixedColumns ) {
16926                         ctx._oFixedColumns.fnRecalculateHeight( this.row(idx).node() );
16927                 }
16928         } );
16929 } );
16930
16931 DataTable.Api.register( 'fixedColumns().rowIndex()', function ( row ) {
16932         row = $(row);
16933
16934         return row.parents('.DTFC_Cloned').length ?
16935                 this.rows( { page: 'current' } ).indexes()[ row.index() ] :
16936                 this.row( row ).index();
16937 } );
16938
16939 DataTable.Api.register( 'fixedColumns().cellIndex()', function ( cell ) {
16940         cell = $(cell);
16941
16942         if ( cell.parents('.DTFC_Cloned').length ) {
16943                 var rowClonedIdx = cell.parent().index();
16944                 var rowIdx = this.rows( { page: 'current' } ).indexes()[ rowClonedIdx ];
16945                 var columnIdx;
16946
16947                 if ( cell.parents('.DTFC_LeftWrapper').length ) {
16948                         columnIdx = cell.index();
16949                 }
16950                 else {
16951                         var columns = this.columns().flatten().length;
16952                         columnIdx = columns - this.context[0]._oFixedColumns.s.iRightColumns + cell.index();
16953                 }
16954
16955                 return {
16956                         row: rowIdx,
16957                         column: this.column.index( 'toData', columnIdx ),
16958                         columnVisible: columnIdx
16959                 };
16960         }
16961         else {
16962                 return this.cell( cell ).index();
16963         }
16964 } );
16965
16966 DataTable.Api.registerPlural( 'cells().fixedNodes()', 'cell().fixedNode()', function () {
16967         return this.iterator( 'cell', function ( settings, row, column ) {
16968                 return settings._oFixedColumns
16969                         ? settings._oFixedColumns.fnToFixedNode( row, column )
16970                         : this.node();
16971         }, 1 );
16972 } );
16973
16974
16975
16976
16977 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
16978  * Initialisation
16979  * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
16980
16981 // Attach a listener to the document which listens for DataTables initialisation
16982 // events so we can automatically initialise
16983 $(document).on( 'init.dt.fixedColumns', function (e, settings) {
16984         if ( e.namespace !== 'dt' ) {
16985                 return;
16986         }
16987
16988         var init = settings.oInit.fixedColumns;
16989         var defaults = DataTable.defaults.fixedColumns;
16990
16991         if ( init || defaults ) {
16992                 var opts = $.extend( {}, init, defaults );
16993
16994                 if ( init !== false ) {
16995                         new FixedColumns( settings, opts );
16996                 }
16997         }
16998 } );
16999
17000
17001
17002 // Make FixedColumns accessible from the DataTables instance
17003 $.fn.dataTable.FixedColumns = FixedColumns;
17004 $.fn.DataTable.FixedColumns = FixedColumns;
17005
17006 return FixedColumns;
17007 }));
17008
17009
17010 /*! FixedHeader 3.1.6
17011  * ©2009-2019 SpryMedia Ltd - datatables.net/license
17012  */
17013
17014 /**
17015  * @summary     FixedHeader
17016  * @description Fix a table's header or footer, so it is always visible while
17017  *              scrolling
17018  * @version     3.1.6
17019  * @file        dataTables.fixedHeader.js
17020  * @author      SpryMedia Ltd (www.sprymedia.co.uk)
17021  * @contact     www.sprymedia.co.uk/contact
17022  * @copyright   Copyright 2009-2019 SpryMedia Ltd.
17023  *
17024  * This source file is free software, available under the following license:
17025  *   MIT license - http://datatables.net/license/mit
17026  *
17027  * This source file is distributed in the hope that it will be useful, but
17028  * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
17029  * or FITNESS FOR A PARTICULAR PURPOSE. See the license files for details.
17030  *
17031  * For details please refer to: http://www.datatables.net
17032  */
17033
17034 (function( factory ){
17035         if ( typeof define === 'function' && define.amd ) {
17036                 // AMD
17037                 define( ['jquery', 'datatables.net'], function ( $ ) {
17038                         return factory( $, window, document );
17039                 } );
17040         }
17041         else if ( typeof exports === 'object' ) {
17042                 // CommonJS
17043                 module.exports = function (root, $) {
17044                         if ( ! root ) {
17045                                 root = window;
17046                         }
17047
17048                         if ( ! $ || ! $.fn.dataTable ) {
17049                                 $ = require('datatables.net')(root, $).$;
17050                         }
17051
17052                         return factory( $, root, root.document );
17053                 };
17054         }
17055         else {
17056                 // Browser
17057                 factory( jQuery, window, document );
17058         }
17059 }(function( $, window, document, undefined ) {
17060 'use strict';
17061 var DataTable = $.fn.dataTable;
17062
17063
17064 var _instCounter = 0;
17065
17066 var FixedHeader = function ( dt, config ) {
17067         // Sanity check - you just know it will happen
17068         if ( ! (this instanceof FixedHeader) ) {
17069                 throw "FixedHeader must be initialised with the 'new' keyword.";
17070         }
17071
17072         // Allow a boolean true for defaults
17073         if ( config === true ) {
17074                 config = {};
17075         }
17076
17077         dt = new DataTable.Api( dt );
17078
17079         this.c = $.extend( true, {}, FixedHeader.defaults, config );
17080
17081         this.s = {
17082                 dt: dt,
17083                 position: {
17084                         theadTop: 0,
17085                         tbodyTop: 0,
17086                         tfootTop: 0,
17087                         tfootBottom: 0,
17088                         width: 0,
17089                         left: 0,
17090                         tfootHeight: 0,
17091                         theadHeight: 0,
17092                         windowHeight: $(window).height(),
17093                         visible: true
17094                 },
17095                 headerMode: null,
17096                 footerMode: null,
17097                 autoWidth: dt.settings()[0].oFeatures.bAutoWidth,
17098                 namespace: '.dtfc'+(_instCounter++),
17099                 scrollLeft: {
17100                         header: -1,
17101                         footer: -1
17102                 },
17103                 enable: true
17104         };
17105
17106         this.dom = {
17107                 floatingHeader: null,
17108                 thead: $(dt.table().header()),
17109                 tbody: $(dt.table().body()),
17110                 tfoot: $(dt.table().footer()),
17111                 header: {
17112                         host: null,
17113                         floating: null,
17114                         placeholder: null
17115                 },
17116                 footer: {
17117                         host: null,
17118                         floating: null,
17119                         placeholder: null
17120                 }
17121         };
17122
17123         this.dom.header.host = this.dom.thead.parent();
17124         this.dom.footer.host = this.dom.tfoot.parent();
17125
17126         var dtSettings = dt.settings()[0];
17127         if ( dtSettings._fixedHeader ) {
17128                 throw "FixedHeader already initialised on table "+dtSettings.nTable.id;
17129         }
17130
17131         dtSettings._fixedHeader = this;
17132
17133         this._constructor();
17134 };
17135
17136
17137 /*
17138  * Variable: FixedHeader
17139  * Purpose:  Prototype for FixedHeader
17140  * Scope:    global
17141  */
17142 $.extend( FixedHeader.prototype, {
17143         /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
17144          * API methods
17145          */
17146
17147         /**
17148          * Kill off FH and any events
17149          */
17150         destroy: function () {
17151                 this.s.dt.off( '.dtfc' );
17152                 $(window).off( this.s.namespace );
17153
17154                 if ( this.c.header ) {
17155                         this._modeChange( 'in-place', 'header', true );
17156                 }
17157
17158                 if ( this.c.footer && this.dom.tfoot.length ) {
17159                         this._modeChange( 'in-place', 'footer', true );
17160                 }
17161         },
17162
17163         /**
17164          * Enable / disable the fixed elements
17165          *
17166          * @param  {boolean} enable `true` to enable, `false` to disable
17167          */
17168         enable: function ( enable, update )
17169         {
17170                 this.s.enable = enable;
17171
17172                 if ( update || update === undefined ) {
17173                         this._positions();
17174                         this._scroll( true );
17175                 }
17176         },
17177
17178         /**
17179          * Get enabled status
17180          */
17181         enabled: function ()
17182         {
17183                 return this.s.enable;
17184         },
17185         
17186         /**
17187          * Set header offset 
17188          *
17189          * @param  {int} new value for headerOffset
17190          */
17191         headerOffset: function ( offset )
17192         {
17193                 if ( offset !== undefined ) {
17194                         this.c.headerOffset = offset;
17195                         this.update();
17196                 }
17197
17198                 return this.c.headerOffset;
17199         },
17200         
17201         /**
17202          * Set footer offset
17203          *
17204          * @param  {int} new value for footerOffset
17205          */
17206         footerOffset: function ( offset )
17207         {
17208                 if ( offset !== undefined ) {
17209                         this.c.footerOffset = offset;
17210                         this.update();
17211                 }
17212
17213                 return this.c.footerOffset;
17214         },
17215
17216         
17217         /**
17218          * Recalculate the position of the fixed elements and force them into place
17219          */
17220         update: function ()
17221         {
17222                 var table = this.s.dt.table().node();
17223
17224                 if ( $(table).is(':visible') ) {
17225                         this.enable( true, false );
17226                 }
17227                 else {
17228                         this.enable( false, false );
17229                 }
17230
17231                 this._positions();
17232                 this._scroll( true );
17233         },
17234
17235
17236         /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
17237          * Constructor
17238          */
17239         
17240         /**
17241          * FixedHeader constructor - adding the required event listeners and
17242          * simple initialisation
17243          *
17244          * @private
17245          */
17246         _constructor: function ()
17247         {
17248                 var that = this;
17249                 var dt = this.s.dt;
17250
17251                 $(window)
17252                         .on( 'scroll'+this.s.namespace, function () {
17253                                 that._scroll();
17254                         } )
17255                         .on( 'resize'+this.s.namespace, DataTable.util.throttle( function () {
17256                                 that.s.position.windowHeight = $(window).height();
17257                                 that.update();
17258                         }, 50 ) );
17259
17260                 var autoHeader = $('.fh-fixedHeader');
17261                 if ( ! this.c.headerOffset && autoHeader.length ) {
17262                         this.c.headerOffset = autoHeader.outerHeight();
17263                 }
17264
17265                 var autoFooter = $('.fh-fixedFooter');
17266                 if ( ! this.c.footerOffset && autoFooter.length ) {
17267                         this.c.footerOffset = autoFooter.outerHeight();
17268                 }
17269
17270                 dt.on( 'column-reorder.dt.dtfc column-visibility.dt.dtfc draw.dt.dtfc column-sizing.dt.dtfc responsive-display.dt.dtfc', function () {
17271                         that.update();
17272                 } );
17273
17274                 dt.on( 'destroy.dtfc', function () {
17275                         that.destroy();
17276                 } );
17277
17278                 this._positions();
17279                 this._scroll();
17280         },
17281
17282
17283         /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
17284          * Private methods
17285          */
17286
17287         /**
17288          * Clone a fixed item to act as a place holder for the original element
17289          * which is moved into a clone of the table element, and moved around the
17290          * document to give the fixed effect.
17291          *
17292          * @param  {string}  item  'header' or 'footer'
17293          * @param  {boolean} force Force the clone to happen, or allow automatic
17294          *   decision (reuse existing if available)
17295          * @private
17296          */
17297         _clone: function ( item, force )
17298         {
17299                 var dt = this.s.dt;
17300                 var itemDom = this.dom[ item ];
17301                 var itemElement = item === 'header' ?
17302                         this.dom.thead :
17303                         this.dom.tfoot;
17304
17305                 if ( ! force && itemDom.floating ) {
17306                         // existing floating element - reuse it
17307                         itemDom.floating.removeClass( 'fixedHeader-floating fixedHeader-locked' );
17308                 }
17309                 else {
17310                         if ( itemDom.floating ) {
17311                                 itemDom.placeholder.remove();
17312                                 this._unsize( item );
17313                                 itemDom.floating.children().detach();
17314                                 itemDom.floating.remove();
17315                         }
17316
17317                         itemDom.floating = $( dt.table().node().cloneNode( false ) )
17318                                 .css( 'table-layout', 'fixed' )
17319                                 .attr( 'aria-hidden', 'true' )
17320                                 .removeAttr( 'id' )
17321                                 .append( itemElement )
17322                                 .appendTo( 'body' );
17323
17324                         // Insert a fake thead/tfoot into the DataTable to stop it jumping around
17325                         itemDom.placeholder = itemElement.clone( false );
17326                         itemDom.placeholder
17327                                 .find( '*[id]' )
17328                                 .removeAttr( 'id' );
17329
17330                         itemDom.host.prepend( itemDom.placeholder );
17331
17332                         // Clone widths
17333                         this._matchWidths( itemDom.placeholder, itemDom.floating );
17334                 }
17335         },
17336
17337         /**
17338          * Copy widths from the cells in one element to another. This is required
17339          * for the footer as the footer in the main table takes its sizes from the
17340          * header columns. That isn't present in the footer so to have it still
17341          * align correctly, the sizes need to be copied over. It is also required
17342          * for the header when auto width is not enabled
17343          *
17344          * @param  {jQuery} from Copy widths from
17345          * @param  {jQuery} to   Copy widths to
17346          * @private
17347          */
17348         _matchWidths: function ( from, to ) {
17349                 var get = function ( name ) {
17350                         return $(name, from)
17351                                 .map( function () {
17352                                         return $(this).width();
17353                                 } ).toArray();
17354                 };
17355
17356                 var set = function ( name, toWidths ) {
17357                         $(name, to).each( function ( i ) {
17358                                 $(this).css( {
17359                                         width: toWidths[i],
17360                                         minWidth: toWidths[i]
17361                                 } );
17362                         } );
17363                 };
17364
17365                 var thWidths = get( 'th' );
17366                 var tdWidths = get( 'td' );
17367
17368                 set( 'th', thWidths );
17369                 set( 'td', tdWidths );
17370         },
17371
17372         /**
17373          * Remove assigned widths from the cells in an element. This is required
17374          * when inserting the footer back into the main table so the size is defined
17375          * by the header columns and also when auto width is disabled in the
17376          * DataTable.
17377          *
17378          * @param  {string} item The `header` or `footer`
17379          * @private
17380          */
17381         _unsize: function ( item ) {
17382                 var el = this.dom[ item ].floating;
17383
17384                 if ( el && (item === 'footer' || (item === 'header' && ! this.s.autoWidth)) ) {
17385                         $('th, td', el).css( {
17386                                 width: '',
17387                                 minWidth: ''
17388                         } );
17389                 }
17390                 else if ( el && item === 'header' ) {
17391                         $('th, td', el).css( 'min-width', '' );
17392                 }
17393         },
17394
17395         /**
17396          * Reposition the floating elements to take account of horizontal page
17397          * scroll
17398          *
17399          * @param  {string} item       The `header` or `footer`
17400          * @param  {int}    scrollLeft Document scrollLeft
17401          * @private
17402          */
17403         _horizontal: function ( item, scrollLeft )
17404         {
17405                 var itemDom = this.dom[ item ];
17406                 var position = this.s.position;
17407                 var lastScrollLeft = this.s.scrollLeft;
17408
17409                 if ( itemDom.floating && lastScrollLeft[ item ] !== scrollLeft ) {
17410                         itemDom.floating.css( 'left', position.left - scrollLeft );
17411
17412                         lastScrollLeft[ item ] = scrollLeft;
17413                 }
17414         },
17415
17416         /**
17417          * Change from one display mode to another. Each fixed item can be in one
17418          * of:
17419          *
17420          * * `in-place` - In the main DataTable
17421          * * `in` - Floating over the DataTable
17422          * * `below` - (Header only) Fixed to the bottom of the table body
17423          * * `above` - (Footer only) Fixed to the top of the table body
17424          * 
17425          * @param  {string}  mode        Mode that the item should be shown in
17426          * @param  {string}  item        'header' or 'footer'
17427          * @param  {boolean} forceChange Force a redraw of the mode, even if already
17428          *     in that mode.
17429          * @private
17430          */
17431         _modeChange: function ( mode, item, forceChange )
17432         {
17433                 var dt = this.s.dt;
17434                 var itemDom = this.dom[ item ];
17435                 var position = this.s.position;
17436
17437                 // Record focus. Browser's will cause input elements to loose focus if
17438                 // they are inserted else where in the doc
17439                 var tablePart = this.dom[ item==='footer' ? 'tfoot' : 'thead' ];
17440                 var focus = $.contains( tablePart[0], document.activeElement ) ?
17441                         document.activeElement :
17442                         null;
17443                 
17444                 if ( focus ) {
17445                         focus.blur();
17446                 }
17447
17448                 if ( mode === 'in-place' ) {
17449                         // Insert the header back into the table's real header
17450                         if ( itemDom.placeholder ) {
17451                                 itemDom.placeholder.remove();
17452                                 itemDom.placeholder = null;
17453                         }
17454
17455                         this._unsize( item );
17456
17457                         if ( item === 'header' ) {
17458                                 itemDom.host.prepend( tablePart );
17459                         }
17460                         else {
17461                                 itemDom.host.append( tablePart );
17462                         }
17463
17464                         if ( itemDom.floating ) {
17465                                 itemDom.floating.remove();
17466                                 itemDom.floating = null;
17467                         }
17468                 }
17469                 else if ( mode === 'in' ) {
17470                         // Remove the header from the read header and insert into a fixed
17471                         // positioned floating table clone
17472                         this._clone( item, forceChange );
17473
17474                         itemDom.floating
17475                                 .addClass( 'fixedHeader-floating' )
17476                                 .css( item === 'header' ? 'top' : 'bottom', this.c[item+'Offset'] )
17477                                 .css( 'left', position.left+'px' )
17478                                 .css( 'width', position.width+'px' );
17479
17480                         if ( item === 'footer' ) {
17481                                 itemDom.floating.css( 'top', '' );
17482                         }
17483                 }
17484                 else if ( mode === 'below' ) { // only used for the header
17485                         // Fix the position of the floating header at base of the table body
17486                         this._clone( item, forceChange );
17487
17488                         itemDom.floating
17489                                 .addClass( 'fixedHeader-locked' )
17490                                 .css( 'top', position.tfootTop - position.theadHeight )
17491                                 .css( 'left', position.left+'px' )
17492                                 .css( 'width', position.width+'px' );
17493                 }
17494                 else if ( mode === 'above' ) { // only used for the footer
17495                         // Fix the position of the floating footer at top of the table body
17496                         this._clone( item, forceChange );
17497
17498                         itemDom.floating
17499                                 .addClass( 'fixedHeader-locked' )
17500                                 .css( 'top', position.tbodyTop )
17501                                 .css( 'left', position.left+'px' )
17502                                 .css( 'width', position.width+'px' );
17503                 }
17504
17505                 // Restore focus if it was lost
17506                 if ( focus && focus !== document.activeElement ) {
17507                         setTimeout( function () {
17508                                 focus.focus();
17509                         }, 10 );
17510                 }
17511
17512                 this.s.scrollLeft.header = -1;
17513                 this.s.scrollLeft.footer = -1;
17514                 this.s[item+'Mode'] = mode;
17515         },
17516
17517         /**
17518          * Cache the positional information that is required for the mode
17519          * calculations that FixedHeader performs.
17520          *
17521          * @private
17522          */
17523         _positions: function ()
17524         {
17525                 var dt = this.s.dt;
17526                 var table = dt.table();
17527                 var position = this.s.position;
17528                 var dom = this.dom;
17529                 var tableNode = $(table.node());
17530
17531                 // Need to use the header and footer that are in the main table,
17532                 // regardless of if they are clones, since they hold the positions we
17533                 // want to measure from
17534                 var thead = tableNode.children('thead');
17535                 var tfoot = tableNode.children('tfoot');
17536                 var tbody = dom.tbody;
17537
17538                 position.visible = tableNode.is(':visible');
17539                 position.width = tableNode.outerWidth();
17540                 position.left = tableNode.offset().left;
17541                 position.theadTop = thead.offset().top;
17542                 position.tbodyTop = tbody.offset().top;
17543                 position.tbodyHeight = tbody.outerHeight();
17544                 position.theadHeight = position.tbodyTop - position.theadTop;
17545
17546                 if ( tfoot.length ) {
17547                         position.tfootTop = tfoot.offset().top;
17548                         position.tfootBottom = position.tfootTop + tfoot.outerHeight();
17549                         position.tfootHeight = position.tfootBottom - position.tfootTop;
17550                 }
17551                 else {
17552                         position.tfootTop = position.tbodyTop + tbody.outerHeight();
17553                         position.tfootBottom = position.tfootTop;
17554                         position.tfootHeight = position.tfootTop;
17555                 }
17556         },
17557
17558
17559         /**
17560          * Mode calculation - determine what mode the fixed items should be placed
17561          * into.
17562          *
17563          * @param  {boolean} forceChange Force a redraw of the mode, even if already
17564          *     in that mode.
17565          * @private
17566          */
17567         _scroll: function ( forceChange )
17568         {
17569                 var windowTop = $(document).scrollTop();
17570                 var windowLeft = $(document).scrollLeft();
17571                 var position = this.s.position;
17572                 var headerMode, footerMode;
17573
17574                 if ( this.c.header ) {
17575                         if ( ! this.s.enable ) {
17576                                 headerMode = 'in-place';
17577                         }
17578                         else if ( ! position.visible || windowTop <= position.theadTop - this.c.headerOffset ) {
17579                                 headerMode = 'in-place';
17580                         }
17581                         else if ( windowTop <= position.tfootTop - position.theadHeight - this.c.headerOffset ) {
17582                                 headerMode = 'in';
17583                         }
17584                         else {
17585                                 headerMode = 'below';
17586                         }
17587
17588                         if ( forceChange || headerMode !== this.s.headerMode ) {
17589                                 this._modeChange( headerMode, 'header', forceChange );
17590                         }
17591
17592                         this._horizontal( 'header', windowLeft );
17593                 }
17594
17595                 if ( this.c.footer && this.dom.tfoot.length ) {
17596                         if ( ! this.s.enable ) {
17597                                 headerMode = 'in-place';
17598                         }
17599                         else if ( ! position.visible || windowTop + position.windowHeight >= position.tfootBottom + this.c.footerOffset ) {
17600                                 footerMode = 'in-place';
17601                         }
17602                         else if ( position.windowHeight + windowTop > position.tbodyTop + position.tfootHeight + this.c.footerOffset ) {
17603                                 footerMode = 'in';
17604                         }
17605                         else {
17606                                 footerMode = 'above';
17607                         }
17608
17609                         if ( forceChange || footerMode !== this.s.footerMode ) {
17610                                 this._modeChange( footerMode, 'footer', forceChange );
17611                         }
17612
17613                         this._horizontal( 'footer', windowLeft );
17614                 }
17615         }
17616 } );
17617
17618
17619 /**
17620  * Version
17621  * @type {String}
17622  * @static
17623  */
17624 FixedHeader.version = "3.1.6";
17625
17626 /**
17627  * Defaults
17628  * @type {Object}
17629  * @static
17630  */
17631 FixedHeader.defaults = {
17632         header: true,
17633         footer: false,
17634         headerOffset: 0,
17635         footerOffset: 0
17636 };
17637
17638
17639 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
17640  * DataTables interfaces
17641  */
17642
17643 // Attach for constructor access
17644 $.fn.dataTable.FixedHeader = FixedHeader;
17645 $.fn.DataTable.FixedHeader = FixedHeader;
17646
17647
17648 // DataTables creation - check if the FixedHeader option has been defined on the
17649 // table and if so, initialise
17650 $(document).on( 'init.dt.dtfh', function (e, settings, json) {
17651         if ( e.namespace !== 'dt' ) {
17652                 return;
17653         }
17654
17655         var init = settings.oInit.fixedHeader;
17656         var defaults = DataTable.defaults.fixedHeader;
17657
17658         if ( (init || defaults) && ! settings._fixedHeader ) {
17659                 var opts = $.extend( {}, defaults, init );
17660
17661                 if ( init !== false ) {
17662                         new FixedHeader( settings, opts );
17663                 }
17664         }
17665 } );
17666
17667 // DataTables API methods
17668 DataTable.Api.register( 'fixedHeader()', function () {} );
17669
17670 DataTable.Api.register( 'fixedHeader.adjust()', function () {
17671         return this.iterator( 'table', function ( ctx ) {
17672                 var fh = ctx._fixedHeader;
17673
17674                 if ( fh ) {
17675                         fh.update();
17676                 }
17677         } );
17678 } );
17679
17680 DataTable.Api.register( 'fixedHeader.enable()', function ( flag ) {
17681         return this.iterator( 'table', function ( ctx ) {
17682                 var fh = ctx._fixedHeader;
17683
17684                 flag = ( flag !== undefined ? flag : true );
17685                 if ( fh && flag !== fh.enabled() ) {
17686                         fh.enable( flag );
17687                 }
17688         } );
17689 } );
17690
17691 DataTable.Api.register( 'fixedHeader.enabled()', function () {
17692         if ( this.context.length ) {
17693                 var fx = this.content[0]._fixedHeader;
17694
17695                 if ( fh ) {
17696                         return fh.enabled();
17697                 }
17698         }
17699
17700         return false;
17701 } );
17702
17703 DataTable.Api.register( 'fixedHeader.disable()', function ( ) {
17704         return this.iterator( 'table', function ( ctx ) {
17705                 var fh = ctx._fixedHeader;
17706
17707                 if ( fh && fh.enabled() ) {
17708                         fh.enable( false );
17709                 }
17710         } );
17711 } );
17712
17713 $.each( ['header', 'footer'], function ( i, el ) {
17714         DataTable.Api.register( 'fixedHeader.'+el+'Offset()', function ( offset ) {
17715                 var ctx = this.context;
17716
17717                 if ( offset === undefined ) {
17718                         return ctx.length && ctx[0]._fixedHeader ?
17719                                 ctx[0]._fixedHeader[el +'Offset']() :
17720                                 undefined;
17721                 }
17722
17723                 return this.iterator( 'table', function ( ctx ) {
17724                         var fh = ctx._fixedHeader;
17725
17726                         if ( fh ) {
17727                                 fh[ el +'Offset' ]( offset );
17728                         }
17729                 } );
17730         } );
17731 } );
17732
17733
17734 return FixedHeader;
17735 }));
17736
17737