All Downloads are FREE. Search and download functionalities are using the official Maven repository.

package.js.dataTables.mjs Maven / Gradle / Ivy

There is a newer version: 2.1.7
Show newest version
/*! DataTables 2.1.8
 * © SpryMedia Ltd - datatables.net/license
 */

import jQuery from 'jquery';

// DataTables code uses $ internally, but we want to be able to
// reassign $ with the `use` method, so it is a regular var.
var $ = jQuery;


var DataTable = function ( selector, options )
{
	// Check if called with a window or jQuery object for DOM less applications
	// This is for backwards compatibility
	if (DataTable.factory(selector, options)) {
		return DataTable;
	}

	// When creating with `new`, create a new DataTable, returning the API instance
	if (this instanceof DataTable) {
		return $(selector).DataTable(options);
	}
	else {
		// Argument switching
		options = selector;
	}

	var _that = this;
	var emptyInit = options === undefined;
	var len = this.length;

	if ( emptyInit ) {
		options = {};
	}

	// Method to get DT API instance from jQuery object
	this.api = function ()
	{
		return new _Api( this );
	};

	this.each(function() {
		// For each initialisation we want to give it a clean initialisation
		// object that can be bashed around
		var o = {};
		var oInit = len > 1 ? // optimisation for single table case
			_fnExtend( o, options, true ) :
			options;

		
		var i=0, iLen;
		var sId = this.getAttribute( 'id' );
		var defaults = DataTable.defaults;
		var $this = $(this);
		
		
		/* Sanity check */
		if ( this.nodeName.toLowerCase() != 'table' )
		{
			_fnLog( null, 0, 'Non-table node initialisation ('+this.nodeName+')', 2 );
			return;
		}
		
		$(this).trigger( 'options.dt', oInit );
		
		/* Backwards compatibility for the defaults */
		_fnCompatOpts( defaults );
		_fnCompatCols( defaults.column );
		
		/* Convert the camel-case defaults to Hungarian */
		_fnCamelToHungarian( defaults, defaults, true );
		_fnCamelToHungarian( defaults.column, defaults.column, true );
		
		/* Setting up the initialisation object */
		_fnCamelToHungarian( defaults, $.extend( oInit, $this.data() ), true );
		
		
		
		/* Check to see if we are re-initialising a table */
		var allSettings = DataTable.settings;
		for ( i=0, iLen=allSettings.length ; i').prependTo(this),
			fastData: function (row, column, type) {
				return _fnGetCellData(oSettings, row, column, type);
			}
		} );
		oSettings.nTable = this;
		oSettings.oInit  = oInit;
		
		allSettings.push( oSettings );
		
		// Make a single API instance available for internal handling
		oSettings.api = new _Api( oSettings );
		
		// Need to add the instance after the instance after the settings object has been added
		// to the settings array, so we can self reference the table instance if more than one
		oSettings.oInstance = (_that.length===1) ? _that : $this.dataTable();
		
		// Backwards compatibility, before we apply all the defaults
		_fnCompatOpts( oInit );
		
		// If the length menu is given, but the init display length is not, use the length menu
		if ( oInit.aLengthMenu && ! oInit.iDisplayLength )
		{
			oInit.iDisplayLength = Array.isArray(oInit.aLengthMenu[0])
				? oInit.aLengthMenu[0][0]
				: $.isPlainObject( oInit.aLengthMenu[0] )
					? oInit.aLengthMenu[0].value
					: oInit.aLengthMenu[0];
		}
		
		// Apply the defaults and init options to make a single init object will all
		// options defined from defaults and instance options.
		oInit = _fnExtend( $.extend( true, {}, defaults ), oInit );
		
		
		// Map the initialisation options onto the settings object
		_fnMap( oSettings.oFeatures, oInit, [
			"bPaginate",
			"bLengthChange",
			"bFilter",
			"bSort",
			"bSortMulti",
			"bInfo",
			"bProcessing",
			"bAutoWidth",
			"bSortClasses",
			"bServerSide",
			"bDeferRender"
		] );
		_fnMap( oSettings, oInit, [
			"ajax",
			"fnFormatNumber",
			"sServerMethod",
			"aaSorting",
			"aaSortingFixed",
			"aLengthMenu",
			"sPaginationType",
			"iStateDuration",
			"bSortCellsTop",
			"iTabIndex",
			"sDom",
			"fnStateLoadCallback",
			"fnStateSaveCallback",
			"renderer",
			"searchDelay",
			"rowId",
			"caption",
			"layout",
			"orderDescReverse",
			"typeDetect",
			[ "iCookieDuration", "iStateDuration" ], // backwards compat
			[ "oSearch", "oPreviousSearch" ],
			[ "aoSearchCols", "aoPreSearchCols" ],
			[ "iDisplayLength", "_iDisplayLength" ]
		] );
		_fnMap( oSettings.oScroll, oInit, [
			[ "sScrollX", "sX" ],
			[ "sScrollXInner", "sXInner" ],
			[ "sScrollY", "sY" ],
			[ "bScrollCollapse", "bCollapse" ]
		] );
		_fnMap( oSettings.oLanguage, oInit, "fnInfoCallback" );
		
		/* Callback functions which are array driven */
		_fnCallbackReg( oSettings, 'aoDrawCallback',       oInit.fnDrawCallback );
		_fnCallbackReg( oSettings, 'aoStateSaveParams',    oInit.fnStateSaveParams );
		_fnCallbackReg( oSettings, 'aoStateLoadParams',    oInit.fnStateLoadParams );
		_fnCallbackReg( oSettings, 'aoStateLoaded',        oInit.fnStateLoaded );
		_fnCallbackReg( oSettings, 'aoRowCallback',        oInit.fnRowCallback );
		_fnCallbackReg( oSettings, 'aoRowCreatedCallback', oInit.fnCreatedRow );
		_fnCallbackReg( oSettings, 'aoHeaderCallback',     oInit.fnHeaderCallback );
		_fnCallbackReg( oSettings, 'aoFooterCallback',     oInit.fnFooterCallback );
		_fnCallbackReg( oSettings, 'aoInitComplete',       oInit.fnInitComplete );
		_fnCallbackReg( oSettings, 'aoPreDrawCallback',    oInit.fnPreDrawCallback );
		
		oSettings.rowIdFn = _fnGetObjectDataFn( oInit.rowId );
		
		/* Browser support detection */
		_fnBrowserDetect( oSettings );
		
		var oClasses = oSettings.oClasses;
		
		$.extend( oClasses, DataTable.ext.classes, oInit.oClasses );
		$this.addClass( oClasses.table );
		
		if (! oSettings.oFeatures.bPaginate) {
			oInit.iDisplayStart = 0;
		}
		
		if ( oSettings.iInitDisplayStart === undefined )
		{
			/* Display start point, taking into account the save saving */
			oSettings.iInitDisplayStart = oInit.iDisplayStart;
			oSettings._iDisplayStart = oInit.iDisplayStart;
		}
		
		var defer = oInit.iDeferLoading;
		if ( defer !== null )
		{
			oSettings.deferLoading = true;
		
			var tmp = Array.isArray(defer);
			oSettings._iRecordsDisplay = tmp ? defer[0] : defer;
			oSettings._iRecordsTotal = tmp ? defer[1] : defer;
		}
		
		/*
		 * Columns
		 * See if we should load columns automatically or use defined ones
		 */
		var columnsInit = [];
		var thead = this.getElementsByTagName('thead');
		var initHeaderLayout = _fnDetectHeader( oSettings, thead[0] );
		
		// If we don't have a columns array, then generate one with nulls
		if ( oInit.aoColumns ) {
			columnsInit = oInit.aoColumns;
		}
		else if ( initHeaderLayout.length ) {
			for ( i=0, iLen=initHeaderLayout[0].length ; i').appendTo( $this );
			}
		
			caption.html( oSettings.caption );
		}
		
		// Store the caption side, so we can remove the element from the document
		// when creating the element
		if (caption.length) {
			caption[0]._captionSide = caption.css('caption-side');
			oSettings.captionNode = caption[0];
		}
		
		if ( thead.length === 0 ) {
			thead = $('').appendTo($this);
		}
		oSettings.nTHead = thead[0];
		$('tr', thead).addClass(oClasses.thead.row);
		
		var tbody = $this.children('tbody');
		if ( tbody.length === 0 ) {
			tbody = $('').insertAfter(thead);
		}
		oSettings.nTBody = tbody[0];
		
		var tfoot = $this.children('tfoot');
		if ( tfoot.length === 0 ) {
			// If we are a scrolling table, and no footer has been given, then we need to create
			// a tfoot element for the caption element to be appended to
			tfoot = $('').appendTo($this);
		}
		oSettings.nTFoot = tfoot[0];
		$('tr', tfoot).addClass(oClasses.tfoot.row);
		
		// Copy the data index array
		oSettings.aiDisplay = oSettings.aiDisplayMaster.slice();
		
		// Initialisation complete - table can be drawn
		oSettings.bInitialised = true;
		
		// Language definitions
		var oLanguage = oSettings.oLanguage;
		$.extend( true, oLanguage, oInit.oLanguage );
		
		if ( oLanguage.sUrl ) {
			// Get the language definitions from a file
			$.ajax( {
				dataType: 'json',
				url: oLanguage.sUrl,
				success: function ( json ) {
					_fnCamelToHungarian( defaults.oLanguage, json );
					$.extend( true, oLanguage, json, oSettings.oInit.oLanguage );
		
					_fnCallbackFire( oSettings, null, 'i18n', [oSettings], true);
					_fnInitialise( oSettings );
				},
				error: function () {
					// Error occurred loading language file
					_fnLog( oSettings, 0, 'i18n file loading error', 21 );
		
					// Continue on as best we can
					_fnInitialise( oSettings );
				}
			} );
		}
		else {
			_fnCallbackFire( oSettings, null, 'i18n', [oSettings], true);
			_fnInitialise( oSettings );
		}
	} );
	_that = null;
	return this;
};



