'))}),s});
\ No newline at end of file
diff --git a/public/datatables/DataTables-1.13.2/js/dataTables.dataTables.js b/public/datatables/DataTables-1.13.2/js/dataTables.dataTables.js
new file mode 100644
index 000000000..09924b8d2
--- /dev/null
+++ b/public/datatables/DataTables-1.13.2/js/dataTables.dataTables.js
@@ -0,0 +1,47 @@
+/*! DataTables styling integration
+ * ©2018 SpryMedia Ltd - datatables.net/license
+ */
+
+(function( factory ){
+ if ( typeof define === 'function' && define.amd ) {
+ // AMD
+ define( ['jquery', 'datatables.net'], 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 );
+ }
+
+ if ( ! $.fn.dataTable ) {
+ require('datatables.net')(root, $);
+ }
+
+ return factory( $, root, root.document );
+ };
+ }
+ else {
+ // Browser
+ factory( jQuery, window, document );
+ }
+}(function( $, window, document, undefined ) {
+'use strict';
+var DataTable = $.fn.dataTable;
+
+
+
+
+
+return DataTable;
+}));
diff --git a/public/datatables/DataTables-1.13.2/js/dataTables.dataTables.min.js b/public/datatables/DataTables-1.13.2/js/dataTables.dataTables.min.js
new file mode 100644
index 000000000..d0e70c276
--- /dev/null
+++ b/public/datatables/DataTables-1.13.2/js/dataTables.dataTables.min.js
@@ -0,0 +1,4 @@
+/*! DataTables styling integration
+ * ©2018 SpryMedia Ltd - datatables.net/license
+ */
+!function(t){"function"==typeof define&&define.amd?define(["jquery","datatables.net"],function(e){return t(e,window,document)}):"object"==typeof exports?module.exports=function(e,n){return e=e||window,(n=n||("undefined"!=typeof window?require("jquery"):require("jquery")(e))).fn.dataTable||require("datatables.net")(e,n),t(n,0,e.document)}:t(jQuery,window,document)}(function(e,n,t,u){"use strict";return e.fn.dataTable});
\ No newline at end of file
diff --git a/public/datatables/DataTables-1.13.2/js/dataTables.foundation.js b/public/datatables/DataTables-1.13.2/js/dataTables.foundation.js
new file mode 100644
index 000000000..2dcb5198d
--- /dev/null
+++ b/public/datatables/DataTables-1.13.2/js/dataTables.foundation.js
@@ -0,0 +1,192 @@
+/*! DataTables Foundation integration
+ * ©2011-2015 SpryMedia Ltd - datatables.net/license
+ */
+
+(function( factory ){
+ if ( typeof define === 'function' && define.amd ) {
+ // AMD
+ define( ['jquery', 'datatables.net'], 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 );
+ }
+
+ if ( ! $.fn.dataTable ) {
+ require('datatables.net')(root, $);
+ }
+
+ return factory( $, root, root.document );
+ };
+ }
+ else {
+ // Browser
+ factory( jQuery, window, document );
+ }
+}(function( $, window, document, undefined ) {
+'use strict';
+var DataTable = $.fn.dataTable;
+
+
+
+/**
+ * DataTables integration for Foundation. This requires Foundation 5 and
+ * DataTables 1.10 or newer.
+ *
+ * This file sets the defaults and adds options to DataTables to style its
+ * controls using Foundation. See http://datatables.net/manual/styling/foundation
+ * for further information.
+ */
+
+// Detect Foundation 5 / 6 as they have different element and class requirements
+var meta = $('
').appendTo('head');
+DataTable.ext.foundationVersion = meta.css('font-family').match(/small|medium|large/) ? 6 : 5;
+meta.remove();
+
+
+$.extend( DataTable.ext.classes, {
+ sWrapper: "dataTables_wrapper dt-foundation",
+ sProcessing: "dataTables_processing panel callout"
+} );
+
+
+/* Set the defaults for DataTables initialisation */
+$.extend( true, DataTable.defaults, {
+ dom:
+ "<'row grid-x'<'small-6 columns cell'l><'small-6 columns cell'f>r>"+
+ "t"+
+ "<'row grid-x'<'small-6 columns cell'i><'small-6 columns cell'p>>",
+ renderer: 'foundation'
+} );
+
+
+/* Page button renderer */
+DataTable.ext.renderer.pageButton.foundation = function ( settings, host, idx, buttons, page, pages ) {
+ var api = new DataTable.Api( settings );
+ var classes = settings.oClasses;
+ var lang = settings.oLanguage.oPaginate;
+ var aria = settings.oLanguage.oAria.paginate || {};
+ var btnDisplay, btnClass;
+ var tag;
+ var v5 = DataTable.ext.foundationVersion === 5;
+
+ var attach = function( container, buttons ) {
+ var i, ien, node, button;
+ var clickHandler = function ( e ) {
+ e.preventDefault();
+ if ( !$(e.currentTarget).hasClass('unavailable') && api.page() != e.data.action ) {
+ api.page( e.data.action ).draw( 'page' );
+ }
+ };
+
+ for ( i=0, ien=buttons.length ; i
0 ?
+ '' : ' unavailable disabled');
+ tag = page > 0 ? 'a' : null;
+ break;
+
+ case 'previous':
+ btnDisplay = lang.sPrevious;
+ btnClass = button + (page > 0 ?
+ '' : ' unavailable disabled');
+ tag = page > 0 ? 'a' : null;
+ break;
+
+ case 'next':
+ btnDisplay = lang.sNext;
+ btnClass = button + (page < pages-1 ?
+ '' : ' unavailable disabled');
+ tag = page < pages-1 ? 'a' : null;
+ break;
+
+ case 'last':
+ btnDisplay = lang.sLast;
+ btnClass = button + (page < pages-1 ?
+ '' : ' unavailable disabled');
+ tag = page < pages-1 ? 'a' : null;
+ break;
+
+ default:
+ btnDisplay = button + 1;
+ btnClass = page === button ?
+ 'current' : '';
+ tag = page === button ?
+ null : 'a';
+ break;
+ }
+
+ if ( v5 ) {
+ tag = 'a';
+ }
+
+ if ( btnDisplay ) {
+ var disabled = btnClass.indexOf('disabled') !== -1;
+
+ node = $('', {
+ 'class': classes.sPageButton+' '+btnClass,
+ 'id': idx === 0 && typeof button === 'string' ?
+ settings.sTableId +'_'+ button :
+ null
+ } )
+ .append( tag ?
+ $('<'+tag+'/>', {
+ 'href': disabled ? null : '#',
+ 'aria-controls': settings.sTableId,
+ 'aria-disabled': disabled ? 'true' : null,
+ 'aria-label': aria[ button ],
+ 'aria-role': 'link',
+ 'aria-current': btnClass === 'current' ? 'page' : null,
+ 'tabindex': settings.iTabIndex,
+ } ).html( btnDisplay ) :
+ btnDisplay
+ )
+ .appendTo( container );
+
+ settings.oApi._fnBindAction(
+ node, {action: button}, clickHandler
+ );
+ }
+ }
+ }
+ };
+
+ attach(
+ $(host).empty().html('').children('ul'),
+ buttons
+ );
+};
+
+
+return DataTable;
+}));
diff --git a/public/datatables/DataTables-1.13.2/js/dataTables.foundation.min.js b/public/datatables/DataTables-1.13.2/js/dataTables.foundation.min.js
new file mode 100644
index 000000000..987334092
--- /dev/null
+++ b/public/datatables/DataTables-1.13.2/js/dataTables.foundation.min.js
@@ -0,0 +1,4 @@
+/*! DataTables Foundation integration
+ * ©2011-2015 SpryMedia Ltd - datatables.net/license
+ */
+!function(n){"function"==typeof define&&define.amd?define(["jquery","datatables.net"],function(a){return n(a,window,document)}):"object"==typeof exports?module.exports=function(a,e){return a=a||window,(e=e||("undefined"!=typeof window?require("jquery"):require("jquery")(a))).fn.dataTable||require("datatables.net")(a,e),n(e,0,a.document)}:n(jQuery,window,document)}(function(y,a,e,n){"use strict";var l=y.fn.dataTable,t=y('').appendTo("head");return l.ext.foundationVersion=t.css("font-family").match(/small|medium|large/)?6:5,t.remove(),y.extend(l.ext.classes,{sWrapper:"dataTables_wrapper dt-foundation",sProcessing:"dataTables_processing panel callout"}),y.extend(!0,l.defaults,{dom:"<'row grid-x'<'small-6 columns cell'l><'small-6 columns cell'f>r>t<'row grid-x'<'small-6 columns cell'i><'small-6 columns cell'p>>",renderer:"foundation"}),l.ext.renderer.pageButton.foundation=function(s,a,o,e,u,d){function c(a,e){for(var n,l,t=function(a){a.preventDefault(),y(a.currentTarget).hasClass("unavailable")||m.page()==a.data.action||m.page(a.data.action).draw("page")},i=0,r=e.length;i",{class:g.sPageButton+" "+p,id:0===o&&"string"==typeof n?s.sTableId+"_"+n:null}).append(b?y("<"+b+"/>",{href:l?null:"#","aria-controls":s.sTableId,"aria-disabled":l?"true":null,"aria-label":w[n],"aria-role":"link","aria-current":"current"===p?"page":null,tabindex:s.iTabIndex}).html(f):f).appendTo(a),s.oApi._fnBindAction(l,{action:n},t))}}var f,p,b,m=new l.Api(s),g=s.oClasses,x=s.oLanguage.oPaginate,w=s.oLanguage.oAria.paginate||{},v=5===l.ext.foundationVersion;c(y(a).empty().html('').children("ul"),e)},l});
\ No newline at end of file
diff --git a/public/datatables/DataTables-1.13.2/js/dataTables.jqueryui.js b/public/datatables/DataTables-1.13.2/js/dataTables.jqueryui.js
new file mode 100644
index 000000000..4c3f7ef62
--- /dev/null
+++ b/public/datatables/DataTables-1.13.2/js/dataTables.jqueryui.js
@@ -0,0 +1,87 @@
+/*! DataTables jQuery UI integration
+ * ©2011-2014 SpryMedia Ltd - datatables.net/license
+ */
+
+(function( factory ){
+ if ( typeof define === 'function' && define.amd ) {
+ // AMD
+ define( ['jquery', 'datatables.net'], 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 );
+ }
+
+ if ( ! $.fn.dataTable ) {
+ require('datatables.net')(root, $);
+ }
+
+ return factory( $, root, root.document );
+ };
+ }
+ else {
+ // Browser
+ factory( jQuery, window, document );
+ }
+}(function( $, window, document, undefined ) {
+'use strict';
+var DataTable = $.fn.dataTable;
+
+
+
+/**
+ * DataTables integration for jQuery UI. This requires jQuery UI and
+ * DataTables 1.10 or newer.
+ *
+ * This file sets the defaults and adds options to DataTables to style its
+ * controls using jQuery UI. See http://datatables.net/manual/styling/jqueryui
+ * for further information.
+ */
+
+var toolbar_prefix = 'fg-toolbar ui-toolbar ui-widget-header ui-helper-clearfix ui-corner-';
+
+/* Set the defaults for DataTables initialisation */
+$.extend( true, DataTable.defaults, {
+ dom:
+ '<"'+toolbar_prefix+'tl ui-corner-tr"lfr>'+
+ 't'+
+ '<"'+toolbar_prefix+'bl ui-corner-br"ip>'
+} );
+
+
+$.extend( DataTable.ext.classes, {
+ "sWrapper": "dataTables_wrapper dt-jqueryui",
+
+ /* Full numbers paging buttons */
+ "sPageButton": "fg-button ui-button ui-state-default",
+ "sPageButtonActive": "ui-state-disabled",
+ "sPageButtonDisabled": "ui-state-disabled",
+
+ /* Features */
+ "sPaging": "dataTables_paginate fg-buttonset ui-buttonset fg-buttonset-multi "+
+ "ui-buttonset-multi paging_", /* Note that the type is postfixed */
+
+ /* Scrolling */
+ "sScrollHead": "dataTables_scrollHead "+"ui-state-default",
+ "sScrollFoot": "dataTables_scrollFoot "+"ui-state-default",
+
+ /* Misc */
+ "sHeaderTH": "ui-state-default",
+ "sFooterTH": "ui-state-default"
+} );
+
+
+return DataTable;
+}));
diff --git a/public/datatables/DataTables-1.13.2/js/dataTables.jqueryui.min.js b/public/datatables/DataTables-1.13.2/js/dataTables.jqueryui.min.js
new file mode 100644
index 000000000..ad21681f2
--- /dev/null
+++ b/public/datatables/DataTables-1.13.2/js/dataTables.jqueryui.min.js
@@ -0,0 +1,4 @@
+/*! DataTables jQuery UI integration
+ * ©2011-2014 SpryMedia Ltd - datatables.net/license
+ */
+!function(a){"function"==typeof define&&define.amd?define(["jquery","datatables.net"],function(e){return a(e,window,document)}):"object"==typeof exports?module.exports=function(e,t){return e=e||window,(t=t||("undefined"!=typeof window?require("jquery"):require("jquery")(e))).fn.dataTable||require("datatables.net")(e,t),a(t,0,e.document)}:a(jQuery,window,document)}(function(e,t,a,u){"use strict";var i=e.fn.dataTable,n="fg-toolbar ui-toolbar ui-widget-header ui-helper-clearfix ui-corner-";return e.extend(!0,i.defaults,{dom:'<"'+n+'tl ui-corner-tr"lfr>t<"'+n+'bl ui-corner-br"ip>'}),e.extend(i.ext.classes,{sWrapper:"dataTables_wrapper dt-jqueryui",sPageButton:"fg-button ui-button ui-state-default",sPageButtonActive:"ui-state-disabled",sPageButtonDisabled:"ui-state-disabled",sPaging:"dataTables_paginate fg-buttonset ui-buttonset fg-buttonset-multi ui-buttonset-multi paging_",sScrollHead:"dataTables_scrollHead ui-state-default",sScrollFoot:"dataTables_scrollFoot ui-state-default",sHeaderTH:"ui-state-default",sFooterTH:"ui-state-default"}),i});
\ No newline at end of file
diff --git a/public/datatables/DataTables-1.13.2/js/dataTables.semanticui.js b/public/datatables/DataTables-1.13.2/js/dataTables.semanticui.js
new file mode 100644
index 000000000..cebc56071
--- /dev/null
+++ b/public/datatables/DataTables-1.13.2/js/dataTables.semanticui.js
@@ -0,0 +1,220 @@
+/*! DataTables Bootstrap 3 integration
+ * ©2011-2015 SpryMedia Ltd - datatables.net/license
+ */
+
+(function( factory ){
+ if ( typeof define === 'function' && define.amd ) {
+ // AMD
+ define( ['jquery', 'datatables.net'], 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 );
+ }
+
+ if ( ! $.fn.dataTable ) {
+ require('datatables.net')(root, $);
+ }
+
+ return factory( $, root, root.document );
+ };
+ }
+ else {
+ // Browser
+ factory( jQuery, window, document );
+ }
+}(function( $, window, document, undefined ) {
+'use strict';
+var DataTable = $.fn.dataTable;
+
+
+
+/**
+ * DataTables integration for FomanticUI (formally SemanticUI)
+ *
+ * This file sets the defaults and adds options to DataTables to style its
+ * controls using Bootstrap. See http://datatables.net/manual/styling/bootstrap
+ * for further information.
+ */
+
+/* Set the defaults for DataTables initialisation */
+$.extend( true, DataTable.defaults, {
+ dom:
+ "<'ui stackable grid'"+
+ "<'row'"+
+ "<'eight wide column'l>"+
+ "<'right aligned eight wide column'f>"+
+ ">"+
+ "<'row dt-table'"+
+ "<'sixteen wide column'tr>"+
+ ">"+
+ "<'row'"+
+ "<'seven wide column'i>"+
+ "<'right aligned nine wide column'p>"+
+ ">"+
+ ">",
+ renderer: 'semanticUI'
+} );
+
+
+/* Default class modification */
+$.extend( DataTable.ext.classes, {
+ sWrapper: "dataTables_wrapper dt-semanticUI",
+ sFilter: "dataTables_filter ui input",
+ sProcessing: "dataTables_processing ui segment",
+ sPageButton: "paginate_button item"
+} );
+
+
+/* Bootstrap paging button renderer */
+DataTable.ext.renderer.pageButton.semanticUI = function ( settings, host, idx, buttons, page, pages ) {
+ var api = new DataTable.Api( settings );
+ var classes = settings.oClasses;
+ var lang = settings.oLanguage.oPaginate;
+ var aria = settings.oLanguage.oAria.paginate || {};
+ var btnDisplay, btnClass;
+
+ var attach = function( container, buttons ) {
+ var i, ien, node, button;
+ var clickHandler = function ( e ) {
+ e.preventDefault();
+ if ( !$(e.currentTarget).hasClass('disabled') && api.page() != e.data.action ) {
+ api.page( e.data.action ).draw( 'page' );
+ }
+ };
+
+ for ( i=0, ien=buttons.length ; i 0 ?
+ '' : ' disabled');
+ break;
+
+ case 'previous':
+ btnDisplay = lang.sPrevious;
+ btnClass = button + (page > 0 ?
+ '' : ' disabled');
+ break;
+
+ case 'next':
+ btnDisplay = lang.sNext;
+ btnClass = button + (page < pages-1 ?
+ '' : ' disabled');
+ break;
+
+ case 'last':
+ btnDisplay = lang.sLast;
+ btnClass = button + (page < pages-1 ?
+ '' : ' disabled');
+ break;
+
+ default:
+ btnDisplay = button + 1;
+ btnClass = page === button ?
+ 'active' : '';
+ break;
+ }
+
+ var disabled = btnClass.indexOf('disabled') !== -1;
+ var tag = disabled ?
+ 'div' :
+ 'a';
+
+ if ( btnDisplay ) {
+ node = $('<'+tag+'>', {
+ 'class': classes.sPageButton+' '+btnClass,
+ 'id': idx === 0 && typeof button === 'string' ?
+ settings.sTableId +'_'+ button :
+ null,
+ 'href': disabled ? null : '#',
+ 'aria-controls': settings.sTableId,
+ 'aria-disabled': disabled ? 'true' : null,
+ 'aria-label': aria[ button ],
+ 'aria-role': 'link',
+ 'aria-current': btnClass === 'active' ? 'page' : null,
+ 'data-dt-idx': button,
+ 'tabindex': settings.iTabIndex
+ } )
+ .html( btnDisplay )
+ .appendTo( container );
+
+ settings.oApi._fnBindAction(
+ node, {action: button}, clickHandler
+ );
+ }
+ }
+ }
+ };
+
+ // IE9 throws an 'unknown error' if document.activeElement is used
+ // inside an iframe or frame.
+ var activeEl;
+
+ try {
+ // Because this approach is destroying and recreating the paging
+ // elements, focus is lost on the select button which is bad for
+ // accessibility. So we want to restore focus once the draw has
+ // completed
+ activeEl = $(host).find(document.activeElement).data('dt-idx');
+ }
+ catch (e) {}
+
+ attach(
+ $(host).empty().html('').children(),
+ buttons
+ );
+
+ if ( activeEl !== undefined ) {
+ $(host).find( '[data-dt-idx='+activeEl+']' ).trigger('focus');
+ }
+};
+
+
+// Javascript enhancements on table initialisation
+$(document).on( 'init.dt', function (e, ctx) {
+ if ( e.namespace !== 'dt' ) {
+ return;
+ }
+
+ var api = new $.fn.dataTable.Api( ctx );
+
+ // Length menu drop down
+ if ( $.fn.dropdown ) {
+ $( 'div.dataTables_length select', api.table().container() ).dropdown();
+ }
+
+ // Filtering input
+ $( 'div.dataTables_filter.ui.input', api.table().container() ).removeClass('input').addClass('form');
+ $( 'div.dataTables_filter input', api.table().container() ).wrap( '' );
+} );
+
+
+return DataTable;
+}));
diff --git a/public/datatables/DataTables-1.13.2/js/dataTables.semanticui.min.js b/public/datatables/DataTables-1.13.2/js/dataTables.semanticui.min.js
new file mode 100644
index 000000000..b191a6326
--- /dev/null
+++ b/public/datatables/DataTables-1.13.2/js/dataTables.semanticui.min.js
@@ -0,0 +1,4 @@
+/*! DataTables Bootstrap 3 integration
+ * ©2011-2015 SpryMedia Ltd - datatables.net/license
+ */
+!function(t){"function"==typeof define&&define.amd?define(["jquery","datatables.net"],function(e){return t(e,window,document)}):"object"==typeof exports?module.exports=function(e,a){return e=e||window,(a=a||("undefined"!=typeof window?require("jquery"):require("jquery")(e))).fn.dataTable||require("datatables.net")(e,a),t(a,0,e.document)}:t(jQuery,window,document)}(function(v,e,i,n){"use strict";var d=v.fn.dataTable;return v.extend(!0,d.defaults,{dom:"<'ui stackable grid'<'row'<'eight wide column'l><'right aligned eight wide column'f>><'row dt-table'<'sixteen wide column'tr>><'row'<'seven wide column'i><'right aligned nine wide column'p>>>",renderer:"semanticUI"}),v.extend(d.ext.classes,{sWrapper:"dataTables_wrapper dt-semanticUI",sFilter:"dataTables_filter ui input",sProcessing:"dataTables_processing ui segment",sPageButton:"paginate_button item"}),d.ext.renderer.pageButton.semanticUI=function(s,e,l,a,o,u){function c(e,a){for(var t,i=function(e){e.preventDefault(),v(e.currentTarget).hasClass("disabled")||b.page()==e.data.action||b.page(e.data.action).draw("page")},n=0,d=a.length;n",{class:g.sPageButton+" "+f,id:0===l&&"string"==typeof t?s.sTableId+"_"+t:null,href:r?null:"#","aria-controls":s.sTableId,"aria-disabled":r?"true":null,"aria-label":w[t],"aria-role":"link","aria-current":"active"===f?"page":null,"data-dt-idx":t,tabindex:s.iTabIndex}).html(p).appendTo(e),s.oApi._fnBindAction(r,{action:t},i))}}var p,f,t,b=new d.Api(s),g=s.oClasses,m=s.oLanguage.oPaginate,w=s.oLanguage.oAria.paginate||{};try{t=v(e).find(i.activeElement).data("dt-idx")}catch(e){}c(v(e).empty().html('').children(),a),t!==n&&v(e).find("[data-dt-idx="+t+"]").trigger("focus")},v(i).on("init.dt",function(e,a){"dt"===e.namespace&&(e=new v.fn.dataTable.Api(a),v.fn.dropdown&&v("div.dataTables_length select",e.table().container()).dropdown(),v("div.dataTables_filter.ui.input",e.table().container()).removeClass("input").addClass("form"),v("div.dataTables_filter input",e.table().container()).wrap(''))}),d});
\ No newline at end of file
diff --git a/public/datatables/DataTables-1.13.2/js/jquery.dataTables.js b/public/datatables/DataTables-1.13.2/js/jquery.dataTables.js
new file mode 100644
index 000000000..e4312c8fc
--- /dev/null
+++ b/public/datatables/DataTables-1.13.2/js/jquery.dataTables.js
@@ -0,0 +1,15629 @@
+/*! DataTables 1.13.2
+ * ©2008-2023 SpryMedia Ltd - datatables.net/license
+ */
+
+/**
+ * @summary DataTables
+ * @description Paginate, search and order HTML tables
+ * @version 1.13.2
+ * @author SpryMedia Ltd
+ * @contact www.datatables.net
+ * @copyright 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
+ window.DataTable = factory( jQuery, window, document );
+ }
+}
+(function( $, window, document, undefined ) {
+ "use strict";
+
+
+ var DataTable = function ( selector, options )
+ {
+ // 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;
+ }
+
+ /**
+ * 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:
+ *
+ * - 1D array of data - add a single row with the data provided
+ * - 2D array of arrays - add multiple rows in a single call
+ * - object - data object when using mData
+ * - array of objects - multiple data objects when using mData
+ *
+ * @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 = Array.isArray(data) && ( Array.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 = $('').insertAfter(thead);
+ }
+ 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 = /['\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 ) {
+ let 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 ( _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 );
+ }
+
+ var origClass = oCol.sClass;
+
+ $.extend( oCol, oOptions );
+ _fnMap( oCol, oOptions, "sWidth", "sWidthOrig" );
+
+ // Merge class from previously defined classes with this one, rather than just
+ // overwriting it in the extend above
+ if (origClass !== oCol.sClass) {
+ oCol.sClass = origClass + ' ' + oCol.sClass;
+ }
+
+ /* 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=0 ; i-- )
+ {
+ def = aoColDefs[i];
+
+ /* Each definition can target multiple columns, as it is an array */
+ var aTargets = def.target !== undefined
+ ? def.target
+ : def.targets !== undefined
+ ? def.targets
+ : def.aTargets;
+
+ if ( ! Array.isArray( aTargets ) )
+ {
+ aTargets = [ aTargets ];
+ }
+
+ for ( j=0, jLen=aTargets.length ; j= 0 )
+ {
+ /* Add columns that we don't yet know about */
+ while( columns.length <= aTargets[j] )
+ {
+ _fnAddColumn( oSettings );
+ }
+
+ /* Integer, basic index */
+ fn( aTargets[j], def );
+ }
+ else if ( typeof aTargets[j] === 'number' && aTargets[j] < 0 )
+ {
+ /* Negative integer, right to left column counting */
+ fn( columns.length+aTargets[j], def );
+ }
+ else if ( typeof aTargets[j] === 'string' )
+ {
+ /* Class name matching on TH element */
+ for ( k=0, kLen=columns.length ; k=0 if successful (index of new aoData entry), -1 if failed
+ * @memberof DataTable#oApi
+ */
+ function _fnAddData ( oSettings, aDataIn, nTr, anTds )
+ {
+ /* Create the object for storing information about this new row */
+ var iRow = oSettings.aoData.length;
+ var oData = $.extend( true, {}, DataTable.models.oRow, {
+ src: nTr ? 'dom' : 'data',
+ idx: iRow
+ } );
+
+ oData._aData = aDataIn;
+ oSettings.aoData.push( oData );
+
+ /* Create the cells */
+ var nTd, sThisType;
+ var columns = oSettings.aoColumns;
+
+ // Invalidate the column types as the new data needs to be revalidated
+ for ( var i=0, iLen=columns.length ; i iTarget )
+ {
+ a[i]--;
+ }
+ }
+
+ if ( iTargetIndex != -1 && splice === undefined )
+ {
+ a.splice( iTargetIndex, 1 );
+ }
+ }
+
+
+ /**
+ * Mark cached data as invalid such that a re-read of the data will occur when
+ * the cached data is next requested. Also update from the data source object.
+ *
+ * @param {object} settings DataTables settings object
+ * @param {int} rowIdx Row index to invalidate
+ * @param {string} [src] Source to invalidate from: undefined, 'auto', 'dom'
+ * or 'data'
+ * @param {int} [colIdx] Column index to invalidate. If undefined the whole
+ * row will be invalidated
+ * @memberof DataTable#oApi
+ *
+ * @todo For the modularisation of v1.11 this will need to become a callback, so
+ * the sort and filter methods can subscribe to it. That will required
+ * initialisation options for sorting, which is why it is not already baked in
+ */
+ function _fnInvalidate( settings, rowIdx, src, colIdx )
+ {
+ var row = settings.aoData[ rowIdx ];
+ var i, ien;
+ var cellWrite = function ( cell, col ) {
+ // This is very frustrating, but in IE if you just write directly
+ // to innerHTML, and elements that are overwritten are GC'ed,
+ // even if there is a reference to them elsewhere
+ while ( cell.childNodes.length ) {
+ cell.removeChild( cell.firstChild );
+ }
+
+ cell.innerHTML = _fnGetCellData( settings, rowIdx, col, 'display' );
+ };
+
+ // Are we reading last data from DOM or the data object?
+ if ( src === 'dom' || ((! src || src === 'auto') && row.src === 'dom') ) {
+ // Read the data from the DOM
+ row._aData = _fnGetRowElements(
+ settings, row, colIdx, colIdx === undefined ? undefined : row._aData
+ )
+ .data;
+ }
+ else {
+ // Reading from data object, update the DOM
+ var cells = row.anCells;
+
+ if ( cells ) {
+ if ( colIdx !== undefined ) {
+ cellWrite( cells[colIdx], colIdx );
+ }
+ else {
+ for ( i=0, ien=cells.length ; i').appendTo( thead );
+ }
+
+ for ( i=0, ien=columns.length ; i=0 ; j-- )
+ {
+ if ( !oSettings.aoColumns[j].bVisible && !bIncludeHidden )
+ {
+ aoLocal[i].splice( j, 1 );
+ }
+ }
+
+ /* Prep the applied array - it needs an element for each row */
+ aApplied.push( [] );
+ }
+
+ for ( i=0, iLen=aoLocal.length ; i', { 'class': iStripes ? asStripeClasses[0] : '' } )
+ .append( $(' | ', {
+ 'valign': 'top',
+ 'colSpan': _fnVisbleColumns( oSettings ),
+ 'class': oSettings.oClasses.sRowEmpty
+ } ).html( sZero ) )[0];
+ }
+
+ /* Header and footer callbacks */
+ _fnCallbackFire( oSettings, 'aoHeaderCallback', 'header', [ $(oSettings.nTHead).children('tr')[0],
+ _fnGetDataMaster( oSettings ), iDisplayStart, iDisplayEnd, aiDisplay ] );
+
+ _fnCallbackFire( oSettings, 'aoFooterCallback', 'footer', [ $(oSettings.nTFoot).children('tr')[0],
+ _fnGetDataMaster( oSettings ), iDisplayStart, iDisplayEnd, aiDisplay ] );
+
+ var body = $(oSettings.nTBody);
+
+ body.children().detach();
+ body.append( $(anRows) );
+
+ /* Call all required callback functions for the end of a draw */
+ _fnCallbackFire( oSettings, 'aoDrawCallback', 'draw', [oSettings] );
+
+ /* Draw is complete, sorting and filtering must be as well */
+ oSettings.bSorted = false;
+ oSettings.bFiltered = false;
+ oSettings.bDrawing = false;
+ }
+
+
+ /**
+ * Redraw the table - taking account of the various features which are enabled
+ * @param {object} oSettings dataTables settings object
+ * @param {boolean} [holdPosition] Keep the current paging position. By default
+ * the paging is reset to the first page
+ * @memberof DataTable#oApi
+ */
+ function _fnReDraw( settings, holdPosition )
+ {
+ var
+ features = settings.oFeatures,
+ sort = features.bSort,
+ filter = features.bFilter;
+
+ if ( sort ) {
+ _fnSort( settings );
+ }
+
+ if ( filter ) {
+ _fnFilterComplete( settings, settings.oPreviousSearch );
+ }
+ else {
+ // No filtering, so we want to just use the display master
+ settings.aiDisplay = settings.aiDisplayMaster.slice();
+ }
+
+ if ( holdPosition !== true ) {
+ settings._iDisplayStart = 0;
+ }
+
+ // Let any modules know about the draw hold position state (used by
+ // scrolling internally)
+ settings._drawHold = holdPosition;
+
+ _fnDraw( settings );
+
+ settings._drawHold = false;
+ }
+
+
+ /**
+ * Add the options to the page HTML for the table
+ * @param {object} oSettings dataTables settings object
+ * @memberof DataTable#oApi
+ */
+ function _fnAddOptionsHtml ( oSettings )
+ {
+ var classes = oSettings.oClasses;
+ var table = $(oSettings.nTable);
+ var holding = $('').insertBefore( table ); // Holding element for speed
+ var features = oSettings.oFeatures;
+
+ // All DataTables are wrapped in a div
+ var insert = $('', {
+ id: oSettings.sTableId+'_wrapper',
+ 'class': classes.sWrapper + (oSettings.nTFoot ? '' : ' '+classes.sNoFooter)
+ } );
+
+ oSettings.nHolding = holding[0];
+ oSettings.nTableWrapper = insert[0];
+ oSettings.nTableReinsertBefore = oSettings.nTable.nextSibling;
+
+ /* Loop over the user set positioning and place the elements as needed */
+ var aDom = oSettings.sDom.split('');
+ var featureNode, cOption, nNewNode, cNext, sAttr, j;
+ for ( var i=0 ; i')[0];
+
+ /* Check to see if we should append an id and/or a class name to the container */
+ cNext = aDom[i+1];
+ if ( cNext == "'" || cNext == '"' )
+ {
+ sAttr = "";
+ j = 2;
+ while ( aDom[i+j] != cNext )
+ {
+ sAttr += aDom[i+j];
+ j++;
+ }
+
+ /* Replace jQuery UI constants @todo depreciated */
+ if ( sAttr == "H" )
+ {
+ sAttr = classes.sJUIHeader;
+ }
+ else if ( sAttr == "F" )
+ {
+ sAttr = classes.sJUIFooter;
+ }
+
+ /* The attribute can be in the format of "#id.class", "#id" or "class" This logic
+ * breaks the string into parts and applies them as needed
+ */
+ if ( sAttr.indexOf('.') != -1 )
+ {
+ var aSplit = sAttr.split('.');
+ nNewNode.id = aSplit[0].substr(1, aSplit[0].length-1);
+ nNewNode.className = aSplit[1];
+ }
+ else if ( sAttr.charAt(0) == "#" )
+ {
+ nNewNode.id = sAttr.substr(1, sAttr.length-1);
+ }
+ else
+ {
+ nNewNode.className = sAttr;
+ }
+
+ i += j; /* Move along the position array */
+ }
+
+ insert.append( nNewNode );
+ insert = $(nNewNode);
+ }
+ else if ( cOption == '>' )
+ {
+ /* End container div */
+ insert = insert.parent();
+ }
+ // @todo Move options into their own plugins?
+ else if ( cOption == 'l' && features.bPaginate && features.bLengthChange )
+ {
+ /* Length */
+ featureNode = _fnFeatureHtmlLength( oSettings );
+ }
+ else if ( cOption == 'f' && features.bFilter )
+ {
+ /* Filter */
+ featureNode = _fnFeatureHtmlFilter( oSettings );
+ }
+ else if ( cOption == 'r' && features.bProcessing )
+ {
+ /* pRocessing */
+ featureNode = _fnFeatureHtmlProcessing( oSettings );
+ }
+ else if ( cOption == 't' )
+ {
+ /* Table */
+ featureNode = _fnFeatureHtmlTable( oSettings );
+ }
+ else if ( cOption == 'i' && features.bInfo )
+ {
+ /* Info */
+ featureNode = _fnFeatureHtmlInfo( oSettings );
+ }
+ else if ( cOption == 'p' && features.bPaginate )
+ {
+ /* Pagination */
+ featureNode = _fnFeatureHtmlPaginate( oSettings );
+ }
+ else if ( DataTable.ext.feature.length !== 0 )
+ {
+ /* Plug-in features */
+ var aoFeatures = DataTable.ext.feature;
+ for ( var k=0, kLen=aoFeatures.length ; k= oSettings.fnRecordsDisplay() ?
+ 0 :
+ iInitDisplayStart;
+
+ oSettings.iInitDisplayStart = -1;
+ }
+ }
+
+ /**
+ * Create an Ajax call based on the table's settings, taking into account that
+ * parameters can have multiple forms, and backwards compatibility.
+ *
+ * @param {object} oSettings dataTables settings object
+ * @param {array} data Data to send to the server, required by
+ * DataTables - may be augmented by developer callbacks
+ * @param {function} fn Callback function to run when data is obtained
+ */
+ function _fnBuildAjax( oSettings, data, fn )
+ {
+ // Compatibility with 1.9-, allow fnServerData and event to manipulate
+ _fnCallbackFire( oSettings, 'aoServerParams', 'serverParams', [data] );
+
+ // Convert to object based for 1.10+ if using the old array scheme which can
+ // come from server-side processing or serverParams
+ if ( data && Array.isArray(data) ) {
+ var tmp = {};
+ var rbracket = /(.*?)\[\]$/;
+
+ $.each( data, function (key, val) {
+ var match = val.name.match(rbracket);
+
+ if ( match ) {
+ // Support for arrays
+ var name = match[0];
+
+ if ( ! tmp[ name ] ) {
+ tmp[ name ] = [];
+ }
+ tmp[ name ].push( val.value );
+ }
+ else {
+ tmp[val.name] = val.value;
+ }
+ } );
+ data = tmp;
+ }
+
+ var ajaxData;
+ var ajax = oSettings.ajax;
+ var instance = oSettings.oInstance;
+ var callback = function ( json ) {
+ var status = oSettings.jqXHR
+ ? oSettings.jqXHR.status
+ : null;
+
+ if ( json === null || (typeof status === 'number' && status == 204 ) ) {
+ json = {};
+ _fnAjaxDataSrc( oSettings, json, [] );
+ }
+
+ var error = json.error || json.sError;
+ if ( error ) {
+ _fnLog( oSettings, 0, error );
+ }
+
+ oSettings.json = json;
+
+ _fnCallbackFire( oSettings, null, 'xhr', [oSettings, json, oSettings.jqXHR] );
+ fn( json );
+ };
+
+ if ( $.isPlainObject( ajax ) && ajax.data )
+ {
+ ajaxData = ajax.data;
+
+ var newData = typeof ajaxData === 'function' ?
+ ajaxData( data, oSettings ) : // fn can manipulate data or return
+ ajaxData; // an object object or array to merge
+
+ // If the function returned something, use that alone
+ data = typeof ajaxData === 'function' && newData ?
+ newData :
+ $.extend( true, data, newData );
+
+ // Remove the data property as we've resolved it already and don't want
+ // jQuery to do it again (it is restored at the end of the function)
+ delete ajax.data;
+ }
+
+ var baseAjax = {
+ "data": data,
+ "success": callback,
+ "dataType": "json",
+ "cache": false,
+ "type": oSettings.sServerMethod,
+ "error": function (xhr, error, thrown) {
+ var ret = _fnCallbackFire( oSettings, null, 'xhr', [oSettings, null, oSettings.jqXHR] );
+
+ if ( $.inArray( true, ret ) === -1 ) {
+ if ( error == "parsererror" ) {
+ _fnLog( oSettings, 0, 'Invalid JSON response', 1 );
+ }
+ else if ( xhr.readyState === 4 ) {
+ _fnLog( oSettings, 0, 'Ajax error', 7 );
+ }
+ }
+
+ _fnProcessingDisplay( oSettings, false );
+ }
+ };
+
+ // Store the data submitted for the API
+ oSettings.oAjaxData = data;
+
+ // Allow plug-ins and external processes to modify the data
+ _fnCallbackFire( oSettings, null, 'preXhr', [oSettings, data] );
+
+ if ( oSettings.fnServerData )
+ {
+ // DataTables 1.9- compatibility
+ oSettings.fnServerData.call( instance,
+ oSettings.sAjaxSource,
+ $.map( data, function (val, key) { // Need to convert back to 1.9 trad format
+ return { name: key, value: val };
+ } ),
+ callback,
+ oSettings
+ );
+ }
+ else if ( oSettings.sAjaxSource || typeof ajax === 'string' )
+ {
+ // DataTables 1.9- compatibility
+ oSettings.jqXHR = $.ajax( $.extend( baseAjax, {
+ url: ajax || oSettings.sAjaxSource
+ } ) );
+ }
+ else if ( typeof ajax === 'function' )
+ {
+ // Is a function - let the caller define what needs to be done
+ oSettings.jqXHR = ajax.call( instance, data, callback, oSettings );
+ }
+ else
+ {
+ // Object to extend the base settings
+ oSettings.jqXHR = $.ajax( $.extend( baseAjax, ajax ) );
+
+ // Restore for next time around
+ ajax.data = ajaxData;
+ }
+ }
+
+
+ /**
+ * Update the table using an Ajax call
+ * @param {object} settings dataTables settings object
+ * @returns {boolean} Block the table drawing or not
+ * @memberof DataTable#oApi
+ */
+ function _fnAjaxUpdate( settings )
+ {
+ settings.iDraw++;
+ _fnProcessingDisplay( settings, true );
+
+ _fnBuildAjax(
+ settings,
+ _fnAjaxParameters( settings ),
+ function(json) {
+ _fnAjaxUpdateDraw( settings, json );
+ }
+ );
+ }
+
+
+ /**
+ * Build up the parameters in an object needed for a server-side processing
+ * request. Note that this is basically done twice, is different ways - a modern
+ * method which is used by default in DataTables 1.10 which uses objects and
+ * arrays, or the 1.9- method with is name / value pairs. 1.9 method is used if
+ * the sAjaxSource option is used in the initialisation, or the legacyAjax
+ * option is set.
+ * @param {object} oSettings dataTables settings object
+ * @returns {bool} block the table drawing or not
+ * @memberof DataTable#oApi
+ */
+ function _fnAjaxParameters( settings )
+ {
+ var
+ columns = settings.aoColumns,
+ columnCount = columns.length,
+ features = settings.oFeatures,
+ preSearch = settings.oPreviousSearch,
+ preColSearch = settings.aoPreSearchCols,
+ i, data = [], dataProp, column, columnSearch,
+ sort = _fnSortFlatten( settings ),
+ displayStart = settings._iDisplayStart,
+ displayLength = features.bPaginate !== false ?
+ settings._iDisplayLength :
+ -1;
+
+ var param = function ( name, value ) {
+ data.push( { 'name': name, 'value': value } );
+ };
+
+ // DataTables 1.9- compatible method
+ param( 'sEcho', settings.iDraw );
+ param( 'iColumns', columnCount );
+ param( 'sColumns', _pluck( columns, 'sName' ).join(',') );
+ param( 'iDisplayStart', displayStart );
+ param( 'iDisplayLength', displayLength );
+
+ // DataTables 1.10+ method
+ var d = {
+ draw: settings.iDraw,
+ columns: [],
+ order: [],
+ start: displayStart,
+ length: displayLength,
+ search: {
+ value: preSearch.sSearch,
+ regex: preSearch.bRegex
+ }
+ };
+
+ for ( i=0 ; i';
+
+ var str = language.sSearch;
+ str = str.match(/_INPUT_/) ?
+ str.replace('_INPUT_', input) :
+ str+input;
+
+ var filter = $('', {
+ 'id': ! features.f ? tableId+'_filter' : null,
+ 'class': classes.sFilter
+ } )
+ .append( $('' ).append( str ) );
+
+ var searchFn = function(event) {
+ /* Update all other filter input elements for the new display */
+ var n = features.f;
+ var val = !this.value ? "" : this.value; // mental IE8 fix :-(
+ if(previousSearch.return && event.key !== "Enter") {
+ return;
+ }
+ /* Now do the filter */
+ if ( val != previousSearch.sSearch ) {
+ _fnFilterComplete( settings, {
+ "sSearch": val,
+ "bRegex": previousSearch.bRegex,
+ "bSmart": previousSearch.bSmart ,
+ "bCaseInsensitive": previousSearch.bCaseInsensitive,
+ "return": previousSearch.return
+ } );
+
+ // Need to redraw, without resorting
+ settings._iDisplayStart = 0;
+ _fnDraw( settings );
+ }
+ };
+
+ var searchDelay = settings.searchDelay !== null ?
+ settings.searchDelay :
+ _fnDataSource( settings ) === 'ssp' ?
+ 400 :
+ 0;
+
+ var jqFilter = $('input', filter)
+ .val( previousSearch.sSearch )
+ .attr( 'placeholder', language.sSearchPlaceholder )
+ .on(
+ 'keyup.DT search.DT input.DT paste.DT cut.DT',
+ searchDelay ?
+ _fnThrottle( searchFn, searchDelay ) :
+ searchFn
+ )
+ .on( 'mouseup', function(e) {
+ // Edge fix! Edge 17 does not trigger anything other than mouse events when clicking
+ // on the clear icon (Edge bug 17584515). This is safe in other browsers as `searchFn`
+ // checks the value to see if it has changed. In other browsers it won't have.
+ setTimeout( function () {
+ searchFn.call(jqFilter[0], e);
+ }, 10);
+ } )
+ .on( 'keypress.DT', function(e) {
+ /* Prevent form submission */
+ if ( e.keyCode == 13 ) {
+ return false;
+ }
+ } )
+ .attr('aria-controls', tableId);
+
+ // Update the input elements whenever the table is filtered
+ $(settings.nTable).on( 'search.dt.DT', function ( ev, s ) {
+ if ( settings === s ) {
+ // IE9 throws an 'unknown error' if document.activeElement is used
+ // inside an iframe or frame...
+ try {
+ if ( jqFilter[0] !== document.activeElement ) {
+ jqFilter.val( previousSearch.sSearch );
+ }
+ }
+ catch ( e ) {}
+ }
+ } );
+
+ return filter[0];
+ }
+
+
+ /**
+ * Filter the table using both the global filter and column based filtering
+ * @param {object} oSettings dataTables settings object
+ * @param {object} oSearch search information
+ * @param {int} [iForce] force a research of the master array (1) or not (undefined or 0)
+ * @memberof DataTable#oApi
+ */
+ function _fnFilterComplete ( oSettings, oInput, iForce )
+ {
+ var oPrevSearch = oSettings.oPreviousSearch;
+ var aoPrevSearch = oSettings.aoPreSearchCols;
+ var fnSaveFilter = function ( oFilter ) {
+ /* Save the filtering values */
+ oPrevSearch.sSearch = oFilter.sSearch;
+ oPrevSearch.bRegex = oFilter.bRegex;
+ oPrevSearch.bSmart = oFilter.bSmart;
+ oPrevSearch.bCaseInsensitive = oFilter.bCaseInsensitive;
+ oPrevSearch.return = oFilter.return;
+ };
+ var fnRegex = function ( o ) {
+ // Backwards compatibility with the bEscapeRegex option
+ return o.bEscapeRegex !== undefined ? !o.bEscapeRegex : o.bRegex;
+ };
+
+ // Resolve any column types that are unknown due to addition or invalidation
+ // @todo As per sort - can this be moved into an event handler?
+ _fnColumnTypes( oSettings );
+
+ /* In server-side processing all filtering is done by the server, so no point hanging around here */
+ if ( _fnDataSource( oSettings ) != 'ssp' )
+ {
+ /* Global filter */
+ _fnFilter( oSettings, oInput.sSearch, iForce, fnRegex(oInput), oInput.bSmart, oInput.bCaseInsensitive, oInput.return );
+ fnSaveFilter( oInput );
+
+ /* Now do the individual column filter */
+ for ( var i=0 ; i input.length ||
+ input.indexOf(prevSearch) !== 0 ||
+ settings.bSorted // On resort, the display master needs to be
+ // re-filtered since indexes will have changed
+ ) {
+ settings.aiDisplay = displayMaster.slice();
+ }
+
+ // Search the display array
+ display = settings.aiDisplay;
+
+ for ( i=0 ; i')[0];
+ var __filter_div_textContent = __filter_div.textContent !== undefined;
+
+ // Update the filtering data for each row if needed (by invalidation or first run)
+ function _fnFilterData ( settings )
+ {
+ var columns = settings.aoColumns;
+ var column;
+ var i, j, ien, jen, filterData, cellData, row;
+ var wasInvalidated = false;
+
+ for ( i=0, ien=settings.aoData.length ; i', {
+ 'class': settings.oClasses.sInfo,
+ 'id': ! nodes ? tid+'_info' : null
+ } );
+
+ if ( ! nodes ) {
+ // Update display on each draw
+ settings.aoDrawCallback.push( {
+ "fn": _fnUpdateInfo,
+ "sName": "information"
+ } );
+
+ n
+ .attr( 'role', 'status' )
+ .attr( 'aria-live', 'polite' );
+
+ // Table is described by our info div
+ $(settings.nTable).attr( 'aria-describedby', tid+'_info' );
+ }
+
+ return n[0];
+ }
+
+
+ /**
+ * Update the information elements in the display
+ * @param {object} settings dataTables settings object
+ * @memberof DataTable#oApi
+ */
+ function _fnUpdateInfo ( settings )
+ {
+ /* Show information about the table */
+ var nodes = settings.aanFeatures.i;
+ if ( nodes.length === 0 ) {
+ return;
+ }
+
+ var
+ lang = settings.oLanguage,
+ start = settings._iDisplayStart+1,
+ end = settings.fnDisplayEnd(),
+ max = settings.fnRecordsTotal(),
+ total = settings.fnRecordsDisplay(),
+ out = total ?
+ lang.sInfo :
+ lang.sInfoEmpty;
+
+ if ( total !== max ) {
+ /* Record set after filtering */
+ out += ' ' + lang.sInfoFiltered;
+ }
+
+ // Convert the macros
+ out += lang.sInfoPostFix;
+ out = _fnInfoMacros( settings, out );
+
+ var callback = lang.fnInfoCallback;
+ if ( callback !== null ) {
+ out = callback.call( settings.oInstance,
+ settings, start, end, max, total, out
+ );
+ }
+
+ $(nodes).html( out );
+ }
+
+
+ function _fnInfoMacros ( settings, str )
+ {
+ // When infinite scrolling, we are always starting at 1. _iDisplayStart is used only
+ // internally
+ var
+ formatter = settings.fnFormatNumber,
+ start = settings._iDisplayStart+1,
+ len = settings._iDisplayLength,
+ vis = settings.fnRecordsDisplay(),
+ all = len === -1;
+
+ return str.
+ replace(/_START_/g, formatter.call( settings, start ) ).
+ replace(/_END_/g, formatter.call( settings, settings.fnDisplayEnd() ) ).
+ replace(/_MAX_/g, formatter.call( settings, settings.fnRecordsTotal() ) ).
+ replace(/_TOTAL_/g, formatter.call( settings, vis ) ).
+ replace(/_PAGE_/g, formatter.call( settings, all ? 1 : Math.ceil( start / len ) ) ).
+ replace(/_PAGES_/g, formatter.call( settings, all ? 1 : Math.ceil( vis / len ) ) );
+ }
+
+
+
+ /**
+ * Draw the table for the first time, adding all required features
+ * @param {object} settings dataTables settings object
+ * @memberof DataTable#oApi
+ */
+ function _fnInitialise ( settings )
+ {
+ var i, iLen, iAjaxStart=settings.iInitDisplayStart;
+ var columns = settings.aoColumns, column;
+ var features = settings.oFeatures;
+ var deferLoading = settings.bDeferLoading; // value modified by the draw
+
+ /* Ensure that the table data is fully initialised */
+ if ( ! settings.bInitialised ) {
+ setTimeout( function(){ _fnInitialise( settings ); }, 200 );
+ return;
+ }
+
+ /* Show the display HTML options */
+ _fnAddOptionsHtml( settings );
+
+ /* Build and draw the header / footer for the table */
+ _fnBuildHead( settings );
+ _fnDrawHead( settings, settings.aoHeader );
+ _fnDrawHead( settings, settings.aoFooter );
+
+ /* Okay to show that something is going on now */
+ _fnProcessingDisplay( settings, true );
+
+ /* Calculate sizes for columns */
+ if ( features.bAutoWidth ) {
+ _fnCalculateColumnWidths( settings );
+ }
+
+ for ( i=0, iLen=columns.length ; i', {
+ 'name': tableId+'_length',
+ 'aria-controls': tableId,
+ 'class': classes.sLengthSelect
+ } );
+
+ for ( var i=0, ien=lengths.length ; i ').addClass( classes.sLength );
+ if ( ! settings.aanFeatures.l ) {
+ div[0].id = tableId+'_length';
+ }
+
+ div.children().append(
+ settings.oLanguage.sLengthMenu.replace( '_MENU_', select[0].outerHTML )
+ );
+
+ // Can't use `select` variable as user might provide their own and the
+ // reference is broken by the use of outerHTML
+ $('select', div)
+ .val( settings._iDisplayLength )
+ .on( 'change.DT', function(e) {
+ _fnLengthChange( settings, $(this).val() );
+ _fnDraw( settings );
+ } );
+
+ // Update node value whenever anything changes the table's length
+ $(settings.nTable).on( 'length.dt.DT', function (e, s, len) {
+ if ( settings === s ) {
+ $('select', div).val( len );
+ }
+ } );
+
+ return div[0];
+ }
+
+
+
+ /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
+ * Note that most of the paging logic is done in
+ * DataTable.ext.pager
+ */
+
+ /**
+ * Generate the node required for default pagination
+ * @param {object} oSettings dataTables settings object
+ * @returns {node} Pagination feature node
+ * @memberof DataTable#oApi
+ */
+ function _fnFeatureHtmlPaginate ( settings )
+ {
+ var
+ type = settings.sPaginationType,
+ plugin = DataTable.ext.pager[ type ],
+ modern = typeof plugin === 'function',
+ redraw = function( settings ) {
+ _fnDraw( settings );
+ },
+ node = $('