/*! datatables 1.10.21 * ©2008-2020 sprymedia ltd - datatables.net/license */ /** * @summary datatables * @description paginate, search and order html tables * @version 1.10.21 * @file jquery.datatables.js * @author sprymedia ltd * @contact www.datatables.net * @copyright copyright 2008-2020 sprymedia ltd. * * this source file is free software, available under the following license: * mit license - http://datatables.net/license * * this source file is distributed in the hope that it will be useful, but * without any warranty; without even the implied warranty of merchantability * or fitness for a particular purpose. see the license files for details. * * for details please refer to: http://www.datatables.net */ /*jslint evil: true, undef: true, browser: true */ /*globals $,require,jquery,define,_selector_run,_selector_opts,_selector_first,_selector_row_indexes,_ext,_api,_api_register,_api_registerplural,_re_new_lines,_re_html,_re_formatted_numeric,_re_escape_regex,_empty,_intval,_numtodecimal,_isnumber,_ishtml,_htmlnumeric,_pluck,_pluck_order,_range,_striphtml,_unique,_fnbuildajax,_fnajaxupdate,_fnajaxparameters,_fnajaxupdatedraw,_fnajaxdatasrc,_fnaddcolumn,_fncolumnoptions,_fnadjustcolumnsizing,_fnvisibletocolumnindex,_fncolumnindextovisible,_fnvisblecolumns,_fngetcolumns,_fncolumntypes,_fnapplycolumndefs,_fnhungarianmap,_fncameltohungarian,_fnlanguagecompat,_fnbrowserdetect,_fnadddata,_fnaddtr,_fnnodetodataindex,_fnnodetocolumnindex,_fngetcelldata,_fnsetcelldata,_fnsplitobjnotation,_fngetobjectdatafn,_fnsetobjectdatafn,_fngetdatamaster,_fncleartable,_fndeleteindex,_fninvalidate,_fngetrowelements,_fncreatetr,_fnbuildhead,_fndrawhead,_fndraw,_fnredraw,_fnaddoptionshtml,_fndetectheader,_fngetuniqueths,_fnfeaturehtmlfilter,_fnfiltercomplete,_fnfiltercustom,_fnfiltercolumn,_fnfilter,_fnfiltercreatesearch,_fnescaperegex,_fnfilterdata,_fnfeaturehtmlinfo,_fnupdateinfo,_fninfomacros,_fninitialise,_fninitcomplete,_fnlengthchange,_fnfeaturehtmllength,_fnfeaturehtmlpaginate,_fnpagechange,_fnfeaturehtmlprocessing,_fnprocessingdisplay,_fnfeaturehtmltable,_fnscrolldraw,_fnapplytochildren,_fncalculatecolumnwidths,_fnthrottle,_fnconverttowidth,_fngetwidestnode,_fngetmaxlenstring,_fnstringtocss,_fnsortflatten,_fnsort,_fnsortaria,_fnsortlistener,_fnsortattachlistener,_fnsortingclasses,_fnsortdata,_fnsavestate,_fnloadstate,_fnsettingsfromnode,_fnlog,_fnmap,_fnbindaction,_fncallbackreg,_fncallbackfire,_fnlengthoverflow,_fnrenderer,_fndatasource,_fnrowattributes*/ (function( factory ) { "use strict"; if ( typeof define === 'function' && define.amd ) { // amd define( ['jquery'], function ( $ ) { return factory( $, window, document ); } ); } else if ( typeof exports === 'object' ) { // commonjs module.exports = function (root, $) { if ( ! root ) { // commonjs environments without a window global must pass a // root. this will give an error otherwise root = window; } if ( ! $ ) { $ = typeof window !== 'undefined' ? // jquery's factory checks for a global window require('jquery') : require('jquery')( root ); } return factory( $, root, root.document ); }; } else { // browser factory( jquery, window, document ); } } (function( $, window, document, undefined ) { "use strict"; /** * datatables is a plug-in for the jquery javascript library. it is a highly * flexible tool, based upon the foundations of progressive enhancement, * which will add advanced interaction controls to any html table. for a * full list of features please refer to * [datatables.net](href="http://datatables.net). * * note that the `datatable` object is not a global variable but is aliased * to `jquery.fn.datatable` and `jquery.fn.datatable` through which it may * be accessed. * * @class * @param {object} [init={}] configuration object for datatables. options * are defined by {@link datatable.defaults} * @requires jquery 1.7+ * * @example * // basic initialisation * $(document).ready( function { * $('#example').datatable(); * } ); * * @example * // initialisation with configuration options - in this case, disable * // pagination and sorting. * $(document).ready( function { * $('#example').datatable( { * "paginate": false, * "sort": false * } ); * } ); */ var datatable = function ( options ) { /** * perform a jquery selector action on the table's tr elements (from the tbody) and * return the resulting jquery object. * @param {string|node|jquery} sselector jquery selector or node collection to act on * @param {object} [oopts] optional parameters for modifying the rows to be included * @param {string} [oopts.filter=none] select tr elements that meet the current filter * criterion ("applied") or all tr elements (i.e. no filter). * @param {string} [oopts.order=current] order of the tr elements in the processed array. * can be either 'current', whereby the current sorting of the table is used, or * 'original' whereby the original order the data was read into the table is used. * @param {string} [oopts.page=all] limit the selection to the currently displayed page * ("current") or not ("all"). if 'current' is given, then order is assumed to be * 'current' and filter is 'applied', regardless of what they might be given as. * @returns {object} jquery object, filtered by the given selector. * @dtopt api * @deprecated since v1.10 * * @example * $(document).ready(function() { * var otable = $('#example').datatable(); * * // highlight every second row * otable.$('tr:odd').css('backgroundcolor', 'blue'); * } ); * * @example * $(document).ready(function() { * var otable = $('#example').datatable(); * * // filter to rows with 'webkit' in them, add a background colour and then * // remove the filter, thus highlighting the 'webkit' rows only. * otable.fnfilter('webkit'); * otable.$('tr', {"search": "applied"}).css('backgroundcolor', 'blue'); * otable.fnfilter(''); * } ); */ this.$ = function ( sselector, oopts ) { return this.api(true).$( sselector, oopts ); }; /** * almost identical to $ in operation, but in this case returns the data for the matched * rows - as such, the jquery selector used should match tr row nodes or td/th cell nodes * rather than any descendants, so the data can be obtained for the row/cell. if matching * rows are found, the data returned is the original data array/object that was used to * create the row (or a generated array if from a dom source). * * this method is often useful in-combination with $ where both functions are given the * same parameters and the array indexes will match identically. * @param {string|node|jquery} sselector jquery selector or node collection to act on * @param {object} [oopts] optional parameters for modifying the rows to be included * @param {string} [oopts.filter=none] select elements that meet the current filter * criterion ("applied") or all elements (i.e. no filter). * @param {string} [oopts.order=current] order of the data in the processed array. * can be either 'current', whereby the current sorting of the table is used, or * 'original' whereby the original order the data was read into the table is used. * @param {string} [oopts.page=all] limit the selection to the currently displayed page * ("current") or not ("all"). if 'current' is given, then order is assumed to be * 'current' and filter is 'applied', regardless of what they might be given as. * @returns {array} data for the matched elements. if any elements, as a result of the * selector, were not tr, td or th elements in the datatable, they will have a null * entry in the array. * @dtopt api * @deprecated since v1.10 * * @example * $(document).ready(function() { * var otable = $('#example').datatable(); * * // get the data from the first row in the table * var data = otable._('tr:first'); * * // do something useful with the data * alert( "first cell is: "+data[0] ); * } ); * * @example * $(document).ready(function() { * var otable = $('#example').datatable(); * * // filter to 'webkit' and get all data for * otable.fnfilter('webkit'); * var data = otable._('tr', {"search": "applied"}); * * // do something with the data * alert( data.length+" rows matched the search" ); * } ); */ this._ = function ( sselector, oopts ) { return this.api(true).rows( sselector, oopts ).data(); }; /** * create a datatables api instance, with the currently selected tables for * the api's context. * @param {boolean} [traditional=false] set the api instance's context to be * only the table referred to by the `datatable.ext.iapiindex` option, as was * used in the api presented by datatables 1.9- (i.e. the traditional mode), * or if all tables captured in the jquery object should be used. * @return {datatables.api} */ this.api = function ( traditional ) { return traditional ? new _api( _fnsettingsfromnode( this[ _ext.iapiindex ] ) ) : new _api( this ); }; /** * add a single new row or multiple rows of data to the table. please note * that this is suitable for client-side processing only - if you are using * server-side processing (i.e. "bserverside": true), then to add data, you * must add it to the data source, i.e. the server-side, through an ajax call. * @param {array|object} data the data to be added to the table. this can be: * * @param {bool} [redraw=true] redraw the table or not * @returns {array} an array of integers, representing the list of indexes in * aodata ({@link datatable.models.osettings}) that have been added to * the table. * @dtopt api * @deprecated since v1.10 * * @example * // global var for counter * var gicount = 2; * * $(document).ready(function() { * $('#example').datatable(); * } ); * * function fnclickaddrow() { * $('#example').datatable().fnadddata( [ * gicount+".1", * gicount+".2", * gicount+".3", * gicount+".4" ] * ); * * gicount++; * } */ this.fnadddata = function( data, redraw ) { var api = this.api( true ); /* check if we want to add multiple rows or not */ var rows = $.isarray(data) && ( $.isarray(data[0]) || $.isplainobject(data[0]) ) ? api.rows.add( data ) : api.row.add( data ); if ( redraw === undefined || redraw ) { api.draw(); } return rows.flatten().toarray(); }; /** * this function will make datatables recalculate the column sizes, based on the data * contained in the table and the sizes applied to the columns (in the dom, css or * through the swidth parameter). this can be useful when the width of the table's * parent element changes (for example a window resize). * @param {boolean} [bredraw=true] redraw the table or not, you will typically want to * @dtopt api * @deprecated since v1.10 * * @example * $(document).ready(function() { * var otable = $('#example').datatable( { * "sscrolly": "200px", * "bpaginate": false * } ); * * $(window).on('resize', function () { * otable.fnadjustcolumnsizing(); * } ); * } ); */ this.fnadjustcolumnsizing = function ( bredraw ) { var api = this.api( true ).columns.adjust(); var settings = api.settings()[0]; var scroll = settings.oscroll; if ( bredraw === undefined || bredraw ) { api.draw( false ); } else if ( scroll.sx !== "" || scroll.sy !== "" ) { /* if not redrawing, but scrolling, we want to apply the new column sizes anyway */ _fnscrolldraw( settings ); } }; /** * quickly and simply clear a table * @param {bool} [bredraw=true] redraw the table or not * @dtopt api * @deprecated since v1.10 * * @example * $(document).ready(function() { * var otable = $('#example').datatable(); * * // immediately 'nuke' the current rows (perhaps waiting for an ajax callback...) * otable.fncleartable(); * } ); */ this.fncleartable = function( bredraw ) { var api = this.api( true ).clear(); if ( bredraw === undefined || bredraw ) { api.draw(); } }; /** * the exact opposite of 'opening' a row, this function will close any rows which * are currently 'open'. * @param {node} ntr the table row to 'close' * @returns {int} 0 on success, or 1 if failed (can't find the row) * @dtopt api * @deprecated since v1.10 * * @example * $(document).ready(function() { * var otable; * * // 'open' an information row when a row is clicked on * $('#example tbody tr').click( function () { * if ( otable.fnisopen(this) ) { * otable.fnclose( this ); * } else { * otable.fnopen( this, "temporary row opened", "info_row" ); * } * } ); * * otable = $('#example').datatable(); * } ); */ this.fnclose = function( ntr ) { this.api( true ).row( ntr ).child.hide(); }; /** * remove a row for the table * @param {mixed} target the index of the row from aodata to be deleted, or * the tr element you want to delete * @param {function|null} [callback] callback function * @param {bool} [redraw=true] redraw the table or not * @returns {array} the row that was deleted * @dtopt api * @deprecated since v1.10 * * @example * $(document).ready(function() { * var otable = $('#example').datatable(); * * // immediately remove the first row * otable.fndeleterow( 0 ); * } ); */ this.fndeleterow = function( target, callback, redraw ) { var api = this.api( true ); var rows = api.rows( target ); var settings = rows.settings()[0]; var data = settings.aodata[ rows[0][0] ]; rows.remove(); if ( callback ) { callback.call( this, settings, data ); } if ( redraw === undefined || redraw ) { api.draw(); } return data; }; /** * restore the table to it's original state in the dom by removing all of datatables * enhancements, alterations to the dom structure of the table and event listeners. * @param {boolean} [remove=false] completely remove the table from the dom * @dtopt api * @deprecated since v1.10 * * @example * $(document).ready(function() { * // this example is fairly pointless in reality, but shows how fndestroy can be used * var otable = $('#example').datatable(); * otable.fndestroy(); * } ); */ this.fndestroy = function ( remove ) { this.api( true ).destroy( remove ); }; /** * redraw the table * @param {bool} [complete=true] re-filter and resort (if enabled) the table before the draw. * @dtopt api * @deprecated since v1.10 * * @example * $(document).ready(function() { * var otable = $('#example').datatable(); * * // re-draw the table - you wouldn't want to do it here, but it's an example :-) * otable.fndraw(); * } ); */ this.fndraw = function( complete ) { // note that this isn't an exact match to the old call to _fndraw - it takes // into account the new data, but can hold position. this.api( true ).draw( complete ); }; /** * filter the input based on data * @param {string} sinput string to filter the table on * @param {int|null} [icolumn] column to limit filtering to * @param {bool} [bregex=false] treat as regular expression or not * @param {bool} [bsmart=true] perform smart filtering or not * @param {bool} [bshowglobal=true] show the input global filter in it's input box(es) * @param {bool} [bcaseinsensitive=true] do case-insensitive matching (true) or not (false) * @dtopt api * @deprecated since v1.10 * * @example * $(document).ready(function() { * var otable = $('#example').datatable(); * * // sometime later - filter... * otable.fnfilter( 'test string' ); * } ); */ this.fnfilter = function( sinput, icolumn, bregex, bsmart, bshowglobal, bcaseinsensitive ) { var api = this.api( true ); if ( icolumn === null || icolumn === undefined ) { api.search( sinput, bregex, bsmart, bcaseinsensitive ); } else { api.column( icolumn ).search( sinput, bregex, bsmart, bcaseinsensitive ); } api.draw(); }; /** * get the data for the whole table, an individual row or an individual cell based on the * provided parameters. * @param {int|node} [src] a tr row node, td/th cell node or an integer. if given as * a tr node then the data source for the whole row will be returned. if given as a * td/th cell node then icol will be automatically calculated and the data for the * cell returned. if given as an integer, then this is treated as the aodata internal * data index for the row (see fngetposition) and the data for that row used. * @param {int} [col] optional column index that you want the data of. * @returns {array|object|string} if mrow is undefined, then the data for all rows is * returned. if mrow is defined, just data for that row, and is icol is * defined, only data for the designated cell is returned. * @dtopt api * @deprecated since v1.10 * * @example * // row data * $(document).ready(function() { * otable = $('#example').datatable(); * * otable.$('tr').click( function () { * var data = otable.fngetdata( this ); * // ... do something with the array / object of data for the row * } ); * } ); * * @example * // individual cell data * $(document).ready(function() { * otable = $('#example').datatable(); * * otable.$('td').click( function () { * var sdata = otable.fngetdata( this ); * alert( 'the cell clicked on had the value of '+sdata ); * } ); * } ); */ this.fngetdata = function( src, col ) { var api = this.api( true ); if ( src !== undefined ) { var type = src.nodename ? src.nodename.tolowercase() : ''; return col !== undefined || type == 'td' || type == 'th' ? api.cell( src, col ).data() : api.row( src ).data() || null; } return api.data().toarray(); }; /** * get an array of the tr nodes that are used in the table's body. note that you will * typically want to use the '$' api method in preference to this as it is more * flexible. * @param {int} [irow] optional row index for the tr element you want * @returns {array|node} if irow is undefined, returns an array of all tr elements * in the table's body, or irow is defined, just the tr element requested. * @dtopt api * @deprecated since v1.10 * * @example * $(document).ready(function() { * var otable = $('#example').datatable(); * * // get the nodes from the table * var nnodes = otable.fngetnodes( ); * } ); */ this.fngetnodes = function( irow ) { var api = this.api( true ); return irow !== undefined ? api.row( irow ).node() : api.rows().nodes().flatten().toarray(); }; /** * get the array indexes of a particular cell from it's dom element * and column index including hidden columns * @param {node} node this can either be a tr, td or th in the table's body * @returns {int} if nnode is given as a tr, then a single index is returned, or * if given as a cell, an array of [row index, column index (visible), * column index (all)] is given. * @dtopt api * @deprecated since v1.10 * * @example * $(document).ready(function() { * $('#example tbody td').click( function () { * // get the position of the current data from the node * var apos = otable.fngetposition( this ); * * // get the data array for this row * var adata = otable.fngetdata( apos[0] ); * * // update the data array and return the value * adata[ apos[1] ] = 'clicked'; * this.innerhtml = 'clicked'; * } ); * * // init datatables * otable = $('#example').datatable(); * } ); */ this.fngetposition = function( node ) { var api = this.api( true ); var nodename = node.nodename.touppercase(); if ( nodename == 'tr' ) { return api.row( node ).index(); } else if ( nodename == 'td' || nodename == 'th' ) { var cell = api.cell( node ).index(); return [ cell.row, cell.columnvisible, cell.column ]; } return null; }; /** * check to see if a row is 'open' or not. * @param {node} ntr the table row to check * @returns {boolean} true if the row is currently open, false otherwise * @dtopt api * @deprecated since v1.10 * * @example * $(document).ready(function() { * var otable; * * // 'open' an information row when a row is clicked on * $('#example tbody tr').click( function () { * if ( otable.fnisopen(this) ) { * otable.fnclose( this ); * } else { * otable.fnopen( this, "temporary row opened", "info_row" ); * } * } ); * * otable = $('#example').datatable(); * } ); */ this.fnisopen = function( ntr ) { return this.api( true ).row( ntr ).child.isshown(); }; /** * this function will place a new row directly after a row which is currently * on display on the page, with the html contents that is passed into the * function. this can be used, for example, to ask for confirmation that a * particular record should be deleted. * @param {node} ntr the table row to 'open' * @param {string|node|jquery} mhtml the html to put into the row * @param {string} sclass class to give the new td cell * @returns {node} the row opened. note that if the table row passed in as the * first parameter, is not found in the table, this method will silently * return. * @dtopt api * @deprecated since v1.10 * * @example * $(document).ready(function() { * var otable; * * // 'open' an information row when a row is clicked on * $('#example tbody tr').click( function () { * if ( otable.fnisopen(this) ) { * otable.fnclose( this ); * } else { * otable.fnopen( this, "temporary row opened", "info_row" ); * } * } ); * * otable = $('#example').datatable(); * } ); */ this.fnopen = function( ntr, mhtml, sclass ) { return this.api( true ) .row( ntr ) .child( mhtml, sclass ) .show() .child()[0]; }; /** * change the pagination - provides the internal logic for pagination in a simple api * function. with this function you can have a datatables table go to the next, * previous, first or last pages. * @param {string|int} maction paging action to take: "first", "previous", "next" or "last" * or page number to jump to (integer), note that page 0 is the first page. * @param {bool} [bredraw=true] redraw the table or not * @dtopt api * @deprecated since v1.10 * * @example * $(document).ready(function() { * var otable = $('#example').datatable(); * otable.fnpagechange( 'next' ); * } ); */ this.fnpagechange = function ( maction, bredraw ) { var api = this.api( true ).page( maction ); if ( bredraw === undefined || bredraw ) { api.draw(false); } }; /** * show a particular column * @param {int} icol the column whose display should be changed * @param {bool} bshow show (true) or hide (false) the column * @param {bool} [bredraw=true] redraw the table or not * @dtopt api * @deprecated since v1.10 * * @example * $(document).ready(function() { * var otable = $('#example').datatable(); * * // hide the second column after initialisation * otable.fnsetcolumnvis( 1, false ); * } ); */ this.fnsetcolumnvis = function ( icol, bshow, bredraw ) { var api = this.api( true ).column( icol ).visible( bshow ); if ( bredraw === undefined || bredraw ) { api.columns.adjust().draw(); } }; /** * get the settings for a particular table for external manipulation * @returns {object} datatables settings object. see * {@link datatable.models.osettings} * @dtopt api * @deprecated since v1.10 * * @example * $(document).ready(function() { * var otable = $('#example').datatable(); * var osettings = otable.fnsettings(); * * // show an example parameter from the settings * alert( osettings._idisplaystart ); * } ); */ this.fnsettings = function() { return _fnsettingsfromnode( this[_ext.iapiindex] ); }; /** * sort the table by a particular column * @param {int} icol the data index to sort on. note that this will not match the * 'display index' if you have hidden data entries * @dtopt api * @deprecated since v1.10 * * @example * $(document).ready(function() { * var otable = $('#example').datatable(); * * // sort immediately with columns 0 and 1 * otable.fnsort( [ [0,'asc'], [1,'asc'] ] ); * } ); */ this.fnsort = function( aasort ) { this.api( true ).order( aasort ).draw(); }; /** * attach a sort listener to an element for a given column * @param {node} nnode the element to attach the sort listener to * @param {int} icolumn the column that a click on this node will sort on * @param {function} [fncallback] callback function when sort is run * @dtopt api * @deprecated since v1.10 * * @example * $(document).ready(function() { * var otable = $('#example').datatable(); * * // sort on column 1, when 'sorter' is clicked on * otable.fnsortlistener( document.getelementbyid('sorter'), 1 ); * } ); */ this.fnsortlistener = function( nnode, icolumn, fncallback ) { this.api( true ).order.listener( nnode, icolumn, fncallback ); }; /** * update a table cell or row - this method will accept either a single value to * update the cell with, an array of values with one element for each column or * an object in the same format as the original data source. the function is * self-referencing in order to make the multi column updates easier. * @param {object|array|string} mdata data to update the cell/row with * @param {node|int} mrow tr element you want to update or the aodata index * @param {int} [icolumn] the column to update, give as null or undefined to * update a whole row. * @param {bool} [bredraw=true] redraw the table or not * @param {bool} [baction=true] perform pre-draw actions or not * @returns {int} 0 on success, 1 on error * @dtopt api * @deprecated since v1.10 * * @example * $(document).ready(function() { * var otable = $('#example').datatable(); * otable.fnupdate( 'example update', 0, 0 ); // single cell * otable.fnupdate( ['a', 'b', 'c', 'd', 'e'], $('tbody tr')[0] ); // row * } ); */ this.fnupdate = function( mdata, mrow, icolumn, bredraw, baction ) { var api = this.api( true ); if ( icolumn === undefined || icolumn === null ) { api.row( mrow ).data( mdata ); } else { api.cell( mrow, icolumn ).data( mdata ); } if ( baction === undefined || baction ) { api.columns.adjust(); } if ( bredraw === undefined || bredraw ) { api.draw(); } return 0; }; /** * provide a common method for plug-ins to check the version of datatables being used, in order * to ensure compatibility. * @param {string} sversion version string to check for, in the format "x.y.z". note that the * formats "x" and "x.y" are also acceptable. * @returns {boolean} true if this version of datatables is greater or equal to the required * version, or false if this version of datatales is not suitable * @method * @dtopt api * @deprecated since v1.10 * * @example * $(document).ready(function() { * var otable = $('#example').datatable(); * alert( otable.fnversioncheck( '1.9.0' ) ); * } ); */ this.fnversioncheck = _ext.fnversioncheck; var _that = this; var emptyinit = options === undefined; var len = this.length; if ( emptyinit ) { options = {}; } this.oapi = this.internal = _ext.internal; // extend with old style plug-in api methods for ( var fn in datatable.ext.internal ) { if ( fn ) { this[fn] = _fnexternapifunc(fn); } } 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; /*global oinit,_that,emptyinit*/ var i=0, ilen, j, jlen, k, klen; var sid = this.getattribute( 'id' ); var binithandedoff = false; 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; } /* 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').appendto($this); } osettings.nthead = thead[0]; var tbody = $this.children('tbody'); if ( tbody.length === 0 ) { tbody = $('').appendto($this); } osettings.ntbody = tbody[0]; var tfoot = $this.children('tfoot'); if ( tfoot.length === 0 && captions.length > 0 && (osettings.oscroll.sx !== "" || osettings.oscroll.sy !== "") ) { // 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); } if ( tfoot.length === 0 || tfoot.children().length === 0 ) { $this.addclass( oclasses.snofooter ); } else if ( tfoot.length > 0 ) { osettings.ntfoot = tfoot[0]; _fndetectheader( osettings.aofooter, osettings.ntfoot ); } /* check if there is data passing into the constructor */ if ( oinit.aadata ) { for ( i=0 ; i/g; // 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' ); // http://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 = /[',$£€¥%\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 ) { var strtype = typeof d === 'string'; // 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 ( _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'; }; var _htmlnumeric = function ( d, decimalpoint, formatted ) { if ( _empty( d ) ) { return true; } var html = _ishtml( d ); return ! html ? null : _isnumber( _striphtml( d ), decimalpoint, formatted ) ? 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') .css( { position: 'fixed', top: 0, left: $(window).scrollleft()*-1, // allow for scrolling height: 1, width: 1, overflow: 'hidden' } ) .append( $('
') .css( { position: 'absolute', top: 1, left: 1, width: 100, overflow: 'scroll' } ) .append( $('
') .css( { width: '100%', height: 10 } ) ) ) .appendto( 'body' ); var outer = n.children(); var inner = outer.children(); // numbers below, in order, are: // inner.offsetwidth, inner.clientwidth, outer.offsetwidth, outer.clientwidth // // ie6 xp: 100 100 100 83 // ie7 vista: 100 100 100 83 // ie 8+ windows: 83 83 100 83 // evergreen windows: 83 83 100 83 // evergreen mac with scrollbars: 85 85 100 85 // evergreen mac without scrollbars: 100 100 100 100 // get scrollbar width browser.barwidth = outer[0].offsetwidth - outer[0].clientwidth; // ie6/7 will oversize a width 100% element inside a scrolling element, to // include the width of the scrollbar, while other browsers ensure the inner // element is contained without forcing scrolling browser.bscrolloversize = inner[0].offsetwidth === 100 && outer[0].clientwidth !== 100; // in rtl text layout, some browsers (most, but not all) will place the // scrollbar on the left, rather than the right. browser.bscrollbarleft = math.round( inner.offset().left ) !== 1; // ie8- don't provide height and width for getboundingclientrect browser.bbounding = n[0].getboundingclientrect().width ? true : false; n.remove(); } $.extend( settings.obrowser, datatable.__browser ); settings.oscroll.ibarwidth = datatable.__browser.barwidth; } /** * array.prototype reduce[right] method, used for browsers which don't support * js 1.6. done this way to reduce code size, since we iterate either way * @param {object} settings datatables settings object * @memberof datatable#oapi */ function _fnreduce ( that, fn, init, start, end, inc ) { var i = start, value, isset = false; if ( init !== undefined ) { value = init; isset = true; } while ( i !== end ) { if ( ! that.hasownproperty(i) ) { continue; } value = isset ? fn( value, that[i], i, that ) : that[i]; isset = true; i += inc; } return value; } /** * add a column to the list used for the table with default values * @param {object} osettings datatables settings object * @param {node} nth the th element for this column * @memberof datatable#oapi */ function _fnaddcolumn( osettings, nth ) { // add column to aocolumns array var odefaults = datatable.defaults.column; var icol = osettings.aocolumns.length; var ocol = $.extend( {}, datatable.models.ocolumn, odefaults, { "nth": nth ? nth : document.createelement('th'), "stitle": odefaults.stitle ? odefaults.stitle : nth ? nth.innerhtml : '', "adatasort": odefaults.adatasort ? odefaults.adatasort : [icol], "mdata": odefaults.mdata ? odefaults.mdata : icol, idx: icol } ); osettings.aocolumns.push( ocol ); // add search object for column specific search. note that the `searchcols[ icol ]` // passed into extend can be undefined. this allows the user to give a default // with only some of the parameters defined, and also not give a default var searchcols = osettings.aopresearchcols; searchcols[ icol ] = $.extend( {}, datatable.models.osearch, searchcols[ icol ] ); // use the default column options function to initialise classes etc _fncolumnoptions( osettings, icol, $(nth).data() ); } /** * apply options for a column * @param {object} osettings datatables settings object * @param {int} icol column index to consider * @param {object} ooptions object with stype, bvisible and bsearchable etc * @memberof datatable#oapi */ function _fncolumnoptions( osettings, icol, ooptions ) { var ocol = osettings.aocolumns[ icol ]; var oclasses = osettings.oclasses; var th = $(ocol.nth); // try to get width information from the dom. we can't get it from css // as we'd need to parse the css stylesheet. `width` option can override if ( ! ocol.swidthorig ) { // width attribute ocol.swidthorig = th.attr('width') || null; // style attribute var t = (th.attr('style') || '').match(/width:\s*(\d+[pxem%]+)/); if ( t ) { ocol.swidthorig = t[1]; } } /* user specified column options */ if ( ooptions !== undefined && ooptions !== null ) { // backwards compatibility _fncompatcols( ooptions ); // map camel case parameters to their hungarian counterparts _fncameltohungarian( datatable.defaults.column, ooptions, true ); /* backwards compatibility for mdataprop */ if ( ooptions.mdataprop !== undefined && !ooptions.mdata ) { ooptions.mdata = ooptions.mdataprop; } if ( ooptions.stype ) { ocol._smanualtype = ooptions.stype; } // `class` is a reserved word in javascript, so we need to provide // the ability to use a valid name for the camel case input if ( ooptions.classname && ! ooptions.sclass ) { ooptions.sclass = ooptions.classname; } if ( ooptions.sclass ) { th.addclass( ooptions.sclass ); } $.extend( ocol, ooptions ); _fnmap( ocol, ooptions, "swidth", "swidthorig" ); /* idatasort to be applied (backwards compatibility), but adatasort will take * priority if defined */ if ( ooptions.idatasort !== undefined ) { ocol.adatasort = [ ooptions.idatasort ]; } _fnmap( ocol, ooptions, "adatasort" ); } /* cache the data get and set functions for speed */ var mdatasrc = ocol.mdata; var mdata = _fngetobjectdatafn( mdatasrc ); var mrender = ocol.mrender ? _fngetobjectdatafn( ocol.mrender ) : null; var attrtest = function( src ) { return typeof src === 'string' && src.indexof('@') !== -1; }; ocol._battrsrc = $.isplainobject( mdatasrc ) && ( attrtest(mdatasrc.sort) || attrtest(mdatasrc.type) || attrtest(mdatasrc.filter) ); ocol._setter = null; ocol.fngetdata = function (rowdata, type, meta) { var innerdata = mdata( rowdata, type, undefined, meta ); return mrender && type ? mrender( innerdata, type, rowdata, meta ) : innerdata; }; ocol.fnsetdata = function ( rowdata, val, meta ) { return _fnsetobjectdatafn( mdatasrc )( rowdata, val, meta ); }; // indicate if datatables should read dom data as an object or array // used in _fngetrowelements if ( typeof mdatasrc !== 'number' ) { osettings._rowreadobject = true; } /* feature sorting overrides column specific when off */ if ( !osettings.ofeatures.bsort ) { ocol.bsortable = false; th.addclass( oclasses.ssortablenone ); // have to add class here as order event isn't called } /* check that the class assignment is correct for sorting */ var basc = $.inarray('asc', ocol.assorting) !== -1; var bdesc = $.inarray('desc', ocol.assorting) !== -1; if ( !ocol.bsortable || (!basc && !bdesc) ) { ocol.ssortingclass = oclasses.ssortablenone; ocol.ssortingclassjui = ""; } else if ( basc && !bdesc ) { ocol.ssortingclass = oclasses.ssortableasc; ocol.ssortingclassjui = oclasses.ssortjuiascallowed; } else if ( !basc && bdesc ) { ocol.ssortingclass = oclasses.ssortabledesc; ocol.ssortingclassjui = oclasses.ssortjuidescallowed; } else { ocol.ssortingclass = oclasses.ssortable; ocol.ssortingclassjui = oclasses.ssortjui; } } /** * adjust the table column widths for new data. note: you would probably want to * do a redraw after calling this function! * @param {object} settings datatables settings object * @memberof datatable#oapi */ function _fnadjustcolumnsizing ( settings ) { /* not interested in doing column width calculation if auto-width is disabled */ if ( settings.ofeatures.bautowidth !== false ) { var columns = settings.aocolumns; _fncalculatecolumnwidths( settings ); for ( var i=0 , ilen=columns.length ; i