/**
 * DataTables extensions
 * 
 * This namespace acts as a collection area for plug-ins that can be used to
 * extend DataTables capabilities. Indeed many of the build in methods
 * use this method to provide their own capabilities (sorting methods for
 * example).
 *
 * Note that this namespace is aliased to `jQuery.fn.dataTableExt` for legacy
 * reasons
 *
 *  @namespace
 */
DataTable.ext = _ext = {
	/**
	 * Buttons. For use with the Buttons extension for DataTables. This is
	 * defined here so other extensions can define buttons regardless of load
	 * order. It is _not_ used by DataTables core.
	 *
	 *  @type object
	 *  @default {}
	 */
	buttons: {},


	/**
	 * Element class names
	 *
	 *  @type object
	 *  @default {}
	 */
	classes: {},


	/**
	 * DataTables build type (expanded by the download builder)
	 *
	 *  @type string
	 */
	builder: "-source-",


	/**
	 * Error reporting.
	 * 
	 * How should DataTables report an error. Can take the value 'alert',
	 * 'throw', 'none' or a function.
	 *
	 *  @type string|function
	 *  @default alert
	 */
	errMode: "alert",


	/**
	 * Legacy so v1 plug-ins don't throw js errors on load
	 */
	feature: [],

	/**
	 * Feature plug-ins.
	 * 
	 * This is an object of callbacks which provide the features for DataTables
	 * to be initialised via the `layout` option.
	 */
	features: {},


	/**
	 * Row searching.
	 * 
	 * This method of searching is complimentary to the default type based
	 * searching, and a lot more comprehensive as it allows you complete control
	 * over the searching logic. Each element in this array is a function
	 * (parameters described below) that is called for every row in the table,
	 * and your logic decides if it should be included in the searching data set
	 * or not.
	 *
	 * Searching functions have the following input parameters:
	 *
	 * 1. `{object}` DataTables settings object: see
	 *    {@link DataTable.models.oSettings}
	 * 2. `{array|object}` Data for the row to be processed (same as the
	 *    original format that was passed in as the data source, or an array
	 *    from a DOM data source
	 * 3. `{int}` Row index ({@link DataTable.models.oSettings.aoData}), which
	 *    can be useful to retrieve the `TR` element if you need DOM interaction.
	 *
	 * And the following return is expected:
	 *
	 * * {boolean} Include the row in the searched result set (true) or not
	 *   (false)
	 *
	 * Note that as with the main search ability in DataTables, technically this
	 * is "filtering", since it is subtractive. However, for consistency in
	 * naming we call it searching here.
	 *
	 *  @type array
	 *  @default []
	 *
	 *  @example
	 *    // The following example shows custom search being applied to the
	 *    // fourth column (i.e. the data[3] index) based on two input values
	 *    // from the end-user, matching the data in a certain range.
	 *    $.fn.dataTable.ext.search.push(
	 *      function( settings, data, dataIndex ) {
	 *        var min = document.getElementById('min').value * 1;
	 *        var max = document.getElementById('max').value * 1;
	 *        var version = data[3] == "-" ? 0 : data[3]*1;
	 *
	 *        if ( min == "" && max == "" ) {
	 *          return true;
	 *        }
	 *        else if ( min == "" && version < max ) {
	 *          return true;
	 *        }
	 *        else if ( min < version && "" == max ) {
	 *          return true;
	 *        }
	 *        else if ( min < version && version < max ) {
	 *          return true;
	 *        }
	 *        return false;
	 *      }
	 *    );
	 */
	search: [],


	/**
	 * Selector extensions
	 *
	 * The `selector` option can be used to extend the options available for the
	 * selector modifier options (`selector-modifier` object data type) that
	 * each of the three built in selector types offer (row, column and cell +
	 * their plural counterparts). For example the Select extension uses this
	 * mechanism to provide an option to select only rows, columns and cells
	 * that have been marked as selected by the end user (`{selected: true}`),
	 * which can be used in conjunction with the existing built in selector
	 * options.
	 *
	 * Each property is an array to which functions can be pushed. The functions
	 * take three attributes:
	 *
	 * * Settings object for the host table
	 * * Options object (`selector-modifier` object type)
	 * * Array of selected item indexes
	 *
	 * The return is an array of the resulting item indexes after the custom
	 * selector has been applied.
	 *
	 *  @type object
	 */
	selector: {
		cell: [],
		column: [],
		row: []
	},


	/**
	 * Legacy configuration options. Enable and disable legacy options that
	 * are available in DataTables.
	 *
	 *  @type object
	 */
	legacy: {
		/**
		 * Enable / disable DataTables 1.9 compatible server-side processing
		 * requests
		 *
		 *  @type boolean
		 *  @default null
		 */
		ajax: null
	},


	/**
	 * Pagination plug-in methods.
	 * 
	 * Each entry in this object is a function and defines which buttons should
	 * be shown by the pagination rendering method that is used for the table:
	 * {@link DataTable.ext.renderer.pageButton}. The renderer addresses how the
	 * buttons are displayed in the document, while the functions here tell it
	 * what buttons to display. This is done by returning an array of button
	 * descriptions (what each button will do).
	 *
	 * Pagination types (the four built in options and any additional plug-in
	 * options defined here) can be used through the `paginationType`
	 * initialisation parameter.
	 *
	 * The functions defined take two parameters:
	 *
	 * 1. `{int} page` The current page index
	 * 2. `{int} pages` The number of pages in the table
	 *
	 * Each function is expected to return an array where each element of the
	 * array can be one of:
	 *
	 * * `first` - Jump to first page when activated
	 * * `last` - Jump to last page when activated
	 * * `previous` - Show previous page when activated
	 * * `next` - Show next page when activated
	 * * `{int}` - Show page of the index given
	 * * `{array}` - A nested array containing the above elements to add a
	 *   containing 'DIV' element (might be useful for styling).
	 *
	 * Note that DataTables v1.9- used this object slightly differently whereby
	 * an object with two functions would be defined for each plug-in. That
	 * ability is still supported by DataTables 1.10+ to provide backwards
	 * compatibility, but this option of use is now decremented and no longer
	 * documented in DataTables 1.10+.
	 *
	 *  @type object
	 *  @default {}
	 *
	 *  @example
	 *    // Show previous, next and current page buttons only
	 *    $.fn.dataTableExt.oPagination.current = function ( page, pages ) {
	 *      return [ 'previous', page, 'next' ];
	 *    };
	 */
	pager: {},


	renderer: {
		pageButton: {},
		header: {}
	},


	/**
	 * Ordering plug-ins - custom data source
	 * 
	 * The extension options for ordering of data available here is complimentary
	 * to the default type based ordering that DataTables typically uses. It
	 * allows much greater control over the the data that is being used to
	 * order a column, but is necessarily therefore more complex.
	 * 
	 * This type of ordering is useful if you want to do ordering based on data
	 * live from the DOM (for example the contents of an 'input' element) rather
	 * than just the static string that DataTables knows of.
	 * 
	 * The way these plug-ins work is that you create an array of the values you
	 * wish to be ordering for the column in question and then return that
	 * array. The data in the array much be in the index order of the rows in
	 * the table (not the currently ordering order!). Which order data gathering
	 * function is run here depends on the `dt-init columns.orderDataType`
	 * parameter that is used for the column (if any).
	 *
	 * The functions defined take two parameters:
	 *
	 * 1. `{object}` DataTables settings object: see
	 *    {@link DataTable.models.oSettings}
	 * 2. `{int}` Target column index
	 *
	 * Each function is expected to return an array:
	 *
	 * * `{array}` Data for the column to be ordering upon
	 *
	 *  @type array
	 *
	 *  @example
	 *    // Ordering using `input` node values
	 *    $.fn.dataTable.ext.order['dom-text'] = function  ( settings, col )
	 *    {
	 *      return this.api().column( col, {order:'index'} ).nodes().map( function ( td, i ) {
	 *        return $('input', td).val();
	 *      } );
	 *    }
	 */
	order: {},


	/**
	 * Type based plug-ins.
	 *
	 * Each column in DataTables has a type assigned to it, either by automatic
	 * detection or by direct assignment using the `type` option for the column.
	 * The type of a column will effect how it is ordering and search (plug-ins
	 * can also make use of the column type if required).
	 *
	 * @namespace
	 */
	type: {
		/**
		 * Automatic column class assignment
		 */
		className: {},

		/**
		 * Type detection functions.
		 *
		 * The functions defined in this object are used to automatically detect
		 * a column's type, making initialisation of DataTables super easy, even
		 * when complex data is in the table.
		 *
		 * The functions defined take two parameters:
		 *
	     *  1. `{*}` Data from the column cell to be analysed
	     *  2. `{settings}` DataTables settings object. This can be used to
	     *     perform context specific type detection - for example detection
	     *     based on language settings such as using a comma for a decimal
	     *     place. Generally speaking the options from the settings will not
	     *     be required
		 *
		 * Each function is expected to return:
		 *
		 * * `{string|null}` Data type detected, or null if unknown (and thus
		 *   pass it on to the other type detection functions.
		 *
		 *  @type array
		 *
		 *  @example
		 *    // Currency type detection plug-in:
		 *    $.fn.dataTable.ext.type.detect.push(
		 *      function ( data, settings ) {
		 *        // Check the numeric part
		 *        if ( ! data.substring(1).match(/[0-9]/) ) {
		 *          return null;
		 *        }
		 *
		 *        // Check prefixed by currency
		 *        if ( data.charAt(0) == '$' || data.charAt(0) == '£' ) {
		 *          return 'currency';
		 *        }
		 *        return null;
		 *      }
		 *    );
		 */
		detect: [],

		/**
		 * Automatic renderer assignment
		 */
		render: {},


		/**
		 * Type based search formatting.
		 *
		 * The type based searching functions can be used to pre-format the
		 * data to be search on. For example, it can be used to strip HTML
		 * tags or to de-format telephone numbers for numeric only searching.
		 *
		 * Note that is a search is not defined for a column of a given type,
		 * no search formatting will be performed.
		 * 
		 * Pre-processing of searching data plug-ins - When you assign the sType
		 * for a column (or have it automatically detected for you by DataTables
		 * or a type detection plug-in), you will typically be using this for
		 * custom sorting, but it can also be used to provide custom searching
		 * by allowing you to pre-processing the data and returning the data in
		 * the format that should be searched upon. This is done by adding
		 * functions this object with a parameter name which matches the sType
		 * for that target column. This is the corollary of afnSortData
		 * for searching data.
		 *
		 * The functions defined take a single parameter:
		 *
	     *  1. `{*}` Data from the column cell to be prepared for searching
		 *
		 * Each function is expected to return:
		 *
		 * * `{string|null}` Formatted string that will be used for the searching.
		 *
		 *  @type object
		 *  @default {}
		 *
		 *  @example
		 *    $.fn.dataTable.ext.type.search['title-numeric'] = function ( d ) {
		 *      return d.replace(/\n/g," ").replace( /<.*?>/g, "" );
		 *    }
		 */
		search: {},


		/**
		 * Type based ordering.
		 *
		 * The column type tells DataTables what ordering to apply to the table
		 * when a column is sorted upon. The order for each type that is defined,
		 * is defined by the functions available in this object.
		 *
		 * Each ordering option can be described by three properties added to
		 * this object:
		 *
		 * * `{type}-pre` - Pre-formatting function
		 * * `{type}-asc` - Ascending order function
		 * * `{type}-desc` - Descending order function
		 *
		 * All three can be used together, only `{type}-pre` or only
		 * `{type}-asc` and `{type}-desc` together. It is generally recommended
		 * that only `{type}-pre` is used, as this provides the optimal
		 * implementation in terms of speed, although the others are provided
		 * for compatibility with existing Javascript sort functions.
		 *
		 * `{type}-pre`: Functions defined take a single parameter:
		 *
	     *  1. `{*}` Data from the column cell to be prepared for ordering
		 *
		 * And return:
		 *
		 * * `{*}` Data to be sorted upon
		 *
		 * `{type}-asc` and `{type}-desc`: Functions are typical Javascript sort
		 * functions, taking two parameters:
		 *
	     *  1. `{*}` Data to compare to the second parameter
	     *  2. `{*}` Data to compare to the first parameter
		 *
		 * And returning:
		 *
		 * * `{*}` Ordering match: <0 if first parameter should be sorted lower
		 *   than the second parameter, ===0 if the two parameters are equal and
		 *   >0 if the first parameter should be sorted height than the second
		 *   parameter.
		 * 
		 *  @type object
		 *  @default {}
		 *
		 *  @example
		 *    // Numeric ordering of formatted numbers with a pre-formatter
		 *    $.extend( $.fn.dataTable.ext.type.order, {
		 *      "string-pre": function(x) {
		 *        a = (a === "-" || a === "") ? 0 : a.replace( /[^\d\-\.]/g, "" );
		 *        return parseFloat( a );
		 *      }
		 *    } );
		 *
		 *  @example
		 *    // Case-sensitive string ordering, with no pre-formatting method
		 *    $.extend( $.fn.dataTable.ext.order, {
		 *      "string-case-asc": function(x,y) {
		 *        return ((x < y) ? -1 : ((x > y) ? 1 : 0));
		 *      },
		 *      "string-case-desc": function(x,y) {
		 *        return ((x < y) ? 1 : ((x > y) ? -1 : 0));
		 *      }
		 *    } );
		 */
		order: {}
	},

	/**
	 * Unique DataTables instance counter
	 *
	 * @type int
	 * @private
	 */
	_unique: 0,


	//
	// Depreciated
	// The following properties are retained for backwards compatibility only.
	// The should not be used in new projects and will be removed in a future
	// version
	//

	/**
	 * Version check function.
	 *  @type function
	 *  @depreciated Since 1.10
	 */
	fnVersionCheck: DataTable.fnVersionCheck,


	/**
	 * Index for what 'this' index API functions should use
	 *  @type int
	 *  @deprecated Since v1.10
	 */
	iApiIndex: 0,


	/**
	 * Software version
	 *  @type string
	 *  @deprecated Since v1.10
	 */
	sVersion: DataTable.version
};


