@schukai/monster 4.127.1 → 4.128.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.
- package/CHANGELOG.md +20 -1
- package/package.json +1 -1
- package/source/components/datatable/datatable.mjs +239 -46
- package/source/components/datatable/style/datatable.pcss +5 -0
- package/source/components/datatable/stylesheet/datatable.mjs +1 -1
- package/source/components/form/message-state-button.mjs +23 -3
- package/source/components/layout/popper.mjs +37 -6
- package/source/dom/constants.mjs +6 -0
- package/source/dom/customelement.mjs +15 -0
- package/source/dom/events.mjs +6 -1
- package/source/dom/updater.mjs +475 -14
- package/test/cases/components/datatable/drag-scroll.mjs +258 -0
- package/test/cases/components/form/message-state-button.mjs +85 -0
- package/test/cases/dom/customelement.mjs +78 -8
- package/test/cases/dom/updater.mjs +848 -6
package/source/dom/updater.mjs
CHANGED
|
@@ -24,9 +24,13 @@ import {
|
|
|
24
24
|
ATTRIBUTE_UPDATER_INSERT,
|
|
25
25
|
ATTRIBUTE_UPDATER_INSERT_REFERENCE,
|
|
26
26
|
ATTRIBUTE_UPDATER_PROPERTIES,
|
|
27
|
+
ATTRIBUTE_UPDATER_PATCH,
|
|
28
|
+
ATTRIBUTE_UPDATER_PATCH_KEY,
|
|
29
|
+
ATTRIBUTE_UPDATER_PATCH_RENDER,
|
|
27
30
|
ATTRIBUTE_UPDATER_REMOVE,
|
|
28
31
|
ATTRIBUTE_UPDATER_REPLACE,
|
|
29
32
|
ATTRIBUTE_UPDATER_SELECT_THIS,
|
|
33
|
+
customElementUpdaterLinkSymbol,
|
|
30
34
|
} from "./constants.mjs";
|
|
31
35
|
|
|
32
36
|
import { Base } from "../types/base.mjs";
|
|
@@ -42,7 +46,13 @@ import { ProxyObserver } from "../types/proxyobserver.mjs";
|
|
|
42
46
|
import { validateArray, validateInstance } from "../types/validate.mjs";
|
|
43
47
|
import { clone } from "../util/clone.mjs";
|
|
44
48
|
import { trimSpaces } from "../util/trimspaces.mjs";
|
|
45
|
-
import {
|
|
49
|
+
import {
|
|
50
|
+
addAttributeToken,
|
|
51
|
+
addToObjectLink,
|
|
52
|
+
getLinkedObjects,
|
|
53
|
+
hasObjectLink,
|
|
54
|
+
removeObjectLink,
|
|
55
|
+
} from "./attributes.mjs";
|
|
46
56
|
import {
|
|
47
57
|
CustomElement,
|
|
48
58
|
updaterTransformerMethodsSymbol,
|
|
@@ -75,12 +85,16 @@ const processingSymbol = Symbol("processing");
|
|
|
75
85
|
const processQueueSymbol = Symbol("processQueue");
|
|
76
86
|
const applyChangeSymbol = Symbol("applyChange");
|
|
77
87
|
const updaterRootSymbol = Symbol.for("@schukai/monster/dom/@@updater-root");
|
|
88
|
+
const disposedSymbol = Symbol("disposed");
|
|
89
|
+
const subjectObserverSymbol = Symbol("subjectObserver");
|
|
90
|
+
const patchNodeKeySymbol = Symbol("patchNodeKey");
|
|
78
91
|
|
|
79
92
|
/**
|
|
80
93
|
* The updater class connects an object with the DOM. In this way, structures and contents in the DOM can be
|
|
81
94
|
* programmatically adapted via attributes.
|
|
82
95
|
*
|
|
83
|
-
* For example, to include a string from an object, the attribute `data-monster-replace`
|
|
96
|
+
* For example, to include a string from an object, the attribute `data-monster-replace`
|
|
97
|
+
* or the lifecycle-safe `data-monster-patch` can be used.
|
|
84
98
|
* a further explanation can be found under [monsterjs.org](https://monsterjs.org/)
|
|
85
99
|
*
|
|
86
100
|
* Changes to attributes are made only when the direct values are changed. If you want to assign changes
|
|
@@ -140,19 +154,23 @@ class Updater extends Base {
|
|
|
140
154
|
|
|
141
155
|
this[pendingDiffsSymbol] = [];
|
|
142
156
|
this[processingSymbol] = false;
|
|
157
|
+
this[disposedSymbol] = false;
|
|
143
158
|
|
|
144
|
-
this[
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
return
|
|
154
|
-
}
|
|
155
|
-
|
|
159
|
+
this[subjectObserverSymbol] = new Observer(() => {
|
|
160
|
+
if (this[disposedSymbol] === true) {
|
|
161
|
+
return Promise.resolve();
|
|
162
|
+
}
|
|
163
|
+
|
|
164
|
+
const real = this[internalSymbol].subject.getRealSubject();
|
|
165
|
+
const diffResult = diff(this[internalSymbol].last, real);
|
|
166
|
+
this[internalSymbol].last = clone(real);
|
|
167
|
+
if (diffResult.length === 0) {
|
|
168
|
+
return Promise.resolve();
|
|
169
|
+
}
|
|
170
|
+
this[pendingDiffsSymbol].push(diffResult);
|
|
171
|
+
return this[processQueueSymbol]();
|
|
172
|
+
});
|
|
173
|
+
this[internalSymbol].subject.attachObserver(this[subjectObserverSymbol]);
|
|
156
174
|
}
|
|
157
175
|
|
|
158
176
|
/**
|
|
@@ -160,6 +178,10 @@ class Updater extends Base {
|
|
|
160
178
|
* @return {Promise}
|
|
161
179
|
*/
|
|
162
180
|
async [processQueueSymbol]() {
|
|
181
|
+
if (this[disposedSymbol] === true) {
|
|
182
|
+
return Promise.resolve();
|
|
183
|
+
}
|
|
184
|
+
|
|
163
185
|
if (this[processingSymbol]) {
|
|
164
186
|
return Promise.resolve();
|
|
165
187
|
}
|
|
@@ -167,6 +189,11 @@ class Updater extends Base {
|
|
|
167
189
|
|
|
168
190
|
try {
|
|
169
191
|
while (this[pendingDiffsSymbol].length) {
|
|
192
|
+
if (this[disposedSymbol] === true) {
|
|
193
|
+
this[pendingDiffsSymbol].length = 0;
|
|
194
|
+
return Promise.resolve();
|
|
195
|
+
}
|
|
196
|
+
|
|
170
197
|
const diffResult = this[pendingDiffsSymbol].shift();
|
|
171
198
|
if (this[internalSymbol].features.batchUpdates === true) {
|
|
172
199
|
const updatePaths = new Map();
|
|
@@ -208,6 +235,10 @@ class Updater extends Base {
|
|
|
208
235
|
|
|
209
236
|
/** @private **/
|
|
210
237
|
async [applyChangeSymbol](change) {
|
|
238
|
+
if (this[disposedSymbol] === true) {
|
|
239
|
+
return Promise.resolve();
|
|
240
|
+
}
|
|
241
|
+
|
|
211
242
|
removeElement.call(this, change);
|
|
212
243
|
insertElement.call(this, change);
|
|
213
244
|
updateContent.call(this, change);
|
|
@@ -255,6 +286,10 @@ class Updater extends Base {
|
|
|
255
286
|
* @throws {Error} the bind argument must start as a value with a path
|
|
256
287
|
*/
|
|
257
288
|
enableEventProcessing() {
|
|
289
|
+
if (this[disposedSymbol] === true) {
|
|
290
|
+
return this;
|
|
291
|
+
}
|
|
292
|
+
|
|
258
293
|
this.disableEventProcessing();
|
|
259
294
|
|
|
260
295
|
this[internalSymbol].element[updaterRootSymbol] = true;
|
|
@@ -293,6 +328,28 @@ class Updater extends Base {
|
|
|
293
328
|
return this;
|
|
294
329
|
}
|
|
295
330
|
|
|
331
|
+
dispose() {
|
|
332
|
+
if (this[disposedSymbol] === true) {
|
|
333
|
+
return this;
|
|
334
|
+
}
|
|
335
|
+
|
|
336
|
+
this[disposedSymbol] = true;
|
|
337
|
+
this.disableEventProcessing();
|
|
338
|
+
this[pendingDiffsSymbol].length = 0;
|
|
339
|
+
|
|
340
|
+
if (this[subjectObserverSymbol] instanceof Observer) {
|
|
341
|
+
this[internalSymbol].subject.detachObserver(this[subjectObserverSymbol]);
|
|
342
|
+
}
|
|
343
|
+
|
|
344
|
+
delete this[timerElementEventHandlerSymbol];
|
|
345
|
+
|
|
346
|
+
return this;
|
|
347
|
+
}
|
|
348
|
+
|
|
349
|
+
isDisposed() {
|
|
350
|
+
return this[disposedSymbol] === true;
|
|
351
|
+
}
|
|
352
|
+
|
|
296
353
|
/**
|
|
297
354
|
* The run method must be called for the update to start working.
|
|
298
355
|
* The method ensures that changes are detected.
|
|
@@ -307,6 +364,10 @@ class Updater extends Base {
|
|
|
307
364
|
* @return {Promise}
|
|
308
365
|
*/
|
|
309
366
|
run() {
|
|
367
|
+
if (this[disposedSymbol] === true) {
|
|
368
|
+
return Promise.resolve();
|
|
369
|
+
}
|
|
370
|
+
|
|
310
371
|
// the key __init__has no further meaning and is only
|
|
311
372
|
// used to create the diff for empty objects.
|
|
312
373
|
this[internalSymbol].last = { __init__: true };
|
|
@@ -320,6 +381,10 @@ class Updater extends Base {
|
|
|
320
381
|
* @return {Monster.DOM.Updater}
|
|
321
382
|
*/
|
|
322
383
|
retrieve() {
|
|
384
|
+
if (this[disposedSymbol] === true) {
|
|
385
|
+
return this;
|
|
386
|
+
}
|
|
387
|
+
|
|
323
388
|
retrieveFromBindings.call(this);
|
|
324
389
|
return this;
|
|
325
390
|
}
|
|
@@ -399,6 +464,13 @@ function getControlEventHandler() {
|
|
|
399
464
|
* @param {Event} event
|
|
400
465
|
*/
|
|
401
466
|
this[symbol] = (event) => {
|
|
467
|
+
if (
|
|
468
|
+
this[disposedSymbol] === true ||
|
|
469
|
+
!this[internalSymbol].element?.isConnected
|
|
470
|
+
) {
|
|
471
|
+
return;
|
|
472
|
+
}
|
|
473
|
+
|
|
402
474
|
const root = findClosestUpdaterRootFromEvent(event);
|
|
403
475
|
if (root !== this[internalSymbol].element) {
|
|
404
476
|
return;
|
|
@@ -419,6 +491,14 @@ function getControlEventHandler() {
|
|
|
419
491
|
}
|
|
420
492
|
|
|
421
493
|
this[timerElementEventHandlerSymbol] = new DeadMansSwitch(50, () => {
|
|
494
|
+
if (
|
|
495
|
+
this[disposedSymbol] === true ||
|
|
496
|
+
!this[internalSymbol].element?.isConnected ||
|
|
497
|
+
!element?.isConnected
|
|
498
|
+
) {
|
|
499
|
+
return;
|
|
500
|
+
}
|
|
501
|
+
|
|
422
502
|
try {
|
|
423
503
|
retrieveAndSetValue.call(this, element);
|
|
424
504
|
} catch (e) {
|
|
@@ -662,6 +742,7 @@ function removeElement(change) {
|
|
|
662
742
|
for (const [, element] of this[internalSymbol].element
|
|
663
743
|
.querySelectorAll(`:scope [${ATTRIBUTE_UPDATER_REMOVE}]`)
|
|
664
744
|
.entries()) {
|
|
745
|
+
teardownManagedSubtree(element);
|
|
665
746
|
element.parentNode.removeChild(element);
|
|
666
747
|
}
|
|
667
748
|
}
|
|
@@ -785,6 +866,7 @@ function insertElement(change) {
|
|
|
785
866
|
)
|
|
786
867
|
) {
|
|
787
868
|
try {
|
|
869
|
+
teardownManagedSubtree(node);
|
|
788
870
|
containerElement.removeChild(node);
|
|
789
871
|
} catch (e) {
|
|
790
872
|
addErrorAttribute(containerElement, e);
|
|
@@ -850,6 +932,30 @@ function applyRecursive(node, key, path) {
|
|
|
850
932
|
);
|
|
851
933
|
}
|
|
852
934
|
|
|
935
|
+
if (node.hasAttribute(ATTRIBUTE_UPDATER_PATCH)) {
|
|
936
|
+
const value = node.getAttribute(ATTRIBUTE_UPDATER_PATCH);
|
|
937
|
+
node.setAttribute(
|
|
938
|
+
ATTRIBUTE_UPDATER_PATCH,
|
|
939
|
+
value.replaceAll(`path:${key}`, `path:${path}`),
|
|
940
|
+
);
|
|
941
|
+
}
|
|
942
|
+
|
|
943
|
+
if (node.hasAttribute(ATTRIBUTE_UPDATER_PATCH_KEY)) {
|
|
944
|
+
const value = node.getAttribute(ATTRIBUTE_UPDATER_PATCH_KEY);
|
|
945
|
+
node.setAttribute(
|
|
946
|
+
ATTRIBUTE_UPDATER_PATCH_KEY,
|
|
947
|
+
value.replaceAll(`path:${key}`, `path:${path}`),
|
|
948
|
+
);
|
|
949
|
+
}
|
|
950
|
+
|
|
951
|
+
if (node.hasAttribute(ATTRIBUTE_UPDATER_PATCH_RENDER)) {
|
|
952
|
+
const value = node.getAttribute(ATTRIBUTE_UPDATER_PATCH_RENDER);
|
|
953
|
+
node.setAttribute(
|
|
954
|
+
ATTRIBUTE_UPDATER_PATCH_RENDER,
|
|
955
|
+
value.replaceAll(`path:${key}`, `path:${path}`),
|
|
956
|
+
);
|
|
957
|
+
}
|
|
958
|
+
|
|
853
959
|
if (node.hasAttribute(ATTRIBUTE_UPDATER_ATTRIBUTES)) {
|
|
854
960
|
const value = node.getAttribute(ATTRIBUTE_UPDATER_ATTRIBUTES);
|
|
855
961
|
node.setAttribute(
|
|
@@ -902,12 +1008,14 @@ function updateContent(change) {
|
|
|
902
1008
|
|
|
903
1009
|
const p = clone(change?.["path"]);
|
|
904
1010
|
runUpdateContent.call(this, this[internalSymbol].element, p, subject);
|
|
1011
|
+
runUpdatePatch.call(this, this[internalSymbol].element, p, subject);
|
|
905
1012
|
|
|
906
1013
|
const slots = this[internalSymbol].element.querySelectorAll("slot");
|
|
907
1014
|
if (slots.length > 0) {
|
|
908
1015
|
for (const [, slot] of Object.entries(slots)) {
|
|
909
1016
|
for (const [, element] of Object.entries(slot.assignedNodes())) {
|
|
910
1017
|
runUpdateContent.call(this, element, p, subject);
|
|
1018
|
+
runUpdatePatch.call(this, element, p, subject);
|
|
911
1019
|
}
|
|
912
1020
|
}
|
|
913
1021
|
}
|
|
@@ -967,6 +1075,7 @@ function runUpdateContent(container, parts, subject) {
|
|
|
967
1075
|
}
|
|
968
1076
|
|
|
969
1077
|
if (value instanceof HTMLElement) {
|
|
1078
|
+
teardownChildNodes(element);
|
|
970
1079
|
while (element.firstChild) {
|
|
971
1080
|
element.removeChild(element.firstChild);
|
|
972
1081
|
}
|
|
@@ -977,12 +1086,364 @@ function runUpdateContent(container, parts, subject) {
|
|
|
977
1086
|
addErrorAttribute(element, e);
|
|
978
1087
|
}
|
|
979
1088
|
} else {
|
|
1089
|
+
teardownChildNodes(element);
|
|
980
1090
|
element.innerHTML = value;
|
|
981
1091
|
}
|
|
982
1092
|
}
|
|
983
1093
|
}
|
|
984
1094
|
}
|
|
985
1095
|
|
|
1096
|
+
function runUpdatePatch(container, parts, subject) {
|
|
1097
|
+
if (!isArray(parts)) return;
|
|
1098
|
+
if (!(container instanceof HTMLElement)) return;
|
|
1099
|
+
parts = clone(parts);
|
|
1100
|
+
|
|
1101
|
+
const mem = new WeakSet();
|
|
1102
|
+
|
|
1103
|
+
while (parts.length > 0) {
|
|
1104
|
+
const current = parts.join(".");
|
|
1105
|
+
parts.pop();
|
|
1106
|
+
|
|
1107
|
+
const query = `[${ATTRIBUTE_UPDATER_PATCH}^="path:${current}"], [${ATTRIBUTE_UPDATER_PATCH}^="static:"], [${ATTRIBUTE_UPDATER_PATCH}^="i18n:"]`;
|
|
1108
|
+
const e = container.querySelectorAll(`${query}`);
|
|
1109
|
+
|
|
1110
|
+
const iterator = new Set([...e]);
|
|
1111
|
+
if (container.matches(query)) {
|
|
1112
|
+
iterator.add(container);
|
|
1113
|
+
}
|
|
1114
|
+
|
|
1115
|
+
for (const [element] of iterator.entries()) {
|
|
1116
|
+
if (mem.has(element)) return;
|
|
1117
|
+
mem.add(element);
|
|
1118
|
+
|
|
1119
|
+
const attributes = element.getAttribute(ATTRIBUTE_UPDATER_PATCH);
|
|
1120
|
+
const cmd = trimSpaces(attributes);
|
|
1121
|
+
|
|
1122
|
+
const pipe = new Pipe(cmd);
|
|
1123
|
+
this[internalSymbol].callbacks.forEach((f, n) => {
|
|
1124
|
+
pipe.setCallback(n, f);
|
|
1125
|
+
});
|
|
1126
|
+
|
|
1127
|
+
let value;
|
|
1128
|
+
try {
|
|
1129
|
+
element.removeAttribute(ATTRIBUTE_ERRORMESSAGE);
|
|
1130
|
+
value = pipe.run(subject);
|
|
1131
|
+
} catch (e) {
|
|
1132
|
+
element.setAttribute(ATTRIBUTE_ERRORMESSAGE, e.message);
|
|
1133
|
+
continue;
|
|
1134
|
+
}
|
|
1135
|
+
|
|
1136
|
+
applyPatchValue.call(this, element, value);
|
|
1137
|
+
}
|
|
1138
|
+
}
|
|
1139
|
+
}
|
|
1140
|
+
|
|
1141
|
+
function applyPatchValue(element, value) {
|
|
1142
|
+
if (!(element instanceof HTMLElement)) {
|
|
1143
|
+
return;
|
|
1144
|
+
}
|
|
1145
|
+
|
|
1146
|
+
if (isArray(value)) {
|
|
1147
|
+
const keyDefinition = element.getAttribute(ATTRIBUTE_UPDATER_PATCH_KEY);
|
|
1148
|
+
if (isString(keyDefinition) && trimSpaces(keyDefinition) !== "") {
|
|
1149
|
+
replaceKeyedPatchedChildren.call(
|
|
1150
|
+
this,
|
|
1151
|
+
element,
|
|
1152
|
+
value,
|
|
1153
|
+
keyDefinition,
|
|
1154
|
+
element.getAttribute(ATTRIBUTE_UPDATER_PATCH_RENDER),
|
|
1155
|
+
);
|
|
1156
|
+
return;
|
|
1157
|
+
}
|
|
1158
|
+
|
|
1159
|
+
replacePatchedChildren(element, value);
|
|
1160
|
+
return;
|
|
1161
|
+
}
|
|
1162
|
+
|
|
1163
|
+
if (isInstance(value, DocumentFragment)) {
|
|
1164
|
+
replacePatchedChildren(element, value);
|
|
1165
|
+
return;
|
|
1166
|
+
}
|
|
1167
|
+
|
|
1168
|
+
if (value instanceof HTMLElement) {
|
|
1169
|
+
const existingChildren = Array.from(element.children);
|
|
1170
|
+
if (existingChildren.length === 1 && existingChildren[0] === value) {
|
|
1171
|
+
return;
|
|
1172
|
+
}
|
|
1173
|
+
|
|
1174
|
+
teardownChildNodes(element);
|
|
1175
|
+
while (element.firstChild) {
|
|
1176
|
+
element.removeChild(element.firstChild);
|
|
1177
|
+
}
|
|
1178
|
+
|
|
1179
|
+
try {
|
|
1180
|
+
element.appendChild(value);
|
|
1181
|
+
} catch (e) {
|
|
1182
|
+
addErrorAttribute(element, e);
|
|
1183
|
+
}
|
|
1184
|
+
return;
|
|
1185
|
+
}
|
|
1186
|
+
|
|
1187
|
+
const nextValue = value === null || value === undefined ? "" : String(value);
|
|
1188
|
+
|
|
1189
|
+
if (element.children.length > 0) {
|
|
1190
|
+
teardownChildNodes(element);
|
|
1191
|
+
}
|
|
1192
|
+
|
|
1193
|
+
element.textContent = nextValue;
|
|
1194
|
+
}
|
|
1195
|
+
|
|
1196
|
+
function replaceKeyedPatchedChildren(
|
|
1197
|
+
element,
|
|
1198
|
+
values,
|
|
1199
|
+
keyDefinition,
|
|
1200
|
+
renderDefinition,
|
|
1201
|
+
) {
|
|
1202
|
+
if (!(element instanceof HTMLElement) || !isArray(values)) {
|
|
1203
|
+
return;
|
|
1204
|
+
}
|
|
1205
|
+
|
|
1206
|
+
const keyPipe = new Pipe(trimSpaces(keyDefinition));
|
|
1207
|
+
this[internalSymbol].callbacks.forEach((f, n) => {
|
|
1208
|
+
keyPipe.setCallback(n, f);
|
|
1209
|
+
});
|
|
1210
|
+
const renderPipe = createPatchRenderPipe.call(this, renderDefinition);
|
|
1211
|
+
|
|
1212
|
+
const existing = new Map();
|
|
1213
|
+
for (const node of Array.from(element.childNodes)) {
|
|
1214
|
+
const key = node?.[patchNodeKeySymbol];
|
|
1215
|
+
if (key !== undefined && !existing.has(key)) {
|
|
1216
|
+
existing.set(key, node);
|
|
1217
|
+
}
|
|
1218
|
+
}
|
|
1219
|
+
|
|
1220
|
+
const nextNodes = [];
|
|
1221
|
+
for (const value of values) {
|
|
1222
|
+
let key;
|
|
1223
|
+
try {
|
|
1224
|
+
key = keyPipe.run(value);
|
|
1225
|
+
} catch (e) {
|
|
1226
|
+
addErrorAttribute(element, e);
|
|
1227
|
+
return;
|
|
1228
|
+
}
|
|
1229
|
+
let renderedValue;
|
|
1230
|
+
try {
|
|
1231
|
+
renderedValue = resolvePatchRenderValue(value, renderPipe);
|
|
1232
|
+
} catch (e) {
|
|
1233
|
+
addErrorAttribute(element, e);
|
|
1234
|
+
return;
|
|
1235
|
+
}
|
|
1236
|
+
|
|
1237
|
+
const normalizedKey = key === null || key === undefined ? "" : String(key);
|
|
1238
|
+
if (existing.has(normalizedKey)) {
|
|
1239
|
+
const reused = existing.get(normalizedKey);
|
|
1240
|
+
existing.delete(normalizedKey);
|
|
1241
|
+
const nextNode = preparePatchedNode(reused, renderedValue);
|
|
1242
|
+
nextNode[patchNodeKeySymbol] = normalizedKey;
|
|
1243
|
+
if (nextNode !== reused && reused.parentNode === element) {
|
|
1244
|
+
element.replaceChild(nextNode, reused);
|
|
1245
|
+
}
|
|
1246
|
+
nextNodes.push(nextNode);
|
|
1247
|
+
continue;
|
|
1248
|
+
}
|
|
1249
|
+
|
|
1250
|
+
let created;
|
|
1251
|
+
try {
|
|
1252
|
+
created = createSinglePatchedNode(renderedValue);
|
|
1253
|
+
} catch (e) {
|
|
1254
|
+
addErrorAttribute(element, e);
|
|
1255
|
+
return;
|
|
1256
|
+
}
|
|
1257
|
+
created[patchNodeKeySymbol] = normalizedKey;
|
|
1258
|
+
nextNodes.push(created);
|
|
1259
|
+
}
|
|
1260
|
+
|
|
1261
|
+
for (const node of existing.values()) {
|
|
1262
|
+
if (node instanceof HTMLElement) {
|
|
1263
|
+
teardownManagedSubtree(node);
|
|
1264
|
+
}
|
|
1265
|
+
if (node.parentNode === element) {
|
|
1266
|
+
element.removeChild(node);
|
|
1267
|
+
}
|
|
1268
|
+
}
|
|
1269
|
+
|
|
1270
|
+
for (const node of nextNodes) {
|
|
1271
|
+
if (node.parentNode !== element) {
|
|
1272
|
+
element.appendChild(node);
|
|
1273
|
+
continue;
|
|
1274
|
+
}
|
|
1275
|
+
|
|
1276
|
+
if (element.lastChild !== node) {
|
|
1277
|
+
element.appendChild(node);
|
|
1278
|
+
}
|
|
1279
|
+
}
|
|
1280
|
+
}
|
|
1281
|
+
|
|
1282
|
+
function preparePatchedNode(node, value) {
|
|
1283
|
+
if (node?.nodeType === Node.TEXT_NODE) {
|
|
1284
|
+
if (
|
|
1285
|
+
value === null ||
|
|
1286
|
+
value === undefined ||
|
|
1287
|
+
isString(value) ||
|
|
1288
|
+
typeof value === "number" ||
|
|
1289
|
+
typeof value === "boolean"
|
|
1290
|
+
) {
|
|
1291
|
+
node.textContent =
|
|
1292
|
+
value === null || value === undefined ? "" : String(value);
|
|
1293
|
+
return node;
|
|
1294
|
+
}
|
|
1295
|
+
|
|
1296
|
+
return createSinglePatchedNode(value);
|
|
1297
|
+
}
|
|
1298
|
+
|
|
1299
|
+
if (node instanceof HTMLElement) {
|
|
1300
|
+
if (value === node) {
|
|
1301
|
+
return node;
|
|
1302
|
+
}
|
|
1303
|
+
|
|
1304
|
+
return createSinglePatchedNode(value);
|
|
1305
|
+
}
|
|
1306
|
+
|
|
1307
|
+
return node;
|
|
1308
|
+
}
|
|
1309
|
+
|
|
1310
|
+
function createPatchRenderPipe(renderDefinition) {
|
|
1311
|
+
if (!isString(renderDefinition) || trimSpaces(renderDefinition) === "") {
|
|
1312
|
+
return null;
|
|
1313
|
+
}
|
|
1314
|
+
|
|
1315
|
+
const renderPipe = new Pipe(trimSpaces(renderDefinition));
|
|
1316
|
+
this[internalSymbol].callbacks.forEach((f, n) => {
|
|
1317
|
+
renderPipe.setCallback(n, f);
|
|
1318
|
+
});
|
|
1319
|
+
|
|
1320
|
+
return renderPipe;
|
|
1321
|
+
}
|
|
1322
|
+
|
|
1323
|
+
function resolvePatchRenderValue(value, renderPipe) {
|
|
1324
|
+
if (!(renderPipe instanceof Pipe)) {
|
|
1325
|
+
return value;
|
|
1326
|
+
}
|
|
1327
|
+
|
|
1328
|
+
return renderPipe.run(value);
|
|
1329
|
+
}
|
|
1330
|
+
|
|
1331
|
+
function replacePatchedChildren(element, value) {
|
|
1332
|
+
if (!(element instanceof HTMLElement)) {
|
|
1333
|
+
return;
|
|
1334
|
+
}
|
|
1335
|
+
|
|
1336
|
+
const fragment = document.createDocumentFragment();
|
|
1337
|
+
|
|
1338
|
+
if (isArray(value)) {
|
|
1339
|
+
for (const entry of value) {
|
|
1340
|
+
appendPatchChild(fragment, entry);
|
|
1341
|
+
}
|
|
1342
|
+
} else if (isInstance(value, DocumentFragment)) {
|
|
1343
|
+
fragment.appendChild(value);
|
|
1344
|
+
}
|
|
1345
|
+
|
|
1346
|
+
teardownChildNodes(element);
|
|
1347
|
+
while (element.firstChild) {
|
|
1348
|
+
element.removeChild(element.firstChild);
|
|
1349
|
+
}
|
|
1350
|
+
|
|
1351
|
+
element.appendChild(fragment);
|
|
1352
|
+
}
|
|
1353
|
+
|
|
1354
|
+
function appendPatchChild(fragment, value) {
|
|
1355
|
+
if (!(fragment instanceof DocumentFragment)) {
|
|
1356
|
+
return;
|
|
1357
|
+
}
|
|
1358
|
+
|
|
1359
|
+
if (value === null || value === undefined) {
|
|
1360
|
+
return;
|
|
1361
|
+
}
|
|
1362
|
+
|
|
1363
|
+
if (isArray(value)) {
|
|
1364
|
+
for (const entry of value) {
|
|
1365
|
+
appendPatchChild(fragment, entry);
|
|
1366
|
+
}
|
|
1367
|
+
return;
|
|
1368
|
+
}
|
|
1369
|
+
|
|
1370
|
+
if (isInstance(value, DocumentFragment) || value instanceof HTMLElement) {
|
|
1371
|
+
fragment.appendChild(value);
|
|
1372
|
+
return;
|
|
1373
|
+
}
|
|
1374
|
+
|
|
1375
|
+
fragment.appendChild(document.createTextNode(String(value)));
|
|
1376
|
+
}
|
|
1377
|
+
|
|
1378
|
+
function createPatchedNodes(value) {
|
|
1379
|
+
const fragment = document.createDocumentFragment();
|
|
1380
|
+
appendPatchChild(fragment, value);
|
|
1381
|
+
return Array.from(fragment.childNodes);
|
|
1382
|
+
}
|
|
1383
|
+
|
|
1384
|
+
function createSinglePatchedNode(value) {
|
|
1385
|
+
const nodes = createPatchedNodes(value);
|
|
1386
|
+
if (nodes.length === 0) {
|
|
1387
|
+
return document.createTextNode("");
|
|
1388
|
+
}
|
|
1389
|
+
|
|
1390
|
+
if (nodes.length !== 1) {
|
|
1391
|
+
throw new Error("keyed patch values must resolve to a single node");
|
|
1392
|
+
}
|
|
1393
|
+
|
|
1394
|
+
return nodes[0];
|
|
1395
|
+
}
|
|
1396
|
+
|
|
1397
|
+
function teardownChildNodes(root) {
|
|
1398
|
+
if (!(root instanceof HTMLElement)) {
|
|
1399
|
+
return;
|
|
1400
|
+
}
|
|
1401
|
+
|
|
1402
|
+
for (const child of Array.from(root.children)) {
|
|
1403
|
+
teardownManagedSubtree(child);
|
|
1404
|
+
}
|
|
1405
|
+
}
|
|
1406
|
+
|
|
1407
|
+
function teardownManagedSubtree(root) {
|
|
1408
|
+
if (!(root instanceof HTMLElement)) {
|
|
1409
|
+
return;
|
|
1410
|
+
}
|
|
1411
|
+
|
|
1412
|
+
const elements = [root, ...root.querySelectorAll("*")];
|
|
1413
|
+
for (const element of elements) {
|
|
1414
|
+
if (!hasObjectLinkSafe(element, customElementUpdaterLinkSymbol)) {
|
|
1415
|
+
continue;
|
|
1416
|
+
}
|
|
1417
|
+
|
|
1418
|
+
try {
|
|
1419
|
+
const linked = getLinkedObjects(element, customElementUpdaterLinkSymbol);
|
|
1420
|
+
for (const updaterSet of linked) {
|
|
1421
|
+
if (!(updaterSet instanceof Set)) {
|
|
1422
|
+
continue;
|
|
1423
|
+
}
|
|
1424
|
+
|
|
1425
|
+
for (const updater of updaterSet) {
|
|
1426
|
+
if (typeof updater?.dispose === "function") {
|
|
1427
|
+
updater.dispose();
|
|
1428
|
+
}
|
|
1429
|
+
}
|
|
1430
|
+
}
|
|
1431
|
+
|
|
1432
|
+
removeObjectLink(element, customElementUpdaterLinkSymbol);
|
|
1433
|
+
} catch (e) {
|
|
1434
|
+
addErrorAttribute(element, e);
|
|
1435
|
+
}
|
|
1436
|
+
}
|
|
1437
|
+
}
|
|
1438
|
+
|
|
1439
|
+
function hasObjectLinkSafe(element, symbol) {
|
|
1440
|
+
try {
|
|
1441
|
+
return hasObjectLink(element, symbol);
|
|
1442
|
+
} catch (e) {
|
|
1443
|
+
return false;
|
|
1444
|
+
}
|
|
1445
|
+
}
|
|
1446
|
+
|
|
986
1447
|
/**
|
|
987
1448
|
* @private
|
|
988
1449
|
* @since 1.8.0
|