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
@@ -44,7 +44,6 @@ export default class VirtualDomVertical extends Renderer{
44
44
 
45
45
  element.style.paddingTop = "";
46
46
  element.style.paddingBottom = "";
47
- // element.style.minWidth = "";
48
47
  element.style.minHeight = "";
49
48
  element.style.display = "";
50
49
  element.style.visibility = "";
@@ -223,17 +222,27 @@ export default class VirtualDomVertical extends Renderer{
223
222
  //////////////////////////////////////
224
223
 
225
224
  //full virtual render
226
- _virtualRenderFill(position, forceMove, offset){
225
+ _virtualRenderFill(position, forceMove, offset) {
227
226
  var element = this.tableElement,
228
227
  holder = this.elementVertical,
229
228
  topPad = 0,
230
229
  rowsHeight = 0,
230
+ rowHeight = 0,
231
231
  heightOccupied = 0,
232
232
  topPadHeight = 0,
233
233
  i = 0,
234
234
  rows = this.rows(),
235
235
  rowsCount = rows.length,
236
- containerHeight = this.elementVertical.clientHeight;
236
+ index = 0,
237
+ row,
238
+ rowFragment,
239
+ renderedRows = [],
240
+ totalRowsRendered = 0,
241
+ rowsToRender = 0,
242
+ fixedHeight = this.table.rowManager.fixedHeight,
243
+ containerHeight = this.elementVertical.clientHeight,
244
+ avgRowHeight = this.table.options.rowHeight,
245
+ resized = true;
237
246
 
238
247
  position = position || 0;
239
248
 
@@ -241,7 +250,7 @@ export default class VirtualDomVertical extends Renderer{
241
250
 
242
251
  if(!position){
243
252
  this.clear();
244
- }else{
253
+ }else {
245
254
  while(element.firstChild) element.removeChild(element.firstChild);
246
255
 
247
256
  //check if position is too close to bottom of table
@@ -261,54 +270,102 @@ export default class VirtualDomVertical extends Renderer{
261
270
 
262
271
  if(rowsCount && Helpers.elVisible(this.elementVertical)){
263
272
  this.vDomTop = position;
264
-
265
273
  this.vDomBottom = position -1;
266
274
 
267
- while ((rowsHeight <= containerHeight + this.vDomWindowBuffer || i < this.vDomWindowMinTotalRows) && this.vDomBottom < rowsCount -1){
268
- var index = this.vDomBottom + 1,
269
- row = rows[index],
270
- rowHeight = 0;
275
+ if(fixedHeight || this.table.options.maxHeight) {
276
+ if(avgRowHeight) {
277
+ rowsToRender = (containerHeight / avgRowHeight) + (this.vDomWindowBuffer / avgRowHeight);
278
+ }
279
+ rowsToRender = Math.max(this.vDomWindowMinTotalRows, Math.ceil(rowsToRender));
280
+ }
281
+ else {
282
+ rowsToRender = rowsCount;
283
+ }
271
284
 
272
- this.styleRow(row, index);
285
+ while(((rowsToRender == rowsCount || rowsHeight <= containerHeight + this.vDomWindowBuffer) || totalRowsRendered < this.vDomWindowMinTotalRows) && this.vDomBottom < rowsCount -1) {
286
+ renderedRows = [];
287
+ rowFragment = document.createDocumentFragment();
273
288
 
274
- element.appendChild(row.getElement());
289
+ i = 0;
275
290
 
276
- row.initialize();
291
+ while ((i < rowsToRender) && this.vDomBottom < rowsCount -1) {
292
+ index = this.vDomBottom + 1,
293
+ row = rows[index];
277
294
 
278
- if(!row.heightInitialized){
279
- row.normalizeHeight(true);
280
- }
295
+ this.styleRow(row, index);
281
296
 
282
- rowHeight = row.getHeight();
297
+ row.initialize(false, true);
298
+ if(!row.heightInitialized && !this.table.options.rowHeight){
299
+ row.clearCellHeight();
300
+ }
283
301
 
284
- if(i < topPad){
285
- topPadHeight += rowHeight;
286
- }else{
287
- rowsHeight += rowHeight;
302
+ rowFragment.appendChild(row.getElement());
303
+ renderedRows.push(row);
304
+ this.vDomBottom ++;
305
+ i++;
288
306
  }
289
307
 
290
- if(rowHeight > this.vDomWindowBuffer){
291
- this.vDomWindowBuffer = rowHeight * 2;
308
+ if(!renderedRows.length){
309
+ break;
292
310
  }
293
311
 
294
- this.vDomBottom ++;
295
- i++;
312
+ element.appendChild(rowFragment);
313
+
314
+ // NOTE: The next 3 loops are separate on purpose
315
+ // This is to batch up the dom writes and reads which drastically improves performance
316
+
317
+ renderedRows.forEach((row) => {
318
+ row.rendered();
319
+
320
+ if(!row.heightInitialized) {
321
+ row.calcHeight(true);
322
+ }
323
+ });
324
+
325
+ renderedRows.forEach((row) => {
326
+ if(!row.heightInitialized) {
327
+ row.setCellHeight();
328
+ }
329
+ });
330
+
331
+ renderedRows.forEach((row) => {
332
+ rowHeight = row.getHeight();
333
+
334
+ if(totalRowsRendered < topPad){
335
+ topPadHeight += rowHeight;
336
+ }else {
337
+ rowsHeight += rowHeight;
338
+ }
339
+
340
+ if(rowHeight > this.vDomWindowBuffer){
341
+ this.vDomWindowBuffer = rowHeight * 2;
342
+ }
343
+ totalRowsRendered++;
344
+ });
345
+
346
+ resized = this.table.rowManager.adjustTableSize();
347
+ containerHeight = this.elementVertical.clientHeight;
348
+ if(resized && (fixedHeight || this.table.options.maxHeight))
349
+ {
350
+ avgRowHeight = rowsHeight / totalRowsRendered;
351
+ rowsToRender = Math.max(this.vDomWindowMinTotalRows, Math.ceil((containerHeight / avgRowHeight) + (this.vDomWindowBuffer / avgRowHeight)));
352
+ }
296
353
  }
297
354
 
298
355
  if(!position){
299
356
  this.vDomTopPad = 0;
300
357
  //adjust row height to match average of rendered elements
301
- this.vDomRowHeight = Math.floor((rowsHeight + topPadHeight) / i);
358
+ this.vDomRowHeight = Math.floor((rowsHeight + topPadHeight) / totalRowsRendered);
302
359
  this.vDomBottomPad = this.vDomRowHeight * (rowsCount - this.vDomBottom -1);
303
360
 
304
361
  this.vDomScrollHeight = topPadHeight + rowsHeight + this.vDomBottomPad - containerHeight;
305
- }else{
362
+ }else {
306
363
  this.vDomTopPad = !forceMove ? this.scrollTop - topPadHeight : (this.vDomRowHeight * this.vDomTop) + offset;
307
364
  this.vDomBottomPad = this.vDomBottom == rowsCount-1 ? 0 : Math.max(this.vDomScrollHeight - this.vDomTopPad - rowsHeight - topPadHeight, 0);
308
365
  }
309
-
310
- element.style.paddingTop = this.vDomTopPad + "px";
311
- element.style.paddingBottom = this.vDomBottomPad + "px";
366
+
367
+ element.style.paddingTop = this.vDomTopPad+"px";
368
+ element.style.paddingBottom = this.vDomBottomPad+"px";
312
369
 
313
370
  if(forceMove){
314
371
  this.scrollTop = this.vDomTopPad + (topPadHeight) + offset - (this.elementVertical.scrollWidth > this.elementVertical.clientWidth ? this.elementVertical.offsetHeight - containerHeight : 0);
@@ -577,4 +634,4 @@ export default class VirtualDomVertical extends Renderer{
577
634
  row.setCellHeight();
578
635
  }
579
636
  }
580
- }
637
+ }
@@ -65,7 +65,7 @@ export default class Row extends CoreFeature{
65
65
  }
66
66
 
67
67
  //functions to setup on first render
68
- initialize(force){
68
+ initialize(force, inFragment){
69
69
  this.create();
70
70
 
71
71
  if(!this.initialized || force){
@@ -80,7 +80,7 @@ export default class Row extends CoreFeature{
80
80
 
81
81
  this.initialized = true;
82
82
 
83
- this.table.columnManager.renderer.renderRowCells(this);
83
+ this.table.columnManager.renderer.renderRowCells(this, inFragment);
84
84
 
85
85
  if(force){
86
86
  this.normalizeHeight();
@@ -94,9 +94,15 @@ export default class Row extends CoreFeature{
94
94
 
95
95
  this.dispatch("row-layout-after", this);
96
96
  }else{
97
- this.table.columnManager.renderer.rerenderRowCells(this);
97
+ this.table.columnManager.renderer.rerenderRowCells(this, inFragment);
98
98
  }
99
99
  }
100
+
101
+ rendered(){
102
+ this.cells.forEach((cell) => {
103
+ cell.cellRendered();
104
+ });
105
+ }
100
106
 
101
107
  reinitializeHeight(){
102
108
  this.heightInitialized = false;
@@ -54,8 +54,8 @@ export default class RowComponent {
54
54
  return this._row.delete();
55
55
  }
56
56
 
57
- scrollTo(){
58
- return this._row.table.rowManager.scrollToRow(this._row);
57
+ scrollTo(position, ifVisible){
58
+ return this._row.table.rowManager.scrollToRow(this._row, position, ifVisible);
59
59
  }
60
60
 
61
61
  move(to, after){
@@ -3,58 +3,66 @@ import CoreFeature from '../CoreFeature.js';
3
3
  export default class DataLoader extends CoreFeature{
4
4
  constructor(table){
5
5
  super(table);
6
-
6
+
7
7
  this.requestOrder = 0; //prevent requests coming out of sequence if overridden by another load request
8
8
  this.loading = false;
9
9
  }
10
-
10
+
11
11
  initialize(){}
12
-
12
+
13
13
  load(data, params, config, replace, silent, columnsChanged){
14
14
  var requestNo = ++this.requestOrder;
15
15
 
16
+ if(this.table.destroyed){
17
+ return Promise.resolve();
18
+ }
19
+
16
20
  this.dispatchExternal("dataLoading", data);
17
-
21
+
18
22
  //parse json data to array
19
23
  if (data && (data.indexOf("{") == 0 || data.indexOf("[") == 0)){
20
24
  data = JSON.parse(data);
21
25
  }
22
-
26
+
23
27
  if(this.confirm("data-loading", [data, params, config, silent])){
24
28
  this.loading = true;
25
-
29
+
26
30
  if(!silent){
27
31
  this.alertLoader();
28
32
  }
29
-
33
+
30
34
  //get params for request
31
35
  params = this.chain("data-params", [data, config, silent], params || {}, params || {});
32
-
36
+
33
37
  params = this.mapParams(params, this.table.options.dataSendParams);
34
-
38
+
35
39
  var result = this.chain("data-load", [data, params, config, silent], false, Promise.resolve([]));
36
40
 
37
41
  return result.then((response) => {
38
- if(!Array.isArray(response) && typeof response == "object"){
39
- response = this.mapParams(response, this.objectInvert(this.table.options.dataReceiveParams));
40
- }
41
-
42
- var rowData = this.chain("data-loaded", response, null, response);
43
-
44
- if(requestNo == this.requestOrder){
45
- this.clearAlert();
46
-
47
- if(rowData !== false){
48
- this.dispatchExternal("dataLoaded", rowData);
49
- this.table.rowManager.setData(rowData, replace, typeof columnsChanged === "undefined" ? !replace : columnsChanged);
42
+ if(!this.table.destroyed){
43
+ if(!Array.isArray(response) && typeof response == "object"){
44
+ response = this.mapParams(response, this.objectInvert(this.table.options.dataReceiveParams));
45
+ }
46
+
47
+ var rowData = this.chain("data-loaded", response, null, response);
48
+
49
+ if(requestNo == this.requestOrder){
50
+ this.clearAlert();
51
+
52
+ if(rowData !== false){
53
+ this.dispatchExternal("dataLoaded", rowData);
54
+ this.table.rowManager.setData(rowData, replace, typeof columnsChanged === "undefined" ? !replace : columnsChanged);
55
+ }
56
+ }else{
57
+ 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");
50
58
  }
51
59
  }else{
52
- 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");
60
+ console.warn("Data Load Response Blocked - Table has been destroyed");
53
61
  }
54
62
  }).catch((error) => {
55
63
  console.error("Data Load Error: ", error);
56
64
  this.dispatchExternal("dataLoadError", error);
57
-
65
+
58
66
  if(!silent){
59
67
  this.alertError();
60
68
  }
@@ -68,52 +76,52 @@ export default class DataLoader extends CoreFeature{
68
76
  });
69
77
  }else{
70
78
  this.dispatchExternal("dataLoaded", data);
71
-
79
+
72
80
  if(!data){
73
81
  data = [];
74
82
  }
75
-
83
+
76
84
  this.table.rowManager.setData(data, replace, typeof columnsChanged === "undefined" ? !replace : columnsChanged);
77
85
  return Promise.resolve();
78
86
  }
79
87
  }
80
-
88
+
81
89
  mapParams(params, map){
82
90
  var output = {};
83
-
91
+
84
92
  for(let key in params){
85
93
  output[map.hasOwnProperty(key) ? map[key] : key] = params[key];
86
94
  }
87
-
95
+
88
96
  return output;
89
97
  }
90
-
98
+
91
99
  objectInvert(obj){
92
100
  var output = {};
93
-
101
+
94
102
  for(let key in obj){
95
103
  output[obj[key]] = key;
96
104
  }
97
-
105
+
98
106
  return output;
99
107
  }
100
-
108
+
101
109
  blockActiveLoad(){
102
110
  this.requestOrder++;
103
111
  }
104
-
112
+
105
113
  alertLoader(){
106
114
  var shouldLoad = typeof this.table.options.dataLoader === "function" ? this.table.options.dataLoader() : this.table.options.dataLoader;
107
-
115
+
108
116
  if(shouldLoad){
109
117
  this.table.alertManager.alert(this.table.options.dataLoaderLoading || this.langText("data|loading"));
110
118
  }
111
119
  }
112
-
120
+
113
121
  alertError(){
114
122
  this.table.alertManager.alert(this.table.options.dataLoaderError || this.langText("data|error"), "error");
115
123
  }
116
-
124
+
117
125
  clearAlert(){
118
126
  this.table.alertManager.clear();
119
127
  }
@@ -83,4 +83,11 @@ export default {
83
83
 
84
84
  return output;
85
85
  },
86
+ "unique":function(values, data, calcParams){
87
+ var unique = values.filter((value, index) => {
88
+ return (values || value === 0) && values.indexOf(value) === index;
89
+ });
90
+
91
+ return unique.length;
92
+ },
86
93
  };
@@ -67,6 +67,9 @@ class DataTree extends Module{
67
67
  this.branchEl = options.dataTreeBranchElement;
68
68
  }
69
69
  }
70
+ }else{
71
+ this.branchEl = document.createElement("div");
72
+ this.branchEl.classList.add("tabulator-data-tree-branch-empty");
70
73
  }
71
74
 
72
75
  if(options.dataTreeCollapseElement){
@@ -305,7 +308,7 @@ class DataTree extends Module{
305
308
 
306
309
  row.create();
307
310
 
308
- config = row.modules.dataTree.children;
311
+ config = row.modules.dataTree;
309
312
 
310
313
  if(!config.index && config.children !== false){
311
314
  children = this.getChildren(row);
@@ -570,7 +573,7 @@ class DataTree extends Module{
570
573
  var config = row.modules.dataTree,
571
574
  output = [];
572
575
 
573
- if(config.children){
576
+ if(config && config.children){
574
577
 
575
578
  if(!Array.isArray(config.children)){
576
579
  config.children = this.generateChildren(row);
@@ -6,8 +6,11 @@ export default function(list, options, setFileContents){
6
6
  workbook = XLSX.utils.book_new(),
7
7
  tableFeatures = new CoreFeature(this),
8
8
  compression = 'compress' in options ? options.compress : true,
9
+ writeOptions = options.writeOptions || {bookType:'xlsx', bookSST:true, compression},
9
10
  output;
10
11
 
12
+ writeOptions.type = 'binary';
13
+
11
14
  workbook.SheetNames = [];
12
15
  workbook.Sheets = {};
13
16
 
@@ -93,7 +96,7 @@ export default function(list, options, setFileContents){
93
96
  return buf;
94
97
  }
95
98
 
96
- output = XLSX.write(workbook, {bookType:'xlsx', bookSST:true, type: 'binary', compression });
99
+ output = XLSX.write(workbook, writeOptions);
97
100
 
98
101
  setFileContents(s2ab(output), "application/octet-stream");
99
- }
102
+ }
@@ -514,8 +514,8 @@ class Edit extends Module{
514
514
  cellEl = cell.getElement();
515
515
 
516
516
  if(this.table.modExists("frozenColumns")){
517
- leftEdge += parseInt(this.table.modules.frozenColumns.leftMargin);
518
- rightEdge -= parseInt(this.table.modules.frozenColumns.rightMargin);
517
+ leftEdge += parseInt(this.table.modules.frozenColumns.leftMargin || 0);
518
+ rightEdge -= parseInt(this.table.modules.frozenColumns.rightMargin || 0);
519
519
  }
520
520
 
521
521
  if(this.table.options.renderHorizontal === "virtual"){
@@ -524,7 +524,6 @@ class Edit extends Module{
524
524
  }
525
525
 
526
526
  if(cellEl.offsetLeft < leftEdge){
527
-
528
527
  this.table.rowManager.element.scrollLeft -= (leftEdge - cellEl.offsetLeft);
529
528
  }else{
530
529
  if(cellEl.offsetLeft + cellEl.offsetWidth > rightEdge){
@@ -18,7 +18,7 @@ export default class Edit{
18
18
 
19
19
  this.initialValues = null;
20
20
 
21
- this.isFilter = !cell._getSelf;
21
+ this.isFilter = cell.getType() === "header";
22
22
 
23
23
  this.filterTimeout = null;
24
24
  this.filtered = false;
@@ -84,7 +84,7 @@ export default class Edit{
84
84
  function clickStop(e){
85
85
  e.stopPropagation();
86
86
  }
87
-
87
+
88
88
  if(!this.isFilter){
89
89
  this.input.style.height = "100%";
90
90
  this.input.focus({preventScroll: true});
@@ -308,6 +308,7 @@ export default class Edit{
308
308
  break;
309
309
 
310
310
  case 9: //tab
311
+ this._keyTab(e);
311
312
  break;
312
313
 
313
314
  default:
@@ -354,6 +355,16 @@ export default class Edit{
354
355
  //////// Keyboard Navigation /////////
355
356
  //////////////////////////////////////
356
357
 
358
+ _keyTab(e){
359
+ if(this.params.autocomplete && this.lastAction === "typing"){
360
+ this._resolveValue(true);
361
+ }else{
362
+ if(this.focusedItem){
363
+ this._chooseItem(this.focusedItem, true);
364
+ }
365
+ }
366
+ }
367
+
357
368
  _keyUp(e){
358
369
  var index = this.displayItems.indexOf(this.focusedItem);
359
370
 
@@ -991,7 +1002,7 @@ export default class Edit{
991
1002
 
992
1003
  _resolveValue(blur){
993
1004
  var output, initialValue;
994
-
1005
+
995
1006
  if(this.popup){
996
1007
  this.popup.hide(true);
997
1008
  }
@@ -59,7 +59,7 @@ export default function(cell, onRendered, success, cancel, editorParams){
59
59
  input.value = cellValue;
60
60
 
61
61
  onRendered(function(){
62
- if(cell._getSelf){
62
+ if(cell.getType() === "cell"){
63
63
  input.focus({preventScroll: true});
64
64
  input.style.height = "100%";
65
65
 
@@ -46,7 +46,7 @@ export default function(cell, onRendered, success, cancel, editorParams){
46
46
  input.value = cellValue;
47
47
 
48
48
  onRendered(function(){
49
- if(cell._getSelf){
49
+ if(cell.getType() === "cell"){
50
50
  input.focus({preventScroll: true});
51
51
  input.style.height = "100%";
52
52
 
@@ -26,7 +26,7 @@ export default function(cell, onRendered, success, cancel, editorParams){
26
26
  input.value = typeof cellValue !== "undefined" ? cellValue : "";
27
27
 
28
28
  onRendered(function(){
29
- if(cell._getSelf){
29
+ if(cell.getType() === "cell"){
30
30
  input.focus({preventScroll: true});
31
31
  input.style.height = "100%";
32
32
 
@@ -43,7 +43,7 @@ export default function(cell, onRendered, success, cancel, editorParams){
43
43
  };
44
44
 
45
45
  onRendered(function () {
46
- if(cell._getSelf){
46
+ if(cell.getType() === "cell"){
47
47
  //submit new value on blur
48
48
  input.removeEventListener("blur", blurFunc);
49
49
 
@@ -36,7 +36,7 @@ export default function(cell, onRendered, success, cancel, editorParams){
36
36
  input.value = cellValue;
37
37
 
38
38
  onRendered(function () {
39
- if(cell._getSelf){
39
+ if(cell.getType() === "cell"){
40
40
  input.focus({preventScroll: true});
41
41
  input.style.height = "100%";
42
42
  }
@@ -31,7 +31,7 @@ export default function(cell, onRendered, success, cancel, editorParams){
31
31
  input.value = value;
32
32
 
33
33
  onRendered(function(){
34
- if(cell._getSelf){
34
+ if(cell.getType() === "cell"){
35
35
  input.focus({preventScroll: true});
36
36
  input.style.height = "100%";
37
37
 
@@ -32,7 +32,7 @@ export default function(cell, onRendered, success, cancel, editorParams){
32
32
 
33
33
  if(this.table.browser != "firefox" && this.table.browser != "safari"){ //prevent blur issue on mac firefox
34
34
  onRendered(function(){
35
- if(cell._getSelf){
35
+ if(cell.getType() === "cell"){
36
36
  input.focus({preventScroll: true});
37
37
  }
38
38
  });
@@ -47,7 +47,7 @@ export default function(cell, onRendered, success, cancel, editorParams){
47
47
  input.value = cellValue;
48
48
 
49
49
  onRendered(function(){
50
- if(cell._getSelf){
50
+ if(cell.getType() == "cell"){
51
51
  input.focus({preventScroll: true});
52
52
  input.style.height = "100%";
53
53
 
@@ -489,6 +489,9 @@ class Export extends Module{
489
489
  getElement:function(){
490
490
  return cellEl;
491
491
  },
492
+ getType:function(){
493
+ return "cell";
494
+ },
492
495
  getColumn:function(){
493
496
  return column.getComponent();
494
497
  },
@@ -22,6 +22,7 @@ class Filter extends Module{
22
22
  this.registerTableOption("initialFilter", false); //initial filtering criteria
23
23
  this.registerTableOption("initialHeaderFilter", false); //initial header filtering criteria
24
24
  this.registerTableOption("headerFilterLiveFilterDelay", 300); //delay before updating column after user types in header filter
25
+ this.registerTableOption("placeholderHeaderFilter", false); //placeholder when header filter is empty
25
26
 
26
27
  this.registerColumnOption("headerFilter");
27
28
  this.registerColumnOption("headerFilterPlaceholder");
@@ -57,6 +58,7 @@ class Filter extends Module{
57
58
  this.subscribe("column-width-fit-before", this.hideHeaderFilterElements.bind(this));
58
59
  this.subscribe("column-width-fit-after", this.showHeaderFilterElements.bind(this));
59
60
  this.subscribe("table-built", this.tableBuilt.bind(this));
61
+ this.subscribe("placeholder", this.generatePlaceholder.bind(this));
60
62
 
61
63
  if(this.table.options.filterMode === "remote"){
62
64
  this.subscribe("data-params", this.remoteFilterParams.bind(this));
@@ -92,6 +94,12 @@ class Filter extends Module{
92
94
  return params;
93
95
  }
94
96
 
97
+ generatePlaceholder(text){
98
+ if(this.table.options.placeholderHeaderFilter && Object.keys(this.headerFilters).length){
99
+ return this.table.options.placeholderHeaderFilter;
100
+ }
101
+ }
102
+
95
103
  ///////////////////////////////////
96
104
  ///////// Table Functions /////////
97
105
  ///////////////////////////////////
@@ -375,6 +383,9 @@ class Filter extends Module{
375
383
  getTable:() => {
376
384
  return this.table;
377
385
  },
386
+ getType:() => {
387
+ return "header";
388
+ },
378
389
  getRow:function(){
379
390
  return {
380
391
  normalizeHeight:function(){
@@ -96,6 +96,9 @@ class Format extends Module{
96
96
  getElement:function(){
97
97
  return el;
98
98
  },
99
+ getType:function(){
100
+ return "header";
101
+ },
99
102
  getColumn:function(){
100
103
  return column.getComponent();
101
104
  },