//
// Backwards compatibility. Alias to pre 1.10 Hungarian notation counter parts
//
$.extend( _ext, {
	afnFiltering: _ext.search,
	aTypes:       _ext.type.detect,
	ofnSearch:    _ext.type.search,
	oSort:        _ext.type.order,
	afnSortData:  _ext.order,
	aoFeatures:   _ext.feature,
	oStdClasses:  _ext.classes,
	oPagination:  _ext.pager
} );


$.extend( DataTable.ext.classes, {
	container: 'dt-container',
	empty: {
		row: 'dt-empty'
	},
	info: {
		container: 'dt-info'
	},
	layout: {
		row: 'dt-layout-row',
		cell: 'dt-layout-cell',
		tableRow: 'dt-layout-table',
		tableCell: '',
		start: 'dt-layout-start',
		end: 'dt-layout-end',
		full: 'dt-layout-full'
	},
	length: {
		container: 'dt-length',
		select: 'dt-input'
	},
	order: {
		canAsc: 'dt-orderable-asc',
		canDesc: 'dt-orderable-desc',
		isAsc: 'dt-ordering-asc',
		isDesc: 'dt-ordering-desc',
		none: 'dt-orderable-none',
		position: 'sorting_'
	},
	processing: {
		container: 'dt-processing'
	},
	scrolling: {
		body: 'dt-scroll-body',
		container: 'dt-scroll',
		footer: {
			self: 'dt-scroll-foot',
			inner: 'dt-scroll-footInner'
		},
		header: {
			self: 'dt-scroll-head',
			inner: 'dt-scroll-headInner'
		}
	},
	search: {
		container: 'dt-search',
		input: 'dt-input'
	},
	table: 'dataTable',	
	tbody: {
		cell: '',
		row: ''
	},
	thead: {
		cell: '',
		row: ''
	},
	tfoot: {
		cell: '',
		row: ''
	},
	paging: {
		active: 'current',
		button: 'dt-paging-button',
		container: 'dt-paging',
		disabled: 'disabled',
		nav: ''
	}
} );


