datatables.net 2.2.2 → 2.3.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/js/dataTables.js CHANGED
@@ -1,4 +1,4 @@
1
- /*! DataTables 2.2.2
1
+ /*! DataTables 2.3.1
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 );
@@ -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
  /**
@@ -1875,6 +1896,26 @@
1875
1896
  init.scrollX = init.scrollX ? '100%' : '';
1876
1897
  }
1877
1898
 
1899
+ // Objects for ordering
1900
+ if ( typeof init.bSort === 'object' ) {
1901
+ init.orderIndicators = init.bSort.indicators !== undefined ? init.bSort.indicators : true;
1902
+ init.orderHandler = init.bSort.handler !== undefined ? init.bSort.handler : true;
1903
+ init.bSort = true;
1904
+ }
1905
+ else if (init.bSort === false) {
1906
+ init.orderIndicators = false;
1907
+ init.orderHandler = false;
1908
+ }
1909
+ else if (init.bSort === true) {
1910
+ init.orderIndicators = true;
1911
+ init.orderHandler = true;
1912
+ }
1913
+
1914
+ // Which cells are the title cells?
1915
+ if (typeof init.bSortCellsTop === 'boolean') {
1916
+ init.titleRow = init.bSortCellsTop;
1917
+ }
1918
+
1878
1919
  // Column search objects are in an array, so it needs to be converted
1879
1920
  // element by element
1880
1921
  var searchCols = init.aoSearchCols;
@@ -3252,7 +3293,7 @@
3252
3293
  * @param {*} settings DataTables settings
3253
3294
  * @param {*} source Source layout array
3254
3295
  * @param {*} incColumns What columns should be included
3255
- * @returns Layout array
3296
+ * @returns Layout array in column index order
3256
3297
  */
3257
3298
  function _fnHeaderLayout( settings, source, incColumns )
3258
3299
  {
@@ -3536,7 +3577,9 @@
3536
3577
 
3537
3578
  _fnDraw( settings );
3538
3579
 
3539
- settings._drawHold = false;
3580
+ settings.api.one('draw', function () {
3581
+ settings._drawHold = false;
3582
+ });
3540
3583
  }
3541
3584
 
3542
3585
 
@@ -3548,10 +3591,9 @@
3548
3591
  var zero = oLang.sZeroRecords;
3549
3592
  var dataSrc = _fnDataSource( settings );
3550
3593
 
