datatables.net 3.0.0-beta.2 → 3.0.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/js/dataTables.js CHANGED
@@ -1,4 +1,4 @@
1
- /*! DataTables 3.0.0-beta.2
1
+ /*! DataTables 3.0.1
2
2
  * Copyright (c) SpryMedia Ltd - datatables.net/license
3
3
  */
4
4
 
@@ -152,7 +152,7 @@ let _stripHtml = function (input, replacement = '') {
152
152
  * This function is replaceable if the user wishes to use a different library
153
153
  * for escaping HTML entities in a string.
154
154
  *
155
- * @param d Value to escape HTML in
155
+ * @param val Value to escape HTML in
156
156
  * @returns Escaped value
157
157
  */
158
158
  let _escapeHtml = function (val) {
@@ -551,7 +551,10 @@ function ajax(optionsIn) {
551
551
  options.contentType = 'application/json; charset=utf-8';
552
552
  }
553
553
  }
554
- xhr.open(method, options.url + (options.url.includes('?') ? '&' : '?') + urlParams, true, options.username || null, options.password || null);
554
+ xhr.open(method, options.url +
555
+ (urlParams
556
+ ? (options.url.includes('?') ? '&' : '?') + urlParams
557
+ : ''), true, options.username || null, options.password || null);
555
558
  // Content type for FormData requests gets set by the browser.
556
559
  if (options.contentType && !(options.data instanceof FormData)) {
557
560
  xhr.setRequestHeader('Content-Type', options.contentType);
@@ -569,11 +572,16 @@ function ajax(optionsIn) {
569
572
  if (options.data instanceof FormData) {
570
573
  sendData = options.data;
571
574
  }
572
- else if (method !== 'GET' && options.data && typeof options.data !== 'string') {
573
- sendData = serialize(options.data, options.traditional);
574
- sendData = convertSpaces(sendData, options);
575
- // So beforeSend matches how jQuery behaves
576
- options.data = sendData;
575
+ else if (method !== 'GET' && options.data) {
576
+ if (typeof options.data === 'string') {
577
+ sendData = options.data;
578
+ }
579
+ else {
580
+ sendData = serialize(options.data, options.traditional);
581
+ sendData = convertSpaces(sendData, options);
582
+ // So beforeSend matches how jQuery behaves
583
+ options.data = sendData;
584
+ }
577
585
  }
578
586
  xhr.onreadystatechange = function () {
579
587
  if (xhr.readyState != 4) {
@@ -623,6 +631,7 @@ function ajax(optionsIn) {
623
631
  if (options.beforeSend) {
624
632
  if (options.beforeSend.call(options, xhr, options) === false) {
625
633
  xhr.abort();
634
+ return xhr;
626
635
  }
627
636
  }
628
637
  xhr.send(sendData);
@@ -635,7 +644,9 @@ ajax.serialize = serialize;
635
644
  * Run callback functions (allowing for none, one or array)
636
645
  *
637
646
  * @param fnIn Function(s) to run
638
- * @param parameters Parameters to pass to the function(s)
647
+ * @param arg1 Parameters to pass to the function(s)
648
+ * @param arg2 Parameters to pass to the function(s)
649
+ * @param arg3 Parameters to pass to the function(s)
639
650
  */
640
651
  function callback(fnIn, arg1, arg2, arg3) {
641
652
  if (!fnIn) {
@@ -809,7 +820,7 @@ function allUnique(src) {
809
820
  * @returns Flattened array
810
821
  */
811
822
  function flatten(out, val) {
812
- if (Array.isArray(val)) {
823
+ if (Array.isArray(val) || arrayLike(val)) {
813
824
  for (var i = 0; i < val.length; i++) {
814
825
  flatten(out, val[i]);
815
826
  }
@@ -855,6 +866,7 @@ function pluck(a, prop, prop2) {
855
866
  * as the indexes to pick from the source array
856
867
  *
857
868
  * @param a Array to get values from
869
+ * @param order Indexes to pick
858
870
  * @param prop Property to read values from
859
871
  * @param prop2 Inner property to get values from if a 2D array
860
872
  * @returns Array of read values
@@ -1352,7 +1364,7 @@ var timer = /*#__PURE__*/Object.freeze({
1352
1364
  * @returns true if this version of DataTables is greater or equal to the
1353
1365
  * required version, or false if this version of DataTales is not suitable
1354
1366
  */
1355
- function check(version1, version2) {
1367
+ function check$1(version1, version2) {
1356
1368
  let dt = external('datatable');
1357
1369
  var parts1 = version2 ? version2.split('.') : dt.ext.version.split('.');
1358
1370
  var parts2 = version1.split('.');
@@ -1372,7 +1384,7 @@ function check(version1, version2) {
1372
1384
 
1373
1385
  var version = /*#__PURE__*/Object.freeze({
1374
1386
  __proto__: null,
1375
- check: check
1387
+ check: check$1
1376
1388
  });
1377
1389
 
1378
1390
  // Note that the aliased properties are for compatibility with DataTables 2-
@@ -1590,9 +1602,12 @@ function parseEventName(original) {
1590
1602
  isFocus = true;
1591
1603
  }
1592
1604
  else if (name === 'blur') {
1593
- name = 'blurout';
1605
+ name = 'focusout';
1594
1606
  isFocus = true;
1595
1607
  }
1608
+ else if (name === 'ready') {
1609
+ name = 'DOMContentLoaded';
1610
+ }
1596
1611
  return {
1597
1612
  eventName: name,
1598
1613
  isFocus,
@@ -1629,6 +1644,14 @@ function add(el, nameFull, handler, selector, one) {
1629
1644
  if (!eventName) {
1630
1645
  return;
1631
1646
  }
1647
+ // Special handling for the "ready" event - it will trigger when the content
1648
+ // is ready, but also if it is already ready, when added.
1649
+ if (el === document && eventName === 'DOMContentLoaded' && nameFull.includes('ready')) {
1650
+ if (document.readyState === 'complete') {
1651
+ handler(new Event('DOMContentLoaded'));
1652
+ return;
1653
+ }
1654
+ }
1632
1655
  // Create a function that will be the actual event handler, and performs any
1633
1656
  // logic we need, such as delegate handling and adding properties.
1634
1657
  let wrapped = function (event) {
@@ -1654,6 +1677,11 @@ function add(el, nameFull, handler, selector, one) {
1654
1677
  if (!dTarget) {
1655
1678
  return;
1656
1679
  }
1680
+ if (isHover &&
1681
+ event.relatedTarget &&
1682
+ dTarget.contains(event.relatedTarget)) {
1683
+ return;
1684
+ }
1657
1685
  callScope = dTarget;
1658
1686
  }
1659
1687
  // Set the properties that jQuery adds to the event object
@@ -1711,7 +1739,7 @@ function remove(el, nameFull, handler, selector) {
1711
1739
  wrapped.delegateSelector === selector &&
1712
1740
  wrapped.original === handler);
1713
1741
  }
1714
- if (eventName && selector) {
1742
+ else if (eventName && selector) {
1715
1743
  removeEvents = stored.filter(wrapped => wrapped.type === eventName &&
1716
1744
  wrapped.delegateSelector === selector);
1717
1745
  }
@@ -1897,7 +1925,7 @@ class Dom {
1897
1925
  /**
1898
1926
  * Add an element (or multiple) to the instance. Will ensure uniqueness.
1899
1927
  *
1900
- * @param el Element(s) to add
1928
+ * @param selector Element(s) to add
1901
1929
  * @param sort Indicate if the element should be added in document order.
1902
1930
  * @returns Self for chaining
1903
1931
  */
@@ -1942,29 +1970,33 @@ class Dom {
1942
1970
  if (!content) {
1943
1971
  return this;
1944
1972
  }
1945
- if (Array.isArray(content)) {
1946
- content.forEach(c => this.append(c));
1947
- return this;
1973
+ if (!arrayLike(content)) {
1974
+ content = [content];
1948
1975
  }
1949
- return this.each(el => {
1950
- if (content instanceof Dom) {
1951
- content.each(item => {
1952
- el.append(item);
1953
- });
1954
- }
1955
- else if (typeof content === 'string') {
1956
- el.insertAdjacentHTML('beforeend', content);
1957
- }
1958
- else if (arrayLike(content)) {
1959
- // Allow for a jQuery object being passed
1960
- let arrayLike = content;
1961
- for (let i = 0; i < arrayLike.length; i++) {
1962
- el.append(arrayLike[i]);
1976
+ // Generate a flat array of the content to be added, with nulls removed
1977
+ // this means it will be an array of nodes and / or strings
1978
+ let flatContent = flatten([], content).filter(c => !!c);
1979
+ /// Got a string somewhere in it, so need to use insertAdjacentHTML
1980
+ if (flatContent.find(val => typeof val === 'string')) {
1981
+ return this.each(el => {
1982
+ for (let i = 0; i < flatContent.length; i++) {
1983
+ if (typeof flatContent[i] === 'string') {
1984
+ el.insertAdjacentHTML('beforeend', flatContent[i]);
1985
+ }
1986
+ else {
1987
+ el.append(flatContent[i]);
1988
+ }
1963
1989
  }
1990
+ });
1991
+ }
1992
+ // Otherwise we can use a document fragment for a single mutation
1993
+ // on the main document
1994
+ return this.each(el => {
1995
+ let fragment = new DocumentFragment();
1996
+ for (let i = 0; i < flatContent.length; i++) {
1997
+ fragment.append(flatContent[i]);
1964
1998
  }
1965
- else {
1966
- el.append(content);
1967
- }
1999
+ el.append(fragment);
1968
2000
  });
1969
2001
  }
1970
2002
  /**
@@ -2131,9 +2163,7 @@ class Dom {
2131
2163
  css(rule, value) {
2132
2164
  // String getter
2133
2165
  if (typeof rule === 'string' && value === undefined) {
2134
- return this.length
2135
- ? getComputedStyle(this[0])[rule]
2136
- : null;
2166
+ return this.length ? getComputedStyle(this[0])[rule] : null;
2137
2167
  }
2138
2168
  return this.each(el => {
2139
2169
  if (typeof rule === 'string') {
@@ -2161,11 +2191,11 @@ class Dom {
2161
2191
  return this.length ? dataConvert(this[0].dataset[name]) : null;
2162
2192
  }
2163
2193
  if (typeof name === 'string') {
2164
- this.each(el => el.dataset[name] = JSON.stringify(value));
2194
+ this.each(el => (el.dataset[name] = JSON.stringify(value)));
2165
2195
  }
2166
2196
  else {
2167
2197
  each(name, (key, val) => {
2168
- this.each(el => el.dataset[key] = JSON.stringify(val));
2198
+ this.each(el => (el.dataset[key] = JSON.stringify(val)));
2169
2199
  });
2170
2200
  }
2171
2201
  return this;
@@ -2296,7 +2326,7 @@ class Dom {
2296
2326
  /**
2297
2327
  * Get all matching descendants
2298
2328
  *
2299
- * @param selector Elements to find
2329
+ * @param input Elements to find
2300
2330
  * @returns A new Dom instance with all matching elements
2301
2331
  */
2302
2332
  find(input) {
@@ -3025,6 +3055,7 @@ const legacy = [];
3025
3055
  * @param name The name of the new feature.
3026
3056
  * @param cb A function that will create the elements and event listeners for
3027
3057
  * the feature being added.
3058
+ * @param legacyChar
3028
3059
  */
3029
3060
  function register$2(name, cb, legacyChar = '') {
3030
3061
  features[name] = cb;
@@ -3889,7 +3920,7 @@ const ext = {
3889
3920
  * Software version
3890
3921
  * @type string
3891
3922
  */
3892
- version: '3.0.0-beta.2'
3923
+ version: '3.0.1'
3893
3924
  };
3894
3925
  //
3895
3926
  // Backwards compatibility. Alias to pre 1.10 Hungarian notation counter parts
@@ -3904,7 +3935,7 @@ Object.assign(ext, {
3904
3935
  oStdClasses: ext.classes,
3905
3936
  oPagination: ext.pager,
3906
3937
  sVersion: ext.version,
3907
- fnVersionCheck: check
3938
+ fnVersionCheck: check$1
3908
3939
  });
3909
3940
 
3910
3941
  /**
@@ -4133,7 +4164,7 @@ function arrayApply(arr, data) {
4133
4164
  function listener(that, name, src) {
4134
4165
  let srcArr = Array.isArray(src) ? src : [src];
4135
4166
  for (var i = 0; i < srcArr.length; i++) {
4136
- that.on(name + '.dt', srcArr[i]);
4167
+ that.on(name + '.dt.DT', srcArr[i]);
4137
4168
  }
4138
4169
  }
4139
4170
  /**
@@ -4248,10 +4279,12 @@ function __mlHelper(localeString) {
4248
4279
  // gives milliseconds epoch
4249
4280
  return d.valueOf();
4250
4281
  }
4251
- },
4252
- className: 'dt-right'
4282
+ }
4253
4283
  });
4254
4284
  }
4285
+ if (!store.className[typeName]) {
4286
+ store.className[typeName] = 'dt-right';
4287
+ }
4255
4288
  return function (d, type) {
4256
4289
  // Allow for a default value
4257
4290
  if (d === null || d === undefined) {
@@ -4352,10 +4385,12 @@ function datetime(format, locale) {
4352
4385
  pre: function (d) {
4353
4386
  return __mldObj(d, format, locale) || 0;
4354
4387
  }
4355
- },
4356
- className: 'dt-right'
4388
+ }
4357
4389
  });
4358
4390
  }
4391
+ if (!store.className[typeName]) {
4392
+ store.className[typeName] = 'dt-right';
4393
+ }
4359
4394
  }
4360
4395
  /**
4361
4396
  * Helpers for `columns.render`.
@@ -4790,7 +4825,7 @@ function create$1(parts = {}) {
4790
4825
  * DOM source.
4791
4826
  *
4792
4827
  * @param settings DataTables settings object
4793
- * @param data data array to be added
4828
+ * @param dataIn data array to be added
4794
4829
  * @param tr TR element to add to the table - optional. If not given, DataTables
4795
4830
  * will create a row automatically
4796
4831
  * @param tds Array of TD|TH elements for the row - must be given if tr is.
@@ -4829,7 +4864,7 @@ function addData(settings, dataIn, tr, tds) {
4829
4864
  * it is not cloned).
4830
4865
  *
4831
4866
  * @param settings DataTables settings object
4832
- * @param trs The TR element(s) to add to the table
4867
+ * @param rows The TR element(s) to add to the table
4833
4868
  * @returns Array of indexes for the added rows
4834
4869
  */
4835
4870
  function addTr(settings, rows) {
@@ -5024,6 +5059,7 @@ function invalidate(settings, rowIdx, src, colIdx) {
5024
5059
  // Update DataTables special `DT_*` attributes for the row
5025
5060
  rowAttributes(settings, row);
5026
5061
  }
5062
+ callbackFire(settings, null, 'rowInvalidate', [settings, rowIdx, colIdx], false);
5027
5063
  }
5028
5064
  /**
5029
5065
  * Get the cells and data for a given row - from a <tr> element
@@ -5369,9 +5405,9 @@ function getWideStrings(settings, colIdx) {
5369
5405
  // Don't want script, dialog or template tags in the width
5370
5406
  // calculations as they are hidden content
5371
5407
  cellString = cellString
5372
- .replace(/<script[\s\S]*?<\/script>/gi, ' ')
5373
- .replace(/<dialog[\s\S]*?<\/dialog>/gi, ' ')
5374
- .replace(/<template[\s\S]*?<\/template>/gi, ' ');
5408
+ .replace(/<script[\s\S]*?<\/script(?:\s[^>]*)?>/gi, ' ')
5409
+ .replace(/<dialog[\s\S]*?<\/dialog(?:\s[^>]*)?>/gi, ' ')
5410
+ .replace(/<template[\s\S]*?<\/template(?:\s[^>]*)?>/gi, ' ');
5375
5411
  var noHtml = util.string
5376
5412
  .stripHtml(cellString, ' ')
5377
5413
  .replace(/&nbsp;/g, ' ');
@@ -5410,7 +5446,7 @@ function getWideStrings(settings, colIdx) {
5410
5446
  /**
5411
5447
  * Append a CSS unit (only if required) to a string
5412
5448
  *
5413
- * @param value to css-ify
5449
+ * @param s Value to css-ify
5414
5450
  * @returns Value with css unit
5415
5451
  */
5416
5452
  function stringToCss(s) {
@@ -5972,6 +6008,7 @@ function columnTypes(settings) {
5972
6008
  var types = ext.type.detect;
5973
6009
  var i, iLen, j, jen, k, ken;
5974
6010
  var col, detectedType, cache;
6011
+ var originalTypes = columns.map(c => c.type).join(',');
5975
6012
  // For each column, spin over the data type detection functions, seeing if
5976
6013
  // one matches
5977
6014
  for (i = 0, iLen = columns.length; i < iLen; i++) {
@@ -6069,6 +6106,10 @@ function columnTypes(settings) {
6069
6106
  _columnAutoRender(settings, i);
6070
6107
  }
6071
6108
  }
6109
+ var newTypes = columns.map(c => c.type).join(',');
6110
+ if (newTypes !== originalTypes) {
6111
+ callbackFire(settings, null, 'columnTypes', [settings], false);
6112
+ }
6072
6113
  }
6073
6114
  /**
6074
6115
  * Apply an auto detected renderer to data which doesn't yet have a renderer
@@ -6339,7 +6380,7 @@ function renderer(ctx, type) {
6339
6380
  /**
6340
6381
  * Add the options to the page HTML for the table
6341
6382
  *
6342
- * @param settings DataTables settings object
6383
+ * @param ctx DataTables context
6343
6384
  */
6344
6385
  function createLayout(ctx) {
6345
6386
  var classes = ctx.classes;
@@ -6716,6 +6757,7 @@ function sortAttachListener(settings, node, selector, column, callback) {
6716
6757
  * Sort the display array to match the master's order
6717
6758
  *
6718
6759
  * @param settings DataTables context
6760
+ * @param display The display array
6719
6761
  */
6720
6762
  function sortDisplay(settings, display) {
6721
6763
  if (display.length < 2) {
@@ -6943,7 +6985,6 @@ function sort(ctx, col, dir) {
6943
6985
  * Function to run on user sort request
6944
6986
  *
6945
6987
  * @param settings dataTables settings object
6946
- * @param attachTo node to attach the handler to
6947
6988
  * @param colIdx column sorting index
6948
6989
  * @param addIndex Counter
6949
6990
  * @param shift Shift click add
@@ -7270,13 +7311,13 @@ function implementState(settings, s, callback) {
7270
7311
  let idx = currentNames.indexOf(col[0]);
7271
7312
  if (idx < 0) {
7272
7313
  // If the column was not found ignore it and continue
7273
- return;
7314
+ continue;
7274
7315
  }
7275
7316
  set[0] = idx;
7276
7317
  }
7277
7318
  else if (set[0] >= columns.length) {
7278
7319
  // If the column index is out of bounds ignore it and continue
7279
- return;
7320
+ continue;
7280
7321
  }
7281
7322
  settings.order.push(set);
7282
7323
  }
@@ -7760,7 +7801,6 @@ const __filter_div_textContent = __filter_div.textContent !== undefined;
7760
7801
  * Filter the table using both the global filter and column based filtering
7761
7802
  *
7762
7803
  * @param settings DataTables settings object
7763
- * @param input search information
7764
7804
  */
7765
7805
  function filterComplete(settings) {
7766
7806
  settings.columns;
@@ -7824,7 +7864,6 @@ function filterCustom(settings) {
7824
7864
  * @param settings
7825
7865
  * @param input
7826
7866
  * @param options
7827
- * @param column
7828
7867
  * @returns
7829
7868
  */
7830
7869
  function filter(searchRows, settings, input, options) {
@@ -9177,7 +9216,7 @@ function getPrototypeNames(name) {
9177
9216
  * Each of the input parameter types will be converted to a DataTables settings
9178
9217
  * object where possible.
9179
9218
  *
9180
- * @param mixed DataTable identifier. Can be one of:
9219
+ * @param mixedIn DataTable identifier. Can be one of:
9181
9220
  * * `string` - jQuery selector. Any DataTables' matching the given selector
9182
9221
  * with be found and used.
9183
9222
  * * `node` - `TABLE` node which has already been formed into a DataTable.
@@ -9466,7 +9505,7 @@ const __reload = function (settings, holdPosition, callback) {
9466
9505
  processingDisplay(settings, true);
9467
9506
  // Cancel an existing request
9468
9507
  var xhr = settings.jqXHR;
9469
- if (xhr && xhr.readyState !== 4) {
9508
+ if (xhr && xhr.readyState !== 4 && typeof xhr.abort === 'function') {
9470
9509
  xhr.abort();
9471
9510
  }
9472
9511
  // Trigger xhr
@@ -9594,12 +9633,13 @@ function selectCells(settings, selector, opts) {
9594
9633
  // Otherwise the selector is a node, and there is one last option - the
9595
9634
  // element might be a child of an element which has dt-row and dt-column
9596
9635
  // data attributes
9597
- host = Dom.s(s).closest('*[data-dt-row]');
9598
- return host.count()
9636
+ let rowHost = Dom.s(s).closest('*[data-dt-row]');
9637
+ let columnHost = Dom.s(s).closest('*[data-dt-column]');
9638
+ return rowHost.count()
9599
9639
  ? [
9600
9640
  {
9601
- row: host.data('dt-row'),
9602
- column: host.data('dt-column')
9641
+ row: parseInt(rowHost.attr('data-dt-row')),
9642
+ column: parseInt(columnHost.attr('data-dt-column'))
9603
9643
  }
9604
9644
  ]
9605
9645
  : [];
@@ -9912,7 +9952,7 @@ function selectColumns(settings, selector, opts) {
9912
9952
  // Otherwise a node which might have a `dt-column` data attribute, or be
9913
9953
  // a child or such an element
9914
9954
  var host = Dom.s(s).closest('*[data-dt-column]');
9915
- return host.count() ? [host.data('dt-column')] : [];
9955
+ return host.count() ? [parseInt(host.attr('data-dt-column'))] : [];
9916
9956
  };
9917
9957
  var selected = selectorRun('column', selector, run, settings, opts);
9918
9958
  return opts.columnOrder && opts.columnOrder === 'index'
@@ -10109,18 +10149,19 @@ registerPlural('columns().widths()', 'column().width()', function () {
10109
10149
  // Injects a fake row into the table for just a moment so the widths can
10110
10150
  // be read, regardless of colspan in the header and rows being present
10111
10151
  // in the body
10112
- var columns = this.columns(':visible').count();
10152
+ var columns = this.columns(':visible');
10113
10153
  var row = Dom
10114
10154
  .c('tr')
10115
- .html('<td>' + Array(columns).join('</td><td>') + '</td>');
10155
+ .html('<td>' + Array(columns.count()).join('</td><td>') + '</td>');
10116
10156
  Dom.s(this.table().body()).append(row);
10117
- var widths = row.children().mapTo(el => {
10118
- return Dom.s(el).width('outer');
10157
+ var widths = [];
10158
+ var indexes = columns.indexes();
10159
+ row.children().each((el, idx) => {
10160
+ widths[indexes[idx]] = Dom.s(el).width('outer');
10119
10161
  });
10120
10162
  row.remove();
10121
- return this.iterator('column', function (settings, column) {
10122
- var visIdx = columnIndexToVisible(settings, column);
10123
- return visIdx !== null ? widths[visIdx] : 0;
10163
+ return this.iterator('column', (settings, column) => {
10164
+ return widths[column] || 0;
10124
10165
  }, true);
10125
10166
  });
10126
10167
  registerPlural('columns().indexes()', 'column().index()', function (type) {
@@ -10241,7 +10282,7 @@ registerPlural('columns().orderable()', 'column().orderable()', function (direct
10241
10282
  /**
10242
10283
  * Set the page length
10243
10284
  *
10244
- * @param settings DataTables context
10285
+ * @param ctx DataTables context
10245
10286
  * @param val Value to change to
10246
10287
  */
10247
10288
  function lengthChange(ctx, val) {
@@ -10592,7 +10633,7 @@ function selectRows(settings, selector, opts) {
10592
10633
  }
10593
10634
  else {
10594
10635
  var host = Dom.s(sel).closest('*[data-dt-row]');
10595
- return host.count() ? [host.data('dt-row')] : [];
10636
+ return host.count() ? [parseInt(host.attr('data-dt-row'))] : [];
10596
10637
  }
10597
10638
  }
10598
10639
  // ID selector. Want to always be able to select rows by id, regardless
@@ -10624,8 +10665,7 @@ function selectRows(settings, selector, opts) {
10624
10665
  // Get nodes in the order from the `rows` array with null values removed
10625
10666
  var nodes = util.array.removeEmpty(util.array.pluckOrder(settings.data, rows, 'tr'));
10626
10667
  // Selector - selector string, array of nodes or jQuery object.
10627
- return Dom
10628
- .s(nodes)
10668
+ return Dom.s(nodes)
10629
10669
  .filter(sel)
10630
10670
  .mapTo((el) => el._DT_RowIndex);
10631
10671
  };
@@ -10770,7 +10810,7 @@ register('row().data()', function (data) {
10770
10810
  util.set(ctx[0].rowId)(data, row.tr.id);
10771
10811
  }
10772
10812
  // Automatically invalidate
10773
- invalidate(ctx[0], this[0], 'data');
10813
+ invalidate(ctx[0], this[0][0], 'data');
10774
10814
  return this;
10775
10815
  });
10776
10816
  register('row().node()', function () {
@@ -11088,10 +11128,10 @@ register('caption()', function (value, side) {
11088
11128
  caption.css('caption-side', side);
11089
11129
  caption.get(0)._captionSide = side;
11090
11130
  }
11091
- if (container.find('div.dataTables_scroll').count()) {
11092
- var selector = side === 'top' ? 'Head' : 'Foot';
11131
+ if (container.find('div.dt-scroll').count()) {
11132
+ var selector = side === 'top' ? 'head' : 'foot';
11093
11133
  container
11094
- .find('div.dataTables_scroll' + selector + ' table')
11134
+ .find('div.dt-scroll-' + selector + ' table')
11095
11135
  .prepend(caption);
11096
11136
  }
11097
11137
  else {
@@ -11104,6 +11144,280 @@ register('caption.node()', function () {
11104
11144
  return ctx.length ? ctx[0].captionNode : null;
11105
11145
  });
11106
11146
 
11147
+ /**
11148
+ * What's this!? "DataTables Plus" is a commercial set of extensions for
11149
+ * DataTables, such as Editor, and the functions in this file allow a license
11150
+ * key to be provided (`DataTable.key(...)`) to unlock those features.
11151
+ *
11152
+ * This is the modal that I've selected to make DataTables sustainable, open
11153
+ * source core, with some commercial extensions available.
11154
+ *
11155
+ * Please support DataTables and open source by purchasing a Plus license from
11156
+ * https://datatables.net/plus .
11157
+ */
11158
+ let _ready = false;
11159
+ let _notice;
11160
+ let _processingKey = false;
11161
+ let _delayedReleaseDate = null;
11162
+ let _delayedSoftware = null;
11163
+ const _licenseInfo = {
11164
+ developers: 0,
11165
+ type: null,
11166
+ expires: null,
11167
+ valid: null
11168
+ };
11169
+ const _wm = Dom.c('div');
11170
+ const _publicKey = 'BE1A9w9D9U/4s4/TogY+1sW/dLJ8IquzK1PmV70J93ZTIvXMZ0eV2NAb52ntpgwVFySSB2fOI7geLNO737rQAyo=';
11171
+ /**
11172
+ * Convert a base64 string to a binary array
11173
+ *
11174
+ * @param b64 Source string
11175
+ * @returns Array
11176
+ */
11177
+ function b64ToBuf(b64) {
11178
+ return Uint8Array.from(atob(b64), c => c.charCodeAt(0));
11179
+ }
11180
+ /**
11181
+ * Logic to check the trial and plus license expiry and display messages if
11182
+ * needed. There is particular consideration for checking a release date of
11183
+ * software, as the license for DataTables Plus is perpetual for the version
11184
+ * purchased, and it shouldn't show a message for the purchased version ever.
11185
+ *
11186
+ * @param releaseDate The date the software was released on.
11187
+ * @param software The software name being validated. Can be null for a general
11188
+ * "Plus" check.
11189
+ * @returns true if valid, false otherwise
11190
+ */
11191
+ function check(releaseDate, software) {
11192
+ let expires = _licenseInfo.expires;
11193
+ if (_licenseInfo.valid === false) {
11194
+ noticePrep('License key invalid');
11195
+ noticeDisplay();
11196
+ }
11197
+ else if (_licenseInfo.type === 'trial') {
11198
+ // Trail is for plus, so the software type isn't taken into account
11199
+ let remaining = expires
11200
+ ? Math.ceil((expires.getTime() - new Date().getTime()) / 86400000)
11201
+ : -1;
11202
+ if (remaining < 0) {
11203
+ // Trial expires
11204
+ consoleMsg('Your trial has now expired - https://datatables.net/plus', 'warn');
11205
+ noticePrep('Trial expired');
11206
+ noticeDisplay();
11207
+ return false;
11208
+ }
11209
+ else {
11210
+ // Let the user know when it is going to expire with a console
11211
+ // message.
11212
+ consoleMsg('Your trial expires in ' +
11213
+ remaining +
11214
+ ' day' +
11215
+ (remaining === 1 ? '' : 's'));
11216
+ return true;
11217
+ }
11218
+ }
11219
+ else if (software === null) {
11220
+ // Validating the key only - there hasn't been any specific software
11221
+ // calling the `plus` parameter yet. The key is good, so carry on.
11222
+ return true;
11223
+ }
11224
+ else if (
11225
+ // Checking if the build version can be used with this key
11226
+ _licenseInfo.type === 'plus' ||
11227
+ (_licenseInfo.type === 'editor' && software === 'editor')) {
11228
+ if (!expires || new Date(releaseDate) > expires) {
11229
+ noticePrep('Upgrade required for this version');
11230
+ noticeDisplay();
11231
+ return false;
11232
+ }
11233
+ return true;
11234
+ }
11235
+ else if (_licenseInfo.type === 'editor' && software !== 'editor') {
11236
+ // Editor specific license
11237
+ noticePrep('License for Editor only. Upgrade for Plus');
11238
+ noticeDisplay();
11239
+ return false;
11240
+ }
11241
+ noticePrep();
11242
+ noticeDisplay();
11243
+ return false;
11244
+ }
11245
+ /**
11246
+ * Common log message handling
11247
+ *
11248
+ * @param msg Message to show
11249
+ * @param level Log level
11250
+ */
11251
+ function consoleMsg(msg, level = 'log') {
11252
+ let fn = level === 'log' ? console.log : console.warn;
11253
+ fn('%cDataTables Plus%c ' + msg, 'background: #007bff; color: #fff; padding: 2px 5px;', 'color: inherit;');
11254
+ }
11255
+ /**
11256
+ * Set the DataTables Plus key to use
11257
+ *
11258
+ * @param key DataTables Plus key - obtain from https://datatables.net/account .
11259
+ */
11260
+ const key = function (key) {
11261
+ _processingKey = true;
11262
+ // Run the verification of the key
11263
+ verify(key)
11264
+ .then(result => {
11265
+ _processingKey = false;
11266
+ check(_delayedReleaseDate, _delayedSoftware);
11267
+ })
11268
+ .catch(() => {
11269
+ _processingKey = false;
11270
+ check(_delayedReleaseDate, _delayedSoftware);
11271
+ });
11272
+ };
11273
+ /**
11274
+ * Build the notice
11275
+ *
11276
+ * @returns
11277
+ */
11278
+ function noticePrep(text) {
11279
+ if (!_ready) {
11280
+ let shadow = _wm[0].attachShadow({ mode: 'closed' });
11281
+ let notice = Dom.c('div').css({
11282
+ position: 'fixed',
11283
+ bottom: '1em',
11284
+ right: '1em',
11285
+ border: '1px solid #ffc107',
11286
+ background: '#fff3cd',
11287
+ color: '#856404',
11288
+ padding: '0.5em 1em',
11289
+ 'font-family': 'sans-serif',
11290
+ 'font-size': '12px',
11291
+ 'border-radius': '4px',
11292
+ 'z-index': '10000',
11293
+ 'box-shadow': '0 2px 5px rgba(0,0,0,0.2)'
11294
+ });
11295
+ Dom.c('a')
11296
+ .attr('href', 'https://datatables.net/tn/25')
11297
+ .attr('target', '_blank')
11298
+ .css({
11299
+ color: 'inherit',
11300
+ 'text-decoration': 'none'
11301
+ })
11302
+ .appendTo(notice);
11303
+ if (!text) {
11304
+ text = 'License key required';
11305
+ }
11306
+ shadow.appendChild(notice[0]);
11307
+ _notice = notice;
11308
+ _ready = true;
11309
+ }
11310
+ if (text) {
11311
+ _notice
11312
+ .find('a')
11313
+ .html('DataTables Plus: ' + text + ' - learn more &#187;');
11314
+ }
11315
+ }
11316
+ /**
11317
+ * Display the license notice
11318
+ */
11319
+ function noticeDisplay() {
11320
+ if (!_processingKey && !document.body.contains(_wm[0])) {
11321
+ document.body.appendChild(_wm[0]);
11322
+ }
11323
+ }
11324
+ /**
11325
+ * Validate the license string, which is in two parts - the first is a payload
11326
+ * that provides a small amount of information about the license, and the second
11327
+ * which is the license key.
11328
+ *
11329
+ * @param licenseString Key to validate
11330
+ * @returns Promise with validation information
11331
+ */
11332
+ function verify(licenseString) {
11333
+ return new Promise(function (resolve) {
11334
+ try {
11335
+ var parts = licenseString.split(':');
11336
+ if (parts.length !== 2) {
11337
+ _licenseInfo.valid = false;
11338
+ return resolve();
11339
+ }
11340
+ var payload = parts[0];
11341
+ var signatureB64 = parts[1];
11342
+ // Backwards compat for old browsers
11343
+ var cryptoObj = window.crypto || window.msCrypto;
11344
+ var subtle = cryptoObj.subtle || cryptoObj.webkitSubtle;
11345
+ var rawKey = b64ToBuf(_publicKey);
11346
+ var rawSig = b64ToBuf(signatureB64);
11347
+ var data = new TextEncoder().encode(payload);
11348
+ subtle
11349
+ .importKey('raw', rawKey, { name: 'ECDSA', namedCurve: 'P-256' }, false, ['verify'])
11350
+ .then(function (key) {
11351
+ return subtle.verify({ name: 'ECDSA', hash: { name: 'SHA-256' } }, key, rawSig, data);
11352
+ })
11353
+ .then(function (isValid) {
11354
+ if (!isValid) {
11355
+ _licenseInfo.valid = false;
11356
+ return resolve();
11357
+ }
11358
+ // Extract the payload to be useful
11359
+ var payloadParts = payload.match(/(plus|trial|editor)_(\d+)_(\d{4})(\d{2})(\d{2})/);
11360
+ if (!payloadParts || payloadParts.length !== 6) {
11361
+ _licenseInfo.valid = false;
11362
+ return resolve();
11363
+ }
11364
+ _licenseInfo.valid = true;
11365
+ _licenseInfo.type = payloadParts[1];
11366
+ _licenseInfo.developers = parseInt(payloadParts[2]);
11367
+ _licenseInfo.expires = new Date(payloadParts[3] +
11368
+ '-' +
11369
+ payloadParts[4] +
11370
+ '-' +
11371
+ payloadParts[5]);
11372
+ resolve();
11373
+ })
11374
+ .catch(function () {
11375
+ _licenseInfo.valid = false;
11376
+ resolve();
11377
+ });
11378
+ }
11379
+ catch (e) {
11380
+ _licenseInfo.valid = false;
11381
+ resolve();
11382
+ }
11383
+ });
11384
+ }
11385
+ /**
11386
+ * Create the `plus` function on `DataTable` which Plus extensions can call to
11387
+ * determine if the license key is valid and in date for the release. The
11388
+ * resulting function is called like this: `DataTable.plus('2026-12-25')` and
11389
+ * will return `true` or `false` depending on the key that was given (or not).
11390
+ *
11391
+ * @param DataTable The DataTable host object
11392
+ */
11393
+ function plus (DataTable) {
11394
+ Object.defineProperty(DataTable, 'plus', {
11395
+ value: function (releaseDate, software = '') {
11396
+ // Unsecure sites are only useful for development, so allow there
11397
+ // and on the site.
11398
+ let host = window.location.hostname;
11399
+ let isDev = host === '192.168.234.234' ||
11400
+ host.endsWith('.datatables.net') ||
11401
+ host === 'datatables.net';
11402
+ if (isDev) {
11403
+ return true;
11404
+ }
11405
+ if (_processingKey) {
11406
+ // The validation of the key is async, so there is a chance that
11407
+ // it could still be happening when this runs. We just queue the
11408
+ // last one if that is the case.
11409
+ _delayedReleaseDate = releaseDate;
11410
+ _delayedSoftware = software;
11411
+ return true;
11412
+ }
11413
+ return check(releaseDate, software);
11414
+ },
11415
+ configurable: false,
11416
+ enumerable: false,
11417
+ writable: false
11418
+ });
11419
+ }
11420
+
11107
11421
  /**
11108
11422
  * CommonJS factory function pass through. This will check if the arguments
11109
11423
  * given are a window object or a jQuery object. If so they are set accordingly.
@@ -11229,6 +11543,8 @@ register$2('info', function (settings, optsIn) {
11229
11543
  /**
11230
11544
  * Update the information elements in the display
11231
11545
  * @param settings DataTables settings object
11546
+ * @param opts
11547
+ * @param node
11232
11548
  */
11233
11549
  function updateInfo(settings, opts, node) {
11234
11550
  var start = settings.displayStart + 1, end = displayEnd(settings), max = recordsTotal(settings), total = recordsDisplay(settings), out = total ? opts.text : opts.empty;
@@ -11301,7 +11617,7 @@ function _pagingDraw(settings, host, opts) {
11301
11617
  if (!settings.initDone) {
11302
11618
  return;
11303
11619
  }
11304
- let plugin = opts.type ? ext.pager[opts.type] : _pagingDynamic, aria = settings.language.aria.paginate || {}, start = settings.displayStart, len = settings.pageLength, visRecords = recordsDisplay(settings), all = len === -1, page = all ? 0 : Math.ceil(start / len), pages = Math.ceil(visRecords / (all ? 1 : len)), buttons = [], buttonEls = [], buttonsNested = plugin(opts).map(function (val) {
11620
+ let plugin = opts.type ? ext.pager[opts.type] : _pagingDynamic, aria = settings.language.aria.paginate || {}, start = settings.displayStart, len = settings.pageLength, visRecords = recordsDisplay(settings), all = len === -1, page = all ? 0 : Math.ceil(start / len), pages = all ? (visRecords ? 1 : 0) : Math.ceil(visRecords / len), buttons = [], buttonEls = [], buttonsNested = plugin(opts).map(function (val) {
11305
11621
  return val === 'numbers'
11306
11622
  ? pagingNumbers(page, pages, opts.buttons, opts.boundaryNumbers)
11307
11623
  : val;
@@ -11463,8 +11779,7 @@ register$2('pageLength', function (settings, optsIn) {
11463
11779
  }
11464
11780
  // Wrapper element - use a span as a holder for where the select will go
11465
11781
  var tmpId = 'tmp-' + +new Date();
11466
- var div = Dom
11467
- .c('div')
11782
+ var div = Dom.c('div')
11468
11783
  .classAdd(classes.container)
11469
11784
  .html(str.replace('_MENU_', '<span id="' + tmpId + '"></span>'));
11470
11785
  // Save text node content for macro updating
@@ -11486,9 +11801,9 @@ register$2('pageLength', function (settings, optsIn) {
11486
11801
  });
11487
11802
  };
11488
11803
  // Next, the select itself, along with the options
11489
- var select = Dom
11490
- .c('select')
11804
+ var select = Dom.c('select')
11491
11805
  .attr('aria-controls', tableId)
11806
+ .attr('autocomplete', 'off')
11492
11807
  .classAdd(classes.select);
11493
11808
  for (i = 0; i < lengths.length; i++) {
11494
11809
  // Attempt to look up the length from the i18n options
@@ -11519,7 +11834,26 @@ register$2('pageLength', function (settings, optsIn) {
11519
11834
  // Update node value whenever anything changes the table's length
11520
11835
  Dom.s(settings.table).on('length.dt.DT', function (e, s, len) {
11521
11836
  if (settings === s) {
11522
- div.find('select').val(len);
11837
+ let localSelect = div.find('select');
11838
+ // Remove any temporary values
11839
+ localSelect.find('option[data-dt-len-tmp]').remove();
11840
+ let option = localSelect.find('option[value="' + len + '"]');
11841
+ // If the select list doesn't have the target value, then we
11842
+ // need to add it for display.
11843
+ if (!option.length) {
11844
+ let after = findInsertBeforePoint(select, len);
11845
+ let tempOption = Dom.c('option')
11846
+ .val(len)
11847
+ .text(len)
11848
+ .attr('data-dt-len-tmp', true);
11849
+ if (after && after.length) {
11850
+ tempOption.insertBefore(after);
11851
+ }
11852
+ else {
11853
+ localSelect.append(tempOption);
11854
+ }
11855
+ }
11856
+ localSelect.val(len);
11523
11857
  // Resolve plurals in the text for the new length
11524
11858
  updateEntries(len);
11525
11859
  }
@@ -11527,6 +11861,19 @@ register$2('pageLength', function (settings, optsIn) {
11527
11861
  updateEntries(settings.pageLength);
11528
11862
  return div;
11529
11863
  }, 'l');
11864
+ /**
11865
+ * Find the element to insert the temporary option before to keep the sequence.
11866
+ *
11867
+ * @param select Select element
11868
+ * @param insertValue Page length value
11869
+ * @returns Target option or null if not found
11870
+ */
11871
+ function findInsertBeforePoint(select, insertValue) {
11872
+ let options = select.find('option');
11873
+ let values = options.mapTo(el => parseInt(el.value));
11874
+ let idx = values.findIndex(val => val > insertValue);
11875
+ return idx < -1 ? null : options.eq(idx);
11876
+ }
11530
11877
 
11531
11878
  let __searchCounter = 0;
11532
11879
  register$2('search', function (settings, optsIn) {
@@ -11537,7 +11884,9 @@ register$2('search', function (settings, optsIn) {
11537
11884
  let classes = settings.classes.search;
11538
11885
  let tableId = settings.tableId;
11539
11886
  let language = settings.language;
11540
- let input = '<input type="search" class="' + classes.input + '"/>';
11887
+ let input = '<input type="search" class="' +
11888
+ classes.input +
11889
+ '" autocomplete="off"/>';
11541
11890
  let opts = util.object.assignDeep({
11542
11891
  columns: '*',
11543
11892
  placeholder: language.searchPlaceholder,
@@ -11937,7 +12286,8 @@ const defaults = {
11937
12286
  },
11938
12287
  stateSaveParams: null,
11939
12288
  tabIndex: 0,
11940
- titleRow: null
12289
+ titleRow: null,
12290
+ typeDetect: true
11941
12291
  };
11942
12292
 
11943
12293
  const DataTable = function (selector, options) {
@@ -12359,6 +12709,8 @@ DataTable.datetime = datetime;
12359
12709
  DataTable.__browser = browser;
12360
12710
  DataTable.Dom = Dom;
12361
12711
  DataTable.ajax = util.ajax;
12712
+ DataTable.key = key;
12713
+ plus(DataTable);
12362
12714
  /**
12363
12715
  * Private data store, containing all of the settings objects that are created
12364
12716
  * for the tables on a given page.