tabulator-tables 5.0.8 → 5.1.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 (112) hide show
  1. package/.editorconfig +6 -0
  2. package/LICENSE +1 -1
  3. package/bower.json +1 -1
  4. package/build/rollup.js +2 -1
  5. package/dist/css/tabulator.css +26 -6
  6. package/dist/css/tabulator.css.map +1 -1
  7. package/dist/css/tabulator.min.css +1 -1
  8. package/dist/css/tabulator.min.css.map +1 -1
  9. package/dist/css/tabulator_bootstrap3.css +26 -6
  10. package/dist/css/tabulator_bootstrap3.css.map +1 -1
  11. package/dist/css/tabulator_bootstrap3.min.css +1 -1
  12. package/dist/css/tabulator_bootstrap3.min.css.map +1 -1
  13. package/dist/css/tabulator_bootstrap4.css +26 -6
  14. package/dist/css/tabulator_bootstrap4.css.map +1 -1
  15. package/dist/css/tabulator_bootstrap4.min.css +1 -1
  16. package/dist/css/tabulator_bootstrap4.min.css.map +1 -1
  17. package/dist/css/tabulator_bulma.css +26 -6
  18. package/dist/css/tabulator_bulma.css.map +1 -1
  19. package/dist/css/tabulator_bulma.min.css +1 -1
  20. package/dist/css/tabulator_bulma.min.css.map +1 -1
  21. package/dist/css/tabulator_materialize.css +33 -10
  22. package/dist/css/tabulator_materialize.css.map +1 -1
  23. package/dist/css/tabulator_materialize.min.css +1 -1
  24. package/dist/css/tabulator_materialize.min.css.map +1 -1
  25. package/dist/css/tabulator_midnight.css +30 -6
  26. package/dist/css/tabulator_midnight.css.map +1 -1
  27. package/dist/css/tabulator_midnight.min.css +1 -1
  28. package/dist/css/tabulator_midnight.min.css.map +1 -1
  29. package/dist/css/tabulator_modern.css +26 -6
  30. package/dist/css/tabulator_modern.css.map +1 -1
  31. package/dist/css/tabulator_modern.min.css +1 -1
  32. package/dist/css/tabulator_modern.min.css.map +1 -1
  33. package/dist/css/tabulator_semanticui.css +26 -6
  34. package/dist/css/tabulator_semanticui.css.map +1 -1
  35. package/dist/css/tabulator_semanticui.min.css +1 -1
  36. package/dist/css/tabulator_semanticui.min.css.map +1 -1
  37. package/dist/css/tabulator_simple.css +26 -6
  38. package/dist/css/tabulator_simple.css.map +1 -1
  39. package/dist/css/tabulator_simple.min.css +1 -1
  40. package/dist/css/tabulator_simple.min.css.map +1 -1
  41. package/dist/css/tabulator_site.css +30 -6
  42. package/dist/css/tabulator_site.css.map +1 -1
  43. package/dist/css/tabulator_site.min.css +1 -1
  44. package/dist/css/tabulator_site.min.css.map +1 -1
  45. package/dist/js/tabulator.js +1182 -548
  46. package/dist/js/tabulator.js.map +1 -1
  47. package/dist/js/tabulator.min.js +2 -2
  48. package/dist/js/tabulator.min.js.map +1 -1
  49. package/dist/js/tabulator_esm.js +1797 -1184
  50. package/dist/js/tabulator_esm.js.map +1 -1
  51. package/dist/js/tabulator_esm.min.js +2 -2
  52. package/dist/js/tabulator_esm.min.js.map +1 -1
  53. package/package.json +1 -1
  54. package/src/js/core/ColumnManager.js +1 -1
  55. package/src/js/core/CoreFeature.js +1 -5
  56. package/src/js/core/FooterManager.js +14 -2
  57. package/src/js/core/RowManager.js +325 -286
  58. package/src/js/core/Tabulator.js +0 -43
  59. package/src/js/core/cell/Cell.js +5 -1
  60. package/src/js/core/column/Column.js +21 -6
  61. package/src/js/core/column/ColumnComponent.js +6 -0
  62. package/src/js/core/column/defaults/options.js +1 -0
  63. package/src/js/core/defaults/options.js +3 -3
  64. package/src/js/core/modules/optional.js +1 -0
  65. package/src/js/core/rendering/Renderer.js +3 -2
  66. package/src/js/core/rendering/renderers/BasicVertical.js +2 -1
  67. package/src/js/core/rendering/renderers/VirtualDomHorizontal.js +165 -151
  68. package/src/js/core/rendering/renderers/VirtualDomVertical.js +1 -1
  69. package/src/js/core/row/Row.js +2 -2
  70. package/src/js/core/tools/DataLoader.js +6 -6
  71. package/src/js/core/tools/InteractionMonitor.js +157 -52
  72. package/src/js/modules/Ajax/Ajax.js +62 -82
  73. package/src/js/modules/ColumnCalcs/ColumnCalcs.js +16 -3
  74. package/src/js/modules/DataTree/DataTree.js +22 -9
  75. package/src/js/modules/Download/defaults/downloaders/json.js +1 -1
  76. package/src/js/modules/Download/defaults/downloaders/jsonLines.js +32 -0
  77. package/src/js/modules/Download/defaults/downloaders/pdf.js +0 -2
  78. package/src/js/modules/Download/defaults/downloaders/xlsx.js +3 -2
  79. package/src/js/modules/Download/defaults/downloaders.js +2 -0
  80. package/src/js/modules/Edit/Edit.js +27 -39
  81. package/src/js/modules/Export/Export.js +1 -1
  82. package/src/js/modules/Filter/Filter.js +1 -1
  83. package/src/js/modules/Format/defaults/formatters/datetime.js +1 -1
  84. package/src/js/modules/Format/defaults/formatters/datetimediff.js +2 -1
  85. package/src/js/modules/FrozenColumns/FrozenColumns.js +1 -1
  86. package/src/js/modules/FrozenRows/FrozenRows.js +9 -0
  87. package/src/js/modules/GroupRows/Group.js +8 -63
  88. package/src/js/modules/GroupRows/GroupComponent.js +1 -1
  89. package/src/js/modules/GroupRows/GroupRows.js +2 -2
  90. package/src/js/modules/Import/Import.js +195 -0
  91. package/src/js/modules/Import/defaults/importers/csv.js +63 -0
  92. package/src/js/modules/Import/defaults/importers/json.js +8 -0
  93. package/src/js/modules/Import/defaults/importers.js +7 -0
  94. package/src/js/modules/Interaction/Interaction.js +5 -0
  95. package/src/js/modules/Keybindings/Keybindings.js +9 -14
  96. package/src/js/modules/Keybindings/defaults/bindings.js +3 -3
  97. package/src/js/modules/Localize/defaults/langs.js +6 -0
  98. package/src/js/modules/Menu/Menu.js +200 -155
  99. package/src/js/modules/MoveRows/MoveRows.js +4 -0
  100. package/src/js/modules/Page/Page.js +282 -185
  101. package/src/js/modules/Page/defaults/pageCounters/pages.js +33 -0
  102. package/src/js/modules/Page/defaults/pageCounters/rows.js +32 -0
  103. package/src/js/modules/Page/defaults/pageCounters.js +8 -0
  104. package/src/js/modules/ResizeRows/ResizeRows.js +1 -1
  105. package/src/js/modules/ResponsiveLayout/ResponsiveLayout.js +7 -9
  106. package/src/js/modules/SelectRow/SelectRow.js +4 -9
  107. package/src/js/modules/Sort/defaults/sorters/datetime.js +2 -2
  108. package/src/js/modules/Validate/Validate.js +7 -5
  109. package/src/scss/tabulator.scss +31 -8
  110. package/src/scss/themes/materialize/tabulator_materialize.scss +5 -4
  111. package/src/scss/themes/tabulator_midnight.scss +4 -0
  112. package/src/scss/themes/tabulator_site.scss +4 -0