/*
 * It is useful to have variables which are scoped locally so only the
 * DataTables functions can access them and they don't leak into global space.
 * At the same time these functions are often useful over multiple files in the
 * core and API, so we list, or at least document, all variables which are used
 * by DataTables as private variables here. This also ensures that there is no
 * clashing of variable names and that they can easily referenced for reuse.
 */


// Defined else where
//  _selector_run
//  _selector_opts
//  _selector_row_indexes

var _ext; // DataTable.ext
var _Api; // DataTable.Api
var _api_register; // DataTable.Api.register
var _api_registerPlural; // DataTable.Api.registerPlural

var _re_dic = {};
var _re_new_lines = /[\r\n\u2028]/g;
var _re_html = /<([^>]*>)/g;
var _max_str_len = Math.pow(2, 28);

// This is not strict ISO8601 - Date.parse() is quite lax, although
// implementations differ between browsers.
var _re_date = /^\d{2,4}[./-]\d{1,2}[./-]\d{1,2}([T ]{1}\d{1,2}[:.]\d{2}([.:]\d{2})?)?$/;

// Escape regular expression special characters
var _re_escape_regex = new RegExp( '(\\' + [ '/', '.', '*', '+', '?', '|', '(', ')', '[', ']', '{', '}', '\\', '$', '^', '-' ].join('|\\') + ')', 'g' );

