tabulator-tables 5.1.8 → 5.2.2

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 (100) hide show
  1. package/bower.json +1 -1
  2. package/dist/css/tabulator.css +64 -51
  3. package/dist/css/tabulator.css.map +1 -1
  4. package/dist/css/tabulator.min.css +1 -1
  5. package/dist/css/tabulator.min.css.map +1 -1
  6. package/dist/css/tabulator_bootstrap3.css +64 -51
  7. package/dist/css/tabulator_bootstrap3.css.map +1 -1
  8. package/dist/css/tabulator_bootstrap3.min.css +1 -1
  9. package/dist/css/tabulator_bootstrap3.min.css.map +1 -1
  10. package/dist/css/tabulator_bootstrap4.css +64 -51
  11. package/dist/css/tabulator_bootstrap4.css.map +1 -1
  12. package/dist/css/tabulator_bootstrap4.min.css +1 -1
  13. package/dist/css/tabulator_bootstrap4.min.css.map +1 -1
  14. package/dist/css/tabulator_bootstrap5.css +1580 -0
  15. package/dist/css/tabulator_bootstrap5.css.map +1 -0
  16. package/dist/css/tabulator_bootstrap5.min.css +2 -0
  17. package/dist/css/tabulator_bootstrap5.min.css.map +1 -0
  18. package/dist/css/tabulator_bulma.css +64 -51
  19. package/dist/css/tabulator_bulma.css.map +1 -1
  20. package/dist/css/tabulator_bulma.min.css +1 -1
  21. package/dist/css/tabulator_bulma.min.css.map +1 -1
  22. package/dist/css/tabulator_materialize.css +64 -51
  23. package/dist/css/tabulator_materialize.css.map +1 -1
  24. package/dist/css/tabulator_materialize.min.css +1 -1
  25. package/dist/css/tabulator_materialize.min.css.map +1 -1
  26. package/dist/css/tabulator_midnight.css +64 -51
  27. package/dist/css/tabulator_midnight.css.map +1 -1
  28. package/dist/css/tabulator_midnight.min.css +1 -1
  29. package/dist/css/tabulator_midnight.min.css.map +1 -1
  30. package/dist/css/tabulator_modern.css +64 -51
  31. package/dist/css/tabulator_modern.css.map +1 -1
  32. package/dist/css/tabulator_modern.min.css +1 -1
  33. package/dist/css/tabulator_modern.min.css.map +1 -1
  34. package/dist/css/tabulator_semanticui.css +64 -51
  35. package/dist/css/tabulator_semanticui.css.map +1 -1
  36. package/dist/css/tabulator_semanticui.min.css +1 -1
  37. package/dist/css/tabulator_semanticui.min.css.map +1 -1
  38. package/dist/css/tabulator_simple.css +64 -51
  39. package/dist/css/tabulator_simple.css.map +1 -1
  40. package/dist/css/tabulator_simple.min.css +1 -1
  41. package/dist/css/tabulator_simple.min.css.map +1 -1
  42. package/dist/css/tabulator_site.css +64 -51
  43. package/dist/css/tabulator_site.css.map +1 -1
  44. package/dist/css/tabulator_site.min.css +1 -1
  45. package/dist/css/tabulator_site.min.css.map +1 -1
  46. package/dist/js/tabulator.js +2540 -1659
  47. package/dist/js/tabulator.js.map +1 -1
  48. package/dist/js/tabulator.min.js +2 -2
  49. package/dist/js/tabulator.min.js.map +1 -1
  50. package/dist/js/tabulator_esm.js +2743 -2067
  51. package/dist/js/tabulator_esm.js.map +1 -1
  52. package/dist/js/tabulator_esm.min.js +2 -2
  53. package/dist/js/tabulator_esm.min.js.map +1 -1
  54. package/package.json +1 -1
  55. package/src/js/core/FooterManager.js +6 -13
  56. package/src/js/core/Module.js +44 -2
  57. package/src/js/core/Tabulator.js +341 -289
  58. package/src/js/core/cell/Cell.js +9 -38
  59. package/src/js/core/column/Column.js +8 -44
  60. package/src/js/core/column/defaults/options.js +0 -2
  61. package/src/js/core/defaults/options.js +5 -2
  62. package/src/js/core/modules/optional.js +2 -0
  63. package/src/js/core/row/Row.js +127 -118
  64. package/src/js/core/tools/Alert.js +63 -0
  65. package/src/js/core/tools/DataLoader.js +12 -84
  66. package/src/js/core/tools/InteractionMonitor.js +1 -1
  67. package/src/js/core/tools/ModuleBinder.js +30 -23
  68. package/src/js/core/tools/Popup.js +251 -0
  69. package/src/js/modules/ColumnCalcs/ColumnCalcs.js +2 -2
  70. package/src/js/modules/Edit/Edit.js +5 -25
  71. package/src/js/modules/Edit/List.js +997 -0
  72. package/src/js/modules/Edit/defaults/editors/autocomplete.js +6 -446
  73. package/src/js/modules/Edit/defaults/editors/input.js +4 -0
  74. package/src/js/modules/Edit/defaults/editors/list.js +7 -0
  75. package/src/js/modules/Edit/defaults/editors/number.js +4 -0
  76. package/src/js/modules/Edit/defaults/editors/select.js +5 -585
  77. package/src/js/modules/Edit/defaults/editors/textarea.js +4 -0
  78. package/src/js/modules/Edit/defaults/editors/tickCross.js +17 -5
  79. package/src/js/modules/Edit/defaults/editors.js +2 -0
  80. package/src/js/modules/Filter/Filter.js +7 -4
  81. package/src/js/modules/Format/defaults/formatters/datetime.js +9 -1
  82. package/src/js/modules/Format/defaults/formatters/datetimediff.js +10 -3
  83. package/src/js/modules/Format/defaults/formatters/link.js +12 -1
  84. package/src/js/modules/Format/defaults/formatters/money.js +5 -3
  85. package/src/js/modules/Format/defaults/formatters/tickCross.js +2 -1
  86. package/src/js/modules/FrozenColumns/FrozenColumns.js +30 -8
  87. package/src/js/modules/HtmlTableImport/HtmlTableImport.js +5 -1
  88. package/src/js/modules/Menu/Menu.js +58 -158
  89. package/src/js/modules/Mutator/Mutator.js +20 -0
  90. package/src/js/modules/Page/Page.js +7 -3
  91. package/src/js/modules/Persistence/Persistence.js +1 -1
  92. package/src/js/modules/Popup/Popup.js +194 -0
  93. package/src/js/modules/ResizeColumns/ResizeColumns.js +139 -82
  94. package/src/js/modules/Sort/defaults/sorters/datetime.js +15 -2
  95. package/src/js/modules/Tooltip/Tooltip.js +132 -0
  96. package/src/js/modules/Validate/Validate.js +107 -71
  97. package/src/scss/tabulator.scss +354 -349
  98. package/src/scss/themes/bootstrap/functions5.scss +302 -0
  99. package/src/scss/themes/bootstrap/tabulator_bootstrap5.scss +546 -0
  100. package/src/scss/themes/bootstrap/variables5.scss +1641 -0