@@ -0,0 +1,63 @@
1
+ function csvImporter(input){
2
+ var data = [],
3
+ row = 0,
4
+ col = 0,
5
+ inQuote = false;
6
+
7
+ //Iterate over each character
8
+ for (let index = 0; index < input.length; index++) {
9
+ let char = input[index],
10
+ nextChar = input[index+1];
11
+
12
+ //Initialize empty row
13
+ if(!data[row]){
14
+ data[row] = [];
15
+ }
16
+
17
+ //Initialize empty column
18
+ if(!data[row][col]){
19
+ data[row][col] = "";
20
+ }
21
+
22
+ //Handle quotation mark inside string
23
+ if (char == '"' && inQuote && nextChar == '"') {
24
+ data[row][col] += char;
25
+ index++;
26
+ continue;
27
+ }
28
+
29
+ //Begin / End Quote
30
+ if (char == '"') {
31
+ inQuote = !inQuote;
32
+ continue;
33
+ }
34
+
35
+ //Next column (if not in quote)
36
+ if (char == ',' && !inQuote) {
37
+ col++;
38
+ continue;
39
+ }
40
+
41
+ //New row if new line and not in quote (CRLF)
42
+ if (char == '\r' && nextChar == '\n' && !inQuote) {
43
+ col = 0;
44
+ row++;
45
+ index++;
46
+ continue;
47
+ }
48
+
49
+ //New row if new line and not in quote (CR or LF)
50
+ if ((char == '\r' || char == '\n') && !inQuote) {
51
+ col = 0;
52
+ row++;
53
+ continue;
54
+ }
55
+
56
+ //Normal Character, append to column
57
+ data[row][col] += char;
58
+ }
59
+
60
+ return data;
61
+ }
62
+
63
+ export default csvImporter;
@@ -0,0 +1,8 @@
1
+ export default function(input){
2
+ try {
3
+ return JSON.parse(input);
4
+ } catch(e) {
5
+ console.warn("JSON Import Error - File contents is invalid JSON", e);
6
+ return Promise.reject();
7
+ }
8
+ }
@@ -0,0 +1,7 @@
1
+ import csv from './importers/csv.js';
2
+ import json from './importers/json.js';
3
+
4
+ export default {
5
+ csv:csv,
6
+ json:json,
7
+ };
@@ -84,6 +84,11 @@ class Interaction extends Module{
84
84
  tap:null,
85
85
  tapDbl:null,
86
86
  tapHold:null,
87
+ },
88
+ group:{
89
+ tap:null,
90
+ tapDbl:null,
91
+ tapHold:null,
87
92
  }