// https://en.wikipedia.org/wiki/Foreign_exchange_market
// - \u20BD - Russian ruble.
// - \u20a9 - South Korean Won
// - \u20BA - Turkish Lira
// - \u20B9 - Indian Rupee
// - R - Brazil (R$) and South Africa
// - fr - Swiss Franc
// - kr - Swedish krona, Norwegian krone and Danish krone
// - \u2009 is thin space and \u202F is narrow no-break space, both used in many
// - Ƀ - Bitcoin
// - Ξ - Ethereum
//   standards as thousands separators.
var _re_formatted_numeric = /['\u00A0,$£€¥%\u2009\u202F\u20BD\u20a9\u20BArfkɃΞ]/gi;


var _empty = function ( d ) {
	return !d || d === true || d === '-' ? true : false;
};


var _intVal = function ( s ) {
	var integer = parseInt( s, 10 );
	return !isNaN(integer) && isFinite(s) ? integer : null;
};

// Convert from a formatted number with characters other than `.` as the
// decimal place, to a Javascript number
var _numToDecimal = function ( num, decimalPoint ) {
	// Cache created regular expressions for speed as this function is called often
	if ( ! _re_dic[ decimalPoint ] ) {
		_re_dic[ decimalPoint ] = new RegExp( _fnEscapeRegex( decimalPoint ), 'g' );
	}
	return typeof num === 'string' && decimalPoint !== '.' ?
		num.replace( /\./g, '' ).replace( _re_dic[ decimalPoint ], '.' ) :
		num;
};


var _isNumber = function ( d, decimalPoint, formatted, allowEmpty ) {
	var type = typeof d;
	var strType = type === 'string';

	if ( type === 'number' || type === 'bigint') {
		return true;
	}

	// If empty return immediately so there must be a number if it is a
	// formatted string (this stops the string "k", or "kr", etc being detected
	// as a formatted number for currency
	if ( allowEmpty && _empty( d ) ) {
		return true;
	}

	if ( decimalPoint && strType ) {
		d = _numToDecimal( d, decimalPoint );
	}

	if ( formatted && strType ) {
		d = d.replace( _re_formatted_numeric, '' );
	}

	return !isNaN( parseFloat(d) ) && isFinite( d );
};


// A string without HTML in it can be considered to be HTML still
var _isHtml = function ( d ) {
	return _empty( d ) || typeof d === 'string';
};

// Is a string a number surrounded by HTML?
var _htmlNumeric = function ( d, decimalPoint, formatted, allowEmpty ) {
	if ( allowEmpty && _empty( d ) ) {
		return true;
	}

	// input and select strings mean that this isn't just a number
	if (typeof d === 'string' && d.match(/<(input|select)/i)) {
		return null;
	}

	var html = _isHtml( d );
	return ! html ?
		null :
		_isNumber( _stripHtml( d ), decimalPoint, formatted, allowEmpty ) ?
			true :
			null;
};


var _pluck = function ( a, prop, prop2 ) {
	var out = [];
	var i=0, ien=a.length;

	// Could have the test in the loop for slightly smaller code, but speed
	// is essential here
	if ( prop2 !== undefined ) {
		for ( ; i _max_str_len) {
		throw new Error('Exceeded max str len');
	}

	var previous;

	input = input.replace(_re_html, ''); // Complete tags

	// Safety for incomplete script tag - use do / while to ensure that
	// we get all instances
	do {
		previous = input;
		input = input.replace(/