tabulator-tables 5.4.4 → 5.5.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.
Files changed (106) hide show
  1. package/bower.json +1 -1
  2. package/build/Bundler.js +7 -3
  3. package/dist/css/tabulator.css +85 -48
  4. package/dist/css/tabulator.css.map +1 -1
  5. package/dist/css/tabulator.min.css +1 -1
  6. package/dist/css/tabulator.min.css.map +1 -1
  7. package/dist/css/tabulator_bootstrap3.css +94 -53
  8. package/dist/css/tabulator_bootstrap3.css.map +1 -1
  9. package/dist/css/tabulator_bootstrap3.min.css +1 -1
  10. package/dist/css/tabulator_bootstrap3.min.css.map +1 -1
  11. package/dist/css/tabulator_bootstrap4.css +111 -68
  12. package/dist/css/tabulator_bootstrap4.css.map +1 -1
  13. package/dist/css/tabulator_bootstrap4.min.css +1 -1
  14. package/dist/css/tabulator_bootstrap4.min.css.map +1 -1
  15. package/dist/css/tabulator_bootstrap5.css +115 -70
  16. package/dist/css/tabulator_bootstrap5.css.map +1 -1
  17. package/dist/css/tabulator_bootstrap5.min.css +1 -1
  18. package/dist/css/tabulator_bootstrap5.min.css.map +1 -1
  19. package/dist/css/tabulator_bulma.css +100 -57
  20. package/dist/css/tabulator_bulma.css.map +1 -1
  21. package/dist/css/tabulator_bulma.min.css +1 -1
  22. package/dist/css/tabulator_bulma.min.css.map +1 -1
  23. package/dist/css/tabulator_materialize.css +109 -69
  24. package/dist/css/tabulator_materialize.css.map +1 -1
  25. package/dist/css/tabulator_materialize.min.css +1 -1
  26. package/dist/css/tabulator_materialize.min.css.map +1 -1
  27. package/dist/css/tabulator_midnight.css +95 -54
  28. package/dist/css/tabulator_midnight.css.map +1 -1
  29. package/dist/css/tabulator_midnight.min.css +1 -1
  30. package/dist/css/tabulator_midnight.min.css.map +1 -1
  31. package/dist/css/tabulator_modern.css +101 -57
  32. package/dist/css/tabulator_modern.css.map +1 -1
  33. package/dist/css/tabulator_modern.min.css +1 -1
  34. package/dist/css/tabulator_modern.min.css.map +1 -1
  35. package/dist/css/tabulator_semanticui.css +138 -77
  36. package/dist/css/tabulator_semanticui.css.map +1 -1
  37. package/dist/css/tabulator_semanticui.min.css +1 -1
  38. package/dist/css/tabulator_semanticui.min.css.map +1 -1
  39. package/dist/css/tabulator_simple.css +85 -48
  40. package/dist/css/tabulator_simple.css.map +1 -1
  41. package/dist/css/tabulator_simple.min.css +1 -1
  42. package/dist/css/tabulator_simple.min.css.map +1 -1
  43. package/dist/css/tabulator_site.css +93 -52
  44. package/dist/css/tabulator_site.css.map +1 -1
  45. package/dist/css/tabulator_site.min.css +1 -1
  46. package/dist/css/tabulator_site.min.css.map +1 -1
  47. package/dist/js/jquery_wrapper.js +10 -2
  48. package/dist/js/tabulator.js +507 -237
  49. package/dist/js/tabulator.js.map +1 -1
  50. package/dist/js/tabulator.min.js +2 -2
  51. package/dist/js/tabulator.min.js.map +1 -1
  52. package/dist/js/tabulator_esm.js +507 -237
  53. package/dist/js/tabulator_esm.js.map +1 -1
  54. package/dist/js/tabulator_esm.min.js +2 -2
  55. package/dist/js/tabulator_esm.min.js.map +1 -1
  56. package/package.json +3 -2
  57. package/src/js/builds/jquery_wrapper.js +10 -2
  58. package/src/js/core/ColumnManager.js +15 -0
  59. package/src/js/core/RowManager.js +59 -41
  60. package/src/js/core/cell/CellComponent.js +5 -3
  61. package/src/js/core/column/ColumnComponent.js +2 -2
  62. package/src/js/core/rendering/renderers/BasicHorizontal.js +12 -5
  63. package/src/js/core/rendering/renderers/BasicVertical.js +49 -28
  64. package/src/js/core/rendering/renderers/VirtualDomHorizontal.js +6 -1
  65. package/src/js/core/rendering/renderers/VirtualDomVertical.js +87 -30
  66. package/src/js/core/row/Row.js +9 -3
  67. package/src/js/core/row/RowComponent.js +2 -2
  68. package/src/js/core/tools/DataLoader.js +44 -36
  69. package/src/js/modules/ColumnCalcs/defaults/calculations.js +7 -0
  70. package/src/js/modules/DataTree/DataTree.js +5 -2
  71. package/src/js/modules/Download/defaults/downloaders/xlsx.js +5 -2
  72. package/src/js/modules/Edit/Edit.js +2 -3
  73. package/src/js/modules/Edit/List.js +14 -3
  74. package/src/js/modules/Edit/defaults/editors/date.js +1 -1
  75. package/src/js/modules/Edit/defaults/editors/datetime.js +1 -1
  76. package/src/js/modules/Edit/defaults/editors/input.js +1 -1
  77. package/src/js/modules/Edit/defaults/editors/number.js +1 -1
  78. package/src/js/modules/Edit/defaults/editors/range.js +1 -1
  79. package/src/js/modules/Edit/defaults/editors/textarea.js +1 -1
  80. package/src/js/modules/Edit/defaults/editors/tickCross.js +1 -1
  81. package/src/js/modules/Edit/defaults/editors/time.js +1 -1
  82. package/src/js/modules/Export/Export.js +3 -0
  83. package/src/js/modules/Filter/Filter.js +11 -0
  84. package/src/js/modules/Format/Format.js +3 -0
  85. package/src/js/modules/Format/defaults/formatters/money.js +9 -2
  86. package/src/js/modules/FrozenColumns/FrozenColumns.js +1 -1
  87. package/src/js/modules/GroupRows/Group.js +27 -10
  88. package/src/js/modules/GroupRows/GroupComponent.js +4 -0
  89. package/src/js/modules/History/defaults/redoers.js +4 -2
  90. package/src/js/modules/History/defaults/undoers.js +6 -2
  91. package/src/js/modules/Interaction/Interaction.js +12 -0
  92. package/src/js/modules/Persistence/Persistence.js +15 -1
  93. package/src/js/modules/ResponsiveLayout/ResponsiveLayout.js +3 -0
  94. package/src/js/modules/SelectRow/SelectRow.js +82 -54
  95. package/src/scss/tabulator.scss +87 -50
  96. package/src/scss/themes/bootstrap/tabulator_bootstrap3.scss +9 -5
  97. package/src/scss/themes/bootstrap/tabulator_bootstrap4.scss +27 -19
  98. package/src/scss/themes/bootstrap/tabulator_bootstrap5.scss +29 -19
  99. package/src/scss/themes/bulma/tabulator_bulma.scss +15 -9
  100. package/src/scss/themes/materialize/tabulator_materialize.scss +15 -11
  101. package/src/scss/themes/materialize/variables.scss +1 -1
  102. package/src/scss/themes/semanticui/tabulator_semanticui.scss +53 -28
  103. package/src/scss/themes/semanticui/variables_table.scss +1 -1
  104. package/src/scss/themes/tabulator_midnight.scss +10 -6
  105. package/src/scss/themes/tabulator_modern.scss +16 -8
  106. package/src/scss/themes/tabulator_site.scss +8 -4
