datatables.net 2.1.8 → 2.2.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.
package/js/dataTables.mjs CHANGED
@@ -1,4 +1,4 @@
1
- /*! DataTables 2.1.8
1
+ /*! DataTables 2.2.0
2
2
  * © SpryMedia Ltd - datatables.net/license
3
3
  */
4
4
 
@@ -376,7 +376,6 @@ var DataTable = function ( selector, options )
376
376
  thead = $('<thead/>').appendTo($this);
377
377
  }
378
378
  oSettings.nTHead = thead[0];
379
- $('tr', thead).addClass(oClasses.thead.row);
380
379
 
381
380
  var tbody = $this.children('tbody');
382
381
  if ( tbody.length === 0 ) {
@@ -391,7 +390,6 @@ var DataTable = function ( selector, options )
391
390
  tfoot = $('<tfoot/>').appendTo($this);
392
391
  }
393
392
  oSettings.nTFoot = tfoot[0];
394
- $('tr', tfoot).addClass(oClasses.tfoot.row);
395
393
 
396
394
  // Copy the data index array
397
395
  oSettings.aiDisplay = oSettings.aiDisplayMaster.slice();
@@ -2108,6 +2106,10 @@ function _fnColumnSizes ( settings )
2108
2106
  var width = _fnColumnsSumWidth(settings, [i], false, false);
2109
2107
 
2110
2108
  cols[i].colEl.css('width', width);
2109
+
2110
+ if (settings.oScroll.sX) {
2111
+ cols[i].colEl.css('min-width', width);
2112
+ }
2111
2113
  }
2112
2114
  }
2113
2115
 
@@ -3175,9 +3177,13 @@ function _fnBuildHead( settings, side )
3175
3177
 
3176
3178
  // Add the number of cells needed to make up to the number of columns
3177
3179
  if (row.length === 1) {
3178
- var cells = $('td, th', row);
3180
+ var cellCount = 0;
3181
+
3182
+ $('td, th', row).each(function () {
3183
+ cellCount += this.colSpan;
3184
+ });
3179
3185
 
3180
- for ( i=cells.length, ien=columns.length ; i<ien ; i++ ) {
3186
+ for ( i=cellCount, ien=columns.length ; i<ien ; i++ ) {
3181
3187
  $('<th/>')
3182
3188
  .html( columns[i][titleProp] || '' )
3183
3189
  .appendTo( row );
@@ -3189,9 +3195,11 @@ function _fnBuildHead( settings, side )
3189
3195
 
3190
3196
  if (side === 'header') {
3191
3197
  settings.aoHeader = detected;
3198
+ $('tr', target).addClass(classes.thead.row);
3192
3199
  }
3193
3200
  else {
3194
3201
  settings.aoFooter = detected;
3202
+ $('tr', target).addClass(classes.tfoot.row);
3195
3203
  }
3196
3204
 
3197
3205
  // Every cell needs to be passed through the renderer
@@ -4454,7 +4462,7 @@ function _fnFilterCustom( settings )
4454
4462
  // So the array reference doesn't break set the results into the
4455
4463
  // existing array
4456
4464
  displayRows.length = 0;
4457
- displayRows.push.apply(displayRows, rows);
4465
+ _fnArrayApply(displayRows, rows);
4458
4466
  }
4459
4467
  }
4460
4468
 
@@ -5182,8 +5190,11 @@ function _fnScrollDraw ( settings )
5182
5190
  // [].find, but it wasn't supported in Chrome until Sept 2015, and DT has 10 year
5183
5191
  // browser support
5184
5192
  var firstTr = null;
5193
+ var start = _fnDataSource( settings ) !== 'ssp'
5194
+ ? settings._iDisplayStart
5195
+ : 0;
5185
5196
 
5186
- for (i=settings._iDisplayStart ; i<settings.aiDisplay.length ; i++) {
5197
+ for (i=start ; i<start + settings.aiDisplay.length ; i++) {
5187
5198
  var idx = settings.aiDisplay[i];
5188
5199
  var tr = settings.aoData[idx].nTr;
5189
5200
 
@@ -5198,7 +5209,7 @@ function _fnScrollDraw ( settings )
5198
5209
  return {
5199
5210
  idx: _fnVisibleToColumnIndex(settings, vis),
5200
5211
  width: $(this).outerWidth()
5201
- }
5212
+ };
5202
5213
  });
