handsontable 18.0.0-rc4 → 18.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/3rdparty/walkontable/src/renderer/cells.d.ts +0 -6
- package/3rdparty/walkontable/src/renderer/cells.js +2 -7
- package/3rdparty/walkontable/src/renderer/cells.mjs +2 -7
- package/3rdparty/walkontable/src/renderer/colGroup.js +1 -1
- package/3rdparty/walkontable/src/renderer/colGroup.mjs +1 -1
- package/3rdparty/walkontable/src/renderer/columnHeaderRows.js +1 -1
- package/3rdparty/walkontable/src/renderer/columnHeaderRows.mjs +1 -1
- package/3rdparty/walkontable/src/renderer/columnHeaders.d.ts +0 -6
- package/3rdparty/walkontable/src/renderer/columnHeaders.js +2 -7
- package/3rdparty/walkontable/src/renderer/columnHeaders.mjs +2 -7
- package/3rdparty/walkontable/src/renderer/rowHeaders.d.ts +0 -6
- package/3rdparty/walkontable/src/renderer/rowHeaders.js +5 -10
- package/3rdparty/walkontable/src/renderer/rowHeaders.mjs +5 -10
- package/3rdparty/walkontable/src/renderer/rows.js +1 -1
- package/3rdparty/walkontable/src/renderer/rows.mjs +1 -1
- package/3rdparty/walkontable/src/utils/nodesPool.d.ts +10 -10
- package/3rdparty/walkontable/src/utils/nodesPool.js +16 -32
- package/3rdparty/walkontable/src/utils/nodesPool.mjs +11 -31
- package/3rdparty/walkontable/src/utils/orderView/constants.d.ts +0 -36
- package/3rdparty/walkontable/src/utils/orderView/constants.js +0 -24
- package/3rdparty/walkontable/src/utils/orderView/constants.mjs +0 -30
- package/3rdparty/walkontable/src/utils/orderView/view.d.ts +27 -20
- package/3rdparty/walkontable/src/utils/orderView/view.js +79 -16
- package/3rdparty/walkontable/src/utils/orderView/view.mjs +86 -17
- package/3rdparty/walkontable/src/utils/orderView/viewSize.d.ts +2 -14
- package/3rdparty/walkontable/src/utils/orderView/viewSize.js +2 -14
- package/3rdparty/walkontable/src/utils/orderView/viewSize.mjs +2 -14
- package/CHANGELOG.md +4 -1
- package/base.js +2 -2
- package/base.mjs +2 -2
- package/core/types.d.ts +4 -0
- package/core.js +25 -4
- package/core.mjs +25 -4
- package/dataMap/metaManager/index.d.ts +22 -0
- package/dataMap/metaManager/index.js +20 -0
- package/dataMap/metaManager/index.mjs +20 -0
- package/dataMap/metaManager/metaLayers/cellMeta.d.ts +30 -0
- package/dataMap/metaManager/metaLayers/cellMeta.js +110 -0
- package/dataMap/metaManager/metaLayers/cellMeta.mjs +111 -1
- package/dataMap/metaManager/metaSchema.js +9 -0
- package/dataMap/metaManager/metaSchema.mjs +9 -0
- package/dataMap/sourceDataValidator.d.ts +25 -2
- package/dataMap/sourceDataValidator.js +163 -29
- package/dataMap/sourceDataValidator.mjs +178 -30
- package/dist/handsontable.full.js +2182 -2392
- package/dist/handsontable.full.min.js +95 -95
- package/dist/handsontable.js +2182 -2387
- package/dist/handsontable.min.js +95 -95
- package/dist/themes/classic.js +2 -2
- package/dist/themes/classic.min.js +2 -2
- package/dist/themes/horizon.js +2 -2
- package/dist/themes/horizon.min.js +2 -2
- package/dist/themes/main.js +2 -2
- package/dist/themes/main.min.js +2 -2
- package/dist/themes/static/variables/colors/ant.js +2 -2
- package/dist/themes/static/variables/colors/ant.min.js +2 -2
- package/dist/themes/static/variables/colors/classic.js +2 -2
- package/dist/themes/static/variables/colors/classic.min.js +2 -2
- package/dist/themes/static/variables/colors/horizon.js +2 -2
- package/dist/themes/static/variables/colors/horizon.min.js +2 -2
- package/dist/themes/static/variables/colors/main.js +2 -2
- package/dist/themes/static/variables/colors/main.min.js +2 -2
- package/dist/themes/static/variables/colors/material.js +2 -2
- package/dist/themes/static/variables/colors/material.min.js +2 -2
- package/dist/themes/static/variables/colors/shadcn.js +2 -2
- package/dist/themes/static/variables/colors/shadcn.min.js +2 -2
- package/dist/themes/static/variables/density.js +2 -2
- package/dist/themes/static/variables/density.min.js +2 -2
- package/dist/themes/static/variables/helpers/iconsMap.js +2 -2
- package/dist/themes/static/variables/helpers/iconsMap.min.js +2 -2
- package/dist/themes/static/variables/icons/horizon.js +2 -2
- package/dist/themes/static/variables/icons/horizon.min.js +2 -2
- package/dist/themes/static/variables/icons/main.js +2 -2
- package/dist/themes/static/variables/icons/main.min.js +2 -2
- package/dist/themes/static/variables/sizing.js +2 -2
- package/dist/themes/static/variables/sizing.min.js +2 -2
- package/dist/themes/static/variables/tokens/classic.js +2 -2
- package/dist/themes/static/variables/tokens/classic.min.js +2 -2
- package/dist/themes/static/variables/tokens/horizon.js +2 -2
- package/dist/themes/static/variables/tokens/horizon.min.js +2 -2
- package/dist/themes/static/variables/tokens/main.js +2 -2
- package/dist/themes/static/variables/tokens/main.min.js +2 -2
- package/helpers/dom/element.js +13 -6
- package/helpers/dom/element.mjs +13 -6
- package/helpers/mixed.js +2 -2
- package/helpers/mixed.mjs +2 -2
- package/package.json +1 -1
- package/styles/handsontable.css +2 -2
- package/styles/handsontable.min.css +2 -2
- package/styles/handsontableStyles.js +1 -1
- package/styles/handsontableStyles.mjs +1 -1
- package/styles/ht-icons-horizon.min.css +2 -2
- package/styles/ht-icons-main.min.css +2 -2
- package/styles/ht-theme-classic-no-icons.min.css +2 -2
- package/styles/ht-theme-classic.min.css +2 -2
- package/styles/ht-theme-horizon-no-icons.min.css +2 -2
- package/styles/ht-theme-horizon.min.css +2 -2
- package/styles/ht-theme-main-no-icons.min.css +2 -2
- package/styles/ht-theme-main.min.css +2 -2
- package/utils/licenseNotification.js +1 -1
- package/utils/licenseNotification.mjs +1 -1
- package/validators/dateValidator/dateValidator.d.ts +3 -0
- package/validators/dateValidator/dateValidator.js +4 -0
- package/validators/dateValidator/dateValidator.mjs +4 -0
- package/validators/timeValidator/timeValidator.d.ts +3 -0
- package/validators/timeValidator/timeValidator.js +4 -0
- package/validators/timeValidator/timeValidator.mjs +4 -0
- package/3rdparty/walkontable/src/utils/orderView/rendererAdapter/differBasedRendererAdapter.d.mts +0 -1
- package/3rdparty/walkontable/src/utils/orderView/rendererAdapter/differBasedRendererAdapter.d.ts +0 -60
- package/3rdparty/walkontable/src/utils/orderView/rendererAdapter/differBasedRendererAdapter.js +0 -96
- package/3rdparty/walkontable/src/utils/orderView/rendererAdapter/differBasedRendererAdapter.mjs +0 -91
- package/3rdparty/walkontable/src/utils/orderView/rendererAdapter/directDomRendererAdapter.d.mts +0 -1
- package/3rdparty/walkontable/src/utils/orderView/rendererAdapter/directDomRendererAdapter.d.ts +0 -45
- package/3rdparty/walkontable/src/utils/orderView/rendererAdapter/directDomRendererAdapter.js +0 -97
- package/3rdparty/walkontable/src/utils/orderView/rendererAdapter/directDomRendererAdapter.mjs +0 -91
- package/3rdparty/walkontable/src/utils/orderView/rendererAdapter/index.d.mts +0 -1
- package/3rdparty/walkontable/src/utils/orderView/rendererAdapter/index.d.ts +0 -10
- package/3rdparty/walkontable/src/utils/orderView/rendererAdapter/index.js +0 -19
- package/3rdparty/walkontable/src/utils/orderView/rendererAdapter/index.mjs +0 -14
- package/3rdparty/walkontable/src/utils/orderView/viewDiffer/index.d.mts +0 -1
- package/3rdparty/walkontable/src/utils/orderView/viewDiffer/index.d.ts +0 -44
- package/3rdparty/walkontable/src/utils/orderView/viewDiffer/index.js +0 -138
- package/3rdparty/walkontable/src/utils/orderView/viewDiffer/index.mjs +0 -133
- package/3rdparty/walkontable/src/utils/orderView/viewDiffer/viewOrder.d.mts +0 -1
- package/3rdparty/walkontable/src/utils/orderView/viewDiffer/viewOrder.d.ts +0 -57
- package/3rdparty/walkontable/src/utils/orderView/viewDiffer/viewOrder.js +0 -137
- package/3rdparty/walkontable/src/utils/orderView/viewDiffer/viewOrder.mjs +0 -127
|
@@ -1,10 +1,15 @@
|
|
|
1
1
|
import { ViewSizeSet } from './viewSizeSet';
|
|
2
|
-
import { ViewDiffer } from './viewDiffer';
|
|
3
2
|
/**
|
|
4
3
|
* Executive model for each table renderer. It's responsible for injecting DOM nodes in a
|
|
5
4
|
* specified order and adjusting the number of elements in the root node.
|
|
6
5
|
*
|
|
7
|
-
*
|
|
6
|
+
* Rendering writes directly to the DOM: the root node keeps exactly `viewSize` children, and on
|
|
7
|
+
* each render cycle the existing children are reused in place (their content is overwritten by the
|
|
8
|
+
* cell renderer). There is no node pool keyed by source coordinate and no diffing strategy — those
|
|
9
|
+
* were removed because keeping a fixed, viewport-sized set of nodes is simpler and bounds memory to
|
|
10
|
+
* the viewport regardless of dataset size.
|
|
11
|
+
*
|
|
12
|
+
* Only this class has rights to juggle DOM elements within the root node (see render method).
|
|
8
13
|
*
|
|
9
14
|
* @class {OrderView}
|
|
10
15
|
*/
|
|
@@ -20,7 +25,7 @@ export declare class OrderView {
|
|
|
20
25
|
*
|
|
21
26
|
* @type {function(number): HTMLElement}
|
|
22
27
|
*/
|
|
23
|
-
nodesPool: (
|
|
28
|
+
nodesPool: () => HTMLElement;
|
|
24
29
|
/**
|
|
25
30
|
* Holder for sizing and positioning of the view.
|
|
26
31
|
*
|
|
@@ -34,32 +39,26 @@ export declare class OrderView {
|
|
|
34
39
|
*/
|
|
35
40
|
collectedNodes: HTMLElement[];
|
|
36
41
|
/**
|
|
37
|
-
*
|
|
38
|
-
*
|
|
39
|
-
*
|
|
40
|
-
* @type {ViewDiffer}
|
|
41
|
-
*/
|
|
42
|
-
viewDiffer: ViewDiffer;
|
|
43
|
-
/**
|
|
44
|
-
* Node type which the order view will manage while rendering the DOM elements.
|
|
42
|
+
* Node type which the order view will manage while rendering the DOM elements (uppercased to
|
|
43
|
+
* match `Element.tagName`).
|
|
45
44
|
*
|
|
46
45
|
* @type {string}
|
|
47
46
|
*/
|
|
48
47
|
childNodeType: string;
|
|
49
48
|
/**
|
|
50
|
-
* The
|
|
49
|
+
* The visual index of the currently processed child within a render cycle.
|
|
51
50
|
*
|
|
52
|
-
* @type {
|
|
51
|
+
* @type {number}
|
|
53
52
|
*/
|
|
54
|
-
|
|
53
|
+
visualIndex: number;
|
|
55
54
|
/**
|
|
56
55
|
* Creates a new OrderView instance.
|
|
57
56
|
*
|
|
58
57
|
* @param {HTMLElement} rootNode The root node to manage.
|
|
59
|
-
* @param {function(
|
|
58
|
+
* @param {function(): HTMLElement} nodesPool Factory for creating new DOM elements.
|
|
60
59
|
* @param {string} childNodeType The type of child nodes to manage.
|
|
61
60
|
*/
|
|
62
|
-
constructor(rootNode: HTMLElement, nodesPool: (
|
|
61
|
+
constructor(rootNode: HTMLElement, nodesPool: () => HTMLElement, childNodeType: string);
|
|
63
62
|
/**
|
|
64
63
|
* Sets the size for rendered elements. It can be a size for rows, cells or size for row
|
|
65
64
|
* headers etc. It depends for what table renderer this instance was created.
|
|
@@ -98,18 +97,26 @@ export declare class OrderView {
|
|
|
98
97
|
*/
|
|
99
98
|
getCurrentNode(): HTMLElement | null;
|
|
100
99
|
/**
|
|
101
|
-
*
|
|
100
|
+
* Returns the count of children in the root node that belong to this view (for shared root nodes
|
|
101
|
+
* only the children matching this view's node type and working space are counted).
|
|
102
|
+
*
|
|
103
|
+
* @returns {number}
|
|
104
|
+
*/
|
|
105
|
+
getRenderedChildCount(): number;
|
|
106
|
+
/**
|
|
107
|
+
* Setups and prepares all necessary properties and starts the rendering process. It adjusts the
|
|
108
|
+
* number of children in the root node to the next view size, creating or removing nodes as needed.
|
|
102
109
|
* This method has to be called only once (at the start) for the render cycle.
|
|
103
110
|
*/
|
|
104
111
|
start(): void;
|
|
105
112
|
/**
|
|
106
|
-
* Renders the DOM element
|
|
113
|
+
* Renders the DOM element for the current visual index by reusing the child already in place.
|
|
114
|
+
* If a child of the wrong node type occupies the slot, it is replaced with a freshly created one.
|
|
107
115
|
* This method has to be called as many times as the size count is met (to cover all previously rendered DOM elements).
|
|
108
116
|
*/
|
|
109
117
|
render(): void;
|
|
110
118
|
/**
|
|
111
|
-
* Ends the render process.
|
|
112
|
-
* This method has to be called only once (at the end) for the render cycle.
|
|
119
|
+
* Ends the render process. No cleanup is required — all work is done in `start()` and `render()`.
|
|
113
120
|
*/
|
|
114
121
|
end(): void;
|
|
115
122
|
}
|
|
@@ -9,8 +9,7 @@ Object.defineProperty(exports, "OrderView", {
|
|
|
9
9
|
}
|
|
10
10
|
});
|
|
11
11
|
const _viewSizeSet = require("./viewSizeSet");
|
|
12
|
-
const
|
|
13
|
-
const _rendererAdapter = require("./rendererAdapter");
|
|
12
|
+
const _constants = require("./constants");
|
|
14
13
|
class OrderView {
|
|
15
14
|
/**
|
|
16
15
|
* Sets the size for rendered elements. It can be a size for rows, cells or size for row
|
|
@@ -58,28 +57,94 @@ class OrderView {
|
|
|
58
57
|
return length > 0 ? this.collectedNodes[length - 1] : null;
|
|
59
58
|
}
|
|
60
59
|
/**
|
|
61
|
-
*
|
|
60
|
+
* Returns the count of children in the root node that belong to this view (for shared root nodes
|
|
61
|
+
* only the children matching this view's node type and working space are counted).
|
|
62
|
+
*
|
|
63
|
+
* @returns {number}
|
|
64
|
+
*/ getRenderedChildCount() {
|
|
65
|
+
const { rootNode, sizeSet } = this;
|
|
66
|
+
let childElementCount = 0;
|
|
67
|
+
if (this.isSharedViewSet()) {
|
|
68
|
+
let element = rootNode.firstElementChild;
|
|
69
|
+
while(element){
|
|
70
|
+
if (element.tagName === this.childNodeType) {
|
|
71
|
+
childElementCount += 1;
|
|
72
|
+
} else if (sizeSet.isPlaceOn(_constants.WORKING_SPACE_TOP)) {
|
|
73
|
+
break;
|
|
74
|
+
}
|
|
75
|
+
element = element.nextElementSibling;
|
|
76
|
+
}
|
|
77
|
+
} else {
|
|
78
|
+
childElementCount = rootNode.childElementCount;
|
|
79
|
+
}
|
|
80
|
+
return childElementCount;
|
|
81
|
+
}
|
|
82
|
+
/**
|
|
83
|
+
* Setups and prepares all necessary properties and starts the rendering process. It adjusts the
|
|
84
|
+
* number of children in the root node to the next view size, creating or removing nodes as needed.
|
|
62
85
|
* This method has to be called only once (at the start) for the render cycle.
|
|
63
86
|
*/ start() {
|
|
64
|
-
this.
|
|
87
|
+
this.collectedNodes.length = 0;
|
|
88
|
+
this.visualIndex = 0;
|
|
89
|
+
const { rootNode, sizeSet } = this;
|
|
90
|
+
const isShared = this.isSharedViewSet();
|
|
91
|
+
const { nextSize } = sizeSet.getViewSize();
|
|
92
|
+
let childElementCount = this.getRenderedChildCount();
|
|
93
|
+
while(childElementCount < nextSize){
|
|
94
|
+
const newNode = this.nodesPool();
|
|
95
|
+
if (!isShared || sizeSet.isPlaceOn(_constants.WORKING_SPACE_BOTTOM)) {
|
|
96
|
+
rootNode.appendChild(newNode);
|
|
97
|
+
} else {
|
|
98
|
+
rootNode.insertBefore(newNode, rootNode.firstChild);
|
|
99
|
+
}
|
|
100
|
+
childElementCount += 1;
|
|
101
|
+
}
|
|
102
|
+
const isSharedPlacedOnTop = isShared && sizeSet.isPlaceOn(_constants.WORKING_SPACE_TOP);
|
|
103
|
+
while(childElementCount > nextSize){
|
|
104
|
+
const childToRemove = isSharedPlacedOnTop ? rootNode.firstChild : rootNode.lastChild;
|
|
105
|
+
if (childToRemove) {
|
|
106
|
+
rootNode.removeChild(childToRemove);
|
|
107
|
+
}
|
|
108
|
+
childElementCount -= 1;
|
|
109
|
+
}
|
|
65
110
|
}
|
|
66
111
|
/**
|
|
67
|
-
* Renders the DOM element
|
|
112
|
+
* Renders the DOM element for the current visual index by reusing the child already in place.
|
|
113
|
+
* If a child of the wrong node type occupies the slot, it is replaced with a freshly created one.
|
|
68
114
|
* This method has to be called as many times as the size count is met (to cover all previously rendered DOM elements).
|
|
69
115
|
*/ render() {
|
|
70
|
-
this
|
|
116
|
+
const { rootNode, sizeSet } = this;
|
|
117
|
+
let visualIndex = this.visualIndex;
|
|
118
|
+
if (this.isSharedViewSet() && sizeSet.isPlaceOn(_constants.WORKING_SPACE_BOTTOM) && sizeSet.sharedSize) {
|
|
119
|
+
visualIndex += sizeSet.sharedSize.nextSize;
|
|
120
|
+
}
|
|
121
|
+
// Index by element children only (`children`, not `childNodes`) to stay consistent with the
|
|
122
|
+
// element-based counting in `start()` and `getRenderedChildCount()`; a stray text/comment node
|
|
123
|
+
// in the root would otherwise shift the slot.
|
|
124
|
+
let node = rootNode.children[visualIndex];
|
|
125
|
+
if (!node) {
|
|
126
|
+
// Defensive guard: `start()` always provisions enough children for this render cycle, so the
|
|
127
|
+
// slot should exist. Recreate it rather than dereferencing `undefined` if that ever breaks.
|
|
128
|
+
node = this.nodesPool();
|
|
129
|
+
rootNode.appendChild(node);
|
|
130
|
+
} else if (node.tagName !== this.childNodeType) {
|
|
131
|
+
const newNode = this.nodesPool();
|
|
132
|
+
node.replaceWith(newNode);
|
|
133
|
+
node = newNode;
|
|
134
|
+
}
|
|
135
|
+
this.collectedNodes.push(node);
|
|
136
|
+
this.visualIndex += 1;
|
|
71
137
|
}
|
|
72
138
|
/**
|
|
73
|
-
* Ends the render process.
|
|
74
|
-
* This method has to be called only once (at the end) for the render cycle.
|
|
139
|
+
* Ends the render process. No cleanup is required — all work is done in `start()` and `render()`.
|
|
75
140
|
*/ end() {
|
|
76
|
-
|
|
141
|
+
// intentionally empty
|
|
77
142
|
}
|
|
78
143
|
/**
|
|
79
144
|
* Creates a new OrderView instance.
|
|
80
145
|
*
|
|
81
146
|
* @param {HTMLElement} rootNode The root node to manage.
|
|
82
|
-
* @param {function(
|
|
147
|
+
* @param {function(): HTMLElement} nodesPool Factory for creating new DOM elements.
|
|
83
148
|
* @param {string} childNodeType The type of child nodes to manage.
|
|
84
149
|
*/ constructor(rootNode, nodesPool, childNodeType){
|
|
85
150
|
/**
|
|
@@ -93,14 +158,12 @@ class OrderView {
|
|
|
93
158
|
* @type {HTMLElement[]}
|
|
94
159
|
*/ this.collectedNodes = [];
|
|
95
160
|
/**
|
|
96
|
-
* The
|
|
97
|
-
* commands that are processed by the OrderView (see `applyCommand` method).
|
|
161
|
+
* The visual index of the currently processed child within a render cycle.
|
|
98
162
|
*
|
|
99
|
-
* @type {
|
|
100
|
-
*/ this.
|
|
163
|
+
* @type {number}
|
|
164
|
+
*/ this.visualIndex = 0;
|
|
101
165
|
this.rootNode = rootNode;
|
|
102
166
|
this.nodesPool = nodesPool;
|
|
103
|
-
this.childNodeType = childNodeType;
|
|
104
|
-
this.rendererAdapter = (0, _rendererAdapter.createRendererAdapter)(this);
|
|
167
|
+
this.childNodeType = typeof childNodeType === 'string' ? childNodeType.toUpperCase() : childNodeType;
|
|
105
168
|
}
|
|
106
169
|
}
|
|
@@ -1,11 +1,16 @@
|
|
|
1
1
|
import { ViewSizeSet } from './viewSizeSet.mjs';
|
|
2
|
-
import {
|
|
3
|
-
import { createRendererAdapter } from './rendererAdapter/index.mjs';
|
|
2
|
+
import { WORKING_SPACE_TOP, WORKING_SPACE_BOTTOM } from './constants.mjs';
|
|
4
3
|
/**
|
|
5
4
|
* Executive model for each table renderer. It's responsible for injecting DOM nodes in a
|
|
6
5
|
* specified order and adjusting the number of elements in the root node.
|
|
7
6
|
*
|
|
8
|
-
*
|
|
7
|
+
* Rendering writes directly to the DOM: the root node keeps exactly `viewSize` children, and on
|
|
8
|
+
* each render cycle the existing children are reused in place (their content is overwritten by the
|
|
9
|
+
* cell renderer). There is no node pool keyed by source coordinate and no diffing strategy — those
|
|
10
|
+
* were removed because keeping a fixed, viewport-sized set of nodes is simpler and bounds memory to
|
|
11
|
+
* the viewport regardless of dataset size.
|
|
12
|
+
*
|
|
13
|
+
* Only this class has rights to juggle DOM elements within the root node (see render method).
|
|
9
14
|
*
|
|
10
15
|
* @class {OrderView}
|
|
11
16
|
*/ export class OrderView {
|
|
@@ -55,28 +60,94 @@ import { createRendererAdapter } from './rendererAdapter/index.mjs';
|
|
|
55
60
|
return length > 0 ? this.collectedNodes[length - 1] : null;
|
|
56
61
|
}
|
|
57
62
|
/**
|
|
58
|
-
*
|
|
63
|
+
* Returns the count of children in the root node that belong to this view (for shared root nodes
|
|
64
|
+
* only the children matching this view's node type and working space are counted).
|
|
65
|
+
*
|
|
66
|
+
* @returns {number}
|
|
67
|
+
*/ getRenderedChildCount() {
|
|
68
|
+
const { rootNode, sizeSet } = this;
|
|
69
|
+
let childElementCount = 0;
|
|
70
|
+
if (this.isSharedViewSet()) {
|
|
71
|
+
let element = rootNode.firstElementChild;
|
|
72
|
+
while(element){
|
|
73
|
+
if (element.tagName === this.childNodeType) {
|
|
74
|
+
childElementCount += 1;
|
|
75
|
+
} else if (sizeSet.isPlaceOn(WORKING_SPACE_TOP)) {
|
|
76
|
+
break;
|
|
77
|
+
}
|
|
78
|
+
element = element.nextElementSibling;
|
|
79
|
+
}
|
|
80
|
+
} else {
|
|
81
|
+
childElementCount = rootNode.childElementCount;
|
|
82
|
+
}
|
|
83
|
+
return childElementCount;
|
|
84
|
+
}
|
|
85
|
+
/**
|
|
86
|
+
* Setups and prepares all necessary properties and starts the rendering process. It adjusts the
|
|
87
|
+
* number of children in the root node to the next view size, creating or removing nodes as needed.
|
|
59
88
|
* This method has to be called only once (at the start) for the render cycle.
|
|
60
89
|
*/ start() {
|
|
61
|
-
this.
|
|
90
|
+
this.collectedNodes.length = 0;
|
|
91
|
+
this.visualIndex = 0;
|
|
92
|
+
const { rootNode, sizeSet } = this;
|
|
93
|
+
const isShared = this.isSharedViewSet();
|
|
94
|
+
const { nextSize } = sizeSet.getViewSize();
|
|
95
|
+
let childElementCount = this.getRenderedChildCount();
|
|
96
|
+
while(childElementCount < nextSize){
|
|
97
|
+
const newNode = this.nodesPool();
|
|
98
|
+
if (!isShared || sizeSet.isPlaceOn(WORKING_SPACE_BOTTOM)) {
|
|
99
|
+
rootNode.appendChild(newNode);
|
|
100
|
+
} else {
|
|
101
|
+
rootNode.insertBefore(newNode, rootNode.firstChild);
|
|
102
|
+
}
|
|
103
|
+
childElementCount += 1;
|
|
104
|
+
}
|
|
105
|
+
const isSharedPlacedOnTop = isShared && sizeSet.isPlaceOn(WORKING_SPACE_TOP);
|
|
106
|
+
while(childElementCount > nextSize){
|
|
107
|
+
const childToRemove = isSharedPlacedOnTop ? rootNode.firstChild : rootNode.lastChild;
|
|
108
|
+
if (childToRemove) {
|
|
109
|
+
rootNode.removeChild(childToRemove);
|
|
110
|
+
}
|
|
111
|
+
childElementCount -= 1;
|
|
112
|
+
}
|
|
62
113
|
}
|
|
63
114
|
/**
|
|
64
|
-
* Renders the DOM element
|
|
115
|
+
* Renders the DOM element for the current visual index by reusing the child already in place.
|
|
116
|
+
* If a child of the wrong node type occupies the slot, it is replaced with a freshly created one.
|
|
65
117
|
* This method has to be called as many times as the size count is met (to cover all previously rendered DOM elements).
|
|
66
118
|
*/ render() {
|
|
67
|
-
this
|
|
119
|
+
const { rootNode, sizeSet } = this;
|
|
120
|
+
let visualIndex = this.visualIndex;
|
|
121
|
+
if (this.isSharedViewSet() && sizeSet.isPlaceOn(WORKING_SPACE_BOTTOM) && sizeSet.sharedSize) {
|
|
122
|
+
visualIndex += sizeSet.sharedSize.nextSize;
|
|
123
|
+
}
|
|
124
|
+
// Index by element children only (`children`, not `childNodes`) to stay consistent with the
|
|
125
|
+
// element-based counting in `start()` and `getRenderedChildCount()`; a stray text/comment node
|
|
126
|
+
// in the root would otherwise shift the slot.
|
|
127
|
+
let node = rootNode.children[visualIndex];
|
|
128
|
+
if (!node) {
|
|
129
|
+
// Defensive guard: `start()` always provisions enough children for this render cycle, so the
|
|
130
|
+
// slot should exist. Recreate it rather than dereferencing `undefined` if that ever breaks.
|
|
131
|
+
node = this.nodesPool();
|
|
132
|
+
rootNode.appendChild(node);
|
|
133
|
+
} else if (node.tagName !== this.childNodeType) {
|
|
134
|
+
const newNode = this.nodesPool();
|
|
135
|
+
node.replaceWith(newNode);
|
|
136
|
+
node = newNode;
|
|
137
|
+
}
|
|
138
|
+
this.collectedNodes.push(node);
|
|
139
|
+
this.visualIndex += 1;
|
|
68
140
|
}
|
|
69
141
|
/**
|
|
70
|
-
* Ends the render process.
|
|
71
|
-
* This method has to be called only once (at the end) for the render cycle.
|
|
142
|
+
* Ends the render process. No cleanup is required — all work is done in `start()` and `render()`.
|
|
72
143
|
*/ end() {
|
|
73
|
-
|
|
144
|
+
// intentionally empty
|
|
74
145
|
}
|
|
75
146
|
/**
|
|
76
147
|
* Creates a new OrderView instance.
|
|
77
148
|
*
|
|
78
149
|
* @param {HTMLElement} rootNode The root node to manage.
|
|
79
|
-
* @param {function(
|
|
150
|
+
* @param {function(): HTMLElement} nodesPool Factory for creating new DOM elements.
|
|
80
151
|
* @param {string} childNodeType The type of child nodes to manage.
|
|
81
152
|
*/ constructor(rootNode, nodesPool, childNodeType){
|
|
82
153
|
/**
|
|
@@ -90,14 +161,12 @@ import { createRendererAdapter } from './rendererAdapter/index.mjs';
|
|
|
90
161
|
* @type {HTMLElement[]}
|
|
91
162
|
*/ this.collectedNodes = [];
|
|
92
163
|
/**
|
|
93
|
-
* The
|
|
94
|
-
* commands that are processed by the OrderView (see `applyCommand` method).
|
|
164
|
+
* The visual index of the currently processed child within a render cycle.
|
|
95
165
|
*
|
|
96
|
-
* @type {
|
|
97
|
-
*/ this.
|
|
166
|
+
* @type {number}
|
|
167
|
+
*/ this.visualIndex = 0;
|
|
98
168
|
this.rootNode = rootNode;
|
|
99
169
|
this.nodesPool = nodesPool;
|
|
100
|
-
this.childNodeType = childNodeType;
|
|
101
|
-
this.rendererAdapter = createRendererAdapter(this);
|
|
170
|
+
this.childNodeType = typeof childNodeType === 'string' ? childNodeType.toUpperCase() : childNodeType;
|
|
102
171
|
}
|
|
103
172
|
}
|
|
@@ -5,25 +5,13 @@
|
|
|
5
5
|
*/
|
|
6
6
|
export declare class ViewSize {
|
|
7
7
|
/**
|
|
8
|
-
*
|
|
9
|
-
*
|
|
10
|
-
* @type {number}
|
|
11
|
-
*/
|
|
12
|
-
currentSize: number;
|
|
13
|
-
/**
|
|
14
|
-
* Next size of the rendered DOM elements which should be fulfilled.
|
|
8
|
+
* Size of the rendered DOM elements which should be fulfilled.
|
|
15
9
|
*
|
|
16
10
|
* @type {number}
|
|
17
11
|
*/
|
|
18
12
|
nextSize: number;
|
|
19
13
|
/**
|
|
20
|
-
*
|
|
21
|
-
*
|
|
22
|
-
* @type {number}
|
|
23
|
-
*/
|
|
24
|
-
currentOffset: number;
|
|
25
|
-
/**
|
|
26
|
-
* Next offset.
|
|
14
|
+
* Offset of the first rendered element according to the scroll position.
|
|
27
15
|
*
|
|
28
16
|
* @type {number}
|
|
29
17
|
*/
|
|
@@ -18,7 +18,6 @@ class ViewSize {
|
|
|
18
18
|
*
|
|
19
19
|
* @param {number} size The size.
|
|
20
20
|
*/ setSize(size) {
|
|
21
|
-
this.currentSize = this.nextSize;
|
|
22
21
|
this.nextSize = size;
|
|
23
22
|
}
|
|
24
23
|
/**
|
|
@@ -26,27 +25,16 @@ class ViewSize {
|
|
|
26
25
|
*
|
|
27
26
|
* @param {number} offset The offset.
|
|
28
27
|
*/ setOffset(offset) {
|
|
29
|
-
this.currentOffset = this.nextOffset;
|
|
30
28
|
this.nextOffset = offset;
|
|
31
29
|
}
|
|
32
30
|
constructor(){
|
|
33
31
|
/**
|
|
34
|
-
*
|
|
35
|
-
*
|
|
36
|
-
* @type {number}
|
|
37
|
-
*/ this.currentSize = 0;
|
|
38
|
-
/**
|
|
39
|
-
* Next size of the rendered DOM elements which should be fulfilled.
|
|
32
|
+
* Size of the rendered DOM elements which should be fulfilled.
|
|
40
33
|
*
|
|
41
34
|
* @type {number}
|
|
42
35
|
*/ this.nextSize = 0;
|
|
43
36
|
/**
|
|
44
|
-
*
|
|
45
|
-
*
|
|
46
|
-
* @type {number}
|
|
47
|
-
*/ this.currentOffset = 0;
|
|
48
|
-
/**
|
|
49
|
-
* Next offset.
|
|
37
|
+
* Offset of the first rendered element according to the scroll position.
|
|
50
38
|
*
|
|
51
39
|
* @type {number}
|
|
52
40
|
*/ this.nextOffset = 0;
|
|
@@ -8,7 +8,6 @@
|
|
|
8
8
|
*
|
|
9
9
|
* @param {number} size The size.
|
|
10
10
|
*/ setSize(size) {
|
|
11
|
-
this.currentSize = this.nextSize;
|
|
12
11
|
this.nextSize = size;
|
|
13
12
|
}
|
|
14
13
|
/**
|
|
@@ -16,27 +15,16 @@
|
|
|
16
15
|
*
|
|
17
16
|
* @param {number} offset The offset.
|
|
18
17
|
*/ setOffset(offset) {
|
|
19
|
-
this.currentOffset = this.nextOffset;
|
|
20
18
|
this.nextOffset = offset;
|
|
21
19
|
}
|
|
22
20
|
constructor(){
|
|
23
21
|
/**
|
|
24
|
-
*
|
|
25
|
-
*
|
|
26
|
-
* @type {number}
|
|
27
|
-
*/ this.currentSize = 0;
|
|
28
|
-
/**
|
|
29
|
-
* Next size of the rendered DOM elements which should be fulfilled.
|
|
22
|
+
* Size of the rendered DOM elements which should be fulfilled.
|
|
30
23
|
*
|
|
31
24
|
* @type {number}
|
|
32
25
|
*/ this.nextSize = 0;
|
|
33
26
|
/**
|
|
34
|
-
*
|
|
35
|
-
*
|
|
36
|
-
* @type {number}
|
|
37
|
-
*/ this.currentOffset = 0;
|
|
38
|
-
/**
|
|
39
|
-
* Next offset.
|
|
27
|
+
* Offset of the first rendered element according to the scroll position.
|
|
40
28
|
*
|
|
41
29
|
* @type {number}
|
|
42
30
|
*/ this.nextOffset = 0;
|
package/CHANGELOG.md
CHANGED
|
@@ -9,7 +9,7 @@ adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
|
|
9
9
|
|
|
10
10
|
<!-- UNVERSIONED -->
|
|
11
11
|
|
|
12
|
-
## [18.0.0
|
|
12
|
+
## [18.0.0] - 2026-06-30
|
|
13
13
|
|
|
14
14
|
### Added
|
|
15
15
|
- **Breaking change**: Added wrapper layout slots and a `layout` option to control the order of UI elements rendered around the grid (pagination, dialog). The license notification always renders last in the bottom area and is not orderable. Built-in UI now mounts into dedicated wrapper containers, which changes the root DOM structure. [#12094](https://github.com/handsontable/handsontable/issues/12094)
|
|
@@ -32,6 +32,7 @@ adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
|
|
32
32
|
- Changed the Notification plugin to render its toasts in the grid's overlay layer. [#12777](https://github.com/handsontable/handsontable/issues/12777)
|
|
33
33
|
- Angular: Modernized the Angular wrapper to align with Angular 17–19, simplify setup, reduce dependencies, and clean up tooling. [#12451](https://github.com/handsontable/handsontable/issues/12451)
|
|
34
34
|
- Angular: Added support for installing Angular 16 through 22, without the --force flag [#12752](https://github.com/handsontable/handsontable/issues/12752)
|
|
35
|
+
- Reduced memory usage and improved initialization time for large datasets by no longer materializing cell metadata for every cell during source data validation. [#12847](https://github.com/handsontable/handsontable/pull/12847)
|
|
35
36
|
|
|
36
37
|
### Removed
|
|
37
38
|
- **Breaking change**: Removed the numbro, moment.js, DOMPurify, and @handsontable/pikaday dependencies. [#12689](https://github.com/handsontable/handsontable/issues/12689)
|
|
@@ -120,6 +121,8 @@ adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
|
|
120
121
|
- React: Fixed React component renderers being unmounted and visibly cleared on every grid render after a cell edit. [#12494](https://github.com/handsontable/handsontable/issues/12494)
|
|
121
122
|
- React: Fixed an issue where `HotColumn` children removed from a `HotTable` left phantom columns behind in the React wrapper. [#12596](https://github.com/handsontable/handsontable/issues/12596)
|
|
122
123
|
- Angular: Fixed subscription leak, missing EmbeddedViewRef cleanup, repeated registerRenderer calls, wrong constructor.name, incorrect prop type, missing null guard in ngOnDestroy, premature editor destruction, redundant double-destroy of already-swept renderer refs, and stale editor reuse when a different column takes an index. [#12657](https://github.com/handsontable/handsontable/issues/12657)
|
|
124
|
+
- Fixed cell meta set with `setCellMeta` (for example, `readOnly`) being reset by `updateSettings`. [#12811](https://github.com/handsontable/handsontable/issues/12811)
|
|
125
|
+
- Reduced memory usage during scrolling and fixed potential out-of-memory errors on very large datasets. [#12844](https://github.com/handsontable/handsontable/pull/12844)
|
|
123
126
|
|
|
124
127
|
## [17.1.0] - 2026-05-19
|
|
125
128
|
|
package/base.js
CHANGED
|
@@ -72,8 +72,8 @@ Handsontable.hooks = _hooks.Hooks.getSingleton();
|
|
|
72
72
|
Handsontable.CellCoords = _src.CellCoords;
|
|
73
73
|
Handsontable.CellRange = _src.CellRange;
|
|
74
74
|
Handsontable.packageName = 'handsontable';
|
|
75
|
-
Handsontable.buildDate = "
|
|
76
|
-
Handsontable.version = "18.0.0
|
|
75
|
+
Handsontable.buildDate = "30/06/2026 08:45:33";
|
|
76
|
+
Handsontable.version = "18.0.0";
|
|
77
77
|
Handsontable.languages = {
|
|
78
78
|
dictionaryKeys: _registry.dictionaryKeys,
|
|
79
79
|
getLanguageDictionary: _registry.getLanguageDictionary,
|
package/base.mjs
CHANGED
|
@@ -43,8 +43,8 @@ Handsontable.hooks = Hooks.getSingleton();
|
|
|
43
43
|
Handsontable.CellCoords = CellCoords;
|
|
44
44
|
Handsontable.CellRange = CellRange;
|
|
45
45
|
Handsontable.packageName = 'handsontable';
|
|
46
|
-
Handsontable.buildDate = "
|
|
47
|
-
Handsontable.version = "18.0.0
|
|
46
|
+
Handsontable.buildDate = "30/06/2026 08:45:33";
|
|
47
|
+
Handsontable.version = "18.0.0";
|
|
48
48
|
Handsontable.languages = {
|
|
49
49
|
dictionaryKeys,
|
|
50
50
|
getLanguageDictionary,
|
package/core/types.d.ts
CHANGED
|
@@ -16,6 +16,8 @@ import type { FocusGridManager as FocusManagerInstance } from '../focusManager/g
|
|
|
16
16
|
import type { FocusScopeManager as FocusScopeManagerInstance } from '../focusManager/scopeManager';
|
|
17
17
|
import type { LayoutManager } from './layout';
|
|
18
18
|
import type { default as EditorManagerInstance } from '../editorManager';
|
|
19
|
+
import type { default as DataSourceInstance } from '../dataMap/dataSource';
|
|
20
|
+
import type { default as MetaManagerInstance } from '../dataMap/metaManager';
|
|
19
21
|
import type { BaseEditor as BaseEditorInstance } from '../editors/baseEditor/baseEditor';
|
|
20
22
|
import type { StylesHandler } from '../utils/stylesHandler';
|
|
21
23
|
import type { ThemeManager } from '../themes/engine/manager';
|
|
@@ -194,6 +196,8 @@ export interface HotInstance {
|
|
|
194
196
|
getFocusScopeManager(): FocusScopeManagerInstance;
|
|
195
197
|
getLayoutManager(): LayoutManager;
|
|
196
198
|
_getEditorManager(): EditorManagerInstance;
|
|
199
|
+
_getDataSource(): DataSourceInstance;
|
|
200
|
+
_getMetaManager(): MetaManagerInstance;
|
|
197
201
|
rootElement: HTMLElement;
|
|
198
202
|
rootDocument: Document;
|
|
199
203
|
rootWindow: Window & typeof globalThis;
|
package/core.js
CHANGED
|
@@ -2428,6 +2428,10 @@ function Core(rootContainer, userSettings, rootInstanceSymbol = false) {
|
|
|
2428
2428
|
* Since 12.0.0 passing `data` inside `settings` objects no longer results in resetting states corresponding to rows and columns
|
|
2429
2429
|
* (for example, row/column sequence, column width, row height, frozen columns etc.).
|
|
2430
2430
|
*
|
|
2431
|
+
* Cell meta set imperatively through [[setCellMeta]] (for example, by the user or the context menu) is preserved across
|
|
2432
|
+
* `updateSettings`, even when `settings` includes `cell`, `cells`, or `columns`. On a direct conflict, a value re-stated
|
|
2433
|
+
* through the declarative `cell` option takes precedence over the preserved imperative value.
|
|
2434
|
+
*
|
|
2431
2435
|
* When [[Hooks#hasExternalDataSource]] is true, Handsontable clears and rebinds the placeholder dataset only during
|
|
2432
2436
|
* initialization or when `settings` includes `data` or `dataProvider`. Other keys alone (for example `height`) do not clear loaded rows.
|
|
2433
2437
|
* If only `columns` changes, the column map is rebuilt without clearing rows.
|
|
@@ -2566,9 +2570,17 @@ function Core(rootContainer, userSettings, rootInstanceSymbol = false) {
|
|
|
2566
2570
|
}
|
|
2567
2571
|
const clen = instance.countCols();
|
|
2568
2572
|
const columnSetting = tableMeta.columns;
|
|
2569
|
-
// Clear cell meta cache
|
|
2573
|
+
// Clear cell meta cache. Cell meta set imperatively through `setCellMeta` (for example, by the
|
|
2574
|
+
// user or the context menu) is snapshotted beforehand and replayed afterward, so that it
|
|
2575
|
+
// survives the clear instead of being discarded (see GitHub issue #4446).
|
|
2570
2576
|
if (settings.cell !== undefined || settings.cells !== undefined || settings.columns !== undefined) {
|
|
2577
|
+
const userDefinedCellMetas = metaManager.getUserDefinedCellMetas();
|
|
2571
2578
|
metaManager.clearCache();
|
|
2579
|
+
// Replay before the column and `cell` option re-application, so that a value re-stated through
|
|
2580
|
+
// the declarative `cell` option still wins on a direct conflict (preserving legacy behavior).
|
|
2581
|
+
userDefinedCellMetas.forEach(({ physicalRow, physicalColumn, key, value })=>{
|
|
2582
|
+
metaManager.setCellMeta(physicalRow, physicalColumn, key, value);
|
|
2583
|
+
});
|
|
2572
2584
|
}
|
|
2573
2585
|
if (clen > 0) {
|
|
2574
2586
|
for(i = 0, j = 0; i < clen; i++){
|
|
@@ -2583,9 +2595,18 @@ function Core(rootContainer, userSettings, rootInstanceSymbol = false) {
|
|
|
2583
2595
|
}
|
|
2584
2596
|
}
|
|
2585
2597
|
if ((0, _mixed.isDefined)(settings.cell)) {
|
|
2586
|
-
settings
|
|
2587
|
-
|
|
2588
|
-
})
|
|
2598
|
+
// The `cell` option is declarative - it is re-applied from settings on every `updateSettings`
|
|
2599
|
+
// call. Recording is disabled so these writes are not tracked as user-defined (and a key
|
|
2600
|
+
// re-stated here de-marks any imperative value), keeping `updateSettings({ cell: [] })` able
|
|
2601
|
+
// to remove previously declared entries.
|
|
2602
|
+
metaManager.disableUserDefinedMetaRecording();
|
|
2603
|
+
try {
|
|
2604
|
+
settings.cell.forEach((cell)=>{
|
|
2605
|
+
instance.setCellMetaObject(cell.row, cell.col, cell);
|
|
2606
|
+
});
|
|
2607
|
+
} finally{
|
|
2608
|
+
metaManager.enableUserDefinedMetaRecording();
|
|
2609
|
+
}
|
|
2589
2610
|
}
|
|
2590
2611
|
instance.runHooks('afterCellMetaReset');
|
|
2591
2612
|
// for the first run, we need to run the source data warnings after cell meta initialization
|
package/core.mjs
CHANGED
|
@@ -2413,6 +2413,10 @@ let activeGuid = null;
|
|
|
2413
2413
|
* Since 12.0.0 passing `data` inside `settings` objects no longer results in resetting states corresponding to rows and columns
|
|
2414
2414
|
* (for example, row/column sequence, column width, row height, frozen columns etc.).
|
|
2415
2415
|
*
|
|
2416
|
+
* Cell meta set imperatively through [[setCellMeta]] (for example, by the user or the context menu) is preserved across
|
|
2417
|
+
* `updateSettings`, even when `settings` includes `cell`, `cells`, or `columns`. On a direct conflict, a value re-stated
|
|
2418
|
+
* through the declarative `cell` option takes precedence over the preserved imperative value.
|
|
2419
|
+
*
|
|
2416
2420
|
* When [[Hooks#hasExternalDataSource]] is true, Handsontable clears and rebinds the placeholder dataset only during
|
|
2417
2421
|
* initialization or when `settings` includes `data` or `dataProvider`. Other keys alone (for example `height`) do not clear loaded rows.
|
|
2418
2422
|
* If only `columns` changes, the column map is rebuilt without clearing rows.
|
|
@@ -2551,9 +2555,17 @@ let activeGuid = null;
|
|
|
2551
2555
|
}
|
|
2552
2556
|
const clen = instance.countCols();
|
|
2553
2557
|
const columnSetting = tableMeta.columns;
|
|
2554
|
-
// Clear cell meta cache
|
|
2558
|
+
// Clear cell meta cache. Cell meta set imperatively through `setCellMeta` (for example, by the
|
|
2559
|
+
// user or the context menu) is snapshotted beforehand and replayed afterward, so that it
|
|
2560
|
+
// survives the clear instead of being discarded (see GitHub issue #4446).
|
|
2555
2561
|
if (settings.cell !== undefined || settings.cells !== undefined || settings.columns !== undefined) {
|
|
2562
|
+
const userDefinedCellMetas = metaManager.getUserDefinedCellMetas();
|
|
2556
2563
|
metaManager.clearCache();
|
|
2564
|
+
// Replay before the column and `cell` option re-application, so that a value re-stated through
|
|
2565
|
+
// the declarative `cell` option still wins on a direct conflict (preserving legacy behavior).
|
|
2566
|
+
userDefinedCellMetas.forEach(({ physicalRow, physicalColumn, key, value })=>{
|
|
2567
|
+
metaManager.setCellMeta(physicalRow, physicalColumn, key, value);
|
|
2568
|
+
});
|
|
2557
2569
|
}
|
|
2558
2570
|
if (clen > 0) {
|
|
2559
2571
|
for(i = 0, j = 0; i < clen; i++){
|
|
@@ -2568,9 +2580,18 @@ let activeGuid = null;
|
|
|
2568
2580
|
}
|
|
2569
2581
|
}
|
|
2570
2582
|
if (isDefined(settings.cell)) {
|
|
2571
|
-
settings
|
|
2572
|
-
|
|
2573
|
-
})
|
|
2583
|
+
// The `cell` option is declarative - it is re-applied from settings on every `updateSettings`
|
|
2584
|
+
// call. Recording is disabled so these writes are not tracked as user-defined (and a key
|
|
2585
|
+
// re-stated here de-marks any imperative value), keeping `updateSettings({ cell: [] })` able
|
|
2586
|
+
// to remove previously declared entries.
|
|
2587
|
+
metaManager.disableUserDefinedMetaRecording();
|
|
2588
|
+
try {
|
|
2589
|
+
settings.cell.forEach((cell)=>{
|
|
2590
|
+
instance.setCellMetaObject(cell.row, cell.col, cell);
|
|
2591
|
+
});
|
|
2592
|
+
} finally{
|
|
2593
|
+
metaManager.enableUserDefinedMetaRecording();
|
|
2594
|
+
}
|
|
2574
2595
|
}
|
|
2575
2596
|
instance.runHooks('afterCellMetaReset');
|
|
2576
2597
|
// for the first run, we need to run the source data warnings after cell meta initialization
|