@@ -1,4 +1,4 @@
1
- /* Tabulator v5.4.4 (c) Oliver Folkerd 2023 */
1
+ /* Tabulator v5.5.1 (c) Oliver Folkerd 2023 */
2
2
  (function (global, factory) {
3
3
  typeof exports === 'object' && typeof module !== 'undefined' ? module.exports = factory() :
4
4
  typeof define === 'function' && define.amd ? define(factory) :
@@ -310,8 +310,8 @@
310
310
  return this._column;
311
311
  }
312
312
 
313
- scrollTo(){
314
- return this._column.table.columnManager.scrollToColumn(this._column);
313
+ scrollTo(position, ifVisible){
314
+ return this._column.table.columnManager.scrollToColumn(this._column, position, ifVisible);
315
315
  }
316
316
 
317
317
  getTable(){
@@ -419,10 +419,12 @@
419
419
  return this._cell.row.getComponent();
420
420
  }
421
421
 
422
- getData(){
423
- return this._cell.row.getData();
422
+ getData(transform){
423
+ return this._cell.row.getData(transform);
424
+ }
425
+ getType(){
426
+ return "cell";
424
427
  }
425
-
426
428
  getField(){
427
429
  return this._cell.column.getField();
428
430
  }
@@ -1995,14 +1997,21 @@
1995
1997
  constructor(table){
1996
1998
  super(table);
1997
1999
  }
1998
-
1999
- renderRowCells(row){
2000
+
2001
+ renderRowCells(row, inFragment) {
2002
+ const rowFrag = document.createDocumentFragment();
2000
2003
  row.cells.forEach((cell) => {
2001
- row.element.appendChild(cell.getElement());
2002
- cell.cellRendered();
2004
+ rowFrag.appendChild(cell.getElement());
2003
2005
  });
2006
+ row.element.appendChild(rowFrag);
2007
+
2008
+ if(!inFragment){
2009
+ row.cells.forEach((cell) => {
2010
+ cell.cellRendered();
2011
+ });
2012
+ }
2004
2013
  }
2005
-
2014
+
2006
2015
  reinitializeColumnWidths(columns){
2007
2016
  columns.forEach(function(column){
2008
2017
  column.reinitializeWidth();
@@ -2183,8 +2192,13 @@
2183
2192
  if(this.initialized){
2184
2193
  this.initializeRow(row);
2185
2194
  }else {
2195
+ const rowFrag = document.createDocumentFragment();
2196
+ row.cells.forEach((cell) => {
2197
+ rowFrag.appendChild(cell.getElement());
2198
+ });
2199
+ row.element.appendChild(rowFrag);
2200
+
2186
2201
  row.cells.forEach((cell) => {
2187
- row.element.appendChild(cell.getElement());
2188
2202
  cell.cellRendered();
2189
2203
  });
2190
2204
  }
@@ -2619,6 +2633,8 @@
2619
2633
 
2620
2634
  this.contentsElement.insertBefore(this.headersElement, this.contentsElement.firstChild);
2621
2635
  this.element.insertBefore(this.contentsElement, this.element.firstChild);
2636
+
2637
+ this.initializeScrollWheelWatcher();
2622
2638
 
2623
2639
  this.subscribe("scroll-horizontal", this.scrollHorizontal.bind(this));
2624
2640
  this.subscribe("scrollbar-vertical", this.padVerticalScrollbar.bind(this));
@@ -2710,6 +2726,19 @@
2710
2726
 
2711
2727
  this.renderer.scrollColumns(left);
2712
2728
  }
2729
+
2730
+ initializeScrollWheelWatcher(){
2731
+ this.contentsElement.addEventListener("wheel", (e) => {
2732
+ var left;
2733
+
2734
+ if(e.deltaX){
2735
+ left = this.contentsElement.scrollLeft + e.deltaX;
2736
+
2737
+ this.table.rowManager.scrollHorizontal(left);
2738
+ this.table.columnManager.scrollHorizontal(left);
2739
+ }
2740
+ });
2741
+ }
2713
2742
 
2714
2743
  ///////////// Column Setup Functions /////////////
2715
2744
  generateColumnsFromRowData(data){
@@ -3364,8 +3393,8 @@
3364
3393
  return this._row.delete();
3365
3394
  }
3366
3395
 
3367
- scrollTo(){
3368
- return this._row.table.rowManager.scrollToRow(this._row);
3396
+ scrollTo(position, ifVisible){
3397
+ return this._row.table.rowManager.scrollToRow(this._row, position, ifVisible);
3369
3398
  }
3370
3399
 
3371
3400
  move(to, after){
@@ -3466,7 +3495,7 @@
3466
3495
  }
3467
3496
 
3468
3497
  //functions to setup on first render
3469
- initialize(force){
3498
+ initialize(force, inFragment){
3470
3499
  this.create();
3471
3500
 
3472
3501
  if(!this.initialized || force){
@@ -3481,7 +3510,7 @@
3481
3510
 
3482
3511
  this.initialized = true;
3483
3512
 
3484
- this.table.columnManager.renderer.renderRowCells(this);
3513
+ this.table.columnManager.renderer.renderRowCells(this, inFragment);
3485
3514
 
3486
3515
  if(force){
3487
3516
  this.normalizeHeight();
@@ -3495,9 +3524,15 @@
3495
3524
 
3496
3525
  this.dispatch("row-layout-after", this);
3497
3526
  }else {
3498
- this.table.columnManager.renderer.rerenderRowCells(this);
3527
+ this.table.columnManager.renderer.rerenderRowCells(this, inFragment);
3499
3528
  }
3500
3529
  }
3530
+
3531
+ rendered(){
3532
+ this.cells.forEach((cell) => {
3533
+ cell.cellRendered();
3534
+ });
3535
+ }
3501
3536
 
3502
3537
  reinitializeHeight(){
3503
3538
  this.heightInitialized = false;
@@ -3860,79 +3895,100 @@
3860
3895
  class BasicVertical extends Renderer{
3861
3896
  constructor(table){
3862
3897
  super(table);
3863
-
3898
+
3864
3899
  this.verticalFillMode = "fill";
3865
-
3900
+
3866
3901
  this.scrollTop = 0;
3867
3902
  this.scrollLeft = 0;
3868
-
3903
+
3869
3904
  this.scrollTop = 0;
3870
3905
  this.scrollLeft = 0;
3871
3906
  }
3872
-
3907
+
3873
3908
  clearRows(){
3874
3909
  var element = this.tableElement;
3875
-
3910
+
3876
3911
  // element.children.detach();
3877
3912
  while(element.firstChild) element.removeChild(element.firstChild);
3878
-
3913
+
3879
3914
  element.scrollTop = 0;
3880
3915
  element.scrollLeft = 0;
3881
-
3916
+
3882
3917
  element.style.minWidth = "";
3883
3918
  element.style.minHeight = "";
3884
3919
  element.style.display = "";
3885
3920
  element.style.visibility = "";
3886
3921
  }
3887
-
3888
- renderRows(){
3922
+
3923
+ renderRows() {
3889
3924
  var element = this.tableElement,
3890
- onlyGroupHeaders = true;
3891
-
3892
- this.rows().forEach((row, index) => {
3925
+ onlyGroupHeaders = true,
3926
+ tableFrag = document.createDocumentFragment(),
3927
+ rows = this.rows();
3928
+
3929
+ rows.forEach((row, index) => {
3893
3930
  this.styleRow(row, index);
3894
- element.appendChild(row.getElement());
3895
- row.initialize(true);
3896
-
3897
- if(row.type !== "group"){
3931
+ row.initialize(false, true);
3932
+
3933
+ if (row.type !== "group") {
3898
3934
  onlyGroupHeaders = false;
3899
3935
  }
3936
+
3937
+ tableFrag.appendChild(row.getElement());
3900
3938
  });
3901
-
3939
+
3940
+ element.appendChild(tableFrag);
3941
+
3942
+ rows.forEach((row) => {
3943
+ row.rendered();
3944
+
3945
+ if(!row.heightInitialized) {
3946
+ row.calcHeight(true);
3947
+ }
3948
+ });
3949
+
3950
+ rows.forEach((row) => {
3951
+ if(!row.heightInitialized) {
3952
+ row.setCellHeight();
3953
+ }
3954
+ });
3955
+
3956
+
3957
+
3902
3958
  if(onlyGroupHeaders){
3903
3959
  element.style.minWidth = this.table.columnManager.getWidth() + "px";
3904
3960
  }else {
3905
3961
  element.style.minWidth = "";
3906
3962
  }
3907
3963
  }
3908
-
3909
-
3964
+
3965
+
3910
3966
  rerenderRows(callback){
3911
3967
  this.clearRows();
3912
-
3968
+
3913
3969
  if(callback){
3914
3970
  callback();
3915
3971
  }
3916
-
3972
+
3917
3973
  this.renderRows();
3918
3974
  }
3919
-
3975
+
3920
3976
  scrollToRowNearestTop(row){
3921
3977
  var rowTop = Helpers.elOffset(row.getElement()).top;
3922
-
3978
+
3923
3979
  return !(Math.abs(this.elementVertical.scrollTop - rowTop) > Math.abs(this.elementVertical.scrollTop + this.elementVertical.clientHeight - rowTop));
3924
3980
  }
3925
-
3981
+
3926
3982
  scrollToRow(row){
3927
3983
  var rowEl = row.getElement();
3928
-
3984
+
3929
3985
  this.elementVertical.scrollTop = Helpers.elOffset(rowEl).top - Helpers.elOffset(this.elementVertical).top + this.elementVertical.scrollTop;
3930
3986
  }
3931
-
3987
+
3932
3988
  visibleRows(includingBuffer){
3933
3989
  return this.rows();
3934
3990
  }
3935
-
3991
+
3936
3992
  }
3937
3993
 
3938
3994
  class VirtualDomVertical extends Renderer{
@@ -3978,7 +4034,6 @@
3978
4034
 
3979
4035
  element.style.paddingTop = "";
3980
4036
  element.style.paddingBottom = "";
3981
- // element.style.minWidth = "";
3982
4037
  element.style.minHeight = "";
3983
4038
  element.style.display = "";
3984
4039
  element.style.visibility = "";
@@ -4157,17 +4212,27 @@
4157
4212
  //////////////////////////////////////
4158
4213
 
4159
4214
  //full virtual render
4160
- _virtualRenderFill(position, forceMove, offset){
4215
+ _virtualRenderFill(position, forceMove, offset) {
4161
4216
  var element = this.tableElement,
4162
4217
  holder = this.elementVertical,
4163
4218
  topPad = 0,
4164
4219
  rowsHeight = 0,
4220
+ rowHeight = 0,
4165
4221
  heightOccupied = 0,
4166
4222
  topPadHeight = 0,
4167
4223
  i = 0,
4168
4224
  rows = this.rows(),
4169
4225
  rowsCount = rows.length,
4170
- containerHeight = this.elementVertical.clientHeight;
4226
+ index = 0,
4227
+ row,
4228
+ rowFragment,
4229
+ renderedRows = [],
4230
+ totalRowsRendered = 0,
4231
+ rowsToRender = 0,
4232
+ fixedHeight = this.table.rowManager.fixedHeight,
4233
+ containerHeight = this.elementVertical.clientHeight,
4234
+ avgRowHeight = this.table.options.rowHeight,
4235
+ resized = true;
4171
4236
 
4172
4237
  position = position || 0;
4173
4238
 
@@ -4195,44 +4260,92 @@
4195
4260
 
4196
4261
  if(rowsCount && Helpers.elVisible(this.elementVertical)){
4197
4262
  this.vDomTop = position;
4198
-
4199
4263
  this.vDomBottom = position -1;
4200
4264
 
4201
- while ((rowsHeight <= containerHeight + this.vDomWindowBuffer || i < this.vDomWindowMinTotalRows) && this.vDomBottom < rowsCount -1){
4202
- var index = this.vDomBottom + 1,
4203
- row = rows[index],
4204
- rowHeight = 0;
4265
+ if(fixedHeight || this.table.options.maxHeight) {
4266
+ if(avgRowHeight) {
4267
+ rowsToRender = (containerHeight / avgRowHeight) + (this.vDomWindowBuffer / avgRowHeight);
4268
+ }
4269
+ rowsToRender = Math.max(this.vDomWindowMinTotalRows, Math.ceil(rowsToRender));
4270
+ }
4271
+ else {
4272
+ rowsToRender = rowsCount;
4273
+ }
4205
4274
 
4206
- this.styleRow(row, index);
4275
+ while(((rowsToRender == rowsCount || rowsHeight <= containerHeight + this.vDomWindowBuffer) || totalRowsRendered < this.vDomWindowMinTotalRows) && this.vDomBottom < rowsCount -1) {
4276
+ renderedRows = [];
4277
+ rowFragment = document.createDocumentFragment();
4207
4278
 
4208
- element.appendChild(row.getElement());
4279
+ i = 0;
4209
4280
 
4210
- row.initialize();
4281
+ while ((i < rowsToRender) && this.vDomBottom < rowsCount -1) {
4282
+ index = this.vDomBottom + 1,
4283
+ row = rows[index];
4211
4284
 
4212
- if(!row.heightInitialized){
4213
- row.normalizeHeight(true);
4214
- }
4285
+ this.styleRow(row, index);
4215
4286
 
4216
- rowHeight = row.getHeight();
4287
+ row.initialize(false, true);
4288
+ if(!row.heightInitialized && !this.table.options.rowHeight){
4289
+ row.clearCellHeight();
4290
+ }
4217
4291
 
4218
- if(i < topPad){
4219
- topPadHeight += rowHeight;
4220
- }else {
4221
- rowsHeight += rowHeight;
4292
+ rowFragment.appendChild(row.getElement());
4293
+ renderedRows.push(row);
4294
+ this.vDomBottom ++;
4295
+ i++;
4222
4296
  }
4223
4297
 
4224
- if(rowHeight > this.vDomWindowBuffer){
4225
- this.vDomWindowBuffer = rowHeight * 2;
4298
+ if(!renderedRows.length){
4299
+ break;
4226
4300
  }
4227
4301
 
4228
- this.vDomBottom ++;
4229
- i++;
4302
+ element.appendChild(rowFragment);
4303
+
4304
+ // NOTE: The next 3 loops are separate on purpose
4305
+ // This is to batch up the dom writes and reads which drastically improves performance
4306
+
4307
+ renderedRows.forEach((row) => {
4308
+ row.rendered();
4309
+
4310
+ if(!row.heightInitialized) {
4311
+ row.calcHeight(true);
4312
+ }
4313
+ });
4314
+
4315
+ renderedRows.forEach((row) => {
4316
+ if(!row.heightInitialized) {
4317
+ row.setCellHeight();
4318
+ }
4319
+ });
4320
+
4321
+ renderedRows.forEach((row) => {
4322
+ rowHeight = row.getHeight();
4323
+
4324
+ if(totalRowsRendered < topPad){
4325
+ topPadHeight += rowHeight;
4326
+ }else {
4327
+ rowsHeight += rowHeight;
4328
+ }
4329
+
4330
+ if(rowHeight > this.vDomWindowBuffer){
4331
+ this.vDomWindowBuffer = rowHeight * 2;
4332
+ }
4333
+ totalRowsRendered++;
4334
+ });
4335
+
4336
+ resized = this.table.rowManager.adjustTableSize();
4337
+ containerHeight = this.elementVertical.clientHeight;
4338
+ if(resized && (fixedHeight || this.table.options.maxHeight))
4339
+ {
4340
+ avgRowHeight = rowsHeight / totalRowsRendered;
4341
+ rowsToRender = Math.max(this.vDomWindowMinTotalRows, Math.ceil((containerHeight / avgRowHeight) + (this.vDomWindowBuffer / avgRowHeight)));
4342
+ }
4230
4343
  }
4231
4344
 
4232
4345
  if(!position){
4233
4346
  this.vDomTopPad = 0;
4234
4347
  //adjust row height to match average of rendered elements
4235
- this.vDomRowHeight = Math.floor((rowsHeight + topPadHeight) / i);
4348
+ this.vDomRowHeight = Math.floor((rowsHeight + topPadHeight) / totalRowsRendered);
4236
4349
  this.vDomBottomPad = this.vDomRowHeight * (rowsCount - this.vDomBottom -1);
4237
4350
 
4238
4351
  this.vDomScrollHeight = topPadHeight + rowsHeight + this.vDomBottomPad - containerHeight;
@@ -4240,9 +4353,9 @@
4240
4353
  this.vDomTopPad = !forceMove ? this.scrollTop - topPadHeight : (this.vDomRowHeight * this.vDomTop) + offset;
4241
4354
  this.vDomBottomPad = this.vDomBottom == rowsCount-1 ? 0 : Math.max(this.vDomScrollHeight - this.vDomTopPad - rowsHeight - topPadHeight, 0);
4242
4355
  }
4243
-
4244
- element.style.paddingTop = this.vDomTopPad + "px";
4245
- element.style.paddingBottom = this.vDomBottomPad + "px";
4356
+
4357
+ element.style.paddingTop = this.vDomTopPad+"px";
4358
+ element.style.paddingBottom = this.vDomBottomPad+"px";
4246
4359
 
4247
4360
  if(forceMove){
4248
4361
  this.scrollTop = this.vDomTopPad + (topPadHeight) + offset - (this.elementVertical.scrollWidth > this.elementVertical.clientWidth ? this.elementVertical.offsetHeight - containerHeight : 0);
@@ -4545,7 +4658,7 @@
4545
4658
 
4546
4659
  this.dataPipeline = []; //hold data pipeline tasks
4547
4660
  this.displayPipeline = []; //hold data display pipeline tasks
4548
-
4661
+
4549
4662
  this.scrollbarWidth = 0;
4550
4663
 
4551
4664
  this.renderer = null;
@@ -4574,12 +4687,18 @@
4574
4687
 
4575
4688
  initializePlaceholder(){
4576
4689
  var placeholder = this.table.options.placeholder;
4577
-
4690
+
4691
+ if(typeof placeholder === "function"){
4692
+ placeholder = placeholder.call(this.table);
4693
+ }
4694
+
4695
+ placeholder = this.chain("placeholder", [placeholder], placeholder, placeholder) || placeholder;
4696
+
4578
4697
  //configure placeholder element
4579
4698
  if(placeholder){
4580
4699
  let el = document.createElement("div");
4581
4700
  el.classList.add("tabulator-placeholder");
4582
-
4701
+
4583
4702
  if(typeof placeholder == "string"){
4584
4703
  let contents = document.createElement("div");
4585
4704
  contents.classList.add("tabulator-placeholder-contents");
@@ -4595,10 +4714,10 @@
4595
4714
  this.placeholderContents = placeholder;
4596
4715
  }else {
4597
4716
  console.warn("Invalid placeholder provided, must be string or HTML Element", placeholder);
4598
-
4717
+
4599
4718
  this.el = null;
4600
4719
  }
4601
-
4720
+
4602
4721
  this.placeholder = el;
4603
4722
  }
4604
4723
  }
@@ -4759,15 +4878,15 @@
4759
4878
  this.destroy();
4760
4879
 
4761
4880
  this.adjustTableSize();
4762
-
4881
+
4763
4882
  this.dispatch("rows-wiped");
4764
4883
  }
4765
-
4884
+
4766
4885
  destroy(){
4767
4886
  this.rows.forEach((row) => {
4768
4887
  row.wipe();
4769
4888
  });
4770
-
4889
+
4771
4890
  this.rows = [];
4772
4891
  this.activeRows = [];
4773
4892
  this.activeRowsPipeline = [];
@@ -4840,7 +4959,7 @@
4840
4959
  rows.push(row);
4841
4960
  this.dispatch("row-added", row, item, pos, index);
4842
4961
  });
4843
-
4962
+
4844
4963
  this.refreshActiveData(refreshDisplayOnly ? "displayPipeline" : false, false, true);
4845
4964
 
4846
4965
  this.regenerateRowPositions();
@@ -5228,28 +5347,28 @@
5228
5347
 
5229
5348
  for(let i = index; i < this.dataPipeline.length; i++){
5230
5349
  let result = this.dataPipeline[i].handler(this.activeRowsPipeline[i].slice(0));
5231
-
5350
+
5232
5351
  this.activeRowsPipeline[i + 1] = result || this.activeRowsPipeline[i].slice(0);
5233
5352
  }
5234
-
5353
+
5235
5354
  this.setActiveRows(this.activeRowsPipeline[this.dataPipeline.length]);
5236
-
5355
+
5237
5356
  case "display":
5238
5357
  index = 0;
5239
5358
  this.resetDisplayRows();
5240
-
5359
+
5241
5360
  case "displayPipeline":
5242
5361
  for(let i = index; i < this.displayPipeline.length; i++){
5243
5362
  let result = this.displayPipeline[i].handler((i ? this.getDisplayRows(i - 1) : this.activeRows).slice(0), renderInPosition);
5244
-
5363
+
5245
5364
  this.setDisplayRows(result || this.getDisplayRows(i - 1).slice(0), i);
5246
5365
  }
5247
5366
 
5248
5367
  case "end":
5249
- //case to handle scenario when trying to skip past end stage
5368
+ //case to handle scenario when trying to skip past end stage
5250
5369
  this.regenerateRowPositions();
5251
5370
  }
5252
-
5371
+
5253
5372
  if(this.getDisplayRows().length){
5254
5373
  this._clearPlaceholder();
5255
5374
  }
@@ -5285,7 +5404,7 @@
5285
5404
  //set display row pipeline data
5286
5405
  setDisplayRows(displayRows, index){
5287
5406
  this.displayRows[index] = displayRows;
5288
-
5407
+
5289
5408
  if(index == this.displayRows.length -1){
5290
5409
  this.displayRowsCount = this.displayRows[this.displayRows.length -1].length;
5291
5410
  }
@@ -5320,7 +5439,7 @@
5320
5439
  //return only actual rows (not group headers etc)
5321
5440
  getRows(type){
5322
5441
  var rows = [];
5323
-
5442
+
5324
5443
  switch(type){
5325
5444
  case "active":
5326
5445
  rows = this.activeRows;
@@ -5329,11 +5448,11 @@
5329
5448
  case "display":
5330
5449
  rows = this.table.rowManager.getDisplayRows();
5331
5450
  break;
5332
-
5451
+
5333
5452
  case "visible":
5334
5453
  rows = this.getVisibleRows(false, true);
5335
5454
  break;
5336
-
5455
+
5337
5456
  default:
5338
5457
  rows = this.chain("rows-retrieve", type, null, this.rows) || this.rows;
5339
5458
  }
@@ -5354,25 +5473,25 @@
5354
5473
  this.dispatchExternal("renderStarted");
5355
5474
 
5356
5475
  this.renderer.rerenderRows(callback);
5357
-
5476
+
5358
5477
  if(!this.fixedHeight){
5359
5478
  this.adjustTableSize();
5360
5479
  }
5361
-
5480
+
5362
5481
  this.scrollBarCheck();
5363
5482
 
5364
5483
  this.dispatchExternal("renderComplete");
5365
5484
  }
5366
5485
  }
5367
-
5486
+
5368
5487
  scrollBarCheck(){
5369
5488
  var scrollbarWidth = 0;
5370
-
5489
+
5371
5490
  //adjust for vertical scrollbar moving table when present
5372
5491
  if(this.element.scrollHeight > this.element.clientHeight){
5373
5492
  scrollbarWidth = this.element.offsetWidth - this.element.clientWidth;
5374
5493
  }
5375
-
5494
+
5376
5495
  if(scrollbarWidth !== this.scrollbarWidth){
5377
5496
  this.scrollbarWidth = scrollbarWidth;
5378
5497
  this.dispatch("scrollbar-vertical", scrollbarWidth);
@@ -5425,7 +5544,7 @@
5425
5544
 
5426
5545
  if(this.firstRender){
5427
5546
  this.firstRender = false;
5428
-
5547
+
5429
5548
  if(!this.fixedHeight){
5430
5549
  this.adjustTableSize();
5431
5550
  }
@@ -5445,7 +5564,7 @@
5445
5564
  if(!this.displayRowsCount){
5446
5565
  this._showPlaceholder();
5447
5566
  }
5448
-
5567
+
5449
5568
  this.scrollBarCheck();
5450
5569
 
5451
5570
  this.dispatchExternal("renderComplete");
@@ -5470,7 +5589,7 @@
5470
5589
 
5471
5590
  this.renderer.clearRows();
5472
5591
  }
5473
-
5592
+
5474
5593
  tableEmpty(){
5475
5594
  this.renderEmptyScroll();
5476
5595
  this._showPlaceholder();
@@ -5478,10 +5597,18 @@
5478
5597
 
5479
5598
  _showPlaceholder(){
5480
5599
  if(this.placeholder){
5600
+ if(this.placeholder && this.placeholder.parentNode){
5601
+ this.placeholder.parentNode.removeChild(this.placeholder);
5602
+ }
5603
+
5604
+ this.initializePlaceholder();
5605
+
5481
5606
  this.placeholder.setAttribute("tabulator-render-mode", this.renderMode);
5482
5607
 
5483
5608
  this.getElement().appendChild(this.placeholder);
5484
5609
  this._positionPlaceholder();
5610
+
5611
+ this.adjustTableSize();
5485
5612
  }
5486
5613
  }
5487
5614
 
@@ -5489,7 +5616,7 @@
5489
5616
  if(this.placeholder && this.placeholder.parentNode){
5490
5617
  this.placeholder.parentNode.removeChild(this.placeholder);
5491
5618
  }
5492
-
5619
+
5493
5620
  // clear empty table placeholder min
5494
5621
  this.tableElement.style.minWidth = "";
5495
5622
  this.tableElement.style.display = "";
@@ -5524,7 +5651,8 @@
5524
5651
 
5525
5652
  //adjust the height of the table holder to fit in the Tabulator element
5526
5653
  adjustTableSize(){
5527
- var initialHeight = this.element.clientHeight, minHeight;
5654
+ let initialHeight = this.element.clientHeight, minHeight;
5655
+ let resized = false;
5528
5656
 
5529
5657
  if(this.renderer.verticalFillMode === "fill"){
5530
5658
  let otherHeight = Math.floor(this.table.columnManager.getElement().getBoundingClientRect().height + (this.table.footerManager && this.table.footerManager.active && !this.table.footerManager.external ? this.table.footerManager.getElement().getBoundingClientRect().height : 0));
@@ -5532,12 +5660,14 @@
5532
5660
  if(this.fixedHeight){
5533
5661
  minHeight = isNaN(this.table.options.minHeight) ? this.table.options.minHeight : this.table.options.minHeight + "px";
5534
5662
 
5663
+ const height = "calc(100% - " + otherHeight + "px)";
5535
5664
  this.element.style.minHeight = minHeight || "calc(100% - " + otherHeight + "px)";
5536
- this.element.style.height = "calc(100% - " + otherHeight + "px)";
5537
- this.element.style.maxHeight = "calc(100% - " + otherHeight + "px)";
5538
- }else {
5665
+ this.element.style.height = height;
5666
+ this.element.style.maxHeight = height;
5667
+ } else {
5539
5668
  this.element.style.height = "";
5540
- this.element.style.height = (this.table.element.clientHeight - otherHeight) + "px";
5669
+ this.element.style.height =
5670
+ this.table.element.clientHeight - otherHeight + "px";
5541
5671
  this.element.scrollTop = this.scrollTop;
5542
5672
  }
5543
5673
 
@@ -5545,17 +5675,19 @@
5545
5675
 
5546
5676
  //check if the table has changed size when dealing with variable height tables
5547
5677
  if(!this.fixedHeight && initialHeight != this.element.clientHeight){
5678
+ resized = true;
5548
5679
  if(this.subscribed("table-resize")){
5549
5680
  this.dispatch("table-resize");
5550
5681
  }else {
5551
5682
  this.redraw();
5552
5683
  }
5553
5684
  }
5554
-
5685
+
5555
5686
  this.scrollBarCheck();
5556
5687
  }
5557
5688
 
5558
5689
  this._positionPlaceholder();
5690
+ return resized;
5559
5691
  }
5560
5692
 
5561
5693
  //reinitialize all rows
@@ -5590,15 +5722,14 @@
5590
5722
 
5591
5723
  //redraw table
5592
5724
  redraw (force){
5593
- var left = this.scrollLeft;
5594
-
5595
- this.adjustTableSize();
5596
-
5725
+ const resized = this.adjustTableSize();
5597
5726
  this.table.tableWidth = this.table.element.clientWidth;
5598
5727
 
5599
5728
  if(!force){
5600
- this.reRenderInPosition();
5601
- this.scrollHorizontal(left);
5729
+ if(resized) {
5730
+ this.reRenderInPosition();
5731
+ }
5732
+ this.scrollHorizontal(this.scrollLeft);
5602
5733
  }else {
5603
5734
  this.renderTable();
5604
5735
  }
@@ -6075,58 +6206,66 @@
6075
6206
  class DataLoader extends CoreFeature{
6076
6207
  constructor(table){
6077
6208
  super(table);
6078
-
6209
+
6079
6210
  this.requestOrder = 0; //prevent requests coming out of sequence if overridden by another load request
6080
6211
  this.loading = false;
6081
6212
  }
6082
-
6213
+
6083
6214
  initialize(){}
6084
-
6215
+
6085
6216
  load(data, params, config, replace, silent, columnsChanged){
6086
6217
  var requestNo = ++this.requestOrder;
6087
6218
 
6219
+ if(this.table.destroyed){
6220
+ return Promise.resolve();
6221
+ }
6222
+
6088
6223
  this.dispatchExternal("dataLoading", data);
6089
-
6224
+
6090
6225
  //parse json data to array
6091
6226
  if (data && (data.indexOf("{") == 0 || data.indexOf("[") == 0)){
6092
6227
  data = JSON.parse(data);
6093
6228
  }
6094
-
6229
+
6095
6230
  if(this.confirm("data-loading", [data, params, config, silent])){
6096
6231
  this.loading = true;
6097
-
6232
+
6098
6233
  if(!silent){
6099
6234
  this.alertLoader();
6100
6235
  }
6101
-
6236
+
6102
6237
  //get params for request
6103
6238
  params = this.chain("data-params", [data, config, silent], params || {}, params || {});
6104
-
6239
+
6105
6240
  params = this.mapParams(params, this.table.options.dataSendParams);
6106
-
6241
+
6107
6242
  var result = this.chain("data-load", [data, params, config, silent], false, Promise.resolve([]));
6108
6243
 
6109
6244
  return result.then((response) => {
6110
- if(!Array.isArray(response) && typeof response == "object"){
6111
- response = this.mapParams(response, this.objectInvert(this.table.options.dataReceiveParams));
6112
- }
6113
-
6114
- var rowData = this.chain("data-loaded", response, null, response);
6115
-
6116
- if(requestNo == this.requestOrder){
6117
- this.clearAlert();
6118
-
6119
- if(rowData !== false){
6120
- this.dispatchExternal("dataLoaded", rowData);
6121
- this.table.rowManager.setData(rowData, replace, typeof columnsChanged === "undefined" ? !replace : columnsChanged);
6245
+ if(!this.table.destroyed){
6246
+ if(!Array.isArray(response) && typeof response == "object"){
6247
+ response = this.mapParams(response, this.objectInvert(this.table.options.dataReceiveParams));
6248
+ }
6249
+
6250
+ var rowData = this.chain("data-loaded", response, null, response);
6251
+
6252
+ if(requestNo == this.requestOrder){
6253
+ this.clearAlert();
6254
+
6255
+ if(rowData !== false){
6256
+ this.dispatchExternal("dataLoaded", rowData);
6257
+ this.table.rowManager.setData(rowData, replace, typeof columnsChanged === "undefined" ? !replace : columnsChanged);
6258
+ }
6259
+ }else {
6260
+ console.warn("Data Load Response Blocked - An active data load request was blocked by an attempt to change table data while the request was being made");
6122
6261
  }
6123
6262
  }else {
6124
- console.warn("Data Load Response Blocked - An active data load request was blocked by an attempt to change table data while the request was being made");
6263
+ console.warn("Data Load Response Blocked - Table has been destroyed");
6125
6264
  }
6126
6265
  }).catch((error) => {
6127
6266
  console.error("Data Load Error: ", error);
6128
6267
  this.dispatchExternal("dataLoadError", error);
6129
-
6268
+
6130
6269
  if(!silent){
6131
6270
  this.alertError();
6132
6271
  }
@@ -6140,52 +6279,52 @@
6140
6279
  });
6141
6280
  }else {
6142
6281
  this.dispatchExternal("dataLoaded", data);
6143
-
6282
+
6144
6283
  if(!data){
6145
6284
  data = [];
6146
6285
  }
6147
-
6286
+
6148
6287
  this.table.rowManager.setData(data, replace, typeof columnsChanged === "undefined" ? !replace : columnsChanged);
6149
6288
  return Promise.resolve();
6150
6289
  }
6151
6290
  }
6152
-
6291
+
6153
6292
  mapParams(params, map){
6154
6293
  var output = {};
6155
-
6294
+
6156
6295
  for(let key in params){
6157
6296
  output[map.hasOwnProperty(key) ? map[key] : key] = params[key];
6158
6297
  }
6159
-
6298
+
6160
6299
  return output;
6161
6300
  }
6162
-
6301
+
6163
6302
  objectInvert(obj){
6164
6303
  var output = {};
6165
-
6304
+
6166
6305
  for(let key in obj){
6167
6306
  output[obj[key]] = key;
6168
6307
  }
6169
-
6308
+
6170
6309
  return output;
6171
6310
  }
6172
-
6311
+
6173
6312
  blockActiveLoad(){
6174
6313
  this.requestOrder++;
6175
6314
  }
6176
-
6315
+
6177
6316
  alertLoader(){
6178
6317
  var shouldLoad = typeof this.table.options.dataLoader === "function" ? this.table.options.dataLoader() : this.table.options.dataLoader;
6179
-
6318
+
6180
6319
  if(shouldLoad){
6181
6320
  this.table.alertManager.alert(this.table.options.dataLoaderLoading || this.langText("data|loading"));
6182
6321
  }
6183
6322
  }
6184
-
6323
+
6185
6324
  alertError(){
6186
6325
  this.table.alertManager.alert(this.table.options.dataLoaderError || this.langText("data|error"), "error");
6187
6326
  }
6188
-
6327
+
6189
6328
  clearAlert(){
6190
6329
  this.table.alertManager.clear();
6191
6330
  }
@@ -9525,6 +9664,13 @@
9525
9664
 
9526
9665
  return output;
9527
9666
  },
9667
+ "unique":function(values, data, calcParams){
9668
+ var unique = values.filter((value, index) => {
9669
+ return (values || value === 0) && values.indexOf(value) === index;
9670
+ });
9671
+
9672
+ return unique.length;
9673
+ },
9528
9674
  };
9529
9675
 
9530
9676
  class ColumnCalcs extends Module{
@@ -10161,6 +10307,9 @@
10161
10307
  this.branchEl = options.dataTreeBranchElement;
10162
10308
  }
10163
10309
  }
10310
+ }else {
10311
+ this.branchEl = document.createElement("div");
10312
+ this.branchEl.classList.add("tabulator-data-tree-branch-empty");
10164
10313
  }
10165
10314
 
10166
10315
  if(options.dataTreeCollapseElement){
@@ -10399,7 +10548,7 @@
10399
10548
 
10400
10549
  row.create();
10401
10550
 
10402
- config = row.modules.dataTree.children;
10551
+ config = row.modules.dataTree;
10403
10552
 
10404
10553
  if(!config.index && config.children !== false){
10405
10554
  children = this.getChildren(row);
@@ -10664,7 +10813,7 @@
10664
10813
  var config = row.modules.dataTree,
10665
10814
  output = [];
10666
10815
 
10667
- if(config.children){
10816
+ if(config && config.children){
10668
10817
 
10669
10818
  if(!Array.isArray(config.children)){
10670
10819
  config.children = this.generateChildren(row);
@@ -10910,8 +11059,11 @@
10910
11059
  workbook = XLSX.utils.book_new(),
10911
11060
  tableFeatures = new CoreFeature(this),
10912
11061
  compression = 'compress' in options ? options.compress : true,
11062
+ writeOptions = options.writeOptions || {bookType:'xlsx', bookSST:true, compression},
10913
11063
  output;
10914
11064
 
11065
+ writeOptions.type = 'binary';
11066
+
10915
11067
  workbook.SheetNames = [];
10916
11068
  workbook.Sheets = {};
10917
11069
 
@@ -10997,7 +11149,7 @@
10997
11149
  return buf;
10998
11150
  }
10999
11151
 
11000
- output = XLSX.write(workbook, {bookType:'xlsx', bookSST:true, type: 'binary', compression });
11152
+ output = XLSX.write(workbook, writeOptions);
11001
11153
 
11002
11154
  setFileContents(s2ab(output), "application/octet-stream");
11003
11155
  }
@@ -11295,7 +11447,7 @@
11295
11447
  input.value = typeof cellValue !== "undefined" ? cellValue : "";
11296
11448
 
11297
11449
  onRendered(function(){
11298
- if(cell._getSelf){
11450
+ if(cell.getType() === "cell"){
11299
11451
  input.focus({preventScroll: true});
11300
11452
  input.style.height = "100%";
11301
11453
 
@@ -11376,7 +11528,7 @@
11376
11528
  input.value = value;
11377
11529
 
11378
11530
  onRendered(function(){
11379
- if(cell._getSelf){
11531
+ if(cell.getType() === "cell"){
11380
11532
  input.focus({preventScroll: true});
11381
11533
  input.style.height = "100%";
11382
11534
 
@@ -11510,7 +11662,7 @@
11510
11662
  };
11511
11663
 
11512
11664
  onRendered(function () {
11513
- if(cell._getSelf){
11665
+ if(cell.getType() === "cell"){
11514
11666
  //submit new value on blur
11515
11667
  input.removeEventListener("blur", blurFunc);
11516
11668
 
@@ -11614,7 +11766,7 @@
11614
11766
  input.value = cellValue;
11615
11767
 
11616
11768
  onRendered(function () {
11617
- if(cell._getSelf){
11769
+ if(cell.getType() === "cell"){
11618
11770
  input.focus({preventScroll: true});
11619
11771
  input.style.height = "100%";
11620
11772
  }
@@ -11719,7 +11871,7 @@
11719
11871
  input.value = cellValue;
11720
11872
 
11721
11873
  onRendered(function(){
11722
- if(cell._getSelf){
11874
+ if(cell.getType() === "cell"){
11723
11875
  input.focus({preventScroll: true});
11724
11876
  input.style.height = "100%";
11725
11877
 
@@ -11846,7 +11998,7 @@
11846
11998
  input.value = cellValue;
11847
11999
 
11848
12000
  onRendered(function(){
11849
- if(cell._getSelf){
12001
+ if(cell.getType() == "cell"){
11850
12002
  input.focus({preventScroll: true});
11851
12003
  input.style.height = "100%";
11852
12004
 
@@ -11972,7 +12124,7 @@
11972
12124
  input.value = cellValue;
11973
12125
 
11974
12126
  onRendered(function(){
11975
- if(cell._getSelf){
12127
+ if(cell.getType() === "cell"){
11976
12128
  input.focus({preventScroll: true});
11977
12129
  input.style.height = "100%";
11978
12130
 
@@ -12067,7 +12219,7 @@
12067
12219
 
12068
12220
  this.initialValues = null;
12069
12221
 
12070
- this.isFilter = !cell._getSelf;
12222
+ this.isFilter = cell.getType() === "header";
12071
12223
 
12072
12224
  this.filterTimeout = null;
12073
12225
  this.filtered = false;
@@ -12133,7 +12285,7 @@
12133
12285
  function clickStop(e){
12134
12286
  e.stopPropagation();
12135
12287
  }
12136
-
12288
+
12137
12289
  if(!this.isFilter){
12138
12290
  this.input.style.height = "100%";
12139
12291
  this.input.focus({preventScroll: true});
@@ -12357,6 +12509,7 @@
12357
12509
  break;
12358
12510
 
12359
12511
  case 9: //tab
12512
+ this._keyTab(e);
12360
12513
  break;
12361
12514
 
12362
12515
  default:
@@ -12403,6 +12556,16 @@
12403
12556
  //////// Keyboard Navigation /////////
12404
12557
  //////////////////////////////////////
12405
12558
 
12559
+ _keyTab(e){
12560
+ if(this.params.autocomplete && this.lastAction === "typing"){
12561
+ this._resolveValue(true);
12562
+ }else {
12563
+ if(this.focusedItem){
12564
+ this._chooseItem(this.focusedItem, true);
12565
+ }
12566
+ }
12567
+ }
12568
+
12406
12569
  _keyUp(e){
12407
12570
  var index = this.displayItems.indexOf(this.focusedItem);
12408
12571
 
@@ -13040,7 +13203,7 @@
13040
13203
 
13041
13204
  _resolveValue(blur){
13042
13205
  var output, initialValue;
13043
-
13206
+
13044
13207
  if(this.popup){
13045
13208
  this.popup.hide(true);
13046
13209
  }
@@ -13420,7 +13583,7 @@
13420
13583
 
13421
13584
  if(this.table.browser != "firefox" && this.table.browser != "safari"){ //prevent blur issue on mac firefox
13422
13585
  onRendered(function(){
13423
- if(cell._getSelf){
13586
+ if(cell.getType() === "cell"){
13424
13587
  input.focus({preventScroll: true});
13425
13588
  }
13426
13589
  });
@@ -14009,8 +14172,8 @@
14009
14172
  cellEl = cell.getElement();
14010
14173
 
14011
14174
  if(this.table.modExists("frozenColumns")){
14012
- leftEdge += parseInt(this.table.modules.frozenColumns.leftMargin);
14013
- rightEdge -= parseInt(this.table.modules.frozenColumns.rightMargin);
14175
+ leftEdge += parseInt(this.table.modules.frozenColumns.leftMargin || 0);
14176
+ rightEdge -= parseInt(this.table.modules.frozenColumns.rightMargin || 0);
14014
14177
  }
14015
14178
 
14016
14179
  if(this.table.options.renderHorizontal === "virtual"){
@@ -14019,7 +14182,6 @@
14019
14182
  }
14020
14183
 
14021
14184
  if(cellEl.offsetLeft < leftEdge){
14022
-
14023
14185
  this.table.rowManager.element.scrollLeft -= (leftEdge - cellEl.offsetLeft);
14024
14186
  }else {
14025
14187
  if(cellEl.offsetLeft + cellEl.offsetWidth > rightEdge){
@@ -14727,6 +14889,9 @@
14727
14889
  getElement:function(){
14728
14890
  return cellEl;
14729
14891
  },
14892
+ getType:function(){
14893
+ return "cell";
14894
+ },
14730
14895
  getColumn:function(){
14731
14896
  return column.getComponent();
14732
14897
  },
@@ -14987,6 +15152,7 @@
14987
15152
  this.registerTableOption("initialFilter", false); //initial filtering criteria
14988
15153
  this.registerTableOption("initialHeaderFilter", false); //initial header filtering criteria
14989
15154
  this.registerTableOption("headerFilterLiveFilterDelay", 300); //delay before updating column after user types in header filter
15155
+ this.registerTableOption("placeholderHeaderFilter", false); //placeholder when header filter is empty
14990
15156
 
14991
15157
  this.registerColumnOption("headerFilter");
14992
15158
  this.registerColumnOption("headerFilterPlaceholder");
@@ -15022,6 +15188,7 @@
15022
15188
  this.subscribe("column-width-fit-before", this.hideHeaderFilterElements.bind(this));
15023
15189
  this.subscribe("column-width-fit-after", this.showHeaderFilterElements.bind(this));
15024
15190
  this.subscribe("table-built", this.tableBuilt.bind(this));
15191
+ this.subscribe("placeholder", this.generatePlaceholder.bind(this));
15025
15192
 
15026
15193
  if(this.table.options.filterMode === "remote"){
15027
15194
  this.subscribe("data-params", this.remoteFilterParams.bind(this));
@@ -15057,6 +15224,12 @@
15057
15224
  return params;
15058
15225
  }
15059
15226
 
15227
+ generatePlaceholder(text){
15228
+ if(this.table.options.placeholderHeaderFilter && Object.keys(this.headerFilters).length){
15229
+ return this.table.options.placeholderHeaderFilter;
15230
+ }
15231
+ }
15232
+
15060
15233
  ///////////////////////////////////
15061
15234
  ///////// Table Functions /////////
15062
15235
  ///////////////////////////////////
@@ -15340,6 +15513,9 @@
15340
15513
  getTable:() => {
15341
15514
  return this.table;
15342
15515
  },
15516
+ getType:() => {
15517
+ return "header";
15518
+ },
15343
15519
  getRow:function(){
15344
15520
  return {
15345
15521
  normalizeHeight:function(){
@@ -15871,7 +16047,7 @@
15871
16047
  function money(cell, formatterParams, onRendered){
15872
16048
  var floatVal = parseFloat(cell.getValue()),
15873
16049
  sign = "",
15874
- number, integer, decimal, rgx;
16050
+ number, integer, decimal, rgx, value;
15875
16051
 
15876
16052
  var decimalSym = formatterParams.decimal || ".";
15877
16053
  var thousandSym = formatterParams.thousand || ",";
@@ -15903,7 +16079,14 @@
15903
16079
  }
15904
16080
  }
15905
16081
 
15906
- return after ? sign + integer + decimal + symbol : sign + symbol + integer + decimal;
16082
+ value = integer + decimal;
16083
+
16084
+ if(sign === true){
16085
+ value = "(" + value + ")";
16086
+ return after ? value + symbol : symbol + value;
16087
+ }else {
16088
+ return after ? sign + value + symbol : sign + symbol + value;
16089
+ }
15907
16090
  }
15908
16091
 
15909
16092
  function link(cell, formatterParams, onRendered){
@@ -16609,6 +16792,9 @@
16609
16792
  getElement:function(){
16610
16793
  return el;
16611
16794
  },
16795
+ getType:function(){
16796
+ return "header";
16797
+ },
16612
16798
  getColumn:function(){
16613
16799
  return column.getComponent();
16614
16800
  },
@@ -16980,7 +17166,7 @@
16980
17166
  layoutElement(element, column){
16981
17167
  var position;
16982
17168
 
16983
- if(column.modules.frozen){
17169
+ if(column.modules.frozen && element){
16984
17170
  element.style.position = "sticky";
16985
17171
 
16986
17172
  if(this.table.rtl){
@@ -17244,6 +17430,10 @@
17244
17430
  this._group.toggleVisibility();
17245
17431
  }
17246
17432
 
17433
+ scrollTo(position, ifVisible){
17434
+ return this._group.groupManager.table.rowManager.scrollToRow(this._group, position, ifVisible);
17435
+ }
17436
+
17247
17437
  _getSelf(){
17248
17438
  return this._group;
17249
17439
  }
@@ -17323,7 +17513,7 @@
17323
17513
  this.arrowElement = document.createElement("div");
17324
17514
  this.arrowElement.classList.add("tabulator-group-toggle");
17325
17515
  this.arrowElement.appendChild(arrow);
17326
-
17516
+
17327
17517
  //setup movable rows
17328
17518
  if(this.groupManager.table.options.movableRows !== false && this.groupManager.table.modExists("moveRow")){
17329
17519
  this.groupManager.table.modules.moveRow.initializeGroupHeader(this);
@@ -17346,9 +17536,15 @@
17346
17536
  toggleElement = this.groupManager.table.options.groupToggleElement == "arrow" ? this.arrowElement : this.element;
17347
17537
 
17348
17538
  toggleElement.addEventListener("click", (e) => {
17349
- e.stopPropagation();
17350
- e.stopImmediatePropagation();
17351
- this.toggleVisibility();
17539
+ if(this.groupManager.table.options.groupToggleElement === "arrow"){
17540
+ e.stopPropagation();
17541
+ e.stopImmediatePropagation();
17542
+ }
17543
+
17544
+ //allow click event to propagate before toggling visibility
17545
+ setTimeout(() => {
17546
+ this.toggleVisibility();
17547
+ });
17352
17548
  });
17353
17549
  }
17354
17550
  }
@@ -17469,7 +17665,7 @@
17469
17665
  if(el.parentNode){
17470
17666
  el.parentNode.removeChild(el);
17471
17667
  }
17472
-
17668
+
17473
17669
  if(!this.groupManager.blockRedraw){
17474
17670
  this.generateGroupHeaderContents();
17475
17671
 
@@ -17594,6 +17790,7 @@
17594
17790
  }
17595
17791
  return count;
17596
17792
  }
17793
+
17597
17794
 
17598
17795
  toggleVisibility(){
17599
17796
  if(this.visible){
@@ -17718,12 +17915,18 @@
17718
17915
  return output;
17719
17916
  }
17720
17917
 
17721
- getRows(component){
17918
+ getRows(component, includeChildren){
17722
17919
  var output = [];
17723
17920
 
17724
- this.rows.forEach(function(row){
17725
- output.push(component ? row.getComponent() : row);
17726
- });
17921
+ if(includeChildren && this.groupList.length){
17922
+ this.groupList.forEach((group) => {
17923
+ output = output.concat(group.getRows(component, includeChildren));
17924
+ });
17925
+ }else {
17926
+ this.rows.forEach(function(row){
17927
+ output.push(component ? row.getComponent() : row);
17928
+ });
17929
+ }
17727
17930
 
17728
17931
  return output;
17729
17932
  }
@@ -17731,7 +17934,9 @@
17731
17934
  generateGroupHeaderContents(){
17732
17935
  var data = [];
17733
17936
 
17734
- this.rows.forEach(function(row){
17937
+ var rows = this.getRows(false, true);
17938
+
17939
+ rows.forEach(function(row){
17735
17940
  data.push(row.getData());
17736
17941
  });
17737
17942
 
@@ -17836,6 +18041,8 @@
17836
18041
  clearCellHeight(){}
17837
18042
 
17838
18043
  deinitializeHeight(){}
18044
+
18045
+ rendered(){}
17839
18046
 
17840
18047
  //////////////// Object Generation /////////////////
17841
18048
  getComponent(){
@@ -18502,8 +18709,12 @@
18502
18709
  },
18503
18710
 
18504
18711
  rowMove: function(action){
18505
- this.table.rowManager.moveRowActual(action.component, this.table.rowManager.rows[action.data.posFrom], !action.data.after);
18506
- this.table.rowManager.redraw();
18712
+ var after = (action.data.posFrom - action.data.posTo) > 0;
18713
+
18714
+ this.table.rowManager.moveRowActual(action.component, this.table.rowManager.getRowFromPosition(action.data.posFrom), after);
18715
+
18716
+ this.table.rowManager.regenerateRowPositions();
18717
+ this.table.rowManager.reRenderInPosition();
18507
18718
  },
18508
18719
  };
18509
18720
 
@@ -18528,8 +18739,10 @@
18528
18739
  },
18529
18740
 
18530
18741
  rowMove: function(action){
18531
- this.table.rowManager.moveRowActual(action.component, this.table.rowManager.rows[action.data.posTo], action.data.after);
18532
- this.table.rowManager.redraw();
18742
+ this.table.rowManager.moveRowActual(action.component, this.table.rowManager.getRowFromPosition(action.data.posTo), action.data.after);
18743
+
18744
+ this.table.rowManager.regenerateRowPositions();
18745
+ this.table.rowManager.reRenderInPosition();
18533
18746
  },
18534
18747
  };
18535
18748
 
@@ -19277,8 +19490,20 @@
19277
19490
 
19278
19491
  this.subscribe("column-init", this.initializeColumn.bind(this));
19279
19492
  this.subscribe("cell-dblclick", this.cellContentsSelectionFixer.bind(this));
19493
+ this.subscribe("scroll-horizontal", this.clearTouchWatchers.bind(this));
19494
+ this.subscribe("scroll-vertical", this.clearTouchWatchers.bind(this));
19280
19495
  }
19281
19496
 
19497
+ clearTouchWatchers(){
19498
+ var types = Object.values(this.touchWatchers);
19499
+
19500
+ types.forEach((type) => {
19501
+ for(let key in type){
19502
+ type[key] = null;
19503
+ }
19504
+ });
19505
+ }
19506
+
19282
19507
  cellContentsSelectionFixer(e, cell){
19283
19508
  var range;
19284
19509
 
@@ -22234,6 +22459,7 @@
22234
22459
  this.config = {
22235
22460
  sort:this.table.options.persistence === true || this.table.options.persistence.sort,
22236
22461
  filter:this.table.options.persistence === true || this.table.options.persistence.filter,
22462
+ headerFilter:this.table.options.persistence === true || this.table.options.persistence.headerFilter,
22237
22463
  group:this.table.options.persistence === true || this.table.options.persistence.group,
22238
22464
  page:this.table.options.persistence === true || this.table.options.persistence.page,
22239
22465
  columns:this.table.options.persistence === true ? ["title", "width", "visible"] : this.table.options.persistence.columns,
@@ -22284,6 +22510,7 @@
22284
22510
  this.subscribe("table-redraw", this.tableRedraw.bind(this));
22285
22511
 
22286
22512
  this.subscribe("filter-changed", this.eventSave.bind(this, "filter"));
22513
+ this.subscribe("filter-changed", this.eventSave.bind(this, "headerFilter"));
22287
22514
  this.subscribe("sort-changed", this.eventSave.bind(this, "sort"));
22288
22515
  this.subscribe("group-changed", this.eventSave.bind(this, "group"));
22289
22516
  this.subscribe("page-changed", this.eventSave.bind(this, "page"));
@@ -22303,7 +22530,7 @@
22303
22530
  }
22304
22531
 
22305
22532
  tableBuilt(){
22306
- var sorters, filters;
22533
+ var sorters, filters, headerFilters;
22307
22534
 
22308
22535
  if(this.config.sort){
22309
22536
  sorters = this.load("sort");
@@ -22320,6 +22547,14 @@
22320
22547
  this.table.options.initialFilter = filters;
22321
22548
  }
22322
22549
  }
22550
+ if(this.config.headerFilter){
22551
+ headerFilters = this.load("headerFilter");
22552
+
22553
+ if(!headerFilters === false){
22554
+ this.table.options.initialHeaderFilter = headerFilters;
22555
+ }
22556
+ }
22557
+
22323
22558
  }
22324
22559
 
22325
22560
  tableRedraw(force){
@@ -22480,6 +22715,10 @@
22480
22715
  data = this.table.modules.filter.getFilters();
22481
22716
  break;
22482
22717
 
22718
+ case "headerFilter":
22719
+ data = this.table.modules.filter.getHeaderFilters();
22720
+ break;
22721
+
22483
22722
  case "sort":
22484
22723
  data = this.validateSorters(this.table.modules.sort.getSort());
22485
22724
  break;
@@ -24212,6 +24451,9 @@
24212
24451
  getData:function(){
24213
24452
  return data;
24214
24453
  },
24454
+ getType:function(){
24455
+ return "cell";
24456
+ },
24215
24457
  getElement:function(){
24216
24458
  return document.createElement("div");
24217
24459
  },
@@ -24476,7 +24718,7 @@
24476
24718
  }
24477
24719
 
24478
24720
  checkRowSelectability(row){
24479
- if(row.type === "row"){
24721
+ if(row && row.type === "row"){
24480
24722
  return this.table.options.selectableCheck.call(this.table, row.getComponent());
24481
24723
  }
24482
24724
 
@@ -24496,48 +24738,44 @@
24496
24738
 
24497
24739
  //select a number of rows
24498
24740
  selectRows(rows){
24499
- var rowMatch;
24741
+ var changes = [],
24742
+ rowMatch, change;
24500
24743
 
24501
24744
  switch(typeof rows){
24502
24745
  case "undefined":
24503
- this.table.rowManager.rows.forEach((row) => {
24504
- this._selectRow(row, true, true);
24505
- });
24506
-
24507
- this._rowSelectionChanged();
24746
+ rowMatch = this.table.rowManager.rows;
24508
24747
  break;
24509
24748
 
24510
24749
  case "string":
24511
24750
  rowMatch = this.table.rowManager.findRow(rows);
24512
24751
 
24513
- if(rowMatch){
24514
- this._selectRow(rowMatch, true, true);
24515
- this._rowSelectionChanged();
24516
- }else {
24752
+ if(!rowMatch){
24517
24753
  rowMatch = this.table.rowManager.getRows(rows);
24518
-
24519
- rowMatch.forEach((row) => {
24520
- this._selectRow(row, true, true);
24521
- });
24522
-
24523
- if(rowMatch.length){
24524
- this._rowSelectionChanged();
24525
- }
24526
24754
  }
24527
24755
  break;
24528
24756
 
24529
24757
  default:
24530
- if(Array.isArray(rows)){
24531
- rows.forEach((row) => {
24532
- this._selectRow(row, true, true);
24533
- });
24534
-
24535
- this._rowSelectionChanged();
24536
- }else {
24537
- this._selectRow(rows, false, true);
24538
- }
24758
+ rowMatch = rows;
24539
24759
  break;
24540
24760
  }
24761
+
24762
+ if(Array.isArray(rowMatch)){
24763
+ if(rowMatch.length){
24764
+ rowMatch.forEach((row) => {
24765
+ change = this._selectRow(row, true, true);
24766
+
24767
+ if(change){
24768
+ changes.push(change);
24769
+ }
24770
+ });
24771
+
24772
+ this._rowSelectionChanged(false, changes);
24773
+ }
24774
+ }else {
24775
+ if(rowMatch){
24776
+ this._selectRow(rowMatch, false, true);
24777
+ }
24778
+ }
24541
24779
  }
24542
24780
 
24543
24781
  //select an individual row
@@ -24575,7 +24813,9 @@
24575
24813
 
24576
24814
  this.dispatchExternal("rowSelected", row.getComponent());
24577
24815
 
24578
- this._rowSelectionChanged(silent);
24816
+ this._rowSelectionChanged(silent, row);
24817
+
24818
+ return row;
24579
24819
  }
24580
24820
  }else {
24581
24821
  if(!silent){
@@ -24590,39 +24830,51 @@
24590
24830
 
24591
24831
  //deselect a number of rows
24592
24832
  deselectRows(rows, silent){
24593
- var self = this,
24594
- rowCount;
24833
+ var changes = [],
24834
+ rowMatch, change;
24595
24835
 
24596
- if(typeof rows == "undefined"){
24836
+ switch(typeof rows){
24837
+ case "undefined":
24838
+ rowMatch = Object.assign([], this.selectedRows);
24839
+ break;
24597
24840
 
24598
- rowCount = self.selectedRows.length;
24841
+ case "string":
24842
+ rowMatch = this.table.rowManager.findRow(rows);
24599
24843
 
24600
- for(let i = 0; i < rowCount; i++){
24601
- self._deselectRow(self.selectedRows[0], true);
24602
- }
24844
+ if(!rowMatch){
24845
+ rowMatch = this.table.rowManager.getRows(rows);
24846
+ }
24847
+ break;
24603
24848
 
24604
- if(rowCount){
24605
- self._rowSelectionChanged(silent);
24849
+ default:
24850
+ rowMatch = rows;
24851
+ break;
24852
+ }
24853
+
24854
+ if(Array.isArray(rowMatch)){
24855
+ if(rowMatch.length){
24856
+ rowMatch.forEach((row) => {
24857
+ change = this._deselectRow(row, true, true);
24858
+
24859
+ if(change){
24860
+ changes.push(change);
24861
+ }
24862
+ });
24863
+
24864
+ this._rowSelectionChanged(silent, [], changes);
24606
24865
  }
24607
-
24608
24866
  }else {
24609
- if(Array.isArray(rows)){
24610
- rows.forEach(function(row){
24611
- self._deselectRow(row, true);
24612
- });
24613
-
24614
- self._rowSelectionChanged(silent);
24615
- }else {
24616
- self._deselectRow(rows, silent);
24867
+ if(rowMatch){
24868
+ this._deselectRow(rowMatch, silent, true);
24617
24869
  }
24618
- }
24870
+ }
24619
24871
  }
24620
24872
 
24621
24873
  //deselect an individual row
24622
24874
  _deselectRow(rowInfo, silent){
24623
24875
  var self = this,
24624
24876
  row = self.table.rowManager.findRow(rowInfo),
24625
- index;
24877
+ index, element;
24626
24878
 
24627
24879
  if(row){
24628
24880
  index = self.selectedRows.findIndex(function(selectedRow){
@@ -24630,8 +24882,13 @@
24630
24882
  });
24631
24883
 
24632
24884
  if(index > -1){
24885
+
24886
+ element = row.getElement();
24887
+
24888
+ if(element){
24889
+ element.classList.remove("tabulator-selected");
24890
+ }
24633
24891
 
24634
- row.getElement().classList.remove("tabulator-selected");
24635
24892
  if(!row.modules.select){
24636
24893
  row.modules.select = {};
24637
24894
  }
@@ -24648,7 +24905,9 @@
24648
24905
 
24649
24906
  this.dispatchExternal("rowDeselected", row.getComponent());
24650
24907
 
24651
- self._rowSelectionChanged(silent);
24908
+ self._rowSelectionChanged(silent, undefined, row);
24909
+
24910
+ return row;
24652
24911
  }
24653
24912
  }else {
24654
24913
  if(!silent){
@@ -24668,7 +24927,6 @@
24668
24927
  }
24669
24928
 
24670
24929
  getSelectedRows(){
24671
-
24672
24930
  var rows = [];
24673
24931
 
24674
24932
  this.selectedRows.forEach(function(row){
@@ -24678,7 +24936,7 @@
24678
24936
  return rows;
24679
24937
  }
24680
24938
 
24681
- _rowSelectionChanged(silent){
24939
+ _rowSelectionChanged(silent, selected = [], deselected = []){
24682
24940
  if(this.headerCheckboxElement){
24683
24941
  if(this.selectedRows.length === 0){
24684
24942
  this.headerCheckboxElement.checked = false;
@@ -24693,7 +24951,19 @@
24693
24951
  }
24694
24952
 
24695
24953
  if(!silent){
24696
- this.dispatchExternal("rowSelectionChanged", this.getSelectedData(), this.getSelectedRows());
24954
+ if(!Array.isArray(selected)){
24955
+ selected = [selected];
24956
+ }
24957
+
24958
+ selected = selected.map(row => row.getComponent());
24959
+
24960
+ if(!Array.isArray(deselected)){
24961
+ deselected = [deselected];
24962
+ }
24963
+
24964
+ deselected = deselected.map(row => row.getComponent());
24965
+
24966
+ this.dispatchExternal("rowSelectionChanged", this.getSelectedData(), this.getSelectedRows(), selected, deselected);
24697
24967
  }
24698
24968
  }
24699
24969