88
93
  }
89
94
 
@@ -13,7 +13,7 @@ class Keybindings extends Module{
13
13
  this.keyupBinding = false;
14
14
  this.keydownBinding = false;
15
15
 
16
- this.registerTableOption("keybindings", []); //array for keybindings
16
+ this.registerTableOption("keybindings", {}); //array for keybindings
17
17
  this.registerTableOption("tabEndNewRow", false); //create new row when tab to end of table
18
18
  }
19
19
 
@@ -25,17 +25,8 @@ class Keybindings extends Module{
25
25
  this.pressedKeys = [];
26
26
 
27
27
  if(bindings !== false){
28
-
29
- for(let key in Keybindings.bindings){
30
- mergedBindings[key] = Keybindings.bindings[key];
31
- }
32
-
33
- if(Object.keys(bindings).length){
34
-
35
- for(let key in bindings){
36
- mergedBindings[key] = bindings[key];
37
- }
38
- }
28
+ Object.assign(mergedBindings, Keybindings.bindings)
29
+ Object.assign(mergedBindings, bindings)
39
30
 
40
31
  this.mapBindings(mergedBindings);
41
32
  this.bindEvents();
@@ -53,7 +44,11 @@ class Keybindings extends Module{
53
44
  }
54
45
 
55
46
  bindings[key].forEach((binding) => {
56
- this.mapBinding(key, binding);
47
+ var bindingList = Array.isArray(binding) ? binding : [binding];
48
+
49
+ bindingList.forEach((item) => {
50
+ this.mapBinding(key, item);
51
+ });
57
52
  });
58
53
  }
59
54
  }else{
@@ -88,7 +83,7 @@ class Keybindings extends Module{
88
83
  break;
89
84
 
90
85
  default:
91
- symbol = parseInt(symbol);
86
+ symbol = isNaN(symbol) ? symbol.toUpperCase().charCodeAt(0) : parseInt(symbol);
92
87
  binding.keys.push(symbol);
93
88
 
94
89
  if(!this.watchKeys[symbol]){
@@ -7,7 +7,7 @@ export default {
7
7
  scrollPageDown:34,
8
8
  scrollToStart:36,
9
9
  scrollToEnd:35,
10
- undo:"ctrl + 90",
11
- redo:"ctrl + 89",
12
- copyToClipboard:"ctrl + 67",
10
+ undo:["ctrl + 90", "meta + 90"],
11
+ redo:["ctrl + 89", "meta + 89"],
12
+ copyToClipboard:["ctrl + 67", "meta + 89"],
13
13
  };
@@ -22,6 +22,12 @@ export default {
22
22
  "next":"Next",
23
23
  "next_title":"Next Page",
24
24
  "all":"All",
25
+ "counter":{
26
+ "showing": "Showing",
27
+ "of": "of",
28
+ "rows": "rows",
29
+ "pages": "pages",
30
+ }
25
31
  },
26
32
  "headerFilters":{
27
33
  "default":"filter column...",
@@ -2,164 +2,194 @@ import Module from '../../core/Module.js';
2
2
  import Helpers from '../../core/tools/Helpers.js';
3
3
 
4
4
  class Menu extends Module{
5
-
5
+
6
6
  constructor(table){
7
7
  super(table);
8
-
8
+
9
+ this.menuContainer = null;
9
10
  this.menuElements = [];
10
11
  this.blurEvent = this.hideMenu.bind(this);
11
12
  this.escEvent = this.escMenu.bind(this);
12
13
  this.nestedMenuBlock = false;
13
14
  this.positionReversedX = false;
14
-
15
+
16
+ this.currentComponent = null;
17
+
18
+ this.columnSubscribers = {};
19
+
15
20
  this.registerTableOption("rowContextMenu", false);
16
21
  this.registerTableOption("rowClickMenu", false);
17
22
  this.registerTableOption("groupContextMenu", false);
18
23
  this.registerTableOption("groupClickMenu", false);
19
-
24
+ this.registerTableOption("menuContainer", false);
25
+
20
26
  this.registerColumnOption("headerContextMenu");
27
+ this.registerColumnOption("headerClickMenu");
21
28
  this.registerColumnOption("headerMenu");
22
29
  this.registerColumnOption("contextMenu");
23
30
  this.registerColumnOption("clickMenu");
24
31
  }
25
-
32
+
26
33
  initialize(){
27
- this.subscribe("cell-layout", this.layoutCell.bind(this));
34
+ this.lookupMenuContainer();
35
+
36
+ this.initializeRowWatchers();
37
+ this.initializeGroupWatchers();
38
+
28
39
  this.subscribe("column-init", this.initializeColumn.bind(this));
29
- this.subscribe("row-init", this.initializeRow.bind(this));
30
40
  }
31
-
32
- layoutCell(cell){
33
- if(cell.column.definition.contextMenu || cell.column.definition.clickMenu){
34
- this.initializeCell(cell);
41
+
42
+ lookupMenuContainer(){
43
+
44
+ this.menuContainer = this.table.options.menuContainer;
45
+
46
+ if(typeof this.menuContainer === "string"){
47
+ this.menuContainer = document.querySelector(this.menuContainer);
48
+
49
+ if(!this.menuContainer){
50
+ console.warn("Menu Error - no container element found matching selector:", this.table.options.menuContainer , "(defaulting to document body)");
51
+ }
52
+ }else if (this.menuContainer === true){
53
+ this.menuContainer = this.table.element;
54
+ }
55
+
56
+ if(this.menuContainer && !this.checkMenuContainerIsParent(this.menuContainer)){
57
+ this.menuContainer = false;
58
+ console.warn("Menu Error - container element does not contain this table:", this.table.options.menuContainer , "(defaulting to document body)");
59
+ }
60
+
61
+ if(!this.menuContainer){
62
+ this.menuContainer = document.body;
35
63
  }
36
64
  }
37
-
38
- initializeColumn(column){
39
- var def = column.definition;
40
-
41
- if(def.headerContextMenu || def.headerClickMenu || def.headerMenu){
42
- this.initializeColumnHeader(column);
65
+
66
+ checkMenuContainerIsParent(container, element = this.table.element){
67
+ if(container === element){
68
+ return true;
69
+ }else{
70
+ return element.parentNode ? this.checkMenuContainerIsParent(container, element.parentNode) : false;
43
71
  }
44
72
  }
45
-
46
- initializeColumnHeader(column){
47
- var headerMenuEl;
48
-
49
- if(column.definition.headerContextMenu){
50
- column.getElement().addEventListener("contextmenu", this.LoadMenuEvent.bind(this, column, column.definition.headerContextMenu));
51
- this.tapHold(column, column.definition.headerContextMenu);
73
+
74
+ initializeRowWatchers(){
75
+ if(this.table.options.rowContextMenu){
76
+ this.subscribe("row-contextmenu", this.loadMenuEvent.bind(this, this.table.options.rowContextMenu));
77
+ this.table.on("rowTapHold", this.loadMenuEvent.bind(this, this.table.options.rowContextMenu));
52
78
  }
53
-
54
- // if(column.definition.headerClickMenu){
55
- // column.getElement().addEventListener("click", this.LoadMenuEvent.bind(this, column, column.definition.headerClickMenu));
56
- // }
57
-
58
- if(column.definition.headerMenu){
59
-
60
- headerMenuEl = document.createElement("span");
61
- headerMenuEl.classList.add("tabulator-header-menu-button");
62
- headerMenuEl.innerHTML = "&vellip;";
63
-
64
- headerMenuEl.addEventListener("click", (e) => {
65
- e.stopPropagation();
66
- e.preventDefault();
67
-
68
- this.LoadMenuEvent(column, column.definition.headerMenu, e);
69
- });
70
-
71
- column.titleElement.insertBefore(headerMenuEl, column.titleElement.firstChild);
79
+
80
+ if(this.table.options.rowClickMenu){
81
+ this.subscribe("row-click", this.loadMenuEvent.bind(this, this.table.options.rowClickMenu));
72
82
  }
73
83
  }
74
-
75
- LoadMenuEvent(component, menu, e){
76
- menu = typeof menu == "function" ? menu.call(this.table, component.getComponent(), e) : menu;
77
-
78
- // if(component instanceof Cell){
79
- // e.stopImmediatePropagation();
80
- // }
81
-
82
- this.loadMenu(e, component, menu);
84
+
85
+ initializeGroupWatchers(){
86
+ if(this.table.options.groupContextMenu){
87
+ this.subscribe("group-contextmenu", this.loadMenuEvent.bind(this, this.table.options.groupContextMenu));
88
+ this.table.on("groupTapHold", this.loadMenuEvent.bind(this, this.table.options.groupContextMenu));
89
+ }
90
+
91
+ if(this.table.options.groupClickMenu){
92
+ this.subscribe("group-click", this.loadMenuEvent.bind(this, this.table.options.groupClickMenu));
93
+ }
83
94
  }
84
-
85
- tapHold(component, menu){
86
- var element = component.getElement(),
87
- tapHold = null,
88
- loaded = false;
89
-
90
- element.addEventListener("touchstart", (e) => {
91
- clearTimeout(tapHold);
92
- loaded = false;
93
-
94
- tapHold = setTimeout(() => {
95
- clearTimeout(tapHold);
96
- tapHold = null;
97
- loaded = true;
98
-
99
- this.LoadMenuEvent(component, menu, e);
100
- }, 1000);
101
-
102
- }, {passive: true});
103
-
104
- element.addEventListener("touchend", (e) => {
105
- clearTimeout(tapHold);
106
- tapHold = null;
107
-
108
- if(loaded){
109
- e.preventDefault();
110
- }
95
+
96
+ initializeColumn(column){
97
+ var options = ["headerContextMenu", "headerClickMenu"],
98
+ def = column.definition;
99
+
100
+ //handle column events
101
+ if(def.headerContextMenu && !this.columnSubscribers.headerContextMenu){
102
+ this.columnSubscribers.headerContextMenu = this.loadMenuTableColumnEvent.bind(this, "headerContextMenu");
103
+ this.subscribe("column-contextmenu", this.columnSubscribers.headerContextMenu);
104
+ this.table.on("headerTapHold", this.loadMenuTableColumnEvent.bind(this, "headerContextMenu"))
105
+ }
106
+
107
+ if(def.headerClickMenu && !this.columnSubscribers.headerClickMenu){
108
+ this.columnSubscribers.headerClickMenu = this.loadMenuTableColumnEvent.bind(this, "headerClickMenu");
109
+ this.subscribe("column-click", this.columnSubscribers.headerClickMenu);
110
+ }
111
+
112
+ if(def.headerMenu){
113
+ this.initializeColumnHeaderMenu(column);
114
+ }
115
+
116
+ //handle cell events
117
+ if(def.contextMenu && !this.columnSubscribers.contextMenu){
118
+ this.columnSubscribers.contextMenu = this.loadMenuTableCellEvent.bind(this, "contextMenu");
119
+ this.subscribe("cell-contextmenu", this.columnSubscribers.contextMenu);
120
+ this.table.on("cellTapHold", this.loadMenuTableCellEvent.bind(this, "contextMenu"))
121
+ }
122
+
123
+ if(def.clickMenu && !this.columnSubscribers.clickMenu){
124
+ this.columnSubscribers.clickMenu = this.loadMenuTableCellEvent.bind(this, "clickMenu");
125
+ this.subscribe("cell-click", this.columnSubscribers.clickMenu);
126
+ }
127
+ }
128
+
129
+ initializeColumnHeaderMenu(column){
130
+ var headerMenuEl;
131
+
132
+ headerMenuEl = document.createElement("span");
133
+ headerMenuEl.classList.add("tabulator-header-menu-button");
134
+ headerMenuEl.innerHTML = "&vellip;";
135
+
136
+ headerMenuEl.addEventListener("click", (e) => {
137
+ e.stopPropagation();
138
+ e.preventDefault();
139
+
140
+ this.loadMenuEvent(column.definition.headerMenu, e, column);
111
141
  });
142
+
143
+ column.titleElement.insertBefore(headerMenuEl, column.titleElement.firstChild);
112
144
  }
113
-
114
- initializeCell(cell){
115
- if(cell.column.definition.contextMenu){
116
- cell.getElement(true).addEventListener("contextmenu", this.LoadMenuEvent.bind(this, cell, cell.column.definition.contextMenu));
117
- this.tapHold(cell, cell.column.definition.contextMenu);
145
+
146
+ loadMenuTableCellEvent(option, e, cell){
147
+ if(cell._cell){
148
+ cell = cell._cell;
118
149
  }
119
-
120
- if(cell.column.definition.clickMenu){
121
- cell.getElement(true).addEventListener("click", this.LoadMenuEvent.bind(this, cell, cell.column.definition.clickMenu));
150
+
151
+ if(cell.column.definition[option]){
152
+ this.loadMenuEvent(cell.column.definition[option], e, cell);
122
153
  }
123
154
  }
124
-
125
- initializeRow(row){
126
- if(this.table.options.rowContextMenu){
127
- row.getElement().addEventListener("contextmenu", this.LoadMenuEvent.bind(this, row, this.table.options.rowContextMenu));
128
- this.tapHold(row, this.table.options.rowContextMenu);
155
+
156
+ loadMenuTableColumnEvent(option, e, column){
157
+ if(column._column){
158
+ column = column._column;
129
159
  }
130
-
131
- if(this.table.options.rowClickMenu){
132
- row.getElement().addEventListener("click", this.LoadMenuEvent.bind(this, row, this.table.options.rowClickMenu));
160
+
161
+ if(column.definition[option]){
162
+ this.loadMenuEvent(column.definition[option], e, column);
133
163
  }
134
164
  }
135
-
136
- initializeGroup (group){
137
- if(this.table.options.groupContextMenu){
138
- group.getElement().addEventListener("contextmenu", this.LoadMenuEvent.bind(this, group, this.table.options.groupContextMenu));
139
- this.tapHold(group, this.table.options.groupContextMenu);
140
- }
141
-
142
- if(this.table.options.groupClickMenu){
143
- group.getElement().addEventListener("click", this.LoadMenuEvent.bind(this, group, this.table.options.groupClickMenu));
165
+
166
+ loadMenuEvent(menu, e, component){
167
+ if(component._group){
168
+ component = component._group;
169
+ }else if(component._row){
170
+ component = component._row;
144
171
  }
172
+
173
+ menu = typeof menu == "function" ? menu.call(this.table, component.getComponent(), e) : menu;
174
+
175
+ this.loadMenu(e, component, menu);
145
176
  }
146
-
177
+
147
178
  loadMenu(e, component, menu, parentEl){
148
-
149
179
  var touch = !(e instanceof MouseEvent);
150
-
180
+
151
181
  var menuEl = document.createElement("div");
152
182
  menuEl.classList.add("tabulator-menu");
153
-
183
+
154
184
  if(!touch){
155
185
  e.preventDefault();
156
186
  }
157
-
187
+
158
188
  //abort if no menu set
159
189
  if(!menu || !menu.length){
160
190
  return;
161
191
  }
162
-
192
+
163
193
  if(!parentEl){
164
194
  if(this.nestedMenuBlock){
165
195
  //abort if child menu already open
@@ -171,35 +201,35 @@ class Menu extends Module{
171
201
  this.nestedMenuBlock = false;
172
202
  }, 100)
173
203
  }
174
-
204
+
175
205
  this.hideMenu();
176
206
  this.menuElements = [];
177
207
  }
178
-
208
+
179
209
  menu.forEach((item) => {
180
210
  var itemEl = document.createElement("div"),
181
211
  label = item.label,
182
212
  disabled = item.disabled;
183
-
213
+
184
214
  if(item.separator){
185
215
  itemEl.classList.add("tabulator-menu-separator");
186
216
  }else{
187
217
  itemEl.classList.add("tabulator-menu-item");
188
-
218
+
189
219
  if(typeof label == "function"){
190
220
  label = label.call(this.table, component.getComponent());
191
221
  }
192
-
222
+
193
223
  if(label instanceof Node){
194
224
  itemEl.appendChild(label);
195
225
  }else{
196
226
  itemEl.innerHTML = label;
197
227
  }
198
-
228
+
199
229
  if(typeof disabled == "function"){
200
230
  disabled = disabled.call(this.table, component.getComponent());
201
231
  }
202
-
232
+
203
233
  if(disabled){
204
234
  itemEl.classList.add("tabulator-menu-item-disabled");
205
235
  itemEl.addEventListener("click", (e) => {
@@ -220,57 +250,67 @@ class Menu extends Module{
220
250
  }
221
251
  }
222
252
  }
223
-
253
+
224
254
  if(item.menu && item.menu.length){
225
255
  itemEl.classList.add("tabulator-menu-item-submenu");
226
256
  }
227
257
  }
228
-
258
+
229
259
  menuEl.appendChild(itemEl);
230
260
  });
231
-
261
+
232
262
  menuEl.addEventListener("click", (e) => {
233
263
  this.hideMenu();
234
264
  });
235
-
265
+
236
266
  this.menuElements.push(menuEl);
237
267
  this.positionMenu(menuEl, parentEl, touch, e);
268
+
269
+ this.currentComponent = component
270
+
271
+ this.dispatchExternal("menuOpened", component.getComponent())
238
272
  }
239
-
273
+
240
274
  hideOldSubMenus(menuEl){
241
275
  var index = this.menuElements.indexOf(menuEl);
242
-
276
+
243
277
  if(index > -1){
244
278
  for(let i = this.menuElements.length - 1; i > index; i--){
245
279
  var el = this.menuElements[i];
246
-
280
+
247
281
  if(el.parentNode){
248
282
  el.parentNode.removeChild(el);
249
283
  }
250
-
284
+
251
285
  this.menuElements.pop();
252
286
  }
253
287
  }
254
288
  }
255
-
289
+
256
290
  positionMenu(element, parentEl, touch, e){
257
- var docHeight = Math.max(document.body.offsetHeight, window.innerHeight),
258
- x, y, parentOffset;
259
-
291
+ var x, y, parentOffset;
292
+
260
293
  if(!parentEl){
261
294
  x = touch ? e.touches[0].pageX : e.pageX;
262
295
  y = touch ? e.touches[0].pageY : e.pageY;
263
-
296
+
297
+ if(this.menuContainer !== document.body){
298
+ parentOffset = Helpers.elOffset(this.menuContainer);
299
+
300
+ x -= parentOffset.left;
301
+ y -= parentOffset.top;
302
+ }
303
+
264
304
  this.positionReversedX = false;
265
305
  }else{
266
306
  parentOffset = Helpers.elOffset(parentEl);
267
307
  x = parentOffset.left + parentEl.offsetWidth;
268
308
  y = parentOffset.top - 1;
269
309
  }
270
-
310
+
271
311
  element.style.top = y + "px";
272
312
  element.style.left = x + "px";
273
-
313
+
274
314
  setTimeout(() => {
275
315
  this.table.rowManager.element.addEventListener("scroll", this.blurEvent);
276
316
  document.body.addEventListener("click", this.blurEvent);
@@ -278,56 +318,61 @@ class Menu extends Module{
278
318
  window.addEventListener("resize", this.blurEvent);
279
319
  document.body.addEventListener("keydown", this.escEvent);
280
320
  }, 100);
281
-
282
- document.body.appendChild(element);
283
-
284
- //move menu to start on bottom edge if it is too close to the edge of the screen
285
- if((y + element.offsetHeight) >= docHeight){
286
- element.style.top = "";
287
-
321
+
322
+ this.menuContainer.appendChild(element);
323
+
324
+ //move menu to start on right edge if it is too close to the edge of the screen
325
+ if((x + element.offsetWidth) >= this.menuContainer.offsetWidth || this.positionReversedX){
326
+ element.style.left = "";
327
+
288
328
  if(parentEl){
289
- element.style.bottom = (docHeight - parentOffset.top - parentEl.offsetHeight - 1) + "px";
329
+ element.style.right = (this.menuContainer.offsetWidth - parentOffset.left) + "px";
290
330
  }else{
291
- element.style.bottom = (docHeight - y) + "px";
331
+ element.style.right = (this.menuContainer.offsetWidth - x) + "px";
292
332
  }
333
+
334
+ this.positionReversedX = true;
293
335
  }
294
-
295
- //move menu to start on right edge if it is too close to the edge of the screen
296
- if((x + element.offsetWidth) >= document.body.offsetWidth || this.positionReversedX){
297
- element.style.left = "";
298
-
336
+
337
+ //move menu to start on bottom edge if it is too close to the edge of the screen
338
+ if((y + element.offsetHeight) >= this.menuContainer.offsetHeight){
339
+ element.style.top = "";
340
+
299
341
  if(parentEl){
300
- element.style.right = (document.documentElement.offsetWidth - parentOffset.left) + "px";
342
+ element.style.bottom = (this.menuContainer.offsetHeight - parentOffset.top - parentEl.offsetHeight - 1) + "px";
301
343
  }else{
302
- element.style.right = (document.documentElement.offsetWidth - x) + "px";
344
+ element.style.bottom = (this.menuContainer.offsetHeight - y) + "px";
303
345
  }
304
-
305
- this.positionReversedX = true;
306
346
  }
307
347
  }
308
-
348
+
309
349
  isOpen(){
310
350
  return !!this.menuElements.length;
311
351
  }
312
-
352
+
313
353
  escMenu(e){
314
354
  if(e.keyCode == 27){
315
355
  this.hideMenu();
316
356
  }
317
357
  }
318
-
319
- hideMenu(){
358
+
359
+ hideMenu(){
320
360
  this.menuElements.forEach((menuEl) => {
321
361
  if(menuEl.parentNode){
322
362
  menuEl.parentNode.removeChild(menuEl);
323
363
  }
324
364
  });
325
-
365
+
326
366
  document.body.removeEventListener("keydown", this.escEvent);
327
367
  document.body.removeEventListener("click", this.blurEvent);
328
368
  document.body.removeEventListener("contextmenu", this.blurEvent);
329
369
  window.removeEventListener("resize", this.blurEvent);
330
370
  this.table.rowManager.element.removeEventListener("scroll", this.blurEvent);
371
+
372
+ if(this.currentComponent){
373
+ this.dispatchExternal("menuClosed", this.currentComponent.getComponent());
374
+ this.currentComponent = null;
375
+ }
331
376
  }
332
377
  }
333
378