@@ -266,11 +266,12 @@ class Filter extends Module{
266
266
  }
267
267
 
268
268
  self.headerFilters[field] = {value:value, func:filterFunc, type:type, params:params || {}};
269
-
270
269
  }else{
271
270
  delete self.headerFilters[field];
272
271
  }
273
272
 
273
+ column.modules.filter.value = value;
274
+
274
275
  filterChangeCheck = JSON.stringify(self.headerFilters);
275
276
 
276
277
  if(self.prevHeaderFilterChangeCheck !== filterChangeCheck){
@@ -300,6 +301,8 @@ class Filter extends Module{
300
301
  field = column.getField(),
301
302
  filterElement, editor, editorElement, cellWrapper, typingTimer, searchTrigger, params;
302
303
 
304
+ column.modules.filter.value = initialValue;
305
+
303
306
  //handle aborted edit
304
307
  function cancel(){}
305
308
 
@@ -522,7 +525,7 @@ class Filter extends Module{
522
525
  //programmatically get value of header filter
523
526
  getHeaderFilterValue(column){
524
527
  if(column.modules.filter && column.modules.filter.headerElement){
525
- return column.modules.filter.headerElement.value;
528
+ return column.modules.filter.value;
526
529
  } else {
527
530
  console.warn("Column Filter Error - No header filter set on column:", column.getField());
528
531
  }
@@ -821,7 +824,7 @@ class Filter extends Module{
821
824
  activeRowComponents = [];
822
825
 
823
826
  if(this.subscribedExternal("dataFiltering")){
824
- this.dispatchExternal("dataFiltering", this.getFilters());
827
+ this.dispatchExternal("dataFiltering", this.getFilters(true));
825
828
  }
826
829
 
827
830
  if(this.table.options.filterMode !== "remote" && (this.filterList.length || Object.keys(this.headerFilters).length)){
@@ -842,7 +845,7 @@ class Filter extends Module{
842
845
  activeRowComponents.push(row.getComponent());
843
846
  });
844
847
 
845
- this.dispatchExternal("dataFiltered", this.getFilters(), activeRowComponents);
848
+ this.dispatchExternal("dataFiltered", this.getFilters(true), activeRowComponents);
846
849
  }
847
850
 
848
851
  return activeRows;
@@ -6,7 +6,15 @@ export default function(cell, formatterParams, onRendered){
6
6
  var value = cell.getValue();
7
7
 
8
8
  if(typeof DT != "undefined"){
9
- var newDatetime = inputFormat === "iso" ? DT.fromISO(String(value)) : DT.fromFormat(String(value), inputFormat);
9
+ var newDatetime;
10
+
11
+ if(DT.isDateTime(value)){
12
+ newDatetime = value;
13
+ }else if(inputFormat === "iso"){
14
+ newDatetime = DT.fromISO(String(value));
15
+ }else{
16
+ newDatetime = DT.fromFormat(String(value), inputFormat);
17
+ }
10
18
 
11
19
  if(newDatetime.isValid){
12
20
  if(formatterParams.timezone){
@@ -9,12 +9,19 @@ export default function (cell, formatterParams, onRendered) {
9
9
  var value = cell.getValue();
10
10
 
11
11
  if(typeof DT != "undefined"){
12
-
13
- var newDatetime = inputFormat === "iso" ? DT.fromISO(String(value)) : DT.fromFormat(String(value), inputFormat);
12
+ var newDatetime;
13
+
14
+ if(DT.isDateTime(value)){
15
+ newDatetime = value;
16
+ }else if(inputFormat === "iso"){
17
+ newDatetime = DT.fromISO(String(value));
18
+ }else{
19
+ newDatetime = DT.fromFormat(String(value), inputFormat);
20
+ }
14
21
 
15
22
  if (newDatetime.isValid){
16
23
  if(humanize){
17
- // return moment.duration(newDatetime.diff(date)).humanize(suffix);
24
+ return newDatetime.diff(date, unit).toHuman() + (suffix ? " " + suffix : "");
18
25
  }else{
19
26
  return parseInt(newDatetime.diff(date, unit)[unit]) + (suffix ? " " + suffix : "");
20
27
  }
@@ -6,9 +6,20 @@ export default function(cell, formatterParams, onRendered){
6
6
  el = document.createElement("a"),
7
7
  data;
8
8
 
9
+ function labelTraverse(path, data){
10
+ var item = path.shift(),
11
+ value = data[item];
12
+
13
+ if(path.length && typeof value === "object"){
14
+ return labelTraverse(path, value);
15
+ }
16
+
17
+ return value;
18
+ };
19
+
9
20
  if(formatterParams.labelField){
10
21
  data = cell.getData();
11
- label = data[formatterParams.labelField];
22
+ label = labelTraverse(formatterParams.labelField.split(this.table.options.nestedFieldSeparator), data);
12
23
  }
13
24
 
14
25
  if(formatterParams.label){
@@ -25,10 +25,12 @@ export default function(cell, formatterParams, onRendered){
25
25
  integer = number[0];
26
26
  decimal = number.length > 1 ? decimalSym + number[1] : "";
27
27
 
28
- rgx = /(\d+)(\d{3})/;
28
+ if (formatterParams.thousand !== false) {
29
+ rgx = /(\d+)(\d{3})/;
29
30
 
30
- while (rgx.test(integer)){
31
- integer = integer.replace(rgx, "$1" + thousandSym + "$2");
31
+ while (rgx.test(integer)){
32
+ integer = integer.replace(rgx, "$1" + thousandSym + "$2");
33
+ }
32
34
  }
33
35
 
34
36
  return after ? sign + integer + decimal + symbol : sign + symbol + integer + decimal;
@@ -3,10 +3,11 @@ export default function(cell, formatterParams, onRendered){
3
3
  element = cell.getElement(),
4
4
  empty = formatterParams.allowEmpty,
5
5
  truthy = formatterParams.allowTruthy,
6
+ trueValueSet = Object.keys(formatterParams).includes("trueValue"),
6
7
  tick = typeof formatterParams.tickElement !== "undefined" ? formatterParams.tickElement : '<svg enable-background="new 0 0 24 24" height="14" width="14" viewBox="0 0 24 24" xml:space="preserve" ><path fill="#2DC214" clip-rule="evenodd" d="M21.652,3.211c-0.293-0.295-0.77-0.295-1.061,0L9.41,14.34 c-0.293,0.297-0.771,0.297-1.062,0L3.449,9.351C3.304,9.203,3.114,9.13,2.923,9.129C2.73,9.128,2.534,9.201,2.387,9.351 l-2.165,1.946C0.078,11.445,0,11.63,0,11.823c0,0.194,0.078,0.397,0.223,0.544l4.94,5.184c0.292,0.296,0.771,0.776,1.062,1.07 l2.124,2.141c0.292,0.293,0.769,0.293,1.062,0l14.366-14.34c0.293-0.294,0.293-0.777,0-1.071L21.652,3.211z" fill-rule="evenodd"/></svg>',
7
8
  cross = typeof formatterParams.crossElement !== "undefined" ? formatterParams.crossElement : '<svg enable-background="new 0 0 24 24" height="14" width="14" viewBox="0 0 24 24" xml:space="preserve" ><path fill="#CE1515" d="M22.245,4.015c0.313,0.313,0.313,0.826,0,1.139l-6.276,6.27c-0.313,0.312-0.313,0.826,0,1.14l6.273,6.272 c0.313,0.313,0.313,0.826,0,1.14l-2.285,2.277c-0.314,0.312-0.828,0.312-1.142,0l-6.271-6.271c-0.313-0.313-0.828-0.313-1.141,0 l-6.276,6.267c-0.313,0.313-0.828,0.313-1.141,0l-2.282-2.28c-0.313-0.313-0.313-0.826,0-1.14l6.278-6.269 c0.313-0.312,0.313-0.826,0-1.14L1.709,5.147c-0.314-0.313-0.314-0.827,0-1.14l2.284-2.278C4.308,1.417,4.821,1.417,5.135,1.73 L11.405,8c0.314,0.314,0.828,0.314,1.141,0.001l6.276-6.267c0.312-0.312,0.826-0.312,1.141,0L22.245,4.015z"/></svg>';
8
9
 
9
- if((truthy && value) || (value === true || value === "true" || value === "True" || value === 1 || value === "1")){
10
+ if((trueValueSet && value === formatterParams.trueValue) || (!trueValueSet && ((truthy && value) || (value === true || value === "true" || value === "True" || value === 1 || value === "1")))){
10
11
  element.setAttribute("aria-checked", true);
11
12
  return tick || "";
12
13
  }else{
@@ -39,7 +39,12 @@ class FrozenColumns extends Module{
39
39
  this.subscribe("row-layout-after", this.layoutRow.bind(this));
40
40
  this.subscribe("table-layout", this.layout.bind(this));
41
41
  this.subscribe("scroll-horizontal", this.scrollHorizontal.bind(this));
42
+ this.subscribe("scroll-horizontal", this.scrollHorizontal.bind(this));
42
43
  this.subscribe("columns-loading", this.reset.bind(this));
44
+
45
+ this.subscribe("column-add", this.reinitializeColumns.bind(this));
46
+ this.subscribe("column-delete", this.reinitializeColumns.bind(this));
47
+
43
48
  this.subscribe("table-redraw", this.layout.bind(this));
44
49
  this.subscribe("layout-refreshing", this.blockLayout.bind(this));
45
50
  this.subscribe("layout-refreshed", this.unblockLayout.bind(this));
@@ -56,6 +61,14 @@ class FrozenColumns extends Module{
56
61
  layoutCell(cell){
57
62
  this.layoutElement(cell.element, cell.column)
58
63
  }
64
+
65
+ reinitializeColumns(){
66
+ this.reset();
67
+
68
+ this.table.columnManager.columnsByIndex.forEach((column) => {
69
+ this.initializeColumn(column);
70
+ });
71
+ }
59
72
 
60
73
  //initialize specific column
61
74
  initializeColumn(column){
@@ -83,8 +96,6 @@ class FrozenColumns extends Module{
83
96
  }
84
97
 
85
98
  frozenCheck(column){
86
- var frozen = false;
87
-
88
99
  if(column.parent.isGroup && column.definition.frozen){
89
100
  console.warn("Frozen Column Error - Parent column group must be frozen, not individual columns or sub column groups");
90
101
  }
@@ -94,8 +105,6 @@ class FrozenColumns extends Module{
94
105
  }else{
95
106
  return column.definition.frozen;
96
107
  }
97
-
98
- return frozen;
99
108
  }
100
109
 
101
110
  //quick layout to smooth horizontal scrolling
@@ -246,11 +255,24 @@ class FrozenColumns extends Module{
246
255
 
247
256
  //layout columns appropriately
248
257
  layout(){
258
+ var visibleRows = [],
259
+ otherRows = [];
260
+
249
261
  if(this.active && !this.blocked){
250
262
  //calculate row padding
251
263
  this.calcMargins();
252
-
253
- this.table.rowManager.getDisplayRows().forEach((row) =>{
264
+
265
+ //calculate left columns
266
+ this.layoutColumnPosition();
267
+
268
+ visibleRows = this.table.rowManager.getVisibleRows();
269
+ otherRows = this.table.rowManager.getDisplayRows().filter(row => !visibleRows.includes(row));
270
+
271
+ otherRows.forEach((row) =>{
272
+ row.deinitialize();
273
+ });
274
+
275
+ visibleRows.forEach((row) =>{
254
276
  if(row.type === "row"){
255
277
  this.layoutRow(row);
256
278
  }
@@ -258,12 +280,12 @@ class FrozenColumns extends Module{
258
280
 
259
281
  this.layoutCalcRows();
260
282
 
261
- //calculate left columns
262
- this.layoutColumnPosition(true);
283
+
263
284
  }
264
285
  }
265
286
 
266
287
  layoutRow(row){
288
+ // console.trace("row")
267
289
  var rowEl = row.getElement();
268
290
 
269
291
  rowEl.style.paddingLeft = this.leftMargin;
@@ -16,7 +16,11 @@ class HtmlTableImport extends Module{
16
16
 
17
17
  tableElementCheck(){
18
18
  if(this.table.originalElement && this.table.originalElement.tagName === "TABLE"){
19
- this.parseTable();
19
+ if(this.table.originalElement.childNodes.length){
20
+ this.parseTable();
21
+ }else{
22
+ console.warn("Unable to parse data from empty table tag, Tabulator should be initialized on a div tag unless importing data from a table element.");
23
+ }
20
24
  }
21
25
  }
22
26
 
@@ -1,5 +1,4 @@
1
1
  import Module from '../../core/Module.js';
2
- import Helpers from '../../core/tools/Helpers.js';
3
2
 
4
3
  class Menu extends Module{
5
4
 
@@ -7,69 +6,44 @@ class Menu extends Module{
7
6
  super(table);
8
7
 
9
8
  this.menuContainer = null;
10
- this.menuElements = [];
11
- this.blurEvent = this.hideMenu.bind(this);
12
- this.escEvent = this.escMenu.bind(this);
13
9
  this.nestedMenuBlock = false;
14
- this.positionReversedX = false;
15
10
 
16
11
  this.currentComponent = null;
12
+ this.rootPopup = null;
17
13
 
18
14
  this.columnSubscribers = {};
19
15
 
16
+ this.registerTableOption("menuContainer", undefined); //deprecated
17
+
20
18
  this.registerTableOption("rowContextMenu", false);
21
19
  this.registerTableOption("rowClickMenu", false);
22
20
  this.registerTableOption("groupContextMenu", false);
23
21
  this.registerTableOption("groupClickMenu", false);
24
- this.registerTableOption("menuContainer", false);
25
22
 
26
23
  this.registerColumnOption("headerContextMenu");
27
24
  this.registerColumnOption("headerClickMenu");
28
25
  this.registerColumnOption("headerMenu");
26
+ this.registerColumnOption("headerMenuIcon");
29
27
  this.registerColumnOption("contextMenu");
30
28
  this.registerColumnOption("clickMenu");
29
+
31
30
  }
32
31
 
33
32
  initialize(){
34
- this.lookupMenuContainer();
35
-
33
+ this.deprecationCheck();
36
34
  this.initializeRowWatchers();
37
35
  this.initializeGroupWatchers();
38
36
 
39
37
  this.subscribe("column-init", this.initializeColumn.bind(this));
40
38
  }
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;
63
- }
64
- }
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;
39
+
40
+ deprecationCheck(){
41
+ if(typeof this.table.options.menuContainer !== "undefined"){
42
+ console.warn("Use of the menuContainer option is now deprecated. Please use the popupContainer option instead");
43
+
44
+ this.table.options.popupContainer = this.table.options.menuContainer;
71
45
  }
72
- }
46
+ }
73
47
 
74
48
  initializeRowWatchers(){
75
49
  if(this.table.options.rowContextMenu){
@@ -127,11 +101,25 @@ class Menu extends Module{
127
101
  }
128
102
 
129
103
  initializeColumnHeaderMenu(column){
130
- var headerMenuEl;
104
+ var icon = column.definition.headerMenuIcon,
105
+ headerMenuEl;
131
106
 
132
107
  headerMenuEl = document.createElement("span");
133
- headerMenuEl.classList.add("tabulator-header-menu-button");
134
- headerMenuEl.innerHTML = "&vellip;";
108
+ headerMenuEl.classList.add("tabulator-header-popup-button");
109
+
110
+ if(icon){
111
+ if(typeof icon === "function"){
112
+ icon = icon(column.getComponent());
113
+ }
114
+
115
+ if(icon instanceof HTMLElement){
116
+ headerMenuEl.appendChild(icon);
117
+ }else{
118
+ headerMenuEl.innerHTML = icon;
119
+ }
120
+ }else{
121
+ headerMenuEl.innerHTML = "&vellip;";
122
+ }
135
123
 
136
124
  headerMenuEl.addEventListener("click", (e) => {
137
125
  e.stopPropagation();
@@ -170,15 +158,16 @@ class Menu extends Module{
170
158
  component = component._row;
171
159
  }
172
160
 
173
- menu = typeof menu == "function" ? menu.call(this.table, component.getComponent(), e) : menu;
161
+ menu = typeof menu == "function" ? menu.call(this.table, e, component.getComponent()) : menu;
174
162
 
175
163
  this.loadMenu(e, component, menu);
176
164
  }
177
165
 
178
- loadMenu(e, component, menu, parentEl){
179
- var touch = !(e instanceof MouseEvent);
166
+ loadMenu(e, component, menu, parentEl, parentPopup){
167
+ var touch = !(e instanceof MouseEvent),
168
+ menuEl = document.createElement("div"),
169
+ popup;
180
170
 
181
- var menuEl = document.createElement("div");
182
171
  menuEl.classList.add("tabulator-menu");
183
172
 
184
173
  if(!touch){
@@ -193,7 +182,7 @@ class Menu extends Module{
193
182
  if(!parentEl){
194
183
  if(this.nestedMenuBlock){
195
184
  //abort if child menu already open
196
- if(this.isOpen()){
185
+ if(this.rootPopup){
197
186
  return;
198
187
  }
199
188
  }else{
@@ -202,8 +191,14 @@ class Menu extends Module{
202
191
  }, 100)
203
192
  }
204
193
 
205
- this.hideMenu();
206
- this.menuElements = [];
194
+ if(this.rootPopup){
195
+ this.rootPopup.hide();
196
+ }
197
+
198
+ this.rootPopup = popup = this.popup(menuEl);
199
+
200
+ }else{
201
+ popup = parentPopup.child(menuEl);
207
202
  }
208
203
 
209
204
  menu.forEach((item) => {
@@ -239,8 +234,7 @@ class Menu extends Module{
239
234
  if(item.menu && item.menu.length){
240
235
  itemEl.addEventListener("click", (e) => {
241
236
  e.stopPropagation();
242
- this.hideOldSubMenus(menuEl);
243
- this.loadMenu(e, component, item.menu, itemEl);
237
+ this.loadMenu(e, component, item.menu, itemEl, popup);
244
238
  });
245
239
  }else{
246
240
  if(item.action){
@@ -260,118 +254,24 @@ class Menu extends Module{
260
254
  });
261
255
 
262
256
  menuEl.addEventListener("click", (e) => {
263
- this.hideMenu();
257
+ this.rootPopup.hide();
264
258
  });
265
259
 
266
- this.menuElements.push(menuEl);
267
- this.positionMenu(menuEl, parentEl, touch, e);
268
-
269
- this.currentComponent = component
260
+ popup.show(parentEl || e);
270
261
 
271
- this.dispatchExternal("menuOpened", component.getComponent())
272
- }
273
-
274
- hideOldSubMenus(menuEl){
275
- var index = this.menuElements.indexOf(menuEl);
276
-
277
- if(index > -1){
278
- for(let i = this.menuElements.length - 1; i > index; i--){
279
- var el = this.menuElements[i];
262
+ if(popup === this.rootPopup){
263
+ this.rootPopup.hideOnBlur(() => {
264
+ this.rootPopup = null;
280
265
 
281
- if(el.parentNode){
282
- el.parentNode.removeChild(el);
266
+ if(this.currentComponent){
267
+ this.dispatchExternal("menuClosed", this.currentComponent.getComponent());
268
+ this.currentComponent = null;
283
269
  }
284
-
285
- this.menuElements.pop();
286
- }
287
- }
288
- }
289
-
290
- positionMenu(element, parentEl, touch, e){
291
- var x, y, parentOffset;
292
-
293
- if(!parentEl){
294
- x = touch ? e.touches[0].pageX : e.pageX;
295
- y = touch ? e.touches[0].pageY : e.pageY;
296
-
297
- if(this.menuContainer !== document.body){
298
- parentOffset = Helpers.elOffset(this.menuContainer);
299
-
300
- x -= parentOffset.left;
301
- y -= parentOffset.top;
302
- }
303
-
304
- this.positionReversedX = false;
305
- }else{
306
- parentOffset = Helpers.elOffset(parentEl);
307
- x = parentOffset.left + parentEl.offsetWidth;
308
- y = parentOffset.top - 1;
309
- }
310
-
311
- element.style.top = y + "px";
312
- element.style.left = x + "px";
313
-
314
- setTimeout(() => {
315
- this.table.rowManager.element.addEventListener("scroll", this.blurEvent);
316
- this.subscribe("cell-editing", this.blurEvent);
317
- document.body.addEventListener("click", this.blurEvent);
318
- document.body.addEventListener("contextmenu", this.blurEvent);
319
- window.addEventListener("resize", this.blurEvent);
320
- document.body.addEventListener("keydown", this.escEvent);
321
- }, 100);
322
-
323
- this.menuContainer.appendChild(element);
324
-
325
- //move menu to start on right edge if it is too close to the edge of the screen
326
- if((x + element.offsetWidth) >= this.menuContainer.offsetWidth || this.positionReversedX){
327
- element.style.left = "";
328
-
329
- if(parentEl){
330
- element.style.right = (this.menuContainer.offsetWidth - parentOffset.left) + "px";
331
- }else{
332
- element.style.right = (this.menuContainer.offsetWidth - x) + "px";
333
- }
334
-
335
- this.positionReversedX = true;
336
- }
337
-
338
- //move menu to start on bottom edge if it is too close to the edge of the screen
339
- if((y + element.offsetHeight) > this.menuContainer.offsetHeight) {
340
- if(parentEl){
341
- element.style.top = (parseInt(element.style.top) - element.offsetHeight + parentEl.offsetHeight + 1) + "px";
342
- }else{
343
- element.style.top = (parseInt(element.style.top) - element.offsetHeight) + "px";
344
- }
345
- }
346
- }
347
-
348
- isOpen(){
349
- return !!this.menuElements.length;
350
- }
351
-
352
- escMenu(e){
353
- if(e.keyCode == 27){
354
- this.hideMenu();
355
- }
356
- }
357
-
358
- hideMenu(){
359
- this.menuElements.forEach((menuEl) => {
360
- if(menuEl.parentNode){
361
- menuEl.parentNode.removeChild(menuEl);
362
- }
363
- });
364
-
365
- document.body.removeEventListener("keydown", this.escEvent);
366
- document.body.removeEventListener("click", this.blurEvent);
367
- document.body.removeEventListener("contextmenu", this.blurEvent);
368
- window.removeEventListener("resize", this.blurEvent);
369
- this.table.rowManager.element.removeEventListener("scroll", this.blurEvent);
370
- this.unsubscribe("cell-editing", this.blurEvent);
371
-
372
- if(this.currentComponent){
373
- this.dispatchExternal("menuClosed", this.currentComponent.getComponent());
374
- this.currentComponent = null;
270
+ });
271
+
272
+ this.currentComponent = component;
273
+
274
+ this.dispatchExternal("menuOpened", component.getComponent())
375
275
  }
376
276
  }
377
277
  }
@@ -18,10 +18,12 @@ class Mutator extends Module{
18
18
  this.registerColumnOption("mutatorEditParams");
19
19
  this.registerColumnOption("mutatorClipboard");
20
20
  this.registerColumnOption("mutatorClipboardParams");
21
+ this.registerColumnOption("mutateLink");
21
22
  }
22
23
 
23
24
  initialize(){
24
25
  this.subscribe("cell-value-changing", this.transformCell.bind(this));
26
+ this.subscribe("cell-value-changed", this.mutateLink.bind(this));
25
27
  this.subscribe("column-layout", this.initializeColumn.bind(this));
26
28
  this.subscribe("row-data-init-before", this.rowDataChanged.bind(this));
27
29
  this.subscribe("row-data-changing", this.rowDataChanged.bind(this));
@@ -125,6 +127,24 @@ class Mutator extends Module{
125
127
  return value;
126
128
  }
127
129
 
130
+ mutateLink(cell){
131
+ var links = cell.column.definition.mutateLink;
132
+
133
+ if(links){
134
+ if(!Array.isArray(links)){
135
+ links = [links];
136
+ }
137
+
138
+ links.forEach((link) => {
139
+ var linkCell = cell.row.getCell(link);
140
+
141
+ if(linkCell){
142
+ linkCell.setValue(linkCell.getValue(), true, true);
143
+ }
144
+ });
145
+ }
146
+ }
147
+
128
148
  enable(){
129
149
  this.enabled = true;
130
150
  }
@@ -65,6 +65,7 @@ class Page extends Module{
65
65
  this.subscribe("row-added", this.rowsUpdated.bind(this));
66
66
  this.subscribe("data-processed", this.initialLoadComplete.bind(this));
67
67
  this.subscribe("table-built", this.calculatePageSizes.bind(this));
68
+ this.subscribe("footer-redraw", this.footerRedraw.bind(this));
68
69
 
69
70
  if(this.table.options.paginationAddRow == "page"){
70
71
  this.subscribe("row-adding-position", this.rowAddingPosition.bind(this));
@@ -145,6 +146,8 @@ class Page extends Module{
145
146
 
146
147
  this.table.rowManager.getTableElement().removeChild(testElRow);
147
148
  }
149
+
150
+ this.dispatchExternal("pageSizeChanged", this.size);
148
151
 
149
152
  this.generatePageSizeSelectList();
150
153
  }
@@ -441,12 +444,12 @@ class Page extends Module{
441
444
  }
442
445
  }
443
446
  }else{
444
- this.table.footerManager.append(this.pageCounterElement);
447
+ this.footerAppend(this.pageCounterElement);
445
448
  }
446
449
 
447
450
  }
448
451
 
449
- this.table.footerManager.append(this.element, this);
452
+ this.footerAppend(this.element);
450
453
  }
451
454
 
452
455
  this.page = this.table.options.paginationInitialPage;
@@ -562,9 +565,10 @@ class Page extends Module{
562
565
  if(size !== true){
563
566
  size = parseInt(size);
564
567
  }
565
-
568
+
566
569
  if(size > 0){
567
570
  this.size = size;
571
+ this.dispatchExternal("pageSizeChanged", size);
568
572
  }
569
573
 
570
574
  if(this.pageSizeSelect){
@@ -451,7 +451,7 @@ class Persistence extends Module{
451
451
 
452
452
  Persistence.moduleName = "persistence";
453
453
 
454
- Persistence.moduleInitOrder = 1;
454
+ Persistence.moduleInitOrder = -10;
455
455
 
456
456
  //load defaults
457
457
  Persistence.readers = defaultReaders;