3551
- if (
3552
- (settings.iDraw < 1 && dataSrc === 'ssp') ||
3553
- (settings.iDraw <= 1 && dataSrc === 'ajax')
3554
- ) {
3594
+ // Make use of the fact that settings.json is only set once the initial data has
3595
+ // been loaded. Show loading when that isn't the case
3596
+ if ((dataSrc === 'ssp' || dataSrc === 'ajax') && ! settings.json) {
3555
3597
  zero = oLang.sLoadingRecords;
3556
3598
  }
3557
3599
  else if ( oLang.sEmptyTable && settings.fnRecordsTotal() === 0 )
@@ -3921,6 +3963,7 @@
3921
3963
  var rows = $(thead).children('tr');
3922
3964
  var row, cell;
3923
3965
  var i, k, l, iLen, shifted, column, colspan, rowspan;
3966
+ var titleRow = settings.titleRow;
3924
3967
  var isHeader = thead && thead.nodeName.toLowerCase() === 'thead';
3925
3968
  var layout = [];
3926
3969
  var unique;
@@ -3949,6 +3992,7 @@
3949
3992
  cell.nodeName.toUpperCase() == 'TH'
3950
3993
  ) {
3951
3994
  var cols = [];
3995
+ var jqCell = $(cell);
3952
3996
 
3953
3997
  // Get the col and rowspan attributes from the DOM and sanitise them
3954
3998
  colspan = cell.getAttribute('colspan') * 1;
@@ -3969,7 +4013,7 @@
3969
4013
  if ( write ) {
3970
4014
  if (unique) {
3971
4015
  // Allow column options to be set from HTML attributes
3972
- _fnColumnOptions( settings, shifted, $(cell).data() );
4016
+ _fnColumnOptions( settings, shifted, jqCell.data() );
3973
4017
 
3974
4018
  // Get the width for the column. This can be defined from the
3975
4019
  // width attribute, style attribute or `columns.width` option
@@ -3986,7 +4030,14 @@
3986
4030
  // Column title handling - can be user set, or read from the DOM
3987
4031
  // This happens before the render, so the original is still in place
3988
4032
  if ( columnDef.sTitle !== null && ! columnDef.autoTitle ) {
3989
- cell.innerHTML = columnDef.sTitle;
4033
+ if (
4034
+ (titleRow === true && i === 0) || // top row
4035
+ (titleRow === false && i === rows.length -1) || // bottom row
4036
+ (titleRow === i) || // specific row
4037
+ (titleRow === null)
4038
+ ) {
4039
+ cell.innerHTML = columnDef.sTitle;
4040
+ }
3990
4041
  }
3991
4042
 
3992
4043
  if (! columnDef.sTitle && unique) {
@@ -4004,12 +4055,12 @@
4004
4055
  // Fall back to the aria-label attribute on the table header if no ariaTitle is
4005
4056
  // provided.
4006
4057
  if (! columnDef.ariaTitle) {
4007
- columnDef.ariaTitle = $(cell).attr("aria-label") || columnDef.sTitle;
4058
+ columnDef.ariaTitle = jqCell.attr("aria-label") || columnDef.sTitle;
4008
4059
  }
4009
4060
 
4010
4061
  // Column specific class names
4011
4062
  if ( columnDef.className ) {
4012
- $(cell).addClass( columnDef.className );
4063
+ jqCell.addClass( columnDef.className );
4013
4064
  }
4014
4065
  }
4015
4066
 
@@ -4021,11 +4072,28 @@
4021
4072
  .appendTo(cell);
4022
4073
  }
4023
4074
 
4024
- if ( isHeader && $('span.dt-column-order', cell).length === 0) {
4075
+ if (
4076
+ settings.orderIndicators &&
4077
+ isHeader &&
4078
+ jqCell.filter(':not([data-dt-order=disable])').length !== 0 &&
4079
+ jqCell.parent(':not([data-dt-order=disable])').length !== 0 &&
4080
+ $('span.dt-column-order', cell).length === 0
4081
+ ) {
4025
4082
  $('<span>')
4026
4083
  .addClass('dt-column-order')
4027
4084
  .appendTo(cell);
4028
4085
  }
4086
+
4087
+ // We need to wrap the elements in the header in another element to use flexbox
4088
+ // layout for those elements
4089
+ var headerFooter = isHeader ? 'header' : 'footer';
4090
+
4091
+ if ( $('span.dt-column-' + headerFooter, cell).length === 0) {
4092
+ $('<div>')
4093
+ .addClass('dt-column-' + headerFooter)
4094
+ .append(cell.childNodes)
4095
+ .appendTo(cell);
4096
+ }
4029
4097
  }
4030
4098
 
4031
4099
  // If there is col / rowspan, copy the information into the layout grid
@@ -4176,6 +4244,11 @@
4176
4244
  // Allow plug-ins and external processes to modify the data
4177
4245
  _fnCallbackFire( oSettings, null, 'preXhr', [oSettings, data, baseAjax], true );
4178
4246
 
4247
+ // Custom Ajax option to submit the parameters as a JSON string
4248
+ if (baseAjax.submitAs === 'json' && typeof data === 'object') {
4249
+ baseAjax.data = JSON.stringify(data);
4250
+ }
4251
+
4179
4252
  if ( typeof ajax === 'function' )
4180
4253
  {
4181
4254
  // Is a function - let the caller define what needs to be done
@@ -5676,24 +5749,30 @@
5676
5749
  function _fnSortInit( settings ) {
5677
5750
  var target = settings.nTHead;
5678
5751
  var headerRows = target.querySelectorAll('tr');
5679
- var legacyTop = settings.bSortCellsTop;
5752
+ var titleRow = settings.titleRow;
5680
5753
  var notSelector = ':not([data-dt-order="disable"]):not([data-dt-order="icon-only"])';
5681
5754
 
5682
5755
  // Legacy support for `orderCellsTop`
5683
- if (legacyTop === true) {
5756
+ if (titleRow === true) {
5684
5757
  target = headerRows[0];
5685
5758
  }
5686
- else if (legacyTop === false) {
5759
+ else if (titleRow === false) {
5687
5760
  target = headerRows[ headerRows.length - 1 ];
5688
5761
  }
5762
+ else if (titleRow !== null) {
5763
+ target = headerRows[titleRow];
5764
+ }
5765
+ // else - all rows
5689
5766
 
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
- );
5767
+ if (settings.orderHandler) {
5768
+ _fnSortAttachListener(
5769
+ settings,
5770
+ target,
5771
+ target === settings.nTHead
5772
+ ? 'tr'+notSelector+' th'+notSelector+', tr'+notSelector+' td'+notSelector
5773
+ : 'th'+notSelector+', td'+notSelector
5774
+ );
5775
+ }
5697
5776
 
5698
5777
  // Need to resolve the user input array into our internal structure
5699
5778
  var order = [];
@@ -5708,7 +5787,9 @@
5708
5787
  var run = false;
5709
5788
  var columns = column === undefined
5710
5789
  ? _fnColumnsFromHeader( e.target )
5711
- : [column];
5790
+ : Array.isArray(column)
5791
+ ? column
5792
+ : [column];
5712
5793
 
5713
5794
  if ( columns.length ) {
5714
5795
  for ( var i=0, ien=columns.length ; i<ien ; i++ ) {
@@ -6331,16 +6412,19 @@
6331
6412
 
6332
6413
  // A column name was stored and should be used for restore
6333
6414
  if (typeof col[0] === 'string') {
6415
+ // Find the name from the current list of column names
6334
6416
  var idx = currentNames.indexOf(col[0]);
6335
6417
 
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;
6418
+ if (idx < 0) {
6419
+ // If the column was not found ignore it and continue
6420
+ return;
6421
+ }
6422
+
6423
+ set[0] = idx;
6340
6424
  }
6341
6425
  else if (set[0] >= columns.length) {
6342
- // If a column name, but it is out of bounds, set to 0
6343
- set[0] = 0;
6426
+ // If the column index is out of bounds ignore it and continue
6427
+ return;
6344
6428
  }
6345
6429
 
6346
6430
  settings.aaSorting.push(set);
@@ -6753,6 +6837,23 @@
6753
6837
  }
6754
6838
  }
6755
6839
 
6840
+ /**
6841
+ * Add one or more listeners to the table
6842
+ *
6843
+ * @param {*} that JQ for the table
6844
+ * @param {*} name Event name
6845
+ * @param {*} src Listener(s)
6846
+ */
6847
+ function _fnListener(that, name, src) {
6848
+ if (!Array.isArray(src)) {
6849
+ src = [src];
6850
+ }
6851
+
6852
+ for (i=0 ; i<src.length ; i++) {
6853
+ that.on(name + '.dt', src[i]);
6854
+ }
6855
+ }
6856
+
6756
6857
 
6757
6858
 
6758
6859
  /**
@@ -7409,12 +7510,24 @@
7409
7510
  ['footer', 'aoFooter'],
7410
7511
  ].forEach(function (item) {
7411
7512
  _api_register( 'table().' + item[0] + '.structure()' , function (selector) {
7412
- var indexes = this.columns(selector).indexes().flatten();
7513
+ var indexes = this.columns(selector).indexes().flatten().toArray();
7413
7514
  var ctx = this.context[0];
7414
-
7415
- return _fnHeaderLayout(ctx, ctx[item[1]], indexes);
7416
- } );
7417
- })
7515
+ var structure = _fnHeaderLayout(ctx, ctx[item[1]], indexes);
7516
+
7517
+ // The structure is in column index order - but from this method we want the return to be
7518
+ // in the columns() selector API order. In order to do that we need to map from one form
7519
+ // to the other
7520
+ var orderedIndexes = indexes.slice().sort(function (a, b) {
7521
+ return a - b;
7522
+ });
7523
+
7524
+ return structure.map(function (row) {
7525
+ return indexes.map(function (colIdx) {
7526
+ return row[orderedIndexes.indexOf(colIdx)];
7527
+ });
7528
+ });
7529
+ });
7530
+ });
7418
7531
 
7419
7532
 
7420
7533
  _api_registerPlural( 'tables().containers()', 'table().container()' , function () {
@@ -7763,7 +7876,7 @@
7763
7876
  {
7764
7877
  var
7765
7878
  out = [], res,
7766
- a, i, ien, j, jen,
7879
+ i, ien,
7767
7880
  selectorType = typeof selector;
7768
7881
 
7769
7882
  // Can't just check for isArray here, as an API or jQuery instance might be
@@ -7773,22 +7886,15 @@
7773
7886
  }
7774
7887
 
7775
7888
  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] ];
7780
-
7781
- for ( j=0, jen=a.length ; j<jen ; j++ ) {
7782
- res = selectFn( typeof a[j] === 'string' ? (a[j]).trim() : a[j] );
7889
+ res = selectFn( typeof selector[i] === 'string' ? selector[i].trim() : selector[i] );
7783
7890
 
7784
- // Remove empty items
7785
- res = res.filter( function (item) {
7786
- return item !== null && item !== undefined;
7787
- });
7891
+ // Remove empty items
7892
+ res = res.filter( function (item) {
7893
+ return item !== null && item !== undefined;
7894
+ });
7788
7895
 
7789
- if ( res && res.length ) {
7790
- out = out.concat( res );
7791
- }
7896
+ if ( res && res.length ) {
7897
+ out = out.concat( res );
7792
7898
  }
7793
7899
  }
7794
7900
 
@@ -7817,6 +7923,7 @@
7817
7923
  }
7818
7924
 
7819
7925
  return $.extend( {
7926
+ columnOrder: 'implied',
7820
7927
  search: 'none',
7821
7928
  order: 'current',
7822
7929
  page: 'all'
@@ -8578,23 +8685,60 @@
8578
8685
 
8579
8686
  var __column_header = function ( settings, column, row ) {
8580
8687
  var header = settings.aoHeader;
8581
- var target = row !== undefined
8582
- ? row
8583
- : settings.bSortCellsTop // legacy support
8584
- ? 0
8585
- : header.length - 1;
8688
+ var titleRow = settings.titleRow;
8689
+ var target = null;
8690
+
8691
+ if (row !== undefined) {
8692
+ target = row;
8693
+ }
8694
+ else if (titleRow === true) { // legacy orderCellsTop support
8695
+ target = 0;
8696
+ }
8697
+ else if (titleRow === false) {
8698
+ target = header.length - 1;
8699
+ }
8700
+ else if (titleRow !== null) {
8701
+ target = titleRow;
8702
+ }
8703
+ else {
8704
+ // Automatic - find the _last_ unique cell from the top that is not empty (last for
8705
+ // backwards compatibility)
8706
+ for (var i=0 ; i<header.length ; i++) {
8707
+ if (header[i][column].unique && $('span.dt-column-title', header[i][column].cell).text()) {
8708
+ target = i;
8709
+ }
8710
+ }
8711
+
8712
+ if (target === null) {
8713
+ target = 0;
8714
+ }
8715
+ }
8586
8716
 
8587
8717
  return header[target][column].cell;
8588
8718
  };
8589
8719
 
8720
+ var __column_header_cells = function (header) {
8721
+ var out = [];
8722
+
8723
+ for (var i=0 ; i<header.length ; i++) {
8724
+ for (var j=0 ; j<header[i].length ; j++) {
8725
+ var cell = header[i][j].cell;
8726
+
8727
+ if (!out.includes(cell)) {
8728
+ out.push(cell);
8729
+ }
8730
+ }
8731
+ }
8732
+
8733
+ return out;
8734
+ }
8735
+
8590
8736
  var __column_selector = function ( settings, selector, opts )
8591
8737
  {
8592
8738
  var
8593
8739
  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) );
8740
+ names, titles,
8741
+ nodes = __column_header_cells(settings.aoHeader);
8598
8742
 
8599
8743
  var run = function ( s ) {
8600
8744
  var selInt = _intVal( s );
@@ -8666,12 +8810,21 @@
8666
8810
  } );
8667
8811
 
8668
8812
  case 'name':
8813
+ // Don't get names, unless needed, and only get once if it is
8814
+ if (!names) {
8815
+ names = _pluck( columns, 'sName' );
8816
+ }
8817
+
8669
8818
  // match by name. `names` is column index complete and in order
8670
8819
  return names.map( function (name, i) {
8671
8820
  return name === match[1] ? i : null;
8672
8821
  } );
8673
8822
 
8674
8823
  case 'title':
8824
+ if (!titles) {
8825
+ titles = _pluck( columns, 'sTitle' );
8826
+ }
8827
+
8675
8828
  // match by column title
8676
8829
  return titles.map( function (title, i) {
8677
8830
  return title === match[1] ? i : null;
@@ -8710,7 +8863,11 @@
8710
8863
  [];
8711
8864
  };
8712
8865
 
8713
- return _selector_run( 'column', selector, run, settings, opts );
8866
+ var selected = _selector_run( 'column', selector, run, settings, opts );
8867
+
8868
+ return opts.columnOrder && opts.columnOrder === 'index'
8869
+ ? selected.sort(function (a, b) { return a - b; })
8870
+ : selected; // implied
8714
8871
  };
8715
8872
 
8716
8873
 
@@ -8834,6 +8991,12 @@
8834
8991
  }, 1 );
8835
8992
  } );
8836
8993
 
8994
+ _api_registerPlural( 'columns().names()', 'column().name()', function () {
8995
+ return this.iterator( 'column', function ( settings, column ) {
8996
+ return settings.aoColumns[column].sName;
8997
+ }, 1 );
8998
+ } );
8999
+
8837
9000
  _api_registerPlural( 'columns().nodes()', 'column().nodes()', function () {
8838
9001
  return this.iterator( 'column-rows', function ( settings, column, i, j, rows ) {
8839
9002
  return _pluck_order( settings.aoData, rows, 'anCells', column ) ;
@@ -9260,7 +9423,10 @@
9260
9423
  // otherwise a 2D array was passed in
9261
9424
 
9262
9425
  return this.iterator( 'table', function ( settings ) {
9263
- settings.aaSorting = Array.isArray(order) ? order.slice() : order;
9426
+ var resolved = [];
9427
+ _fnSortResolve(settings, resolved, order);
9428
+
9429
+ settings.aaSorting = resolved;
9264
9430
  } );
9265
9431
  } );
9266
9432
 
@@ -9386,7 +9552,7 @@
9386
9552
  var fixed = settings.searchFixed;
9387
9553
 
9388
9554
  if (! name) {
9389
- return Object.keys(fixed)
9555
+ return Object.keys(fixed);
9390
9556
  }
9391
9557
  else if (search === undefined) {
9392
9558
  return fixed[name];
@@ -9453,10 +9619,10 @@
9453
9619
  var fixed = settings.aoColumns[colIdx].searchFixed;
9454
9620
 
9455
9621
  if (! name) {
9456
- return Object.keys(fixed)
9622
+ return Object.keys(fixed);
9457
9623
  }
9458
9624
  else if (search === undefined) {
9459
- return fixed[name];
9625
+ return fixed[name] || null;
9460
9626
  }
9461
9627
  else if (search === null) {
9462
9628
  delete fixed[name];
@@ -9908,14 +10074,9 @@
9908
10074
  jqTable.append( tfoot );
9909
10075
  }
9910
10076
 
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
-
10077
+ // Clean up the header / footer
10078
+ cleanHeader(thead, 'header');
10079
+ cleanHeader(tfoot, 'footer');
9919
10080
  settings.colgroup.remove();
9920
10081
 
9921
10082
  settings.aaSorting = [];
@@ -9937,7 +10098,6 @@
9937
10098
  orderClasses.isDesc
9938
10099
  )
9939
10100
  .css('width', '')
9940
- .removeAttr('data-dt-column')
9941
10101
  .removeAttr('aria-sort');
9942
10102
 
9943
10103
  // Add the TR elements back into the table in their original order
@@ -10018,6 +10178,19 @@
10018
10178
  : resolved;
10019
10179
  } );
10020
10180
 
10181
+ // Needed for header and footer, so pulled into its own function
10182
+ function cleanHeader(node, className) {
10183
+ $(node).find('span.dt-column-order').remove();
10184
+ $(node).find('span.dt-column-title').each(function () {
10185
+ var title = $(this).html();
10186
+ $(this).parent().parent().append(title);
10187
+ $(this).remove();
10188
+ });
10189
+ $(node).find('div.dt-column-' + className).remove();
10190
+
10191
+ $('th, td', node).removeAttr('data-dt-column');
10192
+ }
10193
+
10021
10194
  /**
10022
10195
  * Version string for plug-ins to check compatibility. Allowed format is
10023
10196
  * `a.b.c-d` where: a:int, b:int, c:int, d:string(dev|beta|alpha). `d` is used
@@ -10026,7 +10199,7 @@
10026
10199
  * @type string
10027
10200
  * @default Version number
10028
10201
  */
10029
- DataTable.version = "2.2.2";
10202
+ DataTable.version = "2.3.1";
10030
10203
 
10031
10204
  /**
10032
10205
  * Private data store, containing all of the settings objects that are
@@ -10633,6 +10806,10 @@
10633
10806
  "bSortCellsTop": null,
10634
10807
 
10635
10808
 
10809
+ /** Specify which row is the title row in the header. Replacement for bSortCellsTop */
10810
+ titleRow: null,
10811
+
10812
+
10636
10813
  /**
10637
10814
  * Enable or disable the addition of the classes `sorting\_1`, `sorting\_2` and
10638
10815
  * `sorting\_3` to the columns which are currently being sorted on. This is
@@ -10910,6 +11087,13 @@
10910
11087
  1: "entry"
10911
11088
  },
10912
11089
 
11090
+ /**
11091
+ * Page length options
11092
+ */
11093
+ lengthLabels: {
11094
+ '-1': 'All'
11095
+ },
11096
+
10913
11097
  /**
10914
11098
  * This string is shown in preference to `zeroRecords` when the table is
10915
11099
  * empty of data (regardless of filtering). Note that this is an optional
@@ -11180,7 +11364,10 @@
11180
11364
  /**
11181
11365
  * For server-side processing - use the data from the DOM for the first draw
11182
11366
  */
11183
- iDeferLoading: null
11367
+ iDeferLoading: null,
11368
+
11369
+ /** Event listeners */
11370
+ on: null
11184
11371
  };
11185
11372
 
11186
11373
  _fnHungarianMap( DataTable.defaults );
@@ -12007,10 +12194,7 @@
12007
12194
 
12008
12195
  /**
12009
12196
  * 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}.
12197
+ * one unique cell per column. Replaced by titleRow
12014
12198
  */
12015
12199
  "bSortCellsTop": null,
12016
12200
 
@@ -12135,7 +12319,19 @@
12135
12319
  resizeObserver: null,
12136
12320
 
12137
12321
  /** Keep a record of the last size of the container, so we can skip duplicates */
12138
- containerWidth: -1
12322
+ containerWidth: -1,
12323
+
12324
+ /** Reverse the initial order of the data set on desc ordering */
12325
+ orderDescReverse: null,
12326
+
12327
+ /** Show / hide ordering indicators in headers */
12328
+ orderIndicators: true,
12329
+
12330
+ /** Default ordering listener */
12331
+ orderHandler: true,
12332
+
12333
+ /** Title row indicator */
12334
+ titleRow: null
12139
12335
  };
12140
12336
 
12141
12337
  /**
@@ -12965,7 +13161,7 @@
12965
13161
  cell.addClass(classes.order.none);
12966
13162
  }
12967
13163
 
12968
- var legacyTop = settings.bSortCellsTop;
13164
+ var titleRow = settings.titleRow;
12969
13165
  var headerRows = cell.closest('thead').find('tr');
12970
13166
  var rowIdx = cell.parent().index();
12971
13167
 
@@ -12975,11 +13171,10 @@
12975
13171
  cell.attr('data-dt-order') === 'disable' ||
12976
13172
  cell.parent().attr('data-dt-order') === 'disable' ||
12977
13173
 
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)
13174
+ // titleRow support, for defining a specific row in the header
13175
+ (titleRow === true && rowIdx !== 0) ||
13176
+ (titleRow === false && rowIdx !== headerRows.length - 1) ||
13177
+ (typeof titleRow === 'number' && rowIdx !== titleRow)
12983
13178
  ) {
12984
13179
  return;
12985
13180
  }
@@ -12989,7 +13184,7 @@
12989
13184
  // `DT` namespace will allow the event to be removed automatically
12990
13185
  // on destroy, while the `dt` namespaced event is the one we are
12991
13186
  // listening for
12992
- $(settings.nTable).on( 'order.dt.DT column-visibility.dt.DT', function ( e, ctx ) {
13187
+ $(settings.nTable).on( 'order.dt.DT column-visibility.dt.DT', function ( e, ctx, column ) {
12993
13188
  if ( settings !== ctx ) { // need to check this this is the host
12994
13189
  return; // table, not a nested one
12995
13190
  }
@@ -13000,6 +13195,16 @@
13000
13195
  return;
13001
13196
  }
13002
13197
 
13198
+ var orderedColumns = _pluck(sorting, 'col');
13199
+
13200
+ // This handler is only needed on column visibility if the column is part of the
13201
+ // ordering. If it isn't, then we can bail out to save performance. It could be a
13202
+ // separate event handler, but this is a balance between code reuse / size and performance
13203
+ // console.log(e, e.name, column, orderedColumns, orderedColumns.includes(column))
13204
+ if (e.type === 'column-visibility' && ! orderedColumns.includes(column)) {
13205
+ return;
13206
+ }
13207
+
13003
13208
  var i;
13004
13209
  var orderClasses = classes.order;
13005
13210
  var columns = ctx.api.columns( cell );
@@ -13008,8 +13213,8 @@
13008
13213
  var ariaType = '';
13009
13214
  var indexes = columns.indexes();
13010
13215
  var sortDirs = columns.orderable(true).flatten();
13011
- var orderedColumns = _pluck(sorting, 'col');
13012
13216
  var tabIndex = settings.iTabIndex;
13217
+ var canOrder = ctx.orderHandler && orderable;
13013
13218
 
13014
13219
  cell
13015
13220
  .removeClass(
@@ -13017,8 +13222,8 @@
13017
13222
  orderClasses.isDesc
13018
13223
  )
13019
13224
  .toggleClass( orderClasses.none, ! orderable )
13020
- .toggleClass( orderClasses.canAsc, orderable && sortDirs.includes('asc') )
13021
- .toggleClass( orderClasses.canDesc, orderable && sortDirs.includes('desc') );
13225
+ .toggleClass( orderClasses.canAsc, canOrder && sortDirs.includes('asc') )
13226
+ .toggleClass( orderClasses.canDesc, canOrder && sortDirs.includes('desc') );
13022
13227
 
13023
13228
  // Determine if all of the columns that this cell covers are included in the
13024
13229
  // current ordering
@@ -13777,12 +13982,17 @@
13777
13982
  } );
13778
13983
 
13779
13984
  for ( i=0 ; i<lengths.length ; i++ ) {
13780
- select[0][ i ] = new Option(
13781
- typeof language[i] === 'number' ?
13985
+ // Attempt to look up the length from the i18n options
13986
+ var label = settings.api.i18n('lengthLabels.' + lengths[i], null);
13987
+
13988
+ if (label === null) {
13989
+ // If not present, fallback to old style
13990
+ label = typeof language[i] === 'number' ?
13782
13991
  settings.fnFormatNumber( language[i] ) :
13783
- language[i],
13784
- lengths[i]
13785
- );
13992
+ language[i];
13993
+ }
13994
+
13995
+ select[0][ i ] = new Option(label, lengths[i]);
13786
13996
  }
13787
13997
 
13788
13998
  // add for and id to label and input