Allow push install of The_legend_of_ice_soul
[stouyapi.git] / www / datatables / 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.21/fh-3.1.7/sp-1.1.1/sl-1.3.1
8  *
9  * Included libraries:
10  *   DataTables 1.10.21, FixedHeader 3.1.7, SearchPanes 1.1.1, Select 1.3.1
11  */
12
13 /*! DataTables 1.10.21
14  * ©2008-2020 SpryMedia Ltd - datatables.net/license
15  */
16
17 /**
18  * @summary     DataTables
19  * @description Paginate, search and order HTML tables
20  * @version     1.10.21
21  * @file        jquery.dataTables.js
22  * @author      SpryMedia Ltd
23  * @contact     www.datatables.net
24  * @copyright   Copyright 2008-2020 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 !== undefined ) {
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( 'mouseup', function(e) {
4243                                 // Edge fix! Edge 17 does not trigger anything other than mouse events when clicking
4244                                 // on the clear icon (Edge bug 17584515). This is safe in other browsers as `searchFn`
4245                                 // checks the value to see if it has changed. In other browsers it won't have.
4246                                 setTimeout( function () {
4247                                         searchFn.call(jqFilter[0]);
4248                                 }, 10);
4249                         } )
4250                         .on( 'keypress.DT', function(e) {
4251                                 /* Prevent form submission */
4252                                 if ( e.keyCode == 13 ) {
4253                                         return false;
4254                                 }
4255                         } )
4256                         .attr('aria-controls', tableId);
4257         
4258                 // Update the input elements whenever the table is filtered
4259                 $(settings.nTable).on( 'search.dt.DT', function ( ev, s ) {
4260                         if ( settings === s ) {
4261                                 // IE9 throws an 'unknown error' if document.activeElement is used
4262                                 // inside an iframe or frame...
4263                                 try {
4264                                         if ( jqFilter[0] !== document.activeElement ) {
4265                                                 jqFilter.val( previousSearch.sSearch );
4266                                         }
4267                                 }
4268                                 catch ( e ) {}
4269                         }
4270                 } );
4271         
4272                 return filter[0];
4273         }
4274         
4275         
4276         /**
4277          * Filter the table using both the global filter and column based filtering
4278          *  @param {object} oSettings dataTables settings object
4279          *  @param {object} oSearch search information
4280          *  @param {int} [iForce] force a research of the master array (1) or not (undefined or 0)
4281          *  @memberof DataTable#oApi
4282          */
4283         function _fnFilterComplete ( oSettings, oInput, iForce )
4284         {
4285                 var oPrevSearch = oSettings.oPreviousSearch;
4286                 var aoPrevSearch = oSettings.aoPreSearchCols;
4287                 var fnSaveFilter = function ( oFilter ) {
4288                         /* Save the filtering values */
4289                         oPrevSearch.sSearch = oFilter.sSearch;
4290                         oPrevSearch.bRegex = oFilter.bRegex;
4291                         oPrevSearch.bSmart = oFilter.bSmart;
4292                         oPrevSearch.bCaseInsensitive = oFilter.bCaseInsensitive;
4293                 };
4294                 var fnRegex = function ( o ) {
4295                         // Backwards compatibility with the bEscapeRegex option
4296                         return o.bEscapeRegex !== undefined ? !o.bEscapeRegex : o.bRegex;
4297                 };
4298         
4299                 // Resolve any column types that are unknown due to addition or invalidation
4300                 // @todo As per sort - can this be moved into an event handler?
4301                 _fnColumnTypes( oSettings );
4302         
4303                 /* In server-side processing all filtering is done by the server, so no point hanging around here */
4304                 if ( _fnDataSource( oSettings ) != 'ssp' )
4305                 {
4306                         /* Global filter */
4307                         _fnFilter( oSettings, oInput.sSearch, iForce, fnRegex(oInput), oInput.bSmart, oInput.bCaseInsensitive );
4308                         fnSaveFilter( oInput );
4309         
4310                         /* Now do the individual column filter */
4311                         for ( var i=0 ; i<aoPrevSearch.length ; i++ )
4312                         {
4313                                 _fnFilterColumn( oSettings, aoPrevSearch[i].sSearch, i, fnRegex(aoPrevSearch[i]),
4314                                         aoPrevSearch[i].bSmart, aoPrevSearch[i].bCaseInsensitive );
4315                         }
4316         
4317                         /* Custom filtering */
4318                         _fnFilterCustom( oSettings );
4319                 }
4320                 else
4321                 {
4322                         fnSaveFilter( oInput );
4323                 }
4324         
4325                 /* Tell the draw function we have been filtering */
4326                 oSettings.bFiltered = true;
4327                 _fnCallbackFire( oSettings, null, 'search', [oSettings] );
4328         }
4329         
4330         
4331         /**
4332          * Apply custom filtering functions
4333          *  @param {object} oSettings dataTables settings object
4334          *  @memberof DataTable#oApi
4335          */
4336         function _fnFilterCustom( settings )
4337         {
4338                 var filters = DataTable.ext.search;
4339                 var displayRows = settings.aiDisplay;
4340                 var row, rowIdx;
4341         
4342                 for ( var i=0, ien=filters.length ; i<ien ; i++ ) {
4343                         var rows = [];
4344         
4345                         // Loop over each row and see if it should be included
4346                         for ( var j=0, jen=displayRows.length ; j<jen ; j++ ) {
4347                                 rowIdx = displayRows[ j ];
4348                                 row = settings.aoData[ rowIdx ];
4349         
4350                                 if ( filters[i]( settings, row._aFilterData, rowIdx, row._aData, j ) ) {
4351                                         rows.push( rowIdx );
4352                                 }
4353                         }
4354         
4355                         // So the array reference doesn't break set the results into the
4356                         // existing array
4357                         displayRows.length = 0;
4358                         $.merge( displayRows, rows );
4359                 }
4360         }
4361         
4362         
4363         /**
4364          * Filter the table on a per-column basis
4365          *  @param {object} oSettings dataTables settings object
4366          *  @param {string} sInput string to filter on
4367          *  @param {int} iColumn column to filter
4368          *  @param {bool} bRegex treat search string as a regular expression or not
4369          *  @param {bool} bSmart use smart filtering or not
4370          *  @param {bool} bCaseInsensitive Do case insenstive matching or not
4371          *  @memberof DataTable#oApi
4372          */
4373         function _fnFilterColumn ( settings, searchStr, colIdx, regex, smart, caseInsensitive )
4374         {
4375                 if ( searchStr === '' ) {
4376                         return;
4377                 }
4378         
4379                 var data;
4380                 var out = [];
4381                 var display = settings.aiDisplay;
4382                 var rpSearch = _fnFilterCreateSearch( searchStr, regex, smart, caseInsensitive );
4383         
4384                 for ( var i=0 ; i<display.length ; i++ ) {
4385                         data = settings.aoData[ display[i] ]._aFilterData[ colIdx ];
4386         
4387                         if ( rpSearch.test( data ) ) {
4388                                 out.push( display[i] );
4389                         }
4390                 }
4391         
4392                 settings.aiDisplay = out;
4393         }
4394         
4395         
4396         /**
4397          * Filter the data table based on user input and draw the table
4398          *  @param {object} settings dataTables settings object
4399          *  @param {string} input string to filter on
4400          *  @param {int} force optional - force a research of the master array (1) or not (undefined or 0)
4401          *  @param {bool} regex treat as a regular expression or not
4402          *  @param {bool} smart perform smart filtering or not
4403          *  @param {bool} caseInsensitive Do case insenstive matching or not
4404          *  @memberof DataTable#oApi
4405          */
4406         function _fnFilter( settings, input, force, regex, smart, caseInsensitive )
4407         {
4408                 var rpSearch = _fnFilterCreateSearch( input, regex, smart, caseInsensitive );
4409                 var prevSearch = settings.oPreviousSearch.sSearch;
4410                 var displayMaster = settings.aiDisplayMaster;
4411                 var display, invalidated, i;
4412                 var filtered = [];
4413         
4414                 // Need to take account of custom filtering functions - always filter
4415                 if ( DataTable.ext.search.length !== 0 ) {
4416                         force = true;
4417                 }
4418         
4419                 // Check if any of the rows were invalidated
4420                 invalidated = _fnFilterData( settings );
4421         
4422                 // If the input is blank - we just want the full data set
4423                 if ( input.length <= 0 ) {
4424                         settings.aiDisplay = displayMaster.slice();
4425                 }
4426                 else {
4427                         // New search - start from the master array
4428                         if ( invalidated ||
4429                                  force ||
4430                                  regex ||
4431                                  prevSearch.length > input.length ||
4432                                  input.indexOf(prevSearch) !== 0 ||
4433                                  settings.bSorted // On resort, the display master needs to be
4434                                                   // re-filtered since indexes will have changed
4435                         ) {
4436                                 settings.aiDisplay = displayMaster.slice();
4437                         }
4438         
4439                         // Search the display array
4440                         display = settings.aiDisplay;
4441         
4442                         for ( i=0 ; i<display.length ; i++ ) {
4443                                 if ( rpSearch.test( settings.aoData[ display[i] ]._sFilterRow ) ) {
4444                                         filtered.push( display[i] );
4445                                 }
4446                         }
4447         
4448                         settings.aiDisplay = filtered;
4449                 }
4450         }
4451         
4452         
4453         /**
4454          * Build a regular expression object suitable for searching a table
4455          *  @param {string} sSearch string to search for
4456          *  @param {bool} bRegex treat as a regular expression or not
4457          *  @param {bool} bSmart perform smart filtering or not
4458          *  @param {bool} bCaseInsensitive Do case insensitive matching or not
4459          *  @returns {RegExp} constructed object
4460          *  @memberof DataTable#oApi
4461          */
4462         function _fnFilterCreateSearch( search, regex, smart, caseInsensitive )
4463         {
4464                 search = regex ?
4465                         search :
4466                         _fnEscapeRegex( search );
4467                 
4468                 if ( smart ) {
4469                         /* For smart filtering we want to allow the search to work regardless of
4470                          * word order. We also want double quoted text to be preserved, so word
4471                          * order is important - a la google. So this is what we want to
4472                          * generate:
4473                          * 
4474                          * ^(?=.*?\bone\b)(?=.*?\btwo three\b)(?=.*?\bfour\b).*$
4475                          */
4476                         var a = $.map( search.match( /"[^"]+"|[^ ]+/g ) || [''], function ( word ) {
4477                                 if ( word.charAt(0) === '"' ) {
4478                                         var m = word.match( /^"(.*)"$/ );
4479                                         word = m ? m[1] : word;
4480                                 }
4481         
4482                                 return word.replace('"', '');
4483                         } );
4484         
4485                         search = '^(?=.*?'+a.join( ')(?=.*?' )+').*$';
4486                 }
4487         
4488                 return new RegExp( search, caseInsensitive ? 'i' : '' );
4489         }
4490         
4491         
4492         /**
4493          * Escape a string such that it can be used in a regular expression
4494          *  @param {string} sVal string to escape
4495          *  @returns {string} escaped string
4496          *  @memberof DataTable#oApi
4497          */
4498         var _fnEscapeRegex = DataTable.util.escapeRegex;
4499         
4500         var __filter_div = $('<div>')[0];
4501         var __filter_div_textContent = __filter_div.textContent !== undefined;
4502         
4503         // Update the filtering data for each row if needed (by invalidation or first run)
4504         function _fnFilterData ( settings )
4505         {
4506                 var columns = settings.aoColumns;
4507                 var column;
4508                 var i, j, ien, jen, filterData, cellData, row;
4509                 var fomatters = DataTable.ext.type.search;
4510                 var wasInvalidated = false;
4511         
4512                 for ( i=0, ien=settings.aoData.length ; i<ien ; i++ ) {
4513                         row = settings.aoData[i];
4514         
4515                         if ( ! row._aFilterData ) {
4516                                 filterData = [];
4517         
4518                                 for ( j=0, jen=columns.length ; j<jen ; j++ ) {
4519                                         column = columns[j];
4520         
4521                                         if ( column.bSearchable ) {
4522                                                 cellData = _fnGetCellData( settings, i, j, 'filter' );
4523         
4524                                                 if ( fomatters[ column.sType ] ) {
4525                                                         cellData = fomatters[ column.sType ]( cellData );
4526                                                 }
4527         
4528                                                 // Search in DataTables 1.10 is string based. In 1.11 this
4529                                                 // should be altered to also allow strict type checking.
4530                                                 if ( cellData === null ) {
4531                                                         cellData = '';
4532                                                 }
4533         
4534                                                 if ( typeof cellData !== 'string' && cellData.toString ) {
4535                                                         cellData = cellData.toString();
4536                                                 }
4537                                         }
4538                                         else {
4539                                                 cellData = '';
4540                                         }
4541         
4542                                         // If it looks like there is an HTML entity in the string,
4543                                         // attempt to decode it so sorting works as expected. Note that
4544                                         // we could use a single line of jQuery to do this, but the DOM
4545                                         // method used here is much faster http://jsperf.com/html-decode
4546                                         if ( cellData.indexOf && cellData.indexOf('&') !== -1 ) {
4547                                                 __filter_div.innerHTML = cellData;
4548                                                 cellData = __filter_div_textContent ?
4549                                                         __filter_div.textContent :
4550                                                         __filter_div.innerText;
4551                                         }
4552         
4553                                         if ( cellData.replace ) {
4554                                                 cellData = cellData.replace(/[\r\n\u2028]/g, '');
4555                                         }
4556         
4557                                         filterData.push( cellData );
4558                                 }
4559         
4560                                 row._aFilterData = filterData;
4561                                 row._sFilterRow = filterData.join('  ');
4562                                 wasInvalidated = true;
4563                         }
4564                 }
4565         
4566                 return wasInvalidated;
4567         }
4568         
4569         
4570         /**
4571          * Convert from the internal Hungarian notation to camelCase for external
4572          * interaction
4573          *  @param {object} obj Object to convert
4574          *  @returns {object} Inverted object
4575          *  @memberof DataTable#oApi
4576          */
4577         function _fnSearchToCamel ( obj )
4578         {
4579                 return {
4580                         search:          obj.sSearch,
4581                         smart:           obj.bSmart,
4582                         regex:           obj.bRegex,
4583                         caseInsensitive: obj.bCaseInsensitive
4584                 };
4585         }
4586         
4587         
4588         
4589         /**
4590          * Convert from camelCase notation to the internal Hungarian. We could use the
4591          * Hungarian convert function here, but this is cleaner
4592          *  @param {object} obj Object to convert
4593          *  @returns {object} Inverted object
4594          *  @memberof DataTable#oApi
4595          */
4596         function _fnSearchToHung ( obj )
4597         {
4598                 return {
4599                         sSearch:          obj.search,
4600                         bSmart:           obj.smart,
4601                         bRegex:           obj.regex,
4602                         bCaseInsensitive: obj.caseInsensitive
4603                 };
4604         }
4605         
4606         /**
4607          * Generate the node required for the info display
4608          *  @param {object} oSettings dataTables settings object
4609          *  @returns {node} Information element
4610          *  @memberof DataTable#oApi
4611          */
4612         function _fnFeatureHtmlInfo ( settings )
4613         {
4614                 var
4615                         tid = settings.sTableId,
4616                         nodes = settings.aanFeatures.i,
4617                         n = $('<div/>', {
4618                                 'class': settings.oClasses.sInfo,
4619                                 'id': ! nodes ? tid+'_info' : null
4620                         } );
4621         
4622                 if ( ! nodes ) {
4623                         // Update display on each draw
4624                         settings.aoDrawCallback.push( {
4625                                 "fn": _fnUpdateInfo,
4626                                 "sName": "information"
4627                         } );
4628         
4629                         n
4630                                 .attr( 'role', 'status' )
4631                                 .attr( 'aria-live', 'polite' );
4632         
4633                         // Table is described by our info div
4634                         $(settings.nTable).attr( 'aria-describedby', tid+'_info' );
4635                 }
4636         
4637                 return n[0];
4638         }
4639         
4640         
4641         /**
4642          * Update the information elements in the display
4643          *  @param {object} settings dataTables settings object
4644          *  @memberof DataTable#oApi
4645          */
4646         function _fnUpdateInfo ( settings )
4647         {
4648                 /* Show information about the table */
4649                 var nodes = settings.aanFeatures.i;
4650                 if ( nodes.length === 0 ) {
4651                         return;
4652                 }
4653         
4654                 var
4655                         lang  = settings.oLanguage,
4656                         start = settings._iDisplayStart+1,
4657                         end   = settings.fnDisplayEnd(),
4658                         max   = settings.fnRecordsTotal(),
4659                         total = settings.fnRecordsDisplay(),
4660                         out   = total ?
4661                                 lang.sInfo :
4662                                 lang.sInfoEmpty;
4663         
4664                 if ( total !== max ) {
4665                         /* Record set after filtering */
4666                         out += ' ' + lang.sInfoFiltered;
4667                 }
4668         
4669                 // Convert the macros
4670                 out += lang.sInfoPostFix;
4671                 out = _fnInfoMacros( settings, out );
4672         
4673                 var callback = lang.fnInfoCallback;
4674                 if ( callback !== null ) {
4675                         out = callback.call( settings.oInstance,
4676                                 settings, start, end, max, total, out
4677                         );
4678                 }
4679         
4680                 $(nodes).html( out );
4681         }
4682         
4683         
4684         function _fnInfoMacros ( settings, str )
4685         {
4686                 // When infinite scrolling, we are always starting at 1. _iDisplayStart is used only
4687                 // internally
4688                 var
4689                         formatter  = settings.fnFormatNumber,
4690                         start      = settings._iDisplayStart+1,
4691                         len        = settings._iDisplayLength,
4692                         vis        = settings.fnRecordsDisplay(),
4693                         all        = len === -1;
4694         
4695                 return str.
4696                         replace(/_START_/g, formatter.call( settings, start ) ).
4697                         replace(/_END_/g,   formatter.call( settings, settings.fnDisplayEnd() ) ).
4698                         replace(/_MAX_/g,   formatter.call( settings, settings.fnRecordsTotal() ) ).
4699                         replace(/_TOTAL_/g, formatter.call( settings, vis ) ).
4700                         replace(/_PAGE_/g,  formatter.call( settings, all ? 1 : Math.ceil( start / len ) ) ).
4701                         replace(/_PAGES_/g, formatter.call( settings, all ? 1 : Math.ceil( vis / len ) ) );
4702         }
4703         
4704         
4705         
4706         /**
4707          * Draw the table for the first time, adding all required features
4708          *  @param {object} settings dataTables settings object
4709          *  @memberof DataTable#oApi
4710          */
4711         function _fnInitialise ( settings )
4712         {
4713                 var i, iLen, iAjaxStart=settings.iInitDisplayStart;
4714                 var columns = settings.aoColumns, column;
4715                 var features = settings.oFeatures;
4716                 var deferLoading = settings.bDeferLoading; // value modified by the draw
4717         
4718                 /* Ensure that the table data is fully initialised */
4719                 if ( ! settings.bInitialised ) {
4720                         setTimeout( function(){ _fnInitialise( settings ); }, 200 );
4721                         return;
4722                 }
4723         
4724                 /* Show the display HTML options */
4725                 _fnAddOptionsHtml( settings );
4726         
4727                 /* Build and draw the header / footer for the table */
4728                 _fnBuildHead( settings );
4729                 _fnDrawHead( settings, settings.aoHeader );
4730                 _fnDrawHead( settings, settings.aoFooter );
4731         
4732                 /* Okay to show that something is going on now */
4733                 _fnProcessingDisplay( settings, true );
4734         
4735                 /* Calculate sizes for columns */
4736                 if ( features.bAutoWidth ) {
4737                         _fnCalculateColumnWidths( settings );
4738                 }
4739         
4740                 for ( i=0, iLen=columns.length ; i<iLen ; i++ ) {
4741                         column = columns[i];
4742         
4743                         if ( column.sWidth ) {
4744                                 column.nTh.style.width = _fnStringToCss( column.sWidth );
4745                         }
4746                 }
4747         
4748                 _fnCallbackFire( settings, null, 'preInit', [settings] );
4749         
4750                 // If there is default sorting required - let's do it. The sort function
4751                 // will do the drawing for us. Otherwise we draw the table regardless of the
4752                 // Ajax source - this allows the table to look initialised for Ajax sourcing
4753                 // data (show 'loading' message possibly)
4754                 _fnReDraw( settings );
4755         
4756                 // Server-side processing init complete is done by _fnAjaxUpdateDraw
4757                 var dataSrc = _fnDataSource( settings );
4758                 if ( dataSrc != 'ssp' || deferLoading ) {
4759                         // if there is an ajax source load the data
4760                         if ( dataSrc == 'ajax' ) {
4761                                 _fnBuildAjax( settings, [], function(json) {
4762                                         var aData = _fnAjaxDataSrc( settings, json );
4763         
4764                                         // Got the data - add it to the table
4765                                         for ( i=0 ; i<aData.length ; i++ ) {
4766                                                 _fnAddData( settings, aData[i] );
4767                                         }
4768         
4769                                         // Reset the init display for cookie saving. We've already done
4770                                         // a filter, and therefore cleared it before. So we need to make
4771                                         // it appear 'fresh'
4772                                         settings.iInitDisplayStart = iAjaxStart;
4773         
4774                                         _fnReDraw( settings );
4775         
4776                                         _fnProcessingDisplay( settings, false );
4777                                         _fnInitComplete( settings, json );
4778                                 }, settings );
4779                         }
4780                         else {
4781                                 _fnProcessingDisplay( settings, false );
4782                                 _fnInitComplete( settings );
4783                         }
4784                 }
4785         }
4786         
4787         
4788         /**
4789          * Draw the table for the first time, adding all required features
4790          *  @param {object} oSettings dataTables settings object
4791          *  @param {object} [json] JSON from the server that completed the table, if using Ajax source
4792          *    with client-side processing (optional)
4793          *  @memberof DataTable#oApi
4794          */
4795         function _fnInitComplete ( settings, json )
4796         {
4797                 settings._bInitComplete = true;
4798         
4799                 // When data was added after the initialisation (data or Ajax) we need to
4800                 // calculate the column sizing
4801                 if ( json || settings.oInit.aaData ) {
4802                         _fnAdjustColumnSizing( settings );
4803                 }
4804         
4805                 _fnCallbackFire( settings, null, 'plugin-init', [settings, json] );
4806                 _fnCallbackFire( settings, 'aoInitComplete', 'init', [settings, json] );
4807         }
4808         
4809         
4810         function _fnLengthChange ( settings, val )
4811         {
4812                 var len = parseInt( val, 10 );
4813                 settings._iDisplayLength = len;
4814         
4815                 _fnLengthOverflow( settings );
4816         
4817                 // Fire length change event
4818                 _fnCallbackFire( settings, null, 'length', [settings, len] );
4819         }
4820         
4821         
4822         /**
4823          * Generate the node required for user display length changing
4824          *  @param {object} settings dataTables settings object
4825          *  @returns {node} Display length feature node
4826          *  @memberof DataTable#oApi
4827          */
4828         function _fnFeatureHtmlLength ( settings )
4829         {
4830                 var
4831                         classes  = settings.oClasses,
4832                         tableId  = settings.sTableId,
4833                         menu     = settings.aLengthMenu,
4834                         d2       = $.isArray( menu[0] ),
4835                         lengths  = d2 ? menu[0] : menu,
4836                         language = d2 ? menu[1] : menu;
4837         
4838                 var select = $('<select/>', {
4839                         'name':          tableId+'_length',
4840                         'aria-controls': tableId,
4841                         'class':         classes.sLengthSelect
4842                 } );
4843         
4844                 for ( var i=0, ien=lengths.length ; i<ien ; i++ ) {
4845                         select[0][ i ] = new Option(
4846                                 typeof language[i] === 'number' ?
4847                                         settings.fnFormatNumber( language[i] ) :
4848                                         language[i],
4849                                 lengths[i]
4850                         );
4851                 }
4852         
4853                 var div = $('<div><label/></div>').addClass( classes.sLength );
4854                 if ( ! settings.aanFeatures.l ) {
4855                         div[0].id = tableId+'_length';
4856                 }
4857         
4858                 div.children().append(
4859                         settings.oLanguage.sLengthMenu.replace( '_MENU_', select[0].outerHTML )
4860                 );
4861         
4862                 // Can't use `select` variable as user might provide their own and the
4863                 // reference is broken by the use of outerHTML
4864                 $('select', div)
4865                         .val( settings._iDisplayLength )
4866                         .on( 'change.DT', function(e) {
4867                                 _fnLengthChange( settings, $(this).val() );
4868                                 _fnDraw( settings );
4869                         } );
4870         
4871                 // Update node value whenever anything changes the table's length
4872                 $(settings.nTable).on( 'length.dt.DT', function (e, s, len) {
4873                         if ( settings === s ) {
4874                                 $('select', div).val( len );
4875                         }
4876                 } );
4877         
4878                 return div[0];
4879         }
4880         
4881         
4882         
4883         /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
4884          * Note that most of the paging logic is done in
4885          * DataTable.ext.pager
4886          */
4887         
4888         /**
4889          * Generate the node required for default pagination
4890          *  @param {object} oSettings dataTables settings object
4891          *  @returns {node} Pagination feature node
4892          *  @memberof DataTable#oApi
4893          */
4894         function _fnFeatureHtmlPaginate ( settings )
4895         {
4896                 var
4897                         type   = settings.sPaginationType,
4898                         plugin = DataTable.ext.pager[ type ],
4899                         modern = typeof plugin === 'function',
4900                         redraw = function( settings ) {
4901                                 _fnDraw( settings );
4902                         },
4903                         node = $('<div/>').addClass( settings.oClasses.sPaging + type )[0],
4904                         features = settings.aanFeatures;
4905         
4906                 if ( ! modern ) {
4907                         plugin.fnInit( settings, node, redraw );
4908                 }
4909         
4910                 /* Add a draw callback for the pagination on first instance, to update the paging display */
4911                 if ( ! features.p )
4912                 {
4913                         node.id = settings.sTableId+'_paginate';
4914         
4915                         settings.aoDrawCallback.push( {
4916                                 "fn": function( settings ) {
4917                                         if ( modern ) {
4918                                                 var
4919                                                         start      = settings._iDisplayStart,
4920                                                         len        = settings._iDisplayLength,
4921                                                         visRecords = settings.fnRecordsDisplay(),
4922                                                         all        = len === -1,
4923                                                         page = all ? 0 : Math.ceil( start / len ),
4924                                                         pages = all ? 1 : Math.ceil( visRecords / len ),
4925                                                         buttons = plugin(page, pages),
4926                                                         i, ien;
4927         
4928                                                 for ( i=0, ien=features.p.length ; i<ien ; i++ ) {
4929                                                         _fnRenderer( settings, 'pageButton' )(
4930                                                                 settings, features.p[i], i, buttons, page, pages
4931                                                         );
4932                                                 }
4933                                         }
4934                                         else {
4935                                                 plugin.fnUpdate( settings, redraw );
4936                                         }
4937                                 },
4938                                 "sName": "pagination"
4939                         } );
4940                 }
4941         
4942                 return node;
4943         }
4944         
4945         
4946         /**
4947          * Alter the display settings to change the page
4948          *  @param {object} settings DataTables settings object
4949          *  @param {string|int} action Paging action to take: "first", "previous",
4950          *    "next" or "last" or page number to jump to (integer)
4951          *  @param [bool] redraw Automatically draw the update or not
4952          *  @returns {bool} true page has changed, false - no change
4953          *  @memberof DataTable#oApi
4954          */
4955         function _fnPageChange ( settings, action, redraw )
4956         {
4957                 var
4958                         start     = settings._iDisplayStart,
4959                         len       = settings._iDisplayLength,
4960                         records   = settings.fnRecordsDisplay();
4961         
4962                 if ( records === 0 || len === -1 )
4963                 {
4964                         start = 0;
4965                 }
4966                 else if ( typeof action === "number" )
4967                 {
4968                         start = action * len;
4969         
4970                         if ( start > records )
4971                         {
4972                                 start = 0;
4973                         }
4974                 }
4975                 else if ( action == "first" )
4976                 {
4977                         start = 0;
4978                 }
4979                 else if ( action == "previous" )
4980                 {
4981                         start = len >= 0 ?
4982                                 start - len :
4983                                 0;
4984         
4985                         if ( start < 0 )
4986                         {
4987                           start = 0;
4988                         }
4989                 }
4990                 else if ( action == "next" )
4991                 {
4992                         if ( start + len < records )
4993                         {
4994                                 start += len;
4995                         }
4996                 }
4997                 else if ( action == "last" )
4998                 {
4999                         start = Math.floor( (records-1) / len) * len;
5000                 }
5001                 else
5002                 {
5003                         _fnLog( settings, 0, "Unknown paging action: "+action, 5 );
5004                 }
5005         
5006                 var changed = settings._iDisplayStart !== start;
5007                 settings._iDisplayStart = start;
5008         
5009                 if ( changed ) {
5010                         _fnCallbackFire( settings, null, 'page', [settings] );
5011         
5012                         if ( redraw ) {
5013                                 _fnDraw( settings );
5014                         }
5015                 }
5016         
5017                 return changed;
5018         }
5019         
5020         
5021         
5022         /**
5023          * Generate the node required for the processing node
5024          *  @param {object} settings dataTables settings object
5025          *  @returns {node} Processing element
5026          *  @memberof DataTable#oApi
5027          */
5028         function _fnFeatureHtmlProcessing ( settings )
5029         {
5030                 return $('<div/>', {
5031                                 'id': ! settings.aanFeatures.r ? settings.sTableId+'_processing' : null,
5032                                 'class': settings.oClasses.sProcessing
5033                         } )
5034                         .html( settings.oLanguage.sProcessing )
5035                         .insertBefore( settings.nTable )[0];
5036         }
5037         
5038         
5039         /**
5040          * Display or hide the processing indicator
5041          *  @param {object} settings dataTables settings object
5042          *  @param {bool} show Show the processing indicator (true) or not (false)
5043          *  @memberof DataTable#oApi
5044          */
5045         function _fnProcessingDisplay ( settings, show )
5046         {
5047                 if ( settings.oFeatures.bProcessing ) {
5048                         $(settings.aanFeatures.r).css( 'display', show ? 'block' : 'none' );
5049                 }
5050         
5051                 _fnCallbackFire( settings, null, 'processing', [settings, show] );
5052         }
5053         
5054         /**
5055          * Add any control elements for the table - specifically scrolling
5056          *  @param {object} settings dataTables settings object
5057          *  @returns {node} Node to add to the DOM
5058          *  @memberof DataTable#oApi
5059          */
5060         function _fnFeatureHtmlTable ( settings )
5061         {
5062                 var table = $(settings.nTable);
5063         
5064                 // Add the ARIA grid role to the table
5065                 table.attr( 'role', 'grid' );
5066         
5067                 // Scrolling from here on in
5068                 var scroll = settings.oScroll;
5069         
5070                 if ( scroll.sX === '' && scroll.sY === '' ) {
5071                         return settings.nTable;
5072                 }
5073         
5074                 var scrollX = scroll.sX;
5075                 var scrollY = scroll.sY;
5076                 var classes = settings.oClasses;
5077                 var caption = table.children('caption');
5078                 var captionSide = caption.length ? caption[0]._captionSide : null;
5079                 var headerClone = $( table[0].cloneNode(false) );
5080                 var footerClone = $( table[0].cloneNode(false) );
5081                 var footer = table.children('tfoot');
5082                 var _div = '<div/>';
5083                 var size = function ( s ) {
5084                         return !s ? null : _fnStringToCss( s );
5085                 };
5086         
5087                 if ( ! footer.length ) {
5088                         footer = null;
5089                 }
5090         
5091                 /*
5092                  * The HTML structure that we want to generate in this function is:
5093                  *  div - scroller
5094                  *    div - scroll head
5095                  *      div - scroll head inner
5096                  *        table - scroll head table
5097                  *          thead - thead
5098                  *    div - scroll body
5099                  *      table - table (master table)
5100                  *        thead - thead clone for sizing
5101                  *        tbody - tbody
5102                  *    div - scroll foot
5103                  *      div - scroll foot inner
5104                  *        table - scroll foot table
5105                  *          tfoot - tfoot
5106                  */
5107                 var scroller = $( _div, { 'class': classes.sScrollWrapper } )
5108                         .append(
5109                                 $(_div, { 'class': classes.sScrollHead } )
5110                                         .css( {
5111                                                 overflow: 'hidden',
5112                                                 position: 'relative',
5113                                                 border: 0,
5114                                                 width: scrollX ? size(scrollX) : '100%'
5115                                         } )
5116                                         .append(
5117                                                 $(_div, { 'class': classes.sScrollHeadInner } )
5118                                                         .css( {
5119                                                                 'box-sizing': 'content-box',
5120                                                                 width: scroll.sXInner || '100%'
5121                                                         } )
5122                                                         .append(
5123                                                                 headerClone
5124                                                                         .removeAttr('id')
5125                                                                         .css( 'margin-left', 0 )
5126                                                                         .append( captionSide === 'top' ? caption : null )
5127                                                                         .append(
5128                                                                                 table.children('thead')
5129                                                                         )
5130                                                         )
5131                                         )
5132                         )
5133                         .append(
5134                                 $(_div, { 'class': classes.sScrollBody } )
5135                                         .css( {
5136                                                 position: 'relative',
5137                                                 overflow: 'auto',
5138                                                 width: size( scrollX )
5139                                         } )
5140                                         .append( table )
5141                         );
5142         
5143                 if ( footer ) {
5144                         scroller.append(
5145                                 $(_div, { 'class': classes.sScrollFoot } )
5146                                         .css( {
5147                                                 overflow: 'hidden',
5148                                                 border: 0,
5149                                                 width: scrollX ? size(scrollX) : '100%'
5150                                         } )
5151                                         .append(
5152                                                 $(_div, { 'class': classes.sScrollFootInner } )
5153                                                         .append(
5154                                                                 footerClone
5155                                                                         .removeAttr('id')
5156                                                                         .css( 'margin-left', 0 )
5157                                                                         .append( captionSide === 'bottom' ? caption : null )
5158                                                                         .append(
5159                                                                                 table.children('tfoot')
5160                                                                         )
5161                                                         )
5162                                         )
5163                         );
5164                 }
5165         
5166                 var children = scroller.children();
5167                 var scrollHead = children[0];
5168                 var scrollBody = children[1];
5169                 var scrollFoot = footer ? children[2] : null;
5170         
5171                 // When the body is scrolled, then we also want to scroll the headers
5172                 if ( scrollX ) {
5173                         $(scrollBody).on( 'scroll.DT', function (e) {
5174                                 var scrollLeft = this.scrollLeft;
5175         
5176                                 scrollHead.scrollLeft = scrollLeft;
5177         
5178                                 if ( footer ) {
5179                                         scrollFoot.scrollLeft = scrollLeft;
5180                                 }
5181                         } );
5182                 }
5183         
5184                 $(scrollBody).css('max-height', scrollY);
5185                 if (! scroll.bCollapse) {
5186                         $(scrollBody).css('height', scrollY);
5187                 }
5188         
5189                 settings.nScrollHead = scrollHead;
5190                 settings.nScrollBody = scrollBody;
5191                 settings.nScrollFoot = scrollFoot;
5192         
5193                 // On redraw - align columns
5194                 settings.aoDrawCallback.push( {
5195                         "fn": _fnScrollDraw,
5196                         "sName": "scrolling"
5197                 } );
5198         
5199                 return scroller[0];
5200         }
5201         
5202         
5203         
5204         /**
5205          * Update the header, footer and body tables for resizing - i.e. column
5206          * alignment.
5207          *
5208          * Welcome to the most horrible function DataTables. The process that this
5209          * function follows is basically:
5210          *   1. Re-create the table inside the scrolling div
5211          *   2. Take live measurements from the DOM
5212          *   3. Apply the measurements to align the columns
5213          *   4. Clean up
5214          *
5215          *  @param {object} settings dataTables settings object
5216          *  @memberof DataTable#oApi
5217          */
5218         function _fnScrollDraw ( settings )
5219         {
5220                 // Given that this is such a monster function, a lot of variables are use
5221                 // to try and keep the minimised size as small as possible
5222                 var
5223                         scroll         = settings.oScroll,
5224                         scrollX        = scroll.sX,
5225                         scrollXInner   = scroll.sXInner,
5226                         scrollY        = scroll.sY,
5227                         barWidth       = scroll.iBarWidth,
5228                         divHeader      = $(settings.nScrollHead),
5229                         divHeaderStyle = divHeader[0].style,
5230                         divHeaderInner = divHeader.children('div'),
5231                         divHeaderInnerStyle = divHeaderInner[0].style,
5232                         divHeaderTable = divHeaderInner.children('table'),
5233                         divBodyEl      = settings.nScrollBody,
5234                         divBody        = $(divBodyEl),
5235                         divBodyStyle   = divBodyEl.style,
5236                         divFooter      = $(settings.nScrollFoot),
5237                         divFooterInner = divFooter.children('div'),
5238                         divFooterTable = divFooterInner.children('table'),
5239                         header         = $(settings.nTHead),
5240                         table          = $(settings.nTable),
5241                         tableEl        = table[0],
5242                         tableStyle     = tableEl.style,
5243                         footer         = settings.nTFoot ? $(settings.nTFoot) : null,
5244                         browser        = settings.oBrowser,
5245                         ie67           = browser.bScrollOversize,
5246                         dtHeaderCells  = _pluck( settings.aoColumns, 'nTh' ),
5247                         headerTrgEls, footerTrgEls,
5248                         headerSrcEls, footerSrcEls,
5249                         headerCopy, footerCopy,
5250                         headerWidths=[], footerWidths=[],
5251                         headerContent=[], footerContent=[],
5252                         idx, correction, sanityWidth,
5253                         zeroOut = function(nSizer) {
5254                                 var style = nSizer.style;
5255                                 style.paddingTop = "0";
5256                                 style.paddingBottom = "0";
5257                                 style.borderTopWidth = "0";
5258                                 style.borderBottomWidth = "0";
5259                                 style.height = 0;
5260                         };
5261         
5262                 // If the scrollbar visibility has changed from the last draw, we need to
5263                 // adjust the column sizes as the table width will have changed to account
5264                 // for the scrollbar
5265                 var scrollBarVis = divBodyEl.scrollHeight > divBodyEl.clientHeight;
5266                 
5267                 if ( settings.scrollBarVis !== scrollBarVis && settings.scrollBarVis !== undefined ) {
5268                         settings.scrollBarVis = scrollBarVis;
5269                         _fnAdjustColumnSizing( settings );
5270                         return; // adjust column sizing will call this function again
5271                 }
5272                 else {
5273                         settings.scrollBarVis = scrollBarVis;
5274                 }
5275         
5276                 /*
5277                  * 1. Re-create the table inside the scrolling div
5278                  */
5279         
5280                 // Remove the old minimised thead and tfoot elements in the inner table
5281                 table.children('thead, tfoot').remove();
5282         
5283                 if ( footer ) {
5284                         footerCopy = footer.clone().prependTo( table );
5285                         footerTrgEls = footer.find('tr'); // the original tfoot is in its own table and must be sized
5286                         footerSrcEls = footerCopy.find('tr');
5287                 }
5288         
5289                 // Clone the current header and footer elements and then place it into the inner table
5290                 headerCopy = header.clone().prependTo( table );
5291                 headerTrgEls = header.find('tr'); // original header is in its own table
5292                 headerSrcEls = headerCopy.find('tr');
5293                 headerCopy.find('th, td').removeAttr('tabindex');
5294         
5295         
5296                 /*
5297                  * 2. Take live measurements from the DOM - do not alter the DOM itself!
5298                  */
5299         
5300                 // Remove old sizing and apply the calculated column widths
5301                 // Get the unique column headers in the newly created (cloned) header. We want to apply the
5302                 // calculated sizes to this header
5303                 if ( ! scrollX )
5304                 {
5305                         divBodyStyle.width = '100%';
5306                         divHeader[0].style.width = '100%';
5307                 }
5308         
5309                 $.each( _fnGetUniqueThs( settings, headerCopy ), function ( i, el ) {
5310                         idx = _fnVisibleToColumnIndex( settings, i );
5311                         el.style.width = settings.aoColumns[idx].sWidth;
5312                 } );
5313         
5314                 if ( footer ) {
5315                         _fnApplyToChildren( function(n) {
5316                                 n.style.width = "";
5317                         }, footerSrcEls );
5318                 }
5319         
5320                 // Size the table as a whole
5321                 sanityWidth = table.outerWidth();
5322                 if ( scrollX === "" ) {
5323                         // No x scrolling
5324                         tableStyle.width = "100%";
5325         
5326                         // IE7 will make the width of the table when 100% include the scrollbar
5327                         // - which is shouldn't. When there is a scrollbar we need to take this
5328                         // into account.
5329                         if ( ie67 && (table.find('tbody').height() > divBodyEl.offsetHeight ||
5330                                 divBody.css('overflow-y') == "scroll")
5331                         ) {
5332                                 tableStyle.width = _fnStringToCss( table.outerWidth() - barWidth);
5333                         }
5334         
5335                         // Recalculate the sanity width
5336                         sanityWidth = table.outerWidth();
5337                 }
5338                 else if ( scrollXInner !== "" ) {
5339                         // legacy x scroll inner has been given - use it
5340                         tableStyle.width = _fnStringToCss(scrollXInner);
5341         
5342                         // Recalculate the sanity width
5343                         sanityWidth = table.outerWidth();
5344                 }
5345         
5346                 // Hidden header should have zero height, so remove padding and borders. Then
5347                 // set the width based on the real headers
5348         
5349                 // Apply all styles in one pass
5350                 _fnApplyToChildren( zeroOut, headerSrcEls );
5351         
5352                 // Read all widths in next pass
5353                 _fnApplyToChildren( function(nSizer) {
5354                         headerContent.push( nSizer.innerHTML );
5355                         headerWidths.push( _fnStringToCss( $(nSizer).css('width') ) );
5356                 }, headerSrcEls );
5357         
5358                 // Apply all widths in final pass
5359                 _fnApplyToChildren( function(nToSize, i) {
5360                         // Only apply widths to the DataTables detected header cells - this
5361                         // prevents complex headers from having contradictory sizes applied
5362                         if ( $.inArray( nToSize, dtHeaderCells ) !== -1 ) {
5363                                 nToSize.style.width = headerWidths[i];
5364                         }
5365                 }, headerTrgEls );
5366         
5367                 $(headerSrcEls).height(0);
5368         
5369                 /* Same again with the footer if we have one */
5370                 if ( footer )
5371                 {
5372                         _fnApplyToChildren( zeroOut, footerSrcEls );
5373         
5374                         _fnApplyToChildren( function(nSizer) {
5375                                 footerContent.push( nSizer.innerHTML );
5376                                 footerWidths.push( _fnStringToCss( $(nSizer).css('width') ) );
5377                         }, footerSrcEls );
5378         
5379                         _fnApplyToChildren( function(nToSize, i) {
5380                                 nToSize.style.width = footerWidths[i];
5381                         }, footerTrgEls );
5382         
5383                         $(footerSrcEls).height(0);
5384                 }
5385         
5386         
5387                 /*
5388                  * 3. Apply the measurements
5389                  */
5390         
5391                 // "Hide" the header and footer that we used for the sizing. We need to keep
5392                 // the content of the cell so that the width applied to the header and body
5393                 // both match, but we want to hide it completely. We want to also fix their
5394                 // width to what they currently are
5395                 _fnApplyToChildren( function(nSizer, i) {
5396                         nSizer.innerHTML = '<div class="dataTables_sizing">'+headerContent[i]+'</div>';
5397                         nSizer.childNodes[0].style.height = "0";
5398                         nSizer.childNodes[0].style.overflow = "hidden";
5399                         nSizer.style.width = headerWidths[i];
5400                 }, headerSrcEls );
5401         
5402                 if ( footer )
5403                 {
5404                         _fnApplyToChildren( function(nSizer, i) {
5405                                 nSizer.innerHTML = '<div class="dataTables_sizing">'+footerContent[i]+'</div>';
5406                                 nSizer.childNodes[0].style.height = "0";
5407                                 nSizer.childNodes[0].style.overflow = "hidden";
5408                                 nSizer.style.width = footerWidths[i];
5409                         }, footerSrcEls );
5410                 }
5411         
5412                 // Sanity check that the table is of a sensible width. If not then we are going to get
5413                 // misalignment - try to prevent this by not allowing the table to shrink below its min width
5414                 if ( table.outerWidth() < sanityWidth )
5415                 {
5416                         // The min width depends upon if we have a vertical scrollbar visible or not */
5417                         correction = ((divBodyEl.scrollHeight > divBodyEl.offsetHeight ||
5418                                 divBody.css('overflow-y') == "scroll")) ?
5419                                         sanityWidth+barWidth :
5420                                         sanityWidth;
5421         
5422                         // IE6/7 are a law unto themselves...
5423                         if ( ie67 && (divBodyEl.scrollHeight >
5424                                 divBodyEl.offsetHeight || divBody.css('overflow-y') == "scroll")
5425                         ) {
5426                                 tableStyle.width = _fnStringToCss( correction-barWidth );
5427                         }
5428         
5429                         // And give the user a warning that we've stopped the table getting too small
5430                         if ( scrollX === "" || scrollXInner !== "" ) {
5431                                 _fnLog( settings, 1, 'Possible column misalignment', 6 );
5432                         }
5433                 }
5434                 else
5435                 {
5436                         correction = '100%';
5437                 }
5438         
5439                 // Apply to the container elements
5440                 divBodyStyle.width = _fnStringToCss( correction );
5441                 divHeaderStyle.width = _fnStringToCss( correction );
5442         
5443                 if ( footer ) {
5444                         settings.nScrollFoot.style.width = _fnStringToCss( correction );
5445                 }
5446         
5447         
5448                 /*
5449                  * 4. Clean up
5450                  */
5451                 if ( ! scrollY ) {
5452                         /* IE7< puts a vertical scrollbar in place (when it shouldn't be) due to subtracting
5453                          * the scrollbar height from the visible display, rather than adding it on. We need to
5454                          * set the height in order to sort this. Don't want to do it in any other browsers.
5455                          */
5456                         if ( ie67 ) {
5457                                 divBodyStyle.height = _fnStringToCss( tableEl.offsetHeight+barWidth );
5458                         }
5459                 }
5460         
5461                 /* Finally set the width's of the header and footer tables */
5462                 var iOuterWidth = table.outerWidth();
5463                 divHeaderTable[0].style.width = _fnStringToCss( iOuterWidth );
5464                 divHeaderInnerStyle.width = _fnStringToCss( iOuterWidth );
5465         
5466                 // Figure out if there are scrollbar present - if so then we need a the header and footer to
5467                 // provide a bit more space to allow "overflow" scrolling (i.e. past the scrollbar)
5468                 var bScrolling = table.height() > divBodyEl.clientHeight || divBody.css('overflow-y') == "scroll";
5469                 var padding = 'padding' + (browser.bScrollbarLeft ? 'Left' : 'Right' );
5470                 divHeaderInnerStyle[ padding ] = bScrolling ? barWidth+"px" : "0px";
5471         
5472                 if ( footer ) {
5473                         divFooterTable[0].style.width = _fnStringToCss( iOuterWidth );
5474                         divFooterInner[0].style.width = _fnStringToCss( iOuterWidth );
5475                         divFooterInner[0].style[padding] = bScrolling ? barWidth+"px" : "0px";
5476                 }
5477         
5478                 // Correct DOM ordering for colgroup - comes before the thead
5479                 table.children('colgroup').insertBefore( table.children('thead') );
5480         
5481                 /* Adjust the position of the header in case we loose the y-scrollbar */
5482                 divBody.trigger('scroll');
5483         
5484                 // If sorting or filtering has occurred, jump the scrolling back to the top
5485                 // only if we aren't holding the position
5486                 if ( (settings.bSorted || settings.bFiltered) && ! settings._drawHold ) {
5487                         divBodyEl.scrollTop = 0;
5488                 }
5489         }
5490         
5491         
5492         
5493         /**
5494          * Apply a given function to the display child nodes of an element array (typically
5495          * TD children of TR rows
5496          *  @param {function} fn Method to apply to the objects
5497          *  @param array {nodes} an1 List of elements to look through for display children
5498          *  @param array {nodes} an2 Another list (identical structure to the first) - optional
5499          *  @memberof DataTable#oApi
5500          */
5501         function _fnApplyToChildren( fn, an1, an2 )
5502         {
5503                 var index=0, i=0, iLen=an1.length;
5504                 var nNode1, nNode2;
5505         
5506                 while ( i < iLen ) {
5507                         nNode1 = an1[i].firstChild;
5508                         nNode2 = an2 ? an2[i].firstChild : null;
5509         
5510                         while ( nNode1 ) {
5511                                 if ( nNode1.nodeType === 1 ) {
5512                                         if ( an2 ) {
5513                                                 fn( nNode1, nNode2, index );
5514                                         }
5515                                         else {
5516                                                 fn( nNode1, index );
5517                                         }
5518         
5519                                         index++;
5520                                 }
5521         
5522                                 nNode1 = nNode1.nextSibling;
5523                                 nNode2 = an2 ? nNode2.nextSibling : null;
5524                         }
5525         
5526                         i++;
5527                 }
5528         }
5529         
5530         
5531         
5532         var __re_html_remove = /<.*?>/g;
5533         
5534         
5535         /**
5536          * Calculate the width of columns for the table
5537          *  @param {object} oSettings dataTables settings object
5538          *  @memberof DataTable#oApi
5539          */
5540         function _fnCalculateColumnWidths ( oSettings )
5541         {
5542                 var
5543                         table = oSettings.nTable,
5544                         columns = oSettings.aoColumns,
5545                         scroll = oSettings.oScroll,
5546                         scrollY = scroll.sY,
5547                         scrollX = scroll.sX,
5548                         scrollXInner = scroll.sXInner,
5549                         columnCount = columns.length,
5550                         visibleColumns = _fnGetColumns( oSettings, 'bVisible' ),
5551                         headerCells = $('th', oSettings.nTHead),
5552                         tableWidthAttr = table.getAttribute('width'), // from DOM element
5553                         tableContainer = table.parentNode,
5554                         userInputs = false,
5555                         i, column, columnIdx, width, outerWidth,
5556                         browser = oSettings.oBrowser,
5557                         ie67 = browser.bScrollOversize;
5558         
5559                 var styleWidth = table.style.width;
5560                 if ( styleWidth && styleWidth.indexOf('%') !== -1 ) {
5561                         tableWidthAttr = styleWidth;
5562                 }
5563         
5564                 /* Convert any user input sizes into pixel sizes */
5565                 for ( i=0 ; i<visibleColumns.length ; i++ ) {
5566                         column = columns[ visibleColumns[i] ];
5567         
5568                         if ( column.sWidth !== null ) {
5569                                 column.sWidth = _fnConvertToWidth( column.sWidthOrig, tableContainer );
5570         
5571                                 userInputs = true;
5572                         }
5573                 }
5574         
5575                 /* If the number of columns in the DOM equals the number that we have to
5576                  * process in DataTables, then we can use the offsets that are created by
5577                  * the web- browser. No custom sizes can be set in order for this to happen,
5578                  * nor scrolling used
5579                  */
5580                 if ( ie67 || ! userInputs && ! scrollX && ! scrollY &&
5581                      columnCount == _fnVisbleColumns( oSettings ) &&
5582                      columnCount == headerCells.length
5583                 ) {
5584                         for ( i=0 ; i<columnCount ; i++ ) {
5585                                 var colIdx = _fnVisibleToColumnIndex( oSettings, i );
5586         
5587                                 if ( colIdx !== null ) {
5588                                         columns[ colIdx ].sWidth = _fnStringToCss( headerCells.eq(i).width() );
5589                                 }
5590                         }
5591                 }
5592                 else
5593                 {
5594                         // Otherwise construct a single row, worst case, table with the widest
5595                         // node in the data, assign any user defined widths, then insert it into
5596                         // the DOM and allow the browser to do all the hard work of calculating
5597                         // table widths
5598                         var tmpTable = $(table).clone() // don't use cloneNode - IE8 will remove events on the main table
5599                                 .css( 'visibility', 'hidden' )
5600                                 .removeAttr( 'id' );
5601         
5602                         // Clean up the table body
5603                         tmpTable.find('tbody tr').remove();
5604                         var tr = $('<tr/>').appendTo( tmpTable.find('tbody') );
5605         
5606                         // Clone the table header and footer - we can't use the header / footer
5607                         // from the cloned table, since if scrolling is active, the table's
5608                         // real header and footer are contained in different table tags
5609                         tmpTable.find('thead, tfoot').remove();
5610                         tmpTable
5611                                 .append( $(oSettings.nTHead).clone() )
5612                                 .append( $(oSettings.nTFoot).clone() );
5613         
5614                         // Remove any assigned widths from the footer (from scrolling)
5615                         tmpTable.find('tfoot th, tfoot td').css('width', '');
5616         
5617                         // Apply custom sizing to the cloned header
5618                         headerCells = _fnGetUniqueThs( oSettings, tmpTable.find('thead')[0] );
5619         
5620                         for ( i=0 ; i<visibleColumns.length ; i++ ) {
5621                                 column = columns[ visibleColumns[i] ];
5622         
5623                                 headerCells[i].style.width = column.sWidthOrig !== null && column.sWidthOrig !== '' ?
5624                                         _fnStringToCss( column.sWidthOrig ) :
5625                                         '';
5626         
5627                                 // For scrollX we need to force the column width otherwise the
5628                                 // browser will collapse it. If this width is smaller than the
5629                                 // width the column requires, then it will have no effect
5630                                 if ( column.sWidthOrig && scrollX ) {
5631                                         $( headerCells[i] ).append( $('<div/>').css( {
5632                                                 width: column.sWidthOrig,
5633                                                 margin: 0,
5634                                                 padding: 0,
5635                                                 border: 0,
5636                                                 height: 1
5637                                         } ) );
5638                                 }
5639                         }
5640         
5641                         // Find the widest cell for each column and put it into the table
5642                         if ( oSettings.aoData.length ) {
5643                                 for ( i=0 ; i<visibleColumns.length ; i++ ) {
5644                                         columnIdx = visibleColumns[i];
5645                                         column = columns[ columnIdx ];
5646         
5647                                         $( _fnGetWidestNode( oSettings, columnIdx ) )
5648                                                 .clone( false )
5649                                                 .append( column.sContentPadding )
5650                                                 .appendTo( tr );
5651                                 }
5652                         }
5653         
5654                         // Tidy the temporary table - remove name attributes so there aren't
5655                         // duplicated in the dom (radio elements for example)
5656                         $('[name]', tmpTable).removeAttr('name');
5657         
5658                         // Table has been built, attach to the document so we can work with it.
5659                         // A holding element is used, positioned at the top of the container
5660                         // with minimal height, so it has no effect on if the container scrolls
5661                         // or not. Otherwise it might trigger scrolling when it actually isn't
5662                         // needed
5663                         var holder = $('<div/>').css( scrollX || scrollY ?
5664                                         {
5665                                                 position: 'absolute',
5666                                                 top: 0,
5667                                                 left: 0,
5668                                                 height: 1,
5669                                                 right: 0,
5670                                                 overflow: 'hidden'
5671                                         } :
5672                                         {}
5673                                 )
5674                                 .append( tmpTable )
5675                                 .appendTo( tableContainer );
5676         
5677                         // When scrolling (X or Y) we want to set the width of the table as 
5678                         // appropriate. However, when not scrolling leave the table width as it
5679                         // is. This results in slightly different, but I think correct behaviour
5680                         if ( scrollX && scrollXInner ) {
5681                                 tmpTable.width( scrollXInner );
5682                         }
5683                         else if ( scrollX ) {
5684                                 tmpTable.css( 'width', 'auto' );
5685                                 tmpTable.removeAttr('width');
5686         
5687                                 // If there is no width attribute or style, then allow the table to
5688                                 // collapse
5689                                 if ( tmpTable.width() < tableContainer.clientWidth && tableWidthAttr ) {
5690                                         tmpTable.width( tableContainer.clientWidth );
5691                                 }
5692                         }
5693                         else if ( scrollY ) {
5694                                 tmpTable.width( tableContainer.clientWidth );
5695                         }
5696                         else if ( tableWidthAttr ) {
5697                                 tmpTable.width( tableWidthAttr );
5698                         }
5699         
5700                         // Get the width of each column in the constructed table - we need to
5701                         // know the inner width (so it can be assigned to the other table's
5702                         // cells) and the outer width so we can calculate the full width of the
5703                         // table. This is safe since DataTables requires a unique cell for each
5704                         // column, but if ever a header can span multiple columns, this will
5705                         // need to be modified.
5706                         var total = 0;
5707                         for ( i=0 ; i<visibleColumns.length ; i++ ) {
5708                                 var cell = $(headerCells[i]);
5709                                 var border = cell.outerWidth() - cell.width();
5710         
5711                                 // Use getBounding... where possible (not IE8-) because it can give
5712                                 // sub-pixel accuracy, which we then want to round up!
5713                                 var bounding = browser.bBounding ?
5714                                         Math.ceil( headerCells[i].getBoundingClientRect().width ) :
5715                                         cell.outerWidth();
5716         
5717                                 // Total is tracked to remove any sub-pixel errors as the outerWidth
5718                                 // of the table might not equal the total given here (IE!).
5719                                 total += bounding;
5720         
5721                                 // Width for each column to use
5722                                 columns[ visibleColumns[i] ].sWidth = _fnStringToCss( bounding - border );
5723                         }
5724         
5725                         table.style.width = _fnStringToCss( total );
5726         
5727                         // Finished with the table - ditch it
5728                         holder.remove();
5729                 }
5730         
5731                 // If there is a width attr, we want to attach an event listener which
5732                 // allows the table sizing to automatically adjust when the window is
5733                 // resized. Use the width attr rather than CSS, since we can't know if the
5734                 // CSS is a relative value or absolute - DOM read is always px.
5735                 if ( tableWidthAttr ) {
5736                         table.style.width = _fnStringToCss( tableWidthAttr );
5737                 }
5738         
5739                 if ( (tableWidthAttr || scrollX) && ! oSettings._reszEvt ) {
5740                         var bindResize = function () {
5741                                 $(window).on('resize.DT-'+oSettings.sInstance, _fnThrottle( function () {
5742                                         _fnAdjustColumnSizing( oSettings );
5743                                 } ) );
5744                         };
5745         
5746                         // IE6/7 will crash if we bind a resize event handler on page load.
5747                         // To be removed in 1.11 which drops IE6/7 support
5748                         if ( ie67 ) {
5749                                 setTimeout( bindResize, 1000 );
5750                         }
5751                         else {
5752                                 bindResize();
5753                         }
5754         
5755                         oSettings._reszEvt = true;
5756                 }
5757         }
5758         
5759         
5760         /**
5761          * Throttle the calls to a function. Arguments and context are maintained for
5762          * the throttled function
5763          *  @param {function} fn Function to be called
5764          *  @param {int} [freq=200] call frequency in mS
5765          *  @returns {function} wrapped function
5766          *  @memberof DataTable#oApi
5767          */
5768         var _fnThrottle = DataTable.util.throttle;
5769         
5770         
5771         /**
5772          * Convert a CSS unit width to pixels (e.g. 2em)
5773          *  @param {string} width width to be converted
5774          *  @param {node} parent parent to get the with for (required for relative widths) - optional
5775          *  @returns {int} width in pixels
5776          *  @memberof DataTable#oApi
5777          */
5778         function _fnConvertToWidth ( width, parent )
5779         {
5780                 if ( ! width ) {
5781                         return 0;
5782                 }
5783         
5784                 var n = $('<div/>')
5785                         .css( 'width', _fnStringToCss( width ) )
5786                         .appendTo( parent || document.body );
5787         
5788                 var val = n[0].offsetWidth;
5789                 n.remove();
5790         
5791                 return val;
5792         }
5793         
5794         
5795         /**
5796          * Get the widest node
5797          *  @param {object} settings dataTables settings object
5798          *  @param {int} colIdx column of interest
5799          *  @returns {node} widest table node
5800          *  @memberof DataTable#oApi
5801          */
5802         function _fnGetWidestNode( settings, colIdx )
5803         {
5804                 var idx = _fnGetMaxLenString( settings, colIdx );
5805                 if ( idx < 0 ) {
5806                         return null;
5807                 }
5808         
5809                 var data = settings.aoData[ idx ];
5810                 return ! data.nTr ? // Might not have been created when deferred rendering
5811                         $('<td/>').html( _fnGetCellData( settings, idx, colIdx, 'display' ) )[0] :
5812                         data.anCells[ colIdx ];
5813         }
5814         
5815         
5816         /**
5817          * Get the maximum strlen for each data column
5818          *  @param {object} settings dataTables settings object
5819          *  @param {int} colIdx column of interest
5820          *  @returns {string} max string length for each column
5821          *  @memberof DataTable#oApi
5822          */
5823         function _fnGetMaxLenString( settings, colIdx )
5824         {
5825                 var s, max=-1, maxIdx = -1;
5826         
5827                 for ( var i=0, ien=settings.aoData.length ; i<ien ; i++ ) {
5828                         s = _fnGetCellData( settings, i, colIdx, 'display' )+'';
5829                         s = s.replace( __re_html_remove, '' );
5830                         s = s.replace( /&nbsp;/g, ' ' );
5831         
5832                         if ( s.length > max ) {
5833                                 max = s.length;
5834                                 maxIdx = i;
5835                         }
5836                 }
5837         
5838                 return maxIdx;
5839         }
5840         
5841         
5842         /**
5843          * Append a CSS unit (only if required) to a string
5844          *  @param {string} value to css-ify
5845          *  @returns {string} value with css unit
5846          *  @memberof DataTable#oApi
5847          */
5848         function _fnStringToCss( s )
5849         {
5850                 if ( s === null ) {
5851                         return '0px';
5852                 }
5853         
5854                 if ( typeof s == 'number' ) {
5855                         return s < 0 ?
5856                                 '0px' :
5857                                 s+'px';
5858                 }
5859         
5860                 // Check it has a unit character already
5861                 return s.match(/\d$/) ?
5862                         s+'px' :
5863                         s;
5864         }
5865         
5866         
5867         
5868         function _fnSortFlatten ( settings )
5869         {
5870                 var
5871                         i, iLen, k, kLen,
5872                         aSort = [],
5873                         aiOrig = [],
5874                         aoColumns = settings.aoColumns,
5875                         aDataSort, iCol, sType, srcCol,
5876                         fixed = settings.aaSortingFixed,
5877                         fixedObj = $.isPlainObject( fixed ),
5878                         nestedSort = [],
5879                         add = function ( a ) {
5880                                 if ( a.length && ! $.isArray( a[0] ) ) {
5881                                         // 1D array
5882                                         nestedSort.push( a );
5883                                 }
5884                                 else {
5885                                         // 2D array
5886                                         $.merge( nestedSort, a );
5887                                 }
5888                         };
5889         
5890                 // Build the sort array, with pre-fix and post-fix options if they have been
5891                 // specified
5892                 if ( $.isArray( fixed ) ) {
5893                         add( fixed );
5894                 }
5895         
5896                 if ( fixedObj && fixed.pre ) {
5897                         add( fixed.pre );
5898                 }
5899         
5900                 add( settings.aaSorting );
5901         
5902                 if (fixedObj && fixed.post ) {
5903                         add( fixed.post );
5904                 }
5905         
5906                 for ( i=0 ; i<nestedSort.length ; i++ )
5907                 {
5908                         srcCol = nestedSort[i][0];
5909                         aDataSort = aoColumns[ srcCol ].aDataSort;
5910         
5911                         for ( k=0, kLen=aDataSort.length ; k<kLen ; k++ )
5912                         {
5913                                 iCol = aDataSort[k];
5914                                 sType = aoColumns[ iCol ].sType || 'string';
5915         
5916                                 if ( nestedSort[i]._idx === undefined ) {
5917                                         nestedSort[i]._idx = $.inArray( nestedSort[i][1], aoColumns[iCol].asSorting );
5918                                 }
5919         
5920                                 aSort.push( {
5921                                         src:       srcCol,
5922                                         col:       iCol,
5923                                         dir:       nestedSort[i][1],
5924                                         index:     nestedSort[i]._idx,
5925                                         type:      sType,
5926                                         formatter: DataTable.ext.type.order[ sType+"-pre" ]
5927                                 } );
5928                         }
5929                 }
5930         
5931                 return aSort;
5932         }
5933         
5934         /**
5935          * Change the order of the table
5936          *  @param {object} oSettings dataTables settings object
5937          *  @memberof DataTable#oApi
5938          *  @todo This really needs split up!
5939          */
5940         function _fnSort ( oSettings )
5941         {
5942                 var
5943                         i, ien, iLen, j, jLen, k, kLen,
5944                         sDataType, nTh,
5945                         aiOrig = [],
5946                         oExtSort = DataTable.ext.type.order,
5947                         aoData = oSettings.aoData,
5948                         aoColumns = oSettings.aoColumns,
5949                         aDataSort, data, iCol, sType, oSort,
5950                         formatters = 0,
5951                         sortCol,
5952                         displayMaster = oSettings.aiDisplayMaster,
5953                         aSort;
5954         
5955                 // Resolve any column types that are unknown due to addition or invalidation
5956                 // @todo Can this be moved into a 'data-ready' handler which is called when
5957                 //   data is going to be used in the table?
5958                 _fnColumnTypes( oSettings );
5959         
5960                 aSort = _fnSortFlatten( oSettings );
5961         
5962                 for ( i=0, ien=aSort.length ; i<ien ; i++ ) {
5963                         sortCol = aSort[i];
5964         
5965                         // Track if we can use the fast sort algorithm
5966                         if ( sortCol.formatter ) {
5967                                 formatters++;
5968                         }
5969         
5970                         // Load the data needed for the sort, for each cell
5971                         _fnSortData( oSettings, sortCol.col );
5972                 }
5973         
5974                 /* No sorting required if server-side or no sorting array */
5975                 if ( _fnDataSource( oSettings ) != 'ssp' && aSort.length !== 0 )
5976                 {
5977                         // Create a value - key array of the current row positions such that we can use their
5978                         // current position during the sort, if values match, in order to perform stable sorting
5979                         for ( i=0, iLen=displayMaster.length ; i<iLen ; i++ ) {
5980                                 aiOrig[ displayMaster[i] ] = i;
5981                         }
5982         
5983                         /* Do the sort - here we want multi-column sorting based on a given data source (column)
5984                          * and sorting function (from oSort) in a certain direction. It's reasonably complex to
5985                          * follow on it's own, but this is what we want (example two column sorting):
5986                          *  fnLocalSorting = function(a,b){
5987                          *    var iTest;
5988                          *    iTest = oSort['string-asc']('data11', 'data12');
5989                          *      if (iTest !== 0)
5990                          *        return iTest;
5991                          *    iTest = oSort['numeric-desc']('data21', 'data22');
5992                          *    if (iTest !== 0)
5993                          *      return iTest;
5994                          *    return oSort['numeric-asc']( aiOrig[a], aiOrig[b] );
5995                          *  }
5996                          * Basically we have a test for each sorting column, if the data in that column is equal,
5997                          * test the next column. If all columns match, then we use a numeric sort on the row
5998                          * positions in the original data array to provide a stable sort.
5999                          *
6000                          * Note - I know it seems excessive to have two sorting methods, but the first is around
6001                          * 15% faster, so the second is only maintained for backwards compatibility with sorting
6002                          * methods which do not have a pre-sort formatting function.
6003                          */
6004                         if ( formatters === aSort.length ) {
6005                                 // All sort types have formatting functions
6006                                 displayMaster.sort( function ( a, b ) {
6007                                         var
6008                                                 x, y, k, test, sort,
6009                                                 len=aSort.length,
6010                                                 dataA = aoData[a]._aSortData,
6011                                                 dataB = aoData[b]._aSortData;
6012         
6013                                         for ( k=0 ; k<len ; k++ ) {
6014                                                 sort = aSort[k];
6015         
6016                                                 x = dataA[ sort.col ];
6017                                                 y = dataB[ sort.col ];
6018         
6019                                                 test = x<y ? -1 : x>y ? 1 : 0;
6020                                                 if ( test !== 0 ) {
6021                                                         return sort.dir === 'asc' ? test : -test;
6022                                                 }
6023                                         }
6024         
6025                                         x = aiOrig[a];
6026                                         y = aiOrig[b];
6027                                         return x<y ? -1 : x>y ? 1 : 0;
6028                                 } );
6029                         }
6030                         else {
6031                                 // Depreciated - remove in 1.11 (providing a plug-in option)
6032                                 // Not all sort types have formatting methods, so we have to call their sorting
6033                                 // methods.
6034                                 displayMaster.sort( function ( a, b ) {
6035                                         var
6036                                                 x, y, k, l, test, sort, fn,
6037                                                 len=aSort.length,
6038                                                 dataA = aoData[a]._aSortData,
6039                                                 dataB = aoData[b]._aSortData;
6040         
6041                                         for ( k=0 ; k<len ; k++ ) {
6042                                                 sort = aSort[k];
6043         
6044                                                 x = dataA[ sort.col ];
6045                                                 y = dataB[ sort.col ];
6046         
6047                                                 fn = oExtSort[ sort.type+"-"+sort.dir ] || oExtSort[ "string-"+sort.dir ];
6048                                                 test = fn( x, y );
6049                                                 if ( test !== 0 ) {
6050                                                         return test;
6051                                                 }
6052                                         }
6053         
6054                                         x = aiOrig[a];
6055                                         y = aiOrig[b];
6056                                         return x<y ? -1 : x>y ? 1 : 0;
6057                                 } );
6058                         }
6059                 }
6060         
6061                 /* Tell the draw function that we have sorted the data */
6062                 oSettings.bSorted = true;
6063         }
6064         
6065         
6066         function _fnSortAria ( settings )
6067         {
6068                 var label;
6069                 var nextSort;
6070                 var columns = settings.aoColumns;
6071                 var aSort = _fnSortFlatten( settings );
6072                 var oAria = settings.oLanguage.oAria;
6073         
6074                 // ARIA attributes - need to loop all columns, to update all (removing old
6075                 // attributes as needed)
6076                 for ( var i=0, iLen=columns.length ; i<iLen ; i++ )
6077                 {
6078                         var col = columns[i];
6079                         var asSorting = col.asSorting;
6080                         var sTitle = col.sTitle.replace( /<.*?>/g, "" );
6081                         var th = col.nTh;
6082         
6083                         // IE7 is throwing an error when setting these properties with jQuery's
6084                         // attr() and removeAttr() methods...
6085                         th.removeAttribute('aria-sort');
6086         
6087                         /* In ARIA only the first sorting column can be marked as sorting - no multi-sort option */
6088                         if ( col.bSortable ) {
6089                                 if ( aSort.length > 0 && aSort[0].col == i ) {
6090                                         th.setAttribute('aria-sort', aSort[0].dir=="asc" ? "ascending" : "descending" );
6091                                         nextSort = asSorting[ aSort[0].index+1 ] || asSorting[0];
6092                                 }
6093                                 else {
6094                                         nextSort = asSorting[0];
6095                                 }
6096         
6097                                 label = sTitle + ( nextSort === "asc" ?
6098                                         oAria.sSortAscending :
6099                                         oAria.sSortDescending
6100                                 );
6101                         }
6102                         else {
6103                                 label = sTitle;
6104                         }
6105         
6106                         th.setAttribute('aria-label', label);
6107                 }
6108         }
6109         
6110         
6111         /**
6112          * Function to run on user sort request
6113          *  @param {object} settings dataTables settings object
6114          *  @param {node} attachTo node to attach the handler to
6115          *  @param {int} colIdx column sorting index
6116          *  @param {boolean} [append=false] Append the requested sort to the existing
6117          *    sort if true (i.e. multi-column sort)
6118          *  @param {function} [callback] callback function
6119          *  @memberof DataTable#oApi
6120          */
6121         function _fnSortListener ( settings, colIdx, append, callback )
6122         {
6123                 var col = settings.aoColumns[ colIdx ];
6124                 var sorting = settings.aaSorting;
6125                 var asSorting = col.asSorting;
6126                 var nextSortIdx;
6127                 var next = function ( a, overflow ) {
6128                         var idx = a._idx;
6129                         if ( idx === undefined ) {
6130                                 idx = $.inArray( a[1], asSorting );
6131                         }
6132         
6133                         return idx+1 < asSorting.length ?
6134                                 idx+1 :
6135                                 overflow ?
6136                                         null :
6137                                         0;
6138                 };
6139         
6140                 // Convert to 2D array if needed
6141                 if ( typeof sorting[0] === 'number' ) {
6142                         sorting = settings.aaSorting = [ sorting ];
6143                 }
6144         
6145                 // If appending the sort then we are multi-column sorting
6146                 if ( append && settings.oFeatures.bSortMulti ) {
6147                         // Are we already doing some kind of sort on this column?
6148                         var sortIdx = $.inArray( colIdx, _pluck(sorting, '0') );
6149         
6150                         if ( sortIdx !== -1 ) {
6151                                 // Yes, modify the sort
6152                                 nextSortIdx = next( sorting[sortIdx], true );
6153         
6154                                 if ( nextSortIdx === null && sorting.length === 1 ) {
6155                                         nextSortIdx = 0; // can't remove sorting completely
6156                                 }
6157         
6158                                 if ( nextSortIdx === null ) {
6159                                         sorting.splice( sortIdx, 1 );
6160                                 }
6161                                 else {
6162                                         sorting[sortIdx][1] = asSorting[ nextSortIdx ];
6163                                         sorting[sortIdx]._idx = nextSortIdx;
6164                                 }
6165                         }
6166                         else {
6167                                 // No sort on this column yet
6168                                 sorting.push( [ colIdx, asSorting[0], 0 ] );
6169                                 sorting[sorting.length-1]._idx = 0;
6170                         }
6171                 }
6172                 else if ( sorting.length && sorting[0][0] == colIdx ) {
6173                         // Single column - already sorting on this column, modify the sort
6174                         nextSortIdx = next( sorting[0] );
6175         
6176                         sorting.length = 1;
6177                         sorting[0][1] = asSorting[ nextSortIdx ];
6178                         sorting[0]._idx = nextSortIdx;
6179                 }
6180                 else {
6181                         // Single column - sort only on this column
6182                         sorting.length = 0;
6183                         sorting.push( [ colIdx, asSorting[0] ] );
6184                         sorting[0]._idx = 0;
6185                 }
6186         
6187                 // Run the sort by calling a full redraw
6188                 _fnReDraw( settings );
6189         
6190                 // callback used for async user interaction
6191                 if ( typeof callback == 'function' ) {
6192                         callback( settings );
6193                 }
6194         }
6195         
6196         
6197         /**
6198          * Attach a sort handler (click) to a node
6199          *  @param {object} settings dataTables settings object
6200          *  @param {node} attachTo node to attach the handler to
6201          *  @param {int} colIdx column sorting index
6202          *  @param {function} [callback] callback function
6203          *  @memberof DataTable#oApi
6204          */
6205         function _fnSortAttachListener ( settings, attachTo, colIdx, callback )
6206         {
6207                 var col = settings.aoColumns[ colIdx ];
6208         
6209                 _fnBindAction( attachTo, {}, function (e) {
6210                         /* If the column is not sortable - don't to anything */
6211                         if ( col.bSortable === false ) {
6212                                 return;
6213                         }
6214         
6215                         // If processing is enabled use a timeout to allow the processing
6216                         // display to be shown - otherwise to it synchronously
6217                         if ( settings.oFeatures.bProcessing ) {
6218                                 _fnProcessingDisplay( settings, true );
6219         
6220                                 setTimeout( function() {
6221                                         _fnSortListener( settings, colIdx, e.shiftKey, callback );
6222         
6223                                         // In server-side processing, the draw callback will remove the
6224                                         // processing display
6225                                         if ( _fnDataSource( settings ) !== 'ssp' ) {
6226                                                 _fnProcessingDisplay( settings, false );
6227                                         }
6228                                 }, 0 );
6229                         }
6230                         else {
6231                                 _fnSortListener( settings, colIdx, e.shiftKey, callback );
6232                         }
6233                 } );
6234         }
6235         
6236         
6237         /**
6238          * Set the sorting classes on table's body, Note: it is safe to call this function
6239          * when bSort and bSortClasses are false
6240          *  @param {object} oSettings dataTables settings object
6241          *  @memberof DataTable#oApi
6242          */
6243         function _fnSortingClasses( settings )
6244         {
6245                 var oldSort = settings.aLastSort;
6246                 var sortClass = settings.oClasses.sSortColumn;
6247                 var sort = _fnSortFlatten( settings );
6248                 var features = settings.oFeatures;
6249                 var i, ien, colIdx;
6250         
6251                 if ( features.bSort && features.bSortClasses ) {
6252                         // Remove old sorting classes
6253                         for ( i=0, ien=oldSort.length ; i<ien ; i++ ) {
6254                                 colIdx = oldSort[i].src;
6255         
6256                                 // Remove column sorting
6257                                 $( _pluck( settings.aoData, 'anCells', colIdx ) )
6258                                         .removeClass( sortClass + (i<2 ? i+1 : 3) );
6259                         }
6260         
6261                         // Add new column sorting
6262                         for ( i=0, ien=sort.length ; i<ien ; i++ ) {
6263                                 colIdx = sort[i].src;
6264         
6265                                 $( _pluck( settings.aoData, 'anCells', colIdx ) )
6266                                         .addClass( sortClass + (i<2 ? i+1 : 3) );
6267                         }
6268                 }
6269         
6270                 settings.aLastSort = sort;
6271         }
6272         
6273         
6274         // Get the data to sort a column, be it from cache, fresh (populating the
6275         // cache), or from a sort formatter
6276         function _fnSortData( settings, idx )
6277         {
6278                 // Custom sorting function - provided by the sort data type
6279                 var column = settings.aoColumns[ idx ];
6280                 var customSort = DataTable.ext.order[ column.sSortDataType ];
6281                 var customData;
6282         
6283                 if ( customSort ) {
6284                         customData = customSort.call( settings.oInstance, settings, idx,
6285                                 _fnColumnIndexToVisible( settings, idx )
6286                         );
6287                 }
6288         
6289                 // Use / populate cache
6290                 var row, cellData;
6291                 var formatter = DataTable.ext.type.order[ column.sType+"-pre" ];
6292         
6293                 for ( var i=0, ien=settings.aoData.length ; i<ien ; i++ ) {
6294                         row = settings.aoData[i];
6295         
6296                         if ( ! row._aSortData ) {
6297                                 row._aSortData = [];
6298                         }
6299         
6300                         if ( ! row._aSortData[idx] || customSort ) {
6301                                 cellData = customSort ?
6302                                         customData[i] : // If there was a custom sort function, use data from there
6303                                         _fnGetCellData( settings, i, idx, 'sort' );
6304         
6305                                 row._aSortData[ idx ] = formatter ?
6306                                         formatter( cellData ) :
6307                                         cellData;
6308                         }
6309                 }
6310         }
6311         
6312         
6313         
6314         /**
6315          * Save the state of a table
6316          *  @param {object} oSettings dataTables settings object
6317          *  @memberof DataTable#oApi
6318          */
6319         function _fnSaveState ( settings )
6320         {
6321                 if ( !settings.oFeatures.bStateSave || settings.bDestroying )
6322                 {
6323                         return;
6324                 }
6325         
6326                 /* Store the interesting variables */
6327                 var state = {
6328                         time:    +new Date(),
6329                         start:   settings._iDisplayStart,
6330                         length:  settings._iDisplayLength,
6331                         order:   $.extend( true, [], settings.aaSorting ),
6332                         search:  _fnSearchToCamel( settings.oPreviousSearch ),
6333                         columns: $.map( settings.aoColumns, function ( col, i ) {
6334                                 return {
6335                                         visible: col.bVisible,
6336                                         search: _fnSearchToCamel( settings.aoPreSearchCols[i] )
6337                                 };
6338                         } )
6339                 };
6340         
6341                 _fnCallbackFire( settings, "aoStateSaveParams", 'stateSaveParams', [settings, state] );
6342         
6343                 settings.oSavedState = state;
6344                 settings.fnStateSaveCallback.call( settings.oInstance, settings, state );
6345         }
6346         
6347         
6348         /**
6349          * Attempt to load a saved table state
6350          *  @param {object} oSettings dataTables settings object
6351          *  @param {object} oInit DataTables init object so we can override settings
6352          *  @param {function} callback Callback to execute when the state has been loaded
6353          *  @memberof DataTable#oApi
6354          */
6355         function _fnLoadState ( settings, oInit, callback )
6356         {
6357                 var i, ien;
6358                 var columns = settings.aoColumns;
6359                 var loaded = function ( s ) {
6360                         if ( ! s || ! s.time ) {
6361                                 callback();
6362                                 return;
6363                         }
6364         
6365                         // Allow custom and plug-in manipulation functions to alter the saved data set and
6366                         // cancelling of loading by returning false
6367                         var abStateLoad = _fnCallbackFire( settings, 'aoStateLoadParams', 'stateLoadParams', [settings, s] );
6368                         if ( $.inArray( false, abStateLoad ) !== -1 ) {
6369                                 callback();
6370                                 return;
6371                         }
6372         
6373                         // Reject old data
6374                         var duration = settings.iStateDuration;
6375                         if ( duration > 0 && s.time < +new Date() - (duration*1000) ) {
6376                                 callback();
6377                                 return;
6378                         }
6379         
6380                         // Number of columns have changed - all bets are off, no restore of settings
6381                         if ( s.columns && columns.length !== s.columns.length ) {
6382                                 callback();
6383                                 return;
6384                         }
6385         
6386                         // Store the saved state so it might be accessed at any time
6387                         settings.oLoadedState = $.extend( true, {}, s );
6388         
6389                         // Restore key features - todo - for 1.11 this needs to be done by
6390                         // subscribed events
6391                         if ( s.start !== undefined ) {
6392                                 settings._iDisplayStart    = s.start;
6393                                 settings.iInitDisplayStart = s.start;
6394                         }
6395                         if ( s.length !== undefined ) {
6396                                 settings._iDisplayLength   = s.length;
6397                         }
6398         
6399                         // Order
6400                         if ( s.order !== undefined ) {
6401                                 settings.aaSorting = [];
6402                                 $.each( s.order, function ( i, col ) {
6403                                         settings.aaSorting.push( col[0] >= columns.length ?
6404                                                 [ 0, col[1] ] :
6405                                                 col
6406                                         );
6407                                 } );
6408                         }
6409         
6410                         // Search
6411                         if ( s.search !== undefined ) {
6412                                 $.extend( settings.oPreviousSearch, _fnSearchToHung( s.search ) );
6413                         }
6414         
6415                         // Columns
6416                         //
6417                         if ( s.columns ) {
6418                                 for ( i=0, ien=s.columns.length ; i<ien ; i++ ) {
6419                                         var col = s.columns[i];
6420         
6421                                         // Visibility
6422                                         if ( col.visible !== undefined ) {
6423                                                 columns[i].bVisible = col.visible;
6424                                         }
6425         
6426                                         // Search
6427                                         if ( col.search !== undefined ) {
6428                                                 $.extend( settings.aoPreSearchCols[i], _fnSearchToHung( col.search ) );
6429                                         }
6430                                 }
6431                         }
6432         
6433                         _fnCallbackFire( settings, 'aoStateLoaded', 'stateLoaded', [settings, s] );
6434                         callback();
6435                 };
6436         
6437                 if ( ! settings.oFeatures.bStateSave ) {
6438                         callback();
6439                         return;
6440                 }
6441         
6442                 var state = settings.fnStateLoadCallback.call( settings.oInstance, settings, loaded );
6443         
6444                 if ( state !== undefined ) {
6445                         loaded( state );
6446                 }
6447                 // otherwise, wait for the loaded callback to be executed
6448         }
6449         
6450         
6451         /**
6452          * Return the settings object for a particular table
6453          *  @param {node} table table we are using as a dataTable
6454          *  @returns {object} Settings object - or null if not found
6455          *  @memberof DataTable#oApi
6456          */
6457         function _fnSettingsFromNode ( table )
6458         {
6459                 var settings = DataTable.settings;
6460                 var idx = $.inArray( table, _pluck( settings, 'nTable' ) );
6461         
6462                 return idx !== -1 ?
6463                         settings[ idx ] :
6464                         null;
6465         }
6466         
6467         
6468         /**
6469          * Log an error message
6470          *  @param {object} settings dataTables settings object
6471          *  @param {int} level log error messages, or display them to the user
6472          *  @param {string} msg error message
6473          *  @param {int} tn Technical note id to get more information about the error.
6474          *  @memberof DataTable#oApi
6475          */
6476         function _fnLog( settings, level, msg, tn )
6477         {
6478                 msg = 'DataTables warning: '+
6479                         (settings ? 'table id='+settings.sTableId+' - ' : '')+msg;
6480         
6481                 if ( tn ) {
6482                         msg += '. For more information about this error, please see '+
6483                         'http://datatables.net/tn/'+tn;
6484                 }
6485         
6486                 if ( ! level  ) {
6487                         // Backwards compatibility pre 1.10
6488                         var ext = DataTable.ext;
6489                         var type = ext.sErrMode || ext.errMode;
6490         
6491                         if ( settings ) {
6492                                 _fnCallbackFire( settings, null, 'error', [ settings, tn, msg ] );
6493                         }
6494         
6495                         if ( type == 'alert' ) {
6496                                 alert( msg );
6497                         }
6498                         else if ( type == 'throw' ) {
6499                                 throw new Error(msg);
6500                         }
6501                         else if ( typeof type == 'function' ) {
6502                                 type( settings, tn, msg );
6503                         }
6504                 }
6505                 else if ( window.console && console.log ) {
6506                         console.log( msg );
6507                 }
6508         }
6509         
6510         
6511         /**
6512          * See if a property is defined on one object, if so assign it to the other object
6513          *  @param {object} ret target object
6514          *  @param {object} src source object
6515          *  @param {string} name property
6516          *  @param {string} [mappedName] name to map too - optional, name used if not given
6517          *  @memberof DataTable#oApi
6518          */
6519         function _fnMap( ret, src, name, mappedName )
6520         {
6521                 if ( $.isArray( name ) ) {
6522                         $.each( name, function (i, val) {
6523                                 if ( $.isArray( val ) ) {
6524                                         _fnMap( ret, src, val[0], val[1] );
6525                                 }
6526                                 else {
6527                                         _fnMap( ret, src, val );
6528                                 }
6529                         } );
6530         
6531                         return;
6532                 }
6533         
6534                 if ( mappedName === undefined ) {
6535                         mappedName = name;
6536                 }
6537         
6538                 if ( src[name] !== undefined ) {
6539                         ret[mappedName] = src[name];
6540                 }
6541         }
6542         
6543         
6544         /**
6545          * Extend objects - very similar to jQuery.extend, but deep copy objects, and
6546          * shallow copy arrays. The reason we need to do this, is that we don't want to
6547          * deep copy array init values (such as aaSorting) since the dev wouldn't be
6548          * able to override them, but we do want to deep copy arrays.
6549          *  @param {object} out Object to extend
6550          *  @param {object} extender Object from which the properties will be applied to
6551          *      out
6552          *  @param {boolean} breakRefs If true, then arrays will be sliced to take an
6553          *      independent copy with the exception of the `data` or `aaData` parameters
6554          *      if they are present. This is so you can pass in a collection to
6555          *      DataTables and have that used as your data source without breaking the
6556          *      references
6557          *  @returns {object} out Reference, just for convenience - out === the return.
6558          *  @memberof DataTable#oApi
6559          *  @todo This doesn't take account of arrays inside the deep copied objects.
6560          */
6561         function _fnExtend( out, extender, breakRefs )
6562         {
6563                 var val;
6564         
6565                 for ( var prop in extender ) {
6566                         if ( extender.hasOwnProperty(prop) ) {
6567                                 val = extender[prop];
6568         
6569                                 if ( $.isPlainObject( val ) ) {
6570                                         if ( ! $.isPlainObject( out[prop] ) ) {
6571                                                 out[prop] = {};
6572                                         }
6573                                         $.extend( true, out[prop], val );
6574                                 }
6575                                 else if ( breakRefs && prop !== 'data' && prop !== 'aaData' && $.isArray(val) ) {
6576                                         out[prop] = val.slice();
6577                                 }
6578                                 else {
6579                                         out[prop] = val;
6580                                 }
6581                         }
6582                 }
6583         
6584                 return out;
6585         }
6586         
6587         
6588         /**
6589          * Bind an event handers to allow a click or return key to activate the callback.
6590          * This is good for accessibility since a return on the keyboard will have the
6591          * same effect as a click, if the element has focus.
6592          *  @param {element} n Element to bind the action to
6593          *  @param {object} oData Data object to pass to the triggered function
6594          *  @param {function} fn Callback function for when the event is triggered
6595          *  @memberof DataTable#oApi
6596          */
6597         function _fnBindAction( n, oData, fn )
6598         {
6599                 $(n)
6600                         .on( 'click.DT', oData, function (e) {
6601                                         $(n).trigger('blur'); // Remove focus outline for mouse users
6602                                         fn(e);
6603                                 } )
6604                         .on( 'keypress.DT', oData, function (e){
6605                                         if ( e.which === 13 ) {
6606                                                 e.preventDefault();
6607                                                 fn(e);
6608                                         }
6609                                 } )
6610                         .on( 'selectstart.DT', function () {
6611                                         /* Take the brutal approach to cancelling text selection */
6612                                         return false;
6613                                 } );
6614         }
6615         
6616         
6617         /**
6618          * Register a callback function. Easily allows a callback function to be added to
6619          * an array store of callback functions that can then all be called together.
6620          *  @param {object} oSettings dataTables settings object
6621          *  @param {string} sStore Name of the array storage for the callbacks in oSettings
6622          *  @param {function} fn Function to be called back
6623          *  @param {string} sName Identifying name for the callback (i.e. a label)
6624          *  @memberof DataTable#oApi
6625          */
6626         function _fnCallbackReg( oSettings, sStore, fn, sName )
6627         {
6628                 if ( fn )
6629                 {
6630                         oSettings[sStore].push( {
6631                                 "fn": fn,
6632                                 "sName": sName
6633                         } );
6634                 }
6635         }
6636         
6637         
6638         /**
6639          * Fire callback functions and trigger events. Note that the loop over the
6640          * callback array store is done backwards! Further note that you do not want to
6641          * fire off triggers in time sensitive applications (for example cell creation)
6642          * as its slow.
6643          *  @param {object} settings dataTables settings object
6644          *  @param {string} callbackArr Name of the array storage for the callbacks in
6645          *      oSettings
6646          *  @param {string} eventName Name of the jQuery custom event to trigger. If
6647          *      null no trigger is fired
6648          *  @param {array} args Array of arguments to pass to the callback function /
6649          *      trigger
6650          *  @memberof DataTable#oApi
6651          */
6652         function _fnCallbackFire( settings, callbackArr, eventName, args )
6653         {
6654                 var ret = [];
6655         
6656                 if ( callbackArr ) {
6657                         ret = $.map( settings[callbackArr].slice().reverse(), function (val, i) {
6658                                 return val.fn.apply( settings.oInstance, args );
6659                         } );
6660                 }
6661         
6662                 if ( eventName !== null ) {
6663                         var e = $.Event( eventName+'.dt' );
6664         
6665                         $(settings.nTable).trigger( e, args );
6666         
6667                         ret.push( e.result );
6668                 }
6669         
6670                 return ret;
6671         }
6672         
6673         
6674         function _fnLengthOverflow ( settings )
6675         {
6676                 var
6677                         start = settings._iDisplayStart,
6678                         end = settings.fnDisplayEnd(),
6679                         len = settings._iDisplayLength;
6680         
6681                 /* If we have space to show extra rows (backing up from the end point - then do so */
6682                 if ( start >= end )
6683                 {
6684                         start = end - len;
6685                 }
6686         
6687                 // Keep the start record on the current page
6688                 start -= (start % len);
6689         
6690                 if ( len === -1 || start < 0 )
6691                 {
6692                         start = 0;
6693                 }
6694         
6695                 settings._iDisplayStart = start;
6696         }
6697         
6698         
6699         function _fnRenderer( settings, type )
6700         {
6701                 var renderer = settings.renderer;
6702                 var host = DataTable.ext.renderer[type];
6703         
6704                 if ( $.isPlainObject( renderer ) && renderer[type] ) {
6705                         // Specific renderer for this type. If available use it, otherwise use
6706                         // the default.
6707                         return host[renderer[type]] || host._;
6708                 }
6709                 else if ( typeof renderer === 'string' ) {
6710                         // Common renderer - if there is one available for this type use it,
6711                         // otherwise use the default
6712                         return host[renderer] || host._;
6713                 }
6714         
6715                 // Use the default
6716                 return host._;
6717         }
6718         
6719         
6720         /**
6721          * Detect the data source being used for the table. Used to simplify the code
6722          * a little (ajax) and to make it compress a little smaller.
6723          *
6724          *  @param {object} settings dataTables settings object
6725          *  @returns {string} Data source
6726          *  @memberof DataTable#oApi
6727          */
6728         function _fnDataSource ( settings )
6729         {
6730                 if ( settings.oFeatures.bServerSide ) {
6731                         return 'ssp';
6732                 }
6733                 else if ( settings.ajax || settings.sAjaxSource ) {
6734                         return 'ajax';
6735                 }
6736                 return 'dom';
6737         }
6738         
6739
6740         
6741         
6742         /**
6743          * Computed structure of the DataTables API, defined by the options passed to
6744          * `DataTable.Api.register()` when building the API.
6745          *
6746          * The structure is built in order to speed creation and extension of the Api
6747          * objects since the extensions are effectively pre-parsed.
6748          *
6749          * The array is an array of objects with the following structure, where this
6750          * base array represents the Api prototype base:
6751          *
6752          *     [
6753          *       {
6754          *         name:      'data'                -- string   - Property name
6755          *         val:       function () {},       -- function - Api method (or undefined if just an object
6756          *         methodExt: [ ... ],              -- array    - Array of Api object definitions to extend the method result
6757          *         propExt:   [ ... ]               -- array    - Array of Api object definitions to extend the property
6758          *       },
6759          *       {
6760          *         name:     'row'
6761          *         val:       {},
6762          *         methodExt: [ ... ],
6763          *         propExt:   [
6764          *           {
6765          *             name:      'data'
6766          *             val:       function () {},
6767          *             methodExt: [ ... ],
6768          *             propExt:   [ ... ]
6769          *           },
6770          *           ...
6771          *         ]
6772          *       }
6773          *     ]
6774          *
6775          * @type {Array}
6776          * @ignore
6777          */
6778         var __apiStruct = [];
6779         
6780         
6781         /**
6782          * `Array.prototype` reference.
6783          *
6784          * @type object
6785          * @ignore
6786          */
6787         var __arrayProto = Array.prototype;
6788         
6789         
6790         /**
6791          * Abstraction for `context` parameter of the `Api` constructor to allow it to
6792          * take several different forms for ease of use.
6793          *
6794          * Each of the input parameter types will be converted to a DataTables settings
6795          * object where possible.
6796          *
6797          * @param  {string|node|jQuery|object} mixed DataTable identifier. Can be one
6798          *   of:
6799          *
6800          *   * `string` - jQuery selector. Any DataTables' matching the given selector
6801          *     with be found and used.
6802          *   * `node` - `TABLE` node which has already been formed into a DataTable.
6803          *   * `jQuery` - A jQuery object of `TABLE` nodes.
6804          *   * `object` - DataTables settings object
6805          *   * `DataTables.Api` - API instance
6806          * @return {array|null} Matching DataTables settings objects. `null` or
6807          *   `undefined` is returned if no matching DataTable is found.
6808          * @ignore
6809          */
6810         var _toSettings = function ( mixed )
6811         {
6812                 var idx, jq;
6813                 var settings = DataTable.settings;
6814                 var tables = $.map( settings, function (el, i) {
6815                         return el.nTable;
6816                 } );
6817         
6818                 if ( ! mixed ) {
6819                         return [];
6820                 }
6821                 else if ( mixed.nTable && mixed.oApi ) {
6822                         // DataTables settings object
6823                         return [ mixed ];
6824                 }
6825                 else if ( mixed.nodeName && mixed.nodeName.toLowerCase() === 'table' ) {
6826                         // Table node
6827                         idx = $.inArray( mixed, tables );
6828                         return idx !== -1 ? [ settings[idx] ] : null;
6829                 }
6830                 else if ( mixed && typeof mixed.settings === 'function' ) {
6831                         return mixed.settings().toArray();
6832                 }
6833                 else if ( typeof mixed === 'string' ) {
6834                         // jQuery selector
6835                         jq = $(mixed);
6836                 }
6837                 else if ( mixed instanceof $ ) {
6838                         // jQuery object (also DataTables instance)
6839                         jq = mixed;
6840                 }
6841         
6842                 if ( jq ) {
6843                         return jq.map( function(i) {
6844                                 idx = $.inArray( this, tables );
6845                                 return idx !== -1 ? settings[idx] : null;
6846                         } ).toArray();
6847                 }
6848         };
6849         
6850         
6851         /**
6852          * DataTables API class - used to control and interface with  one or more
6853          * DataTables enhanced tables.
6854          *
6855          * The API class is heavily based on jQuery, presenting a chainable interface
6856          * that you can use to interact with tables. Each instance of the API class has
6857          * a "context" - i.e. the tables that it will operate on. This could be a single
6858          * table, all tables on a page or a sub-set thereof.
6859          *
6860          * Additionally the API is designed to allow you to easily work with the data in
6861          * the tables, retrieving and manipulating it as required. This is done by
6862          * presenting the API class as an array like interface. The contents of the
6863          * array depend upon the actions requested by each method (for example
6864          * `rows().nodes()` will return an array of nodes, while `rows().data()` will
6865          * return an array of objects or arrays depending upon your table's
6866          * configuration). The API object has a number of array like methods (`push`,
6867          * `pop`, `reverse` etc) as well as additional helper methods (`each`, `pluck`,
6868          * `unique` etc) to assist your working with the data held in a table.
6869          *
6870          * Most methods (those which return an Api instance) are chainable, which means
6871          * the return from a method call also has all of the methods available that the
6872          * top level object had. For example, these two calls are equivalent:
6873          *
6874          *     // Not chained
6875          *     api.row.add( {...} );
6876          *     api.draw();
6877          *
6878          *     // Chained
6879          *     api.row.add( {...} ).draw();
6880          *
6881          * @class DataTable.Api
6882          * @param {array|object|string|jQuery} context DataTable identifier. This is
6883          *   used to define which DataTables enhanced tables this API will operate on.
6884          *   Can be one of:
6885          *
6886          *   * `string` - jQuery selector. Any DataTables' matching the given selector
6887          *     with be found and used.
6888          *   * `node` - `TABLE` node which has already been formed into a DataTable.
6889          *   * `jQuery` - A jQuery object of `TABLE` nodes.
6890          *   * `object` - DataTables settings object
6891          * @param {array} [data] Data to initialise the Api instance with.
6892          *
6893          * @example
6894          *   // Direct initialisation during DataTables construction
6895          *   var api = $('#example').DataTable();
6896          *
6897          * @example
6898          *   // Initialisation using a DataTables jQuery object
6899          *   var api = $('#example').dataTable().api();
6900          *
6901          * @example
6902          *   // Initialisation as a constructor
6903          *   var api = new $.fn.DataTable.Api( 'table.dataTable' );
6904          */
6905         _Api = function ( context, data )
6906         {
6907                 if ( ! (this instanceof _Api) ) {
6908                         return new _Api( context, data );
6909                 }
6910         
6911                 var settings = [];
6912                 var ctxSettings = function ( o ) {
6913                         var a = _toSettings( o );
6914                         if ( a ) {
6915                                 settings.push.apply( settings, a );
6916                         }
6917                 };
6918         
6919                 if ( $.isArray( context ) ) {
6920                         for ( var i=0, ien=context.length ; i<ien ; i++ ) {
6921                                 ctxSettings( context[i] );
6922                         }
6923                 }
6924                 else {
6925                         ctxSettings( context );
6926                 }
6927         
6928                 // Remove duplicates
6929                 this.context = _unique( settings );
6930         
6931                 // Initial data
6932                 if ( data ) {
6933                         $.merge( this, data );
6934                 }
6935         
6936                 // selector
6937                 this.selector = {
6938                         rows: null,
6939                         cols: null,
6940                         opts: null
6941                 };
6942         
6943                 _Api.extend( this, this, __apiStruct );
6944         };
6945         
6946         DataTable.Api = _Api;
6947         
6948         // Don't destroy the existing prototype, just extend it. Required for jQuery 2's
6949         // isPlainObject.
6950         $.extend( _Api.prototype, {
6951                 any: function ()
6952                 {
6953                         return this.count() !== 0;
6954                 },
6955         
6956         
6957                 concat:  __arrayProto.concat,
6958         
6959         
6960                 context: [], // array of table settings objects
6961         
6962         
6963                 count: function ()
6964                 {
6965                         return this.flatten().length;
6966                 },
6967         
6968         
6969                 each: function ( fn )
6970                 {
6971                         for ( var i=0, ien=this.length ; i<ien; i++ ) {
6972                                 fn.call( this, this[i], i, this );
6973                         }
6974         
6975                         return this;
6976                 },
6977         
6978         
6979                 eq: function ( idx )
6980                 {
6981                         var ctx = this.context;
6982         
6983                         return ctx.length > idx ?
6984                                 new _Api( ctx[idx], this[idx] ) :
6985                                 null;
6986                 },
6987         
6988         
6989                 filter: function ( fn )
6990                 {
6991                         var a = [];
6992         
6993                         if ( __arrayProto.filter ) {
6994                                 a = __arrayProto.filter.call( this, fn, this );
6995                         }
6996                         else {
6997                                 // Compatibility for browsers without EMCA-252-5 (JS 1.6)
6998                                 for ( var i=0, ien=this.length ; i<ien ; i++ ) {
6999                                         if ( fn.call( this, this[i], i, this ) ) {
7000                                                 a.push( this[i] );
7001                                         }
7002                                 }
7003                         }
7004         
7005                         return new _Api( this.context, a );
7006                 },
7007         
7008         
7009                 flatten: function ()
7010                 {
7011                         var a = [];
7012                         return new _Api( this.context, a.concat.apply( a, this.toArray() ) );
7013                 },
7014         
7015         
7016                 join:    __arrayProto.join,
7017         
7018         
7019                 indexOf: __arrayProto.indexOf || function (obj, start)
7020                 {
7021                         for ( var i=(start || 0), ien=this.length ; i<ien ; i++ ) {
7022                                 if ( this[i] === obj ) {
7023                                         return i;
7024                                 }
7025                         }
7026                         return -1;
7027                 },
7028         
7029                 iterator: function ( flatten, type, fn, alwaysNew ) {
7030                         var
7031                                 a = [], ret,
7032                                 i, ien, j, jen,
7033                                 context = this.context,
7034                                 rows, items, item,
7035                                 selector = this.selector;
7036         
7037                         // Argument shifting
7038                         if ( typeof flatten === 'string' ) {
7039                                 alwaysNew = fn;
7040                                 fn = type;
7041                                 type = flatten;
7042                                 flatten = false;
7043                         }
7044         
7045                         for ( i=0, ien=context.length ; i<ien ; i++ ) {
7046                                 var apiInst = new _Api( context[i] );
7047         
7048                                 if ( type === 'table' ) {
7049                                         ret = fn.call( apiInst, context[i], i );
7050         
7051                                         if ( ret !== undefined ) {
7052                                                 a.push( ret );
7053                                         }
7054                                 }
7055                                 else if ( type === 'columns' || type === 'rows' ) {
7056                                         // this has same length as context - one entry for each table
7057                                         ret = fn.call( apiInst, context[i], this[i], i );
7058         
7059                                         if ( ret !== undefined ) {
7060                                                 a.push( ret );
7061                                         }
7062                                 }
7063                                 else if ( type === 'column' || type === 'column-rows' || type === 'row' || type === 'cell' ) {
7064                                         // columns and rows share the same structure.
7065                                         // 'this' is an array of column indexes for each context
7066                                         items = this[i];
7067         
7068                                         if ( type === 'column-rows' ) {
7069                                                 rows = _selector_row_indexes( context[i], selector.opts );
7070                                         }
7071         
7072                                         for ( j=0, jen=items.length ; j<jen ; j++ ) {
7073                                                 item = items[j];
7074         
7075                                                 if ( type === 'cell' ) {
7076                                                         ret = fn.call( apiInst, context[i], item.row, item.column, i, j );
7077                                                 }
7078                                                 else {
7079                                                         ret = fn.call( apiInst, context[i], item, i, j, rows );
7080                                                 }
7081         
7082                                                 if ( ret !== undefined ) {
7083                                                         a.push( ret );
7084                                                 }
7085                                         }
7086                                 }
7087                         }
7088         
7089                         if ( a.length || alwaysNew ) {
7090                                 var api = new _Api( context, flatten ? a.concat.apply( [], a ) : a );
7091                                 var apiSelector = api.selector;
7092                                 apiSelector.rows = selector.rows;
7093                                 apiSelector.cols = selector.cols;
7094                                 apiSelector.opts = selector.opts;
7095                                 return api;
7096                         }
7097                         return this;
7098                 },
7099         
7100         
7101                 lastIndexOf: __arrayProto.lastIndexOf || function (obj, start)
7102                 {
7103                         // Bit cheeky...
7104                         return this.indexOf.apply( this.toArray.reverse(), arguments );
7105                 },
7106         
7107         
7108                 length:  0,
7109         
7110         
7111                 map: function ( fn )
7112                 {
7113                         var a = [];
7114         
7115                         if ( __arrayProto.map ) {
7116                                 a = __arrayProto.map.call( this, fn, this );
7117                         }
7118                         else {
7119                                 // Compatibility for browsers without EMCA-252-5 (JS 1.6)
7120                                 for ( var i=0, ien=this.length ; i<ien ; i++ ) {
7121                                         a.push( fn.call( this, this[i], i ) );
7122                                 }
7123                         }
7124         
7125                         return new _Api( this.context, a );
7126                 },
7127         
7128         
7129                 pluck: function ( prop )
7130                 {
7131                         return this.map( function ( el ) {
7132                                 return el[ prop ];
7133                         } );
7134                 },
7135         
7136                 pop:     __arrayProto.pop,
7137         
7138         
7139                 push:    __arrayProto.push,
7140         
7141         
7142                 // Does not return an API instance
7143                 reduce: __arrayProto.reduce || function ( fn, init )
7144                 {
7145                         return _fnReduce( this, fn, init, 0, this.length, 1 );
7146                 },
7147         
7148         
7149                 reduceRight: __arrayProto.reduceRight || function ( fn, init )
7150                 {
7151                         return _fnReduce( this, fn, init, this.length-1, -1, -1 );
7152                 },
7153         
7154         
7155                 reverse: __arrayProto.reverse,
7156         
7157         
7158                 // Object with rows, columns and opts
7159                 selector: null,
7160         
7161         
7162                 shift:   __arrayProto.shift,
7163         
7164         
7165                 slice: function () {
7166                         return new _Api( this.context, this );
7167                 },
7168         
7169         
7170                 sort:    __arrayProto.sort, // ? name - order?
7171         
7172         
7173                 splice:  __arrayProto.splice,
7174         
7175         
7176                 toArray: function ()
7177                 {
7178                         return __arrayProto.slice.call( this );
7179                 },
7180         
7181         
7182                 to$: function ()
7183                 {
7184                         return $( this );
7185                 },
7186         
7187         
7188                 toJQuery: function ()
7189                 {
7190                         return $( this );
7191                 },
7192         
7193         
7194                 unique: function ()
7195                 {
7196                         return new _Api( this.context, _unique(this) );
7197                 },
7198         
7199         
7200                 unshift: __arrayProto.unshift
7201         } );
7202         
7203         
7204         _Api.extend = function ( scope, obj, ext )
7205         {
7206                 // Only extend API instances and static properties of the API
7207                 if ( ! ext.length || ! obj || ( ! (obj instanceof _Api) && ! obj.__dt_wrapper ) ) {
7208                         return;
7209                 }
7210         
7211                 var
7212                         i, ien,
7213                         struct,
7214                         methodScoping = function ( scope, fn, struc ) {
7215                                 return function () {
7216                                         var ret = fn.apply( scope, arguments );
7217         
7218                                         // Method extension
7219                                         _Api.extend( ret, ret, struc.methodExt );
7220                                         return ret;
7221                                 };
7222                         };
7223         
7224                 for ( i=0, ien=ext.length ; i<ien ; i++ ) {
7225                         struct = ext[i];
7226         
7227                         // Value
7228                         obj[ struct.name ] = struct.type === 'function' ?
7229                                 methodScoping( scope, struct.val, struct ) :
7230                                 struct.type === 'object' ?
7231                                         {} :
7232                                         struct.val;
7233         
7234                         obj[ struct.name ].__dt_wrapper = true;
7235         
7236                         // Property extension
7237                         _Api.extend( scope, obj[ struct.name ], struct.propExt );
7238                 }
7239         };
7240         
7241         
7242         // @todo - Is there need for an augment function?
7243         // _Api.augment = function ( inst, name )
7244         // {
7245         //      // Find src object in the structure from the name
7246         //      var parts = name.split('.');
7247         
7248         //      _Api.extend( inst, obj );
7249         // };
7250         
7251         
7252         //     [
7253         //       {
7254         //         name:      'data'                -- string   - Property name
7255         //         val:       function () {},       -- function - Api method (or undefined if just an object
7256         //         methodExt: [ ... ],              -- array    - Array of Api object definitions to extend the method result
7257         //         propExt:   [ ... ]               -- array    - Array of Api object definitions to extend the property
7258         //       },
7259         //       {
7260         //         name:     'row'
7261         //         val:       {},
7262         //         methodExt: [ ... ],
7263         //         propExt:   [
7264         //           {
7265         //             name:      'data'
7266         //             val:       function () {},
7267         //             methodExt: [ ... ],
7268         //             propExt:   [ ... ]
7269         //           },
7270         //           ...
7271         //         ]
7272         //       }
7273         //     ]
7274         
7275         _Api.register = _api_register = function ( name, val )
7276         {
7277                 if ( $.isArray( name ) ) {
7278                         for ( var j=0, jen=name.length ; j<jen ; j++ ) {
7279                                 _Api.register( name[j], val );
7280                         }
7281                         return;
7282                 }
7283         
7284                 var
7285                         i, ien,
7286                         heir = name.split('.'),
7287                         struct = __apiStruct,
7288                         key, method;
7289         
7290                 var find = function ( src, name ) {
7291                         for ( var i=0, ien=src.length ; i<ien ; i++ ) {
7292                                 if ( src[i].name === name ) {
7293                                         return src[i];
7294                                 }
7295                         }
7296                         return null;
7297                 };
7298         
7299                 for ( i=0, ien=heir.length ; i<ien ; i++ ) {
7300                         method = heir[i].indexOf('()') !== -1;
7301                         key = method ?
7302                                 heir[i].replace('()', '') :
7303                                 heir[i];
7304         
7305                         var src = find( struct, key );
7306                         if ( ! src ) {
7307                                 src = {
7308                                         name:      key,
7309                                         val:       {},
7310                                         methodExt: [],
7311                                         propExt:   [],
7312                                         type:      'object'
7313                                 };
7314                                 struct.push( src );
7315                         }
7316         
7317                         if ( i === ien-1 ) {
7318                                 src.val = val;
7319                                 src.type = typeof val === 'function' ?
7320                                         'function' :
7321                                         $.isPlainObject( val ) ?
7322                                                 'object' :
7323                                                 'other';
7324                         }
7325                         else {
7326                                 struct = method ?
7327                                         src.methodExt :
7328                                         src.propExt;
7329                         }
7330                 }
7331         };
7332         
7333         _Api.registerPlural = _api_registerPlural = function ( pluralName, singularName, val ) {
7334                 _Api.register( pluralName, val );
7335         
7336                 _Api.register( singularName, function () {
7337                         var ret = val.apply( this, arguments );
7338         
7339                         if ( ret === this ) {
7340                                 // Returned item is the API instance that was passed in, return it
7341                                 return this;
7342                         }
7343                         else if ( ret instanceof _Api ) {
7344                                 // New API instance returned, want the value from the first item
7345                                 // in the returned array for the singular result.
7346                                 return ret.length ?
7347                                         $.isArray( ret[0] ) ?
7348                                                 new _Api( ret.context, ret[0] ) : // Array results are 'enhanced'
7349                                                 ret[0] :
7350                                         undefined;
7351                         }
7352         
7353                         // Non-API return - just fire it back
7354                         return ret;
7355                 } );
7356         };
7357         
7358         
7359         /**
7360          * Selector for HTML tables. Apply the given selector to the give array of
7361          * DataTables settings objects.
7362          *
7363          * @param {string|integer} [selector] jQuery selector string or integer
7364          * @param  {array} Array of DataTables settings objects to be filtered
7365          * @return {array}
7366          * @ignore
7367          */
7368         var __table_selector = function ( selector, a )
7369         {
7370                 if ( $.isArray(selector) ) {
7371                         return $.map( selector, function (item) {
7372                                 return __table_selector(item, a);
7373                         } );
7374                 }
7375         
7376                 // Integer is used to pick out a table by index
7377                 if ( typeof selector === 'number' ) {
7378                         return [ a[ selector ] ];
7379                 }
7380         
7381                 // Perform a jQuery selector on the table nodes
7382                 var nodes = $.map( a, function (el, i) {
7383                         return el.nTable;
7384                 } );
7385         
7386                 return $(nodes)
7387                         .filter( selector )
7388                         .map( function (i) {
7389                                 // Need to translate back from the table node to the settings
7390                                 var idx = $.inArray( this, nodes );
7391                                 return a[ idx ];
7392                         } )
7393                         .toArray();
7394         };
7395         
7396         
7397         
7398         /**
7399          * Context selector for the API's context (i.e. the tables the API instance
7400          * refers to.
7401          *
7402          * @name    DataTable.Api#tables
7403          * @param {string|integer} [selector] Selector to pick which tables the iterator
7404          *   should operate on. If not given, all tables in the current context are
7405          *   used. This can be given as a jQuery selector (for example `':gt(0)'`) to
7406          *   select multiple tables or as an integer to select a single table.
7407          * @returns {DataTable.Api} Returns a new API instance if a selector is given.
7408          */
7409         _api_register( 'tables()', function ( selector ) {
7410                 // A new instance is created if there was a selector specified
7411                 return selector !== undefined && selector !== null ?
7412                         new _Api( __table_selector( selector, this.context ) ) :
7413                         this;
7414         } );
7415         
7416         
7417         _api_register( 'table()', function ( selector ) {
7418                 var tables = this.tables( selector );
7419                 var ctx = tables.context;
7420         
7421                 // Truncate to the first matched table
7422                 return ctx.length ?
7423                         new _Api( ctx[0] ) :
7424                         tables;
7425         } );
7426         
7427         
7428         _api_registerPlural( 'tables().nodes()', 'table().node()' , function () {
7429                 return this.iterator( 'table', function ( ctx ) {
7430                         return ctx.nTable;
7431                 }, 1 );
7432         } );
7433         
7434         
7435         _api_registerPlural( 'tables().body()', 'table().body()' , function () {
7436                 return this.iterator( 'table', function ( ctx ) {
7437                         return ctx.nTBody;
7438                 }, 1 );
7439         } );
7440         
7441         
7442         _api_registerPlural( 'tables().header()', 'table().header()' , function () {
7443                 return this.iterator( 'table', function ( ctx ) {
7444                         return ctx.nTHead;
7445                 }, 1 );
7446         } );
7447         
7448         
7449         _api_registerPlural( 'tables().footer()', 'table().footer()' , function () {
7450                 return this.iterator( 'table', function ( ctx ) {
7451                         return ctx.nTFoot;
7452                 }, 1 );
7453         } );
7454         
7455         
7456         _api_registerPlural( 'tables().containers()', 'table().container()' , function () {
7457                 return this.iterator( 'table', function ( ctx ) {
7458                         return ctx.nTableWrapper;
7459                 }, 1 );
7460         } );
7461         
7462         
7463         
7464         /**
7465          * Redraw the tables in the current context.
7466          */
7467         _api_register( 'draw()', function ( paging ) {
7468                 return this.iterator( 'table', function ( settings ) {
7469                         if ( paging === 'page' ) {
7470                                 _fnDraw( settings );
7471                         }
7472                         else {
7473                                 if ( typeof paging === 'string' ) {
7474                                         paging = paging === 'full-hold' ?
7475                                                 false :
7476                                                 true;
7477                                 }
7478         
7479                                 _fnReDraw( settings, paging===false );
7480                         }
7481                 } );
7482         } );
7483         
7484         
7485         
7486         /**
7487          * Get the current page index.
7488          *
7489          * @return {integer} Current page index (zero based)
7490          *//**
7491          * Set the current page.
7492          *
7493          * Note that if you attempt to show a page which does not exist, DataTables will
7494          * not throw an error, but rather reset the paging.
7495          *
7496          * @param {integer|string} action The paging action to take. This can be one of:
7497          *  * `integer` - The page index to jump to
7498          *  * `string` - An action to take:
7499          *    * `first` - Jump to first page.
7500          *    * `next` - Jump to the next page
7501          *    * `previous` - Jump to previous page
7502          *    * `last` - Jump to the last page.
7503          * @returns {DataTables.Api} this
7504          */
7505         _api_register( 'page()', function ( action ) {
7506                 if ( action === undefined ) {
7507                         return this.page.info().page; // not an expensive call
7508                 }
7509         
7510                 // else, have an action to take on all tables
7511                 return this.iterator( 'table', function ( settings ) {
7512                         _fnPageChange( settings, action );
7513                 } );
7514         } );
7515         
7516         
7517         /**
7518          * Paging information for the first table in the current context.
7519          *
7520          * If you require paging information for another table, use the `table()` method
7521          * with a suitable selector.
7522          *
7523          * @return {object} Object with the following properties set:
7524          *  * `page` - Current page index (zero based - i.e. the first page is `0`)
7525          *  * `pages` - Total number of pages
7526          *  * `start` - Display index for the first record shown on the current page
7527          *  * `end` - Display index for the last record shown on the current page
7528          *  * `length` - Display length (number of records). Note that generally `start
7529          *    + length = end`, but this is not always true, for example if there are
7530          *    only 2 records to show on the final page, with a length of 10.
7531          *  * `recordsTotal` - Full data set length
7532          *  * `recordsDisplay` - Data set length once the current filtering criterion
7533          *    are applied.
7534          */
7535         _api_register( 'page.info()', function ( action ) {
7536                 if ( this.context.length === 0 ) {
7537                         return undefined;
7538                 }
7539         
7540                 var
7541                         settings   = this.context[0],
7542                         start      = settings._iDisplayStart,
7543                         len        = settings.oFeatures.bPaginate ? settings._iDisplayLength : -1,
7544                         visRecords = settings.fnRecordsDisplay(),
7545                         all        = len === -1;
7546         
7547                 return {
7548                         "page":           all ? 0 : Math.floor( start / len ),
7549                         "pages":          all ? 1 : Math.ceil( visRecords / len ),
7550                         "start":          start,
7551                         "end":            settings.fnDisplayEnd(),
7552                         "length":         len,
7553                         "recordsTotal":   settings.fnRecordsTotal(),
7554                         "recordsDisplay": visRecords,
7555                         "serverSide":     _fnDataSource( settings ) === 'ssp'
7556                 };
7557         } );
7558         
7559         
7560         /**
7561          * Get the current page length.
7562          *
7563          * @return {integer} Current page length. Note `-1` indicates that all records
7564          *   are to be shown.
7565          *//**
7566          * Set the current page length.
7567          *
7568          * @param {integer} Page length to set. Use `-1` to show all records.
7569          * @returns {DataTables.Api} this
7570          */
7571         _api_register( 'page.len()', function ( len ) {
7572                 // Note that we can't call this function 'length()' because `length`
7573                 // is a Javascript property of functions which defines how many arguments
7574                 // the function expects.
7575                 if ( len === undefined ) {
7576                         return this.context.length !== 0 ?
7577                                 this.context[0]._iDisplayLength :
7578                                 undefined;
7579                 }
7580         
7581                 // else, set the page length
7582                 return this.iterator( 'table', function ( settings ) {
7583                         _fnLengthChange( settings, len );
7584                 } );
7585         } );
7586         
7587         
7588         
7589         var __reload = function ( settings, holdPosition, callback ) {
7590                 // Use the draw event to trigger a callback
7591                 if ( callback ) {
7592                         var api = new _Api( settings );
7593         
7594                         api.one( 'draw', function () {
7595                                 callback( api.ajax.json() );
7596                         } );
7597                 }
7598         
7599                 if ( _fnDataSource( settings ) == 'ssp' ) {
7600                         _fnReDraw( settings, holdPosition );
7601                 }
7602                 else {
7603                         _fnProcessingDisplay( settings, true );
7604         
7605                         // Cancel an existing request
7606                         var xhr = settings.jqXHR;
7607                         if ( xhr && xhr.readyState !== 4 ) {
7608                                 xhr.abort();
7609                         }
7610         
7611                         // Trigger xhr
7612                         _fnBuildAjax( settings, [], function( json ) {
7613                                 _fnClearTable( settings );
7614         
7615                                 var data = _fnAjaxDataSrc( settings, json );
7616                                 for ( var i=0, ien=data.length ; i<ien ; i++ ) {
7617                                         _fnAddData( settings, data[i] );
7618                                 }
7619         
7620                                 _fnReDraw( settings, holdPosition );
7621                                 _fnProcessingDisplay( settings, false );
7622                         } );
7623                 }
7624         };
7625         
7626         
7627         /**
7628          * Get the JSON response from the last Ajax request that DataTables made to the
7629          * server. Note that this returns the JSON from the first table in the current
7630          * context.
7631          *
7632          * @return {object} JSON received from the server.
7633          */
7634         _api_register( 'ajax.json()', function () {
7635                 var ctx = this.context;
7636         
7637                 if ( ctx.length > 0 ) {
7638                         return ctx[0].json;
7639                 }
7640         
7641                 // else return undefined;
7642         } );
7643         
7644         
7645         /**
7646          * Get the data submitted in the last Ajax request
7647          */
7648         _api_register( 'ajax.params()', function () {
7649                 var ctx = this.context;
7650         
7651                 if ( ctx.length > 0 ) {
7652                         return ctx[0].oAjaxData;
7653                 }
7654         
7655                 // else return undefined;
7656         } );
7657         
7658         
7659         /**
7660          * Reload tables from the Ajax data source. Note that this function will
7661          * automatically re-draw the table when the remote data has been loaded.
7662          *
7663          * @param {boolean} [reset=true] Reset (default) or hold the current paging
7664          *   position. A full re-sort and re-filter is performed when this method is
7665          *   called, which is why the pagination reset is the default action.
7666          * @returns {DataTables.Api} this
7667          */
7668         _api_register( 'ajax.reload()', function ( callback, resetPaging ) {
7669                 return this.iterator( 'table', function (settings) {
7670                         __reload( settings, resetPaging===false, callback );
7671                 } );
7672         } );
7673         
7674         
7675         /**
7676          * Get the current Ajax URL. Note that this returns the URL from the first
7677          * table in the current context.
7678          *
7679          * @return {string} Current Ajax source URL
7680          *//**
7681          * Set the Ajax URL. Note that this will set the URL for all tables in the
7682          * current context.
7683          *
7684          * @param {string} url URL to set.
7685          * @returns {DataTables.Api} this
7686          */
7687         _api_register( 'ajax.url()', function ( url ) {
7688                 var ctx = this.context;
7689         
7690                 if ( url === undefined ) {
7691                         // get
7692                         if ( ctx.length === 0 ) {
7693                                 return undefined;
7694                         }
7695                         ctx = ctx[0];
7696         
7697                         return ctx.ajax ?
7698                                 $.isPlainObject( ctx.ajax ) ?
7699                                         ctx.ajax.url :
7700                                         ctx.ajax :
7701                                 ctx.sAjaxSource;
7702                 }
7703         
7704                 // set
7705                 return this.iterator( 'table', function ( settings ) {
7706                         if ( $.isPlainObject( settings.ajax ) ) {
7707                                 settings.ajax.url = url;
7708                         }
7709                         else {
7710                                 settings.ajax = url;
7711                         }
7712                         // No need to consider sAjaxSource here since DataTables gives priority
7713                         // to `ajax` over `sAjaxSource`. So setting `ajax` here, renders any
7714                         // value of `sAjaxSource` redundant.
7715                 } );
7716         } );
7717         
7718         
7719         /**
7720          * Load data from the newly set Ajax URL. Note that this method is only
7721          * available when `ajax.url()` is used to set a URL. Additionally, this method
7722          * has the same effect as calling `ajax.reload()` but is provided for
7723          * convenience when setting a new URL. Like `ajax.reload()` it will
7724          * automatically redraw the table once the remote data has been loaded.
7725          *
7726          * @returns {DataTables.Api} this
7727          */
7728         _api_register( 'ajax.url().load()', function ( callback, resetPaging ) {
7729                 // Same as a reload, but makes sense to present it for easy access after a
7730                 // url change
7731                 return this.iterator( 'table', function ( ctx ) {
7732                         __reload( ctx, resetPaging===false, callback );
7733                 } );
7734         } );
7735         
7736         
7737         
7738         
7739         var _selector_run = function ( type, selector, selectFn, settings, opts )
7740         {
7741                 var
7742                         out = [], res,
7743                         a, i, ien, j, jen,
7744                         selectorType = typeof selector;
7745         
7746                 // Can't just check for isArray here, as an API or jQuery instance might be
7747                 // given with their array like look
7748                 if ( ! selector || selectorType === 'string' || selectorType === 'function' || selector.length === undefined ) {
7749                         selector = [ selector ];
7750                 }
7751         
7752                 for ( i=0, ien=selector.length ; i<ien ; i++ ) {
7753                         // Only split on simple strings - complex expressions will be jQuery selectors
7754                         a = selector[i] && selector[i].split && ! selector[i].match(/[\[\(:]/) ?
7755                                 selector[i].split(',') :
7756                                 [ selector[i] ];
7757         
7758                         for ( j=0, jen=a.length ; j<jen ; j++ ) {
7759                                 res = selectFn( typeof a[j] === 'string' ? $.trim(a[j]) : a[j] );
7760         
7761                                 if ( res && res.length ) {
7762                                         out = out.concat( res );
7763                                 }
7764                         }
7765                 }
7766         
7767                 // selector extensions
7768                 var ext = _ext.selector[ type ];
7769                 if ( ext.length ) {
7770                         for ( i=0, ien=ext.length ; i<ien ; i++ ) {
7771                                 out = ext[i]( settings, opts, out );
7772                         }
7773                 }
7774         
7775                 return _unique( out );
7776         };
7777         
7778         
7779         var _selector_opts = function ( opts )
7780         {
7781                 if ( ! opts ) {
7782                         opts = {};
7783                 }
7784         
7785                 // Backwards compatibility for 1.9- which used the terminology filter rather
7786                 // than search
7787                 if ( opts.filter && opts.search === undefined ) {
7788                         opts.search = opts.filter;
7789                 }
7790         
7791                 return $.extend( {
7792                         search: 'none',
7793                         order: 'current',
7794                         page: 'all'
7795                 }, opts );
7796         };
7797         
7798         
7799         var _selector_first = function ( inst )
7800         {
7801                 // Reduce the API instance to the first item found
7802                 for ( var i=0, ien=inst.length ; i<ien ; i++ ) {
7803                         if ( inst[i].length > 0 ) {
7804                                 // Assign the first element to the first item in the instance
7805                                 // and truncate the instance and context
7806                                 inst[0] = inst[i];
7807                                 inst[0].length = 1;
7808                                 inst.length = 1;
7809                                 inst.context = [ inst.context[i] ];
7810         
7811                                 return inst;
7812                         }
7813                 }
7814         
7815                 // Not found - return an empty instance
7816                 inst.length = 0;
7817                 return inst;
7818         };
7819         
7820         
7821         var _selector_row_indexes = function ( settings, opts )
7822         {
7823                 var
7824                         i, ien, tmp, a=[],
7825                         displayFiltered = settings.aiDisplay,
7826                         displayMaster = settings.aiDisplayMaster;
7827         
7828                 var
7829                         search = opts.search,  // none, applied, removed
7830                         order  = opts.order,   // applied, current, index (original - compatibility with 1.9)
7831                         page   = opts.page;    // all, current
7832         
7833                 if ( _fnDataSource( settings ) == 'ssp' ) {
7834                         // In server-side processing mode, most options are irrelevant since
7835                         // rows not shown don't exist and the index order is the applied order
7836                         // Removed is a special case - for consistency just return an empty
7837                         // array
7838                         return search === 'removed' ?
7839                                 [] :
7840                                 _range( 0, displayMaster.length );
7841                 }
7842                 else if ( page == 'current' ) {
7843                         // Current page implies that order=current and fitler=applied, since it is
7844                         // fairly senseless otherwise, regardless of what order and search actually
7845                         // are
7846                         for ( i=settings._iDisplayStart, ien=settings.fnDisplayEnd() ; i<ien ; i++ ) {
7847                                 a.push( displayFiltered[i] );
7848                         }
7849                 }
7850                 else if ( order == 'current' || order == 'applied' ) {
7851                         if ( search == 'none') {
7852                                 a = displayMaster.slice();
7853                         }
7854                         else if ( search == 'applied' ) {
7855                                 a = displayFiltered.slice();
7856                         }
7857                         else if ( search == 'removed' ) {
7858                                 // O(n+m) solution by creating a hash map
7859                                 var displayFilteredMap = {};
7860         
7861                                 for ( var i=0, ien=displayFiltered.length ; i<ien ; i++ ) {
7862                                         displayFilteredMap[displayFiltered[i]] = null;
7863                                 }
7864         
7865                                 a = $.map( displayMaster, function (el) {
7866                                         return ! displayFilteredMap.hasOwnProperty(el) ?
7867                                                 el :
7868                                                 null;
7869                                 } );
7870                         }
7871                 }
7872                 else if ( order == 'index' || order == 'original' ) {
7873                         for ( i=0, ien=settings.aoData.length ; i<ien ; i++ ) {
7874                                 if ( search == 'none' ) {
7875                                         a.push( i );
7876                                 }
7877                                 else { // applied | removed
7878                                         tmp = $.inArray( i, displayFiltered );
7879         
7880                                         if ((tmp === -1 && search == 'removed') ||
7881                                                 (tmp >= 0   && search == 'applied') )
7882                                         {
7883                                                 a.push( i );
7884                                         }
7885                                 }
7886                         }
7887                 }
7888         
7889                 return a;
7890         };
7891         
7892         
7893         /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
7894          * Rows
7895          *
7896          * {}          - no selector - use all available rows
7897          * {integer}   - row aoData index
7898          * {node}      - TR node
7899          * {string}    - jQuery selector to apply to the TR elements
7900          * {array}     - jQuery array of nodes, or simply an array of TR nodes
7901          *
7902          */
7903         var __row_selector = function ( settings, selector, opts )
7904         {
7905                 var rows;
7906                 var run = function ( sel ) {
7907                         var selInt = _intVal( sel );
7908                         var i, ien;
7909                         var aoData = settings.aoData;
7910         
7911                         // Short cut - selector is a number and no options provided (default is
7912                         // all records, so no need to check if the index is in there, since it
7913                         // must be - dev error if the index doesn't exist).
7914                         if ( selInt !== null && ! opts ) {
7915                                 return [ selInt ];
7916                         }
7917         
7918                         if ( ! rows ) {
7919                                 rows = _selector_row_indexes( settings, opts );
7920                         }
7921         
7922                         if ( selInt !== null && $.inArray( selInt, rows ) !== -1 ) {
7923                                 // Selector - integer
7924                                 return [ selInt ];
7925                         }
7926                         else if ( sel === null || sel === undefined || sel === '' ) {
7927                                 // Selector - none
7928                                 return rows;
7929                         }
7930         
7931                         // Selector - function
7932                         if ( typeof sel === 'function' ) {
7933                                 return $.map( rows, function (idx) {
7934                                         var row = aoData[ idx ];
7935                                         return sel( idx, row._aData, row.nTr ) ? idx : null;
7936                                 } );
7937                         }
7938         
7939                         // Selector - node
7940                         if ( sel.nodeName ) {
7941                                 var rowIdx = sel._DT_RowIndex;  // Property added by DT for fast lookup
7942                                 var cellIdx = sel._DT_CellIndex;
7943         
7944                                 if ( rowIdx !== undefined ) {
7945                                         // Make sure that the row is actually still present in the table
7946                                         return aoData[ rowIdx ] && aoData[ rowIdx ].nTr === sel ?
7947                                                 [ rowIdx ] :
7948                                                 [];
7949                                 }
7950                                 else if ( cellIdx ) {
7951                                         return aoData[ cellIdx.row ] && aoData[ cellIdx.row ].nTr === sel.parentNode ?
7952                                                 [ cellIdx.row ] :
7953                                                 [];
7954                                 }
7955                                 else {
7956                                         var host = $(sel).closest('*[data-dt-row]');
7957                                         return host.length ?
7958                                                 [ host.data('dt-row') ] :
7959                                                 [];
7960                                 }
7961                         }
7962         
7963                         // ID selector. Want to always be able to select rows by id, regardless
7964                         // of if the tr element has been created or not, so can't rely upon
7965                         // jQuery here - hence a custom implementation. This does not match
7966                         // Sizzle's fast selector or HTML4 - in HTML5 the ID can be anything,
7967                         // but to select it using a CSS selector engine (like Sizzle or
7968                         // querySelect) it would need to need to be escaped for some characters.
7969                         // DataTables simplifies this for row selectors since you can select
7970                         // only a row. A # indicates an id any anything that follows is the id -
7971                         // unescaped.
7972                         if ( typeof sel === 'string' && sel.charAt(0) === '#' ) {
7973                                 // get row index from id
7974                                 var rowObj = settings.aIds[ sel.replace( /^#/, '' ) ];
7975                                 if ( rowObj !== undefined ) {
7976                                         return [ rowObj.idx ];
7977                                 }
7978         
7979                                 // need to fall through to jQuery in case there is DOM id that
7980                                 // matches
7981                         }
7982                         
7983                         // Get nodes in the order from the `rows` array with null values removed
7984                         var nodes = _removeEmpty(
7985                                 _pluck_order( settings.aoData, rows, 'nTr' )
7986                         );
7987         
7988                         // Selector - jQuery selector string, array of nodes or jQuery object/
7989                         // As jQuery's .filter() allows jQuery objects to be passed in filter,
7990                         // it also allows arrays, so this will cope with all three options
7991                         return $(nodes)
7992                                 .filter( sel )
7993                                 .map( function () {
7994                                         return this._DT_RowIndex;
7995                                 } )
7996                                 .toArray();
7997                 };
7998         
7999                 return _selector_run( 'row', selector, run, settings, opts );
8000         };
8001         
8002         
8003         _api_register( 'rows()', function ( selector, opts ) {
8004                 // argument shifting
8005                 if ( selector === undefined ) {
8006                         selector = '';
8007                 }
8008                 else if ( $.isPlainObject( selector ) ) {
8009                         opts = selector;
8010                         selector = '';
8011                 }
8012         
8013                 opts = _selector_opts( opts );
8014         
8015                 var inst = this.iterator( 'table', function ( settings ) {
8016                         return __row_selector( settings, selector, opts );
8017                 }, 1 );
8018         
8019                 // Want argument shifting here and in __row_selector?
8020                 inst.selector.rows = selector;
8021                 inst.selector.opts = opts;
8022         
8023                 return inst;
8024         } );
8025         
8026         _api_register( 'rows().nodes()', function () {
8027                 return this.iterator( 'row', function ( settings, row ) {
8028                         return settings.aoData[ row ].nTr || undefined;
8029                 }, 1 );
8030         } );
8031         
8032         _api_register( 'rows().data()', function () {
8033                 return this.iterator( true, 'rows', function ( settings, rows ) {
8034                         return _pluck_order( settings.aoData, rows, '_aData' );
8035                 }, 1 );
8036         } );
8037         
8038         _api_registerPlural( 'rows().cache()', 'row().cache()', function ( type ) {
8039                 return this.iterator( 'row', function ( settings, row ) {
8040                         var r = settings.aoData[ row ];
8041                         return type === 'search' ? r._aFilterData : r._aSortData;
8042                 }, 1 );
8043         } );
8044         
8045         _api_registerPlural( 'rows().invalidate()', 'row().invalidate()', function ( src ) {
8046                 return this.iterator( 'row', function ( settings, row ) {
8047                         _fnInvalidate( settings, row, src );
8048                 } );
8049         } );
8050         
8051         _api_registerPlural( 'rows().indexes()', 'row().index()', function () {
8052                 return this.iterator( 'row', function ( settings, row ) {
8053                         return row;
8054                 }, 1 );
8055         } );
8056         
8057         _api_registerPlural( 'rows().ids()', 'row().id()', function ( hash ) {
8058                 var a = [];
8059                 var context = this.context;
8060         
8061                 // `iterator` will drop undefined values, but in this case we want them
8062                 for ( var i=0, ien=context.length ; i<ien ; i++ ) {
8063                         for ( var j=0, jen=this[i].length ; j<jen ; j++ ) {
8064                                 var id = context[i].rowIdFn( context[i].aoData[ this[i][j] ]._aData );
8065                                 a.push( (hash === true ? '#' : '' )+ id );
8066                         }
8067                 }
8068         
8069                 return new _Api( context, a );
8070         } );
8071         
8072         _api_registerPlural( 'rows().remove()', 'row().remove()', function () {
8073                 var that = this;
8074         
8075                 this.iterator( 'row', function ( settings, row, thatIdx ) {
8076                         var data = settings.aoData;
8077                         var rowData = data[ row ];
8078                         var i, ien, j, jen;
8079                         var loopRow, loopCells;
8080         
8081                         data.splice( row, 1 );
8082         
8083                         // Update the cached indexes
8084                         for ( i=0, ien=data.length ; i<ien ; i++ ) {
8085                                 loopRow = data[i];
8086                                 loopCells = loopRow.anCells;
8087         
8088                                 // Rows
8089                                 if ( loopRow.nTr !== null ) {
8090                                         loopRow.nTr._DT_RowIndex = i;
8091                                 }
8092         
8093                                 // Cells
8094                                 if ( loopCells !== null ) {
8095                                         for ( j=0, jen=loopCells.length ; j<jen ; j++ ) {
8096                                                 loopCells[j]._DT_CellIndex.row = i;
8097                                         }
8098                                 }
8099                         }
8100         
8101                         // Delete from the display arrays
8102                         _fnDeleteIndex( settings.aiDisplayMaster, row );
8103                         _fnDeleteIndex( settings.aiDisplay, row );
8104                         _fnDeleteIndex( that[ thatIdx ], row, false ); // maintain local indexes
8105         
8106                         // For server-side processing tables - subtract the deleted row from the count
8107                         if ( settings._iRecordsDisplay > 0 ) {
8108                                 settings._iRecordsDisplay--;
8109                         }
8110         
8111                         // Check for an 'overflow' they case for displaying the table
8112                         _fnLengthOverflow( settings );
8113         
8114                         // Remove the row's ID reference if there is one
8115                         var id = settings.rowIdFn( rowData._aData );
8116                         if ( id !== undefined ) {
8117                                 delete settings.aIds[ id ];
8118                         }
8119                 } );
8120         
8121                 this.iterator( 'table', function ( settings ) {
8122                         for ( var i=0, ien=settings.aoData.length ; i<ien ; i++ ) {
8123                                 settings.aoData[i].idx = i;
8124                         }
8125                 } );
8126         
8127                 return this;
8128         } );
8129         
8130         
8131         _api_register( 'rows.add()', function ( rows ) {
8132                 var newRows = this.iterator( 'table', function ( settings ) {
8133                                 var row, i, ien;
8134                                 var out = [];
8135         
8136                                 for ( i=0, ien=rows.length ; i<ien ; i++ ) {
8137                                         row = rows[i];
8138         
8139                                         if ( row.nodeName && row.nodeName.toUpperCase() === 'TR' ) {
8140                                                 out.push( _fnAddTr( settings, row )[0] );
8141                                         }
8142                                         else {
8143                                                 out.push( _fnAddData( settings, row ) );
8144                                         }
8145                                 }
8146         
8147                                 return out;
8148                         }, 1 );
8149         
8150                 // Return an Api.rows() extended instance, so rows().nodes() etc can be used
8151                 var modRows = this.rows( -1 );
8152                 modRows.pop();
8153                 $.merge( modRows, newRows );
8154         
8155                 return modRows;
8156         } );
8157         
8158         
8159         
8160         
8161         
8162         /**
8163          *
8164          */
8165         _api_register( 'row()', function ( selector, opts ) {
8166                 return _selector_first( this.rows( selector, opts ) );
8167         } );
8168         
8169         
8170         _api_register( 'row().data()', function ( data ) {
8171                 var ctx = this.context;
8172         
8173                 if ( data === undefined ) {
8174                         // Get
8175                         return ctx.length && this.length ?
8176                                 ctx[0].aoData[ this[0] ]._aData :
8177                                 undefined;
8178                 }
8179         
8180                 // Set
8181                 var row = ctx[0].aoData[ this[0] ];
8182                 row._aData = data;
8183         
8184                 // If the DOM has an id, and the data source is an array
8185                 if ( $.isArray( data ) && row.nTr && row.nTr.id ) {
8186                         _fnSetObjectDataFn( ctx[0].rowId )( data, row.nTr.id );
8187                 }
8188         
8189                 // Automatically invalidate
8190                 _fnInvalidate( ctx[0], this[0], 'data' );
8191         
8192                 return this;
8193         } );
8194         
8195         
8196         _api_register( 'row().node()', function () {
8197                 var ctx = this.context;
8198         
8199                 return ctx.length && this.length ?
8200                         ctx[0].aoData[ this[0] ].nTr || null :
8201                         null;
8202         } );
8203         
8204         
8205         _api_register( 'row.add()', function ( row ) {
8206                 // Allow a jQuery object to be passed in - only a single row is added from
8207                 // it though - the first element in the set
8208                 if ( row instanceof $ && row.length ) {
8209                         row = row[0];
8210                 }
8211         
8212                 var rows = this.iterator( 'table', function ( settings ) {
8213                         if ( row.nodeName && row.nodeName.toUpperCase() === 'TR' ) {
8214                                 return _fnAddTr( settings, row )[0];
8215                         }
8216                         return _fnAddData( settings, row );
8217                 } );
8218         
8219                 // Return an Api.rows() extended instance, with the newly added row selected
8220                 return this.row( rows[0] );
8221         } );
8222         
8223         
8224         
8225         var __details_add = function ( ctx, row, data, klass )
8226         {
8227                 // Convert to array of TR elements
8228                 var rows = [];
8229                 var addRow = function ( r, k ) {
8230                         // Recursion to allow for arrays of jQuery objects
8231                         if ( $.isArray( r ) || r instanceof $ ) {
8232                                 for ( var i=0, ien=r.length ; i<ien ; i++ ) {
8233                                         addRow( r[i], k );
8234                                 }
8235                                 return;
8236                         }
8237         
8238                         // If we get a TR element, then just add it directly - up to the dev
8239                         // to add the correct number of columns etc
8240                         if ( r.nodeName && r.nodeName.toLowerCase() === 'tr' ) {
8241                                 rows.push( r );
8242                         }
8243                         else {
8244                                 // Otherwise create a row with a wrapper
8245                                 var created = $('<tr><td/></tr>').addClass( k );
8246                                 $('td', created)
8247                                         .addClass( k )
8248                                         .html( r )
8249                                         [0].colSpan = _fnVisbleColumns( ctx );
8250         
8251                                 rows.push( created[0] );
8252                         }
8253                 };
8254         
8255                 addRow( data, klass );
8256         
8257                 if ( row._details ) {
8258                         row._details.detach();
8259                 }
8260         
8261                 row._details = $(rows);
8262         
8263                 // If the children were already shown, that state should be retained
8264                 if ( row._detailsShow ) {
8265                         row._details.insertAfter( row.nTr );
8266                 }
8267         };
8268         
8269         
8270         var __details_remove = function ( api, idx )
8271         {
8272                 var ctx = api.context;
8273         
8274                 if ( ctx.length ) {
8275                         var row = ctx[0].aoData[ idx !== undefined ? idx : api[0] ];
8276         
8277                         if ( row && row._details ) {
8278                                 row._details.remove();
8279         
8280                                 row._detailsShow = undefined;
8281                                 row._details = undefined;
8282                         }
8283                 }
8284         };
8285         
8286         
8287         var __details_display = function ( api, show ) {
8288                 var ctx = api.context;
8289         
8290                 if ( ctx.length && api.length ) {
8291                         var row = ctx[0].aoData[ api[0] ];
8292         
8293                         if ( row._details ) {
8294                                 row._detailsShow = show;
8295         
8296                                 if ( show ) {
8297                                         row._details.insertAfter( row.nTr );
8298                                 }
8299                                 else {
8300                                         row._details.detach();
8301                                 }
8302         
8303                                 __details_events( ctx[0] );
8304                         }
8305                 }
8306         };
8307         
8308         
8309         var __details_events = function ( settings )
8310         {
8311                 var api = new _Api( settings );
8312                 var namespace = '.dt.DT_details';
8313                 var drawEvent = 'draw'+namespace;
8314                 var colvisEvent = 'column-visibility'+namespace;
8315                 var destroyEvent = 'destroy'+namespace;
8316                 var data = settings.aoData;
8317         
8318                 api.off( drawEvent +' '+ colvisEvent +' '+ destroyEvent );
8319         
8320                 if ( _pluck( data, '_details' ).length > 0 ) {
8321                         // On each draw, insert the required elements into the document
8322                         api.on( drawEvent, function ( e, ctx ) {
8323                                 if ( settings !== ctx ) {
8324                                         return;
8325                                 }
8326         
8327                                 api.rows( {page:'current'} ).eq(0).each( function (idx) {
8328                                         // Internal data grab
8329                                         var row = data[ idx ];
8330         
8331                                         if ( row._detailsShow ) {
8332                                                 row._details.insertAfter( row.nTr );
8333                                         }
8334                                 } );
8335                         } );
8336         
8337                         // Column visibility change - update the colspan
8338                         api.on( colvisEvent, function ( e, ctx, idx, vis ) {
8339                                 if ( settings !== ctx ) {
8340                                         return;
8341                                 }
8342         
8343                                 // Update the colspan for the details rows (note, only if it already has
8344                                 // a colspan)
8345                                 var row, visible = _fnVisbleColumns( ctx );
8346         
8347                                 for ( var i=0, ien=data.length ; i<ien ; i++ ) {
8348                                         row = data[i];
8349         
8350                                         if ( row._details ) {
8351                                                 row._details.children('td[colspan]').attr('colspan', visible );
8352                                         }
8353                                 }
8354                         } );
8355         
8356                         // Table destroyed - nuke any child rows
8357                         api.on( destroyEvent, function ( e, ctx ) {
8358                                 if ( settings !== ctx ) {
8359                                         return;
8360                                 }
8361         
8362                                 for ( var i=0, ien=data.length ; i<ien ; i++ ) {
8363                                         if ( data[i]._details ) {
8364                                                 __details_remove( api, i );
8365                                         }
8366                                 }
8367                         } );
8368                 }
8369         };
8370         
8371         // Strings for the method names to help minification
8372         var _emp = '';
8373         var _child_obj = _emp+'row().child';
8374         var _child_mth = _child_obj+'()';
8375         
8376         // data can be:
8377         //  tr
8378         //  string
8379         //  jQuery or array of any of the above
8380         _api_register( _child_mth, function ( data, klass ) {
8381                 var ctx = this.context;
8382         
8383                 if ( data === undefined ) {
8384                         // get
8385                         return ctx.length && this.length ?
8386                                 ctx[0].aoData[ this[0] ]._details :
8387                                 undefined;
8388                 }
8389                 else if ( data === true ) {
8390                         // show
8391                         this.child.show();
8392                 }
8393                 else if ( data === false ) {
8394                         // remove
8395                         __details_remove( this );
8396                 }
8397                 else if ( ctx.length && this.length ) {
8398                         // set
8399                         __details_add( ctx[0], ctx[0].aoData[ this[0] ], data, klass );
8400                 }
8401         
8402                 return this;
8403         } );
8404         
8405         
8406         _api_register( [
8407                 _child_obj+'.show()',
8408                 _child_mth+'.show()' // only when `child()` was called with parameters (without
8409         ], function ( show ) {   // it returns an object and this method is not executed)
8410                 __details_display( this, true );
8411                 return this;
8412         } );
8413         
8414         
8415         _api_register( [
8416                 _child_obj+'.hide()',
8417                 _child_mth+'.hide()' // only when `child()` was called with parameters (without
8418         ], function () {         // it returns an object and this method is not executed)
8419                 __details_display( this, false );
8420                 return this;
8421         } );
8422         
8423         
8424         _api_register( [
8425                 _child_obj+'.remove()',
8426                 _child_mth+'.remove()' // only when `child()` was called with parameters (without
8427         ], function () {           // it returns an object and this method is not executed)
8428                 __details_remove( this );
8429                 return this;
8430         } );
8431         
8432         
8433         _api_register( _child_obj+'.isShown()', function () {
8434                 var ctx = this.context;
8435         
8436                 if ( ctx.length && this.length ) {
8437                         // _detailsShown as false or undefined will fall through to return false
8438                         return ctx[0].aoData[ this[0] ]._detailsShow || false;
8439                 }
8440                 return false;
8441         } );
8442         
8443         
8444         
8445         /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
8446          * Columns
8447          *
8448          * {integer}           - column index (>=0 count from left, <0 count from right)
8449          * "{integer}:visIdx"  - visible column index (i.e. translate to column index)  (>=0 count from left, <0 count from right)
8450          * "{integer}:visible" - alias for {integer}:visIdx  (>=0 count from left, <0 count from right)
8451          * "{string}:name"     - column name
8452          * "{string}"          - jQuery selector on column header nodes
8453          *
8454          */
8455         
8456         // can be an array of these items, comma separated list, or an array of comma
8457         // separated lists
8458         
8459         var __re_column_selector = /^([^:]+):(name|visIdx|visible)$/;
8460         
8461         
8462         // r1 and r2 are redundant - but it means that the parameters match for the
8463         // iterator callback in columns().data()
8464         var __columnData = function ( settings, column, r1, r2, rows ) {
8465                 var a = [];
8466                 for ( var row=0, ien=rows.length ; row<ien ; row++ ) {
8467                         a.push( _fnGetCellData( settings, rows[row], column ) );
8468                 }
8469                 return a;
8470         };
8471         
8472         
8473         var __column_selector = function ( settings, selector, opts )
8474         {
8475                 var
8476                         columns = settings.aoColumns,
8477                         names = _pluck( columns, 'sName' ),
8478                         nodes = _pluck( columns, 'nTh' );
8479         
8480                 var run = function ( s ) {
8481                         var selInt = _intVal( s );
8482         
8483                         // Selector - all
8484                         if ( s === '' ) {
8485                                 return _range( columns.length );
8486                         }
8487         
8488                         // Selector - index
8489                         if ( selInt !== null ) {
8490                                 return [ selInt >= 0 ?
8491                                         selInt : // Count from left
8492                                         columns.length + selInt // Count from right (+ because its a negative value)
8493                                 ];
8494                         }
8495         
8496                         // Selector = function
8497                         if ( typeof s === 'function' ) {
8498                                 var rows = _selector_row_indexes( settings, opts );
8499         
8500                                 return $.map( columns, function (col, idx) {
8501                                         return s(
8502                                                         idx,
8503                                                         __columnData( settings, idx, 0, 0, rows ),
8504                                                         nodes[ idx ]
8505                                                 ) ? idx : null;
8506                                 } );
8507                         }
8508         
8509                         // jQuery or string selector
8510                         var match = typeof s === 'string' ?
8511                                 s.match( __re_column_selector ) :
8512                                 '';
8513         
8514                         if ( match ) {
8515                                 switch( match[2] ) {
8516                                         case 'visIdx':
8517                                         case 'visible':
8518                                                 var idx = parseInt( match[1], 10 );
8519                                                 // Visible index given, convert to column index
8520                                                 if ( idx < 0 ) {
8521                                                         // Counting from the right
8522                                                         var visColumns = $.map( columns, function (col,i) {
8523                                                                 return col.bVisible ? i : null;
8524                                                         } );
8525                                                         return [ visColumns[ visColumns.length + idx ] ];
8526                                                 }
8527                                                 // Counting from the left
8528                                                 return [ _fnVisibleToColumnIndex( settings, idx ) ];
8529         
8530                                         case 'name':
8531                                                 // match by name. `names` is column index complete and in order
8532                                                 return $.map( names, function (name, i) {
8533                                                         return name === match[1] ? i : null;
8534                                                 } );
8535         
8536                                         default:
8537                                                 return [];
8538                                 }
8539                         }
8540         
8541                         // Cell in the table body
8542                         if ( s.nodeName && s._DT_CellIndex ) {
8543                                 return [ s._DT_CellIndex.column ];
8544                         }
8545         
8546                         // jQuery selector on the TH elements for the columns
8547                         var jqResult = $( nodes )
8548                                 .filter( s )
8549                                 .map( function () {
8550                                         return $.inArray( this, nodes ); // `nodes` is column index complete and in order
8551                                 } )
8552                                 .toArray();
8553         
8554                         if ( jqResult.length || ! s.nodeName ) {
8555                                 return jqResult;
8556                         }
8557         
8558                         // Otherwise a node which might have a `dt-column` data attribute, or be
8559                         // a child or such an element
8560                         var host = $(s).closest('*[data-dt-column]');
8561                         return host.length ?
8562                                 [ host.data('dt-column') ] :
8563                                 [];
8564                 };
8565         
8566                 return _selector_run( 'column', selector, run, settings, opts );
8567         };
8568         
8569         
8570         var __setColumnVis = function ( settings, column, vis ) {
8571                 var
8572                         cols = settings.aoColumns,
8573                         col  = cols[ column ],
8574                         data = settings.aoData,
8575                         row, cells, i, ien, tr;
8576         
8577                 // Get
8578                 if ( vis === undefined ) {
8579                         return col.bVisible;
8580                 }
8581         
8582                 // Set
8583                 // No change
8584                 if ( col.bVisible === vis ) {
8585                         return;
8586                 }
8587         
8588                 if ( vis ) {
8589                         // Insert column
8590                         // Need to decide if we should use appendChild or insertBefore
8591                         var insertBefore = $.inArray( true, _pluck(cols, 'bVisible'), column+1 );
8592         
8593                         for ( i=0, ien=data.length ; i<ien ; i++ ) {
8594                                 tr = data[i].nTr;
8595                                 cells = data[i].anCells;
8596         
8597                                 if ( tr ) {
8598                                         // insertBefore can act like appendChild if 2nd arg is null
8599                                         tr.insertBefore( cells[ column ], cells[ insertBefore ] || null );
8600                                 }
8601                         }
8602                 }
8603                 else {
8604                         // Remove column
8605                         $( _pluck( settings.aoData, 'anCells', column ) ).detach();
8606                 }
8607         
8608                 // Common actions
8609                 col.bVisible = vis;
8610         };
8611         
8612         
8613         _api_register( 'columns()', function ( selector, opts ) {
8614                 // argument shifting
8615                 if ( selector === undefined ) {
8616                         selector = '';
8617                 }
8618                 else if ( $.isPlainObject( selector ) ) {
8619                         opts = selector;
8620                         selector = '';
8621                 }
8622         
8623                 opts = _selector_opts( opts );
8624         
8625                 var inst = this.iterator( 'table', function ( settings ) {
8626                         return __column_selector( settings, selector, opts );
8627                 }, 1 );
8628         
8629                 // Want argument shifting here and in _row_selector?
8630                 inst.selector.cols = selector;
8631                 inst.selector.opts = opts;
8632         
8633                 return inst;
8634         } );
8635         
8636         _api_registerPlural( 'columns().header()', 'column().header()', function ( selector, opts ) {
8637                 return this.iterator( 'column', function ( settings, column ) {
8638                         return settings.aoColumns[column].nTh;
8639                 }, 1 );
8640         } );
8641         
8642         _api_registerPlural( 'columns().footer()', 'column().footer()', function ( selector, opts ) {
8643                 return this.iterator( 'column', function ( settings, column ) {
8644                         return settings.aoColumns[column].nTf;
8645                 }, 1 );
8646         } );
8647         
8648         _api_registerPlural( 'columns().data()', 'column().data()', function () {
8649                 return this.iterator( 'column-rows', __columnData, 1 );
8650         } );
8651         
8652         _api_registerPlural( 'columns().dataSrc()', 'column().dataSrc()', function () {
8653                 return this.iterator( 'column', function ( settings, column ) {
8654                         return settings.aoColumns[column].mData;
8655                 }, 1 );
8656         } );
8657         
8658         _api_registerPlural( 'columns().cache()', 'column().cache()', function ( type ) {
8659                 return this.iterator( 'column-rows', function ( settings, column, i, j, rows ) {
8660                         return _pluck_order( settings.aoData, rows,
8661                                 type === 'search' ? '_aFilterData' : '_aSortData', column
8662                         );
8663                 }, 1 );
8664         } );
8665         
8666         _api_registerPlural( 'columns().nodes()', 'column().nodes()', function () {
8667                 return this.iterator( 'column-rows', function ( settings, column, i, j, rows ) {
8668                         return _pluck_order( settings.aoData, rows, 'anCells', column ) ;
8669                 }, 1 );
8670         } );
8671         
8672         _api_registerPlural( 'columns().visible()', 'column().visible()', function ( vis, calc ) {
8673                 var that = this;
8674                 var ret = this.iterator( 'column', function ( settings, column ) {
8675                         if ( vis === undefined ) {
8676                                 return settings.aoColumns[ column ].bVisible;
8677                         } // else
8678                         __setColumnVis( settings, column, vis );
8679                 } );
8680         
8681                 // Group the column visibility changes
8682                 if ( vis !== undefined ) {
8683                         this.iterator( 'table', function ( settings ) {
8684                                 // Redraw the header after changes
8685                                 _fnDrawHead( settings, settings.aoHeader );
8686                                 _fnDrawHead( settings, settings.aoFooter );
8687                 
8688                                 // Update colspan for no records display. Child rows and extensions will use their own
8689                                 // listeners to do this - only need to update the empty table item here
8690                                 if ( ! settings.aiDisplay.length ) {
8691                                         $(settings.nTBody).find('td[colspan]').attr('colspan', _fnVisbleColumns(settings));
8692                                 }
8693                 
8694                                 _fnSaveState( settings );
8695         
8696                                 // Second loop once the first is done for events
8697                                 that.iterator( 'column', function ( settings, column ) {
8698                                         _fnCallbackFire( settings, null, 'column-visibility', [settings, column, vis, calc] );
8699                                 } );
8700         
8701                                 if ( calc === undefined || calc ) {
8702                                         that.columns.adjust();
8703                                 }
8704                         });
8705                 }
8706         
8707                 return ret;
8708         } );
8709         
8710         _api_registerPlural( 'columns().indexes()', 'column().index()', function ( type ) {
8711                 return this.iterator( 'column', function ( settings, column ) {
8712                         return type === 'visible' ?
8713                                 _fnColumnIndexToVisible( settings, column ) :
8714                                 column;
8715                 }, 1 );
8716         } );
8717         
8718         _api_register( 'columns.adjust()', function () {
8719                 return this.iterator( 'table', function ( settings ) {
8720                         _fnAdjustColumnSizing( settings );
8721                 }, 1 );
8722         } );
8723         
8724         _api_register( 'column.index()', function ( type, idx ) {
8725                 if ( this.context.length !== 0 ) {
8726                         var ctx = this.context[0];
8727         
8728                         if ( type === 'fromVisible' || type === 'toData' ) {
8729                                 return _fnVisibleToColumnIndex( ctx, idx );
8730                         }
8731                         else if ( type === 'fromData' || type === 'toVisible' ) {
8732                                 return _fnColumnIndexToVisible( ctx, idx );
8733                         }
8734                 }
8735         } );
8736         
8737         _api_register( 'column()', function ( selector, opts ) {
8738                 return _selector_first( this.columns( selector, opts ) );
8739         } );
8740         
8741         
8742         
8743         var __cell_selector = function ( settings, selector, opts )
8744         {
8745                 var data = settings.aoData;
8746                 var rows = _selector_row_indexes( settings, opts );
8747                 var cells = _removeEmpty( _pluck_order( data, rows, 'anCells' ) );
8748                 var allCells = $( [].concat.apply([], cells) );
8749                 var row;
8750                 var columns = settings.aoColumns.length;
8751                 var a, i, ien, j, o, host;
8752         
8753                 var run = function ( s ) {
8754                         var fnSelector = typeof s === 'function';
8755         
8756                         if ( s === null || s === undefined || fnSelector ) {
8757                                 // All cells and function selectors
8758                                 a = [];
8759         
8760                                 for ( i=0, ien=rows.length ; i<ien ; i++ ) {
8761                                         row = rows[i];
8762         
8763                                         for ( j=0 ; j<columns ; j++ ) {
8764                                                 o = {
8765                                                         row: row,
8766                                                         column: j
8767                                                 };
8768         
8769                                                 if ( fnSelector ) {
8770                                                         // Selector - function
8771                                                         host = data[ row ];
8772         
8773                                                         if ( s( o, _fnGetCellData(settings, row, j), host.anCells ? host.anCells[j] : null ) ) {
8774                                                                 a.push( o );
8775                                                         }
8776                                                 }
8777                                                 else {
8778                                                         // Selector - all
8779                                                         a.push( o );
8780                                                 }
8781                                         }
8782                                 }
8783         
8784                                 return a;
8785                         }
8786                         
8787                         // Selector - index
8788                         if ( $.isPlainObject( s ) ) {
8789                                 // Valid cell index and its in the array of selectable rows
8790                                 return s.column !== undefined && s.row !== undefined && $.inArray( s.row, rows ) !== -1 ?
8791                                         [s] :
8792                                         [];
8793                         }
8794         
8795                         // Selector - jQuery filtered cells
8796                         var jqResult = allCells
8797                                 .filter( s )
8798                                 .map( function (i, el) {
8799                                         return { // use a new object, in case someone changes the values
8800                                                 row:    el._DT_CellIndex.row,
8801                                                 column: el._DT_CellIndex.column
8802                                         };
8803                                 } )
8804                                 .toArray();
8805         
8806                         if ( jqResult.length || ! s.nodeName ) {
8807                                 return jqResult;
8808                         }
8809         
8810                         // Otherwise the selector is a node, and there is one last option - the
8811                         // element might be a child of an element which has dt-row and dt-column
8812                         // data attributes
8813                         host = $(s).closest('*[data-dt-row]');
8814                         return host.length ?
8815                                 [ {
8816                                         row: host.data('dt-row'),
8817                                         column: host.data('dt-column')
8818                                 } ] :
8819                                 [];
8820                 };
8821         
8822                 return _selector_run( 'cell', selector, run, settings, opts );
8823         };
8824         
8825         
8826         
8827         
8828         _api_register( 'cells()', function ( rowSelector, columnSelector, opts ) {
8829                 // Argument shifting
8830                 if ( $.isPlainObject( rowSelector ) ) {
8831                         // Indexes
8832                         if ( rowSelector.row === undefined ) {
8833                                 // Selector options in first parameter
8834                                 opts = rowSelector;
8835                                 rowSelector = null;
8836                         }
8837                         else {
8838                                 // Cell index objects in first parameter
8839                                 opts = columnSelector;
8840                                 columnSelector = null;
8841                         }
8842                 }
8843                 if ( $.isPlainObject( columnSelector ) ) {
8844                         opts = columnSelector;
8845                         columnSelector = null;
8846                 }
8847         
8848                 // Cell selector
8849                 if ( columnSelector === null || columnSelector === undefined ) {
8850                         return this.iterator( 'table', function ( settings ) {
8851                                 return __cell_selector( settings, rowSelector, _selector_opts( opts ) );
8852                         } );
8853                 }
8854         
8855                 // The default built in options need to apply to row and columns
8856                 var internalOpts = opts ? {
8857                         page: opts.page,
8858                         order: opts.order,
8859                         search: opts.search
8860                 } : {};
8861         
8862                 // Row + column selector
8863                 var columns = this.columns( columnSelector, internalOpts );
8864                 var rows = this.rows( rowSelector, internalOpts );
8865                 var i, ien, j, jen;
8866         
8867                 var cellsNoOpts = this.iterator( 'table', function ( settings, idx ) {
8868                         var a = [];
8869         
8870                         for ( i=0, ien=rows[idx].length ; i<ien ; i++ ) {
8871                                 for ( j=0, jen=columns[idx].length ; j<jen ; j++ ) {
8872                                         a.push( {
8873                                                 row:    rows[idx][i],
8874                                                 column: columns[idx][j]
8875                                         } );
8876                                 }
8877                         }
8878         
8879                         return a;
8880                 }, 1 );
8881         
8882                 // There is currently only one extension which uses a cell selector extension
8883                 // It is a _major_ performance drag to run this if it isn't needed, so this is
8884                 // an extension specific check at the moment
8885                 var cells = opts && opts.selected ?
8886                         this.cells( cellsNoOpts, opts ) :
8887                         cellsNoOpts;
8888         
8889                 $.extend( cells.selector, {
8890                         cols: columnSelector,
8891                         rows: rowSelector,
8892                         opts: opts
8893                 } );
8894         
8895                 return cells;
8896         } );
8897         
8898         
8899         _api_registerPlural( 'cells().nodes()', 'cell().node()', function () {
8900                 return this.iterator( 'cell', function ( settings, row, column ) {
8901                         var data = settings.aoData[ row ];
8902         
8903                         return data && data.anCells ?
8904                                 data.anCells[ column ] :
8905                                 undefined;
8906                 }, 1 );
8907         } );
8908         
8909         
8910         _api_register( 'cells().data()', function () {
8911                 return this.iterator( 'cell', function ( settings, row, column ) {
8912                         return _fnGetCellData( settings, row, column );
8913                 }, 1 );
8914         } );
8915         
8916         
8917         _api_registerPlural( 'cells().cache()', 'cell().cache()', function ( type ) {
8918                 type = type === 'search' ? '_aFilterData' : '_aSortData';
8919         
8920                 return this.iterator( 'cell', function ( settings, row, column ) {
8921                         return settings.aoData[ row ][ type ][ column ];
8922                 }, 1 );
8923         } );
8924         
8925         
8926         _api_registerPlural( 'cells().render()', 'cell().render()', function ( type ) {
8927                 return this.iterator( 'cell', function ( settings, row, column ) {
8928                         return _fnGetCellData( settings, row, column, type );
8929                 }, 1 );
8930         } );
8931         
8932         
8933         _api_registerPlural( 'cells().indexes()', 'cell().index()', function () {
8934                 return this.iterator( 'cell', function ( settings, row, column ) {
8935                         return {
8936                                 row: row,
8937                                 column: column,
8938                                 columnVisible: _fnColumnIndexToVisible( settings, column )
8939                         };
8940                 }, 1 );
8941         } );
8942         
8943         
8944         _api_registerPlural( 'cells().invalidate()', 'cell().invalidate()', function ( src ) {
8945                 return this.iterator( 'cell', function ( settings, row, column ) {
8946                         _fnInvalidate( settings, row, src, column );
8947                 } );
8948         } );
8949         
8950         
8951         
8952         _api_register( 'cell()', function ( rowSelector, columnSelector, opts ) {
8953                 return _selector_first( this.cells( rowSelector, columnSelector, opts ) );
8954         } );
8955         
8956         
8957         _api_register( 'cell().data()', function ( data ) {
8958                 var ctx = this.context;
8959                 var cell = this[0];
8960         
8961                 if ( data === undefined ) {
8962                         // Get
8963                         return ctx.length && cell.length ?
8964                                 _fnGetCellData( ctx[0], cell[0].row, cell[0].column ) :
8965                                 undefined;
8966                 }
8967         
8968                 // Set
8969                 _fnSetCellData( ctx[0], cell[0].row, cell[0].column, data );
8970                 _fnInvalidate( ctx[0], cell[0].row, 'data', cell[0].column );
8971         
8972                 return this;
8973         } );
8974         
8975         
8976         
8977         /**
8978          * Get current ordering (sorting) that has been applied to the table.
8979          *
8980          * @returns {array} 2D array containing the sorting information for the first
8981          *   table in the current context. Each element in the parent array represents
8982          *   a column being sorted upon (i.e. multi-sorting with two columns would have
8983          *   2 inner arrays). The inner arrays may have 2 or 3 elements. The first is
8984          *   the column index that the sorting condition applies to, the second is the
8985          *   direction of the sort (`desc` or `asc`) and, optionally, the third is the
8986          *   index of the sorting order from the `column.sorting` initialisation array.
8987          *//**
8988          * Set the ordering for the table.
8989          *
8990          * @param {integer} order Column index to sort upon.
8991          * @param {string} direction Direction of the sort to be applied (`asc` or `desc`)
8992          * @returns {DataTables.Api} this
8993          *//**
8994          * Set the ordering for the table.
8995          *
8996          * @param {array} order 1D array of sorting information to be applied.
8997          * @param {array} [...] Optional additional sorting conditions
8998          * @returns {DataTables.Api} this
8999          *//**
9000          * Set the ordering for the table.
9001          *
9002          * @param {array} order 2D array of sorting information to be applied.
9003          * @returns {DataTables.Api} this
9004          */
9005         _api_register( 'order()', function ( order, dir ) {
9006                 var ctx = this.context;
9007         
9008                 if ( order === undefined ) {
9009                         // get
9010                         return ctx.length !== 0 ?
9011                                 ctx[0].aaSorting :
9012                                 undefined;
9013                 }
9014         
9015                 // set
9016                 if ( typeof order === 'number' ) {
9017                         // Simple column / direction passed in
9018                         order = [ [ order, dir ] ];
9019                 }
9020                 else if ( order.length && ! $.isArray( order[0] ) ) {
9021                         // Arguments passed in (list of 1D arrays)
9022                         order = Array.prototype.slice.call( arguments );
9023                 }
9024                 // otherwise a 2D array was passed in
9025         
9026                 return this.iterator( 'table', function ( settings ) {
9027                         settings.aaSorting = order.slice();
9028                 } );
9029         } );
9030         
9031         
9032         /**
9033          * Attach a sort listener to an element for a given column
9034          *
9035          * @param {node|jQuery|string} node Identifier for the element(s) to attach the
9036          *   listener to. This can take the form of a single DOM node, a jQuery
9037          *   collection of nodes or a jQuery selector which will identify the node(s).
9038          * @param {integer} column the column that a click on this node will sort on
9039          * @param {function} [callback] callback function when sort is run
9040          * @returns {DataTables.Api} this
9041          */
9042         _api_register( 'order.listener()', function ( node, column, callback ) {
9043                 return this.iterator( 'table', function ( settings ) {
9044                         _fnSortAttachListener( settings, node, column, callback );
9045                 } );
9046         } );
9047         
9048         
9049         _api_register( 'order.fixed()', function ( set ) {
9050                 if ( ! set ) {
9051                         var ctx = this.context;
9052                         var fixed = ctx.length ?
9053                                 ctx[0].aaSortingFixed :
9054                                 undefined;
9055         
9056                         return $.isArray( fixed ) ?
9057                                 { pre: fixed } :
9058                                 fixed;
9059                 }
9060         
9061                 return this.iterator( 'table', function ( settings ) {
9062                         settings.aaSortingFixed = $.extend( true, {}, set );
9063                 } );
9064         } );
9065         
9066         
9067         // Order by the selected column(s)
9068         _api_register( [
9069                 'columns().order()',
9070                 'column().order()'
9071         ], function ( dir ) {
9072                 var that = this;
9073         
9074                 return this.iterator( 'table', function ( settings, i ) {
9075                         var sort = [];
9076         
9077                         $.each( that[i], function (j, col) {
9078                                 sort.push( [ col, dir ] );
9079                         } );
9080         
9081                         settings.aaSorting = sort;
9082                 } );
9083         } );
9084         
9085         
9086         
9087         _api_register( 'search()', function ( input, regex, smart, caseInsen ) {
9088                 var ctx = this.context;
9089         
9090                 if ( input === undefined ) {
9091                         // get
9092                         return ctx.length !== 0 ?
9093                                 ctx[0].oPreviousSearch.sSearch :
9094                                 undefined;
9095                 }
9096         
9097                 // set
9098                 return this.iterator( 'table', function ( settings ) {
9099                         if ( ! settings.oFeatures.bFilter ) {
9100                                 return;
9101                         }
9102         
9103                         _fnFilterComplete( settings, $.extend( {}, settings.oPreviousSearch, {
9104                                 "sSearch": input+"",
9105                                 "bRegex":  regex === null ? false : regex,
9106                                 "bSmart":  smart === null ? true  : smart,
9107                                 "bCaseInsensitive": caseInsen === null ? true : caseInsen
9108                         } ), 1 );
9109                 } );
9110         } );
9111         
9112         
9113         _api_registerPlural(
9114                 'columns().search()',
9115                 'column().search()',
9116                 function ( input, regex, smart, caseInsen ) {
9117                         return this.iterator( 'column', function ( settings, column ) {
9118                                 var preSearch = settings.aoPreSearchCols;
9119         
9120                                 if ( input === undefined ) {
9121                                         // get
9122                                         return preSearch[ column ].sSearch;
9123                                 }
9124         
9125                                 // set
9126                                 if ( ! settings.oFeatures.bFilter ) {
9127                                         return;
9128                                 }
9129         
9130                                 $.extend( preSearch[ column ], {
9131                                         "sSearch": input+"",
9132                                         "bRegex":  regex === null ? false : regex,
9133                                         "bSmart":  smart === null ? true  : smart,
9134                                         "bCaseInsensitive": caseInsen === null ? true : caseInsen
9135                                 } );
9136         
9137                                 _fnFilterComplete( settings, settings.oPreviousSearch, 1 );
9138                         } );
9139                 }
9140         );
9141         
9142         /*
9143          * State API methods
9144          */
9145         
9146         _api_register( 'state()', function () {
9147                 return this.context.length ?
9148                         this.context[0].oSavedState :
9149                         null;
9150         } );
9151         
9152         
9153         _api_register( 'state.clear()', function () {
9154                 return this.iterator( 'table', function ( settings ) {
9155                         // Save an empty object
9156                         settings.fnStateSaveCallback.call( settings.oInstance, settings, {} );
9157                 } );
9158         } );
9159         
9160         
9161         _api_register( 'state.loaded()', function () {
9162                 return this.context.length ?
9163                         this.context[0].oLoadedState :
9164                         null;
9165         } );
9166         
9167         
9168         _api_register( 'state.save()', function () {
9169                 return this.iterator( 'table', function ( settings ) {
9170                         _fnSaveState( settings );
9171                 } );
9172         } );
9173         
9174         
9175         
9176         /**
9177          * Provide a common method for plug-ins to check the version of DataTables being
9178          * used, in order to ensure compatibility.
9179          *
9180          *  @param {string} version Version string to check for, in the format "X.Y.Z".
9181          *    Note that the formats "X" and "X.Y" are also acceptable.
9182          *  @returns {boolean} true if this version of DataTables is greater or equal to
9183          *    the required version, or false if this version of DataTales is not
9184          *    suitable
9185          *  @static
9186          *  @dtopt API-Static
9187          *
9188          *  @example
9189          *    alert( $.fn.dataTable.versionCheck( '1.9.0' ) );
9190          */
9191         DataTable.versionCheck = DataTable.fnVersionCheck = function( version )
9192         {
9193                 var aThis = DataTable.version.split('.');
9194                 var aThat = version.split('.');
9195                 var iThis, iThat;
9196         
9197                 for ( var i=0, iLen=aThat.length ; i<iLen ; i++ ) {
9198                         iThis = parseInt( aThis[i], 10 ) || 0;
9199                         iThat = parseInt( aThat[i], 10 ) || 0;
9200         
9201                         // Parts are the same, keep comparing
9202                         if (iThis === iThat) {
9203                                 continue;
9204                         }
9205         
9206                         // Parts are different, return immediately
9207                         return iThis > iThat;
9208                 }
9209         
9210                 return true;
9211         };
9212         
9213         
9214         /**
9215          * Check if a `<table>` node is a DataTable table already or not.
9216          *
9217          *  @param {node|jquery|string} table Table node, jQuery object or jQuery
9218          *      selector for the table to test. Note that if more than more than one
9219          *      table is passed on, only the first will be checked
9220          *  @returns {boolean} true the table given is a DataTable, or false otherwise
9221          *  @static
9222          *  @dtopt API-Static
9223          *
9224          *  @example
9225          *    if ( ! $.fn.DataTable.isDataTable( '#example' ) ) {
9226          *      $('#example').dataTable();
9227          *    }
9228          */
9229         DataTable.isDataTable = DataTable.fnIsDataTable = function ( table )
9230         {
9231                 var t = $(table).get(0);
9232                 var is = false;
9233         
9234                 if ( table instanceof DataTable.Api ) {
9235                         return true;
9236                 }
9237         
9238                 $.each( DataTable.settings, function (i, o) {
9239                         var head = o.nScrollHead ? $('table', o.nScrollHead)[0] : null;
9240                         var foot = o.nScrollFoot ? $('table', o.nScrollFoot)[0] : null;
9241         
9242                         if ( o.nTable === t || head === t || foot === t ) {
9243                                 is = true;
9244                         }
9245                 } );
9246         
9247                 return is;
9248         };
9249         
9250         
9251         /**
9252          * Get all DataTable tables that have been initialised - optionally you can
9253          * select to get only currently visible tables.
9254          *
9255          *  @param {boolean} [visible=false] Flag to indicate if you want all (default)
9256          *    or visible tables only.
9257          *  @returns {array} Array of `table` nodes (not DataTable instances) which are
9258          *    DataTables
9259          *  @static
9260          *  @dtopt API-Static
9261          *
9262          *  @example
9263          *    $.each( $.fn.dataTable.tables(true), function () {
9264          *      $(table).DataTable().columns.adjust();
9265          *    } );
9266          */
9267         DataTable.tables = DataTable.fnTables = function ( visible )
9268         {
9269                 var api = false;
9270         
9271                 if ( $.isPlainObject( visible ) ) {
9272                         api = visible.api;
9273                         visible = visible.visible;
9274                 }
9275         
9276                 var a = $.map( DataTable.settings, function (o) {
9277                         if ( !visible || (visible && $(o.nTable).is(':visible')) ) {
9278                                 return o.nTable;
9279                         }
9280                 } );
9281         
9282                 return api ?
9283                         new _Api( a ) :
9284                         a;
9285         };
9286         
9287         
9288         /**
9289          * Convert from camel case parameters to Hungarian notation. This is made public
9290          * for the extensions to provide the same ability as DataTables core to accept
9291          * either the 1.9 style Hungarian notation, or the 1.10+ style camelCase
9292          * parameters.
9293          *
9294          *  @param {object} src The model object which holds all parameters that can be
9295          *    mapped.
9296          *  @param {object} user The object to convert from camel case to Hungarian.
9297          *  @param {boolean} force When set to `true`, properties which already have a
9298          *    Hungarian value in the `user` object will be overwritten. Otherwise they
9299          *    won't be.
9300          */
9301         DataTable.camelToHungarian = _fnCamelToHungarian;
9302         
9303         
9304         
9305         /**
9306          *
9307          */
9308         _api_register( '$()', function ( selector, opts ) {
9309                 var
9310                         rows   = this.rows( opts ).nodes(), // Get all rows
9311                         jqRows = $(rows);
9312         
9313                 return $( [].concat(
9314                         jqRows.filter( selector ).toArray(),
9315                         jqRows.find( selector ).toArray()
9316                 ) );
9317         } );
9318         
9319         
9320         // jQuery functions to operate on the tables
9321         $.each( [ 'on', 'one', 'off' ], function (i, key) {
9322                 _api_register( key+'()', function ( /* event, handler */ ) {
9323                         var args = Array.prototype.slice.call(arguments);
9324         
9325                         // Add the `dt` namespace automatically if it isn't already present
9326                         args[0] = $.map( args[0].split( /\s/ ), function ( e ) {
9327                                 return ! e.match(/\.dt\b/) ?
9328                                         e+'.dt' :
9329                                         e;
9330                                 } ).join( ' ' );
9331         
9332                         var inst = $( this.tables().nodes() );
9333                         inst[key].apply( inst, args );
9334                         return this;
9335                 } );
9336         } );
9337         
9338         
9339         _api_register( 'clear()', function () {
9340                 return this.iterator( 'table', function ( settings ) {
9341                         _fnClearTable( settings );
9342                 } );
9343         } );
9344         
9345         
9346         _api_register( 'settings()', function () {
9347                 return new _Api( this.context, this.context );
9348         } );
9349         
9350         
9351         _api_register( 'init()', function () {
9352                 var ctx = this.context;
9353                 return ctx.length ? ctx[0].oInit : null;
9354         } );
9355         
9356         
9357         _api_register( 'data()', function () {
9358                 return this.iterator( 'table', function ( settings ) {
9359                         return _pluck( settings.aoData, '_aData' );
9360                 } ).flatten();
9361         } );
9362         
9363         
9364         _api_register( 'destroy()', function ( remove ) {
9365                 remove = remove || false;
9366         
9367                 return this.iterator( 'table', function ( settings ) {
9368                         var orig      = settings.nTableWrapper.parentNode;
9369                         var classes   = settings.oClasses;
9370                         var table     = settings.nTable;
9371                         var tbody     = settings.nTBody;
9372                         var thead     = settings.nTHead;
9373                         var tfoot     = settings.nTFoot;
9374                         var jqTable   = $(table);
9375                         var jqTbody   = $(tbody);
9376                         var jqWrapper = $(settings.nTableWrapper);
9377                         var rows      = $.map( settings.aoData, function (r) { return r.nTr; } );
9378                         var i, ien;
9379         
9380                         // Flag to note that the table is currently being destroyed - no action
9381                         // should be taken
9382                         settings.bDestroying = true;
9383         
9384                         // Fire off the destroy callbacks for plug-ins etc
9385                         _fnCallbackFire( settings, "aoDestroyCallback", "destroy", [settings] );
9386         
9387                         // If not being removed from the document, make all columns visible
9388                         if ( ! remove ) {
9389                                 new _Api( settings ).columns().visible( true );
9390                         }
9391         
9392                         // Blitz all `DT` namespaced events (these are internal events, the
9393                         // lowercase, `dt` events are user subscribed and they are responsible
9394                         // for removing them
9395                         jqWrapper.off('.DT').find(':not(tbody *)').off('.DT');
9396                         $(window).off('.DT-'+settings.sInstance);
9397         
9398                         // When scrolling we had to break the table up - restore it
9399                         if ( table != thead.parentNode ) {
9400                                 jqTable.children('thead').detach();
9401                                 jqTable.append( thead );
9402                         }
9403         
9404                         if ( tfoot && table != tfoot.parentNode ) {
9405                                 jqTable.children('tfoot').detach();
9406                                 jqTable.append( tfoot );
9407                         }
9408         
9409                         settings.aaSorting = [];
9410                         settings.aaSortingFixed = [];
9411                         _fnSortingClasses( settings );
9412         
9413                         $( rows ).removeClass( settings.asStripeClasses.join(' ') );
9414         
9415                         $('th, td', thead).removeClass( classes.sSortable+' '+
9416                                 classes.sSortableAsc+' '+classes.sSortableDesc+' '+classes.sSortableNone
9417                         );
9418         
9419                         // Add the TR elements back into the table in their original order
9420                         jqTbody.children().detach();
9421                         jqTbody.append( rows );
9422         
9423                         // Remove the DataTables generated nodes, events and classes
9424                         var removedMethod = remove ? 'remove' : 'detach';
9425                         jqTable[ removedMethod ]();
9426                         jqWrapper[ removedMethod ]();
9427         
9428                         // If we need to reattach the table to the document
9429                         if ( ! remove && orig ) {
9430                                 // insertBefore acts like appendChild if !arg[1]
9431                                 orig.insertBefore( table, settings.nTableReinsertBefore );
9432         
9433                                 // Restore the width of the original table - was read from the style property,
9434                                 // so we can restore directly to that
9435                                 jqTable
9436                                         .css( 'width', settings.sDestroyWidth )
9437                                         .removeClass( classes.sTable );
9438         
9439                                 // If the were originally stripe classes - then we add them back here.
9440                                 // Note this is not fool proof (for example if not all rows had stripe
9441                                 // classes - but it's a good effort without getting carried away
9442                                 ien = settings.asDestroyStripes.length;
9443         
9444                                 if ( ien ) {
9445                                         jqTbody.children().each( function (i) {
9446                                                 $(this).addClass( settings.asDestroyStripes[i % ien] );
9447                                         } );
9448                                 }
9449                         }
9450         
9451                         /* Remove the settings object from the settings array */
9452                         var idx = $.inArray( settings, DataTable.settings );
9453                         if ( idx !== -1 ) {
9454                                 DataTable.settings.splice( idx, 1 );
9455                         }
9456                 } );
9457         } );
9458         
9459         
9460         // Add the `every()` method for rows, columns and cells in a compact form
9461         $.each( [ 'column', 'row', 'cell' ], function ( i, type ) {
9462                 _api_register( type+'s().every()', function ( fn ) {
9463                         var opts = this.selector.opts;
9464                         var api = this;
9465         
9466                         return this.iterator( type, function ( settings, arg1, arg2, arg3, arg4 ) {
9467                                 // Rows and columns:
9468                                 //  arg1 - index
9469                                 //  arg2 - table counter
9470                                 //  arg3 - loop counter
9471                                 //  arg4 - undefined
9472                                 // Cells:
9473                                 //  arg1 - row index
9474                                 //  arg2 - column index
9475                                 //  arg3 - table counter
9476                                 //  arg4 - loop counter
9477                                 fn.call(
9478                                         api[ type ](
9479                                                 arg1,
9480                                                 type==='cell' ? arg2 : opts,
9481                                                 type==='cell' ? opts : undefined
9482                                         ),
9483                                         arg1, arg2, arg3, arg4
9484                                 );
9485                         } );
9486                 } );
9487         } );
9488         
9489         
9490         // i18n method for extensions to be able to use the language object from the
9491         // DataTable
9492         _api_register( 'i18n()', function ( token, def, plural ) {
9493                 var ctx = this.context[0];
9494                 var resolved = _fnGetObjectDataFn( token )( ctx.oLanguage );
9495         
9496                 if ( resolved === undefined ) {
9497                         resolved = def;
9498                 }
9499         
9500                 if ( plural !== undefined && $.isPlainObject( resolved ) ) {
9501                         resolved = resolved[ plural ] !== undefined ?
9502                                 resolved[ plural ] :
9503                                 resolved._;
9504                 }
9505         
9506                 return resolved.replace( '%d', plural ); // nb: plural might be undefined,
9507         } );
9508         /**
9509          * Version string for plug-ins to check compatibility. Allowed format is
9510          * `a.b.c-d` where: a:int, b:int, c:int, d:string(dev|beta|alpha). `d` is used
9511          * only for non-release builds. See http://semver.org/ for more information.
9512          *  @member
9513          *  @type string
9514          *  @default Version number
9515          */
9516         DataTable.version = "1.10.21";
9517
9518         /**
9519          * Private data store, containing all of the settings objects that are
9520          * created for the tables on a given page.
9521          *
9522          * Note that the `DataTable.settings` object is aliased to
9523          * `jQuery.fn.dataTableExt` through which it may be accessed and
9524          * manipulated, or `jQuery.fn.dataTable.settings`.
9525          *  @member
9526          *  @type array
9527          *  @default []
9528          *  @private
9529          */
9530         DataTable.settings = [];
9531
9532         /**
9533          * Object models container, for the various models that DataTables has
9534          * available to it. These models define the objects that are used to hold
9535          * the active state and configuration of the table.
9536          *  @namespace
9537          */
9538         DataTable.models = {};
9539         
9540         
9541         
9542         /**
9543          * Template object for the way in which DataTables holds information about
9544          * search information for the global filter and individual column filters.
9545          *  @namespace
9546          */
9547         DataTable.models.oSearch = {
9548                 /**
9549                  * Flag to indicate if the filtering should be case insensitive or not
9550                  *  @type boolean
9551                  *  @default true
9552                  */
9553                 "bCaseInsensitive": true,
9554         
9555                 /**
9556                  * Applied search term
9557                  *  @type string
9558                  *  @default <i>Empty string</i>
9559                  */
9560                 "sSearch": "",
9561         
9562                 /**
9563                  * Flag to indicate if the search term should be interpreted as a
9564                  * regular expression (true) or not (false) and therefore and special
9565                  * regex characters escaped.
9566                  *  @type boolean
9567                  *  @default false
9568                  */
9569                 "bRegex": false,
9570         
9571                 /**
9572                  * Flag to indicate if DataTables is to use its smart filtering or not.
9573                  *  @type boolean
9574                  *  @default true
9575                  */
9576                 "bSmart": true
9577         };
9578         
9579         
9580         
9581         
9582         /**
9583          * Template object for the way in which DataTables holds information about
9584          * each individual row. This is the object format used for the settings
9585          * aoData array.
9586          *  @namespace
9587          */
9588         DataTable.models.oRow = {
9589                 /**
9590                  * TR element for the row
9591                  *  @type node
9592                  *  @default null
9593                  */
9594                 "nTr": null,
9595         
9596                 /**
9597                  * Array of TD elements for each row. This is null until the row has been
9598                  * created.
9599                  *  @type array nodes
9600                  *  @default []
9601                  */
9602                 "anCells": null,
9603         
9604                 /**
9605                  * Data object from the original data source for the row. This is either
9606                  * an array if using the traditional form of DataTables, or an object if
9607                  * using mData options. The exact type will depend on the passed in
9608                  * data from the data source, or will be an array if using DOM a data
9609                  * source.
9610                  *  @type array|object
9611                  *  @default []
9612                  */
9613                 "_aData": [],
9614         
9615                 /**
9616                  * Sorting data cache - this array is ostensibly the same length as the
9617                  * number of columns (although each index is generated only as it is
9618                  * needed), and holds the data that is used for sorting each column in the
9619                  * row. We do this cache generation at the start of the sort in order that
9620                  * the formatting of the sort data need be done only once for each cell
9621                  * per sort. This array should not be read from or written to by anything
9622                  * other than the master sorting methods.
9623                  *  @type array
9624                  *  @default null
9625                  *  @private
9626                  */
9627                 "_aSortData": null,
9628         
9629                 /**
9630                  * Per cell filtering data cache. As per the sort data cache, used to
9631                  * increase the performance of the filtering in DataTables
9632                  *  @type array
9633                  *  @default null
9634                  *  @private
9635                  */
9636                 "_aFilterData": null,
9637         
9638                 /**
9639                  * Filtering data cache. This is the same as the cell filtering cache, but
9640                  * in this case a string rather than an array. This is easily computed with
9641                  * a join on `_aFilterData`, but is provided as a cache so the join isn't
9642                  * needed on every search (memory traded for performance)
9643                  *  @type array
9644                  *  @default null
9645                  *  @private
9646                  */
9647                 "_sFilterRow": null,
9648         
9649                 /**
9650                  * Cache of the class name that DataTables has applied to the row, so we
9651                  * can quickly look at this variable rather than needing to do a DOM check
9652                  * on className for the nTr property.
9653                  *  @type string
9654                  *  @default <i>Empty string</i>
9655                  *  @private
9656                  */
9657                 "_sRowStripe": "",
9658         
9659                 /**
9660                  * Denote if the original data source was from the DOM, or the data source
9661                  * object. This is used for invalidating data, so DataTables can
9662                  * automatically read data from the original source, unless uninstructed
9663                  * otherwise.
9664                  *  @type string
9665                  *  @default null
9666                  *  @private
9667                  */
9668                 "src": null,
9669         
9670                 /**
9671                  * Index in the aoData array. This saves an indexOf lookup when we have the
9672                  * object, but want to know the index
9673                  *  @type integer
9674                  *  @default -1
9675                  *  @private
9676                  */
9677                 "idx": -1
9678         };
9679         
9680         
9681         /**
9682          * Template object for the column information object in DataTables. This object
9683          * is held in the settings aoColumns array and contains all the information that
9684          * DataTables needs about each individual column.
9685          *
9686          * Note that this object is related to {@link DataTable.defaults.column}
9687          * but this one is the internal data store for DataTables's cache of columns.
9688          * It should NOT be manipulated outside of DataTables. Any configuration should
9689          * be done through the initialisation options.
9690          *  @namespace
9691          */
9692         DataTable.models.oColumn = {
9693                 /**
9694                  * Column index. This could be worked out on-the-fly with $.inArray, but it
9695                  * is faster to just hold it as a variable
9696                  *  @type integer
9697                  *  @default null
9698                  */
9699                 "idx": null,
9700         
9701                 /**
9702                  * A list of the columns that sorting should occur on when this column
9703                  * is sorted. That this property is an array allows multi-column sorting
9704                  * to be defined for a column (for example first name / last name columns
9705                  * would benefit from this). The values are integers pointing to the
9706                  * columns to be sorted on (typically it will be a single integer pointing
9707                  * at itself, but that doesn't need to be the case).
9708                  *  @type array
9709                  */
9710                 "aDataSort": null,
9711         
9712                 /**
9713                  * Define the sorting directions that are applied to the column, in sequence
9714                  * as the column is repeatedly sorted upon - i.e. the first value is used
9715                  * as the sorting direction when the column if first sorted (clicked on).
9716                  * Sort it again (click again) and it will move on to the next index.
9717                  * Repeat until loop.
9718                  *  @type array
9719                  */
9720                 "asSorting": null,
9721         
9722                 /**
9723                  * Flag to indicate if the column is searchable, and thus should be included
9724                  * in the filtering or not.
9725                  *  @type boolean
9726                  */
9727                 "bSearchable": null,
9728         
9729                 /**
9730                  * Flag to indicate if the column is sortable or not.
9731                  *  @type boolean
9732                  */
9733                 "bSortable": null,
9734         
9735                 /**
9736                  * Flag to indicate if the column is currently visible in the table or not
9737                  *  @type boolean
9738                  */
9739                 "bVisible": null,
9740         
9741                 /**
9742                  * Store for manual type assignment using the `column.type` option. This
9743                  * is held in store so we can manipulate the column's `sType` property.
9744                  *  @type string
9745                  *  @default null
9746                  *  @private
9747                  */
9748                 "_sManualType": null,
9749         
9750                 /**
9751                  * Flag to indicate if HTML5 data attributes should be used as the data
9752                  * source for filtering or sorting. True is either are.
9753                  *  @type boolean
9754                  *  @default false
9755                  *  @private
9756                  */
9757                 "_bAttrSrc": false,
9758         
9759                 /**
9760                  * Developer definable function that is called whenever a cell is created (Ajax source,
9761                  * etc) or processed for input (DOM source). This can be used as a compliment to mRender
9762                  * allowing you to modify the DOM element (add background colour for example) when the
9763                  * element is available.
9764                  *  @type function
9765                  *  @param {element} nTd The TD node that has been created
9766                  *  @param {*} sData The Data for the cell
9767                  *  @param {array|object} oData The data for the whole row
9768                  *  @param {int} iRow The row index for the aoData data store
9769                  *  @default null
9770                  */
9771                 "fnCreatedCell": null,
9772         
9773                 /**
9774                  * Function to get data from a cell in a column. You should <b>never</b>
9775                  * access data directly through _aData internally in DataTables - always use
9776                  * the method attached to this property. It allows mData to function as
9777                  * required. This function is automatically assigned by the column
9778                  * initialisation method
9779                  *  @type function
9780                  *  @param {array|object} oData The data array/object for the array
9781                  *    (i.e. aoData[]._aData)
9782                  *  @param {string} sSpecific The specific data type you want to get -
9783                  *    'display', 'type' 'filter' 'sort'
9784                  *  @returns {*} The data for the cell from the given row's data
9785                  *  @default null
9786                  */
9787                 "fnGetData": null,
9788         
9789                 /**
9790                  * Function to set data for a cell in the column. You should <b>never</b>
9791                  * set the data directly to _aData internally in DataTables - always use
9792                  * this method. It allows mData to function as required. This function
9793                  * is automatically assigned by the column initialisation method
9794                  *  @type function
9795                  *  @param {array|object} oData The data array/object for the array
9796                  *    (i.e. aoData[]._aData)
9797                  *  @param {*} sValue Value to set
9798                  *  @default null
9799                  */
9800                 "fnSetData": null,
9801         
9802                 /**
9803                  * Property to read the value for the cells in the column from the data
9804                  * source array / object. If null, then the default content is used, if a
9805                  * function is given then the return from the function is used.
9806                  *  @type function|int|string|null
9807                  *  @default null
9808                  */
9809                 "mData": null,
9810         
9811                 /**
9812                  * Partner property to mData which is used (only when defined) to get
9813                  * the data - i.e. it is basically the same as mData, but without the
9814                  * 'set' option, and also the data fed to it is the result from mData.
9815                  * This is the rendering method to match the data method of mData.
9816                  *  @type function|int|string|null
9817                  *  @default null
9818                  */
9819                 "mRender": null,
9820         
9821                 /**
9822                  * Unique header TH/TD element for this column - this is what the sorting
9823                  * listener is attached to (if sorting is enabled.)
9824                  *  @type node
9825                  *  @default null
9826                  */
9827                 "nTh": null,
9828         
9829                 /**
9830                  * Unique footer TH/TD element for this column (if there is one). Not used
9831                  * in DataTables as such, but can be used for plug-ins to reference the
9832                  * footer for each column.
9833                  *  @type node
9834                  *  @default null
9835                  */
9836                 "nTf": null,
9837         
9838                 /**
9839                  * The class to apply to all TD elements in the table's TBODY for the column
9840                  *  @type string
9841                  *  @default null
9842                  */
9843                 "sClass": null,
9844         
9845                 /**
9846                  * When DataTables calculates the column widths to assign to each column,
9847                  * it finds the longest string in each column and then constructs a
9848                  * temporary table and reads the widths from that. The problem with this
9849                  * is that "mmm" is much wider then "iiii", but the latter is a longer
9850                  * string - thus the calculation can go wrong (doing it properly and putting
9851                  * it into an DOM object and measuring that is horribly(!) slow). Thus as
9852                  * a "work around" we provide this option. It will append its value to the
9853                  * text that is found to be the longest string for the column - i.e. padding.
9854                  *  @type string
9855                  */
9856                 "sContentPadding": null,
9857         
9858                 /**
9859                  * Allows a default value to be given for a column's data, and will be used
9860                  * whenever a null data source is encountered (this can be because mData
9861                  * is set to null, or because the data source itself is null).
9862                  *  @type string
9863                  *  @default null
9864                  */
9865                 "sDefaultContent": null,
9866         
9867                 /**
9868                  * Name for the column, allowing reference to the column by name as well as
9869                  * by index (needs a lookup to work by name).
9870                  *  @type string
9871                  */
9872                 "sName": null,
9873         
9874                 /**
9875                  * Custom sorting data type - defines which of the available plug-ins in
9876                  * afnSortData the custom sorting will use - if any is defined.
9877                  *  @type string
9878                  *  @default std
9879                  */
9880                 "sSortDataType": 'std',
9881         
9882                 /**
9883                  * Class to be applied to the header element when sorting on this column
9884                  *  @type string
9885                  *  @default null
9886                  */
9887                 "sSortingClass": null,
9888         
9889                 /**
9890                  * Class to be applied to the header element when sorting on this column -
9891                  * when jQuery UI theming is used.
9892                  *  @type string
9893                  *  @default null
9894                  */
9895                 "sSortingClassJUI": null,
9896         
9897                 /**
9898                  * Title of the column - what is seen in the TH element (nTh).
9899                  *  @type string
9900                  */
9901                 "sTitle": null,
9902         
9903                 /**
9904                  * Column sorting and filtering type
9905                  *  @type string
9906                  *  @default null
9907                  */
9908                 "sType": null,
9909         
9910                 /**
9911                  * Width of the column
9912                  *  @type string
9913                  *  @default null
9914                  */
9915                 "sWidth": null,
9916         
9917                 /**
9918                  * Width of the column when it was first "encountered"
9919                  *  @type string
9920                  *  @default null
9921                  */
9922                 "sWidthOrig": null
9923         };
9924         
9925         
9926         /*
9927          * Developer note: The properties of the object below are given in Hungarian
9928          * notation, that was used as the interface for DataTables prior to v1.10, however
9929          * from v1.10 onwards the primary interface is camel case. In order to avoid
9930          * breaking backwards compatibility utterly with this change, the Hungarian
9931          * version is still, internally the primary interface, but is is not documented
9932          * - hence the @name tags in each doc comment. This allows a Javascript function
9933          * to create a map from Hungarian notation to camel case (going the other direction
9934          * would require each property to be listed, which would at around 3K to the size
9935          * of DataTables, while this method is about a 0.5K hit.
9936          *
9937          * Ultimately this does pave the way for Hungarian notation to be dropped
9938          * completely, but that is a massive amount of work and will break current
9939          * installs (therefore is on-hold until v2).
9940          */
9941         
9942         /**
9943          * Initialisation options that can be given to DataTables at initialisation
9944          * time.
9945          *  @namespace
9946          */
9947         DataTable.defaults = {
9948                 /**
9949                  * An array of data to use for the table, passed in at initialisation which
9950                  * will be used in preference to any data which is already in the DOM. This is
9951                  * particularly useful for constructing tables purely in Javascript, for
9952                  * example with a custom Ajax call.
9953                  *  @type array
9954                  *  @default null
9955                  *
9956                  *  @dtopt Option
9957                  *  @name DataTable.defaults.data
9958                  *
9959                  *  @example
9960                  *    // Using a 2D array data source
9961                  *    $(document).ready( function () {
9962                  *      $('#example').dataTable( {
9963                  *        "data": [
9964                  *          ['Trident', 'Internet Explorer 4.0', 'Win 95+', 4, 'X'],
9965                  *          ['Trident', 'Internet Explorer 5.0', 'Win 95+', 5, 'C'],
9966                  *        ],
9967                  *        "columns": [
9968                  *          { "title": "Engine" },
9969                  *          { "title": "Browser" },
9970                  *          { "title": "Platform" },
9971                  *          { "title": "Version" },
9972                  *          { "title": "Grade" }
9973                  *        ]
9974                  *      } );
9975                  *    } );
9976                  *
9977                  *  @example
9978                  *    // Using an array of objects as a data source (`data`)
9979                  *    $(document).ready( function () {
9980                  *      $('#example').dataTable( {
9981                  *        "data": [
9982                  *          {
9983                  *            "engine":   "Trident",
9984                  *            "browser":  "Internet Explorer 4.0",
9985                  *            "platform": "Win 95+",
9986                  *            "version":  4,
9987                  *            "grade":    "X"
9988                  *          },
9989                  *          {
9990                  *            "engine":   "Trident",
9991                  *            "browser":  "Internet Explorer 5.0",
9992                  *            "platform": "Win 95+",
9993                  *            "version":  5,
9994                  *            "grade":    "C"
9995                  *          }
9996                  *        ],
9997                  *        "columns": [
9998                  *          { "title": "Engine",   "data": "engine" },
9999                  *          { "title": "Browser",  "data": "browser" },
10000                  *          { "title": "Platform", "data": "platform" },
10001                  *          { "title": "Version",  "data": "version" },
10002                  *          { "title": "Grade",    "data": "grade" }
10003                  *        ]
10004                  *      } );
10005                  *    } );
10006                  */
10007                 "aaData": null,
10008         
10009         
10010                 /**
10011                  * If ordering is enabled, then DataTables will perform a first pass sort on
10012                  * initialisation. You can define which column(s) the sort is performed
10013                  * upon, and the sorting direction, with this variable. The `sorting` array
10014                  * should contain an array for each column to be sorted initially containing
10015                  * the column's index and a direction string ('asc' or 'desc').
10016                  *  @type array
10017                  *  @default [[0,'asc']]
10018                  *
10019                  *  @dtopt Option
10020                  *  @name DataTable.defaults.order
10021                  *
10022                  *  @example
10023                  *    // Sort by 3rd column first, and then 4th column
10024                  *    $(document).ready( function() {
10025                  *      $('#example').dataTable( {
10026                  *        "order": [[2,'asc'], [3,'desc']]
10027                  *      } );
10028                  *    } );
10029                  *
10030                  *    // No initial sorting
10031                  *    $(document).ready( function() {
10032                  *      $('#example').dataTable( {
10033                  *        "order": []
10034                  *      } );
10035                  *    } );
10036                  */
10037                 "aaSorting": [[0,'asc']],
10038         
10039         
10040                 /**
10041                  * This parameter is basically identical to the `sorting` parameter, but
10042                  * cannot be overridden by user interaction with the table. What this means
10043                  * is that you could have a column (visible or hidden) which the sorting
10044                  * will always be forced on first - any sorting after that (from the user)
10045                  * will then be performed as required. This can be useful for grouping rows
10046                  * together.
10047                  *  @type array
10048                  *  @default null
10049                  *
10050                  *  @dtopt Option
10051                  *  @name DataTable.defaults.orderFixed
10052                  *
10053                  *  @example
10054                  *    $(document).ready( function() {
10055                  *      $('#example').dataTable( {
10056                  *        "orderFixed": [[0,'asc']]
10057                  *      } );
10058                  *    } )
10059                  */
10060                 "aaSortingFixed": [],
10061         
10062         
10063                 /**
10064                  * DataTables can be instructed to load data to display in the table from a
10065                  * Ajax source. This option defines how that Ajax call is made and where to.
10066                  *
10067                  * The `ajax` property has three different modes of operation, depending on
10068                  * how it is defined. These are:
10069                  *
10070                  * * `string` - Set the URL from where the data should be loaded from.
10071                  * * `object` - Define properties for `jQuery.ajax`.
10072                  * * `function` - Custom data get function
10073                  *
10074                  * `string`
10075                  * --------
10076                  *
10077                  * As a string, the `ajax` property simply defines the URL from which
10078                  * DataTables will load data.
10079                  *
10080                  * `object`
10081                  * --------
10082                  *
10083                  * As an object, the parameters in the object are passed to
10084                  * [jQuery.ajax](http://api.jquery.com/jQuery.ajax/) allowing fine control
10085                  * of the Ajax request. DataTables has a number of default parameters which
10086                  * you can override using this option. Please refer to the jQuery
10087                  * documentation for a full description of the options available, although
10088                  * the following parameters provide additional options in DataTables or
10089                  * require special consideration:
10090                  *
10091                  * * `data` - As with jQuery, `data` can be provided as an object, but it
10092                  *   can also be used as a function to manipulate the data DataTables sends
10093                  *   to the server. The function takes a single parameter, an object of
10094                  *   parameters with the values that DataTables has readied for sending. An
10095                  *   object may be returned which will be merged into the DataTables
10096                  *   defaults, or you can add the items to the object that was passed in and
10097                  *   not return anything from the function. This supersedes `fnServerParams`
10098                  *   from DataTables 1.9-.
10099                  *
10100                  * * `dataSrc` - By default DataTables will look for the property `data` (or
10101                  *   `aaData` for compatibility with DataTables 1.9-) when obtaining data
10102                  *   from an Ajax source or for server-side processing - this parameter
10103                  *   allows that property to be changed. You can use Javascript dotted
10104                  *   object notation to get a data source for multiple levels of nesting, or
10105                  *   it my be used as a function. As a function it takes a single parameter,
10106                  *   the JSON returned from the server, which can be manipulated as
10107                  *   required, with the returned value being that used by DataTables as the
10108                  *   data source for the table. This supersedes `sAjaxDataProp` from
10109                  *   DataTables 1.9-.
10110                  *
10111                  * * `success` - Should not be overridden it is used internally in
10112                  *   DataTables. To manipulate / transform the data returned by the server
10113                  *   use `ajax.dataSrc`, or use `ajax` as a function (see below).
10114                  *
10115                  * `function`
10116                  * ----------
10117                  *
10118                  * As a function, making the Ajax call is left up to yourself allowing
10119                  * complete control of the Ajax request. Indeed, if desired, a method other
10120                  * than Ajax could be used to obtain the required data, such as Web storage
10121                  * or an AIR database.
10122                  *
10123                  * The function is given four parameters and no return is required. The
10124                  * parameters are:
10125                  *
10126                  * 1. _object_ - Data to send to the server
10127                  * 2. _function_ - Callback function that must be executed when the required
10128                  *    data has been obtained. That data should be passed into the callback
10129                  *    as the only parameter
10130                  * 3. _object_ - DataTables settings object for the table
10131                  *
10132                  * Note that this supersedes `fnServerData` from DataTables 1.9-.
10133                  *
10134                  *  @type string|object|function
10135                  *  @default null
10136                  *
10137                  *  @dtopt Option
10138                  *  @name DataTable.defaults.ajax
10139                  *  @since 1.10.0
10140                  *
10141                  * @example
10142                  *   // Get JSON data from a file via Ajax.
10143                  *   // Note DataTables expects data in the form `{ data: [ ...data... ] }` by default).
10144                  *   $('#example').dataTable( {
10145                  *     "ajax": "data.json"
10146                  *   } );
10147                  *
10148                  * @example
10149                  *   // Get JSON data from a file via Ajax, using `dataSrc` to change
10150                  *   // `data` to `tableData` (i.e. `{ tableData: [ ...data... ] }`)
10151                  *   $('#example').dataTable( {
10152                  *     "ajax": {
10153                  *       "url": "data.json",
10154                  *       "dataSrc": "tableData"
10155                  *     }
10156                  *   } );
10157                  *
10158                  * @example
10159                  *   // Get JSON data from a file via Ajax, using `dataSrc` to read data
10160                  *   // from a plain array rather than an array in an object
10161                  *   $('#example').dataTable( {
10162                  *     "ajax": {
10163                  *       "url": "data.json",
10164                  *       "dataSrc": ""
10165                  *     }
10166                  *   } );
10167                  *
10168                  * @example
10169                  *   // Manipulate the data returned from the server - add a link to data
10170                  *   // (note this can, should, be done using `render` for the column - this
10171                  *   // is just a simple example of how the data can be manipulated).
10172                  *   $('#example').dataTable( {
10173                  *     "ajax": {
10174                  *       "url": "data.json",
10175                  *       "dataSrc": function ( json ) {
10176                  *         for ( var i=0, ien=json.length ; i<ien ; i++ ) {
10177                  *           json[i][0] = '<a href="/message/'+json[i][0]+'>View message</a>';
10178                  *         }
10179                  *         return json;
10180                  *       }
10181                  *     }
10182                  *   } );
10183                  *
10184                  * @example
10185                  *   // Add data to the request
10186                  *   $('#example').dataTable( {
10187                  *     "ajax": {
10188                  *       "url": "data.json",
10189                  *       "data": function ( d ) {
10190                  *         return {
10191                  *           "extra_search": $('#extra').val()
10192                  *         };
10193                  *       }
10194                  *     }
10195                  *   } );
10196                  *
10197                  * @example
10198                  *   // Send request as POST
10199                  *   $('#example').dataTable( {
10200                  *     "ajax": {
10201                  *       "url": "data.json",
10202                  *       "type": "POST"
10203                  *     }
10204                  *   } );
10205                  *
10206                  * @example
10207                  *   // Get the data from localStorage (could interface with a form for
10208                  *   // adding, editing and removing rows).
10209                  *   $('#example').dataTable( {
10210                  *     "ajax": function (data, callback, settings) {
10211                  *       callback(
10212                  *         JSON.parse( localStorage.getItem('dataTablesData') )
10213                  *       );
10214                  *     }
10215                  *   } );
10216                  */
10217                 "ajax": null,
10218         
10219         
10220                 /**
10221                  * This parameter allows you to readily specify the entries in the length drop
10222                  * down menu that DataTables shows when pagination is enabled. It can be
10223                  * either a 1D array of options which will be used for both the displayed
10224                  * option and the value, or a 2D array which will use the array in the first
10225                  * position as the value, and the array in the second position as the
10226                  * displayed options (useful for language strings such as 'All').
10227                  *
10228                  * Note that the `pageLength` property will be automatically set to the
10229                  * first value given in this array, unless `pageLength` is also provided.
10230                  *  @type array
10231                  *  @default [ 10, 25, 50, 100 ]
10232                  *
10233                  *  @dtopt Option
10234                  *  @name DataTable.defaults.lengthMenu
10235                  *
10236                  *  @example
10237                  *    $(document).ready( function() {
10238                  *      $('#example').dataTable( {
10239                  *        "lengthMenu": [[10, 25, 50, -1], [10, 25, 50, "All"]]
10240                  *      } );
10241                  *    } );
10242                  */
10243                 "aLengthMenu": [ 10, 25, 50, 100 ],
10244         
10245         
10246                 /**
10247                  * The `columns` option in the initialisation parameter allows you to define
10248                  * details about the way individual columns behave. For a full list of
10249                  * column options that can be set, please see
10250                  * {@link DataTable.defaults.column}. Note that if you use `columns` to
10251                  * define your columns, you must have an entry in the array for every single
10252                  * column that you have in your table (these can be null if you don't which
10253                  * to specify any options).
10254                  *  @member
10255                  *
10256                  *  @name DataTable.defaults.column
10257                  */
10258                 "aoColumns": null,
10259         
10260                 /**
10261                  * Very similar to `columns`, `columnDefs` allows you to target a specific
10262                  * column, multiple columns, or all columns, using the `targets` property of
10263                  * each object in the array. This allows great flexibility when creating
10264                  * tables, as the `columnDefs` arrays can be of any length, targeting the
10265                  * columns you specifically want. `columnDefs` may use any of the column
10266                  * options available: {@link DataTable.defaults.column}, but it _must_
10267                  * have `targets` defined in each object in the array. Values in the `targets`
10268                  * array may be:
10269                  *   <ul>
10270                  *     <li>a string - class name will be matched on the TH for the column</li>
10271                  *     <li>0 or a positive integer - column index counting from the left</li>
10272                  *     <li>a negative integer - column index counting from the right</li>
10273                  *     <li>the string "_all" - all columns (i.e. assign a default)</li>
10274                  *   </ul>
10275                  *  @member
10276                  *
10277                  *  @name DataTable.defaults.columnDefs
10278                  */
10279                 "aoColumnDefs": null,
10280         
10281         
10282                 /**
10283                  * Basically the same as `search`, this parameter defines the individual column
10284                  * filtering state at initialisation time. The array must be of the same size
10285                  * as the number of columns, and each element be an object with the parameters
10286                  * `search` and `escapeRegex` (the latter is optional). 'null' is also
10287                  * accepted and the default will be used.
10288                  *  @type array
10289                  *  @default []
10290                  *
10291                  *  @dtopt Option
10292                  *  @name DataTable.defaults.searchCols
10293                  *
10294                  *  @example
10295                  *    $(document).ready( function() {
10296                  *      $('#example').dataTable( {
10297                  *        "searchCols": [
10298                  *          null,
10299                  *          { "search": "My filter" },
10300                  *          null,
10301                  *          { "search": "^[0-9]", "escapeRegex": false }
10302                  *        ]
10303                  *      } );
10304                  *    } )
10305                  */
10306                 "aoSearchCols": [],
10307         
10308         
10309                 /**
10310                  * An array of CSS classes that should be applied to displayed rows. This
10311                  * array may be of any length, and DataTables will apply each class
10312                  * sequentially, looping when required.
10313                  *  @type array
10314                  *  @default null <i>Will take the values determined by the `oClasses.stripe*`
10315                  *    options</i>
10316                  *
10317                  *  @dtopt Option
10318                  *  @name DataTable.defaults.stripeClasses
10319                  *
10320                  *  @example
10321                  *    $(document).ready( function() {
10322                  *      $('#example').dataTable( {
10323                  *        "stripeClasses": [ 'strip1', 'strip2', 'strip3' ]
10324                  *      } );
10325                  *    } )
10326                  */
10327                 "asStripeClasses": null,
10328         
10329         
10330                 /**
10331                  * Enable or disable automatic column width calculation. This can be disabled
10332                  * as an optimisation (it takes some time to calculate the widths) if the
10333                  * tables widths are passed in using `columns`.
10334                  *  @type boolean
10335                  *  @default true
10336                  *
10337                  *  @dtopt Features
10338                  *  @name DataTable.defaults.autoWidth
10339                  *
10340                  *  @example
10341                  *    $(document).ready( function () {
10342                  *      $('#example').dataTable( {
10343                  *        "autoWidth": false
10344                  *      } );
10345                  *    } );
10346                  */
10347                 "bAutoWidth": true,
10348         
10349         
10350                 /**
10351                  * Deferred rendering can provide DataTables with a huge speed boost when you
10352                  * are using an Ajax or JS data source for the table. This option, when set to
10353                  * true, will cause DataTables to defer the creation of the table elements for
10354                  * each row until they are needed for a draw - saving a significant amount of
10355                  * time.
10356                  *  @type boolean
10357                  *  @default false
10358                  *
10359                  *  @dtopt Features
10360                  *  @name DataTable.defaults.deferRender
10361                  *
10362                  *  @example
10363                  *    $(document).ready( function() {
10364                  *      $('#example').dataTable( {
10365                  *        "ajax": "sources/arrays.txt",
10366                  *        "deferRender": true
10367                  *      } );
10368                  *    } );
10369                  */
10370                 "bDeferRender": false,
10371         
10372         
10373                 /**
10374                  * Replace a DataTable which matches the given selector and replace it with
10375                  * one which has the properties of the new initialisation object passed. If no
10376                  * table matches the selector, then the new DataTable will be constructed as
10377                  * per normal.
10378                  *  @type boolean
10379                  *  @default false
10380                  *
10381                  *  @dtopt Options
10382                  *  @name DataTable.defaults.destroy
10383                  *
10384                  *  @example
10385                  *    $(document).ready( function() {
10386                  *      $('#example').dataTable( {
10387                  *        "srollY": "200px",
10388                  *        "paginate": false
10389                  *      } );
10390                  *
10391                  *      // Some time later....
10392                  *      $('#example').dataTable( {
10393                  *        "filter": false,
10394                  *        "destroy": true
10395                  *      } );
10396                  *    } );
10397                  */
10398                 "bDestroy": false,
10399         
10400         
10401                 /**
10402                  * Enable or disable filtering of data. Filtering in DataTables is "smart" in
10403                  * that it allows the end user to input multiple words (space separated) and
10404                  * will match a row containing those words, even if not in the order that was
10405                  * specified (this allow matching across multiple columns). Note that if you
10406                  * wish to use filtering in DataTables this must remain 'true' - to remove the
10407                  * default filtering input box and retain filtering abilities, please use
10408                  * {@link DataTable.defaults.dom}.
10409                  *  @type boolean
10410                  *  @default true
10411                  *
10412                  *  @dtopt Features
10413                  *  @name DataTable.defaults.searching
10414                  *
10415                  *  @example
10416                  *    $(document).ready( function () {
10417                  *      $('#example').dataTable( {
10418                  *        "searching": false
10419                  *      } );
10420                  *    } );
10421                  */
10422                 "bFilter": true,
10423         
10424         
10425                 /**
10426                  * Enable or disable the table information display. This shows information
10427                  * about the data that is currently visible on the page, including information
10428                  * about filtered data if that action is being performed.
10429                  *  @type boolean
10430                  *  @default true
10431                  *
10432                  *  @dtopt Features
10433                  *  @name DataTable.defaults.info
10434                  *
10435                  *  @example
10436                  *    $(document).ready( function () {
10437                  *      $('#example').dataTable( {
10438                  *        "info": false
10439                  *      } );
10440                  *    } );
10441                  */
10442                 "bInfo": true,
10443         
10444         
10445                 /**
10446                  * Allows the end user to select the size of a formatted page from a select
10447                  * menu (sizes are 10, 25, 50 and 100). Requires pagination (`paginate`).
10448                  *  @type boolean
10449                  *  @default true
10450                  *
10451                  *  @dtopt Features
10452                  *  @name DataTable.defaults.lengthChange
10453                  *
10454                  *  @example
10455                  *    $(document).ready( function () {
10456                  *      $('#example').dataTable( {
10457                  *        "lengthChange": false
10458                  *      } );
10459                  *    } );
10460                  */
10461                 "bLengthChange": true,
10462         
10463         
10464                 /**
10465                  * Enable or disable pagination.
10466                  *  @type boolean
10467                  *  @default true
10468                  *
10469                  *  @dtopt Features
10470                  *  @name DataTable.defaults.paging
10471                  *
10472                  *  @example
10473                  *    $(document).ready( function () {
10474                  *      $('#example').dataTable( {
10475                  *        "paging": false
10476                  *      } );
10477                  *    } );
10478                  */
10479                 "bPaginate": true,
10480         
10481         
10482                 /**
10483                  * Enable or disable the display of a 'processing' indicator when the table is
10484                  * being processed (e.g. a sort). This is particularly useful for tables with
10485                  * large amounts of data where it can take a noticeable amount of time to sort
10486                  * the entries.
10487                  *  @type boolean
10488                  *  @default false
10489                  *
10490                  *  @dtopt Features
10491                  *  @name DataTable.defaults.processing
10492                  *
10493                  *  @example
10494                  *    $(document).ready( function () {
10495                  *      $('#example').dataTable( {
10496                  *        "processing": true
10497                  *      } );
10498                  *    } );
10499                  */
10500                 "bProcessing": false,
10501         
10502         
10503                 /**
10504                  * Retrieve the DataTables object for the given selector. Note that if the
10505                  * table has already been initialised, this parameter will cause DataTables
10506                  * to simply return the object that has already been set up - it will not take
10507                  * account of any changes you might have made to the initialisation object
10508                  * passed to DataTables (setting this parameter to true is an acknowledgement
10509                  * that you understand this). `destroy` can be used to reinitialise a table if
10510                  * you need.
10511                  *  @type boolean
10512                  *  @default false
10513                  *
10514                  *  @dtopt Options
10515                  *  @name DataTable.defaults.retrieve
10516                  *
10517                  *  @example
10518                  *    $(document).ready( function() {
10519                  *      initTable();
10520                  *      tableActions();
10521                  *    } );
10522                  *
10523                  *    function initTable ()
10524                  *    {
10525                  *      return $('#example').dataTable( {
10526                  *        "scrollY": "200px",
10527                  *        "paginate": false,
10528                  *        "retrieve": true
10529                  *      } );
10530                  *    }
10531                  *
10532                  *    function tableActions ()
10533                  *    {
10534                  *      var table = initTable();
10535                  *      // perform API operations with oTable
10536                  *    }
10537                  */
10538                 "bRetrieve": false,
10539         
10540         
10541                 /**
10542                  * When vertical (y) scrolling is enabled, DataTables will force the height of
10543                  * the table's viewport to the given height at all times (useful for layout).
10544                  * However, this can look odd when filtering data down to a small data set,
10545                  * and the footer is left "floating" further down. This parameter (when
10546                  * enabled) will cause DataTables to collapse the table's viewport down when
10547                  * the result set will fit within the given Y height.
10548                  *  @type boolean
10549                  *  @default false
10550                  *
10551                  *  @dtopt Options
10552                  *  @name DataTable.defaults.scrollCollapse
10553                  *
10554                  *  @example
10555                  *    $(document).ready( function() {
10556                  *      $('#example').dataTable( {
10557                  *        "scrollY": "200",
10558                  *        "scrollCollapse": true
10559                  *      } );
10560                  *    } );
10561                  */
10562                 "bScrollCollapse": false,
10563         
10564         
10565                 /**
10566                  * Configure DataTables to use server-side processing. Note that the
10567                  * `ajax` parameter must also be given in order to give DataTables a
10568                  * source to obtain the required data for each draw.
10569                  *  @type boolean
10570                  *  @default false
10571                  *
10572                  *  @dtopt Features
10573                  *  @dtopt Server-side
10574                  *  @name DataTable.defaults.serverSide
10575                  *
10576                  *  @example
10577                  *    $(document).ready( function () {
10578                  *      $('#example').dataTable( {
10579                  *        "serverSide": true,
10580                  *        "ajax": "xhr.php"
10581                  *      } );
10582                  *    } );
10583                  */
10584                 "bServerSide": false,
10585         
10586         
10587                 /**
10588                  * Enable or disable sorting of columns. Sorting of individual columns can be
10589                  * disabled by the `sortable` option for each column.
10590                  *  @type boolean
10591                  *  @default true
10592                  *
10593                  *  @dtopt Features
10594                  *  @name DataTable.defaults.ordering
10595                  *
10596                  *  @example
10597                  *    $(document).ready( function () {
10598                  *      $('#example').dataTable( {
10599                  *        "ordering": false
10600                  *      } );
10601                  *    } );
10602                  */
10603                 "bSort": true,
10604         
10605         
10606                 /**
10607                  * Enable or display DataTables' ability to sort multiple columns at the
10608                  * same time (activated by shift-click by the user).
10609                  *  @type boolean
10610                  *  @default true
10611                  *
10612                  *  @dtopt Options
10613                  *  @name DataTable.defaults.orderMulti
10614                  *
10615                  *  @example
10616                  *    // Disable multiple column sorting ability
10617                  *    $(document).ready( function () {
10618                  *      $('#example').dataTable( {
10619                  *        "orderMulti": false
10620                  *      } );
10621                  *    } );
10622                  */
10623                 "bSortMulti": true,
10624         
10625         
10626                 /**
10627                  * Allows control over whether DataTables should use the top (true) unique
10628                  * cell that is found for a single column, or the bottom (false - default).
10629                  * This is useful when using complex headers.
10630                  *  @type boolean
10631                  *  @default false
10632                  *
10633                  *  @dtopt Options
10634                  *  @name DataTable.defaults.orderCellsTop
10635                  *
10636                  *  @example
10637                  *    $(document).ready( function() {
10638                  *      $('#example').dataTable( {
10639                  *        "orderCellsTop": true
10640                  *      } );
10641                  *    } );
10642                  */
10643                 "bSortCellsTop": false,
10644         
10645         
10646                 /**
10647                  * Enable or disable the addition of the classes `sorting\_1`, `sorting\_2` and
10648                  * `sorting\_3` to the columns which are currently being sorted on. This is
10649                  * presented as a feature switch as it can increase processing time (while
10650                  * classes are removed and added) so for large data sets you might want to
10651                  * turn this off.
10652                  *  @type boolean
10653                  *  @default true
10654                  *
10655                  *  @dtopt Features
10656                  *  @name DataTable.defaults.orderClasses
10657                  *
10658                  *  @example
10659                  *    $(document).ready( function () {
10660                  *      $('#example').dataTable( {
10661                  *        "orderClasses": false
10662                  *      } );
10663                  *    } );
10664                  */
10665                 "bSortClasses": true,
10666         
10667         
10668                 /**
10669                  * Enable or disable state saving. When enabled HTML5 `localStorage` will be
10670                  * used to save table display information such as pagination information,
10671                  * display length, filtering and sorting. As such when the end user reloads
10672                  * the page the display display will match what thy had previously set up.
10673                  *
10674                  * Due to the use of `localStorage` the default state saving is not supported
10675                  * in IE6 or 7. If state saving is required in those browsers, use
10676                  * `stateSaveCallback` to provide a storage solution such as cookies.
10677                  *  @type boolean
10678                  *  @default false
10679                  *
10680                  *  @dtopt Features
10681                  *  @name DataTable.defaults.stateSave
10682                  *
10683                  *  @example
10684                  *    $(document).ready( function () {
10685                  *      $('#example').dataTable( {
10686                  *        "stateSave": true
10687                  *      } );
10688                  *    } );
10689                  */
10690                 "bStateSave": false,
10691         
10692         
10693                 /**
10694                  * This function is called when a TR element is created (and all TD child
10695                  * elements have been inserted), or registered if using a DOM source, allowing
10696                  * manipulation of the TR element (adding classes etc).
10697                  *  @type function
10698                  *  @param {node} row "TR" element for the current row
10699                  *  @param {array} data Raw data array for this row
10700                  *  @param {int} dataIndex The index of this row in the internal aoData array
10701                  *
10702                  *  @dtopt Callbacks
10703                  *  @name DataTable.defaults.createdRow
10704                  *
10705                  *  @example
10706                  *    $(document).ready( function() {
10707                  *      $('#example').dataTable( {
10708                  *        "createdRow": function( row, data, dataIndex ) {
10709                  *          // Bold the grade for all 'A' grade browsers
10710                  *          if ( data[4] == "A" )
10711                  *          {
10712                  *            $('td:eq(4)', row).html( '<b>A</b>' );
10713                  *          }
10714                  *        }
10715                  *      } );
10716                  *    } );
10717                  */
10718                 "fnCreatedRow": null,
10719         
10720         
10721                 /**
10722                  * This function is called on every 'draw' event, and allows you to
10723                  * dynamically modify any aspect you want about the created DOM.
10724                  *  @type function
10725                  *  @param {object} settings DataTables settings object
10726                  *
10727                  *  @dtopt Callbacks
10728                  *  @name DataTable.defaults.drawCallback
10729                  *
10730                  *  @example
10731                  *    $(document).ready( function() {
10732                  *      $('#example').dataTable( {
10733                  *        "drawCallback": function( settings ) {
10734                  *          alert( 'DataTables has redrawn the table' );
10735                  *        }
10736                  *      } );
10737                  *    } );
10738                  */
10739                 "fnDrawCallback": null,
10740         
10741         
10742                 /**
10743                  * Identical to fnHeaderCallback() but for the table footer this function
10744                  * allows you to modify the table footer on every 'draw' event.
10745                  *  @type function
10746                  *  @param {node} foot "TR" element for the footer
10747                  *  @param {array} data Full table data (as derived from the original HTML)
10748                  *  @param {int} start Index for the current display starting point in the
10749                  *    display array
10750                  *  @param {int} end Index for the current display ending point in the
10751                  *    display array
10752                  *  @param {array int} display Index array to translate the visual position
10753                  *    to the full data array
10754                  *
10755                  *  @dtopt Callbacks
10756                  *  @name DataTable.defaults.footerCallback
10757                  *
10758                  *  @example
10759                  *    $(document).ready( function() {
10760                  *      $('#example').dataTable( {
10761                  *        "footerCallback": function( tfoot, data, start, end, display ) {
10762                  *          tfoot.getElementsByTagName('th')[0].innerHTML = "Starting index is "+start;
10763                  *        }
10764                  *      } );
10765                  *    } )
10766                  */
10767                 "fnFooterCallback": null,
10768         
10769         
10770                 /**
10771                  * When rendering large numbers in the information element for the table
10772                  * (i.e. "Showing 1 to 10 of 57 entries") DataTables will render large numbers
10773                  * to have a comma separator for the 'thousands' units (e.g. 1 million is
10774                  * rendered as "1,000,000") to help readability for the end user. This
10775                  * function will override the default method DataTables uses.
10776                  *  @type function
10777                  *  @member
10778                  *  @param {int} toFormat number to be formatted
10779                  *  @returns {string} formatted string for DataTables to show the number
10780                  *
10781                  *  @dtopt Callbacks
10782                  *  @name DataTable.defaults.formatNumber
10783                  *
10784                  *  @example
10785                  *    // Format a number using a single quote for the separator (note that
10786                  *    // this can also be done with the language.thousands option)
10787                  *    $(document).ready( function() {
10788                  *      $('#example').dataTable( {
10789                  *        "formatNumber": function ( toFormat ) {
10790                  *          return toFormat.toString().replace(
10791                  *            /\B(?=(\d{3})+(?!\d))/g, "'"
10792                  *          );
10793                  *        };
10794                  *      } );
10795                  *    } );
10796                  */
10797                 "fnFormatNumber": function ( toFormat ) {
10798                         return toFormat.toString().replace(
10799                                 /\B(?=(\d{3})+(?!\d))/g,
10800                                 this.oLanguage.sThousands
10801                         );
10802                 },
10803         
10804         
10805                 /**
10806                  * This function is called on every 'draw' event, and allows you to
10807                  * dynamically modify the header row. This can be used to calculate and
10808                  * display useful information about the table.
10809                  *  @type function
10810                  *  @param {node} head "TR" element for the header
10811                  *  @param {array} data Full table data (as derived from the original HTML)
10812                  *  @param {int} start Index for the current display starting point in the
10813                  *    display array
10814                  *  @param {int} end Index for the current display ending point in the
10815                  *    display array
10816                  *  @param {array int} display Index array to translate the visual position
10817                  *    to the full data array
10818                  *
10819                  *  @dtopt Callbacks
10820                  *  @name DataTable.defaults.headerCallback
10821                  *
10822                  *  @example
10823                  *    $(document).ready( function() {
10824                  *      $('#example').dataTable( {
10825                  *        "fheaderCallback": function( head, data, start, end, display ) {
10826                  *          head.getElementsByTagName('th')[0].innerHTML = "Displaying "+(end-start)+" records";
10827                  *        }
10828                  *      } );
10829                  *    } )
10830                  */
10831                 "fnHeaderCallback": null,
10832         
10833         
10834                 /**
10835                  * The information element can be used to convey information about the current
10836                  * state of the table. Although the internationalisation options presented by
10837                  * DataTables are quite capable of dealing with most customisations, there may
10838                  * be times where you wish to customise the string further. This callback
10839                  * allows you to do exactly that.
10840                  *  @type function
10841                  *  @param {object} oSettings DataTables settings object
10842                  *  @param {int} start Starting position in data for the draw
10843                  *  @param {int} end End position in data for the draw
10844                  *  @param {int} max Total number of rows in the table (regardless of
10845                  *    filtering)
10846                  *  @param {int} total Total number of rows in the data set, after filtering
10847                  *  @param {string} pre The string that DataTables has formatted using it's
10848                  *    own rules
10849                  *  @returns {string} The string to be displayed in the information element.
10850                  *
10851                  *  @dtopt Callbacks
10852                  *  @name DataTable.defaults.infoCallback
10853                  *
10854                  *  @example
10855                  *    $('#example').dataTable( {
10856                  *      "infoCallback": function( settings, start, end, max, total, pre ) {
10857                  *        return start +" to "+ end;
10858                  *      }
10859                  *    } );
10860                  */
10861                 "fnInfoCallback": null,
10862         
10863         
10864                 /**
10865                  * Called when the table has been initialised. Normally DataTables will
10866                  * initialise sequentially and there will be no need for this function,
10867                  * however, this does not hold true when using external language information
10868                  * since that is obtained using an async XHR call.
10869                  *  @type function
10870                  *  @param {object} settings DataTables settings object
10871                  *  @param {object} json The JSON object request from the server - only
10872                  *    present if client-side Ajax sourced data is used
10873                  *
10874                  *  @dtopt Callbacks
10875                  *  @name DataTable.defaults.initComplete
10876                  *
10877                  *  @example
10878                  *    $(document).ready( function() {
10879                  *      $('#example').dataTable( {
10880                  *        "initComplete": function(settings, json) {
10881                  *          alert( 'DataTables has finished its initialisation.' );
10882                  *        }
10883                  *      } );
10884                  *    } )
10885                  */
10886                 "fnInitComplete": null,
10887         
10888         
10889                 /**
10890                  * Called at the very start of each table draw and can be used to cancel the
10891                  * draw by returning false, any other return (including undefined) results in
10892                  * the full draw occurring).
10893                  *  @type function
10894                  *  @param {object} settings DataTables settings object
10895                  *  @returns {boolean} False will cancel the draw, anything else (including no
10896                  *    return) will allow it to complete.
10897                  *
10898                  *  @dtopt Callbacks
10899                  *  @name DataTable.defaults.preDrawCallback
10900                  *
10901                  *  @example
10902                  *    $(document).ready( function() {
10903                  *      $('#example').dataTable( {
10904                  *        "preDrawCallback": function( settings ) {
10905                  *          if ( $('#test').val() == 1 ) {
10906                  *            return false;
10907                  *          }
10908                  *        }
10909                  *      } );
10910                  *    } );
10911                  */
10912                 "fnPreDrawCallback": null,
10913         
10914         
10915                 /**
10916                  * This function allows you to 'post process' each row after it have been
10917                  * generated for each table draw, but before it is rendered on screen. This
10918                  * function might be used for setting the row class name etc.
10919                  *  @type function
10920                  *  @param {node} row "TR" element for the current row
10921                  *  @param {array} data Raw data array for this row
10922                  *  @param {int} displayIndex The display index for the current table draw
10923                  *  @param {int} displayIndexFull The index of the data in the full list of
10924                  *    rows (after filtering)
10925                  *
10926                  *  @dtopt Callbacks
10927                  *  @name DataTable.defaults.rowCallback
10928                  *
10929                  *  @example
10930                  *    $(document).ready( function() {
10931                  *      $('#example').dataTable( {
10932                  *        "rowCallback": function( row, data, displayIndex, displayIndexFull ) {
10933                  *          // Bold the grade for all 'A' grade browsers
10934                  *          if ( data[4] == "A" ) {
10935                  *            $('td:eq(4)', row).html( '<b>A</b>' );
10936                  *          }
10937                  *        }
10938                  *      } );
10939                  *    } );
10940                  */
10941                 "fnRowCallback": null,
10942         
10943         
10944                 /**
10945                  * __Deprecated__ The functionality provided by this parameter has now been
10946                  * superseded by that provided through `ajax`, which should be used instead.
10947                  *
10948                  * This parameter allows you to override the default function which obtains
10949                  * the data from the server so something more suitable for your application.
10950                  * For example you could use POST data, or pull information from a Gears or
10951                  * AIR database.
10952                  *  @type function
10953                  *  @member
10954                  *  @param {string} source HTTP source to obtain the data from (`ajax`)
10955                  *  @param {array} data A key/value pair object containing the data to send
10956                  *    to the server
10957                  *  @param {function} callback to be called on completion of the data get
10958                  *    process that will draw the data on the page.
10959                  *  @param {object} settings DataTables settings object
10960                  *
10961                  *  @dtopt Callbacks
10962                  *  @dtopt Server-side
10963                  *  @name DataTable.defaults.serverData
10964                  *
10965                  *  @deprecated 1.10. Please use `ajax` for this functionality now.
10966                  */
10967                 "fnServerData": null,
10968         
10969         
10970                 /**
10971                  * __Deprecated__ The functionality provided by this parameter has now been
10972                  * superseded by that provided through `ajax`, which should be used instead.
10973                  *
10974                  *  It is often useful to send extra data to the server when making an Ajax
10975                  * request - for example custom filtering information, and this callback
10976                  * function makes it trivial to send extra information to the server. The
10977                  * passed in parameter is the data set that has been constructed by
10978                  * DataTables, and you can add to this or modify it as you require.
10979                  *  @type function
10980                  *  @param {array} data Data array (array of objects which are name/value
10981                  *    pairs) that has been constructed by DataTables and will be sent to the
10982                  *    server. In the case of Ajax sourced data with server-side processing
10983                  *    this will be an empty array, for server-side processing there will be a
10984                  *    significant number of parameters!
10985                  *  @returns {undefined} Ensure that you modify the data array passed in,
10986                  *    as this is passed by reference.
10987                  *
10988                  *  @dtopt Callbacks
10989                  *  @dtopt Server-side
10990                  *  @name DataTable.defaults.serverParams
10991                  *
10992                  *  @deprecated 1.10. Please use `ajax` for this functionality now.
10993                  */
10994                 "fnServerParams": null,
10995         
10996         
10997                 /**
10998                  * Load the table state. With this function you can define from where, and how, the
10999                  * state of a table is loaded. By default DataTables will load from `localStorage`
11000                  * but you might wish to use a server-side database or cookies.
11001                  *  @type function
11002                  *  @member
11003                  *  @param {object} settings DataTables settings object
11004                  *  @param {object} callback Callback that can be executed when done. It
11005                  *    should be passed the loaded state object.
11006                  *  @return {object} The DataTables state object to be loaded
11007                  *
11008                  *  @dtopt Callbacks
11009                  *  @name DataTable.defaults.stateLoadCallback
11010                  *
11011                  *  @example
11012                  *    $(document).ready( function() {
11013                  *      $('#example').dataTable( {
11014                  *        "stateSave": true,
11015                  *        "stateLoadCallback": function (settings, callback) {
11016                  *          $.ajax( {
11017                  *            "url": "/state_load",
11018                  *            "dataType": "json",
11019                  *            "success": function (json) {
11020                  *              callback( json );
11021                  *            }
11022                  *          } );
11023                  *        }
11024                  *      } );
11025                  *    } );
11026                  */
11027                 "fnStateLoadCallback": function ( settings ) {
11028                         try {
11029                                 return JSON.parse(
11030                                         (settings.iStateDuration === -1 ? sessionStorage : localStorage).getItem(
11031                                                 'DataTables_'+settings.sInstance+'_'+location.pathname
11032                                         )
11033                                 );
11034                         } catch (e) {
11035                                 return {};
11036                         }
11037                 },
11038         
11039         
11040                 /**
11041                  * Callback which allows modification of the saved state prior to loading that state.
11042                  * This callback is called when the table is loading state from the stored data, but
11043                  * prior to the settings object being modified by the saved state. Note that for
11044                  * plug-in authors, you should use the `stateLoadParams` event to load parameters for
11045                  * a plug-in.
11046                  *  @type function
11047                  *  @param {object} settings DataTables settings object
11048                  *  @param {object} data The state object that is to be loaded
11049                  *
11050                  *  @dtopt Callbacks
11051                  *  @name DataTable.defaults.stateLoadParams
11052                  *
11053                  *  @example
11054                  *    // Remove a saved filter, so filtering is never loaded
11055                  *    $(document).ready( function() {
11056                  *      $('#example').dataTable( {
11057                  *        "stateSave": true,
11058                  *        "stateLoadParams": function (settings, data) {
11059                  *          data.oSearch.sSearch = "";
11060                  *        }
11061                  *      } );
11062                  *    } );
11063                  *
11064                  *  @example
11065                  *    // Disallow state loading by returning false
11066                  *    $(document).ready( function() {
11067                  *      $('#example').dataTable( {
11068                  *        "stateSave": true,
11069                  *        "stateLoadParams": function (settings, data) {
11070                  *          return false;
11071                  *        }
11072                  *      } );
11073                  *    } );
11074                  */
11075                 "fnStateLoadParams": null,
11076         
11077         
11078                 /**
11079                  * Callback that is called when the state has been loaded from the state saving method
11080                  * and the DataTables settings object has been modified as a result of the loaded state.
11081                  *  @type function
11082                  *  @param {object} settings DataTables settings object
11083                  *  @param {object} data The state object that was loaded
11084                  *
11085                  *  @dtopt Callbacks
11086                  *  @name DataTable.defaults.stateLoaded
11087                  *
11088                  *  @example
11089                  *    // Show an alert with the filtering value that was saved
11090                  *    $(document).ready( function() {
11091                  *      $('#example').dataTable( {
11092                  *        "stateSave": true,
11093                  *        "stateLoaded": function (settings, data) {
11094                  *          alert( 'Saved filter was: '+data.oSearch.sSearch );
11095                  *        }
11096                  *      } );
11097                  *    } );
11098                  */
11099                 "fnStateLoaded": null,
11100         
11101         
11102                 /**
11103                  * Save the table state. This function allows you to define where and how the state
11104                  * information for the table is stored By default DataTables will use `localStorage`
11105                  * but you might wish to use a server-side database or cookies.
11106                  *  @type function
11107                  *  @member
11108                  *  @param {object} settings DataTables settings object
11109                  *  @param {object} data The state object to be saved
11110                  *
11111                  *  @dtopt Callbacks
11112                  *  @name DataTable.defaults.stateSaveCallback
11113                  *
11114                  *  @example
11115                  *    $(document).ready( function() {
11116                  *      $('#example').dataTable( {
11117                  *        "stateSave": true,
11118                  *        "stateSaveCallback": function (settings, data) {
11119                  *          // Send an Ajax request to the server with the state object
11120                  *          $.ajax( {
11121                  *            "url": "/state_save",
11122                  *            "data": data,
11123                  *            "dataType": "json",
11124                  *            "method": "POST"
11125                  *            "success": function () {}
11126                  *          } );
11127                  *        }
11128                  *      } );
11129                  *    } );
11130                  */
11131                 "fnStateSaveCallback": function ( settings, data ) {
11132                         try {
11133                                 (settings.iStateDuration === -1 ? sessionStorage : localStorage).setItem(
11134                                         'DataTables_'+settings.sInstance+'_'+location.pathname,
11135                                         JSON.stringify( data )
11136                                 );
11137                         } catch (e) {}
11138                 },
11139         
11140         
11141                 /**
11142                  * Callback which allows modification of the state to be saved. Called when the table
11143                  * has changed state a new state save is required. This method allows modification of
11144                  * the state saving object prior to actually doing the save, including addition or
11145                  * other state properties or modification. Note that for plug-in authors, you should
11146                  * use the `stateSaveParams` event to save parameters for a plug-in.
11147                  *  @type function
11148                  *  @param {object} settings DataTables settings object
11149                  *  @param {object} data The state object to be saved
11150                  *
11151                  *  @dtopt Callbacks
11152                  *  @name DataTable.defaults.stateSaveParams
11153                  *
11154                  *  @example
11155                  *    // Remove a saved filter, so filtering is never saved
11156                  *    $(document).ready( function() {
11157                  *      $('#example').dataTable( {
11158                  *        "stateSave": true,
11159                  *        "stateSaveParams": function (settings, data) {
11160                  *          data.oSearch.sSearch = "";
11161                  *        }
11162                  *      } );
11163                  *    } );
11164                  */
11165                 "fnStateSaveParams": null,
11166         
11167         
11168                 /**
11169                  * Duration for which the saved state information is considered valid. After this period
11170                  * has elapsed the state will be returned to the default.
11171                  * Value is given in seconds.
11172                  *  @type int
11173                  *  @default 7200 <i>(2 hours)</i>
11174                  *
11175                  *  @dtopt Options
11176                  *  @name DataTable.defaults.stateDuration
11177                  *
11178                  *  @example
11179                  *    $(document).ready( function() {
11180                  *      $('#example').dataTable( {
11181                  *        "stateDuration": 60*60*24; // 1 day
11182                  *      } );
11183                  *    } )
11184                  */
11185                 "iStateDuration": 7200,
11186         
11187         
11188                 /**
11189                  * When enabled DataTables will not make a request to the server for the first
11190                  * page draw - rather it will use the data already on the page (no sorting etc
11191                  * will be applied to it), thus saving on an XHR at load time. `deferLoading`
11192                  * is used to indicate that deferred loading is required, but it is also used
11193                  * to tell DataTables how many records there are in the full table (allowing
11194                  * the information element and pagination to be displayed correctly). In the case
11195                  * where a filtering is applied to the table on initial load, this can be
11196                  * indicated by giving the parameter as an array, where the first element is
11197                  * the number of records available after filtering and the second element is the
11198                  * number of records without filtering (allowing the table information element
11199                  * to be shown correctly).
11200                  *  @type int | array
11201                  *  @default null
11202                  *
11203                  *  @dtopt Options
11204                  *  @name DataTable.defaults.deferLoading
11205                  *
11206                  *  @example
11207                  *    // 57 records available in the table, no filtering applied
11208                  *    $(document).ready( function() {
11209                  *      $('#example').dataTable( {
11210                  *        "serverSide": true,
11211                  *        "ajax": "scripts/server_processing.php",
11212                  *        "deferLoading": 57
11213                  *      } );
11214                  *    } );
11215                  *
11216                  *  @example
11217                  *    // 57 records after filtering, 100 without filtering (an initial filter applied)
11218                  *    $(document).ready( function() {
11219                  *      $('#example').dataTable( {
11220                  *        "serverSide": true,
11221                  *        "ajax": "scripts/server_processing.php",
11222                  *        "deferLoading": [ 57, 100 ],
11223                  *        "search": {
11224                  *          "search": "my_filter"
11225                  *        }
11226                  *      } );
11227                  *    } );
11228                  */
11229                 "iDeferLoading": null,
11230         
11231         
11232                 /**
11233                  * Number of rows to display on a single page when using pagination. If
11234                  * feature enabled (`lengthChange`) then the end user will be able to override
11235                  * this to a custom setting using a pop-up menu.
11236                  *  @type int
11237                  *  @default 10
11238                  *
11239                  *  @dtopt Options
11240                  *  @name DataTable.defaults.pageLength
11241                  *
11242                  *  @example
11243                  *    $(document).ready( function() {
11244                  *      $('#example').dataTable( {
11245                  *        "pageLength": 50
11246                  *      } );
11247                  *    } )
11248                  */
11249                 "iDisplayLength": 10,
11250         
11251         
11252                 /**
11253                  * Define the starting point for data display when using DataTables with
11254                  * pagination. Note that this parameter is the number of records, rather than
11255                  * the page number, so if you have 10 records per page and want to start on
11256                  * the third page, it should be "20".
11257                  *  @type int
11258                  *  @default 0
11259                  *
11260                  *  @dtopt Options
11261                  *  @name DataTable.defaults.displayStart
11262                  *
11263                  *  @example
11264                  *    $(document).ready( function() {
11265                  *      $('#example').dataTable( {
11266                  *        "displayStart": 20
11267                  *      } );
11268                  *    } )
11269                  */
11270                 "iDisplayStart": 0,
11271         
11272         
11273                 /**
11274                  * By default DataTables allows keyboard navigation of the table (sorting, paging,
11275                  * and filtering) by adding a `tabindex` attribute to the required elements. This
11276                  * allows you to tab through the controls and press the enter key to activate them.
11277                  * The tabindex is default 0, meaning that the tab follows the flow of the document.
11278                  * You can overrule this using this parameter if you wish. Use a value of -1 to
11279                  * disable built-in keyboard navigation.
11280                  *  @type int
11281                  *  @default 0
11282                  *
11283                  *  @dtopt Options
11284                  *  @name DataTable.defaults.tabIndex
11285                  *
11286                  *  @example
11287                  *    $(document).ready( function() {
11288                  *      $('#example').dataTable( {
11289                  *        "tabIndex": 1
11290                  *      } );
11291                  *    } );
11292                  */
11293                 "iTabIndex": 0,
11294         
11295         
11296                 /**
11297                  * Classes that DataTables assigns to the various components and features
11298                  * that it adds to the HTML table. This allows classes to be configured
11299                  * during initialisation in addition to through the static
11300                  * {@link DataTable.ext.oStdClasses} object).
11301                  *  @namespace
11302                  *  @name DataTable.defaults.classes
11303                  */
11304                 "oClasses": {},
11305         
11306         
11307                 /**
11308                  * All strings that DataTables uses in the user interface that it creates
11309                  * are defined in this object, allowing you to modified them individually or
11310                  * completely replace them all as required.
11311                  *  @namespace
11312                  *  @name DataTable.defaults.language
11313                  */
11314                 "oLanguage": {
11315                         /**
11316                          * Strings that are used for WAI-ARIA labels and controls only (these are not
11317                          * actually visible on the page, but will be read by screenreaders, and thus
11318                          * must be internationalised as well).
11319                          *  @namespace
11320                          *  @name DataTable.defaults.language.aria
11321                          */
11322                         "oAria": {
11323                                 /**
11324                                  * ARIA label that is added to the table headers when the column may be
11325                                  * sorted ascending by activing the column (click or return when focused).
11326                                  * Note that the column header is prefixed to this string.
11327                                  *  @type string
11328                                  *  @default : activate to sort column ascending
11329                                  *
11330                                  *  @dtopt Language
11331                                  *  @name DataTable.defaults.language.aria.sortAscending
11332                                  *
11333                                  *  @example
11334                                  *    $(document).ready( function() {
11335                                  *      $('#example').dataTable( {
11336                                  *        "language": {
11337                                  *          "aria": {
11338                                  *            "sortAscending": " - click/return to sort ascending"
11339                                  *          }
11340                                  *        }
11341                                  *      } );
11342                                  *    } );
11343                                  */
11344                                 "sSortAscending": ": activate to sort column ascending",
11345         
11346                                 /**
11347                                  * ARIA label that is added to the table headers when the column may be
11348                                  * sorted descending by activing the column (click or return when focused).
11349                                  * Note that the column header is prefixed to this string.
11350                                  *  @type string
11351                                  *  @default : activate to sort column ascending
11352                                  *
11353                                  *  @dtopt Language
11354                                  *  @name DataTable.defaults.language.aria.sortDescending
11355                                  *
11356                                  *  @example
11357                                  *    $(document).ready( function() {
11358                                  *      $('#example').dataTable( {
11359                                  *        "language": {
11360                                  *          "aria": {
11361                                  *            "sortDescending": " - click/return to sort descending"
11362                                  *          }
11363                                  *        }
11364                                  *      } );
11365                                  *    } );
11366                                  */
11367                                 "sSortDescending": ": activate to sort column descending"
11368                         },
11369         
11370                         /**
11371                          * Pagination string used by DataTables for the built-in pagination
11372                          * control types.
11373                          *  @namespace
11374                          *  @name DataTable.defaults.language.paginate
11375                          */
11376                         "oPaginate": {
11377                                 /**
11378                                  * Text to use when using the 'full_numbers' type of pagination for the
11379                                  * button to take the user to the first page.
11380                                  *  @type string
11381                                  *  @default First
11382                                  *
11383                                  *  @dtopt Language
11384                                  *  @name DataTable.defaults.language.paginate.first
11385                                  *
11386                                  *  @example
11387                                  *    $(document).ready( function() {
11388                                  *      $('#example').dataTable( {
11389                                  *        "language": {
11390                                  *          "paginate": {
11391                                  *            "first": "First page"
11392                                  *          }
11393                                  *        }
11394                                  *      } );
11395                                  *    } );
11396                                  */
11397                                 "sFirst": "First",
11398         
11399         
11400                                 /**
11401                                  * Text to use when using the 'full_numbers' type of pagination for the
11402                                  * button to take the user to the last page.
11403                                  *  @type string
11404                                  *  @default Last
11405                                  *
11406                                  *  @dtopt Language
11407                                  *  @name DataTable.defaults.language.paginate.last
11408                                  *
11409                                  *  @example
11410                                  *    $(document).ready( function() {
11411                                  *      $('#example').dataTable( {
11412                                  *        "language": {
11413                                  *          "paginate": {
11414                                  *            "last": "Last page"
11415                                  *          }
11416                                  *        }
11417                                  *      } );
11418                                  *    } );
11419                                  */
11420                                 "sLast": "Last",
11421         
11422         
11423                                 /**
11424                                  * Text to use for the 'next' pagination button (to take the user to the
11425                                  * next page).
11426                                  *  @type string
11427                                  *  @default Next
11428                                  *
11429                                  *  @dtopt Language
11430                                  *  @name DataTable.defaults.language.paginate.next
11431                                  *
11432                                  *  @example
11433                                  *    $(document).ready( function() {
11434                                  *      $('#example').dataTable( {
11435                                  *        "language": {
11436                                  *          "paginate": {
11437                                  *            "next": "Next page"
11438                                  *          }
11439                                  *        }
11440                                  *      } );
11441                                  *    } );
11442                                  */
11443                                 "sNext": "Next",
11444         
11445         
11446                                 /**
11447                                  * Text to use for the 'previous' pagination button (to take the user to
11448                                  * the previous page).
11449                                  *  @type string
11450                                  *  @default Previous
11451                                  *
11452                                  *  @dtopt Language
11453                                  *  @name DataTable.defaults.language.paginate.previous
11454                                  *
11455                                  *  @example
11456                                  *    $(document).ready( function() {
11457                                  *      $('#example').dataTable( {
11458                                  *        "language": {
11459                                  *          "paginate": {
11460                                  *            "previous": "Previous page"
11461                                  *          }
11462                                  *        }
11463                                  *      } );
11464                                  *    } );
11465                                  */
11466                                 "sPrevious": "Previous"
11467                         },
11468         
11469                         /**
11470                          * This string is shown in preference to `zeroRecords` when the table is
11471                          * empty of data (regardless of filtering). Note that this is an optional
11472                          * parameter - if it is not given, the value of `zeroRecords` will be used
11473                          * instead (either the default or given value).
11474                          *  @type string
11475                          *  @default No data available in table
11476                          *
11477                          *  @dtopt Language
11478                          *  @name DataTable.defaults.language.emptyTable
11479                          *
11480                          *  @example
11481                          *    $(document).ready( function() {
11482                          *      $('#example').dataTable( {
11483                          *        "language": {
11484                          *          "emptyTable": "No data available in table"
11485                          *        }
11486                          *      } );
11487                          *    } );
11488                          */
11489                         "sEmptyTable": "No data available in table",
11490         
11491         
11492                         /**
11493                          * This string gives information to the end user about the information
11494                          * that is current on display on the page. The following tokens can be
11495                          * used in the string and will be dynamically replaced as the table
11496                          * display updates. This tokens can be placed anywhere in the string, or
11497                          * removed as needed by the language requires:
11498                          *
11499                          * * `\_START\_` - Display index of the first record on the current page
11500                          * * `\_END\_` - Display index of the last record on the current page
11501                          * * `\_TOTAL\_` - Number of records in the table after filtering
11502                          * * `\_MAX\_` - Number of records in the table without filtering
11503                          * * `\_PAGE\_` - Current page number
11504                          * * `\_PAGES\_` - Total number of pages of data in the table
11505                          *
11506                          *  @type string
11507                          *  @default Showing _START_ to _END_ of _TOTAL_ entries
11508                          *
11509                          *  @dtopt Language
11510                          *  @name DataTable.defaults.language.info
11511                          *
11512                          *  @example
11513                          *    $(document).ready( function() {
11514                          *      $('#example').dataTable( {
11515                          *        "language": {
11516                          *          "info": "Showing page _PAGE_ of _PAGES_"
11517                          *        }
11518                          *      } );
11519                          *    } );
11520                          */
11521                         "sInfo": "Showing _START_ to _END_ of _TOTAL_ entries",
11522         
11523         
11524                         /**
11525                          * Display information string for when the table is empty. Typically the
11526                          * format of this string should match `info`.
11527                          *  @type string
11528                          *  @default Showing 0 to 0 of 0 entries
11529                          *
11530                          *  @dtopt Language
11531                          *  @name DataTable.defaults.language.infoEmpty
11532                          *
11533                          *  @example
11534                          *    $(document).ready( function() {
11535                          *      $('#example').dataTable( {
11536                          *        "language": {
11537                          *          "infoEmpty": "No entries to show"
11538                          *        }
11539                          *      } );
11540                          *    } );
11541                          */
11542                         "sInfoEmpty": "Showing 0 to 0 of 0 entries",
11543         
11544         
11545                         /**
11546                          * When a user filters the information in a table, this string is appended
11547                          * to the information (`info`) to give an idea of how strong the filtering
11548                          * is. The variable _MAX_ is dynamically updated.
11549                          *  @type string
11550                          *  @default (filtered from _MAX_ total entries)
11551                          *
11552                          *  @dtopt Language
11553                          *  @name DataTable.defaults.language.infoFiltered
11554                          *
11555                          *  @example
11556                          *    $(document).ready( function() {
11557                          *      $('#example').dataTable( {
11558                          *        "language": {
11559                          *          "infoFiltered": " - filtering from _MAX_ records"
11560                          *        }
11561                          *      } );
11562                          *    } );
11563                          */
11564                         "sInfoFiltered": "(filtered from _MAX_ total entries)",
11565         
11566         
11567                         /**
11568                          * If can be useful to append extra information to the info string at times,
11569                          * and this variable does exactly that. This information will be appended to
11570                          * the `info` (`infoEmpty` and `infoFiltered` in whatever combination they are
11571                          * being used) at all times.
11572                          *  @type string
11573                          *  @default <i>Empty string</i>
11574                          *
11575                          *  @dtopt Language
11576                          *  @name DataTable.defaults.language.infoPostFix
11577                          *
11578                          *  @example
11579                          *    $(document).ready( function() {
11580                          *      $('#example').dataTable( {
11581                          *        "language": {
11582                          *          "infoPostFix": "All records shown are derived from real information."
11583                          *        }
11584                          *      } );
11585                          *    } );
11586                          */
11587                         "sInfoPostFix": "",
11588         
11589         
11590                         /**
11591                          * This decimal place operator is a little different from the other
11592                          * language options since DataTables doesn't output floating point
11593                          * numbers, so it won't ever use this for display of a number. Rather,
11594                          * what this parameter does is modify the sort methods of the table so
11595                          * that numbers which are in a format which has a character other than
11596                          * a period (`.`) as a decimal place will be sorted numerically.
11597                          *
11598                          * Note that numbers with different decimal places cannot be shown in
11599                          * the same table and still be sortable, the table must be consistent.
11600                          * However, multiple different tables on the page can use different
11601                          * decimal place characters.
11602                          *  @type string
11603                          *  @default 
11604                          *
11605                          *  @dtopt Language
11606                          *  @name DataTable.defaults.language.decimal
11607                          *
11608                          *  @example
11609                          *    $(document).ready( function() {
11610                          *      $('#example').dataTable( {
11611                          *        "language": {
11612                          *          "decimal": ","
11613                          *          "thousands": "."
11614                          *        }
11615                          *      } );
11616                          *    } );
11617                          */
11618                         "sDecimal": "",
11619         
11620         
11621                         /**
11622                          * DataTables has a build in number formatter (`formatNumber`) which is
11623                          * used to format large numbers that are used in the table information.
11624                          * By default a comma is used, but this can be trivially changed to any
11625                          * character you wish with this parameter.
11626                          *  @type string
11627                          *  @default ,
11628                          *
11629                          *  @dtopt Language
11630                          *  @name DataTable.defaults.language.thousands
11631                          *
11632                          *  @example
11633                          *    $(document).ready( function() {
11634                          *      $('#example').dataTable( {
11635                          *        "language": {
11636                          *          "thousands": "'"
11637                          *        }
11638                          *      } );
11639                          *    } );
11640                          */
11641                         "sThousands": ",",
11642         
11643         
11644                         /**
11645                          * Detail the action that will be taken when the drop down menu for the
11646                          * pagination length option is changed. The '_MENU_' variable is replaced
11647                          * with a default select list of 10, 25, 50 and 100, and can be replaced
11648                          * with a custom select box if required.
11649                          *  @type string
11650                          *  @default Show _MENU_ entries
11651                          *
11652                          *  @dtopt Language
11653                          *  @name DataTable.defaults.language.lengthMenu
11654                          *
11655                          *  @example
11656                          *    // Language change only
11657                          *    $(document).ready( function() {
11658                          *      $('#example').dataTable( {
11659                          *        "language": {
11660                          *          "lengthMenu": "Display _MENU_ records"
11661                          *        }
11662                          *      } );
11663                          *    } );
11664                          *
11665                          *  @example
11666                          *    // Language and options change
11667                          *    $(document).ready( function() {
11668                          *      $('#example').dataTable( {
11669                          *        "language": {
11670                          *          "lengthMenu": 'Display <select>'+
11671                          *            '<option value="10">10</option>'+
11672                          *            '<option value="20">20</option>'+
11673                          *            '<option value="30">30</option>'+
11674                          *            '<option value="40">40</option>'+
11675                          *            '<option value="50">50</option>'+
11676                          *            '<option value="-1">All</option>'+
11677                          *            '</select> records'
11678                          *        }
11679                          *      } );
11680                          *    } );
11681                          */
11682                         "sLengthMenu": "Show _MENU_ entries",
11683         
11684         
11685                         /**
11686                          * When using Ajax sourced data and during the first draw when DataTables is
11687                          * gathering the data, this message is shown in an empty row in the table to
11688                          * indicate to the end user the the data is being loaded. Note that this
11689                          * parameter is not used when loading data by server-side processing, just
11690                          * Ajax sourced data with client-side processing.
11691                          *  @type string
11692                          *  @default Loading...
11693                          *
11694                          *  @dtopt Language
11695                          *  @name DataTable.defaults.language.loadingRecords
11696                          *
11697                          *  @example
11698                          *    $(document).ready( function() {
11699                          *      $('#example').dataTable( {
11700                          *        "language": {
11701                          *          "loadingRecords": "Please wait - loading..."
11702                          *        }
11703                          *      } );
11704                          *    } );
11705                          */
11706                         "sLoadingRecords": "Loading...",
11707         
11708         
11709                         /**
11710                          * Text which is displayed when the table is processing a user action
11711                          * (usually a sort command or similar).
11712                          *  @type string
11713                          *  @default Processing...
11714                          *
11715                          *  @dtopt Language
11716                          *  @name DataTable.defaults.language.processing
11717                          *
11718                          *  @example
11719                          *    $(document).ready( function() {
11720                          *      $('#example').dataTable( {
11721                          *        "language": {
11722                          *          "processing": "DataTables is currently busy"
11723                          *        }
11724                          *      } );
11725                          *    } );
11726                          */
11727                         "sProcessing": "Processing...",
11728         
11729         
11730                         /**
11731                          * Details the actions that will be taken when the user types into the
11732                          * filtering input text box. The variable "_INPUT_", if used in the string,
11733                          * is replaced with the HTML text box for the filtering input allowing
11734                          * control over where it appears in the string. If "_INPUT_" is not given
11735                          * then the input box is appended to the string automatically.
11736                          *  @type string
11737                          *  @default Search:
11738                          *
11739                          *  @dtopt Language
11740                          *  @name DataTable.defaults.language.search
11741                          *
11742                          *  @example
11743                          *    // Input text box will be appended at the end automatically
11744                          *    $(document).ready( function() {
11745                          *      $('#example').dataTable( {
11746                          *        "language": {
11747                          *          "search": "Filter records:"
11748                          *        }
11749                          *      } );
11750                          *    } );
11751                          *
11752                          *  @example
11753                          *    // Specify where the filter should appear
11754                          *    $(document).ready( function() {
11755                          *      $('#example').dataTable( {
11756                          *        "language": {
11757                          *          "search": "Apply filter _INPUT_ to table"
11758                          *        }
11759                          *      } );
11760                          *    } );
11761                          */
11762                         "sSearch": "Search:",
11763         
11764         
11765                         /**
11766                          * Assign a `placeholder` attribute to the search `input` element
11767                          *  @type string
11768                          *  @default 
11769                          *
11770                          *  @dtopt Language
11771                          *  @name DataTable.defaults.language.searchPlaceholder
11772                          */
11773                         "sSearchPlaceholder": "",
11774         
11775         
11776                         /**
11777                          * All of the language information can be stored in a file on the
11778                          * server-side, which DataTables will look up if this parameter is passed.
11779                          * It must store the URL of the language file, which is in a JSON format,
11780                          * and the object has the same properties as the oLanguage object in the
11781                          * initialiser object (i.e. the above parameters). Please refer to one of
11782                          * the example language files to see how this works in action.
11783                          *  @type string
11784                          *  @default <i>Empty string - i.e. disabled</i>
11785                          *
11786                          *  @dtopt Language
11787                          *  @name DataTable.defaults.language.url
11788                          *
11789                          *  @example
11790                          *    $(document).ready( function() {
11791                          *      $('#example').dataTable( {
11792                          *        "language": {
11793                          *          "url": "http://www.sprymedia.co.uk/dataTables/lang.txt"
11794                          *        }
11795                          *      } );
11796                          *    } );
11797                          */
11798                         "sUrl": "",
11799         
11800         
11801                         /**
11802                          * Text shown inside the table records when the is no information to be
11803                          * displayed after filtering. `emptyTable` is shown when there is simply no
11804                          * information in the table at all (regardless of filtering).
11805                          *  @type string
11806                          *  @default No matching records found
11807                          *
11808                          *  @dtopt Language
11809                          *  @name DataTable.defaults.language.zeroRecords
11810                          *
11811                          *  @example
11812                          *    $(document).ready( function() {
11813                          *      $('#example').dataTable( {
11814                          *        "language": {
11815                          *          "zeroRecords": "No records to display"
11816                          *        }
11817                          *      } );
11818                          *    } );
11819                          */
11820                         "sZeroRecords": "No matching records found"
11821                 },
11822         
11823         
11824                 /**
11825                  * This parameter allows you to have define the global filtering state at
11826                  * initialisation time. As an object the `search` parameter must be
11827                  * defined, but all other parameters are optional. When `regex` is true,
11828                  * the search string will be treated as a regular expression, when false
11829                  * (default) it will be treated as a straight string. When `smart`
11830                  * DataTables will use it's smart filtering methods (to word match at
11831                  * any point in the data), when false this will not be done.
11832                  *  @namespace
11833                  *  @extends DataTable.models.oSearch
11834                  *
11835                  *  @dtopt Options
11836                  *  @name DataTable.defaults.search
11837                  *
11838                  *  @example
11839                  *    $(document).ready( function() {
11840                  *      $('#example').dataTable( {
11841                  *        "search": {"search": "Initial search"}
11842                  *      } );
11843                  *    } )
11844                  */
11845                 "oSearch": $.extend( {}, DataTable.models.oSearch ),
11846         
11847         
11848                 /**
11849                  * __Deprecated__ The functionality provided by this parameter has now been
11850                  * superseded by that provided through `ajax`, which should be used instead.
11851                  *
11852                  * By default DataTables will look for the property `data` (or `aaData` for
11853                  * compatibility with DataTables 1.9-) when obtaining data from an Ajax
11854                  * source or for server-side processing - this parameter allows that
11855                  * property to be changed. You can use Javascript dotted object notation to
11856                  * get a data source for multiple levels of nesting.
11857                  *  @type string
11858                  *  @default data
11859                  *
11860                  *  @dtopt Options
11861                  *  @dtopt Server-side
11862                  *  @name DataTable.defaults.ajaxDataProp
11863                  *
11864                  *  @deprecated 1.10. Please use `ajax` for this functionality now.
11865                  */
11866                 "sAjaxDataProp": "data",
11867         
11868         
11869                 /**
11870                  * __Deprecated__ The functionality provided by this parameter has now been
11871                  * superseded by that provided through `ajax`, which should be used instead.
11872                  *
11873                  * You can instruct DataTables to load data from an external
11874                  * source using this parameter (use aData if you want to pass data in you
11875                  * already have). Simply provide a url a JSON object can be obtained from.
11876                  *  @type string
11877                  *  @default null
11878                  *
11879                  *  @dtopt Options
11880                  *  @dtopt Server-side
11881                  *  @name DataTable.defaults.ajaxSource
11882                  *
11883                  *  @deprecated 1.10. Please use `ajax` for this functionality now.
11884                  */
11885                 "sAjaxSource": null,
11886         
11887         
11888                 /**
11889                  * This initialisation variable allows you to specify exactly where in the
11890                  * DOM you want DataTables to inject the various controls it adds to the page
11891                  * (for example you might want the pagination controls at the top of the
11892                  * table). DIV elements (with or without a custom class) can also be added to
11893                  * aid styling. The follow syntax is used:
11894                  *   <ul>
11895                  *     <li>The following options are allowed:
11896                  *       <ul>
11897                  *         <li>'l' - Length changing</li>
11898                  *         <li>'f' - Filtering input</li>
11899                  *         <li>'t' - The table!</li>
11900                  *         <li>'i' - Information</li>
11901                  *         <li>'p' - Pagination</li>
11902                  *         <li>'r' - pRocessing</li>
11903                  *       </ul>
11904                  *     </li>
11905                  *     <li>The following constants are allowed:
11906                  *       <ul>
11907                  *         <li>'H' - jQueryUI theme "header" classes ('fg-toolbar ui-widget-header ui-corner-tl ui-corner-tr ui-helper-clearfix')</li>
11908                  *         <li>'F' - jQueryUI theme "footer" classes ('fg-toolbar ui-widget-header ui-corner-bl ui-corner-br ui-helper-clearfix')</li>
11909                  *       </ul>
11910                  *     </li>
11911                  *     <li>The following syntax is expected:
11912                  *       <ul>
11913                  *         <li>'&lt;' and '&gt;' - div elements</li>
11914                  *         <li>'&lt;"class" and '&gt;' - div with a class</li>
11915                  *         <li>'&lt;"#id" and '&gt;' - div with an ID</li>
11916                  *       </ul>
11917                  *     </li>
11918                  *     <li>Examples:
11919                  *       <ul>
11920                  *         <li>'&lt;"wrapper"flipt&gt;'</li>
11921                  *         <li>'&lt;lf&lt;t&gt;ip&gt;'</li>
11922                  *       </ul>
11923                  *     </li>
11924                  *   </ul>
11925                  *  @type string
11926                  *  @default lfrtip <i>(when `jQueryUI` is false)</i> <b>or</b>
11927                  *    <"H"lfr>t<"F"ip> <i>(when `jQueryUI` is true)</i>
11928                  *
11929                  *  @dtopt Options
11930                  *  @name DataTable.defaults.dom
11931                  *
11932                  *  @example
11933                  *    $(document).ready( function() {
11934                  *      $('#example').dataTable( {
11935                  *        "dom": '&lt;"top"i&gt;rt&lt;"bottom"flp&gt;&lt;"clear"&gt;'
11936                  *      } );
11937                  *    } );
11938                  */
11939                 "sDom": "lfrtip",
11940         
11941         
11942                 /**
11943                  * Search delay option. This will throttle full table searches that use the
11944                  * DataTables provided search input element (it does not effect calls to
11945                  * `dt-api search()`, providing a delay before the search is made.
11946                  *  @type integer
11947                  *  @default 0
11948                  *
11949                  *  @dtopt Options
11950                  *  @name DataTable.defaults.searchDelay
11951                  *
11952                  *  @example
11953                  *    $(document).ready( function() {
11954                  *      $('#example').dataTable( {
11955                  *        "searchDelay": 200
11956                  *      } );
11957                  *    } )
11958                  */
11959                 "searchDelay": null,
11960         
11961         
11962                 /**
11963                  * DataTables features six different built-in options for the buttons to
11964                  * display for pagination control:
11965                  *
11966                  * * `numbers` - Page number buttons only
11967                  * * `simple` - 'Previous' and 'Next' buttons only
11968                  * * 'simple_numbers` - 'Previous' and 'Next' buttons, plus page numbers
11969                  * * `full` - 'First', 'Previous', 'Next' and 'Last' buttons
11970                  * * `full_numbers` - 'First', 'Previous', 'Next' and 'Last' buttons, plus page numbers
11971                  * * `first_last_numbers` - 'First' and 'Last' buttons, plus page numbers
11972                  *  
11973                  * Further methods can be added using {@link DataTable.ext.oPagination}.
11974                  *  @type string
11975                  *  @default simple_numbers
11976                  *
11977                  *  @dtopt Options
11978                  *  @name DataTable.defaults.pagingType
11979                  *
11980                  *  @example
11981                  *    $(document).ready( function() {
11982                  *      $('#example').dataTable( {
11983                  *        "pagingType": "full_numbers"
11984                  *      } );
11985                  *    } )
11986                  */
11987                 "sPaginationType": "simple_numbers",
11988         
11989         
11990                 /**
11991                  * Enable horizontal scrolling. When a table is too wide to fit into a
11992                  * certain layout, or you have a large number of columns in the table, you
11993                  * can enable x-scrolling to show the table in a viewport, which can be
11994                  * scrolled. This property can be `true` which will allow the table to
11995                  * scroll horizontally when needed, or any CSS unit, or a number (in which
11996                  * case it will be treated as a pixel measurement). Setting as simply `true`
11997                  * is recommended.
11998                  *  @type boolean|string
11999                  *  @default <i>blank string - i.e. disabled</i>
12000                  *
12001                  *  @dtopt Features
12002                  *  @name DataTable.defaults.scrollX
12003                  *
12004                  *  @example
12005                  *    $(document).ready( function() {
12006                  *      $('#example').dataTable( {
12007                  *        "scrollX": true,
12008                  *        "scrollCollapse": true
12009                  *      } );
12010                  *    } );
12011                  */
12012                 "sScrollX": "",
12013         
12014         
12015                 /**
12016                  * This property can be used to force a DataTable to use more width than it
12017                  * might otherwise do when x-scrolling is enabled. For example if you have a
12018                  * table which requires to be well spaced, this parameter is useful for
12019                  * "over-sizing" the table, and thus forcing scrolling. This property can by
12020                  * any CSS unit, or a number (in which case it will be treated as a pixel
12021                  * measurement).
12022                  *  @type string
12023                  *  @default <i>blank string - i.e. disabled</i>
12024                  *
12025                  *  @dtopt Options
12026                  *  @name DataTable.defaults.scrollXInner
12027                  *
12028                  *  @example
12029                  *    $(document).ready( function() {
12030                  *      $('#example').dataTable( {
12031                  *        "scrollX": "100%",
12032                  *        "scrollXInner": "110%"
12033                  *      } );
12034                  *    } );
12035                  */
12036                 "sScrollXInner": "",
12037         
12038         
12039                 /**
12040                  * Enable vertical scrolling. Vertical scrolling will constrain the DataTable
12041                  * to the given height, and enable scrolling for any data which overflows the
12042                  * current viewport. This can be used as an alternative to paging to display
12043                  * a lot of data in a small area (although paging and scrolling can both be
12044                  * enabled at the same time). This property can be any CSS unit, or a number
12045                  * (in which case it will be treated as a pixel measurement).
12046                  *  @type string
12047                  *  @default <i>blank string - i.e. disabled</i>
12048                  *
12049                  *  @dtopt Features
12050                  *  @name DataTable.defaults.scrollY
12051                  *
12052                  *  @example
12053                  *    $(document).ready( function() {
12054                  *      $('#example').dataTable( {
12055                  *        "scrollY": "200px",
12056                  *        "paginate": false
12057                  *      } );
12058                  *    } );
12059                  */
12060                 "sScrollY": "",
12061         
12062         
12063                 /**
12064                  * __Deprecated__ The functionality provided by this parameter has now been
12065                  * superseded by that provided through `ajax`, which should be used instead.
12066                  *
12067                  * Set the HTTP method that is used to make the Ajax call for server-side
12068                  * processing or Ajax sourced data.
12069                  *  @type string
12070                  *  @default GET
12071                  *
12072                  *  @dtopt Options
12073                  *  @dtopt Server-side
12074                  *  @name DataTable.defaults.serverMethod
12075                  *
12076                  *  @deprecated 1.10. Please use `ajax` for this functionality now.
12077                  */
12078                 "sServerMethod": "GET",
12079         
12080         
12081                 /**
12082                  * DataTables makes use of renderers when displaying HTML elements for
12083                  * a table. These renderers can be added or modified by plug-ins to
12084                  * generate suitable mark-up for a site. For example the Bootstrap
12085                  * integration plug-in for DataTables uses a paging button renderer to
12086                  * display pagination buttons in the mark-up required by Bootstrap.
12087                  *
12088                  * For further information about the renderers available see
12089                  * DataTable.ext.renderer
12090                  *  @type string|object
12091                  *  @default null
12092                  *
12093                  *  @name DataTable.defaults.renderer
12094                  *
12095                  */
12096                 "renderer": null,
12097         
12098         
12099                 /**
12100                  * Set the data property name that DataTables should use to get a row's id
12101                  * to set as the `id` property in the node.
12102                  *  @type string
12103                  *  @default DT_RowId
12104                  *
12105                  *  @name DataTable.defaults.rowId
12106                  */
12107                 "rowId": "DT_RowId"
12108         };
12109         
12110         _fnHungarianMap( DataTable.defaults );
12111         
12112         
12113         
12114         /*
12115          * Developer note - See note in model.defaults.js about the use of Hungarian
12116          * notation and camel case.
12117          */
12118         
12119         /**
12120          * Column options that can be given to DataTables at initialisation time.
12121          *  @namespace
12122          */
12123         DataTable.defaults.column = {
12124                 /**
12125                  * Define which column(s) an order will occur on for this column. This
12126                  * allows a column's ordering to take multiple columns into account when
12127                  * doing a sort or use the data from a different column. For example first
12128                  * name / last name columns make sense to do a multi-column sort over the
12129                  * two columns.
12130                  *  @type array|int
12131                  *  @default null <i>Takes the value of the column index automatically</i>
12132                  *
12133                  *  @name DataTable.defaults.column.orderData
12134                  *  @dtopt Columns
12135                  *
12136                  *  @example
12137                  *    // Using `columnDefs`
12138                  *    $(document).ready( function() {
12139                  *      $('#example').dataTable( {
12140                  *        "columnDefs": [
12141                  *          { "orderData": [ 0, 1 ], "targets": [ 0 ] },
12142                  *          { "orderData": [ 1, 0 ], "targets": [ 1 ] },
12143                  *          { "orderData": 2, "targets": [ 2 ] }
12144                  *        ]
12145                  *      } );
12146                  *    } );
12147                  *
12148                  *  @example
12149                  *    // Using `columns`
12150                  *    $(document).ready( function() {
12151                  *      $('#example').dataTable( {
12152                  *        "columns": [
12153                  *          { "orderData": [ 0, 1 ] },
12154                  *          { "orderData": [ 1, 0 ] },
12155                  *          { "orderData": 2 },
12156                  *          null,
12157                  *          null
12158                  *        ]
12159                  *      } );
12160                  *    } );
12161                  */
12162                 "aDataSort": null,
12163                 "iDataSort": -1,
12164         
12165         
12166                 /**
12167                  * You can control the default ordering direction, and even alter the
12168                  * behaviour of the sort handler (i.e. only allow ascending ordering etc)
12169                  * using this parameter.
12170                  *  @type array
12171                  *  @default [ 'asc', 'desc' ]
12172                  *
12173                  *  @name DataTable.defaults.column.orderSequence
12174                  *  @dtopt Columns
12175                  *
12176                  *  @example
12177                  *    // Using `columnDefs`
12178                  *    $(document).ready( function() {
12179                  *      $('#example').dataTable( {
12180                  *        "columnDefs": [
12181                  *          { "orderSequence": [ "asc" ], "targets": [ 1 ] },
12182                  *          { "orderSequence": [ "desc", "asc", "asc" ], "targets": [ 2 ] },
12183                  *          { "orderSequence": [ "desc" ], "targets": [ 3 ] }
12184                  *        ]
12185                  *      } );
12186                  *    } );
12187                  *
12188                  *  @example
12189                  *    // Using `columns`
12190                  *    $(document).ready( function() {
12191                  *      $('#example').dataTable( {
12192                  *        "columns": [
12193                  *          null,
12194                  *          { "orderSequence": [ "asc" ] },
12195                  *          { "orderSequence": [ "desc", "asc", "asc" ] },
12196                  *          { "orderSequence": [ "desc" ] },
12197                  *          null
12198                  *        ]
12199                  *      } );
12200                  *    } );
12201                  */
12202                 "asSorting": [ 'asc', 'desc' ],
12203         
12204         
12205                 /**
12206                  * Enable or disable filtering on the data in this column.
12207                  *  @type boolean
12208                  *  @default true
12209                  *
12210                  *  @name DataTable.defaults.column.searchable
12211                  *  @dtopt Columns
12212                  *
12213                  *  @example
12214                  *    // Using `columnDefs`
12215                  *    $(document).ready( function() {
12216                  *      $('#example').dataTable( {
12217                  *        "columnDefs": [
12218                  *          { "searchable": false, "targets": [ 0 ] }
12219                  *        ] } );
12220                  *    } );
12221                  *
12222                  *  @example
12223                  *    // Using `columns`
12224                  *    $(document).ready( function() {
12225                  *      $('#example').dataTable( {
12226                  *        "columns": [
12227                  *          { "searchable": false },
12228                  *          null,
12229                  *          null,
12230                  *          null,
12231                  *          null
12232                  *        ] } );
12233                  *    } );
12234                  */
12235                 "bSearchable": true,
12236         
12237         
12238                 /**
12239                  * Enable or disable ordering on this column.
12240                  *  @type boolean
12241                  *  @default true
12242                  *
12243                  *  @name DataTable.defaults.column.orderable
12244                  *  @dtopt Columns
12245                  *
12246                  *  @example
12247                  *    // Using `columnDefs`
12248                  *    $(document).ready( function() {
12249                  *      $('#example').dataTable( {
12250                  *        "columnDefs": [
12251                  *          { "orderable": false, "targets": [ 0 ] }
12252                  *        ] } );
12253                  *    } );
12254                  *
12255                  *  @example
12256                  *    // Using `columns`
12257                  *    $(document).ready( function() {
12258                  *      $('#example').dataTable( {
12259                  *        "columns": [
12260                  *          { "orderable": false },
12261                  *          null,
12262                  *          null,
12263                  *          null,
12264                  *          null
12265                  *        ] } );
12266                  *    } );
12267                  */
12268                 "bSortable": true,
12269         
12270         
12271                 /**
12272                  * Enable or disable the display of this column.
12273                  *  @type boolean
12274                  *  @default true
12275                  *
12276                  *  @name DataTable.defaults.column.visible
12277                  *  @dtopt Columns
12278                  *
12279                  *  @example
12280                  *    // Using `columnDefs`
12281                  *    $(document).ready( function() {
12282                  *      $('#example').dataTable( {
12283                  *        "columnDefs": [
12284                  *          { "visible": false, "targets": [ 0 ] }
12285                  *        ] } );
12286                  *    } );
12287                  *
12288                  *  @example
12289                  *    // Using `columns`
12290                  *    $(document).ready( function() {
12291                  *      $('#example').dataTable( {
12292                  *        "columns": [
12293                  *          { "visible": false },
12294                  *          null,
12295                  *          null,
12296                  *          null,
12297                  *          null
12298                  *        ] } );
12299                  *    } );
12300                  */
12301                 "bVisible": true,
12302         
12303         
12304                 /**
12305                  * Developer definable function that is called whenever a cell is created (Ajax source,
12306                  * etc) or processed for input (DOM source). This can be used as a compliment to mRender
12307                  * allowing you to modify the DOM element (add background colour for example) when the
12308                  * element is available.
12309                  *  @type function
12310                  *  @param {element} td The TD node that has been created
12311                  *  @param {*} cellData The Data for the cell
12312                  *  @param {array|object} rowData The data for the whole row
12313                  *  @param {int} row The row index for the aoData data store
12314                  *  @param {int} col The column index for aoColumns
12315                  *
12316                  *  @name DataTable.defaults.column.createdCell
12317                  *  @dtopt Columns
12318                  *
12319                  *  @example
12320                  *    $(document).ready( function() {
12321                  *      $('#example').dataTable( {
12322                  *        "columnDefs": [ {
12323                  *          "targets": [3],
12324                  *          "createdCell": function (td, cellData, rowData, row, col) {
12325                  *            if ( cellData == "1.7" ) {
12326                  *              $(td).css('color', 'blue')
12327                  *            }
12328                  *          }
12329                  *        } ]
12330                  *      });
12331                  *    } );
12332                  */
12333                 "fnCreatedCell": null,
12334         
12335         
12336                 /**
12337                  * This parameter has been replaced by `data` in DataTables to ensure naming
12338                  * consistency. `dataProp` can still be used, as there is backwards
12339                  * compatibility in DataTables for this option, but it is strongly
12340                  * recommended that you use `data` in preference to `dataProp`.
12341                  *  @name DataTable.defaults.column.dataProp
12342                  */
12343         
12344         
12345                 /**
12346                  * This property can be used to read data from any data source property,
12347                  * including deeply nested objects / properties. `data` can be given in a
12348                  * number of different ways which effect its behaviour:
12349                  *
12350                  * * `integer` - treated as an array index for the data source. This is the
12351                  *   default that DataTables uses (incrementally increased for each column).
12352                  * * `string` - read an object property from the data source. There are
12353                  *   three 'special' options that can be used in the string to alter how
12354                  *   DataTables reads the data from the source object:
12355                  *    * `.` - Dotted Javascript notation. Just as you use a `.` in
12356                  *      Javascript to read from nested objects, so to can the options
12357                  *      specified in `data`. For example: `browser.version` or
12358                  *      `browser.name`. If your object parameter name contains a period, use
12359                  *      `\\` to escape it - i.e. `first\\.name`.
12360                  *    * `[]` - Array notation. DataTables can automatically combine data
12361                  *      from and array source, joining the data with the characters provided
12362                  *      between the two brackets. For example: `name[, ]` would provide a
12363                  *      comma-space separated list from the source array. If no characters
12364                  *      are provided between the brackets, the original array source is
12365                  *      returned.
12366                  *    * `()` - Function notation. Adding `()` to the end of a parameter will
12367                  *      execute a function of the name given. For example: `browser()` for a
12368                  *      simple function on the data source, `browser.version()` for a
12369                  *      function in a nested property or even `browser().version` to get an
12370                  *      object property if the function called returns an object. Note that
12371                  *      function notation is recommended for use in `render` rather than
12372                  *      `data` as it is much simpler to use as a renderer.
12373                  * * `null` - use the original data source for the row rather than plucking
12374                  *   data directly from it. This action has effects on two other
12375                  *   initialisation options:
12376                  *    * `defaultContent` - When null is given as the `data` option and
12377                  *      `defaultContent` is specified for the column, the value defined by
12378                  *      `defaultContent` will be used for the cell.
12379                  *    * `render` - When null is used for the `data` option and the `render`
12380                  *      option is specified for the column, the whole data source for the
12381                  *      row is used for the renderer.
12382                  * * `function` - the function given will be executed whenever DataTables
12383                  *   needs to set or get the data for a cell in the column. The function
12384                  *   takes three parameters:
12385                  *    * Parameters:
12386                  *      * `{array|object}` The data source for the row
12387                  *      * `{string}` The type call data requested - this will be 'set' when
12388                  *        setting data or 'filter', 'display', 'type', 'sort' or undefined
12389                  *        when gathering data. Note that when `undefined` is given for the
12390                  *        type DataTables expects to get the raw data for the object back<
12391                  *      * `{*}` Data to set when the second parameter is 'set'.
12392                  *    * Return:
12393                  *      * The return value from the function is not required when 'set' is
12394                  *        the type of call, but otherwise the return is what will be used
12395                  *        for the data requested.
12396                  *
12397                  * Note that `data` is a getter and setter option. If you just require
12398                  * formatting of data for output, you will likely want to use `render` which
12399                  * is simply a getter and thus simpler to use.
12400                  *
12401                  * Note that prior to DataTables 1.9.2 `data` was called `mDataProp`. The
12402                  * name change reflects the flexibility of this property and is consistent
12403                  * with the naming of mRender. If 'mDataProp' is given, then it will still
12404                  * be used by DataTables, as it automatically maps the old name to the new
12405                  * if required.
12406                  *
12407                  *  @type string|int|function|null
12408                  *  @default null <i>Use automatically calculated column index</i>
12409                  *
12410                  *  @name DataTable.defaults.column.data
12411                  *  @dtopt Columns
12412                  *
12413                  *  @example
12414                  *    // Read table data from objects
12415                  *    // JSON structure for each row:
12416                  *    //   {
12417                  *    //      "engine": {value},
12418                  *    //      "browser": {value},
12419                  *    //      "platform": {value},
12420                  *    //      "version": {value},
12421                  *    //      "grade": {value}
12422                  *    //   }
12423                  *    $(document).ready( function() {
12424                  *      $('#example').dataTable( {
12425                  *        "ajaxSource": "sources/objects.txt",
12426                  *        "columns": [
12427                  *          { "data": "engine" },
12428                  *          { "data": "browser" },
12429                  *          { "data": "platform" },
12430                  *          { "data": "version" },
12431                  *          { "data": "grade" }
12432                  *        ]
12433                  *      } );
12434                  *    } );
12435                  *
12436                  *  @example
12437                  *    // Read information from deeply nested objects
12438                  *    // JSON structure for each row:
12439                  *    //   {
12440                  *    //      "engine": {value},
12441                  *    //      "browser": {value},
12442                  *    //      "platform": {
12443                  *    //         "inner": {value}
12444                  *    //      },
12445                  *    //      "details": [
12446                  *    //         {value}, {value}
12447                  *    //      ]
12448                  *    //   }
12449                  *    $(document).ready( function() {
12450                  *      $('#example').dataTable( {
12451                  *        "ajaxSource": "sources/deep.txt",
12452                  *        "columns": [
12453                  *          { "data": "engine" },
12454                  *          { "data": "browser" },
12455                  *          { "data": "platform.inner" },
12456                  *          { "data": "details.0" },
12457                  *          { "data": "details.1" }
12458                  *        ]
12459                  *      } );
12460                  *    } );
12461                  *
12462                  *  @example
12463                  *    // Using `data` as a function to provide different information for
12464                  *    // sorting, filtering and display. In this case, currency (price)
12465                  *    $(document).ready( function() {
12466                  *      $('#example').dataTable( {
12467                  *        "columnDefs": [ {
12468                  *          "targets": [ 0 ],
12469                  *          "data": function ( source, type, val ) {
12470                  *            if (type === 'set') {
12471                  *              source.price = val;
12472                  *              // Store the computed dislay and filter values for efficiency
12473                  *              source.price_display = val=="" ? "" : "$"+numberFormat(val);
12474                  *              source.price_filter  = val=="" ? "" : "$"+numberFormat(val)+" "+val;
12475                  *              return;
12476                  *            }
12477                  *            else if (type === 'display') {
12478                  *              return source.price_display;
12479                  *            }
12480                  *            else if (type === 'filter') {
12481                  *              return source.price_filter;
12482                  *            }
12483                  *            // 'sort', 'type' and undefined all just use the integer
12484                  *            return source.price;
12485                  *          }
12486                  *        } ]
12487                  *      } );
12488                  *    } );
12489                  *
12490                  *  @example
12491                  *    // Using default content
12492                  *    $(document).ready( function() {
12493                  *      $('#example').dataTable( {
12494                  *        "columnDefs": [ {
12495                  *          "targets": [ 0 ],
12496                  *          "data": null,
12497                  *          "defaultContent": "Click to edit"
12498                  *        } ]
12499                  *      } );
12500                  *    } );
12501                  *
12502                  *  @example
12503                  *    // Using array notation - outputting a list from an array
12504                  *    $(document).ready( function() {
12505                  *      $('#example').dataTable( {
12506                  *        "columnDefs": [ {
12507                  *          "targets": [ 0 ],
12508                  *          "data": "name[, ]"
12509                  *        } ]
12510                  *      } );
12511                  *    } );
12512                  *
12513                  */
12514                 "mData": null,
12515         
12516         
12517                 /**
12518                  * This property is the rendering partner to `data` and it is suggested that
12519                  * when you want to manipulate data for display (including filtering,
12520                  * sorting etc) without altering the underlying data for the table, use this
12521                  * property. `render` can be considered to be the the read only companion to
12522                  * `data` which is read / write (then as such more complex). Like `data`
12523                  * this option can be given in a number of different ways to effect its
12524                  * behaviour:
12525                  *
12526                  * * `integer` - treated as an array index for the data source. This is the
12527                  *   default that DataTables uses (incrementally increased for each column).
12528                  * * `string` - read an object property from the data source. There are
12529                  *   three 'special' options that can be used in the string to alter how
12530                  *   DataTables reads the data from the source object:
12531                  *    * `.` - Dotted Javascript notation. Just as you use a `.` in
12532                  *      Javascript to read from nested objects, so to can the options
12533                  *      specified in `data`. For example: `browser.version` or
12534                  *      `browser.name`. If your object parameter name contains a period, use
12535                  *      `\\` to escape it - i.e. `first\\.name`.
12536                  *    * `[]` - Array notation. DataTables can automatically combine data
12537                  *      from and array source, joining the data with the characters provided
12538                  *      between the two brackets. For example: `name[, ]` would provide a
12539                  *      comma-space separated list from the source array. If no characters
12540                  *      are provided between the brackets, the original array source is
12541                  *      returned.
12542                  *    * `()` - Function notation. Adding `()` to the end of a parameter will
12543                  *      execute a function of the name given. For example: `browser()` for a
12544                  *      simple function on the data source, `browser.version()` for a
12545                  *      function in a nested property or even `browser().version` to get an
12546                  *      object property if the function called returns an object.
12547                  * * `object` - use different data for the different data types requested by
12548                  *   DataTables ('filter', 'display', 'type' or 'sort'). The property names
12549                  *   of the object is the data type the property refers to and the value can
12550                  *   defined using an integer, string or function using the same rules as
12551                  *   `render` normally does. Note that an `_` option _must_ be specified.
12552                  *   This is the default value to use if you haven't specified a value for
12553                  *   the data type requested by DataTables.
12554                  * * `function` - the function given will be executed whenever DataTables
12555                  *   needs to set or get the data for a cell in the column. The function
12556                  *   takes three parameters:
12557                  *    * Parameters:
12558                  *      * {array|object} The data source for the row (based on `data`)
12559                  *      * {string} The type call data requested - this will be 'filter',
12560                  *        'display', 'type' or 'sort'.
12561                  *      * {array|object} The full data source for the row (not based on
12562                  *        `data`)
12563                  *    * Return:
12564                  *      * The return value from the function is what will be used for the
12565                  *        data requested.
12566                  *
12567                  *  @type string|int|function|object|null
12568                  *  @default null Use the data source value.
12569                  *
12570                  *  @name DataTable.defaults.column.render
12571                  *  @dtopt Columns
12572                  *
12573                  *  @example
12574                  *    // Create a comma separated list from an array of objects
12575                  *    $(document).ready( function() {
12576                  *      $('#example').dataTable( {
12577                  *        "ajaxSource": "sources/deep.txt",
12578                  *        "columns": [
12579                  *          { "data": "engine" },
12580                  *          { "data": "browser" },
12581                  *          {
12582                  *            "data": "platform",
12583                  *            "render": "[, ].name"
12584                  *          }
12585                  *        ]
12586                  *      } );
12587                  *    } );
12588                  *
12589                  *  @example
12590                  *    // Execute a function to obtain data
12591                  *    $(document).ready( function() {
12592                  *      $('#example').dataTable( {
12593                  *        "columnDefs": [ {
12594                  *          "targets": [ 0 ],
12595                  *          "data": null, // Use the full data source object for the renderer's source
12596                  *          "render": "browserName()"
12597                  *        } ]
12598                  *      } );
12599                  *    } );
12600                  *
12601                  *  @example
12602                  *    // As an object, extracting different data for the different types
12603                  *    // This would be used with a data source such as:
12604                  *    //   { "phone": 5552368, "phone_filter": "5552368 555-2368", "phone_display": "555-2368" }
12605                  *    // Here the `phone` integer is used for sorting and type detection, while `phone_filter`
12606                  *    // (which has both forms) is used for filtering for if a user inputs either format, while
12607                  *    // the formatted phone number is the one that is shown in the table.
12608                  *    $(document).ready( function() {
12609                  *      $('#example').dataTable( {
12610                  *        "columnDefs": [ {
12611                  *          "targets": [ 0 ],
12612                  *          "data": null, // Use the full data source object for the renderer's source
12613                  *          "render": {
12614                  *            "_": "phone",
12615                  *            "filter": "phone_filter",
12616                  *            "display": "phone_display"
12617                  *          }
12618                  *        } ]
12619                  *      } );
12620                  *    } );
12621                  *
12622                  *  @example
12623                  *    // Use as a function to create a link from the data source
12624                  *    $(document).ready( function() {
12625                  *      $('#example').dataTable( {
12626                  *        "columnDefs": [ {
12627                  *          "targets": [ 0 ],
12628                  *          "data": "download_link",
12629                  *          "render": function ( data, type, full ) {
12630                  *            return '<a href="'+data+'">Download</a>';
12631                  *          }
12632                  *        } ]
12633                  *      } );
12634                  *    } );
12635                  */
12636                 "mRender": null,
12637         
12638         
12639                 /**
12640                  * Change the cell type created for the column - either TD cells or TH cells. This
12641                  * can be useful as TH cells have semantic meaning in the table body, allowing them
12642                  * to act as a header for a row (you may wish to add scope='row' to the TH elements).
12643                  *  @type string
12644                  *  @default td
12645                  *
12646                  *  @name DataTable.defaults.column.cellType
12647                  *  @dtopt Columns
12648                  *
12649                  *  @example
12650                  *    // Make the first column use TH cells
12651                  *    $(document).ready( function() {
12652                  *      $('#example').dataTable( {
12653                  *        "columnDefs": [ {
12654                  *          "targets": [ 0 ],
12655                  *          "cellType": "th"
12656                  *        } ]
12657                  *      } );
12658                  *    } );
12659                  */
12660                 "sCellType": "td",
12661         
12662         
12663                 /**
12664                  * Class to give to each cell in this column.
12665                  *  @type string
12666                  *  @default <i>Empty string</i>
12667                  *
12668                  *  @name DataTable.defaults.column.class
12669                  *  @dtopt Columns
12670                  *
12671                  *  @example
12672                  *    // Using `columnDefs`
12673                  *    $(document).ready( function() {
12674                  *      $('#example').dataTable( {
12675                  *        "columnDefs": [
12676                  *          { "class": "my_class", "targets": [ 0 ] }
12677                  *        ]
12678                  *      } );
12679                  *    } );
12680                  *
12681                  *  @example
12682                  *    // Using `columns`
12683                  *    $(document).ready( function() {
12684                  *      $('#example').dataTable( {
12685                  *        "columns": [
12686                  *          { "class": "my_class" },
12687                  *          null,
12688                  *          null,
12689                  *          null,
12690                  *          null
12691                  *        ]
12692                  *      } );
12693                  *    } );
12694                  */
12695                 "sClass": "",
12696         
12697                 /**
12698                  * When DataTables calculates the column widths to assign to each column,
12699                  * it finds the longest string in each column and then constructs a
12700                  * temporary table and reads the widths from that. The problem with this
12701                  * is that "mmm" is much wider then "iiii", but the latter is a longer
12702                  * string - thus the calculation can go wrong (doing it properly and putting
12703                  * it into an DOM object and measuring that is horribly(!) slow). Thus as
12704                  * a "work around" we provide this option. It will append its value to the
12705                  * text that is found to be the longest string for the column - i.e. padding.
12706                  * Generally you shouldn't need this!
12707                  *  @type string
12708                  *  @default <i>Empty string<i>
12709                  *
12710                  *  @name DataTable.defaults.column.contentPadding
12711                  *  @dtopt Columns
12712                  *
12713                  *  @example
12714                  *    // Using `columns`
12715                  *    $(document).ready( function() {
12716                  *      $('#example').dataTable( {
12717                  *        "columns": [
12718                  *          null,
12719                  *          null,
12720                  *          null,
12721                  *          {
12722                  *            "contentPadding": "mmm"
12723                  *          }
12724                  *        ]
12725                  *      } );
12726                  *    } );
12727                  */
12728                 "sContentPadding": "",
12729         
12730         
12731                 /**
12732                  * Allows a default value to be given for a column's data, and will be used
12733                  * whenever a null data source is encountered (this can be because `data`
12734                  * is set to null, or because the data source itself is null).
12735                  *  @type string
12736                  *  @default null
12737                  *
12738                  *  @name DataTable.defaults.column.defaultContent
12739                  *  @dtopt Columns
12740                  *
12741                  *  @example
12742                  *    // Using `columnDefs`
12743                  *    $(document).ready( function() {
12744                  *      $('#example').dataTable( {
12745                  *        "columnDefs": [
12746                  *          {
12747                  *            "data": null,
12748                  *            "defaultContent": "Edit",
12749                  *            "targets": [ -1 ]
12750                  *          }
12751                  *        ]
12752                  *      } );
12753                  *    } );
12754                  *
12755                  *  @example
12756                  *    // Using `columns`
12757                  *    $(document).ready( function() {
12758                  *      $('#example').dataTable( {
12759                  *        "columns": [
12760                  *          null,
12761                  *          null,
12762                  *          null,
12763                  *          {
12764                  *            "data": null,
12765                  *            "defaultContent": "Edit"
12766                  *          }
12767                  *        ]
12768                  *      } );
12769                  *    } );
12770                  */
12771                 "sDefaultContent": null,
12772         
12773         
12774                 /**
12775                  * This parameter is only used in DataTables' server-side processing. It can
12776                  * be exceptionally useful to know what columns are being displayed on the
12777                  * client side, and to map these to database fields. When defined, the names
12778                  * also allow DataTables to reorder information from the server if it comes
12779                  * back in an unexpected order (i.e. if you switch your columns around on the
12780                  * client-side, your server-side code does not also need updating).
12781                  *  @type string
12782                  *  @default <i>Empty string</i>
12783                  *
12784                  *  @name DataTable.defaults.column.name
12785                  *  @dtopt Columns
12786                  *
12787                  *  @example
12788                  *    // Using `columnDefs`
12789                  *    $(document).ready( function() {
12790                  *      $('#example').dataTable( {
12791                  *        "columnDefs": [
12792                  *          { "name": "engine", "targets": [ 0 ] },
12793                  *          { "name": "browser", "targets": [ 1 ] },
12794                  *          { "name": "platform", "targets": [ 2 ] },
12795                  *          { "name": "version", "targets": [ 3 ] },
12796                  *          { "name": "grade", "targets": [ 4 ] }
12797                  *        ]
12798                  *      } );
12799                  *    } );
12800                  *
12801                  *  @example
12802                  *    // Using `columns`
12803                  *    $(document).ready( function() {
12804                  *      $('#example').dataTable( {
12805                  *        "columns": [
12806                  *          { "name": "engine" },
12807                  *          { "name": "browser" },
12808                  *          { "name": "platform" },
12809                  *          { "name": "version" },
12810                  *          { "name": "grade" }
12811                  *        ]
12812                  *      } );
12813                  *    } );
12814                  */
12815                 "sName": "",
12816         
12817         
12818                 /**
12819                  * Defines a data source type for the ordering which can be used to read
12820                  * real-time information from the table (updating the internally cached
12821                  * version) prior to ordering. This allows ordering to occur on user
12822                  * editable elements such as form inputs.
12823                  *  @type string
12824                  *  @default std
12825                  *
12826                  *  @name DataTable.defaults.column.orderDataType
12827                  *  @dtopt Columns
12828                  *
12829                  *  @example
12830                  *    // Using `columnDefs`
12831                  *    $(document).ready( function() {
12832                  *      $('#example').dataTable( {
12833                  *        "columnDefs": [
12834                  *          { "orderDataType": "dom-text", "targets": [ 2, 3 ] },
12835                  *          { "type": "numeric", "targets": [ 3 ] },
12836                  *          { "orderDataType": "dom-select", "targets": [ 4 ] },
12837                  *          { "orderDataType": "dom-checkbox", "targets": [ 5 ] }
12838                  *        ]
12839                  *      } );
12840                  *    } );
12841                  *
12842                  *  @example
12843                  *    // Using `columns`
12844                  *    $(document).ready( function() {
12845                  *      $('#example').dataTable( {
12846                  *        "columns": [
12847                  *          null,
12848                  *          null,
12849                  *          { "orderDataType": "dom-text" },
12850                  *          { "orderDataType": "dom-text", "type": "numeric" },
12851                  *          { "orderDataType": "dom-select" },
12852                  *          { "orderDataType": "dom-checkbox" }
12853                  *        ]
12854                  *      } );
12855                  *    } );
12856                  */
12857                 "sSortDataType": "std",
12858         
12859         
12860                 /**
12861                  * The title of this column.
12862                  *  @type string
12863                  *  @default null <i>Derived from the 'TH' value for this column in the
12864                  *    original HTML table.</i>
12865                  *
12866                  *  @name DataTable.defaults.column.title
12867                  *  @dtopt Columns
12868                  *
12869                  *  @example
12870                  *    // Using `columnDefs`
12871                  *    $(document).ready( function() {
12872                  *      $('#example').dataTable( {
12873                  *        "columnDefs": [
12874                  *          { "title": "My column title", "targets": [ 0 ] }
12875                  *        ]
12876                  *      } );
12877                  *    } );
12878                  *
12879                  *  @example
12880                  *    // Using `columns`
12881                  *    $(document).ready( function() {
12882                  *      $('#example').dataTable( {
12883                  *        "columns": [
12884                  *          { "title": "My column title" },
12885                  *          null,
12886                  *          null,
12887                  *          null,
12888                  *          null
12889                  *        ]
12890                  *      } );
12891                  *    } );
12892                  */
12893                 "sTitle": null,
12894         
12895         
12896                 /**
12897                  * The type allows you to specify how the data for this column will be
12898                  * ordered. Four types (string, numeric, date and html (which will strip
12899                  * HTML tags before ordering)) are currently available. Note that only date
12900                  * formats understood by Javascript's Date() object will be accepted as type
12901                  * date. For example: "Mar 26, 2008 5:03 PM". May take the values: 'string',
12902                  * 'numeric', 'date' or 'html' (by default). Further types can be adding
12903                  * through plug-ins.
12904                  *  @type string
12905                  *  @default null <i>Auto-detected from raw data</i>
12906                  *
12907                  *  @name DataTable.defaults.column.type
12908                  *  @dtopt Columns
12909                  *
12910                  *  @example
12911                  *    // Using `columnDefs`
12912                  *    $(document).ready( function() {
12913                  *      $('#example').dataTable( {
12914                  *        "columnDefs": [
12915                  *          { "type": "html", "targets": [ 0 ] }
12916                  *        ]
12917                  *      } );
12918                  *    } );
12919                  *
12920                  *  @example
12921                  *    // Using `columns`
12922                  *    $(document).ready( function() {
12923                  *      $('#example').dataTable( {
12924                  *        "columns": [
12925                  *          { "type": "html" },
12926                  *          null,
12927                  *          null,
12928                  *          null,
12929                  *          null
12930                  *        ]
12931                  *      } );
12932                  *    } );
12933                  */
12934                 "sType": null,
12935         
12936         
12937                 /**
12938                  * Defining the width of the column, this parameter may take any CSS value
12939                  * (3em, 20px etc). DataTables applies 'smart' widths to columns which have not
12940                  * been given a specific width through this interface ensuring that the table
12941                  * remains readable.
12942                  *  @type string
12943                  *  @default null <i>Automatic</i>
12944                  *
12945                  *  @name DataTable.defaults.column.width
12946                  *  @dtopt Columns
12947                  *
12948                  *  @example
12949                  *    // Using `columnDefs`
12950                  *    $(document).ready( function() {
12951                  *      $('#example').dataTable( {
12952                  *        "columnDefs": [
12953                  *          { "width": "20%", "targets": [ 0 ] }
12954                  *        ]
12955                  *      } );
12956                  *    } );
12957                  *
12958                  *  @example
12959                  *    // Using `columns`
12960                  *    $(document).ready( function() {
12961                  *      $('#example').dataTable( {
12962                  *        "columns": [
12963                  *          { "width": "20%" },
12964                  *          null,
12965                  *          null,
12966                  *          null,
12967                  *          null
12968                  *        ]
12969                  *      } );
12970                  *    } );
12971                  */
12972                 "sWidth": null
12973         };
12974         
12975         _fnHungarianMap( DataTable.defaults.column );
12976         
12977         
12978         
12979         /**
12980          * DataTables settings object - this holds all the information needed for a
12981          * given table, including configuration, data and current application of the
12982          * table options. DataTables does not have a single instance for each DataTable
12983          * with the settings attached to that instance, but rather instances of the
12984          * DataTable "class" are created on-the-fly as needed (typically by a
12985          * $().dataTable() call) and the settings object is then applied to that
12986          * instance.
12987          *
12988          * Note that this object is related to {@link DataTable.defaults} but this
12989          * one is the internal data store for DataTables's cache of columns. It should
12990          * NOT be manipulated outside of DataTables. Any configuration should be done
12991          * through the initialisation options.
12992          *  @namespace
12993          *  @todo Really should attach the settings object to individual instances so we
12994          *    don't need to create new instances on each $().dataTable() call (if the
12995          *    table already exists). It would also save passing oSettings around and
12996          *    into every single function. However, this is a very significant
12997          *    architecture change for DataTables and will almost certainly break
12998          *    backwards compatibility with older installations. This is something that
12999          *    will be done in 2.0.
13000          */
13001         DataTable.models.oSettings = {
13002                 /**
13003                  * Primary features of DataTables and their enablement state.
13004                  *  @namespace
13005                  */
13006                 "oFeatures": {
13007         
13008                         /**
13009                          * Flag to say if DataTables should automatically try to calculate the
13010                          * optimum table and columns widths (true) or not (false).
13011                          * Note that this parameter will be set by the initialisation routine. To
13012                          * set a default use {@link DataTable.defaults}.
13013                          *  @type boolean
13014                          */
13015                         "bAutoWidth": null,
13016         
13017                         /**
13018                          * Delay the creation of TR and TD elements until they are actually
13019                          * needed by a driven page draw. This can give a significant speed
13020                          * increase for Ajax source and Javascript source data, but makes no
13021                          * difference at all fro DOM and server-side processing tables.
13022                          * Note that this parameter will be set by the initialisation routine. To
13023                          * set a default use {@link DataTable.defaults}.
13024                          *  @type boolean
13025                          */
13026                         "bDeferRender": null,
13027         
13028                         /**
13029                          * Enable filtering on the table or not. Note that if this is disabled
13030                          * then there is no filtering at all on the table, including fnFilter.
13031                          * To just remove the filtering input use sDom and remove the 'f' option.
13032                          * Note that this parameter will be set by the initialisation routine. To
13033                          * set a default use {@link DataTable.defaults}.
13034                          *  @type boolean
13035                          */
13036                         "bFilter": null,
13037         
13038                         /**
13039                          * Table information element (the 'Showing x of y records' div) enable
13040                          * flag.
13041                          * Note that this parameter will be set by the initialisation routine. To
13042                          * set a default use {@link DataTable.defaults}.
13043                          *  @type boolean
13044                          */
13045                         "bInfo": null,
13046         
13047                         /**
13048                          * Present a user control allowing the end user to change the page size
13049                          * when pagination is enabled.
13050                          * Note that this parameter will be set by the initialisation routine. To
13051                          * set a default use {@link DataTable.defaults}.
13052                          *  @type boolean
13053                          */
13054                         "bLengthChange": null,
13055         
13056                         /**
13057                          * Pagination enabled or not. Note that if this is disabled then length
13058                          * changing must also be disabled.
13059                          * Note that this parameter will be set by the initialisation routine. To
13060                          * set a default use {@link DataTable.defaults}.
13061                          *  @type boolean
13062                          */
13063                         "bPaginate": null,
13064         
13065                         /**
13066                          * Processing indicator enable flag whenever DataTables is enacting a
13067                          * user request - typically an Ajax request for server-side processing.
13068                          * Note that this parameter will be set by the initialisation routine. To
13069                          * set a default use {@link DataTable.defaults}.
13070                          *  @type boolean
13071                          */
13072                         "bProcessing": null,
13073         
13074                         /**
13075                          * Server-side processing enabled flag - when enabled DataTables will
13076                          * get all data from the server for every draw - there is no filtering,
13077                          * sorting or paging done on the client-side.
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                         "bServerSide": null,
13083         
13084                         /**
13085                          * Sorting enablement flag.
13086                          * Note that this parameter will be set by the initialisation routine. To
13087                          * set a default use {@link DataTable.defaults}.
13088                          *  @type boolean
13089                          */
13090                         "bSort": null,
13091         
13092                         /**
13093                          * Multi-column sorting
13094                          * Note that this parameter will be set by the initialisation routine. To
13095                          * set a default use {@link DataTable.defaults}.
13096                          *  @type boolean
13097                          */
13098                         "bSortMulti": null,
13099         
13100                         /**
13101                          * Apply a class to the columns which are being sorted to provide a
13102                          * visual highlight or not. This can slow things down when enabled since
13103                          * there is a lot of DOM interaction.
13104                          * Note that this parameter will be set by the initialisation routine. To
13105                          * set a default use {@link DataTable.defaults}.
13106                          *  @type boolean
13107                          */
13108                         "bSortClasses": null,
13109         
13110                         /**
13111                          * State saving enablement flag.
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                         "bStateSave": null
13117                 },
13118         
13119         
13120                 /**
13121                  * Scrolling settings for a table.
13122                  *  @namespace
13123                  */
13124                 "oScroll": {
13125                         /**
13126                          * When the table is shorter in height than sScrollY, collapse the
13127                          * table container down to the height of the table (when true).
13128                          * Note that this parameter will be set by the initialisation routine. To
13129                          * set a default use {@link DataTable.defaults}.
13130                          *  @type boolean
13131                          */
13132                         "bCollapse": null,
13133         
13134                         /**
13135                          * Width of the scrollbar for the web-browser's platform. Calculated
13136                          * during table initialisation.
13137                          *  @type int
13138                          *  @default 0
13139                          */
13140                         "iBarWidth": 0,
13141         
13142                         /**
13143                          * Viewport width for horizontal scrolling. Horizontal scrolling is
13144                          * disabled if an empty string.
13145                          * Note that this parameter will be set by the initialisation routine. To
13146                          * set a default use {@link DataTable.defaults}.
13147                          *  @type string
13148                          */
13149                         "sX": null,
13150         
13151                         /**
13152                          * Width to expand the table to when using x-scrolling. Typically you
13153                          * should not need to use this.
13154                          * Note that this parameter will be set by the initialisation routine. To
13155                          * set a default use {@link DataTable.defaults}.
13156                          *  @type string
13157                          *  @deprecated
13158                          */
13159                         "sXInner": null,
13160         
13161                         /**
13162                          * Viewport height for vertical scrolling. Vertical scrolling is disabled
13163                          * if an empty string.
13164                          * Note that this parameter will be set by the initialisation routine. To
13165                          * set a default use {@link DataTable.defaults}.
13166                          *  @type string
13167                          */
13168                         "sY": null
13169                 },
13170         
13171                 /**
13172                  * Language information for the table.
13173                  *  @namespace
13174                  *  @extends DataTable.defaults.oLanguage
13175                  */
13176                 "oLanguage": {
13177                         /**
13178                          * Information callback function. See
13179                          * {@link DataTable.defaults.fnInfoCallback}
13180                          *  @type function
13181                          *  @default null
13182                          */
13183                         "fnInfoCallback": null
13184                 },
13185         
13186                 /**
13187                  * Browser support parameters
13188                  *  @namespace
13189                  */
13190                 "oBrowser": {
13191                         /**
13192                          * Indicate if the browser incorrectly calculates width:100% inside a
13193                          * scrolling element (IE6/7)
13194                          *  @type boolean
13195                          *  @default false
13196                          */
13197                         "bScrollOversize": false,
13198         
13199                         /**
13200                          * Determine if the vertical scrollbar is on the right or left of the
13201                          * scrolling container - needed for rtl language layout, although not
13202                          * all browsers move the scrollbar (Safari).
13203                          *  @type boolean
13204                          *  @default false
13205                          */
13206                         "bScrollbarLeft": false,
13207         
13208                         /**
13209                          * Flag for if `getBoundingClientRect` is fully supported or not
13210                          *  @type boolean
13211                          *  @default false
13212                          */
13213                         "bBounding": false,
13214         
13215                         /**
13216                          * Browser scrollbar width
13217                          *  @type integer
13218                          *  @default 0
13219                          */
13220                         "barWidth": 0
13221                 },
13222         
13223         
13224                 "ajax": null,
13225         
13226         
13227                 /**
13228                  * Array referencing the nodes which are used for the features. The
13229                  * parameters of this object match what is allowed by sDom - i.e.
13230                  *   <ul>
13231                  *     <li>'l' - Length changing</li>
13232                  *     <li>'f' - Filtering input</li>
13233                  *     <li>'t' - The table!</li>
13234                  *     <li>'i' - Information</li>
13235                  *     <li>'p' - Pagination</li>
13236                  *     <li>'r' - pRocessing</li>
13237                  *   </ul>
13238                  *  @type array
13239                  *  @default []
13240                  */
13241                 "aanFeatures": [],
13242         
13243                 /**
13244                  * Store data information - see {@link DataTable.models.oRow} for detailed
13245                  * information.
13246                  *  @type array
13247                  *  @default []
13248                  */
13249                 "aoData": [],
13250         
13251                 /**
13252                  * Array of indexes which are in the current display (after filtering etc)
13253                  *  @type array
13254                  *  @default []
13255                  */
13256                 "aiDisplay": [],
13257         
13258                 /**
13259                  * Array of indexes for display - no filtering
13260                  *  @type array
13261                  *  @default []
13262                  */
13263                 "aiDisplayMaster": [],
13264         
13265                 /**
13266                  * Map of row ids to data indexes
13267                  *  @type object
13268                  *  @default {}
13269                  */
13270                 "aIds": {},
13271         
13272                 /**
13273                  * Store information about each column that is in use
13274                  *  @type array
13275                  *  @default []
13276                  */
13277                 "aoColumns": [],
13278         
13279                 /**
13280                  * Store information about the table's header
13281                  *  @type array
13282                  *  @default []
13283                  */
13284                 "aoHeader": [],
13285         
13286                 /**
13287                  * Store information about the table's footer
13288                  *  @type array
13289                  *  @default []
13290                  */
13291                 "aoFooter": [],
13292         
13293                 /**
13294                  * Store the applied global search information in case we want to force a
13295                  * research or compare the old search to a new one.
13296                  * Note that this parameter will be set by the initialisation routine. To
13297                  * set a default use {@link DataTable.defaults}.
13298                  *  @namespace
13299                  *  @extends DataTable.models.oSearch
13300                  */
13301                 "oPreviousSearch": {},
13302         
13303                 /**
13304                  * Store the applied search for each column - see
13305                  * {@link DataTable.models.oSearch} for the format that is used for the
13306                  * filtering information for each column.
13307                  *  @type array
13308                  *  @default []
13309                  */
13310                 "aoPreSearchCols": [],
13311         
13312                 /**
13313                  * Sorting that is applied to the table. Note that the inner arrays are
13314                  * used in the following manner:
13315                  * <ul>
13316                  *   <li>Index 0 - column number</li>
13317                  *   <li>Index 1 - current sorting direction</li>
13318                  * </ul>
13319                  * Note that this parameter will be set by the initialisation routine. To
13320                  * set a default use {@link DataTable.defaults}.
13321                  *  @type array
13322                  *  @todo These inner arrays should really be objects
13323                  */
13324                 "aaSorting": null,
13325         
13326                 /**
13327                  * Sorting that is always applied to the table (i.e. prefixed in front of
13328                  * aaSorting).
13329                  * Note that this parameter will be set by the initialisation routine. To
13330                  * set a default use {@link DataTable.defaults}.
13331                  *  @type array
13332                  *  @default []
13333                  */
13334                 "aaSortingFixed": [],
13335         
13336                 /**
13337                  * Classes to use for the striping of a table.
13338                  * Note that this parameter will be set by the initialisation routine. To
13339                  * set a default use {@link DataTable.defaults}.
13340                  *  @type array
13341                  *  @default []
13342                  */
13343                 "asStripeClasses": null,
13344         
13345                 /**
13346                  * If restoring a table - we should restore its striping classes as well
13347                  *  @type array
13348                  *  @default []
13349                  */
13350                 "asDestroyStripes": [],
13351         
13352                 /**
13353                  * If restoring a table - we should restore its width
13354                  *  @type int
13355                  *  @default 0
13356                  */
13357                 "sDestroyWidth": 0,
13358         
13359                 /**
13360                  * Callback functions array for every time a row is inserted (i.e. on a draw).
13361                  *  @type array
13362                  *  @default []
13363                  */
13364                 "aoRowCallback": [],
13365         
13366                 /**
13367                  * Callback functions for the header on each draw.
13368                  *  @type array
13369                  *  @default []
13370                  */
13371                 "aoHeaderCallback": [],
13372         
13373                 /**
13374                  * Callback function for the footer on each draw.
13375                  *  @type array
13376                  *  @default []
13377                  */
13378                 "aoFooterCallback": [],
13379         
13380                 /**
13381                  * Array of callback functions for draw callback functions
13382                  *  @type array
13383                  *  @default []
13384                  */
13385                 "aoDrawCallback": [],
13386         
13387                 /**
13388                  * Array of callback functions for row created function
13389                  *  @type array
13390                  *  @default []
13391                  */
13392                 "aoRowCreatedCallback": [],
13393         
13394                 /**
13395                  * Callback functions for just before the table is redrawn. A return of
13396                  * false will be used to cancel the draw.
13397                  *  @type array
13398                  *  @default []
13399                  */
13400                 "aoPreDrawCallback": [],
13401         
13402                 /**
13403                  * Callback functions for when the table has been initialised.
13404                  *  @type array
13405                  *  @default []
13406                  */
13407                 "aoInitComplete": [],
13408         
13409         
13410                 /**
13411                  * Callbacks for modifying the settings to be stored for state saving, prior to
13412                  * saving state.
13413                  *  @type array
13414                  *  @default []
13415                  */
13416                 "aoStateSaveParams": [],
13417         
13418                 /**
13419                  * Callbacks for modifying the settings that have been stored for state saving
13420                  * prior to using the stored values to restore the state.
13421                  *  @type array
13422                  *  @default []
13423                  */
13424                 "aoStateLoadParams": [],
13425         
13426                 /**
13427                  * Callbacks for operating on the settings object once the saved state has been
13428                  * loaded
13429                  *  @type array
13430                  *  @default []
13431                  */
13432                 "aoStateLoaded": [],
13433         
13434                 /**
13435                  * Cache the table ID for quick access
13436                  *  @type string
13437                  *  @default <i>Empty string</i>
13438                  */
13439                 "sTableId": "",
13440         
13441                 /**
13442                  * The TABLE node for the main table
13443                  *  @type node
13444                  *  @default null
13445                  */
13446                 "nTable": null,
13447         
13448                 /**
13449                  * Permanent ref to the thead element
13450                  *  @type node
13451                  *  @default null
13452                  */
13453                 "nTHead": null,
13454         
13455                 /**
13456                  * Permanent ref to the tfoot element - if it exists
13457                  *  @type node
13458                  *  @default null
13459                  */
13460                 "nTFoot": null,
13461         
13462                 /**
13463                  * Permanent ref to the tbody element
13464                  *  @type node
13465                  *  @default null
13466                  */
13467                 "nTBody": null,
13468         
13469                 /**
13470                  * Cache the wrapper node (contains all DataTables controlled elements)
13471                  *  @type node
13472                  *  @default null
13473                  */
13474                 "nTableWrapper": null,
13475         
13476                 /**
13477                  * Indicate if when using server-side processing the loading of data
13478                  * should be deferred until the second draw.
13479                  * Note that this parameter will be set by the initialisation routine. To
13480                  * set a default use {@link DataTable.defaults}.
13481                  *  @type boolean
13482                  *  @default false
13483                  */
13484                 "bDeferLoading": false,
13485         
13486                 /**
13487                  * Indicate if all required information has been read in
13488                  *  @type boolean
13489                  *  @default false
13490                  */
13491                 "bInitialised": false,
13492         
13493                 /**
13494                  * Information about open rows. Each object in the array has the parameters
13495                  * 'nTr' and 'nParent'
13496                  *  @type array
13497                  *  @default []
13498                  */
13499                 "aoOpenRows": [],
13500         
13501                 /**
13502                  * Dictate the positioning of DataTables' control elements - see
13503                  * {@link DataTable.model.oInit.sDom}.
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 null
13508                  */
13509                 "sDom": null,
13510         
13511                 /**
13512                  * Search delay (in mS)
13513                  *  @type integer
13514                  *  @default null
13515                  */
13516                 "searchDelay": null,
13517         
13518                 /**
13519                  * Which type of pagination should be used.
13520                  * Note that this parameter will be set by the initialisation routine. To
13521                  * set a default use {@link DataTable.defaults}.
13522                  *  @type string
13523                  *  @default two_button
13524                  */
13525                 "sPaginationType": "two_button",
13526         
13527                 /**
13528                  * The state duration (for `stateSave`) in seconds.
13529                  * Note that this parameter will be set by the initialisation routine. To
13530                  * set a default use {@link DataTable.defaults}.
13531                  *  @type int
13532                  *  @default 0
13533                  */
13534                 "iStateDuration": 0,
13535         
13536                 /**
13537                  * Array of callback functions for state saving. Each array element is an
13538                  * object with the following parameters:
13539                  *   <ul>
13540                  *     <li>function:fn - function to call. Takes two parameters, oSettings
13541                  *       and the JSON string to save that has been thus far created. Returns
13542                  *       a JSON string to be inserted into a json object
13543                  *       (i.e. '"param": [ 0, 1, 2]')</li>
13544                  *     <li>string:sName - name of callback</li>
13545                  *   </ul>
13546                  *  @type array
13547                  *  @default []
13548                  */
13549                 "aoStateSave": [],
13550         
13551                 /**
13552                  * Array of callback functions for state loading. Each array element is an
13553                  * object with the following parameters:
13554                  *   <ul>
13555                  *     <li>function:fn - function to call. Takes two parameters, oSettings
13556                  *       and the object stored. May return false to cancel state loading</li>
13557                  *     <li>string:sName - name of callback</li>
13558                  *   </ul>
13559                  *  @type array
13560                  *  @default []
13561                  */
13562                 "aoStateLoad": [],
13563         
13564                 /**
13565                  * State that was saved. Useful for back reference
13566                  *  @type object
13567                  *  @default null
13568                  */
13569                 "oSavedState": null,
13570         
13571                 /**
13572                  * State that was loaded. Useful for back reference
13573                  *  @type object
13574                  *  @default null
13575                  */
13576                 "oLoadedState": null,
13577         
13578                 /**
13579                  * Source url for AJAX data for the table.
13580                  * Note that this parameter will be set by the initialisation routine. To
13581                  * set a default use {@link DataTable.defaults}.
13582                  *  @type string
13583                  *  @default null
13584                  */
13585                 "sAjaxSource": null,
13586         
13587                 /**
13588                  * Property from a given object from which to read the table data from. This
13589                  * can be an empty string (when not server-side processing), in which case
13590                  * it is  assumed an an array is given directly.
13591                  * Note that this parameter will be set by the initialisation routine. To
13592                  * set a default use {@link DataTable.defaults}.
13593                  *  @type string
13594                  */
13595                 "sAjaxDataProp": null,
13596         
13597                 /**
13598                  * Note if draw should be blocked while getting data
13599                  *  @type boolean
13600                  *  @default true
13601                  */
13602                 "bAjaxDataGet": true,
13603         
13604                 /**
13605                  * The last jQuery XHR object that was used for server-side data gathering.
13606                  * This can be used for working with the XHR information in one of the
13607                  * callbacks
13608                  *  @type object
13609                  *  @default null
13610                  */
13611                 "jqXHR": null,
13612         
13613                 /**
13614                  * JSON returned from the server in the last Ajax request
13615                  *  @type object
13616                  *  @default undefined
13617                  */
13618                 "json": undefined,
13619         
13620                 /**
13621                  * Data submitted as part of the last Ajax request
13622                  *  @type object
13623                  *  @default undefined
13624                  */
13625                 "oAjaxData": undefined,
13626         
13627                 /**
13628                  * Function to get the server-side data.
13629                  * Note that this parameter will be set by the initialisation routine. To
13630                  * set a default use {@link DataTable.defaults}.
13631                  *  @type function
13632                  */
13633                 "fnServerData": null,
13634         
13635                 /**
13636                  * Functions which are called prior to sending an Ajax request so extra
13637                  * parameters can easily be sent to the server
13638                  *  @type array
13639                  *  @default []
13640                  */
13641                 "aoServerParams": [],
13642         
13643                 /**
13644                  * Send the XHR HTTP method - GET or POST (could be PUT or DELETE if
13645                  * required).
13646                  * Note that this parameter will be set by the initialisation routine. To
13647                  * set a default use {@link DataTable.defaults}.
13648                  *  @type string
13649                  */
13650                 "sServerMethod": null,
13651         
13652                 /**
13653                  * Format numbers for display.
13654                  * Note that this parameter will be set by the initialisation routine. To
13655                  * set a default use {@link DataTable.defaults}.
13656                  *  @type function
13657                  */
13658                 "fnFormatNumber": null,
13659         
13660                 /**
13661                  * List of options that can be used for the user selectable length menu.
13662                  * Note that this parameter will be set by the initialisation routine. To
13663                  * set a default use {@link DataTable.defaults}.
13664                  *  @type array
13665                  *  @default []
13666                  */
13667                 "aLengthMenu": null,
13668         
13669                 /**
13670                  * Counter for the draws that the table does. Also used as a tracker for
13671                  * server-side processing
13672                  *  @type int
13673                  *  @default 0
13674                  */
13675                 "iDraw": 0,
13676         
13677                 /**
13678                  * Indicate if a redraw is being done - useful for Ajax
13679                  *  @type boolean
13680                  *  @default false
13681                  */
13682                 "bDrawing": false,
13683         
13684                 /**
13685                  * Draw index (iDraw) of the last error when parsing the returned data
13686                  *  @type int
13687                  *  @default -1
13688                  */
13689                 "iDrawError": -1,
13690         
13691                 /**
13692                  * Paging display length
13693                  *  @type int
13694                  *  @default 10
13695                  */
13696                 "_iDisplayLength": 10,
13697         
13698                 /**
13699                  * Paging start point - aiDisplay index
13700                  *  @type int
13701                  *  @default 0
13702                  */
13703                 "_iDisplayStart": 0,
13704         
13705                 /**
13706                  * Server-side processing - number of records in the result set
13707                  * (i.e. before filtering), Use fnRecordsTotal rather than
13708                  * this property to get the value of the number of records, regardless of
13709                  * the server-side processing setting.
13710                  *  @type int
13711                  *  @default 0
13712                  *  @private
13713                  */
13714                 "_iRecordsTotal": 0,
13715         
13716                 /**
13717                  * Server-side processing - number of records in the current display set
13718                  * (i.e. after filtering). Use fnRecordsDisplay rather than
13719                  * this property to get the value of the number of records, regardless of
13720                  * the server-side processing setting.
13721                  *  @type boolean
13722                  *  @default 0
13723                  *  @private
13724                  */
13725                 "_iRecordsDisplay": 0,
13726         
13727                 /**
13728                  * The classes to use for the table
13729                  *  @type object
13730                  *  @default {}
13731                  */
13732                 "oClasses": {},
13733         
13734                 /**
13735                  * Flag attached to the settings object so you can check in the draw
13736                  * callback if filtering has been done in the draw. Deprecated in favour of
13737                  * events.
13738                  *  @type boolean
13739                  *  @default false
13740                  *  @deprecated
13741                  */
13742                 "bFiltered": false,
13743         
13744                 /**
13745                  * Flag attached to the settings object so you can check in the draw
13746                  * callback if sorting has been done in the draw. Deprecated in favour of
13747                  * events.
13748                  *  @type boolean
13749                  *  @default false
13750                  *  @deprecated
13751                  */
13752                 "bSorted": false,
13753         
13754                 /**
13755                  * Indicate that if multiple rows are in the header and there is more than
13756                  * one unique cell per column, if the top one (true) or bottom one (false)
13757                  * should be used for sorting / title by DataTables.
13758                  * Note that this parameter will be set by the initialisation routine. To
13759                  * set a default use {@link DataTable.defaults}.
13760                  *  @type boolean
13761                  */
13762                 "bSortCellsTop": null,
13763         
13764                 /**
13765                  * Initialisation object that is used for the table
13766                  *  @type object
13767                  *  @default null
13768                  */
13769                 "oInit": null,
13770         
13771                 /**
13772                  * Destroy callback functions - for plug-ins to attach themselves to the
13773                  * destroy so they can clean up markup and events.
13774                  *  @type array
13775                  *  @default []
13776                  */
13777                 "aoDestroyCallback": [],
13778         
13779         
13780                 /**
13781                  * Get the number of records in the current record set, before filtering
13782                  *  @type function
13783                  */
13784                 "fnRecordsTotal": function ()
13785                 {
13786                         return _fnDataSource( this ) == 'ssp' ?
13787                                 this._iRecordsTotal * 1 :
13788                                 this.aiDisplayMaster.length;
13789                 },
13790         
13791                 /**
13792                  * Get the number of records in the current record set, after filtering
13793                  *  @type function
13794                  */
13795                 "fnRecordsDisplay": function ()
13796                 {
13797                         return _fnDataSource( this ) == 'ssp' ?
13798                                 this._iRecordsDisplay * 1 :
13799                                 this.aiDisplay.length;
13800                 },
13801         
13802                 /**
13803                  * Get the display end point - aiDisplay index
13804                  *  @type function
13805                  */
13806                 "fnDisplayEnd": function ()
13807                 {
13808                         var
13809                                 len      = this._iDisplayLength,
13810                                 start    = this._iDisplayStart,
13811                                 calc     = start + len,
13812                                 records  = this.aiDisplay.length,
13813                                 features = this.oFeatures,
13814                                 paginate = features.bPaginate;
13815         
13816                         if ( features.bServerSide ) {
13817                                 return paginate === false || len === -1 ?
13818                                         start + records :
13819                                         Math.min( start+len, this._iRecordsDisplay );
13820                         }
13821                         else {
13822                                 return ! paginate || calc>records || len===-1 ?
13823                                         records :
13824                                         calc;
13825                         }
13826                 },
13827         
13828                 /**
13829                  * The DataTables object for this table
13830                  *  @type object
13831                  *  @default null
13832                  */
13833                 "oInstance": null,
13834         
13835                 /**
13836                  * Unique identifier for each instance of the DataTables object. If there
13837                  * is an ID on the table node, then it takes that value, otherwise an
13838                  * incrementing internal counter is used.
13839                  *  @type string
13840                  *  @default null
13841                  */
13842                 "sInstance": null,
13843         
13844                 /**
13845                  * tabindex attribute value that is added to DataTables control elements, allowing
13846                  * keyboard navigation of the table and its controls.
13847                  */
13848                 "iTabIndex": 0,
13849         
13850                 /**
13851                  * DIV container for the footer scrolling table if scrolling
13852                  */
13853                 "nScrollHead": null,
13854         
13855                 /**
13856                  * DIV container for the footer scrolling table if scrolling
13857                  */
13858                 "nScrollFoot": null,
13859         
13860                 /**
13861                  * Last applied sort
13862                  *  @type array
13863                  *  @default []
13864                  */
13865                 "aLastSort": [],
13866         
13867                 /**
13868                  * Stored plug-in instances
13869                  *  @type object
13870                  *  @default {}
13871                  */
13872                 "oPlugins": {},
13873         
13874                 /**
13875                  * Function used to get a row's id from the row's data
13876                  *  @type function
13877                  *  @default null
13878                  */
13879                 "rowIdFn": null,
13880         
13881                 /**
13882                  * Data location where to store a row's id
13883                  *  @type string
13884                  *  @default null
13885                  */
13886                 "rowId": null
13887         };
13888
13889         /**
13890          * Extension object for DataTables that is used to provide all extension
13891          * options.
13892          *
13893          * Note that the `DataTable.ext` object is available through
13894          * `jQuery.fn.dataTable.ext` where it may be accessed and manipulated. It is
13895          * also aliased to `jQuery.fn.dataTableExt` for historic reasons.
13896          *  @namespace
13897          *  @extends DataTable.models.ext
13898          */
13899         
13900         
13901         /**
13902          * DataTables extensions
13903          * 
13904          * This namespace acts as a collection area for plug-ins that can be used to
13905          * extend DataTables capabilities. Indeed many of the build in methods
13906          * use this method to provide their own capabilities (sorting methods for
13907          * example).
13908          *
13909          * Note that this namespace is aliased to `jQuery.fn.dataTableExt` for legacy
13910          * reasons
13911          *
13912          *  @namespace
13913          */
13914         DataTable.ext = _ext = {
13915                 /**
13916                  * Buttons. For use with the Buttons extension for DataTables. This is
13917                  * defined here so other extensions can define buttons regardless of load
13918                  * order. It is _not_ used by DataTables core.
13919                  *
13920                  *  @type object
13921                  *  @default {}
13922                  */
13923                 buttons: {},
13924         
13925         
13926                 /**
13927                  * Element class names
13928                  *
13929                  *  @type object
13930                  *  @default {}
13931                  */
13932                 classes: {},
13933         
13934         
13935                 /**
13936                  * DataTables build type (expanded by the download builder)
13937                  *
13938                  *  @type string
13939                  */
13940                 build:"dt/dt-1.10.21/fh-3.1.7/sp-1.1.1/sl-1.3.1",
13941         
13942         
13943                 /**
13944                  * Error reporting.
13945                  * 
13946                  * How should DataTables report an error. Can take the value 'alert',
13947                  * 'throw', 'none' or a function.
13948                  *
13949                  *  @type string|function
13950                  *  @default alert
13951                  */
13952                 errMode: "alert",
13953         
13954         
13955                 /**
13956                  * Feature plug-ins.
13957                  * 
13958                  * This is an array of objects which describe the feature plug-ins that are
13959                  * available to DataTables. These feature plug-ins are then available for
13960                  * use through the `dom` initialisation option.
13961                  * 
13962                  * Each feature plug-in is described by an object which must have the
13963                  * following properties:
13964                  * 
13965                  * * `fnInit` - function that is used to initialise the plug-in,
13966                  * * `cFeature` - a character so the feature can be enabled by the `dom`
13967                  *   instillation option. This is case sensitive.
13968                  *
13969                  * The `fnInit` function has the following input parameters:
13970                  *
13971                  * 1. `{object}` DataTables settings object: see
13972                  *    {@link DataTable.models.oSettings}
13973                  *
13974                  * And the following return is expected:
13975                  * 
13976                  * * {node|null} The element which contains your feature. Note that the
13977                  *   return may also be void if your plug-in does not require to inject any
13978                  *   DOM elements into DataTables control (`dom`) - for example this might
13979                  *   be useful when developing a plug-in which allows table control via
13980                  *   keyboard entry
13981                  *
13982                  *  @type array
13983                  *
13984                  *  @example
13985                  *    $.fn.dataTable.ext.features.push( {
13986                  *      "fnInit": function( oSettings ) {
13987                  *        return new TableTools( { "oDTSettings": oSettings } );
13988                  *      },
13989                  *      "cFeature": "T"
13990                  *    } );
13991                  */
13992                 feature: [],
13993         
13994         
13995                 /**
13996                  * Row searching.
13997                  * 
13998                  * This method of searching is complimentary to the default type based
13999                  * searching, and a lot more comprehensive as it allows you complete control
14000                  * over the searching logic. Each element in this array is a function
14001                  * (parameters described below) that is called for every row in the table,
14002                  * and your logic decides if it should be included in the searching data set
14003                  * or not.
14004                  *
14005                  * Searching functions have the following input parameters:
14006                  *
14007                  * 1. `{object}` DataTables settings object: see
14008                  *    {@link DataTable.models.oSettings}
14009                  * 2. `{array|object}` Data for the row to be processed (same as the
14010                  *    original format that was passed in as the data source, or an array
14011                  *    from a DOM data source
14012                  * 3. `{int}` Row index ({@link DataTable.models.oSettings.aoData}), which
14013                  *    can be useful to retrieve the `TR` element if you need DOM interaction.
14014                  *
14015                  * And the following return is expected:
14016                  *
14017                  * * {boolean} Include the row in the searched result set (true) or not
14018                  *   (false)
14019                  *
14020                  * Note that as with the main search ability in DataTables, technically this
14021                  * is "filtering", since it is subtractive. However, for consistency in
14022                  * naming we call it searching here.
14023                  *
14024                  *  @type array
14025                  *  @default []
14026                  *
14027                  *  @example
14028                  *    // The following example shows custom search being applied to the
14029                  *    // fourth column (i.e. the data[3] index) based on two input values
14030                  *    // from the end-user, matching the data in a certain range.
14031                  *    $.fn.dataTable.ext.search.push(
14032                  *      function( settings, data, dataIndex ) {
14033                  *        var min = document.getElementById('min').value * 1;
14034                  *        var max = document.getElementById('max').value * 1;
14035                  *        var version = data[3] == "-" ? 0 : data[3]*1;
14036                  *
14037                  *        if ( min == "" && max == "" ) {
14038                  *          return true;
14039                  *        }
14040                  *        else if ( min == "" && version < max ) {
14041                  *          return true;
14042                  *        }
14043                  *        else if ( min < version && "" == max ) {
14044                  *          return true;
14045                  *        }
14046                  *        else if ( min < version && version < max ) {
14047                  *          return true;
14048                  *        }
14049                  *        return false;
14050                  *      }
14051                  *    );
14052                  */
14053                 search: [],
14054         
14055         
14056                 /**
14057                  * Selector extensions
14058                  *
14059                  * The `selector` option can be used to extend the options available for the
14060                  * selector modifier options (`selector-modifier` object data type) that
14061                  * each of the three built in selector types offer (row, column and cell +
14062                  * their plural counterparts). For example the Select extension uses this
14063                  * mechanism to provide an option to select only rows, columns and cells
14064                  * that have been marked as selected by the end user (`{selected: true}`),
14065                  * which can be used in conjunction with the existing built in selector
14066                  * options.
14067                  *
14068                  * Each property is an array to which functions can be pushed. The functions
14069                  * take three attributes:
14070                  *
14071                  * * Settings object for the host table
14072                  * * Options object (`selector-modifier` object type)
14073                  * * Array of selected item indexes
14074                  *
14075                  * The return is an array of the resulting item indexes after the custom
14076                  * selector has been applied.
14077                  *
14078                  *  @type object
14079                  */
14080                 selector: {
14081                         cell: [],
14082                         column: [],
14083                         row: []
14084                 },
14085         
14086         
14087                 /**
14088                  * Internal functions, exposed for used in plug-ins.
14089                  * 
14090                  * Please note that you should not need to use the internal methods for
14091                  * anything other than a plug-in (and even then, try to avoid if possible).
14092                  * The internal function may change between releases.
14093                  *
14094                  *  @type object
14095                  *  @default {}
14096                  */
14097                 internal: {},
14098         
14099         
14100                 /**
14101                  * Legacy configuration options. Enable and disable legacy options that
14102                  * are available in DataTables.
14103                  *
14104                  *  @type object
14105                  */
14106                 legacy: {
14107                         /**
14108                          * Enable / disable DataTables 1.9 compatible server-side processing
14109                          * requests
14110                          *
14111                          *  @type boolean
14112                          *  @default null
14113                          */
14114                         ajax: null
14115                 },
14116         
14117         
14118                 /**
14119                  * Pagination plug-in methods.
14120                  * 
14121                  * Each entry in this object is a function and defines which buttons should
14122                  * be shown by the pagination rendering method that is used for the table:
14123                  * {@link DataTable.ext.renderer.pageButton}. The renderer addresses how the
14124                  * buttons are displayed in the document, while the functions here tell it
14125                  * what buttons to display. This is done by returning an array of button
14126                  * descriptions (what each button will do).
14127                  *
14128                  * Pagination types (the four built in options and any additional plug-in
14129                  * options defined here) can be used through the `paginationType`
14130                  * initialisation parameter.
14131                  *
14132                  * The functions defined take two parameters:
14133                  *
14134                  * 1. `{int} page` The current page index
14135                  * 2. `{int} pages` The number of pages in the table
14136                  *
14137                  * Each function is expected to return an array where each element of the
14138                  * array can be one of:
14139                  *
14140                  * * `first` - Jump to first page when activated
14141                  * * `last` - Jump to last page when activated
14142                  * * `previous` - Show previous page when activated
14143                  * * `next` - Show next page when activated
14144                  * * `{int}` - Show page of the index given
14145                  * * `{array}` - A nested array containing the above elements to add a
14146                  *   containing 'DIV' element (might be useful for styling).
14147                  *
14148                  * Note that DataTables v1.9- used this object slightly differently whereby
14149                  * an object with two functions would be defined for each plug-in. That
14150                  * ability is still supported by DataTables 1.10+ to provide backwards
14151                  * compatibility, but this option of use is now decremented and no longer
14152                  * documented in DataTables 1.10+.
14153                  *
14154                  *  @type object
14155                  *  @default {}
14156                  *
14157                  *  @example
14158                  *    // Show previous, next and current page buttons only
14159                  *    $.fn.dataTableExt.oPagination.current = function ( page, pages ) {
14160                  *      return [ 'previous', page, 'next' ];
14161                  *    };
14162                  */
14163                 pager: {},
14164         
14165         
14166                 renderer: {
14167                         pageButton: {},
14168                         header: {}
14169                 },
14170         
14171         
14172                 /**
14173                  * Ordering plug-ins - custom data source
14174                  * 
14175                  * The extension options for ordering of data available here is complimentary
14176                  * to the default type based ordering that DataTables typically uses. It
14177                  * allows much greater control over the the data that is being used to
14178                  * order a column, but is necessarily therefore more complex.
14179                  * 
14180                  * This type of ordering is useful if you want to do ordering based on data
14181                  * live from the DOM (for example the contents of an 'input' element) rather
14182                  * than just the static string that DataTables knows of.
14183                  * 
14184                  * The way these plug-ins work is that you create an array of the values you
14185                  * wish to be ordering for the column in question and then return that
14186                  * array. The data in the array much be in the index order of the rows in
14187                  * the table (not the currently ordering order!). Which order data gathering
14188                  * function is run here depends on the `dt-init columns.orderDataType`
14189                  * parameter that is used for the column (if any).
14190                  *
14191                  * The functions defined take two parameters:
14192                  *
14193                  * 1. `{object}` DataTables settings object: see
14194                  *    {@link DataTable.models.oSettings}
14195                  * 2. `{int}` Target column index
14196                  *
14197                  * Each function is expected to return an array:
14198                  *
14199                  * * `{array}` Data for the column to be ordering upon
14200                  *
14201                  *  @type array
14202                  *
14203                  *  @example
14204                  *    // Ordering using `input` node values
14205                  *    $.fn.dataTable.ext.order['dom-text'] = function  ( settings, col )
14206                  *    {
14207                  *      return this.api().column( col, {order:'index'} ).nodes().map( function ( td, i ) {
14208                  *        return $('input', td).val();
14209                  *      } );
14210                  *    }
14211                  */
14212                 order: {},
14213         
14214         
14215                 /**
14216                  * Type based plug-ins.
14217                  *
14218                  * Each column in DataTables has a type assigned to it, either by automatic
14219                  * detection or by direct assignment using the `type` option for the column.
14220                  * The type of a column will effect how it is ordering and search (plug-ins
14221                  * can also make use of the column type if required).
14222                  *
14223                  * @namespace
14224                  */
14225                 type: {
14226                         /**
14227                          * Type detection functions.
14228                          *
14229                          * The functions defined in this object are used to automatically detect
14230                          * a column's type, making initialisation of DataTables super easy, even
14231                          * when complex data is in the table.
14232                          *
14233                          * The functions defined take two parameters:
14234                          *
14235                      *  1. `{*}` Data from the column cell to be analysed
14236                      *  2. `{settings}` DataTables settings object. This can be used to
14237                      *     perform context specific type detection - for example detection
14238                      *     based on language settings such as using a comma for a decimal
14239                      *     place. Generally speaking the options from the settings will not
14240                      *     be required
14241                          *
14242                          * Each function is expected to return:
14243                          *
14244                          * * `{string|null}` Data type detected, or null if unknown (and thus
14245                          *   pass it on to the other type detection functions.
14246                          *
14247                          *  @type array
14248                          *
14249                          *  @example
14250                          *    // Currency type detection plug-in:
14251                          *    $.fn.dataTable.ext.type.detect.push(
14252                          *      function ( data, settings ) {
14253                          *        // Check the numeric part
14254                          *        if ( ! data.substring(1).match(/[0-9]/) ) {
14255                          *          return null;
14256                          *        }
14257                          *
14258                          *        // Check prefixed by currency
14259                          *        if ( data.charAt(0) == '$' || data.charAt(0) == '&pound;' ) {
14260                          *          return 'currency';
14261                          *        }
14262                          *        return null;
14263                          *      }
14264                          *    );
14265                          */
14266                         detect: [],
14267         
14268         
14269                         /**
14270                          * Type based search formatting.
14271                          *
14272                          * The type based searching functions can be used to pre-format the
14273                          * data to be search on. For example, it can be used to strip HTML
14274                          * tags or to de-format telephone numbers for numeric only searching.
14275                          *
14276                          * Note that is a search is not defined for a column of a given type,
14277                          * no search formatting will be performed.
14278                          * 
14279                          * Pre-processing of searching data plug-ins - When you assign the sType
14280                          * for a column (or have it automatically detected for you by DataTables
14281                          * or a type detection plug-in), you will typically be using this for
14282                          * custom sorting, but it can also be used to provide custom searching
14283                          * by allowing you to pre-processing the data and returning the data in
14284                          * the format that should be searched upon. This is done by adding
14285                          * functions this object with a parameter name which matches the sType
14286                          * for that target column. This is the corollary of <i>afnSortData</i>
14287                          * for searching data.
14288                          *
14289                          * The functions defined take a single parameter:
14290                          *
14291                      *  1. `{*}` Data from the column cell to be prepared for searching
14292                          *
14293                          * Each function is expected to return:
14294                          *
14295                          * * `{string|null}` Formatted string that will be used for the searching.
14296                          *
14297                          *  @type object
14298                          *  @default {}
14299                          *
14300                          *  @example
14301                          *    $.fn.dataTable.ext.type.search['title-numeric'] = function ( d ) {
14302                          *      return d.replace(/\n/g," ").replace( /<.*?>/g, "" );
14303                          *    }
14304                          */
14305                         search: {},
14306         
14307         
14308                         /**
14309                          * Type based ordering.
14310                          *
14311                          * The column type tells DataTables what ordering to apply to the table
14312                          * when a column is sorted upon. The order for each type that is defined,
14313                          * is defined by the functions available in this object.
14314                          *
14315                          * Each ordering option can be described by three properties added to
14316                          * this object:
14317                          *
14318                          * * `{type}-pre` - Pre-formatting function
14319                          * * `{type}-asc` - Ascending order function
14320                          * * `{type}-desc` - Descending order function
14321                          *
14322                          * All three can be used together, only `{type}-pre` or only
14323                          * `{type}-asc` and `{type}-desc` together. It is generally recommended
14324                          * that only `{type}-pre` is used, as this provides the optimal
14325                          * implementation in terms of speed, although the others are provided
14326                          * for compatibility with existing Javascript sort functions.
14327                          *
14328                          * `{type}-pre`: Functions defined take a single parameter:
14329                          *
14330                      *  1. `{*}` Data from the column cell to be prepared for ordering
14331                          *
14332                          * And return:
14333                          *
14334                          * * `{*}` Data to be sorted upon
14335                          *
14336                          * `{type}-asc` and `{type}-desc`: Functions are typical Javascript sort
14337                          * functions, taking two parameters:
14338                          *
14339                      *  1. `{*}` Data to compare to the second parameter
14340                      *  2. `{*}` Data to compare to the first parameter
14341                          *
14342                          * And returning:
14343                          *
14344                          * * `{*}` Ordering match: <0 if first parameter should be sorted lower
14345                          *   than the second parameter, ===0 if the two parameters are equal and
14346                          *   >0 if the first parameter should be sorted height than the second
14347                          *   parameter.
14348                          * 
14349                          *  @type object
14350                          *  @default {}
14351                          *
14352                          *  @example
14353                          *    // Numeric ordering of formatted numbers with a pre-formatter
14354                          *    $.extend( $.fn.dataTable.ext.type.order, {
14355                          *      "string-pre": function(x) {
14356                          *        a = (a === "-" || a === "") ? 0 : a.replace( /[^\d\-\.]/g, "" );
14357                          *        return parseFloat( a );
14358                          *      }
14359                          *    } );
14360                          *
14361                          *  @example
14362                          *    // Case-sensitive string ordering, with no pre-formatting method
14363                          *    $.extend( $.fn.dataTable.ext.order, {
14364                          *      "string-case-asc": function(x,y) {
14365                          *        return ((x < y) ? -1 : ((x > y) ? 1 : 0));
14366                          *      },
14367                          *      "string-case-desc": function(x,y) {
14368                          *        return ((x < y) ? 1 : ((x > y) ? -1 : 0));
14369                          *      }
14370                          *    } );
14371                          */
14372                         order: {}
14373                 },
14374         
14375                 /**
14376                  * Unique DataTables instance counter
14377                  *
14378                  * @type int
14379                  * @private
14380                  */
14381                 _unique: 0,
14382         
14383         
14384                 //
14385                 // Depreciated
14386                 // The following properties are retained for backwards compatiblity only.
14387                 // The should not be used in new projects and will be removed in a future
14388                 // version
14389                 //
14390         
14391                 /**
14392                  * Version check function.
14393                  *  @type function
14394                  *  @depreciated Since 1.10
14395                  */
14396                 fnVersionCheck: DataTable.fnVersionCheck,
14397         
14398         
14399                 /**
14400                  * Index for what 'this' index API functions should use
14401                  *  @type int
14402                  *  @deprecated Since v1.10
14403                  */
14404                 iApiIndex: 0,
14405         
14406         
14407                 /**
14408                  * jQuery UI class container
14409                  *  @type object
14410                  *  @deprecated Since v1.10
14411                  */
14412                 oJUIClasses: {},
14413         
14414         
14415                 /**
14416                  * Software version
14417                  *  @type string
14418                  *  @deprecated Since v1.10
14419                  */
14420                 sVersion: DataTable.version
14421         };
14422         
14423         
14424         //
14425         // Backwards compatibility. Alias to pre 1.10 Hungarian notation counter parts
14426         //
14427         $.extend( _ext, {
14428                 afnFiltering: _ext.search,
14429                 aTypes:       _ext.type.detect,
14430                 ofnSearch:    _ext.type.search,
14431                 oSort:        _ext.type.order,
14432                 afnSortData:  _ext.order,
14433                 aoFeatures:   _ext.feature,
14434                 oApi:         _ext.internal,
14435                 oStdClasses:  _ext.classes,
14436                 oPagination:  _ext.pager
14437         } );
14438         
14439         
14440         $.extend( DataTable.ext.classes, {
14441                 "sTable": "dataTable",
14442                 "sNoFooter": "no-footer",
14443         
14444                 /* Paging buttons */
14445                 "sPageButton": "paginate_button",
14446                 "sPageButtonActive": "current",
14447                 "sPageButtonDisabled": "disabled",
14448         
14449                 /* Striping classes */
14450                 "sStripeOdd": "odd",
14451                 "sStripeEven": "even",
14452         
14453                 /* Empty row */
14454                 "sRowEmpty": "dataTables_empty",
14455         
14456                 /* Features */
14457                 "sWrapper": "dataTables_wrapper",
14458                 "sFilter": "dataTables_filter",
14459                 "sInfo": "dataTables_info",
14460                 "sPaging": "dataTables_paginate paging_", /* Note that the type is postfixed */
14461                 "sLength": "dataTables_length",
14462                 "sProcessing": "dataTables_processing",
14463         
14464                 /* Sorting */
14465                 "sSortAsc": "sorting_asc",
14466                 "sSortDesc": "sorting_desc",
14467                 "sSortable": "sorting", /* Sortable in both directions */
14468                 "sSortableAsc": "sorting_asc_disabled",
14469                 "sSortableDesc": "sorting_desc_disabled",
14470                 "sSortableNone": "sorting_disabled",
14471                 "sSortColumn": "sorting_", /* Note that an int is postfixed for the sorting order */
14472         
14473                 /* Filtering */
14474                 "sFilterInput": "",
14475         
14476                 /* Page length */
14477                 "sLengthSelect": "",
14478         
14479                 /* Scrolling */
14480                 "sScrollWrapper": "dataTables_scroll",
14481                 "sScrollHead": "dataTables_scrollHead",
14482                 "sScrollHeadInner": "dataTables_scrollHeadInner",
14483                 "sScrollBody": "dataTables_scrollBody",
14484                 "sScrollFoot": "dataTables_scrollFoot",
14485                 "sScrollFootInner": "dataTables_scrollFootInner",
14486         
14487                 /* Misc */
14488                 "sHeaderTH": "",
14489                 "sFooterTH": "",
14490         
14491                 // Deprecated
14492                 "sSortJUIAsc": "",
14493                 "sSortJUIDesc": "",
14494                 "sSortJUI": "",
14495                 "sSortJUIAscAllowed": "",
14496                 "sSortJUIDescAllowed": "",
14497                 "sSortJUIWrapper": "",
14498                 "sSortIcon": "",
14499                 "sJUIHeader": "",
14500                 "sJUIFooter": ""
14501         } );
14502         
14503         
14504         var extPagination = DataTable.ext.pager;
14505         
14506         function _numbers ( page, pages ) {
14507                 var
14508                         numbers = [],
14509                         buttons = extPagination.numbers_length,
14510                         half = Math.floor( buttons / 2 ),
14511                         i = 1;
14512         
14513                 if ( pages <= buttons ) {
14514                         numbers = _range( 0, pages );
14515                 }
14516                 else if ( page <= half ) {
14517                         numbers = _range( 0, buttons-2 );
14518                         numbers.push( 'ellipsis' );
14519                         numbers.push( pages-1 );
14520                 }
14521                 else if ( page >= pages - 1 - half ) {
14522                         numbers = _range( pages-(buttons-2), pages );
14523                         numbers.splice( 0, 0, 'ellipsis' ); // no unshift in ie6
14524                         numbers.splice( 0, 0, 0 );
14525                 }
14526                 else {
14527                         numbers = _range( page-half+2, page+half-1 );
14528                         numbers.push( 'ellipsis' );
14529                         numbers.push( pages-1 );
14530                         numbers.splice( 0, 0, 'ellipsis' );
14531                         numbers.splice( 0, 0, 0 );
14532                 }
14533         
14534                 numbers.DT_el = 'span';
14535                 return numbers;
14536         }
14537         
14538         
14539         $.extend( extPagination, {
14540                 simple: function ( page, pages ) {
14541                         return [ 'previous', 'next' ];
14542                 },
14543         
14544                 full: function ( page, pages ) {
14545                         return [  'first', 'previous', 'next', 'last' ];
14546                 },
14547         
14548                 numbers: function ( page, pages ) {
14549                         return [ _numbers(page, pages) ];
14550                 },
14551         
14552                 simple_numbers: function ( page, pages ) {
14553                         return [ 'previous', _numbers(page, pages), 'next' ];
14554                 },
14555         
14556                 full_numbers: function ( page, pages ) {
14557                         return [ 'first', 'previous', _numbers(page, pages), 'next', 'last' ];
14558                 },
14559                 
14560                 first_last_numbers: function (page, pages) {
14561                         return ['first', _numbers(page, pages), 'last'];
14562                 },
14563         
14564                 // For testing and plug-ins to use
14565                 _numbers: _numbers,
14566         
14567                 // Number of number buttons (including ellipsis) to show. _Must be odd!_
14568                 numbers_length: 7
14569         } );
14570         
14571         
14572         $.extend( true, DataTable.ext.renderer, {
14573                 pageButton: {
14574                         _: function ( settings, host, idx, buttons, page, pages ) {
14575                                 var classes = settings.oClasses;
14576                                 var lang = settings.oLanguage.oPaginate;
14577                                 var aria = settings.oLanguage.oAria.paginate || {};
14578                                 var btnDisplay, btnClass, counter=0;
14579         
14580                                 var attach = function( container, buttons ) {
14581                                         var i, ien, node, button, tabIndex;
14582                                         var disabledClass = classes.sPageButtonDisabled;
14583                                         var clickHandler = function ( e ) {
14584                                                 _fnPageChange( settings, e.data.action, true );
14585                                         };
14586         
14587                                         for ( i=0, ien=buttons.length ; i<ien ; i++ ) {
14588                                                 button = buttons[i];
14589         
14590                                                 if ( $.isArray( button ) ) {
14591                                                         var inner = $( '<'+(button.DT_el || 'div')+'/>' )
14592                                                                 .appendTo( container );
14593                                                         attach( inner, button );
14594                                                 }
14595                                                 else {
14596                                                         btnDisplay = null;
14597                                                         btnClass = button;
14598                                                         tabIndex = settings.iTabIndex;
14599         
14600                                                         switch ( button ) {
14601                                                                 case 'ellipsis':
14602                                                                         container.append('<span class="ellipsis">&#x2026;</span>');
14603                                                                         break;
14604         
14605                                                                 case 'first':
14606                                                                         btnDisplay = lang.sFirst;
14607         
14608                                                                         if ( page === 0 ) {
14609                                                                                 tabIndex = -1;
14610                                                                                 btnClass += ' ' + disabledClass;
14611                                                                         }
14612                                                                         break;
14613         
14614                                                                 case 'previous':
14615                                                                         btnDisplay = lang.sPrevious;
14616         
14617                                                                         if ( page === 0 ) {
14618                                                                                 tabIndex = -1;
14619                                                                                 btnClass += ' ' + disabledClass;
14620                                                                         }
14621                                                                         break;
14622         
14623                                                                 case 'next':
14624                                                                         btnDisplay = lang.sNext;
14625         
14626                                                                         if ( pages === 0 || page === pages-1 ) {
14627                                                                                 tabIndex = -1;
14628                                                                                 btnClass += ' ' + disabledClass;
14629                                                                         }
14630                                                                         break;
14631         
14632                                                                 case 'last':
14633                                                                         btnDisplay = lang.sLast;
14634         
14635                                                                         if ( page === pages-1 ) {
14636                                                                                 tabIndex = -1;
14637                                                                                 btnClass += ' ' + disabledClass;
14638                                                                         }
14639                                                                         break;
14640         
14641                                                                 default:
14642                                                                         btnDisplay = button + 1;
14643                                                                         btnClass = page === button ?
14644                                                                                 classes.sPageButtonActive : '';
14645                                                                         break;
14646                                                         }
14647         
14648                                                         if ( btnDisplay !== null ) {
14649                                                                 node = $('<a>', {
14650                                                                                 'class': classes.sPageButton+' '+btnClass,
14651                                                                                 'aria-controls': settings.sTableId,
14652                                                                                 'aria-label': aria[ button ],
14653                                                                                 'data-dt-idx': counter,
14654                                                                                 'tabindex': tabIndex,
14655                                                                                 'id': idx === 0 && typeof button === 'string' ?
14656                                                                                         settings.sTableId +'_'+ button :
14657                                                                                         null
14658                                                                         } )
14659                                                                         .html( btnDisplay )
14660                                                                         .appendTo( container );
14661         
14662                                                                 _fnBindAction(
14663                                                                         node, {action: button}, clickHandler
14664                                                                 );
14665         
14666                                                                 counter++;
14667                                                         }
14668                                                 }
14669                                         }
14670                                 };
14671         
14672                                 // IE9 throws an 'unknown error' if document.activeElement is used
14673                                 // inside an iframe or frame. Try / catch the error. Not good for
14674                                 // accessibility, but neither are frames.
14675                                 var activeEl;
14676         
14677                                 try {
14678                                         // Because this approach is destroying and recreating the paging
14679                                         // elements, focus is lost on the select button which is bad for
14680                                         // accessibility. So we want to restore focus once the draw has
14681                                         // completed
14682                                         activeEl = $(host).find(document.activeElement).data('dt-idx');
14683                                 }
14684                                 catch (e) {}
14685         
14686                                 attach( $(host).empty(), buttons );
14687         
14688                                 if ( activeEl !== undefined ) {
14689                                         $(host).find( '[data-dt-idx='+activeEl+']' ).trigger('focus');
14690                                 }
14691                         }
14692                 }
14693         } );
14694         
14695         
14696         
14697         // Built in type detection. See model.ext.aTypes for information about
14698         // what is required from this methods.
14699         $.extend( DataTable.ext.type.detect, [
14700                 // Plain numbers - first since V8 detects some plain numbers as dates
14701                 // e.g. Date.parse('55') (but not all, e.g. Date.parse('22')...).
14702                 function ( d, settings )
14703                 {
14704                         var decimal = settings.oLanguage.sDecimal;
14705                         return _isNumber( d, decimal ) ? 'num'+decimal : null;
14706                 },
14707         
14708                 // Dates (only those recognised by the browser's Date.parse)
14709                 function ( d, settings )
14710                 {
14711                         // V8 tries _very_ hard to make a string passed into `Date.parse()`
14712                         // valid, so we need to use a regex to restrict date formats. Use a
14713                         // plug-in for anything other than ISO8601 style strings
14714                         if ( d && !(d instanceof Date) && ! _re_date.test(d) ) {
14715                                 return null;
14716                         }
14717                         var parsed = Date.parse(d);
14718                         return (parsed !== null && !isNaN(parsed)) || _empty(d) ? 'date' : null;
14719                 },
14720         
14721                 // Formatted numbers
14722                 function ( d, settings )
14723                 {
14724                         var decimal = settings.oLanguage.sDecimal;
14725                         return _isNumber( d, decimal, true ) ? 'num-fmt'+decimal : null;
14726                 },
14727         
14728                 // HTML numeric
14729                 function ( d, settings )
14730                 {
14731                         var decimal = settings.oLanguage.sDecimal;
14732                         return _htmlNumeric( d, decimal ) ? 'html-num'+decimal : null;
14733                 },
14734         
14735                 // HTML numeric, formatted
14736                 function ( d, settings )
14737                 {
14738                         var decimal = settings.oLanguage.sDecimal;
14739                         return _htmlNumeric( d, decimal, true ) ? 'html-num-fmt'+decimal : null;
14740                 },
14741         
14742                 // HTML (this is strict checking - there must be html)
14743                 function ( d, settings )
14744                 {
14745                         return _empty( d ) || (typeof d === 'string' && d.indexOf('<') !== -1) ?
14746                                 'html' : null;
14747                 }
14748         ] );
14749         
14750         
14751         
14752         // Filter formatting functions. See model.ext.ofnSearch for information about
14753         // what is required from these methods.
14754         // 
14755         // Note that additional search methods are added for the html numbers and
14756         // html formatted numbers by `_addNumericSort()` when we know what the decimal
14757         // place is
14758         
14759         
14760         $.extend( DataTable.ext.type.search, {
14761                 html: function ( data ) {
14762                         return _empty(data) ?
14763                                 data :
14764                                 typeof data === 'string' ?
14765                                         data
14766                                                 .replace( _re_new_lines, " " )
14767                                                 .replace( _re_html, "" ) :
14768                                         '';
14769                 },
14770         
14771                 string: function ( data ) {
14772                         return _empty(data) ?
14773                                 data :
14774                                 typeof data === 'string' ?
14775                                         data.replace( _re_new_lines, " " ) :
14776                                         data;
14777                 }
14778         } );
14779         
14780         
14781         
14782         var __numericReplace = function ( d, decimalPlace, re1, re2 ) {
14783                 if ( d !== 0 && (!d || d === '-') ) {
14784                         return -Infinity;
14785                 }
14786         
14787                 // If a decimal place other than `.` is used, it needs to be given to the
14788                 // function so we can detect it and replace with a `.` which is the only
14789                 // decimal place Javascript recognises - it is not locale aware.
14790                 if ( decimalPlace ) {
14791                         d = _numToDecimal( d, decimalPlace );
14792                 }
14793         
14794                 if ( d.replace ) {
14795                         if ( re1 ) {
14796                                 d = d.replace( re1, '' );
14797                         }
14798         
14799                         if ( re2 ) {
14800                                 d = d.replace( re2, '' );
14801                         }
14802                 }
14803         
14804                 return d * 1;
14805         };
14806         
14807         
14808         // Add the numeric 'deformatting' functions for sorting and search. This is done
14809         // in a function to provide an easy ability for the language options to add
14810         // additional methods if a non-period decimal place is used.
14811         function _addNumericSort ( decimalPlace ) {
14812                 $.each(
14813                         {
14814                                 // Plain numbers
14815                                 "num": function ( d ) {
14816                                         return __numericReplace( d, decimalPlace );
14817                                 },
14818         
14819                                 // Formatted numbers
14820                                 "num-fmt": function ( d ) {
14821                                         return __numericReplace( d, decimalPlace, _re_formatted_numeric );
14822                                 },
14823         
14824                                 // HTML numeric
14825                                 "html-num": function ( d ) {
14826                                         return __numericReplace( d, decimalPlace, _re_html );
14827                                 },
14828         
14829                                 // HTML numeric, formatted
14830                                 "html-num-fmt": function ( d ) {
14831                                         return __numericReplace( d, decimalPlace, _re_html, _re_formatted_numeric );
14832                                 }
14833                         },
14834                         function ( key, fn ) {
14835                                 // Add the ordering method
14836                                 _ext.type.order[ key+decimalPlace+'-pre' ] = fn;
14837         
14838                                 // For HTML types add a search formatter that will strip the HTML
14839                                 if ( key.match(/^html\-/) ) {
14840                                         _ext.type.search[ key+decimalPlace ] = _ext.type.search.html;
14841                                 }
14842                         }
14843                 );
14844         }
14845         
14846         
14847         // Default sort methods
14848         $.extend( _ext.type.order, {
14849                 // Dates
14850                 "date-pre": function ( d ) {
14851                         var ts = Date.parse( d );
14852                         return isNaN(ts) ? -Infinity : ts;
14853                 },
14854         
14855                 // html
14856                 "html-pre": function ( a ) {
14857                         return _empty(a) ?
14858                                 '' :
14859                                 a.replace ?
14860                                         a.replace( /<.*?>/g, "" ).toLowerCase() :
14861                                         a+'';
14862                 },
14863         
14864                 // string
14865                 "string-pre": function ( a ) {
14866                         // This is a little complex, but faster than always calling toString,
14867                         // http://jsperf.com/tostring-v-check
14868                         return _empty(a) ?
14869                                 '' :
14870                                 typeof a === 'string' ?
14871                                         a.toLowerCase() :
14872                                         ! a.toString ?
14873                                                 '' :
14874                                                 a.toString();
14875                 },
14876         
14877                 // string-asc and -desc are retained only for compatibility with the old
14878                 // sort methods
14879                 "string-asc": function ( x, y ) {
14880                         return ((x < y) ? -1 : ((x > y) ? 1 : 0));
14881                 },
14882         
14883                 "string-desc": function ( x, y ) {
14884                         return ((x < y) ? 1 : ((x > y) ? -1 : 0));
14885                 }
14886         } );
14887         
14888         
14889         // Numeric sorting types - order doesn't matter here
14890         _addNumericSort( '' );
14891         
14892         
14893         $.extend( true, DataTable.ext.renderer, {
14894                 header: {
14895                         _: function ( settings, cell, column, classes ) {
14896                                 // No additional mark-up required
14897                                 // Attach a sort listener to update on sort - note that using the
14898                                 // `DT` namespace will allow the event to be removed automatically
14899                                 // on destroy, while the `dt` namespaced event is the one we are
14900                                 // listening for
14901                                 $(settings.nTable).on( 'order.dt.DT', function ( e, ctx, sorting, columns ) {
14902                                         if ( settings !== ctx ) { // need to check this this is the host
14903                                                 return;               // table, not a nested one
14904                                         }
14905         
14906                                         var colIdx = column.idx;
14907         
14908                                         cell
14909                                                 .removeClass(
14910                                                         column.sSortingClass +' '+
14911                                                         classes.sSortAsc +' '+
14912                                                         classes.sSortDesc
14913                                                 )
14914                                                 .addClass( columns[ colIdx ] == 'asc' ?
14915                                                         classes.sSortAsc : columns[ colIdx ] == 'desc' ?
14916                                                                 classes.sSortDesc :
14917                                                                 column.sSortingClass
14918                                                 );
14919                                 } );
14920                         },
14921         
14922                         jqueryui: function ( settings, cell, column, classes ) {
14923                                 $('<div/>')
14924                                         .addClass( classes.sSortJUIWrapper )
14925                                         .append( cell.contents() )
14926                                         .append( $('<span/>')
14927                                                 .addClass( classes.sSortIcon+' '+column.sSortingClassJUI )
14928                                         )
14929                                         .appendTo( cell );
14930         
14931                                 // Attach a sort listener to update on sort
14932                                 $(settings.nTable).on( 'order.dt.DT', function ( e, ctx, sorting, columns ) {
14933                                         if ( settings !== ctx ) {
14934                                                 return;
14935                                         }
14936         
14937                                         var colIdx = column.idx;
14938         
14939                                         cell
14940                                                 .removeClass( classes.sSortAsc +" "+classes.sSortDesc )
14941                                                 .addClass( columns[ colIdx ] == 'asc' ?
14942                                                         classes.sSortAsc : columns[ colIdx ] == 'desc' ?
14943                                                                 classes.sSortDesc :
14944                                                                 column.sSortingClass
14945                                                 );
14946         
14947                                         cell
14948                                                 .find( 'span.'+classes.sSortIcon )
14949                                                 .removeClass(
14950                                                         classes.sSortJUIAsc +" "+
14951                                                         classes.sSortJUIDesc +" "+
14952                                                         classes.sSortJUI +" "+
14953                                                         classes.sSortJUIAscAllowed +" "+
14954                                                         classes.sSortJUIDescAllowed
14955                                                 )
14956                                                 .addClass( columns[ colIdx ] == 'asc' ?
14957                                                         classes.sSortJUIAsc : columns[ colIdx ] == 'desc' ?
14958                                                                 classes.sSortJUIDesc :
14959                                                                 column.sSortingClassJUI
14960                                                 );
14961                                 } );
14962                         }
14963                 }
14964         } );
14965         
14966         /*
14967          * Public helper functions. These aren't used internally by DataTables, or
14968          * called by any of the options passed into DataTables, but they can be used
14969          * externally by developers working with DataTables. They are helper functions
14970          * to make working with DataTables a little bit easier.
14971          */
14972         
14973         var __htmlEscapeEntities = function ( d ) {
14974                 return typeof d === 'string' ?
14975                         d
14976                                 .replace(/&/g, '&amp;')
14977                                 .replace(/</g, '&lt;')
14978                                 .replace(/>/g, '&gt;')
14979                                 .replace(/"/g, '&quot;') :
14980                         d;
14981         };
14982         
14983         /**
14984          * Helpers for `columns.render`.
14985          *
14986          * The options defined here can be used with the `columns.render` initialisation
14987          * option to provide a display renderer. The following functions are defined:
14988          *
14989          * * `number` - Will format numeric data (defined by `columns.data`) for
14990          *   display, retaining the original unformatted data for sorting and filtering.
14991          *   It takes 5 parameters:
14992          *   * `string` - Thousands grouping separator
14993          *   * `string` - Decimal point indicator
14994          *   * `integer` - Number of decimal points to show
14995          *   * `string` (optional) - Prefix.
14996          *   * `string` (optional) - Postfix (/suffix).
14997          * * `text` - Escape HTML to help prevent XSS attacks. It has no optional
14998          *   parameters.
14999          *
15000          * @example
15001          *   // Column definition using the number renderer
15002          *   {
15003          *     data: "salary",
15004          *     render: $.fn.dataTable.render.number( '\'', '.', 0, '$' )
15005          *   }
15006          *
15007          * @namespace
15008          */
15009         DataTable.render = {
15010                 number: function ( thousands, decimal, precision, prefix, postfix ) {
15011                         return {
15012                                 display: function ( d ) {
15013                                         if ( typeof d !== 'number' && typeof d !== 'string' ) {
15014                                                 return d;
15015                                         }
15016         
15017                                         var negative = d < 0 ? '-' : '';
15018                                         var flo = parseFloat( d );
15019         
15020                                         // If NaN then there isn't much formatting that we can do - just
15021                                         // return immediately, escaping any HTML (this was supposed to
15022                                         // be a number after all)
15023                                         if ( isNaN( flo ) ) {
15024                                                 return __htmlEscapeEntities( d );
15025                                         }
15026         
15027                                         flo = flo.toFixed( precision );
15028                                         d = Math.abs( flo );
15029         
15030                                         var intPart = parseInt( d, 10 );
15031                                         var floatPart = precision ?
15032                                                 decimal+(d - intPart).toFixed( precision ).substring( 2 ):
15033                                                 '';
15034         
15035                                         return negative + (prefix||'') +
15036                                                 intPart.toString().replace(
15037                                                         /\B(?=(\d{3})+(?!\d))/g, thousands
15038                                                 ) +
15039                                                 floatPart +
15040                                                 (postfix||'');
15041                                 }
15042                         };
15043                 },
15044         
15045                 text: function () {
15046                         return {
15047                                 display: __htmlEscapeEntities,
15048                                 filter: __htmlEscapeEntities
15049                         };
15050                 }
15051         };
15052         
15053         
15054         /*
15055          * This is really a good bit rubbish this method of exposing the internal methods
15056          * publicly... - To be fixed in 2.0 using methods on the prototype
15057          */
15058         
15059         
15060         /**
15061          * Create a wrapper function for exporting an internal functions to an external API.
15062          *  @param {string} fn API function name
15063          *  @returns {function} wrapped function
15064          *  @memberof DataTable#internal
15065          */
15066         function _fnExternApiFunc (fn)
15067         {
15068                 return function() {
15069                         var args = [_fnSettingsFromNode( this[DataTable.ext.iApiIndex] )].concat(
15070                                 Array.prototype.slice.call(arguments)
15071                         );
15072                         return DataTable.ext.internal[fn].apply( this, args );
15073                 };
15074         }
15075         
15076         
15077         /**
15078          * Reference to internal functions for use by plug-in developers. Note that
15079          * these methods are references to internal functions and are considered to be
15080          * private. If you use these methods, be aware that they are liable to change
15081          * between versions.
15082          *  @namespace
15083          */
15084         $.extend( DataTable.ext.internal, {
15085                 _fnExternApiFunc: _fnExternApiFunc,
15086                 _fnBuildAjax: _fnBuildAjax,
15087                 _fnAjaxUpdate: _fnAjaxUpdate,
15088                 _fnAjaxParameters: _fnAjaxParameters,
15089                 _fnAjaxUpdateDraw: _fnAjaxUpdateDraw,
15090                 _fnAjaxDataSrc: _fnAjaxDataSrc,
15091                 _fnAddColumn: _fnAddColumn,
15092                 _fnColumnOptions: _fnColumnOptions,
15093                 _fnAdjustColumnSizing: _fnAdjustColumnSizing,
15094                 _fnVisibleToColumnIndex: _fnVisibleToColumnIndex,
15095                 _fnColumnIndexToVisible: _fnColumnIndexToVisible,
15096                 _fnVisbleColumns: _fnVisbleColumns,
15097                 _fnGetColumns: _fnGetColumns,
15098                 _fnColumnTypes: _fnColumnTypes,
15099                 _fnApplyColumnDefs: _fnApplyColumnDefs,
15100                 _fnHungarianMap: _fnHungarianMap,
15101                 _fnCamelToHungarian: _fnCamelToHungarian,
15102                 _fnLanguageCompat: _fnLanguageCompat,
15103                 _fnBrowserDetect: _fnBrowserDetect,
15104                 _fnAddData: _fnAddData,
15105                 _fnAddTr: _fnAddTr,
15106                 _fnNodeToDataIndex: _fnNodeToDataIndex,
15107                 _fnNodeToColumnIndex: _fnNodeToColumnIndex,
15108                 _fnGetCellData: _fnGetCellData,
15109                 _fnSetCellData: _fnSetCellData,
15110                 _fnSplitObjNotation: _fnSplitObjNotation,
15111                 _fnGetObjectDataFn: _fnGetObjectDataFn,
15112                 _fnSetObjectDataFn: _fnSetObjectDataFn,
15113                 _fnGetDataMaster: _fnGetDataMaster,
15114                 _fnClearTable: _fnClearTable,
15115                 _fnDeleteIndex: _fnDeleteIndex,
15116                 _fnInvalidate: _fnInvalidate,
15117                 _fnGetRowElements: _fnGetRowElements,
15118                 _fnCreateTr: _fnCreateTr,
15119                 _fnBuildHead: _fnBuildHead,
15120                 _fnDrawHead: _fnDrawHead,
15121                 _fnDraw: _fnDraw,
15122                 _fnReDraw: _fnReDraw,
15123                 _fnAddOptionsHtml: _fnAddOptionsHtml,
15124                 _fnDetectHeader: _fnDetectHeader,
15125                 _fnGetUniqueThs: _fnGetUniqueThs,
15126                 _fnFeatureHtmlFilter: _fnFeatureHtmlFilter,
15127                 _fnFilterComplete: _fnFilterComplete,
15128                 _fnFilterCustom: _fnFilterCustom,
15129                 _fnFilterColumn: _fnFilterColumn,
15130                 _fnFilter: _fnFilter,
15131                 _fnFilterCreateSearch: _fnFilterCreateSearch,
15132                 _fnEscapeRegex: _fnEscapeRegex,
15133                 _fnFilterData: _fnFilterData,
15134                 _fnFeatureHtmlInfo: _fnFeatureHtmlInfo,
15135                 _fnUpdateInfo: _fnUpdateInfo,
15136                 _fnInfoMacros: _fnInfoMacros,
15137                 _fnInitialise: _fnInitialise,
15138                 _fnInitComplete: _fnInitComplete,
15139                 _fnLengthChange: _fnLengthChange,
15140                 _fnFeatureHtmlLength: _fnFeatureHtmlLength,
15141                 _fnFeatureHtmlPaginate: _fnFeatureHtmlPaginate,
15142                 _fnPageChange: _fnPageChange,
15143                 _fnFeatureHtmlProcessing: _fnFeatureHtmlProcessing,
15144                 _fnProcessingDisplay: _fnProcessingDisplay,
15145                 _fnFeatureHtmlTable: _fnFeatureHtmlTable,
15146                 _fnScrollDraw: _fnScrollDraw,
15147                 _fnApplyToChildren: _fnApplyToChildren,
15148                 _fnCalculateColumnWidths: _fnCalculateColumnWidths,
15149                 _fnThrottle: _fnThrottle,
15150                 _fnConvertToWidth: _fnConvertToWidth,
15151                 _fnGetWidestNode: _fnGetWidestNode,
15152                 _fnGetMaxLenString: _fnGetMaxLenString,
15153                 _fnStringToCss: _fnStringToCss,
15154                 _fnSortFlatten: _fnSortFlatten,
15155                 _fnSort: _fnSort,
15156                 _fnSortAria: _fnSortAria,
15157                 _fnSortListener: _fnSortListener,
15158                 _fnSortAttachListener: _fnSortAttachListener,
15159                 _fnSortingClasses: _fnSortingClasses,
15160                 _fnSortData: _fnSortData,
15161                 _fnSaveState: _fnSaveState,
15162                 _fnLoadState: _fnLoadState,
15163                 _fnSettingsFromNode: _fnSettingsFromNode,
15164                 _fnLog: _fnLog,
15165                 _fnMap: _fnMap,
15166                 _fnBindAction: _fnBindAction,
15167                 _fnCallbackReg: _fnCallbackReg,
15168                 _fnCallbackFire: _fnCallbackFire,
15169                 _fnLengthOverflow: _fnLengthOverflow,
15170                 _fnRenderer: _fnRenderer,
15171                 _fnDataSource: _fnDataSource,
15172                 _fnRowAttributes: _fnRowAttributes,
15173                 _fnExtend: _fnExtend,
15174                 _fnCalculateEnd: function () {} // Used by a lot of plug-ins, but redundant
15175                                                 // in 1.10, so this dead-end function is
15176                                                 // added to prevent errors
15177         } );
15178         
15179
15180         // jQuery access
15181         $.fn.dataTable = DataTable;
15182
15183         // Provide access to the host jQuery object (circular reference)
15184         DataTable.$ = $;
15185
15186         // Legacy aliases
15187         $.fn.dataTableSettings = DataTable.settings;
15188         $.fn.dataTableExt = DataTable.ext;
15189
15190         // With a capital `D` we return a DataTables API instance rather than a
15191         // jQuery object
15192         $.fn.DataTable = function ( opts ) {
15193                 return $(this).dataTable( opts ).api();
15194         };
15195
15196         // All properties that are available to $.fn.dataTable should also be
15197         // available on $.fn.DataTable
15198         $.each( DataTable, function ( prop, val ) {
15199                 $.fn.DataTable[ prop ] = val;
15200         } );
15201
15202
15203         // Information about events fired by DataTables - for documentation.
15204         /**
15205          * Draw event, fired whenever the table is redrawn on the page, at the same
15206          * point as fnDrawCallback. This may be useful for binding events or
15207          * performing calculations when the table is altered at all.
15208          *  @name DataTable#draw.dt
15209          *  @event
15210          *  @param {event} e jQuery event object
15211          *  @param {object} o DataTables settings object {@link DataTable.models.oSettings}
15212          */
15213
15214         /**
15215          * Search event, fired when the searching applied to the table (using the
15216          * built-in global search, or column filters) is altered.
15217          *  @name DataTable#search.dt
15218          *  @event
15219          *  @param {event} e jQuery event object
15220          *  @param {object} o DataTables settings object {@link DataTable.models.oSettings}
15221          */
15222
15223         /**
15224          * Page change event, fired when the paging of the table is altered.
15225          *  @name DataTable#page.dt
15226          *  @event
15227          *  @param {event} e jQuery event object
15228          *  @param {object} o DataTables settings object {@link DataTable.models.oSettings}
15229          */
15230
15231         /**
15232          * Order event, fired when the ordering applied to the table is altered.
15233          *  @name DataTable#order.dt
15234          *  @event
15235          *  @param {event} e jQuery event object
15236          *  @param {object} o DataTables settings object {@link DataTable.models.oSettings}
15237          */
15238
15239         /**
15240          * DataTables initialisation complete event, fired when the table is fully
15241          * drawn, including Ajax data loaded, if Ajax data is required.
15242          *  @name DataTable#init.dt
15243          *  @event
15244          *  @param {event} e jQuery event object
15245          *  @param {object} oSettings DataTables settings object
15246          *  @param {object} json The JSON object request from the server - only
15247          *    present if client-side Ajax sourced data is used</li></ol>
15248          */
15249
15250         /**
15251          * State save event, fired when the table has changed state a new state save
15252          * is required. This event allows modification of the state saving object
15253          * prior to actually doing the save, including addition or other state
15254          * properties (for plug-ins) or modification of a DataTables core property.
15255          *  @name DataTable#stateSaveParams.dt
15256          *  @event
15257          *  @param {event} e jQuery event object
15258          *  @param {object} oSettings DataTables settings object
15259          *  @param {object} json The state information to be saved
15260          */
15261
15262         /**
15263          * State load event, fired when the table is loading state from the stored
15264          * data, but prior to the settings object being modified by the saved state
15265          * - allowing modification of the saved state is required or loading of
15266          * state for a plug-in.
15267          *  @name DataTable#stateLoadParams.dt
15268          *  @event
15269          *  @param {event} e jQuery event object
15270          *  @param {object} oSettings DataTables settings object
15271          *  @param {object} json The saved state information
15272          */
15273
15274         /**
15275          * State loaded event, fired when state has been loaded from stored data and
15276          * the settings object has been modified by the loaded data.
15277          *  @name DataTable#stateLoaded.dt
15278          *  @event
15279          *  @param {event} e jQuery event object
15280          *  @param {object} oSettings DataTables settings object
15281          *  @param {object} json The saved state information
15282          */
15283
15284         /**
15285          * Processing event, fired when DataTables is doing some kind of processing
15286          * (be it, order, search or anything else). It can be used to indicate to
15287          * the end user that there is something happening, or that something has
15288          * finished.
15289          *  @name DataTable#processing.dt
15290          *  @event
15291          *  @param {event} e jQuery event object
15292          *  @param {object} oSettings DataTables settings object
15293          *  @param {boolean} bShow Flag for if DataTables is doing processing or not
15294          */
15295
15296         /**
15297          * Ajax (XHR) event, fired whenever an Ajax request is completed from a
15298          * request to made to the server for new data. This event is called before
15299          * DataTables processed the returned data, so it can also be used to pre-
15300          * process the data returned from the server, if needed.
15301          *
15302          * Note that this trigger is called in `fnServerData`, if you override
15303          * `fnServerData` and which to use this event, you need to trigger it in you
15304          * success function.
15305          *  @name DataTable#xhr.dt
15306          *  @event
15307          *  @param {event} e jQuery event object
15308          *  @param {object} o DataTables settings object {@link DataTable.models.oSettings}
15309          *  @param {object} json JSON returned from the server
15310          *
15311          *  @example
15312          *     // Use a custom property returned from the server in another DOM element
15313          *     $('#table').dataTable().on('xhr.dt', function (e, settings, json) {
15314          *       $('#status').html( json.status );
15315          *     } );
15316          *
15317          *  @example
15318          *     // Pre-process the data returned from the server
15319          *     $('#table').dataTable().on('xhr.dt', function (e, settings, json) {
15320          *       for ( var i=0, ien=json.aaData.length ; i<ien ; i++ ) {
15321          *         json.aaData[i].sum = json.aaData[i].one + json.aaData[i].two;
15322          *       }
15323          *       // Note no return - manipulate the data directly in the JSON object.
15324          *     } );
15325          */
15326
15327         /**
15328          * Destroy event, fired when the DataTable is destroyed by calling fnDestroy
15329          * or passing the bDestroy:true parameter in the initialisation object. This
15330          * can be used to remove bound events, added DOM nodes, etc.
15331          *  @name DataTable#destroy.dt
15332          *  @event
15333          *  @param {event} e jQuery event object
15334          *  @param {object} o DataTables settings object {@link DataTable.models.oSettings}
15335          */
15336
15337         /**
15338          * Page length change event, fired when number of records to show on each
15339          * page (the length) is changed.
15340          *  @name DataTable#length.dt
15341          *  @event
15342          *  @param {event} e jQuery event object
15343          *  @param {object} o DataTables settings object {@link DataTable.models.oSettings}
15344          *  @param {integer} len New length
15345          */
15346
15347         /**
15348          * Column sizing has changed.
15349          *  @name DataTable#column-sizing.dt
15350          *  @event
15351          *  @param {event} e jQuery event object
15352          *  @param {object} o DataTables settings object {@link DataTable.models.oSettings}
15353          */
15354
15355         /**
15356          * Column visibility has changed.
15357          *  @name DataTable#column-visibility.dt
15358          *  @event
15359          *  @param {event} e jQuery event object
15360          *  @param {object} o DataTables settings object {@link DataTable.models.oSettings}
15361          *  @param {int} column Column index
15362          *  @param {bool} vis `false` if column now hidden, or `true` if visible
15363          */
15364
15365         return $.fn.dataTable;
15366 }));
15367
15368
15369 /*! FixedHeader 3.1.7
15370  * ©2009-2020 SpryMedia Ltd - datatables.net/license
15371  */
15372
15373 /**
15374  * @summary     FixedHeader
15375  * @description Fix a table's header or footer, so it is always visible while
15376  *              scrolling
15377  * @version     3.1.7
15378  * @file        dataTables.fixedHeader.js
15379  * @author      SpryMedia Ltd (www.sprymedia.co.uk)
15380  * @contact     www.sprymedia.co.uk/contact
15381  * @copyright   Copyright 2009-2020 SpryMedia Ltd.
15382  *
15383  * This source file is free software, available under the following license:
15384  *   MIT license - http://datatables.net/license/mit
15385  *
15386  * This source file is distributed in the hope that it will be useful, but
15387  * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
15388  * or FITNESS FOR A PARTICULAR PURPOSE. See the license files for details.
15389  *
15390  * For details please refer to: http://www.datatables.net
15391  */
15392
15393 (function( factory ){
15394         if ( typeof define === 'function' && define.amd ) {
15395                 // AMD
15396                 define( ['jquery', 'datatables.net'], function ( $ ) {
15397                         return factory( $, window, document );
15398                 } );
15399         }
15400         else if ( typeof exports === 'object' ) {
15401                 // CommonJS
15402                 module.exports = function (root, $) {
15403                         if ( ! root ) {
15404                                 root = window;
15405                         }
15406
15407                         if ( ! $ || ! $.fn.dataTable ) {
15408                                 $ = require('datatables.net')(root, $).$;
15409                         }
15410
15411                         return factory( $, root, root.document );
15412                 };
15413         }
15414         else {
15415                 // Browser
15416                 factory( jQuery, window, document );
15417         }
15418 }(function( $, window, document, undefined ) {
15419 'use strict';
15420 var DataTable = $.fn.dataTable;
15421
15422
15423 var _instCounter = 0;
15424
15425 var FixedHeader = function ( dt, config ) {
15426         // Sanity check - you just know it will happen
15427         if ( ! (this instanceof FixedHeader) ) {
15428                 throw "FixedHeader must be initialised with the 'new' keyword.";
15429         }
15430
15431         // Allow a boolean true for defaults
15432         if ( config === true ) {
15433                 config = {};
15434         }
15435
15436         dt = new DataTable.Api( dt );
15437
15438         this.c = $.extend( true, {}, FixedHeader.defaults, config );
15439
15440         this.s = {
15441                 dt: dt,
15442                 position: {
15443                         theadTop: 0,
15444                         tbodyTop: 0,
15445                         tfootTop: 0,
15446                         tfootBottom: 0,
15447                         width: 0,
15448                         left: 0,
15449                         tfootHeight: 0,
15450                         theadHeight: 0,
15451                         windowHeight: $(window).height(),
15452                         visible: true
15453                 },
15454                 headerMode: null,
15455                 footerMode: null,
15456                 autoWidth: dt.settings()[0].oFeatures.bAutoWidth,
15457                 namespace: '.dtfc'+(_instCounter++),
15458                 scrollLeft: {
15459                         header: -1,
15460                         footer: -1
15461                 },
15462                 enable: true
15463         };
15464
15465         this.dom = {
15466                 floatingHeader: null,
15467                 thead: $(dt.table().header()),
15468                 tbody: $(dt.table().body()),
15469                 tfoot: $(dt.table().footer()),
15470                 header: {
15471                         host: null,
15472                         floating: null,
15473                         placeholder: null
15474                 },
15475                 footer: {
15476                         host: null,
15477                         floating: null,
15478                         placeholder: null
15479                 }
15480         };
15481
15482         this.dom.header.host = this.dom.thead.parent();
15483         this.dom.footer.host = this.dom.tfoot.parent();
15484
15485         var dtSettings = dt.settings()[0];
15486         if ( dtSettings._fixedHeader ) {
15487                 throw "FixedHeader already initialised on table "+dtSettings.nTable.id;
15488         }
15489
15490         dtSettings._fixedHeader = this;
15491
15492         this._constructor();
15493 };
15494
15495
15496 /*
15497  * Variable: FixedHeader
15498  * Purpose:  Prototype for FixedHeader
15499  * Scope:    global
15500  */
15501 $.extend( FixedHeader.prototype, {
15502         /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
15503          * API methods
15504          */
15505
15506         /**
15507          * Kill off FH and any events
15508          */
15509         destroy: function () {
15510                 this.s.dt.off( '.dtfc' );
15511                 $(window).off( this.s.namespace );
15512
15513                 if ( this.c.header ) {
15514                         this._modeChange( 'in-place', 'header', true );
15515                 }
15516
15517                 if ( this.c.footer && this.dom.tfoot.length ) {
15518                         this._modeChange( 'in-place', 'footer', true );
15519                 }
15520         },
15521
15522         /**
15523          * Enable / disable the fixed elements
15524          *
15525          * @param  {boolean} enable `true` to enable, `false` to disable
15526          */
15527         enable: function ( enable, update )
15528         {
15529                 this.s.enable = enable;
15530
15531                 if ( update || update === undefined ) {
15532                         this._positions();
15533                         this._scroll( true );
15534                 }
15535         },
15536
15537         /**
15538          * Get enabled status
15539          */
15540         enabled: function ()
15541         {
15542                 return this.s.enable;
15543         },
15544         
15545         /**
15546          * Set header offset 
15547          *
15548          * @param  {int} new value for headerOffset
15549          */
15550         headerOffset: function ( offset )
15551         {
15552                 if ( offset !== undefined ) {
15553                         this.c.headerOffset = offset;
15554                         this.update();
15555                 }
15556
15557                 return this.c.headerOffset;
15558         },
15559         
15560         /**
15561          * Set footer offset
15562          *
15563          * @param  {int} new value for footerOffset
15564          */
15565         footerOffset: function ( offset )
15566         {
15567                 if ( offset !== undefined ) {
15568                         this.c.footerOffset = offset;
15569                         this.update();
15570                 }
15571
15572                 return this.c.footerOffset;
15573         },
15574
15575         
15576         /**
15577          * Recalculate the position of the fixed elements and force them into place
15578          */
15579         update: function ()
15580         {
15581                 var table = this.s.dt.table().node();
15582
15583                 if ( $(table).is(':visible') ) {
15584                         this.enable( true, false );
15585                 }
15586                 else {
15587                         this.enable( false, false );
15588                 }
15589
15590                 this._positions();
15591                 this._scroll( true );
15592         },
15593
15594
15595         /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
15596          * Constructor
15597          */
15598         
15599         /**
15600          * FixedHeader constructor - adding the required event listeners and
15601          * simple initialisation
15602          *
15603          * @private
15604          */
15605         _constructor: function ()
15606         {
15607                 var that = this;
15608                 var dt = this.s.dt;
15609
15610                 $(window)
15611                         .on( 'scroll'+this.s.namespace, function () {
15612                                 that._scroll();
15613                         } )
15614                         .on( 'resize'+this.s.namespace, DataTable.util.throttle( function () {
15615                                 that.s.position.windowHeight = $(window).height();
15616                                 that.update();
15617                         }, 50 ) );
15618
15619                 var autoHeader = $('.fh-fixedHeader');
15620                 if ( ! this.c.headerOffset && autoHeader.length ) {
15621                         this.c.headerOffset = autoHeader.outerHeight();
15622                 }
15623
15624                 var autoFooter = $('.fh-fixedFooter');
15625                 if ( ! this.c.footerOffset && autoFooter.length ) {
15626                         this.c.footerOffset = autoFooter.outerHeight();
15627                 }
15628
15629                 dt.on( 'column-reorder.dt.dtfc column-visibility.dt.dtfc draw.dt.dtfc column-sizing.dt.dtfc responsive-display.dt.dtfc', function () {
15630                         that.update();
15631                 } );
15632
15633                 dt.on( 'destroy.dtfc', function () {
15634                         that.destroy();
15635                 } );
15636
15637                 this._positions();
15638                 this._scroll();
15639         },
15640
15641
15642         /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
15643          * Private methods
15644          */
15645
15646         /**
15647          * Clone a fixed item to act as a place holder for the original element
15648          * which is moved into a clone of the table element, and moved around the
15649          * document to give the fixed effect.
15650          *
15651          * @param  {string}  item  'header' or 'footer'
15652          * @param  {boolean} force Force the clone to happen, or allow automatic
15653          *   decision (reuse existing if available)
15654          * @private
15655          */
15656         _clone: function ( item, force )
15657         {
15658                 var dt = this.s.dt;
15659                 var itemDom = this.dom[ item ];
15660                 var itemElement = item === 'header' ?
15661                         this.dom.thead :
15662                         this.dom.tfoot;
15663
15664                 if ( ! force && itemDom.floating ) {
15665                         // existing floating element - reuse it
15666                         itemDom.floating.removeClass( 'fixedHeader-floating fixedHeader-locked' );
15667                 }
15668                 else {
15669                         if ( itemDom.floating ) {
15670                                 itemDom.placeholder.remove();
15671                                 this._unsize( item );
15672                                 itemDom.floating.children().detach();
15673                                 itemDom.floating.remove();
15674                         }
15675
15676                         itemDom.floating = $( dt.table().node().cloneNode( false ) )
15677                                 .css( 'table-layout', 'fixed' )
15678                                 .attr( 'aria-hidden', 'true' )
15679                                 .removeAttr( 'id' )
15680                                 .append( itemElement )
15681                                 .appendTo( 'body' );
15682
15683                         // Insert a fake thead/tfoot into the DataTable to stop it jumping around
15684                         itemDom.placeholder = itemElement.clone( false );
15685                         itemDom.placeholder
15686                                 .find( '*[id]' )
15687                                 .removeAttr( 'id' );
15688
15689                         itemDom.host.prepend( itemDom.placeholder );
15690
15691                         // Clone widths
15692                         this._matchWidths( itemDom.placeholder, itemDom.floating );
15693                 }
15694         },
15695
15696         /**
15697          * Copy widths from the cells in one element to another. This is required
15698          * for the footer as the footer in the main table takes its sizes from the
15699          * header columns. That isn't present in the footer so to have it still
15700          * align correctly, the sizes need to be copied over. It is also required
15701          * for the header when auto width is not enabled
15702          *
15703          * @param  {jQuery} from Copy widths from
15704          * @param  {jQuery} to   Copy widths to
15705          * @private
15706          */
15707         _matchWidths: function ( from, to ) {
15708                 var get = function ( name ) {
15709                         return $(name, from)
15710                                 .map( function () {
15711                                         return $(this).width();
15712                                 } ).toArray();
15713                 };
15714
15715                 var set = function ( name, toWidths ) {
15716                         $(name, to).each( function ( i ) {
15717                                 $(this).css( {
15718                                         width: toWidths[i],
15719                                         minWidth: toWidths[i]
15720                                 } );
15721                         } );
15722                 };
15723
15724                 var thWidths = get( 'th' );
15725                 var tdWidths = get( 'td' );
15726
15727                 set( 'th', thWidths );
15728                 set( 'td', tdWidths );
15729         },
15730
15731         /**
15732          * Remove assigned widths from the cells in an element. This is required
15733          * when inserting the footer back into the main table so the size is defined
15734          * by the header columns and also when auto width is disabled in the
15735          * DataTable.
15736          *
15737          * @param  {string} item The `header` or `footer`
15738          * @private
15739          */
15740         _unsize: function ( item ) {
15741                 var el = this.dom[ item ].floating;
15742
15743                 if ( el && (item === 'footer' || (item === 'header' && ! this.s.autoWidth)) ) {
15744                         $('th, td', el).css( {
15745                                 width: '',
15746                                 minWidth: ''
15747                         } );
15748                 }
15749                 else if ( el && item === 'header' ) {
15750                         $('th, td', el).css( 'min-width', '' );
15751                 }
15752         },
15753
15754         /**
15755          * Reposition the floating elements to take account of horizontal page
15756          * scroll
15757          *
15758          * @param  {string} item       The `header` or `footer`
15759          * @param  {int}    scrollLeft Document scrollLeft
15760          * @private
15761          */
15762         _horizontal: function ( item, scrollLeft )
15763         {
15764                 var itemDom = this.dom[ item ];
15765                 var position = this.s.position;
15766                 var lastScrollLeft = this.s.scrollLeft;
15767
15768                 if ( itemDom.floating && lastScrollLeft[ item ] !== scrollLeft ) {
15769                         itemDom.floating.css( 'left', position.left - scrollLeft );
15770
15771                         lastScrollLeft[ item ] = scrollLeft;
15772                 }
15773         },
15774
15775         /**
15776          * Change from one display mode to another. Each fixed item can be in one
15777          * of:
15778          *
15779          * * `in-place` - In the main DataTable
15780          * * `in` - Floating over the DataTable
15781          * * `below` - (Header only) Fixed to the bottom of the table body
15782          * * `above` - (Footer only) Fixed to the top of the table body
15783          * 
15784          * @param  {string}  mode        Mode that the item should be shown in
15785          * @param  {string}  item        'header' or 'footer'
15786          * @param  {boolean} forceChange Force a redraw of the mode, even if already
15787          *     in that mode.
15788          * @private
15789          */
15790         _modeChange: function ( mode, item, forceChange )
15791         {
15792                 var dt = this.s.dt;
15793                 var itemDom = this.dom[ item ];
15794                 var position = this.s.position;
15795
15796                 // It isn't trivial to add a !important css attribute...
15797                 var importantWidth = function (w) {
15798                         itemDom.floating.attr('style', function(i,s) {
15799                                 return (s || '') + 'width: '+w+'px !important;';
15800                         });
15801                 };
15802
15803                 // Record focus. Browser's will cause input elements to loose focus if
15804                 // they are inserted else where in the doc
15805                 var tablePart = this.dom[ item==='footer' ? 'tfoot' : 'thead' ];
15806                 var focus = $.contains( tablePart[0], document.activeElement ) ?
15807                         document.activeElement :
15808                         null;
15809                 
15810                 if ( focus ) {
15811                         focus.blur();
15812                 }
15813
15814                 if ( mode === 'in-place' ) {
15815                         // Insert the header back into the table's real header
15816                         if ( itemDom.placeholder ) {
15817                                 itemDom.placeholder.remove();
15818                                 itemDom.placeholder = null;
15819                         }
15820
15821                         this._unsize( item );
15822
15823                         if ( item === 'header' ) {
15824                                 itemDom.host.prepend( tablePart );
15825                         }
15826                         else {
15827                                 itemDom.host.append( tablePart );
15828                         }
15829
15830                         if ( itemDom.floating ) {
15831                                 itemDom.floating.remove();
15832                                 itemDom.floating = null;
15833                         }
15834                 }
15835                 else if ( mode === 'in' ) {
15836                         // Remove the header from the read header and insert into a fixed
15837                         // positioned floating table clone
15838                         this._clone( item, forceChange );
15839
15840                         itemDom.floating
15841                                 .addClass( 'fixedHeader-floating' )
15842                                 .css( item === 'header' ? 'top' : 'bottom', this.c[item+'Offset'] )
15843                                 .css( 'left', position.left+'px' );
15844
15845                         importantWidth(position.width);
15846
15847                         if ( item === 'footer' ) {
15848                                 itemDom.floating.css( 'top', '' );
15849                         }
15850                 }
15851                 else if ( mode === 'below' ) { // only used for the header
15852                         // Fix the position of the floating header at base of the table body
15853                         this._clone( item, forceChange );
15854
15855                         itemDom.floating
15856                                 .addClass( 'fixedHeader-locked' )
15857                                 .css( 'top', position.tfootTop - position.theadHeight )
15858                                 .css( 'left', position.left+'px' );
15859
15860                         importantWidth(position.width);
15861                 }
15862                 else if ( mode === 'above' ) { // only used for the footer
15863                         // Fix the position of the floating footer at top of the table body
15864                         this._clone( item, forceChange );
15865
15866                         itemDom.floating
15867                                 .addClass( 'fixedHeader-locked' )
15868                                 .css( 'top', position.tbodyTop )
15869                                 .css( 'left', position.left+'px' );
15870
15871                         importantWidth(position.width);
15872                 }
15873
15874                 // Restore focus if it was lost
15875                 if ( focus && focus !== document.activeElement ) {
15876                         setTimeout( function () {
15877                                 focus.focus();
15878                         }, 10 );
15879                 }
15880
15881                 this.s.scrollLeft.header = -1;
15882                 this.s.scrollLeft.footer = -1;
15883                 this.s[item+'Mode'] = mode;
15884         },
15885
15886         /**
15887          * Cache the positional information that is required for the mode
15888          * calculations that FixedHeader performs.
15889          *
15890          * @private
15891          */
15892         _positions: function ()
15893         {
15894                 var dt = this.s.dt;
15895                 var table = dt.table();
15896                 var position = this.s.position;
15897                 var dom = this.dom;
15898                 var tableNode = $(table.node());
15899
15900                 // Need to use the header and footer that are in the main table,
15901                 // regardless of if they are clones, since they hold the positions we
15902                 // want to measure from
15903                 var thead = tableNode.children('thead');
15904                 var tfoot = tableNode.children('tfoot');
15905                 var tbody = dom.tbody;
15906
15907                 position.visible = tableNode.is(':visible');
15908                 position.width = tableNode.outerWidth();
15909                 position.left = tableNode.offset().left;
15910                 position.theadTop = thead.offset().top;
15911                 position.tbodyTop = tbody.offset().top;
15912                 position.tbodyHeight = tbody.outerHeight();
15913                 position.theadHeight = position.tbodyTop - position.theadTop;
15914
15915                 if ( tfoot.length ) {
15916                         position.tfootTop = tfoot.offset().top;
15917                         position.tfootBottom = position.tfootTop + tfoot.outerHeight();
15918                         position.tfootHeight = position.tfootBottom - position.tfootTop;
15919                 }
15920                 else {
15921                         position.tfootTop = position.tbodyTop + tbody.outerHeight();
15922                         position.tfootBottom = position.tfootTop;
15923                         position.tfootHeight = position.tfootTop;
15924                 }
15925         },
15926
15927
15928         /**
15929          * Mode calculation - determine what mode the fixed items should be placed
15930          * into.
15931          *
15932          * @param  {boolean} forceChange Force a redraw of the mode, even if already
15933          *     in that mode.
15934          * @private
15935          */
15936         _scroll: function ( forceChange )
15937         {
15938                 var windowTop = $(document).scrollTop();
15939                 var windowLeft = $(document).scrollLeft();
15940                 var position = this.s.position;
15941                 var headerMode, footerMode;
15942
15943                 if ( this.c.header ) {
15944                         if ( ! this.s.enable ) {
15945                                 headerMode = 'in-place';
15946                         }
15947                         else if ( ! position.visible || windowTop <= position.theadTop - this.c.headerOffset ) {
15948                                 headerMode = 'in-place';
15949                         }
15950                         else if ( windowTop <= position.tfootTop - position.theadHeight - this.c.headerOffset ) {
15951                                 headerMode = 'in';
15952                         }
15953                         else {
15954                                 headerMode = 'below';
15955                         }
15956
15957                         if ( forceChange || headerMode !== this.s.headerMode ) {
15958                                 this._modeChange( headerMode, 'header', forceChange );
15959                         }
15960
15961                         this._horizontal( 'header', windowLeft );
15962                 }
15963
15964                 if ( this.c.footer && this.dom.tfoot.length ) {
15965                         if ( ! this.s.enable ) {
15966                                 footerMode = 'in-place';
15967                         }
15968                         else if ( ! position.visible || windowTop + position.windowHeight >= position.tfootBottom + this.c.footerOffset ) {
15969                                 footerMode = 'in-place';
15970                         }
15971                         else if ( position.windowHeight + windowTop > position.tbodyTop + position.tfootHeight + this.c.footerOffset ) {
15972                                 footerMode = 'in';
15973                         }
15974                         else {
15975                                 footerMode = 'above';
15976                         }
15977
15978                         if ( forceChange || footerMode !== this.s.footerMode ) {
15979                                 this._modeChange( footerMode, 'footer', forceChange );
15980                         }
15981
15982                         this._horizontal( 'footer', windowLeft );
15983                 }
15984         }
15985 } );
15986
15987
15988 /**
15989  * Version
15990  * @type {String}
15991  * @static
15992  */
15993 FixedHeader.version = "3.1.7";
15994
15995 /**
15996  * Defaults
15997  * @type {Object}
15998  * @static
15999  */
16000 FixedHeader.defaults = {
16001         header: true,
16002         footer: false,
16003         headerOffset: 0,
16004         footerOffset: 0
16005 };
16006
16007
16008 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
16009  * DataTables interfaces
16010  */
16011
16012 // Attach for constructor access
16013 $.fn.dataTable.FixedHeader = FixedHeader;
16014 $.fn.DataTable.FixedHeader = FixedHeader;
16015
16016
16017 // DataTables creation - check if the FixedHeader option has been defined on the
16018 // table and if so, initialise
16019 $(document).on( 'init.dt.dtfh', function (e, settings, json) {
16020         if ( e.namespace !== 'dt' ) {
16021                 return;
16022         }
16023
16024         var init = settings.oInit.fixedHeader;
16025         var defaults = DataTable.defaults.fixedHeader;
16026
16027         if ( (init || defaults) && ! settings._fixedHeader ) {
16028                 var opts = $.extend( {}, defaults, init );
16029
16030                 if ( init !== false ) {
16031                         new FixedHeader( settings, opts );
16032                 }
16033         }
16034 } );
16035
16036 // DataTables API methods
16037 DataTable.Api.register( 'fixedHeader()', function () {} );
16038
16039 DataTable.Api.register( 'fixedHeader.adjust()', function () {
16040         return this.iterator( 'table', function ( ctx ) {
16041                 var fh = ctx._fixedHeader;
16042
16043                 if ( fh ) {
16044                         fh.update();
16045                 }
16046         } );
16047 } );
16048
16049 DataTable.Api.register( 'fixedHeader.enable()', function ( flag ) {
16050         return this.iterator( 'table', function ( ctx ) {
16051                 var fh = ctx._fixedHeader;
16052
16053                 flag = ( flag !== undefined ? flag : true );
16054                 if ( fh && flag !== fh.enabled() ) {
16055                         fh.enable( flag );
16056                 }
16057         } );
16058 } );
16059
16060 DataTable.Api.register( 'fixedHeader.enabled()', function () {
16061         if ( this.context.length ) {
16062                 var fh = this.content[0]._fixedHeader;
16063
16064                 if ( fh ) {
16065                         return fh.enabled();
16066                 }
16067         }
16068
16069         return false;
16070 } );
16071
16072 DataTable.Api.register( 'fixedHeader.disable()', function ( ) {
16073         return this.iterator( 'table', function ( ctx ) {
16074                 var fh = ctx._fixedHeader;
16075
16076                 if ( fh && fh.enabled() ) {
16077                         fh.enable( false );
16078                 }
16079         } );
16080 } );
16081
16082 $.each( ['header', 'footer'], function ( i, el ) {
16083         DataTable.Api.register( 'fixedHeader.'+el+'Offset()', function ( offset ) {
16084                 var ctx = this.context;
16085
16086                 if ( offset === undefined ) {
16087                         return ctx.length && ctx[0]._fixedHeader ?
16088                                 ctx[0]._fixedHeader[el +'Offset']() :
16089                                 undefined;
16090                 }
16091
16092                 return this.iterator( 'table', function ( ctx ) {
16093                         var fh = ctx._fixedHeader;
16094
16095                         if ( fh ) {
16096                                 fh[ el +'Offset' ]( offset );
16097                         }
16098                 } );
16099         } );
16100 } );
16101
16102
16103 return FixedHeader;
16104 }));
16105
16106
16107 /*! SearchPanes 1.1.1
16108  * 2019-2020 SpryMedia Ltd - datatables.net/license
16109  */
16110 (function () {
16111     'use strict';
16112
16113     var $;
16114     var DataTable;
16115     function setJQuery(jq) {
16116         $ = jq;
16117         DataTable = jq.fn.dataTable;
16118     }
16119     var SearchPane = /** @class */ (function () {
16120         /**
16121          * Creates the panes, sets up the search function
16122          * @param paneSettings The settings for the searchPanes
16123          * @param opts The options for the default features
16124          * @param idx the index of the column for this pane
16125          * @returns {object} the pane that has been created, including the table and the index of the pane
16126          */
16127         function SearchPane(paneSettings, opts, idx, layout, panesContainer, panes) {
16128             var _this = this;
16129             if (panes === void 0) { panes = null; }
16130             // Check that the required version of DataTables is included
16131             if (!DataTable || !DataTable.versionCheck || !DataTable.versionCheck('1.10.0')) {
16132                 throw new Error('SearchPane requires DataTables 1.10 or newer');
16133             }
16134             // Check that Select is included
16135             if (!DataTable.select) {
16136                 throw new Error('SearchPane requires Select');
16137             }
16138             var table = new DataTable.Api(paneSettings);
16139             this.classes = $.extend(true, {}, SearchPane.classes);
16140             // Get options from user
16141             this.c = $.extend(true, {}, SearchPane.defaults, opts);
16142             this.customPaneSettings = panes;
16143             this.s = {
16144                 cascadeRegen: false,
16145                 clearing: false,
16146                 colOpts: [],
16147                 deselect: false,
16148                 displayed: false,
16149                 dt: table,
16150                 dtPane: undefined,
16151                 filteringActive: false,
16152                 index: idx,
16153                 indexes: [],
16154                 lastCascade: false,
16155                 lastSelect: false,
16156                 listSet: false,
16157                 name: undefined,
16158                 redraw: false,
16159                 rowData: {
16160                     arrayFilter: [],
16161                     arrayOriginal: [],
16162                     arrayTotals: [],
16163                     bins: {},
16164                     binsOriginal: {},
16165                     binsTotal: {},
16166                     filterMap: new Map(),
16167                     totalOptions: 0
16168                 },
16169                 scrollTop: 0,
16170                 searchFunction: undefined,
16171                 selectPresent: false,
16172                 serverSelect: [],
16173                 serverSelecting: false,
16174                 showFiltered: false,
16175                 tableLength: null,
16176                 updating: false
16177             };
16178             var rowLength = table.columns().eq(0).toArray().length;
16179             this.colExists = this.s.index < rowLength;
16180             // Add extra elements to DOM object including clear and hide buttons
16181             this.c.layout = layout;
16182             var layVal = parseInt(layout.split('-')[1], 10);
16183             this.dom = {
16184                 buttonGroup: $('<div/>').addClass(this.classes.buttonGroup),
16185                 clear: $('<button type="button">&#215;</button>')
16186                     .addClass(this.classes.dull)
16187                     .addClass(this.classes.paneButton)
16188                     .addClass(this.classes.clearButton),
16189                 container: $('<div/>').addClass(this.classes.container).addClass(this.classes.layout +
16190                     (layVal < 10 ? layout : layout.split('-')[0] + '-9')),
16191                 countButton: $('<button type="button"></button>')
16192                     .addClass(this.classes.paneButton)
16193                     .addClass(this.classes.countButton),
16194                 dtP: $('<table><thead><tr><th>' +
16195                     (this.colExists
16196                         ? $(table.column(this.colExists ? this.s.index : 0).header()).text()
16197                         : this.customPaneSettings.header || 'Custom Pane') + '</th><th/></tr></thead></table>'),
16198                 lower: $('<div/>').addClass(this.classes.subRow2).addClass(this.classes.narrowButton),
16199                 nameButton: $('<button type="button"></button>').addClass(this.classes.paneButton).addClass(this.classes.nameButton),
16200                 panesContainer: panesContainer,
16201                 searchBox: $('<input/>').addClass(this.classes.paneInputButton).addClass(this.classes.search),
16202                 searchButton: $('<button type = "button" class="' + this.classes.searchIcon + '"></button>')
16203                     .addClass(this.classes.paneButton),
16204                 searchCont: $('<div/>').addClass(this.classes.searchCont),
16205                 searchLabelCont: $('<div/>').addClass(this.classes.searchLabelCont),
16206                 topRow: $('<div/>').addClass(this.classes.topRow),
16207                 upper: $('<div/>').addClass(this.classes.subRow1).addClass(this.classes.narrowSearch)
16208             };
16209             this.s.displayed = false;
16210             table = this.s.dt;
16211             this.selections = [];
16212             this.s.colOpts = this.colExists ? this._getOptions() : this._getBonusOptions();
16213             var colOpts = this.s.colOpts;
16214             var clear = $('<button type="button">X</button>').addClass(this.classes.paneButton);
16215             $(clear).text(table.i18n('searchPanes.clearPane', 'X'));
16216             this.dom.container.addClass(colOpts.className);
16217             this.dom.container.addClass((this.customPaneSettings !== null && this.customPaneSettings.className !== undefined)
16218                 ? this.customPaneSettings.className
16219                 : '');
16220             // Set the value of name incase ordering is desired
16221             if (this.s.colOpts.name !== undefined) {
16222                 this.s.name = this.s.colOpts.name;
16223             }
16224             else if (this.customPaneSettings !== null && this.customPaneSettings.name !== undefined) {
16225                 this.s.name = this.customPaneSettings.name;
16226             }
16227             else {
16228                 this.s.name = this.colExists ?
16229                     $(table.column(this.s.index).header()).text() :
16230                     this.customPaneSettings.header || 'Custom Pane';
16231             }
16232             $(panesContainer).append(this.dom.container);
16233             var tableNode = table.table(0).node();
16234             // Custom search function for table
16235             this.s.searchFunction = function (settings, searchData, dataIndex, origData) {
16236                 // If no data has been selected then show all
16237                 if (_this.selections.length === 0) {
16238                     return true;
16239                 }
16240                 if (settings.nTable !== tableNode) {
16241                     return true;
16242                 }
16243                 var filter = '';
16244                 if (_this.colExists) {
16245                     // Get the current filtered data
16246                     filter = searchData[_this.s.index];
16247                     if (colOpts.orthogonal.filter !== 'filter') {
16248                         // get the filter value from the map
16249                         filter = _this.s.rowData.filterMap.get(dataIndex);
16250                         if (filter instanceof $.fn.dataTable.Api) {
16251                             filter = filter.toArray();
16252                         }
16253                     }
16254                 }
16255                 return _this._search(filter, dataIndex);
16256             };
16257             $.fn.dataTable.ext.search.push(this.s.searchFunction);
16258             // If the clear button for this pane is clicked clear the selections
16259             if (this.c.clear) {
16260                 $(clear).on('click', function () {
16261                     var searches = _this.dom.container.find(_this.classes.search);
16262                     searches.each(function () {
16263                         $(this).val('');
16264                         $(this).trigger('input');
16265                     });
16266                     _this.clearPane();
16267                 });
16268             }
16269             // Sometimes the top row of the panes containing the search box and ordering buttons appears
16270             //  weird if the width of the panes is lower than expected, this fixes the design.
16271             // Equally this may occur when the table is resized.
16272             table.on('draw.dtsp', function () {
16273                 _this._adjustTopRow();
16274             });
16275             table.on('buttons-action', function () {
16276                 _this._adjustTopRow();
16277             });
16278             $(window).on('resize.dtsp', DataTable.util.throttle(function () {
16279                 _this._adjustTopRow();
16280             }));
16281             // When column-reorder is present and the columns are moved, it is necessary to
16282             //  reassign all of the panes indexes to the new index of the column.
16283             table.on('column-reorder.dtsp', function (e, settings, details) {
16284                 _this.s.index = details.mapping[_this.s.index];
16285             });
16286             return this;
16287         }
16288         /**
16289          * In the case of a rebuild there is potential for new data to have been included or removed
16290          * so all of the rowData must be reset as a precaution.
16291          */
16292         SearchPane.prototype.clearData = function () {
16293             this.s.rowData = {
16294                 arrayFilter: [],
16295                 arrayOriginal: [],
16296                 arrayTotals: [],
16297                 bins: {},
16298                 binsOriginal: {},
16299                 binsTotal: {},
16300                 filterMap: new Map(),
16301                 totalOptions: 0
16302             };
16303         };
16304         /**
16305          * Clear the selections in the pane
16306          */
16307         SearchPane.prototype.clearPane = function () {
16308             // Deselect all rows which are selected and update the table and filter count.
16309             this.s.dtPane.rows({ selected: true }).deselect();
16310             this.updateTable();
16311             return this;
16312         };
16313         /**
16314          * Strips all of the SearchPanes elements from the document and turns all of the listeners for the buttons off
16315          */
16316         SearchPane.prototype.destroy = function () {
16317             $(this.s.dtPane).off('.dtsp');
16318             $(this.s.dt).off('.dtsp');
16319             $(this.dom.nameButton).off('.dtsp');
16320             $(this.dom.countButton).off('.dtsp');
16321             $(this.dom.clear).off('.dtsp');
16322             $(this.dom.searchButton).off('.dtsp');
16323             $(this.dom.container).remove();
16324             var searchIdx = $.fn.dataTable.ext.search.indexOf(this.s.searchFunction);
16325             while (searchIdx !== -1) {
16326                 $.fn.dataTable.ext.search.splice(searchIdx, 1);
16327                 searchIdx = $.fn.dataTable.ext.search.indexOf(this.s.searchFunction);
16328             }
16329             // If the datatables have been defined for the panes then also destroy these
16330             if (this.s.dtPane !== undefined) {
16331                 this.s.dtPane.destroy();
16332             }
16333             this.s.listSet = false;
16334         };
16335         /**
16336          * Updates the number of filters that have been applied in the title
16337          */
16338         SearchPane.prototype.getPaneCount = function () {
16339             return this.s.dtPane !== undefined ?
16340                 this.s.dtPane.rows({ selected: true }).data().toArray().length :
16341                 0;
16342         };
16343         /**
16344          * Rebuilds the panes from the start having deleted the old ones
16345          * @param? last boolean to indicate if this is the last pane a selection was made in
16346          * @param? dataIn data to be used in buildPane
16347          * @param? init Whether this is the initial draw or not
16348          * @param? maintainSelection Whether the current selections are to be maintained over rebuild
16349          */
16350         SearchPane.prototype.rebuildPane = function (last, dataIn, init, maintainSelection) {
16351             if (last === void 0) { last = false; }
16352             if (dataIn === void 0) { dataIn = null; }
16353             if (init === void 0) { init = null; }
16354             if (maintainSelection === void 0) { maintainSelection = false; }
16355             this.clearData();
16356             var selectedRows = [];
16357             this.s.serverSelect = [];
16358             var prevEl = null;
16359             // When rebuilding strip all of the HTML Elements out of the container and start from scratch
16360             if (this.s.dtPane !== undefined) {
16361                 if (maintainSelection) {
16362                     if (!this.s.dt.page.info().serverSide) {
16363                         selectedRows = this.s.dtPane.rows({ selected: true }).data().toArray();
16364                     }
16365                     else {
16366                         this.s.serverSelect = this.s.dtPane.rows({ selected: true }).data().toArray();
16367                     }
16368                 }
16369                 this.s.dtPane.clear().destroy();
16370                 prevEl = $(this.dom.container).prev();
16371                 this.destroy();
16372                 this.s.dtPane = undefined;
16373                 $.fn.dataTable.ext.search.push(this.s.searchFunction);
16374             }
16375             this.dom.container.removeClass(this.classes.hidden);
16376             this.s.displayed = false;
16377             this._buildPane(!this.s.dt.page.info().serverSide ?
16378                 selectedRows :
16379                 this.s.serverSelect, last, dataIn, init, prevEl);
16380             return this;
16381         };
16382         /**
16383          * removes the pane from the page and sets the displayed property to false.
16384          */
16385         SearchPane.prototype.removePane = function () {
16386             this.s.displayed = false;
16387             $(this.dom.container).hide();
16388         };
16389         /**
16390          * Sets the cascadeRegen property of the pane. Accessible from above because as SearchPanes.ts deals with the rebuilds.
16391          * @param val the boolean value that the cascadeRegen property is to be set to
16392          */
16393         SearchPane.prototype.setCascadeRegen = function (val) {
16394             this.s.cascadeRegen = val;
16395         };
16396         /**
16397          * This function allows the clearing property to be assigned. This is used when implementing cascadePane.
16398          * In setting this to true for the clearing of the panes selection on the deselects it forces the pane to
16399          * repopulate from the entire dataset not just the displayed values.
16400          * @param val the boolean value which the clearing property is to be assigned
16401          */
16402         SearchPane.prototype.setClear = function (val) {
16403             this.s.clearing = val;
16404         };
16405         /**
16406          * Updates the values of all of the panes
16407          * @param draw whether this has been triggered by a draw event or not
16408          */
16409         SearchPane.prototype.updatePane = function (draw) {
16410             if (draw === void 0) { draw = false; }
16411             this.s.updating = true;
16412             this._updateCommon(draw);
16413             this.s.updating = false;
16414         };
16415         /**
16416          * Updates the panes if one of the options to do so has been set to true
16417          *   rather than the filtered message when using viewTotal.
16418          */
16419         SearchPane.prototype.updateTable = function () {
16420             var selectedRows = this.s.dtPane.rows({ selected: true }).data().toArray();
16421             this.selections = selectedRows;
16422             this._searchExtras();
16423             // If either of the options that effect how the panes are displayed are selected then update the Panes
16424             if (this.c.cascadePanes || this.c.viewTotal) {
16425                 this.updatePane();
16426             }
16427         };
16428         /**
16429          * Sets the listeners for the pane.
16430          *
16431          * Having it in it's own function makes it easier to only set them once
16432          */
16433         SearchPane.prototype._setListeners = function () {
16434             var _this = this;
16435             var rowData = this.s.rowData;
16436             var t0;
16437             // When an item is selected on the pane, add these to the array which holds selected items.
16438             // Custom search will perform.
16439             this.s.dtPane.on('select.dtsp', function () {
16440                 if (_this.s.dt.page.info().serverSide && !_this.s.updating) {
16441                     if (!_this.s.serverSelecting) {
16442                         _this.s.serverSelect = _this.s.dtPane.rows({ selected: true }).data().toArray();
16443                         _this.s.scrollTop = $(_this.s.dtPane.table().node()).parent()[0].scrollTop;
16444                         _this.s.selectPresent = true;
16445                         _this.s.dt.draw(false);
16446                     }
16447                 }
16448                 else {
16449                     clearTimeout(t0);
16450                     $(_this.dom.clear).removeClass(_this.classes.dull);
16451                     _this.s.selectPresent = true;
16452                     if (!_this.s.updating) {
16453                         _this._makeSelection();
16454                     }
16455                     _this.s.selectPresent = false;
16456                 }
16457             });
16458             // When an item is deselected on the pane, re add the currently selected items to the array
16459             // which holds selected items. Custom search will be performed.
16460             this.s.dtPane.on('deselect.dtsp', function () {
16461                 t0 = setTimeout(function () {
16462                     if (_this.s.dt.page.info().serverSide && !_this.s.updating) {
16463                         if (!_this.s.serverSelecting) {
16464                             _this.s.serverSelect = _this.s.dtPane.rows({ selected: true }).data().toArray();
16465                             _this.s.deselect = true;
16466                             _this.s.dt.draw(false);
16467                         }
16468                     }
16469                     else {
16470                         _this.s.deselect = true;
16471                         if (_this.s.dtPane.rows({ selected: true }).data().toArray().length === 0) {
16472                             $(_this.dom.clear).addClass(_this.classes.dull);
16473                         }
16474                         _this._makeSelection();
16475                         _this.s.deselect = false;
16476                         _this.s.dt.state.save();
16477                     }
16478                 }, 50);
16479             });
16480             // When saving the state store all of the selected rows for preselection next time around
16481             this.s.dt.on('stateSaveParams.dtsp', function (e, settings, data) {
16482                 // If the data being passed in is empty then a state clear must have occured so clear the panes state as well
16483                 if ($.isEmptyObject(data)) {
16484                     _this.s.dtPane.state.clear();
16485                     return;
16486                 }
16487                 var selected = [];
16488                 var searchTerm;
16489                 var order;
16490                 var bins;
16491                 var arrayFilter;
16492                 // Get all of the data needed for the state save from the pane
16493                 if (_this.s.dtPane !== undefined) {
16494                     selected = _this.s.dtPane.rows({ selected: true }).data().map(function (item) { return item.filter.toString(); }).toArray();
16495                     searchTerm = $(_this.dom.searchBox).val();
16496                     order = _this.s.dtPane.order();
16497                     bins = rowData.binsOriginal;
16498                     arrayFilter = rowData.arrayOriginal;
16499                 }
16500                 if (data.searchPanes === undefined) {
16501                     data.searchPanes = {};
16502                 }
16503                 if (data.searchPanes.panes === undefined) {
16504                     data.searchPanes.panes = [];
16505                 }
16506                 // Add the panes data to the state object
16507                 data.searchPanes.panes.push({
16508                     arrayFilter: arrayFilter,
16509                     bins: bins,
16510                     id: _this.s.index,
16511                     order: order,
16512                     searchTerm: searchTerm,
16513                     selected: selected
16514                 });
16515             });
16516             this.s.dtPane.on('user-select.dtsp', function (e, _dt, type, cell, originalEvent) {
16517                 originalEvent.stopPropagation();
16518             });
16519             this.s.dtPane.on('draw.dtsp', function () {
16520                 _this._adjustTopRow();
16521             });
16522             // When the button to order by the name of the options is clicked then
16523             //  change the ordering to whatever it isn't currently
16524             $(this.dom.nameButton).on('click.dtsp', function () {
16525                 var currentOrder = _this.s.dtPane.order()[0][1];
16526                 _this.s.dtPane.order([0, currentOrder === 'asc' ? 'desc' : 'asc']).draw();
16527                 _this.s.dt.state.save();
16528             });
16529             // When the button to order by the number of entries in the column is clicked then
16530             //  change the ordering to whatever it isn't currently
16531             $(this.dom.countButton).on('click.dtsp', function () {
16532                 var currentOrder = _this.s.dtPane.order()[0][1];
16533                 _this.s.dtPane.order([1, currentOrder === 'asc' ? 'desc' : 'asc']).draw();
16534                 _this.s.dt.state.save();
16535             });
16536             // When the clear button is clicked reset the pane
16537             $(this.dom.clear).on('click.dtsp', function () {
16538                 var searches = _this.dom.container.find('.' + _this.classes.search);
16539                 searches.each(function () {
16540                     // set the value of the search box to be an empty string and then search on that, effectively reseting
16541                     $(this).val('');
16542                     $(this).trigger('input');
16543                 });
16544                 _this.clearPane();
16545             });
16546             // When the search button is clicked then draw focus to the search box
16547             $(this.dom.searchButton).on('click.dtsp', function () {
16548                 $(_this.dom.searchBox).focus();
16549             });
16550             // When a character is inputted into the searchbox search the pane for matching values.
16551             // Doing it this way means that no button has to be clicked to trigger a search, it is done asynchronously
16552             $(this.dom.searchBox).on('input.dtsp', function () {
16553                 _this.s.dtPane.search($(_this.dom.searchBox).val()).draw();
16554                 _this.s.dt.state.save();
16555             });
16556             // Make sure to save the state once the pane has been built
16557             this.s.dt.state.save();
16558             return true;
16559         };
16560         /**
16561          * Takes in potentially undetected rows and adds them to the array if they are not yet featured
16562          * @param filter the filter value of the potential row
16563          * @param display the display value of the potential row
16564          * @param sort the sort value of the potential row
16565          * @param type the type value of the potential row
16566          * @param arrayFilter the array to be populated
16567          * @param bins the bins to be populated
16568          */
16569         SearchPane.prototype._addOption = function (filter, display, sort, type, arrayFilter, bins) {
16570             // If the filter is an array then take a note of this, and add the elements to the arrayFilter array
16571             if (Array.isArray(filter) || filter instanceof DataTable.Api) {
16572                 // Convert to an array so that we can work with it
16573                 if (filter instanceof DataTable.Api) {
16574                     filter = filter.toArray();
16575                     display = display.toArray();
16576                 }
16577                 if (filter.length === display.length) {
16578                     for (var i = 0; i < filter.length; i++) {
16579                         // If we haven't seen this row before add it
16580                         if (!bins[filter[i]]) {
16581                             bins[filter[i]] = 1;
16582                             arrayFilter.push({
16583                                 display: display[i],
16584                                 filter: filter[i],
16585                                 sort: sort[i],
16586                                 type: type[i]
16587                             });
16588                         }
16589                         // Otherwise just increment the count
16590                         else {
16591                             bins[filter[i]]++;
16592                         }
16593                         this.s.rowData.totalOptions++;
16594                     }
16595                     return;
16596                 }
16597                 else {
16598                     throw new Error('display and filter not the same length');
16599                 }
16600             }
16601             // If the values were affected by othogonal data and are not an array then check if it is already present
16602             else if (typeof this.s.colOpts.orthogonal === 'string') {
16603                 if (!bins[filter]) {
16604                     bins[filter] = 1;
16605                     arrayFilter.push({
16606                         display: display,
16607                         filter: filter,
16608                         sort: sort,
16609                         type: type
16610                     });
16611                     this.s.rowData.totalOptions++;
16612                 }
16613                 else {
16614                     bins[filter]++;
16615                     this.s.rowData.totalOptions++;
16616                     return;
16617                 }
16618             }
16619             // Otherwise we must just be adding an option
16620             else {
16621                 arrayFilter.push({
16622                     display: display,
16623                     filter: filter,
16624                     sort: sort,
16625                     type: type
16626                 });
16627             }
16628         };
16629         /**
16630          * Adds a row to the panes table
16631          * @param display the value to be displayed to the user
16632          * @param filter the value to be filtered on when searchpanes is implemented
16633          * @param shown the number of rows in the table that are currently visible matching this criteria
16634          * @param total the total number of rows in the table that match this criteria
16635          * @param sort the value to be sorted in the pane table
16636          * @param type the value of which the type is to be derived from
16637          */
16638         SearchPane.prototype._addRow = function (display, filter, shown, total, sort, type) {
16639             var index;
16640             for (var _i = 0, _a = this.s.indexes; _i < _a.length; _i++) {
16641                 var entry = _a[_i];
16642                 if (entry.filter === filter) {
16643                     index = entry.index;
16644                 }
16645             }
16646             if (index === undefined) {
16647                 index = this.s.indexes.length;
16648                 this.s.indexes.push({ filter: filter, index: index });
16649             }
16650             return this.s.dtPane.row.add({
16651                 display: display !== '' ? display : this.c.emptyMessage,
16652                 filter: filter,
16653                 index: index,
16654                 shown: shown,
16655                 sort: sort !== '' ? sort : this.c.emptyMessage,
16656                 total: total,
16657                 type: type
16658             });
16659         };
16660         /**
16661          * Adjusts the layout of the top row when the screen is resized
16662          */
16663         SearchPane.prototype._adjustTopRow = function () {
16664             var subContainers = this.dom.container.find('.' + this.classes.subRowsContainer);
16665             var subRow1 = this.dom.container.find('.dtsp-subRow1');
16666             var subRow2 = this.dom.container.find('.dtsp-subRow2');
16667             var topRow = this.dom.container.find('.' + this.classes.topRow);
16668             // If the width is 0 then it is safe to assume that the pane has not yet been displayed.
16669             //  Even if it has, if the width is 0 it won't make a difference if it has the narrow class or not
16670             if (($(subContainers[0]).width() < 252 || $(topRow[0]).width() < 252) && $(subContainers[0]).width() !== 0) {
16671                 $(subContainers[0]).addClass(this.classes.narrow);
16672                 $(subRow1[0]).addClass(this.classes.narrowSub).removeClass(this.classes.narrowSearch);
16673                 $(subRow2[0]).addClass(this.classes.narrowSub).removeClass(this.classes.narrowButton);
16674             }
16675             else {
16676                 $(subContainers[0]).removeClass(this.classes.narrow);
16677                 $(subRow1[0]).removeClass(this.classes.narrowSub).addClass(this.classes.narrowSearch);
16678                 $(subRow2[0]).removeClass(this.classes.narrowSub).addClass(this.classes.narrowButton);
16679             }
16680         };
16681         /**
16682          * Method to construct the actual pane.
16683          * @param selectedRows previously selected Rows to be reselected
16684          * @last boolean to indicate whether this pane was the last one to have a selection made
16685          */
16686         SearchPane.prototype._buildPane = function (selectedRows, last, dataIn, init, prevEl) {
16687             var _this = this;
16688             if (selectedRows === void 0) { selectedRows = []; }
16689             if (last === void 0) { last = false; }
16690             if (dataIn === void 0) { dataIn = null; }
16691             if (init === void 0) { init = null; }
16692             if (prevEl === void 0) { prevEl = null; }
16693             // Aliases
16694             this.selections = [];
16695             var table = this.s.dt;
16696             var column = table.column(this.colExists ? this.s.index : 0);
16697             var colOpts = this.s.colOpts;
16698             var rowData = this.s.rowData;
16699             // Other Variables
16700             var countMessage = table.i18n('searchPanes.count', '{total}');
16701             var filteredMessage = table.i18n('searchPanes.countFiltered', '{shown} ({total})');
16702             var loadedFilter = table.state.loaded();
16703             // If the listeners have not been set yet then using the latest state may result in funny errors
16704             if (this.s.listSet) {
16705                 loadedFilter = table.state();
16706             }
16707             // If it is not a custom pane in place
16708             if (this.colExists) {
16709                 var idx = -1;
16710                 if (loadedFilter && loadedFilter.searchPanes && loadedFilter.searchPanes.panes) {
16711                     for (var i = 0; i < loadedFilter.searchPanes.panes.length; i++) {
16712                         if (loadedFilter.searchPanes.panes[i].id === this.s.index) {
16713                             idx = i;
16714                             break;
16715                         }
16716                     }
16717                 }
16718                 // Perform checks that do not require populate pane to run
16719                 if ((colOpts.show === false
16720                     || (colOpts.show !== undefined && colOpts.show !== true)) &&
16721                     idx === -1) {
16722                     this.dom.container.addClass(this.classes.hidden);
16723                     this.s.displayed = false;
16724                     return false;
16725                 }
16726                 else if (colOpts.show === true || idx !== -1) {
16727                     this.s.displayed = true;
16728                 }
16729                 if (!this.s.dt.page.info().serverSide) {
16730                     // Only run populatePane if the data has not been collected yet
16731                     if (rowData.arrayFilter.length === 0) {
16732                         this._populatePane(last);
16733                         this.s.rowData.totalOptions = 0;
16734                         this._detailsPane();
16735                         if (loadedFilter && loadedFilter.searchPanes && loadedFilter.searchPanes.panes) {
16736                             // If the index is not found then no data has been added to the state for this pane,
16737                             //  which will only occur if it has previously failed to meet the criteria to be
16738                             //  displayed, therefore we can just hide it again here
16739                             if (idx !== -1) {
16740                                 rowData.binsOriginal = loadedFilter.searchPanes.panes[idx].bins;
16741                                 rowData.arrayOriginal = loadedFilter.searchPanes.panes[idx].arrayFilter;
16742                             }
16743                             else {
16744                                 this.dom.container.addClass(this.classes.hidden);
16745                                 this.s.displayed = false;
16746                                 return;
16747                             }
16748                         }
16749                         else {
16750                             rowData.arrayOriginal = rowData.arrayTotals;
16751                             rowData.binsOriginal = rowData.binsTotal;
16752                         }
16753                     }
16754                     var binLength = Object.keys(rowData.binsOriginal).length;
16755                     var uniqueRatio = this._uniqueRatio(binLength, table.rows()[0].length);
16756                     // Don't show the pane if there isn't enough variance in the data, or there is only 1 entry for that pane
16757                     if (this.s.displayed === false && ((colOpts.show === undefined && colOpts.threshold === null ?
16758                         uniqueRatio > this.c.threshold :
16759                         uniqueRatio > colOpts.threshold)
16760                         || (colOpts.show !== true && binLength <= 1))) {
16761                         this.dom.container.addClass(this.classes.hidden);
16762                         this.s.displayed = false;
16763                         return;
16764                     }
16765                     // If the option viewTotal is true then find
16766                     // the total count for the whole table to display alongside the displayed count
16767                     if (this.c.viewTotal && rowData.arrayTotals.length === 0) {
16768                         this.s.rowData.totalOptions = 0;
16769                         this._detailsPane();
16770                     }
16771                     else {
16772                         rowData.binsTotal = rowData.bins;
16773                     }
16774                     this.dom.container.addClass(this.classes.show);
16775                     this.s.displayed = true;
16776                 }
16777                 else if (dataIn !== null) {
16778                     if (dataIn.tableLength !== undefined) {
16779                         this.s.tableLength = dataIn.tableLength;
16780                         this.s.rowData.totalOptions = this.s.tableLength;
16781                     }
16782                     else if (this.s.tableLength === null || table.rows()[0].length > this.s.tableLength) {
16783                         this.s.tableLength = table.rows()[0].length;
16784                         this.s.rowData.totalOptions = this.s.tableLength;
16785                     }
16786                     var colTitle = table.column(this.s.index).dataSrc();
16787                     if (dataIn[colTitle] !== undefined) {
16788                         for (var _i = 0, _a = dataIn[colTitle]; _i < _a.length; _i++) {
16789                             var dataPoint = _a[_i];
16790                             this.s.rowData.arrayFilter.push({
16791                                 display: dataPoint.label,
16792                                 filter: dataPoint.value,
16793                                 sort: dataPoint.label,
16794                                 type: dataPoint.label
16795                             });
16796                             this.s.rowData.bins[dataPoint.value] = this.c.viewTotal || this.c.cascadePanes ?
16797                                 dataPoint.count :
16798                                 dataPoint.total;
16799                             this.s.rowData.binsTotal[dataPoint.value] = dataPoint.total;
16800                         }
16801                     }
16802                     var binLength = Object.keys(rowData.binsTotal).length;
16803                     var uniqueRatio = this._uniqueRatio(binLength, this.s.tableLength);
16804                     // Don't show the pane if there isn't enough variance in the data, or there is only 1 entry for that pane
16805                     if (this.s.displayed === false && ((colOpts.show === undefined && colOpts.threshold === null ?
16806                         uniqueRatio > this.c.threshold :
16807                         uniqueRatio > colOpts.threshold)
16808                         || (colOpts.show !== true && binLength <= 1))) {
16809                         this.dom.container.addClass(this.classes.hidden);
16810                         this.s.displayed = false;
16811                         return;
16812                     }
16813                     this.s.displayed = true;
16814                 }
16815             }
16816             else {
16817                 this.s.displayed = true;
16818             }
16819             // If the variance is accceptable then display the search pane
16820             this._displayPane();
16821             if (!this.s.listSet) {
16822                 // Here, when the state is loaded if the data object on the original table is empty,
16823                 //  then a state.clear() must have occurred, so delete all of the panes tables state objects too.
16824                 this.dom.dtP.on('stateLoadParams.dt', function (e, settings, data) {
16825                     if ($.isEmptyObject(table.state.loaded())) {
16826                         $.each(data, function (index, value) {
16827                             delete data[index];
16828                         });
16829                     }
16830                 });
16831             }
16832             // Add the container to the document in its original location
16833             if (prevEl !== null && $(this.dom.panesContainer).has(prevEl).length > 0) {
16834                 $(this.dom.panesContainer).insertAfter(prevEl);
16835             }
16836             else {
16837                 $(this.dom.panesContainer).prepend(this.dom.container);
16838             }
16839             // Declare the datatable for the pane
16840             var errMode = $.fn.dataTable.ext.errMode;
16841             $.fn.dataTable.ext.errMode = 'none';
16842             var haveScroller = DataTable.Scroller;
16843             this.s.dtPane = $(this.dom.dtP).DataTable($.extend(true, {
16844                 columnDefs: [
16845                     {
16846                         className: 'dtsp-nameColumn',
16847                         data: 'display',
16848                         render: function (data, type, row) {
16849                             if (type === 'sort') {
16850                                 return row.sort;
16851                             }
16852                             else if (type === 'type') {
16853                                 return row.type;
16854                             }
16855                             var message;
16856                             (_this.s.filteringActive || _this.s.showFiltered) && _this.c.viewTotal
16857                                 ? message = filteredMessage.replace(/{total}/, row.total)
16858                                 : message = countMessage.replace(/{total}/, row.total);
16859                             message = message.replace(/{shown}/, row.shown);
16860                             while (message.indexOf('{total}') !== -1) {
16861                                 message = message.replace(/{total}/, row.total);
16862                             }
16863                             while (message.indexOf('{shown}') !== -1) {
16864                                 message = message.replace(/{shown}/, row.shown);
16865                             }
16866                             // We are displaying the count in the same columne as the name of the search option.
16867                             // This is so that there is not need to call columns.adjust(), which in turn speeds up the code
16868                             var displayMessage = '';
16869                             var pill = '<span class="' + _this.classes.pill + '">' + message + '</span>';
16870                             if (_this.c.hideCount || colOpts.hideCount) {
16871                                 pill = '';
16872                             }
16873                             if (!_this.c.dataLength) {
16874                                 displayMessage = '<span class="' + _this.classes.name + '">' + data + '</span>' + pill;
16875                             }
16876                             else if (data !== null && data.length > _this.c.dataLength) {
16877                                 displayMessage = '<span title="' + data + '" class="' + _this.classes.name + '">'
16878                                     + data.substr(0, _this.c.dataLength) + '...'
16879                                     + '</span>'
16880                                     + pill;
16881                             }
16882                             else {
16883                                 displayMessage = '<span class="' + _this.classes.name + '">' + data + '</span>' + pill;
16884                             }
16885                             return displayMessage;
16886                         },
16887                         targets: 0,
16888                         // Accessing the private datatables property to set type based on the original table.
16889                         // This is null if not defined by the user, meaning that automatic type detection would take place
16890                         type: table.settings()[0].aoColumns[this.s.index] !== undefined ?
16891                             table.settings()[0].aoColumns[this.s.index]._sManualType :
16892                             null
16893                     },
16894                     {
16895                         className: 'dtsp-countColumn ' + this.classes.badgePill,
16896                         data: 'total',
16897                         targets: 1,
16898                         visible: false
16899                     }
16900                 ],
16901                 deferRender: true,
16902                 dom: 't',
16903                 info: false,
16904                 paging: haveScroller ? true : false,
16905                 scrollY: '200px',
16906                 scroller: haveScroller ? true : false,
16907                 select: true,
16908                 stateSave: table.settings()[0].oFeatures.bStateSave ? true : false
16909             }, this.c.dtOpts, colOpts !== undefined ? colOpts.dtOpts : {}, (this.customPaneSettings !== null && this.customPaneSettings.dtOpts !== undefined)
16910                 ? this.customPaneSettings.dtOpts
16911                 : {}));
16912             $(this.dom.dtP).addClass(this.classes.table);
16913             // This is hacky but necessary for when datatables is generating the column titles automatically
16914             $(this.dom.searchBox).attr('placeholder', colOpts.header !== undefined
16915                 ? colOpts.header
16916                 : this.colExists
16917                     ? table.settings()[0].aoColumns[this.s.index].sTitle
16918                     : this.customPaneSettings.header || 'Custom Pane');
16919             // As the pane table is not in the document yet we must initialise select ourselves
16920             $.fn.dataTable.select.init(this.s.dtPane);
16921             $.fn.dataTable.ext.errMode = errMode;
16922             // If it is not a custom pane
16923             if (this.colExists) {
16924                 // On initialisation, do we need to set a filtering value from a
16925                 // saved state or init option?
16926                 var search = column.search();
16927                 search = search ? search.substr(1, search.length - 2).split('|') : [];
16928                 // Count the number of empty cells
16929                 var count_1 = 0;
16930                 rowData.arrayFilter.forEach(function (element) {
16931                     if (element.filter === '') {
16932                         count_1++;
16933                     }
16934                 });
16935                 // Add all of the search options to the pane
16936                 for (var i = 0, ien = rowData.arrayFilter.length; i < ien; i++) {
16937                     var selected = false;
16938                     for (var _b = 0, _c = this.s.serverSelect; _b < _c.length; _b++) {
16939                         var option = _c[_b];
16940                         if (option.filter === rowData.arrayFilter[i].filter) {
16941                             selected = true;
16942                         }
16943                     }
16944                     if (this.s.dt.page.info().serverSide &&
16945                         (!this.c.cascadePanes ||
16946                             (this.c.cascadePanes && rowData.bins[rowData.arrayFilter[i].filter] !== 0) ||
16947                             (this.c.cascadePanes && init !== null) ||
16948                             selected)) {
16949                         var row = this._addRow(rowData.arrayFilter[i].display, rowData.arrayFilter[i].filter, init ?
16950                             rowData.binsTotal[rowData.arrayFilter[i].filter] :
16951                             rowData.bins[rowData.arrayFilter[i].filter], this.c.viewTotal || init
16952                             ? String(rowData.binsTotal[rowData.arrayFilter[i].filter])
16953                             : rowData.bins[rowData.arrayFilter[i].filter], rowData.arrayFilter[i].sort, rowData.arrayFilter[i].type);
16954                         if (colOpts.preSelect !== undefined && colOpts.preSelect.indexOf(rowData.arrayFilter[i].filter) !== -1) {
16955                             row.select();
16956                         }
16957                         for (var _d = 0, _e = this.s.serverSelect; _d < _e.length; _d++) {
16958                             var option = _e[_d];
16959                             if (option.filter === rowData.arrayFilter[i].filter) {
16960                                 this.s.serverSelecting = true;
16961                                 row.select();
16962                                 this.s.serverSelecting = false;
16963                             }
16964                         }
16965                     }
16966                     else if (!this.s.dt.page.info().serverSide &&
16967                         rowData.arrayFilter[i] &&
16968                         (rowData.bins[rowData.arrayFilter[i].filter] !== undefined || !this.c.cascadePanes)) {
16969                         var row = this._addRow(rowData.arrayFilter[i].display, rowData.arrayFilter[i].filter, rowData.bins[rowData.arrayFilter[i].filter], rowData.binsTotal[rowData.arrayFilter[i].filter], rowData.arrayFilter[i].sort, rowData.arrayFilter[i].type);
16970                         if (colOpts.preSelect !== undefined && colOpts.preSelect.indexOf(rowData.arrayFilter[i].filter) !== -1) {
16971                             row.select();
16972                         }
16973                     }
16974                     else if (!this.s.dt.page.info().serverSide) {
16975                         this._addRow(this.c.emptyMessage, count_1, count_1, this.c.emptyMessage, this.c.emptyMessage, this.c.emptyMessage);
16976                     }
16977                 }
16978             }
16979             // If there are custom options set or it is a custom pane then get them
16980             if (colOpts.options !== undefined ||
16981                 (this.customPaneSettings !== null && this.customPaneSettings.options !== undefined)) {
16982                 this._getComparisonRows();
16983             }
16984             DataTable.select.init(this.s.dtPane);
16985             // Display the pane
16986             this.s.dtPane.draw();
16987             this._adjustTopRow();
16988             if (!this.s.listSet) {
16989                 this._setListeners();
16990                 this.s.listSet = true;
16991             }
16992             for (var _f = 0, selectedRows_1 = selectedRows; _f < selectedRows_1.length; _f++) {
16993                 var selection = selectedRows_1[_f];
16994                 if (selection !== undefined) {
16995                     for (var _g = 0, _h = this.s.dtPane.rows().indexes().toArray(); _g < _h.length; _g++) {
16996                         var row = _h[_g];
16997                         if (this.s.dtPane.row(row).data() !== undefined && selection.filter === this.s.dtPane.row(row).data().filter) {
16998                             // If this is happening when serverSide processing is happening then different behaviour is needed
16999                             if (this.s.dt.page.info().serverSide) {
17000                                 this.s.serverSelecting = true;
17001                                 this.s.dtPane.row(row).select();
17002                                 this.s.serverSelecting = false;
17003                             }
17004                             else {
17005                                 this.s.dtPane.row(row).select();
17006                             }
17007                         }
17008                     }
17009                 }
17010             }
17011             this.s.dt.draw();
17012             // Reload the selection, searchbox entry and ordering from the previous state
17013             if (loadedFilter && loadedFilter.searchPanes && loadedFilter.searchPanes.panes) {
17014                 if (!this.c.cascadePanes) {
17015                     this._reloadSelect(loadedFilter);
17016                 }
17017                 for (var _j = 0, _k = loadedFilter.searchPanes.panes; _j < _k.length; _j++) {
17018                     var pane = _k[_j];
17019                     if (pane.id === this.s.index) {
17020                         $(this.dom.searchBox).val(pane.searchTerm);
17021                         $(this.dom.searchBox).trigger('input');
17022                         this.s.dtPane.order(pane.order).draw();
17023                     }
17024                 }
17025             }
17026             // Make sure to save the state once the pane has been built
17027             this.s.dt.state.save();
17028             return true;
17029         };
17030         /**
17031          * Update the array which holds the display and filter values for the table
17032          */
17033         SearchPane.prototype._detailsPane = function () {
17034             var _this = this;
17035             var table = this.s.dt;
17036             this.s.rowData.arrayTotals = [];
17037             this.s.rowData.binsTotal = {};
17038             var settings = this.s.dt.settings()[0];
17039             table.rows().every(function (rowIdx) {
17040                 _this._populatePaneArray(rowIdx, _this.s.rowData.arrayTotals, settings, _this.s.rowData.binsTotal);
17041             });
17042         };
17043         /**
17044          * Appends all of the HTML elements to their relevant parent Elements
17045          */
17046         SearchPane.prototype._displayPane = function () {
17047             var container = this.dom.container;
17048             var colOpts = this.s.colOpts;
17049             var layVal = parseInt(this.c.layout.split('-')[1], 10);
17050             //  Empty everything to start again
17051             $(this.dom.topRow).empty();
17052             $(this.dom.dtP).empty();
17053             $(this.dom.topRow).addClass(this.classes.topRow);
17054             // If there are more than 3 columns defined then make there be a smaller gap between the panes
17055             if (layVal > 3) {
17056                 $(this.dom.container).addClass(this.classes.smallGap);
17057             }
17058             $(this.dom.topRow).addClass(this.classes.subRowsContainer);
17059             $(this.dom.upper).appendTo(this.dom.topRow);
17060             $(this.dom.lower).appendTo(this.dom.topRow);
17061             $(this.dom.searchCont).appendTo(this.dom.upper);
17062             $(this.dom.buttonGroup).appendTo(this.dom.lower);
17063             // If no selections have been made in the pane then disable the clear button
17064             if (this.c.dtOpts.searching === false ||
17065                 (colOpts.dtOpts !== undefined &&
17066                     colOpts.dtOpts.searching === false) ||
17067                 (!this.c.controls || !colOpts.controls) ||
17068                 (this.customPaneSettings !== null &&
17069                     this.customPaneSettings.dtOpts !== undefined &&
17070                     this.customPaneSettings.dtOpts.searching !== undefined &&
17071                     !this.customPaneSettings.dtOpts.searching)) {
17072                 $(this.dom.searchBox).attr('disabled', 'disabled')
17073                     .removeClass(this.classes.paneInputButton)
17074                     .addClass(this.classes.disabledButton);
17075             }
17076             $(this.dom.searchBox).appendTo(this.dom.searchCont);
17077             // Create the contents of the searchCont div. Worth noting that this function will change when using semantic ui
17078             this._searchContSetup();
17079             // If the clear button is allowed to show then display it
17080             if (this.c.clear && this.c.controls && colOpts.controls) {
17081                 $(this.dom.clear).appendTo(this.dom.buttonGroup);
17082             }
17083             if (this.c.orderable && colOpts.orderable && this.c.controls && colOpts.controls) {
17084                 $(this.dom.nameButton).appendTo(this.dom.buttonGroup);
17085             }
17086             // If the count column is hidden then don't display the ordering button for it
17087             if (!this.c.hideCount &&
17088                 !colOpts.hideCount &&
17089                 this.c.orderable &&
17090                 colOpts.orderable &&
17091                 this.c.controls &&
17092                 colOpts.controls) {
17093                 $(this.dom.countButton).appendTo(this.dom.buttonGroup);
17094             }
17095             $(this.dom.topRow).prependTo(this.dom.container);
17096             $(container).append(this.dom.dtP);
17097             $(container).show();
17098         };
17099         /**
17100          * Gets the options for the row for the customPanes
17101          * @returns {object} The options for the row extended to include the options from the user.
17102          */
17103         SearchPane.prototype._getBonusOptions = function () {
17104             // We need to reset the thresholds as if they have a value in colOpts then that value will be used
17105             var defaultMutator = {
17106                 orthogonal: {
17107                     threshold: null
17108                 },
17109                 threshold: null
17110             };
17111             return $.extend(true, {}, SearchPane.defaults, defaultMutator, this.c !== undefined ? this.c : {});
17112         };
17113         /**
17114          * Adds the custom options to the pane
17115          * @returns {Array} Returns the array of rows which have been added to the pane
17116          */
17117         SearchPane.prototype._getComparisonRows = function () {
17118             var colOpts = this.s.colOpts;
17119             // Find the appropriate options depending on whether this is a pane for a specific column or a custom pane
17120             var options = colOpts.options !== undefined
17121                 ? colOpts.options
17122                 : this.customPaneSettings !== null && this.customPaneSettings.options !== undefined
17123                     ? this.customPaneSettings.options
17124                     : undefined;
17125             if (options === undefined) {
17126                 return;
17127             }
17128             var tableVals = this.s.dt.rows({ search: 'applied' }).data().toArray();
17129             var appRows = this.s.dt.rows({ search: 'applied' });
17130             var tableValsTotal = this.s.dt.rows().data().toArray();
17131             var allRows = this.s.dt.rows();
17132             var rows = [];
17133             // Clear all of the other rows from the pane, only custom options are to be displayed when they are defined
17134             this.s.dtPane.clear();
17135             for (var _i = 0, options_1 = options; _i < options_1.length; _i++) {
17136                 var comp = options_1[_i];
17137                 // Initialise the object which is to be placed in the row
17138                 var insert = comp.label !== '' ? comp.label : this.c.emptyMessage;
17139                 var comparisonObj = {
17140                     display: insert,
17141                     filter: typeof comp.value === 'function' ? comp.value : [],
17142                     shown: 0,
17143                     sort: insert,
17144                     total: 0,
17145                     type: insert
17146                 };
17147                 // If a custom function is in place
17148                 if (typeof comp.value === 'function') {
17149                     // Count the number of times the function evaluates to true for the data currently being displayed
17150                     for (var tVal = 0; tVal < tableVals.length; tVal++) {
17151                         if (comp.value.call(this.s.dt, tableVals[tVal], appRows[0][tVal])) {
17152                             comparisonObj.shown++;
17153                         }
17154                     }
17155                     // Count the number of times the function evaluates to true for the original data in the Table
17156                     for (var i = 0; i < tableValsTotal.length; i++) {
17157                         if (comp.value.call(this.s.dt, tableValsTotal[i], allRows[0][i])) {
17158                             comparisonObj.total++;
17159                         }
17160                     }
17161                     // Update the comparisonObj
17162                     if (typeof comparisonObj.filter !== 'function') {
17163                         comparisonObj.filter.push(comp.filter);
17164                     }
17165                 }
17166                 // If cascadePanes is not active or if it is and the comparisonObj should be shown then add it to the pane
17167                 if (!this.c.cascadePanes || (this.c.cascadePanes && comparisonObj.shown !== 0)) {
17168                     rows.push(this._addRow(comparisonObj.display, comparisonObj.filter, comparisonObj.shown, comparisonObj.total, comparisonObj.sort, comparisonObj.type));
17169                 }
17170             }
17171             return rows;
17172         };
17173         /**
17174          * Gets the options for the row for the customPanes
17175          * @returns {object} The options for the row extended to include the options from the user.
17176          */
17177         SearchPane.prototype._getOptions = function () {
17178             var table = this.s.dt;
17179             // We need to reset the thresholds as if they have a value in colOpts then that value will be used
17180             var defaultMutator = {
17181                 orthogonal: {
17182                     threshold: null
17183                 },
17184                 threshold: null
17185             };
17186             return $.extend(true, {}, SearchPane.defaults, defaultMutator, table.settings()[0].aoColumns[this.s.index].searchPanes);
17187         };
17188         /**
17189          * This method allows for changes to the panes and table to be made when a selection or a deselection occurs
17190          * @param select Denotes whether a selection has been made or not
17191          */
17192         SearchPane.prototype._makeSelection = function () {
17193             this.updateTable();
17194             this.s.updating = true;
17195             this.s.dt.draw();
17196             this.s.updating = false;
17197         };
17198         /**
17199          * Fill the array with the values that are currently being displayed in the table
17200          * @param last boolean to indicate whether this was the last pane a selection was made in
17201          */
17202         SearchPane.prototype._populatePane = function (last) {
17203             if (last === void 0) { last = false; }
17204             var table = this.s.dt;
17205             this.s.rowData.arrayFilter = [];
17206             this.s.rowData.bins = {};
17207             var settings = this.s.dt.settings()[0];
17208             // If cascadePanes or viewTotal are active it is necessary to get the data which is currently
17209             //  being displayed for their functionality. Also make sure that this was not the last pane to have a selection made
17210             if (!this.s.dt.page.info().serverSide) {
17211                 var indexArray = (this.c.cascadePanes || this.c.viewTotal) && (!this.s.clearing && !last) ?
17212                     table.rows({ search: 'applied' }).indexes() :
17213                     table.rows().indexes();
17214                 for (var _i = 0, _a = indexArray.toArray(); _i < _a.length; _i++) {
17215                     var index = _a[_i];
17216                     this._populatePaneArray(index, this.s.rowData.arrayFilter, settings);
17217                 }
17218             }
17219         };
17220         /**
17221          * Populates an array with all of the data for the table
17222          * @param rowIdx The current row index to be compared
17223          * @param arrayFilter The array that is to be populated with row Details
17224          * @param bins The bins object that is to be populated with the row counts
17225          */
17226         SearchPane.prototype._populatePaneArray = function (rowIdx, arrayFilter, settings, bins) {
17227             if (bins === void 0) { bins = this.s.rowData.bins; }
17228             var colOpts = this.s.colOpts;
17229             // Retrieve the rendered data from the cell using the fnGetCellData function
17230             //  rather than the cell().render API method for optimisation
17231             if (typeof colOpts.orthogonal === 'string') {
17232                 var rendered = settings.oApi._fnGetCellData(settings, rowIdx, this.s.index, colOpts.orthogonal);
17233                 this.s.rowData.filterMap.set(rowIdx, rendered);
17234                 this._addOption(rendered, rendered, rendered, rendered, arrayFilter, bins);
17235             }
17236             else {
17237                 var filter = settings.oApi._fnGetCellData(settings, rowIdx, this.s.index, colOpts.orthogonal.search);
17238                 this.s.rowData.filterMap.set(rowIdx, filter);
17239                 if (!bins[filter]) {
17240                     bins[filter] = 1;
17241                     this._addOption(filter, settings.oApi._fnGetCellData(settings, rowIdx, this.s.index, colOpts.orthogonal.display), settings.oApi._fnGetCellData(settings, rowIdx, this.s.index, colOpts.orthogonal.sort), settings.oApi._fnGetCellData(settings, rowIdx, this.s.index, colOpts.orthogonal.type), arrayFilter, bins);
17242                     this.s.rowData.totalOptions++;
17243                 }
17244                 else {
17245                     bins[filter]++;
17246                     this.s.rowData.totalOptions++;
17247                     return;
17248                 }
17249             }
17250         };
17251         /**
17252          * Reloads all of the previous selects into the panes
17253          * @param loadedFilter The loaded filters from a previous state
17254          */
17255         SearchPane.prototype._reloadSelect = function (loadedFilter) {
17256             // If the state was not saved don't selected any
17257             if (loadedFilter === undefined) {
17258                 return;
17259             }
17260             var idx;
17261             // For each pane, check that the loadedFilter list exists and is not null,
17262             // find the id of each search item and set it to be selected.
17263             for (var i = 0; i < loadedFilter.searchPanes.panes.length; i++) {
17264                 if (loadedFilter.searchPanes.panes[i].id === this.s.index) {
17265                     idx = i;
17266                     break;
17267                 }
17268             }
17269             if (idx !== undefined) {
17270                 var table = this.s.dtPane;
17271                 var rows = table.rows({ order: 'index' }).data().map(function (item) { return item.filter !== null ?
17272                     item.filter.toString() :
17273                     null; }).toArray();
17274                 for (var _i = 0, _a = loadedFilter.searchPanes.panes[idx].selected; _i < _a.length; _i++) {
17275                     var filter = _a[_i];
17276                     var id = -1;
17277                     if (filter !== null) {
17278                         id = rows.indexOf(filter.toString());
17279                     }
17280                     if (id > -1) {
17281                         table.row(id).select();
17282                         this.s.dt.state.save();
17283                     }
17284                 }
17285             }
17286         };
17287         /**
17288          * This method decides whether a row should contribute to the pane or not
17289          * @param filter the value that the row is to be filtered on
17290          * @param dataIndex the row index
17291          */
17292         SearchPane.prototype._search = function (filter, dataIndex) {
17293             var colOpts = this.s.colOpts;
17294             var table = this.s.dt;
17295             // For each item selected in the pane, check if it is available in the cell
17296             for (var _i = 0, _a = this.selections; _i < _a.length; _i++) {
17297                 var colSelect = _a[_i];
17298                 // if the filter is an array then is the column present in it
17299                 if (Array.isArray(filter)) {
17300                     if (filter.indexOf(colSelect.filter) !== -1) {
17301                         return true;
17302                     }
17303                 }
17304                 // if the filter is a function then does it meet the criteria of that function or not
17305                 else if (typeof colSelect.filter === 'function') {
17306                     if (colSelect.filter.call(table, table.row(dataIndex).data(), dataIndex)) {
17307                         if (colOpts.combiner === 'or') {
17308                             return true;
17309                         }
17310                     }
17311                     // If the combiner is an "and" then we need to check against all possible selections
17312                     //  so if it fails here then the and is not met and return false
17313                     else if (colOpts.combiner === 'and') {
17314                         return false;
17315                     }
17316                 }
17317                 // otherwise if the two filter values are equal then return true
17318                 else if (filter === colSelect.filter) {
17319                     return true;
17320                 }
17321             }
17322             // If the combiner is an and then we need to check against all possible selections
17323             //  so return true here if so because it would have returned false earlier if it had failed
17324             if (colOpts.combiner === 'and') {
17325                 return true;
17326             }
17327             // Otherwise it hasn't matched with anything by this point so it must be false
17328             else {
17329                 return false;
17330             }
17331         };
17332         /**
17333          * Creates the contents of the searchCont div
17334          *
17335          * NOTE This is overridden when semantic ui styling in order to integrate the search button into the text box.
17336          */
17337         SearchPane.prototype._searchContSetup = function () {
17338             if (this.c.controls && this.s.colOpts.controls) {
17339                 $(this.dom.searchButton).appendTo(this.dom.searchLabelCont);
17340             }
17341             if (!(this.c.dtOpts.searching === false ||
17342                 this.s.colOpts.dtOpts.searching === false ||
17343                 (this.customPaneSettings !== null &&
17344                     this.customPaneSettings.dtOpts !== undefined &&
17345                     this.customPaneSettings.dtOpts.searching !== undefined &&
17346                     !this.customPaneSettings.dtOpts.searching))) {
17347                 $(this.dom.searchLabelCont).appendTo(this.dom.searchCont);
17348             }
17349         };
17350         /**
17351          * Adds outline to the pane when a selection has been made
17352          */
17353         SearchPane.prototype._searchExtras = function () {
17354             var updating = this.s.updating;
17355             this.s.updating = true;
17356             var filters = this.s.dtPane.rows({ selected: true }).data().pluck('filter').toArray();
17357             var nullIndex = filters.indexOf(this.c.emptyMessage);
17358             var container = $(this.s.dtPane.table().container());
17359             // If null index is found then search for empty cells as a filter.
17360             if (nullIndex > -1) {
17361                 filters[nullIndex] = '';
17362             }
17363             // If a filter has been applied then outline the respective pane, remove it when it no longer is.
17364             if (filters.length > 0) {
17365                 container.addClass(this.classes.selected);
17366             }
17367             else if (filters.length === 0) {
17368                 container.removeClass(this.classes.selected);
17369             }
17370             this.s.updating = updating;
17371         };
17372         /**
17373          * Finds the ratio of the number of different options in the table to the number of rows
17374          * @param bins the number of different options in the table
17375          * @param rowCount the total number of rows in the table
17376          * @returns {number} returns the ratio
17377          */
17378         SearchPane.prototype._uniqueRatio = function (bins, rowCount) {
17379             if (rowCount > 0 &&
17380                 ((this.s.rowData.totalOptions > 0 && !this.s.dt.page.info().serverSide) ||
17381                     (this.s.dt.page.info().serverSide && this.s.tableLength > 0))) {
17382                 return bins / this.s.rowData.totalOptions;
17383             }
17384             else {
17385                 return 1;
17386             }
17387         };
17388         /**
17389          * updates the options within the pane
17390          * @param draw a flag to define whether this has been called due to a draw event or not
17391          */
17392         SearchPane.prototype._updateCommon = function (draw) {
17393             if (draw === void 0) { draw = false; }
17394             // Update the panes if doing a deselect. if doing a select then
17395             // update all of the panes except for the one causing the change
17396             if (!this.s.dt.page.info().serverSide &&
17397                 this.s.dtPane !== undefined &&
17398                 (!this.s.filteringActive || this.c.cascadePanes || draw === true) &&
17399                 (this.c.cascadePanes !== true || this.s.selectPresent !== true) && (!this.s.lastSelect || !this.s.lastCascade)) {
17400                 var colOpts = this.s.colOpts;
17401                 var selected = this.s.dtPane.rows({ selected: true }).data().toArray();
17402                 var scrollTop = $(this.s.dtPane.table().node()).parent()[0].scrollTop;
17403                 var rowData = this.s.rowData;
17404                 // Clear the pane in preparation for adding the updated search options
17405                 this.s.dtPane.clear();
17406                 // If it is not a custom pane
17407                 if (this.colExists) {
17408                     // Only run populatePane if the data has not been collected yet
17409                     if (rowData.arrayFilter.length === 0) {
17410                         this._populatePane();
17411                     }
17412                     // If cascadePanes is active and the table has returned to its default state then
17413                     //  there is a need to update certain parts ofthe rowData.
17414                     else if (this.c.cascadePanes
17415                         && this.s.dt.rows().data().toArray().length === this.s.dt.rows({ search: 'applied' }).data().toArray().length) {
17416                         rowData.arrayFilter = rowData.arrayOriginal;
17417                         rowData.bins = rowData.binsOriginal;
17418                     }
17419                     // Otherwise if viewTotal or cascadePanes is active then the data from the table must be read.
17420                     else if (this.c.viewTotal || this.c.cascadePanes) {
17421                         this._populatePane();
17422                     }
17423                     // If the viewTotal option is selected then find the totals for the table
17424                     if (this.c.viewTotal) {
17425                         this._detailsPane();
17426                     }
17427                     else {
17428                         rowData.binsTotal = rowData.bins;
17429                     }
17430                     if (this.c.viewTotal && !this.c.cascadePanes) {
17431                         rowData.arrayFilter = rowData.arrayTotals;
17432                     }
17433                     var _loop_1 = function (dataP) {
17434                         // If both view Total and cascadePanes have been selected and the count of the row is not 0 then add it to pane
17435                         // Do this also if the viewTotal option has been selected and cascadePanes has not
17436                         if (dataP && ((rowData.bins[dataP.filter] !== undefined && rowData.bins[dataP.filter] !== 0 && this_1.c.cascadePanes)
17437                             || !this_1.c.cascadePanes
17438                             || this_1.s.clearing)) {
17439                             var row = this_1._addRow(dataP.display, dataP.filter, !this_1.c.viewTotal
17440                                 ? rowData.bins[dataP.filter]
17441                                 : rowData.bins[dataP.filter] !== undefined
17442                                     ? rowData.bins[dataP.filter]
17443                                     : 0, this_1.c.viewTotal
17444                                 ? String(rowData.binsTotal[dataP.filter])
17445                                 : rowData.bins[dataP.filter], dataP.sort, dataP.type);
17446                             // Find out if the filter was selected in the previous search, if so select it and remove from array.
17447                             var selectIndex = selected.findIndex(function (element) {
17448                                 return element.filter === dataP.filter;
17449                             });
17450                             if (selectIndex !== -1) {
17451                                 row.select();
17452                                 selected.splice(selectIndex, 1);
17453                             }
17454                         }
17455                     };
17456                     var this_1 = this;
17457                     for (var _i = 0, _a = rowData.arrayFilter; _i < _a.length; _i++) {
17458                         var dataP = _a[_i];
17459                         _loop_1(dataP);
17460                     }
17461                 }
17462                 if ((colOpts.searchPanes !== undefined && colOpts.searchPanes.options !== undefined) ||
17463                     colOpts.options !== undefined ||
17464                     (this.customPaneSettings !== null && this.customPaneSettings.options !== undefined)) {
17465                     var rows = this._getComparisonRows();
17466                     var _loop_2 = function (row) {
17467                         var selectIndex = selected.findIndex(function (element) {
17468                             if (element.display === row.data().display) {
17469                                 return true;
17470                             }
17471                         });
17472                         if (selectIndex !== -1) {
17473                             row.select();
17474                             selected.splice(selectIndex, 1);
17475                         }
17476                     };
17477                     for (var _b = 0, rows_1 = rows; _b < rows_1.length; _b++) {
17478                         var row = rows_1[_b];
17479                         _loop_2(row);
17480                     }
17481                 }
17482                 // Add search options which were previously selected but whos results are no
17483                 // longer present in the resulting data set.
17484                 for (var _c = 0, selected_1 = selected; _c < selected_1.length; _c++) {
17485                     var selectedEl = selected_1[_c];
17486                     var row = this._addRow(selectedEl.display, selectedEl.filter, 0, this.c.viewTotal
17487                         ? selectedEl.total
17488                         : 0, selectedEl.filter, selectedEl.filter);
17489                     this.s.updating = true;
17490                     row.select();
17491                     this.s.updating = false;
17492                 }
17493                 this.s.dtPane.draw();
17494                 this.s.dtPane.table().node().parentNode.scrollTop = scrollTop;
17495             }
17496         };
17497         SearchPane.version = '1.1.0';
17498         SearchPane.classes = {
17499             buttonGroup: 'dtsp-buttonGroup',
17500             buttonSub: 'dtsp-buttonSub',
17501             clear: 'dtsp-clear',
17502             clearAll: 'dtsp-clearAll',
17503             clearButton: 'clearButton',
17504             container: 'dtsp-searchPane',
17505             countButton: 'dtsp-countButton',
17506             disabledButton: 'dtsp-disabledButton',
17507             dull: 'dtsp-dull',
17508             hidden: 'dtsp-hidden',
17509             hide: 'dtsp-hide',
17510             layout: 'dtsp-',
17511             name: 'dtsp-name',
17512             nameButton: 'dtsp-nameButton',
17513             narrow: 'dtsp-narrow',
17514             paneButton: 'dtsp-paneButton',
17515             paneInputButton: 'dtsp-paneInputButton',
17516             pill: 'dtsp-pill',
17517             search: 'dtsp-search',
17518             searchCont: 'dtsp-searchCont',
17519             searchIcon: 'dtsp-searchIcon',
17520             searchLabelCont: 'dtsp-searchButtonCont',
17521             selected: 'dtsp-selected',
17522             smallGap: 'dtsp-smallGap',
17523             subRow1: 'dtsp-subRow1',
17524             subRow2: 'dtsp-subRow2',
17525             subRowsContainer: 'dtsp-subRowsContainer',
17526             title: 'dtsp-title',
17527             topRow: 'dtsp-topRow'
17528         };
17529         // Define SearchPanes default options
17530         SearchPane.defaults = {
17531             cascadePanes: false,
17532             clear: true,
17533             combiner: 'or',
17534             controls: true,
17535             container: function (dt) {
17536                 return dt.table().container();
17537             },
17538             dataLength: 30,
17539             dtOpts: {},
17540             emptyMessage: '<i>No Data</i>',
17541             hideCount: false,
17542             layout: 'columns-3',
17543             name: undefined,
17544             orderable: true,
17545             orthogonal: {
17546                 display: 'display',
17547                 hideCount: false,
17548                 search: 'filter',
17549                 show: undefined,
17550                 sort: 'sort',
17551                 threshold: 0.6,
17552                 type: 'type'
17553             },
17554             preSelect: [],
17555             threshold: 0.6,
17556             viewTotal: false
17557         };
17558         return SearchPane;
17559     }());
17560
17561     var $$1;
17562     var DataTable$1;
17563     function setJQuery$1(jq) {
17564         $$1 = jq;
17565         DataTable$1 = jq.fn.dataTable;
17566     }
17567     var SearchPanes = /** @class */ (function () {
17568         function SearchPanes(paneSettings, opts, fromInit) {
17569             var _this = this;
17570             if (fromInit === void 0) { fromInit = false; }
17571             this.regenerating = false;
17572             // Check that the required version of DataTables is included
17573             if (!DataTable$1 || !DataTable$1.versionCheck || !DataTable$1.versionCheck('1.10.0')) {
17574                 throw new Error('SearchPane requires DataTables 1.10 or newer');
17575             }
17576             // Check that Select is included
17577             if (!DataTable$1.select) {
17578                 throw new Error('SearchPane requires Select');
17579             }
17580             var table = new DataTable$1.Api(paneSettings);
17581             this.classes = $$1.extend(true, {}, SearchPanes.classes);
17582             // Get options from user
17583             this.c = $$1.extend(true, {}, SearchPanes.defaults, opts);
17584             // Add extra elements to DOM object including clear
17585             this.dom = {
17586                 clearAll: $$1('<button type="button">Clear All</button>').addClass(this.classes.clearAll),
17587                 container: $$1('<div/>').addClass(this.classes.panes).text(table.i18n('searchPanes.loadMessage', 'Loading Search Panes...')),
17588                 emptyMessage: $$1('<div/>').addClass(this.classes.emptyMessage),
17589                 options: $$1('<div/>').addClass(this.classes.container),
17590                 panes: $$1('<div/>').addClass(this.classes.container),
17591                 title: $$1('<div/>').addClass(this.classes.title),
17592                 titleRow: $$1('<div/>').addClass(this.classes.titleRow),
17593                 wrapper: $$1('<div/>')
17594             };
17595             this.s = {
17596                 colOpts: [],
17597                 dt: table,
17598                 filterPane: -1,
17599                 panes: [],
17600                 selectionList: [],
17601                 serverData: {},
17602                 updating: false
17603             };
17604             if (table.settings()[0]._searchPanes !== undefined) {
17605                 return;
17606             }
17607             // We are using the xhr event to rebuild the panes if required due to viewTotal being enabled
17608             // If viewTotal is not enabled then we simply update the data from the server
17609             table.on('xhr', function (e, settings, json, xhr) {
17610                 if (json.searchPanes && json.searchPanes.options) {
17611                     _this.s.serverData = json.searchPanes.options;
17612                     _this.s.serverData.tableLength = json.recordsTotal;
17613                     if (_this.c.viewTotal || _this.c.cascadePanes) {
17614                         _this._serverTotals();
17615                     }
17616                 }
17617             });
17618             table.settings()[0]._searchPanes = this;
17619             this.dom.clearAll.text(table.i18n('searchPanes.clearMessage', 'Clear All'));
17620             this._getState();
17621             if (this.s.dt.settings()[0]._bInitComplete || fromInit) {
17622                 this._paneDeclare(table, paneSettings, opts);
17623             }
17624             else {
17625                 table.one('preInit.dt', function (settings) {
17626                     _this._paneDeclare(table, paneSettings, opts);
17627                 });
17628             }
17629         }
17630         /**
17631          * Clear the selections of all of the panes
17632          */
17633         SearchPanes.prototype.clearSelections = function () {
17634             // Load in all of the searchBoxes in the documents
17635             var searches = this.dom.container.find(this.classes.search);
17636             // For each searchBox set the input text to be empty and then trigger
17637             //  an input on them so that they no longer filter the panes
17638             searches.each(function () {
17639                 $$1(this).val('');
17640                 $$1(this).trigger('input');
17641             });
17642             var returnArray = [];
17643             // For every pane, clear the selections in the pane
17644             for (var _i = 0, _a = this.s.panes; _i < _a.length; _i++) {
17645                 var pane = _a[_i];
17646                 if (pane.s.dtPane !== undefined) {
17647                     returnArray.push(pane.clearPane());
17648                 }
17649             }
17650             this.s.dt.draw();
17651             return returnArray;
17652         };
17653         /**
17654          * returns the container node for the searchPanes
17655          */
17656         SearchPanes.prototype.getNode = function () {
17657             return this.dom.container;
17658         };
17659         /**
17660          * rebuilds all of the panes
17661          */
17662         SearchPanes.prototype.rebuild = function (targetIdx, maintainSelection) {
17663             if (targetIdx === void 0) { targetIdx = false; }
17664             if (maintainSelection === void 0) { maintainSelection = false; }
17665             $$1(this.dom.emptyMessage).remove();
17666             // As a rebuild from scratch is required, empty the searchpanes container.
17667             var returnArray = [];
17668             // Rebuild each pane individually, if a specific pane has been selected then only rebuild that one
17669             $$1(this.dom.panes).empty();
17670             for (var _i = 0, _a = this.s.panes; _i < _a.length; _i++) {
17671                 var pane = _a[_i];
17672                 if (targetIdx !== false && pane.s.index !== targetIdx) {
17673                     $$1(this.dom.panes).append(pane.dom.container);
17674                     continue;
17675                 }
17676                 pane.clearData();
17677                 returnArray.push(
17678                 // Pass a boolean to say whether this is the last choice made for maintaining selections when rebuilding
17679                 pane.rebuildPane(this.s.selectionList[this.s.selectionList.length - 1] !== undefined ?
17680                     pane.s.index === this.s.selectionList[this.s.selectionList.length - 1].index :
17681                     false, this.s.dt.page.info().serverSide ?
17682                     this.s.serverData :
17683                     undefined, null, maintainSelection));
17684                 $$1(this.dom.panes).append(pane.dom.container);
17685             }
17686             if (this.c.cascadePanes || this.c.viewTotal) {
17687                 this.redrawPanes(true);
17688             }
17689             else {
17690                 this._updateSelection();
17691             }
17692             // Attach panes, clear buttons, and title bar to the document
17693             this._updateFilterCount();
17694             this._attachPaneContainer();
17695             this.s.dt.draw();
17696             // If a single pane has been rebuilt then return only that pane
17697             if (returnArray.length === 1) {
17698                 return returnArray[0];
17699             }
17700             // Otherwise return all of the panes that have been rebuilt
17701             else {
17702                 return returnArray;
17703             }
17704         };
17705         /**
17706          * Redraws all of the panes
17707          */
17708         SearchPanes.prototype.redrawPanes = function (rebuild) {
17709             if (rebuild === void 0) { rebuild = false; }
17710             var table = this.s.dt;
17711             // Only do this if the redraw isn't being triggered by the panes updating themselves
17712             if (!this.s.updating && !this.s.dt.page.info().serverSide) {
17713                 var filterActive = true;
17714                 var filterPane = this.s.filterPane;
17715                 // If the number of rows currently visible is equal to the number of rows in the table
17716                 //  then there can't be any filtering taking place
17717                 if (table.rows({ search: 'applied' }).data().toArray().length === table.rows().data().toArray().length) {
17718                     filterActive = false;
17719                 }
17720                 // Otherwise if viewTotal is active then it is necessary to determine which panes a select is present in.
17721                 //  If there is only one pane with a selection present then it should not show the filtered message as
17722                 //  more selections may be made in that pane.
17723                 else if (this.c.viewTotal) {
17724                     for (var _i = 0, _a = this.s.panes; _i < _a.length; _i++) {
17725                         var pane = _a[_i];
17726                         if (pane.s.dtPane !== undefined) {
17727                             var selectLength = pane.s.dtPane.rows({ selected: true }).data().toArray().length;
17728                             if (selectLength === 0) {
17729                                 for (var _b = 0, _c = this.s.selectionList; _b < _c.length; _b++) {
17730                                     var selection = _c[_b];
17731                                     if (selection.index === pane.s.index && selection.rows.length !== 0) {
17732                                         selectLength = selection.rows.length;
17733                                     }
17734                                 }
17735                             }
17736                             // If filterPane === -1 then a pane with a selection has not been found yet, so set filterPane to that panes index
17737                             if (selectLength > 0 && filterPane === -1) {
17738                                 filterPane = pane.s.index;
17739                             }
17740                             // Then if another pane is found with a selection then set filterPane to null to
17741                             //  show that multiple panes have selections present
17742                             else if (selectLength > 0) {
17743                                 filterPane = null;
17744                             }
17745                         }
17746                     }
17747                 }
17748                 var deselectIdx = void 0;
17749                 var newSelectionList = [];
17750                 // Don't run this if it is due to the panes regenerating
17751                 if (!this.regenerating) {
17752                     for (var _d = 0, _e = this.s.panes; _d < _e.length; _d++) {
17753                         var pane = _e[_d];
17754                         // Identify the pane where a selection or deselection has been made and add it to the list.
17755                         if (pane.s.selectPresent) {
17756                             this.s.selectionList.push({ index: pane.s.index, rows: pane.s.dtPane.rows({ selected: true }).data().toArray(), protect: false });
17757                             table.state.save();
17758                             break;
17759                         }
17760                         else if (pane.s.deselect) {
17761                             deselectIdx = pane.s.index;
17762                             var selectedData = pane.s.dtPane.rows({ selected: true }).data().toArray();
17763                             if (selectedData.length > 0) {
17764                                 this.s.selectionList.push({ index: pane.s.index, rows: selectedData, protect: true });
17765                             }
17766                         }
17767                     }
17768                     if (this.s.selectionList.length > 0) {
17769                         var last = this.s.selectionList[this.s.selectionList.length - 1].index;
17770                         for (var _f = 0, _g = this.s.panes; _f < _g.length; _f++) {
17771                             var pane = _g[_f];
17772                             pane.s.lastSelect = (pane.s.index === last);
17773                         }
17774                     }
17775                     // Remove selections from the list from the pane where a deselect has taken place
17776                     for (var i = 0; i < this.s.selectionList.length; i++) {
17777                         if (this.s.selectionList[i].index !== deselectIdx || this.s.selectionList[i].protect === true) {
17778                             var further = false;
17779                             // Find out if this selection is the last one in the list for that pane
17780                             for (var j = i + 1; j < this.s.selectionList.length; j++) {
17781                                 if (this.s.selectionList[j].index === this.s.selectionList[i].index) {
17782                                     further = true;
17783                                 }
17784                             }
17785                             // If there are no selections for this pane in the list then just push this one
17786                             if (!further) {
17787                                 newSelectionList.push(this.s.selectionList[i]);
17788                                 this.s.selectionList[i].protect = false;
17789                             }
17790                         }
17791                     }
17792                     var solePane = -1;
17793                     if (newSelectionList.length === 1) {
17794                         solePane = newSelectionList[0].index;
17795                     }
17796                     // Update all of the panes to reflect the current state of the filters
17797                     for (var _h = 0, _j = this.s.panes; _h < _j.length; _h++) {
17798                         var pane = _j[_h];
17799                         if (pane.s.dtPane !== undefined) {
17800                             var tempFilter = true;
17801                             pane.s.filteringActive = true;
17802                             if ((filterPane !== -1 && filterPane !== null && filterPane === pane.s.index) ||
17803                                 filterActive === false ||
17804                                 pane.s.index === solePane) {
17805                                 tempFilter = false;
17806                                 pane.s.filteringActive = false;
17807                             }
17808                             pane.updatePane(!tempFilter ? false : filterActive);
17809                         }
17810                     }
17811                     // Update the label that shows how many filters are in place
17812                     this._updateFilterCount();
17813                     // If the length of the selections are different then some of them have been removed and a deselect has occured
17814                     if (newSelectionList.length > 0 && (newSelectionList.length < this.s.selectionList.length || rebuild)) {
17815                         this._cascadeRegen(newSelectionList);
17816                         var last = newSelectionList[newSelectionList.length - 1].index;
17817                         for (var _k = 0, _l = this.s.panes; _k < _l.length; _k++) {
17818                             var pane = _l[_k];
17819                             pane.s.lastSelect = (pane.s.index === last);
17820                         }
17821                     }
17822                     else if (newSelectionList.length > 0) {
17823                         // Update all of the other panes as you would just making a normal selection
17824                         for (var _m = 0, _o = this.s.panes; _m < _o.length; _m++) {
17825                             var paneUpdate = _o[_m];
17826                             if (paneUpdate.s.dtPane !== undefined) {
17827                                 var tempFilter = true;
17828                                 paneUpdate.s.filteringActive = true;
17829                                 if ((filterPane !== -1 && filterPane !== null && filterPane === paneUpdate.s.index) || filterActive === false) {
17830                                     tempFilter = false;
17831                                     paneUpdate.s.filteringActive = false;
17832                                 }
17833                                 paneUpdate.updatePane(!tempFilter ? tempFilter : filterActive);
17834                             }
17835                         }
17836                     }
17837                 }
17838                 else {
17839                     var solePane = -1;
17840                     if (newSelectionList.length === 1) {
17841                         solePane = newSelectionList[0].index;
17842                     }
17843                     for (var _p = 0, _q = this.s.panes; _p < _q.length; _p++) {
17844                         var pane = _q[_p];
17845                         if (pane.s.dtPane !== undefined) {
17846                             var tempFilter = true;
17847                             pane.s.filteringActive = true;
17848                             if ((filterPane !== -1 && filterPane !== null && filterPane === pane.s.index) ||
17849                                 filterActive === false ||
17850                                 pane.s.index === solePane) {
17851                                 tempFilter = false;
17852                                 pane.s.filteringActive = false;
17853                             }
17854                             pane.updatePane(!tempFilter ? tempFilter : filterActive);
17855                         }
17856                     }
17857                     // Update the label that shows how many filters are in place
17858                     this._updateFilterCount();
17859                 }
17860                 if (!filterActive) {
17861                     this.s.selectionList = [];
17862                 }
17863             }
17864         };
17865         /**
17866          * Attach the panes, buttons and title to the document
17867          */
17868         SearchPanes.prototype._attach = function () {
17869             var _this = this;
17870             $$1(this.dom.container).removeClass(this.classes.hide);
17871             $$1(this.dom.titleRow).removeClass(this.classes.hide);
17872             $$1(this.dom.titleRow).remove();
17873             $$1(this.dom.title).appendTo(this.dom.titleRow);
17874             // If the clear button is permitted attach it
17875             if (this.c.clear) {
17876                 $$1(this.dom.clearAll).appendTo(this.dom.titleRow);
17877                 $$1(this.dom.clearAll).on('click.dtsps', function () {
17878                     _this.clearSelections();
17879                 });
17880             }
17881             $$1(this.dom.titleRow).appendTo(this.dom.container);
17882             // Attach the container for each individual pane to the overall container
17883             for (var _i = 0, _a = this.s.panes; _i < _a.length; _i++) {
17884                 var pane = _a[_i];
17885                 $$1(pane.dom.container).appendTo(this.dom.panes);
17886             }
17887             // Attach everything to the document
17888             $$1(this.dom.panes).appendTo(this.dom.container);
17889             if ($$1('div.' + this.classes.container).length === 0) {
17890                 $$1(this.dom.container).prependTo(this.s.dt);
17891             }
17892             return this.dom.container;
17893         };
17894         /**
17895          * Attach the top row containing the filter count and clear all button
17896          */
17897         SearchPanes.prototype._attachExtras = function () {
17898             $$1(this.dom.container).removeClass(this.classes.hide);
17899             $$1(this.dom.titleRow).removeClass(this.classes.hide);
17900             $$1(this.dom.titleRow).remove();
17901             $$1(this.dom.title).appendTo(this.dom.titleRow);
17902             // If the clear button is permitted attach it
17903             if (this.c.clear) {
17904                 $$1(this.dom.clearAll).appendTo(this.dom.titleRow);
17905             }
17906             $$1(this.dom.titleRow).appendTo(this.dom.container);
17907             return this.dom.container;
17908         };
17909         /**
17910          * If there are no panes to display then this method is called to either
17911          *   display a message in their place or hide them completely.
17912          */
17913         SearchPanes.prototype._attachMessage = function () {
17914             // Create a message to display on the screen
17915             var message;
17916             try {
17917                 message = this.s.dt.i18n('searchPanes.emptyPanes', 'No SearchPanes');
17918             }
17919             catch (error) {
17920                 message = null;
17921             }
17922             // If the message is an empty string then searchPanes.emptyPanes is undefined,
17923             //  therefore the pane container should be removed from the display
17924             if (message === null) {
17925                 $$1(this.dom.container).addClass(this.classes.hide);
17926                 $$1(this.dom.titleRow).removeClass(this.classes.hide);
17927                 return;
17928             }
17929             else {
17930                 $$1(this.dom.container).removeClass(this.classes.hide);
17931                 $$1(this.dom.titleRow).addClass(this.classes.hide);
17932             }
17933             // Otherwise display the message
17934             $$1(this.dom.emptyMessage).text(message);
17935             this.dom.emptyMessage.appendTo(this.dom.container);
17936             return this.dom.container;
17937         };
17938         /**
17939          * Attaches the panes to the document and displays a message or hides if there are none
17940          */
17941         SearchPanes.prototype._attachPaneContainer = function () {
17942             // If a pane is to be displayed then attach the normal pane output
17943             for (var _i = 0, _a = this.s.panes; _i < _a.length; _i++) {
17944                 var pane = _a[_i];
17945                 if (pane.s.displayed === true) {
17946                     return this._attach();
17947                 }
17948             }
17949             // Otherwise attach the custom message or remove the container from the display
17950             return this._attachMessage();
17951         };
17952         /**
17953          * Prepares the panes for selections to be made when cascade is active and a deselect has occured
17954          * @param newSelectionList the list of selections which are to be made
17955          */
17956         SearchPanes.prototype._cascadeRegen = function (newSelectionList) {
17957             // Set this to true so that the actions taken do not cause this to run until it is finished
17958             this.regenerating = true;
17959             // If only one pane has been selected then take note of its index
17960             var solePane = -1;
17961             if (newSelectionList.length === 1) {
17962                 solePane = newSelectionList[0].index;
17963             }
17964             // Let the pane know that a cascadeRegen is taking place to avoid unexpected behaviour
17965             //  and clear all of the previous selections in the pane
17966             for (var _i = 0, _a = this.s.panes; _i < _a.length; _i++) {
17967                 var pane = _a[_i];
17968                 pane.setCascadeRegen(true);
17969                 pane.setClear(true);
17970                 // If this is the same as the pane with the only selection then pass it as a parameter into clearPane
17971                 if ((pane.s.dtPane !== undefined && pane.s.index === solePane) || pane.s.dtPane !== undefined) {
17972                     pane.clearPane();
17973                 }
17974                 pane.setClear(false);
17975             }
17976             // Remake Selections
17977             this._makeCascadeSelections(newSelectionList);
17978             // Set the selection list property to be the list without the selections from the deselect pane
17979             this.s.selectionList = newSelectionList;
17980             // The regeneration of selections is over so set it back to false
17981             for (var _b = 0, _c = this.s.panes; _b < _c.length; _b++) {
17982                 var pane = _c[_b];
17983                 pane.setCascadeRegen(false);
17984             }
17985             this.regenerating = false;
17986         };
17987         /**
17988          * Attaches the message to the document but does not add any panes
17989          */
17990         SearchPanes.prototype._checkMessage = function () {
17991             // If a pane is to be displayed then attach the normal pane output
17992             for (var _i = 0, _a = this.s.panes; _i < _a.length; _i++) {
17993                 var pane = _a[_i];
17994                 if (pane.s.displayed === true) {
17995                     return;
17996                 }
17997             }
17998             // Otherwise attach the custom message or remove the container from the display
17999             return this._attachMessage();
18000         };
18001         /**
18002          * Gets the selection list from the previous state and stores it in the selectionList Property
18003          */
18004         SearchPanes.prototype._getState = function () {
18005             var loadedFilter = this.s.dt.state.loaded();
18006             if (loadedFilter && loadedFilter.searchPanes && loadedFilter.searchPanes.selectionList !== undefined) {
18007                 this.s.selectionList = loadedFilter.searchPanes.selectionList;
18008             }
18009         };
18010         /**
18011          * Makes all of the selections when cascade is active
18012          * @param newSelectionList the list of selections to be made, in the order they were originally selected
18013          */
18014         SearchPanes.prototype._makeCascadeSelections = function (newSelectionList) {
18015             // make selections in the order they were made previously, excluding those from the pane where a deselect was made
18016             for (var i = 0; i < newSelectionList.length; i++) {
18017                 var _loop_1 = function (pane) {
18018                     if (pane.s.index === newSelectionList[i].index && pane.s.dtPane !== undefined) {
18019                         // When regenerating the cascade selections we need this flag so that the panes are only ignored if it
18020                         //  is the last selection and the pane for that selection
18021                         if (i === newSelectionList.length - 1) {
18022                             pane.s.lastCascade = true;
18023                         }
18024                         // if there are any selections currently in the pane then deselect them as we are about to make our new selections
18025                         if (pane.s.dtPane.rows({ selected: true }).data().toArray().length > 0 && pane.s.dtPane !== undefined) {
18026                             pane.setClear(true);
18027                             pane.clearPane();
18028                             pane.setClear(false);
18029                         }
18030                         var _loop_2 = function (row) {
18031                             pane.s.dtPane.rows().every(function (rowIdx) {
18032                                 if (pane.s.dtPane.row(rowIdx).data() !== undefined &&
18033                                     row !== undefined &&
18034                                     pane.s.dtPane.row(rowIdx).data().filter === row.filter) {
18035                                     pane.s.dtPane.row(rowIdx).select();
18036                                 }
18037                             });
18038                         };
18039                         // select every row in the pane that was selected previously
18040                         for (var _i = 0, _a = newSelectionList[i].rows; _i < _a.length; _i++) {
18041                             var row = _a[_i];
18042                             _loop_2(row);
18043                         }
18044                         // Update the label that shows how many filters are in place
18045                         this_1._updateFilterCount();
18046                         pane.s.lastCascade = false;
18047                     }
18048                 };
18049                 var this_1 = this;
18050                 // As the selections may have been made across the panes in a different order to the pane index we must identify
18051                 //  which pane has the index of the selection. This is also important for colreorder etc
18052                 for (var _i = 0, _a = this.s.panes; _i < _a.length; _i++) {
18053                     var pane = _a[_i];
18054                     _loop_1(pane);
18055                 }
18056             }
18057             // Make sure that the state is saved after all of these selections
18058             this.s.dt.state.save();
18059         };
18060         /**
18061          * Declares the instances of individual searchpanes dependant on the number of columns.
18062          * It is necessary to run this once preInit has completed otherwise no panes will be
18063          *  created as the column count will be 0.
18064          * @param table the DataTable api for the parent table
18065          * @param paneSettings the settings passed into the constructor
18066          * @param opts the options passed into the constructor
18067          */
18068         SearchPanes.prototype._paneDeclare = function (table, paneSettings, opts) {
18069             var _this = this;
18070             // Create Panes
18071             table
18072                 .columns(this.c.columns.length > 0 ? this.c.columns : undefined)
18073                 .eq(0)
18074                 .each(function (idx) {
18075                 _this.s.panes.push(new SearchPane(paneSettings, opts, idx, _this.c.layout, _this.dom.panes));
18076             });
18077             // If there is any extra custom panes defined then create panes for them too
18078             var rowLength = table.columns().eq(0).toArray().length;
18079             var paneLength = this.c.panes.length;
18080             for (var i = 0; i < paneLength; i++) {
18081                 var id = rowLength + i;
18082                 this.s.panes.push(new SearchPane(paneSettings, opts, id, this.c.layout, this.dom.panes, this.c.panes[i]));
18083             }
18084             // If a custom ordering is being used
18085             if (this.c.order.length > 0) {
18086                 // Make a new Array of panes based upon the order
18087                 var newPanes = this.c.order.map(function (name, index, values) {
18088                     return _this._findPane(name);
18089                 });
18090                 // Remove the old panes from the dom
18091                 this.dom.panes.empty();
18092                 this.s.panes = newPanes;
18093                 // Append the panes in the correct order
18094                 for (var _i = 0, _a = this.s.panes; _i < _a.length; _i++) {
18095                     var pane = _a[_i];
18096                     this.dom.panes.append(pane.dom.container);
18097                 }
18098             }
18099             // If this internal property is true then the DataTable has been initialised already
18100             if (this.s.dt.settings()[0]._bInitComplete) {
18101                 this._paneStartup(table);
18102             }
18103             else {
18104                 // Otherwise add the paneStartup function to the list of functions that are to be run when the table is initialised
18105                 // This will garauntee that the panes are initialised before the init event and init Complete callback is fired
18106                 this.s.dt.settings()[0].aoInitComplete.push({ fn: function () {
18107                         _this._paneStartup(table);
18108                     } });
18109             }
18110         };
18111         /**
18112          * Finds a pane based upon the name of that pane
18113          * @param name string representing the name of the pane
18114          * @returns SearchPane The pane which has that name
18115          */
18116         SearchPanes.prototype._findPane = function (name) {
18117             for (var _i = 0, _a = this.s.panes; _i < _a.length; _i++) {
18118                 var pane = _a[_i];
18119                 if (name === pane.s.name) {
18120                     return pane;
18121                 }
18122             }
18123         };
18124         /**
18125          * Runs the start up functions for the panes to enable listeners and populate panes
18126          * @param table the DataTable api for the parent Table
18127          */
18128         SearchPanes.prototype._paneStartup = function (table) {
18129             var _this = this;
18130             // Magic number of 500 is a guess at what will be fast
18131             if (this.s.dt.page.info().recordsTotal <= 500) {
18132                 this._startup(table);
18133             }
18134             else {
18135                 setTimeout(function () {
18136                     _this._startup(table);
18137                 }, 100);
18138             }
18139         };
18140         /**
18141          * Works out which panes to update when data is recieved from the server and viewTotal is active
18142          */
18143         SearchPanes.prototype._serverTotals = function () {
18144             var selectPresent = false;
18145             var deselectPresent = false;
18146             var table = this.s.dt;
18147             for (var _i = 0, _a = this.s.panes; _i < _a.length; _i++) {
18148                 var pane = _a[_i];
18149                 // Identify the pane where a selection or deselection has been made and add it to the list.
18150                 if (pane.s.selectPresent) {
18151                     this.s.selectionList.push({ index: pane.s.index, rows: pane.s.dtPane.rows({ selected: true }).data().toArray(), protect: false });
18152                     table.state.save();
18153                     pane.s.selectPresent = false;
18154                     selectPresent = true;
18155                     break;
18156                 }
18157                 else if (pane.s.deselect) {
18158                     var selectedData = pane.s.dtPane.rows({ selected: true }).data().toArray();
18159                     if (selectedData.length > 0) {
18160                         this.s.selectionList.push({ index: pane.s.index, rows: selectedData, protect: true });
18161                     }
18162                     selectPresent = true;
18163                     deselectPresent = true;
18164                 }
18165             }
18166             // Build an updated list based on any selections or deselections added
18167             if (!selectPresent) {
18168                 this.s.selectionList = [];
18169             }
18170             else {
18171                 var newSelectionList = [];
18172                 for (var i = 0; i < this.s.selectionList.length; i++) {
18173                     var further = false;
18174                     // Find out if this selection is the last one in the list for that pane
18175                     for (var j = i + 1; j < this.s.selectionList.length; j++) {
18176                         if (this.s.selectionList[j].index === this.s.selectionList[i].index) {
18177                             further = true;
18178                         }
18179                     }
18180                     // If there are no selections for this pane in the list then just push this one
18181                     if (!further &&
18182                         this.s.panes[this.s.selectionList[i].index].s.dtPane.rows({ selected: true }).data().toArray().length > 0) {
18183                         newSelectionList.push(this.s.selectionList[i]);
18184                     }
18185                 }
18186                 this.s.selectionList = newSelectionList;
18187             }
18188             var initIdx = -1;
18189             // If there has been a deselect and only one pane has a selection then update everything
18190             if (deselectPresent && this.s.selectionList.length === 1) {
18191                 for (var _b = 0, _c = this.s.panes; _b < _c.length; _b++) {
18192                     var pane = _c[_b];
18193                     pane.s.lastSelect = false;
18194                     pane.s.deselect = false;
18195                     if (pane.s.dtPane !== undefined && pane.s.dtPane.rows({ selected: true }).data().toArray().length > 0) {
18196                         initIdx = pane.s.index;
18197                     }
18198                 }
18199             }
18200             // Otherwise if there are more 1 selections then find the last one and set it to not update that pane
18201             else if (this.s.selectionList.length > 0) {
18202                 var last = this.s.selectionList[this.s.selectionList.length - 1].index;
18203                 for (var _d = 0, _e = this.s.panes; _d < _e.length; _d++) {
18204                     var pane = _e[_d];
18205                     pane.s.lastSelect = (pane.s.index === last);
18206                     pane.s.deselect = false;
18207                 }
18208             }
18209             // Otherwise if there are no selections then find where that took place and do not update to maintain scrolling
18210             else if (this.s.selectionList.length === 0) {
18211                 for (var _f = 0, _g = this.s.panes; _f < _g.length; _f++) {
18212                     var pane = _g[_f];
18213                     // pane.s.lastSelect = (pane.s.deselect === true);
18214                     pane.s.lastSelect = false;
18215                     pane.s.deselect = false;
18216                 }
18217             }
18218             $$1(this.dom.panes).empty();
18219             // Rebuild the desired panes
18220             for (var _h = 0, _j = this.s.panes; _h < _j.length; _h++) {
18221                 var pane = _j[_h];
18222                 if (!pane.s.lastSelect) {
18223                     pane.rebuildPane(undefined, this.s.dt.page.info().serverSide ? this.s.serverData : undefined, pane.s.index === initIdx ? true : null, true);
18224                 }
18225                 else {
18226                     pane._setListeners();
18227                 }
18228                 // append all of the panes and enable select
18229                 $$1(this.dom.panes).append(pane.dom.container);
18230                 if (pane.s.dtPane !== undefined) {
18231                     $$1(pane.s.dtPane.table().node()).parent()[0].scrollTop = pane.s.scrollTop;
18232                     $$1.fn.dataTable.select.init(pane.s.dtPane);
18233                 }
18234             }
18235         };
18236         /**
18237          * Initialises the tables previous/preset selections and initialises callbacks for events
18238          * @param table the parent table for which the searchPanes are being created
18239          */
18240         SearchPanes.prototype._startup = function (table) {
18241             var _this = this;
18242             $$1(this.dom.container).text('');
18243             // Attach clear button and title bar to the document
18244             this._attachExtras();
18245             $$1(this.dom.container).append(this.dom.panes);
18246             $$1(this.dom.panes).empty();
18247             if (this.c.viewTotal && !this.c.cascadePanes) {
18248                 var loadedFilter = this.s.dt.state.loaded();
18249                 if (loadedFilter !== null &&
18250                     loadedFilter !== undefined &&
18251                     loadedFilter.searchPanes !== undefined &&
18252                     loadedFilter.searchPanes.panes !== undefined) {
18253                     var filterActive = false;
18254                     for (var _i = 0, _a = loadedFilter.searchPanes.panes; _i < _a.length; _i++) {
18255                         var pane = _a[_i];
18256                         if (pane.selected.length > 0) {
18257                             filterActive = true;
18258                             break;
18259                         }
18260                     }
18261                     if (filterActive) {
18262                         for (var _b = 0, _c = this.s.panes; _b < _c.length; _b++) {
18263                             var pane = _c[_b];
18264                             pane.s.showFiltered = true;
18265                         }
18266                     }
18267                 }
18268             }
18269             for (var _d = 0, _e = this.s.panes; _d < _e.length; _d++) {
18270                 var pane = _e[_d];
18271                 pane.rebuildPane(undefined, this.s.dt.page.info().serverSide ? this.s.serverData : undefined);
18272                 $$1(this.dom.panes).append(pane.dom.container);
18273             }
18274             if (this.c.viewTotal && !this.c.cascadePanes) {
18275                 for (var _f = 0, _g = this.s.panes; _f < _g.length; _f++) {
18276                     var pane = _g[_f];
18277                     pane.updatePane();
18278                 }
18279             }
18280             this._updateFilterCount();
18281             this._checkMessage();
18282             // When a draw is called on the DataTable, update all of the panes incase the data in the DataTable has changed
18283             table.on('draw.dtsps', function () {
18284                 _this._updateFilterCount();
18285                 if ((_this.c.cascadePanes || _this.c.viewTotal) && !_this.s.dt.page.info().serverSide) {
18286                     _this.redrawPanes();
18287                 }
18288                 else {
18289                     _this._updateSelection();
18290                 }
18291                 _this.s.filterPane = -1;
18292             });
18293             // Whenever a state save occurs store the selection list in the state object
18294             this.s.dt.on('stateSaveParams.dtsp', function (e, settings, data) {
18295                 if (data.searchPanes === undefined) {
18296                     data.searchPanes = {};
18297                 }
18298                 data.searchPanes.selectionList = _this.s.selectionList;
18299             });
18300             // If the data is reloaded from the server then it is possible that it has changed completely,
18301             // so we need to rebuild the panes
18302             this.s.dt.on('xhr', function () {
18303                 var processing = false;
18304                 if (!_this.s.dt.page.info().serverSide) {
18305                     _this.s.dt.one('draw', function () {
18306                         if (processing) {
18307                             return;
18308                         }
18309                         processing = true;
18310                         $$1(_this.dom.panes).empty();
18311                         for (var _i = 0, _a = _this.s.panes; _i < _a.length; _i++) {
18312                             var pane = _a[_i];
18313                             pane.clearData(); // Clears all of the bins and will mean that the data has to be re-read
18314                             // Pass a boolean to say whether this is the last choice made for maintaining selections when rebuilding
18315                             pane.rebuildPane(_this.s.selectionList[_this.s.selectionList.length - 1] !== undefined ?
18316                                 pane.s.index === _this.s.selectionList[_this.s.selectionList.length - 1].index :
18317                                 false, undefined, undefined, true);
18318                             $$1(_this.dom.panes).append(pane.dom.container);
18319                         }
18320                         if (_this.c.cascadePanes || _this.c.viewTotal) {
18321                             _this.redrawPanes(_this.c.cascadePanes);
18322                         }
18323                         else {
18324                             _this._updateSelection();
18325                         }
18326                         _this._checkMessage();
18327                     });
18328                 }
18329             });
18330             if (this.s.selectionList !== undefined && this.s.selectionList.length > 0) {
18331                 var last = this.s.selectionList[this.s.selectionList.length - 1].index;
18332                 for (var _h = 0, _j = this.s.panes; _h < _j.length; _h++) {
18333                     var pane = _j[_h];
18334                     pane.s.lastSelect = (pane.s.index === last);
18335                 }
18336             }
18337             // If cascadePanes is active then make the previous selections in the order they were previously
18338             if (this.s.selectionList.length > 0 && this.c.cascadePanes) {
18339                 this._cascadeRegen(this.s.selectionList);
18340             }
18341             // PreSelect any selections which have been defined using the preSelect option
18342             table
18343                 .columns(this.c.columns.length > 0 ? this.c.columns : undefined)
18344                 .eq(0)
18345                 .each(function (idx) {
18346                 if (_this.s.panes[idx] !== undefined &&
18347                     _this.s.panes[idx].s.dtPane !== undefined &&
18348                     _this.s.panes[idx].s.colOpts.preSelect !== undefined) {
18349                     var tableLength = _this.s.panes[idx].s.dtPane.rows().data().toArray().length;
18350                     for (var i = 0; i < tableLength; i++) {
18351                         if (_this.s.panes[idx].s.colOpts.preSelect.indexOf(_this.s.panes[idx].s.dtPane.cell(i, 0).data()) !== -1) {
18352                             _this.s.panes[idx].s.dtPane.row(i).select();
18353                             _this.s.panes[idx].updateTable();
18354                         }
18355                     }
18356                 }
18357             });
18358             // Update the title bar to show how many filters have been selected
18359             this._updateFilterCount();
18360             // If the table is destroyed and restarted then clear the selections so that they do not persist.
18361             table.on('destroy.dtsps', function () {
18362                 for (var _i = 0, _a = _this.s.panes; _i < _a.length; _i++) {
18363                     var pane = _a[_i];
18364                     pane.destroy();
18365                 }
18366                 table.off('.dtsps');
18367                 $$1(_this.dom.clearAll).off('.dtsps');
18368                 $$1(_this.dom.container).remove();
18369                 _this.clearSelections();
18370             });
18371             // When the clear All button has been pressed clear all of the selections in the panes
18372             if (this.c.clear) {
18373                 $$1(this.dom.clearAll).on('click.dtsps', function () {
18374                     _this.clearSelections();
18375                 });
18376             }
18377             if (this.s.dt.page.info().serverSide) {
18378                 table.on('preXhr.dt', function (e, settings, data) {
18379                     if (data.searchPanes === undefined) {
18380                         data.searchPanes = {};
18381                     }
18382                     for (var _i = 0, _a = _this.s.panes; _i < _a.length; _i++) {
18383                         var pane = _a[_i];
18384                         var src = _this.s.dt.column(pane.s.index).dataSrc();
18385                         if (data.searchPanes[src] === undefined) {
18386                             data.searchPanes[src] = {};
18387                         }
18388                         if (pane.s.dtPane !== undefined) {
18389                             var rowData = pane.s.dtPane.rows({ selected: true }).data().toArray();
18390                             for (var i = 0; i < rowData.length; i++) {
18391                                 data.searchPanes[src][i] = rowData[i].display;
18392                             }
18393                         }
18394                     }
18395                     if (_this.c.viewTotal) {
18396                         _this._prepViewTotal();
18397                     }
18398                 });
18399             }
18400             else {
18401                 table.on('preXhr.dt', function (e, settings, data) {
18402                     for (var _i = 0, _a = _this.s.panes; _i < _a.length; _i++) {
18403                         var pane = _a[_i];
18404                         pane.clearData();
18405                     }
18406                 });
18407             }
18408             table.settings()[0]._searchPanes = this;
18409         };
18410         SearchPanes.prototype._prepViewTotal = function () {
18411             var filterPane = this.s.filterPane;
18412             var filterActive = false;
18413             for (var _i = 0, _a = this.s.panes; _i < _a.length; _i++) {
18414                 var pane = _a[_i];
18415                 if (pane.s.dtPane !== undefined) {
18416                     var selectLength = pane.s.dtPane.rows({ selected: true }).data().toArray().length;
18417                     // If filterPane === -1 then a pane with a selection has not been found yet, so set filterPane to that panes index
18418                     if (selectLength > 0 && filterPane === -1) {
18419                         filterPane = pane.s.index;
18420                         filterActive = true;
18421                     }
18422                     // Then if another pane is found with a selection then set filterPane to null to
18423                     //  show that multiple panes have selections present
18424                     else if (selectLength > 0) {
18425                         filterPane = null;
18426                     }
18427                 }
18428             }
18429             // Update all of the panes to reflect the current state of the filters
18430             for (var _b = 0, _c = this.s.panes; _b < _c.length; _b++) {
18431                 var pane = _c[_b];
18432                 if (pane.s.dtPane !== undefined) {
18433                     pane.s.filteringActive = true;
18434                     if ((filterPane !== -1 && filterPane !== null && filterPane === pane.s.index) || filterActive === false) {
18435                         pane.s.filteringActive = false;
18436                     }
18437                 }
18438             }
18439         };
18440         /**
18441          * Updates the number of filters that have been applied in the title
18442          */
18443         SearchPanes.prototype._updateFilterCount = function () {
18444             var filterCount = 0;
18445             // Add the number of all of the filters throughout the panes
18446             for (var _i = 0, _a = this.s.panes; _i < _a.length; _i++) {
18447                 var pane = _a[_i];
18448                 if (pane.s.dtPane !== undefined) {
18449                     filterCount += pane.getPaneCount();
18450                 }
18451             }
18452             // Run the message through the internationalisation method to improve readability
18453             var message = this.s.dt.i18n('searchPanes.title', 'Filters Active - %d', filterCount);
18454             $$1(this.dom.title).text(message);
18455             if (this.c.filterChanged !== undefined && typeof this.c.filterChanged === 'function') {
18456                 this.c.filterChanged(filterCount);
18457             }
18458         };
18459         /**
18460          * Updates the selectionList when cascade is not in place
18461          */
18462         SearchPanes.prototype._updateSelection = function () {
18463             this.s.selectionList = [];
18464             for (var _i = 0, _a = this.s.panes; _i < _a.length; _i++) {
18465                 var pane = _a[_i];
18466                 if (pane.s.dtPane !== undefined) {
18467                     this.s.selectionList.push({ index: pane.s.index, rows: pane.s.dtPane.rows({ selected: true }).data().toArray(), protect: false });
18468                 }
18469             }
18470             this.s.dt.state.save();
18471         };
18472         SearchPanes.version = '1.1.1';
18473         SearchPanes.classes = {
18474             clear: 'dtsp-clear',
18475             clearAll: 'dtsp-clearAll',
18476             container: 'dtsp-searchPanes',
18477             emptyMessage: 'dtsp-emptyMessage',
18478             hide: 'dtsp-hidden',
18479             panes: 'dtsp-panesContainer',
18480             search: 'dtsp-search',
18481             title: 'dtsp-title',
18482             titleRow: 'dtsp-titleRow'
18483         };
18484         // Define SearchPanes default options
18485         SearchPanes.defaults = {
18486             cascadePanes: false,
18487             clear: true,
18488             container: function (dt) {
18489                 return dt.table().container();
18490             },
18491             columns: [],
18492             filterChanged: undefined,
18493             layout: 'columns-3',
18494             order: [],
18495             panes: [],
18496             viewTotal: false
18497         };
18498         return SearchPanes;
18499     }());
18500
18501     /*! SearchPanes 1.1.1
18502      * 2019-2020 SpryMedia Ltd - datatables.net/license
18503      */
18504     // DataTables extensions common UMD. Note that this allows for AMD, CommonJS
18505     // (with window and jQuery being allowed as parameters to the returned
18506     // function) or just default browser loading.
18507     (function (factory) {
18508         if (typeof define === 'function' && define.amd) {
18509             // AMD
18510             define(['jquery', 'datatables.net'], function ($) {
18511                 return factory($, window, document);
18512             });
18513         }
18514         else if (typeof exports === 'object') {
18515             // CommonJS
18516             module.exports = function (root, $) {
18517                 if (!root) {
18518                     root = window;
18519                 }
18520                 if (!$ || !$.fn.dataTable) {
18521                     $ = require('datatables.net')(root, $).$;
18522                 }
18523                 return factory($, root, root.document);
18524             };
18525         }
18526         else {
18527             // Browser - assume jQuery has already been loaded
18528             factory(window.jQuery, window, document);
18529         }
18530     }(function ($, window, document) {
18531         setJQuery($);
18532         setJQuery$1($);
18533         var DataTable = $.fn.dataTable;
18534         $.fn.dataTable.SearchPanes = SearchPanes;
18535         $.fn.DataTable.SearchPanes = SearchPanes;
18536         $.fn.dataTable.SearchPane = SearchPane;
18537         $.fn.DataTable.SearchPane = SearchPane;
18538         DataTable.Api.register('searchPanes.rebuild()', function () {
18539             return this.iterator('table', function () {
18540                 if (this.searchPanes) {
18541                     this.searchPanes.rebuild();
18542                 }
18543             });
18544         });
18545         DataTable.Api.register('column().paneOptions()', function (options) {
18546             return this.iterator('column', function (idx) {
18547                 var col = this.aoColumns[idx];
18548                 if (!col.searchPanes) {
18549                     col.searchPanes = {};
18550                 }
18551                 col.searchPanes.values = options;
18552                 if (this.searchPanes) {
18553                     this.searchPanes.rebuild();
18554                 }
18555             });
18556         });
18557         var apiRegister = $.fn.dataTable.Api.register;
18558         apiRegister('searchPanes()', function () {
18559             return this;
18560         });
18561         apiRegister('searchPanes.clearSelections()', function () {
18562             var ctx = this.context[0];
18563             ctx._searchPanes.clearSelections();
18564             return this;
18565         });
18566         apiRegister('searchPanes.rebuildPane()', function (targetIdx, maintainSelections) {
18567             var ctx = this.context[0];
18568             ctx._searchPanes.rebuild(targetIdx, maintainSelections);
18569             return this;
18570         });
18571         apiRegister('searchPanes.container()', function () {
18572             var ctx = this.context[0];
18573             return ctx._searchPanes.getNode();
18574         });
18575         $.fn.dataTable.ext.buttons.searchPanesClear = {
18576             text: 'Clear Panes',
18577             action: function (e, dt, node, config) {
18578                 dt.searchPanes.clearSelections();
18579             }
18580         };
18581         $.fn.dataTable.ext.buttons.searchPanes = {
18582             action: function (e, dt, node, config) {
18583                 e.stopPropagation();
18584                 this.popover(config._panes.getNode(), {
18585                     align: 'dt-container'
18586                 });
18587             },
18588             config: {},
18589             init: function (dt, node, config) {
18590                 var panes = new $.fn.dataTable.SearchPanes(dt, $.extend({
18591                     filterChanged: function (count) {
18592                         dt.button(node).text(dt.i18n('searchPanes.collapse', { 0: 'SearchPanes', _: 'SearchPanes (%d)' }, count));
18593                     }
18594                 }, config.config));
18595                 var message = dt.i18n('searchPanes.collapse', 'SearchPanes', 0);
18596                 dt.button(node).text(message);
18597                 config._panes = panes;
18598             },
18599             text: 'Search Panes'
18600         };
18601         function _init(settings, fromPre) {
18602             if (fromPre === void 0) { fromPre = false; }
18603             var api = new DataTable.Api(settings);
18604             var opts = api.init().searchPanes || DataTable.defaults.searchPanes;
18605             var searchPanes = new SearchPanes(api, opts, fromPre);
18606             var node = searchPanes.getNode();
18607             return node;
18608         }
18609         // Attach a listener to the document which listens for DataTables initialisation
18610         // events so we can automatically initialise
18611         $(document).on('preInit.dt.dtsp', function (e, settings, json) {
18612             if (e.namespace !== 'dt') {
18613                 return;
18614             }
18615             if (settings.oInit.searchPanes ||
18616                 DataTable.defaults.searchPanes) {
18617                 if (!settings._searchPanes) {
18618                     _init(settings, true);
18619                 }
18620             }
18621         });
18622         // DataTables `dom` feature option
18623         DataTable.ext.feature.push({
18624             cFeature: 'P',
18625             fnInit: _init
18626         });
18627         // DataTables 2 layout feature
18628         if (DataTable.ext.features) {
18629             DataTable.ext.features.register('searchPanes', _init);
18630         }
18631     }));
18632
18633 }());
18634
18635
18636 (function (factory) {
18637     if (typeof define === 'function' && define.amd) {
18638         // AMD
18639         define(['jquery', 'datatables.net-dt', 'datatables.net-searchPanes'], function ($) {
18640             return factory($, window, document);
18641         });
18642     }
18643     else if (typeof exports === 'object') {
18644         // CommonJS
18645         module.exports = function (root, $) {
18646             if (!root) {
18647                 root = window;
18648             }
18649             if (!$ || !$.fn.dataTable) {
18650                 $ = require('datatables.net-dt')(root, $).$;
18651             }
18652             if (!$.fn.dataTable.searchPanes) {
18653                 require('datatables.net-searchpanes')(root, $);
18654             }
18655             return factory($, root, root.document);
18656         };
18657     }
18658     else {
18659         // Browser
18660         factory(jQuery, window, document);
18661     }
18662 }(function ($, window, document) {
18663     'use strict';
18664     var DataTable = $.fn.dataTable;
18665     return DataTable.searchPanes;
18666 }));
18667
18668
18669 /*! Select for DataTables 1.3.1
18670  * 2015-2019 SpryMedia Ltd - datatables.net/license/mit
18671  */
18672
18673 /**
18674  * @summary     Select for DataTables
18675  * @description A collection of API methods, events and buttons for DataTables
18676  *   that provides selection options of the items in a DataTable
18677  * @version     1.3.1
18678  * @file        dataTables.select.js
18679  * @author      SpryMedia Ltd (www.sprymedia.co.uk)
18680  * @contact     datatables.net/forums
18681  * @copyright   Copyright 2015-2019 SpryMedia Ltd.
18682  *
18683  * This source file is free software, available under the following license:
18684  *   MIT license - http://datatables.net/license/mit
18685  *
18686  * This source file is distributed in the hope that it will be useful, but
18687  * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
18688  * or FITNESS FOR A PARTICULAR PURPOSE. See the license files for details.
18689  *
18690  * For details please refer to: http://www.datatables.net/extensions/select
18691  */
18692 (function( factory ){
18693         if ( typeof define === 'function' && define.amd ) {
18694                 // AMD
18695                 define( ['jquery', 'datatables.net'], function ( $ ) {
18696                         return factory( $, window, document );
18697                 } );
18698         }
18699         else if ( typeof exports === 'object' ) {
18700                 // CommonJS
18701                 module.exports = function (root, $) {
18702                         if ( ! root ) {
18703                                 root = window;
18704                         }
18705
18706                         if ( ! $ || ! $.fn.dataTable ) {
18707                                 $ = require('datatables.net')(root, $).$;
18708                         }
18709
18710                         return factory( $, root, root.document );
18711                 };
18712         }
18713         else {
18714                 // Browser
18715                 factory( jQuery, window, document );
18716         }
18717 }(function( $, window, document, undefined ) {
18718 'use strict';
18719 var DataTable = $.fn.dataTable;
18720
18721
18722 // Version information for debugger
18723 DataTable.select = {};
18724
18725 DataTable.select.version = '1.3.1';
18726
18727 DataTable.select.init = function ( dt ) {
18728         var ctx = dt.settings()[0];
18729         var init = ctx.oInit.select;
18730         var defaults = DataTable.defaults.select;
18731         var opts = init === undefined ?
18732                 defaults :
18733                 init;
18734
18735         // Set defaults
18736         var items = 'row';
18737         var style = 'api';
18738         var blurable = false;
18739         var toggleable = true;
18740         var info = true;
18741         var selector = 'td, th';
18742         var className = 'selected';
18743         var setStyle = false;
18744
18745         ctx._select = {};
18746
18747         // Initialisation customisations
18748         if ( opts === true ) {
18749                 style = 'os';
18750                 setStyle = true;
18751         }
18752         else if ( typeof opts === 'string' ) {
18753                 style = opts;
18754                 setStyle = true;
18755         }
18756         else if ( $.isPlainObject( opts ) ) {
18757                 if ( opts.blurable !== undefined ) {
18758                         blurable = opts.blurable;
18759                 }
18760                 
18761                 if ( opts.toggleable !== undefined ) {
18762                         toggleable = opts.toggleable;
18763                 }
18764
18765                 if ( opts.info !== undefined ) {
18766                         info = opts.info;
18767                 }
18768
18769                 if ( opts.items !== undefined ) {
18770                         items = opts.items;
18771                 }
18772
18773                 if ( opts.style !== undefined ) {
18774                         style = opts.style;
18775                         setStyle = true;
18776                 }
18777                 else {
18778                         style = 'os';
18779                         setStyle = true;
18780                 }
18781
18782                 if ( opts.selector !== undefined ) {
18783                         selector = opts.selector;
18784                 }
18785
18786                 if ( opts.className !== undefined ) {
18787                         className = opts.className;
18788                 }
18789         }
18790
18791         dt.select.selector( selector );
18792         dt.select.items( items );
18793         dt.select.style( style );
18794         dt.select.blurable( blurable );
18795         dt.select.toggleable( toggleable );
18796         dt.select.info( info );
18797         ctx._select.className = className;
18798
18799
18800         // Sort table based on selected rows. Requires Select Datatables extension
18801         $.fn.dataTable.ext.order['select-checkbox'] = function ( settings, col ) {
18802                 return this.api().column( col, {order: 'index'} ).nodes().map( function ( td ) {
18803                         if ( settings._select.items === 'row' ) {
18804                                 return $( td ).parent().hasClass( settings._select.className );
18805                         } else if ( settings._select.items === 'cell' ) {
18806                                 return $( td ).hasClass( settings._select.className );
18807                         }
18808                         return false;
18809                 });
18810         };
18811
18812         // If the init options haven't enabled select, but there is a selectable
18813         // class name, then enable
18814         if ( ! setStyle && $( dt.table().node() ).hasClass( 'selectable' ) ) {
18815                 dt.select.style( 'os' );
18816         }
18817 };
18818
18819 /*
18820
18821 Select is a collection of API methods, event handlers, event emitters and
18822 buttons (for the `Buttons` extension) for DataTables. It provides the following
18823 features, with an overview of how they are implemented:
18824
18825 ## Selection of rows, columns and cells. Whether an item is selected or not is
18826    stored in:
18827
18828 * rows: a `_select_selected` property which contains a boolean value of the
18829   DataTables' `aoData` object for each row
18830 * columns: a `_select_selected` property which contains a boolean value of the
18831   DataTables' `aoColumns` object for each column
18832 * cells: a `_selected_cells` property which contains an array of boolean values
18833   of the `aoData` object for each row. The array is the same length as the
18834   columns array, with each element of it representing a cell.
18835
18836 This method of using boolean flags allows Select to operate when nodes have not
18837 been created for rows / cells (DataTables' defer rendering feature).
18838
18839 ## API methods
18840
18841 A range of API methods are available for triggering selection and de-selection
18842 of rows. Methods are also available to configure the selection events that can
18843 be triggered by an end user (such as which items are to be selected). To a large
18844 extent, these of API methods *is* Select. It is basically a collection of helper
18845 functions that can be used to select items in a DataTable.
18846
18847 Configuration of select is held in the object `_select` which is attached to the
18848 DataTables settings object on initialisation. Select being available on a table
18849 is not optional when Select is loaded, but its default is for selection only to
18850 be available via the API - so the end user wouldn't be able to select rows
18851 without additional configuration.
18852
18853 The `_select` object contains the following properties:
18854
18855 ```
18856 {
18857         items:string       - Can be `rows`, `columns` or `cells`. Defines what item 
18858                              will be selected if the user is allowed to activate row
18859                              selection using the mouse.
18860         style:string       - Can be `none`, `single`, `multi` or `os`. Defines the
18861                              interaction style when selecting items
18862         blurable:boolean   - If row selection can be cleared by clicking outside of
18863                              the table
18864         toggleable:boolean - If row selection can be cancelled by repeated clicking
18865                              on the row
18866         info:boolean       - If the selection summary should be shown in the table
18867                              information elements
18868 }
18869 ```
18870
18871 In addition to the API methods, Select also extends the DataTables selector
18872 options for rows, columns and cells adding a `selected` option to the selector
18873 options object, allowing the developer to select only selected items or
18874 unselected items.
18875
18876 ## Mouse selection of items
18877
18878 Clicking on items can be used to select items. This is done by a simple event
18879 handler that will select the items using the API methods.
18880
18881  */
18882
18883
18884 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
18885  * Local functions
18886  */
18887
18888 /**
18889  * Add one or more cells to the selection when shift clicking in OS selection
18890  * style cell selection.
18891  *
18892  * Cell range is more complicated than row and column as we want to select
18893  * in the visible grid rather than by index in sequence. For example, if you
18894  * click first in cell 1-1 and then shift click in 2-2 - cells 1-2 and 2-1
18895  * should also be selected (and not 1-3, 1-4. etc)
18896  * 
18897  * @param  {DataTable.Api} dt   DataTable
18898  * @param  {object}        idx  Cell index to select to
18899  * @param  {object}        last Cell index to select from
18900  * @private
18901  */
18902 function cellRange( dt, idx, last )
18903 {
18904         var indexes;
18905         var columnIndexes;
18906         var rowIndexes;
18907         var selectColumns = function ( start, end ) {
18908                 if ( start > end ) {
18909                         var tmp = end;
18910                         end = start;
18911                         start = tmp;
18912                 }
18913                 
18914                 var record = false;
18915                 return dt.columns( ':visible' ).indexes().filter( function (i) {
18916                         if ( i === start ) {
18917                                 record = true;
18918                         }
18919                         
18920                         if ( i === end ) { // not else if, as start might === end
18921                                 record = false;
18922                                 return true;
18923                         }
18924
18925                         return record;
18926                 } );
18927         };
18928
18929         var selectRows = function ( start, end ) {
18930                 var indexes = dt.rows( { search: 'applied' } ).indexes();
18931
18932                 // Which comes first - might need to swap
18933                 if ( indexes.indexOf( start ) > indexes.indexOf( end ) ) {
18934                         var tmp = end;
18935                         end = start;
18936                         start = tmp;
18937                 }
18938
18939                 var record = false;
18940                 return indexes.filter( function (i) {
18941                         if ( i === start ) {
18942                                 record = true;
18943                         }
18944                         
18945                         if ( i === end ) {
18946                                 record = false;
18947                                 return true;
18948                         }
18949
18950                         return record;
18951                 } );
18952         };
18953
18954         if ( ! dt.cells( { selected: true } ).any() && ! last ) {
18955                 // select from the top left cell to this one
18956                 columnIndexes = selectColumns( 0, idx.column );
18957                 rowIndexes = selectRows( 0 , idx.row );
18958         }
18959         else {
18960                 // Get column indexes between old and new
18961                 columnIndexes = selectColumns( last.column, idx.column );
18962                 rowIndexes = selectRows( last.row , idx.row );
18963         }
18964
18965         indexes = dt.cells( rowIndexes, columnIndexes ).flatten();
18966
18967         if ( ! dt.cells( idx, { selected: true } ).any() ) {
18968                 // Select range
18969                 dt.cells( indexes ).select();
18970         }
18971         else {
18972                 // Deselect range
18973                 dt.cells( indexes ).deselect();
18974         }
18975 }
18976
18977 /**
18978  * Disable mouse selection by removing the selectors
18979  *
18980  * @param {DataTable.Api} dt DataTable to remove events from
18981  * @private
18982  */
18983 function disableMouseSelection( dt )
18984 {
18985         var ctx = dt.settings()[0];
18986         var selector = ctx._select.selector;
18987
18988         $( dt.table().container() )
18989                 .off( 'mousedown.dtSelect', selector )
18990                 .off( 'mouseup.dtSelect', selector )
18991                 .off( 'click.dtSelect', selector );
18992
18993         $('body').off( 'click.dtSelect' + _safeId(dt.table().node()) );
18994 }
18995
18996 /**
18997  * Attach mouse listeners to the table to allow mouse selection of items
18998  *
18999  * @param {DataTable.Api} dt DataTable to remove events from
19000  * @private
19001  */
19002 function enableMouseSelection ( dt )
19003 {
19004         var container = $( dt.table().container() );
19005         var ctx = dt.settings()[0];
19006         var selector = ctx._select.selector;
19007         var matchSelection;
19008
19009         container
19010                 .on( 'mousedown.dtSelect', selector, function(e) {
19011                         // Disallow text selection for shift clicking on the table so multi
19012                         // element selection doesn't look terrible!
19013                         if ( e.shiftKey || e.metaKey || e.ctrlKey ) {
19014                                 container
19015                                         .css( '-moz-user-select', 'none' )
19016                                         .one('selectstart.dtSelect', selector, function () {
19017                                                 return false;
19018                                         } );
19019                         }
19020
19021                         if ( window.getSelection ) {
19022                                 matchSelection = window.getSelection();
19023                         }
19024                 } )
19025                 .on( 'mouseup.dtSelect', selector, function() {
19026                         // Allow text selection to occur again, Mozilla style (tested in FF
19027                         // 35.0.1 - still required)
19028                         container.css( '-moz-user-select', '' );
19029                 } )
19030                 .on( 'click.dtSelect', selector, function ( e ) {
19031                         var items = dt.select.items();
19032                         var idx;
19033
19034                         // If text was selected (click and drag), then we shouldn't change
19035                         // the row's selected state
19036                         if ( matchSelection ) {
19037                                 var selection = window.getSelection();
19038
19039                                 // If the element that contains the selection is not in the table, we can ignore it
19040                                 // This can happen if the developer selects text from the click event
19041                                 if ( ! selection.anchorNode || $(selection.anchorNode).closest('table')[0] === dt.table().node() ) {
19042                                         if ( selection !== matchSelection ) {
19043                                                 return;
19044                                         }
19045                                 }
19046                         }
19047
19048                         var ctx = dt.settings()[0];
19049                         var wrapperClass = $.trim(dt.settings()[0].oClasses.sWrapper).replace(/ +/g, '.');
19050
19051                         // Ignore clicks inside a sub-table
19052                         if ( $(e.target).closest('div.'+wrapperClass)[0] != dt.table().container() ) {
19053                                 return;
19054                         }
19055
19056                         var cell = dt.cell( $(e.target).closest('td, th') );
19057
19058                         // Check the cell actually belongs to the host DataTable (so child
19059                         // rows, etc, are ignored)
19060                         if ( ! cell.any() ) {
19061                                 return;
19062                         }
19063
19064                         var event = $.Event('user-select.dt');
19065                         eventTrigger( dt, event, [ items, cell, e ] );
19066
19067                         if ( event.isDefaultPrevented() ) {
19068                                 return;
19069                         }
19070
19071                         var cellIndex = cell.index();
19072                         if ( items === 'row' ) {
19073                                 idx = cellIndex.row;
19074                                 typeSelect( e, dt, ctx, 'row', idx );
19075                         }
19076                         else if ( items === 'column' ) {
19077                                 idx = cell.index().column;
19078                                 typeSelect( e, dt, ctx, 'column', idx );
19079                         }
19080                         else if ( items === 'cell' ) {
19081                                 idx = cell.index();
19082                                 typeSelect( e, dt, ctx, 'cell', idx );
19083                         }
19084
19085                         ctx._select_lastCell = cellIndex;
19086                 } );
19087
19088         // Blurable
19089         $('body').on( 'click.dtSelect' + _safeId(dt.table().node()), function ( e ) {
19090                 if ( ctx._select.blurable ) {
19091                         // If the click was inside the DataTables container, don't blur
19092                         if ( $(e.target).parents().filter( dt.table().container() ).length ) {
19093                                 return;
19094                         }
19095
19096                         // Ignore elements which have been removed from the DOM (i.e. paging
19097                         // buttons)
19098                         if ( $(e.target).parents('html').length === 0 ) {
19099                                 return;
19100                         }
19101
19102                         // Don't blur in Editor form
19103                         if ( $(e.target).parents('div.DTE').length ) {
19104                                 return;
19105                         }
19106
19107                         clear( ctx, true );
19108                 }
19109         } );
19110 }
19111
19112 /**
19113  * Trigger an event on a DataTable
19114  *
19115  * @param {DataTable.Api} api      DataTable to trigger events on
19116  * @param  {boolean}      selected true if selected, false if deselected
19117  * @param  {string}       type     Item type acting on
19118  * @param  {boolean}      any      Require that there are values before
19119  *     triggering
19120  * @private
19121  */
19122 function eventTrigger ( api, type, args, any )
19123 {
19124         if ( any && ! api.flatten().length ) {
19125                 return;
19126         }
19127
19128         if ( typeof type === 'string' ) {
19129                 type = type +'.dt';
19130         }
19131
19132         args.unshift( api );
19133
19134         $(api.table().node()).trigger( type, args );
19135 }
19136
19137 /**
19138  * Update the information element of the DataTable showing information about the
19139  * items selected. This is done by adding tags to the existing text
19140  * 
19141  * @param {DataTable.Api} api DataTable to update
19142  * @private
19143  */
19144 function info ( api )
19145 {
19146         var ctx = api.settings()[0];
19147
19148         if ( ! ctx._select.info || ! ctx.aanFeatures.i ) {
19149                 return;
19150         }
19151
19152         if ( api.select.style() === 'api' ) {
19153                 return;
19154         }
19155
19156         var rows    = api.rows( { selected: true } ).flatten().length;
19157         var columns = api.columns( { selected: true } ).flatten().length;
19158         var cells   = api.cells( { selected: true } ).flatten().length;
19159
19160         var add = function ( el, name, num ) {
19161                 el.append( $('<span class="select-item"/>').append( api.i18n(
19162                         'select.'+name+'s',
19163                         { _: '%d '+name+'s selected', 0: '', 1: '1 '+name+' selected' },
19164                         num
19165                 ) ) );
19166         };
19167
19168         // Internal knowledge of DataTables to loop over all information elements
19169         $.each( ctx.aanFeatures.i, function ( i, el ) {
19170                 el = $(el);
19171
19172                 var output  = $('<span class="select-info"/>');
19173                 add( output, 'row', rows );
19174                 add( output, 'column', columns );
19175                 add( output, 'cell', cells  );
19176
19177                 var exisiting = el.children('span.select-info');
19178                 if ( exisiting.length ) {
19179                         exisiting.remove();
19180                 }
19181
19182                 if ( output.text() !== '' ) {
19183                         el.append( output );
19184                 }
19185         } );
19186 }
19187
19188 /**
19189  * Initialisation of a new table. Attach event handlers and callbacks to allow
19190  * Select to operate correctly.
19191  *
19192  * This will occur _after_ the initial DataTables initialisation, although
19193  * before Ajax data is rendered, if there is ajax data
19194  *
19195  * @param  {DataTable.settings} ctx Settings object to operate on
19196  * @private
19197  */
19198 function init ( ctx ) {
19199         var api = new DataTable.Api( ctx );
19200
19201         // Row callback so that classes can be added to rows and cells if the item
19202         // was selected before the element was created. This will happen with the
19203         // `deferRender` option enabled.
19204         // 
19205         // This method of attaching to `aoRowCreatedCallback` is a hack until
19206         // DataTables has proper events for row manipulation If you are reviewing
19207         // this code to create your own plug-ins, please do not do this!
19208         ctx.aoRowCreatedCallback.push( {
19209                 fn: function ( row, data, index ) {
19210                         var i, ien;
19211                         var d = ctx.aoData[ index ];
19212
19213                         // Row
19214                         if ( d._select_selected ) {
19215                                 $( row ).addClass( ctx._select.className );
19216                         }
19217
19218                         // Cells and columns - if separated out, we would need to do two
19219                         // loops, so it makes sense to combine them into a single one
19220                         for ( i=0, ien=ctx.aoColumns.length ; i<ien ; i++ ) {
19221                                 if ( ctx.aoColumns[i]._select_selected || (d._selected_cells && d._selected_cells[i]) ) {
19222                                         $(d.anCells[i]).addClass( ctx._select.className );
19223                                 }
19224                         }
19225                 },
19226                 sName: 'select-deferRender'
19227         } );
19228
19229         // On Ajax reload we want to reselect all rows which are currently selected,
19230         // if there is an rowId (i.e. a unique value to identify each row with)
19231         api.on( 'preXhr.dt.dtSelect', function () {
19232                 // note that column selection doesn't need to be cached and then
19233                 // reselected, as they are already selected
19234                 var rows = api.rows( { selected: true } ).ids( true ).filter( function ( d ) {
19235                         return d !== undefined;
19236                 } );
19237
19238                 var cells = api.cells( { selected: true } ).eq(0).map( function ( cellIdx ) {
19239                         var id = api.row( cellIdx.row ).id( true );
19240                         return id ?
19241                                 { row: id, column: cellIdx.column } :
19242                                 undefined;
19243                 } ).filter( function ( d ) {
19244                         return d !== undefined;
19245                 } );
19246
19247                 // On the next draw, reselect the currently selected items
19248                 api.one( 'draw.dt.dtSelect', function () {
19249                         api.rows( rows ).select();
19250
19251                         // `cells` is not a cell index selector, so it needs a loop
19252                         if ( cells.any() ) {
19253                                 cells.each( function ( id ) {
19254                                         api.cells( id.row, id.column ).select();
19255                                 } );
19256                         }
19257                 } );
19258         } );
19259
19260         // Update the table information element with selected item summary
19261         api.on( 'draw.dtSelect.dt select.dtSelect.dt deselect.dtSelect.dt info.dt', function () {
19262                 info( api );
19263         } );
19264
19265         // Clean up and release
19266         api.on( 'destroy.dtSelect', function () {
19267                 disableMouseSelection( api );
19268                 api.off( '.dtSelect' );
19269         } );
19270 }
19271
19272 /**
19273  * Add one or more items (rows or columns) to the selection when shift clicking
19274  * in OS selection style
19275  *
19276  * @param  {DataTable.Api} dt   DataTable
19277  * @param  {string}        type Row or column range selector
19278  * @param  {object}        idx  Item index to select to
19279  * @param  {object}        last Item index to select from
19280  * @private
19281  */
19282 function rowColumnRange( dt, type, idx, last )
19283 {
19284         // Add a range of rows from the last selected row to this one
19285         var indexes = dt[type+'s']( { search: 'applied' } ).indexes();
19286         var idx1 = $.inArray( last, indexes );
19287         var idx2 = $.inArray( idx, indexes );
19288
19289         if ( ! dt[type+'s']( { selected: true } ).any() && idx1 === -1 ) {
19290                 // select from top to here - slightly odd, but both Windows and Mac OS
19291                 // do this
19292                 indexes.splice( $.inArray( idx, indexes )+1, indexes.length );
19293         }
19294         else {
19295                 // reverse so we can shift click 'up' as well as down
19296                 if ( idx1 > idx2 ) {
19297                         var tmp = idx2;
19298                         idx2 = idx1;
19299                         idx1 = tmp;
19300                 }
19301
19302                 indexes.splice( idx2+1, indexes.length );
19303                 indexes.splice( 0, idx1 );
19304         }
19305
19306         if ( ! dt[type]( idx, { selected: true } ).any() ) {
19307                 // Select range
19308                 dt[type+'s']( indexes ).select();
19309         }
19310         else {
19311                 // Deselect range - need to keep the clicked on row selected
19312                 indexes.splice( $.inArray( idx, indexes ), 1 );
19313                 dt[type+'s']( indexes ).deselect();
19314         }
19315 }
19316
19317 /**
19318  * Clear all selected items
19319  *
19320  * @param  {DataTable.settings} ctx Settings object of the host DataTable
19321  * @param  {boolean} [force=false] Force the de-selection to happen, regardless
19322  *     of selection style
19323  * @private
19324  */
19325 function clear( ctx, force )
19326 {
19327         if ( force || ctx._select.style === 'single' ) {
19328                 var api = new DataTable.Api( ctx );
19329                 
19330                 api.rows( { selected: true } ).deselect();
19331                 api.columns( { selected: true } ).deselect();
19332                 api.cells( { selected: true } ).deselect();
19333         }
19334 }
19335
19336 /**
19337  * Select items based on the current configuration for style and items.
19338  *
19339  * @param  {object}             e    Mouse event object
19340  * @param  {DataTables.Api}     dt   DataTable
19341  * @param  {DataTable.settings} ctx  Settings object of the host DataTable
19342  * @param  {string}             type Items to select
19343  * @param  {int|object}         idx  Index of the item to select
19344  * @private
19345  */
19346 function typeSelect ( e, dt, ctx, type, idx )
19347 {
19348         var style = dt.select.style();
19349         var toggleable = dt.select.toggleable();
19350         var isSelected = dt[type]( idx, { selected: true } ).any();
19351         
19352         if ( isSelected && ! toggleable ) {
19353                 return;
19354         }
19355
19356         if ( style === 'os' ) {
19357                 if ( e.ctrlKey || e.metaKey ) {
19358                         // Add or remove from the selection
19359                         dt[type]( idx ).select( ! isSelected );
19360                 }
19361                 else if ( e.shiftKey ) {
19362                         if ( type === 'cell' ) {
19363                                 cellRange( dt, idx, ctx._select_lastCell || null );
19364                         }
19365                         else {
19366                                 rowColumnRange( dt, type, idx, ctx._select_lastCell ?
19367                                         ctx._select_lastCell[type] :
19368                                         null
19369                                 );
19370                         }
19371                 }
19372                 else {
19373                         // No cmd or shift click - deselect if selected, or select
19374                         // this row only
19375                         var selected = dt[type+'s']( { selected: true } );
19376
19377                         if ( isSelected && selected.flatten().length === 1 ) {
19378                                 dt[type]( idx ).deselect();
19379                         }
19380                         else {
19381                                 selected.deselect();
19382                                 dt[type]( idx ).select();
19383                         }
19384                 }
19385         } else if ( style == 'multi+shift' ) {
19386                 if ( e.shiftKey ) {
19387                         if ( type === 'cell' ) {
19388                                 cellRange( dt, idx, ctx._select_lastCell || null );
19389                         }
19390                         else {
19391                                 rowColumnRange( dt, type, idx, ctx._select_lastCell ?
19392                                         ctx._select_lastCell[type] :
19393                                         null
19394                                 );
19395                         }
19396                 }
19397                 else {
19398                         dt[ type ]( idx ).select( ! isSelected );
19399                 }
19400         }
19401         else {
19402                 dt[ type ]( idx ).select( ! isSelected );
19403         }
19404 }
19405
19406 function _safeId( node ) {
19407         return node.id.replace(/[^a-zA-Z0-9\-\_]/g, '-');
19408 }
19409
19410
19411
19412 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
19413  * DataTables selectors
19414  */
19415
19416 // row and column are basically identical just assigned to different properties
19417 // and checking a different array, so we can dynamically create the functions to
19418 // reduce the code size
19419 $.each( [
19420         { type: 'row', prop: 'aoData' },
19421         { type: 'column', prop: 'aoColumns' }
19422 ], function ( i, o ) {
19423         DataTable.ext.selector[ o.type ].push( function ( settings, opts, indexes ) {
19424                 var selected = opts.selected;
19425                 var data;
19426                 var out = [];
19427
19428                 if ( selected !== true && selected !== false ) {
19429                         return indexes;
19430                 }
19431
19432                 for ( var i=0, ien=indexes.length ; i<ien ; i++ ) {
19433                         data = settings[ o.prop ][ indexes[i] ];
19434
19435                         if ( (selected === true && data._select_selected === true) ||
19436                              (selected === false && ! data._select_selected )
19437                         ) {
19438                                 out.push( indexes[i] );
19439                         }
19440                 }
19441
19442                 return out;
19443         } );
19444 } );
19445
19446 DataTable.ext.selector.cell.push( function ( settings, opts, cells ) {
19447         var selected = opts.selected;
19448         var rowData;
19449         var out = [];
19450
19451         if ( selected === undefined ) {
19452                 return cells;
19453         }
19454
19455         for ( var i=0, ien=cells.length ; i<ien ; i++ ) {
19456                 rowData = settings.aoData[ cells[i].row ];
19457
19458                 if ( (selected === true && rowData._selected_cells && rowData._selected_cells[ cells[i].column ] === true) ||
19459                      (selected === false && ( ! rowData._selected_cells || ! rowData._selected_cells[ cells[i].column ] ) )
19460                 ) {
19461                         out.push( cells[i] );
19462                 }
19463         }
19464
19465         return out;
19466 } );
19467
19468
19469
19470 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
19471  * DataTables API
19472  *
19473  * For complete documentation, please refer to the docs/api directory or the
19474  * DataTables site
19475  */
19476
19477 // Local variables to improve compression
19478 var apiRegister = DataTable.Api.register;
19479 var apiRegisterPlural = DataTable.Api.registerPlural;
19480
19481 apiRegister( 'select()', function () {
19482         return this.iterator( 'table', function ( ctx ) {
19483                 DataTable.select.init( new DataTable.Api( ctx ) );
19484         } );
19485 } );
19486
19487 apiRegister( 'select.blurable()', function ( flag ) {
19488         if ( flag === undefined ) {
19489                 return this.context[0]._select.blurable;
19490         }
19491
19492         return this.iterator( 'table', function ( ctx ) {
19493                 ctx._select.blurable = flag;
19494         } );
19495 } );
19496
19497 apiRegister( 'select.toggleable()', function ( flag ) {
19498         if ( flag === undefined ) {
19499                 return this.context[0]._select.toggleable;
19500         }
19501
19502         return this.iterator( 'table', function ( ctx ) {
19503                 ctx._select.toggleable = flag;
19504         } );
19505 } );
19506
19507 apiRegister( 'select.info()', function ( flag ) {
19508         if ( info === undefined ) {
19509                 return this.context[0]._select.info;
19510         }
19511
19512         return this.iterator( 'table', function ( ctx ) {
19513                 ctx._select.info = flag;
19514         } );
19515 } );
19516
19517 apiRegister( 'select.items()', function ( items ) {
19518         if ( items === undefined ) {
19519                 return this.context[0]._select.items;
19520         }
19521
19522         return this.iterator( 'table', function ( ctx ) {
19523                 ctx._select.items = items;
19524
19525                 eventTrigger( new DataTable.Api( ctx ), 'selectItems', [ items ] );
19526         } );
19527 } );
19528
19529 // Takes effect from the _next_ selection. None disables future selection, but
19530 // does not clear the current selection. Use the `deselect` methods for that
19531 apiRegister( 'select.style()', function ( style ) {
19532         if ( style === undefined ) {
19533                 return this.context[0]._select.style;
19534         }
19535
19536         return this.iterator( 'table', function ( ctx ) {
19537                 ctx._select.style = style;
19538
19539                 if ( ! ctx._select_init ) {
19540                         init( ctx );
19541                 }
19542
19543                 // Add / remove mouse event handlers. They aren't required when only
19544                 // API selection is available
19545                 var dt = new DataTable.Api( ctx );
19546                 disableMouseSelection( dt );
19547                 
19548                 if ( style !== 'api' ) {
19549                         enableMouseSelection( dt );
19550                 }
19551
19552                 eventTrigger( new DataTable.Api( ctx ), 'selectStyle', [ style ] );
19553         } );
19554 } );
19555
19556 apiRegister( 'select.selector()', function ( selector ) {
19557         if ( selector === undefined ) {
19558                 return this.context[0]._select.selector;
19559         }
19560
19561         return this.iterator( 'table', function ( ctx ) {
19562                 disableMouseSelection( new DataTable.Api( ctx ) );
19563
19564                 ctx._select.selector = selector;
19565
19566                 if ( ctx._select.style !== 'api' ) {
19567                         enableMouseSelection( new DataTable.Api( ctx ) );
19568                 }
19569         } );
19570 } );
19571
19572
19573
19574 apiRegisterPlural( 'rows().select()', 'row().select()', function ( select ) {
19575         var api = this;
19576
19577         if ( select === false ) {
19578                 return this.deselect();
19579         }
19580
19581         this.iterator( 'row', function ( ctx, idx ) {
19582                 clear( ctx );
19583
19584                 ctx.aoData[ idx ]._select_selected = true;
19585                 $( ctx.aoData[ idx ].nTr ).addClass( ctx._select.className );
19586         } );
19587
19588         this.iterator( 'table', function ( ctx, i ) {
19589                 eventTrigger( api, 'select', [ 'row', api[i] ], true );
19590         } );
19591
19592         return this;
19593 } );
19594
19595 apiRegisterPlural( 'columns().select()', 'column().select()', function ( select ) {
19596         var api = this;
19597
19598         if ( select === false ) {
19599                 return this.deselect();
19600         }
19601
19602         this.iterator( 'column', function ( ctx, idx ) {
19603                 clear( ctx );
19604
19605                 ctx.aoColumns[ idx ]._select_selected = true;
19606
19607                 var column = new DataTable.Api( ctx ).column( idx );
19608
19609                 $( column.header() ).addClass( ctx._select.className );
19610                 $( column.footer() ).addClass( ctx._select.className );
19611
19612                 column.nodes().to$().addClass( ctx._select.className );
19613         } );
19614
19615         this.iterator( 'table', function ( ctx, i ) {
19616                 eventTrigger( api, 'select', [ 'column', api[i] ], true );
19617         } );
19618
19619         return this;
19620 } );
19621
19622 apiRegisterPlural( 'cells().select()', 'cell().select()', function ( select ) {
19623         var api = this;
19624
19625         if ( select === false ) {
19626                 return this.deselect();
19627         }
19628
19629         this.iterator( 'cell', function ( ctx, rowIdx, colIdx ) {
19630                 clear( ctx );
19631
19632                 var data = ctx.aoData[ rowIdx ];
19633
19634                 if ( data._selected_cells === undefined ) {
19635                         data._selected_cells = [];
19636                 }
19637
19638                 data._selected_cells[ colIdx ] = true;
19639
19640                 if ( data.anCells ) {
19641                         $( data.anCells[ colIdx ] ).addClass( ctx._select.className );
19642                 }
19643         } );
19644
19645         this.iterator( 'table', function ( ctx, i ) {
19646                 eventTrigger( api, 'select', [ 'cell', api[i] ], true );
19647         } );
19648
19649         return this;
19650 } );
19651
19652
19653 apiRegisterPlural( 'rows().deselect()', 'row().deselect()', function () {
19654         var api = this;
19655
19656         this.iterator( 'row', function ( ctx, idx ) {
19657                 ctx.aoData[ idx ]._select_selected = false;
19658                 $( ctx.aoData[ idx ].nTr ).removeClass( ctx._select.className );
19659         } );
19660
19661         this.iterator( 'table', function ( ctx, i ) {
19662                 eventTrigger( api, 'deselect', [ 'row', api[i] ], true );
19663         } );
19664
19665         return this;
19666 } );
19667
19668 apiRegisterPlural( 'columns().deselect()', 'column().deselect()', function () {
19669         var api = this;
19670
19671         this.iterator( 'column', function ( ctx, idx ) {
19672                 ctx.aoColumns[ idx ]._select_selected = false;
19673
19674                 var api = new DataTable.Api( ctx );
19675                 var column = api.column( idx );
19676
19677                 $( column.header() ).removeClass( ctx._select.className );
19678                 $( column.footer() ).removeClass( ctx._select.className );
19679
19680                 // Need to loop over each cell, rather than just using
19681                 // `column().nodes()` as cells which are individually selected should
19682                 // not have the `selected` class removed from them
19683                 api.cells( null, idx ).indexes().each( function (cellIdx) {
19684                         var data = ctx.aoData[ cellIdx.row ];
19685                         var cellSelected = data._selected_cells;
19686
19687                         if ( data.anCells && (! cellSelected || ! cellSelected[ cellIdx.column ]) ) {
19688                                 $( data.anCells[ cellIdx.column  ] ).removeClass( ctx._select.className );
19689                         }
19690                 } );
19691         } );
19692
19693         this.iterator( 'table', function ( ctx, i ) {
19694                 eventTrigger( api, 'deselect', [ 'column', api[i] ], true );
19695         } );
19696
19697         return this;
19698 } );
19699
19700 apiRegisterPlural( 'cells().deselect()', 'cell().deselect()', function () {
19701         var api = this;
19702
19703         this.iterator( 'cell', function ( ctx, rowIdx, colIdx ) {
19704                 var data = ctx.aoData[ rowIdx ];
19705
19706                 data._selected_cells[ colIdx ] = false;
19707
19708                 // Remove class only if the cells exist, and the cell is not column
19709                 // selected, in which case the class should remain (since it is selected
19710                 // in the column)
19711                 if ( data.anCells && ! ctx.aoColumns[ colIdx ]._select_selected ) {
19712                         $( data.anCells[ colIdx ] ).removeClass( ctx._select.className );
19713                 }
19714         } );
19715
19716         this.iterator( 'table', function ( ctx, i ) {
19717                 eventTrigger( api, 'deselect', [ 'cell', api[i] ], true );
19718         } );
19719
19720         return this;
19721 } );
19722
19723
19724
19725 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
19726  * Buttons
19727  */
19728 function i18n( label, def ) {
19729         return function (dt) {
19730                 return dt.i18n( 'buttons.'+label, def );
19731         };
19732 }
19733
19734 // Common events with suitable namespaces
19735 function namespacedEvents ( config ) {
19736         var unique = config._eventNamespace;
19737
19738         return 'draw.dt.DT'+unique+' select.dt.DT'+unique+' deselect.dt.DT'+unique;
19739 }
19740
19741 function enabled ( dt, config ) {
19742         if ( $.inArray( 'rows', config.limitTo ) !== -1 && dt.rows( { selected: true } ).any() ) {
19743                 return true;
19744         }
19745
19746         if ( $.inArray( 'columns', config.limitTo ) !== -1 && dt.columns( { selected: true } ).any() ) {
19747                 return true;
19748         }
19749
19750         if ( $.inArray( 'cells', config.limitTo ) !== -1 && dt.cells( { selected: true } ).any() ) {
19751                 return true;
19752         }
19753
19754         return false;
19755 }
19756
19757 var _buttonNamespace = 0;
19758
19759 $.extend( DataTable.ext.buttons, {
19760         selected: {
19761                 text: i18n( 'selected', 'Selected' ),
19762                 className: 'buttons-selected',
19763                 limitTo: [ 'rows', 'columns', 'cells' ],
19764                 init: function ( dt, node, config ) {
19765                         var that = this;
19766                         config._eventNamespace = '.select'+(_buttonNamespace++);
19767
19768                         // .DT namespace listeners are removed by DataTables automatically
19769                         // on table destroy
19770                         dt.on( namespacedEvents(config), function () {
19771                                 that.enable( enabled(dt, config) );
19772                         } );
19773
19774                         this.disable();
19775                 },
19776                 destroy: function ( dt, node, config ) {
19777                         dt.off( config._eventNamespace );
19778                 }
19779         },
19780         selectedSingle: {
19781                 text: i18n( 'selectedSingle', 'Selected single' ),
19782                 className: 'buttons-selected-single',
19783                 init: function ( dt, node, config ) {
19784                         var that = this;
19785                         config._eventNamespace = '.select'+(_buttonNamespace++);
19786
19787                         dt.on( namespacedEvents(config), function () {
19788                                 var count = dt.rows( { selected: true } ).flatten().length +
19789                                             dt.columns( { selected: true } ).flatten().length +
19790                                             dt.cells( { selected: true } ).flatten().length;
19791
19792                                 that.enable( count === 1 );
19793                         } );
19794
19795                         this.disable();
19796                 },
19797                 destroy: function ( dt, node, config ) {
19798                         dt.off( config._eventNamespace );
19799                 }
19800         },
19801         selectAll: {
19802                 text: i18n( 'selectAll', 'Select all' ),
19803                 className: 'buttons-select-all',
19804                 action: function () {
19805                         var items = this.select.items();
19806                         this[ items+'s' ]().select();
19807                 }
19808         },
19809         selectNone: {
19810                 text: i18n( 'selectNone', 'Deselect all' ),
19811                 className: 'buttons-select-none',
19812                 action: function () {
19813                         clear( this.settings()[0], true );
19814                 },
19815                 init: function ( dt, node, config ) {
19816                         var that = this;
19817                         config._eventNamespace = '.select'+(_buttonNamespace++);
19818
19819                         dt.on( namespacedEvents(config), function () {
19820                                 var count = dt.rows( { selected: true } ).flatten().length +
19821                                             dt.columns( { selected: true } ).flatten().length +
19822                                             dt.cells( { selected: true } ).flatten().length;
19823
19824                                 that.enable( count > 0 );
19825                         } );
19826
19827                         this.disable();
19828                 },
19829                 destroy: function ( dt, node, config ) {
19830                         dt.off( config._eventNamespace );
19831                 }
19832         }
19833 } );
19834
19835 $.each( [ 'Row', 'Column', 'Cell' ], function ( i, item ) {
19836         var lc = item.toLowerCase();
19837
19838         DataTable.ext.buttons[ 'select'+item+'s' ] = {
19839                 text: i18n( 'select'+item+'s', 'Select '+lc+'s' ),
19840                 className: 'buttons-select-'+lc+'s',
19841                 action: function () {
19842                         this.select.items( lc );
19843                 },
19844                 init: function ( dt ) {
19845                         var that = this;
19846
19847                         dt.on( 'selectItems.dt.DT', function ( e, ctx, items ) {
19848                                 that.active( items === lc );
19849                         } );
19850                 }
19851         };
19852 } );
19853
19854
19855
19856 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
19857  * Initialisation
19858  */
19859
19860 // DataTables creation - check if select has been defined in the options. Note
19861 // this required that the table be in the document! If it isn't then something
19862 // needs to trigger this method unfortunately. The next major release of
19863 // DataTables will rework the events and address this.
19864 $(document).on( 'preInit.dt.dtSelect', function (e, ctx) {
19865         if ( e.namespace !== 'dt' ) {
19866                 return;
19867         }
19868
19869         DataTable.select.init( new DataTable.Api( ctx ) );
19870 } );
19871
19872
19873 return DataTable.select;
19874 }));
19875
19876