oxidized-web 0.15.1 → 0.17.0

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.

Potentially problematic release.


This version of oxidized-web might be problematic. Click here for more details.

Files changed (50) hide show
  1. checksums.yaml +4 -4
  2. data/.gitignore +4 -0
  3. data/.rubocop.yml +22 -2
  4. data/CHANGELOG.md +30 -1
  5. data/README.md +13 -3
  6. data/Rakefile +9 -4
  7. data/docs/configuration.md +90 -0
  8. data/docs/development.md +42 -39
  9. data/lib/oxidized/web/public/scripts/oxidized.js +13 -13
  10. data/lib/oxidized/web/public/weblibs/bootstrap-icons.css +31 -3
  11. data/lib/oxidized/web/public/weblibs/bootstrap.bundle.js +20 -19
  12. data/lib/oxidized/web/public/weblibs/bootstrap.bundle.js.map +1 -1
  13. data/lib/oxidized/web/public/weblibs/bootstrap.css +110 -124
  14. data/lib/oxidized/web/public/weblibs/bootstrap.css.map +1 -1
  15. data/lib/oxidized/web/public/weblibs/bootstrap.js +20 -17
  16. data/lib/oxidized/web/public/weblibs/bootstrap.js.map +1 -1
  17. data/lib/oxidized/web/public/weblibs/buttons.bootstrap5.css +3 -3
  18. data/lib/oxidized/web/public/weblibs/buttons.colVis.js +14 -5
  19. data/lib/oxidized/web/public/weblibs/dataTables.bootstrap5.css +111 -17
  20. data/lib/oxidized/web/public/weblibs/dataTables.buttons.js +25 -7
  21. data/lib/oxidized/web/public/weblibs/dataTables.js +336 -106
  22. data/lib/oxidized/web/public/weblibs/dayjs-plugin-utc.min.js +1 -0
  23. data/lib/oxidized/web/public/weblibs/dayjs.min.js +1 -0
  24. data/lib/oxidized/web/public/weblibs/fonts/bootstrap-icons.woff +0 -0
  25. data/lib/oxidized/web/public/weblibs/fonts/bootstrap-icons.woff2 +0 -0
  26. data/lib/oxidized/web/version.rb +1 -1
  27. data/lib/oxidized/web/views/conf_search.haml +1 -1
  28. data/lib/oxidized/web/views/diffs.haml +6 -7
  29. data/lib/oxidized/web/views/head.haml +4 -0
  30. data/lib/oxidized/web/views/node.haml +3 -2
  31. data/lib/oxidized/web/views/nodes.haml +13 -5
  32. data/lib/oxidized/web/views/stats.haml +11 -3
  33. data/lib/oxidized/web/views/version.haml +1 -2
  34. data/lib/oxidized/web/views/versions.haml +11 -7
  35. data/lib/oxidized/web/webapp.rb +41 -29
  36. data/lib/oxidized/web.rb +72 -16
  37. data/oxidized-web.gemspec +22 -13
  38. data/package-lock.json +37 -25
  39. data/package.json +7 -5
  40. data/spec/spec_helper.rb +1 -0
  41. data/spec/web/node/show_spec.rb +100 -0
  42. data/spec/web/node/version_spec.rb +161 -0
  43. data/spec/{node_spec.rb → web/node_spec.rb} +1 -1
  44. data/spec/{nodes_spec.rb → web/nodes_spec.rb} +1 -1
  45. data/spec/{root_spec.rb → web/root_spec.rb} +1 -1
  46. data/spec/{webapp_spec.rb → web/webapp_spec.rb} +1 -1
  47. data/spec/web_spec.rb +98 -0
  48. metadata +69 -69
  49. data/.rubocop_todo.yml +0 -64
  50. data/spec/node_version_spec.rb +0 -102
@@ -1,4 +1,4 @@
1
- /*! DataTables 2.2.2
1
+ /*! DataTables 2.3.2
2
2
  * © SpryMedia Ltd - datatables.net/license
3
3
  */
4
4
 
@@ -89,15 +89,19 @@
89
89
  var defaults = DataTable.defaults;
90
90
  var $this = $(this);
91
91
 
92
-
93
- /* Sanity check */
92
+ // Sanity check
94
93
  if ( this.nodeName.toLowerCase() != 'table' )
95
94
  {
96
95
  _fnLog( null, 0, 'Non-table node initialisation ('+this.nodeName+')', 2 );
97
96
  return;
98
97
  }
99
98
 
100
- $(this).trigger( 'options.dt', oInit );
99
+ // Special case for options
100
+ if (oInit.on && oInit.on.options) {
101
+ _fnListener($this, 'options', oInit.on.options);
102
+ }
103
+
104
+ $this.trigger( 'options.dt', oInit );
101
105
 
102
106
  /* Backwards compatibility for the defaults */
103
107
  _fnCompatOpts( defaults );
