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.mjs 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
 
@@ -118,7 +118,7 @@ let _stripHtml = function (input, replacement = '') {
118
118
  * This function is replaceable if the user wishes to use a different library
119
119
  * for escaping HTML entities in a string.
120
120
  *
121
- * @param d Value to escape HTML in
121
+ * @param val Value to escape HTML in
122
122
  * @returns Escaped value
123
123
  */
124
124
  let _escapeHtml = function (val) {
@@ -517,7 +517,10 @@ function ajax(optionsIn) {
517
517
  options.contentType = 'application/json; charset=utf-8';
518
518
  }
519
519
  }
520
- xhr.open(method, options.url + (options.url.includes('?') ? '&' : '?') + urlParams, true, options.username || null, options.password || null);
520
+ xhr.open(method, options.url +
521
+ (urlParams
522
+ ? (options.url.includes('?') ? '&' : '?') + urlParams
523
+ : ''), true, options.username || null, options.password || null);
521
524
  // Content type for FormData requests gets set by the browser.
522
525
  if (options.contentType && !(options.data instanceof FormData)) {
523
526
  xhr.setRequestHeader('Content-Type', options.contentType);
@@ -535,11 +538,16 @@ function ajax(optionsIn) {
535
538
  if (options.data instanceof FormData) {
536
539
  sendData = options.data;
537
540
  }
538
- else if (method !== 'GET' && options.data && typeof options.data !== 'string') {
539
- sendData = serialize(options.data, options.traditional);
540
- sendData = convertSpaces(sendData, options);
541
- // So beforeSend matches how jQuery behaves
542
- options.data = sendData;
541
+ else if (method !== 'GET' && options.data) {
542
+ if (typeof options.data === 'string') {
543
+ sendData = options.data;
544
+ }
545
+ else {
546
+ sendData = serialize(options.data, options.traditional);
547
+ sendData = convertSpaces(sendData, options);
548
+ // So beforeSend matches how jQuery behaves
549
+ options.data = sendData;
550
+ }
543
551
  }
544
552
  xhr.onreadystatechange = function () {
545
553
  if (xhr.readyState != 4) {
@@ -589,6 +597,7 @@ function ajax(optionsIn) {
589
597
  if (options.beforeSend) {
590
598
  if (options.beforeSend.call(options, xhr, options) === false) {
591
599
  xhr.abort();
600
+ return xhr;
592
601
  }
593
602
  }
594
603
  xhr.send(sendData);
@@ -601,7 +610,9 @@ ajax.serialize = serialize;
601
610
  * Run callback functions (allowing for none, one or array)
602
611
  *
603
612
  * @param fnIn Function(s) to run
604
- * @param parameters Parameters to pass to the function(s)
613
+ * @param arg1 Parameters to pass to the function(s)
614
+ * @param arg2 Parameters to pass to the function(s)
615
+ * @param arg3 Parameters to pass to the function(s)
605
616
  */
606
617
  function callback(fnIn, arg1, arg2, arg3) {
607
618
  if (!fnIn) {
@@ -775,7 +786,7 @@ function allUnique(src) {
775
786
  * @returns Flattened array
776
787
  */
777
788
  function flatten(out, val) {
778
- if (Array.isArray(val)) {
789
+ if (Array.isArray(val) || arrayLike(val)) {
779
790
  for (var i = 0; i < val.length; i++) {
780
791
  flatten(out, val[i]);
781
792
  }
@@ -821,6 +832,7 @@ function pluck(a, prop, prop2) {
821
832
  * as the indexes to pick from the source array
822
833
  *
823
834
  * @param a Array to get values from
835
+ * @param order Indexes to pick
824
836
  * @param prop Property to read values from
825
837
  * @param prop2 Inner property to get values from if a 2D array
826
838
  * @returns Array of read values
@@ -1318,7 +1330,7 @@ var timer = /*#__PURE__*/Object.freeze({
1318
1330
  * @returns true if this version of DataTables is greater or equal to the
1319
1331
  * required version, or false if this version of DataTales is not suitable
1320
1332
  */
1321
- function check(version1, version2) {
1333
+ function check$1(version1, version2) {
1322
1334
  let dt = external('datatable');
1323
1335
  var parts1 = version2 ? version2.split('.') : dt.ext.version.split('.');
1324
1336
  var parts2 = version1.split('.');
@@ -1338,7 +1350,7 @@ function check(version1, version2) {
1338
1350
 
1339
1351
  var version = /*#__PURE__*/Object.freeze({
1340
1352
  __proto__: null,
1341
- check: check
1353
+ check: check$1
1342
1354
  });
1343
1355
 
1344
1356
  // Note that the aliased properties are for compatibility with DataTables 2-
@@ -1556,9 +1568,12 @@ function parseEventName(original) {
1556
1568
  isFocus = true;
1557
1569
  }
1558
1570
  else if (name === 'blur') {
1559
- name = 'blurout';
1571
+ name = 'focusout';
1560
1572
  isFocus = true;
1561
1573
  }
1574
+ else if (name === 'ready') {
1575
+ name = 'DOMContentLoaded';
1576
+ }
1562
1577
  return {
1563
1578
  eventName: name,
1564
1579
  isFocus,
@@ -1595,6 +1610,14 @@ function add(el, nameFull, handler, selector, one) {
1595
1610
  if (!eventName) {
1596
1611
  return;
1597
1612
  }
1613
+ // Special handling for the "ready" event - it will trigger when the content
1614
+ // is ready, but also if it is already ready, when added.
1615
+ if (el === document && eventName === 'DOMContentLoaded' && nameFull.includes('ready')) {
1616
+ if (document.readyState === 'complete') {
1617
+ handler(new Event('DOMContentLoaded'));
1618
+ return;
1619
+ }
1620
+ }
1598
1621
  // Create a function that will be the actual event handler, and performs any
1599
1622
  // logic we need, such as delegate handling and adding properties.
1600
1623
  let wrapped = function (event) {
@@ -1620,6 +1643,11 @@ function add(el, nameFull, handler, selector, one) {
1620
1643
  if (!dTarget) {
1621
1644
  return;
1622
1645
  }
1646
+ if (isHover &&
1647
+ event.relatedTarget &&
1648
+ dTarget.contains(event.relatedTarget)) {
1649
+ return;
1650
+ }
1623
1651
  callScope = dTarget;
1624
1652
  }
1625
1653
  // Set the properties that jQuery adds to the event object
@@ -1677,7 +1705,7 @@ function remove(el, nameFull, handler, selector) {
1677
1705
  wrapped.delegateSelector === selector &&
1678
1706
  wrapped.original === handler);
1679
1707
  }
1680
- if (eventName && selector) {
1708
+ else if (eventName && selector) {
1681
1709
  removeEvents = stored.filter(wrapped => wrapped.type === eventName &&
1682
1710
  wrapped.delegateSelector === selector);
1683
1711
  }
@@ -1863,7 +1891,7 @@ class Dom {
1863
1891
  /**
1864
1892
  * Add an element (or multiple) to the instance. Will ensure uniqueness.
1865
1893
  *
1866
- * @param el Element(s) to add
1894
+ * @param selector Element(s) to add
1867
1895
  * @param sort Indicate if the element should be added in document order.
1868
1896
  * @returns Self for chaining
1869
1897
  */
@@ -1908,29 +1936,33 @@ class Dom {
1908
1936
  if (!content) {
1909
1937
  return this;
1910
1938
  }
1911
- if (Array.isArray(content)) {
1912
- content.forEach(c => this.append(c));
1913
- return this;
1939
+ if (!arrayLike(content)) {
1940
+ content = [content];
1914
1941
  }
1915
- return this.each(el => {
1916
- if (content instanceof Dom) {
1917
- content.each(item => {
1918
- el.append(item);
1919
- });
1920
- }
1921
- else if (typeof content === 'string') {
1922
- el.insertAdjacentHTML('beforeend', content);
1923
- }
1924
- else if (arrayLike(content)) {
1925
- // Allow for a jQuery object being passed
1926
- let arrayLike = content;
1927
- for (let i = 0; i < arrayLike.length; i++) {
1928
- el.append(arrayLike[i]);
1942
+ // Generate a flat array of the content to be added, with nulls removed
1943
+ // this means it will be an array of nodes and / or strings
1944
+ let flatContent = flatten([], content).filter(c => !!c);
1945
+ /// Got a string somewhere in it, so need to use insertAdjacentHTML
1946
+ if (flatContent.find(val => typeof val === 'string')) {
1947
+ return this.each(el => {
1948
+ for (let i = 0; i < flatContent.length; i++) {
1949
+ if (typeof flatContent[i] === 'string') {
1950
+ el.insertAdjacentHTML('beforeend', flatContent[i]);
1951
+ }
1952
+ else {
1953
+ el.append(flatContent[i]);
1954
+ }
1929
1955
  }
1956
+ });
1957
+ }
1958
+ // Otherwise we can use a document fragment for a single mutation
1959
+ // on the main document
1960
+ return this.each(el => {
1961
+ let fragment = new DocumentFragment();
1962
+ for (let i = 0; i < flatContent.length; i++) {
1963
+ fragment.append(flatContent[i]);
1930
1964
  }
1931
- else {
1932
- el.append(content);
1933
- }
1965
+ el.append(fragment);
1934
1966
  });
1935
1967
  }
1936
1968
  /**
@@ -2097,9 +2129,7 @@ class Dom {
2097
2129
  css(rule, value) {
2098
2130
  // String getter
2099
2131
  if (typeof rule === 'string' && value === undefined) {
2100
- return this.length
2101
- ? getComputedStyle(this[0])[rule]
2102
- : null;
2132
+ return this.length ? getComputedStyle(this[0])[rule] : null;
2103
2133
  }
2104
2134
  return this.each(el => {
2105
2135
  if (typeof rule === 'string') {
@@ -2127,11 +2157,11 @@ class Dom {
2127
2157
  return this.length ? dataConvert(this[0].dataset[name]) : null;
2128
2158
  }
2129
2159
  if (typeof name === 'string') {
2130
- this.each(el => el.dataset[name] = JSON.stringify(value));
2160
+ this.each(el => (el.dataset[name] = JSON.stringify(value)));
2131
2161
  }
2132
2162
  else {
2133
2163
  each(name, (key, val) => {
2134
- this.each(el => el.dataset[key] = JSON.stringify(val));
2164
+ this.each(el => (el.dataset[key] = JSON.stringify(val)));
2135
2165
  });
2136
2166
  }
2137
2167
  return this;
@@ -2262,7 +2292,7 @@ class Dom {
2262
2292
  /**
2263
2293
  * Get all matching descendants
2264
2294
  *
2265
- * @param selector Elements to find
2295
+ * @param input Elements to find
2266
2296
  * @returns A new Dom instance with all matching elements
2267
2297
  */
2268
2298
  find(input) {
@@ -2991,6 +3021,7 @@ const legacy = [];
2991
3021
  * @param name The name of the new feature.
2992
3022
  * @param cb A function that will create the elements and event listeners for
2993
3023
  * the feature being added.
3024
+ * @param legacyChar
2994
3025
  */
2995
3026
  function register$2(name, cb, legacyChar = '') {
2996
3027
  features[name] = cb;
@@ -3855,7 +3886,7 @@ const ext = {
3855
3886
  * Software version
3856
3887
  * @type string
3857
3888
  */
3858
- version: '3.0.0-beta.2'
3889
+ version: '3.0.1'
3859
3890
  };
3860
3891
  //
3861
3892
  // Backwards compatibility. Alias to pre 1.10 Hungarian notation counter parts
@@ -3870,7 +3901,7 @@ Object.assign(ext, {
3870
3901
  oStdClasses: ext.classes,
3871
3902
  oPagination: ext.pager,
3872
3903
  sVersion: ext.version,
3873
- fnVersionCheck: check
3904
+ fnVersionCheck: check$1
3874
3905
  });
3875
3906
 
3876
3907
  /**
@@ -4099,7 +4130,7 @@ function arrayApply(arr, data) {
4099
4130
  function listener(that, name, src) {
4100
4131
  let srcArr = Array.isArray(src) ? src : [src];
4101
4132
  for (var i = 0; i < srcArr.length; i++) {
4102
- that.on(name + '.dt', srcArr[i]);
4133
+ that.on(name + '.dt.DT', srcArr[i]);
4103
4134
  }
4104
4135
  }
4105
4136
  /**
@@ -4214,10 +4245,12 @@ function __mlHelper(localeString) {
4214
4245
  // gives milliseconds epoch
4215
4246
  return d.valueOf();
4216
4247
  }
4217
- },
4218
- className: 'dt-right'
4248
+ }
4219
4249
  });
4220
4250
  }
4251
+ if (!store.className[typeName]) {
4252
+ store.className[typeName] = 'dt-right';
4253
+ }
4221
4254
  return function (d, type) {
4222
4255
  // Allow for a default value
4223
4256
  if (d === null || d === undefined) {
@@ -4318,10 +4351,12 @@ function datetime(format, locale) {
4318
4351
  pre: function (d) {
4319
4352
  return __mldObj(d, format, locale) || 0;
4320
4353
  }
4321
- },
4322
- className: 'dt-right'
4354
+ }
4323
4355
  });
4324
4356
  }
4357
+ if (!store.className[typeName]) {
4358
+ store.className[typeName] = 'dt-right';
4359
+ }
4325
4360
  }
4326
4361
  /**
4327
4362
  * Helpers for `columns.render`.
@@ -4756,7 +4791,7 @@ function create$1(parts = {}) {
4756
4791
  * DOM source.
4757
4792
  *
4758
4793
  * @param settings DataTables settings object
4759
- * @param data data array to be added
4794
+ * @param dataIn data array to be added
4760
4795
  * @param tr TR element to add to the table - optional. If not given, DataTables
4761
4796
  * will create a row automatically
4762
4797
  * @param tds Array of TD|TH elements for the row - must be given if tr is.
@@ -4795,7 +4830,7 @@ function addData(settings, dataIn, tr, tds) {
4795
4830
  * it is not cloned).
4796
4831
  *
4797
4832
  * @param settings DataTables settings object
4798
- * @param trs The TR element(s) to add to the table
4833
+ * @param rows The TR element(s) to add to the table
4799
4834
  * @returns Array of indexes for the added rows
4800
4835
  */
4801
4836
  function addTr(settings, rows) {
@@ -4990,6 +5025,7 @@ function invalidate(settings, rowIdx, src, colIdx) {
4990
5025
  // Update DataTables special `DT_*` attributes for the row
4991
5026
  rowAttributes(settings, row);
4992
5027
  }
5028
+ callbackFire(settings, null, 'rowInvalidate', [settings, rowIdx, colIdx], false);
4993
5029
  }
4994
5030
  /**
4995
5031
  * Get the cells and data for a given row - from a <tr> element
@@ -5335,9 +5371,9 @@ function getWideStrings(settings, colIdx) {
5335
5371
  // Don't want script, dialog or template tags in the width
5336
5372
  // calculations as they are hidden content
5337
5373
  cellString = cellString
5338
- .replace(/<script[\s\S]*?<\/script>/gi, ' ')
5339
- .replace(/<dialog[\s\S]*?<\/dialog>/gi, ' ')
5340
- .replace(/<template[\s\S]*?<\/template>/gi, ' ');
5374
+ .replace(/<script[\s\S]*?<\/script(?:\s[^>]*)?>/gi, ' ')
5375
+ .replace(/<dialog[\s\S]*?<\/dialog(?:\s[^>]*)?>/gi, ' ')
5376
+ .replace(/<template[\s\S]*?<\/template(?:\s[^>]*)?>/gi, ' ');
5341
5377
  var noHtml = util.string
5342
5378
  .stripHtml(cellString, ' ')
5343
5379
  .replace(/&nbsp;/g, ' ');
@@ -5376,7 +5412,7 @@ function getWideStrings(settings, colIdx) {
5376
5412
  /**
5377
5413
  * Append a CSS unit (only if required) to a string
5378
5414
  *
5379
- * @param value to css-ify
5415
+ * @param s Value to css-ify
5380
5416
  * @returns Value with css unit
5381
5417
  */
5382
5418
  function stringToCss(s) {
@@ -5938,6 +5974,7 @@ function columnTypes(settings) {
5938
5974
  var types = ext.type.detect;
5939
5975
  var i, iLen, j, jen, k, ken;
5940
5976
  var col, detectedType, cache;
5977
+ var originalTypes = columns.map(c => c.type).join(',');
5941
5978
  // For each column, spin over the data type detection functions, seeing if
5942
5979
  // one matches
5943
5980
  for (i = 0, iLen = columns.length; i < iLen; i++) {
@@ -6035,6 +6072,10 @@ function columnTypes(settings) {
6035
6072
  _columnAutoRender(settings, i);
6036
6073
  }
6037
6074
  }
6075
+ var newTypes = columns.map(c => c.type).join(',');
6076
+ if (newTypes !== originalTypes) {
6077
+ callbackFire(settings, null, 'columnTypes', [settings], false);
6078
+ }
6038
6079
  }
6039
6080
  /**
6040
6081
  * Apply an auto detected renderer to data which doesn't yet have a renderer
@@ -6305,7 +6346,7 @@ function renderer(ctx, type) {
6305
6346
  /**
6306
6347
  * Add the options to the page HTML for the table
6307
6348
  *
6308
- * @param settings DataTables settings object
6349
+ * @param ctx DataTables context
6309
6350
  */
6310
6351
  function createLayout(ctx) {
6311
6352
  var classes = ctx.classes;
@@ -6682,6 +6723,7 @@ function sortAttachListener(settings, node, selector, column, callback) {
6682
6723
  * Sort the display array to match the master's order
6683
6724
  *
6684
6725
  * @param settings DataTables context
6726
+ * @param display The display array
6685
6727
  */
6686
6728
  function sortDisplay(settings, display) {
6687
6729
  if (display.length < 2) {
@@ -6909,7 +6951,6 @@ function sort(ctx, col, dir) {
6909
6951
  * Function to run on user sort request
6910
6952
  *
6911
6953
  * @param settings dataTables settings object
6912
- * @param attachTo node to attach the handler to
6913
6954
  * @param colIdx column sorting index
6914
6955
  * @param addIndex Counter
6915
6956
  * @param shift Shift click add
@@ -7236,13 +7277,13 @@ function implementState(settings, s, callback) {
7236
7277
  let idx = currentNames.indexOf(col[0]);
7237
7278
  if (idx < 0) {
7238
7279
  // If the column was not found ignore it and continue
7239
- return;
7280
+ continue;
7240
7281
  }
7241
7282
  set[0] = idx;
7242
7283
  }
7243
7284
  else if (set[0] >= columns.length) {
7244
7285
  // If the column index is out of bounds ignore it and continue
7245
- return;
7286
+ continue;
7246
7287
  }
7247
7288
  settings.order.push(set);
7248
7289
  }
@@ -7726,7 +7767,6 @@ const __filter_div_textContent = __filter_div.textContent !== undefined;
7726
7767
  * Filter the table using both the global filter and column based filtering
7727
7768
  *
7728
7769
  * @param settings DataTables settings object
7729
- * @param input search information
7730
7770
  */
7731
7771
  function filterComplete(settings) {
7732
7772
  settings.columns;
@@ -7790,7 +7830,6 @@ function filterCustom(settings) {
7790
7830
  * @param settings
7791
7831
  * @param input
7792
7832
  * @param options
7793
- * @param column
7794
7833
  * @returns
7795
7834
  */
7796
7835
  function filter(searchRows, settings, input, options) {
@@ -9143,7 +9182,7 @@ function getPrototypeNames(name) {
9143
9182
  * Each of the input parameter types will be converted to a DataTables settings
9144
9183
  * object where possible.
9145
9184
  *
9146
- * @param mixed DataTable identifier. Can be one of:
9185
+ * @param mixedIn DataTable identifier. Can be one of:
9147
9186
  * * `string` - jQuery selector. Any DataTables' matching the given selector
9148
9187
  * with be found and used.
9149
9188
  * * `node` - `TABLE` node which has already been formed into a DataTable.
@@ -9432,7 +9471,7 @@ const __reload = function (settings, holdPosition, callback) {
9432
9471
  processingDisplay(settings, true);
9433
9472
  // Cancel an existing request
9434
9473
  var xhr = settings.jqXHR;
9435
- if (xhr && xhr.readyState !== 4) {
9474
+ if (xhr && xhr.readyState !== 4 && typeof xhr.abort === 'function') {
9436
9475
  xhr.abort();
9437
9476
  }
9438
9477
  // Trigger xhr
@@ -9560,12 +9599,13 @@ function selectCells(settings, selector, opts) {
9560
9599
  // Otherwise the selector is a node, and there is one last option - the
9561
9600
  // element might be a child of an element which has dt-row and dt-column
9562
9601
  // data attributes
9563
- host = Dom.s(s).closest('*[data-dt-row]');
9564
- return host.count()
9602
+ let rowHost = Dom.s(s).closest('*[data-dt-row]');
9603
+ let columnHost = Dom.s(s).closest('*[data-dt-column]');
9604
+ return rowHost.count()
9565
9605
  ? [
9566
9606
  {
9567
- row: host.data('dt-row'),
9568
- column: host.data('dt-column')
9607
+ row: parseInt(rowHost.attr('data-dt-row')),
9608
+ column: parseInt(columnHost.attr('data-dt-column'))
9569
9609
  }
9570
9610
  ]
9571
9611
  : [];
@@ -9878,7 +9918,7 @@ function selectColumns(settings, selector, opts) {
9878
9918
  // Otherwise a node which might have a `dt-column` data attribute, or be
9879
9919
  // a child or such an element
9880
9920
  var host = Dom.s(s).closest('*[data-dt-column]');
9881
- return host.count() ? [host.data('dt-column')] : [];
9921
+ return host.count() ? [parseInt(host.attr('data-dt-column'))] : [];
9882
9922
  };
9883
9923
  var selected = selectorRun('column', selector, run, settings, opts);
9884
9924
  return opts.columnOrder && opts.columnOrder === 'index'
@@ -10075,18 +10115,19 @@ registerPlural('columns().widths()', 'column().width()', function () {
10075
10115
  // Injects a fake row into the table for just a moment so the widths can
10076
10116
  // be read, regardless of colspan in the header and rows being present
10077
10117
  // in the body
10078
- var columns = this.columns(':visible').count();
10118
+ var columns = this.columns(':visible');
10079
10119
  var row = Dom
10080
10120
  .c('tr')
10081
- .html('<td>' + Array(columns).join('</td><td>') + '</td>');
10121
+ .html('<td>' + Array(columns.count()).join('</td><td>') + '</td>');
10082
10122
  Dom.s(this.table().body()).append(row);
10083
- var widths = row.children().mapTo(el => {
10084
- return Dom.s(el).width('outer');
10123
+ var widths = [];
10124
+ var indexes = columns.indexes();
10125
+ row.children().each((el, idx) => {
10126
+ widths[indexes[idx]] = Dom.s(el).width('outer');
10085
10127
  });
10086
10128
  row.remove();
10087
- return this.iterator('column', function (settings, column) {
10088
- var visIdx = columnIndexToVisible(settings, column);
10089
- return visIdx !== null ? widths[visIdx] : 0;
10129
+ return this.iterator('column', (settings, column) => {
10130
+ return widths[column] || 0;
10090
10131
  }, true);
10091
10132
  });
10092
10133
  registerPlural('columns().indexes()', 'column().index()', function (type) {
@@ -10207,7 +10248,7 @@ registerPlural('columns().orderable()', 'column().orderable()', function (direct
10207
10248
  /**
10208
10249
  * Set the page length
10209
10250
  *
10210
- * @param settings DataTables context
10251
+ * @param ctx DataTables context
10211
10252
  * @param val Value to change to
10212
10253
  */
10213
10254
  function lengthChange(ctx, val) {
@@ -10558,7 +10599,7 @@ function selectRows(settings, selector, opts) {
10558
10599
  }
10559
10600
  else {
10560
10601
  var host = Dom.s(sel).closest('*[data-dt-row]');
10561
- return host.count() ? [host.data('dt-row')] : [];
10602
+ return host.count() ? [parseInt(host.attr('data-dt-row'))] : [];
10562
10603
  }
10563
10604
  }
10564
10605
  // ID selector. Want to always be able to select rows by id, regardless
@@ -10590,8 +10631,7 @@ function selectRows(settings, selector, opts) {
10590
10631
  // Get nodes in the order from the `rows` array with null values removed
10591
10632
  var nodes = util.array.removeEmpty(util.array.pluckOrder(settings.data, rows, 'tr'));
10592
10633
  // Selector - selector string, array of nodes or jQuery object.
10593
- return Dom
10594
- .s(nodes)
10634
+ return Dom.s(nodes)
10595
10635
  .filter(sel)
10596
10636
  .mapTo((el) => el._DT_RowIndex);
10597
10637
  };
@@ -10736,7 +10776,7 @@ register('row().data()', function (data) {
10736
10776
  util.set(ctx[0].rowId)(data, row.tr.id);
10737
10777
  }
10738
10778
  // Automatically invalidate
10739
- invalidate(ctx[0], this[0], 'data');
10779
+ invalidate(ctx[0], this[0][0], 'data');
10740
10780
  return this;
10741
10781
  });
10742
10782
  register('row().node()', function () {
@@ -11054,10 +11094,10 @@ register('caption()', function (value, side) {
11054
11094
  caption.css('caption-side', side);
11055
11095
  caption.get(0)._captionSide = side;
11056
11096
  }
11057
- if (container.find('div.dataTables_scroll').count()) {
11058
- var selector = side === 'top' ? 'Head' : 'Foot';
11097
+ if (container.find('div.dt-scroll').count()) {
11098
+ var selector = side === 'top' ? 'head' : 'foot';
11059
11099
  container
11060
- .find('div.dataTables_scroll' + selector + ' table')
11100
+ .find('div.dt-scroll-' + selector + ' table')
11061
11101
  .prepend(caption);
11062
11102
  }
11063
11103
  else {
@@ -11070,6 +11110,280 @@ register('caption.node()', function () {
11070
11110
  return ctx.length ? ctx[0].captionNode : null;
11071
11111
  });
11072
11112
 
11113
+ /**
11114
+ * What's this!? "DataTables Plus" is a commercial set of extensions for
11115
+ * DataTables, such as Editor, and the functions in this file allow a license
11116
+ * key to be provided (`DataTable.key(...)`) to unlock those features.
11117
+ *
11118
+ * This is the modal that I've selected to make DataTables sustainable, open
11119
+ * source core, with some commercial extensions available.
11120
+ *
11121
+ * Please support DataTables and open source by purchasing a Plus license from
11122
+ * https://datatables.net/plus .
11123
+ */
11124
+ let _ready = false;
11125
+ let _notice;
11126
+ let _processingKey = false;
11127
+ let _delayedReleaseDate = null;
11128
+ let _delayedSoftware = null;
11129
+ const _licenseInfo = {
11130
+ developers: 0,
11131
+ type: null,
11132
+ expires: null,
11133
+ valid: null
11134
+ };
11135
+ const _wm = Dom.c('div');
11136
+ const _publicKey = 'BE1A9w9D9U/4s4/TogY+1sW/dLJ8IquzK1PmV70J93ZTIvXMZ0eV2NAb52ntpgwVFySSB2fOI7geLNO737rQAyo=';
11137
+ /**
11138
+ * Convert a base64 string to a binary array
11139
+ *
11140
+ * @param b64 Source string
11141
+ * @returns Array
11142
+ */
11143
+ function b64ToBuf(b64) {
11144
+ return Uint8Array.from(atob(b64), c => c.charCodeAt(0));
11145
+ }
11146
+ /**
11147
+ * Logic to check the trial and plus license expiry and display messages if
11148
+ * needed. There is particular consideration for checking a release date of
11149
+ * software, as the license for DataTables Plus is perpetual for the version
11150
+ * purchased, and it shouldn't show a message for the purchased version ever.
11151
+ *
11152
+ * @param releaseDate The date the software was released on.
11153
+ * @param software The software name being validated. Can be null for a general
11154
+ * "Plus" check.
11155
+ * @returns true if valid, false otherwise
11156
+ */
11157
+ function check(releaseDate, software) {
11158
+ let expires = _licenseInfo.expires;
11159
+ if (_licenseInfo.valid === false) {
11160
+ noticePrep('License key invalid');
11161
+ noticeDisplay();
11162
+ }
11163
+ else if (_licenseInfo.type === 'trial') {
11164
+ // Trail is for plus, so the software type isn't taken into account
11165
+ let remaining = expires
11166
+ ? Math.ceil((expires.getTime() - new Date().getTime()) / 86400000)
11167
+ : -1;
11168
+ if (remaining < 0) {
11169
+ // Trial expires
11170
+ consoleMsg('Your trial has now expired - https://datatables.net/plus', 'warn');
11171
+ noticePrep('Trial expired');
11172
+ noticeDisplay();
11173
+ return false;
11174
+ }
11175
+ else {
11176
+ // Let the user know when it is going to expire with a console
11177
+ // message.
11178
+ consoleMsg('Your trial expires in ' +
11179
+ remaining +
11180
+ ' day' +
11181
+ (remaining === 1 ? '' : 's'));
11182
+ return true;
11183
+ }
11184
+ }
11185
+ else if (software === null) {
11186
+ // Validating the key only - there hasn't been any specific software
11187
+ // calling the `plus` parameter yet. The key is good, so carry on.
11188
+ return true;
11189
+ }
11190
+ else if (
11191
+ // Checking if the build version can be used with this key
11192
+ _licenseInfo.type === 'plus' ||
11193
+ (_licenseInfo.type === 'editor' && software === 'editor')) {
11194
+ if (!expires || new Date(releaseDate) > expires) {
11195
+ noticePrep('Upgrade required for this version');
11196
+ noticeDisplay();
11197
+ return false;
11198
+ }
11199
+ return true;
11200
+ }
11201
+ else if (_licenseInfo.type === 'editor' && software !== 'editor') {
11202
+ // Editor specific license
11203
+ noticePrep('License for Editor only. Upgrade for Plus');
11204
+ noticeDisplay();
11205
+ return false;
11206
+ }
11207
+ noticePrep();
11208
+ noticeDisplay();
11209
+ return false;
11210
+ }
11211
+ /**
11212
+ * Common log message handling
11213
+ *
11214
+ * @param msg Message to show
11215
+ * @param level Log level
11216
+ */
11217
+ function consoleMsg(msg, level = 'log') {
11218
+ let fn = level === 'log' ? console.log : console.warn;
11219
+ fn('%cDataTables Plus%c ' + msg, 'background: #007bff; color: #fff; padding: 2px 5px;', 'color: inherit;');
11220
+ }
11221
+ /**
11222
+ * Set the DataTables Plus key to use
11223
+ *
11224
+ * @param key DataTables Plus key - obtain from https://datatables.net/account .
11225
+ */
11226
+ const key = function (key) {
11227
+ _processingKey = true;
11228
+ // Run the verification of the key
11229
+ verify(key)
11230
+ .then(result => {
11231
+ _processingKey = false;
11232
+ check(_delayedReleaseDate, _delayedSoftware);
11233
+ })
11234
+ .catch(() => {
11235
+ _processingKey = false;
11236
+ check(_delayedReleaseDate, _delayedSoftware);
11237
+ });
11238
+ };
11239
+ /**
11240
+ * Build the notice
11241
+ *
11242
+ * @returns
11243
+ */
11244
+ function noticePrep(text) {
11245
+ if (!_ready) {
11246
+ let shadow = _wm[0].attachShadow({ mode: 'closed' });
11247
+ let notice = Dom.c('div').css({
11248
+ position: 'fixed',
11249
+ bottom: '1em',
11250
+ right: '1em',
11251
+ border: '1px solid #ffc107',
11252
+ background: '#fff3cd',
11253
+ color: '#856404',
11254
+ padding: '0.5em 1em',
11255
+ 'font-family': 'sans-serif',
11256
+ 'font-size': '12px',
11257
+ 'border-radius': '4px',
11258
+ 'z-index': '10000',
11259
+ 'box-shadow': '0 2px 5px rgba(0,0,0,0.2)'
11260
+ });
11261
+ Dom.c('a')
11262
+ .attr('href', 'https://datatables.net/tn/25')
11263
+ .attr('target', '_blank')
11264
+ .css({
11265
+ color: 'inherit',
11266
+ 'text-decoration': 'none'
11267
+ })
11268
+ .appendTo(notice);
11269
+ if (!text) {
11270
+ text = 'License key required';
11271
+ }
11272
+ shadow.appendChild(notice[0]);
11273
+ _notice = notice;
11274
+ _ready = true;
11275
+ }
11276
+ if (text) {
11277
+ _notice
11278
+ .find('a')
11279
+ .html('DataTables Plus: ' + text + ' - learn more &#187;');
11280
+ }
11281
+ }
11282
+ /**
11283
+ * Display the license notice
11284
+ */
11285
+ function noticeDisplay() {
11286
+ if (!_processingKey && !document.body.contains(_wm[0])) {
11287
+ document.body.appendChild(_wm[0]);
11288
+ }
11289
+ }
11290
+ /**
11291
+ * Validate the license string, which is in two parts - the first is a payload
11292
+ * that provides a small amount of information about the license, and the second
11293
+ * which is the license key.
11294
+ *
11295
+ * @param licenseString Key to validate
11296
+ * @returns Promise with validation information
11297
+ */
11298
+ function verify(licenseString) {
11299
+ return new Promise(function (resolve) {
11300
+ try {
11301
+ var parts = licenseString.split(':');
11302
+ if (parts.length !== 2) {
11303
+ _licenseInfo.valid = false;
11304
+ return resolve();
11305
+ }
11306
+ var payload = parts[0];
11307
+ var signatureB64 = parts[1];
11308
+ // Backwards compat for old browsers
11309
+ var cryptoObj = window.crypto || window.msCrypto;
11310
+ var subtle = cryptoObj.subtle || cryptoObj.webkitSubtle;
11311
+ var rawKey = b64ToBuf(_publicKey);
11312
+ var rawSig = b64ToBuf(signatureB64);
11313
+ var data = new TextEncoder().encode(payload);
11314
+ subtle
11315
+ .importKey('raw', rawKey, { name: 'ECDSA', namedCurve: 'P-256' }, false, ['verify'])
11316
+ .then(function (key) {
11317
+ return subtle.verify({ name: 'ECDSA', hash: { name: 'SHA-256' } }, key, rawSig, data);
11318
+ })
11319
+ .then(function (isValid) {
11320
+ if (!isValid) {
11321
+ _licenseInfo.valid = false;
11322
+ return resolve();
11323
+ }
11324
+ // Extract the payload to be useful
11325
+ var payloadParts = payload.match(/(plus|trial|editor)_(\d+)_(\d{4})(\d{2})(\d{2})/);
11326
+ if (!payloadParts || payloadParts.length !== 6) {
11327
+ _licenseInfo.valid = false;
11328
+ return resolve();
11329
+ }
11330
+ _licenseInfo.valid = true;
11331
+ _licenseInfo.type = payloadParts[1];
11332
+ _licenseInfo.developers = parseInt(payloadParts[2]);
11333
+ _licenseInfo.expires = new Date(payloadParts[3] +
11334
+ '-' +
11335
+ payloadParts[4] +
11336
+ '-' +
11337
+ payloadParts[5]);
11338
+ resolve();
11339
+ })
11340
+ .catch(function () {
11341
+ _licenseInfo.valid = false;
11342
+ resolve();
11343
+ });
11344
+ }
11345
+ catch (e) {
11346
+ _licenseInfo.valid = false;
11347
+ resolve();
11348
+ }
11349
+ });
11350
+ }
11351
+ /**
11352
+ * Create the `plus` function on `DataTable` which Plus extensions can call to
11353
+ * determine if the license key is valid and in date for the release. The
11354
+ * resulting function is called like this: `DataTable.plus('2026-12-25')` and
11355
+ * will return `true` or `false` depending on the key that was given (or not).
11356
+ *
11357
+ * @param DataTable The DataTable host object
11358
+ */
11359
+ function plus (DataTable) {
11360
+ Object.defineProperty(DataTable, 'plus', {
11361
+ value: function (releaseDate, software = '') {
11362
+ // Unsecure sites are only useful for development, so allow there
11363
+ // and on the site.
11364
+ let host = window.location.hostname;
11365
+ let isDev = host === '192.168.234.234' ||
11366
+ host.endsWith('.datatables.net') ||
11367
+ host === 'datatables.net';
11368
+ if (isDev) {
11369
+ return true;
11370
+ }
11371
+ if (_processingKey) {
11372
+ // The validation of the key is async, so there is a chance that
11373
+ // it could still be happening when this runs. We just queue the
11374
+ // last one if that is the case.
11375
+ _delayedReleaseDate = releaseDate;
11376
+ _delayedSoftware = software;
11377
+ return true;
11378
+ }
11379
+ return check(releaseDate, software);
11380
+ },
11381
+ configurable: false,
11382
+ enumerable: false,
11383
+ writable: false
11384
+ });
11385
+ }
11386
+
11073
11387
  /**
11074
11388
  * CommonJS factory function pass through. This will check if the arguments
11075
11389
  * given are a window object or a jQuery object. If so they are set accordingly.
@@ -11195,6 +11509,8 @@ register$2('info', function (settings, optsIn) {
11195
11509
  /**
11196
11510
  * Update the information elements in the display
11197
11511
  * @param settings DataTables settings object
11512
+ * @param opts
11513
+ * @param node
11198
11514
  */
11199
11515
  function updateInfo(settings, opts, node) {
11200
11516
  var start = settings.displayStart + 1, end = displayEnd(settings), max = recordsTotal(settings), total = recordsDisplay(settings), out = total ? opts.text : opts.empty;
@@ -11267,7 +11583,7 @@ function _pagingDraw(settings, host, opts) {
11267
11583
  if (!settings.initDone) {
11268
11584
  return;
11269
11585
  }
11270
- 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) {
11586
+ 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) {
11271
11587
  return val === 'numbers'
11272
11588
  ? pagingNumbers(page, pages, opts.buttons, opts.boundaryNumbers)
11273
11589
  : val;
@@ -11429,8 +11745,7 @@ register$2('pageLength', function (settings, optsIn) {
11429
11745
  }
11430
11746
  // Wrapper element - use a span as a holder for where the select will go
11431
11747
  var tmpId = 'tmp-' + +new Date();
11432
- var div = Dom
11433
- .c('div')
11748
+ var div = Dom.c('div')
11434
11749
  .classAdd(classes.container)
11435
11750
  .html(str.replace('_MENU_', '<span id="' + tmpId + '"></span>'));
11436
11751
  // Save text node content for macro updating
@@ -11452,9 +11767,9 @@ register$2('pageLength', function (settings, optsIn) {
11452
11767
  });
11453
11768
  };
11454
11769
  // Next, the select itself, along with the options
11455
- var select = Dom
11456
- .c('select')
11770
+ var select = Dom.c('select')
11457
11771
  .attr('aria-controls', tableId)
11772
+ .attr('autocomplete', 'off')
11458
11773
  .classAdd(classes.select);
11459
11774
  for (i = 0; i < lengths.length; i++) {
11460
11775
  // Attempt to look up the length from the i18n options
@@ -11485,7 +11800,26 @@ register$2('pageLength', function (settings, optsIn) {
11485
11800
  // Update node value whenever anything changes the table's length
11486
11801
  Dom.s(settings.table).on('length.dt.DT', function (e, s, len) {
11487
11802
  if (settings === s) {
11488
- div.find('select').val(len);
11803
+ let localSelect = div.find('select');
11804
+ // Remove any temporary values
11805
+ localSelect.find('option[data-dt-len-tmp]').remove();
11806
+ let option = localSelect.find('option[value="' + len + '"]');
11807
+ // If the select list doesn't have the target value, then we
11808
+ // need to add it for display.
11809
+ if (!option.length) {
11810
+ let after = findInsertBeforePoint(select, len);
11811
+ let tempOption = Dom.c('option')
11812
+ .val(len)
11813
+ .text(len)
11814
+ .attr('data-dt-len-tmp', true);
11815
+ if (after && after.length) {
11816
+ tempOption.insertBefore(after);
11817
+ }
11818
+ else {
11819
+ localSelect.append(tempOption);
11820
+ }
11821
+ }
11822
+ localSelect.val(len);
11489
11823
  // Resolve plurals in the text for the new length
11490
11824
  updateEntries(len);
11491
11825
  }
@@ -11493,6 +11827,19 @@ register$2('pageLength', function (settings, optsIn) {
11493
11827
  updateEntries(settings.pageLength);
11494
11828
  return div;
11495
11829
  }, 'l');
11830
+ /**
11831
+ * Find the element to insert the temporary option before to keep the sequence.
11832
+ *
11833
+ * @param select Select element
11834
+ * @param insertValue Page length value
11835
+ * @returns Target option or null if not found
11836
+ */
11837
+ function findInsertBeforePoint(select, insertValue) {
11838
+ let options = select.find('option');
11839
+ let values = options.mapTo(el => parseInt(el.value));
11840
+ let idx = values.findIndex(val => val > insertValue);
11841
+ return idx < -1 ? null : options.eq(idx);
11842
+ }
11496
11843
 
11497
11844
  let __searchCounter = 0;
11498
11845
  register$2('search', function (settings, optsIn) {
@@ -11503,7 +11850,9 @@ register$2('search', function (settings, optsIn) {
11503
11850
  let classes = settings.classes.search;
11504
11851
  let tableId = settings.tableId;
11505
11852
  let language = settings.language;
11506
- let input = '<input type="search" class="' + classes.input + '"/>';
11853
+ let input = '<input type="search" class="' +
11854
+ classes.input +
11855
+ '" autocomplete="off"/>';
11507
11856
  let opts = util.object.assignDeep({
11508
11857
  columns: '*',
11509
11858
  placeholder: language.searchPlaceholder,
@@ -11903,7 +12252,8 @@ const defaults = {
11903
12252
  },
11904
12253
  stateSaveParams: null,
11905
12254
  tabIndex: 0,
11906
- titleRow: null
12255
+ titleRow: null,
12256
+ typeDetect: true
11907
12257
  };
11908
12258
 
11909
12259
  const DataTable = function (selector, options) {
@@ -12325,6 +12675,8 @@ DataTable.datetime = datetime;
12325
12675
  DataTable.__browser = browser;
12326
12676
  DataTable.Dom = Dom;
12327
12677
  DataTable.ajax = util.ajax;
12678
+ DataTable.key = key;
12679
+ plus(DataTable);
12328
12680
  /**
12329
12681
  * Private data store, containing all of the settings objects that are created
12330
12682
  * for the tables on a given page.