PageSourceSearch

https://paten33.it.com/js/dataTables.js?1787301697

js paten33.it.com collected 2026-10-10 00:34:45 UTC 481,939 bytes, 13,882 lines download raw bytes

vendor: 6,079 bytes, lines 1-169
1/*! DataTables 2.3.4
2 * © SpryMedia Ltd - datatables.net/license
3 */
4
5(function (factory) {
6    "use strict";
7
8    if (typeof define === 'function' && define.amd) {
9        // AMD
10        define(['jquery'], function ($) {
11            return factory($, window, document);
12        });
13    }
14    else if (typeof exports === 'object') {
15        // CommonJS
16        // jQuery's factory checks for a global window - if it isn't present then it
17        // returns a factory function that expects the window object
18        var jq = require('jquery');
19
20        if (typeof window === 'undefined') {
21            module.exports = function (root, $) {
22                if (!root) {
23                    // CommonJS environments without a window global must pass a
24                    // root. This will give an error otherwise
25                    root = window;
26                }
27
28                if (!$) {
29                    $ = jq(root);
30                }
31
32                return factory($, root, root.document);
33            };
34        }
35        else {
36            module.exports = factory(jq, window, window.document);
37        }
38    }
39    else {
40        // Browser
41        window.DataTable = factory(jQuery, window, document);
42    }
43}(function ($, window, document) {
44    "use strict";
45
46
47    var DataTable = function (selector, options) {
48        // Check if called with a window or jQuery object for DOM less applications
49        // This is for backwards compatibility
50        if (DataTable.factory(selector, options)) {
51            return DataTable;
52        }
53
54        // When creating with `new`, create a new DataTable, returning the API instance
55        if (this instanceof DataTable) {
56            return $(selector).DataTable(options);
57        }
58        else {
59            // Argument switching
60            options = selector;
61        }
62
63        var _that = this;
64        var emptyInit = options === undefined;
65        var len = this.length;
66
67        if (emptyInit) {
68            options = {};
69        }
70
71        // Method to get DT API instance from jQuery object
72        this.api = function () {
73            return new _Api(this);
74        };
75
76        this.each(function () {
77            // For each initialisation we want to give it a clean initialisation
78            // object that can be bashed around
79            var o = {};
80            var oInit = len > 1 ? // optimisation for single table case
81                _fnExtend(o, options, true) :
82                options;
83
84
85            var i = 0, iLen;
86            var sId = this.getAttribute('id');
87            var defaults = DataTable.defaults;
88            var $this = $(this);
89
90            // Sanity check
91            if (this.nodeName.toLowerCase() != 'table') {
92                _fnLog(null, 0, 'Non-table node initialisation (' + this.nodeName + ')', 2);
93                return;
94            }
95
96            // Special case for options
97            if (oInit.on && oInit.on.options) {
98                _fnListener($this, 'options', oInit.on.options);
99            }
100
101            $this.trigger('options.dt', oInit);
102
103            /* Backwards compatibility for the defaults */
104            _fnCompatOpts(defaults);
105            _fnCompatCols(defaults.column);
106
107            /* Convert the camel-case defaults to Hungarian */
108            _fnCamelToHungarian(defaults, defaults, true);
109            _fnCamelToHungarian(defaults.column, defaults.column, true);
110
111            /* Setting up the initialisation object */
112            _fnCamelToHungarian(defaults, $.extend(oInit, _fnEscapeObject($this.data())), true);
113
114
115
116            /* Check to see if we are re-initialising a table */
117            var allSettings = DataTable.settings;
118            for (i = 0, iLen = allSettings.length; i < iLen; i++) {
119                var s = allSettings[i];
120
121                /* Base check on table node */
122                if (
123                    s.nTable == this ||
124                    (s.nTHead && s.nTHead.parentNode == this) ||
125                    (s.nTFoot && s.nTFoot.parentNode == this)
126                ) {
127                    var bRetrieve = oInit.bRetrieve !== undefined ? oInit.bRetrieve : defaults.bRetrieve;
128                    var bDestroy = oInit.bDestroy !== undefined ? oInit.bDestroy : defaults.bDestroy;
129
130                    if (emptyInit || bRetrieve) {
131                        return s.oInstance;
132                    }
133                    else if (bDestroy) {
134                        new DataTable.Api(s).destroy();
135                        break;
136                    }
137                    else {
138                        _fnLog(s, 0, 'Cannot reinitialise DataTable', 3);
139                        return;
140                    }
141                }
142
143                /* If the element we are initialising has the same ID as a table which was previously
144                 * initialised, but the table nodes don't match (from before) then we destroy the old
145                 * instance by simply deleting it. This is under the assumption that the table has been
146                 * destroyed by other methods. Anyone using non-id selectors will need to do this manually
147                 */
148                if (s.sTableId == this.id) {
149                    allSettings.splice(i, 1);
150                    break;
151                }
152            }
153
154            /* Ensure the table has an ID - required for accessibility */
155            if (sId === null || sId === "") {
156                sId = "DataTables_Table_" + (DataTable.ext._unique++);
157                this.id = sId;
158            }
159
160            // Replacing an existing colgroup with our own. Not ideal, but a merge could take a lot of code
161            $this.children('colgroup').remove();
162
163            /* Create the settings object for this table and set some of the default parameters */
164            var oSettings = $.extend(true, {}, DataTable.models.oSettings, {
165                "sDestroyWidth": $this[0].style.width,
166                "sInstance": sId,
167                "sTableId": sId,
168                colgroup: $('<colgroup>').prependTo(this),
169                fastData: function (row, column, type) {
170                    return _fnGetCellData(oSettings, row, column, type);
171                }
172            });
173            oSettings.nTable = this;
174            oSettings.oInit = oInit;
175
176            allSettings.push(oSettings);
177
178            // Make a single API instance available for internal handling
179            oSettings.api = new _Api(oSettings);
180
181            // Need to add the instance after the instance after the settings object has been added
182            // to the settings array, so we can self reference the table instance if more than one
183            oSettings.oInstance = (_that.length === 1) ? _that : $this.dataTable();
184
185            // Backwards compatibility, before we apply all the defaults
186            _fnCompatOpts(oInit);
187
188            // If the length menu is given, but the init display length is not, use the length menu
189            if (oInit.aLengthMenu && !oInit.iDisplayLength) {
190                oInit.iDisplayLength = Array.isArray(oInit.aLengthMenu[0])
191                    ? oInit.aLengthMenu[0][0]
192                    : $.isPlainObject(oInit.aLengthMenu[0])
193                        ? oInit.aLengthMenu[0].value
194                        : oInit.aLengthMenu[0];
195            }
196
197            // Apply the defaults and init options to make a single init object will all
198            // options defined from defaults and instance options.
199            oInit = _fnExtend($.extend(true, {}, defaults), oInit);
200
201
202            // Map the initialisation options onto the settings object
203            _fnMap(oSettings.oFeatures, oInit, [
204                "bPaginate",
205                "bLengthChange",
206                "bFilter",
207                "bSort",
208                "bSortMulti",
209                "bInfo",
210                "bProcessing",
211                "bAutoWidth",
212                "bSortClasses",
213                "bServerSide",
214                "bDeferRender"
215            ]);
216            _fnMap(oSettings, oInit, [
217                "ajax",
218                "fnFormatNumber",
219                "sServerMethod",
220                "aaSorting",
221                "aaSortingFixed",
222                "aLengthMenu",
223                "sPaginationType",
224                "iStateDuration",
225                "bSortCellsTop",
226                "iTabIndex",
227                "sDom",
228                "fnStateLoadCallback",
229                "fnStateSaveCallback",
230                "renderer",
231                "searchDelay",
232                "rowId",
233                "caption",
234                "layout",
235                "orderDescReverse",
236                "orderIndicators",
237                "orderHandler",
238                "titleRow",
239                "typeDetect",
240                ["iCookieDuration", "iStateDuration"], // backwards compat
241                ["oSearch", "oPreviousSearch"],
242                ["aoSearchCols", "aoPreSearchCols"],
243                ["iDisplayLength", "_iDisplayLength"]
244            ]);
245            _fnMap(oSettings.oScroll, oInit, [
246                ["sScrollX", "sX"],
247                ["sScrollXInner", "sXInner"],
248                ["sScrollY", "sY"],
249                ["bScrollCollapse", "bCollapse"]
250            ]);
251            _fnMap(oSettings.oLanguage, oInit, "fnInfoCallback");
252
253            /* Callback functions which are array driven */
254            _fnCallbackReg(oSettings, 'aoDrawCallback', oInit.fnDrawCallback);
255            _fnCallbackReg(oSettings, 'aoStateSaveParams', oInit.fnStateSaveParams);
256            _fnCallbackReg(oSettings, 'aoStateLoadParams', oInit.fnStateLoadParams);
257            _fnCallbackReg(oSettings, 'aoStateLoaded', oInit.fnStateLoaded);
258            _fnCallbackReg(oSettings, 'aoRowCallback', oInit.fnRowCallback);
259            _fnCallbackReg(oSettings, 'aoRowCreatedCallback', oInit.fnCreatedRow);
260            _fnCallbackReg(oSettings, 'aoHeaderCallback', oInit.fnHeaderCallback);
261            _fnCallbackReg(oSettings, 'aoFooterCallback', oInit.fnFooterCallback);
262            _fnCallbackReg(oSettings, 'aoInitComplete', oInit.fnInitComplete);
263            _fnCallbackReg(oSettings, 'aoPreDrawCallback', oInit.fnPreDrawCallback);
264
265            oSettings.rowIdFn = _fnGetObjectDataFn(oInit.rowId);
266
267            // Add event listeners
268            if (oInit.on) {
269                Object.keys(oInit.on).forEach(function (key) {
270                    _fnListener($this, key, oInit.on[key]);
271                });
272            }
273
274            /* Browser support detection */
275            _fnBrowserDetect(oSettings);
276
277            var oClasses = oSettings.oClasses;
278
279            $.extend(oClasses, DataTable.ext.classes, oInit.oClasses);
280            $this.addClass(oClasses.table);
281
282            if (!oSettings.oFeatures.bPaginate) {
283                oInit.iDisplayStart = 0;
284            }
285
286            if (oSettings.iInitDisplayStart === undefined) {
287                /* Display start point, taking into account the save saving */
288                oSettings.iInitDisplayStart = oInit.iDisplayStart;
289                oSettings._iDisplayStart = oInit.iDisplayStart;
290            }
291
292            var defer = oInit.iDeferLoading;
293            if (defer !== null) {
294                oSettings.deferLoading = true;
295
296                var tmp = Array.isArray(defer);
297                oSettings._iRecordsDisplay = tmp ? defer[0] : defer;
298                oSettings._iRecordsTotal = tmp ? defer[1] : defer;
299            }
300
301            /*
302             * Columns
303             * See if we should load columns automatically or use defined ones
304             */
305            var columnsInit = [];
306            var thead = this.getElementsByTagName('thead');
307            var initHeaderLayout = _fnDetectHeader(oSettings, thead[0]);
308
309            // If we don't have a columns array, then generate one with nulls
310            if (oInit.aoColumns) {
311                columnsInit = oInit.aoColumns;
312            }
313            else if (initHeaderLayout.length) {
314                for (i = 0, iLen = initHeaderLayout[0].length; i < iLen; i++) {
315                    columnsInit.push(null);
316                }
317            }
318
319            // Add the columns
320            for (i = 0, iLen = columnsInit.length; i < iLen; i++) {
321                _fnAddColumn(oSettings);
322            }
323
324            // Apply the column definitions
325            _fnApplyColumnDefs(oSettings, oInit.aoColumnDefs, columnsInit, initHeaderLayout, function (iCol, oDef) {
326                _fnColumnOptions(oSettings, iCol, oDef);
327            });
328
329            /* HTML5 attribute detection - build an mData object automatically if the
330             * attributes are found
331             */
332            var rowOne = $this.children('tbody').find('tr:first-child').eq(0);
333
334            if (rowOne.length) {
335                var a = function (cell, name) {
336                    return cell.getAttribute('data-' + name) !== null ? name : null;
337                };
338
339                $(rowOne[0]).children('th, td').each(function (i, cell) {
340                    var col = oSettings.aoColumns[i];
341
342                    if (!col) {
343                        _fnLog(oSettings, 0, 'Incorrect column count', 18);
344                    }
345
346                    if (col.mData === i) {
347                        var sort = a(cell, 'sort') || a(cell, 'order');
348                        var filter = a(cell, 'filter') || a(cell, 'search');
349
350                        if (sort !== null || filter !== null) {
351                            col.mData = {
352                                _: i + '.display',
353                                sort: sort !== null ? i + '.@data-' + sort : undefined,
354                                type: sort !== null ? i + '.@data-' + sort : undefined,
355                                filter: filter !== null ? i + '.@data-' + filter : undefined
356                            };
357                            col._isArrayHost = true;
358
359                            _fnColumnOptions(oSettings, i);
360                        }
361                    }
362                });
363            }
364
365            // Must be done after everything which can be overridden by the state saving!
366            _fnCallbackReg(oSettings, 'aoDrawCallback', _fnSaveState);
367
368            var features = oSettings.oFeatures;
369            if (oInit.bStateSave) {
370                features.bStateSave = true;
371            }
372
373            // If aaSorting is not defined, then we use the first indicator in asSorting
374            // in case that has been altered, so the default sort reflects that option
375            if (oInit.aaSorting === undefined) {
376                var sorting = oSettings.aaSorting;
377                for (i = 0, iLen = sorting.length; i < iLen; i++) {
378                    sorting[i][1] = oSettings.aoColumns[i].asSorting[0];
379                }
380            }
381
382            // Do a first pass on the sorting classes (allows any size changes to be taken into
383            // account, and also will apply sorting disabled classes if disabled
384            _fnSortingClasses(oSettings);
385
386            _fnCallbackReg(oSettings, 'aoDrawCallback', function () {
387                if (oSettings.bSorted || _fnDataSource(oSettings) === 'ssp' || features.bDeferRender) {
388                    _fnSortingClasses(oSettings);
389                }
390            });
391
392
393            /*
394             * Table HTML init
395             * Cache the header, body and footer as required, creating them if needed
396             */
397            var caption = $this.children('caption');
398
399            if (oSettings.caption) {
400                if (caption.length === 0) {
401                    caption = $('<caption/>').appendTo($this);
402                }
403
404                caption.html(oSettings.caption);
405            }
406
407            // Store the caption side, so we can remove the element from the document
408            // when creating the element
409            if (caption.length) {
410                caption[0]._captionSide = caption.css('caption-side');
411                oSettings.captionNode = caption[0];
412            }
413
414            if (thead.length === 0) {
415                thead = $('<thead/>').appendTo($this);
416            }
417            oSettings.nTHead = thead[0];
418
419            var tbody = $this.children('tbody');
420            if (tbody.length === 0) {
421                tbody = $('<tbody/>').insertAfter(thead);
422            }
423            oSettings.nTBody = tbody[0];
424
425            var tfoot = $this.children('tfoot');
426            if (tfoot.length === 0) {
427                // If we are a scrolling table, and no footer has been given, then we need to create
428                // a tfoot element for the caption element to be appended to
429                tfoot = $('<tfoot/>').appendTo($this);
430            }
431            oSettings.nTFoot = tfoot[0];
432
433            // Copy the data index array
434            oSettings.aiDisplay = oSettings.aiDisplayMaster.slice();
435
436            // Initialisation complete - table can be drawn
437            oSettings.bInitialised = true;
438
439            // Language definitions
440            var oLanguage = oSettings.oLanguage;
441            $.extend(true, oLanguage, oInit.oLanguage);
442
443            if (oLanguage.sUrl) {
444                // Get the language definitions from a file
445                $.ajax({
446                    dataType: 'json',
447                    url: oLanguage.sUrl,
448                    success: function (json) {
449                        _fnCamelToHungarian(defaults.oLanguage, json);
450                        $.extend(true, oLanguage, json, oSettings.oInit.oLanguage);
451
452                        _fnCallbackFire(oSettings, null, 'i18n', [oSettings], true);
453                        _fnInitialise(oSettings);
454                    },
455                    error: function () {
456                        // Error occurred loading language file
457                        _fnLog(oSettings, 0, 'i18n file loading error', 21);
458
459                        // Continue on as best we can
460                        _fnInitialise(oSettings);
461                    }
462                });
463            }
464            else {
465                _fnCallbackFire(oSettings, null, 'i18n', [oSettings], true);
466                _fnInitialise(oSettings);
467            }
468        });
469        _that = null;
470        return this;
471    };
472
473
474
475    /**
476     * DataTables extensions
477     * 
478     * This namespace acts as a collection area for plug-ins that can be used to
479     * extend DataTables capabilities. Indeed many of the build in methods
480     * use this method to provide their own capabilities (sorting methods for
481     * example).
482     *
483     * Note that this namespace is aliased to `jQuery.fn.dataTableExt` for legacy
484     * reasons
485     *
486     *  @namespace
487     */
488    DataTable.ext = _ext = {
489        /**
490         * DataTables build type (expanded by the download builder)
491         *
492         *  @type string
493         */
494        builder: "-source-",
495
496        /**
497         * Buttons. For use with the Buttons extension for DataTables. This is
498         * defined here so other extensions can define buttons regardless of load
499         * order. It is _not_ used by DataTables core.
500         *
501         *  @type object
502         *  @default {}
503         */
504        buttons: {},
505
506
507        /**
508         * ColumnControl buttons and content
509         *
510         *  @type object
511         */
512        ccContent: {},
513
514
515        /**
516         * Element class names
517         *
518         *  @type object
519         *  @default {}
520         */
521        classes: {},
522
523
524        /**
525         * Error reporting.
526         * 
527         * How should DataTables report an error. Can take the value 'alert',
528         * 'throw', 'none' or a function.
529         *
530         *  @type string|function
531         *  @default alert
532         */
533        errMode: "alert",
534
535        /** HTML entity escaping */
536        escape: {
537            /** When reading data-* attributes for initialisation options */
538            attributes: false
539        },
540
541        /**
542         * Legacy so v1 plug-ins don't throw js errors on load
543         */
544        feature: [],
545
546        /**
547         * Feature plug-ins.
548         * 
549         * This is an object of callbacks which provide the features for DataTables
550         * to be initialised via the `layout` option.
551         */
552        features: {},
553
554
555        /**
556         * Row searching.
557         * 
558         * This method of searching is complimentary to the default type based
559         * searching, and a lot more comprehensive as it allows you complete control
560         * over the searching logic. Each element in this array is a function
561         * (parameters described below) that is called for every row in the table,
562         * and your logic decides if it should be included in the searching data set
563         * or not.
564         *
565         * Searching functions have the following input parameters:
566         *
567         * 1. `{object}` DataTables settings object: see
568         *    {@link DataTable.models.oSettings}
569         * 2. `{array|object}` Data for the row to be processed (same as the
570         *    original format that was passed in as the data source, or an array
571         *    from a DOM data source
572         * 3. `{int}` Row index ({@link DataTable.models.oSettings.aoData}), which
573         *    can be useful to retrieve the `TR` element if you need DOM 
573interaction.
574         *
575         * And the following return is expected:
576         *
577         * * {boolean} Include the row in the searched result set (true) or not
578         *   (false)
579         *
580         * Note that as with the main search ability in DataTables, technically this
581         * is "filtering", since it is subtractive. However, for consistency in
582         * naming we call it searching here.
583         *
584         *  @type array
585         *  @default []
586         *
587         *  @example
588         *    // The following example shows custom search being applied to the
589         *    // fourth column (i.e. the data[3] index) based on two input values
590         *    // from the end-user, matching the data in a certain range.
591         *    $.fn.dataTable.ext.search.push(
592         *      function( settings, data, dataIndex ) {
593         *        var min = document.getElementById('min').value * 1;
594         *        var max = document.getElementById('max').value * 1;
595         *        var version = data[3] == "-" ? 0 : data[3]*1;
596         *
597         *        if ( min == "" && max == "" ) {
598         *          return true;
599         *        }
600         *        else if ( min == "" && version < max ) {
601         *          return true;
602         *        }
603         *        else if ( min < version && "" == max ) {
604         *          return true;
605         *        }
606         *        else if ( min < version && version < max ) {
607         *          return true;
608         *        }
609         *        return false;
610         *      }
611         *    );
612         */
613        search: [],
614
615
616        /**
617         * Selector extensions
618         *
619         * The `selector` option can be used to extend the options available for the
620         * selector modifier options (`selector-modifier` object data type) that
621         * each of the three built in selector types offer (row, column and cell +
622         * their plural counterparts). For example the Select extension uses this
623         * mechanism to provide an option to select only rows, columns and cells
624         * that have been marked as selected by the end user (`{selected: true}`),
625         * which can be used in conjunction with the existing built in selector
626         * options.
627         *
628         * Each property is an array to which functions can be pushed. The functions
629         * take three attributes:
630         *
631         * * Settings object for the host table
632         * * Options object (`selector-modifier` object type)
633         * * Array of selected item indexes
634         *
635         * The return is an array of the resulting item indexes after the custom
636         * selector has been applied.
637         *
638         *  @type object
639         */
640        selector: {
641            cell: [],
642            column: [],
643            row: []
644        },
645
646
647        /**
648         * Legacy configuration options. Enable and disable legacy options that
649         * are available in DataTables.
650         *
651         *  @type object
652         */
653        legacy: {
654            /**
655             * Enable / disable DataTables 1.9 compatible server-side processing
656             * requests
657             *
658             *  @type boolean
659             *  @default null
660             */
661            ajax: null
662        },
663
664
665        /**
666         * Pagination plug-in methods.
667         * 
668         * Each entry in this object is a function and defines which buttons should
669         * be shown by the pagination rendering method that is used for the table:
670         * {@link DataTable.ext.renderer.pageButton}. The renderer addresses how the
671         * buttons are displayed in the document, while the functions here tell it
672         * what buttons to display. This is done by returning an array of button
673         * descriptions (what each button will do).
674         *
675         * Pagination types (the four built in options and any additional plug-in
676         * options defined here) can be used through the `paginationType`
677         * initialisation parameter.
678         *
679         * The functions defined take two parameters:
680         *
681         * 1. `{int} page` The current page index
682         * 2. `{int} pages` The number of pages in the table
683         *
684         * Each function is expected to return an array where each element of the
685         * array can be one of:
686         *
687         * * `first` - Jump to first page when activated
688         * * `last` - Jump to last page when activated
689         * * `previous` - Show previous page when activated
690         * * `next` - Show next page when activated
691         * * `{int}` - Show page of the index given
692         * * `{array}` - A nested array containing the above elements to add a
693         *   containing 'DIV' element (might be useful for styling).
694         *
695         * Note that DataTables v1.9- used this object slightly differently whereby
696         * an object with two functions would be defined for each plug-in. That
697         * ability is still supported by DataTables 1.10+ to provide backwards
698         * compatibility, but this option of use is now decremented and no longer
699         * documented in DataTables 1.10+.
700         *
701         *  @type object
702         *  @default {}
703         *
704         *  @example
705         *    // Show previous, next and current page buttons only
706         *    $.fn.dataTableExt.oPagination.current = function ( page, pages ) {
707         *      return [ 'previous', page, 'next' ];
708         *    };
709         */
710        pager: {},
711
712
713        renderer: {
714            pageButton: {},
715            header: {}
716        },
717
718
719        /**
720         * Ordering plug-ins - custom data source
721         * 
722         * The extension options for ordering of data available here is complimentary
723         * to the default type based ordering that DataTables typically uses. It
724         * allows much greater control over the data that is being used to
725         * order a column, but is necessarily therefore more complex.
726         * 
727         * This type of ordering is useful if you want to do ordering based on data
728         * live from the DOM (for example the contents of an 'input' element) rather
729         * than just the static string that DataTables knows of.
730         * 
731         * The way these plug-ins work is that you create an array of the values you
732         * wish to be ordering for the column in question and then return that
733         * array. The data in the array much be in the index order of the rows in
734         * the table (not the currently ordering order!). Which order data gathering
735         * function is run here depends on the `dt-init columns.orderDataType`
736         * parameter that is used for the column (if any).
737         *
738         * The functions defined take two parameters:
739         *
740         * 1. `{object}` DataTables settings object: see
741         *    {@link DataTable.models.oSettings}
742         * 2. `{int}` Target column index
743         *
744         * Each function is expected to return an array:
745         *
746         * * `{array}` Data for the column to be ordering upon
747         *
748         *  @type array
749         *
750         *  @example
751         *    // Ordering using `input` node values
752         *    $.fn.dataTable.ext.order['dom-text'] = function  ( settings, col )
753         *    {
754         *      return this.api().column( col, {order:'index'} ).nodes().map( function ( td, i ) {
755         *        return $('input', td).val();
756         *      } );
757         *    }
758         */
759        order: {},
760
761
762        /**
763         * Type based plug-ins.
764         *
765         * Each column in DataTables has a type assigned to it, either by automatic
766         * detection or by direct assignment using the `type` option for the column.
767         * The type of a column will effect how it is ordering and search (plug-ins
768         * can also make use of the column type if required).
769         *
770         * @namespace
771         */
772        type: {
773            /**
774             * Automatic column class assignment
775             */
776            className: {},
777
778            /**
779             * Type detection functions.
780             *
781             * The functions defined in this object are used to automatically detect
782             * a column's type, making initialisation of DataTables super easy, even
783             * when complex data is in the table.
784             *
785             * The functions defined take two parameters:
786             *
787             *  1. `{*}` Data from the column cell to be analysed
788             *  2. `{settings}` DataTables settings object. This can be used to
789             *     perform context specific type detection - for example detection
790             *     based on language settings such as using a comma for a decimal
791             *     place. Generally speaking the options from the settings will not
792             *     be required
793             *
794             * Each function is expected to return:
795             *
796             * * `{string|null}` Data type detected, or null if unknown (and thus
797             *   pass it on to the other type detection functions.
798             *
799             *  @type array
800             *
801             *  @example
802             *    // Currency type detection plug-in:
803             *    $.fn.dataTable.ext.type.detect.push(
804             *      function ( data, settings ) {
805             *        // Check the numeric part
806             *        if ( ! data.substring(1).match(/[0-9]/) ) {
807             *          return null;
808             *        }
809             *
810             *        // Check prefixed by currency
811             *        if ( data.charAt(0) == '$' || data.charAt(0) == '&pound;' ) {
812             *          return 'currency';
813             *        }
814             *        return null;
815             *      }
816             *    );
817             */
818            detect: [],
819
820            /**
821             * Automatic renderer assignment
822             */
823            render: {},
824
825
826            /**
827             * Type based search formatting.
828             *
829             * The type based searching functions can be used to pre-format the
830             * data to be search on. For example, it can be used to strip HTML
831             * tags or to de-format telephone numbers for numeric only searching.
832             *
833             * Note that is a search is not defined for a column of a given type,
834             * no search formatting will be performed.
835             * 
836             * Pre-processing of searching data plug-ins - When you assign the sType
837             * for a column (or have it automatically detected for you by DataTables
838             * or a type detection plug-in), you will typically be using this for
839             * custom sorting, but it can also be used to provide custom searching
840             * by allowing you to pre-processing the data and returning the data in
841             * the format that should be searched upon. This is done by adding
842             * functions this object with a parameter name which matches the sType
843             * for that target column. This is the corollary of <i>afnSortData</i>
844             * for searching data.
845             *
846             * The functions defined take a single parameter:
847             *
848             *  1. `{*}` Data from the column cell to be prepared for searching
849             *
850             * Each function is expected to return:
851             *
852             * * `{string|null}` Formatted string that will be used for the searching.
853             *
854             *  @type object
855             *  @default {}
856             *
857             *  @example
858             *    $.fn.dataTable.ext.type.search['title-numeric'] = function ( d ) {
859             *      return d.replace(/\n/g," ").replace( /<.*?>/g, "" );
860             *    }
861             */
862            search: {},
863
864
865            /**
866             * Type based ordering.
867             *
868             * The column type tells DataTables what ordering to apply to the table
869             * when a column is sorted upon. The order for each type that is defined,
870             * is defined by the functions available in this object.
871             *
872             * Each ordering option can be described by three properties added to
873             * this object:
874             *
875             * * `{type}-pre` - Pre-formatting function
876             * * `{type}-asc` - Ascending order function
877             * * `{type}-desc` - Descending order function
878             *
879             * All three can be used together, only `{type}-pre` or only
880             * `{type}-asc` and `{type}-desc` together. It is generally recommended
881             * that only `{type}-pre` is used, as this provides the optimal
882             * implementation in terms of speed, although the others are provided
883             * for compatibility with existing JavaScript sort functions.
884             *
885             * `{type}-pre`: Functions defined take a single parameter:
886             *
887             *  1. `{*}` Data from the column cell to be prepared for ordering
888             *
889             * And return:
890             *
891             * * `{*}` Data to be sorted upon
892             *
893             * `{type}-asc` and `{type}-desc`: Functions are typical JavaScript sort
894             * functions, taking two parameters:
895             *
896             *  1. `{*}` Data to compare to the second parameter
897             *  2. `{*}` Data to compare to the first parameter
898             *
899             * And returning:
900             *
901             * * `{*}` Ordering match: <0 if first parameter should be sorted lower
902             *   than the second parameter, ===0 if the two parameters are equal and
903             *   >0 if the first parameter should be sorted height than the second
904             *   parameter.
905             * 
906             *  @type object
907             *  @default {}
908             *
909             *  @example
910             *    // Numeric ordering of formatted numbers with a pre-formatter
911             *    $.extend( $.fn.dataTable.ext.type.order, {
912             *      "string-pre": function(x) {
913             *        a = (a === "-" || a === "") ? 0 : a.replace( /[^\d\-\.]/g, "" );
914             *        return parseFloat( a );
915             *      }
916             *    } );
917             *
918             *  @example
919             *    // Case-sensitive string ordering, with no pre-formatting method
920             *    $.extend( $.fn.dataTable.ext.order, {
921             *      "string-case-asc": function(x,y) {
922             *        return ((x < y) ? -1 : ((x > y) ? 1 : 0));
923             *      },
924             *      "string-case-desc": function(x,y) {
925             *        return ((x < y) ? 1 : ((x > y) ? -1 : 0));
926             *      }
927             *    } );
928             */
929            order: {}
930        },
931
932        /**
933         * Unique DataTables instance counter
934         *
935         * @type int
936         * @private
937         */
938        _unique: 0,
939
940
941        //
942        // Depreciated
943        // The following properties are retained for backwards compatibility only.
944        // The should not be used in new projects and will be removed in a future
945        // version
946        //
947
948        /**
949         * Version check function.
950         *  @type function
951         *  @depreciated Since 1.10
952         */
953        fnVersionCheck: DataTable.fnVersionCheck,
954
955
956        /**
957         * Index for what 'this' index API functions should use
958         *  @type int
959         *  @deprecated Since v1.10
960         */
961        iApiIndex: 0,
962
963
964        /**
965         * Software version
966         *  @type string
967         *  @deprecated Since v1.10
968         */
969        sVersion: DataTable.version
970    };
971
972
973    //
974    // Backwards compatibility. Alias to pre 1.10 Hungarian notation counter parts
975    //
976    $.extend(_ext, {
977        afnFiltering: _ext.search,
978        aTypes: _ext.type.detect,
979        ofnSearch: _ext.type.search,
980        oSort: _ext.type.order,
981        afnSortData: _ext.order,
982        aoFeatures: _ext.feature,
983        oStdClasses: _ext.classes,
984        oPagination: _ext.pager
985    });
986
987
988    $.extend(DataTable.ext.classes, {
989        container: 'dt-container',
990        empty: {
991            row: 'dt-empty'
992        },
993        info: {
994            container: 'dt-info'
995        },
996        layout: {
997            row: 'dt-layout-row',
998            cell: 'dt-layout-cell',
999            tableRow: 'dt-layout-table',
1000            tableCell: '',
1001            start: 'dt-layout-start',
1002            end: 'dt-layout-end',
1003            full: 'dt-layout-full'
1004        },
1005        length: {
1006            container: 'dt-length',
1007            select: 'dt-input'
1008        },
1009        order: {
1010            canAsc: 'dt-orderable-asc',
1011            canDesc: 'dt-orderable-desc',
1012            isAsc: 'dt-ordering-asc',
1013            isDesc: 'dt-ordering-desc',
1014            none: 'dt-orderable-none',
1015            position: 'sorting_'
1016        },
1017        processing: {
1018            container: 'dt-processing'
1019        },
1020        scrolling: {
1021            body: 'dt-scroll-body',
1022            container: 'dt-scroll',
1023            footer: {
1024                self: 'dt-scroll-foot',
1025                inner: 'dt-scroll-footInner'
1026            },
1027            header: {
1028                self: 'dt-scroll-head',
1029                inner: 'dt-scroll-headInner'
1030            }
1031        },
1032        search: {
1033            container: 'dt-search',
1034            input: 'dt-input'
1035        },
1036        table: 'dataTable',
1037        tbody: {
1038            cell: '',
1039            row: ''
1040        },
1041        thead: {
1042            cell: '',
1043            row: ''
1044        },
1045        tfoot: {
1046            cell: '',
1047            row: ''
1048        },
1049        paging: {
1050            active: 'current',
1051            button: 'dt-paging-button',
1052            container: 'dt-paging',
1053            disabled: 'disabled',
1054            nav: ''
1055        }
1056    });
1057
1058
1059    /*
1060     * It is useful to have variables which are scoped locally s
1060o only the
1061     * DataTables functions can access them and they don't leak into global space.
1062     * At the same time these functions are often useful over multiple files in the
1063     * core and API, so we list, or at least document, all variables which are used
1064     * by DataTables as private variables here. This also ensures that there is no
1065     * clashing of variable names and that they can easily referenced for reuse.
1066     */
1067
1068
1069    // Defined else where
1070    //  _selector_run
1071    //  _selector_opts
1072    //  _selector_row_indexes
1073
1074    var _ext; // DataTable.ext
1075    var _Api; // DataTable.Api
1076    var _api_register; // DataTable.Api.register
1077    var _api_registerPlural; // DataTable.Api.registerPlural
1078
1079    var _re_dic = {};
1080    var _re_new_lines = /[\r\n\u2028]/g;
1081    var _re_html = /<([^>]*>)/g;
1082    var _max_str_len = Math.pow(2, 28);
1083
1084    // This is not strict ISO8601 - Date.parse() is quite lax, although
1085    // implementations differ between browsers.
1086    var _re_date = /^\d{2,4}[./-]\d{1,2}[./-]\d{1,2}([T ]{1}\d{1,2}[:.]\d{2}([.:]\d{2})?)?$/;
1087
1088    // Escape regular expression special characters
1089    var _re_escape_regex = new RegExp('(\\' + ['/', '.', '*', '+', '?', '|', '(', ')', '[', ']', '{', '}', '\\', '$', '^', '-'].join('|\\') + ')', 'g');
1090
1091    // https://en.wikipedia.org/wiki/Foreign_exchange_market
1092    // - \u20BD - Russian ruble.
1093    // - \u20a9 - South Korean Won
1094    // - \u20BA - Turkish Lira
1095    // - \u20B9 - Indian Rupee
1096    // - R - Brazil (R$) and South Africa
1097    // - fr - Swiss Franc
1098    // - kr - Swedish krona, Norwegian krone and Danish krone
1099    // - \u2009 is thin space and \u202F is narrow no-break space, both used in many
1100    // - Ƀ - Bitcoin
1101    // - Ξ - Ethereum
1102    //   standards as thousands separators.
1103    var _re_formatted_numeric = /['\u00A0,$£€¥%\u2009\u202F\u20BD\u20a9\u20BArfkɃΞ]/gi;
1104
1105
1106    var _empty = function (d) {
1107        return !d || d === true || d === '-' ? true : false;
1108    };
1109
1110
1111    var _intVal = function (s) {
1112        var integer = parseInt(s, 10);
1113        return !isNaN(integer) && isFinite(s) ? integer : null;
1114    };
1115
1116    // Convert from a formatted number with characters other than `.` as the
1117    // decimal place, to a JavaScript number
1118    var _numToDecimal = function (num, decimalPoint) {
1119        // Cache created regular expressions for speed as this function is called often
1120        if (!_re_dic[decimalPoint]) {
1121            _re_dic[decimalPoint] = new RegExp(_fnEscapeRegex(decimalPoint), 'g');
1122        }
1123        return typeof num === 'string' && decimalPoint !== '.' ?
1124            num.replace(/\./g, '').replace(_re_dic[decimalPoint], '.') :
1125            num;
1126    };
1127
1128
1129    var _isNumber = function (d, decimalPoint, formatted, allowEmpty) {
1130        var type = typeof d;
1131        var strType = type === 'string';
1132
1133        if (type === 'number' || type === 'bigint') {
1134            return true;
1135        }
1136
1137        // If empty return immediately so there must be a number if it is a
1138        // formatted string (this stops the string "k", or "kr", etc being detected
1139        // as a formatted number for currency
1140        if (allowEmpty && _empty(d)) {
1141            return true;
1142        }
1143
1144        if (decimalPoint && strType) {
1145            d = _numToDecimal(d, decimalPoint);
1146        }
1147
1148        if (formatted && strType) {
1149            d = d.replace(_re_formatted_numeric, '');
1150        }
1151
1152        return !isNaN(parseFloat(d)) && isFinite(d);
1153    };
1154
1155
1156    // A string without HTML in it can be considered to be HTML still
1157    var _isHtml = function (d) {
1158        return _empty(d) || typeof d === 'string';
1159    };
1160
1161    // Is a string a number surrounded by HTML?
1162    var _htmlNumeric = function (d, decimalPoint, formatted, allowEmpty) {
1163        if (allowEmpty && _empty(d)) {
1164            return true;
1165        }
1166
1167        // input and select strings mean that this isn't just a number
1168        if (typeof d === 'string' && d.match(/<(input|select)/i)) {
1169            return null;
1170        }
1171
1172        var html = _isHtml(d);
1173        return !html ?
1174            null :
1175            _isNumber(_stripHtml(d), decimalPoint, formatted, allowEmpty) ?
1176                true :
1177                null;
1178    };
1179
1180
1181    var _pluck = function (a, prop, prop2) {
1182        var out = [];
1183        var i = 0, iLen = a.length;
1184
1185        // Could have the test in the loop for slightly smaller code, but speed
1186        // is essential here
1187        if (prop2 !== undefined) {
1188            for (; i < iLen; i++) {
1189                if (a[i] && a[i][prop]) {
1190                    out.push(a[i][prop][prop2]);
1191                }
1192            }
1193        }
1194        else {
1195            for (; i < iLen; i++) {
1196                if (a[i]) {
1197                    out.push(a[i][prop]);
1198                }
1199            }
1200        }
1201
1202        return out;
1203    };
1204
1205
1206    // Basically the same as _pluck, but rather than looping over `a` we use `order`
1207    // as the indexes to pick from `a`
1208    var _pluck_order = function (a, order, prop, prop2) {
1209        var out = [];
1210        var i = 0, iLen = order.length;
1211
1212        // Could have the test in the loop for slightly smaller code, but speed
1213        // is essential here
1214        if (prop2 !== undefined) {
1215            for (; i < iLen; i++) {
1216                if (a[order[i]] && a[order[i]][prop]) {
1217                    out.push(a[order[i]][prop][prop2]);
1218                }
1219            }
1220        }
1221        else {
1222            for (; i < iLen; i++) {
1223                if (a[order[i]]) {
1224                    out.push(a[order[i]][prop]);
1225                }
1226            }
1227        }
1228
1229        return out;
1230    };
1231
1232
1233    var _range = function (len, start) {
1234        var out = [];
1235        var end;
1236
1237        if (start === undefined) {
1238            start = 0;
1239            end = len;
1240        }
1241        else {
1242            end = start;
1243            start = len;
1244        }
1245
1246        for (var i = start; i < end; i++) {
1247            out.push(i);
1248        }
1249
1250        return out;
1251    };
1252
1253
1254    var _removeEmpty = function (a) {
1255        var out = [];
1256
1257        for (var i = 0, iLen = a.length; i < iLen; i++) {
1258            if (a[i]) { // careful - will remove all falsy values!
1259                out.push(a[i]);
1260            }
1261        }
1262
1263        return out;
1264    };
1265
1266    // Replaceable function in api.util
1267    var _stripHtml = function (input) {
1268        if (!input || typeof input !== 'string') {
1269            return input;
1270        }
1271
1272        // Irrelevant check to workaround CodeQL's false positive on the regex
1273        if (input.length > _max_str_len) {
1274            throw new Error('Exceeded max str len');
1275        }
1276
1277        var previous;
1278
1279        input = input.replace(_re_html, ''); // Complete tags
1280
1281        // Safety for incomplete script tag - use do / while to ensure that
1282        // we get all instances
1283        do {
1284            previous = input;
1285            input = input.replace(/<script/i, '');
1286        } while (input !== previous);
1287
1288        return previous;
1289    };
1290
1291    // Replaceable function in api.util
1292    var _escapeHtml = function (d) {
1293        if (Array.isArray(d)) {
1294            d = d.join(',');
1295        }
1296
1297        return typeof d === 'string' ?
1298            d
1299                .replace(/&/g, '&amp;')
1300                .replace(/</g, '&lt;')
1301                .replace(/>/g, '&gt;')
1302                .replace(/"/g, '&quot;') :
1303            d;
1304    };
1305
1306    // Remove diacritics from a string by decomposing it and then removing
1307    // non-ascii characters
1308    var _normalize = function (str, both) {
1309        if (typeof str !== 'string') {
1310            return str;
1311        }
1312
1313        // It is faster to just run `normalize` than it is to check if
1314        // we need to with a regex! (Check as it isn't available in old
1315        // Safari)
1316        var res = str.normalize
1317            ? str.normalize("NFD")
1318            : str;
1319
1320        // Equally, here we check if a regex is needed or not
1321        return res.length !== str.length
1322            ? (both === true ? str + ' ' : '') + res.replace(/[\u0300-\u036f]/g, "")
1323            : res;
1324    }
1325
1326    /**
1327     * Determine if all values in the array are unique. This means we can short
1328     * cut the _unique method at the cost of a single loop. A sorted array is used
1329     * to easily check the values.
1330     *
1331     * @param  {array} src Source array
1332     * @return {boolean} true if all unique, false otherwise
1333     * @ignore
1334     */
1335    var _areAllUnique = function (src) {
1336        if (src.length < 2) {
1337            return true;
1338        }
1339
1340        var sorted = src.slice().sort();
1341        var last = sorted[0];
1342
1343        for (var i = 1, iLen = sorted.length; i < iLen; i++) {
1344            if (sorted[i] === last) {
1345                return false;
vendor: 28,737 bytes, lines 1346-2122
1346            }
1347
1348            last = sorted[i];
1349        }
1350
1351        return true;
1352    };
1353
1354
1355    /**
1356     * Find the unique elements in a source array.
1357     *
1358     * @param  {array} src Source array
1359     * @return {array} Array of unique items
1360     * @ignore
1361     */
1362    var _unique = function (src) {
1363        if (Array.from && Set) {
1364            return Array.from(new Set(src));
1365        }
1366
1367        if (_areAllUnique(src)) {
1368            return src.slice();
1369        }
1370
1371        // A faster unique method is to use object keys to identify used values,
1372        // but this doesn't work with arrays or objects, which we must also
1373        // consider. See jsperf.app/compare-array-unique-versions/4 for more
1374        // information.
1375        var
1376            out = [],
1377            val,
1378            i, iLen = src.length,
1379            j, k = 0;
1380
1381        again: for (i = 0; i < iLen; i++) {
1382            val = src[i];
1383
1384            for (j = 0; j < k; j++) {
1385                if (out[j] === val) {
1386                    continue again;
1387                }
1388            }
1389
1390            out.push(val);
1391            k++;
1392        }
1393
1394        return out;
1395    };
1396
1397    // Surprisingly this is faster than [].concat.apply
1398    // https://jsperf.com/flatten-an-array-loop-vs-reduce/2
1399    var _flatten = function (out, val) {
1400        if (Array.isArray(val)) {
1401            for (var i = 0; i < val.length; i++) {
1402                _flatten(out, val[i]);
1403            }
1404        }
1405        else {
1406            out.push(val);
1407        }
1408
1409        return out;
1410    }
1411
1412    // Similar to jQuery's addClass, but use classList.add
1413    function _addClass(el, name) {
1414        if (name) {
1415            name.split(' ').forEach(function (n) {
1416                if (n) {
1417                    // `add` does deduplication, so no need to check `contains`
1418                    el.classList.add(n);
1419                }
1420            });
1421        }
1422    }
1423
1424    /**
1425     * DataTables utility methods
1426     * 
1427     * This namespace provides helper methods that DataTables uses internally to
1428     * create a DataTable, but which are not exclusively used only for DataTables.
1429     * These methods can be used by extension authors to save the duplication of
1430     * code.
1431     *
1432     *  @namespace
1433     */
1434    DataTable.util = {
1435        /**
1436         * Return a string with diacritic characters decomposed
1437         * @param {*} mixed Function or string to normalize
1438         * @param {*} both Return original string and the normalized string
1439         * @returns String or undefined
1440         */
1441        diacritics: function (mixed, both) {
1442            var type = typeof mixed;
1443
1444            if (type !== 'function') {
1445                return _normalize(mixed, both);
1446            }
1447            _normalize = mixed;
1448        },
1449
1450        /**
1451         * Debounce a function
1452         *
1453         * @param {function} fn Function to be called
1454         * @param {integer} freq Call frequency in mS
1455         * @return {function} Wrapped function
1456         */
1457        debounce: function (fn, timeout) {
1458            var timer;
1459
1460            return function () {
1461                var that = this;
1462                var args = arguments;
1463
1464                clearTimeout(timer);
1465
1466                timer = setTimeout(function () {
1467                    fn.apply(that, args);
1468                }, timeout || 250);
1469            };
1470        },
1471
1472        /**
1473         * Throttle the calls to a function. Arguments and context are maintained
1474         * for the throttled function.
1475         *
1476         * @param {function} fn Function to be called
1477         * @param {integer} freq Call frequency in mS
1478         * @return {function} Wrapped function
1479         */
1480        throttle: function (fn, freq) {
1481            var
1482                frequency = freq !== undefined ? freq : 200,
1483                last,
1484                timer;
1485
1486            return function () {
1487                var
1488                    that = this,
1489                    now = +new Date(),
1490                    args = arguments;
1491
1492                if (last && now < last + frequency) {
1493                    clearTimeout(timer);
1494
1495                    timer = setTimeout(function () {
1496                        last = undefined;
1497                        fn.apply(that, args);
1498                    }, frequency);
1499                }
1500                else {
1501                    last = now;
1502                    fn.apply(that, args);
1503                }
1504            };
1505        },
1506
1507        /**
1508         * Escape a string such that it can be used in a regular expression
1509         *
1510         *  @param {string} val string to escape
1511         *  @returns {string} escaped string
1512         */
1513        escapeRegex: function (val) {
1514            return val.replace(_re_escape_regex, '\\$1');
1515        },
1516
1517        /**
1518         * Create a function that will write to a nested object or array
1519         * @param {*} source JSON notation string
1520         * @returns Write function
1521         */
1522        set: function (source) {
1523            if ($.isPlainObject(source)) {
1524                /* Unlike get, only the underscore (global) option is used for for
1525                 * setting data since we don't know the type here. This is why an object
1526                 * option is not documented for `mData` (which is read/write), but it is
1527                 * for `mRender` which is read only.
1528                 */
1529                return DataTable.util.set(source._);
1530            }
1531            else if (source === null) {
1532                // Nothing to do when the data source is null
1533                return function () { };
1534            }
1535            else if (typeof source === 'function') {
1536                return function (data, val, meta) {
1537                    source(data, 'set', val, meta);
1538                };
1539            }
1540            else if (
1541                typeof source === 'string' && (source.indexOf('.') !== -1 ||
1542                    source.indexOf('[') !== -1 || source.indexOf('(') !== -1)
1543            ) {
1544                // Like the get, we need to get data from a nested object
1545                var setData = function (data, val, src) {
1546                    var a = _fnSplitObjNotation(src), b;
1547                    var aLast = a[a.length - 1];
1548                    var arrayNotation, funcNotation, o, innerSrc;
1549
1550                    for (var i = 0, iLen = a.length - 1; i < iLen; i++) {
1551                        // Protect against prototype pollution
1552                        if (a[i] === '__proto__' || a[i] === 'constructor') {
1553                            throw new Error('Cannot set prototype values');
1554                        }
1555
1556                        // Check if we are dealing with an array notation request
1557                        arrayNotation = a[i].match(__reArray);
1558                        funcNotation = a[i].match(__reFn);
1559
1560                        if (arrayNotation) {
1561                            a[i] = a[i].replace(__reArray, '');
1562                            data[a[i]] = [];
1563
1564                            // Get the remainder of the nested object to set so we can recurse
1565                            b = a.slice();
1566                            b.splice(0, i + 1);
1567                            innerSrc = b.join('.');
1568
1569                            // Traverse each entry in the array setting the properties requested
1570                            if (Array.isArray(val)) {
1571                                for (var j = 0, jLen = val.length; j < jLen; j++) {
1572                                    o = {};
1573                                    setData(o, val[j], innerSrc);
1574                                    data[a[i]].push(o);
1575                                }
1576                            }
1577                            else {
1578                                // We've been asked to save data to an array, but it
1579                                // isn't array data to be saved. Best that can be done
1580                                // is to just save the value.
1581                                data[a[i]] = val;
1582                            }
1583
1584                            // The inner call to setData has already traversed through the remainder
1585                            // of the source and has set the data, thus we can exit here
1586                            return;
1587                        }
1588                        else if (funcNotation) {
1589                            // Function call
1590                            a[i] = a[i].replace(__reFn, '');
1591                            data = data[a[i]](val);
1592                        }
1593
1594                        // If the nested object doesn't currently exist - since we are
1595                        // trying to set the value - create it
1596                        if (data[a[i]] === null || data[a[i]] === undefined) {
1597                            data[a[i]] = {};
1598                        }
1599                        data = data[a[i]];
1600                    }
1601
1602                    // Last item in the input - i.e, the actual set
1603                    if (aLast.match(__reFn)) {
1604                        // Function call
1605                        data = data[aLast.replace(__reFn, '')](val);
1606                    }
1607                    else {
1608                        // If array notation is used, we just want to strip it and use the property name
1609                        // and assign the value. If it isn't used, then we get the result we want anyway
1610                        data[aLast.replace(__reArray, '')] = val;
1611                    }
1612                };
1613
1614                return function (data, val) { // meta is also passed in, but not used
1615                    return setData(data, val, source);
1616                };
1617            }
1618            else {
1619                // Array or flat object mapping
1620                return function (data, val) { // meta is also passed in, but not used
1621                    data[source] = val;
1622                };
1623            }
1624        },
1625
1626        /**
1627         * Create a function that will read nested objects from arrays, based on JSON notation
1628         * @param {*} source JSON notation string
1629         * @returns Value read
1630         */
1631        get: function (source) {
1632            if ($.isPlainObject(source)) {
1633                // Build an object of get functions, and wrap them in a single call
1634                var o = {};
1635                $.each(source, function (key, val) {
1636                    if (val) {
1637                        o[key] = DataTable.util.get(val);
1638                    }
1639                });
1640
1641                return function (data, type, row, meta) {
1642                    var t = o[type] || o._;
1643                    return t !== undefined ?
1644                        t(data, type, row, meta) :
1645                        data;
1646                };
1647            }
1648            else if (source === null) {
1649                // Give an empty string for rendering / sorting etc
1650                return function (data) { // type, row and meta also passed, but not used
1651                    return data;
1652                };
1653            }
1654            else if (typeof source === 'function') {
1655                return function (data, type, row, meta) {
1656                    return source(data, type, row, meta);
1657                };
1658            }
1659            else if (
1660                typeof source === 'string' && (source.indexOf('.') !== -1 ||
1661                    source.indexOf('[') !== -1 || source.indexOf('(') !== -1)
1662            ) {
1663                /* If there is a . in the source string then the data source is in a
1664                 * nested object so we loop over the data for each level to get the next
1665                 * level down. On each loop we test for undefined, and if found immediately
1666                 * return. This allows entire objects to be missing and sDefaultContent to
1667                 * be used if defined, rather than throwing an error
1668                 */
1669                var fetchData = function (data, type, src) {
1670                    var arrayNotation, funcNotation, out, innerSrc;
1671
1672                    if (src !== "") {
1673                        var a = _fnSplitObjNotation(src);
1674
1675                        for (var i = 0, iLen = a.length; i < iLen; i++) {
1676                            // Check if we are dealing with special notation
1677                            arrayNotation = a[i].match(__reArray);
1678                            funcNotation = a[i].match(__reFn);
1679
1680                            if (arrayNotation) {
1681                                // Array notation
1682                                a[i] = a[i].replace(__reArray, '');
1683
1684                                // Condition allows simply [] to be passed in
1685                                if (a[i] !== "") {
1686                                    data = data[a[i]];
1687                                }
1688                                out = [];
1689
1690                                // Get the remainder of the nested object to get
1691                                a.splice(0, i + 1);
1692                                innerSrc = a.join('.');
1693
1694                                // Traverse each entry in the array getting the properties requested
1695                                if (Array.isArray(data)) {
1696                                    for (var j = 0, jLen = data.length; j < jLen; j++) {
1697                                        out.push(fetchData(data[j], type, innerSrc));
1698                                    }
1699                                }
1700
1701                                // If a string is given in between the array notation indicators, that
1702                                // is used to join the strings together, otherwise an array is returned
1703                                var join = arrayNotation[0].substring(1, arrayNotation[0].length - 1);
1704                                data = (join === "") ? out : out.join(join);
1705
1706                                // The inner call to fetchData has already traversed through the remainder
1707                                // of the source requested, so we exit from the loop
1708                                break;
1709                            }
1710                            else if (funcNotation) {
1711                                // Function call
1712                                a[i] = a[i].replace(__reFn, '');
1713                                data = data[a[i]]();
1714                                continue;
1715                            }
1716
1717                            if (data === null || data[a[i]] === null) {
1718                                return null;
1719                            }
1720                            else if (data === undefined || data[a[i]] === undefined) {
1721                                return undefined;
1722                            }
1723
1724                            data = data[a[i]];
1725                        }
1726                    }
1727
1728                    return data;
1729                };
1730
1731                return function (data, type) { // row and meta also passed, but not used
1732                    return fetchData(data, type, source);
1733                };
1734            }
1735            else {
1736                // Array or flat object mapping
1737                return function (data) { // row and meta also passed, but not used
1738                    return data[source];
1739                };
1740            }
1741        },
1742
1743        stripHtml: function (mixed) {
1744            var type = typeof mixed;
1745
1746            if (type === 'function') {
1747                _stripHtml = mixed;
1748                return;
1749            }
1750            else if (type === 'string') {
1751                return _stripHtml(mixed);
1752            }
1753            return mixed;
1754        },
1755
1756        escapeHtml: function (mixed) {
1757            var type = typeof mixed;
1758
1759            if (type === 'function') {
1760                _escapeHtml = mixed;
1761                return;
1762            }
1763            else if (type === 'string' || Array.isArray(mixed)) {
1764                return _escapeHtml(mixed);
1765            }
1766            return mixed;
1767        },
1768
1769        unique: _unique
1770    };
1771
1772
1773
1774    /**
1775     * Create a mapping object that allows camel case parameters to be looked up
1776     * for their Hungarian counterparts. The mapping is stored in a private
1777     * parameter called `_hungarianMap` which can be accessed on the source object.
1778     *  @param {object} o
1779     *  @memberof DataTable#oApi
1780     */
1781    function _fnHungarianMap(o) {
1782        var
1783            hungarian = 'a aa ai ao as b fn i m o s ',
1784            match,
1785            newKey,
1786            map = {};
1787
1788        $.each(o, function (key) {
1789            match = key.match(/^([^A-Z]+?)([A-Z])/);
1790
1791            if (match && hungarian.indexOf(match[1] + ' ') !== -1) {
1792                newKey = key.replace(match[0], match[2].toLowerCase());
1793                map[newKey] = key;
1794
1795                if (match[1] === 'o') {
1796                    _fnHungarianMap(o[key]);
1797                }
1798            }
1799        });
1800
1801        o._hungarianMap = map;
1802    }
1803
1804
1805    /**
1806     * Convert from camel case parameters to Hungarian, based on a Hungarian map
1807     * created by _fnHungarianMap.
1808     *  @param {object} src The model object which holds all parameters that can be
1809     *    mapped.
1810     *  @param {object} user The object to convert from camel case to Hungarian.
1811     *  @param {boolean} force When set to `true`, properties which already have a
1812     *    Hungarian value in the `user` object will be overwritten. Otherwise they
1813     *    won't be.
1814     *  @memberof DataTable#oApi
1815     */
1816    function _fnCamelToHungarian(src, user, force) {
1817        if (!src._hungarianMap) {
1818            _fnHungarianMap(src);
1819        }
1820
1821        var hungarianKey;
1822
1823        $.each(user, function (key) {
1824            hungarianKey = src._hungarianMap[key];
1825
1826            if (hungarianKey !== undefined && (force || user[hungarianKey] === undefined)) {
1827                // For objects, we need to buzz down into the object to copy parameters
1828                if (hungarianKey.charAt(0) === 'o') {
1829                    // Copy the camelCase options over to the hungarian
1830                    if (!user[hungarianKey]) {
1831                        user[hungarianKey] = {};
1832                    }
1833                    $.extend(true, user[hungarianKey], user[key]);
1834
1835                    _fnCamelToHungarian(src[hungarianKey], user[hungarianKey], force);
1836                }
1837                else {
1838                    user[hungarianKey] = user[key];
1839                }
1840            }
1841        });
1842    }
1843
1844    /**
1845     * Map one parameter onto another
1846     *  @param {object} o Object to map
1847     *  @param {*} knew The new parameter name
1848     *  @param {*} old The old parameter name
1849     */
1850    var _fnCompatMap = function (o, knew, old) {
1851        if (o[knew] !== undefined) {
1852            o[old] = o[knew];
1853        }
1854    };
1855
1856
1857    /**
1858     * Provide backwards compatibility for the main DT options. Note that the new
1859     * options are mapped onto the old parameters, so this is an external interface
1860     * change only.
1861     *  @param {object} init Object to map
1862     */
1863    function _fnCompatOpts(init) {
1864        _fnCompatMap(init, 'ordering', 'bSort');
1865        _fnCompatMap(init, 'orderMulti', 'bSortMulti');
1866        _fnCompatMap(init, 'orderClasses', 'bSortClasses');
1867        _fnCompatMap(init, 'orderCellsTop', 'bSortCellsTop');
1868        _fnCompatMap(init, 'order', 'aaSorting');
1869        _fnCompatMap(init, 'orderFixed', 'aaSortingFixed');
1870        _fnCompatMap(init, 'paging', 'bPaginate');
1871        _fnCompatMap(init, 'pagingType', 'sPaginationType');
1872        _fnCompatMap(init, 'pageLength', 'iDisplayLength');
1873        _fnCompatMap(init, 'searching', 'bFilter');
1874
1875        // Boolean initialisation of x-scrolling
1876        if (typeof init.sScrollX === 'boolean') {
1877            init.sScrollX = init.sScrollX ? '100%' : '';
1878        }
1879        if (typeof init.scrollX === 'boolean') {
1880            init.scrollX = init.scrollX ? '100%' : '';
1881        }
1882
1883        // Objects for ordering
1884        if (typeof init.bSort === 'object') {
1885            init.orderIndicators = init.bSort.indicators !== undefined ? init.bSort.indicators : true;
1886            init.orderHandler = init.bSort.handler !== undefined ? init.bSort.handler : true;
1887            init.bSort = true;
1888        }
1889        else if (init.bSort === false) {
1890            init.orderIndicators = false;
1891            init.orderHandler = false;
1892        }
1893        else if (init.bSort === true) {
1894            init.orderIndicators = true;
1895            init.orderHandler = true;
1896        }
1897
1898        // Which cells are the title cells?
1899        if (typeof init.bSortCellsTop === 'boolean') {
1900            init.titleRow = init.bSortCellsTop;
1901        }
1902
1903        // Column search objects are in an array, so it needs to be converted
1904        // element by element
1905        var searchCols = init.aoSearchCols;
1906
1907        if (searchCols) {
1908            for (var i = 0, iLen = searchCols.length; i < iLen; i++) {
1909                if (searchCols[i]) {
1910                    _fnCamelToHungarian(DataTable.models.oSearch, searchCols[i]);
1911                }
1912            }
1913        }
1914
1915        // Enable search delay if server-side processing is enabled
1916        if (init.serverSide && !init.searchDelay) {
1917            init.searchDelay = 400;
1918        }
1919    }
1920
1921
1922    /**
1923     * Provide backwards compatibility for column options. Note that the new options
1924     * are mapped onto the old parameters, so this is an external interface change
1925     * only.
1926     *  @param {object} init Object to map
1927     */
1928    function _fnCompatCols(init) {
1929        _fnCompatMap(init, 'orderable', 'bSortable');
1930        _fnCompatMap(init, 'orderData', 'aDataSort');
1931        _fnCompatMap(init, 'orderSequence', 'asSorting');
1932        _fnCompatMap(init, 'orderDataType', 'sortDataType');
1933
1934        // orderData can be given as an integer
1935        var dataSort = init.aDataSort;
1936        if (typeof dataSort === 'number' && !Array.isArray(dataSort)) {
1937            init.aDataSort = [dataSort];
1938        }
1939    }
1940
1941
1942    /**
1943     * Browser feature detection for capabilities, quirks
1944     *  @param {object} settings dataTables settings object
1945     *  @memberof DataTable#oApi
1946     */
1947    function _fnBrowserDetect(settings) {
1948        // We don't need to do this every time DataTables is constructed, the values
1949        // calculated are specific to the browser and OS configuration which we
1950        // don't expect to change between initialisations
1951        if (!DataTable.__browser) {
1952            var browser = {};
1953            DataTable.__browser = browser;
1954
1955            // Scrolling feature / quirks detection
1956            var n = $('<div/>')
1957                .css({
1958                    position: 'fixed',
1959                    top: 0,
1960                    left: -1 * window.pageXOffset, // allow for scrolling
1961                    height: 1,
1962                    width: 1,
1963                    overflow: 'hidden'
1964                })
1965                .append(
1966                    $('<div/>')
1967                        .css({
1968                            position: 'absolute',
1969                            top: 1,
1970                            left: 1,
1971                            width: 100,
1972                            overflow: 'scroll'
1973                        })
1974                        .append(
1975                            $('<div/>')
1976                                .css({
1977                                    width: '100%',
1978                                    height: 10
1979                                })
1980                        )
1981                )
1982                .appendTo('body');
1983
1984            var outer = n.children();
1985            var inner = outer.children();
1986
1987            // Get scrollbar width
1988            browser.barWidth = outer[0].offsetWidth - outer[0].clientWidth;
1989
1990            // In rtl text layout, some browsers (most, but not all) will place the
1991            // scrollbar on the left, rather than the right.
1992            browser.bScrollbarLeft = Math.round(inner.offset().left) !== 1;
1993
1994            n.remove();
1995        }
1996
1997        $.extend(settings.oBrowser, DataTable.__browser);
1998        settings.oScroll.iBarWidth = DataTable.__browser.barWidth;
1999    }
2000
2001    /**
2002     * Add a column to the list used for the table with default values
2003     *  @param {object} oSettings dataTables settings object
2004     *  @memberof DataTable#oApi
2005     */
2006    function _fnAddColumn(oSettings) {
2007        // Add column to aoColumns array
2008        var oDefaults = DataTable.defaults.column;
2009        var iCol = oSettings.aoColumns.length;
2010        var oCol = $.extend({}, DataTable.models.oColumn, oDefaults, {
2011            "aDataSort": oDefaults.aDataSort ? oDefaults.aDataSort : [iCol],
2012            "mData": oDefaults.mData ? oDefaults.mData : iCol,
2013            idx: iCol,
2014            searchFixed: {},
2015            colEl: $('<col>').attr('data-dt-column', iCol)
2016        });
2017        oSettings.aoColumns.push(oCol);
2018
2019        // Add search object for column specific search. Note that the `searchCols[ iCol ]`
2020        // passed into extend can be undefined. This allows the user to give a default
2021        // with only some of the parameters defined, and also not give a default
2022        var searchCols = oSettings.aoPreSearchCols;
2023        searchCols[iCol] = $.extend({}, DataTable.models.oSearch, searchCols[iCol]);
2024    }
2025
2026
2027    /**
2028     * Apply options for a column
2029     *  @param {object} oSettings dataTables settings object
2030     *  @param {int} iCol column index to consider
2031     *  @param {object} oOptions object with sType, bVisible and bSearchable etc
2032     *  @memberof DataTable#oApi
2033     */
2034    function _fnColumnOptions(oSettings, iCol, oOptions) {
2035        var oCol = oSettings.aoColumns[iCol];
2036
2037        /* User specified column options */
2038        if (oOptions !== undefined && oOptions !== null) {
2039            // Backwards compatibility
2040            _fnCompatCols(oOptions);
2041
2042            // Map camel case parameters to their Hungarian counterparts
2043            _fnCamelToHungarian(DataTable.defaults.column, oOptions, true);
2044
2045            /* Backwards compatibility for mDataProp */
2046            if (oOptions.mDataProp !== undefined && !oOptions.mData) {
2047                oOptions.mData = oOptions.mDataProp;
2048            }
2049
2050            if (oOptions.sType) {
2051                oCol._sManualType = oOptions.sType;
2052            }
2053
2054            // `class` is a reserved word in JavaScript, so we need to provide
2055            // the ability to use a valid name for the camel case input
2056            if (oOptions.className && !oOptions.sClass) {
2057                oOptions.sClass = oOptions.className;
2058            }
2059
2060            var origClass = oCol.sClass;
2061
2062            $.extend(oCol, oOptions);
2063            _fnMap(oCol, oOptions, "sWidth", "sWidthOrig");
2064
2065            // Merge class from previously defined classes with this one, rather than just
2066            // overwriting it in the extend above
2067            if (origClass !== oCol.sClass) {
2068                oCol.sClass = origClass + ' ' + oCol.sClass;
2069            }
2070
2071            /* iDataSort to be applied (backwards compatibility), but aDataSort will take
2072             * priority if defined
2073             */
2074            if (oOptions.iDataSort !== undefined) {
2075                oCol.aDataSort = [oOptions.iDataSort];
2076            }
2077            _fnMap(oCol, oOptions, "aDataSort");
2078        }
2079
2080        /* Cache the data get and set functions for speed */
2081        var mDataSrc = oCol.mData;
2082        var mData = _fnGetObjectDataFn(mDataSrc);
2083
2084        // The `render` option can be given as an array to access the helper rendering methods.
2085        // The first element is the rendering method to use, the rest are the parameters to pass
2086        if (oCol.mRender && Array.isArray(oCol.mRender)) {
2087            var copy = oCol.mRender.slice();
2088            var name = copy.shift();
2089
2090            oCol.mRender = DataTable.render[name].apply(window, copy);
2091        }
2092
2093        oCol._render = oCol.mRender ? _fnGetObjectDataFn(oCol.mRender) : null;
2094
2095        var attrTest = function (src) {
2096            return typeof src === 'string' && src.indexOf('@') !== -1;
2097        };
2098        oCol._bAttrSrc = $.isPlainObject(mDataSrc) && (
2099            attrTest(mDataSrc.sort) || attrTest(mDataSrc.type) || attrTest(mDataSrc.filter)
2100        );
2101        oCol._setter = null;
2102
2103        oCol.fnGetData = function (rowData, type, meta) {
2104            var innerData = mData(rowData, type, undefined, meta);
2105
2106            return oCol._render && type ?
2107                oCol._render(innerData, type, rowData, meta) :
2108                innerData;
2109        };
2110        oCol.fnSetData = function (rowData, val, meta) {
2111            return _fnSetObjectDataFn(mDataSrc)(rowData, val, meta);
2112        };
2113
2114        // Indicate if DataTables should read DOM data as an object or array
2115        // Used in _fnGetRowElements
2116        if (typeof mDataSrc !== 'number' && !oCol._isArrayHost) {
2117            oSettings._rowReadObject = true;
2118        }
2119
2120        /* Feature sorting overrides column specific when off */
2121        if (!oSettings.oFeatures.bSort) {
2122            oCol.bSortable = false;
2123        }
2124    }
2125
2126
2127    /**
2128     * Adjust the table column widths for new data. Note: you would probably want to
2129     * do a redraw after calling this function!
2130     *  @param {object} settings dataTables settings object
2131     *  @memberof DataTable#oApi
2132     */
2133    function _fnAdjustColumnSizing(settings) {
2134        _fnCalculateColumnWidths(settings);
2135        _fnColumnSizes(settings);
2136
2137        var scroll = settings.oScroll;
2138        if (scroll.sY !== '' || scroll.sX !== '') {
2139            _fnScrollDraw(settings);
2140        }
2141
2142        _fnCallbackFire(settings, null, 'column-sizing', [settings]);
2143    }
2144
2145    /**
2146     * Apply column sizes
2147     *
2148     * @param {*} settings DataTables settings object
2149     */
2150    function _fnColumnSizes(settings) {
2151        var cols = settings.aoColumns;
2152
2153        for (var i = 0; i < cols.length; i++) {
2154            var width = _fnColumnsSumWidth(settings, [i], false, false);
2155
2156            cols[i].colEl.css('width', width);
2157
2158            if (settings.oScroll.sX) {
2159                cols[i].colEl.css('min-width', width);
2160            }
2161        }
2162    }
2163
2164
2165    /**
2166     * Convert the index of a visible column to the index in the data array (take account
2167     * of hidden columns)
2168     *  @param {object} oSettings dataTables settings object
2169     *  @param {int} iMatch Visible column index to lookup
2170     *  @returns {int} i the data index
2171     *  @memberof DataTable#oApi
2172     */
2173    function _fnVisibleToColumnIndex(oSettings, iMatch) {
2174        var aiVis = _fnGetColumns(oSettings, 'bVisible');
2175
2176        return typeof aiVis[iMatch] === 'number' ?
2177            aiVis[iMatch] :
2178            null;
2179    }
2180
2181
2182    /**
2183     * Convert the index of an index in the data array and convert it to the visible
2184     *   column index (take account of hidden columns)
2185     *  @param {int} iMatch Column index to lookup
2186     *  @param {object} oSettings dataTables settings object
2187     *  @returns {int} i the data index
2188     *  @memberof DataTable#oApi
2189     */
2190    function _fnColumnIndexToVisible(oSettings, iMatch) {
2191        var aiVis = _fnGetColumns(oSettings, 'bVisible');
2192        var iPos = aiVis.indexOf(iMatch);
2193
2194        return iPos !== -1 ? iPos : null;
2195    }
2196
2197
2198    /**
2199     * Get the number of visible columns
2200     *  @param {object} oSettings dataTables settings object
2201     *  @returns {int} i the number of visible columns
2202     *  @memberof DataTable#oApi
2203     */
2204    function _fnVisibleColumns(settings) {
2205        var layout = settings.aoHeader;
2206        var columns = settings.aoColumns;
2207        var vis = 0;
2208
2209        if (layout.length) {
2210            for (var i = 0, iLen = layout[0].length; i < iLen; i++) {
2211                if (columns[i].bVisible && $(layout[0][i].cell).css('display') !== 'none') {
2212                    vis++;
2213                }
2214            }
2215        }
2216
2217        return vis;
2218    }
2219
2220
2221    /**
2222     * Get an array of column indexes that match a given property
2223     *  @param {object} oSettings dataTables settings object
2224     *  @param {string} sParam Parameter in aoColumns to look for - typically
2225     *    bVisible or bSearchable
2226     *  @returns {array} Array of indexes with matched properties
2227     *  @memberof DataTable#oApi
2228     */
2229    function _fnGetColumns(oSettings, sParam) {
2230        var a = [];
2231
2232        oSettings.aoColumns.map(function (val, i) {
2233            if (val[sParam]) {
2234                a.push(i);
2235            }
2236        });
2237
2238        return a;
2239    }
2240
2241    /**
2242     * Allow the result from a type detection function to be `true` while
2243     * translating that into a string. Old type detection functions will
2244     * return the type name if it passes. An object store would be better,
2245     * but not backwards compatible.
2246     *
2247     * @param {*} typeDetect Object or function for type detection
2248     * @param {*} res Result from the type detection function
2249     * @returns Type name or false
2250     */
2251    function _typeResult(typeDetect, res) {
2252        return res === true
2253            ? typeDetect._name
2254            : res;
2255    }
2256
2257    /**
2258     * Calculate the 'type' of a column
2259     *  @param {object} settings dataTables settings object
2260     *  @memberof DataTable#oApi
2261     */
2262    function _fnColumnTypes(settings) {
2263        var columns = settings.aoColumns;
2264        var data = settings.aoData;
2265        var types = DataTable.ext.type.detect;
2266        var i, iLen, j, jen, k, ken;
2267        var col, detectedType, cache;
2268
2269        // For each column, spin over the data type detection functions, seeing if one matches
2270        for (i = 0, iLen = columns.length; i < iLen; i++) {
2271            col = columns[i];
2272            cache = [];
2273
2274            if (!col.sType && col._sManualType) {
2275                col.sType = col._sManualType;
2276            }
2277            else if (!col.sType) {
2278                // With SSP type detection can be unreliable and error prone, so we provide a way
2279                // to turn it off.
2280                if (!settings.typeDetect) {
2281                    return;
2282                }
2283
2284                for (j = 0, jen = types.length; j < jen; j++) {
2285                    var typeDetect = types[j];
2286
2287                    // There can be either one, or three type detection functions
2288                    var oneOf = typeDetect.oneOf;
2289                    var allOf = typeDetect.allOf || typeDetect;
2290                    var init = typeDetect.init;
2291                    var one = false;
2292
2293                    detectedType = null;
2294
2295                    // Fast detect based on column assignment
2296                    if (init) {
2297                        detectedType = _typeResult(typeDetect, init(settings, col, i));
2298
2299                        if (detectedType) {
2300                            col.sType = detectedType;
2301                            break;
2302                        }
2303                    }
2304
2305                    for (k = 0, ken = data.length; k < ken; k++) {
2306                        if (!data[k]) {
2307                            continue;
2308                        }
2309
2310                        // Use a cache array so we only need to get the type data
2311                        // from the formatter once (when using multiple detectors)
2312                        if (cache[k] === undefined) {
2313                            cache[k] = _fnGetCellData(settings, k, i, 'type');
2314                        }
2315
2316                        // Only one data point in the column needs to match this function
2317                        if (oneOf && !one) {
2318                            one = _typeResult(typeDetect, oneOf(cache[k], settings));
2319                        }
2320
2321                        // All data points need to match this function
2322                        detectedType = _typeResult(typeDetect, allOf(cache[k], settings));
2323
2324                        // If null, then this type can't apply to this column, so
2325                        // rather than testing all cells, break out. There is an
2326                        // exception for the last type which is `html`. We need to
2327                        // scan all rows since it is possible to mix string and HTML
2328                        // types
2329                        if (!detectedType && j !== types.length - 3) {
2330                            break;
2331                        }
2332
2333                        // Only a single match is needed for html type since it is
2334                        // bottom of the pile and very similar to string - but it
2335                        // must not be empty
2336                        if (detectedType === 'html' && !_empty(cache[k])) {
2337                            break;
2338                        }
2339                    }
2340
2341                    // Type is valid for all data points in the column - use this
2342                    // type
2343                    if ((oneOf && one && detectedType) || (!oneOf && detectedType)) {
2344                        col.sType = detectedType;
2345                        break;
2346                    }
2347                }
2348
2349                // Fall back - if no type was detected, always use string
2350                if (!col.sType) {
2351                    col.sType = 'string';
2352                }
2353            }
2354
2355            // Set class names for header / footer for auto type classes
2356            var autoClass = _ext.type.className[col.sType];
2357
2358            if (autoClass) {
2359                _columnAutoClass(settings.aoHeader, i, autoClass);
2360                _columnAutoClass(settings.aoFooter, i, autoClass);
2361            }
2362
2363            var renderer = _ext.type.render[col.sType];
2364
2365            // This can only happen once! There is no way to remove
2366            // a renderer. After the first time the renderer has
2367            // already been set so createTr will run the renderer itself.
2368            if (renderer && !col._render) {
2369                col._render = DataTable.util.get(renderer);
2370
2371                _columnAutoRender(settings, i);
2372            }
2373        }
2374    }
2375
2376    /**
2377     * Apply an auto detected renderer to data which doesn't yet have
2378     * a renderer
2379     */
2380    function _columnAutoRender(settings, colIdx) {
2381        var data = settings.aoData;
2382
2383        for (var i = 0; i < data.length; i++) {
2384            if (data[i].nTr) {
2385                // We have to update the display here since there is no
2386                // invalidation check for the data
2387                var display = _fnGetCellData(settings, i, colIdx, 'display');
2388
2389                data[i].displayData[colIdx] = display;
2390                _fnWriteCell(data[i].anCells[colIdx], display);
2391
2392                // No need to update sort / filter data since it has
2393                // been invalidated and will be re-read with the
2394                // renderer now applied
2395            }
2396        }
2397    }
2398
2399    /**
2400     * Apply a class name to a column's header cells
2401     */
2402    function _columnAutoClass(container, colIdx, className) {
2403        container.forEach(function (row) {
2404            if (row[colIdx] && row[colIdx].unique) {
2405                _addClass(row[colIdx].cell, className);
2406            }
2407        });
2408    }
2409
2410    /**
2411     * Take the column definitions and static columns arrays and calculate how
2412     * they relate to column indexes. The callback function will then apply the
2413     * definition found for a column to a suitable configuration object.
2414     *  @param {object} oSettings dataTables settings object
2415     *  @param {array} aoColDefs The aoColumnDefs array that is to be applied
2416     *  @param {array} aoCols The aoColumns array that defines columns individually
2417     *  @param {array} headerLayout Layout for header as it was loaded
2418     *  @param {function} fn Callback function - takes two parameters, the calculated
2419     *    column index and the definition for that column.
2420     *  @memberof DataTable#oApi
2421     */
2422    function _fnApplyColumnDefs(oSettings, aoColDefs, aoCols, headerLayout, fn) {
2423        var i, iLen, j, jLen, k, kLen, def;
2424        var columns = oSettings.aoColumns;
2425
2426        if (aoCols) {
2427            for (i = 0, iLen = aoCols.length; i < iLen; i++) {
2428                if (aoCols[i] && aoCols[i].name) {
2429                    columns[i].sName = aoCols[i].name;
2430                }
2431            }
2432        }
2433
2434        // Column definitions with aTargets
2435        if (aoColDefs) {
2436            /* Loop over the definitions array - loop in reverse so first instance has priority */
2437            for (i = aoColDefs.length - 1; i >= 0; i--) {
2438                def = aoColDefs[i];
2439
2440                /* Each definition can target multiple columns, as it is an array */
2441                var aTargets = def.target !== undefined
2442                    ? def.target
2443                    : def.targets !== undefined
2444                        ? def.targets
2445                        : def.aTargets;
2446
2447                if (!Array.isArray(aTargets)) {
2448                    aTargets = [aTargets];
2449                }
2450
2451                for (j = 0, jLen = aTargets.length; j < jLen; j++) {
2452                    var target = aTargets[j];
2453
2454                    if (typeof target === 'number' && target >= 0) {
2455                        /* Add columns that we don't yet know about */
2456                        while (columns.length <= target) {
2457                            _fnAddColumn(oSettings);
2458                        }
2459
2460                        /* Integer, basic index */
2461                        fn(target, def);
2462                    }
2463                    else if (typeof target === 'number' && target < 0) {
2464                        /* Negative integer, right to left column counting */
2465                        fn(columns.length + target, def);
2466                    }
2467                    else if (typeof target === 'string') {
2468                        for (k = 0, kLen = columns.length; k < kLen; k++) {
2469                            if (target === '_all') {
2470                                // Apply to all columns
2471                                fn(k, def);
2472                            }
2473                            else if (target.indexOf(':name') !== -1) {
2474                                // Column selector
2475                                if (columns[k].sName === target.replace(':name', '')) {
2476                                    fn(k, def);
2477                                }
2478                            }
2479                            else {
2480                                // Cell selector
2481                                headerLayout.forEach(function (row) {
2482                                    if (row[k]) {
2483                                        var cell = $(row[k].cell);
2484
2485                                        // Legacy support. Note that it means that we don't support
2486                                        // an element name selector only, since they are treated as
2487                                        // class names for 1.x compat.
2488                                        if (target.match(/^[a-z][\w-]*$/i)) {
2489                                            target = '.' + target;
2490                                        }
2491
2492                                        if (cell.is(target)) {
2493                                            fn(k, def);
2494                                        }
2495                                    }
2496                                });
2497                            }
2498                        }
2499                    }
2500                }
2501            }
2502        }
2503
2504        // Statically defined columns array
2505        if (aoCols) {
2506            for (i = 0, iLen = aoCols.length; i < iLen; i++) {
2507                fn(i, aoCols[i]);
2508            }
2509        }
2510    }
2511
2512
2513    /**
2514     * Get the width for a given set of columns
2515     *
2516     * @param {*} settings DataTables settings object
2517     * @param {*} targets Columns - comma separated string or array of numbers
2518     * @param {*} original Use the original width (true) or calculated (false)
2519     * @param {*} incVisible Include visible columns (true) or not (false)
2520     * @returns Combined CSS value
2521     */
2522    function _fnColumnsSumWidth(settings, targets, original, incVisible) {
2523        if (!Array.isArray(targets)) {
2524            targets = _fnColumnsFromHeader(targets);
2525        }
2526
2527        var sum = 0;
2528        var unit;
2529        var columns = settings.aoColumns;
2530
2531        for (var i = 0, iLen = targets.length; i < iLen; i++) {
2532            var column = columns[targets[i]];
2533            var definedWidth = original ?
2534                column.sWidthOrig :
2535                column.sWidth;
2536
2537            if (!incVisible && column.bVisible === false) {
2538                continue;
2539            }
2540
2541            if (definedWidth === null || definedWidth === undefined) {
2542                return null; // can't determine a defined width - browser defined
2543            }
2544            else if (typeof definedWidth === 'number') {
2545                unit = 'px';
2546                sum += definedWidth;
2547            }
2548            else {
2549                var matched = definedWidth.match(/([\d\.]+)([^\d]*)/);
2550
2551                if (matched) {
2552                    sum += matched[1] * 1;
2553                    unit = matched.length === 3 ?
2554                        matched[2] :
2555                        'px';
2556                }
2557            }
2558        }
2559
2560        return sum + unit;
2561    }
2562
2563    function _fnColumnsFromHeader(cell) {
2564        var attr = $(cell).closest('[data-dt-column]').attr('data-dt-column');
2565
2566        if (!attr) {
2567            return [];
2568        }
2569
2570        return attr.split(',').map(function (val) {
2571            return val * 1;
2572        });
2573    }
2574    /**
2575     * Add a data array to the table, creating DOM node etc. This is the parallel to
2576     * _fnGatherData, but for adding rows from a JavaScript source, rather than a
2577     * DOM source.
2578     *  @param {object} settings dataTables settings object
2579     *  @param {array} data data array to be added
2580     *  @param {node} [tr] TR element to add to the table - optional. If not given,
2581     *    DataTables will create a row automatically
2582     *  @param {array} [tds] Array of TD|TH elements for the row - must be given
2583     *    if nTr is.
2584     *  @returns {int} >=0 if successful (index of new aoData entry), -1 if failed
2585     *  @memberof DataTable#oApi
2586     */
2587    function _fnAddData(settings, dataIn, tr, tds) {
2588        /* Create the object for storing information about this new row */
2589        var rowIdx = settings.aoData.length;
2590        var rowModel = $.extend(true, {}, DataTable.models.oRow, {
2591            src: tr ? 'dom' : 'data',
2592            idx: rowIdx
2593        });
2594
2595        rowModel._aData = dataIn;
2596        settings.aoData.push(rowModel);
2597
2598        var columns = settings.aoColumns;
2599
2600        for (var i = 0, iLen = columns.length; i < iLen; i++) {
2601            // Invalidate the column types as the new data needs to be revalidated
2602            columns[i].sType = null;
2603        }
2604
2605        /* Add to the display array */
2606        settings.aiDisplayMaster.push(rowIdx);
2607
2608        var id = settings.rowIdFn(dataIn);
2609        if (id !== undefined) {
2610            settings.aIds[id] = rowModel;
2611        }
2612
2613        /* Create the DOM information, or register it if already present */
vendor: 11,588 bytes, lines 2614-2952
2614        if (tr || !settings.oFeatures.bDeferRender) {
2615            _fnCreateTr(settings, rowIdx, tr, tds);
2616        }
2617
2618        return rowIdx;
2619    }
2620
2621
2622    /**
2623     * Add one or more TR elements to the table. Generally we'd expect to
2624     * use this for reading data from a DOM sourced table, but it could be
2625     * used for an TR element. Note that if a TR is given, it is used (i.e.
2626     * it is not cloned).
2627     *  @param {object} settings dataTables settings object
2628     *  @param {array|node|jQuery} trs The TR element(s) to add to the table
2629     *  @returns {array} Array of indexes for the added rows
2630     *  @memberof DataTable#oApi
2631     */
2632    function _fnAddTr(settings, trs) {
2633        var row;
2634
2635        // Allow an individual node to be passed in
2636        if (!(trs instanceof $)) {
2637            trs = $(trs);
2638        }
2639
2640        return trs.map(function (i, el) {
2641            row = _fnGetRowElements(settings, el);
2642            return _fnAddData(settings, row.data, el, row.cells);
2643        });
2644    }
2645
2646
2647    /**
2648     * Get the data for a given cell from the internal cache, taking into account data mapping
2649     *  @param {object} settings dataTables settings object
2650     *  @param {int} rowIdx aoData row id
2651     *  @param {int} colIdx Column index
2652     *  @param {string} type data get type ('display', 'type' 'filter|search' 'sort|order')
2653     *  @returns {*} Cell data
2654     *  @memberof DataTable#oApi
2655     */
2656    function _fnGetCellData(settings, rowIdx, colIdx, type) {
2657        if (type === 'search') {
2658            type = 'filter';
2659        }
2660        else if (type === 'order') {
2661            type = 'sort';
2662        }
2663
2664        var row = settings.aoData[rowIdx];
2665
2666        if (!row) {
2667            return undefined;
2668        }
2669
2670        var draw = settings.iDraw;
2671        var col = settings.aoColumns[colIdx];
2672        var rowData = row._aData;
2673        var defaultContent = col.sDefaultContent;
2674        var cellData = col.fnGetData(rowData, type, {
2675            settings: settings,
2676            row: rowIdx,
2677            col: colIdx
2678        });
2679
2680        // Allow for a node being returned for non-display types
2681        if (type !== 'display' && cellData && typeof cellData === 'object' && cellData.nodeName) {
2682            cellData = cellData.innerHTML;
2683        }
2684
2685        if (cellData === undefined) {
2686            if (settings.iDrawError != draw && defaultContent === null) {
2687                _fnLog(settings, 0, "Requested unknown parameter " +
2688                    (typeof col.mData == 'function' ? '{function}' : "'" + col.mData + "'") +
2689                    " for row " + rowIdx + ", column " + colIdx, 4);
2690                settings.iDrawError = draw;
2691            }
2692            return defaultContent;
2693        }
2694
2695        // When the data source is null and a specific data type is requested (i.e.
2696        // not the original data), we can use default column data
2697        if ((cellData === rowData || cellData === null) && defaultContent !== null && type !== undefined) {
2698            cellData = defaultContent;
2699        }
2700        else if (typeof cellData === 'function') {
2701            // If the data source is a function, then we run it and use the return,
2702            // executing in the scope of the data object (for instances)
2703            return cellData.call(rowData);
2704        }
2705
2706        if (cellData === null && type === 'display') {
2707            return '';
2708        }
2709
2710        if (type === 'filter') {
2711            var formatters = DataTable.ext.type.search;
2712
2713            if (formatters[col.sType]) {
2714                cellData = formatters[col.sType](cellData);
2715            }
2716        }
2717
2718        return cellData;
2719    }
2720
2721
2722    /**
2723     * Set the value for a specific cell, into the internal data cache
2724     *  @param {object} settings dataTables settings object
2725     *  @param {int} rowIdx aoData row id
2726     *  @param {int} colIdx Column index
2727     *  @param {*} val Value to set
2728     *  @memberof DataTable#oApi
2729     */
2730    function _fnSetCellData(settings, rowIdx, colIdx, val) {
2731        var col = settings.aoColumns[colIdx];
2732        var rowData = settings.aoData[rowIdx]._aData;
2733
2734        col.fnSetData(rowData, val, {
2735            settings: settings,
2736            row: rowIdx,
2737            col: colIdx
2738        });
2739    }
2740
2741    /**
2742     * Write a value to a cell
2743     * @param {*} td Cell
2744     * @param {*} val Value
2745     */
2746    function _fnWriteCell(td, val) {
2747        if (val && typeof val === 'object' && val.nodeName) {
2748            $(td)
2749                .empty()
2750                .append(val);
2751        }
2752        else {
2753            td.innerHTML = val;
2754        }
2755    }
2756
2757
2758    // Private variable that is used to match action syntax in the data property object
2759    var __reArray = /\[.*?\]$/;
2760    var __reFn = /\(\)$/;
2761
2762    /**
2763     * Split string on periods, taking into account escaped periods
2764     * @param  {string} str String to split
2765     * @return {array} Split string
2766     */
2767    function _fnSplitObjNotation(str) {
2768        var parts = str.match(/(\\.|[^.])+/g) || [''];
2769
2770        return parts.map(function (s) {
2771            return s.replace(/\\\./g, '.');
2772        });
2773    }
2774
2775
2776    /**
2777     * Return a function that can be used to get data from a source object, taking
2778     * into account the ability to use nested objects as a source
2779     *  @param {string|int|function} mSource The data source for the object
2780     *  @returns {function} Data get function
2781     *  @memberof DataTable#oApi
2782     */
2783    var _fnGetObjectDataFn = DataTable.util.get;
2784
2785
2786    /**
2787     * Return a function that can be used to set data from a source object, taking
2788     * into account the ability to use nested objects as a source
2789     *  @param {string|int|function} mSource The data source for the object
2790     *  @returns {function} Data set function
2791     *  @memberof DataTable#oApi
2792     */
2793    var _fnSetObjectDataFn = DataTable.util.set;
2794
2795
2796    /**
2797     * Return an array with the full table data
2798     *  @param {object} oSettings dataTables settings object
2799     *  @returns array {array} aData Master data array
2800     *  @memberof DataTable#oApi
2801     */
2802    function _fnGetDataMaster(settings) {
2803        return _pluck(settings.aoData, '_aData');
2804    }
2805
2806
2807    /**
2808     * Nuke the table
2809     *  @param {object} oSettings dataTables settings object
2810     *  @memberof DataTable#oApi
2811     */
2812    function _fnClearTable(settings) {
2813        settings.aoData.length = 0;
2814        settings.aiDisplayMaster.length = 0;
2815        settings.aiDisplay.length = 0;
2816        settings.aIds = {};
2817    }
2818
2819
2820    /**
2821     * Mark cached data as invalid such that a re-read of the data will occur when
2822     * the cached data is next requested. Also update from the data source object.
2823     *
2824     * @param {object} settings DataTables settings object
2825     * @param {int}    rowIdx   Row index to invalidate
2826     * @param {string} [src]    Source to invalidate from: undefined, 'auto', 'dom'
2827     *     or 'data'
2828     * @param {int}    [colIdx] Column index to invalidate. If undefined the whole
2829     *     row will be invalidated
2830     * @memberof DataTable#oApi
2831     *
2832     * @todo For the modularisation of v1.11 this will need to become a callback, so
2833     *   the sort and filter methods can subscribe to it. That will required
2834     *   initialisation options for sorting, which is why it is not already baked in
2835     */
2836    function _fnInvalidate(settings, rowIdx, src, colIdx) {
2837        var row = settings.aoData[rowIdx];
2838        var i, iLen;
2839
2840        // Remove the cached data for the row
2841        row._aSortData = null;
2842        row._aFilterData = null;
2843        row.displayData = null;
2844
2845        // Are we reading last data from DOM or the data object?
2846        if (src === 'dom' || ((!src || src === 'auto') && row.src === 'dom')) {
2847            // Read the data from the DOM
2848            row._aData = _fnGetRowElements(
2849                settings, row, colIdx, colIdx === undefined ? undefined : row._aData
2850            )
2851                .data;
2852        }
2853        else {
2854            // Reading from data object, update the DOM
2855            var cells = row.anCells;
2856            var display = _fnGetRowDisplay(settings, rowIdx);
2857
2858            if (cells) {
2859                if (colIdx !== undefined) {
2860                    _fnWriteCell(cells[colIdx], display[colIdx]);
2861                }
2862                else {
2863                    for (i = 0, iLen = cells.length; i < iLen; i++) {
2864                        _fnWriteCell(cells[i], display[i]);
2865                    }
2866                }
2867            }
2868        }
2869
2870        // Column specific invalidation
2871        var cols = settings.aoColumns;
2872        if (colIdx !== undefined) {
2873            // Type - the data might have changed
2874            cols[colIdx].sType = null;
2875
2876            // Max length string. Its a fairly cheep recalculation, so not worth
2877            // something more complicated
2878            cols[colIdx].maxLenString = null;
2879        }
2880        else {
2881            for (i = 0, iLen = cols.length; i < iLen; i++) {
2882                cols[i].sType = null;
2883                cols[i].maxLenString = null;
2884            }
2885
2886            // Update DataTables special `DT_*` attributes for the row
2887            _fnRowAttributes(settings, row);
2888        }
2889    }
2890
2891
2892    /**
2893     * Build a data source object from an HTML row, reading the contents of the
2894     * cells that are in the row.
2895     *
2896     * @param {object} settings DataTables settings object
2897     * @param {node|object} TR element from which to read data or existing row
2898     *   object from which to re-read the data from the cells
2899     * @param {int} [colIdx] Optional column index
2900     * @param {array|object} [d] Data source object. If `colIdx` is given then this
2901     *   parameter should also be given and will be used to write the data into.
2902     *   Only the column in question will be written
2903     * @returns {object} Object with two parameters: `data` the data read, in
2904     *   document order, and `cells` and array of nodes (they can be useful to the
2905     *   caller, so rather than needing a second traversal to get them, just return
2906     *   them from here).
2907     * @memberof DataTable#oApi
2908     */
2909    function _fnGetRowElements(settings, row, colIdx, d) {
2910        var
2911            tds = [],
2912            td = row.firstChild,
2913            name, col, i = 0, contents,
2914            columns = settings.aoColumns,
2915            objectRead = settings._rowReadObject;
2916
2917        // Allow the data object to be passed in, or construct
2918        d = d !== undefined ?
2919            d :
2920            objectRead ?
2921                {} :
2922                [];
2923
2924        var attr = function (str, td) {
2925            if (typeof str === 'string') {
2926                var idx = str.indexOf('@');
2927
2928                if (idx !== -1) {
2929                    var attr = str.substring(idx + 1);
2930                    var setter = _fnSetObjectDataFn(str);
2931                    setter(d, td.getAttribute(attr));
2932                }
2933            }
2934        };
2935
2936        // Read data from a cell and store into the data object
2937        var cellProcess = function (cell) {
2938            if (colIdx === undefined || colIdx === i) {
2939                col = columns[i];
2940                contents = (cell.innerHTML).trim();
2941
2942                if (col && col._bAttrSrc) {
2943                    var setter = _fnSetObjectDataFn(col.mData._);
2944                    setter(d, contents);
2945
2946                    attr(col.mData.sort, cell);
2947                    attr(col.mData.type, cell);
2948                    attr(col.mData.filter, cell);
2949                }
2950                else {
2951                    // Depending on the `data` option for the columns the data can
2952                    // be read to either an object or an array.
2953                    if (objectRead) {
2954                        if (!col._setter) {
2955                            // Cache the setter function
2956                            col._setter = _fnSetObjectDataFn(col.mData);
2957                        }
2958                        col._setter(d, contents);
2959                    }
2960                    else {
2961                        d[i] = contents;
2962                    }
2963                }
2964            }
2965
2966            i++;
2967        };
2968
2969        if (td) {
2970            // `tr` element was passed in
2971            while (td) {
2972                name = td.nodeName.toUpperCase();
2973
2974                if (name == "TD" || name == "TH") {
2975                    cellProcess(td);
2976                    tds.push(td);
2977                }
2978
2979                td = td.nextSibling;
2980            }
2981        }
2982        else {
2983            // Existing row object passed in
2984            tds = row.anCells;
2985
2986            for (var j = 0, jen = tds.length; j < jen; j++) {
2987                cellProcess(tds[j]);
2988            }
2989        }
2990
2991        // Read the ID from the DOM if present
2992        var rowNode = row.firstChild ? row : row.nTr;
2993
2994        if (rowNode) {
2995            var id = rowNode.getAttribute('id');
2996
2997            if (id) {
2998                _fnSetObjectDataFn(settings.rowId)(d, id);
2999            }
3000        }
3001
3002        return {
3003            data: d,
3004            cells: tds
3005        };
3006    }
3007
3008    /**
3009     * Render and cache a row's display data for the columns, if required
3010     * @returns 
3011     */
3012    function _fnGetRowDisplay(settings, rowIdx) {
3013        var rowModal = settings.aoData[rowIdx];
3014        var columns = settings.aoColumns;
3015
3016        if (!rowModal.displayData) {
3017            // Need to render and cache
3018            rowModal.displayData = [];
3019
3020            for (var colIdx = 0, len = columns.length; colIdx < len; colIdx++) {
3021                rowModal.displayData.push(
3022                    _fnGetCellData(settings, rowIdx, colIdx, 'display')
3023                );
3024            }
3025        }
3026
3027        return rowModal.displayData;
3028    }
3029
3030    /**
3031     * Create a new TR element (and it's TD children) for a row
3032     *  @param {object} oSettings dataTables settings object
3033     *  @param {int} iRow Row to consider
3034     *  @param {node} [nTrIn] TR element to add to the table - optional. If not given,
3035     *    DataTables will create a row automatically
3036     *  @param {array} [anTds] Array of TD|TH elements for the row - must be given
3037     *    if nTr is.
3038     *  @memberof DataTable#oApi
3039     */
3040    function _fnCreateTr(oSettings, iRow, nTrIn, anTds) {
3041        var
3042            row = oSettings.aoData[iRow],
3043            rowData = row._aData,
3044            cells = [],
3045            nTr, nTd, oCol,
3046            i, iLen, create,
3047            trClass = oSettings.oClasses.tbody.row;
3048
3049        if (row.nTr === null) {
3050            nTr = nTrIn || document.createElement('tr');
3051
3052            row.nTr = nTr;
3053            row.anCells = cells;
3054
3055            _addClass(nTr, trClass);
3056
3057            /* Use a private property on the node to allow reserve mapping from the node
3058             * to the aoData array for fast look up
3059             */
3060            nTr._DT_RowIndex = iRow;
3061
3062            /* Special parameters can be given by the data source to be used on the row */
3063            _fnRowAttributes(oSettings, row);
3064
3065            /* Process each column */
3066            for (i = 0, iLen = oSettings.aoColumns.length; i < iLen; i++) {
3067                oCol = oSettings.aoColumns[i];
3068                create = nTrIn && anTds[i] ? false : true;
3069
3070                nTd = create ? document.createElement(oCol.sCellType) : anTds[i];
3071
3072                if (!nTd) {
3073                    _fnLog(oSettings, 0, 'Incorrect column count', 18);
3074                }
3075
3076                nTd._DT_CellIndex = {
3077                    row: iRow,
3078                    column: i
3079                };
3080
3081                cells.push(nTd);
3082
3083                var display = _fnGetRowDisplay(oSettings, iRow);
3084
3085                // Need to create the HTML if new, or if a rendering function is defined
3086                if (
3087                    create ||
3088                    (
3089                        (oCol.mRender || oCol.mData !== i) &&
3090                        (!$.isPlainObject(oCol.mData) || oCol.mData._ !== i + '.display')
3091                    )
3092                ) {
3093                    _fnWriteCell(nTd, display[i]);
3094                }
3095
3096                // column class
3097                _addClass(nTd, oCol.sClass);
3098
3099                // Visibility - add or remove as required
3100                if (oCol.bVisible && create) {
3101                    nTr.appendChild(nTd);
3102                }
3103                else if (!oCol.bVisible && !create) {
3104                    nTd.parentNode.removeChild(nTd);
3105                }
3106
3107                if (oCol.fnCreatedCell) {
3108                    oCol.fnCreatedCell.call(oSettings.oInstance,
3109                        nTd, _fnGetCellData(oSettings, iRow, i), rowData, iRow, i
3110                    );
3111                }
3112            }
3113
3114            _fnCallbackFire(oSettings, 'aoRowCreatedCallback', 'row-created', [nTr, rowData, iRow, cells]);
3115        }
3116        else {
3117            _addClass(row.nTr, trClass);
3118        }
3119    }
3120
3121
3122    /**
3123     * Add attributes to a row based on the special `DT_*` parameters in a data
3124     * source object.
3125     *  @param {object} settings DataTables settings object
3126     *  @param {object} DataTables row object for the row to be modified
3127     *  @memberof DataTable#oApi
3128     */
3129    function _fnRowAttributes(settings, row) {
3130        var tr = row.nTr;
3131        var data = row._aData;
3132
3133        if (tr) {
3134            var id = settings.rowIdFn(data);
3135
3136            if (id) {
3137                tr.id = id;
3138            }
3139
3140            if (data.DT_RowClass) {
3141                // Remove any classes added by DT_RowClass before
3142                var a = data.DT_RowClass.split(' ');
3143                row.__rowc = row.__rowc ?
3144                    _unique(row.__rowc.concat(a)) :
3145                    a;
3146
3147                $(tr)
3148                    .removeClass(row.__rowc.join(' '))
3149                    .addClass(data.DT_RowClass);
3150            }
3151
3152            if (data.DT_RowAttr) {
3153                $(tr).attr(data.DT_RowAttr);
3154            }
3155
3156            if (data.DT_RowData) {
3157                $(tr).data(data.DT_RowData);
3158            }
3159        }
3160    }
3161
3162
3163    /**
3164     * Create the HTML header for the table
3165     *  @param {object} oSettings dataTables settings object
3166     *  @memberof DataTable#oApi
3167     */
3168    function _fnBuildHead(settings, side) {
3169        var classes = settings.oClasses;
3170        var columns = settings.aoColumns;
3171        var i, iLen, row;
3172        var target = side === 'header'
3173            ? settings.nTHead
3174            : settings.nTFoot;
3175        var titleProp = side === 'header' ? 'sTitle' : side;
3176
3177        // Footer might be defined
3178        if (!target) {
3179            return;
3180        }
3181
3182        // If no cells yet and we have content for them, then create
3183        if (side === 'header' || _pluck(settings.aoColumns, titleProp).join('')) {
3184            row = $('tr', target);
3185
3186            // Add a row if needed
3187            if (!row.length) {
3188                row = $('<tr/>').appendTo(target)
3189            }
3190
3191            // Add the number of cells needed to make up to the number of columns
3192            if (row.length === 1) {
3193                var cellCount = 0;
3194
3195                $('td, th', row).each(function () {
3196                    cellCount += this.colSpan;
3197                });
3198
3199                for (i = cellCount, iLen = columns.length; i < iLen; i++) {
3200                    $('<th/>')
3201                        .html(columns[i][titleProp] || '')
3202                        .appendTo(row);
3203                }
3204            }
3205        }
3206
3207        var detected = _fnDetectHeader(settings, target, true);
3208
3209        if (side === 'header') {
3210            settings.aoHeader = detected;
3211            $('tr', target).addClass(classes.thead.row);
3212        }
3213        else {
3214            settings.aoFooter = detected;
3215            $('tr', target).addClass(classes.tfoot.row);
3216        }
3217
3218        // Every cell needs to be passed through the renderer
3219        $(target).children('tr').children('th, td')
3220            .each(function () {
3221                _fnRenderer(settings, side)(
3222                    settings, $(this), classes
3223                );
3224            });
3225    }
3226
3227    /**
3228     * Build a layout structure for a header or footer
3229     *
3230     * @param {*} settings DataTables settings
3231     * @param {*} source Source layout array
3232     * @param {*} incColumns What columns should be included
3233     * @returns Layout array in column index order
3234     */
3235    function _fnHeaderLayout(settings, source, incColumns) {
3236        var row, column, cell;
3237        var local = [];
3238        var structure = [];
3239        var columns = settings.aoColumns;
3240        var columnCount = columns.length;
3241        var rowspan, colspan;
3242
3243        if (!source) {
3244            return;
3245        }
3246
3247        // Default is to work on only visible columns
3248        if (!incColumns) {
3249            incColumns = _range(columnCount)
3250                .filter(function (idx) {
3251                    return columns[idx].bVisible;
3252                });
3253        }
3254
3255        // Make a copy of the master layout array, but with only the columns we want
3256        for (row = 0; row < source.length; row++) {
3257            // Remove any columns we haven't selected
3258            local[row] = source[row].slice().filter(function (cell, i) {
3259                return incColumns.includes(i);
3260            });
3261
3262            // Prep the structure array - it needs an element for each row
3263            structure.push([]);
3264        }
3265
3266        for (row = 0; row < local.length; row++) {
3267            for (column = 0; column < local[row].length; column++) {
3268                rowspan = 1;
3269                colspan = 1;
3270
3271                // Check to see if there is already a cell (row/colspan) covering our target
3272                // insert point. If there is, then there is nothing to do.
3273                if (structure[row][column] === undefined) {
3274                    cell = local[row][column].cell;
3275
3276                    // Expand for rowspan
3277                    while (
3278                        local[row + rowspan] !== undefined &&
3279                        local[row][column].cell == local[row + rowspan][column].cell
3280                    ) {
3281                        structure[row + rowspan][column] = null;
3282                        rowspan++;
3283                    }
3284
3285                    // And for colspan
3286                    while (
3287                        local[row][column + colspan] !== undefined &&
3288                        local[row][column].cell == local[row][column + colspan].cell
3289                    ) {
3290                        // Which also needs to go over rows
3291                        for (var k = 0; k < rowspan; k++) {
3292                            structure[row + k][column + colspan] = null;
3293                        }
3294
3295                        colspan++;
3296                    }
3297
3298                    var titleSpan = $('span.dt-column-title', cell);
3299
3300                    structure[row][column] = {
3301                        cell: cell,
3302                        colspan: colspan,
3303                        rowspan: rowspan,
3304                        title: titleSpan.length
3305                            ? titleSpan.html()
3306                            : $(cell).html()
3307                    };
3308                }
3309            }
3310        }
3311
3312        return structure;
3313    }
3314
3315
3316    /**
3317     * Draw the header (or footer) element based on the column visibility states.
3318     *
3319     *  @param object oSettings dataTables settings object
3320     *  @param array aoSource Layout array from _fnDetectHeader
3321     *  @memberof DataTable#oApi
3322     */
3323    function _fnDrawHead(settings, source) {
3324        var layout = _fnHeaderLayout(settings, source);
3325        var tr, n;
3326
3327        for (var row = 0; row < source.length; row++) {
3328            tr = source[row].row;
3329
3330            // All cells are going to be replaced, so empty out the row
3331            // Can't use $().empty() as that kills event handlers
3332            if (tr) {
3333                while ((n = tr.firstChild)) {
3334                    tr.removeChild(n);
3335                }
3336            }
3337
3338            for (var column = 0; column < layout[row].length; column++) {
3339                var point = layout[row][column];
3340
3341                if (point) {
3342                    $(point.cell)
3343                        .appendTo(tr)
3344                        .attr('rowspan', point.rowspan)
3345                        .attr('colspan', point.colspan);
3346                }
3347            }
3348        }
3349    }
3350
3351
3352    /**
3353     * Insert the required TR nodes into the table for display
3354     *  @param {object} oSettings dataTables settings object
3355     *  @param ajaxComplete true after ajax call to complete rendering
3356     *  @memberof DataTable#oApi
3357     */
3358    function _fnDraw(oSettings, ajaxComplete) {
3359        // Allow for state saving and a custom start position
3360        _fnStart(oSettings);
3361
3362        /* Provide a pre-callback function which can be used to cancel the draw is false is returned */
3363        var aPreDraw = _fnCallbackFire(oSettings, 'aoPreDrawCallback', 'preDraw', [oSettings]);
3364        if (aPreDraw.indexOf(false) !== -1) {
3365            _fnProcessingDisplay(oSettings, false);
3366            return;
3367        }
3368
3369        var anRows = [];
3370        var iRowCount = 0;
3371        var bServerSide = _fnDataSource(oSettings) == 'ssp';
3372        var aiDisplay = oSettings.aiDisplay;
3373        var iDisplayStart = oSettings._iDisplayStart;
3374        var iDisplayEnd = oSettings.fnDisplayEnd();
3375        var columns = oSettings.aoColumns;
3376        var body = $(oSettings.nTBody);
3377
3378        oSettings.bDrawing = true;
3379
3380        /* Server-side processing draw intercept */
3381        if (oSettings.deferLoading) {
3382            oSettings.deferLoading = false;
3383            oSettings.iDraw++;
3384            _fnProcessingDisplay(oSettings, false);
3385        }
3386        else if (!bServerSide) {
3387            oSettings.iDraw++;
3388        }
3389        else if (!oSettings.bDestroying && !ajaxComplete) {
3390            // Show loading message for server-side processing
3391            if (oSettings.iDraw === 0) {
3392                body.empty().append(_emptyRow(oSettings));
3393            }
3394
3395            _fnAjaxUpdate(oSettings);
3396            return;
3397        }
3398
3399        if (aiDisplay.length !== 0) {
3400            var iStart = bServerSide ? 0 : iDisplayStart;
3401            var iEnd = bServerSide ? oSettings.aoData.length : iDisplayEnd;
3402
3403            for (var j = iStart; j < iEnd; j++) {
3404                var iDataIndex = aiDisplay[j];
3405                var aoData = oSettings.aoData[iDataIndex];
3406                if (aoData.nTr === null) {
3407                    _fnCreateTr(oSettings, iDataIndex);
3408                }
3409
3410                var nRow = aoData.nTr;
3411
3412                // Add various classes as needed
3413                for (var i = 0; i < columns.length; i++) {
3414                    var col = columns[i];
3415                    var td = aoData.anCells[i];
3416
3417                    _addClass(td, _ext.type.className[col.sType]); // auto class
3418                    _addClass(td, oSettings.oClasses.tbody.cell); // all cells
3419                }
3420
3421                // Row callback functions - might want to manipulate the row
3422                // iRowCount and j are not currently documented. Are they at all
3423                // useful?
3424                _fnCallbackFire(oSettings, 'aoRowCallback', null,
3425                    [nRow, aoData._aData, iRowCount, j, iDataIndex]);
3426
3427                anRows.push(nRow);
3428                iRowCount++;
3429            }
3430        }
3431        else {
3432            anRows[0] = _emptyRow(oSettings);
3433        }
3434
3435        /* Header and footer callbacks */
3436        _fnCallbackFire(oSettings, 'aoHeaderCallback', 'header', [$(oSettings.nTHead).children('tr')[0],
3437        _fnGetDataMaster(oSettings), iDisplayStart, iDisplayEnd, aiDisplay]);
3438
3439        _fnCallbackFire(oSettings, 'aoFooterCallback', 'footer', [$(oSettings.nTFoot).children('tr')[0],
3440        _fnGetDataMaster(oSettings), iDisplayStart, iDisplayEnd, aiDisplay]);
3441
3442        // replaceChildren is faster, but only became widespread in 2020,
3443        // so a fall back in jQuery is provided for older browsers.
3444        if (body[0].replaceChildren) {
3445            body[0].replaceChildren.apply(body[0], anRows);
3446        }
3447        else {
3448            body.children().detach();
3449            body.append($(anRows));
3450        }
3451
3452        // Empty table needs a specific class
3453        $(oSettings.nTableWrapper).toggleClass('dt-empty-footer', $('tr', oSettings.nTFoot).length === 0);
3454
3455        /* Call all required callback functions for the end of a draw */
3456        _fnCallbackFire(oSettings, 'aoDrawCallback', 'draw', [oSettings], true);
3457
3458        /* Draw is complete, sorting and filtering must be as well */
3459        oSettings.bSorted = false;
3460        oSettings.bFiltered = false;
3461        oSettings.bDrawing = false;
3462    }
3463
3464
3465    /**
3466     * Redraw the table - taking account of the various features which are enabled
3467     *  @param {object} oSettings dataTables settings object
3468     *  @param {boolean} [holdPosition] Keep the current paging position. By default
3469     *    the paging is reset to the first page
3470     *  @memberof DataTable#oApi
3471     */
3472    function _fnReDraw(settings, holdPosition, recompute) {
3473        var
3474            features = settings.oFeatures,
3475            sort = features.bSort,
3476            filter = features.bFilter;
3477
3478        if (recompute === undefined || recompute === true) {
3479            // Resolve any column types that are unknown due to addition or invalidation
3480            _fnColumnTypes(settings);
3481
3482            if (sort) {
3483                _fnSort(settings);
3484            }
3485
3486            if (filter) {
3487                _fnFilterComplete(settings, settings.oPreviousSearch);
3488            }
3489            else {
3490                // No filtering, so we want to just use the display master
3491                settings.aiDisplay = settings.aiDisplayMaster.slice();
3492            }
3493        }
3494
3495        if (holdPosition !== true) {
3496            settings._iDisplayStart = 0;
3497        }
3498
3499        // Let any modules know about the draw hold position state (used by
3500        // scrolling internally)
3501        settings._drawHold = holdPosition;
3502
3503        _fnDraw(settings);
3504
3505        settings.api.one('draw', function () {
3506            settings._drawHold = false;
3507        });
3508    }
3509
3510
3511    /*
3512     * Table is empty - create a row with an empty message in it
3513     */
3514    function _emptyRow(settings) {
3515        var oLang = settings.oLanguage;
3516        var zero = oLang.sZeroRecords;
3517        var dataSrc = _fnDataSource(settings);
3518
3519        // Make use of the fact that settings.json is only set once the initial data has
3520        // been loaded. Show loading when that isn't the case
3521        if ((dataSrc === 'ssp' || dataSrc === 'ajax') && !settings.json) {
3522            zero = oLang.sLoadingRecords;
3523        }
3524        else if (oLang.sEmptyTable && settings.fnRecordsTotal() === 0) {
3525            zero = oLang.sEmptyTable;
3526        }
3527
3528        return $('<tr/>')
3529            .append($('<td />', {
3530                'colSpan': _fnVisibleColumns(settings),
3531                'class': settings.oClasses.empty.row
3532            }).html(zero))[0];
3533    }
3534
3535
3536    /**
3537     * Expand the layout items into an object for the rendering function
3538     */
3539    function _layoutItems(row, align, items) {
3540        if (Array.isArray(items)) {
3541            for (var i = 0; i < items.length; i++) {
3542                _layoutItems(row, align, items[i]);
3543            }
3544
3545            return;
3546        }
3547
3548        var rowCell = row[align];
3549
3550        // If it is an object, then there can be multiple features contained in it
3551        if ($.isPlainObject(items)) {
3552            // A feature plugin cannot be named "features" due to this check
3553            if (items.features) {
3554                if (items.rowId) {
3555                    row.id = items.rowId;
3556                }
3557                if (items.rowClass) {
3558                    row.className = items.rowClass;
3559                }
3560
3561                rowCell.id = items.id;
3562                rowCell.className = items.className;
3563
3564                _layoutItems(row, align, items.features);
3565            }
3566            else {
3567                Object.keys(items).map(function (key) {
3568                    rowCell.contents.push({
3569                        feature: key,
3570                        opts: items[key]
3571                    });
3572                });
3573            }
3574        }
3575        else {
3576            rowCell.contents.push(items);
3577        }
3578    }
3579
3580    /**
3581     * Find, or create a layout row
3582     */
3583    function _layoutGetRow(rows, rowNum, align) {
3584        var row;
3585
3586        // Find existing rows
3587        for (var i = 0; i < rows.length; i++) {
3588            row = rows[i];
3589
3590            if (row.rowNum === rowNum) {
3591                // full is on its own, but start and end share a row
3592                if (
3593                    (align === 'full' && row.full) ||
3594                    ((align === 'start' || align === 'end') && (row.start || row.end))
3595                ) {
3596                    if (!row[align]) {
3597                        row[align] = {
3598                            contents: []
3599                        };
3600                    }
3601
3602                    return row;
3603                }
3604            }
3605        }
3606
3607        // If we get this far, then there was no match, create a new row
3608        row = {
3609            rowNum: rowNum
3610        };
3611
3612        row[align] = {
3613            contents: []
3614        };
3615
3616        rows.push(row);
3617
3618        return row;
3619    }
3620
3621    /**
3622     * Convert a `layout` object given by a user to the object structure needed
3623     * for the renderer. This is done twice, once for above and once for below
3624     * the table. Ordering must also be considered.
3625     *
3626     * @param {*} settings DataTables settings object
3627     * @param {*} layout Layout object to convert
3628     * @param {string} side `top` or `bottom`
3629     * @returns Converted array structure - one item for each row.
3630     */
3631    function _layoutArray(settings, layout, side) {
3632        var rows = [];
3633
3634        // Split out into an array
3635        $.each(layout, function (pos, items) {
3636            if (items === null) {
3637                return;
3638            }
3639
3640            var parts = pos.match(/^([a-z]+)([0-9]*)([A-Za-z]*)$/);
3641            var rowNum = parts[2]
3642                ? parts[2] * 1
3643                : 0;
3644            var align = parts[3]
3645                ? parts[3].toLowerCase()
3646                : 'full';
3647
3648            // Filter out the side we aren't interested in
3649            if (parts[1] !== side) {
3650                return;
3651            }
3652
3653            // Get or create the row we should attach to
3654            var row = _layoutGetRow(rows, rowNum, align);
3655
3656            _layoutItems(row, align, items);
3657        });
3658
3659        // Order by item identifier
3660        rows.sort(function (a, b) {
3661            var order1 = a.rowNum;
3662            var order2 = b.rowNum;
3663
3664            // If both in the same row, then the row with `full` comes first
3665            if (order1 === order2) {
3666                var ret = a.full && !b.full ? -1 : 1;
3667
3668                return side === 'bottom'
3669                    ? ret * -1
3670                    : ret;
3671            }
3672
3673            return order2 - order1;
3674        });
3675
3676        // Invert for below the table
3677        if (side === 'bottom') {
3678            rows.reverse();
3679        }
3680
3681        for (var row = 0; row < rows.length; row++) {
3682            delete rows[row].rowNum;
3683
3684            _layoutResolve(settings, rows[row]);
3685        }
3686
3687        return rows;
3688    }
3689
3690
3691    /**
3692     * Convert the contents of a row's layout object to nodes that can be inserted
3693     * into the document by a renderer. Execute functions, look up plug-ins, etc.
3694     *
3695     * @param {*} settings DataTables settings object
3696     * @param {*} row Layout object for this row
3697     */
3698    function _layoutResolve(settings, row) {
3699        var getFeature = function (feature, opts) {
3700            if (!_ext.features[feature]) {
3701                _fnLog(settings, 0, 'Unknown feature: ' + feature);
3702            }
3703
3704            return _ext.features[feature].apply(this, [settings, opts]);
3705        };
3706
3707        var resolve = function (item) {
3708            if (!row[item]) {
3709                return;
3710            }
3711
3712            var line = row[item].contents;
3713
3714            for (var i = 0, iLen = line.length; i < iLen; i++) {
3715                if (!line[i]) {
3716                    continue;
3717                }
3718                else if (typeof line[i] === 'string') {
3719                    line[i] = getFeature(line[i], null);
3720                }
3721                else if ($.isPlainObject(line[i])) {
3722                    // If it's an object, it just has feature and opts properties from
3723                    // the transform in _layoutArray
3724                    line[i] = getFeature(line[i].feature, line[i].opts);
3725                }
3726                else if (typeof line[i].node === 'function') {
3727                    line[i] = line[i].node(settings);
3728                }
3729                else if (typeof line[i] === 'function') {
3730                    var inst = line[i](settings);
3731
3732                    line[i] = typeof inst.node === 'function' ?
3733                        inst.node() :
3734                        inst;
3735                }
3736            }
3737        };
3738
3739        resolve('start');
3740        resolve('end');
3741        resolve('full');
3742    }
3743
3744
3745    /**
3746     * Add the options to the page HTML for the table
3747     *  @param {object} settings DataTables settings object
3748     *  @memberof DataTable#oApi
3749     */
3750    function _fnAddOptionsHtml(settings) {
3751        var classes = settings.oClasses;
3752        var table = $(settings.nTable);
3753
3754        // Wrapper div around everything DataTables controls
3755        var insert = $('<div/>')
3756            .attr({
3757                id: settings.sTableId + '_wrapper',
3758                'class': classes.container
3759            })
3760            .insertBefore(table);
3761
3762        settings.nTableWrapper = insert[0];
3763
3764        if (settings.sDom) {
3765            // Legacy
3766            _fnLayoutDom(settings, settings.sDom, insert);
3767        }
3768        else {
3769            var top = _layoutArray(settings, settings.layout, 'top');
3770            var bottom = _layoutArray(settings, settings.layout, 'bottom');
3771            var renderer = _fnRenderer(settings, 'layout');
3772
3773            // Everything above - the renderer will actually insert the contents into the document
3774            top.forEach(function (item) {
3775                renderer(settings, insert, item);
3776            });
3777
3778            // The table - always the center of attention
3779            renderer(settings, insert, {
3780                full: {
3781                    table: true,
3782                    contents: [_fnFeatureHtmlTable(settings)]
3783                }
3784            });
3785
3786            // Everything below
3787            bottom.forEach(function (item) {
3788                renderer(settings, insert, item);
3789            });
3790        }
3791
3792        // Processing floats on top, so it isn't an inserted feature
3793        _processingHtml(settings);
3794    }
3795
3796    /**
3797     * Draw the table with the legacy DOM property
3798     * @param {*} settings DT settings object
3799     * @param {*} dom DOM string
3800     * @param {*} insert Insert point
3801     */
3802    function _fnLayoutDom(settings, dom, insert) {
3803        var parts = dom.match(/(".*?")|('.*?')|./g);
3804        var featureNode, option, newNode, next, attr;
3805
3806        for (var i = 0; i < parts.length; i++) {
3807            featureNode = null;
3808            option = parts[i];
3809
3810            if (option == '<') {
3811                // New container div
3812                newNode = $('<div/>');
3813
3814                // Check to see if we should append an id and/or a class name to the container
3815                next = parts[i + 1];
3816
3817                if (next[0] == "'" || next[0] == '"') {
3818                    attr = next.replace(/['"]/g, '');
3819
3820                    var id = '', className;
3821
3822                    /* The attribute can be in the format of "#id.class", "#id" or "class" This logic
3823                     * breaks the string into parts and applies them as needed
3824                     */
3825                    if (attr.indexOf('.') != -1) {
3826                        var split = attr.split('.');
3827
3828                        id = split[0];
3829                        className = split[1];
3830                    }
3831                    else if (attr[0] == "#") {
3832                        id = attr;
3833                    }
3834                    else {
3835                        className = attr;
3836                    }
3837
3838                    newNode
3839                        .attr('id', id.substring(1))
3840                        .addClass(className);
3841
3842                    i++; // Move along the position array
3843                }
3844
3845                insert.append(newNode);
3846                insert = newNode;
3847            }
3848            else if (option == '>') {
3849                // End container div
3850                insert = insert.parent();
3851            }
3852            else if (option == 't') {
3853                // Table
3854                featureNode = _fnFeatureHtmlTable(settings);
3855            }
3856            else {
3857                DataTable.ext.feature.forEach(function (feature) {
3858                    if (option == feature.cFeature) {
3859                        featureNode = feature.fnInit(settings);
3860                    }
3861                });
3862            }
3863
3864            // Add to the display
3865            if (featureNode) {
3866                insert.append(featureNode);
3867            }
3868        }
3869    }
3870
3871
3872    /**
3873     * Use the DOM source to create up an array of header cells. The idea here is to
3874     * create a layout grid (array) of rows x columns, which contains a reference
3875     * to the cell at that point in the grid (regardless of col/rowspan), such that
3876     * any column / row could be removed and the new grid constructed
3877     *  @param {node} thead The header/footer element for the table
3878     *  @returns {array} Calculated layout array
3879     *  @memberof DataTable#oApi
3880     */
3881    function _fnDetectHeader(settings, thead, write) {
3882        var columns = settings.aoColumns;
3883        var rows = $(thead).children('tr');
3884        var row, cell;
3885        var i, k, l, iLen, shifted, column, colspan, rowspan;
3886        var titleRow = settings.titleRow;
3887        var isHeader = thead && thead.nodeName.toLowerCase() === 'thead';
3888        var layout = [];
3889        var unique;
3890        var shift = function (a, i, j) {
3891            var k = a[i];
3892            while (k[j]) {
3893                j++;
3894            }
3895            return j;
3896        };
3897
3898        // We know how many rows there are in the layout - so prep it
3899        for (i = 0, iLen = rows.length; i < iLen; i++) {
3900            layout.push([]);
3901        }
3902
3903        for (i = 0, iLen = rows.length; i < iLen; i++) {
3904            row = rows[i];
3905            column = 0;
3906
3907            // For every cell in the row..
3908            cell = row.firstChild;
3909            while (cell) {
3910                if (
3911                    cell.nodeName.toUpperCase() == 'TD' ||
3912                    cell.nodeName.toUpperCase() == 'TH'
3913                ) {
3914                    var cols = [];
3915                    var jqCell = $(cell);
3916
3917                    // Get the col and rowspan attributes from the DOM and sanitise them
3918                    colspan = cell.getAttribute('colspan') * 1;
3919                    rowspan = cell.getAttribute('rowspan') * 1;
3920                    colspan = (!colspan || colspan === 0 || colspan === 1) ? 1 : colspan;
3921                    rowspan = (!rowspan || rowspan === 0 || rowspan === 1) ? 1 : rowspan;
3922
3923                    // There might be colspan cells already in this row, so shift our target
3924                    // accordingly
3925                    shifted = shift(layout, i, column);
3926
3927                    // Cache calculation for unique columns
3928                    unique = colspan === 1 ?
3929                        true :
3930                        false;
3931
3932                    // Perform header setup
3933                    if (write) {
3934                        if (unique) {
3935                            // Allow column options to be set from HTML attributes
3936                            _fnColumnOptions(settings, shifted, _fnEscapeObject(jqCell.data()));
3937
3938                            // Get the width for the column. This can be defined from the
3939                            // width attribute, style attribute or `columns.width` option
3940                            var columnDef = columns[shifted];
3941                            var width = cell.getAttribute('width') || null;
3942                            var t = cell.style.width.match(/width:\s*(\d+[pxem%]+)/);
3943                            if (t) {
3944                                width = t[1];
3945                            }
3946
3947                            columnDef.sWidthOrig = columnDef.sWidth || width;
3948
3949                            if (isHeader) {
3950                                // Column title handling - can be user set, or read from the DOM
3951                                // This happens before the render, so the original is still in place
3952                                if (columnDef.sTitle !== null && !columnDef.autoTitle) {
3953                                    if (
3954                                        (titleRow === true && i === 0) || // top row
3955                                        (titleRow === false && i === rows.length - 1) || // bottom row
3956                                        (titleRow === i) || // specific row
3957                                        (titleRow === null)
3958                                    ) {
3959                                        cell.innerHTML = columnDef.sTitle;
3960                                    }
3961                                }
3962
3963                                if (!columnDef.sTitle && unique) {
3964                                    columnDef.sTitle = _stripHtml(cell.innerHTML);
3965                                    columnDef.autoTitle = true;
3966                                }
3967                            }
3968                            else {
3969                                // Footer specific operations
3970                                if (columnDef.footer) {
3971                                    cell.innerHTML = columnDef.footer;
3972                                }
3973                            }
3974
3975                            // Fall back to the aria-label attribute on the table header if no ariaTitle is
3976                            // provided.
3977                            if (!columnDef.ariaTitle) {
3978                                columnDef.ariaTitle = jqCell.attr("aria-label") || columnDef.sTitle;
3979                            }
3980
3981                            // Column specific class names
3982                            if (columnDef.className) {
3983                                jqCell.addClass(columnDef.className);
3984                            }
3985                        }
3986
3987                        // Wrap the column title so we can write to it in future
3988                        if ($('span.dt-column-title', cell).length === 0) {
3989                            $('<span>')
3990                                .addClass('dt-column-title')
3991                                .append(cell.childNodes)
3992                                .appendTo(cell);
3993                        }
3994
3995                        if (
3996                            settings.orderIndicators &&
3997                            isHeader &&
3998                            jqCell.filter(':not([data-dt-order=disable])').length !== 0 &&
3999                            jqCell.parent(':not([data-dt-order=disable])').length !== 0 &&
4000                            $('span.dt-column-order', cell).length === 0
4001                        ) {
4002                            $('<span>')
4003                                .addClass('dt-column-order')
4004                                .appendTo(cell);
4005                        }
4006
4007                        // We need to wrap the elements in the header in another element to use flexbox
4008                        // layout for those elements
4009                        var headerFooter = isHeader ? 'header' : 'footer';
4010
4011                        if ($('span.dt-column-' + headerFooter, cell).length === 0) {
4012                            $('<div>')
4013                                .addClass('dt-column-' + headerFooter)
4014                                .append(cell.childNodes)
4015                                .appendTo(cell);
4016                        }
4017                    }
4018
4019                    // If there is col / rowspan, copy the information into the layout grid
4020                    for (l = 0; l < colspan; l++) {
4021                        for (k = 0; k < rowspan; k++) {
4022                            layout[i + k][shifted + l] = {
4023                                cell: cell,
4024                                unique: unique
4025                            };
4026
4027                            layout[i + k].row = row;
4028                        }
4029
4030                        cols.push(shifted + l);
4031                    }
4032
4033                    // Assign an attribute so spanning cells can still be identified
4034                    // as belonging to a column
4035                    cell.setAttribute('data-dt-column', _unique(cols).join(','));
4036                }
4037
4038                cell = cell.nextSibling;
4039            }
4040        }
4041
4042        return layout;
4043    }
4044
4045    /**
4046     * Set the start position for draw
4047     *  @param {object} oSettings dataTables settings object
4048     */
4049    function _fnStart(oSettings) {
4050        var bServerSide = _fnDataSource(oSettings) == 'ssp';
4051        var iInitDisplayStart = oSettings.iInitDisplayStart;
4052
4053        // Check and see if we have an initial draw position from state saving
4054        if (iInitDisplayStart !== undefined && iInitDisplayStart !== -1) {
4055            oSettings._iDisplayStart = bServerSide ?
4056                iInitDisplayStart :
4057                iInitDisplayStart >= oSettings.fnRecordsDisplay() ?
4058                    0 :
4059                    iInitDisplayStart;
4060
4061            oSettings.iInitDisplayStart = -1;
4062        }
4063    }
4064
4065    /**
4066     * Create an Ajax call based on the table's settings, taking into account that
4067     * parameters can have multiple forms, and backwards compatibility.
4068     *
4069     * @param {object} oSettings dataTables settings object
4070     * @param {array} data Data to send to the server, required by
4071     *     DataTables - may be augmented by developer callbacks
4072     * @param {function} fn Callback function to run when data is obtained
4073     */
4074    function _fnBuildAjax(oSettings, data, fn) {
4075        var ajaxData;
4076        var ajax = oSettings.ajax;
4077        var instance = oSettings.oInstance;
4078        var callback = function (json) {
4079            var status = oSettings.jqXHR ? oSettings.jqXHR.status : null;
4080
4081            if (json === null || (typeof status === 'number' && status == 204)) {
4082                json = {};
4083                _fnAjaxDataSrc(oSettings, json, []);
4084            }
4085
4086            var error = json.error || json.sError;
4087            if (error) {
4088                _fnLog(oSettings, 0, error);
4089            }
4090
4091            // Microsoft often wrap JSON as a string in another JSON object
4092            // Let's handle that automatically
4093            if (json.d && typeof json.d === 'string') {
4094                try {
4095                    json = JSON.parse(json.d);
4096                } catch (e) {
4097                    // noop
4098                }
4099            }
4100
4101            oSettings.json = json;
4102
4103            _fnCallbackFire(oSettings, null, 'xhr', [oSettings, json, oSettings.jqXHR], true);
4104            fn(json);
4105        };
4106
4107        if ($.isPlainObject(ajax) && ajax.data) {
4108            ajaxData = ajax.data;
4109
4110            var newData =
4111                typeof ajaxData === 'function'
4112                    ? ajaxData(data, oSettings) // fn can manipulate data or return
4113                    : ajaxData; // an object or array to merge
4114
4115            // If the function returned something, use that alone
4116            data = typeof ajaxData === 'function' && newData ? newData : $.extend(true, data, newData);
4117
4118            // Remove the data property as we've resolved it already and don't want
4119            // jQuery to do it again (it is restored at the end of the function)
4120            delete ajax.data;
4121        }
4122
4123        var baseAjax = {
4124            url: typeof ajax === 'string' ? ajax : '',
4125            data: data,
4126            success: callback,
4127            dataType: 'json',
4128            cache: false,
4129            type: oSettings.sServerMethod,
4130            error: function (xhr, error) {
4131                var ret = _fnCallbackFire(
4132                    oSettings,
4133                    null,
4134                    'xhr',
4135                    [oSettings, null, oSettings.jqXHR],
4136                    true
4137                );
4138
4139                if (ret.indexOf(true) === -1) {
4140                    if (error == 'parsererror') {
4141                        _fnLog(oSettings, 0, 'Invalid JSON response', 1);
4142                    }
4143                    else if (xhr.readyState === 4) {
4144                        _fnLog(oSettings, 0, 'Ajax error', 7);
4145                    }
4146                }
4147
4148                _fnProcessingDisplay(oSettings, false);
4149            }
4150        };
4151
4152        // If `ajax` option is an object, extend and override our default base
4153        if ($.isPlainObject(ajax)) {
4154            $.extend(baseAjax, ajax);
4155        }
4156
4157        // Store the data submitted for the API
4158        oSettings.oAjaxData = data;
4159
4160        // Allow plug-ins and external processes to modify the data
4161        _fnCallbackFire(oSettings, null, 'preXhr', [oSettings, data, baseAjax], true);
4162
4163        // Custom Ajax option to submit the parameters as a JSON string
4164        if (baseAjax.submitAs === 'json' && typeof data === 'object') {
4165            baseAjax.data = JSON.stringify(data);
4166        }
4167
4168        if (typeof ajax === 'function') {
4169            // Is a function - let the caller define what needs to be done
4170            oSettings.jqXHR = ajax.call(instance, data, callback, oSettings);
4171        }
4172        else if (ajax.url === '') {
4173            // No url, so don't load any data. Just apply an empty data array
4174            // to the object for the callback.
4175            var empty = {};
4176
4177            _fnAjaxDataSrc(oSettings, empty, []);
4178            callback(empty);
4179        }
4180        else {
4181            // Object to extend the base settings
4182            oSettings.jqXHR = $.ajax(baseAjax);
4183        }
4184
4185        // Restore for next time around
4186        if (ajaxData) {
4187            ajax.data = ajaxData;
4188        }
4189    }
4190
4191    /**
4192     * Update the table using an Ajax call
4193     *  @param {object} settings dataTables settings object
4194     *  @returns {boolean} Block the table drawing or not
4195     *  @memberof DataTable#oApi
4196     */
4197    function _fnAjaxUpdate(settings) {
4198        settings.iDraw++;
4199        _fnProcessingDisplay(settings, true);
4200
4201        _fnBuildAjax(settings, _fnAjaxParameters(settings), function (json) {
4202            _fnAjaxUpdateDraw(settings, json);
4203        });
4204    }
4205
4206    /**
4207     * Build up the parameters in an object needed for a server-side processing
4208     * request.
4209     *  @param {object} oSettings dataTables settings object
4210     *  @returns {bool} block the table drawing or not
4211     *  @memberof DataTable#oApi
4212     */
4213    function _fnAjaxParameters(settings) {
4214        var columns = settings.aoColumns,
4215            features = settings.oFeatures,
4216            preSearch = settings.oPreviousSearch,
4217            preColSearch = settings.aoPreSearchCols,
4218            colData = function (idx, prop) {
4219                return typeof columns[idx][prop] === 'function' ? 'function' : columns[idx][prop];
4220            };
4221
4222        return {
4223            draw: settings.iDraw,
4224            columns: columns.map(function (column, i) {
4225                return {
4226                    data: colData(i, 'mData'),
4227                    name: column.sName,
4228                    searchable: column.bSearchable,
4229                    orderable: column.bSortable,
4230                    search: {
4231                        value: preColSearch[i].search,
4232                        regex: preColSearch[i].regex,
4233                        fixed: Object.keys(column.searchFixed)
4234                            .map(function (name) {
4235                                return {
4236                                    name: name,
4237                                    term: typeof column.searchFixed[name] !== 'function'
4238                                        ? column.searchFixed[name].toString()
4239                                        : 'function'
4240                                };
4241                            })
4242                    }
4243                };
4244            }),
4245            order: _fnSortFlatten(settings).map(function (val) {
4246                return {
4247                    column: val.col,
4248                    dir: val.dir,
4249                    name: colData(val.col, 'sName')
4250                };
4251            }),
4252            start: settings._iDisplayStart,
4253            length: features.bPaginate ? settings._iDisplayLength : -1,
4254            search: {
4255                value: preSearch.search,
4256                regex: preSearch.regex,
4257                fixed: Object.keys(settings.searchFixed)
4258                    .map(function (name) {
4259                        return {
4260                            name: name,
4261                            term: typeof settings.searchFixed[name] !== 'function'
4262                                ? settings.searchFixed[name].toString()
4263                                : 'function'
4264                        };
4265                    })
4266            }
4267        };
4268    }
4269
4270    /**
4271     * Data the data from the server (nuking the old) and redraw the table
4272     *  @param {object} oSettings dataTables settings object
4273     *  @param {object} json json data return from the server.
4274     *  @param {string} json.sEcho Tracking flag for DataTables to match requests
4275     *  @param {int} json.iTotalRecords Number of records in the data set, not accounting for filtering
4276     *  @param {int} json.iTotalDisplayRecords Number of records in the data set, accounting for filtering
4277     *  @param {array} json.aaData The data to display on this page
4278     *  @param {string} [json.sColumns] Column ordering (sName, comma separated)
4279     *  @memberof DataTable#oApi
4280     */
4281    function _fnAjaxUpdateDraw(settings, json) {
4282        var data = _fnAjaxDataSrc(settings, json);
4283        var draw = _fnAjaxDataSrcParam(settings, 'draw', json);
4284        var recordsTotal = _fnAjaxDataSrcParam(settings, 'recordsTotal', json);
4285        var recordsFiltered = _fnAjaxDataSrcParam(settings, 'recordsFiltered', json);
4286
4287        if (draw !== undefined) {
4288            // Protect against out of sequence returns
4289            if (draw * 1 < settings.iDraw) {
4290                return;
4291            }
4292            settings.iDraw = draw * 1;
4293        }
4294
4295        // No data in returned object, so rather than an array, we show an empty table
4296        if (!data) {
4297            data = [];
4298        }
4299
4300        _fnClearTable(settings);
4301        settings._iRecordsTotal = parseInt(recordsTotal, 10);
4302        settings._iRecordsDisplay = parseInt(recordsFiltered, 10);
4303
4304        for (var i = 0, iLen = data.length; i < iLen; i++) {
4305            _fnAddData(settings, data[i]);
4306        }
4307        settings.aiDisplay = settings.aiDisplayMaster.slice();
4308
4309        _fnColumnTypes(settings);
4310        _fnDraw(settings, true);
4311        _fnInitComplete(settings);
4312        _fnProcessingDisplay(settings, false);
4313    }
4314
4315    /**
4316     * Get the data from the JSON data source to use for drawing a table. Using
4317     * `_fnGetObjectDataFn` allows the data to be sourced from a property of the
4318     * source object, or from a processing function.
4319     *  @param {object} settings dataTables settings object
4320     *  @param  {object} json Data source object / array from the server
4321     *  @return {array} Array of data to use
4322     */
4323    function _fnAjaxDataSrc(settings, json, write) {
4324        var dataProp = 'data';
4325
4326        if ($.isPlainObject(settings.ajax) && settings.ajax.dataSrc !== undefined) {
4327            // Could in inside a `dataSrc` object, or not!
4328            var dataSrc = settings.ajax.dataSrc;
4329
4330            // string, function and object are valid types
4331            if (typeof dataSrc === 'string' || typeof dataSrc === 'function') {
4332                dataProp = dataSrc;
4333            }
4334            else if (dataSrc.data !== undefined) {
4335                dataProp = dataSrc.data;
4336            }
4337        }
4338
4339        if (!write) {
4340            if (dataProp === 'data') {
4341                // If the default, then we still want to support the old style, and safely ignore
4342                // it if possible
4343                return json.aaData || json[dataProp];
4344            }
4345
4346            return dataProp !== '' ? _fnGetObjectDataFn(dataProp)(json) : json;
4347        }
4348
4349        // set
4350        _fnSetObjectDataFn(dataProp)(json, write);
4351    }
4352
4353    /**
4354     * Very similar to _fnAjaxDataSrc, but for the other SSP properties
4355     * @param {*} settings DataTables settings object
4356     * @param {*} param Target parameter
4357     * @param {*} json JSON data
4358     * @returns Resolved value
4359     */
4360    function _fnAjaxDataSrcParam(settings, param, json) {
4361        var dataSrc = $.isPlainObject(settings.ajax) ? settings.ajax.dataSrc : null;
4362
4363        if (dataSrc && dataSrc[param]) {
4364            // Get from custom location
4365            return _fnGetObjectDataFn(dataSrc[param])(json);
4366        }
4367
4368        // else - Default behaviour
4369        var old = '';
4370
4371        // Legacy support
4372        if (param === 'draw') {
4373            old = 'sEcho';
4374        }
4375        else if (param === 'recordsTotal') {
4376            old = 'iTotalRecords';
4377        }
4378        else if (param === 'recordsFiltered') {
4379            old = 'iTotalDisplayRecords';
4380        }
4381
4382        return json[old] !== undefined ? json[old] : json[param];
4383    }
4384
4385
4386    /**
4387     * Filter the table using both the global filter and column based filtering
4388     *  @param {object} settings dataTables settings object
4389     *  @param {object} input search information
4390     *  @memberof DataTable#oApi
4391     */
4392    function _fnFilterComplete(settings, input) {
4393        var columnsSearch = settings.aoPreSearchCols;
4394
4395        // In server-side processing all filtering is done by the server, so no point hanging around here
4396        if (_fnDataSource(settings) != 'ssp') {
4397            // Check if any of the rows were invalidated
4398            _fnFilterData(settings);
4399
4400            // Start from the full data set
4401            settings.aiDisplay = settings.aiDisplayMaster.slice();
4402
4403            // Global filter first
4404            _fnFilter(settings.aiDisplay, settings, input.search, input);
4405
4406            $.each(settings.searchFixed, function (name, term) {
4407                _fnFilter(settings.aiDisplay, settings, term, {});
4408            });
4409
4410            // Then individual column filters
4411            for (var i = 0; i < columnsSearch.length; i++) {
4412                var col = columnsSearch[i];
4413
4414                _fnFilter(
4415                    settings.aiDisplay,
4416                    settings,
4417                    col.search,
4418                    col,
4419                    i
4420                );
4421
4422                $.each(settings.aoColumns[i].searchFixed, function (name, term) {
4423                    _fnFilter(settings.aiDisplay, settings, term, {}, i);
4424                });
4425            }
4426
4427            // And finally global filtering
4428            _fnFilterCustom(settings);
4429        }
4430
4431        // Tell the draw function we have been filtering
4432        settings.bFiltered = true;
4433
4434        _fnCallbackFire(settings, null, 'search', [settings]);
4435    }
4436
4437
4438    /**
4439     * Apply custom filtering functions
4440     * 
4441     * This is legacy now that we have named functions, but it is widely used
4442     * from 1.x, so it is not yet deprecated.
4443     *  @param {object} oSettings dataTables settings object
4444     *  @memberof DataTable#oApi
4445     */
4446    function _fnFilterCustom(settings) {
4447        var filters = DataTable.ext.search;
4448        var displayRows = settings.aiDisplay;
4449        var row, rowIdx;
4450
4451        for (var i = 0, iLen = filters.length; i < iLen; i++) {
4452            var rows = [];
4453
4454            // Loop over each row and see if it should be included
4455            for (var j = 0, jen = displayRows.length; j < jen; j++) {
4456                rowIdx = displayRows[j];
4457                row = settings.aoData[rowIdx];
4458
4459                if (filters[i](settings, row._aFilterData, rowIdx, row._aData, j)) {
4460                    rows.push(rowIdx);
4461                }
4462            }
4463
4464            // So the array reference doesn't break set the results into the
4465            // existing array
4466            displayRows.length = 0;
4467            _fnArrayApply(displayRows, rows);
4468        }
4469    }
4470
4471
4472    /**
4473     * Filter the data table based on user input and draw the table
4474     */
4475    function _fnFilter(searchRows, settings, input, options, column) {
4476        if (input === '') {
4477            return;
4478        }
4479
4480        var i = 0;
4481        var matched = [];
4482
4483        // Search term can be a function, regex or string - if a string we apply our
4484        // smart filtering regex (assuming the options require that)
4485        var searchFunc = typeof input === 'function' ? input : null;
4486        var rpSearch = input instanceof RegExp
4487            ? input
4488            : searchFunc
4489                ? null
4490                : _fnFilterCreateSearch(input, options);
4491
4492        // Then for each row, does the test pass. If not, lop the row from the array
4493        for (i = 0; i < searchRows.length; i++) {
4494            var row = settings.aoData[searchRows[i]];
4495            var data = column === undefined
4496                ? row._sFilterRow
4497                : row._aFilterData[column];
4498
4499            if ((searchFunc && searchFunc(data, row._aData, searchRows[i], column)) || (rpSearch && rpSearch.test(data))) {
4500                matched.push(searchRows[i]);
4501            }
4502        }
4503
4504        // Mutate the searchRows array
4505        searchRows.length = matched.length;
4506
4507        for (i = 0; i < matched.length; i++) {
4508            searchRows[i] = matched[i];
4509        }
4510    }
4511
4512
4513    /**
4514     * Build a regular expression object suitable for searching a table
4515     *  @param {string} sSearch string to search for
4516     *  @param {bool} bRegex treat as a regular expression or not
4517     *  @param {bool} bSmart perform smart filtering or not
4518     *  @param {bool} bCaseInsensitive Do case-insensitive matching or not
4519     *  @returns {RegExp} constructed object
4520     *  @memberof DataTable#oApi
4521     */
4522    function _fnFilterCreateSearch(search, inOpts) {
4523        var not = [];
4524        var options = $.extend({}, {
4525            boundary: false,
4526            caseInsensitive: true,
4527            exact: false,
4528            regex: false,
4529            smart: true
4530        }, inOpts);
4531
4532        if (typeof search !== 'string') {
4533            search = search.toString();
4534        }
4535
4536        // Remove diacritics if normalize is set up to do so
4537        search = _normalize(search);
4538
4539        if (options.exact) {
4540            return new RegExp(
4541                '^' + _fnEscapeRegex(search) + '$',
4542                options.caseInsensitive ? 'i' : ''
4543            );
4544        }
4545
4546        search = options.regex ?
4547            search :
4548            _fnEscapeRegex(search);
4549
4550        if (options.smart) {
4551            /* For smart filtering we want to allow the search to work regardless of
4552             * word order. We also want double quoted text to be preserved, so word
4553             * order is important - a la google. And a negative look around for
4554             * finding rows which don't contain a given string.
4555             * 
4556             * So this is the sort of thing we want to generate:
4557             * 
4558             * ^(?=.*?\bone\b)(?=.*?\btwo three\b)(?=.*?\bfour\b).*$
4559             */
4560            var parts = search.match(/!?["\u201C][^"\u201D]+["\u201D]|[^ ]+/g) || [''];
4561            var a = parts.map(function (word) {
4562                var negative = false;
4563                var m;
4564
4565                // Determine if it is a "does not include"
4566                if (word.charAt(0) === '!') {
4567                    negative = true;
4568                    word = word.substring(1);
4569                }
4570
4571                // Strip the quotes from around matched phrases
4572                if (word.charAt(0) === '"') {
4573                    m = word.match(/^"(.*)"$/);
4574                    word = m ? m[1] : word;
4575                }
4576                else if (word.charAt(0) === '\u201C') {
4577                    // Smart quote match (iPhone users)
4578                    m = word.match(/^\u201C(.*)\u201D$/);
4579                    word = m ? m[1] : word;
4580                }
4581
4582                // For our "not" case, we need to modify the string that is
4583                // allowed to match at the end of the expression.
4584                if (negative) {
4585                    if (word.length > 1) {
4586                        not.push('(?!' + word + ')');
4587                    }
4588
4589                    word = '';
4590                }
4591
4592                return word.replace(/"/g, '');
4593            });
4594
4595            var match = not.length
4596                ? not.join('')
4597                : '';
4598
4599            var boundary = options.boundary
4600                ? '\\b'
4601                : '';
4602
4603            search = '^(?=.*?' + boundary + a.join(')(?=.*?' + boundary) + ')(' + match + '.)*$';
4604        }
4605
4606        return new RegExp(search, options.caseInsensitive ? 'i' : '');
4607    }
4608
4609
4610    /**
4611     * Escape a string such that it can be used in a regular expression
4612     *  @param {string} sVal string to escape
4613     *  @returns {string} escaped string
4614     *  @memberof DataTable#oApi
4615     */
4616    var _fnEscapeRegex = DataTable.util.escapeRegex;
4617
4618    var __filter_div = $('<div>')[0];
4619    var __filter_div_textContent = __filter_div.textContent !== undefined;
4620
4621    // Update the filtering data for each row if needed (by invalidation or first run)
4622    function _fnFilterData(settings) {
4623        var columns = settings.aoColumns;
4624        var data = settings.aoData;
4625        var column;
4626        var j, jen, filterData, cellData, row;
4627        var wasInvalidated = false;
4628
4629        for (var rowIdx = 0; rowIdx < data.length; rowIdx++) {
4630            if (!data[rowIdx]) {
4631                continue;
4632            }
4633
4634            row = data[rowIdx];
4635
4636            if (!row._aFilterData) {
4637                filterData = [];
4638
4639                for (j = 0, jen = columns.length; j < jen; j++) {
4640                    column = columns[j];
4641
4642                    if (column.bSearchable) {
4643                        cellData = _fnGetCellData(settings, rowIdx, j, 'filter');
4644
4645                        // Search in DataTables is string based
4646                        if (cellData === null) {
4647                            cellData = '';
4648                        }
4649
4650                        if (typeof cellData !== 'string' && cellData.toString) {
4651                            cellData = cellData.toString();
4652                        }
4653                    }
4654                    else {
4655                        cellData = '';
4656                    }
4657
4658                    // If it looks like there is an HTML entity in the string,
4659                    // attempt to decode it so sorting works as expected. Note that
4660                    // we could use a single line of jQuery to do this, but the DOM
4661                    // method used here is much faster https://jsperf.com/html-decode
4662                    if (cellData.indexOf && cellData.indexOf('&') !== -1) {
4663                        __filter_div.innerHTML = cellData;
4664                        cellData = __filter_div_textContent ?
4665                            __filter_div.textContent :
4666                            __filter_div.innerText;
4667                    }
4668
4669                    if (cellData.replace) {
4670                        cellData = cellData.replace(/[\r\n\u2028]/g, '');
4671                    }
4672
4673                    filterData.push(cellData);
4674                }
4675
4676                row._aFilterData = filterData;
4677                row._sFilterRow = filterData.join('  ');
4678                wasInvalidated = true;
4679            }
4680        }
4681
4682        return wasInvalidated;
4683    }
4684
4685
4686    /**
4687     * Draw the table for the first time, adding all required features
4688     *  @param {object} settings dataTables settings object
4689     *  @memberof DataTable#oApi
4690     */
4691    function _fnInitialise(settings) {
4692        var i;
4693        var init = settings.oInit;
4694        var deferLoading = settings.deferLoading;
4695        var dataSrc = _fnDataSource(settings);
4696
4697        // Ensure that the table data is fully initialised
4698        if (!settings.bInitialised) {
4699            setTimeout(function () { _fnInitialise(settings); }, 200);
4700            return;
4701        }
4702
4703        // Build the header / footer for the table
4704        _fnBuildHead(settings, 'header');
4705        _fnBuildHead(settings, 'footer');
4706
4707        // Load the table's state (if needed) and then render around it and draw
4708        _fnLoadState(settings, init, function () {
4709            // Then draw the header / footer
4710            _fnDrawHead(settings, settings.aoHeader);
4711            _fnDrawHead(settings, settings.aoFooter);
4712
4713            // Cache the paging start point, as the first redraw will reset it
4714            var iAjaxStart = settings.iInitDisplayStart
4715
4716            // Local data load
4717            // Check if there is data passing into the constructor
4718            if (init.aaData) {
4719                for (i = 0; i < init.aaData.length; i++) {
4720                    _fnAddData(settings, init.aaData[i]);
4721                }
4722            }
4723            else if (deferLoading || dataSrc == 'dom') {
4724                // Grab the data from the page
4725                _fnAddTr(settings, $(settings.nTBody).children('tr'));
4726            }
4727
4728            // Filter not yet applied - copy the display master
4729            settings.aiDisplay = settings.aiDisplayMaster.slice();
4730
4731            // Enable features
4732            _fnAddOptionsHtml(settings);
4733            _fnSortInit(settings);
4734
4735            _colGroup(settings);
4736
4737            /* Okay to show that something is going on now */
4738            _fnProcessingDisplay(settings, true);
4739
4740            _fnCallbackFire(settings, null, 'preInit', [settings], true);
4741
4742            // If there is default sorting required - let's do it. The sort function
4743            // will do the drawing for us. Otherwise we draw the table regardless of the
4744            // Ajax source - this allows the table to look initialised for Ajax sourcing
4745            // data (show 'loading' message possibly)
4746            _fnReDraw(settings);
4747
4748            // Server-side processing init complete is done by _fnAjaxUpdateDraw
4749            if (dataSrc != 'ssp' || deferLoading) {
4750                // if there is an ajax source load the data
4751                if (dataSrc == 'ajax') {
4752                    _fnBuildAjax(settings, {}, function (json) {
4753                        var aData = _fnAjaxDataSrc(settings, json);
4754
4755                        // Got the data - add it to the table
4756                        for (i = 0; i < aData.length; i++) {
4757                            _fnAddData(settings, aData[i]);
4758                        }
4759
4760                        // Reset the init display for cookie saving. We've already done
4761                        // a filter, and therefore cleared it before. So we need to make
4762                        // it appear 'fresh'
4763                        settings.iInitDisplayStart = iAjaxStart;
4764
4765                        _fnReDraw(settings);
4766                        _fnProcessingDisplay(settings, false);
4767                        _fnInitComplete(settings);
4768                    }, settings);
4769                }
4770                else {
4771                    _fnInitComplete(settings);
4772                    _fnProcessingDisplay(settings, false);
4773                }
4774            }
4775        });
4776    }
4777
4778
4779    /**
4780     * Draw the table for the first time, adding all required features
4781     *  @param {object} settings dataTables settings object
4782     *  @memberof DataTable#oApi
4783     */
4784    function _fnInitComplete(settings) {
4785        if (settings._bInitComplete) {
4786            return;
4787        }
4788
4789        var args = [settings, settings.json];
4790
4791        settings._bInitComplete = true;
4792
4793        // Table is fully set up and we have data, so calculate the
4794        // column widths
4795        _fnAdjustColumnSizing(settings);
4796
4797        _fnCallbackFire(settings, null, 'plugin-init', args, true);
4798        _fnCallbackFire(settings, 'aoInitComplete', 'init', args, true);
4799    }
4800
4801    function _fnLengthChange(settings, val) {
4802        var len = parseInt(val, 10);
4803        settings._iDisplayLength = len;
4804
4805        _fnLengthOverflow(settings);
4806
4807        // Fire length change event
4808        _fnCallbackFire(settings, null, 'length', [settings, len]);
4809    }
4810
4811    /**
4812     * Alter the display settings to change the page
4813     *  @param {object} settings DataTables settings object
4814     *  @param {string|int} action Paging action to take: "first", "previous",
4815     *    "next" or "last" or page number to jump to (integer)
4816     *  @param [bool] redraw Automatically draw the update or not
4817     *  @returns {bool} true page has changed, false - no change
4818     *  @memberof DataTable#oApi
4819     */
4820    function _fnPageChange(settings, action, redraw) {
4821        var
4822            start = settings._iDisplayStart,
4823            len = settings._iDisplayLength,
4824            records = settings.fnRecordsDisplay();
4825
4826        if (records === 0 || len === -1) {
4827            start = 0;
4828        }
4829        else if (typeof action === "number") {
4830            start = action * len;
4831
4832            if (start > records) {
4833                start = 0;
4834            }
4835        }
4836        else if (action == "first") {
4837            start = 0;
4838        }
4839        else if (action == "previous") {
4840            start = len >= 0 ?
4841                start - len :
4842                0;
4843
4844            if (start < 0) {
4845                start = 0;
4846            }
4847        }
4848        else if (action == "next") {
4849            if (start + len < records) {
4850                start += len;
4851            }
4852        }
4853        else if (action == "last") {
4854            start = Math.floor((records - 1) / len) * len;
4855        }
4856        else if (action === 'ellipsis') {
4857            return;
4858        }
4859        else {
4860            _fnLog(settings, 0, "Unknown paging action: " + action, 5);
4861        }
4862
4863        var changed = settings._iDisplayStart !== start;
4864        settings._iDisplayStart = start;
4865
4866        _fnCallbackFire(settings, null, changed ? 'page' : 'page-nc', [settings]);
4867
4868        if (changed && redraw) {
4869            _fnDraw(settings);
4870        }
4871
4872        return changed;
4873    }
4874
4875
4876    /**
4877     * Generate the node required for the processing node
4878     *  @param {object} settings DataTables settings object
4879     */
4880    function _processingHtml(settings) {
4881        var table = settings.nTable;
4882        var scrolling = settings.oScroll.sX !== '' || settings.oScroll.sY !== '';
4883
4884        if (settings.oFeatures.bProcessing) {
4885            var n = $('<div/>', {
4886                'id': settings.sTableId + '_processing',
4887                'class': settings.oClasses.processing.container,
4888                'role': 'status'
4889            })
4890                .html(settings.oLanguage.sProcessing)
4891                .append('<div><div></div><div></div><div></div><div></div></div>');
4892
4893            // Different positioning depending on if scrolling is enabled or not
4894            if (scrolling) {
4895                n.prependTo($('div.dt-scroll', settings.nTableWrapper));
4896            }
4897            else {
4898                n.insertBefore(table);
4899            }
4900
4901            $(table).on('processing.dt.DT', function (e, s, show) {
4902                n.css('display', show ? 'block' : 'none');
4903            });
4904        }
4905    }
4906
4907
4908    /**
4909     * Display or hide the processing indicator
4910     *  @param {object} settings DataTables settings object
4911     *  @param {bool} show Show the processing indicator (true) or not (false)
4912     */
4913    function _fnProcessingDisplay(settings, show) {
4914        // Ignore cases when we are still redrawing
4915        if (settings.bDrawing && show === false) {
4916            return;
4917        }
4918
4919        _fnCallbackFire(settings, null, 'processing', [settings, show]);
4920    }
4921
4922    /**
4923     * Show the processing element if an action takes longer than a given time
4924     *
4925     * @param {*} settings DataTables settings object
4926     * @param {*} enable Do (true) or not (false) async processing (local feature enablement)
4927     * @param {*} run Function to run
4928     */
4929    function _fnProcessingRun(settings, enable, run) {
4930        if (!enable) {
4931            // Immediate execution, synchronous
4932            run();
4933        }
4934        else {
4935            _fnProcessingDisplay(settings, true);
4936
4937            // Allow the processing display to show if needed
4938            setTimeout(function () {
4939                run();
4940
4941                _fnProcessingDisplay(settings, false);
4942            }, 0);
4943        }
4944    }
4945    /**
4946     * Add any control elements for the table - specifically scrolling
4947     *  @param {object} settings dataTables settings object
4948     *  @returns {node} Node to add to the DOM
4949     *  @memberof DataTable#oApi
4950     */
4951    function _fnFeatureHtmlTable(settings) {
4952        var table = $(settings.nTable);
4953
4954        // Scrolling from here on in
4955        var scroll = settings.oScroll;
4956
4957        if (scroll.sX === '' && scroll.sY === '') {
4958            return settings.nTable;
4959        }
4960
4961        var scrollX = scroll.sX;
4962        var scrollY = scroll.sY;
4963        var classes = settings.oClasses.scrolling;
4964        var caption = settings.captionNode;
4965        var captionSide = caption ? caption._captionSide : null;
4966        var headerClone = $(table[0].cloneNode(false));
4967        var footerClone = $(table[0].cloneNode(false));
4968        var footer = table.children('tfoot');
4969        var _div = '<div/>';
4970        var size = function (s) {
4971            return !s ? null : _fnStringToCss(s);
4972        };
4973
4974        if (!footer.length) {
4975            footer = null;
4976        }
4977
4978        /*
4979         * The HTML structure that we want to generate in this function is:
4980         *  div - scroller
4981         *    div - scroll head
4982         *      div - scroll head inner
4983         *        table - scroll head table
4984         *          thead - thead
4985         *    div - scroll body
4986         *      table - table (master table)
4987         *        thead - thead clone for sizing
4988         *        tbody - tbody
4989         *    div - scroll foot
4990         *      div - scroll foot inner
4991         *        table - scroll foot table
4992         *          tfoot - tfoot
4993         */
4994        var scroller = $(_div, { 'class': classes.container })
4995            .append(
4996                $(_div, { 'class': classes.header.self })
4997                    .css({
4998                        overflow: 'hidden',
4999                        position: 'relative',
5000                        border: 0,
5001                        width: scrollX ? size(scrollX) : '100%'
5002                    })
5003                    .append(
5004                        $(_div, { 'class': classes.header.inner })
5005                            .css({
5006                                'box-sizing': 'content-box',
5007                                width: scroll.sXInner || '100%'
5008                            })
5009                            .append(
5010                                headerClone
5011                                    .removeAttr('id')
5012                                    .css('margin-left', 0)
5013                                    .append(captionSide === 'top' ? caption : null)
5014                                    .append(
5015                                        table.children('thead')
5016                                    )
5017                            )
5018                    )
5019            )
5020            .append(
5021                $(_div, { 'class': classes.body })
5022                    .css({
5023                        position: 'relative',
5024                        overflow: 'auto',
5025                        width: size(scrollX)
5026                    })
5027                    .append(table)
5028            );
5029
5030        if (footer) {
5031            scroller.append(
5032                $(_div, { 'class': classes.footer.self })
5033                    .css({
5034                        overflow: 'hidden',
5035                        border: 0,
5036                        width: scrollX ? size(scrollX) : '100%'
5037                    })
5038                    .append(
5039                        $(_div, { 'class': classes.footer.inner })
5040                            .append(
5041                                footerClone
5042                                    .removeAttr('id')
5043                                    .css('margin-left', 0)
5044                                    .append(captionSide === 'bottom' ? caption : null)
5045                                    .append(
5046                                        table.children('tfoot')
5047                                    )
5048                            )
5049                    )
5050            );
5051        }
5052
5053        var children = scroller.children();
5054        var scrollHead = children[0];
5055        var scrollBody = children[1];
5056        var scrollFoot = footer ? children[2] : null;
5057
5058        // When the body is scrolled, then we also want to scroll the headers
5059        $(scrollBody).on('scroll.DT', function () {
5060            var scrollLeft = this.scrollLeft;
5061
5062            scrollHead.scrollLeft = scrollLeft;
5063
5064            if (footer) {
5065                scrollFoot.scrollLeft = scrollLeft;
5066            }
5067        });
5068
5069        // When focus is put on the header cells, we might need to scroll the body
5070        $('th, td', scrollHead).on('focus', function () {
5071            var scrollLeft = scrollHead.scrollLeft;
5072
5073            scrollBody.scrollLeft = scrollLeft;
5074
5075            if (footer) {
5076                scrollBody.scrollLeft = scrollLeft;
5077            }
5078        });
5079
5080        $(scrollBody).css('max-height', scrollY);
5081        if (!scroll.bCollapse) {
5082            $(scrollBody).css('height', scrollY);
5083        }
5084
5085        settings.nScrollHead = scrollHead;
5086        settings.nScrollBody = scrollBody;
5087        settings.nScrollFoot = scrollFoot;
5088
5089        // On redraw - align columns
5090        settings.aoDrawCallback.push(_fnScrollDraw);
5091
5092        return scroller[0];
5093    }
5094
5095
5096
5097    /**
5098     * Update the header, footer and body tables for resizing - i.e. column
5099     * alignment.
5100     *
5101     * Welcome to the most horrible function DataTables. The process that this
5102     * function follows is basically:
5103     *   1. Re-create the table inside the scrolling div
5104     *   2. Correct colgroup > col values if needed
5105     *   3. Copy colgroup > col over to header and footer
5106     *   4. Clean up
5107     *
5108     *  @param {object} settings dataTables settings object
5109     *  @memberof DataTable#oApi
5110     */
5111    function _fnScrollDraw(settings) {
5112        // Given that this is such a monster function, a lot of variables are use
5113        // to try and keep the minimised size as small as possible
5114        var
5115            scroll = settings.oScroll,
5116            barWidth = scroll.iBarWidth,
5117            divHeader = $(settings.nScrollHead),
5118            divHeaderInner = divHeader.children('div'),
5119            divHeaderTable = divHeaderInner.children('table'),
5120            divBodyEl = settings.nScrollBody,
5121            divBody = $(divBodyEl),
5122            divFooter = $(settings.nScrollFoot),
5123            divFooterInner = divFooter.children('div'),
5124            divFooterTable = divFooterInner.children('table'),
5125            header = $(settings.nTHead),
5126            table = $(settings.nTable),
5127            footer = settings.nTFoot && $('th, td', settings.nTFoot).length ? $(settings.nTFoot) : null,
5128            browser = settings.oBrowser,
5129            headerCopy, footerCopy;
5130
5131        // If the scrollbar visibility has changed from the last draw, we need to
5132        // adjust the column sizes as the table width will have changed to account
5133        // for the scrollbar
5134        var scrollBarVis = divBodyEl.scrollHeight > divBodyEl.clientHeight;
5135
5136        if (settings.scrollBarVis !== scrollBarVis && settings.scrollBarVis !== undefined) {
5137            settings.scrollBarVis = scrollBarVis;
5138            _fnAdjustColumnSizing(settings);
5139            return; // adjust column sizing will call this function again
5140        }
5141        else {
5142            settings.scrollBarVis = scrollBarVis;
5143        }
5144
5145        // 1. Re-create the table inside the scrolling div
5146        // Remove the old minimised thead and tfoot elements in the inner table
5147        table.children('thead, tfoot').remove();
5148
5149        // Clone the current header and footer elements and then place it into the inner table
5150        headerCopy = header.clone().prependTo(table);
5151        headerCopy.find('th, td').removeAttr('tabindex');
5152        headerCopy.find('[id]').removeAttr('id');
5153
5154        if (footer) {
5155            footerCopy = footer.clone().prependTo(table);
5156            footerCopy.find('[id]').removeAttr('id');
5157        }
5158
5159        // 2. Correct colgroup > col values if needed
5160        // It is possible that the cell sizes are smaller than the content, so we need to
5161        // correct colgroup>col for such cases. This can happen if the auto width detection
5162        // uses a cell which has a longer string, but isn't the widest! For example 
5163        // "Chief Executive Officer (CEO)" is the longest string in the demo, but
5164        // "Systems Administrator" is actually the widest string since it doesn't collapse.
5165        // Note the use of translating into a column index to get the `col` element. This
5166        // is because of Responsive which might remove `col` elements, knocking the alignment
5167        // of the indexes out.
5168        if (settings.aiDisplay.length) {
5169            // Get the column sizes from the first row in the table. This should really be a
5170            // [].find, but it wasn't supported in Chrome until Sept 2015, and DT has 10 year
5171            // browser support
5172            var firstTr = null;
5173            var start = _fnDataSource(settings) !== 'ssp'
5174                ? settings._iDisplayStart
5175                : 0;
5176
5177            for (i = start; i < start + settings.aiDisplay.length; i++) {
5178                var idx = settings.aiDisplay[i];
5179                var tr = settings.aoData[idx].nTr;
5180
5181                if (tr) {
5182                    firstTr = tr;
5183                    break;
5184                }
5185            }
5186
5187            if (firstTr) {
5188                var colSizes = $(firstTr).children('th, td').map(function (vis) {
5189                    return {
5190                        idx: _fnVisibleToColumnIndex(settings, vis),
5191                        width: $(this).outerWidth()
5192                    };
5193                });
5194
5195                // Check against what the colgroup > col is set to and correct if needed
5196                for (var i = 0; i < colSizes.length; i++) {
5197                    var colEl = settings.aoColumns[colSizes[i].idx].colEl[0];
5198                    var colWidth = colEl.style.width.replace('px', '');
5199
5200                    if (colWidth !== colSizes[i].width) {
5201                        colEl.style.width = colSizes[i].width + 'px';
5202
5203                        if (scroll.sX) {
5204                            colEl.style.minWidth = colSizes[i].width + 'px';
5205                        }
5206                    }
5207                }
5208            }
5209        }
5210
5211        // 3. Copy the colgroup over to the header and footer
5212        divHeaderTable
5213            .find('colgroup')
5214            .remove();
5215
5216        divHeaderTable.append(settings.colgroup.clone());
5217
5218        if (footer) {
5219            divFooterTable
5220                .find('colgroup')
5221                .remove();
5222
5223            divFooterTable.append(settings.colgroup.clone());
5224        }
5225
5226        // "Hide" the header and footer that we used for the sizing. We need to keep
5227        // the content of the cell so that the width applied to the header and body
5228        // both match, but we want to hide it completely.
5229        $('th, td', headerCopy).each(function () {
5230            $(this.childNodes).wrapAll('<div class="dt-scroll-sizing">');
5231        });
5232
5233        if (footer) {
5234            $('th, td', footerCopy).each(function () {
5235                $(this.childNodes).wrapAll('<div class="dt-scroll-sizing">');
5236            });
5237        }
5238
5239        // 4. Clean up
5240        // Figure out if there are scrollbar present - if so then we need the header and footer to
5241        // provide a bit more space to allow "overflow" scrolling (i.e. past the scrollbar)
5242        var isScrolling = Math.floor(table.height()) > divBodyEl.clientHeight || divBody.css('overflow-y') == "scroll";
5243        var paddingSide = 'padding' + (browser.bScrollbarLeft ? 'Left' : 'Right');
5244
5245        // Set the width's of the header and footer tables
5246        var outerWidth = table.outerWidth();
5247
5248        divHeaderTable.css('width', _fnStringToCss(outerWidth));
5249        divHeaderInner
5250            .css('width', _fnStringToCss(outerWidth))
5251            .css(paddingSide, isScrolling ? barWidth + "px" : "0px");
5252
5253        if (footer) {
5254            divFooterTable.css('width', _fnStringToCss(outerWidth));
5255            divFooterInner
5256                .css('width', _fnStringToCss(outerWidth))
5257                .css(paddingSide, isScrolling ? barWidth + "px" : "0px");
5258        }
5259
5260        // Correct DOM ordering for colgroup - comes before the thead
5261        table.children('colgroup').prependTo(table);
5262
5263        // Adjust the position of the header in case we loose the y-scrollbar
5264        divBody.trigger('scroll');
5265
5266        // If sorting or filtering has occurred, jump the scrolling back to the top
5267        // only if we aren't holding the position
5268        if ((settings.bSorted || settings.bFiltered) && !settings._drawHold) {
5269            divBodyEl.scrollTop = 0;
5270        }
5271    }
5272
5273    /**
5274     * Calculate the width of columns for the table
5275     *  @param {object} settings dataTables settings object
5276     *  @memberof DataTable#oApi
5277     */
5278    function _fnCalculateColumnWidths(settings) {
5279        // Not interested in doing column width calculation if auto-width is disabled
5280        if (!settings.oFeatures.bAutoWidth) {
5281            return;
5282        }
5283
5284        var
5285            table = settings.nTable,
5286            columns = settings.aoColumns,
5287            scroll = settings.oScroll,
5288            scrollY = scroll.sY,
5289            scrollX = scroll.sX,
5290            scrollXInner = scroll.sXInner,
5291            visibleColumns = _fnGetColumns(settings, 'bVisible'),
5292            tableWidthAttr = table.getAttribute('width'), // from DOM element
5293            tableContainer = table.parentNode,
5294            i, column, columnIdx;
5295
5296        var styleWidth = table.style.width;
5297        var containerWidth = _fnWrapperWidth(settings);
5298
5299        // Don't re-run for the same width as the last time
5300        if (containerWidth === settings.containerWidth) {
5301            return false;
5302        }
5303
5304        settings.containerWidth = containerWidth;
5305
5306        // If there is no width applied as a CSS style or as an attribute, we assume that
5307        // the width is intended to be 100%, which is usually is in CSS, but it is very
5308        // difficult to correctly parse the rules to get the final result.
5309        if (!styleWidth && !tableWidthAttr) {
5310            table.style.width = '100%';
5311            styleWidth = '100%';
5312        }
5313
5314        if (styleWidth && styleWidth.indexOf('%') !== -1) {
5315            tableWidthAttr = styleWidth;
5316        }
5317
5318        // Let plug-ins know that we are doing a recalc, in case they have changed any of the
5319        // visible columns their own way (e.g. Responsive uses display:none).
5320        _fnCallbackFire(
5321            settings,
5322            null,
5323            'column-calc',
5324            { visible: visibleColumns },
5325            false
5326        );
5327
5328        // Construct a single row, worst case, table with the widest
5329        // node in the data, assign any user defined widths, then insert it into
5330        // the DOM and allow the browser to do all the hard work of calculating
5331        // table widths
5332        var tmpTable = $(table.cloneNode())
5333            .css('visibility', 'hidden')
5334            .removeAttr('id');
5335
5336        // Clean up the table body
5337        tmpTable.append('<tbody/>')
5338        var tr = $('<tr/>').appendTo(tmpTable.find('tbody'));
5339
5340        // Clone the table header and footer - we can't use the header / footer
5341        // from the cloned table, since if scrolling is active, the table's
5342        // real header and footer are contained in different table tags
5343        tmpTable
5344            .append($(settings.nTHead).clone())
5345            .append($(settings.nTFoot).clone());
5346
5347        // Remove any assigned widths from the footer (from scrolling)
5348        tmpTable.find('tfoot th, tfoot td').css('width', '');
5349
5350        // Apply custom sizing to the cloned header
5351        tmpTable.find('thead th, thead td').each(function () {
5352            // Get the `width` from the header layout
5353            var width = _fnColumnsSumWidth(settings, this, true, false);
5354
5355            if (width) {
5356                this.style.width = width;
5357
5358                // For scrollX we need to force the column width otherwise the
5359                // browser will collapse it. If this width is smaller than the
5360                // width the column requires, then it will have no effect
5361                if (scrollX) {
5362                    this.style.minWidth = width;
5363
5364                    $(this).append($('<div/>').css({
5365                        width: width,
5366                        margin: 0,
5367                        padding: 0,
5368                        border: 0,
5369                        height: 1
5370                    }));
5371                }
5372            }
5373            else {
5374                this.style.width = '';
5375            }
5376        });
5377
5378        // Find the widest piece of data for each column and put it into the table
5379        for (i = 0; i < visibleColumns.length; i++) {
5380            columnIdx = visibleColumns[i];
5381            column = columns[columnIdx];
5382
5383            var longest = _fnGetMaxLenString(settings, columnIdx);
5384            var autoClass = _ext.type.className[column.sType];
5385            var text = longest + column.sContentPadding;
5386            var insert = longest.indexOf('<') === -1
5387                ? document.createTextNode(text)
5388                : text
5389
5390            $('<td/>')
5391                .addClass(autoClass)
5392                .addClass(column.sClass)
5393                .append(insert)
5394                .appendTo(tr);
5395        }
5396
5397        // Tidy the temporary table - remove name attributes so there aren't
5398        // duplicated in the dom (radio elements for example)
5399        $('[name]', tmpTable).removeAttr('name');
5400
5401        // Table has been built, attach to the document so we can work with it.
5402        // A holding element is used, positioned at the top of the container
5403        // with minimal height, so it has no effect on if the container scrolls
5404        // or not. Otherwise it might trigger scrolling when it actually isn't
5405        // needed
5406        var holder = $('<div/>').css(scrollX || scrollY ?
5407            {
5408                position: 'absolute',
5409                top: 0,
5410                left: 0,
5411                height: 1,
5412                right: 0,
5413                overflow: 'hidden'
5414            } :
5415            {}
5416        )
5417            .append(tmpTable)
5418            .appendTo(tableContainer);
5419
5420        // When scrolling (X or Y) we want to set the width of the table as 
5421        // appropriate. However, when not scrolling leave the table width as it
5422        // is. This results in slightly different, but I think correct behaviour
5423        if (scrollX && scrollXInner) {
5424            tmpTable.width(scrollXInner);
5425        }
5426        else if (scrollX) {
5427            tmpTable.css('width', 'auto');
5428            tmpTable.removeAttr('width');
5429
5430            // If there is no width attribute or style, then allow the table to
5431            // collapse
5432            if (tmpTable.outerWidth() < tableContainer.clientWidth && tableWidthAttr) {
5433                tmpTable.outerWidth(tableContainer.clientWidth);
5434            }
5435        }
5436        else if (scrollY) {
5437            tmpTable.outerWidth(tableContainer.clientWidth);
5438        }
5439        else if (tableWidthAttr) {
5440            tmpTable.outerWidth(tableWidthAttr);
5441        }
5442
5443        // Get the width of each column in the constructed table
5444        var total = 0;
5445        var bodyCells = tmpTable.find('tbody tr').eq(0).children();
5446
5447        for (i = 0; i < visibleColumns.length; i++) {
5448            // Use getBounding for sub-pixel accuracy, which we then want to round up!
5449            var bounding = bodyCells[i].getBoundingClientRect().width;
5450
5451            // Total is tracked to remove any sub-pixel errors as the outerWidth
5452            // of the table might not equal the total given here
5453            total += bounding;
5454
5455            // Width for each column to use
5456            columns[visibleColumns[i]].sWidth = _fnStringToCss(bounding);
5457        }
5458
5459        table.style.width = _fnStringToCss(total);
5460
5461        // Finished with the table - ditch it
5462        holder.remove();
5463
5464        // If there is a width attr, we want to attach an event listener which
5465        // allows the table sizing to automatically adjust when the window is
5466        // resized. Use the width attr rather than CSS, since we can't know if the
5467        // CSS is a relative value or absolute - DOM read is always px.
5468        if (tableWidthAttr) {
5469            table.style.width = _fnStringToCss(tableWidthAttr);
5470        }
5471
5472        if ((tableWidthAttr || scrollX) && !settings._reszEvt) {
5473            var resize = DataTable.util.throttle(function () {
5474                var newWidth = _fnWrapperWidth(settings);
5475
5476                // Don't do it if destroying or the container width is 0
5477                if (!settings.bDestroying && newWidth !== 0) {
5478                    _fnAdjustColumnSizing(settings);
5479                }
5480            });
5481
5482            // For browsers that support it (~2020 onwards for wide support) we can watch for the
5483            // container changing width.
5484            if (window.ResizeObserver) {
5485                // This is a tricky beast - if the element is visible when `.observe()` is called,
5486                // then the callback is immediately run. Which we don't want. If the element isn't
5487                // visible, then it isn't run, but we want it to run when it is then made visible.
5488                // This flag allows the above to be satisfied.
5489                var first = $(settings.nTableWrapper).is(':visible');
5490
5491                // Use an empty div to attach the observer so it isn't impacted by height changes
5492                var resizer = $('<div>')
5493                    .css({
5494                        width: '100%',
5495                        height: 0
5496                    })
5497                    .addClass('dt-autosize')
5498                    .appendTo(settings.nTableWrapper);
5499
5500                settings.resizeObserver = new ResizeObserver(function (e) {
5501                    if (first) {
5502                        first = false;
5503                    }
5504                    else {
5505                        resize();
5506                    }
5507                });
5508
5509                settings.resizeObserver.observe(resizer[0]);
5510            }
5511            else {
5512                // For old browsers, the best we can do is listen for a window resize
5513                $(window).on('resize.DT-' + settings.sInstance, resize);
5514            }
5515
5516            settings._reszEvt = true;
5517        }
5518    }
5519
5520    /**
5521     * Get the width of the DataTables wrapper element
5522     *
5523     * @param {*} settings DataTables settings object
5524     * @returns Width
5525     */
5526    function _fnWrapperWidth(settings) {
5527        return $(settings.nTableWrapper).is(':visible')
5528            ? $(settings.nTableWrapper).width()
5529            : 0;
5530    }
5531
5532    /**
5533     * Get the maximum strlen for each data column
5534     *  @param {object} settings dataTables settings object
5535     *  @param {int} colIdx column of interest
5536     *  @returns {string} string of the max length
5537     *  @memberof DataTable#oApi
5538     */
5539    function _fnGetMaxLenString(settings, colIdx) {
5540        var column = settings.aoColumns[colIdx];
5541
5542        if (!column.maxLenString) {
5543            var s, max = '', maxLen = -1;
5544
5545            for (var i = 0, iLen = settings.aiDisplayMaster.length; i < iLen; i++) {
5546                var rowIdx = settings.aiDisplayMaster[i];
5547                var data = _fnGetRowDisplay(settings, rowIdx)[colIdx];
5548
5549                var cellString = data && typeof data === 'object' && data.nodeType
5550                    ? data.innerHTML
5551                    : data + '';
5552
5553                // Remove id / name attributes from elements so they
5554                // don't interfere with existing elements
5555                cellString = cellString
5556                    .replace(/id=".*?"/g, '')
5557                    .replace(/name=".*?"/g, '');
5558
5559                s = _stripHtml(cellString)
5560                    .replace(/&nbsp;/g, ' ');
5561
5562                if (s.length > maxLen) {
5563                    // We want the HTML in the string, but the length that
5564                    // is important is the stripped string
5565                    max = cellString;
5566                    maxLen = s.length;
5567                }
5568            }
5569
5570            column.maxLenString = max;
5571        }
5572
5573        return column.maxLenString;
5574    }
5575
5576
5577    /**
5578     * Append a CSS unit (only if required) to a string
5579     *  @param {string} value to css-ify
5580     *  @returns {string} value with css unit
5581     *  @memberof DataTable#oApi
5582     */
5583    function _fnStringToCss(s) {
5584        if (s === null) {
5585            return '0px';
5586        }
5587
5588        if (typeof s == 'number') {
5589            return s < 0 ?
5590                '0px' :
5591                s + 'px';
5592        }
5593
5594        // Check it has a unit character already
5595        return s.match(/\d$/) ?
5596            s + 'px' :
5597            s;
5598    }
5599
5600    /**
5601     * Re-insert the `col` elements for current visibility
5602     *
5603     * @param {*} settings DT settings
5604     */
5605    function _colGroup(settings) {
5606        var cols = settings.aoColumns;
5607
5608        settings.colgroup.empty();
5609
5610        for (i = 0; i < cols.length; i++) {
5611            if (cols[i].bVisible) {
5612                settings.colgroup.append(cols[i].colEl);
5613            }
5614        }
5615    }
5616
5617
5618    function _fnSortInit(settings) {
5619        var target = settings.nTHead;
5620        var headerRows = target.querySelectorAll('tr');
5621        var titleRow = settings.titleRow;
5622        var notSelector = ':not([data-dt-order="disable"]):not([data-dt-order="icon-only"])';
5623
5624        // Legacy support for `orderCellsTop`
5625        if (titleRow === true) {
5626            target = headerRows[0];
5627        }
5628        else if (titleRow === false) {
5629            target = headerRows[headerRows.length - 1];
5630        }
5631        else if (titleRow !== null) {
5632            target = headerRows[titleRow];
5633        }
5634        // else - all rows
5635
5636        if (settings.orderHandler) {
5637            _fnSortAttachListener(
5638                settings,
5639                target,
5640                target === settings.nTHead
5641                    ? 'tr' + notSelector + ' th' + notSelector + ', tr' + notSelector + ' td' + notSelector
5642                    : 'th' + notSelector + ', td' + notSelector
5643            );
5644        }
5645
5646        // Need to resolve the user input array into our internal structure
5647        var order = [];
5648        _fnSortResolve(settings, order, settings.aaSorting);
5649
5650        settings.aaSorting = order;
5651    }
5652
5653
5654    function _fnSortAttachListener(settings, node, selector, column, callback) {
5655        _fnBindAction(node, selector, function (e) {
5656            var run = false;
5657            var columns = column === undefined
5658                ? _fnColumnsFromHeader(e.target)
5659                : typeof column === 'function'
5660                    ? column()
5661                    : Array.isArray(column)
5662                        ? column
5663                        : [column];
5664
5665            if (columns.length) {
5666                for (var i = 0, iLen = columns.length; i < iLen; i++) {
5667                    var ret = _fnSortAdd(settings, columns[i], i, e.shiftKey);
5668
5669                    if (ret !== false) {
5670                        run = true;
5671                    }
5672
5673                    // If the first entry is no sort, then subsequent
5674                    // sort columns are ignored
5675                    if (settings.aaSorting.length === 1 && settings.aaSorting[0][1] === '') {
5676                        break;
5677                    }
5678                }
5679
5680                if (run) {
5681                    _fnProcessingRun(settings, true, function () {
5682                        _fnSort(settings);
5683                        _fnSortDisplay(settings, settings.aiDisplay);
5684
5685                        _fnReDraw(settings, false, false);
5686
5687                        if (callback) {
5688                            callback();
5689                        }
5690                    });
5691                }
5692            }
5693        });
5694    }
5695
5696    /**
5697     * Sort the display array to match the master's order
5698     * @param {*} settings
5699     */
5700    function _fnSortDisplay(settings, display) {
5701        if (display.length < 2) {
5702            return;
5703        }
5704
5705        var master = settings.aiDisplayMaster;
5706        var masterMap = {};
5707        var map = {};
5708        var i;
5709
5710        // Rather than needing an `indexOf` on master array, we can create a map
5711        for (i = 0; i < master.length; i++) {
5712            masterMap[master[i]] = i;
5713        }
5714
5715        // And then cache what would be the indexOf from the display
5716        for (i = 0; i < display.length; i++) {
5717            map[display[i]] = masterMap[display[i]];
5718        }
5719
5720        display.sort(function (a, b) {
5721            // Short version of this function is simply `master.indexOf(a) - master.indexOf(b);`
5722            return map[a] - map[b];
5723        });
5724    }
5725
5726
5727    function _fnSortResolve(settings, nestedSort, sort) {
5728        var push = function (a) {
5729            if ($.isPlainObject(a)) {
5730                if (a.idx !== undefined) {
5731                    // Index based ordering
5732                    nestedSort.push([a.idx, a.dir]);
5733                }
5734                else if (a.name) {
5735                    // Name based ordering
5736                    var cols = _pluck(settings.aoColumns, 'sName');
5737                    var idx = cols.indexOf(a.name);
5738
5739                    if (idx !== -1) {
5740                        nestedSort.push([idx, a.dir]);
5741                    }
5742                }
5743            }
5744            else {
5745                // Plain column index and direction pair
5746                nestedSort.push(a);
5747            }
5748        };
5749
5750        if ($.isPlainObject(sort)) {
5751            // Object
5752            push(sort);
5753        }
5754        else if (sort.length && typeof sort[0] === 'number') {
5755            // 1D array
5756            push(sort);
5757        }
5758        else if (sort.length) {
5759            // 2D array
5760            for (var z = 0; z < sort.length; z++) {
5761                push(sort[z]); // Object or array
5762            }
5763        }
5764    }
5765
5766
5767    function _fnSortFlatten(settings) {
5768        var
5769            i, k, kLen,
5770            aSort = [],
5771            extSort = DataTable.ext.type.order,
5772            aoColumns = settings.aoColumns,
5773            aDataSort, iCol, sType, srcCol,
5774            fixed = settings.aaSortingFixed,
5775            fixedObj = $.isPlainObject(fixed),
5776            nestedSort = [];
5777
5778        if (!settings.oFeatures.bSort) {
5779            return aSort;
5780        }
5781
5782        // Build the sort array, with pre-fix and post-fix options if they have been
5783        // specified
5784        if (Array.isArray(fixed)) {
5785            _fnSortResolve(settings, nestedSort, fixed);
5786        }
5787
5788        if (fixedObj && fixed.pre) {
5789            _fnSortResolve(settings, nestedSort, fixed.pre);
5790        }
5791
5792        _fnSortResolve(settings, nestedSort, settings.aaSorting);
5793
5794        if (fixedObj && fixed.post) {
5795            _fnSortResolve(settings, nestedSort, fixed.post);
5796        }
5797
5798        for (i = 0; i < nestedSort.length; i++) {
5799            srcCol = nestedSort[i][0];
5800
5801            if (aoColumns[srcCol]) {
5802                aDataSort = aoColumns[srcCol].aDataSort;
5803
5804                for (k = 0, kLen = aDataSort.length; k < kLen; k++) {
5805                    iCol = aDataSort[k];
5806                    sType = aoColumns[iCol].sType || 'string';
5807
5808                    if (nestedSort[i]._idx === undefined) {
5809                        nestedSort[i]._idx = aoColumns[iCol].asSorting.indexOf(nestedSort[i][1]);
5810                    }
5811
5812                    if (nestedSort[i][1]) {
5813                        aSort.push({
5814                            src: srcCol,
5815                            col: iCol,
5816                            dir: nestedSort[i][1],
5817                            index: nestedSort[i]._idx,
5818                            type: sType,
5819                            formatter: extSort[sType + "-pre"],
5820                            sorter: extSort[sType + "-" + nestedSort[i][1]]
5821                        });
5822                    }
5823                }
5824            }
5825        }
5826
5827        return aSort;
5828    }
5829
5830    /**
5831     * Change the order of the table
5832     *  @param {object} oSettings dataTables settings object
5833     *  @memberof DataTable#oApi
5834     */
5835    function _fnSort(oSettings, col, dir) {
5836        var
5837            i, iLen,
5838            aiOrig = [],
5839            extSort = DataTable.ext.type.order,
5840            aoData = oSettings.aoData,
5841            sortCol,
5842            displayMaster = oSettings.aiDisplayMaster,
5843            aSort;
5844
5845        // Make sure the columns all have types defined
5846        _fnColumnTypes(oSettings);
5847
5848        // Allow a specific column to be sorted, which will _not_ alter the display
5849        // master
5850        if (col !== undefined) {
5851            var srcCol = oSettings.aoColumns[col];
5852
5853            aSort = [{
5854                src: col,
5855                col: col,
5856                dir: dir,
5857                index: 0,
5858                type: srcCol.sType,
5859                formatter: extSort[srcCol.sType + "-pre"],
5860                sorter: extSort[srcCol.sType + "-" + dir]
5861            }];
5862            displayMaster = displayMaster.slice();
5863        }
5864        else {
5865            aSort = _fnSortFlatten(oSettings);
5866        }
5867
5868        for (i = 0, iLen = aSort.length; i < iLen; i++) {
5869            sortCol = aSort[i];
5870
5871            // Load the data needed for the sort, for each cell
5872            _fnSortData(oSettings, sortCol.col);
5873        }
5874
5875        /* No sorting required if server-side or no sorting array */
5876        if (_fnDataSource(oSettings) != 'ssp' && aSort.length !== 0) {
5877            // Reset the initial positions on each pass so we get a stable sort
5878            for (i = 0, iLen = displayMaster.length; i < iLen; i++) {
5879                aiOrig[i] = i;
5880            }
5881
5882            // If the first sort is desc, then reverse the array to preserve original
5883            // order, just in reverse
5884            if (aSort.length && aSort[0].dir === 'desc' && oSettings.orderDescReverse) {
5885                aiOrig.reverse();
5886            }
5887
5888            /* Do the sort - here we want multi-column sorting based on a given data source (column)
5889             * and sorting function (from oSort) in a certain direction. It's reasonably complex to
5890             * follow on its own, but this is what we want (example two column sorting):
5891             *  fnLocalSorting = function(a,b){
5892             *    var test;
5893             *    test = oSort['string-asc']('data11', 'data12');
5894             *      if (test !== 0)
5895             *        return test;
5896             *    test = oSort['numeric-desc']('data21', 'data22');
5897             *    if (test !== 0)
5898             *      return test;
5899             *    return oSort['numeric-asc']( aiOrig[a], aiOrig[b] );
5900             *  }
5901             * Basically we have a test for each sorting column, if the data in that column is equal,
5902             * test the next column. If all columns match, then we use a numeric sort on the row
5903             * positions in the original data array to provide a stable sort.
5904             */
5905            displayMaster.sort(function (a, b) {
5906                var
5907                    x, y, k, test, sort,
5908                    len = aSort.length,
5909                    dataA = aoData[a]._aSortData,
5910                    dataB = aoData[b]._aSortData;
5911
5912                for (k = 0; k < len; k++) {
5913                    sort = aSort[k];
5914
5915                    // Data, which may have already been through a `-pre` function
5916                    x = dataA[sort.col];
5917                    y = dataB[sort.col];
5918
5919                    if (sort.sorter) {
5920                        // If there is a custom sorter (`-asc` or `-desc`) for this
5921                        // data type, use it
5922                        test = sort.sorter(x, y);
5923
5924                        if (test !== 0) {
5925                            return test;
5926                        }
5927                    }
5928                    else {
5929                        // Otherwise, use generic sorting
5930                        test = x < y ? -1 : x > y ? 1 : 0;
5931
5932                        if (test !== 0) {
5933                            return sort.dir === 'asc' ? test : -test;
5934                        }
5935                    }
5936                }
5937
5938                x = aiOrig[a];
5939                y = aiOrig[b];
5940
5941                return x < y ? -1 : x > y ? 1 : 0;
5942            });
5943        }
5944        else if (aSort.length === 0) {
5945            // Apply index order
5946            displayMaster.sort(function (x, y) {
5947                return x < y ? -1 : x > y ? 1 : 0;
5948            });
5949        }
5950
5951        if (col === undefined) {
5952            // Tell the draw function that we have sorted the data
5953            oSettings.bSorted = true;
5954            oSettings.sortDetails = aSort;
5955
5956            _fnCallbackFire(oSettings, null, 'order', [oSettings, aSort]);
5957        }
5958
5959        return displayMaster;
5960    }
5961
5962
5963    /**
5964     * Function to run on user sort request
5965     *  @param {object} settings dataTables settings object
5966     *  @param {node} attachTo node to attach the handler to
5967     *  @param {int} colIdx column sorting index
5968     *  @param {int} addIndex Counter
5969     *  @param {boolean} [shift=false] Shift click add
5970     *  @param {function} [callback] callback function
5971     *  @memberof DataTable#oApi
5972     */
5973    function _fnSortAdd(settings, colIdx, addIndex, shift) {
5974        var col = settings.aoColumns[colIdx];
5975        var sorting = settings.aaSorting;
5976        var asSorting = col.asSorting;
5977        var nextSortIdx;
5978        var next = function (a, overflow) {
5979            var idx = a._idx;
5980            if (idx === undefined) {
5981                idx = asSorting.indexOf(a[1]);
5982            }
5983
5984            return idx + 1 < asSorting.length ?
5985                idx + 1 :
5986                overflow ?
5987                    null :
5988                    0;
5989        };
5990
5991        if (!col.bSortable) {
5992            return false;
5993        }
5994
5995        // Convert to 2D array if needed
5996        if (typeof sorting[0] === 'number') {
5997            sorting = settings.aaSorting = [sorting];
5998        }
5999
6000        // If appending the sort then we are multi-column sorting
6001        if ((shift || addIndex) && settings.oFeatures.bSortMulti) {
6002            // Are we already doing some kind of sort on this column?
6003            var sortIdx = _pluck(sorting, '0').indexOf(colIdx);
6004
6005            if (sortIdx !== -1) {
6006                // Yes, modify the sort
6007                nextSortIdx = next(sorting[sortIdx], true);
6008
6009                if (nextSortIdx === null && sorting.length === 1) {
6010                    nextSortIdx = 0; // can't remove sorting completely
6011                }
6012
6013                if (nextSortIdx === null || asSorting[nextSortIdx] === '') {
6014                    sorting.splice(sortIdx, 1);
6015                }
6016                else {
6017                    sorting[sortIdx][1] = asSorting[nextSortIdx];
6018                    sorting[sortIdx]._idx = nextSortIdx;
6019                }
6020            }
6021            else if (shift) {
6022                // No sort on this column yet, being added by shift click
6023                // add it as itself
6024                sorting.push([colIdx, asSorting[0], 0]);
6025                sorting[sorting.length - 1]._idx = 0;
6026            }
6027            else {
6028                // No sort on this column yet, being added from a colspan
6029                // so add with same direction as first column
6030                sorting.push([colIdx, sorting[0][1], 0]);
6031                sorting[sorting.length - 1]._idx = 0;
6032            }
6033        }
6034        else if (sorting.length && sorting[0][0] == colIdx) {
6035            // Single column - already sorting on this column, modify the sort
6036            nextSortIdx = next(sorting[0]);
6037
6038            sorting.length = 1;
6039            sorting[0][1] = asSorting[nextSortIdx];
6040            sorting[0]._idx = nextSortIdx;
6041        }
6042        else {
6043            // Single column - sort only on this column
6044            sorting.length = 0;
6045            sorting.push([colIdx, asSorting[0]]);
6046            sorting[0]._idx = 0;
6047        }
6048    }
6049
6050
6051    /**
6052     * Set the sorting classes on table's body, Note: it is safe to call this function
6053     * when bSort and bSortClasses are false
6054     *  @param {object} oSettings dataTables settings object
6055     *  @memberof DataTable#oApi
6056     */
6057    function _fnSortingClasses(settings) {
6058        var oldSort = settings.aLastSort;
6059        var sortClass = settings.oClasses.order.position;
6060        var sort = _fnSortFlatten(settings);
6061        var features = settings.oFeatures;
6062        var i, iLen, colIdx;
6063
6064        if (features.bSort && features.bSortClasses) {
6065            // Remove old sorting classes
6066            for (i = 0, iLen = oldSort.length; i < iLen; i++) {
6067                colIdx = oldSort[i].src;
6068
6069                // Remove column sorting
6070                $(_pluck(settings.aoData, 'anCells', colIdx))
6071                    .removeClass(sortClass + (i < 2 ? i + 1 : 3));
6072            }
6073
6074            // Add new column sorting
6075            for (i = 0, iLen = sort.length; i < iLen; i++) {
6076                colIdx = sort[i].src;
6077
6078                $(_pluck(settings.aoData, 'anCells', colIdx))
6079                    .addClass(sortClass + (i < 2 ? i + 1 : 3));
6080            }
6081        }
6082
6083        settings.aLastSort = sort;
6084    }
6085
6086
6087    // Get the data to sort a column, be it from cache, fresh (populating the
6088    // cache), or from a sort formatter
6089    function _fnSortData(settings, colIdx) {
6090        // Custom sorting function - provided by the sort data type
6091        var column = settings.aoColumns[colIdx];
6092        var customSort = DataTable.ext.order[column.sSortDataType];
6093        var customData;
6094
6095        if (customSort) {
6096            customData = customSort.call(settings.oInstance, settings, colIdx,
6097                _fnColumnIndexToVisible(settings, colIdx)
6098            );
6099        }
6100
6101        // Use / populate cache
6102        var row, cellData;
6103        var formatter = DataTable.ext.type.order[column.sType + "-pre"];
6104        var data = settings.aoData;
6105
6106        for (var rowIdx = 0; rowIdx < data.length; rowIdx++) {
6107            // Sparse array
6108            if (!data[rowIdx]) {
6109                continue;
6110            }
6111
6112            row = data[rowIdx];
6113
6114            if (!row._aSortData) {
6115                row._aSortData = [];
6116            }
6117
6118            if (!row._aSortData[colIdx] || customSort) {
6119                cellData = customSort ?
6120                    customData[rowIdx] : // If there was a custom sort function, use data from there
6121                    _fnGetCellData(settings, rowIdx, colIdx, 'sort');
6122
6123                row._aSortData[colIdx] = formatter ?
6124                    formatter(cellData, settings) :
6125                    cellData;
6126            }
6127        }
6128    }
6129
6130
6131    /**
6132     * State information for a table
6133     *
6134     * @param {*} settings
6135     * @returns State object
6136     */
6137    function _fnSaveState(settings) {
6138        if (settings._bLoadingState) {
6139            return;
6140        }
6141
6142        // Sort state saving uses [[idx, order]] structure.
6143        var sorting = [];
6144        _fnSortResolve(settings, sorting, settings.aaSorting);
6145
6146        /* Store the interesting variables */
6147        var columns = settings.aoColumns;
6148        var state = {
6149            time: +new Date(),
6150            start: settings._iDisplayStart,
6151            length: settings._iDisplayLength,
6152            order: sorting.map(function (sort) {
6153                // If a column name is available, use it
6154                return columns[sort[0]] && columns[sort[0]].sName
6155                    ? [columns[sort[0]].sName, sort[1]]
6156                    : sort.slice();
6157            }),
6158            search: $.extend({}, settings.oPreviousSearch),
6159            columns: settings.aoColumns.map(function (col, i) {
6160                return {
6161                    name: col.sName,
6162                    visible: col.bVisible,
6163                    search: $.extend({}, settings.aoPreSearchCols[i])
6164                };
6165            })
6166        };
6167
6168        settings.oSavedState = state;
6169        _fnCallbackFire(settings, "aoStateSaveParams", 'stateSaveParams', [settings, state]);
6170
6171        if (settings.oFeatures.bStateSave && !settings.bDestroying) {
6172            settings.fnStateSaveCallback.call(settings.oInstance, settings, state);
6173        }
6174    }
6175
6176
6177    /**
6178     * Attempt to load a saved table state
6179     *  @param {object} oSettings dataTables settings object
6180     *  @param {object} oInit DataTables init object so we can override settings
6181     *  @param {function} callback Callback to execute when the state has been loaded
6182     *  @memberof DataTable#oApi
6183     */
6184    function _fnLoadState(settings, init, callback) {
6185        if (!settings.oFeatures.bStateSave) {
6186            callback();
6187            return;
6188        }
6189
6190        var loaded = function (state) {
6191            _fnImplementState(settings, state, callback);
6192        }
6193
6194        var state = settings.fnStateLoadCallback.call(settings.oInstance, settings, loaded);
6195
6196        if (state !== undefined) {
6197            _fnImplementState(settings, state, callback);
6198        }
6199        // otherwise, wait for the loaded callback to be executed
6200
6201        return true;
6202    }
6203
6204    function _fnImplementState(settings, s, callback) {
6205        var i, iLen;
6206        var columns = settings.aoColumns;
6207        var currentNames = _pluck(settings.aoColumns, 'sName');
6208
6209        settings._bLoadingState = true;
6210
6211        // When StateRestore was introduced the state could now be implemented at any time
6212        // Not just initialisation. To do this an api instance is required in some places
6213        var api = settings._bInitComplete ? new DataTable.Api(settings) : null;
6214
6215        if (!s || !s.time) {
6216            settings._bLoadingState = false;
6217            callback();
6218            return;
6219        }
6220
6221        // Reject old data
6222        var duration = settings.iStateDuration;
6223        if (duration > 0 && s.time < +new Date() - (duration * 1000)) {
6224            settings._bLoadingState = false;
6225            callback();
6226            return;
6227        }
6228
6229        // Allow custom and plug-in manipulation functions to alter the saved data set and
6230        // cancelling of loading by returning false
6231        var abStateLoad = _fnCallbackFire(settings, 'aoStateLoadParams', 'stateLoadParams', [settings, s]);
6232        if (abStateLoad.indexOf(false) !== -1) {
6233            settings._bLoadingState = false;
6234            callback();
6235            return;
6236        }
6237
6238        // Store the saved state so it might be accessed at any time
6239        settings.oLoadedState = $.extend(true, {}, s);
6240
6241        // This is needed for ColReorder, which has to happen first to allow all
6242        // the stored indexes to be usable. It is not publicly documented.
6243        _fnCallbackFire(settings, null, 'stateLoadInit', [settings, s], true);
6244
6245        // Page Length
6246        if (s.length !== undefined) {
6247            // If already initialised just set the value directly so that the select element is also updated
6248            if (api) {
6249                api.page.len(s.length)
6250            }
6251            else {
6252                settings._iDisplayLength = s.length;
6253            }
6254        }
6255
6256        // Restore key features
6257        if (s.start !== undefined) {
6258            if (api === null) {
6259                settings._iDisplayStart = s.start;
6260                settings.iInitDisplayStart = s.start;
6261            }
6262            else {
6263                _fnPageChange(settings, s.start / settings._iDisplayLength);
6264            }
6265        }
6266
6267        // Order
6268        if (s.order !== undefined) {
6269            settings.aaSorting = [];
6270            $.each(s.order, function (i, col) {
6271                var set = [col[0], col[1]];
6272
6273                // A column name was stored and should be used for restore
6274                if (typeof col[0] === 'string') {
6275                    // Find the name from the current list of column names
6276                    var idx = currentNames.indexOf(col[0]);
6277
6278                    if (idx < 0) {
6279                        // If the column was not found ignore it and continue
6280                        return;
6281                    }
6282
6283                    set[0] = idx;
6284                }
6285                else if (set[0] >= columns.length) {
6286                    // If the column index is out of bounds ignore it and continue
6287                    return;
6288                }
6289
6290                settings.aaSorting.push(set);
6291            });
6292        }
6293
6294        // Search
6295        if (s.search !== undefined) {
6296            $.extend(settings.oPreviousSearch, s.search);
6297        }
6298
6299        // Columns
6300        if (s.columns) {
6301            var set = s.columns;
6302            var incoming = _pluck(s.columns, 'name');
6303
6304            // Check if it is a 2.2 style state object with a `name` property for the columns, and if
6305            // the name was defined. If so, then create a new array that will map the state object
6306            // given, to the current columns (don't bother if they are already matching tho).
6307            if (incoming.join('').length && incoming.join('') !== currentNames.join('')) {
6308                set = [];
6309
6310                // For each column, try to find the name in the incoming array
6311                for (i = 0; i < currentNames.length; i++) {
6312                    if (currentNames[i] != '') {
6313                        var idx = incoming.indexOf(currentNames[i]);
6314
6315                        if (idx >= 0) {
6316                            set.push(s.columns[idx]);
6317                        }
6318                        else {
6319                            // No matching column name in the state's columns, so this might be a new
6320                            // column and thus can't have a state already.
6321                            set.push({});
6322                        }
6323                    }
6324                    else {
6325                        // If no name, but other columns did have a name, then there is no knowing
6326                        // where this one came from originally so it can't be restored.
6327                        set.push({});
6328                    }
6329                }
6330            }
6331
6332            // If the number of columns to restore is different from current, then all bets are off.
6333            if (set.length === columns.length) {
6334                for (i = 0, iLen = set.length; i < iLen; i++) {
6335                    var col = set[i];
6336
6337                    // Visibility
6338                    if (col.visible !== undefined) {
6339                        // If the api is defined, the table has been initialised so we need to use it rather than internal settings
6340                        if (api) {
6341                            // Don't redraw the columns on every iteration of this loop, we will do this at the end instead
6342                            api.column(i).visible(col.visible, false);
6343                        }
6344                        else {
6345                            columns[i].bVisible = col.visible;
6346                        }
6347                    }
6348
6349                    // Search
6350                    if (col.search !== undefined) {
6351                        $.extend(settings.aoPreSearchCols[i], col.search);
6352                    }
6353                }
6354
6355                // If the api is defined then we need to adjust the columns once the visibility has been changed
6356                if (api) {
6357                    api.one('draw', function () {
6358                        api.columns.adjust();
6359                    });
6360                }
6361            }
6362        }
6363
6364        settings._bLoadingState = false;
6365        _fnCallbackFire(settings, 'aoStateLoaded', 'stateLoaded', [settings, s]);
6366        callback();
6367    }
6368
6369    /**
6370     * Log an error message
6371     *  @param {object} settings dataTables settings object
6372     *  @param {int} level log error messages, or display them to the user
6373     *  @param {string} msg error message
6374     *  @param {int} tn Technical note id to get more information about the error.
6375     *  @memberof DataTable#oApi
6376     */
6377    function _fnLog(settings, level, msg, tn) {
6378        msg = 'DataTables warning: ' +
vendor: 4,620 bytes, lines 6379-6509
6379            (settings ? 'table id=' + settings.sTableId + ' - ' : '') + msg;
6380
6381        if (tn) {
6382            msg += '. For more information about this error, please see ' +
6383                'https://datatables.net/tn/' + tn;
6384        }
6385
6386        if (!level) {
6387            // Backwards compatibility pre 1.10
6388            var ext = DataTable.ext;
6389            var type = ext.sErrMode || ext.errMode;
6390
6391            if (settings) {
6392                _fnCallbackFire(settings, null, 'dt-error', [settings, tn, msg], true);
6393            }
6394
6395            if (type == 'alert') {
6396                alert(msg);
6397            }
6398            else if (type == 'throw') {
6399                throw new Error(msg);
6400            }
6401            else if (typeof type == 'function') {
6402                type(settings, tn, msg);
6403            }
6404        }
6405        else if (window.console && console.log) {
6406            console.log(msg);
6407        }
6408    }
6409
6410
6411    /**
6412     * See if a property is defined on one object, if so assign it to the other object
6413     *  @param {object} ret target object
6414     *  @param {object} src source object
6415     *  @param {string} name property
6416     *  @param {string} [mappedName] name to map too - optional, name used if not given
6417     *  @memberof DataTable#oApi
6418     */
6419    function _fnMap(ret, src, name, mappedName) {
6420        if (Array.isArray(name)) {
6421            $.each(name, function (i, val) {
6422                if (Array.isArray(val)) {
6423                    _fnMap(ret, src, val[0], val[1]);
6424                }
6425                else {
6426                    _fnMap(ret, src, val);
6427                }
6428            });
6429
6430            return;
6431        }
6432
6433        if (mappedName === undefined) {
6434            mappedName = name;
6435        }
6436
6437        if (src[name] !== undefined) {
6438            ret[mappedName] = src[name];
6439        }
6440    }
6441
6442
6443    /**
6444     * Extend objects - very similar to jQuery.extend, but deep copy objects, and
6445     * shallow copy arrays. The reason we need to do this, is that we don't want to
6446     * deep copy array init values (such as aaSorting) since the dev wouldn't be
6447     * able to override them, but we do want to deep copy arrays.
6448     *  @param {object} out Object to extend
6449     *  @param {object} extender Object from which the properties will be applied to
6450     *      out
6451     *  @param {boolean} breakRefs If true, then arrays will be sliced to take an
6452     *      independent copy with the exception of the `data` or `aaData` parameters
6453     *      if they are present. This is so you can pass in a collection to
6454     *      DataTables and have that used as your data source without breaking the
6455     *      references
6456     *  @returns {object} out Reference, just for convenience - out === the return.
6457     *  @memberof DataTable#oApi
6458     *  @todo This doesn't take account of arrays inside the deep copied objects.
6459     */
6460    function _fnExtend(out, extender, breakRefs) {
6461        var val;
6462
6463        for (var prop in extender) {
6464            if (Object.prototype.hasOwnProperty.call(extender, prop)) {
6465                val = extender[prop];
6466
6467                if ($.isPlainObject(val)) {
6468                    if (!$.isPlainObject(out[prop])) {
6469                        out[prop] = {};
6470                    }
6471                    $.extend(true, out[prop], val);
6472                }
6473                else if (breakRefs && prop !== 'data' && prop !== 'aaData' && Array.isArray(val)) {
6474                    out[prop] = val.slice();
6475                }
6476                else {
6477                    out[prop] = val;
6478                }
6479            }
6480        }
6481
6482        return out;
6483    }
6484
6485
6486    /**
6487     * Bind an event handler to allow a click or return key to activate the callback.
6488     * This is good for accessibility since a return on the keyboard will have the
6489     * same effect as a click, if the element has focus.
6490     *  @param {element} n Element to bind the action to
6491     *  @param {object|string} selector Selector (for delegated events) or data object
6492     *   to pass to the triggered function
6493     *  @param {function} fn Callback function for when the event is triggered
6494     *  @memberof DataTable#oApi
6495     */
6496    function _fnBindAction(n, selector, fn) {
6497        $(n)
6498            .on('click.DT', selector, function (e) {
6499                fn(e);
6500            })
6501            .on('keypress.DT', selector, function (e) {
6502                if (e.which === 13) {
6503                    e.preventDefault();
6504                    fn(e);
6505                }
6506            })
6507            .on('selectstart.DT', selector, function () {
6508                // Don't want a double click resulting in text selection
6509                return false;
6510            });
6511    }
6512
6513
6514    /**
6515     * Register a callback function. Easily allows a callback function to be added to
6516     * an array store of callback functions that can then all be called together.
6517     *  @param {object} settings dataTables settings object
6518     *  @param {string} store Name of the array storage for the callbacks in oSettings
6519     *  @param {function} fn Function to be called back
6520     *  @memberof DataTable#oApi
6521     */
6522    function _fnCallbackReg(settings, store, fn) {
6523        if (fn) {
6524            settings[store].push(fn);
6525        }
6526    }
6527
6528
6529    /**
6530     * Fire callback functions and trigger events. Note that the loop over the
6531     * callback array store is done backwards! Further note that you do not want to
6532     * fire off triggers in time sensitive applications (for example cell creation)
6533     * as its slow.
6534     *  @param {object} settings dataTables settings object
6535     *  @param {string} callbackArr Name of the array storage for the callbacks in
6536     *      oSettings
6537     *  @param {string} eventName Name of the jQuery custom event to trigger. If
6538     *      null no trigger is fired
6539     *  @param {array} args Array of arguments to pass to the callback function /
6540     *      trigger
6541     *  @param {boolean} [bubbles] True if the event should bubble
6542     *  @memberof DataTable#oApi
6543     */
6544    function _fnCallbackFire(settings, callbackArr, eventName, args, bubbles) {
6545        var ret = [];
6546
6547        if (callbackArr) {
6548            ret = settings[callbackArr].slice().reverse().map(function (val) {
6549                return val.apply(settings.oInstance, args);
6550            });
6551        }
6552
6553        if (eventName !== null) {
6554            var e = $.Event(eventName + '.dt');
6555            var table = $(settings.nTable);
6556
6557            // Expose the DataTables API on the event object for easy access
6558            e.dt = settings.api;
6559
6560            table[bubbles ? 'trigger' : 'triggerHandler'](e, args);
6561
6562            // If not yet attached to the document, trigger the event
6563            // on the body directly to sort of simulate the bubble
6564            if (bubbles && table.parents('body').length === 0) {
6565                $('body').trigger(e, args);
6566            }
6567
6568            ret.push(e.result);
6569        }
6570
6571        return ret;
6572    }
6573
6574
6575    function _fnLengthOverflow(settings) {
6576        var
6577            start = settings._iDisplayStart,
6578            end = settings.fnDisplayEnd(),
6579            len = settings._iDisplayLength;
6580
6581        /* If we have space to show extra rows (backing up from the end point - then do so */
6582        if (start >= end) {
6583            start = end - len;
6584        }
6585
6586        // Keep the start record on the current page
6587        start -= (start % len);
6588
6589        if (len === -1 || start < 0) {
6590            start = 0;
6591        }
6592
6593        settings._iDisplayStart = start;
6594    }
6595
6596
6597    function _fnRenderer(settings, type) {
6598        var renderer = settings.renderer;
6599        var host = DataTable.ext.renderer[type];
6600
6601        if ($.isPlainObject(renderer) && renderer[type]) {
6602            // Specific renderer for this type. If available use it, otherwise use
6603            // the default.
6604            return host[renderer[type]] || host._;
6605        }
6606        else if (typeof renderer === 'string') {
6607            // Common renderer - if there is one available for this type use it,
6608            // otherwise use the default
6609            return host[renderer] || host._;
6610        }
6611
6612        // Use the default
6613        return host._;
6614    }
6615
6616
6617    /**
6618     * Detect the data source being used for the table. Used to simplify the code
6619     * a little (ajax) and to make it compress a little smaller.
6620     *
6621     *  @param {object} settings dataTables settings object
6622     *  @returns {string} Data source
6623     *  @memberof DataTable#oApi
6624     */
6625    function _fnDataSource(settings) {
6626        if (settings.oFeatures.bServerSide) {
6627            return 'ssp';
6628        }
6629        else if (settings.ajax) {
6630            return 'ajax';
6631        }
6632        return 'dom';
6633    }
6634
6635    /**
6636     * Common replacement for language strings
6637     *
6638     * @param {*} settings DT settings object
6639     * @param {*} str String with values to replace
6640     * @param {*} entries Plural number for _ENTRIES_ - can be undefined
6641     * @returns String
6642     */
6643    function _fnMacros(settings, str, entries) {
6644        // When infinite scrolling, we are always starting at 1. _iDisplayStart is
6645        // used only internally
6646        var
6647            formatter = settings.fnFormatNumber,
6648            start = settings._iDisplayStart + 1,
6649            len = settings._iDisplayLength,
6650            vis = settings.fnRecordsDisplay(),
6651            max = settings.fnRecordsTotal(),
6652            all = len === -1;
6653
6654        return str.
6655            replace(/_START_/g, formatter.call(settings, start)).
6656            replace(/_END_/g, formatter.call(settings, settings.fnDisplayEnd())).
6657            replace(/_MAX_/g, formatter.call(settings, max)).
6658            replace(/_TOTAL_/g, formatter.call(settings, vis)).
6659            replace(/_PAGE_/g, formatter.call(settings, all ? 1 : Math.ceil(start / len))).
6660            replace(/_PAGES_/g, formatter.call(settings, all ? 1 : Math.ceil(vis / len))).
6661            replace(/_ENTRIES_/g, settings.api.i18n('entries', '', entries)).
6662            replace(/_ENTRIES-MAX_/g, settings.api.i18n('entries', '', max)).
6663            replace(/_ENTRIES-TOTAL_/g, settings.api.i18n('entries', '', vis));
6664    }
6665
6666    /**
6667     * Add elements to an array as quickly as possible, but stack safe.
6668     *
6669     * @param {*} arr Array to add the data to
6670     * @param {*} data Data array that is to be added
6671     * @returns 
6672     */
6673    function _fnArrayApply(arr, data) {
6674        if (!data) {
6675            return;
6676        }
6677
6678        // Chrome can throw a max stack error if apply is called with
6679        // too large an array, but apply is faster.
6680        if (data.length < 10000) {
6681            arr.push.apply(arr, data);
6682        }
6683        else {
6684            for (i = 0; i < data.length; i++) {
6685                arr.push(data[i]);
6686            }
6687        }
6688    }
6689
6690    /**
6691     * Add one or more listeners to the table
6692     *
6693     * @param {*} that JQ for the table
6694     * @param {*} name Event name
6695     * @param {*} src Listener(s)
6696     */
6697    function _fnListener(that, name, src) {
6698        if (!Array.isArray(src)) {
6699            src = [src];
6700        }
6701
6702        for (i = 0; i < src.length; i++) {
6703            that.on(name + '.dt', src[i]);
6704        }
6705    }
6706
6707    /**
6708     * Escape HTML entities in strings, in an object
6709     */
6710    function _fnEscapeObject(obj) {
6711        if (DataTable.ext.escape.attributes) {
6712            $.each(obj, function (key, val) {
6713                obj[key] = _escapeHtml(val);
6714            })
6715        }
6716
6717        return obj;
6718    }
6719
6720
6721
6722    /**
6723     * Computed structure of the DataTables API, defined by the options passed to
6724     * `DataTable.Api.register()` when building the API.
6725     *
6726     * The structure is built in order to speed creation and extension of the Api
6727     * objects since the extensions are effectively pre-parsed.
6728     *
6729     * The array is an array of objects with the following structure, where this
6730     * base array represents the Api prototype base:
6731     *
6732     *     [
6733     *       {
6734     *         name:      'data'                -- string   - Property name
6735     *         val:       function () {},       -- function - Api method (or undefined if just an object
6736     *         methodExt: [ ... ],              -- array    - Array of Api object definitions to extend the method result
6737     *         propExt:   [ ... ]               -- array    - Array of Api object definitions to extend the property
6738     *       },
6739     *       {
6740     *         name:     'row'
6741     *         val:       {},
6742     *         methodExt: [ ... ],
6743     *         propExt:   [
6744     *           {
6745     *             name:      'data'
6746     *             val:       function () {},
6747     *             methodExt: [ ... ],
6748     *             propExt:   [ ... ]
6749     *           },
6750     *           ...
6751     *         ]
6752     *       }
6753     *     ]
6754     *
6755     * @type {Array}
6756     * @ignore
6757     */
6758    var __apiStruct = [];
6759
6760
6761    /**
6762     * `Array.prototype` reference.
6763     *
6764     * @type object
6765     * @ignore
6766     */
6767    var __arrayProto = Array.prototype;
6768
6769
6770    /**
6771     * Abstraction for `context` parameter of the `Api` constructor to allow it to
6772     * take several different forms for ease of use.
6773     *
6774     * Each of the input parameter types will be converted to a DataTables settings
6775     * object where possible.
6776     *
6777     * @param  {string|node|jQuery|object} mixed DataTable identifier. Can be one
6778     *   of:
6779     *
6780     *   * `string` - jQuery selector. Any DataTables' matching the given selector
6781     *     with be found and used.
6782     *   * `node` - `TABLE` node which has already been formed into a DataTable.
6783     *   * `jQuery` - A jQuery object of `TABLE` nodes.
6784     *   * `object` - DataTables settings object
6785     *   * `DataTables.Api` - API instance
6786     * @return {array|null} Matching DataTables settings objects. `null` or
6787     *   `undefined` is returned if no matching DataTable is found.
6788     * @ignore
6789     */
6790    var _toSettings = function (mixed) {
6791        var idx, jq;
6792        var settings = DataTable.settings;
6793        var tables = _pluck(settings, 'nTable');
6794
6795        if (!mixed) {
6796            return [];
6797        }
6798        else if (mixed.nTable && mixed.oFeatures) {
6799            // DataTables settings object
6800            return [mixed];
6801        }
6802        else if (mixed.nodeName && mixed.nodeName.toLowerCase() === 'table') {
6803            // Table node
6804            idx = tables.indexOf(mixed);
6805            return idx !== -1 ? [settings[idx]] : null;
6806        }
6807        else if (mixed && typeof mixed.settings === 'function') {
6808            return mixed.settings().toArray();
6809        }
6810        else if (typeof mixed === 'string') {
6811            // jQuery selector
6812            jq = $(mixed).get();
6813        }
6814        else if (mixed instanceof $) {
6815            // jQuery object (also DataTables instance)
6816            jq = mixed.get();
6817        }
6818
6819        if (jq) {
6820            return settings.filter(function (v, idx) {
6821                return jq.includes(tables[idx]);
6822            });
6823        }
6824    };
6825
6826
6827    /**
6828     * DataTables API class - used to control and interface with  one or more
6829     * DataTables enhanced tables.
6830     *
6831     * The API class is heavily based on jQuery, presenting a chainable interface
6832     * that you can use to interact with tables. Each instance of the API class has
6833     * a "context" - i.e. the tables that it will operate on. This could be a single
6834     * table, all tables on a page or a sub-set thereof.
6835     *
6836     * Additionally the API is designed to allow you to easily work with the data in
6837     * the tables, retrieving and manipulating it as required. This is done by
6838     * presenting the API class as an array like interface. The contents of the
6839     * array depend upon the actions requested by each method (for example
6840     * `rows().nodes()` will return an array of nodes, while `rows().data()` will
6841     * return an array of objects or arrays depending upon your table's
6842     * configuration). The API object has a number of array like methods (`push`,
6843     * `pop`, `reverse` etc) as well as additional helper methods (`each`, `pluck`,
6844     * `unique` etc) to assist your working with the data held in a table.
6845     *
6846     * Most methods (those which return an Api instance) are chainable, which means
6847     * the return from a method call also has all of the methods available that the
6848     * top level object had. For example, these two calls are equivalent:
6849     *
6850     *     // Not chained
6851     *     api.row.add( {...} );
6852     *     api.draw();
6853     *
6854     *     // Chained
6855     *     api.row.add( {...} ).draw();
6856     *
6857     * @class DataTable.Api
6858     * @param {array|object|string|jQuery} context DataTable identifier. This is
6859     *   used to define which DataTables enhanced tables this API will operate on.
6860     *   Can be one of:
6861     *
6862     *   * `string` - jQuery selector. Any DataTables' matching the given selector
6863     *     with be found and used.
6864     *   * `node` - `TABLE` node which has already been formed into a DataTable.
6865     *   * `jQuery` - A jQuery object of `TABLE` nodes.
6866     *   * `object` - DataTables settings object
6867     * @param {array} [data] Data to initialise the Api instance with.
6868     *
6869     * @example
6870     *   // Direct initialisation during DataTables construction
6871     *   var api = $('#example').DataTable();
6872     *
6873     * @example
6874     *   // Initialisation using a DataTables jQuery object
6875     *   var api = $('#example').dataTable().api();
6876     *
6877     * @example
6878     *   // Initialisation as a constructor
6879     *   var api = new DataTable.Api( 'table.dataTable' );
6880     */
6881    _Api = function (context, data) {
6882        if (!(this instanceof _Api)) {
6883            return new _Api(context, data);
6884        }
6885
6886        var i;
6887        var settings = [];
6888        var ctxSettings = function (o) {
6889            var a = _toSettings(o);
6890            if (a) {
6891                settings.push.apply(settings, a);
6892            }
6893        };
6894
6895        if (Array.isArray(context)) {
6896            for (i = 0; i < context.length; i++) {
6897                ctxSettings(context[i]);
6898            }
6899        }
6900        else {
6901            ctxSettings(context);
6902        }
6903
6904        // Remove duplicates
6905        this.context = settings.length > 1
6906            ? _unique(settings)
6907            : settings;
6908
6909        // Initial data
6910        _fnArrayApply(this, data);
6911
6912        // selector
6913        this.selector = {
6914            rows: null,
6915            cols: null,
6916            opts: null
6917        };
6918
6919        _Api.extend(this, this, __apiStruct);
6920    };
6921
6922    DataTable.Api = _Api;
6923
6924    // Don't destroy the existing prototype, just extend it. Required for jQuery 2's
6925    // isPlainObject.
6926    $.extend(_Api.prototype, {
6927        any: function () {
6928            return this.count() !== 0;
6929        },
6930
6931        context: [], // array of table settings objects
6932
6933        count: function () {
6934            return this.flatten().length;
6935        },
6936
6937        each: function (fn) {
6938            for (var i = 0, iLen = this.length; i < iLen; i++) {
6939                fn.call(this, this[i], i, this);
6940            }
6941
6942            return this;
6943        },
6944
6945        eq: function (idx) {
6946            var ctx = this.context;
6947
6948            return ctx.length > idx ?
6949                new _Api(ctx[idx], this[idx]) :
6950                null;
6951        },
6952
6953        filter: function (fn) {
6954            var a = __arrayProto.filter.call(this, fn, this);
6955
6956            return new _Api(this.context, a);
6957        },
6958
6959        flatten: function () {
6960            var a = [];
6961
6962            return new _Api(this.context, a.concat.apply(a, this.toArray()));
6963        },
6964
6965        get: function (idx) {
6966            return this[idx];
6967        },
6968
6969        join: __arrayProto.join,
6970
6971        includes: function (find) {
6972            return this.indexOf(find) === -1 ? false : true;
6973        },
6974
6975        indexOf: __arrayProto.indexOf,
6976
6977        iterator: function (flatten, type, fn, alwaysNew) {
6978            var
6979                a = [], ret,
6980                i, iLen, j, jen,
6981                context = this.context,
6982                rows, items, item,
6983                selector = this.selector;
6984
6985            // Argument shifting
6986            if (typeof flatten === 'string') {
6987                alwaysNew = fn;
6988                fn = type;
6989                type = flatten;
6990                flatten = false;
vendor: 5,743 bytes, lines 6991-7186
6991            }
6992
6993            for (i = 0, iLen = context.length; i < iLen; i++) {
6994                var apiInst = new _Api(context[i]);
6995
6996                if (type === 'table') {
6997                    ret = fn.call(apiInst, context[i], i);
6998
6999                    if (ret !== undefined) {
7000                        a.push(ret);
7001                    }
7002                }
7003                else if (type === 'columns' || type === 'rows') {
7004                    // this has same length as context - one entry for each table
7005                    ret = fn.call(apiInst, context[i], this[i], i);
7006
7007                    if (ret !== undefined) {
7008                        a.push(ret);
7009                    }
7010                }
7011                else if (type === 'every' || type === 'column' || type === 'column-rows' || type === 'row' || type === 'cell') {
7012                    // columns and rows share the same structure.
7013                    // 'this' is an array of column indexes for each context
7014                    items = this[i];
7015
7016                    if (type === 'column-rows') {
7017                        rows = _selector_row_indexes(context[i], selector.opts);
7018                    }
7019
7020                    for (j = 0, jen = items.length; j < jen; j++) {
7021                        item = items[j];
7022
7023                        if (type === 'cell') {
7024                            ret = fn.call(apiInst, context[i], item.row, item.column, i, j);
7025                        }
7026                        else {
7027                            ret = fn.call(apiInst, context[i], item, i, j, rows);
7028                        }
7029
7030                        if (ret !== undefined) {
7031                            a.push(ret);
7032                        }
7033                    }
7034                }
7035            }
7036
7037            if (a.length || alwaysNew) {
7038                var api = new _Api(context, flatten ? a.concat.apply([], a) : a);
7039                var apiSelector = api.selector;
7040                apiSelector.rows = selector.rows;
7041                apiSelector.cols = selector.cols;
7042                apiSelector.opts = selector.opts;
7043                return api;
7044            }
7045            return this;
7046        },
7047
7048        lastIndexOf: __arrayProto.lastIndexOf,
7049
7050        length: 0,
7051
7052        map: function (fn) {
7053            var a = __arrayProto.map.call(this, fn, this);
7054
7055            return new _Api(this.context, a);
7056        },
7057
7058        pluck: function (prop) {
7059            var fn = DataTable.util.get(prop);
7060
7061            return this.map(function (el) {
7062                return fn(el);
7063            });
7064        },
7065
7066        pop: __arrayProto.pop,
7067
7068        push: __arrayProto.push,
7069
7070        reduce: __arrayProto.reduce,
7071
7072        reduceRight: __arrayProto.reduceRight,
7073
7074        reverse: __arrayProto.reverse,
7075
7076        // Object with rows, columns and opts
7077        selector: null,
7078
7079        shift: __arrayProto.shift,
7080
7081        slice: function () {
7082            return new _Api(this.context, this);
7083        },
7084
7085        sort: __arrayProto.sort,
7086
7087        splice: __arrayProto.splice,
7088
7089        toArray: function () {
7090            return __arrayProto.slice.call(this);
7091        },
7092
7093        to$: function () {
7094            return $(this);
7095        },
7096
7097        toJQuery: function () {
7098            return $(this);
7099        },
7100
7101        unique: function () {
7102            return new _Api(this.context, _unique(this.toArray()));
7103        },
7104
7105        unshift: __arrayProto.unshift
7106    });
7107
7108
7109    function _api_scope(scope, fn, struct) {
7110        return function () {
7111            var ret = fn.apply(scope || this, arguments);
7112
7113            // Method extension
7114            _Api.extend(ret, ret, struct.methodExt);
7115            return ret;
7116        };
7117    }
7118
7119    function _api_find(src, name) {
7120        for (var i = 0, iLen = src.length; i < iLen; i++) {
7121            if (src[i].name === name) {
7122                return src[i];
7123            }
7124        }
7125        return null;
7126    }
7127
7128    window.__apiStruct = __apiStruct;
7129
7130    _Api.extend = function (scope, obj, ext) {
7131        // Only extend API instances and static properties of the API
7132        if (!ext.length || !obj || (!(obj instanceof _Api) && !obj.__dt_wrapper)) {
7133            return;
7134        }
7135
7136        var
7137            i, iLen,
7138            struct;
7139
7140        for (i = 0, iLen = ext.length; i < iLen; i++) {
7141            struct = ext[i];
7142
7143            if (struct.name === '__proto__') {
7144                continue;
7145            }
7146
7147            // Value
7148            obj[struct.name] = struct.type === 'function' ?
7149                _api_scope(scope, struct.val, struct) :
7150                struct.type === 'object' ?
7151                    {} :
7152                    struct.val;
7153
7154            obj[struct.name].__dt_wrapper = true;
7155
7156            // Property extension
7157            _Api.extend(scope, obj[struct.name], struct.propExt);
7158        }
7159    };
7160
7161    //     [
7162    //       {
7163    //         name:      'data'                -- string   - Property name
7164    //         val:       function () {},       -- function - Api method (or undefined if just an object
7165    //         methodExt: [ ... ],              -- array    - Array of Api object definitions to extend the method result
7166    //         propExt:   [ ... ]               -- array    - Array of Api object definitions to extend the property
7167    //       },
7168    //       {
7169    //         name:     'row'
7170    //         val:       {},
7171    //         methodExt: [ ... ],
7172    //         propExt:   [
7173    //           {
7174    //             name:      'data'
7175    //             val:       function () {},
7176    //             methodExt: [ ... ],
7177    //             propExt:   [ ... ]
7178    //           },
7179    //           ...
7180    //         ]
7181    //       }
7182    //     ]
7183
7184
7185    _Api.register = _api_register = function (name, val) {
7186        if (Array.isArray(name)) {
7187            for (var j = 0, jen = name.length; j < jen; j++) {
7188                _Api.register(name[j], val);
7189            }
7190            return;
7191        }
7192
7193        var
7194            i, iLen,
7195            heir = name.split('.'),
7196            struct = __apiStruct,
7197            key, method;
7198
7199        for (i = 0, iLen = heir.length; i < iLen; i++) {
7200            method = heir[i].indexOf('()') !== -1;
7201            key = method ?
7202                heir[i].replace('()', '') :
7203                heir[i];
7204
7205            var src = _api_find(struct, key);
7206            if (!src) {
7207                src = {
7208                    name: key,
7209                    val: {},
7210                    methodExt: [],
7211                    propExt: [],
7212                    type: 'object'
7213                };
7214                struct.push(src);
7215            }
7216
7217            if (i === iLen - 1) {
7218                src.val = val;
7219                src.type = typeof val === 'function' ?
7220                    'function' :
7221                    $.isPlainObject(val) ?
7222                        'object' :
7223                        'other';
7224            }
7225            else {
7226                struct = method ?
7227                    src.methodExt :
7228                    src.propExt;
7229            }
7230        }
7231    };
7232
7233    _Api.registerPlural = _api_registerPlural = function (pluralName, singularName, val) {
7234        _Api.register(pluralName, val);
7235
7236        _Api.register(singularName, function () {
7237            var ret = val.apply(this, arguments);
7238
7239            if (ret === this) {
7240                // Returned item is the API instance that was passed in, return it
7241                return this;
7242            }
7243            else if (ret instanceof _Api) {
7244                // New API instance returned, want the value from the first item
7245                // in the returned array for the singular result.
7246                return ret.length ?
7247                    Array.isArray(ret[0]) ?
7248                        new _Api(ret.context, ret[0]) : // Array results are 'enhanced'
7249                        ret[0] :
7250                    undefined;
7251            }
7252
7253            // Non-API return - just fire it back
7254            return ret;
7255        });
7256    };
7257
7258
7259    /**
7260     * Selector for HTML tables. Apply the given selector to the give array of
7261     * DataTables settings objects.
7262     *
7263     * @param {string|integer} [selector] jQuery selector string or integer
7264     * @param  {array} Array of DataTables settings objects to be filtered
7265     * @return {array}
7266     * @ignore
7267     */
7268    var __table_selector = function (selector, a) {
7269        if (Array.isArray(selector)) {
7270            var result = [];
7271
7272            selector.forEach(function (sel) {
7273                var inner = __table_selector(sel, a);
7274
7275                _fnArrayApply(result, inner);
7276            });
7277
7278            return result.filter(function (item) {
7279                return item;
7280            });
7281        }
7282
7283        // Integer is used to pick out a table by index
7284        if (typeof selector === 'number') {
7285            return [a[selector]];
7286        }
7287
7288        // Perform a jQuery selector on the table nodes
7289        var nodes = a.map(function (el) {
7290            return el.nTable;
7291        });
7292
7293        return $(nodes)
7294            .filter(selector)
7295            .map(function () {
7296                // Need to translate back from the table node to the settings
7297                var idx = nodes.indexOf(this);
7298                return a[idx];
7299            })
7300            .toArray();
7301    };
7302
7303
7304
7305    /**
7306     * Context selector for the API's context (i.e. the tables the API instance
7307     * refers to.
7308     *
7309     * @name    DataTable.Api#tables
7310     * @param {string|integer} [selector] Selector to pick which tables the iterator
7311     *   should operate on. If not given, all tables in the current context are
7312     *   used. This can be given as a jQuery selector (for example `':gt(0)'`) to
7313     *   select multiple tables or as an integer to select a single table.
7314     * @returns {DataTable.Api} Returns a new API instance if a selector is given.
7315     */
7316    _api_register('tables()', function (selector) {
7317        // A new instance is created if there was a selector specified
7318        return selector !== undefined && selector !== null ?
7319            new _Api(__table_selector(selector, this.context)) :
7320            this;
7321    });
7322
7323
7324    _api_register('table()', function (selector) {
7325        var tables = this.tables(selector);
7326        var ctx = tables.context;
7327
7328        // Truncate to the first matched table
7329        return ctx.length ?
7330            new _Api(ctx[0]) :
7331            tables;
7332    });
7333
7334    // Common methods, combined to reduce size
7335    [
7336        ['nodes', 'node', 'nTable'],
7337        ['body', 'body', 'nTBody'],
7338        ['header', 'header', 'nTHead'],
7339        ['footer', 'footer', 'nTFoot'],
7340    ].forEach(function (item) {
7341        _api_registerPlural(
7342            'tables().' + item[0] + '()',
7343            'table().' + item[1] + '()',
7344            function () {
7345                return this.iterator('table', function (ctx) {
7346                    return ctx[item[2]];
7347                }, 1);
7348            }
7349        );
7350    });
7351
7352    // Structure methods
7353    [
7354        ['header', 'aoHeader'],
7355        ['footer', 'aoFooter'],
7356    ].forEach(function (item) {
7357        _api_register('table().' + item[0] + '.structure()', function (selector) {
7358            var indexes = this.columns(selector).indexes().flatten().toArray();
7359            var ctx = this.context[0];
7360            var structure = _fnHeaderLayout(ctx, ctx[item[1]], indexes);
7361
7362            // The structure is in column index order - but from this method we want the return to be
7363            // in the columns() selector API order. In order to do that we need to map from one form
7364            // to the other
7365            var orderedIndexes = indexes.slice().sort(function (a, b) {
7366                return a - b;
7367            });
7368
7369            return structure.map(function (row) {
7370                return indexes.map(function (colIdx) {
7371                    return row[orderedIndexes.indexOf(colIdx)];
7372                });
7373            });
7374        });
7375    });
7376
7377
7378    _api_registerPlural('tables().containers()', 'table().container()', function () {
7379        return this.iterator('table', function (ctx) {
7380            return ctx.nTableWrapper;
7381        }, 1);
7382    });
7383
7384    _api_register('tables().every()', function (fn) {
7385        var that = this;
7386
7387        return this.iterator('table', function (s, i) {
7388            fn.call(that.table(i), i);
7389        });
7390    });
7391
7392    _api_register('caption()', function (value, side) {
7393        var context = this.context;
7394
7395        // Getter - return existing node's content
7396        if (value === undefined) {
7397            var caption = context[0].captionNode;
7398
7399            return caption && context.length ?
7400                caption.innerHTML :
7401                null;
7402        }
7403
7404        return this.iterator('table', function (ctx) {
7405            var table = $(ctx.nTable);
7406            var caption = $(ctx.captionNode);
7407            var container = $(ctx.nTableWrapper);
7408
7409            // Create the node if it doesn't exist yet
7410            if (!caption.length) {
7411                caption = $('<caption/>').html(value);
7412                ctx.captionNode = caption[0];
7413
7414                // If side isn't set, we need to insert into the document to let the
7415                // CSS decide so we can read it back, otherwise there is no way to
7416                // know if the CSS would put it top or bottom for scrolling
7417                if (!side) {
7418                    table.prepend(caption);
7419
7420                    side = caption.css('caption-side');
7421                }
7422            }
7423
7424            caption.html(value);
7425
7426            if (side) {
7427                caption.css('caption-side', side);
7428                caption[0]._captionSide = side;
7429            }
7430
7431            if (container.find('div.dataTables_scroll').length) {
7432                var selector = (side === 'top' ? 'Head' : 'Foot');
7433
7434                container.find('div.dataTables_scroll' + selector + ' table').prepend(caption);
7435            }
7436            else {
7437                table.prepend(caption);
7438            }
7439        }, 1);
7440    });
7441
7442    _api_register('caption.node()', function () {
7443        var ctx = this.context;
7444
7445        return ctx.length ? ctx[0].captionNode : null;
7446    });
7447
7448
7449    /**
7450     * Redraw the tables in the current context.
7451     */
7452    _api_register('draw()', function (paging) {
7453        return this.iterator('table', function (settings) {
7454            if (paging === 'page') {
7455                _fnDraw(settings);
7456            }
7457            else {
7458                if (typeof paging === 'string') {
7459                    paging = paging === 'full-hold' ?
7460                        false :
7461                        true;
7462                }
7463
7464                _fnReDraw(settings, paging === false);
7465            }
7466        });
7467    });
7468
7469
7470
7471    /**
7472     * Get the current page index.
7473     *
7474     * @return {integer} Current page index (zero based)
7475     *//**
7476    * Set the current page.
7477    *
7478    * Note that if you attempt to show a page which does not exist, DataTables will
7479    * not throw an error, but rather reset the paging.
7480    *
7481    * @param {integer|string} action The paging action to take. This can be one of:
vendor: 8,952 bytes, lines 7482-7762
7482    *  * `integer` - The page index to jump to
7483    *  * `string` - An action to take:
7484    *    * `first` - Jump to first page.
7485    *    * `next` - Jump to the next page
7486    *    * `previous` - Jump to previous page
7487    *    * `last` - Jump to the last page.
7488    * @returns {DataTables.Api} this
7489    */
7490    _api_register('page()', function (action) {
7491        if (action === undefined) {
7492            return this.page.info().page; // not an expensive call
7493        }
7494
7495        // else, have an action to take on all tables
7496        return this.iterator('table', function (settings) {
7497            _fnPageChange(settings, action);
7498        });
7499    });
7500
7501
7502    /**
7503     * Paging information for the first table in the current context.
7504     *
7505     * If you require paging information for another table, use the `table()` method
7506     * with a suitable selector.
7507     *
7508     * @return {object} Object with the following properties set:
7509     *  * `page` - Current page index (zero based - i.e. the first page is `0`)
7510     *  * `pages` - Total number of pages
7511     *  * `start` - Display index for the first record shown on the current page
7512     *  * `end` - Display index for the last record shown on the current page
7513     *  * `length` - Display length (number of records). Note that generally `start
7514     *    + length = end`, but this is not always true, for example if there are
7515     *    only 2 records to show on the final page, with a length of 10.
7516     *  * `recordsTotal` - Full data set length
7517     *  * `recordsDisplay` - Data set length once the current filtering criterion
7518     *    are applied.
7519     */
7520    _api_register('page.info()', function () {
7521        if (this.context.length === 0) {
7522            return undefined;
7523        }
7524
7525        var
7526            settings = this.context[0],
7527            start = settings._iDisplayStart,
7528            len = settings.oFeatures.bPaginate ? settings._iDisplayLength : -1,
7529            visRecords = settings.fnRecordsDisplay(),
7530            all = len === -1;
7531
7532        return {
7533            "page": all ? 0 : Math.floor(start / len),
7534            "pages": all ? 1 : Math.ceil(visRecords / len),
7535            "start": start,
7536            "end": settings.fnDisplayEnd(),
7537            "length": len,
7538            "recordsTotal": settings.fnRecordsTotal(),
7539            "recordsDisplay": visRecords,
7540            "serverSide": _fnDataSource(settings) === 'ssp'
7541        };
7542    });
7543
7544
7545    /**
7546     * Get the current page length.
7547     *
7548     * @return {integer} Current page length. Note `-1` indicates that all records
7549     *   are to be shown.
7550     *//**
7551    * Set the current page length.
7552    *
7553    * @param {integer} Page length to set. Use `-1` to show all records.
7554    * @returns {DataTables.Api} this
7555    */
7556    _api_register('page.len()', function (len) {
7557        // Note that we can't call this function 'length()' because `length`
7558        // is a JavaScript property of functions which defines how many arguments
7559        // the function expects.
7560        if (len === undefined) {
7561            return this.context.length !== 0 ?
7562                this.context[0]._iDisplayLength :
7563                undefined;
7564        }
7565
7566        // else, set the page length
7567        return this.iterator('table', function (settings) {
7568            _fnLengthChange(settings, len);
7569        });
7570    });
7571
7572
7573
7574    var __reload = function (settings, holdPosition, callback) {
7575        // Use the draw event to trigger a callback
7576        if (callback) {
7577            var api = new _Api(settings);
7578
7579            api.one('draw', function () {
7580                callback(api.ajax.json());
7581            });
7582        }
7583
7584        if (_fnDataSource(settings) == 'ssp') {
7585            _fnReDraw(settings, holdPosition);
7586        }
7587        else {
7588            _fnProcessingDisplay(settings, true);
7589
7590            // Cancel an existing request
7591            var xhr = settings.jqXHR;
7592            if (xhr && xhr.readyState !== 4) {
7593                xhr.abort();
7594            }
7595
7596            // Trigger xhr
7597            _fnBuildAjax(settings, {}, function (json) {
7598                _fnClearTable(settings);
7599
7600                var data = _fnAjaxDataSrc(settings, json);
7601                for (var i = 0, iLen = data.length; i < iLen; i++) {
7602                    _fnAddData(settings, data[i]);
7603                }
7604
7605                _fnReDraw(settings, holdPosition);
7606                _fnInitComplete(settings);
7607                _fnProcessingDisplay(settings, false);
7608            });
7609        }
7610    };
7611
7612
7613    /**
7614     * Get the JSON response from the last Ajax request that DataTables made to the
7615     * server. Note that this returns the JSON from the first table in the current
7616     * context.
7617     *
7618     * @return {object} JSON received from the server.
7619     */
7620    _api_register('ajax.json()', function () {
7621        var ctx = this.context;
7622
7623        if (ctx.length > 0) {
7624            return ctx[0].json;
7625        }
7626
7627        // else return undefined;
7628    });
7629
7630
7631    /**
7632     * Get the data submitted in the last Ajax request
7633     */
7634    _api_register('ajax.params()', function () {
7635        var ctx = this.context;
7636
7637        if (ctx.length > 0) {
7638            return ctx[0].oAjaxData;
7639        }
7640
7641        // else return undefined;
7642    });
7643
7644
7645    /**
7646     * Reload tables from the Ajax data source. Note that this function will
7647     * automatically re-draw the table when the remote data has been loaded.
7648     *
7649     * @param {boolean} [reset=true] Reset (default) or hold the current paging
7650     *   position. A full re-sort and re-filter is performed when this method is
7651     *   called, which is why the pagination reset is the default action.
7652     * @returns {DataTables.Api} this
7653     */
7654    _api_register('ajax.reload()', function (callback, resetPaging) {
7655        return this.iterator('table', function (settings) {
7656            __reload(settings, resetPaging === false, callback);
7657        });
7658    });
7659
7660
7661    /**
7662     * Get the current Ajax URL. Note that this returns the URL from the first
7663     * table in the current context.
7664     *
7665     * @return {string} Current Ajax source URL
7666     *//**
7667    * Set the Ajax URL. Note that this will set the URL for all tables in the
7668    * current context.
7669    *
7670    * @param {string} url URL to set.
7671    * @returns {DataTables.Api} this
7672    */
7673    _api_register('ajax.url()', function (url) {
7674        var ctx = this.context;
7675
7676        if (url === undefined) {
7677            // get
7678            if (ctx.length === 0) {
7679                return undefined;
7680            }
7681            ctx = ctx[0];
7682
7683            return $.isPlainObject(ctx.ajax) ?
7684                ctx.ajax.url :
7685                ctx.ajax;
7686        }
7687
7688        // set
7689        return this.iterator('table', function (settings) {
7690            if ($.isPlainObject(settings.ajax)) {
7691                settings.ajax.url = url;
7692            }
7693            else {
7694                settings.ajax = url;
7695            }
7696        });
7697    });
7698
7699
7700    /**
7701     * Load data from the newly set Ajax URL. Note that this method is only
7702     * available when `ajax.url()` is used to set a URL. Additionally, this method
7703     * has the same effect as calling `ajax.reload()` but is provided for
7704     * convenience when setting a new URL. Like `ajax.reload()` it will
7705     * automatically redraw the table once the remote data has been loaded.
7706     *
7707     * @returns {DataTables.Api} this
7708     */
7709    _api_register('ajax.url().load()', function (callback, resetPaging) {
7710        // Same as a reload, but makes sense to present it for easy access after a
7711        // url change
7712        return this.iterator('table', function (ctx) {
7713            __reload(ctx, resetPaging === false, callback);
7714        });
7715    });
7716
7717
7718
7719
7720    var _selector_run = function (type, selector, selectFn, settings, opts) {
7721        var
7722            out = [], res,
7723            i, iLen,
7724            selectorType = typeof selector;
7725
7726        // Can't just check for isArray here, as an API or jQuery instance might be
7727        // given with their array like look
7728        if (!selector || selectorType === 'string' || selectorType === 'function' || selector.length === undefined) {
7729            selector = [selector];
7730        }
7731
7732        for (i = 0, iLen = selector.length; i < iLen; i++) {
7733            res = selectFn(typeof selector[i] === 'string' ? selector[i].trim() : selector[i]);
7734
7735            // Remove empty items
7736            res = res.filter(function (item) {
7737                return item !== null && item !== undefined;
7738            });
7739
7740            if (res && res.length) {
7741                out = out.concat(res);
7742            }
7743        }
7744
7745        // selector extensions
7746        var ext = _ext.selector[type];
7747        if (ext.length) {
7748            for (i = 0, iLen = ext.length; i < iLen; i++) {
7749                out = ext[i](settings, opts, out);
7750            }
7751        }
7752
7753        return _unique(out);
7754    };
7755
7756
7757    var _selector_opts = function (opts) {
7758        if (!opts) {
7759            opts = {};
7760        }
7761
7762        // Backwards compatibility for 1.9- which used the terminology f
7762ilter rather
7763        // than search
7764        if (opts.filter && opts.search === undefined) {
7765            opts.search = opts.filter;
7766        }
7767
7768        return $.extend({
7769            columnOrder: 'implied',
7770            search: 'none',
7771            order: 'current',
7772            page: 'all'
7773        }, opts);
7774    };
7775
7776
7777    // Reduce the API instance to the first item found
7778    var _selector_first = function (old) {
7779        var inst = new _Api(old.context[0]);
7780
7781        // Use a push rather than passing to the constructor, since it will
7782        // merge arrays down automatically, which isn't what is wanted here
7783        if (old.length) {
7784            inst.push(old[0]);
7785        }
7786
7787        inst.selector = old.selector;
7788
7789        // Limit to a single row / column / cell
7790        if (inst.length && inst[0].length > 1) {
7791            inst[0].splice(1);
7792        }
7793
7794        return inst;
7795    };
7796
7797
7798    var _selector_row_indexes = function (settings, opts) {
7799        var
7800            i, iLen, tmp, a = [],
7801            displayFiltered = settings.aiDisplay,
7802            displayMaster = settings.aiDisplayMaster;
7803
7804        var
7805            search = opts.search,  // none, applied, removed
7806            order = opts.order,   // applied, current, index (original - compatibility with 1.9)
7807            page = opts.page;    // all, current
7808
7809        if (_fnDataSource(settings) == 'ssp') {
7810            // In server-side processing mode, most options are irrelevant since
7811            // rows not shown don't exist and the index order is the applied order
7812            // Removed is a special case - for consistency just return an empty
7813            // array
7814            return search === 'removed' ?
7815                [] :
7816                _range(0, displayMaster.length);
7817        }
7818
7819        if (page == 'current') {
7820            // Current page implies that order=current and filter=applied, since it is
7821            // fairly senseless otherwise, regardless of what order and search actually
7822            // are
7823            for (i = settings._iDisplayStart, iLen = settings.fnDisplayEnd(); i < iLen; i++) {
7824                a.push(displayFiltered[i]);
7825            }
7826        }
7827        else if (order == 'current' || order == 'applied') {
7828            if (search == 'none') {
7829                a = displayMaster.slice();
7830            }
7831            else if (search == 'applied') {
7832                a = displayFiltered.slice();
7833            }
7834            else if (search == 'removed') {
7835                // O(n+m) solution by creating a hash map
7836                var displayFilteredMap = {};
7837
7838                for (i = 0, iLen = displayFiltered.length; i < iLen; i++) {
7839                    displayFilteredMap[displayFiltered[i]] = null;
7840                }
7841
7842                displayMaster.forEach(function (item) {
7843                    if (!Object.prototype.hasOwnProperty.call(displayFilteredMap, item)) {
7844                        a.push(item);
7845                    }
7846                });
7847            }
7848        }
7849        else if (order == 'index' || order == 'original') {
7850            for (i = 0, iLen = settings.aoData.length; i < iLen; i++) {
7851                if (!settings.aoData[i]) {
7852                    continue;
7853                }
7854
7855                if (search == 'none') {
7856                    a.push(i);
7857                }
7858                else { // applied | removed
7859                    tmp = displayFiltered.indexOf(i);
7860
7861                    if ((tmp === -1 && search == 'removed') ||
7862                        (tmp >= 0 && search == 'applied')) {
7863                        a.push(i);
7864                    }
7865                }
7866            }
7867        }
7868        else if (typeof order === 'number') {
7869            // Order the rows by the given column
7870            var ordered = _fnSort(settings, order, 'asc');
7871
7872            if (search === 'none') {
7873                a = ordered;
7874            }
7875            else { // applied | removed
7876                for (i = 0; i < ordered.length; i++) {
7877                    tmp = displayFiltered.indexOf(ordered[i]);
7878
7879                    if ((tmp === -1 && search == 'removed') ||
7880                        (tmp >= 0 && search == 'applied')) {
7881                        a.push(ordered[i]);
7882                    }
7883                }
7884            }
7885        }
7886
7887        return a;
7888    };
7889
7890
7891    /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
7892     * Rows
7893     *
7894     * {}          - no selector - use all available rows
7895     * {integer}   - row aoData index
7896     * {node}      - TR node
7897     * {string}    - jQuery selector to apply to the TR elements
7898     * {array}     - jQuery array of nodes, or simply an array of TR nodes
7899     *
7900     */
7901    var __row_selector = function (settings, selector, opts) {
7902        var rows;
7903        var run = function (sel) {
7904            var selInt = _intVal(sel);
7905            var aoData = settings.aoData;
7906
7907            // Short cut - selector is a number and no options provided (default is
7908            // all records, so no need to check if the index is in there, since it
7909            // must be - dev error if the index doesn't exist).
7910            if (selInt !== null && !opts) {
7911                return [selInt];
7912            }
7913
7914            if (!rows) {
7915                rows = _selector_row_indexes(settings, opts);
7916            }
7917
7918            if (selInt !== null && rows.indexOf(selInt) !== -1) {
7919                // Selector - integer
7920                return [selInt];
7921            }
7922            else if (sel === null || sel === undefined || sel === '') {
7923                // Selector - none
7924                return rows;
7925            }
7926
7927            // Selector - function
7928            if (typeof sel === 'function') {
7929                return rows.map(function (idx) {
7930                    var row = aoData[idx];
7931                    return sel(idx, row._aData, row.nTr) ? idx : null;
7932                });
7933            }
7934
7935            // Selector - node
7936            if (sel.nodeName) {
7937                var rowIdx = sel._DT_RowIndex;  // Property added by DT for fast lookup
7938                var cellIdx = sel._DT_CellIndex;
7939
7940                if (rowIdx !== undefined) {
7941                    // Make sure that the row is actually still present in the table
7942                    return aoData[rowIdx] && aoData[rowIdx].nTr === sel ?
7943                        [rowIdx] :
7944                        [];
7945                }
7946                else if (cellIdx) {
7947                    return aoData[cellIdx.row] && aoData[cellIdx.row].nTr === sel.parentNode ?
7948                        [cellIdx.row] :
7949                        [];
7950                }
7951                else {
7952                    var host = $(sel).closest('*[data-dt-row]');
7953                    return host.length ?
7954                        [host.data('dt-row')] :
7955                        [];
7956                }
7957            }
7958
7959            // ID selector. Want to always be able to select rows by id, regardless
7960            // of if the tr element has been created or not, so can't rely upon
7961            // jQuery here - hence a custom implementation. This does not match
7962            // Sizzle's fast selector or HTML4 - in HTML5 the ID can be anything,
7963            // but to select it using a CSS selector engine (like Sizzle or
7964            // querySelect) it would need to need to be escaped for some characters.
7965            // DataTables simplifies this for row selectors since you can select
7966            // only a row. A # indicates an id any anything that follows is the id -
7967            // unescaped.
7968            if (typeof sel === 'string' && sel.charAt(0) === '#') {
7969                // get row index from id
7970                var rowObj = settings.aIds[sel.replace(/^#/, '')];
7971                if (rowObj !== undefined) {
7972                    return [rowObj.idx];
7973                }
7974
7975                // need to fall through to jQuery in case there is DOM id that
7976                // matches
7977            }
7978
7979            // Get nodes in the order from the `rows` array with 
vendor: 13,430 bytes, lines 7979-8417
7979null values removed
7980            var nodes = _removeEmpty(
7981                _pluck_order(settings.aoData, rows, 'nTr')
7982            );
7983
7984            // Selector - jQuery selector string, array of nodes or jQuery object/
7985            // As jQuery's .filter() allows jQuery objects to be passed in filter,
7986            // it also allows arrays, so this will cope with all three options
7987            return $(nodes)
7988                .filter(sel)
7989                .map(function () {
7990                    return this._DT_RowIndex;
7991                })
7992                .toArray();
7993        };
7994
7995        var matched = _selector_run('row', selector, run, settings, opts);
7996
7997        if (opts.order === 'current' || opts.order === 'applied') {
7998            _fnSortDisplay(settings, matched);
7999        }
8000
8001        return matched;
8002    };
8003
8004
8005    _api_register('rows()', function (selector, opts) {
8006        // argument shifting
8007        if (selector === undefined) {
8008            selector = '';
8009        }
8010        else if ($.isPlainObject(selector)) {
8011            opts = selector;
8012            selector = '';
8013        }
8014
8015        opts = _selector_opts(opts);
8016
8017        var inst = this.iterator('table', function (settings) {
8018            return __row_selector(settings, selector, opts);
8019        }, 1);
8020
8021        // Want argument shifting here and in __row_selector?
8022        inst.selector.rows = selector;
8023        inst.selector.opts = opts;
8024
8025        return inst;
8026    });
8027
8028    _api_register('rows().nodes()', function () {
8029        return this.iterator('row', function (settings, row) {
8030            return settings.aoData[row].nTr || undefined;
8031        }, 1);
8032    });
8033
8034    _api_register('rows().data()', function () {
8035        return this.iterator(true, 'rows', function (settings, rows) {
8036            return _pluck_order(settings.aoData, rows, '_aData');
8037        }, 1);
8038    });
8039
8040    _api_registerPlural('rows().cache()', 'row().cache()', function (type) {
8041        return this.iterator('row', function (settings, row) {
8042            var r = settings.aoData[row];
8043            return type === 'search' ? r._aFilterData : r._aSortData;
8044        }, 1);
8045    });
8046
8047    _api_registerPlural('rows().invalidate()', 'row().invalidate()', function (src) {
8048        return this.iterator('row', function (settings, row) {
8049            _fnInvalidate(settings, row, src);
8050        });
8051    });
8052
8053    _api_registerPlural('rows().indexes()', 'row().index()', function () {
8054        return this.iterator('row', function (settings, row) {
8055            return row;
8056        }, 1);
8057    });
8058
8059    _api_registerPlural('rows().ids()', 'row().id()', function (hash) {
8060        var a = [];
8061        var context = this.context;
8062
8063        // `iterator` will drop undefined values, but in this case we want them
8064        for (var i = 0, iLen = context.length; i < iLen; i++) {
8065            for (var j = 0, jen = this[i].length; j < jen; j++) {
8066                var id = context[i].rowIdFn(context[i].aoData[this[i][j]]._aData);
8067                a.push((hash === true ? '#' : '') + id);
8068            }
8069        }
8070
8071        return new _Api(context, a);
8072    });
8073
8074    _api_registerPlural('rows().remove()', 'row().remove()', function () {
8075        this.iterator('row', function (settings, row) {
8076            var data = settings.aoData;
8077            var rowData = data[row];
8078
8079            // Delete from the display arrays
8080            var idx = settings.aiDisplayMaster.indexOf(row);
8081            if (idx !== -1) {
8082                settings.aiDisplayMaster.splice(idx, 1);
8083            }
8084
8085            // For server-side processing tables - subtract the deleted row from the count
8086            if (settings._iRecordsDisplay > 0) {
8087                settings._iRecordsDisplay--;
8088            }
8089
8090            // Check for an 'overflow' they case for displaying the table
8091            _fnLengthOverflow(settings);
8092
8093            // Remove the row's ID reference if there is one
8094            var id = settings.rowIdFn(rowData._aData);
8095            if (id !== undefined) {
8096                delete settings.aIds[id];
8097            }
8098
8099            data[row] = null;
8100        });
8101
8102        return this;
8103    });
8104
8105
8106    _api_register('rows.add()', function (rows) {
8107        var newRows = this.iterator('table', function (settings) {
8108            var row, i, iLen;
8109            var out = [];
8110
8111            for (i = 0, iLen = rows.length; i < iLen; i++) {
8112                row = rows[i];
8113
8114                if (row.nodeName && row.nodeName.toUpperCase() === 'TR') {
8115                    out.push(_fnAddTr(settings, row)[0]);
8116                }
8117                else {
8118                    out.push(_fnAddData(settings, row));
8119                }
8120            }
8121
8122            return out;
8123        }, 1);
8124
8125        // Return an Api.rows() extended instance, so rows().nodes() etc can be used
8126        var modRows = this.rows(-1);
8127        modRows.pop();
8128        _fnArrayApply(modRows, newRows);
8129
8130        return modRows;
8131    });
8132
8133
8134
8135
8136
8137    /**
8138     *
8139     */
8140    _api_register('row()', function (selector, opts) {
8141        return _selector_first(this.rows(selector, opts));
8142    });
8143
8144
8145    _api_register('row().data()', function (data) {
8146        var ctx = this.context;
8147
8148        if (data === undefined) {
8149            // Get
8150            return ctx.length && this.length && this[0].length ?
8151                ctx[0].aoData[this[0]]._aData :
8152                undefined;
8153        }
8154
8155        // Set
8156        var row = ctx[0].aoData[this[0]];
8157        row._aData = data;
8158
8159        // If the DOM has an id, and the data source is an array
8160        if (Array.isArray(data) && row.nTr && row.nTr.id) {
8161            _fnSetObjectDataFn(ctx[0].rowId)(data, row.nTr.id);
8162        }
8163
8164        // Automatically invalidate
8165        _fnInvalidate(ctx[0], this[0], 'data');
8166
8167        return this;
8168    });
8169
8170
8171    _api_register('row().node()', function () {
8172        var ctx = this.context;
8173
8174        if (ctx.length && this.length && this[0].length) {
8175            var row = ctx[0].aoData[this[0]];
8176
8177            if (row && row.nTr) {
8178                return row.nTr;
8179            }
8180        }
8181
8182        return null;
8183    });
8184
8185
8186    _api_register('row.add()', function (row) {
8187        // Allow a jQuery object to be passed in - only a single row is added from
8188        // it though - the first element in the set
8189        if (row instanceof $ && row.length) {
8190            row = row[0];
8191        }
8192
8193        var rows = this.iterator('table', function (settings) {
8194            if (row.nodeName && row.nodeName.toUpperCase() === 'TR') {
8195                return _fnAddTr(settings, row)[0];
8196            }
8197            return _fnAddData(settings, row);
8198        });
8199
8200        // Return an Api.rows() extended instance, with the newly added row selected
8201        return this.row(rows[0]);
8202    });
8203
8204
8205    $(document).on('plugin-init.dt', function (e, context) {
8206        var api = new _Api(context);
8207
8208        api.on('stateSaveParams.DT', function (e, settings, d) {
8209            // This could be more compact with the API, but it is a lot faster as a simple
8210            // internal loop
8211            var idFn = settings.rowIdFn;
8212            var rows = settings.aiDisplayMaster;
8213            var ids = [];
8214
8215            for (var i = 0; i < rows.length; i++) {
8216                var rowIdx = rows[i];
8217                var data = settings.aoData[rowIdx];
8218
8219                if (data._detailsShow) {
8220                    ids.push('#' + idFn(data._aData));
8221                }
8222            }
8223
8224            d.childRows = ids;
8225        });
8226
8227        // For future state loads (e.g. with StateRestore)
8228        api.on('stateLoaded.DT', function (e, settings, state) {
8229            __details_state_load(api, state);
8230        });
8231
8232        // And the initial load state
8233        __details_state_load(api, api.state.loaded());
8234    });
8235
8236    var __details_state_load = function (api, state) {
8237        if (state && state.childRows) {
8238            api
8239                .rows(state.childRows.map(function (id) {
8240                    // Escape any `:` characters from the row id. Accounts for
8241                    // already escaped characters.
8242                    return id.replace(/([^:\\]*(?:\\.[^:\\]*)*):/g, "$1\\:");
8243                }))
8244                .every(function () {
8245                    _fnCallbackFire(api.settings()[0], null, 'requestChild', [this])
8246                });
8247        }
8248    }
8249
8250    var __details_add = function (ctx, row, data, klass) {
8251        // Convert to array of TR elements
8252        var rows = [];
8253        var addRow = function (r, k) {
8254            // Recursion to allow for arrays of jQuery objects
8255            if (Array.isArray(r) || r instanceof $) {
8256                for (var i = 0, iLen = r.length; i < iLen; i++) {
8257                    addRow(r[i], k);
8258                }
8259                return;
8260            }
8261
8262            // If we get a TR element, then just add it directly - up to the dev
8263            // to add the correct number of columns etc
8264            if (r.nodeName && r.nodeName.toLowerCase() === 'tr') {
8265                r.setAttribute('data-dt-row', row.idx);
8266                rows.push(r);
8267            }
8268            else {
8269                // Otherwise create a row with a wrapper
8270                var created = $('<tr><td></td></tr>')
8271                    .attr('data-dt-row', row.idx)
8272                    .addClass(k);
8273
8274                $('td', created)
8275                    .addClass(k)
8276                    .html(r)[0].colSpan = _fnVisibleColumns(ctx);
8277
8278                rows.push(created[0]);
8279            }
8280        };
8281
8282        addRow(data, klass);
8283
8284        if (row._details) {
8285            row._details.detach();
8286        }
8287
8288        row._details = $(rows);
8289
8290        // If the children were already shown, that state should be retained
8291        if (row._detailsShow) {
8292            row._details.insertAfter(row.nTr);
8293        }
8294    };
8295
8296
8297    // Make state saving of child row details async to allow them to be batch processed
8298    var __details_state = DataTable.util.throttle(
8299        function (ctx) {
8300            _fnSaveState(ctx[0])
8301        },
8302        500
8303    );
8304
8305
8306    var __details_remove = function (api, idx) {
8307        var ctx = api.context;
8308
8309        if (ctx.length) {
8310            var row = ctx[0].aoData[idx !== undefined ? idx : api[0]];
8311
8312            if (row && row._details) {
8313                row._details.detach();
8314
8315                row._detailsShow = undefined;
8316                row._details = undefined;
8317                $(row.nTr).removeClass('dt-hasChild');
8318                __details_state(ctx);
8319            }
8320        }
8321    };
8322
8323
8324    var __details_display = function (api, show) {
8325        var ctx = api.context;
8326
8327        if (ctx.length && api.length) {
8328            var row = ctx[0].aoData[api[0]];
8329
8330            if (row._details) {
8331                row._detailsShow = show;
8332
8333                if (show) {
8334                    row._details.insertAfter(row.nTr);
8335                    $(row.nTr).addClass('dt-hasChild');
8336                }
8337                else {
8338                    row._details.detach();
8339                    $(row.nTr).removeClass('dt-hasChild');
8340                }
8341
8342                _fnCallbackFire(ctx[0], null, 'childRow', [show, api.row(api[0])])
8343
8344                __details_events(ctx[0]);
8345                __details_state(ctx);
8346            }
8347        }
8348    };
8349
8350
8351    var __details_events = function (settings) {
8352        var api = new _Api(settings);
8353        var namespace = '.dt.DT_details';
8354        var drawEvent = 'draw' + namespace;
8355        var colvisEvent = 'column-sizing' + namespace;
8356        var destroyEvent = 'destroy' + namespace;
8357        var data = settings.aoData;
8358
8359        api.off(drawEvent + ' ' + colvisEvent + ' ' + destroyEvent);
8360
8361        if (_pluck(data, '_details').length > 0) {
8362            // On each draw, insert the required elements into the document
8363            api.on(drawEvent, function (e, ctx) {
8364                if (settings !== ctx) {
8365                    return;
8366                }
8367
8368                api.rows({ page: 'current' }).eq(0).each(function (idx) {
8369                    // Internal data grab
8370                    var row = data[idx];
8371
8372                    if (row._detailsShow) {
8373                        row._details.insertAfter(row.nTr);
8374                    }
8375                });
8376            });
8377
8378            // Column visibility change - update the colspan
8379            api.on(colvisEvent, function (e, ctx) {
8380                if (settings !== ctx) {
8381                    return;
8382                }
8383
8384                // Update the colspan for the details rows (note, only if it already has
8385                // a colspan)
8386                var row, visible = _fnVisibleColumns(ctx);
8387
8388                for (var i = 0, iLen = data.length; i < iLen; i++) {
8389                    row = data[i];
8390
8391                    if (row && row._details) {
8392                        row._details.each(function () {
8393                            var el = $(this).children('td');
8394
8395                            if (el.length == 1) {
8396                                el.attr('colspan', visible);
8397                            }
8398                        });
8399                    }
8400                }
8401            });
8402
8403            // Table destroyed - nuke any child rows
8404            api.on(destroyEvent, function (e, ctx) {
8405                if (settings !== ctx) {
8406                    return;
8407                }
8408
8409                for (var i = 0, iLen = data.length; i < iLen; i++) {
8410                    if (data[i] && data[i]._details) {
8411                        __details_remove(api, i);
8412                    }
8413                }
8414            });
8415        }
8416    };
8417
8418    // Strings for the method names to help minification
8419    var _emp = '';
8420    var _child_obj = _emp + 'row().child';
8421    var _child_mth = _child_obj + '()';
8422
8423    // data can be:
8424    //  tr
8425    //  string
8426    //  jQuery or array of any of the above
8427    _api_register(_child_mth, function (data, klass) {
8428        var ctx = this.context;
8429
8430        if (data === undefined) {
8431            // get
8432            return ctx.length && this.length && ctx[0].aoData[this[0]]
8433                ? ctx[0].aoData[this[0]]._details
8434                : undefined;
8435        }
8436        else if (data === true) {
8437            // show
8438            this.child.show();
8439        }
8440        else if (data === false) {
8441            // remove
8442            __details_remove(this);
8443        }
8444        else if (ctx.length && this.length) {
8445            // set
8446            __details_add(ctx[0], ctx[0].aoData[this[0]], data, klass);
8447        }
8448
8449        return this;
8450    });
8451
8452
8453    _api_register([
8454        _child_obj + '.show()',
8455        _child_mth + '.show()' // only when `child()` was called with parameters (without
8456    ], function () {         // it returns an object and this method is not executed)
8457        __details_display(this, true);
8458        return this;
8459    });
8460
8461
8462    _api_register([
8463        _child_obj + '.hide()',
8464        _child_mth + '.hide()' // only when `child()` was called with parameters (without
8465    ], function () {         // it returns an object and this method is not executed)
8466        __details_display(this, false);
8467        return this;
8468    });
8469
8470
8471    _api_register([
8472        _child_obj + '.remove()',
8473        _child_mth + '.remove()' // only when `child()` was called with parameters (without
8474    ], function () {           // it returns an object and this method is not executed)
8475        __details_remove(this);
8476        return this;
8477    });
8478
8479
8480    _api_register(_child_obj + '.isShown()', function () {
8481        var ctx = this.context;
8482
8483        if (ctx.length && this.length && ctx[0].aoData[this[0]]) {
8484            // _detailsShown as false or undefined will fall through to return false
8485            return ctx[0].aoData[this[0]]._detailsShow || false;
8486        }
8487        return false;
8488    });
8489
8490
8491
8492    /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
8493     * Columns
8494     *
8495     * {integer}           - column index (>=0 count from left, <0 count from right)
8496     * "{integer}:visIdx"  - visible column index (i.e. translate to column index)  (>=0 count from left, <0 count from right)
8497     * "{integer}:visible" - alias for {integer}:visIdx  (>=0 count from left, <0 count from right)
8498     * "{string}:name"     - column name
8499     * "{string}"          - jQuery selector on column header nodes
8500     *
8501     */
8502
8503    // can be an array of these items, comma separated list, or an array of comma
8504    // separated lists
8505
8506    var __re_column_selector = /^([^:]+)?:(name|title|visIdx|visible)$/;
8507
8508
8509    // r1 and r2 are redundant - but it means that the parameters match for the
8510    // iterator callback in columns().data()
8511    var __columnData = function (settings, column, r1, r2, rows, type) {
8512        var a = [];
8513        for (var row = 0, iLen = rows.length; row < iLen; row++) {
8514            a.push(_fnGetCellData(settings, rows[row], column, type));
8515        }
8516        return a;
8517    };
8518
8519
8520    var __column_header = function (settings, column, row) {
8521        var header = settings.aoHeader;
8522        var titleRow = settings.titleRow;
8523        var target = null;
8524
8525        if (row !== undefined) {
8526            target = row;
8527        }
8528        else if (titleRow === true) { // legacy orderCellsTop support
8529            target = 0;
8530        }
8531        else if (titleRow === false) {
8532            target = header.length - 1;
8533        }
8534        else if (titleRow !== null) {
8535            target = titleRow;
8536        }
8537        else {
8538            // Automatic - find the _last_ unique cell from the top that is not empty (last for
8539            // backwards compatibility)
8540            for (var i = 0; i < header.length; i++) {
8541                if (header[i][column].unique && $('span.dt-column-title', header[i][column].cell).text()) {
8542                    target = i;
8543                }
8544            }
8545
8546            if (target === null) {
8547                target = 0;
8548            }
8549        }
8550
8551        return header[target][column].cell;
8552    };
8553
8554    var __column_header_cells = function (header) {
8555        var out = [];
8556
8557        for (var i = 0; i < header.length; i++) {
8558            for (var j = 0; j < header[i].length; j++) {
8559                var cell = header[i][j].cell;
8560
8561                if (!out.includes(cell)) {
8562                    out.push(cell);
8563                }
8564            }
8565        }
8566
8567        return out;
8568    }
8569
8570    var __column_selector = function (settings, selector, opts) {
8571        var
8572            columns = settings.aoColumns,
8573            names, titles,
8574            nodes = __column_header_cells(settings.aoHeader);
8575
8576        var run = function (s) {
8577            var selInt = _intVal(s);
8578
8579            // Selector - all
8580            if (s === '') {
8581                return _range(columns.length);
8582            }
8583
8584            // Selector - index
8585            if (selInt !== null) {
8586                return [selInt >= 0 ?
8587                    selInt : // Count from left
8588                    columns.length + selInt // Count from right (+ because its a negative value)
8589                ];
8590            }
8591
8592            // Selector = function
8593            if (typeof s === 'function') {
8594                var rows = _selector_row_indexes(settings, opts);
8595
8596                return columns.map(function (col, idx) {
8597                    return s(
8598                        idx,
8599                        __columnData(settings, idx, 0, 0, rows),
8600                        __column_header(settings, idx)
8601                    ) ? idx : null;
8602                });
8603            }
8604
8605            // jQuery or string selector
8606            var match = typeof s === 'string' ?
8607                s.match(__re_column_selector) :
8608                '';
8609
8610            if (match) {
8611                switch (match[2]) {
8612                    case 'visIdx':
8613                    case 'visible':
8614                        // Selector is a column index
8615                        if (match[1] && match[1].match(/^\d+$/)) {
8616                            var idx = parseInt(match[1], 10);
8617
8618                            // Visible index given, convert to column index
8619                            if (idx < 0) {
8620                                // Counting from the right
8621                                var visColumns = columns.map(function (col, i) {
8622                                    return col.bVisible ? i : null;
8623                                });
8624                                return [visColumns[visColumns.length + idx]];
8625                            }
8626                            // Counting from the left
8627                            return [_fnVisibleToColumnIndex(settings, idx)];
8628                        }
8629
8630                        return columns.map(function (col, idx) {
8631                            // Not visible, can't match
8632                            if (!col.bVisible) {
8633                                return null;
8634                            }
8635
8636                            // Selector
8637                            if (match[1]) {
8638                                return $(nodes[idx]).filter(match[1]).length > 0 ? idx : null;
8639                            }
8640
8641                            // `:visible` on its own
8642                            return idx;
8643                        });
8644
8645                    case 'name':
8646                        // Don't get names, unless needed, and only get once if it is
8647                        if (!names) {
8648                            names = _pluck(columns, 'sName');
8649                        }
8650
8651                        // match by name. `names` is column index complete and in order
8652                        return names.map(function (name, i) {
8653                            return name === match[1] ? i : null;
8654                        });
8655
8656                    case 'title':
8657                        if (!titles) {
8658                            titles = _pluck(columns, 'sTitle');
8659                        }
8660
8661                        // match by column title
8662                        return titles.map(function (title, i) {
8663                            return title === match[1] ? i : null;
8664                        });
8665
8666                    default:
8667                        return [];
8668                }
8669            }
8670
8671            // Cell in the table body
8672            if (s.nodeName && s._DT_CellIndex) {
8673                return [s._DT_CellIndex.column];
8674            }
8675
8676            // jQuery selector on the TH elements for the columns
8677            var jqResult = $(nodes)
8678                .filter(s)
8679                .map(function () {
8680                    return _fnColumnsFromHeader(this); // `nodes` is column index complete and in order
8681                })
8682                .toArray()
8683                .sort(function (a, b) {
8684                    return a - b;
8685                });
8686
8687            if (jqResult.length || !s.nodeName) {
8688                return jqResult;
8689            }
8690
8691            // Otherwise a node which might have a `dt-column` data attribute, or be
8692            // a child or such an element
8693            var host = $(s).closest('*[data-dt-column]');
8694            return host.length ?
8695                [host.data('dt-column')] :
8696                [];
8697        };
8698
8699        var selected = _selector_run('column', selector, run, settings, opts);
8700
8701        return opts.columnOrder && opts.columnOrder === 'index'
8702            ? selected.sort(function (a, b) { return a - b; })
8703            : selected; // implied
8704    };
8705
8706
8707    var __setColumnVis = function (settings, column, vis) {
8708        var
8709            cols = settings.aoColumns,
8710            col = cols[column],
8711            data = settings.aoData,
8712            cells, i, iLen, tr;
8713
8714        // Get
8715        if (vis === undefined) {
8716            return col.bVisible;
8717        }
8718
8719        // Set
8720        // No change
8721        if (col.bVisible === vis) {
8722            return false;
8723        }
8724
8725        if (vis) {
8726            // Insert column
8727            // Need to decide if we should use appendChild or insertBefore
8728            var insertBefore = _pluck(cols, 'bVisible').indexOf(true, column + 1);
8729
8730            for (i = 0, iLen = data.length; i < iLen; i++) {
8731                if (data[i]) {
8732                    tr = data[i].nTr;
8733                    cells = data[i].anCells;
8734
8735                    if (tr) {
8736                        // insertBefore can act like appendChild if 2nd arg is null
8737                        tr.insertBefore(cells[column], cells[insertBefore] || null);
8738                    }
8739                }
8740            }
8741        }
8742        else {
8743            // Remove column
8744            $(_pluck(settings.aoData, 'anCells', column)).detach();
8745        }
8746
8747        // Common actions
8748        col.bVisible = vis;
8749
8750        _colGroup(settings);
8751
8752        return true;
8753    };
8754
8755
8756    _api_register('columns()', function (selector, opts) {
8757        // argument shifting
8758        if (selector === undefined) {
8759            selector = '';
8760        }
8761        else if ($.isPlainObject(selector)) {
8762            opts = selector;
8763            selector = '';
8764        }
8765
8766        opts = _selector_opts(opts);
8767
8768        var inst = this.iterator('table', function (settings) {
8769            return __column_selector(settings, selector, opts);
8770        }, 1);
8771
8772        // Want argument shifting here and in _row_selector?
8773        inst.selector.cols = selector;
8774        inst.selector.opts = opts;
8775
8776        return inst;
8777    });
8778
8779    _api_registerPlural('columns().header()', 'column().header()', function (row) {
8780        return this.iterator('column', function (settings, column) {
8781            return __column_header(settings, column, row);
8782        }, 1);
8783    });
8784
8785    _api_registerPlural('columns().footer()', 'column().footer()', function (row) {
8786        return this.iterator('column', function (settings, column) {
8787            var footer = settings.aoFooter;
8788
8789            if (!footer.length) {
8790                return null;
8791            }
8792
8793            return settings.aoFooter[row !== undefined ? row : 0][column].cell;
8794        }, 1);
8795    });
8796
8797    _api_registerPlural('columns().data()', 'column().data()', function () {
8798        return this.iterator('column-rows', __columnData, 1);
8799    });
8800
8801    _api_registerPlural('columns().render()', 'column().render()', function (type) {
8802        return this.iterator('column-rows', function (settings, column, i, j, rows) {
8803            return __columnData(settings, column, i, j, rows, type);
8804        }, 1);
8805    });
8806
8807    _api_registerPlural('columns().dataSrc()', 'column().dataSrc()', function () {
8808        return this.iterator('column', function (settings, column) {
8809            return settings.aoColumns[column].mData;
8810        }, 1);
8811    });
8812
8813    _api_registerPlural('columns().cache()', 'column().cache()', function (type) {
8814        return this.iterator('column-rows', function (settings, column, i, j, rows) {
8815            return _pluck_order(settings.aoData, rows,
8816                type === 'search' ? '_aFilterData' : '_aSortData', column
8817            );
8818        }, 1);
8819    });
8820
8821    _api_registerPlural('columns().init()', 'column().init()', function () {
8822        return this.iterator('column', function (settings, column) {
8823            return settings.aoColumns[column];
8824        }, 1);
8825    });
8826
8827    _api_registerPlural('columns().names()', 'column().name()', function () {
8828        return this.iterator('column', function (settings, column) {
8829            return settings.aoColumns[column].sName;
8830        }, 1);
8831    });
8832
8833    _api_registerPlural('columns().nodes()', 'column().nodes()', function () {
8834        return this.iterator('column-rows', function (settings, column, i, j, rows) {
8835            return _pluck_order(settings.aoData, rows, 'anCells', column);
8836        }, 1);
8837    });
8838
8839    _api_registerPlural('columns().titles()', 'column().title()', function (title, row) {
8840        return this.iterator('column', function (settings, column) {
8841            // Argument shifting
8842            if (typeof title === 'number') {
8843                row = title;
8844                title = undefined;
8845            }
8846
8847            var span = $('span.dt-column-title', this.column(column).header(row));
8848
8849            if (title !== undefined) {
8850                span.html(title);
8851                return this;
8852            }
8853
8854            return span.html();
8855        }, 1);
8856    });
8857
8858    _api_registerPlural('columns().types()', 'column().type()', function () {
8859        return this.iterator('column', function (settings, column) {
8860            var type = settings.aoColumns[column].sType;
8861
8862            // If the type was invalidated, then resolve it. This actually does
8863            // all columns at the moment. Would only happen once if getting all
8864            // column's data types.
8865            if (!type) {
8866                _fnColumnTypes(settings);
8867            }
8868
8869            return type;
8870        }, 1);
8871    });
8872
8873    _api_registerPlural('columns().visible()', 'column().visible()', function (vis, calc) {
8874        var that = this;
8875        var changed = [];
8876        var ret = this.iterator('column', function (settings, column) {
8877            if (vis === undefined) {
8878                return settings.aoColumns[column].bVisible;
8879            } // else
8880
8881            if (__setColumnVis(settings, column, vis)) {
8882                changed.push(column);
8883            }
8884        });
8885
8886        // Group the column visibility changes
8887        if (vis !== undefined) {
8888            this.iterator('table', function (settings) {
8889                // Redraw the header after changes
8890                _fnDrawHead(settings, settings.aoHeader);
8891                _fnDrawHead(settings, settings.aoFooter);
8892
8893                // Update colspan for no records display. Child rows and extensions will use their own
8894                // listeners to do this - only need to update the empty table item here
8895                if (!settings.aiDisplay.length) {
8896                    $(settings.nTBody).find('td[colspan]').attr('colspan', _fnVisibleColumns(settings));
8897                }
8898
8899                _fnSaveState(settings);
8900
8901                // Second loop once the first is done for events
8902                that.iterator('column', function (settings, column) {
8903                    if (changed.includes(column)) {
8904                        _fnCallbackFire(settings, null, 'column-visibility', [settings, column, vis, calc]);
8905                    }
8906                });
8907
8908                if (changed.length && (calc === undefined || calc)) {
8909                    that.columns.adjust();
8910                }
8911            });
8912        }
8913
8914        return ret;
8915    });
8916
8917    _api_registerPlural('columns().widths()', 'column().width()', function () {
8918        // Injects a fake row into the table for just a moment so the widths can
8919        // be read, regardless of colspan in the header and rows being present in
8920        // the body
8921        var columns = this.columns(':visible').count();
8922        var row = $('<tr>').html('<td>' + Array(columns).join('</td><td>') + '</td>');
8923
8924        $(this.table().body()).append(row);
8925
8926        var widths = row.children().map(function () {
8927            return $(this).outerWidth();
8928        });
8929
8930        row.remove();
8931
8932        return this.iterator('column', function (settings, column) {
8933            var visIdx = _fnColumnIndexToVisible(settings, column);
8934
8935            return visIdx !== null ? widths[visIdx] : 0;
8936        }, 1);
8937    });
8938
8939    _api_registerPlural('columns().indexes()', 'column().index()', function (type) {
8940        return this.iterator('column', function (settings, column) {
8941            return type === 'visible' ?
8942                _fnColumnIndexToVisible(settings, column) :
8943                column;
8944        }, 1);
8945    });
8946
8947    _api_register('columns.adjust()', function () {
8948        return this.iterator('table', function (settings) {
8949            // Force a column sizing to happen with a manual call - otherwise it can skip
8950            // if the size hasn't changed
8951            settings.containerWidth = -1;
8952
8953            _fnAdjustColumnSizing(settings);
8954        }, 1);
8955    });
8956
8957    _api_register('column.index()', function (type, idx) {
8958        if (this.context.length !== 0) {
8959            var ctx = this.context[0];
8960
8961            if (type === 'fromVisible' || type === 'toData') {
8962                return _fnVisibleToColumnIndex(ctx, idx);
8963            }
8964            else if (type === 'fromData' || type === 'toVisible') {
8965                return _fnColumnIndexToVisible(ctx, idx);
8966            }
8967        }
8968    });
8969
8970    _api_register('column()', function (selector, opts) {
8971        return _selector_first(this.columns(selector, opts));
8972    });
8973
8974    var __cell_selector = function (settings, selector, opts) {
8975        var data = settings.aoData;
8976        var rows = _selector_row_indexes(settings, opts);
8977        var cells = _removeEmpty(_pluck_order(data, rows, 'anCells'));
8978        var allCells = $(_flatten([], cells));
8979        var row;
8980        var columns = settings.aoColumns.length;
8981        var a, i, iLen, j, o, host;
8982
8983        var run = function (s) {
8984            var fnSelector = typeof s === 'function';
8985
8986            if (s === null || s === undefined || fnSelector) {
8987                // All cells and function selectors
8988                a = [];
8989
8990                for (i = 0, iLen = rows.length; i < iLen; i++) {
8991                    row = rows[i];
8992
8993                    for (j = 0; j < columns; j++) {
8994                        o = {
8995                            row: row,
8996                            column: j
8997                        };
8998
8999                        if (fnSelector) {
9000                            // Selector - function
9001                            host = data[row];
9002
9003                            if (s(o, _fnGetCellData(settings, row, j), host.anCells ? host.anCells[j] : null)) {
9004                                a.push(o);
9005                            }
9006                        }
9007                        else {
9008                            // Selector - all
9009                            a.push(o);
9010                        }
9011                    }
9012                }
9013
9014                return a;
9015            }
9016
9017            // Selector - index
9018            if ($.isPlainObject(s)) {
9019                // Valid cell index and its in the array of selectable rows
9020                return s.column !== undefined && s.row !== undefined && rows.indexOf(s.row) !== -1 ?
9021                    [s] :
9022                    [];
9023            }
9024
9025            // Selector - jQuery filtered cells
9026            var jqResult = allCells
9027                .filter(s)
9028                .map(function (i, el) {
9029                    return { // use a new object, in case someone changes the values
9030                        row: el._DT_CellIndex.row,
9031                        column: el._DT_CellIndex.column
9032                    };
9033                })
9034                .toArray();
9035
9036            if (jqResult.length || !s.nodeName) {
vendor: 4,033 bytes, lines 9037-9163
9037                return jqResult;
9038            }
9039
9040            // Otherwise the selector is a node, and there is one last option - the
9041            // element might be a child of an element which has dt-row and dt-column
9042            // data attributes
9043            host = $(s).closest('*[data-dt-row]');
9044            return host.length ?
9045                [{
9046                    row: host.data('dt-row'),
9047                    column: host.data('dt-column')
9048                }] :
9049                [];
9050        };
9051
9052        return _selector_run('cell', selector, run, settings, opts);
9053    };
9054
9055
9056
9057
9058    _api_register('cells()', function (rowSelector, columnSelector, opts) {
9059        // Argument shifting
9060        if ($.isPlainObject(rowSelector)) {
9061            // Indexes
9062            if (rowSelector.row === undefined) {
9063                // Selector options in first parameter
9064                opts = rowSelector;
9065                rowSelector = null;
9066            }
9067            else {
9068                // Cell index objects in first parameter
9069                opts = columnSelector;
9070                columnSelector = null;
9071            }
9072        }
9073        if ($.isPlainObject(columnSelector)) {
9074            opts = columnSelector;
9075            columnSelector = null;
9076        }
9077
9078        // Cell selector
9079        if (columnSelector === null || columnSelector === undefined) {
9080            return this.iterator('table', function (settings) {
9081                return __cell_selector(settings, rowSelector, _selector_opts(opts));
9082            });
9083        }
9084
9085        // The default built in options need to apply to row and columns
9086        var internalOpts = opts ? {
9087            page: opts.page,
9088            order: opts.order,
9089            search: opts.search
9090        } : {};
9091
9092        // Row + column selector
9093        var columns = this.columns(columnSelector, internalOpts);
9094        var rows = this.rows(rowSelector, internalOpts);
9095        var i, iLen, j, jen;
9096
9097        var cellsNoOpts = this.iterator('table', function (settings, idx) {
9098            var a = [];
9099
9100            for (i = 0, iLen = rows[idx].length; i < iLen; i++) {
9101                for (j = 0, jen = columns[idx].length; j < jen; j++) {
9102                    a.push({
9103                        row: rows[idx][i],
9104                        column: columns[idx][j]
9105                    });
9106                }
9107            }
9108
9109            return a;
9110        }, 1);
9111
9112        // There is currently only one extension which uses a cell selector extension
9113        // It is a _major_ performance drag to run this if it isn't needed, so this is
9114        // an extension specific check at the moment
9115        var cells = opts && opts.selected ?
9116            this.cells(cellsNoOpts, opts) :
9117            cellsNoOpts;
9118
9119        $.extend(cells.selector, {
9120            cols: columnSelector,
9121            rows: rowSelector,
9122            opts: opts
9123        });
9124
9125        return cells;
9126    });
9127
9128
9129    _api_registerPlural('cells().nodes()', 'cell().node()', function () {
9130        return this.iterator('cell', function (settings, row, column) {
9131            var data = settings.aoData[row];
9132
9133            return data && data.anCells ?
9134                data.anCells[column] :
9135                undefined;
9136        }, 1);
9137    });
9138
9139
9140    _api_register('cells().data()', function () {
9141        return this.iterator('cell', function (settings, row, column) {
9142            return _fnGetCellData(settings, row, column);
9143        }, 1);
9144    });
9145
9146
9147    _api_registerPlural('cells().cache()', 'cell().cache()', function (type) {
9148        type = type === 'search' ? '_aFilterData' : '_aSortData';
9149
9150        return this.iterator('cell', function (settings, row, column) {
9151            return settings.aoData[row][type][column];
9152        }, 1);
9153    });
9154
9155
9156    _api_registerPlural('cells().render()', 'cell().render()', function (type) {
9157        return this.iterator('cell', function (settings, row, column) {
9158            return _fnGetCellData(settings, row, column, type);
9159        }, 1);
9160    });
9161
9162
9163    _api_registerPlural('cells().indexes()', 'cell().index()', function () {
9164        return this.iterator('cell', function (settings, row, column) {
9165            return {
9166                row: row,
9167                column: column,
9168                columnVisible: _fnColumnIndexToVisible(settings, column)
9169            };
9170        }, 1);
9171    });
9172
9173
9174    _api_registerPlural('cells().invalidate()', 'cell().invalidate()', function (src) {
9175        return this.iterator('cell', function (settings, row, column) {
9176            _fnInvalidate(settings, row, src, column);
9177        });
9178    });
9179
9180
9181
9182    _api_register('cell()', function (rowSelector, columnSelector, opts) {
9183        return _selector_first(this.cells(rowSelector, columnSelector, opts));
9184    });
9185
9186
9187    _api_register('cell().data()', function (data) {
9188        var ctx = this.context;
9189        var cell = this[0];
9190
9191        if (data === undefined) {
9192            // Get
9193            return ctx.length && cell.length ?
9194                _fnGetCellData(ctx[0], cell[0].row, cell[0].column) :
9195                undefined;
9196        }
9197
9198        // Set
9199        _fnSetCellData(ctx[0], cell[0].row, cell[0].column, data);
9200        _fnInvalidate(ctx[0], cell[0].row, 'data', cell[0].column);
9201
9202        return this;
9203    });
9204
9205
9206
9207    /**
9208     * Get current ordering (sorting) that has been applied to the table.
9209     *
9210     * @returns {array} 2D array containing the sorting information for the first
9211     *   table in the current context. Each element in the parent array represents
9212     *   a column being sorted upon (i.e. multi-sorting with two columns would have
9213     *   2 inner arrays). The inner arrays may have 2 or 3 elements. The first is
9214     *   the column index that the sorting condition applies to, the second is the
9215     *   direction of the sort (`desc` or `asc`) and, optionally, the third is the
9216     *   index of the sorting order from the `column.sorting` initialisation array.
9217     *//**
9218    * Set the ordering for the table.
9219    *
9220    * @param {integer} order Column index to sort upon.
9221    * @param {string} direction Direction of the sort to be applied (`asc` or `desc`)
9222    * @returns {DataTables.Api} this
9223    *//**
9224    * Set the ordering for the table.
9225    *
9226    * @param {array} order 1D array of sorting information to be applied.
9227    * @param {array} [...] Optional additional sorting conditions
9228    * @returns {DataTables.Api} this
9229    *//**
9230    * Set the ordering for the table.
9231    *
9232    * @param {array} order 2D array of sorting information to be applied.
9233    * @returns {DataTables.Api} this
9234    */
9235    _api_register('order()', function (order, dir) {
9236        var ctx = this.context;
9237        var args = Array.prototype.slice.call(arguments);
9238
9239        if (order === undefined) {
9240            // get
9241            return ctx.length !== 0 ?
9242                ctx[0].aaSorting :
9243                undefined;
9244        }
9245
9246        // set
9247        if (typeof order === 'number') {
9248            // Simple column / direction passed in
9249            order = [[order, dir]];
9250        }
9251        else if (args.length > 1) {
9252            // Arguments passed in (list of 1D arrays)
9253            order = args;
9254        }
9255        // otherwise a 2D array was passed in
9256
9257        return this.iterator('table', function (settings) {
9258            var resolved = [];
9259            _fnSortResolve(settings, resolved, order);
9260
9261            settings.aaSorting = resolved;
9262        });
9263    });
9264
9265
9266    /**
9267     * Attach a sort listener to an element for a given column
9268     *
9269     * @param {node|jQuery|string} node Identifier for the element(s) to attach the
9270     *   listener to. This can take the form of a single DOM node, a jQuery
9271     *   collection of nodes or a jQuery selector which will identify the node(s).
9272     * @param {integer} column the column that a click on this node will sort on
9273     * @param {function} [callback] callback function when sort is run
9274     * @returns {DataTables.Api} this
9275     */
9276    _api_register('order.listener()', function (node, column, callback) {
9277        return this.iterator('table', function (settings) {
9278            _fnSortAttachListener(settings, node, {}, column, callback);
9279        });
9280    });
9281
9282
9283    _api_register('order.fixed()', function (set) {
9284        if (!set) {
9285            var ctx = this.context;
9286            var fixed = ctx.length ?
9287                ctx[0].aaSortingFixed :
9288                undefined;
9289
9290            return Array.isArray(fixed) ?
9291                { pre: fixed } :
9292                fixed;
9293        }
9294
9295        return this.iterator('table', function (settings) {
9296            settings.aaSortingFixed = $.extend(true, {}, set);
9297        });
9298    });
9299
9300
9301    // Order by the selected column(s)
9302    _api_register([
9303        'columns().order()',
9304        'column().order()'
9305    ], function (dir) {
9306        var that = this;
9307
9308        if (!dir) {
9309            return this.iterator('column', function (settings, idx) {
9310                var sort = _fnSortFlatten(settings);
9311
9312                for (var i = 0, iLen = sort.length; i < iLen; i++) {
9313                    if (sort[i].col === idx) {
9314                        return sort[i].dir;
9315                    }
9316                }
9317
9318                return null;
9319            }, 1);
9320        }
9321        else {
9322            return this.iterator('table', function (settings, i) {
9323                settings.aaSorting = that[i].map(function (col) {
9324                    return [col, dir];
9325                });
9326            });
9327        }
9328    });
9329
9330    _api_registerPlural('columns().orderable()', 'column().orderable()', function (directions) {
9331        return this.iterator('column', function (settings, idx) {
9332            var col = settings.aoColumns[idx];
9333
9334            return directions ?
9335                col.asSorting :
9336                col.bSortable;
9337        }, 1);
9338    });
9339
9340
9341    _api_register('processing()', function (show) {
9342        return this.iterator('table', function (ctx) {
9343            _fnProcessingDisplay(ctx, show);
9344        });
9345    });
9346
9347
9348    _api_register('search()', function (input, regex, smart, caseInsen) {
9349        var ctx = this.context;
9350
9351        if (input === undefined) {
9352            // get
9353            return ctx.length !== 0 ?
9354                ctx[0].oPreviousSearch.search :
9355                undefined;
9356        }
9357
9358        // set
9359        return this.iterator('table', function (settings) {
9360            if (!settings.oFeatures.bFilter) {
9361                return;
9362            }
9363
9364            if (typeof regex === 'object') {
9365                // New style options to pass to the search builder
9366                _fnFilterComplete(settings, $.extend(settings.oPreviousSearch, regex, {
9367                    search: input
9368                }));
9369            }
9370            else {
9371                // Compat for the old options
9372                _fnFilterComplete(settings, $.extend(settings.oPreviousSearch, {
9373                    search: input,
9374                    regex: regex === null ? false : regex,
9375                    smart: smart === null ? true : smart,
9376                    caseInsensitive: caseInsen === null ? true : caseInsen
9377                }));
9378            }
9379        });
9380    });
9381
9382    _api_register('search.fixed()', function (name, search) {
9383        var ret = this.iterator(true, 'table', function (settings) {
9384            var fixed = settings.searchFixed;
9385
9386            if (!name) {
9387                return Object.keys(fixed);
9388            }
9389            else if (search === undefined) {
9390                return fixed[name];
9391            }
9392            else if (search === null) {
9393                delete fixed[name];
9394            }
9395            else {
9396                fixed[name] = search;
9397            }
9398
9399            return this;
9400        });
9401
9402        return name !== undefined && search === undefined
9403            ? ret[0]
9404            : ret;
9405    });
9406
9407    _api_registerPlural(
9408        'columns().search()',
9409        'column().search()',
9410        function (input, regex, smart, caseInsen) {
9411            return this.iterator('column', function (settings, column) {
9412                var preSearch = settings.aoPreSearchCols;
9413
9414                if (input === undefined) {
9415                    // get
9416                    return preSearch[column].search;
9417                }
9418
9419                // set
9420                if (!settings.oFeatures.bFilter) {
9421                    return;
9422                }
9423
9424                if (typeof regex === 'object') {
9425                    // New style options to pass to the search builder
9426                    $.extend(preSearch[column], regex, {
9427                        search: input
9428                    });
9429                }
9430                else {
9431                    // Old style (with not all options available)
9432                    $.extend(preSearch[column], {
9433                        search: input,
9434                        regex: regex === null ? false : regex,
9435                        smart: smart === null ? true : smart,
9436                        caseInsensitive: caseInsen === null ? true : caseInsen
9437                    });
9438                }
9439
9440                _fnFilterComplete(settings, settings.oPreviousSearch);
9441            });
9442        }
9443    );
9444
9445    _api_register([
9446        'columns().search.fixed()',
9447        'column().search.fixed()'
9448    ],
9449        function (name, search) {
9450            var ret = this.iterator(true, 'column', function (settings, colIdx) {
9451                var fixed = settings.aoColumns[colIdx].searchFixed;
9452
9453                if (!name) {
9454                    return Object.keys(fixed);
9455                }
9456                else if (search === undefined) {
9457                    return fixed[name] || null;
9458                }
9459                else if (search === null) {
9460                    delete fixed[name];
9461                }
9462                else {
9463                    fixed[name] = search;
9464                }
9465
9466                return this;
9467            });
9468
9469            return name !== undefined && search === undefined
9470                ? ret[0]
9471                : ret;
9472        }
9473    );
9474    /*
9475     * State API methods
9476     */
9477
9478    _api_register('state()', function (set, ignoreTime) {
9479        // getter
9480        if (!set) {
9481            return this.context.length ?
9482                this.context[0].oSavedState :
9483                null;
9484        }
9485
9486        var setMutate = $.extend(true, {}, set);
9487
9488        // setter
9489        return this.iterator('table', function (settings) {
9490            if (ignoreTime !== false) {
9491                setMutate.time = +new Date() + 100;
9492            }
9493
9494            _fnImplementState(settings, setMutate, function () { });
9495        });
9496    });
9497
9498
9499    _api_register('state.clear()', function () {
9500        return this.iterator('table', function (settings) {
9501            // Save an empty object
9502            settings.fnStateSaveCallback.call(settings.oInstance, settings, {});
9503        });
9504    });
9505
9506
9507    _api_register('state.loaded()', function () {
9508        return this.context.length ?
9509            this.context[0].oLoadedState :
9510            null;
9511    });
9512
9513
9514    _api_register('state.save()', function () {
9515        return this.iterator('table', function (settings) {
9516            _fnSaveState(settings);
9517        });
9518    });
9519
9520    // Can be assigned in DateTable.use() - note luxon and moment vars are in helpers.js
9521    var __bootstrap;
9522    var __foundation;
9523
9524    /**
9525     * Set the libraries that DataTables uses, or the global objects.
9526     * Note that the arguments can be either way around (legacy support)
9527     * and the second is optional. See docs.
9528     */
9529    DataTable.use = function (arg1, arg2) {
9530        // Reverse arguments for legacy support
9531        var module = typeof arg1 === 'string'
9532            ? arg2
9533            : arg1;
9534        var type = typeof arg2 === 'string'
9535            ? arg2
9536            : arg1;
9537
9538        // Getter
9539        if (module === undefined && typeof type === 'string') {
9540            switch (type) {
9541                case 'lib':
9542                case 'jq':
9543                    return $;
9544
9545                case 'win':
9546                    return window;
9547
9548                case 'datetime':
9549                    return DataTable.DateTime;
9550
9551                case 'luxon':
9552                    return __luxon;
9553
9554                case 'moment':
9555                    return __moment;
9556
9557                case 'bootstrap':
9558                    // Use local if set, otherwise try window, which could be undefined
9559                    return __bootstrap || window.bootstrap;
9560
9561                case 'foundation':
9562                    // Ditto
9563                    return __foundation || window.Foundation;
9564
9565                default:
9566                    return null;
9567            }
9568        }
9569
9570        // Setter
9571        if (type === 'lib' || type === 'jq' || (module && module.fn && module.fn.jquery)) {
9572            $ = module;
9573        }
9574        else if (type === 'win' || (module && module.document)) {
9575            window = module;
9576            document = module.document;
9577        }
9578        else if (type === 'datetime' || (module && module.type === 'DateTime')) {
9579            DataTable.DateTime = module;
9580        }
9581        else if (type === 'luxon' || (module && module.FixedOffsetZone)) {
9582            __luxon = module;
9583        }
9584        else if (type === 'moment' || (module && module.isMoment)) {
9585            __moment = module;
9586        }
9587        else if (type === 'bootstrap' || (module && module.Modal && module.Modal.NAME === 'modal')) {
9588            // This is currently for BS5 only. BS3/4 attach to jQuery, so no need to use `.use()`
9589            __bootstrap = module;
9590        }
9591        else if (type === 'foundation' || (module && module.Reveal)) {
9592            __foundation = module;
9593        }
9594    }
9595
9596    /**
9597     * CommonJS factory function pass through. This will check if the arguments
9598     * given are a window object or a jQuery object. If so they are set
9599     * accordingly.
9600     * @param {*} root Window
9601     * @param {*} jq jQUery
9602     * @returns {boolean} Indicator
9603     */
9604    DataTable.factory = function (root, jq) {
9605        var is = false;
9606
9607        // Test if the first parameter is a window object
9608        if (root && root.document) {
9609            window = root;
9610            document = root.document;
9611        }
9612
9613        // Test if the second parameter is a jQuery object
9614        if (jq && jq.fn && jq.fn.jquery) {
9615            $ = jq;
9616            is = true;
9617        }
9618
9619        return is;
9620    }
9621
9622    /**
9623     * Provide a common method for plug-ins to check the version of DataTables being
9624     * used, in order to ensure compatibility.
9625     *
9626     *  @param {string} version Version string to check for, in the format "X.Y.Z".
9627     *    Note that the formats "X" and "X.Y" are also acceptable.
9628     *  @param {string} [version2=current DataTables version] As above, but optional.
9629     *   If not given the current DataTables version will be used.
9630     *  @returns {boolean} true if this version of DataTables is greater or equal to
9631     *    the required version, or false if this version of DataTales is not
9632     *    suitable
9633     *  @static
9634     *  @dtopt API-Static
9635     *
9636     *  @example
9637     *    alert( $.fn.dataTable.versionCheck( '1.9.0' ) );
9638     */
9639    DataTable.versionCheck = function (version, version2) {
9640        var aThis = version2 ?
9641            version2.split('.') :
vendor: 4,354 bytes, lines 9642-9783
9642            DataTable.version.split('.');
9643        var aThat = version.split('.');
9644        var iThis, iThat;
9645
9646        for (var i = 0, iLen = aThat.length; i < iLen; i++) {
9647            iThis = parseInt(aThis[i], 10) || 0;
9648            iThat = parseInt(aThat[i], 10) || 0;
9649
9650            // Parts are the same, keep comparing
9651            if (iThis === iThat) {
9652                continue;
9653            }
9654
9655            // Parts are different, return immediately
9656            return iThis > iThat;
9657        }
9658
9659        return true;
9660    };
9661
9662
9663    /**
9664     * Check if a `<table>` node is a DataTable table already or not.
9665     *
9666     *  @param {node|jquery|string} table Table node, jQuery object or jQuery
9667     *      selector for the table to test. Note that if more than more than one
9668     *      table is passed on, only the first will be checked
9669     *  @returns {boolean} true the table given is a DataTable, or false otherwise
9670     *  @static
9671     *  @dtopt API-Static
9672     *
9673     *  @example
9674     *    if ( ! $.fn.DataTable.isDataTable( '#example' ) ) {
9675     *      $('#example').dataTable();
9676     *    }
9677     */
9678    DataTable.isDataTable = function (table) {
9679        var t = $(table).get(0);
9680        var is = false;
9681
9682        if (table instanceof DataTable.Api) {
9683            return true;
9684        }
9685
9686        $.each(DataTable.settings, function (i, o) {
9687            var head = o.nScrollHead ? $('table', o.nScrollHead)[0] : null;
9688            var foot = o.nScrollFoot ? $('table', o.nScrollFoot)[0] : null;
9689
9690            if (o.nTable === t || head === t || foot === t) {
9691                is = true;
9692            }
9693        });
9694
9695        return is;
9696    };
9697
9698
9699    /**
9700     * Get all DataTable tables that have been initialised - optionally you can
9701     * select to get only currently visible tables.
9702     *
9703     *  @param {boolean} [visible=false] Flag to indicate if you want all (default)
9704     *    or visible tables only.
9705     *  @returns {array} Array of `table` nodes (not DataTable instances) which are
9706     *    DataTables
9707     *  @static
9708     *  @dtopt API-Static
9709     *
9710     *  @example
9711     *    $.each( $.fn.dataTable.tables(true), function () {
9712     *      $(table).DataTable().columns.adjust();
9713     *    } );
9714     */
9715    DataTable.tables = function (visible) {
9716        var api = false;
9717
9718        if ($.isPlainObject(visible)) {
9719            api = visible.api;
9720            visible = visible.visible;
9721        }
9722
9723        var a = DataTable.settings
9724            .filter(function (o) {
9725                return !visible || (visible && $(o.nTable).is(':visible'))
9726                    ? true
9727                    : false;
9728            })
9729            .map(function (o) {
9730                return o.nTable;
9731            });
9732
9733        return api ?
9734            new _Api(a) :
9735            a;
9736    };
9737
9738
9739    /**
9740     * Convert from camel case parameters to Hungarian notation. This is made public
9741     * for the extensions to provide the same ability as DataTables core to accept
9742     * either the 1.9 style Hungarian notation, or the 1.10+ style camelCase
9743     * parameters.
9744     *
9745     *  @param {object} src The model object which holds all parameters that can be
9746     *    mapped.
9747     *  @param {object} user The object to convert from camel case to Hungarian.
9748     *  @param {boolean} force When set to `true`, properties which already have a
9749     *    Hungarian value in the `user` object will be overwritten. Otherwise they
9750     *    won't be.
9751     */
9752    DataTable.camelToHungarian = _fnCamelToHungarian;
9753
9754
9755
9756    /**
9757     *
9758     */
9759    _api_register('$()', function (selector, opts) {
9760        var
9761            rows = this.rows(opts).nodes(), // Get all rows
9762            jqRows = $(rows);
9763
9764        return $([].concat(
9765            jqRows.filter(selector).toArray(),
9766            jqRows.find(selector).toArray()
9767        ));
9768    });
9769
9770
9771    // jQuery functions to operate on the tables
9772    $.each(['on', 'one', 'off'], function (i, key) {
9773        _api_register(key + '()', function ( /* event, handler */) {
9774            var args = Array.prototype.slice.call(arguments);
9775
9776            // Add the `dt` namespace automatically if it isn't already present
9777            args[0] = args[0].split(/\s/).map(function (e) {
9778                return !e.match(/\.dt\b/) ?
9779                    e + '.dt' :
9780                    e;
9781            }).join(' ');
9782
9783            var inst = $(this.tables().nodes());
9784            inst[key].apply(inst, args);
9785            return this;
9786        });
9787    });
9788
9789
9790    _api_register('clear()', function () {
9791        return this.iterator('table', function (settings) {
9792            _fnClearTable(settings);
9793        });
9794    });
9795
9796
9797    _api_register('error()', function (msg) {
9798        return this.iterator('table', function (settings) {
9799            _fnLog(settings, 0, msg);
9800        });
9801    });
9802
9803
9804    _api_register('settings()', function () {
9805        return new _Api(this.context, this.context);
9806    });
9807
9808
9809    _api_register('init()', function () {
9810        var ctx = this.context;
9811        return ctx.length ? ctx[0].oInit : null;
9812    });
9813
9814
9815    _api_register('data()', function () {
9816        return this.iterator('table', function (settings) {
9817            return _pluck(settings.aoData, '_aData');
9818        }).flatten();
9819    });
9820
9821
9822    _api_register('trigger()', function (name, args, bubbles) {
9823        return this.iterator('table', function (settings) {
9824            return _fnCallbackFire(settings, null, name, args, bubbles);
9825        }).flatten();
9826    });
9827
9828
9829    _api_register('ready()', function (fn) {
9830        var ctx = this.context;
9831
9832        // Get status of first table
9833        if (!fn) {
9834            return ctx.length
9835                ? (ctx[0]._bInitComplete || false)
9836                : null;
9837        }
9838
9839        // Function to run either once the table becomes ready or
9840        // immediately if it is already ready.
9841        return this.tables().every(function () {
9842            var api = this;
9843
9844            if (this.context[0]._bInitComplete) {
9845                fn.call(api);
9846            }
9847            else {
9848                this.on('init.dt.DT', function () {
9849                    fn.call(api);
9850                });
9851            }
9852        });
9853    });
9854
9855
9856    _api_register('destroy()', function (remove) {
9857        remove = remove || false;
9858
9859        return this.iterator('table', function (settings) {
9860            var classes = settings.oClasses;
9861            var table = settings.nTable;
9862            var tbody = settings.nTBody;
9863            var thead = settings.nTHead;
9864            var tfoot = settings.nTFoot;
9865            var jqTable = $(table);
9866            var jqTbody = $(tbody);
9867            var jqWrapper = $(settings.nTableWrapper);
9868            var rows = settings.aoData.map(function (r) { return r ? r.nTr : null; });
9869            var orderClasses = classes.order;
9870
9871            // Flag to note that the table is currently being destroyed - no action
9872            // should be taken
9873            settings.bDestroying = true;
9874
9875            // Fire off the destroy callbacks for plug-ins etc
9876            _fnCallbackFire(settings, "aoDestroyCallback", "destroy", [settings], true);
9877
9878            // If not being removed from the document, make all columns visible
9879            if (!remove) {
9880                new _Api(settings).columns().visible(true);
9881            }
9882
9883            // Container width change listener
9884            if (settings.resizeObserver) {
9885                settings.resizeObserver.disconnect();
9886            }
9887
9888            // Blitz all `DT` namespaced events (these are internal events, the
9889            // lowercase, `dt` events are user subscribed and they are responsible
9890            // for removing them
9891            jqWrapper.off('.DT').find(':not(tbody *)').off('.DT');
9892            $(window).off('.DT-' + settings.sInstance);
9893
9894            // When scrolling we had to break the table up - restore it
9895            if (table != thead.parentNode) {
9896                jqTable.children('thead').detach();
9897                jqTable.append(thead);
9898            }
9899
9900            if (tfoot && table != tfoot.parentNode) {
9901                jqTable.children('tfoot').detach();
9902                jqTable.append(tfoot);
9903            }
9904
9905            // Clean up the header / footer
9906            cleanHeader(thead, 'header');
9907            cleanHeader(tfoot, 'footer');
9908            settings.colgroup.remove();
9909
9910            settings.aaSorting = [];
9911            settings.aaSortingFixed = [];
9912            _fnSortingClasses(settings);
9913
9914            $(jqTable).find('th, td').removeClass(
9915                $.map(DataTable.ext.type.className, function (v) {
9916                    return v;
9917                }).join(' ')
9918            );
9919
9920            $('th, td', thead)
9921                .removeClass(
9922                    orderClasses.none + ' ' +
9923                    orderClasses.canAsc + ' ' +
9924                    orderClasses.canDesc + ' ' +
9925                    orderClasses.isAsc + ' ' +
9926                    orderClasses.isDesc
9927                )
9928                .css('width', '')
9929                .removeAttr('aria-sort');
9930
9931            // Add the TR elements back into the table in their original order
9932            jqTbody.children().detach();
9933            jqTbody.append(rows);
9934
9935            var orig = settings.nTableWrapper.parentNode;
9936            var insertBefore = settings.nTableWrapper.nextSibling;
9937
9938            // Remove the DataTables generated nodes, events and classes
9939            var removedMethod = remove ? 'remove' : 'detach';
9940            jqTable[removedMethod]();
9941            jqWrapper[removedMethod]();
9942
9943            // If we need to reattach the table to the document
9944            if (!remove && orig) {
9945                // insertBefore acts like appendChild if !arg[1]
9946                orig.insertBefore(table, insertBefore);
9947
9948                // Restore the width of the original table - was read from the style property,
9949                // so we can restore directly to that
9950                jqTable
9951                    .css('width', settings.sDestroyWidth)
9952                    .removeClass(classes.table);
9953            }
9954
9955            /* Remove the settings object from the settings array */
9956            var idx = DataTable.settings.indexOf(settings);
9957            if (idx !== -1) {
9958                DataTable.settings.splice(idx, 1);
9959            }
9960        });
9961    });
9962
9963
9964    // Add the `every()` method for rows, columns and cells in a compact form
9965    $.each(['column', 'row', 'cell'], function (i, type) {
9966        _api_register(type + 's().every()', function (fn) {
9967            var opts = this.selector.opts;
9968            var api = this;
9969            var inst;
9970            var counter = 0;
9971
9972            return this.iterator('every', function (settings, selectedIdx, tableIdx) {
9973                inst = api[type](selectedIdx, opts);
9974
9975                if (type === 'cell') {
9976                    fn.call(inst, inst[0][0].row, inst[0][0].column, tableIdx, counter);
9977                }
9978                else {
9979                    fn.call(inst, selectedIdx, tableIdx, counter);
9980                }
9981
9982                counter++;
9983            });
9984        });
9985    });
9986
9987
9988    // i18n method for extensions to be able to use the language object from the
9989    // DataTable
9990    _api_register('i18n()', function (token, def, plural) {
9991        var ctx = this.context[0];
9992        var resolved = _fnGetObjectDataFn(token)(ctx.oLanguage);
9993
9994        if (resolved === undefined) {
9995            resolved = def;
9996        }
9997
9998        if ($.isPlainObject(resolved)) {
9999            resolved = plural !== undefined && resolved[plural] !== undefined
10000                ? resolved[plural]
10001                : plural === false
10002                    ? resolved
10003                    : resolved._;
10004        }
10005
10006        return typeof resolved === 'string'
10007            ? resolved.replace('%d', plural) // nb: plural might be undefined,
10008            : resolved;
10009    });
10010
10011    // Needed for header and footer, so pulled into its own function
10012    function cleanHeader(node, className) {
10013        $(node).find('span.dt-column-order').remove();
10014        $(node).find('span.dt-column-title').each(function () {
10015            var title = $(this).html();
10016            $(this).parent().parent().append(title);
10017            $(this).remove();
10018        });
10019        $(node).find('div.dt-column-' + className).remove();
10020
10021        $('th, td', node).removeAttr('data-dt-column');
10022    }
10023
10024    /**
10025     * Version string for plug-ins to check compatibility. Allowed format is
10026     * `a.b.c-d` where: a:int, b:int, c:int, d:string(dev|beta|alpha). `d` is used
10027     * only for non-release builds. See https://semver.org/ for more information.
10028     *  @member
10029     *  @type string
10030     *  @default Version number
10031     */
10032    DataTable.version = "2.3.4";
10033
10034    /**
10035     * Private data store, containing all of the settings objects that are
10036     * created for the tables on a given page.
10037     *
10038     * Note that the `DataTable.settings` object is aliased to
10039     * `jQuery.fn.dataTableExt` through which it may be accessed and
10040     * manipulated, or `jQuery.fn.dataTable.settings`.
10041     *  @member
10042     *  @type array
10043     *  @default []
10044     *  @private
10045     */
10046    DataTable.settings = [];
10047
10048    /**
10049     * Object models container, for the various models that DataTables has
10050     * available to it. These models define the objects that are used to hold
10051     * the active state and configuration of the table.
10052     *  @namespace
10053     */
10054    DataTable.models = {};
10055
10056
10057
10058    /**
10059     * Template object for the way in which DataTables holds information about
10060     * search information for the global filter and individual column filters.
10061     *  @namespace
10062     */
10063    DataTable.models.oSearch = {
10064        /**
10065         * Flag to whether or not the filtering should be case-insensitive
10066         */
10067        "caseInsensitive": true,
10068
10069        /**
10070         * Applied search term
10071         */
10072        "search": "",
10073
10074        /**
10075         * Flag to indicate if the search term should be interpreted as a
10076         * regular expression (true) or not (false) and therefore and special
10077         * regex characters escaped.
10078         */
10079        "regex": false,
10080
10081        /**
10082         * Flag to indicate if DataTables is to use its smart filtering or not.
10083         */
10084        "smart": true,
10085
10086        /**
10087         * Flag to indicate if DataTables should only trigger a search when
10088         * the return key is pressed.
10089         */
10090        "return": false
10091    };
10092
10093
10094
10095
10096    /**
10097     * Template object for the way in which DataTables holds information about
10098     * each individual row. This is the object format used for the settings
10099     * aoData array.
10100     *  @namespace
10101     */
10102    DataTable.models.oRow = {
10103        /**
10104         * TR element for the row
10105         */
10106        "nTr": null,
10107
10108        /**
10109         * Array of TD elements for each row. This is null until the row has been
10110         * created.
10111         */
10112        "anCells": null,
10113
10114        /**
10115         * Data object from the original data source for the row. This is either
10116         * an array if using the traditional form of DataTables, or an object if
10117         * using mData options. The exact type will depend on the passed in
10118         * data from the data source, or will be an array if using DOM a data
10119         * source.
10120         */
10121        "_aData": [],
10122
10123        /**
10124         * Sorting data cache - this array is ostensibly the same length as the
10125         * number of columns (although each index is generated only as it is
10126         * needed), and holds the data that is used for sorting each column in the
10127         * row. We do this cache generation at the start of the sort in order that
10128         * the formatting of the sort data need be done only once for each cell
10129         * per sort. This array should not be read from or written to by anything
10130         * other than the master sorting methods.
10131         */
10132        "_aSortData": null,
10133
10134        /**
10135         * Per cell filtering data cache. As per the sort data cache, used to
10136         * increase the performance of the filtering in DataTables
10137         */
10138        "_aFilterData": null,
10139
10140        /**
10141         * Filtering data cache. This is the same as the cell filtering cache, but
10142         * in this case a string rather than an array. This is easily computed with
10143         * a join on `_aFilterData`, but is provided as a cache so the join isn't
10144         * needed on every search (memory traded for performance)
10145         */
10146        "_sFilterRow": null,
10147
10148        /**
10149         * Denote if the original data source was from the DOM, or the data source
10150         * object. This is used for invalidating data, so DataTables can
10151         * automatically read data from the original source, unless uninstructed
10152         * otherwise.
10153         */
10154        "src": null,
10155
10156        /**
10157         * Index in the aoData array. This saves an indexOf lookup when we have the
10158         * object, but want to know the index
10159         */
10160        "idx": -1,
10161
10162        /**
10163         * Cached display value
10164         */
10165        displayData: null
10166    };
10167
10168
10169    /**
10170     * Template object for the column information object in DataTables. This object
10171     * is held in the settings aoColumns array and contains all the information that
10172     * DataTables needs about each individual column.
10173     *
10174     * Note that this object is related to {@link DataTable.defaults.column}
10175     * but this one is the internal data store for DataTables's cache of columns.
10176     * It should NOT be manipulated outside of DataTables. Any configuration should
10177     * be done through the initialisation options.
10178     *  @namespace
10179     */
10180    DataTable.models.oColumn = {
10181        /**
10182         * Column index.
10183         */
10184        "idx": null,
10185
10186        /**
10187         * A list of the columns that sorting should occur on when this column
10188         * is sorted. That this property is an array allows multi-column sorting
10189         * to be defined for a column (for example first name / last name columns
10190         * would benefit from this). The values are integers pointing to the
10191         * columns to be sorted on (typically it will be a single integer pointing
10192         * at itself, but that doesn't need to be the case).
10193         */
10194        "aDataSort": null,
10195
10196        /**
10197         * Define the sorting directions that are applied to the column, in sequence
10198         * as the column is repeatedly sorted upon - i.e. the first value is used
10199         * as the sorting direction when the column if first sorted (clicked on).
10200         * Sort it again (click again) and it will move on to the next index.
10201         * Repeat until loop.
10202         */
10203        "asSorting": null,
10204
10205        /**
10206         * Flag to indicate if the column is searchable, and thus should be included
10207         * in the filtering or not.
10208         */
10209        "bSearchable": null,
10210
10211        /**
10212         * Flag to indicate if the column is sortable or not.
10213         */
10214        "bSortable": null,
10215
10216        /**
10217         * Flag to indicate if the column is currently visible in the table or not
10218         */
10219        "bVisible": null,
10220
10221        /**
10222         * Store for manual type assignment using the `column.type` option. This
10223         * is held in store so we can manipulate the column's `sType` property.
10224         */
10225        "_sManualType": null,
10226
10227        /**
10228         * Flag to indicate if HTML5 data attributes should be used as the data
10229         * source for filtering or sorting. True is either are.
10230         */
10231        "_bAttrSrc": false,
10232
10233        /**
10234         * Developer definable function that is called whenever a cell is created (Ajax source,
10235         * etc) or processed for input (DOM source). This can be used as a compliment to mRender
10236         * allowing you to modify the DOM element (add background colour for example) when the
10237         * element is available.
10238         */
10239        "fnCreatedCell": null,
10240
10241        /**
10242         * Function to get data from a cell in a column. You should <b>never</b>
10243         * access data directly through _aData internally in DataTables - always use
10244         * the method attached to this property. It allows mData to function as
10245         * required. This function is automatically assigned by the column
10246         * initialisation method
10247         */
10248        "fnGetData": null,
10249
10250        /**
10251         * Function to set data for a cell in the column. You should <b>never</b>
10252         * set the data directly to _aData internally in DataTables - always use
10253         * this method. It allows mData to function as required. This function
10254         * is automatically assigned by the column initialisation method
10255         */
10256        "fnSetData": null,
10257
10258        /**
10259         * Property to read the value for the cells in the column from the data
10260         * source array / object. If null, then the default content is used, if a
10261         * function is given then the return from the function is used.
10262         */
10263        "mData": null,
10264
10265        /**
10266         * Partner property to mData which is used (only when defined) to get
10267         * the data - i.e. it is basically the same as mData, but without the
10268         * 'set' option, and also the data fed to it is the result from mData.
10269         * This is the rendering method to match the data method of mData.
10270         */
10271        "mRender": null,
10272
10273        /**
10274         * The class to apply to all TD elements in the table's TBODY for the column
10275         */
10276        "sClass": null,
10277
10278        /**
10279         * When DataTables calculates the column widths to assign to each column,
10280         * it finds the longest string in each column and then constructs a
10281         * temporary table and reads the widths from that. The problem with this
10282         * is that "mmm" is much wider then "iiii", but the latter is a longer
10283         * string - thus the calculation can go wrong (doing it properly and putting
10284         * it into an DOM object and measuring that is horribly(!) slow). Thus as
10285         * a "work around" we provide this option. It will append its value to the
10286         * text that is found to be the longest string for the column - i.e. padding.
10287         */
10288        "sContentPadding": null,
10289
10290        /**
10291         * Allows a default value to be given for a column's data, and will be used
10292         * whenever a null data source is encountered (this can be because mData
10293         * is set to null, or because the data source itself is null).
10294         */
10295        "sDefaultContent": null,
10296
10297        /**
10298         * Name for the column, allowing reference to the column by name as well as
10299         * by index (needs a lookup to work by name).
10300         */
10301        "sName": null,
10302
10303        /**
10304         * Custom sorting data type - defines which of the available plug-ins in
10305         * afnSortData the custom sorting will use - if any is defined.
10306         */
10307        "sSortDataType": 'std',
10308
10309        /**
10310         * Class to be applied to the header element when sorting on this column
10311         */
10312        "sSortingClass": null,
10313
10314        /**
10315         * Title of the column - what is seen in the TH element (nTh).
10316         */
10317        "sTitle": null,
10318
10319        /**
10320         * Column sorting and filtering type
10321         */
10322        "sType": null,
10323
10324        /**
10325         * Width of the column
10326         */
10327        "sWidth": null,
10328
10329        /**
10330         * Width of the column when it was first "encountered"
10331         */
10332        "sWidthOrig": null,
10333
10334        /** Cached string which is the longest in the column */
10335        maxLenString: null,
10336
10337        /**
10338         * Store for named searches
10339         */
10340        searchFixed: null
10341    };
10342
10343
10344    /*
10345     * Developer note: The properties of the object below are given in Hungarian
10346     * notation, that was used as the interface for DataTables prior to v1.10, however
10347     * from v1.10 onwards the primary interface is camel case. In order to avoid
10348     * breaking backwards compatibility utterly with this change, the Hungarian
10349     * version is still, internally the primary interface, but is is not documented
10350     * - hence the @name tags in each doc comment. This allows a JavaScript function
10351     * to create a map from Hungarian notation to camel case (going the other direction
10352     * would require each property to be listed, which would add around 3K to the size
10353     * of DataTables, while this method is about a 0.5K hit).
10354     *
10355     * Ultimately this does pave the way for Hungarian notation to be dropped
10356     * completely, but that is a massive amount of work and will break current
10357     * installs (therefore is on-hold until v2).
10358     */
10359
10360    /**
10361     * Initialisation options that can be given to DataTables at initialisation
10362     * time.
10363     *  @namespace
10364     */
10365    DataTable.defaults = {
10366        /**
10367         * An array of data to use for the table, passed in at initialisation which
10368         * will be used in preference to any data which is already in the DOM. This is
10369         * particularly useful for constructing tables purely in JavaScript, for
10370         * example with a custom Ajax call.
10371         */
10372        "aaData": null,
10373
10374
10375        /**
10376         * If ordering is enabled, then DataTables will perform a first pass sort on
10377         * initialisation. You can define which column(s) the sort is performed
10378         * upon, and the sorting direction, with this variable. The `sorting` array
10379         * should contain an array for each column to be sorted initially containing
10380         * the column's index and a direction string ('asc' or 'desc').
10381         */
10382        "aaSorting": [[0, 'asc']],
10383
10384
10385        /**
10386         * This parameter is basically identical to the `sorting` parameter, but
10387         * cannot be overridden by user interaction with the table. What this means
10388         * is that you could have a column (visible or hidden) which the sorting
10389         * will always be forced on first - any sorting after that (from the user)
10390         * will then be performed as required. This can be useful for grouping rows
10391         * together.
10392         */
10393        "aaSortingFixed": [],
10394
10395
10396        /**
10397         * DataTables can be instructed to load data to display in the table from a
10398         * Ajax source. This option defines how that Ajax call is made and where to.
10399         *
10400         * The `ajax` property has three different modes of operation, depending on
10401         * how it is defined. These are:
10402         *
10403         * * `string` - Set the URL from where the data should be loaded from.
10404         * * `object` - Define properties for `jQuery.ajax`.
10405         * * `function` - Custom data get function
10406         *
10407         * `string`
10408         * --------
10409         *
10410         * As a string, the `ajax` property simply defines the URL from which
10411         * DataTables will load data.
10412         *
10413         * `object`
10414         * --------
10415         *
10416         * As an object, the parameters in the object are passed to
10417         * [jQuery.ajax](https://api.jquery.com/jQuery.ajax/) allowing fine control
10418         * of the Ajax request. DataTables has a number of default parameters which
10419         * you can override using this option. Please refer to the jQuery
10420         * documentation for a full description of the options available, although
10421         * the following parameters provide additional options in DataTables or
10422         * require special consideration:
10423         *
10424         * * `data` - As with jQuery, `data` can be provided as an object, but it
10425         *   can also be used as a function to manipulate the data DataTables sends
10426         *   to the server. The function takes a single parameter, an object of
10427         *   parameters with the values that DataTables has readied for sending. An
10428         *   object may be returned which will be merged into the DataTables
10429         *   defaults, or you can add the items to the object that was passed in and
10430         *   not return anything from the function. This supersedes `fnServerParams`
10431         *   from DataTables 1.9-.
10432         *
10433         * * `dataSrc` - By default DataTables will look for the property `data` (or
10434         *   `aaData` for compatibility with DataTables 1.9-) when obtaining data
10435         *   from an Ajax source or for server-side processing - this parameter
10436         *   allows that property to be changed. You can use JavaScript dotted
10437         *   object notation to get a data source for multiple levels of nesting, or
10438         *   it my be used as a function. As a function it takes a single parameter,
10439         *   the JSON returned from the server, which can be manipulated as
10440         *   required, with the returned value being that used by DataTables as the
10441         *   data source for the table.
10442         *
10443         * * `success` - Should not be overridden it is used internally in
10444         *   DataTables. To manipulate / transform the data returned by the server
10445         *   use `ajax.dataSrc`, or use `ajax` as a function (see below).
10446         *
10447         * `function`
10448         * ----------
10449         *
10450         * As a function, making the Ajax call is left up to yourself allowing
10451         * complete control of the Ajax request. Indeed, if desired, a method other
10452         * than Ajax could be used to obtain the required data, such as Web storage
10453         * or an AIR database.
10454         *
10455         * The function is given four parameters and no return is required. The
10456         * parameters are:
10457         *
10458         * 1. _object_ - Data to send to the server
10459         * 2. _function_ - Callback function that must be executed when the required
10460         *    data has been obtained. That data should be passed into the callback
10461         *    as the only parameter
10462         * 3. _object_ - DataTables settings object for the table
10463         */
10464        "ajax": null,
10465
10466
10467        /**
10468         * This parameter allows you to readily specify the entries in the length drop
10469         * down menu that DataTables shows when pagination is enabled. It can be
10470         * either a 1D array of options which will be used for both the displayed
10471         * option and the value, or a 2D array which will use the array in the first
10472         * position as the value, and the array in the second position as the
10473         * displayed options (useful for language strings such as 'All').
10474         *
10475         * Note that the `pageLength` property will be automatically set to the
10476         * first value given in this array, unless `pageLength` is also provided.
10477         */
10478        "aLengthMenu": [10, 25, 50, 100],
10479
10480
10481        /**
10482         * The `columns` option in the initialisation parameter allows you to define
10483         * details about the way individual columns behave. For a full list of
10484         * column options that can be set, please see
10485         * {@link DataTable.defaults.column}. Note that if you use `columns` to
10486         * define your columns, you must have an entry in the array for every single
10487         * column that you have in your table (these can be null if you don't which
10488         * to specify any options).
10489         */
10490        "aoColumns": null,
10491
10492        /**
10493         * Very similar to `columns`, `columnDefs` allows you to target a specific
10494         * column, multiple columns, or all columns, using the `targets` property of
10495         * each object in the array. This allows great flexibility when creating
10496         * tables, as the `columnDefs` arrays can be of any length, targeting the
10497         * columns you specifically want. `columnDefs` may use any of the column
10498         * options available: {@link DataTable.defaults.column}, but it _must_
10499         * have `targets` defined in each object in the array. Values in the `targets`
10500         * array may be:
10501         *   <ul>
10502         *     <li>a string - class name will be matched on the TH for the column</li>
10503         *     <li>0 or a positive integer - column index counting from the left</li>
10504         *     <li>a negative integer - column index counting from the right</li>
10505         *     <li>the string "_all" - all columns (i.e. assign a default)</li>
10506         *   </ul>
10507         */
10508        "aoColumnDefs": null,
10509
10510
10511        /**
10512         * Basically the same as `search`, this parameter defines the individual column
10513         * filtering state at initialisation time. The array must be of the same size
10514         * as the number of columns, and each element be an object with the parameters
10515         * `search` and `escapeRegex` (the latter is optional). 'null' is also
10516         * accepted and the default will be used.
10517         */
10518        "aoSearchCols": [],
10519
10520
10521        /**
10522         * Enable or disable automatic column width calculation. This can be disabled
10523         * as an optimisation (it takes some time to calculate the widths) if the
10524         * tables widths are passed in using `columns`.
10525         */
10526        "bAutoWidth": true,
10527
10528
10529        /**
10530         * Deferred rendering can provide DataTables with a huge speed boost when you
10531         * are using an Ajax or JS data source for the table. This option, when set to
10532         * true, will cause DataTables to defer the creation of the table elements for
10533         * each row until they are needed for a draw - saving a significant amount of
10534         * time.
10535         */
10536        "bDeferRender": true,
10537
10538
10539        /**
10540         * Replace a DataTable which matches the given selector and replace it with
10541         * one which has the properties of the new initialisation object passed. If no
10542         * table matches the selector, then the new DataTable will be constructed as
10543         * per normal.
10544         */
10545        "bDestroy": false,
10546
10547
10548        /**
10549         * Enable or disable filtering of data. Filtering in DataTables is "smart" in
10550         * that it allows the end user to input multiple words (space separated) and
10551         * will match a row containing those words, even if not in the order that was
10552         * specified (this allow matching across multiple columns). Note that if you
10553         * wish to use filtering in DataTables this must remain 'true' - to remove the
10554         * default filtering input box and retain filtering abilities, please use
10555         * {@link DataTable.defaults.dom}.
10556         */
10557        "bFilter": true,
10558
10559        /**
10560         * Used only for compatibility with DT1
10561         * @deprecated
10562         */
10563        "bInfo": true,
10564
10565        /**
10566         * Used only for compatibility with DT1
10567         * @deprecated
10568         */
10569        "bLengthChange": true,
10570
10571        /**
10572         * Enable or disable pagination.
10573         */
10574        "bPaginate": true,
10575
10576
10577        /**
10578         * Enable or disable the display of a 'processing' indicator when the table is
10579         * being processed (e.g. a sort). This is particularly useful for tables with
10580         * large amounts of data where it can take a noticeable amount of time to sort
10581         * the entries.
10582         */
10583        "bProcessing": false,
10584
10585
10586        /**
10587         * Retrieve the DataTables object for the given selector. Note that if the
10588         * table has already been initialised, this parameter will cause DataTables
10589         * to simply return the object that has already been set up - it will not take
10590         * account of any changes you might have made to the initialisation object
10591         * passed to DataTables (setting this parameter to true is an acknowledgement
10592         * that you understand this). `destroy` can be used to reinitialise a table if
10593         * you need.
10594         */
10595        "bRetrieve": false,
10596
10597
10598        /**
10599         * When vertical (y) scrolling is enabled, DataTables will force the height of
10600         * the table's viewport to the given height at all times (useful for layout).
10601         * However, this can look odd when filtering data down to a small data set,
10602         * and the footer is left "floating" further down. This parameter (when
10603         * enabled) will cause DataTables to collapse the table's viewport down when
10604         * the result set will fit within the given Y height.
10605         */
10606        "bScrollCollapse": false,
10607
10608
10609        /**
10610         * Configure DataTables to use server-side processing. Note that the
10611         * `ajax` parameter must also be given in order to give DataTables a
10612         * source to obtain the required data for each draw.
10613         */
10614        "bServerSide": false,
10615
10616
10617        /**
10618         * Enable or disable sorting of columns. Sorting of individual columns can be
10619         * disabled by the `sortable` option for each column.
10620         */
10621        "bSort": true,
10622
10623
10624        /**
10625         * Enable or display DataTables' ability to sort multiple columns at the
10626         * same time (activated by shift-click by the user).
10627         */
10628        "bSortMulti": true,
10629
10630
10631        /**
10632         * Allows control over whether DataTables should use the top (true) unique
10633         * cell that is found for a single column, or the bottom (false - default).
10634         * This is useful when using complex headers.
10635         */
10636        "bSortCellsTop": null,
10637
10638
10639        /** Specify which row is the title row in the header. Replacement for bSortCellsTop */
10640        titleRow: null,
10641
10642
10643        /**
10644         * Enable or disable the addition of the classes `sorting\_1`, `sorting\_2` and
10645         * `sorting\_3` to the columns which are currently being sorted on. This is
10646         * presented as a feature switch as it can increase processing time (while
10647         * classes are removed and added) so for large data sets you might want to
10648         * turn this off.
10649         */
10650        "bSortClasses": true,
10651
10652
10653        /**
10654         * Enable or disable state saving. When enabled HTML5 `localStorage` will be
10655         * used to save table display information such as pagination information,
10656         * display length, filtering and sorting. As such when the end user reloads
10657         * the page the display will match what thy had previously set up.
10658         */
10659        "bStateSave": false,
10660
10661
10662        /**
10663         * This function is called when a TR element is created (and all TD child
10664         * elements have been inserted), or registered if using a DOM source, allowing
10665         * manipulation of the TR element (adding classes etc).
10666         */
10667        "fnCreatedRow": null,
10668
10669
10670        /**
10671         * This function is called on every 'draw' event, and allows you to
10672         * dynamically modify any aspect you want about the created DOM.
10673         */
10674        "fnDrawCallback": null,
10675
10676
10677        /**
10678         * Identical to fnHeaderCallback() but for the table footer this function
10679         * allows you to modify the table footer on every 'draw' event.
10680         */
10681        "fnFooterCallback": null,
10682
10683
10684        /**
10685         * When rendering large numbers in the information element for the table
10686         * (i.e. "Showing 1 to 10 of 57 entries") DataTables will render large numbers
10687         * to have a comma separator for the 'thousands' units (e.g. 1 million is
10688         * rendered as "1,000,000") to help readability for the end user. This
10689         * function will override the default method DataTables uses.
10690         */
10691        "fnFormatNumber": function (toFormat) {
10692            return toFormat.toString().replace(
10693                /\B(?=(\d{3})+(?!\d))/g,
10694                this.oLanguage.sThousands
10695            );
10696        },
10697
10698
10699        /**
10700         * This function is called on every 'draw' event, and allows you to
10701         * dynamically modify the header row. This can be used to calculate and
10702         * display useful information about the table.
10703         */
10704        "fnHeaderCallback": null,
10705
10706
10707        /**
10708         * The information element can be used to convey information about the current
10709         * state of the table. Although the internationalisation options presented by
10710         * DataTables are quite capable of dealing with most customisations, there may
10711         * be times where you wish to customise the string further. This callback
10712         * allows you to do exactly that.
10713         */
10714        "fnInfoCallback": null,
10715
10716
10717        /**
10718         * Called when the table has been initialised. Normally DataTables will
10719         * initialise sequentially and there will be no need for this function,
10720         * however, this does not hold true when using external language information
10721         * since that is obtained using an async XHR call.
10722         */
10723        "fnInitComplete": null,
10724
10725
10726        /**
10727         * Called at the very start of each table draw and can be used to cancel the
10728         * draw by returning false, any other return (including undefined) results in
10729         * the full draw occurring).
10730         */
10731        "fnPreDrawCallback": null,
10732
10733
10734        /**
10735         * This function allows you to 'post process' each row after it have been
10736         * generated for each table draw, but before it is rendered on screen. This
10737         * function might be used for setting the row class name etc.
10738         */
10739        "fnRowCallback": null,
10740
10741
10742        /**
10743         * Load the table state. With this function you can define from where, and how, the
10744         * state of a table is loaded. By default DataTables will load from `localStorage`
10745         * but you might wish to use a server-side database or cookies.
10746         */
10747        "fnStateLoadCallback": function (settings) {
10748            try {
10749                return JSON.parse(
vendor: 6,206 bytes, lines 10750-10914
10750                    (settings.iStateDuration === -1 ? sessionStorage : localStorage).getItem(
10751                        'DataTables_' + settings.sInstance + '_' + location.pathname
10752                    )
10753                );
10754            } catch (e) {
10755                return {};
10756            }
10757        },
10758
10759
10760        /**
10761         * Callback which allows modification of the saved state prior to loading that state.
10762         * This callback is called when the table is loading state from the stored data, but
10763         * prior to the settings object being modified by the saved state. Note that for
10764         * plug-in authors, you should use the `stateLoadParams` event to load parameters for
10765         * a plug-in.
10766         */
10767        "fnStateLoadParams": null,
10768
10769
10770        /**
10771         * Callback that is called when the state has been loaded from the state saving method
10772         * and the DataTables settings object has been modified as a result of the loaded state.
10773         */
10774        "fnStateLoaded": null,
10775
10776
10777        /**
10778         * Save the table state. This function allows you to define where and how the state
10779         * information for the table is stored By default DataTables will use `localStorage`
10780         * but you might wish to use a server-side database or cookies.
10781         */
10782        "fnStateSaveCallback": function (settings, data) {
10783            try {
10784                (settings.iStateDuration === -1 ? sessionStorage : localStorage).setItem(
10785                    'DataTables_' + settings.sInstance + '_' + location.pathname,
10786                    JSON.stringify(data)
10787                );
10788            } catch (e) {
10789                // noop
10790            }
10791        },
10792
10793
10794        /**
10795         * Callback which allows modification of the state to be saved. Called when the table
10796         * has changed state a new state save is required. This method allows modification of
10797         * the state saving object prior to actually doing the save, including addition or
10798         * other state properties or modification. Note that for plug-in authors, you should
10799         * use the `stateSaveParams` event to save parameters for a plug-in.
10800         */
10801        "fnStateSaveParams": null,
10802
10803
10804        /**
10805         * Duration for which the saved state information is considered valid. After this period
10806         * has elapsed the state will be returned to the default.
10807         * Value is given in seconds.
10808         */
10809        "iStateDuration": 7200,
10810
10811
10812        /**
10813         * Number of rows to display on a single page when using pagination. If
10814         * feature enabled (`lengthChange`) then the end user will be able to override
10815         * this to a custom setting using a pop-up menu.
10816         */
10817        "iDisplayLength": 10,
10818
10819
10820        /**
10821         * Define the starting point for data display when using DataTables with
10822         * pagination. Note that this parameter is the number of records, rather than
10823         * the page number, so if you have 10 records per page and want to start on
10824         * the third page, it should be "20".
10825         */
10826        "iDisplayStart": 0,
10827
10828
10829        /**
10830         * By default DataTables allows keyboard navigation of the table (sorting, paging,
10831         * and filtering) by adding a `tabindex` attribute to the required elements. This
10832         * allows you to tab through the controls and press the enter key to activate them.
10833         * The tabindex is default 0, meaning that the tab follows the flow of the document.
10834         * You can overrule this using this parameter if you wish. Use a value of -1 to
10835         * disable built-in keyboard navigation.
10836         */
10837        "iTabIndex": 0,
10838
10839
10840        /**
10841         * Classes that DataTables assigns to the various components and features
10842         * that it adds to the HTML table. This allows classes to be configured
10843         * during initialisation in addition to through the static
10844         * {@link DataTable.ext.oStdClasses} object).
10845         */
10846        "oClasses": {},
10847
10848
10849        /**
10850         * All strings that DataTables uses in the user interface that it creates
10851         * are defined in this object, allowing you to modified them individually or
10852         * completely replace them all as required.
10853         */
10854        "oLanguage": {
10855            /**
10856             * Strings that are used for WAI-ARIA labels and controls only (these are not
10857             * actually visible on the page, but will be read by screenreaders, and thus
10858             * must be internationalised as well).
10859             */
10860            "oAria": {
10861                /**
10862                 * ARIA label that is added to the table headers when the column may be sorted
10863                 */
10864                "orderable": ": Activate to sort",
10865
10866                /**
10867                 * ARIA label that is added to the table headers when the column is currently being sorted
10868                 */
10869                "orderableReverse": ": Activate to invert sorting",
10870
10871                /**
10872                 * ARIA label that is added to the table headers when the column is currently being 
10873                 * sorted and next step is to remove sorting
10874                 */
10875                "orderableRemove": ": Activate to remove sorting",
10876
10877                paginate: {
10878                    first: 'First',
10879                    last: 'Last',
10880                    next: 'Next',
10881                    previous: 'Previous',
10882                    number: ''
10883                }
10884            },
10885
10886            /**
10887             * Pagination string used by DataTables for the built-in pagination
10888             * control types.
10889             */
10890            "oPaginate": {
10891                /**
10892                 * Label and character for first page button («)
10893                 */
10894                "sFirst": "\u00AB",
10895
10896                /**
10897                 * Last page button (»)
10898                 */
10899                "sLast": "\u00BB",
10900
10901                /**
10902                 * Next page button (›)
10903                 */
10904                "sNext": "\u203A",
10905
10906                /**
10907                 * Previous page button (‹)
10908                 */
10909                "sPrevious": "\u2039",
10910            },
10911
10912            /**
10913             * Plural object for the data type the table is showing
10914             */
10915            entries: {
10916                _: "entries",
10917                1: "entry"
10918            },
10919
10920            /**
10921             * Page length options
10922             */
10923            lengthLabels: {
10924                '-1': 'All'
10925            },
10926
10927            /**
10928             * This string is shown in preference to `zeroRecords` when the table is
10929             * empty of data (regardless of filtering). Note that this is an optional
10930             * parameter - if it is not given, the value of `zeroRecords` will be used
10931             * instead (either the default or given value).
10932             */
10933            "sEmptyTable": "No data available in table",
10934
10935
10936            /**
10937             * This string gives information to the end user about the information
10938             * that is current on display on the page. The following tokens can be
10939             * used in the string and will be dynamically replaced as the table
10940             * display updates. This tokens can be placed anywhere in the string, or
10941             * removed as needed by the language requires:
10942             *
10943             * * `\_START\_` - Display index of the first record on the current page
10944             * * `\_END\_` - Display index of the last record on the current page
10945             * * `\_TOTAL\_` - Number of records in the table after filtering
10946             * * `\_MAX\_` - Number of records in the table without filtering
10947             * * `\_PAGE\_` - Current page number
10948             * * `\_PAGES\_` - Total number of pages of data in the table
10949             */
10950            "sInfo": "Showing _START_ to _END_ of _TOTAL_ _ENTRIES-TOTAL_",
10951
10952
10953            /**
10954             * Display information string for when the table is empty. Typically the
10955             * format of this string should match `info`.
10956             */
10957            "sInfoEmpty": "Showing 0 to 0 of 0 _ENTRIES-TOTAL_",
10958
10959
10960            /**
10961             * When a user filters the information in a table, this string is appended
10962             * to the information (`info`) to give an idea of how strong the filtering
10963             * is. The variable _MAX_ is dynamically updated.
10964             */
10965            "sInfoFiltered": "(filtered from _MAX_ total _ENTRIES-MAX_)",
10966
10967
10968            /**
10969             * If can be useful to append extra information to the info string at times,
10970             * and this variable does exactly that. This information will be appended to
10971             * the `info` (`infoEmpty` and `infoFiltered` in whatever combination they are
10972             * being used) at all times.
10973             */
10974            "sInfoPostFix": "",
10975
10976
10977            /**
10978             * This decimal place operator is a little different from the other
10979             * language options since DataTables doesn't output floating point
10980             * numbers, so it won't ever use this for display of a number. Rather,
10981             * what this parameter does is modify the sort methods of the table so
10982             * that numbers which are in a format which has a character other than
10983             * a period (`.`) as a decimal place will be sorted numerically.
10984             *
10985             * Note that numbers with different decimal places cannot be shown in
10986             * the same table and still be sortable, the table must be consistent.
10987             * However, multiple different tables on the page can use different
10988             * decimal place characters.
10989             */
10990            "sDecimal": "",
10991
10992
10993            /**
10994             * DataTables has a build in number formatter (`formatNumber`) which is
10995             * used to format large numbers that are used in the table information.
10996             * By default a comma is used, but this can be trivially changed to any
10997             * character you wish with this parameter.
10998             */
10999            "sThousands": ",",
11000
11001
11002            /**
11003             * Detail the action that will be taken when the drop down menu for the
11004             * pagination length option is changed. The '_MENU_' variable is replaced
11005             * with a default select list of 10, 25, 50 and 100, and can be replaced
11006             * with a custom select box if required.
11007             */
11008            "sLengthMenu": "_MENU_ _ENTRIES_ per page",
11009
11010
11011            /**
11012             * When using Ajax sourced data and during the first draw when DataTables is
11013             * gathering the data, this message is shown in an empty row in the table to
11014             * indicate to the end user the data is being loaded. Note that this
11015             * parameter is not used when loading data by server-side processing, just
11016             * Ajax sourced data with client-side processing.
11017             */
11018            "sLoadingRecords": "Loading...",
11019
11020
11021            /**
11022             * Text which is displayed when the table is processing a user action
11023             * (usually a sort command or similar).
11024             */
11025            "sProcessing": "",
11026
11027
11028            /**
11029             * Details the actions that will be taken when the user types into the
11030             * filtering input text box. The variable "_INPUT_", if used in the string,
11031             * is replaced with the HTML text box for the filtering input allowing
11032             * control over where it appears in the string. If "_INPUT_" is not given
11033             * then the input box is appended to the string automatically.
11034             */
11035            "sSearch": "Search:",
11036
11037
11038            /**
11039             * Assign a `placeholder` attribute to the search `input` element
11040             *  @type string
11041             *  @default 
11042             *
11043             *  @dtopt Language
11044             *  @name DataTable.defaults.language.searchPlaceholder
11045             */
11046            "sSearchPlaceholder": "",
11047
11048
11049            /**
11050             * All of the language information can be stored in a file on the
11051             * server-side, which DataTables will look up if this parameter is passed.
11052             * It must store the URL of the language file, which is in a JSON format,
11053             * and the object has the same properties as the oLanguage object in the
11054             * initialiser object (i.e. the above parameters). Please refer to one of
11055             * the example language files to see how this works in action.
11056             */
11057            "sUrl": "",
11058
11059
11060            /**
11061             * Text shown inside the table records when the is no information to be
11062             * displayed after filtering. `emptyTable` is shown when there is simply no
11063             * information in the table at all (regardless of filtering).
11064             */
11065            "sZeroRecords": "No matching records found"
11066        },
11067
11068
11069        /** The initial data order is reversed when `desc` ordering */
11070        orderDescReverse: true,
11071
11072
11073        /**
11074         * This parameter allows you to have define the global filtering state at
11075         * initialisation time. As an object the `search` parameter must be
11076         * defined, but all other parameters are optional. When `regex` is true,
11077         * the search string will be treated as a regular expression, when false
11078         * (default) it will be treated as a straight string. When `smart`
11079         * DataTables will use it's smart filtering methods (to word match at
11080         * any point in the data), when false this will not be done.
11081         */
11082        "oSearch": $.extend({}, DataTable.models.oSearch),
11083
11084
11085        /**
11086         * Table and control layout. This replaces the legacy `dom` option.
11087         */
11088        layout: {
11089            topStart: 'pageLength',
11090            topEnd: 'search',
11091            bottomStart: 'info',
11092            bottomEnd: 'paging'
11093        },
11094
11095
11096        /**
11097         * Legacy DOM layout option
11098         */
11099        "sDom": null,
11100
11101
11102        /**
11103         * Search delay option. This will throttle full table searches that use the
11104         * DataTables provided search input element (it does not effect calls to
11105         * `dt-api search()`, providing a delay before the search is made.
11106         */
11107        "searchDelay": null,
11108
11109
11110        /**
11111         * DataTables features six different built-in options for the buttons to
11112         * display for pagination control:
11113         *
11114         * * `numbers` - Page number buttons only
11115         * * `simple` - 'Previous' and 'Next' buttons only
11116         * * 'simple_numbers` - 'Previous' and 'Next' buttons, plus page numbers
11117         * * `full` - 'First', 'Previous', 'Next' and 'Last' buttons
11118         * * `full_numbers` - 'First', 'Previous', 'Next' and 'Last' buttons, plus page numbers
11119         * * `first_last_numbers` - 'First' and 'Last' buttons, plus page numbers
11120         */
11121        "sPaginationType": "",
11122
11123
11124        /**
11125         * Enable horizontal scrolling. When a table is too wide to fit into a
11126         * certain layout, or you have a large number of columns in the table, you
11127         * can enable x-scrolling to show the table in a viewport, which can be
11128         * scrolled. This property can be `true` which will allow the table to
11129         * scroll horizontally when needed, or any CSS unit, or a number (in which
11130         * case it will be treated as a pixel measurement). Setting as simply `true`
11131         * is recommended.
11132         */
11133        "sScrollX": "",
11134
11135
11136        /**
11137         * This property can be used to force a DataTable to use more width than it
11138         * might otherwise do when x-scrolling is enabled. For example if you have a
11139         * table which requires to be well spaced, this parameter is useful for
11140         * "over-sizing" the table, and thus forcing scrolling. This property can by
11141         * any CSS unit, or a number (in which case it will be treated as a pixel
11142         * measurement).
11143         */
11144        "sScrollXInner": "",
11145
11146
11147        /**
11148         * Enable vertical scrolling. Vertical scrolling will constrain the DataTable
11149         * to the given height, and enable scrolling for any data which overflows the
11150         * current viewport. This can be used as an alternative to paging to display
11151         * a lot of data in a small area (although paging and scrolling can both be
11152         * enabled at the same time). This property can be any CSS unit, or a number
11153         * (in which case it will be treated as a pixel measurement).
11154         */
11155        "sScrollY": "",
11156
11157
11158        /**
11159         * __Deprecated__ The functionality provided by this parameter has now been
11160         * superseded by that provided through `ajax`, which should be used instead.
11161         *
11162         * Set the HTTP method that is used to make the Ajax call for server-side
11163         * processing or Ajax sourced data.
11164         */
11165        "sServerMethod": "GET",
11166
11167
11168        /**
11169         * DataTables makes use of renderers when displaying HTML elements for
11170         * a table. These renderers can be added or modified by plug-ins to
11171         * generate suitable mark-up for a site. For example the Bootstrap
11172         * integration plug-in for DataTables uses a paging button renderer to
11173         * display pagination buttons in the mark-up required by Bootstrap.
11174         *
11175         * For further information about the renderers available see
11176         * DataTable.ext.renderer
11177         */
11178        "renderer": null,
11179
11180
11181        /**
11182         * Set the data property name that DataTables should use to get a row's id
11183         * to set as the `id` property in the node.
11184         */
11185        "rowId": "DT_RowId",
11186
11187
11188        /**
11189         * Caption value
11190         */
11191        "caption": null,
11192
11193
11194        /**
11195         * For server-side processing - use the data from the DOM for the first draw
11196         */
11197        iDeferLoading: null,
11198
11199        /** Event listeners */
11200        on: null
11201    };
11202
11203    _fnHungarianMap(DataTable.defaults);
11204
11205
11206
11207    /*
11208     * Developer note - See note in model.defaults.js about the use of Hungarian
11209     * notation and camel case.
11210     */
11211
11212    /**
11213     * Column options that can be given to DataTables at initialisation time.
11214     *  @namespace
11215     */
11216    DataTable.defaults.column = {
11217        /**
11218         * Define which column(s) an order will occur on for this column. This
11219         * allows a column's ordering to take multiple columns into account when
11220         * doing a sort or use the data from a different column. For example first
11221         * name / last name columns make sense to do a multi-column sort over the
11222         * two columns.
11223         */
11224        "aDataSort": null,
11225        "iDataSort": -1,
11226
11227        ariaTitle: '',
11228
11229
11230        /**
11231         * You can control the default ordering direction, and even alter the
11232         * behaviour of the sort handler (i.e. only allow ascending ordering etc)
11233         * using this parameter.
11234         */
11235        "asSorting": ['asc', 'desc', ''],
11236
11237
11238        /**
11239         * Enable or disable filtering on the data in this column.
11240         */
11241        "bSearchable": true,
11242
11243
11244        /**
11245         * Enable or disable ordering on this column.
11246         */
11247        "bSortable": true,
11248
11249
11250        /**
11251         * Enable or disable the display of this column.
11252         */
11253        "bVisible": true,
11254
11255
11256        /**
11257         * Developer definable function that is called whenever a cell is created (Ajax source,
11258         * etc) or processed for input (DOM source). This can be used as a compliment to mRender
11259         * allowing you to modify the DOM element (add background colour for example) when the
11260         * element is available.
11261         */
11262        "fnCreatedCell": null,
11263
11264
11265        /**
11266         * This property can be used to read data from any data source property,
11267         * including deeply nested objects / properties. `data` can be given in a
11268         * number of different ways which effect its behaviour:
11269         *
11270         * * `integer` - treated as an array index for the data source. This is the
11271         *   default that DataTables uses (incrementally increased for each column).
11272         * * `string` - read an object property from the data source. There are
11273         *   three 'special' options that can be used in the string to alter how
11274         *   DataTables reads the data from the source object:
11275         *    * `.` - Dotted JavaScript notation. Just as you use a `.` in
11276         *      JavaScript to read from nested objects, so to can the options
11277         *      specified in `data`. For example: `browser.version` or
11278         *      `browser.name`. If your object parameter name contains a period, use
11279         *      `\\` to escape it - i.e. `first\\.name`.
11280         *    * `[]` - Array notation. DataTables can automatically combine data
11281         *      from and array source, joining the data with the characters provided
11282         *      between the two brackets. For example: `name[, ]` would provide a
11283         *      comma-space separated list from the source array. If no characters
11284         *      are provided between the brackets, the original array source is
11285         *      returned.
11286         *    * `()` - Function notation. Adding `()` to the end of a parameter will
11287         *      execute a function of the name given. For example: `browser()` for a
11288         *      simple function on the data source, `browser.version()` for a
11289         *      function in a nested property or even `browser().version` to get an
11290         *      object property if the function called returns an object. Note that
11291         *      function notation is recommended for use in `render` rather than
11292         *      `data` as it is much simpler to use as a renderer.
11293         * * `null` - use the original data source for the row rather than plucking
11294         *   data directly from it. This action has effects on two other
11295         *   initialisation options:
11296         *    * `defaultContent` - When null is given as the `data` option and
11297         *      `defaultContent` is specified for the column, the value defined by
11298         *      `defaultContent` will be used for the cell.
11299         *    * `render` - When null is used for the `data` option and the `render`
11300         *      option is specified for the column, the whole data source for the
11301         *      row is used for the renderer.
11302         * * `function` - the function given will be executed whenever DataTables
11303         *   needs to set or get the data for a cell in the column. The function
11304         *   takes three parameters:
11305         *    * Parameters:
11306         *      * `{array|object}` The data source for the row
11307         *      * `{string}` The type call data requested - this will be 'set' when
11308         *        setting data or 'filter', 'display', 'type', 'sort' or undefined
11309         *        when gathering data. Note that when `undefined` is given for the
11310         *        type DataTables expects to get the raw data for the object back<
11311         *      * `{*}` Data to set when the second parameter is 'set'.
11312         *    * Return:
11313         *      * The return value from the function is not required when '
11313set' is
11314         *        the type of call, but otherwise the return is what will be used
11315         *        for the data requested.
11316         *
11317         * Note that `data` is a getter and setter option. If you just require
11318         * formatting of data for output, you will likely want to use `render` which
11319         * is simply a getter and thus simpler to use.
11320         *
11321         * Note that prior to DataTables 1.9.2 `data` was called `mDataProp`. The
11322         * name change reflects the flexibility of this property and is consistent
11323         * with the naming of mRender. If 'mDataProp' is given, then it will still
11324         * be used by DataTables, as it automatically maps the old name to the new
11325         * if required.
11326         */
11327        "mData": null,
11328
11329
11330        /**
11331         * This property is the rendering partner to `data` and it is suggested that
11332         * when you want to manipulate data for display (including filtering,
11333         * sorting etc) without altering the underlying data for the table, use this
11334         * property. `render` can be considered to be the read only companion to
11335         * `data` which is read / write (then as such more complex). Like `data`
11336         * this option can be given in a number of different ways to effect its
11337         * behaviour:
11338         *
11339         * * `integer` - treated as an array index for the data source. This is the
11340         *   default that DataTables uses (incrementally increased for each column).
11341         * * `string` - read an object property from the data source. There are
11342         *   three 'special' options that can be used in the string to alter how
11343         *   DataTables reads the data from the source object:
11344         *    * `.` - Dotted JavaScript notation. Just as you use a `.` in
11345         *      JavaScript to read from nested objects, so to can the options
11346         *      specified in `data`. For example: `browser.version` or
11347         *      `browser.name`. If your object parameter name contains a period, use
11348         *      `\\` to escape it - i.e. `first\\.name`.
11349         *    * `[]` - Array notation. DataTables can automatically combine data
11350         *      from and array source, joining the data with the characters provided
11351         *      between the two brackets. For example: `name[, ]` would provide a
11352         *      comma-space separated list from the source array. If no characters
11353         *      are provided between the brackets, the original array source is
11354         *      returned.
11355         *    * `()` - Function notation. Adding `()` to the end of a parameter will
11356         *      execute a function of the name given. For example: `browser()` for a
11357         *      simple function on the data source, `browser.version()` for a
11358         *      function in a nested property or even `browser().version` to get an
11359         *      object property if the function called returns an object.
11360         * * `object` - use different data for the different data types requested by
11361         *   DataTables ('filter', 'display', 'type' or 'sort'). The property names
11362         *   of the object is the data type the property refers to and the value can
11363         *   defined using an integer, string or function using the same rules as
11364         *   `render` normally does. Note that an `_` option _must_ be specified.
11365         *   This is the default value to use if you haven't specified a value for
11366         *   the data type requested by DataTables.
11367         * * `function` - the function given will be executed whenever DataTables
11368         *   needs to set or get the data for a cell in the column. The function
11369         *   takes three parameters:
11370         *    * Parameters:
11371         *      * {array|object} The data source for the row (based on `data`)
11372         *      * {string} The type call data requested - this will be 'filter',
11373         *        'display', 'type' or 'sort'.
11374         *      * {array|object} The full data source for the row (not based on
11375         *        `data`)
11376         *    * Return:
11377         *      * The return value from the function is what will be used for the
11378         *        data requested.
11379         */
11380        "mRender": null,
11381
11382
11383        /**
11384         * Change the cell type created for the column - either TD cells or TH cells. This
11385         * can be useful as TH cells have semantic meaning in the table body, allowing them
11386         * to act as a header for a row (you may wish to add scope='row' to the TH elements).
11387         */
11388        "sCellType": "td",
11389
11390
11391        /**
11392         * Class to give to each cell in this column.
11393         */
11394        "sClass": "",
11395
11396        /**
11397         * When DataTables calculates the column widths to assign to each column,
11398         * it finds the longest string in each column and then constructs a
11399         * temporary table and reads the widths from that. The problem with this
11400         * is that "mmm" is much wider then "iiii", but the latter is a longer
11401         * string - thus the calculation can go wrong (doing it properly and putting
11402         * it into an DOM object and measuring that is horribly(!) slow). Thus as
11403         * a "work around" we provide this option. It will append its value to the
11404         * text that is found to be the longest string for the column - i.e. padding.
11405         * Generally you shouldn't need this!
11406         */
11407        "sContentPadding": "",
11408
11409
11410        /**
11411         * Allows a default value to be given for a column's data, and will be used
11412         * whenever a null data source is encountered (this can be because `data`
11413         * is set to null, or because the data source itself is null).
11414         */
11415        "sDefaultContent": null,
11416
11417
11418        /**
11419         * This parameter is only used in DataTables' server-side processing. It can
11420         * be exceptionally useful to know what columns are being displayed on the
11421         * client side, and to map these to database fields. When defined, the names
11422         * also allow DataTables to reorder information from the server if it comes
11423         * back in an unexpected order (i.e. if you switch your columns around on the
11424         * client-side, your server-side code does not also need updating).
11425         */
11426        "sName": "",
11427
11428
11429        /**
11430         * Defines a data source type for the ordering which can be used to read
11431         * real-time information from the table (updating the internally cached
11432         * version) prior to ordering. This allows ordering to occur on user
11433         * editable elements such as form inputs.
11434         */
11435        "sSortDataType": "std",
11436
11437
11438        /**
11439         * The title of this column.
11440         */
11441        "sTitle": null,
11442
11443
11444        /**
11445         * The type allows you to specify how the data for this column will be
11446         * ordered. Four types (string, numeric, date and html (which will strip
11447         * HTML tags before ordering)) are currently available. Note that only date
11448         * formats understood by JavaScript's Date() object will be accepted as type
11449         * date. For example: "Mar 26, 2008 5:03 PM". May take the values: 'string',
11450         * 'numeric', 'date' or 'html' (by default). Further types can be adding
11451         * through plug-ins.
11452         */
11453        "sType": null,
11454
11455
11456        /**
11457         * Defining the width of the column, this parameter may take any CSS value
11458         * (3em, 20px etc). DataTables applies 'smart' widths to columns which have not
11459         * been given a specific width through this interface ensuring that the table
11460         * remains readable.
11461         */
11462        "sWidth": null
11463    };
11464
11465    _fnHungarianMap(DataTable.defaults.column);
11466
11467
11468
11469    /**
11470     * DataTables settings object - this holds all the information needed for a
11471     * given table, including configuration, data and current application of the
11472     * table options. DataTables does not have a single instance for each DataTable
11473     * with the settings attached to that instance, but rather instances of the
11474     * DataTable "class" are created on-the-fly as needed (typically by a
11475     * $().dataTable() call) and the settings object is then applied to that
11476     * instance.
11477     *
11478     * Note that this object is related to {@link DataTable.defaults} but this
11479     * one is the internal data store for DataTables's cache of columns. It should
11480     * NOT be manipulated outside of DataTables. Any configuration should be done
11481     * through the initialisation options.
11482     */
11483    DataTable.models.oSettings = {
11484        /**
11485         * Primary features of DataTables and their enablement state.
11486         */
11487        "oFeatures": {
11488
11489            /**
11490             * Flag to say if DataTables should automatically try to calculate the
11491             * optimum table and columns widths (true) or not (false).
11492             * Note that this parameter will be set by the initialisation routine. To
11493             * set a default use {@link DataTable.defaults}.
11494             */
11495            "bAutoWidth": null,
11496
11497            /**
11498             * Delay the creation of TR and TD elements until they are actually
11499             * needed by a driven page draw. This can give a significant speed
11500             * increase for Ajax source and JavaScript source data, but makes no
11501             * difference at all for DOM and server-side processing tables.
11502             * Note that this parameter will be set by the initialisation routine. To
11503             * set a default use {@link DataTable.defaults}.
11504             */
11505            "bDeferRender": null,
11506
11507            /**
11508             * Enable filtering on the table or not. Note that if this is disabled
11509             * then there is no filtering at all on the table, including fnFilter.
11510             * To just remove the filtering input use sDom and remove the 'f' option.
11511             * Note that this parameter will be set by the initialisation routine. To
11512             * set a default use {@link DataTable.defaults}.
11513             */
11514            "bFilter": null,
11515
11516            /**
11517             * Used only for compatibility with DT1
11518             * @deprecated
11519             */
11520            "bInfo": true,
11521
11522            /**
11523             * Used only for compatibility with DT1
11524             * @deprecated
11525             */
11526            "bLengthChange": true,
11527
11528            /**
11529             * Pagination enabled or not. Note that if this is disabled then length
11530             * changing must also be disabled.
11531             * Note that this parameter will be set by the initialisation routine. To
11532             * set a default use {@link DataTable.defaults}.
11533             */
11534            "bPaginate": null,
11535
11536            /**
11537             * Processing indicator enable flag whenever DataTables is enacting a
11538             * user request - typically an Ajax request for server-side processing.
11539             * Note that this parameter will be set by the initialisation routine. To
11540             * set a default use {@link DataTable.defaults}.
11541             */
11542            "bProcessing": null,
11543
11544            /**
11545             * Server-side processing enabled flag - when enabled DataTables will
11546             * get all data from the server for every draw - there is no filtering,
11547             * sorting or paging done on the client-side.
11548             * Note that this parameter will be set by the initialisation routine. To
11549             * set a default use {@link DataTable.defaults}.
11550             */
11551            "bServerSide": null,
11552
11553            /**
11554             * Sorting enablement flag.
11555             * Note that this parameter will be set by the initialisation routine. To
11556             * set a default use {@link DataTable.defaults}.
11557             */
11558            "bSort": null,
11559
11560            /**
11561             * Multi-column sorting
11562             * Note that this parameter will be set by the initialisation routine. To
11563             * set a default use {@link DataTable.defaults}.
11564             */
11565            "bSortMulti": null,
11566
11567            /**
11568             * Apply a class to the columns which are being sorted to provide a
11569             * visual highlight or not. This can slow things down when enabled since
11570             * there is a lot of DOM interaction.
11571             * Note that this parameter will be set by the initialisation routine. To
11572             * set a default use {@link DataTable.defaults}.
11573             */
11574            "bSortClasses": null,
11575
11576            /**
11577             * State saving enablement flag.
11578             * Note that this parameter will be set by the initialisation routine. To
11579             * set a default use {@link DataTable.defaults}.
11580             */
11581            "bStateSave": null
11582        },
11583
11584
11585        /**
11586         * Scrolling settings for a table.
11587         */
11588        "oScroll": {
11589            /**
11590             * When the table is shorter in height than sScrollY, collapse the
11591             * table container down to the height of the table (when true).
11592             * Note that this parameter will be set by the initialisation routine. To
11593             * set a default use {@link DataTable.defaults}.
11594             */
11595            "bCollapse": null,
11596
11597            /**
11598             * Width of the scrollbar for the web-browser's platform. Calculated
11599             * during table initialisation.
11600             */
11601            "iBarWidth": 0,
11602
11603            /**
11604             * Viewport width for horizontal scrolling. Horizontal scrolling is
11605             * disabled if an empty string.
11606             * Note that this parameter will be set by the initialisation routine. To
11607             * set a default use {@link DataTable.defaults}.
11608             */
11609            "sX": null,
11610
11611            /**
11612             * Width to expand the table to when using x-scrolling. Typically you
11613             * should not need to use this.
11614             * Note that this parameter will be set by the initialisation routine. To
11615             * set a default use {@link DataTable.defaults}.
11616             *  @deprecated
11617             */
11618            "sXInner": null,
11619
11620            /**
11621             * Viewport height for vertical scrolling. Vertical scrolling is disabled
11622             * if an empty string.
11623             * Note that this parameter will be set by the initialisation routine. To
11624             * set a default use {@link DataTable.defaults}.
11625             */
11626            "sY": null
11627        },
11628
11629        /**
11630         * Language information for the table.
11631         */
11632        "oLanguage": {
11633            /**
11634             * Information callback function. See
11635             * {@link DataTable.defaults.fnInfoCallback}
11636             */
11637            "fnInfoCallback": null
11638        },
11639
11640        /**
11641         * Browser support parameters
11642         */
11643        "oBrowser": {
11644            /**
11645             * Determine if the vertical scrollbar is on the right or left of the
11646             * scrolling container - needed for rtl language layout, although not
11647             * all browsers move the scrollbar (Safari).
11648             */
11649            "bScrollbarLeft": false,
11650
11651            /**
11652             * Browser scrollbar width
11653             */
11654            "barWidth": 0
11655        },
11656
11657
11658        "ajax": null,
11659
11660
11661        /**
11662         * Array referencing the nodes which are used for the features. The
11663         * parameters of this object match what is allowed by sDom - i.e.
11664         *   <ul>
11665         *     <li>'l' - Length changing</li>
11666         *     <li>'f' - Filtering input</li>
11667         *     <li>'t' - The table!</li>
11668         *     <li>'i' - Information</li>
11669         *     <li>'p' - Pagination</li>
11670         *     <li>'r' - pRocessing</li>
11671         *   </ul>
11672         */
11673        "aanFeatures": [],
11674
11675        /**
11676         * Store data information - see {@link DataTable.models.oRow} for detailed
11677         * information.
11678         */
11679        "aoData": [],
11680
11681        /**
11682         * Array of indexes which are in the current display (after filtering etc)
11683         */
11684        "aiDisplay": [],
11685
11686        /**
11687         * Array of indexes for display - no filtering
11688         */
11689        "aiDisplayMaster": [],
11690
11691        /**
11692         * Map of row ids to data indexes
11693         */
11694        "aIds": {},
11695
11696        /**
11697         * Store information about each column that is in use
11698         */
11699        "aoColumns": [],
11700
11701        /**
11702         * Store information about the table's header
11703         */
11704        "aoHeader": [],
11705
11706        /**
11707         * Store information about the table's footer
11708         */
11709        "aoFooter": [],
11710
11711        /**
11712         * Store the applied global search information in case we want to force a
11713         * research or compare the old search to a new one.
11714         * Note that this parameter will be set by the initialisation routine. To
11715         * set a default use {@link DataTable.defaults}.
11716         */
11717        "oPreviousSearch": {},
11718
11719        /**
11720         * Store for named searches
11721         */
11722        searchFixed: {},
11723
11724        /**
11725         * Store the applied search for each column - see
11726         * {@link DataTable.models.oSearch} for the format that is used for the
11727         * filtering information for each column.
11728         */
11729        "aoPreSearchCols": [],
11730
11731        /**
11732         * Sorting that is applied to the table. Note that the inner arrays are
11733         * used in the following manner:
11734         * <ul>
11735         *   <li>Index 0 - column number</li>
11736         *   <li>Index 1 - current sorting direction</li>
11737         * </ul>
11738         * Note that this parameter will be set by the initialisation routine. To
11739         * set a default use {@link DataTable.defaults}.
11740         */
11741        "aaSorting": null,
11742
11743        /**
11744         * Sorting that is always applied to the table (i.e. prefixed in front of
11745         * aaSorting).
11746         * Note that this parameter will be set by the initialisation routine. To
11747         * set a default use {@link DataTable.defaults}.
11748         */
11749        "aaSortingFixed": [],
11750
11751        /**
11752         * If restoring a table - we should restore its width
11753         */
11754        "sDestroyWidth": 0,
11755
11756        /**
11757         * Callback functions array for every time a row is inserted (i.e. on a draw).
11758         */
11759        "aoRowCallback": [],
11760
11761        /**
11762         * Callback functions for the header on each draw.
11763         */
11764        "aoHeaderCallback": [],
11765
11766        /**
11767         * Callback function for the footer on each draw.
11768         */
11769        "aoFooterCallback": [],
11770
11771        /**
11772         * Array of callback functions for draw callback functions
11773         */
11774        "aoDrawCallback": [],
11775
11776        /**
11777         * Array of callback functions for row created function
11778         */
11779        "aoRowCreatedCallback": [],
11780
11781        /**
11782         * Callback functions for just before the table is redrawn. A return of
11783         * false will be used to cancel the draw.
11784         */
11785        "aoPreDrawCallback": [],
11786
11787        /**
11788         * Callback functions for when the table has been initialised.
11789         */
11790        "aoInitComplete": [],
11791
11792
11793        /**
11794         * Callbacks for modifying the settings to be stored for state saving, prior to
11795         * saving state.
11796         */
11797        "aoStateSaveParams": [],
11798
11799        /**
11800         * Callbacks for modifying the settings that have been stored for state saving
11801         * prior to using the stored values to restore the state.
11802         */
11803        "aoStateLoadParams": [],
11804
11805        /**
11806         * Callbacks for operating on the settings object once the saved state has been
11807         * loaded
11808         */
11809        "aoStateLoaded": [],
11810
11811        /**
11812         * Cache the table ID for quick access
11813         */
11814        "sTableId": "",
11815
11816        /**
11817         * The TABLE node for the main table
11818         */
11819        "nTable": null,
11820
11821        /**
11822         * Permanent ref to the thead element
11823         */
11824        "nTHead": null,
11825
11826        /**
11827         * Permanent ref to the tfoot element - if it exists
11828         */
11829        "nTFoot": null,
11830
11831        /**
11832         * Permanent ref to the tbody element
11833         */
11834        "nTBody": null,
11835
11836        /**
11837         * Cache the wrapper node (contains all DataTables controlled elements)
11838         */
11839        "nTableWrapper": null,
11840
11841        /**
11842         * Indicate if all required information has been read in
11843         */
11844        "bInitialised": false,
11845
11846        /**
11847         * Information about open rows. Each object in the array has the parameters
11848         * 'nTr' and 'nParent'
11849         */
11850        "aoOpenRows": [],
11851
11852        /**
11853         * Dictate the positioning of DataTables' control elements - see
11854         * {@link DataTable.model.oInit.sDom}.
11855         * Note that this parameter will be set by the initialisation routine. To
11856         * set a default use {@link DataTable.defaults}.
11857         */
11858        "sDom": null,
11859
11860        /**
11861         * Search delay (in mS)
11862         */
11863        "searchDelay": null,
11864
11865        /**
11866         * Which type of pagination should be used.
11867         * Note that this parameter will be set by the initialisation routine. To
11868         * set a default use {@link DataTable.defaults}.
11869         */
11870        "sPaginationType": "two_button",
11871
11872        /**
11873         * Number of paging controls on the page. Only used for backwards compatibility
11874         */
11875        pagingControls: 0,
11876
11877        /**
11878         * The state duration (for `stateSave`) in seconds.
11879         * Note that this parameter will be set by the initialisation routine. To
11880         * set a default use {@link DataTable.defaults}.
11881         */
11882        "iStateDuration": 0,
11883
11884        /**
11885         * Array of callback functions for state saving. Each array element is an
11886         * object with the following parameters:
11887         *   <ul>
11888         *     <li>function:fn - function to call. Takes two parameters, oSettings
11889         *       and the JSON string to save that has been thus far created. Returns
11890         *       a JSON string to be inserted into a json object
11891         *       (i.e. '"param": [ 0, 1, 2]')</li>
11892         *     <li>string:sName - name of callback</li>
11893         *   </ul>
11894         */
11895        "aoStateSave": [],
11896
11897        /**
11898         * Array of callback functions for state loading. Each array element is an
11899         * object with the following parameters:
11900         *   <ul>
11901         *     <li>function:fn - function to call. Takes two parameters, oSettings
11902         *       and the object stored. May return false to cancel state loading</li>
11903         *     <li>string:sName - name of callback</li>
11904         *   </ul>
11905         */
11906        "aoStateLoad": [],
11907
11908        /**
11909         * State that was saved. Useful for back reference
11910         */
11911        "oSavedState": null,
11912
11913        /**
11914         * State that was loaded. Useful for back reference
11915         */
11916        "oLoadedState": null,
11917
11918        /**
11919         * Note if draw should be blocked while getting data
11920         */
11921        "bAjaxDataGet": true,
11922
11923        /**
11924         * The last jQuery XHR object that was used for server-side data gathering.
11925         * This can be used for working with the XHR information in one of the
11926         * callbacks
11927         */
11928        "jqXHR": null,
11929
11930        /**
11931         * JSON returned from the server in the last Ajax request
11932         */
11933        "json": undefined,
11934
11935        /**
11936         * Data submitted as part of the last Ajax request
11937         */
11938        "oAjaxData": undefined,
11939
11940        /**
11941         * Send the XHR HTTP method - GET or POST (could be PUT or DELETE if
11942         * required).
11943         * Note that this parameter will be set by the initialisation routine. To
11944         * set a default use {@link DataTable.defaults}.
11945         */
11946        "sServerMethod": null,
11947
11948        /**
11949         * Format numbers for display.
11950         * Note that this parameter will be set by the initialisation routine. To
11951         * set a default use {@link DataTable.defaults}.
11952         */
11953        "fnFormatNumber": null,
11954
11955        /**
11956         * List of options that can be used for the user selectable length menu.
11957         * Note that this parameter will be set by the initialisation routine. To
11958         * set a default use {@link DataTable.defaults}.
11959         */
11960        "aLengthMenu": null,
11961
11962        /**
11963         * Counter for the draws that the table does. Also used as a tracker for
11964         * server-side processing
11965         */
11966        "iDraw": 0,
11967
11968        /**
11969         * Indicate if a redraw is being done - useful for Ajax
11970         */
11971        "bDrawing": false,
11972
11973        /**
11974         * Draw index (iDraw) of the last error when parsing the returned data
11975         */
11976        "iDrawError": -1,
11977
11978        /**
11979         * Paging display length
11980         */
11981        "_iDisplayLength": 10,
11982
11983        /**
11984         * Paging start point - aiDisplay index
11985         */
11986        "_iDisplayStart": 0,
11987
11988        /**
11989         * Server-side processing - number of records in the result set
11990         * (i.e. before filtering), Use fnRecordsTotal rather than
11991         * this property to get the value of the number of records, regardless of
11992         * the server-side processing setting.
11993         */
11994        "_iRecordsTotal": 0,
11995
11996        /**
11997         * Server-side processing - number of records in the current display set
11998         * (i.e. after filtering). Use fnRecordsDisplay rather than
11999         * this property to get the value of the number of records, regardless of
12000         * the server-side processing setting.
12001         */
12002        "_iRecordsDisplay": 0,
12003
12004        /**
12005         * The classes to use for the table
12006         */
12007        "oClasses": {},
12008
12009        /**
12010         * Flag attached to the settings object so you can check in the draw
12011         * callback if filtering has been done in the draw. Deprecated in favour of
12012         * events.
12013         *  @deprecated
12014         */
12015        "bFiltered": false,
12016
12017        /**
12018         * Flag attached to the settings object so you can check in the draw
12019         * callback if sorting has been done in the draw. Deprecated in favour of
12020         * events.
12021         *  @deprecated
12022         */
12023        "bSorted": false,
12024
12025        /**
12026         * Indicate that if multiple rows are in the header and there is more than
12027         * one unique cell per column. Replaced by titleRow
12028         */
12029        "bSortCellsTop": null,
12030
12031        /**
12032         * Initialisation object that is used for the table
12033         */
12034        "oInit": null,
12035
12036        /**
12037         * Destroy callback functions - for plug-ins to attach themselves to the
12038         * destroy so they can clean up markup and events.
12039         */
12040        "aoDestroyCallback": [],
12041
12042
12043        /**
12044         * Get the number of records in the current record set, before filtering
12045         */
12046        "fnRecordsTotal": function () {
12047            return _fnDataSource(this) == 'ssp' ?
12048                this._iRecordsTotal * 1 :
12049                this.aiDisplayMaster.length;
12050        },
12051
12052        /**
12053         * Get the number of records in the current record set, after filtering
12054         */
12055        "fnRecordsDisplay": function () {
12056            return _fnDataSource(this) == 'ssp' ?
12057                this._iRecordsDisplay * 1 :
12058                this.aiDisplay.length;
12059        },
12060
12061        /**
12062         * Get the display end point - aiDisplay index
12063         */
12064        "fnDisplayEnd": function () {
12065            var
12066                len = this._iDisplayLength,
12067                start = this._iDisplayStart,
12068                calc = start + len,
12069                records = this.aiDisplay.length,
12070                features = this.oFeatures,
12071                paginate = features.bPaginate;
12072
12073            if (features.bServerSide) {
12074                return paginate === false || len === -1 ?
12075                    start + records :
12076                    Math.min(start + len, this._iRecordsDisplay);
12077            }
12078            else {
12079                return !paginate || calc > records || len === -1 ?
12080                    records :
12081                    calc;
12082            }
12083        },
12084
12085        /**
12086         * The DataTables object for this table
12087         */
12088        "oInstance": null,
12089
12090        /**
12091         * Unique identifier for each instance of the DataTables object. If there
12092         * is an ID on the table node, then it takes that value, otherwise an
12093         * incrementing internal counter is used.
12094         */
12095        "sInstance": null,
12096
12097        /**
12098         * tabindex attribute value that is added to DataTables control elements, allowing
12099         * keyboard navigation of the table and its controls.
12100         */
12101        "iTabIndex": 0,
12102
12103        /**
12104         * DIV container for the footer scrolling table if scrolling
12105         */
12106        "nScrollHead": null,
12107
12108        /**
12109         * DIV container for the footer scrolling table if scrolling
12110         */
12111        "nScrollFoot": null,
12112
12113        /**
12114         * Last applied sort
12115         */
12116        "aLastSort": [],
12117
12118        /**
12119         * Stored plug-in instances
12120         */
12121        "oPlugins": {},
12122
12123        /**
12124         * Function used to get a row's id from the row's data
12125         */
12126        "rowIdFn": null,
12127
12128        /**
12129         * Data location where to store a row's id
12130         */
12131        "rowId": null,
12132
12133        caption: '',
12134
12135        captionNode: null,
12136
12137        colgroup: null,
12138
12139        /** Delay loading of data */
12140        deferLoading: null,
12141
12142        /** Allow auto type detection */
12143        typeDetect: true,
12144
12145        /** ResizeObserver for the container div */
12146        resizeObserver: null,
12147
12148        /** Keep a record of the last size of the container, so we can skip duplicates */
12149        containerWidth: -1,
12150
12151        /** Reverse the initial order of the data set on desc ordering */
12152        orderDescReverse: null,
12153
12154        /** Show / hide ordering indicators in headers */
12155        orderIndicators: true,
12156
12157        /** Default ordering listener */
12158        orderHandler: true,
12159
12160        /** Title row indicator */
12161        titleRow: null
12162    };
12163
12164    /**
12165     * Extension object for DataTables that is used to provide all extension
12166     * options.
12167     *
12168     * Note that the `DataTable.ext` object is available through
12169     * `jQuery.fn.dataTable.ext` where it may be accessed and manipulated. It is
12170     * also aliased to `jQuery.fn.dataTableExt` for historic reasons.
12171     *  @namespace
12172     *  @extends DataTable.models.ext
12173     */
12174
12175
12176    var extPagination = DataTable.ext.pager;
12177
12178    // Paging buttons configuration
12179    $.extend(extPagination, {
12180        simple: function () {
12181            return ['previous', 'next'];
12182        },
12183
12184        full: function () {
12185            return ['first', 'previous', 'next', 'last'];
12186        },
12187
12188        numbers: function () {
12189            return ['numbers'];
12190        },
12191
12192        simple_numbers: function () {
12193            return ['previous', 'numbers', 'next'];
12194        },
12195
12196        full_numbers: function () {
12197            return ['first', 'previous', 'numbers', 'next', 'last'];
12198        },
12199
12200        first_last: function () {
12201            return ['first', 'last'];
12202        },
12203
12204        first_last_numbers: function () {
12205            return ['first', 'numbers', 'last'];
12206        },
12207
12208        // For testing and plug-ins to use
12209        _numbers: _pagingNumbers,
12210
12211        // Number of number buttons - legacy, use `numbers` option for paging feature
12212        numbers_length: 7
12213    });
12214
12215
12216    $.extend(true, DataTable.ext.renderer, {
12217        pagingButton: {
12218            _: function (settings, buttonType, content, active, disabled) {
12219                var classes = settings.oClasses.paging;
12220                var btnClasses = [classes.button];
12221                var btn;
12222
12223                if (active) {
12224                    btnClasses.push(classes.active);
12225                }
12226
12227                if (disabled) {
12228                    btnClasses.push(classes.disabled)
12229                }
12230
12231                if (buttonType === 'ellipsis') {
12232                    btn = $('<span class="ellipsis"></span>').html(content)[0];
12233                }
12234                else {
12235                    btn = $('<button>', {
12236                        class: btnClasses.join(' '),
12237                        role: 'link',
12238                        type: 'button'
12239                    }).html(content);
12240                }
12241
12242                return {
12243                    display: btn,
12244                    clicker: btn
12245                }
12246            }
12247        },
12248
12249        pagingContainer: {
12250            _: function (settings, buttons) {
12251                // No wrapping element - just append directly to the host
12252                return buttons;
12253            }
12254        }
12255    });
12256
12257    // Common function to remove new lines, strip HTML and diacritic control
12258    var _filterString = function (stripHtml, normalize) {
12259        return function (str) {
12260            if (_empty(str) || typeof str !== 'string') {
12261                return str;
12262            }
12263
12264            str = str.replace(_re_new_lines, " ");
12265
12266            if (stripHtml) {
12267                str = _stripHtml(str);
12268            }
12269
12270            if (normalize) {
12271                str = _normalize(str, false);
12272            }
12273
12274            return str;
12275        };
12276    }
12277
12278    /*
12279     * Public helper functions. These aren't used internally by DataTables, or
12280     * called by any of the options passed into DataTables, but they can be used
12281     * externally by developers working with DataTables. They are helper functions
12282     * to make working with DataTables a little bit easier.
12283     */
12284
12285    /**
12286     * Common logic for moment, luxon or a date action.
12287     *
12288     * Happens after __mldObj, so don't need to call `resolveWindowsLibs` again
12289     */
12290    function __mld(dtLib, momentFn, luxonFn, dateFn, arg1) {
12291        if (__moment) {
12292            return dtLib[momentFn](arg1);
12293        }
12294        else if (__luxon) {
12295            return dtLib[luxonFn](arg1);
12296        }
12297
12298        return dateFn ? dtLib[dateFn](arg1) : dtLib;
12299    }
12300
12301
12302    var __mlWarning = false;
vendor: 6,471 bytes, lines 12303-12495
12303    var __luxon; // Can be assigned in DateTable.use()
12304    var __moment; // Can be assigned in DateTable.use()
12305
12306    /**
12307     * 
12308     */
12309    function resolveWindowLibs() {
12310        if (window.luxon && !__luxon) {
12311            __luxon = window.luxon;
12312        }
12313
12314        if (window.moment && !__moment) {
12315            __moment = window.moment;
12316        }
12317    }
12318
12319    function __mldObj(d, format, locale) {
12320        var dt;
12321
12322        resolveWindowLibs();
12323
12324        if (__moment) {
12325            dt = __moment.utc(d, format, locale, true);
12326
12327            if (!dt.isValid()) {
12328                return null;
12329            }
12330        }
12331        else if (__luxon) {
12332            dt = format && typeof d === 'string'
12333                ? __luxon.DateTime.fromFormat(d, format)
12334                : __luxon.DateTime.fromISO(d);
12335
12336            if (!dt.isValid) {
12337                return null;
12338            }
12339
12340            dt = dt.setLocale(locale);
12341        }
12342        else if (!format) {
12343            // No format given, must be ISO
12344            dt = new Date(d);
12345        }
12346        else {
12347            if (!__mlWarning) {
12348                alert('DataTables warning: Formatted date without Moment.js or Luxon - https://datatables.net/tn/17');
12349            }
12350
12351            __mlWarning = true;
12352        }
12353
12354        return dt;
12355    }
12356
12357    // Wrapper for date, datetime and time which all operate the same way with the exception of
12358    // the output string for auto locale support
12359    function __mlHelper(localeString) {
12360        return function (from, to, locale, def) {
12361            // Luxon and Moment support
12362            // Argument shifting
12363            if (arguments.length === 0) {
12364                locale = 'en';
12365                to = null; // means toLocaleString
12366                from = null; // means iso8601
12367            }
12368            else if (arguments.length === 1) {
12369                locale = 'en';
12370                to = from;
12371                from = null;
12372            }
12373            else if (arguments.length === 2) {
12374                locale = to;
12375                to = from;
12376                from = null;
12377            }
12378
12379            var typeName = 'datetime' + (to ? '-' + to : '');
12380
12381            // Add type detection and sorting specific to this date format - we need to be able to identify
12382            // date type columns as such, rather than as numbers in extensions. Hence the need for this.
12383            if (!DataTable.ext.type.order[typeName + '-pre']) {
12384                DataTable.type(typeName, {
12385                    detect: function (d) {
12386                        // The renderer will give the value to type detect as the type!
12387                        return d === typeName ? typeName : false;
12388                    },
12389                    order: {
12390                        pre: function (d) {
12391                            // The renderer gives us Moment, Luxon or Date objects for the sorting, all of which have a
12392                            // `valueOf` which gives milliseconds epoch
12393                            return d.valueOf();
12394                        }
12395                    },
12396                    className: 'dt-right'
12397                });
12398            }
12399
12400            return function (d, type) {
12401                // Allow for a default value
12402                if (d === null || d === undefined) {
12403                    if (def === '--now') {
12404                        // We treat everything as UTC further down, so no changes are
12405                        // made, as such need to get the local date / time as if it were
12406                        // UTC
12407                        var local = new Date();
12408                        d = new Date(Date.UTC(
12409                            local.getFullYear(), local.getMonth(), local.getDate(),
12410                            local.getHours(), local.getMinutes(), local.getSeconds()
12411                        ));
12412                    }
12413                    else {
12414                        d = '';
12415                    }
12416                }
12417
12418                if (type === 'type') {
12419                    // Typing uses the type name for fast matching
12420                    return typeName;
12421                }
12422
12423                if (d === '') {
12424                    return type !== 'sort'
12425                        ? ''
12426                        : __mldObj('0000-01-01 00:00:00', null, locale);
12427                }
12428
12429                // Shortcut. If `from` and `to` are the same, we are using the renderer to
12430                // format for ordering, not display - its already in the display format.
12431                if (to !== null && from === to && type !== 'sort' && type !== 'type' && !(d instanceof Date)) {
12432                    return d;
12433                }
12434
12435                var dt = __mldObj(d, from, locale);
12436
12437                if (dt === null) {
12438                    return d;
12439                }
12440
12441                if (type === 'sort') {
12442                    return dt;
12443                }
12444
12445                var formatted = to === null
12446                    ? __mld(dt, 'toDate', 'toJSDate', '')[localeString](
12447                        navigator.language,
12448                        { timeZone: "UTC" }
12449                    )
12450                    : __mld(dt, 'format', 'toFormat', 'toISOString', to);
12451
12452                // XSS protection
12453                return type === 'display' ?
12454                    _escapeHtml(formatted) :
12455                    formatted;
12456            };
12457        }
12458    }
12459
12460    // Based on locale, determine standard number formatting
12461    // Fallback for legacy browsers is US English
12462    var __thousands = ',';
12463    var __decimal = '.';
12464
12465    if (window.Intl !== undefined) {
12466        try {
12467            var num = new Intl.NumberFormat().formatToParts(100000.1);
12468
12469            for (var i = 0; i < num.length; i++) {
12470                if (num[i].type === 'group') {
12471                    __thousands = num[i].value;
12472                }
12473                else if (num[i].type === 'decimal') {
12474                    __decimal = num[i].value;
12475                }
12476            }
12477        }
12478        catch (e) {
12479            // noop
12480        }
12481    }
12482
12483    // Formatted date time detection - use by declaring the formats you are going to use
12484    DataTable.datetime = function (format, locale) {
12485        var typeName = 'datetime-' + format;
12486
12487        if (!locale) {
12488            locale = 'en';
12489        }
12490
12491        if (!DataTable.ext.type.order[typeName]) {
12492            DataTable.type(typeName, {
12493                detect: function (d) {
12494                    var dt = __mldObj(d, format, locale);
12495                    return d === '' || dt ? typeName : false;
12496                },
12497                order: {
12498                    pre: function (d) {
12499                        return __mldObj(d, format, locale) || 0;
12500                    }
12501                },
12502                className: 'dt-right'
12503            });
12504        }
12505    }
12506
12507    /**
12508     * Helpers for `columns.render`.
12509     *
12510     * The options defined here can be used with the `columns.render` initialisation
12511     * option to provide a display renderer. The following functions are defined:
12512     *
12513     * * `moment` - Uses the MomentJS library to convert from a given format into another.
12514     * This renderer has three overloads:
12515     *   * 1 parameter:
12516     *     * `string` - Format to convert to (assumes input is ISO8601 and locale is `en`)
12517     *   * 2 parameters:
12518     *     * `string` - Format to convert from
12519     *     * `string` - Format to convert to. Assumes `en` locale
12520     *   * 3 parameters:
12521     *     * `string` - Format to convert from
12522     *     * `string` - Format to convert to
12523     *     * `string` - Locale
12524     * * `number` - Will format numeric data (defined by `columns.data`) for
12525     *   display, retaining the original unformatted data for sorting and filtering.
12526     *   It takes 5 parameters:
12527     *   * `string` - Thousands grouping separator
12528     *   * `string` - Decimal point indicator
12529     *   * `integer` - Number of decimal points to show
12530     *   * `string` (optional) - Prefix.
12531     *   * `string` (optional) - Postfix (/suffix).
12532     * * `text` - Escape HTML to help prevent XSS attacks. It has no optional
12533     *   parameters.
12534     *
12535     * @example
12536     *   // Column definition using the number renderer
12537     *   {
12538     *     data: "salary",
12539     *     render: $.fn.dataTable.render.number( '\'', '.', 0, '$' )
12540     *   }
12541     *
12542     * @namespace
12543     */
12544    DataTable.render = {
12545        date: __mlHelper('toLocaleDateString'),
12546        datetime: __mlHelper('toLocaleString'),
12547        time: __mlHelper('toLocaleTimeString'),
12548        number: function (thousands, decimal, precision, prefix, postfix) {
12549            // Auto locale detection
12550            if (thousands === null || thousands === undefined) {
12551                thousands = __thousands;
12552            }
12553
12554            if (decimal === null || decimal === undefined) {
12555                decimal = __decimal;
12556            }
12557
12558            return {
12559                display: function (d) {
12560                    if (typeof d !== 'number' && typeof d !== 'string') {
12561                        return d;
12562                    }
12563
12564                    if (d === '' || d === null) {
12565                        return d;
12566                    }
12567
12568                    var negative = d < 0 ? '-' : '';
12569                    var flo = parseFloat(d);
12570                    var abs = Math.abs(flo);
12571
12572                    // Scientific notation for large and small numbers
12573                    if (abs >= 100000000000 || (abs < 0.0001 && abs !== 0)) {
12574                        var exp = flo.toExponential(precision).split(/e\+?/);
12575                        return exp[0] + ' x 10<sup>' + exp[1] + '</sup>';
12576                    }
12577
12578                    // If NaN then there isn't much formatting that we can do - just
12579                    // return immediately, escaping any HTML (this was supposed to
12580                    // be a number after all)
12581                    if (isNaN(flo)) {
12582                        return _escapeHtml(d);
12583                    }
12584
12585                    flo = flo.toFixed(precision);
12586                    d = Math.abs(flo);
12587
12588                    var intPart = parseInt(d, 10);
12589                    var floatPart = precision ?
12590                        decimal + (d - intPart).toFixed(precision).substring(2) :
12591                        '';
12592
12593                    // If zero, then can't have a negative prefix
12594                    if (intPart === 0 && parseFloat(floatPart) === 0) {
12595                        negative = '';
12596                    }
12597
12598                    return negative + (prefix || '') +
12599                        intPart.toString().replace(
12600                            /\B(?=(\d{3})+(?!\d))/g, thousands
12601                        ) +
12602                        floatPart +
12603                        (postfix || '');
12604                }
12605            };
12606        },
12607
12608        text: function () {
12609            return {
12610                display: _escapeHtml,
12611                filter: _escapeHtml
12612            };
12613        }
12614    };
12615
12616
12617    var _extTypes = DataTable.ext.type;
12618
12619    // Get / set type
12620    DataTable.type = function (name, prop, val) {
12621        if (!prop) {
12622            return {
12623                className: _extTypes.className[name],
12624                detect: _extTypes.detect.find(function (fn) {
12625                    return fn._name === name;
12626                }),
12627                order: {
12628                    pre: _extTypes.order[name + '-pre'],
12629                    asc: _extTypes.order[name + '-asc'],
12630                    desc: _extTypes.order[name + '-desc']
12631                },
12632                render: _extTypes.render[name],
12633                search: _extTypes.search[name]
12634            };
12635        }
12636
12637        var setProp = function (prop, propVal) {
12638            _extTypes[prop][name] = propVal;
12639        };
12640        var setDetect = function (detect) {
12641            // `detect` can be a function or an object - we set a name
12642            // property for either - that is used for the detection
12643            Object.defineProperty(detect, "_name", { value: name });
12644
12645            var idx = _extTypes.detect.findIndex(function (item) {
12646                return item._name === name;
12647            });
12648
12649            if (idx === -1) {
12650                _extTypes.detect.unshift(detect);
12651            }
12652            else {
12653                _extTypes.detect.splice(idx, 1, detect);
12654            }
12655        };
12656        var setOrder = function (obj) {
12657            _extTypes.order[name + '-pre'] = obj.pre; // can be undefined
12658            _extTypes.order[name + '-asc'] = obj.asc; // can be undefined
12659            _extTypes.order[name + '-desc'] = obj.desc; // can be undefined
12660        };
12661
12662        // prop is optional
12663        if (val === undefined) {
12664            val = prop;
12665            prop = null;
12666        }
12667
12668        if (prop === 'className') {
12669            setProp('className', val);
12670        }
12671        else if (prop === 'detect') {
12672            setDetect(val);
12673        }
12674        else if (prop === 'order') {
12675            setOrder(val);
12676        }
12677        else if (prop === 'render') {
12678            setProp('render', val);
12679        }
12680        else if (prop === 'search') {
12681            setProp('search', val);
12682        }
12683        else if (!prop) {
12684            if (val.className) {
12685                setProp('className', val.className);
12686            }
12687
12688            if (val.detect !== undefined) {
12689                setDetect(val.detect);
12690            }
12691
12692            if (val.order) {
12693                setOrder(val.order);
12694            }
12695
12696            if (val.render !== undefined) {
12697                setProp('render', val.render);
12698            }
12699
12700            if (val.search !== undefined) {
12701                setProp('search', val.search);
12702            }
12703        }
12704    }
12705
12706    // Get a list of types
12707    DataTable.types = function () {
12708        return _extTypes.detect.map(function (fn) {
12709            return fn._name;
12710        });
12711    };
12712
12713    var __diacriticSort = function (a, b) {
12714        a = a !== null && a !== undefined ? a.toString().toLowerCase() : '';
12715        b = b !== null && b !== undefined ? b.toString().toLowerCase() : '';
12716
12717        // Checked for `navigator.languages` support in `oneOf` so this code can't execute in old
12718        // Safari and thus can disable this check
12719        // eslint-disable-next-line compat/compat
12720        return a.localeCompare(b, navigator.languages[0] || navigator.language, {
12721            numeric: true,
12722            ignorePunctuation: true,
12723        });
12724    }
12725
12726    var __diacriticHtmlSort = function (a, b) {
12727        a = _stripHtml(a);
12728        b = _stripHtml(b);
12729
12730        return __diacriticSort(a, b);
12731    }
12732
12733    //
12734    // Built in data types
12735    //
12736
12737    DataTable.type('string', {
12738        detect: function () {
12739            return 'string';
12740        },
12741        order: {
12742            pre: function (a) {
12743                // This is a little complex, but faster than always calling toString,
12744                // http://jsperf.com/tostring-v-check
12745                return _empty(a) && typeof a !== 'boolean' ?
12746                    '' :
12747                    typeof a === 'string' ?
12748                        a.toLowerCase() :
12749                        !a.toString ?
12750                            '' :
12751                            a.toString();
12752            }
12753        },
12754        search: _filterString(false, true)
12755    });
12756
12757    DataTable.type('string-utf8', {
12758        detect: {
12759            allOf: function (d) {
12760                return true;
12761            },
12762            oneOf: function (d) {
12763                // At least one data point must contain a non-ASCII character
12764                // This line will also check if navigator.languages is supported or not. If not (Safari 10.0-)
12765                // this data type won't be supported.
12766                // eslint-disable-next-line compat/compat
12767                return !_empty(d) && navigator.languages && typeof d === 'string' && d.match(/[^\x00-\x7F]/);
12768            }
12769        },
12770        order: {
12771            asc: __diacriticSort,
12772            desc: function (a, b) {
12773                return __diacriticSort(a, b) * -1;
12774            }
12775        },
12776        search: _filterString(false, true)
12777    });
12778
12779
12780    DataTable.type('html', {
12781        detect: {
12782            allOf: function (d) {
12783                return _empty(d) || (typeof d === 'string' && d.indexOf('<') !== -1);
12784            },
12785            oneOf: function (d) {
12786                // At least one data point must contain a `<`
12787                return !_empty(d) && typeof d === 'string' && d.indexOf('<') !== -1;
12788            }
12789        },
12790        order: {
12791            pre: function (a) {
12792                return _empty(a) ?
12793                    '' :
12794                    a.replace ?
12795                        _stripHtml(a).trim().toLowerCase() :
12796                        a + '';
12797            }
12798        },
12799        search: _filterString(true, true)
12800    });
12801
12802
12803    DataTable.type('html-utf8', {
12804        detect: {
12805            allOf: function (d) {
12806                return _empty(d) || (typeof d === 'string' && d.indexOf('<') !== -1);
12807            },
12808            oneOf: function (d) {
12809                // At least one data point must contain a `<` and a non-ASCII character
12810                // eslint-disable-next-line compat/compat
12811                return navigator.languages &&
12812                    !_empty(d) &&
12813                    typeof d === 'string' &&
12814                    d.indexOf('<') !== -1 &&
12815                    typeof d === 'string' && d.match(/[^\x00-\x7F]/);
12816            }
12817        },
12818        order: {
12819            asc: __diacriticHtmlSort,
12820            desc: function (a, b) {
12821                return __diacriticHtmlSort(a, b) * -1;
12822            }
12823        },
12824        search: _filterString(true, true)
12825    });
12826
12827
12828    DataTable.type('date', {
12829        className: 'dt-type-date',
12830        detect: {
12831            allOf: function (d) {
12832                // V8 tries _very_ hard to make a string passed into `Date.parse()`
12833                // valid, so we need to use a regex to restrict date formats. Use a
12834                // plug-in for anything other than ISO8601 style strings
12835                if (d && !(d instanceof Date) && !_re_date.test(d)) {
12836                    return null;
12837                }
12838                var parsed = Date.parse(d);
12839                return (parsed !== null && !isNaN(parsed)) || _empty(d);
12840            },
12841            oneOf: function (d) {
12842                // At least one entry must be a date or a string with a date
12843                return (d instanceof Date) || (typeof d === 'string' && _re_date.test(d));
12844            }
12845        },
12846        order: {
12847            pre: function (d) {
12848                var ts = Date.parse(d);
12849                return isNaN(ts) ? -Infinity : ts;
12850            }
12851        }
12852    });
12853
12854
12855    DataTable.type('html-num-fmt', {
12856        className: 'dt-type-numeric',
12857        detect: {
12858            allOf: function (d, settings) {
12859                var decimal = settings.oLanguage.sDecimal;
12860                return _htmlNumeric(d, decimal, true, false);
12861            },
12862            oneOf: function (d, settings) {
12863                // At least one data point must contain a numeric value
12864                var decimal = settings.oLanguage.sDecimal;
12865                return _htmlNumeric(d, decimal, true, false);
12866            }
12867        },
12868        order: {
12869            pre: function (d, s) {
12870                var dp = s.oLanguage.sDecimal;
12871                return __numericReplace(d, dp, _re_html, _re_formatted_numeric);
12872            }
12873        },
12874        search: _filterString(true, true)
12875    });
12876
12877
12878    DataTable.type('html-num', {
12879        className: 'dt-type-numeric',
12880        detect: {
12881            allOf: function (d, settings) {
12882                var decimal = settings.oLanguage.sDecimal;
12883                return _htmlNumeric(d, decimal, false, true);
12884            },
12885            oneOf: function (d, settings) {
12886                // At least one data point must contain a numeric value
12887                var decimal = settings.oLanguage.sDecimal;
12888                return _htmlNumeric(d, decimal, false, false);
12889            }
12890        },
12891        order: {
12892            pre: function (d, s) {
12893                var dp = s.oLanguage.sDecimal;
12894                return __numericReplace(d, dp, _re_html);
12895            }
12896        },
12897        search: _filterString(true, true)
12898    });
12899
12900
12901    DataTable.type('num-fmt', {
12902        className: 'dt-type-numeric',
12903        detect: {
12904            allOf: function (d, settings) {
12905                var decimal = settings.oLanguage.sDecimal;
12906                return _isNumber(d, decimal, true, true);
12907            },
12908            oneOf: function (d, settings) {
12909                // At least one data point must contain a numeric value
12910                var decimal = settings.oLanguage.sDecimal;
12911                return _isNumber(d, decimal, true, false);
12912            }
12913        },
12914        order: {
12915            pre: function (d, s) {
12916                var dp = s.oLanguage.sDecimal;
12917                return __numericReplace(d, dp, _re_formatted_numeric);
12918            }
12919        }
12920    });
12921
12922
12923    DataTable.type('num', {
12924        className: 'dt-type-numeric',
12925        detect: {
12926            allOf: function (d, settings) {
12927                var decimal = settings.oLanguage.sDecimal;
12928                return _isNumber(d, decimal, false, true);
12929            },
12930            oneOf: function (d, settings) {
12931                // At least one data point must contain a numeric value
12932                var decimal = settings.oLanguage.sDecimal;
12933                return _isNumber(d, decimal, false, false);
12934            }
12935        },
12936        order: {
12937            pre: function (d, s) {
12938                var dp = s.oLanguage.sDecimal;
12939                return __numericReplace(d, dp);
12940            }
12941        }
12942    });
12943
12944
12945
12946
12947    var __numericReplace = function (d, decimalPlace, re1, re2) {
12948        if (d !== 0 && (!d || d === '-')) {
12949            return -Infinity;
12950        }
12951
12952        var type = typeof d;
12953
12954        if (type === 'number' || type === 'bigint') {
12955            return d;
12956        }
12957
12958        // If a decimal place other than `.` is used, it needs to be given to the
12959        // function so we can detect it and replace with a `.` which is the only
12960        // decimal place JavaScript recognises - it is not locale aware.
12961        if (decimalPlace) {
12962            d = _numToDecimal(d, decimalPlace);
12963        }
12964
12965        if (d.replace) {
12966            if (re1) {
12967                d = d.replace(re1, '');
12968            }
12969
12970            if (re2) {
12971                d = d.replace(re2, '');
12972            }
12973        }
12974
12975        return d * 1;
12976    };
12977
12978
12979    $.extend(true, DataTable.ext.renderer, {
12980        footer: {
12981            _: function (settings, cell, classes) {
12982                cell.addClass(classes.tfoot.cell);
12983            }
12984        },
12985
12986        header: {
12987            _: function (settings, cell, classes) {
12988                cell.addClass(classes.thead.cell);
12989
12990                if (!settings.oFeatures.bSort) {
12991                    cell.addClass(classes.order.none);
12992                }
12993
12994                var titleRow = settings.titleRow;
12995                var headerRows = cell.closest('thead').find('tr');
12996                var rowIdx = cell.parent().index();
12997
12998                // Conditions to not apply the ordering icons
12999                if (
13000                    // Cells and rows which have the attribute to disable the icons
13001                    cell.attr('data-dt-order') === 'disable' ||
13002                    cell.parent().attr('data-dt-order') === 'disable' ||
13003
13004                    // titleRow support, for defining a specific row in the header
13005                    (titleRow === true && rowIdx !== 0) ||
13006                    (titleRow === false && rowIdx !== headerRows.length - 1) ||
13007                    (typeof titleRow === 'number' && rowIdx !== titleRow)
13008                ) {
13009                    return;
13010                }
13011
13012                // No additional mark-up required
13013                // Attach a sort listener to update on sort - note that using the
13014                // `DT` namespace will allow the event to be removed automatically
13015                // on destroy, while the `dt` namespaced event is the one we are
13016                // listening for
13017                $(settings.nTable).on('order.dt.DT column-visibility.dt.DT', function (e, ctx, column) {
13018                    if (settings !== ctx) { // need to check if this is the host
13019                        return;               // table, not a nested one
13020                    }
13021
13022                    var sorting = ctx.sortDetails;
13023
13024                    if (!sorting) {
13025                        return;
13026                    }
13027
13028                    var orderedColumns = _pluck(sorting, 'col');
13029
13030                    // This handler is only needed on column visibility if the column is part of the
13031                    // ordering. If it isn't, then we can bail out to save performance. It could be a
13032                    // separate event handler, but this is a balance between code reuse / size and performance
13033                    // console.log(e, e.name, column, orderedColumns, orderedColumns.includes(column))
13034                    if (e.type === 'column-visibility' && !orderedColumns.includes(column)) {
13035                        return;
13036                    }
13037
13038                    var i;
13039                    var orderClasses = classes.order;
13040                    var columns = ctx.api.columns(cell);
13041                    var col = settings.aoColumns[columns.flatten()[0]];
13042                    var orderable = columns.orderable().includes(true);
13043                    var ariaType = '';
13044                    var indexes = columns.indexes();
13045                    var sortDirs = columns.orderable(true).flatten();
13046                    var tabIndex = settings.iTabIndex;
13047                    var canOrder = ctx.orderHandler && orderable;
13048
13049                    cell
13050                        .removeClass(
13051                            orderClasses.isAsc + ' ' +
13052                            orderClasses.isDesc
13053                        )
13054                        .toggleClass(orderClasses.none, !orderable)
13055                        .toggleClass(orderClasses.canAsc, canOrder && sortDirs.includes('asc'))
13056                        .toggleClass(orderClasses.canDesc, canOrder && sortDirs.includes('desc'));
13057
13058                    // Determine if all of the columns that this cell covers are included in the
13059                    // current ordering
13060                    var isOrdering = true;
13061
13062                    for (i = 0; i < indexes.length; i++) {
13063                        if (!orderedColumns.includes(indexes[i])) {
13064                            isOrdering = false;
13065                        }
13066                    }
13067
13068                    if (isOrdering) {
13069                        // Get the ordering direction for the columns under this cell
13070                        // Note that it is possible for a cell to be asc and desc sorting
13071                        // (column spanning cells)
13072                        var orderDirs = columns.order();
13073
13074                        cell.addClass(
13075                            orderDirs.includes('asc') ? orderClasses.isAsc : '' +
13076                                orderDirs.includes('desc') ? orderClasses.isDesc : ''
13077                        );
13078                    }
13079
13080                    // Find the first visible column that has ordering applied to it - it get's
13081                    // the aria information, as the ARIA spec says that only one column should
13082                    // be marked with aria-sort
13083                    var firstVis = -1; // column index
13084
13085                    for (i = 0; i < orderedColumns.length; i++) {
13086                        if (settings.aoColumns[orderedColumns[i]].bVisible) {
13087                            firstVis = orderedColumns[i];
13088                            break;
13089                        }
13090                    }
13091
13092                    if (indexes[0] == firstVis) {
13093                        var firstSort = sorting[0];
13094                        var sortOrder = col.asSorting;
13095
13096                        cell.attr('aria-sort', firstSort.dir === 'asc' ? 'ascending' : 'descending');
13097
13098                        // Determine if the next click will remove sorting or change the sort
13099                        ariaType = !sortOrder[firstSort.index + 1] ? 'Remove' : 'Reverse';
13100                    }
13101                    else {
13102                        cell.removeAttr('aria-sort');
13103                    }
13104
13105                    // Make the headers tab-able for keyboard navigation
13106                    if (orderable) {
13107                        var orderSpan = cell.find('.dt-column-order');
13108
13109                        orderSpan
13110                            .attr('role', 'button')
13111                            .attr('aria-label', orderable
13112                                ? col.ariaTitle + ctx.api.i18n('oAria.orderable' + ariaType)
13113                                : col.ariaTitle
13114                            );
13115
13116                        if (tabIndex !== -1) {
13117                            orderSpan.attr('tabindex', tabIndex);
13118                        }
13119                    }
13120                });
13121            }
13122        },
13123
13124        layout: {
13125            _: function (settings, container, items) {
13126                var classes = settings.oClasses.layout;
13127                var row = $('<div/>')
13128                    .attr('id', items.id || null)
13129                    .addClass(items.className || classes.row)
13130                    .appendTo(container);
13131
13132                DataTable.ext.renderer.layout._forLayoutRow(items, function (key, val) {
13133                    if (key === 'id' || key === 'className') {
13134                        return;
13135                    }
13136
13137                    var klass = '';
13138
13139                    if (val.table) {
13140                        row.addClass(classes.tableRow);
13141                        klass += classes.tableCell + ' ';
13142                    }
13143
13144                    if (key === 'start') {
13145                        klass += classes.start;
13146                    }
13147                    else if (key === 'end') {
13148                        klass += classes.end;
13149                    }
13150                    else {
13151                        klass += classes.full;
13152                    }
13153
13154                    $('<div/>')
13155                        .attr({
13156                            id: val.id || null,
13157                            "class": val.className
13158                                ? val.className
13159                                : classes.cell + ' ' + klass
13160                        })
13161                        .append(val.contents)
13162                        .appendTo(row);
13163                });
13164            },
13165
13166            // Shared for use by the styling frameworks
13167            _forLayoutRow: function (items, fn) {
13168                // As we are inserting dom elements, we need start / end in a
13169                // specific order, this function is used for sorting the layout
13170                // keys.
13171                var layoutEnum = function (x) {
13172                    switch (x) {
13173                        case '': return 0;
13174                        case 'start': return 1;
13175                        case 'end': return 2;
13176                        default: return 3;
13177                    }
13178                };
13179
13180                Object
13181                    .keys(items)
13182                    .sort(function (a, b) {
13183                        return layoutEnum(a) - layoutEnum(b);
13184                    })
13185                    .forEach(function (key) {
13186                        fn(key, items[key]);
13187                    });
13188            }
13189        }
13190    });
13191
13192
13193    DataTable.feature = {};
13194
13195    // Third parameter is internal only!
13196    DataTable.feature.register = function (name, cb, legacy) {
13197        DataTable.ext.features[name] = cb;
13198
13199        if (legacy) {
13200            _ext.feature.push({
13201                cFeature: legacy,
13202                fnInit: cb
13203            });
13204        }
13205    };
13206
13207    function _divProp(el, prop, val) {
13208        if (val) {
13209            el[prop] = val;
13210        }
13211    }
13212
13213    DataTable.feature.register('div', function (settings, opts) {
13214        var n = $('<div>')[0];
13215
13216        if (opts) {
13217            _divProp(n, 'className', opts.className);
13218            _divProp(n, 'id', opts.id);
13219            _divProp(n, 'innerHTML', opts.html);
13220            _divProp(n, 'textContent', opts.text);
13221        }
13222
13223        return n;
13224    });
13225
13226    DataTable.feature.register('info', function (settings, opts) {
13227        // For compatibility with the legacy `info` top level option
13228        if (!settings.oFeatures.bInfo) {
13229            return null;
13230        }
13231
13232        var
13233            lang = settings.oLanguage,
13234            tid = settings.sTableId,
13235            n = $('<div/>', {
13236                'class': settings.oClasses.info.container,
13237            });
13238
13239        opts = $.extend({
13240            callback: lang.fnInfoCallback,
13241            empty: lang.sInfoEmpty,
13242            postfix: lang.sInfoPostFix,
13243            search: lang.sInfoFiltered,
13244            text: lang.sInfo,
13245        }, opts);
13246
13247
13248        // Update display on each draw
13249        settings.aoDrawCallback.push(function (s) {
13250            _fnUpdateInfo(s, opts, n);
13251        });
13252
13253        // For the first info display in the table, we add a callback and aria information.
13254        if (!settings._infoEl) {
13255            n.attr({
13256                'aria-live': 'polite',
13257                id: tid + '_info',
13258                role: 'status'
13259            });
13260
13261            // Table is described by our info div
13262            $(settings.nTable).attr('aria-describedby', tid + '_info');
13263
13264            settings._infoEl = n;
13265        }
13266
13267        return n;
13268    }, 'i');
13269
13270    /**
13271     * Update the information elements in the display
13272     *  @param {object} settings dataTables settings object
13273     *  @memberof DataTable#oApi
13274     */
13275    function _fnUpdateInfo(settings, opts, node) {
13276        var
13277            start = settings._iDisplayStart + 1,
13278            end = settings.fnDisplayEnd(),
13279            max = settings.fnRecordsTotal(),
13280            total = settings.fnRecordsDisplay(),
13281            out = total
13282                ? opts.text
13283                : opts.empty;
13284
13285        if (total !== max) {
13286            // Record set after filtering
13287            out += ' ' + opts.search;
13288        }
13289
13290        // Convert the macros
13291        out += opts.postfix;
13292        out = _fnMacros(settings, out);
13293
13294        if (opts.callback) {
13295            out = opts.callback.call(settings.oInstance,
13296                settings, start, end, max, total, out
13297            );
13298        }
13299
13300        node.html(out);
13301
13302        _fnCallbackFire(settings, null, 'info', [settings, node[0], out]);
13303    }
13304
13305    var __searchCounter = 0;
13306
13307    // opts
13308    // - text
13309    // - placeholder
13310    DataTable.feature.register('search', function (settings, opts) {
13311        // Don't show the input if filtering isn't available on the table
13312        if (!settings.oFeatures.bFilter) {
13313            return null;
13314        }
13315
13316        var classes = settings.oClasses.search;
13317        var tableId = settings.sTableId;
13318        var language = settings.oLanguage;
13319        var previousSearch = settings.oPreviousSearch;
13320        var input = '<input type="search" class="' + classes.input + '"/>';
13321
13322        opts = $.extend({
13323            placeholder: language.sSearchPlaceholder,
13324            processing: false,
13325            text: language.sSearch
13326        }, opts);
13327
13328        // The _INPUT_ is optional - is appended if not present
13329        if (opts.text.indexOf('_INPUT_') === -1) {
13330            opts.text += '_INPUT_';
13331        }
13332
13333        opts.text = _fnMacros(settings, opts.text);
13334
13335        // We can put the <input> outside of the label if it is at the start or end
13336        // which helps improve accessability (not all screen readers like implicit
13337        // for elements).
13338        var end = opts.text.match(/_INPUT_$/);
13339        var start = opts.text.match(/^_INPUT_/);
13340        var removed = opts.text.replace(/_INPUT_/, '');
13341        var str = '<label>' + opts.text + '</label>';
13342
13343        if (start) {
13344            str = '_INPUT_<label>' + removed + '</label>';
13345        }
13346        else if (end) {
13347            str = '<label>' + removed + '</label>_INPUT_';
13348        }
13349
13350        var filter = $('<div>')
13351            .addClass(classes.container)
13352            .append(str.replace(/_INPUT_/, input));
13353
13354        // add for and id to label and input
13355        filter.find('label').attr('for', 'dt-search-' + __searchCounter);
13356        filter.find('input').attr('id', 'dt-search-' + __searchCounter);
13357        __searchCounter++;
13358
13359        var searchFn = function (event) {
13360            var val = this.value;
13361
13362            if (previousSearch.return && event.key !== "Enter") {
13363                return;
13364            }
13365
13366            /* Now do the filter */
13367            if (val != previousSearch.search) {
13368                _fnProcessingRun(settings, opts.processing, function () {
13369                    previousSearch.search = val;
13370
13371                    _fnFilterComplete(settings, previousSearch);
13372
13373                    // Need to redraw, without resorting
13374                    settings._iDisplayStart = 0;
13375                    _fnDraw(settings);
13376                });
13377            }
13378        };
13379
13380        var searchDelay = settings.searchDelay !== null ?
13381            settings.searchDelay :
13382            0;
13383
13384        var jqFilter = $('input', filter)
13385            .val(previousSearch.search)
13386            .attr('placeholder', opts.placeholder)
13387            .on(
13388                'keyup.DT search.DT input.DT paste.DT cut.DT',
13389                searchDelay ?
13390                    DataTable.util.debounce(searchFn, searchDelay) :
13391                    searchFn
13392            )
13393            .on('mouseup.DT', function (e) {
13394                // Edge fix! Edge 17 does not trigger anything other than mouse events when clicking
13395                // on the clear icon (Edge bug 17584515). This is safe in other browsers as `searchFn`
13396                // checks the value to see if it has changed. In other browsers it won't have.
13397                setTimeout(function () {
13398                    searchFn.call(jqFilter[0], e);
13399                }, 10);
13400            })
13401            .on('keypress.DT', function (e) {
13402                /* Prevent form submission */
13403                if (e.keyCode == 13) {
13404                    return false;
13405                }
13406            })
13407            .attr('aria-controls', tableId);
13408
13409        // Update the input elements whenever the table is filtered
13410        $(settings.nTable).on('search.dt.DT', function (ev, s) {
13411            if (settings === s && jqFilter[0] !== document.activeElement) {
13412                jqFilter.val(typeof previousSearch.search !== 'function'
13413                    ? previousSearch.search
13414                    : ''
13415                );
13416            }
13417        });
13418
13419        return filter;
13420    }, 'f');
13421
13422    // opts
13423    // - type - button configuration
13424    // - buttons - number of buttons to show - must be odd
13425    DataTable.feature.register('paging', function (settings, opts) {
13426        // Don't show the paging input if the table doesn't have paging enabled
13427        if (!settings.oFeatures.bPaginate) {
13428            return null;
13429        }
13430
13431        opts = $.extend({
13432            buttons: DataTable.ext.pager.numbers_length,
13433            type: settings.sPaginationType,
13434            boundaryNumbers: true,
13435            firstLast: true,
13436            previousNext: true,
13437            numbers: true
13438        }, opts);
13439
13440        var host = $('<div/>')
13441            .addClass(settings.oClasses.paging.container + (opts.type ? ' paging_' + opts.type : ''))
13442            .append(
13443                $('<nav>')
13444                    .attr('aria-label', 'pagination')
13445                    .addClass(settings.oClasses.paging.nav)
13446            );
13447        var draw = function () {
13448            _pagingDraw(settings, host.children(), opts);
13449        };
13450
13451        settings.aoDrawCallback.push(draw);
13452
13453        // Responsive redraw of paging control
13454        $(settings.nTable).on('column-sizing.dt.DT', draw);
13455
13456        return host;
13457    }, 'p');
13458
13459    /**
13460     * Dynamically create the button type array based on the configuration options.
13461     * This will only happen if the paging type is not defined.
13462     */
13463    function _pagingDynamic(opts) {
13464        var out = [];
13465
13466        if (opts.numbers) {
13467            out.push('numbers');
13468        }
13469
13470        if (opts.previousNext) {
13471            out.unshift('previous');
13472            out.push('next');
13473        }
13474
13475        if (opts.firstLast) {
13476            out.unshift('first');
13477            out.push('last');
13478        }
13479
13480        return out;
13481    }
13482
13483    function _pagingDraw(settings, host, opts) {
13484        if (!settings._bInitComplete) {
13485            return;
13486        }
13487
13488        var
13489            plugin = opts.type
13490                ? DataTable.ext.pager[opts.type]
13491                : _pagingDynamic,
13492            aria = settings.oLanguage.oAria.paginate || {},
13493            start = settings._iDisplayStart,
13494            len = settings._iDisplayLength,
13495            visRecords = settings.fnRecordsDisplay(),
13496            all = len === -1,
13497            page = all ? 0 : Math.ceil(start / len),
13498            pages = all ? 1 : Math.ceil(visRecords / len),
13499            buttons = [],
13500            buttonEls = [],
13501            buttonsNested = plugin(opts)
13502                .map(function (val) {
13503                    return val === 'numbers'
13504                        ? _pagingNumbers(page, pages, opts.buttons, opts.boundaryNumbers)
13505                        : val;
13506                });
13507
13508        // .flat() would be better, but not supported in old Safari
13509        buttons = buttons.concat.apply(buttons, buttonsNested);
13510
13511        for (var i = 0; i < buttons.length; i++) {
13512            var button = buttons[i];
13513
13514            var btnInfo = _pagingButtonInfo(settings, button, page, pages);
13515            var btn = _fnRenderer(settings, 'pagingButton')(
13516                settings,
13517                button,
13518                btnInfo.display,
13519                btnInfo.active,
13520                btnInfo.disabled
13521            );
13522
13523            var ariaLabel = typeof button === 'string'
13524                ? aria[button]
13525                : aria.number
13526                    ? aria.number + (button + 1)
13527                    : null;
13528
13529            // Common attributes
13530            $(btn.clicker).attr({
13531                'aria-controls': settings.sTableId,
13532                'aria-disabled': btnInfo.disabled ? 'true' : null,
13533                'aria-current': btnInfo.active ? 'page' : null,
13534                'aria-label': ariaLabel,
13535                'data-dt-idx': button,
13536                'tabIndex': btnInfo.disabled
13537                    ? -1
13538                    : settings.iTabIndex && btn.clicker[0].nodeName.toLowerCase() !== 'span'
13539                        ? settings.iTabIndex
13540                        : null, // `0` doesn't need a tabIndex since it is the default
13541            });
13542
13543            if (typeof button !== 'number') {
13544                $(btn.clicker).addClass(button);
13545            }
13546
13547            _fnBindAction(
13548                btn.clicker, { action: button }, function (e) {
13549                    e.preventDefault();
13550
13551                    _fnPageChange(settings, e.data.action, true);
13552                }
13553            );
13554
13555            buttonEls.push(btn.display);
13556        }
13557
13558        var wrapped = _fnRenderer(settings, 'pagingContainer')(
13559            settings, buttonEls
13560        );
13561
13562        var activeEl = host.find(document.activeElement).data('dt-idx');
13563
13564        host.empty().append(wrapped);
13565
13566        if (activeEl !== undefined) {
13567            host.find('[data-dt-idx=' + activeEl + ']').trigger('focus');
13568        }
13569
13570        // Responsive - check if the buttons are over two lines based on the
13571        // height of the buttons and the container.
13572        if (buttonEls.length) {
13573            var outerHeight = $(buttonEls[0]).outerHeight();
13574
13575            if (
13576                opts.buttons > 1 && // prevent infinite
13577                outerHeight > 0 && // will be 0 if hidden
13578                $(host).height() >= (outerHeight * 2) - 10
13579            ) {
13580                _pagingDraw(settings, host, $.extend({}, opts, { buttons: opts.buttons - 2 }));
13581            }
13582        }
13583    }
13584
13585    /**
13586     * Get properties for a button based on the current paging state of the table
13587     *
13588     * @param {*} settings DT settings object
13589     * @param {*} button The button type in question
13590     * @param {*} page Table's current page
13591     * @param {*} pages Number of pages
13592     * @returns Info object
13593     */
13594    function _pagingButtonInfo(settings, button, page, pages) {
13595        var lang = settings.oLanguage.oPaginate;
13596        var o = {
13597            display: '',
13598            active: false,
13599            disabled: false
13600        };
13601
13602        switch (button) {
13603            case 'ellipsis':
13604                o.display = '&#x2026;';
13605                break;
13606
13607            case 'first':
13608                o.display = lang.sFirst;
13609
13610                if (page === 0) {
13611                    o.disabled = true;
13612                }
13613                break;
13614
13615            case 'previous':
13616                o.display = lang.sPrevious;
13617
13618                if (page === 0) {
13619                    o.disabled = true;
13620                }
13621                break;
13622
13623            case 'next':
13624                o.display = lang.sNext;
13625
13626                if (pages === 0 || page === pages - 1) {
13627                    o.disabled = true;
13628                }
13629                break;
13630
13631            case 'last':
13632                o.display = lang.sLast;
13633
13634                if (pages === 0 || page === pages - 1) {
13635                    o.disabled = true;
13636                }
13637                break;
13638
13639            default:
13640                if (typeof button === 'number') {
13641                    o.display = settings.fnFormatNumber(button + 1);
13642
13643                    if (page === button) {
13644                        o.active = true;
13645                    }
13646                }
13647                break;
13648        }
13649
13650        return o;
13651    }
13652
13653    /**
13654     * Compute what number buttons to show in the paging control
13655     *
13656     * @param {*} page Current page
13657     * @param {*} pages Total number of pages
13658     * @param {*} buttons Target number of number buttons
13659     * @param {boolean} addFirstLast Indicate if page 1 and end should be included
13660     * @returns Buttons to show
13661     */
13662    function _pagingNumbers(page, pages, buttons, addFirstLast) {
13663        var
13664            numbers = [],
13665            half = Math.floor(buttons / 2),
13666            before = addFirstLast ? 2 : 1,
13667            after = addFirstLast ? 1 : 0;
13668
13669        if (pages <= buttons) {
13670            numbers = _range(0, pages);
13671        }
13672        else if (buttons === 1) {
13673            // Single button - current page only
13674            numbers = [page];
13675        }
13676        else if (buttons === 3) {
13677            // Special logic for just three buttons
13678            if (page <= 1) {
13679                numbers = [0, 1, 'ellipsis'];
13680            }
13681            else if (page >= pages - 2) {
13682                numbers = _range(pages - 2, pages);
13683                numbers.unshift('ellipsis');
13684            }
13685            else {
13686                numbers = ['ellipsis', page, 'ellipsis'];
13687            }
13688        }
13689        else if (page <= half) {
13690            numbers = _range(0, buttons - before);
13691            numbers.push('ellipsis');
13692
13693            if (addFirstLast) {
13694                numbers.push(pages - 1);
13695            }
13696        }
13697        else if (page >= pages - 1 - half) {
13698            numbers = _range(pages - (buttons - before), pages);
13699            numbers.unshift('ellipsis');
13700
13701            if (addFirstLast) {
13702                numbers.unshift(0);
13703            }
13704        }
13705        else {
13706            numbers = _range(page - half + before, page + half - after);
13707            numbers.push('ellipsis');
13708            numbers.unshift('ellipsis');
13709
13710            if (addFirstLast) {
13711                numbers.push(pages - 1);
13712                numbers.unshift(0);
13713            }
13714        }
13715
13716        return numbers;
13717    }
13718
13719    var __lengthCounter = 0;
13720
13721    // opts
13722    // - menu
13723    // - text
13724    DataTable.feature.register('pageLength', function (settings, opts) {
13725        var features = settings.oFeatures;
13726
13727        // For compatibility with the legacy `pageLength` top level option
13728        if (!features.bPaginate || !features.bLengthChange) {
13729            return null;
13730        }
13731
13732        opts = $.extend({
13733            menu: settings.aLengthMenu,
13734            text: settings.oLanguage.sLengthMenu
13735        }, opts);
13736
13737        var
13738            classes = settings.oClasses.length,
13739            tableId = settings.sTableId,
13740            menu = opts.menu,
13741            lengths = [],
13742            language = [],
13743            i;
13744
13745        // Options can be given in a number of ways
13746        if (Array.isArray(menu[0])) {
13747            // Old 1.x style - 2D array
13748            lengths = menu[0];
13749            language = menu[1];
13750        }
13751        else {
13752            for (i = 0; i < menu.length; i++) {
13753                // An object with different label and value
13754                if ($.isPlainObject(menu[i])) {
13755                    lengths.push(menu[i].value);
13756                    language.push(menu[i].label);
13757                }
13758                else {
13759                    // Or just a number to display and use
13760                    lengths.push(menu[i]);
13761                    language.push(menu[i]);
13762                }
13763            }
13764        }
13765
13766        // We can put the <select> outside of the label if it is at the start or
13767        // end which helps improve accessability (not all screen readers like
13768        // implicit for elements).
13769        var end = opts.text.match(/_MENU_$/);
13770        var start = opts.text.match(/^_MENU_/);
13771        var removed = opts.text.replace(/_MENU_/, '');
13772        var str = '<label>' + opts.text + '</label>';
13773
13774        if (start) {
13775            str = '_MENU_<label>' + removed + '</label>';
13776        }
13777        else if (end) {
13778            str = '<label>' + removed + '</label>_MENU_';
13779        }
13780
13781        // Wrapper element - use a span as a holder for where the select will go
13782        var tmpId = 'tmp-' + (+new Date())
13783        var div = $('<div/>')
13784            .addClass(classes.container)
13785            .append(
13786                str.replace('_MENU_', '<span id="' + tmpId + '"></span>')
13787            );
13788
13789        // Save text node content for macro updating
13790        var textNodes = [];
13791        Array.prototype.slice.call(div.find('label')[0].childNodes).forEach(function (el) {
13792            if (el.nodeType === Node.TEXT_NODE) {
13793                textNodes.push({
13794                    el: el,
13795                    text: el.textContent
13796                });
13797            }
13798        });
13799
13800        // Update the label text in case it has an entries value
13801        var updateEntries = function (len) {
13802            textNodes.forEach(function (node) {
13803                node.el.textContent = _fnMacros(settings, node.text, len);
13804            });
13805        }
13806
13807        // Next, the select itself, along with the options
13808        var select = $('<select/>', {
13809            'aria-controls': tableId,
13810            'class': classes.select
13811        });
13812
13813        for (i = 0; i < lengths.length; i++) {
13814            // Attempt to look up the length from the i18n options
13815            var label = settings.api.i18n('lengthLabels.' + lengths[i], null);
13816
13817            if (label === null) {
13818                // If not present, fallback to old style
13819                label = typeof language[i] === 'number' ?
13820                    settings.fnFormatNumber(language[i]) :
13821                    language[i];
13822            }
13823
13824            select[0][i] = new Option(label, lengths[i]);
13825        }
13826
13827        // add for and id to label and input
13828        div.find('label').attr('for', 'dt-length-' + __lengthCounter);
13829        select.attr('id', 'dt-length-' + __lengthCounter);
13830        __lengthCounter++;
13831
13832        // Swap in the select list
13833        div.find('#' + tmpId).replaceWith(select);
13834
13835        // Can't use `select` variable as user might provide their own and the
13836        // reference is broken by the use of outerHTML
13837        $('select', div)
13838            .val(settings._iDisplayLength)
13839            .on('change.DT', function () {
13840                _fnLengthChange(settings, $(this).val());
13841                _fnDraw(settings);
13842            });
13843
13844        // Update node value whenever anything changes the table's length
13845        $(settings.nTable).on('length.dt.DT', function (e, s, len) {
13846            if (settings === s) {
13847                $('select', div).val(len);
13848
13849                // Resolve plurals in the text for the new length
13850                updateEntries(len);
13851            }
13852        });
13853
13854        updateEntries(settings._iDisplayLength);
13855
13856        return div;
13857    }, 'l');
13858
13859    // jQuery access
13860    $.fn.dataTable = DataTable;
13861
13862    // Provide access to the host jQuery object (circular reference)
13863    DataTable.$ = $;
13864
13865    // Legacy aliases
13866    $.fn.dataTableSettings = DataTable.settings;
13867    $.fn.dataTableExt = DataTable.ext;
13868
13869    // With a capital `D` we return a DataTables API instance rather than a
13870    // jQuery object
13871    $.fn.DataTable = function (opts) {
13872        return $(this).dataTable(opts).api();
13873    };
13874
13875    // All properties that are available to $.fn.dataTable should also be
13876    // available on $.fn.DataTable
13877    $.each(DataTable, function (prop, val) {
13878        $.fn.DataTable[prop] = val;
13879    });
13880
13881    return DataTable;
13882}));

Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.