@@ -108,7 +112,7 @@
108
112
  _fnCamelToHungarian( defaults.column, defaults.column, true );
109
113
 
110
114
  /* Setting up the initialisation object */
111
- _fnCamelToHungarian( defaults, $.extend( oInit, $this.data() ), true );
115
+ _fnCamelToHungarian( defaults, $.extend( oInit, _fnEscapeObject($this.data()) ), true );
112
116
 
113
117
 
114
118
 
@@ -236,6 +240,9 @@
236
240
  "caption",
237
241
  "layout",
238
242
  "orderDescReverse",
243
+ "orderIndicators",
244
+ "orderHandler",
245
+ "titleRow",
239
246
  "typeDetect",
240
247
  [ "iCookieDuration", "iStateDuration" ], // backwards compat
241
248
  [ "oSearch", "oPreviousSearch" ],
@@ -264,6 +271,13 @@
264
271
 
265
272
  oSettings.rowIdFn = _fnGetObjectDataFn( oInit.rowId );
266
273
 
274
+ // Add event listeners
275
+ if (oInit.on) {
276
+ Object.keys(oInit.on).forEach(function (key) {
277
+ _fnListener($this, key, oInit.on[key]);
278
+ });
279
+ }
280
+
267
281
  /* Browser support detection */
268
282
  _fnBrowserDetect( oSettings );
269
283
 
@@ -324,7 +338,7 @@
324
338
  /* HTML5 attribute detection - build an mData object automatically if the
325
339
  * attributes are found
326
340
  */
327
- var rowOne = $this.children('tbody').find('tr').eq(0);
341
+ var rowOne = $this.children('tbody').find('tr:first-child').eq(0);
328
342
 