5203
5214
 
5204
5215
  // Check against what the colgroup > col is set to and correct if needed
@@ -5208,6 +5219,10 @@ function _fnScrollDraw ( settings )
5208
5219
 
5209
5220
  if (colWidth !== colSizes[i].width) {
5210
5221
  colEl.style.width = colSizes[i].width + 'px';
5222
+
5223
+ if (scroll.sX) {
5224
+ colEl.style.minWidth = colSizes[i].width + 'px';
5225
+ }
5211
5226
  }
5212
5227
  }
5213
5228
  }
@@ -5357,6 +5372,8 @@ function _fnCalculateColumnWidths ( settings )
5357
5372
  // browser will collapse it. If this width is smaller than the
5358
5373
  // width the column requires, then it will have no effect
5359
5374
  if ( scrollX ) {
5375
+ this.style.minWidth = width;
5376
+
5360
5377
  $( this ).append( $('<div/>').css( {
5361
5378
  width: width,
5362
5379
  margin: 0,
@@ -5466,15 +5483,52 @@ function _fnCalculateColumnWidths ( settings )
5466
5483
  }
5467
5484
 
5468
5485
  if ( (tableWidthAttr || scrollX) && ! settings._reszEvt ) {
5469
- var bindResize = function () {
5470
- $(window).on('resize.DT-'+settings.sInstance, DataTable.util.throttle( function () {
5471
- if (! settings.bDestroying) {
5472
- _fnAdjustColumnSizing( settings );
5486
+ var wrapperWidth = function () {
5487
+ return $(settings.nTableWrapper).is(':visible')
5488
+ ? $(settings.nTableWrapper).width()
5489
+ : 0;
5490
+ }
5491
+
5492
+ settings.containerWidth = wrapperWidth();
5493
+
5494
+ var resize = DataTable.util.throttle( function () {
5495
+ var newWidth = wrapperWidth();
5496
+
5497
+ // Don't do it if destroying, is the same size as last time, or the container
5498
+ // width is 0
5499
+ if (
5500
+ ! settings.bDestroying &&
5501
+ settings.containerWidth !== newWidth &&
5502
+ newWidth !== 0
5503
+ ) {
5504
+ // Do a resize
5505
+ _fnAdjustColumnSizing( settings );
5506
+ settings.containerWidth = newWidth;
5507
+ }
5508
+ } );
5509
+
5510
+ // For browsers that support it (~2020 onwards for wide support) we can watch for the
5511
+ // container changing width.
5512
+ if (window.ResizeObserver) {
5513
+ settings.resizeObserver = new ResizeObserver(function (e) {
5514
+ var box = e[0].contentBoxSize;
5515
+ var size = Array.isArray(box)
5516
+ ? box[0].inlineSize // Spec
5517
+ : box.inlineSize; // Old Firefox
5518
+
5519
+ // Under this condition a resize will trigger its own resize, causing an error.
5520
+ if (size < settings.containerWidth) {
5521
+ return;
5473
5522
  }
5474
- } ) );
5475
- };
5476
5523
 
5477
- bindResize();
5524
+ resize();
5525
+ });
5526
+ settings.resizeObserver.observe(settings.nTableWrapper);
5527
+ }
5528
+ else {
5529
+ // For old browsers, the best we can do is listen for a window resize
5530
+ $(window).on('resize.DT-'+settings.sInstance, resize);
5531
+ }
5478
5532
 
5479
5533
  settings._reszEvt = true;
5480
5534
  }
@@ -6088,15 +6142,26 @@ function _fnSaveState ( settings )
6088
6142
  return;
6089
6143
  }
6090
6144
 
6145
+ // Sort state saving uses [[idx, order]] structure.
6146
+ var sorting = [];
6147
+ _fnSortResolve(settings, sorting, settings.aaSorting );
6148
+
6091
6149
  /* Store the interesting variables */
6150
+ var columns = settings.aoColumns;
6092
6151
  var state = {
6093
6152
  time: +new Date(),
6094
6153
  start: settings._iDisplayStart,
6095
6154
  length: settings._iDisplayLength,
6096
- order: $.extend( true, [], settings.aaSorting ),
6155
+ order: sorting.map(function (sort) {
6156
+ // If a column name is available, use it
6157
+ return columns[sort[0]] && columns[sort[0]].sName
6158
+ ? [ columns[sort[0]].sName, sort[1] ]
6159
+ : sort.slice();
6160
+ } ),
6097
6161
  search: $.extend({}, settings.oPreviousSearch),
6098
6162
  columns: settings.aoColumns.map( function ( col, i ) {
6099
6163
  return {
6164
+ name: col.sName,
6100
6165
  visible: col.bVisible,
6101
6166
  search: $.extend({}, settings.aoPreSearchCols[i])
6102
6167
  };
@@ -6144,6 +6209,8 @@ function _fnLoadState ( settings, init, callback )
6144
6209
  function _fnImplementState ( settings, s, callback) {
6145
6210
  var i, ien;
6146
6211
  var columns = settings.aoColumns;
6212
+ var currentNames = _pluck(settings.aoColumns, 'sName');
6213
+
6147
6214
  settings._bLoadingState = true;
6148
6215
 
6149
6216
  // When StateRestore was introduced the state could now be implemented at any time
@@ -6173,13 +6240,6 @@ function _fnImplementState ( settings, s, callback) {
6173
6240
  return;
6174
6241
  }
6175
6242
 
6176
- // Number of columns have changed - all bets are off, no restore of settings
6177
- if ( s.columns && columns.length !== s.columns.length ) {
6178
- settings._bLoadingState = false;
6179
- callback();
6180
- return;
6181
- }
6182
-
6183
6243
  // Store the saved state so it might be accessed at any time
6184
6244
  settings.oLoadedState = $.extend( true, {}, s );
6185
6245
 
@@ -6213,10 +6273,23 @@ function _fnImplementState ( settings, s, callback) {
6213
6273
  if ( s.order !== undefined ) {
6214
6274
  settings.aaSorting = [];
6215
6275
  $.each( s.order, function ( i, col ) {
6216
- settings.aaSorting.push( col[0] >= columns.length ?
6217
- [ 0, col[1] ] :
6218
- col
6219
- );
6276
+ var set = [ col[0], col[1] ];
6277
+
6278
+ // A column name was stored and should be used for restore
6279
+ if (typeof col[0] === 'string') {
6280
+ var idx = currentNames.indexOf(col[0]);
6281
+
6282
+ // Find the name from the current list of column names, or fallback to index 0
6283
+ set[0] = idx >= 0
6284
+ ? idx
6285
+ : 0;
6286
+ }
6287
+ else if (set[0] >= columns.length) {
6288
+ // If a column name, but it is out of bounds, set to 0
6289
+ set[0] = 0;
6290
+ }
6291
+
6292
+ settings.aaSorting.push(set);
6220
6293
  } );
6221
6294
  }
6222
6295
 
@@ -6227,31 +6300,65 @@ function _fnImplementState ( settings, s, callback) {
6227
6300
 
6228
6301
  // Columns
6229
6302
  if ( s.columns ) {
6230
- for ( i=0, ien=s.columns.length ; i<ien ; i++ ) {
6231
- var col = s.columns[i];
6232
-
6233
- // Visibility
6234
- if ( col.visible !== undefined ) {
6235
- // If the api is defined, the table has been initialised so we need to use it rather than internal settings
6236
- if (api) {
6237
- // Don't redraw the columns on every iteration of this loop, we will do this at the end instead
6238
- api.column(i).visible(col.visible, false);
6303
+ var set = s.columns;
6304
+ var incoming = _pluck(s.columns, 'name');
6305
+
6306
+ // Check if it is a 2.2 style state object with a `name` property for the columns, and if
6307
+ // the name was defined. If so, then create a new array that will map the state object
6308
+ // given, to the current columns (don't bother if they are already matching tho).
6309
+ if (incoming.join('').length && incoming.join('') !== currentNames.join('')) {
6310
+ set = [];
6311
+
6312
+ // For each column, try to find the name in the incoming array
6313
+ for (i=0 ; i<currentNames.length ; i++) {
6314
+ if (currentNames[i] != '') {
6315
+ var idx = incoming.indexOf(currentNames[i]);
6316
+
6317
+ if (idx >= 0) {
6318
+ set.push(s.columns[idx]);
6319
+ }
6320
+ else {
6321
+ // No matching column name in the state's columns, so this might be a new
6322
+ // column and thus can't have a state already.
6323
+ set.push({});
6324
+ }
6239
6325
  }
6240
6326
  else {
6241
- columns[i].bVisible = col.visible;
6327
+ // If no name, but other columns did have a name, then there is no knowing
6328
+ // where this one came from originally so it can't be restored.
6329
+ set.push({});
6330
+ }
6331
+ }
6332
+ }
6333
+
6334
+ // If the number of columns to restore is different from current, then all bets are off.
6335
+ if (set.length === columns.length) {
6336
+ for ( i=0, ien=set.length ; i<ien ; i++ ) {
6337
+ var col = set[i];
6338
+
6339
+ // Visibility
6340
+ if ( col.visible !== undefined ) {
6341
+ // If the api is defined, the table has been initialised so we need to use it rather than internal settings
6342
+ if (api) {
6343
+ // Don't redraw the columns on every iteration of this loop, we will do this at the end instead
6344
+ api.column(i).visible(col.visible, false);
6345
+ }
6346
+ else {
6347
+ columns[i].bVisible = col.visible;
6348
+ }
6349
+ }
6350
+
6351
+ // Search
6352
+ if ( col.search !== undefined ) {
6353
+ $.extend( settings.aoPreSearchCols[i], col.search );
6242
6354
  }
6243
6355
  }
6244
6356
 
6245
- // Search
6246
- if ( col.search !== undefined ) {
6247
- $.extend( settings.aoPreSearchCols[i], col.search );
6357
+ // If the api is defined then we need to adjust the columns once the visibility has been changed
6358
+ if (api) {
6359
+ api.columns.adjust();
6248
6360
  }
6249
6361
  }
6250
-
6251
- // If the api is defined then we need to adjust the columns once the visibility has been changed
6252
- if (api) {
6253
- api.columns.adjust();
6254
- }
6255
6362
  }
6256
6363
 
6257
6364
  settings._bLoadingState = false;
@@ -6568,6 +6675,30 @@ function _fnMacros ( settings, str, entries )
6568
6675
  replace(/_ENTRIES-TOTAL_/g, settings.api.i18n('entries', '', vis) );
6569
6676
  }
6570
6677
 
6678
+ /**
6679
+ * Add elements to an array as quickly as possible, but stack stafe.
6680
+ *
6681
+ * @param {*} arr Array to add the data to
6682
+ * @param {*} data Data array that is to be added
6683
+ * @returns
6684
+ */
6685
+ function _fnArrayApply(arr, data) {
6686
+ if (! data) {
6687
+ return;
6688
+ }
6689
+
6690
+ // Chrome can throw a max stack error if apply is called with
6691
+ // too large an array, but apply is faster.
6692
+ if (data.length < 10000) {
6693
+ arr.push.apply(arr, data);
6694
+ }
6695
+ else {
6696
+ for (i=0 ; i<data.length ; i++) {
6697
+ arr.push(data[i]);
6698
+ }
6699
+ }
6700
+ }
6701
+
6571
6702
 
6572
6703
 
6573
6704
  /**
@@ -6760,18 +6891,7 @@ _Api = function ( context, data )
6760
6891
  : settings;
6761
6892
 
6762
6893
  // Initial data
6763
- if ( data ) {
6764
- // Chrome can throw a max stack error if apply is called with
6765
- // too large an array, but apply is faster.
6766
- if (data.length < 10000) {
6767
- this.push.apply(this, data);
6768
- }
6769
- else {
6770
- for (i=0 ; i<data.length ; i++) {
6771
- this.push(data[i]);
6772
- }
6773
- }
6774
- }
6894
+ _fnArrayApply(this, data);
6775
6895
 
6776
6896
  // selector
6777
6897
  this.selector = {
@@ -7152,7 +7272,7 @@ var __table_selector = function ( selector, a )
7152
7272
  selector.forEach(function (sel) {
7153
7273
  var inner = __table_selector(sel, a);
7154
7274
 
7155
- result.push.apply(result, inner);
7275
+ _fnArrayApply(result, inner);
7156
7276
  });
7157
7277
 
7158
7278
  return result.filter( function (item) {
@@ -8006,7 +8126,7 @@ _api_register( 'rows.add()', function ( rows ) {
8006
8126
  // Return an Api.rows() extended instance, so rows().nodes() etc can be used
8007
8127
  var modRows = this.rows( -1 );
8008
8128
  modRows.pop();
8009
- modRows.push.apply(modRows, newRows);
8129
+ _fnArrayApply(modRows, newRows);
8010
8130
 
8011
8131
  return modRows;
8012
8132
  } );
@@ -8519,7 +8639,10 @@ var __column_selector = function ( settings, selector, opts )
8519
8639
  .map( function () {
8520
8640
  return _fnColumnsFromHeader( this ); // `nodes` is column index complete and in order
8521
8641
  } )
8522
- .toArray();
8642
+ .toArray()
8643
+ .sort(function (a, b) {
8644
+ return a - b;
8645
+ });
8523
8646
 
8524
8647
  if ( jqResult.length || ! s.nodeName ) {
8525
8648
  return jqResult;
@@ -9338,6 +9461,10 @@ _api_register( 'state.save()', function () {
9338
9461
  } );
9339
9462
  } );
9340
9463
 
9464
+ // Can be assigned in DateTable.use() - note luxon and moment vars are in helpers.js
9465
+ var __bootstrap;
9466
+ var __foundation;
9467
+
9341
9468
  /**
9342
9469
  * Set the libraries that DataTables uses, or the global objects.
9343
9470
  * Note that the arguments can be either way around (legacy support)
@@ -9371,6 +9498,14 @@ DataTable.use = function (arg1, arg2) {
9371
9498
  case 'moment':
9372
9499
  return __moment;
9373
9500
 
9501
+ case 'bootstrap':
9502
+ // Use local if set, otherwise try window, which could be undefined
9503
+ return __bootstrap || window.bootstrap;
9504
+
9505
+ case 'foundation':
9506
+ // Ditto
9507
+ return __foundation || window.Foundation;
9508
+
9374
9509
  default:
9375
9510
  return null;
9376
9511
  }
@@ -9380,7 +9515,7 @@ DataTable.use = function (arg1, arg2) {
9380
9515
  if (type === 'lib' || type === 'jq' || (module && module.fn && module.fn.jquery)) {
9381
9516
  $ = module;
9382
9517
  }
9383
- else if (type == 'win' || (module && module.document)) {
9518
+ else if (type === 'win' || (module && module.document)) {
9384
9519
  window = module;
9385
9520
  document = module.document;
9386
9521
  }
@@ -9393,6 +9528,14 @@ DataTable.use = function (arg1, arg2) {
9393
9528
  else if (type === 'moment' || (module && module.isMoment)) {
9394
9529
  __moment = module;
9395
9530
  }
9531
+ else if (type === 'bootstrap' || (module && module.Modal && module.Modal.NAME === 'modal'))
9532
+ {
9533
+ // This is currently for BS5 only. BS3/4 attach to jQuery, so no need to use `.use()`
9534
+ __bootstrap = module;
9535
+ }
9536
+ else if (type === 'foundation' || (module && module.Reveal)) {
9537
+ __foundation = module;
9538
+ }
9396
9539
  }
9397
9540
 
9398
9541
  /**
@@ -9683,6 +9826,11 @@ _api_register( 'destroy()', function ( remove ) {
9683
9826
  new _Api( settings ).columns().visible( true );
9684
9827
  }
9685
9828
 
9829
+ // Container width change listener
9830
+ if (settings.resizeObserver) {
9831
+ settings.resizeObserver.disconnect();
9832
+ }
9833
+
9686
9834
  // Blitz all `DT` namespaced events (these are internal events, the
9687
9835
  // lowercase, `dt` events are user subscribed and they are responsible
9688
9836
  // for removing them
@@ -9801,7 +9949,7 @@ _api_register( 'i18n()', function ( token, def, plural ) {
9801
9949
  * @type string
9802
9950
  * @default Version number
9803
9951
  */
9804
- DataTable.version = "2.1.8";
9952
+ DataTable.version = "2.2.0";
9805
9953
 
9806
9954
  /**
9807
9955
  * Private data store, containing all of the settings objects that are
@@ -11904,7 +12052,13 @@ DataTable.models.oSettings = {
11904
12052
  deferLoading: null,
11905
12053
 
11906
12054
  /** Allow auto type detection */
11907
- typeDetect: true
12055
+ typeDetect: true,
12056
+
12057
+ /** ResizeObserver for the container div */
12058
+ resizeObserver: null,
12059
+
12060
+ /** Keep a record of the last size of the container, so we can skip duplicates */
12061
+ containerWidth: 0
11908
12062
  };
11909
12063
 
11910
12064
  /**
@@ -12046,8 +12200,8 @@ function __mld( dtLib, momentFn, luxonFn, dateFn, arg1 ) {
12046
12200
 
12047
12201
 
12048
12202
  var __mlWarning = false;
12049
- var __luxon; // Can be assigned in DateTeble.use()
12050
- var __moment; // Can be assigned in DateTeble.use()
12203
+ var __luxon; // Can be assigned in DateTable.use()
12204
+ var __moment; // Can be assigned in DateTable.use()
12051
12205
 
12052
12206
  /**
12053
12207
  *
@@ -12083,7 +12237,7 @@ function __mldObj (d, format, locale) {
12083
12237
  return null;
12084
12238
  }
12085
12239
 
12086
- dt.setLocale(locale);
12240
+ dt = dt.setLocale(locale);
12087
12241
  }
12088
12242
  else if (! format) {
12089
12243
  // No format given, must be ISO
@@ -12466,6 +12620,13 @@ var __diacriticSort = function (a, b) {
12466
12620
  });
12467
12621
  }
12468
12622
 
12623
+ var __diacriticHtmlSort = function (a, b) {
12624
+ a = _stripHtml(a);
12625
+ b = _stripHtml(b);
12626
+
12627
+ return __diacriticSort(a, b);
12628
+ }
12629
+
12469
12630
  //
12470
12631
  // Built in data types
12471
12632
  //
@@ -12536,6 +12697,31 @@ DataTable.type('html', {
12536
12697
  });
12537
12698
 
12538
12699
 
12700
+ DataTable.type('html-utf8', {
12701
+ detect: {
12702
+ allOf: function ( d ) {
12703
+ return _empty( d ) || (typeof d === 'string' && d.indexOf('<') !== -1);
12704
+ },
12705
+ oneOf: function ( d ) {
12706
+ // At least one data point must contain a `<` and a non-ASCII character
12707
+ // eslint-disable-next-line compat/compat
12708
+ return navigator.languages &&
12709
+ ! _empty( d ) &&
12710
+ typeof d === 'string' &&
12711
+ d.indexOf('<') !== -1 &&
12712
+ typeof d === 'string' && d.match(/[^\x00-\x7F]/);
12713
+ }
12714
+ },
12715
+ order: {
12716
+ asc: __diacriticHtmlSort,
12717
+ desc: function (a, b) {
12718
+ return __diacriticHtmlSort(a, b) * -1;
12719
+ }
12720
+ },
12721
+ search: _filterString(true, true)
12722
+ });
12723
+
12724
+
12539
12725
  DataTable.type('date', {
12540
12726
  className: 'dt-type-date',
12541
12727
  detect: {
@@ -12746,6 +12932,7 @@ $.extend( true, DataTable.ext.renderer, {
12746
12932
  var indexes = columns.indexes();
12747
12933
  var sortDirs = columns.orderable(true).flatten();
12748
12934
  var orderedColumns = _pluck(sorting, 'col');
12935
+ var tabIndex = settings.iTabIndex;
12749
12936
 
12750
12937
  cell
12751
12938
  .removeClass(
@@ -12810,8 +12997,13 @@ $.extend( true, DataTable.ext.renderer, {
12810
12997
 
12811
12998
  // Make the headers tab-able for keyboard navigation
12812
12999
  if (orderable) {
12813
- cell.find('.dt-column-title').attr('role', 'button');
12814
- cell.attr('tabindex', 0)
13000
+ var orderSpan = cell.find('.dt-column-order');
13001
+
13002
+ orderSpan.attr('role', 'button');
13003
+
13004
+ if (tabIndex !== -1) {
13005
+ orderSpan.attr('tabindex', tabIndex);
13006
+ }
12815
13007
  }
12816
13008
  } );
12817
13009
  }
@@ -12825,7 +13017,7 @@ $.extend( true, DataTable.ext.renderer, {
12825
13017
  .addClass(items.className || classes.row)
12826
13018
  .appendTo( container );
12827
13019
 
12828
- $.each( items, function (key, val) {
13020
+ DataTable.ext.renderer.layout._forLayoutRow(items, function (key, val) {
12829
13021
  if (key === 'id' || key === 'className') {
12830
13022
  return;
12831
13023
  }
@@ -12856,7 +13048,31 @@ $.extend( true, DataTable.ext.renderer, {
12856
13048
  })
12857
13049
  .append( val.contents )
12858
13050
  .appendTo( row );
12859
- } );
13051
+ });
13052
+ },
13053
+
13054
+ // Shared for use by the styling frameworks
13055
+ _forLayoutRow: function (items, fn) {
13056
+ // As we are inserting dom elements, we need start / end in a
13057
+ // specific order, this function is used for sorting the layout
13058
+ // keys.
13059
+ var layoutEnum = function (x) {
13060
+ switch (x) {
13061
+ case '': return 0;
13062
+ case 'start': return 1;
13063
+ case 'end': return 2;
13064
+ default: return 3;
13065
+ }
13066
+ };
13067
+
13068
+ Object
13069
+ .keys(items)
13070
+ .sort(function (a, b) {
13071
+ return layoutEnum(a) - layoutEnum(b);
13072
+ })
13073
+ .forEach(function (key) {
13074
+ fn(key, items[key]);
13075
+ });
12860
13076
  }
12861
13077
  }
12862
13078
  } );
@@ -13208,7 +13424,7 @@ function _pagingDraw(settings, host, opts) {
13208
13424
  'data-dt-idx': button,
13209
13425
  'tabIndex': btnInfo.disabled
13210
13426
  ? -1
13211
- : settings.iTabIndex
13427
+ : settings.iTabIndex && btn.clicker[0].nodeName.toLowerCase() !== 'span'
13212
13428
  ? settings.iTabIndex
13213
13429
  : null, // `0` doesn't need a tabIndex since it is the default
13214
13430
  });
@@ -13242,12 +13458,16 @@ function _pagingDraw(settings, host, opts) {
13242
13458
 
13243
13459
  // Responsive - check if the buttons are over two lines based on the
13244
13460
  // height of the buttons and the container.
13245
- if (
13246
- buttonEls.length && // any buttons
13247
- opts.buttons > 1 && // prevent infinite
13248
- $(host).height() >= ($(buttonEls[0]).outerHeight() * 2) - 10
13249
- ) {
13250
- _pagingDraw(settings, host, $.extend({}, opts, { buttons: opts.buttons - 2 }));
13461
+ if (buttonEls.length) {
13462
+ var outerHeight = $(buttonEls[0]).outerHeight();
13463
+
13464
+ if (
13465
+ opts.buttons > 1 && // prevent infinite
13466
+ outerHeight > 0 && // will be 0 if hidden
13467
+ $(host).height() >= (outerHeight * 2) - 10
13468
+ ) {
13469
+ _pagingDraw(settings, host, $.extend({}, opts, { buttons: opts.buttons - 2 }));
13470
+ }
13251
13471
  }
13252
13472
  }
13253
13473
 
@@ -13271,7 +13491,6 @@ function _pagingButtonInfo(settings, button, page, pages) {
13271
13491
  switch ( button ) {
13272
13492
  case 'ellipsis':
13273
13493
  o.display = '&#x2026;';
13274
- o.disabled = true;
13275
13494
  break;
13276
13495
 
13277
13496
  case 'first':
@@ -13458,7 +13677,7 @@ DataTable.feature.register( 'pageLength', function ( settings, opts ) {
13458
13677
 
13459
13678
  // Save text node content for macro updating
13460
13679
  var textNodes = [];
13461
- Array.from(div.find('label')[0].childNodes).forEach(function (el) {
13680
+ Array.prototype.slice.call(div.find('label')[0].childNodes).forEach(function (el) {
13462
13681
  if (el.nodeType === Node.TEXT_NODE) {
13463
13682
  textNodes.push({
13464
13683
  el: el,
@@ -13476,7 +13695,6 @@ DataTable.feature.register( 'pageLength', function ( settings, opts ) {
13476
13695
 
13477
13696
  // Next, the select itself, along with the options
13478
13697
  var select = $('<select/>', {
13479
- 'name': tableId+'_length',
13480
13698
  'aria-controls': tableId,
13481
13699
  'class': classes.select
13482
13700
  } );
package/package.json CHANGED
@@ -4,7 +4,7 @@
4
4
  "main": "js/dataTables.js",
5
5
  "module": "js/dataTables.mjs",
6
6
  "types": "./types/types.d.ts",
7
- "version": "2.1.8",
7
+ "version": "2.2.0",
8
8
  "files": [
9
9
  "js/**/*.js",
10
10
  "js/**/*.mjs",