329
343
  if ( rowOne.length ) {
330
344
  var a = function ( cell, name ) {
@@ -482,6 +496,13 @@
482
496
  * @namespace
483
497
  */
484
498
  DataTable.ext = _ext = {
499
+ /**
500
+ * DataTables build type (expanded by the download builder)
501
+ *
502
+ * @type string
503
+ */
504
+ builder: "-source-",
505
+
485
506
  /**
486
507
  * Buttons. For use with the Buttons extension for DataTables. This is
487
508
  * defined here so other extensions can define buttons regardless of load
@@ -494,20 +515,20 @@
494
515
 
495
516
 
496
517
  /**
497
- * Element class names
518
+ * ColumnControl buttons and content
498
519
  *
499
520
  * @type object
500
- * @default {}
501
521
  */
502
- classes: {},
522
+ ccContent: {},
503
523
 
504
524
 
505
525
  /**
506
- * DataTables build type (expanded by the download builder)
526
+ * Element class names
507
527
  *
508
- * @type string
528
+ * @type object
529
+ * @default {}
509
530
  */
510
- builder: "-source-",
531
+ classes: {},
511
532
 
512
533
 
513
534
  /**
@@ -521,6 +542,11 @@
521
542
  */
522
543
  errMode: "alert",
523
544
 
545
+ /** HTML entity escaping */
546
+ escape: {
547
+ /** When reading data-* attributes for initialisation options */
548
+ attributes: false
549
+ },
524
550
 
525
551
  /**
526
552
  * Legacy so v1 plug-ins don't throw js errors on load
@@ -1875,6 +1901,26 @@
1875
1901
  init.scrollX = init.scrollX ? '100%' : '';
1876
1902
  }
1877
1903
 
1904
+ // Objects for ordering
1905
+ if ( typeof init.bSort === 'object' ) {
1906
+ init.orderIndicators = init.bSort.indicators !== undefined ? init.bSort.indicators : true;
1907
+ init.orderHandler = init.bSort.handler !== undefined ? init.bSort.handler : true;
1908
+ init.bSort = true;
1909
+ }
1910
+ else if (init.bSort === false) {
1911
+ init.orderIndicators = false;
1912
+ init.orderHandler = false;
1913
+ }
1914
+ else if (init.bSort === true) {
1915
+ init.orderIndicators = true;
1916
+ init.orderHandler = true;
1917
+ }
1918
+
1919
+ // Which cells are the title cells?
1920
+ if (typeof init.bSortCellsTop === 'boolean') {
1921
+ init.titleRow = init.bSortCellsTop;
1922
+ }
1923
+
1878
1924
  // Column search objects are in an array, so it needs to be converted
1879
1925
  // element by element
1880
1926
  var searchCols = init.aoSearchCols;
@@ -3252,7 +3298,7 @@
3252
3298
  * @param {*} settings DataTables settings
3253
3299
  * @param {*} source Source layout array
3254
3300
  * @param {*} incColumns What columns should be included
3255
- * @returns Layout array
3301
+ * @returns Layout array in column index order
3256
3302
  */
3257
3303
  function _fnHeaderLayout( settings, source, incColumns )
3258
3304
  {
@@ -3536,7 +3582,9 @@
3536
3582
 
3537
3583
  _fnDraw( settings );
3538
3584
 
3539
- settings._drawHold = false;
3585
+ settings.api.one('draw', function () {
3586
+ settings._drawHold = false;
3587
+ });
3540
3588
  }
3541
3589
 
3542
3590
 
@@ -3548,10 +3596,9 @@
3548
3596
  var zero = oLang.sZeroRecords;
3549
3597
  var dataSrc = _fnDataSource( settings );
3550
3598
 
3551
- if (
3552
- (settings.iDraw < 1 && dataSrc === 'ssp') ||
3553
- (settings.iDraw <= 1 && dataSrc === 'ajax')
3554
- ) {
3599
+ // Make use of the fact that settings.json is only set once the initial data has
3600
+ // been loaded. Show loading when that isn't the case
3601
+ if ((dataSrc === 'ssp' || dataSrc === 'ajax') && ! settings.json) {
3555
3602
  zero = oLang.sLoadingRecords;
3556
3603
  }
3557
3604
  else if ( oLang.sEmptyTable && settings.fnRecordsTotal() === 0 )
@@ -3921,6 +3968,7 @@
3921
3968
  var rows = $(thead).children('tr');
3922
3969
  var row, cell;
3923
3970
  var i, k, l, iLen, shifted, column, colspan, rowspan;
3971
+ var titleRow = settings.titleRow;
3924
3972
  var isHeader = thead && thead.nodeName.toLowerCase() === 'thead';
3925
3973
  var layout = [];
3926
3974
  var unique;
@@ -3949,6 +3997,7 @@
3949
3997
  cell.nodeName.toUpperCase() == 'TH'
3950
3998
  ) {
3951
3999
  var cols = [];
4000
+ var jqCell = $(cell);
3952
4001
 
3953
4002
  // Get the col and rowspan attributes from the DOM and sanitise them
3954
4003
  colspan = cell.getAttribute('colspan') * 1;
@@ -3969,7 +4018,7 @@
3969
4018
  if ( write ) {
3970
4019
  if (unique) {
3971
4020
  // Allow column options to be set from HTML attributes
3972
- _fnColumnOptions( settings, shifted, $(cell).data() );
4021
+ _fnColumnOptions( settings, shifted, _fnEscapeObject(jqCell.data()) );
3973
4022
 
3974
4023
  // Get the width for the column. This can be defined from the
3975
4024
  // width attribute, style attribute or `columns.width` option
@@ -3986,7 +4035,14 @@
3986
4035
  // Column title handling - can be user set, or read from the DOM
3987
4036
  // This happens before the render, so the original is still in place
3988
4037
  if ( columnDef.sTitle !== null && ! columnDef.autoTitle ) {
3989
- cell.innerHTML = columnDef.sTitle;
4038
+ if (
4039
+ (titleRow === true && i === 0) || // top row
4040
+ (titleRow === false && i === rows.length -1) || // bottom row
4041
+ (titleRow === i) || // specific row
4042
+ (titleRow === null)
4043
+ ) {
4044
+ cell.innerHTML = columnDef.sTitle;
4045
+ }
3990
4046
  }
3991
4047
 
3992
4048
  if (! columnDef.sTitle && unique) {
@@ -4004,12 +4060,12 @@
4004
4060
  // Fall back to the aria-label attribute on the table header if no ariaTitle is
4005
4061
  // provided.
4006
4062
  if (! columnDef.ariaTitle) {
4007
- columnDef.ariaTitle = $(cell).attr("aria-label") || columnDef.sTitle;
4063
+ columnDef.ariaTitle = jqCell.attr("aria-label") || columnDef.sTitle;
4008
4064
  }
4009
4065
 
4010
4066
  // Column specific class names
4011
4067
  if ( columnDef.className ) {
4012
- $(cell).addClass( columnDef.className );
4068
+ jqCell.addClass( columnDef.className );
4013
4069
  }
4014
4070
  }
4015
4071
 
@@ -4021,11 +4077,28 @@
4021
4077
  .appendTo(cell);
4022
4078
  }
4023
4079
 
4024
- if ( isHeader && $('span.dt-column-order', cell).length === 0) {
4080
+ if (
4081
+ settings.orderIndicators &&
4082
+ isHeader &&
4083
+ jqCell.filter(':not([data-dt-order=disable])').length !== 0 &&
4084
+ jqCell.parent(':not([data-dt-order=disable])').length !== 0 &&
4085
+ $('span.dt-column-order', cell).length === 0
4086
+ ) {
4025
4087
  $('<span>')
4026
4088
  .addClass('dt-column-order')
4027
4089
  .appendTo(cell);
4028
4090
  }
4091
+
4092
+ // We need to wrap the elements in the header in another element to use flexbox
4093
+ // layout for those elements
4094
+ var headerFooter = isHeader ? 'header' : 'footer';
4095
+
4096
+ if ( $('span.dt-column-' + headerFooter, cell).length === 0) {
4097
+ $('<div>')
4098
+ .addClass('dt-column-' + headerFooter)
4099
+ .append(cell.childNodes)
4100
+ .appendTo(cell);
4101
+ }
4029
4102
  }
4030
4103
 
4031
4104
  // If there is col / rowspan, copy the information into the layout grid
@@ -4176,6 +4249,11 @@
4176
4249
  // Allow plug-ins and external processes to modify the data
4177
4250
  _fnCallbackFire( oSettings, null, 'preXhr', [oSettings, data, baseAjax], true );
4178
4251
 
4252
+ // Custom Ajax option to submit the parameters as a JSON string
4253
+ if (baseAjax.submitAs === 'json' && typeof data === 'object') {
4254
+ baseAjax.data = JSON.stringify(data);
4255
+ }
4256
+
4179
4257
  if ( typeof ajax === 'function' )
4180
4258
  {
4181
4259
  // Is a function - let the caller define what needs to be done
@@ -4186,7 +4264,7 @@
4186
4264
  // to the object for the callback.
4187
4265
  var empty = {};
4188
4266
 
4189
- DataTable.util.set(ajax.dataSrc)(empty, []);
4267
+ _fnAjaxDataSrc(oSettings, empty, []);
4190
4268
  callback(empty);
4191
4269
  }
4192
4270
  else {
@@ -5676,24 +5754,30 @@
5676
5754
  function _fnSortInit( settings ) {
5677
5755
  var target = settings.nTHead;
5678
5756
  var headerRows = target.querySelectorAll('tr');
5679
- var legacyTop = settings.bSortCellsTop;
5757
+ var titleRow = settings.titleRow;
5680
5758
  var notSelector = ':not([data-dt-order="disable"]):not([data-dt-order="icon-only"])';
5681
5759
 
5682
5760
  // Legacy support for `orderCellsTop`
5683
- if (legacyTop === true) {
5761
+ if (titleRow === true) {
5684
5762
  target = headerRows[0];
5685
5763
  }
5686
- else if (legacyTop === false) {
5764
+ else if (titleRow === false) {
5687
5765
  target = headerRows[ headerRows.length - 1 ];
5688
5766
  }
5767
+ else if (titleRow !== null) {
5768
+ target = headerRows[titleRow];
5769
+ }
5770
+ // else - all rows
5689
5771
 
5690
- _fnSortAttachListener(
5691
- settings,
5692
- target,
5693
- target === settings.nTHead
5694
- ? 'tr'+notSelector+' th'+notSelector+', tr'+notSelector+' td'+notSelector
5695
- : 'th'+notSelector+', td'+notSelector
5696
- );
5772
+ if (settings.orderHandler) {
5773
+ _fnSortAttachListener(
5774
+ settings,
5775
+ target,
5776
+ target === settings.nTHead
5777
+ ? 'tr'+notSelector+' th'+notSelector+', tr'+notSelector+' td'+notSelector
5778
+ : 'th'+notSelector+', td'+notSelector
5779
+ );
5780
+ }
5697
5781
 
5698
5782
  // Need to resolve the user input array into our internal structure
5699
5783
  var order = [];
@@ -5708,7 +5792,11 @@
5708
5792
  var run = false;
5709
5793
  var columns = column === undefined
5710
5794
  ? _fnColumnsFromHeader( e.target )
5711
- : [column];
5795
+ : typeof column === 'function'
5796
+ ? column()
5797
+ : Array.isArray(column)
5798
+ ? column
5799
+ : [column];
5712
5800
 
5713
5801
  if ( columns.length ) {
5714
5802
  for ( var i=0, ien=columns.length ; i<ien ; i++ ) {
@@ -6331,16 +6419,19 @@
6331
6419
 
6332
6420
  // A column name was stored and should be used for restore
6333
6421
  if (typeof col[0] === 'string') {
6422
+ // Find the name from the current list of column names
6334
6423
  var idx = currentNames.indexOf(col[0]);
6335
6424
 
6336
- // Find the name from the current list of column names, or fallback to index 0
6337
- set[0] = idx >= 0
6338
- ? idx
6339
- : 0;
6425
+ if (idx < 0) {
6426
+ // If the column was not found ignore it and continue
6427
+ return;
6428
+ }
6429
+
6430
+ set[0] = idx;
6340
6431
  }
6341
6432
  else if (set[0] >= columns.length) {
6342
- // If a column name, but it is out of bounds, set to 0
6343
- set[0] = 0;
6433
+ // If the column index is out of bounds ignore it and continue
6434
+ return;
6344
6435
  }
6345
6436
 
6346
6437
  settings.aaSorting.push(set);
@@ -6753,6 +6844,36 @@
6753
6844
  }
6754
6845
  }
6755
6846
 
6847
+ /**
6848
+ * Add one or more listeners to the table
6849
+ *
6850
+ * @param {*} that JQ for the table
6851
+ * @param {*} name Event name
6852
+ * @param {*} src Listener(s)
6853
+ */
6854
+ function _fnListener(that, name, src) {
6855
+ if (!Array.isArray(src)) {
6856
+ src = [src];
6857
+ }
6858
+
6859
+ for (i=0 ; i<src.length ; i++) {
6860
+ that.on(name + '.dt', src[i]);
6861
+ }
6862
+ }
6863
+
6864
+ /**
6865
+ * Escape HTML entities in strings, in an object
6866
+ */
6867
+ function _fnEscapeObject(obj) {
6868
+ if (DataTable.ext.escape.attributes) {
6869
+ $.each(obj, function (key, val) {
6870
+ obj[key] = _escapeHtml(val);
6871
+ })
6872
+ }
6873
+
6874
+ return obj;
6875
+ }
6876
+
6756
6877
 
6757
6878
 
6758
6879
  /**
@@ -7409,12 +7530,24 @@
7409
7530
  ['footer', 'aoFooter'],
7410
7531
  ].forEach(function (item) {
7411
7532
  _api_register( 'table().' + item[0] + '.structure()' , function (selector) {
7412
- var indexes = this.columns(selector).indexes().flatten();
7533
+ var indexes = this.columns(selector).indexes().flatten().toArray();
7413
7534
  var ctx = this.context[0];
7414
-
7415
- return _fnHeaderLayout(ctx, ctx[item[1]], indexes);
7416
- } );
7417
- })
7535
+ var structure = _fnHeaderLayout(ctx, ctx[item[1]], indexes);
7536
+
7537
+ // The structure is in column index order - but from this method we want the return to be
7538
+ // in the columns() selector API order. In order to do that we need to map from one form
7539
+ // to the other
7540
+ var orderedIndexes = indexes.slice().sort(function (a, b) {
7541
+ return a - b;
7542
+ });
7543
+
7544
+ return structure.map(function (row) {
7545
+ return indexes.map(function (colIdx) {
7546
+ return row[orderedIndexes.indexOf(colIdx)];
7547
+ });
7548
+ });
7549
+ });
7550
+ });
7418
7551
 
7419
7552
 
7420
7553
  _api_registerPlural( 'tables().containers()', 'table().container()' , function () {
@@ -7763,7 +7896,7 @@
7763
7896
  {
7764
7897
  var
7765
7898
  out = [], res,
7766
- a, i, ien, j, jen,
7899
+ i, ien,
7767
7900
  selectorType = typeof selector;
7768
7901
 
7769
7902
  // Can't just check for isArray here, as an API or jQuery instance might be
@@ -7773,22 +7906,15 @@
7773
7906
  }
7774
7907
 
7775
7908
  for ( i=0, ien=selector.length ; i<ien ; i++ ) {
7776
- // Only split on simple strings - complex expressions will be jQuery selectors
7777
- a = selector[i] && selector[i].split && ! selector[i].match(/[[(:]/) ?
7778
- selector[i].split(',') :
7779
- [ selector[i] ];
7909
+ res = selectFn( typeof selector[i] === 'string' ? selector[i].trim() : selector[i] );
7780
7910
 
7781
- for ( j=0, jen=a.length ; j<jen ; j++ ) {
7782
- res = selectFn( typeof a[j] === 'string' ? (a[j]).trim() : a[j] );
7783
-
7784
- // Remove empty items
7785
- res = res.filter( function (item) {
7786
- return item !== null && item !== undefined;
7787
- });
7911
+ // Remove empty items
7912
+ res = res.filter( function (item) {
7913
+ return item !== null && item !== undefined;
7914
+ });
7788
7915
 
7789
- if ( res && res.length ) {
7790
- out = out.concat( res );
7791
- }
7916
+ if ( res && res.length ) {
7917
+ out = out.concat( res );
7792
7918
  }
7793
7919
  }
7794
7920
 
@@ -7817,6 +7943,7 @@
7817
7943
  }
7818
7944
 
7819
7945
  return $.extend( {
7946
+ columnOrder: 'implied',
7820
7947
  search: 'none',
7821
7948
  order: 'current',
7822
7949
  page: 'all'
@@ -8578,23 +8705,60 @@
8578
8705
 
8579
8706
  var __column_header = function ( settings, column, row ) {
8580
8707
  var header = settings.aoHeader;
8581
- var target = row !== undefined
8582
- ? row
8583
- : settings.bSortCellsTop // legacy support
8584
- ? 0
8585
- : header.length - 1;
8708
+ var titleRow = settings.titleRow;
8709
+ var target = null;
8710
+
8711
+ if (row !== undefined) {
8712
+ target = row;
8713
+ }
8714
+ else if (titleRow === true) { // legacy orderCellsTop support
8715
+ target = 0;
8716
+ }
8717
+ else if (titleRow === false) {
8718
+ target = header.length - 1;
8719
+ }
8720
+ else if (titleRow !== null) {
8721
+ target = titleRow;
8722
+ }
8723
+ else {
8724
+ // Automatic - find the _last_ unique cell from the top that is not empty (last for
8725
+ // backwards compatibility)
8726
+ for (var i=0 ; i<header.length ; i++) {
8727
+ if (header[i][column].unique && $('span.dt-column-title', header[i][column].cell).text()) {
8728
+ target = i;
8729
+ }
8730
+ }
8731
+
8732
+ if (target === null) {
8733
+ target = 0;
8734
+ }
8735
+ }
8586
8736
 
8587
8737
  return header[target][column].cell;
8588
8738
  };
8589
8739
 
8740
+ var __column_header_cells = function (header) {
8741
+ var out = [];
8742
+
8743
+ for (var i=0 ; i<header.length ; i++) {
8744
+ for (var j=0 ; j<header[i].length ; j++) {
8745
+ var cell = header[i][j].cell;
8746
+
8747
+ if (!out.includes(cell)) {
8748
+ out.push(cell);
8749
+ }
8750
+ }
8751
+ }
8752
+
8753
+ return out;
8754
+ }
8755
+
8590
8756
  var __column_selector = function ( settings, selector, opts )
8591
8757
  {
8592
8758
  var
8593
8759
  columns = settings.aoColumns,
8594
- names = _pluck( columns, 'sName' ),
8595
- titles = _pluck( columns, 'sTitle' ),
8596
- cells = DataTable.util.get('[].[].cell')(settings.aoHeader),
8597
- nodes = _unique( _flatten([], cells) );
8760
+ names, titles,
8761
+ nodes = __column_header_cells(settings.aoHeader);
8598
8762
 
8599
8763
  var run = function ( s ) {
8600
8764
  var selInt = _intVal( s );
@@ -8666,12 +8830,21 @@
8666
8830
  } );
8667
8831
 
8668
8832
  case 'name':
8833
+ // Don't get names, unless needed, and only get once if it is
8834
+ if (!names) {
8835
+ names = _pluck( columns, 'sName' );
8836
+ }
8837
+
8669
8838
  // match by name. `names` is column index complete and in order
8670
8839
  return names.map( function (name, i) {
8671
8840
  return name === match[1] ? i : null;
8672
8841
  } );
8673
8842
 
8674
8843
  case 'title':
8844
+ if (!titles) {
8845
+ titles = _pluck( columns, 'sTitle' );
8846
+ }
8847
+
8675
8848
  // match by column title
8676
8849
  return titles.map( function (title, i) {
8677
8850
  return title === match[1] ? i : null;
@@ -8710,7 +8883,11 @@
8710
8883
  [];
8711
8884
  };
8712
8885
 
8713
- return _selector_run( 'column', selector, run, settings, opts );
8886
+ var selected = _selector_run( 'column', selector, run, settings, opts );
8887
+
8888
+ return opts.columnOrder && opts.columnOrder === 'index'
8889
+ ? selected.sort(function (a, b) { return a - b; })
8890
+ : selected; // implied
8714
8891
  };
8715
8892
 
8716
8893
 
@@ -8834,6 +9011,12 @@
8834
9011
  }, 1 );
8835
9012
  } );
8836
9013
 
9014
+ _api_registerPlural( 'columns().names()', 'column().name()', function () {
9015
+ return this.iterator( 'column', function ( settings, column ) {
9016
+ return settings.aoColumns[column].sName;
9017
+ }, 1 );
9018
+ } );
9019
+
8837
9020
  _api_registerPlural( 'columns().nodes()', 'column().nodes()', function () {
8838
9021
  return this.iterator( 'column-rows', function ( settings, column, i, j, rows ) {
8839
9022
  return _pluck_order( settings.aoData, rows, 'anCells', column ) ;
@@ -9260,7 +9443,10 @@
9260
9443
  // otherwise a 2D array was passed in
9261
9444
 
9262
9445
  return this.iterator( 'table', function ( settings ) {
9263
- settings.aaSorting = Array.isArray(order) ? order.slice() : order;
9446
+ var resolved = [];
9447
+ _fnSortResolve(settings, resolved, order);
9448
+
9449
+ settings.aaSorting = resolved;
9264
9450
  } );
9265
9451
  } );
9266
9452
 
@@ -9386,7 +9572,7 @@
9386
9572
  var fixed = settings.searchFixed;
9387
9573
 
9388
9574
  if (! name) {
9389
- return Object.keys(fixed)
9575
+ return Object.keys(fixed);
9390
9576
  }
9391
9577
  else if (search === undefined) {
9392
9578
  return fixed[name];
@@ -9453,10 +9639,10 @@
9453
9639
  var fixed = settings.aoColumns[colIdx].searchFixed;
9454
9640
 
9455
9641
  if (! name) {
9456
- return Object.keys(fixed)
9642
+ return Object.keys(fixed);
9457
9643
  }
9458
9644
  else if (search === undefined) {
9459
- return fixed[name];
9645
+ return fixed[name] || null;
9460
9646
  }
9461
9647
  else if (search === null) {
9462
9648
  delete fixed[name];
@@ -9908,14 +10094,9 @@
9908
10094
  jqTable.append( tfoot );
9909
10095
  }
9910
10096
 
9911
- // Clean up the header
9912
- $(thead).find('span.dt-column-order').remove();
9913
- $(thead).find('span.dt-column-title').each(function () {
9914
- var title = $(this).html();
9915
- $(this).parent().append(title);
9916
- $(this).remove();
9917
- });
9918
-
10097
+ // Clean up the header / footer
10098
+ cleanHeader(thead, 'header');
10099
+ cleanHeader(tfoot, 'footer');
9919
10100
  settings.colgroup.remove();
9920
10101
 
9921
10102
  settings.aaSorting = [];
@@ -9937,7 +10118,6 @@
9937
10118
  orderClasses.isDesc
9938
10119
  )
9939
10120
  .css('width', '')
9940
- .removeAttr('data-dt-column')
9941
10121
  .removeAttr('aria-sort');
9942
10122
 
9943
10123
  // Add the TR elements back into the table in their original order
@@ -10018,6 +10198,19 @@
10018
10198
  : resolved;
10019
10199
  } );
10020
10200
 
10201
+ // Needed for header and footer, so pulled into its own function
10202
+ function cleanHeader(node, className) {
10203
+ $(node).find('span.dt-column-order').remove();
10204
+ $(node).find('span.dt-column-title').each(function () {
10205
+ var title = $(this).html();
10206
+ $(this).parent().parent().append(title);
10207
+ $(this).remove();
10208
+ });
10209
+ $(node).find('div.dt-column-' + className).remove();
10210
+
10211
+ $('th, td', node).removeAttr('data-dt-column');
10212
+ }
10213
+
10021
10214
  /**
10022
10215
  * Version string for plug-ins to check compatibility. Allowed format is
10023
10216
  * `a.b.c-d` where: a:int, b:int, c:int, d:string(dev|beta|alpha). `d` is used
@@ -10026,7 +10219,7 @@
10026
10219
  * @type string
10027
10220
  * @default Version number
10028
10221
  */
10029
- DataTable.version = "2.2.2";
10222
+ DataTable.version = "2.3.2";
10030
10223
 
10031
10224
  /**
10032
10225
  * Private data store, containing all of the settings objects that are
@@ -10633,6 +10826,10 @@
10633
10826
  "bSortCellsTop": null,
10634
10827
 
10635
10828
 
10829
+ /** Specify which row is the title row in the header. Replacement for bSortCellsTop */
10830
+ titleRow: null,
10831
+
10832
+
10636
10833
  /**
10637
10834
  * Enable or disable the addition of the classes `sorting\_1`, `sorting\_2` and
10638
10835
  * `sorting\_3` to the columns which are currently being sorted on. This is
@@ -10910,6 +11107,13 @@
10910
11107
  1: "entry"
10911
11108
  },
10912
11109
 
11110
+ /**
11111
+ * Page length options
11112
+ */
11113
+ lengthLabels: {
11114
+ '-1': 'All'
11115
+ },
11116
+
10913
11117
  /**
10914
11118
  * This string is shown in preference to `zeroRecords` when the table is
10915
11119
  * empty of data (regardless of filtering). Note that this is an optional
@@ -11180,7 +11384,10 @@
11180
11384
  /**
11181
11385
  * For server-side processing - use the data from the DOM for the first draw
11182
11386
  */
11183
- iDeferLoading: null
11387
+ iDeferLoading: null,
11388
+
11389
+ /** Event listeners */
11390
+ on: null
11184
11391
  };
11185
11392
 
11186
11393
  _fnHungarianMap( DataTable.defaults );
@@ -12007,10 +12214,7 @@
12007
12214
 
12008
12215
  /**
12009
12216
  * Indicate that if multiple rows are in the header and there is more than
12010
- * one unique cell per column, if the top one (true) or bottom one (false)
12011
- * should be used for sorting / title by DataTables.
12012
- * Note that this parameter will be set by the initialisation routine. To
12013
- * set a default use {@link DataTable.defaults}.
12217
+ * one unique cell per column. Replaced by titleRow
12014
12218
  */
12015
12219
  "bSortCellsTop": null,
12016
12220
 
@@ -12135,7 +12339,19 @@
12135
12339
  resizeObserver: null,
12136
12340
 
12137
12341
  /** Keep a record of the last size of the container, so we can skip duplicates */
12138
- containerWidth: -1
12342
+ containerWidth: -1,
12343
+
12344
+ /** Reverse the initial order of the data set on desc ordering */
12345
+ orderDescReverse: null,
12346
+
12347
+ /** Show / hide ordering indicators in headers */
12348
+ orderIndicators: true,
12349
+
12350
+ /** Default ordering listener */
12351
+ orderHandler: true,
12352
+
12353
+ /** Title row indicator */
12354
+ titleRow: null
12139
12355
  };
12140
12356
 
12141
12357
  /**
@@ -12965,7 +13181,7 @@
12965
13181
  cell.addClass(classes.order.none);
12966
13182
  }
12967
13183
 
12968
- var legacyTop = settings.bSortCellsTop;
13184
+ var titleRow = settings.titleRow;
12969
13185
  var headerRows = cell.closest('thead').find('tr');
12970
13186
  var rowIdx = cell.parent().index();
12971
13187
 
@@ -12975,11 +13191,10 @@
12975
13191
  cell.attr('data-dt-order') === 'disable' ||
12976
13192
  cell.parent().attr('data-dt-order') === 'disable' ||
12977
13193
 
12978
- // Legacy support for `orderCellsTop`. If it is set, then cells
12979
- // which are not in the top or bottom row of the header (depending
12980
- // on the value) do not get the sorting classes applied to them
12981
- (legacyTop === true && rowIdx !== 0) ||
12982
- (legacyTop === false && rowIdx !== headerRows.length - 1)
13194
+ // titleRow support, for defining a specific row in the header
13195
+ (titleRow === true && rowIdx !== 0) ||
13196
+ (titleRow === false && rowIdx !== headerRows.length - 1) ||
13197
+ (typeof titleRow === 'number' && rowIdx !== titleRow)
12983
13198
  ) {
12984
13199
  return;
12985
13200
  }
@@ -12989,7 +13204,7 @@
12989
13204
  // `DT` namespace will allow the event to be removed automatically
12990
13205
  // on destroy, while the `dt` namespaced event is the one we are
12991
13206
  // listening for
12992
- $(settings.nTable).on( 'order.dt.DT column-visibility.dt.DT', function ( e, ctx ) {
13207
+ $(settings.nTable).on( 'order.dt.DT column-visibility.dt.DT', function ( e, ctx, column ) {
12993
13208
  if ( settings !== ctx ) { // need to check this this is the host
12994
13209
  return; // table, not a nested one
12995
13210
  }
@@ -13000,6 +13215,16 @@
13000
13215
  return;
13001
13216
  }
13002
13217
 
13218
+ var orderedColumns = _pluck(sorting, 'col');
13219
+
13220
+ // This handler is only needed on column visibility if the column is part of the
13221
+ // ordering. If it isn't, then we can bail out to save performance. It could be a
13222
+ // separate event handler, but this is a balance between code reuse / size and performance
13223
+ // console.log(e, e.name, column, orderedColumns, orderedColumns.includes(column))
13224
+ if (e.type === 'column-visibility' && ! orderedColumns.includes(column)) {
13225
+ return;
13226
+ }
13227
+
13003
13228
  var i;
13004
13229
  var orderClasses = classes.order;
13005
13230
  var columns = ctx.api.columns( cell );
@@ -13008,8 +13233,8 @@
13008
13233
  var ariaType = '';
13009
13234
  var indexes = columns.indexes();
13010
13235
  var sortDirs = columns.orderable(true).flatten();
13011
- var orderedColumns = _pluck(sorting, 'col');
13012
13236
  var tabIndex = settings.iTabIndex;
13237
+ var canOrder = ctx.orderHandler && orderable;
13013
13238
 
13014
13239
  cell
13015
13240
  .removeClass(
@@ -13017,8 +13242,8 @@
13017
13242
  orderClasses.isDesc
13018
13243
  )
13019
13244
  .toggleClass( orderClasses.none, ! orderable )
13020
- .toggleClass( orderClasses.canAsc, orderable && sortDirs.includes('asc') )
13021
- .toggleClass( orderClasses.canDesc, orderable && sortDirs.includes('desc') );
13245
+ .toggleClass( orderClasses.canAsc, canOrder && sortDirs.includes('asc') )
13246
+ .toggleClass( orderClasses.canDesc, canOrder && sortDirs.includes('desc') );
13022
13247
 
13023
13248
  // Determine if all of the columns that this cell covers are included in the
13024
13249
  // current ordering
@@ -13777,12 +14002,17 @@
13777
14002
  } );
13778
14003
 
13779
14004
  for ( i=0 ; i<lengths.length ; i++ ) {
13780
- select[0][ i ] = new Option(
13781
- typeof language[i] === 'number' ?
14005
+ // Attempt to look up the length from the i18n options
14006
+ var label = settings.api.i18n('lengthLabels.' + lengths[i], null);
14007
+
14008
+ if (label === null) {
14009
+ // If not present, fallback to old style
14010
+ label = typeof language[i] === 'number' ?
13782
14011
  settings.fnFormatNumber( language[i] ) :
13783
- language[i],
13784
- lengths[i]
13785
- );
14012
+ language[i];
14013
+ }
14014
+
14015
+ select[0][ i ] = new Option(label, lengths[i]);
13786
14016
  }
13787
14017
 
13788
14018
  // add for and id to label and input