@schukai/monster 3.102.2 → 3.102.4

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.
@@ -12,36 +12,36 @@
12
12
  * SPDX-License-Identifier: AGPL-3.0
13
13
  */
14
14
 
15
- import {internalSymbol} from "../constants.mjs";
16
- import {diff} from "../data/diff.mjs";
17
- import {Pathfinder} from "../data/pathfinder.mjs";
18
- import {Pipe} from "../data/pipe.mjs";
15
+ import { internalSymbol } from "../constants.mjs";
16
+ import { diff } from "../data/diff.mjs";
17
+ import { Pathfinder } from "../data/pathfinder.mjs";
18
+ import { Pipe } from "../data/pipe.mjs";
19
19
  import {
20
- ATTRIBUTE_ERRORMESSAGE,
21
- ATTRIBUTE_UPDATER_ATTRIBUTES,
22
- ATTRIBUTE_UPDATER_BIND,
23
- ATTRIBUTE_UPDATER_BIND_TYPE,
24
- ATTRIBUTE_UPDATER_INSERT,
25
- ATTRIBUTE_UPDATER_INSERT_REFERENCE,
26
- ATTRIBUTE_UPDATER_REMOVE,
27
- ATTRIBUTE_UPDATER_REPLACE,
28
- ATTRIBUTE_UPDATER_SELECT_THIS,
20
+ ATTRIBUTE_ERRORMESSAGE,
21
+ ATTRIBUTE_UPDATER_ATTRIBUTES,
22
+ ATTRIBUTE_UPDATER_BIND,
23
+ ATTRIBUTE_UPDATER_BIND_TYPE,
24
+ ATTRIBUTE_UPDATER_INSERT,
25
+ ATTRIBUTE_UPDATER_INSERT_REFERENCE,
26
+ ATTRIBUTE_UPDATER_REMOVE,
27
+ ATTRIBUTE_UPDATER_REPLACE,
28
+ ATTRIBUTE_UPDATER_SELECT_THIS,
29
29
  } from "./constants.mjs";
30
30
 
31
- import {Base} from "../types/base.mjs";
32
- import {isArray, isString, isInstance, isIterable} from "../types/is.mjs";
33
- import {Observer} from "../types/observer.mjs";
34
- import {ProxyObserver} from "../types/proxyobserver.mjs";
35
- import {validateArray, validateInstance} from "../types/validate.mjs";
36
- import {clone} from "../util/clone.mjs";
37
- import {trimSpaces} from "../util/trimspaces.mjs";
38
- import {addAttributeToken, addToObjectLink} from "./attributes.mjs";
39
- import {updaterTransformerMethodsSymbol} from "./customelement.mjs";
40
- import {findTargetElementFromEvent} from "./events.mjs";
41
- import {findDocumentTemplate} from "./template.mjs";
42
- import {getWindow} from "./util.mjs";
43
-
44
- export {Updater, addObjectWithUpdaterToElement};
31
+ import { Base } from "../types/base.mjs";
32
+ import { isArray, isString, isInstance, isIterable } from "../types/is.mjs";
33
+ import { Observer } from "../types/observer.mjs";
34
+ import { ProxyObserver } from "../types/proxyobserver.mjs";
35
+ import { validateArray, validateInstance } from "../types/validate.mjs";
36
+ import { clone } from "../util/clone.mjs";
37
+ import { trimSpaces } from "../util/trimspaces.mjs";
38
+ import { addAttributeToken, addToObjectLink } from "./attributes.mjs";
39
+ import { updaterTransformerMethodsSymbol } from "./customelement.mjs";
40
+ import { findTargetElementFromEvent } from "./events.mjs";
41
+ import { findDocumentTemplate } from "./template.mjs";
42
+ import { getWindow } from "./util.mjs";
43
+
44
+ export { Updater, addObjectWithUpdaterToElement };
45
45
 
46
46
  /**
47
47
  * The updater class connects an object with the DOM. In this way, structures and contents in the DOM can be
@@ -68,190 +68,190 @@ export {Updater, addObjectWithUpdaterToElement};
68
68
  * @summary The updater class connects an object with the dom
69
69
  */
70
70
  class Updater extends Base {
71
- /**
72
- * @since 1.8.0
73
- * @param {HTMLElement} element
74
- * @param {object|ProxyObserver|undefined} subject
75
- * @throws {TypeError} value is not a object
76
- * @throws {TypeError} value is not an instance of HTMLElement
77
- * @see {@link findDocumentTemplate}
78
- */
79
- constructor(element, subject) {
80
- super();
81
-
82
- /**
83
- * @type {HTMLElement}
84
- */
85
- if (subject === undefined) subject = {};
86
- if (!isInstance(subject, ProxyObserver)) {
87
- subject = new ProxyObserver(subject);
88
- }
89
-
90
- this[internalSymbol] = {
91
- element: validateInstance(element, HTMLElement),
92
- last: {},
93
- callbacks: new Map(),
94
- eventTypes: ["keyup", "click", "change", "drop", "touchend", "input"],
95
- subject: subject,
96
- };
97
-
98
- this[internalSymbol].callbacks.set(
99
- "checkstate",
100
- getCheckStateCallback.call(this),
101
- );
102
-
103
- this[internalSymbol].subject.attachObserver(
104
- new Observer(() => {
105
- const s = this[internalSymbol].subject.getRealSubject();
106
-
107
- const diffResult = diff(this[internalSymbol].last, s);
108
- this[internalSymbol].last = clone(s);
109
-
110
- const promises = [];
111
-
112
- for (const [, change] of Object.entries(diffResult)) {
113
- promises.push(
114
- new Promise((resolve, reject) => {
115
- getWindow().requestAnimationFrame(() => {
116
- try {
117
- removeElement.call(this, change);
118
- insertElement.call(this, change);
119
- updateContent.call(this, change);
120
- updateAttributes.call(this, change);
121
-
122
- resolve();
123
- } catch (error) {
124
- reject(error);
125
- }
126
- });
127
- }),
128
- );
129
- }
130
-
131
- return Promise.all(promises);
132
- }),
133
- );
134
- }
135
-
136
- /**
137
- * Defaults: 'keyup', 'click', 'change', 'drop', 'touchend'
138
- *
139
- * @see {@link https://developer.mozilla.org/de/docs/Web/Events}
140
- * @since 1.9.0
141
- * @param {Array} types
142
- * @return {Updater}
143
- */
144
- setEventTypes(types) {
145
- this[internalSymbol].eventTypes = validateArray(types);
146
- return this;
147
- }
148
-
149
- /**
150
- * With this method, the eventlisteners are hooked in and the magic begins.
151
- *
152
- * ```js
153
- * updater.run().then(() => {
154
- * updater.enableEventProcessing();
155
- * });
156
- * ```
157
- *
158
- * @since 1.9.0
159
- * @return {Updater}
160
- * @throws {Error} the bind argument must start as a value with a path
161
- */
162
- enableEventProcessing() {
163
- this.disableEventProcessing();
164
-
165
- for (const type of this[internalSymbol].eventTypes) {
166
- // @see https://developer.mozilla.org/en-US/docs/Web/API/EventTarget/addEventListener
167
- this[internalSymbol].element.addEventListener(
168
- type,
169
- getControlEventHandler.call(this),
170
- {
171
- capture: true,
172
- passive: true,
173
- },
174
- );
175
- }
176
-
177
- return this;
178
- }
179
-
180
- /**
181
- * This method turns off the magic or who loves it more profane it removes the eventListener.
182
- *
183
- * @since 1.9.0
184
- * @return {Updater}
185
- */
186
- disableEventProcessing() {
187
- for (const type of this[internalSymbol].eventTypes) {
188
- this[internalSymbol].element.removeEventListener(
189
- type,
190
- getControlEventHandler.call(this),
191
- );
192
- }
193
-
194
- return this;
195
- }
196
-
197
- /**
198
- * The run method must be called for the update to start working.
199
- * The method ensures that changes are detected.
200
- *
201
- * ```js
202
- * updater.run().then(() => {
203
- * updater.enableEventProcessing();
204
- * });
205
- * ```
206
- *
207
- * @summary Let the magic begin
208
- * @return {Promise}
209
- */
210
- run() {
211
- // the key __init__has no further meaning and is only
212
- // used to create the diff for empty objects.
213
- this[internalSymbol].last = {__init__: true};
214
- return this[internalSymbol].subject.notifyObservers();
215
- }
216
-
217
- /**
218
- * Gets the values of bound elements and changes them in subject
219
- *
220
- * @since 1.27.0
221
- * @return {Monster.DOM.Updater}
222
- */
223
- retrieve() {
224
- retrieveFromBindings.call(this);
225
- return this;
226
- }
227
-
228
- /**
229
- * If you have passed a ProxyObserver in the constructor, you will get the object that the ProxyObserver manages here.
230
- * However, if you passed a simple object, here you will get a proxy for that object.
231
- *
232
- * For changes, the ProxyObserver must be used.
233
- *
234
- * @since 1.8.0
235
- * @return {Proxy}
236
- */
237
- getSubject() {
238
- return this[internalSymbol].subject.getSubject();
239
- }
240
-
241
- /**
242
- * This method can be used to register commands that can be called via call: instruction.
243
- * This can be used to provide a pipe with its own functionality.
244
- *
245
- * @param {string} name
246
- * @param {function} callback
247
- * @return {Transformer}
248
- * @throws {TypeError} value is not a string
249
- * @throws {TypeError} value is not a function
250
- */
251
- setCallback(name, callback) {
252
- this[internalSymbol].callbacks.set(name, callback);
253
- return this;
254
- }
71
+ /**
72
+ * @since 1.8.0
73
+ * @param {HTMLElement} element
74
+ * @param {object|ProxyObserver|undefined} subject
75
+ * @throws {TypeError} value is not a object
76
+ * @throws {TypeError} value is not an instance of HTMLElement
77
+ * @see {@link findDocumentTemplate}
78
+ */
79
+ constructor(element, subject) {
80
+ super();
81
+
82
+ /**
83
+ * @type {HTMLElement}
84
+ */
85
+ if (subject === undefined) subject = {};
86
+ if (!isInstance(subject, ProxyObserver)) {
87
+ subject = new ProxyObserver(subject);
88
+ }
89
+
90
+ this[internalSymbol] = {
91
+ element: validateInstance(element, HTMLElement),
92
+ last: {},
93
+ callbacks: new Map(),
94
+ eventTypes: ["keyup", "click", "change", "drop", "touchend", "input"],
95
+ subject: subject,
96
+ };
97
+
98
+ this[internalSymbol].callbacks.set(
99
+ "checkstate",
100
+ getCheckStateCallback.call(this),
101
+ );
102
+
103
+ this[internalSymbol].subject.attachObserver(
104
+ new Observer(() => {
105
+ const s = this[internalSymbol].subject.getRealSubject();
106
+
107
+ const diffResult = diff(this[internalSymbol].last, s);
108
+ this[internalSymbol].last = clone(s);
109
+
110
+ const promises = [];
111
+
112
+ for (const [, change] of Object.entries(diffResult)) {
113
+ promises.push(
114
+ new Promise((resolve, reject) => {
115
+ getWindow().requestAnimationFrame(() => {
116
+ try {
117
+ removeElement.call(this, change);
118
+ insertElement.call(this, change);
119
+ updateContent.call(this, change);
120
+ updateAttributes.call(this, change);
121
+
122
+ resolve();
123
+ } catch (error) {
124
+ reject(error);
125
+ }
126
+ });
127
+ }),
128
+ );
129
+ }
130
+
131
+ return Promise.all(promises);
132
+ }),
133
+ );
134
+ }
135
+
136
+ /**
137
+ * Defaults: 'keyup', 'click', 'change', 'drop', 'touchend'
138
+ *
139
+ * @see {@link https://developer.mozilla.org/de/docs/Web/Events}
140
+ * @since 1.9.0
141
+ * @param {Array} types
142
+ * @return {Updater}
143
+ */
144
+ setEventTypes(types) {
145
+ this[internalSymbol].eventTypes = validateArray(types);
146
+ return this;
147
+ }
148
+
149
+ /**
150
+ * With this method, the eventlisteners are hooked in and the magic begins.
151
+ *
152
+ * ```js
153
+ * updater.run().then(() => {
154
+ * updater.enableEventProcessing();
155
+ * });
156
+ * ```
157
+ *
158
+ * @since 1.9.0
159
+ * @return {Updater}
160
+ * @throws {Error} the bind argument must start as a value with a path
161
+ */
162
+ enableEventProcessing() {
163
+ this.disableEventProcessing();
164
+
165
+ for (const type of this[internalSymbol].eventTypes) {
166
+ // @see https://developer.mozilla.org/en-US/docs/Web/API/EventTarget/addEventListener
167
+ this[internalSymbol].element.addEventListener(
168
+ type,
169
+ getControlEventHandler.call(this),
170
+ {
171
+ capture: true,
172
+ passive: true,
173
+ },
174
+ );
175
+ }
176
+
177
+ return this;
178
+ }
179
+
180
+ /**
181
+ * This method turns off the magic or who loves it more profane it removes the eventListener.
182
+ *
183
+ * @since 1.9.0
184
+ * @return {Updater}
185
+ */
186
+ disableEventProcessing() {
187
+ for (const type of this[internalSymbol].eventTypes) {
188
+ this[internalSymbol].element.removeEventListener(
189
+ type,
190
+ getControlEventHandler.call(this),
191
+ );
192
+ }
193
+
194
+ return this;
195
+ }
196
+
197
+ /**
198
+ * The run method must be called for the update to start working.
199
+ * The method ensures that changes are detected.
200
+ *
201
+ * ```js
202
+ * updater.run().then(() => {
203
+ * updater.enableEventProcessing();
204
+ * });
205
+ * ```
206
+ *
207
+ * @summary Let the magic begin
208
+ * @return {Promise}
209
+ */
210
+ run() {
211
+ // the key __init__has no further meaning and is only
212
+ // used to create the diff for empty objects.
213
+ this[internalSymbol].last = { __init__: true };
214
+ return this[internalSymbol].subject.notifyObservers();
215
+ }
216
+
217
+ /**
218
+ * Gets the values of bound elements and changes them in subject
219
+ *
220
+ * @since 1.27.0
221
+ * @return {Monster.DOM.Updater}
222
+ */
223
+ retrieve() {
224
+ retrieveFromBindings.call(this);
225
+ return this;
226
+ }
227
+
228
+ /**
229
+ * If you have passed a ProxyObserver in the constructor, you will get the object that the ProxyObserver manages here.
230
+ * However, if you passed a simple object, here you will get a proxy for that object.
231
+ *
232
+ * For changes, the ProxyObserver must be used.
233
+ *
234
+ * @since 1.8.0
235
+ * @return {Proxy}
236
+ */
237
+ getSubject() {
238
+ return this[internalSymbol].subject.getSubject();
239
+ }
240
+
241
+ /**
242
+ * This method can be used to register commands that can be called via call: instruction.
243
+ * This can be used to provide a pipe with its own functionality.
244
+ *
245
+ * @param {string} name
246
+ * @param {function} callback
247
+ * @return {Transformer}
248
+ * @throws {TypeError} value is not a string
249
+ * @throws {TypeError} value is not a function
250
+ */
251
+ setCallback(name, callback) {
252
+ this[internalSymbol].callbacks.set(name, callback);
253
+ return this;
254
+ }
255
255
  }
256
256
 
257
257
  /**
@@ -262,20 +262,20 @@ class Updater extends Base {
262
262
  * @this Updater
263
263
  */
264
264
  function getCheckStateCallback() {
265
- return function (current) {
266
- // this is a reference to the current object (therefore no array function here)
267
- if (this instanceof HTMLInputElement) {
268
- if (["radio", "checkbox"].indexOf(this.type) !== -1) {
269
- return `${this.value}` === `${current}` ? "true" : undefined;
270
- }
271
- } else if (this instanceof HTMLOptionElement) {
272
- if (isArray(current) && current.indexOf(this.value) !== -1) {
273
- return "true";
274
- }
275
-
276
- return undefined;
277
- }
278
- };
265
+ return function (current) {
266
+ // this is a reference to the current object (therefore no array function here)
267
+ if (this instanceof HTMLInputElement) {
268
+ if (["radio", "checkbox"].indexOf(this.type) !== -1) {
269
+ return `${this.value}` === `${current}` ? "true" : undefined;
270
+ }
271
+ } else if (this instanceof HTMLOptionElement) {
272
+ if (isArray(current) && current.indexOf(this.value) !== -1) {
273
+ return "true";
274
+ }
275
+
276
+ return undefined;
277
+ }
278
+ };
279
279
  }
280
280
 
281
281
  /**
@@ -290,32 +290,32 @@ const symbol = Symbol("@schukai/monster/updater@@EventHandler");
290
290
  * @throws {Error} the bind argument must start as a value with a path
291
291
  */
292
292
  function getControlEventHandler() {
293
- if (this[symbol]) {
294
- return this[symbol];
295
- }
296
-
297
- /**
298
- * @throws {Error} the bind argument must start as a value with a path.
299
- * @throws {Error} unsupported object
300
- * @param {Event} event
301
- */
302
- this[symbol] = (event) => {
303
- const element = findTargetElementFromEvent(event, ATTRIBUTE_UPDATER_BIND);
304
-
305
- if (element === undefined) {
306
- return;
307
- }
308
-
309
- queueMicrotask(() => {
310
- try {
311
- retrieveAndSetValue.call(this, element);
312
- } catch (e) {
313
- addAttributeToken(element, ATTRIBUTE_ERRORMESSAGE, e.message || `${e}`);
314
- }
315
- });
316
- };
317
-
318
- return this[symbol];
293
+ if (this[symbol]) {
294
+ return this[symbol];
295
+ }
296
+
297
+ /**
298
+ * @throws {Error} the bind argument must start as a value with a path.
299
+ * @throws {Error} unsupported object
300
+ * @param {Event} event
301
+ */
302
+ this[symbol] = (event) => {
303
+ const element = findTargetElementFromEvent(event, ATTRIBUTE_UPDATER_BIND);
304
+
305
+ if (element === undefined) {
306
+ return;
307
+ }
308
+
309
+ queueMicrotask(() => {
310
+ try {
311
+ retrieveAndSetValue.call(this, element);
312
+ } catch (e) {
313
+ addAttributeToken(element, ATTRIBUTE_ERRORMESSAGE, e.message || `${e}`);
314
+ }
315
+ });
316
+ };
317
+
318
+ return this[symbol];
319
319
  }
320
320
 
321
321
  /**
@@ -325,129 +325,128 @@ function getControlEventHandler() {
325
325
  * @private
326
326
  */
327
327
  function retrieveAndSetValue(element) {
328
- const pathfinder = new Pathfinder(this[internalSymbol].subject.getSubject());
329
-
330
- let path = element.getAttribute(ATTRIBUTE_UPDATER_BIND);
331
- if (path === null)
332
- throw new Error("the bind argument must start as a value with a path");
333
-
334
- if (path.indexOf("path:") !== 0) {
335
- throw new Error("the bind argument must start as a value with a path");
336
- }
337
-
338
- path = path.substring(5); // remove path: from the string
339
-
340
- let value;
341
-
342
- if (element instanceof HTMLInputElement) {
343
- switch (element.type) {
344
- case "checkbox":
345
- value = element.checked ? element.value : undefined;
346
- break;
347
- default:
348
- value = element.value;
349
- break;
350
- }
351
- } else if (element instanceof HTMLTextAreaElement) {
352
- value = element.value;
353
- } else if (element instanceof HTMLSelectElement) {
354
- switch (element.type) {
355
- case "select-one":
356
- value = element.value;
357
- break;
358
- case "select-multiple":
359
- value = element.value;
360
-
361
- let options = element?.selectedOptions;
362
- if (options === undefined)
363
- options = element.querySelectorAll(":scope option:checked");
364
- value = Array.from(options).map(({value}) => value);
365
-
366
- break;
367
- }
368
-
369
- // values from custom elements
370
- } else if (
371
- (element?.constructor?.prototype &&
372
- !!Object.getOwnPropertyDescriptor(
373
- element.constructor.prototype,
374
- "value",
375
- )?.["get"]) ||
376
- element.hasOwnProperty("value")
377
- ) {
378
- value = element?.["value"];
379
- } else {
380
- throw new Error("unsupported object");
381
- }
382
-
383
- if (isString(value)) {
384
- const type = element.getAttribute(ATTRIBUTE_UPDATER_BIND_TYPE);
385
- switch (type) {
386
- case "number":
387
- case "int":
388
- case "float":
389
- case "integer":
390
- value = Number(value);
391
- if (isNaN(value)) {
392
- value = 0;
393
- }
394
- break;
395
- case "boolean":
396
- case "bool":
397
- case "checkbox":
398
- value = value === "true" || value === "1" || value === "on";
399
- break;
400
-
401
- case "string[]":
402
- if (value === "") {
403
- value = [];
404
- }
405
-
406
- value = value.split(",").map((v) => `${v}`);
407
- break;
408
-
409
- case "int[]":
410
- case "integer[]":
411
-
412
- if (value === "") {
413
- value = [];
414
- } else {
415
-
416
- value = value.split(",").map((v) => {
417
- try {
418
- return parseInt(v, 10);
419
- } catch (e) {
420
-
421
- }
422
- return -1;
423
- }).filter((v) => v !== -1);
424
- }
425
-
426
- break
427
- case "[]":
428
- case "array":
429
- case "list":
430
- value = value.split(",");
431
- break;
432
- case "object":
433
- case "json":
434
- value = JSON.parse(value);
435
- break;
436
- default:
437
- break;
438
- }
439
- }
440
-
441
- const copy = clone(this[internalSymbol].subject.getRealSubject());
442
-
443
- const pf = new Pathfinder(copy);
444
- pf.setVia(path, value);
445
-
446
- const diffResult = diff(copy, this[internalSymbol].subject.getRealSubject());
447
-
448
- if (diffResult.length > 0) {
449
- pathfinder.setVia(path, value);
450
- }
328
+ const pathfinder = new Pathfinder(this[internalSymbol].subject.getSubject());
329
+
330
+ let path = element.getAttribute(ATTRIBUTE_UPDATER_BIND);
331
+ if (path === null)
332
+ throw new Error("the bind argument must start as a value with a path");
333
+
334
+ if (path.indexOf("path:") !== 0) {
335
+ throw new Error("the bind argument must start as a value with a path");
336
+ }
337
+
338
+ path = path.substring(5); // remove path: from the string
339
+
340
+ let value;
341
+
342
+ if (element instanceof HTMLInputElement) {
343
+ switch (element.type) {
344
+ case "checkbox":
345
+ value = element.checked ? element.value : undefined;
346
+ break;
347
+ default:
348
+ value = element.value;
349
+ break;
350
+ }
351
+ } else if (element instanceof HTMLTextAreaElement) {
352
+ value = element.value;
353
+ } else if (element instanceof HTMLSelectElement) {
354
+ switch (element.type) {
355
+ case "select-one":
356
+ value = element.value;
357
+ break;
358
+ case "select-multiple":
359
+ value = element.value;
360
+
361
+ let options = element?.selectedOptions;
362
+ if (options === undefined)
363
+ options = element.querySelectorAll(":scope option:checked");
364
+ value = Array.from(options).map(({ value }) => value);
365
+
366
+ break;
367
+ }
368
+
369
+ // values from custom elements
370
+ } else if (
371
+ (element?.constructor?.prototype &&
372
+ !!Object.getOwnPropertyDescriptor(
373
+ element.constructor.prototype,
374
+ "value",
375
+ )?.["get"]) ||
376
+ element.hasOwnProperty("value")
377
+ ) {
378
+ value = element?.["value"];
379
+ } else {
380
+ throw new Error("unsupported object");
381
+ }
382
+
383
+ if (isString(value)) {
384
+ const type = element.getAttribute(ATTRIBUTE_UPDATER_BIND_TYPE);
385
+ switch (type) {
386
+ case "number":
387
+ case "int":
388
+ case "float":
389
+ case "integer":
390
+ value = Number(value);
391
+ if (isNaN(value)) {
392
+ value = 0;
393
+ }
394
+ break;
395
+ case "boolean":
396
+ case "bool":
397
+ case "checkbox":
398
+ value = value === "true" || value === "1" || value === "on";
399
+ break;
400
+
401
+ case "string[]":
402
+ if (value === "") {
403
+ value = [];
404
+ }
405
+
406
+ value = value.split(",").map((v) => `${v}`);
407
+ break;
408
+
409
+ case "int[]":
410
+ case "integer[]":
411
+ if (value === "") {
412
+ value = [];
413
+ } else {
414
+ value = value
415
+ .split(",")
416
+ .map((v) => {
417
+ try {
418
+ return parseInt(v, 10);
419
+ } catch (e) {}
420
+ return -1;
421
+ })
422
+ .filter((v) => v !== -1);
423
+ }
424
+
425
+ break;
426
+ case "[]":
427
+ case "array":
428
+ case "list":
429
+ value = value.split(",");
430
+ break;
431
+ case "object":
432
+ case "json":
433
+ value = JSON.parse(value);
434
+ break;
435
+ default:
436
+ break;
437
+ }
438
+ }
439
+
440
+ const copy = clone(this[internalSymbol].subject.getRealSubject());
441
+
442
+ const pf = new Pathfinder(copy);
443
+ pf.setVia(path, value);
444
+
445
+ const diffResult = diff(copy, this[internalSymbol].subject.getRealSubject());
446
+
447
+ if (diffResult.length > 0) {
448
+ pathfinder.setVia(path, value);
449
+ }
451
450
  }
452
451
 
453
452
  /**
@@ -457,15 +456,15 @@ function retrieveAndSetValue(element) {
457
456
  * @private
458
457
  */
459
458
  function retrieveFromBindings() {
460
- if (this[internalSymbol].element.matches(`[${ATTRIBUTE_UPDATER_BIND}]`)) {
461
- retrieveAndSetValue.call(this, this[internalSymbol].element);
462
- }
463
-
464
- for (const [, element] of this[internalSymbol].element
465
- .querySelectorAll(`[${ATTRIBUTE_UPDATER_BIND}]`)
466
- .entries()) {
467
- retrieveAndSetValue.call(this, element);
468
- }
459
+ if (this[internalSymbol].element.matches(`[${ATTRIBUTE_UPDATER_BIND}]`)) {
460
+ retrieveAndSetValue.call(this, this[internalSymbol].element);
461
+ }
462
+
463
+ for (const [, element] of this[internalSymbol].element
464
+ .querySelectorAll(`[${ATTRIBUTE_UPDATER_BIND}]`)
465
+ .entries()) {
466
+ retrieveAndSetValue.call(this, element);
467
+ }
469
468
  }
470
469
 
471
470
  /**
@@ -476,11 +475,11 @@ function retrieveFromBindings() {
476
475
  * @return {void}
477
476
  */
478
477
  function removeElement(change) {
479
- for (const [, element] of this[internalSymbol].element
480
- .querySelectorAll(`:scope [${ATTRIBUTE_UPDATER_REMOVE}]`)
481
- .entries()) {
482
- element.parentNode.removeChild(element);
483
- }
478
+ for (const [, element] of this[internalSymbol].element
479
+ .querySelectorAll(`:scope [${ATTRIBUTE_UPDATER_REMOVE}]`)
480
+ .entries()) {
481
+ element.parentNode.removeChild(element);
482
+ }
484
483
  }
485
484
 
486
485
  /**
@@ -496,133 +495,133 @@ function removeElement(change) {
496
495
  * @this Updater
497
496
  */
498
497
  function insertElement(change) {
499
- const subject = this[internalSymbol].subject.getRealSubject();
498
+ const subject = this[internalSymbol].subject.getRealSubject();
500
499
 
501
- const mem = new WeakSet();
502
- let wd = 0;
500
+ const mem = new WeakSet();
501
+ let wd = 0;
503
502
 
504
- const container = this[internalSymbol].element;
503
+ const container = this[internalSymbol].element;
505
504
 
506
- while (true) {
507
- let found = false;
508
- wd++;
509
-
510
- const p = clone(change?.["path"]);
511
- if (!isArray(p)) return;
512
-
513
- while (p.length > 0) {
514
- const current = p.join(".");
515
-
516
- let iterator = new Set();
517
- const query = `[${ATTRIBUTE_UPDATER_INSERT}*="path:${current}"]`;
518
-
519
- const e = container.querySelectorAll(query);
520
-
521
- if (e.length > 0) {
522
- iterator = new Set([...e]);
523
- }
524
-
525
- if (container.matches(query)) {
526
- iterator.add(container);
527
- }
528
-
529
- for (const [, containerElement] of iterator.entries()) {
530
- if (mem.has(containerElement)) continue;
531
- mem.add(containerElement);
532
-
533
- found = true;
534
-
535
- const attributes = containerElement.getAttribute(
536
- ATTRIBUTE_UPDATER_INSERT,
537
- );
538
- if (attributes === null) continue;
539
-
540
- const def = trimSpaces(attributes);
541
- const i = def.indexOf(" ");
542
- const key = trimSpaces(def.substr(0, i));
543
- const refPrefix = `${key}-`;
544
- const cmd = trimSpaces(def.substr(i));
545
-
546
- // this case is actually excluded by the query but is nevertheless checked again here
547
- if (cmd.indexOf("|") > 0) {
548
- throw new Error("pipes are not allowed when cloning a node.");
549
- }
550
-
551
- const pipe = new Pipe(cmd);
552
- this[internalSymbol].callbacks.forEach((f, n) => {
553
- pipe.setCallback(n, f);
554
- });
555
-
556
- let value;
557
- try {
558
- containerElement.removeAttribute(ATTRIBUTE_ERRORMESSAGE);
559
- value = pipe.run(subject);
560
- } catch (e) {
561
- containerElement.setAttribute(ATTRIBUTE_ERRORMESSAGE, e.message);
562
- }
563
-
564
- const dataPath = cmd.split(":").pop();
565
-
566
- let insertPoint;
567
- if (containerElement.hasChildNodes()) {
568
- insertPoint = containerElement.lastChild;
569
- }
570
-
571
- if (!isIterable(value)) {
572
- throw new Error("the value is not iterable");
573
- }
574
-
575
- const available = new Set();
576
-
577
- for (const [i] of Object.entries(value)) {
578
- const ref = refPrefix + i;
579
- const currentPath = `${dataPath}.${i}`;
580
-
581
- available.add(ref);
582
- const refElement = containerElement.querySelector(
583
- `[${ATTRIBUTE_UPDATER_INSERT_REFERENCE}="${ref}"]`,
584
- );
585
-
586
- if (refElement instanceof HTMLElement) {
587
- insertPoint = refElement;
588
- continue;
589
- }
590
-
591
- appendNewDocumentFragment(containerElement, key, ref, currentPath);
592
- }
593
-
594
- const nodes = containerElement.querySelectorAll(
595
- `[${ATTRIBUTE_UPDATER_INSERT_REFERENCE}*="${refPrefix}"]`,
596
- );
597
-
598
- for (const [, node] of Object.entries(nodes)) {
599
- if (
600
- !available.has(
601
- node.getAttribute(ATTRIBUTE_UPDATER_INSERT_REFERENCE),
602
- )
603
- ) {
604
- try {
605
- containerElement.removeChild(node);
606
- } catch (e) {
607
- containerElement.setAttribute(
608
- ATTRIBUTE_ERRORMESSAGE,
609
- `${containerElement.getAttribute(ATTRIBUTE_ERRORMESSAGE)}, ${
610
- e.message
611
- }`.trim(),
612
- );
613
- }
614
- }
615
- }
616
- }
617
-
618
- p.pop();
619
- }
620
-
621
- if (found === false) break;
622
- if (wd++ > 200) {
623
- throw new Error("the maximum depth for the recursion is reached.");
624
- }
625
- }
505
+ while (true) {
506
+ let found = false;
507
+ wd++;
508
+
509
+ const p = clone(change?.["path"]);
510
+ if (!isArray(p)) return;
511
+
512
+ while (p.length > 0) {
513
+ const current = p.join(".");
514
+
515
+ let iterator = new Set();
516
+ const query = `[${ATTRIBUTE_UPDATER_INSERT}*="path:${current}"]`;
517
+
518
+ const e = container.querySelectorAll(query);
519
+
520
+ if (e.length > 0) {
521
+ iterator = new Set([...e]);
522
+ }
523
+
524
+ if (container.matches(query)) {
525
+ iterator.add(container);
526
+ }
527
+
528
+ for (const [, containerElement] of iterator.entries()) {
529
+ if (mem.has(containerElement)) continue;
530
+ mem.add(containerElement);
531
+
532
+ found = true;
533
+
534
+ const attributes = containerElement.getAttribute(
535
+ ATTRIBUTE_UPDATER_INSERT,
536
+ );
537
+ if (attributes === null) continue;
538
+
539
+ const def = trimSpaces(attributes);
540
+ const i = def.indexOf(" ");
541
+ const key = trimSpaces(def.substr(0, i));
542
+ const refPrefix = `${key}-`;
543
+ const cmd = trimSpaces(def.substr(i));
544
+
545
+ // this case is actually excluded by the query but is nevertheless checked again here
546
+ if (cmd.indexOf("|") > 0) {
547
+ throw new Error("pipes are not allowed when cloning a node.");
548
+ }
549
+
550
+ const pipe = new Pipe(cmd);
551
+ this[internalSymbol].callbacks.forEach((f, n) => {
552
+ pipe.setCallback(n, f);
553
+ });
554
+
555
+ let value;
556
+ try {
557
+ containerElement.removeAttribute(ATTRIBUTE_ERRORMESSAGE);
558
+ value = pipe.run(subject);
559
+ } catch (e) {
560
+ containerElement.setAttribute(ATTRIBUTE_ERRORMESSAGE, e.message);
561
+ }
562
+
563
+ const dataPath = cmd.split(":").pop();
564
+
565
+ let insertPoint;
566
+ if (containerElement.hasChildNodes()) {
567
+ insertPoint = containerElement.lastChild;
568
+ }
569
+
570
+ if (!isIterable(value)) {
571
+ throw new Error("the value is not iterable");
572
+ }
573
+
574
+ const available = new Set();
575
+
576
+ for (const [i] of Object.entries(value)) {
577
+ const ref = refPrefix + i;
578
+ const currentPath = `${dataPath}.${i}`;
579
+
580
+ available.add(ref);
581
+ const refElement = containerElement.querySelector(
582
+ `[${ATTRIBUTE_UPDATER_INSERT_REFERENCE}="${ref}"]`,
583
+ );
584
+
585
+ if (refElement instanceof HTMLElement) {
586
+ insertPoint = refElement;
587
+ continue;
588
+ }
589
+
590
+ appendNewDocumentFragment(containerElement, key, ref, currentPath);
591
+ }
592
+
593
+ const nodes = containerElement.querySelectorAll(
594
+ `[${ATTRIBUTE_UPDATER_INSERT_REFERENCE}*="${refPrefix}"]`,
595
+ );
596
+
597
+ for (const [, node] of Object.entries(nodes)) {
598
+ if (
599
+ !available.has(
600
+ node.getAttribute(ATTRIBUTE_UPDATER_INSERT_REFERENCE),
601
+ )
602
+ ) {
603
+ try {
604
+ containerElement.removeChild(node);
605
+ } catch (e) {
606
+ containerElement.setAttribute(
607
+ ATTRIBUTE_ERRORMESSAGE,
608
+ `${containerElement.getAttribute(ATTRIBUTE_ERRORMESSAGE)}, ${
609
+ e.message
610
+ }`.trim(),
611
+ );
612
+ }
613
+ }
614
+ }
615
+ }
616
+
617
+ p.pop();
618
+ }
619
+
620
+ if (found === false) break;
621
+ if (wd++ > 200) {
622
+ throw new Error("the maximum depth for the recursion is reached.");
623
+ }
624
+ }
626
625
  }
627
626
 
628
627
  /**
@@ -637,17 +636,17 @@ function insertElement(change) {
637
636
  * @throws {Error} no template was found with the specified key.
638
637
  */
639
638
  function appendNewDocumentFragment(container, key, ref, path) {
640
- const template = findDocumentTemplate(key, container);
639
+ const template = findDocumentTemplate(key, container);
641
640
 
642
- const nodes = template.createDocumentFragment();
643
- for (const [, node] of Object.entries(nodes.childNodes)) {
644
- if (node instanceof HTMLElement) {
645
- applyRecursive(node, key, path);
646
- node.setAttribute(ATTRIBUTE_UPDATER_INSERT_REFERENCE, ref);
647
- }
641
+ const nodes = template.createDocumentFragment();
642
+ for (const [, node] of Object.entries(nodes.childNodes)) {
643
+ if (node instanceof HTMLElement) {
644
+ applyRecursive(node, key, path);
645
+ node.setAttribute(ATTRIBUTE_UPDATER_INSERT_REFERENCE, ref);
646
+ }
648
647
 
649
- container.appendChild(node);
650
- }
648
+ container.appendChild(node);
649
+ }
651
650
  }
652
651
 
653
652
  /**
@@ -660,27 +659,27 @@ function appendNewDocumentFragment(container, key, ref, path) {
660
659
  * @return {void}
661
660
  */
662
661
  function applyRecursive(node, key, path) {
663
- if (node instanceof HTMLElement) {
664
- if (node.hasAttribute(ATTRIBUTE_UPDATER_REPLACE)) {
665
- const value = node.getAttribute(ATTRIBUTE_UPDATER_REPLACE);
666
- node.setAttribute(
667
- ATTRIBUTE_UPDATER_REPLACE,
668
- value.replaceAll(`path:${key}`, `path:${path}`),
669
- );
670
- }
671
-
672
- if (node.hasAttribute(ATTRIBUTE_UPDATER_ATTRIBUTES)) {
673
- const value = node.getAttribute(ATTRIBUTE_UPDATER_ATTRIBUTES);
674
- node.setAttribute(
675
- ATTRIBUTE_UPDATER_ATTRIBUTES,
676
- value.replaceAll(`path:${key}`, `path:${path}`),
677
- );
678
- }
679
-
680
- for (const [, child] of Object.entries(node.childNodes)) {
681
- applyRecursive(child, key, path);
682
- }
683
- }
662
+ if (node instanceof HTMLElement) {
663
+ if (node.hasAttribute(ATTRIBUTE_UPDATER_REPLACE)) {
664
+ const value = node.getAttribute(ATTRIBUTE_UPDATER_REPLACE);
665
+ node.setAttribute(
666
+ ATTRIBUTE_UPDATER_REPLACE,
667
+ value.replaceAll(`path:${key}`, `path:${path}`),
668
+ );
669
+ }
670
+
671
+ if (node.hasAttribute(ATTRIBUTE_UPDATER_ATTRIBUTES)) {
672
+ const value = node.getAttribute(ATTRIBUTE_UPDATER_ATTRIBUTES);
673
+ node.setAttribute(
674
+ ATTRIBUTE_UPDATER_ATTRIBUTES,
675
+ value.replaceAll(`path:${key}`, `path:${path}`),
676
+ );
677
+ }
678
+
679
+ for (const [, child] of Object.entries(node.childNodes)) {
680
+ applyRecursive(child, key, path);
681
+ }
682
+ }
684
683
  }
685
684
 
686
685
  /**
@@ -692,19 +691,19 @@ function applyRecursive(node, key, path) {
692
691
  * @this Updater
693
692
  */
694
693
  function updateContent(change) {
695
- const subject = this[internalSymbol].subject.getRealSubject();
696
-
697
- const p = clone(change?.["path"]);
698
- runUpdateContent.call(this, this[internalSymbol].element, p, subject);
699
-
700
- const slots = this[internalSymbol].element.querySelectorAll("slot");
701
- if (slots.length > 0) {
702
- for (const [, slot] of Object.entries(slots)) {
703
- for (const [, element] of Object.entries(slot.assignedNodes())) {
704
- runUpdateContent.call(this, element, p, subject);
705
- }
706
- }
707
- }
694
+ const subject = this[internalSymbol].subject.getRealSubject();
695
+
696
+ const p = clone(change?.["path"]);
697
+ runUpdateContent.call(this, this[internalSymbol].element, p, subject);
698
+
699
+ const slots = this[internalSymbol].element.querySelectorAll("slot");
700
+ if (slots.length > 0) {
701
+ for (const [, slot] of Object.entries(slots)) {
702
+ for (const [, element] of Object.entries(slot.assignedNodes())) {
703
+ runUpdateContent.call(this, element, p, subject);
704
+ }
705
+ }
706
+ }
708
707
  }
709
708
 
710
709
  /**
@@ -717,69 +716,69 @@ function updateContent(change) {
717
716
  * @return {void}
718
717
  */
719
718
  function runUpdateContent(container, parts, subject) {
720
- if (!isArray(parts)) return;
721
- if (!(container instanceof HTMLElement)) return;
722
- parts = clone(parts);
723
-
724
- const mem = new WeakSet();
725
-
726
- while (parts.length > 0) {
727
- const current = parts.join(".");
728
- parts.pop();
729
-
730
- // Unfortunately, static data is always changed as well, since it is not possible to react to changes here.
731
- const query = `[${ATTRIBUTE_UPDATER_REPLACE}^="path:${current}"], [${ATTRIBUTE_UPDATER_REPLACE}^="static:"], [${ATTRIBUTE_UPDATER_REPLACE}^="i18n:"]`;
732
- const e = container.querySelectorAll(`${query}`);
733
-
734
- const iterator = new Set([...e]);
735
-
736
- if (container.matches(query)) {
737
- iterator.add(container);
738
- }
739
-
740
- /**
741
- * @type {HTMLElement}
742
- */
743
- for (const [element] of iterator.entries()) {
744
- if (mem.has(element)) return;
745
- mem.add(element);
746
-
747
- const attributes = element.getAttribute(ATTRIBUTE_UPDATER_REPLACE);
748
- const cmd = trimSpaces(attributes);
749
-
750
- const pipe = new Pipe(cmd);
751
- this[internalSymbol].callbacks.forEach((f, n) => {
752
- pipe.setCallback(n, f);
753
- });
754
-
755
- let value;
756
- try {
757
- element.removeAttribute(ATTRIBUTE_ERRORMESSAGE);
758
- value = pipe.run(subject);
759
- } catch (e) {
760
- element.setAttribute(ATTRIBUTE_ERRORMESSAGE, e.message);
761
- }
762
-
763
- if (value instanceof HTMLElement) {
764
- while (element.firstChild) {
765
- element.removeChild(element.firstChild);
766
- }
767
-
768
- try {
769
- element.appendChild(value);
770
- } catch (e) {
771
- element.setAttribute(
772
- ATTRIBUTE_ERRORMESSAGE,
773
- `${element.getAttribute(ATTRIBUTE_ERRORMESSAGE)}, ${
774
- e.message
775
- }`.trim(),
776
- );
777
- }
778
- } else {
779
- element.innerHTML = value;
780
- }
781
- }
782
- }
719
+ if (!isArray(parts)) return;
720
+ if (!(container instanceof HTMLElement)) return;
721
+ parts = clone(parts);
722
+
723
+ const mem = new WeakSet();
724
+
725
+ while (parts.length > 0) {
726
+ const current = parts.join(".");
727
+ parts.pop();
728
+
729
+ // Unfortunately, static data is always changed as well, since it is not possible to react to changes here.
730
+ const query = `[${ATTRIBUTE_UPDATER_REPLACE}^="path:${current}"], [${ATTRIBUTE_UPDATER_REPLACE}^="static:"], [${ATTRIBUTE_UPDATER_REPLACE}^="i18n:"]`;
731
+ const e = container.querySelectorAll(`${query}`);
732
+
733
+ const iterator = new Set([...e]);
734
+
735
+ if (container.matches(query)) {
736
+ iterator.add(container);
737
+ }
738
+
739
+ /**
740
+ * @type {HTMLElement}
741
+ */
742
+ for (const [element] of iterator.entries()) {
743
+ if (mem.has(element)) return;
744
+ mem.add(element);
745
+
746
+ const attributes = element.getAttribute(ATTRIBUTE_UPDATER_REPLACE);
747
+ const cmd = trimSpaces(attributes);
748
+
749
+ const pipe = new Pipe(cmd);
750
+ this[internalSymbol].callbacks.forEach((f, n) => {
751
+ pipe.setCallback(n, f);
752
+ });
753
+
754
+ let value;
755
+ try {
756
+ element.removeAttribute(ATTRIBUTE_ERRORMESSAGE);
757
+ value = pipe.run(subject);
758
+ } catch (e) {
759
+ element.setAttribute(ATTRIBUTE_ERRORMESSAGE, e.message);
760
+ }
761
+
762
+ if (value instanceof HTMLElement) {
763
+ while (element.firstChild) {
764
+ element.removeChild(element.firstChild);
765
+ }
766
+
767
+ try {
768
+ element.appendChild(value);
769
+ } catch (e) {
770
+ element.setAttribute(
771
+ ATTRIBUTE_ERRORMESSAGE,
772
+ `${element.getAttribute(ATTRIBUTE_ERRORMESSAGE)}, ${
773
+ e.message
774
+ }`.trim(),
775
+ );
776
+ }
777
+ } else {
778
+ element.innerHTML = value;
779
+ }
780
+ }
781
+ }
783
782
  }
784
783
 
785
784
  /**
@@ -789,9 +788,9 @@ function runUpdateContent(container, parts, subject) {
789
788
  * @return {void}
790
789
  */
791
790
  function updateAttributes(change) {
792
- const subject = this[internalSymbol].subject.getRealSubject();
793
- const p = clone(change?.["path"]);
794
- runUpdateAttributes.call(this, this[internalSymbol].element, p, subject);
791
+ const subject = this[internalSymbol].subject.getRealSubject();
792
+ const p = clone(change?.["path"]);
793
+ runUpdateAttributes.call(this, this[internalSymbol].element, p, subject);
795
794
  }
796
795
 
797
796
  /**
@@ -803,70 +802,70 @@ function updateAttributes(change) {
803
802
  * @this Updater
804
803
  */
805
804
  function runUpdateAttributes(container, parts, subject) {
806
- if (!isArray(parts)) return;
807
- parts = clone(parts);
805
+ if (!isArray(parts)) return;
806
+ parts = clone(parts);
808
807
 
809
- const mem = new WeakSet();
808
+ const mem = new WeakSet();
810
809
 
811
- while (parts.length > 0) {
812
- const current = parts.join(".");
813
- parts.pop();
810
+ while (parts.length > 0) {
811
+ const current = parts.join(".");
812
+ parts.pop();
814
813
 
815
- let iterator = new Set();
814
+ let iterator = new Set();
816
815
 
817
- const query = `[${ATTRIBUTE_UPDATER_SELECT_THIS}][${ATTRIBUTE_UPDATER_ATTRIBUTES}], [${ATTRIBUTE_UPDATER_ATTRIBUTES}*="path:${current}"], [${ATTRIBUTE_UPDATER_ATTRIBUTES}^="static:"], [${ATTRIBUTE_UPDATER_ATTRIBUTES}^="i18n:"]`;
816
+ const query = `[${ATTRIBUTE_UPDATER_SELECT_THIS}][${ATTRIBUTE_UPDATER_ATTRIBUTES}], [${ATTRIBUTE_UPDATER_ATTRIBUTES}*="path:${current}"], [${ATTRIBUTE_UPDATER_ATTRIBUTES}^="static:"], [${ATTRIBUTE_UPDATER_ATTRIBUTES}^="i18n:"]`;
818
817
 
819
- const e = container.querySelectorAll(query);
818
+ const e = container.querySelectorAll(query);
820
819
 
821
- if (e.length > 0) {
822
- iterator = new Set([...e]);
823
- }
820
+ if (e.length > 0) {
821
+ iterator = new Set([...e]);
822
+ }
824
823
 
825
- if (container.matches(query)) {
826
- iterator.add(container);
827
- }
824
+ if (container.matches(query)) {
825
+ iterator.add(container);
826
+ }
828
827
 
829
- for (const [element] of iterator.entries()) {
830
- if (mem.has(element)) return;
831
- mem.add(element);
828
+ for (const [element] of iterator.entries()) {
829
+ if (mem.has(element)) return;
830
+ mem.add(element);
832
831
 
833
- // this case occurs when the ATTRIBUTE_UPDATER_SELECT_THIS attribute is set
834
- if (!element.hasAttribute(ATTRIBUTE_UPDATER_ATTRIBUTES)) {
835
- continue;
836
- }
832
+ // this case occurs when the ATTRIBUTE_UPDATER_SELECT_THIS attribute is set
833
+ if (!element.hasAttribute(ATTRIBUTE_UPDATER_ATTRIBUTES)) {
834
+ continue;
835
+ }
837
836
 
838
- const attributes = element.getAttribute(ATTRIBUTE_UPDATER_ATTRIBUTES);
837
+ const attributes = element.getAttribute(ATTRIBUTE_UPDATER_ATTRIBUTES);
839
838
 
840
- for (let [, def] of Object.entries(attributes.split(","))) {
841
- def = trimSpaces(def);
842
- const i = def.indexOf(" ");
843
- const name = trimSpaces(def.substr(0, i));
844
- const cmd = trimSpaces(def.substr(i));
839
+ for (let [, def] of Object.entries(attributes.split(","))) {
840
+ def = trimSpaces(def);
841
+ const i = def.indexOf(" ");
842
+ const name = trimSpaces(def.substr(0, i));
843
+ const cmd = trimSpaces(def.substr(i));
845
844
 
846
- const pipe = new Pipe(cmd);
845
+ const pipe = new Pipe(cmd);
847
846
 
848
- this[internalSymbol].callbacks.forEach((f, n) => {
849
- pipe.setCallback(n, f, element);
850
- });
847
+ this[internalSymbol].callbacks.forEach((f, n) => {
848
+ pipe.setCallback(n, f, element);
849
+ });
851
850
 
852
- let value;
853
- try {
854
- element.removeAttribute(ATTRIBUTE_ERRORMESSAGE);
855
- value = pipe.run(subject);
856
- } catch (e) {
857
- element.setAttribute(ATTRIBUTE_ERRORMESSAGE, e.message);
858
- }
851
+ let value;
852
+ try {
853
+ element.removeAttribute(ATTRIBUTE_ERRORMESSAGE);
854
+ value = pipe.run(subject);
855
+ } catch (e) {
856
+ element.setAttribute(ATTRIBUTE_ERRORMESSAGE, e.message);
857
+ }
859
858
 
860
- if (value === undefined) {
861
- element.removeAttribute(name);
862
- } else if (element.getAttribute(name) !== value) {
863
- element.setAttribute(name, value);
864
- }
859
+ if (value === undefined) {
860
+ element.removeAttribute(name);
861
+ } else if (element.getAttribute(name) !== value) {
862
+ element.setAttribute(name, value);
863
+ }
865
864
 
866
- handleInputControlAttributeUpdate.call(this, element, name, value);
867
- }
868
- }
869
- }
865
+ handleInputControlAttributeUpdate.call(this, element, name, value);
866
+ }
867
+ }
868
+ }
870
869
  }
871
870
 
872
871
  /**
@@ -879,54 +878,54 @@ function runUpdateAttributes(container, parts, subject) {
879
878
  */
880
879
 
881
880
  function handleInputControlAttributeUpdate(element, name, value) {
882
- if (element instanceof HTMLSelectElement) {
883
- switch (element.type) {
884
- case "select-multiple":
885
- for (const [index, opt] of Object.entries(element.options)) {
886
- opt.selected = value.indexOf(opt.value) !== -1;
887
- }
888
-
889
- break;
890
- case "select-one":
891
- // Only one value may be selected
892
-
893
- for (const [index, opt] of Object.entries(element.options)) {
894
- if (opt.value === value) {
895
- element.selectedIndex = index;
896
- break;
897
- }
898
- }
899
-
900
- break;
901
- }
902
- } else if (element instanceof HTMLInputElement) {
903
- switch (element.type) {
904
- case "radio":
905
- if (name === "checked") {
906
- element.checked = value !== undefined;
907
- }
908
-
909
- break;
910
-
911
- case "checkbox":
912
- if (name === "checked") {
913
- element.checked = value !== undefined;
914
- }
915
-
916
- break;
917
- case "text":
918
- default:
919
- if (name === "value") {
920
- element.value = value === undefined ? "" : value;
921
- }
922
-
923
- break;
924
- }
925
- } else if (element instanceof HTMLTextAreaElement) {
926
- if (name === "value") {
927
- element.value = value === undefined ? "" : value;
928
- }
929
- }
881
+ if (element instanceof HTMLSelectElement) {
882
+ switch (element.type) {
883
+ case "select-multiple":
884
+ for (const [index, opt] of Object.entries(element.options)) {
885
+ opt.selected = value.indexOf(opt.value) !== -1;
886
+ }
887
+
888
+ break;
889
+ case "select-one":
890
+ // Only one value may be selected
891
+
892
+ for (const [index, opt] of Object.entries(element.options)) {
893
+ if (opt.value === value) {
894
+ element.selectedIndex = index;
895
+ break;
896
+ }
897
+ }
898
+
899
+ break;
900
+ }
901
+ } else if (element instanceof HTMLInputElement) {
902
+ switch (element.type) {
903
+ case "radio":
904
+ if (name === "checked") {
905
+ element.checked = value !== undefined;
906
+ }
907
+
908
+ break;
909
+
910
+ case "checkbox":
911
+ if (name === "checked") {
912
+ element.checked = value !== undefined;
913
+ }
914
+
915
+ break;
916
+ case "text":
917
+ default:
918
+ if (name === "value") {
919
+ element.value = value === undefined ? "" : value;
920
+ }
921
+
922
+ break;
923
+ }
924
+ } else if (element instanceof HTMLTextAreaElement) {
925
+ if (name === "value") {
926
+ element.value = value === undefined ? "" : value;
927
+ }
928
+ }
930
929
  }
931
930
 
932
931
  /**
@@ -945,83 +944,83 @@ function handleInputControlAttributeUpdate(element, name, value) {
945
944
  * @throws {TypeError} symbol must be an instance of Symbol
946
945
  */
947
946
  function addObjectWithUpdaterToElement(elements, symbol, object, config = {}) {
948
- if (!(this instanceof HTMLElement)) {
949
- throw new TypeError(
950
- "the context of this function must be an instance of HTMLElement",
951
- );
952
- }
953
-
954
- if (!(typeof symbol === "symbol")) {
955
- throw new TypeError("symbol must be an instance of Symbol");
956
- }
957
-
958
- const updaters = new Set();
959
-
960
- if (elements instanceof NodeList) {
961
- elements = new Set([...elements]);
962
- } else if (elements instanceof HTMLElement) {
963
- elements = new Set([elements]);
964
- } else if (elements instanceof Set) {
965
- } else {
966
- throw new TypeError(
967
- `elements is not a valid type. (actual: ${typeof elements})`,
968
- );
969
- }
970
-
971
- const result = [];
972
-
973
- const updaterCallbacks = [];
974
- const cb = this?.[updaterTransformerMethodsSymbol];
975
- if (this instanceof HTMLElement && typeof cb === "function") {
976
- const callbacks = cb.call(this);
977
- if (typeof callbacks === "object") {
978
- for (const [name, callback] of Object.entries(callbacks)) {
979
- if (typeof callback === "function") {
980
- updaterCallbacks.push([name, callback]);
981
- } else {
982
- addAttributeToken(
983
- this,
984
- ATTRIBUTE_ERRORMESSAGE,
985
- `onUpdaterPipeCallbacks: ${name} is not a function`,
986
- );
987
- }
988
- }
989
- } else {
990
- addAttributeToken(
991
- this,
992
- ATTRIBUTE_ERRORMESSAGE,
993
- `onUpdaterPipeCallbacks do not return an object with functions`,
994
- );
995
- }
996
- }
997
-
998
- elements.forEach((element) => {
999
- if (!(element instanceof HTMLElement)) return;
1000
- if (element instanceof HTMLTemplateElement) return;
1001
-
1002
- const u = new Updater(element, object);
1003
- updaters.add(u);
1004
-
1005
- if (updaterCallbacks.length > 0) {
1006
- for (const [name, callback] of updaterCallbacks) {
1007
- u.setCallback(name, callback);
1008
- }
1009
- }
1010
-
1011
- result.push(
1012
- u.run().then(() => {
1013
- if (config.eventProcessing === true) {
1014
- u.enableEventProcessing();
1015
- }
1016
-
1017
- return u;
1018
- }),
1019
- );
1020
- });
1021
-
1022
- if (updaters.size > 0) {
1023
- addToObjectLink(this, symbol, updaters);
1024
- }
1025
-
1026
- return result;
947
+ if (!(this instanceof HTMLElement)) {
948
+ throw new TypeError(
949
+ "the context of this function must be an instance of HTMLElement",
950
+ );
951
+ }
952
+
953
+ if (!(typeof symbol === "symbol")) {
954
+ throw new TypeError("symbol must be an instance of Symbol");
955
+ }
956
+
957
+ const updaters = new Set();
958
+
959
+ if (elements instanceof NodeList) {
960
+ elements = new Set([...elements]);
961
+ } else if (elements instanceof HTMLElement) {
962
+ elements = new Set([elements]);
963
+ } else if (elements instanceof Set) {
964
+ } else {
965
+ throw new TypeError(
966
+ `elements is not a valid type. (actual: ${typeof elements})`,
967
+ );
968
+ }
969
+
970
+ const result = [];
971
+
972
+ const updaterCallbacks = [];
973
+ const cb = this?.[updaterTransformerMethodsSymbol];
974
+ if (this instanceof HTMLElement && typeof cb === "function") {
975
+ const callbacks = cb.call(this);
976
+ if (typeof callbacks === "object") {
977
+ for (const [name, callback] of Object.entries(callbacks)) {
978
+ if (typeof callback === "function") {
979
+ updaterCallbacks.push([name, callback]);
980
+ } else {
981
+ addAttributeToken(
982
+ this,
983
+ ATTRIBUTE_ERRORMESSAGE,
984
+ `onUpdaterPipeCallbacks: ${name} is not a function`,
985
+ );
986
+ }
987
+ }
988
+ } else {
989
+ addAttributeToken(
990
+ this,
991
+ ATTRIBUTE_ERRORMESSAGE,
992
+ `onUpdaterPipeCallbacks do not return an object with functions`,
993
+ );
994
+ }
995
+ }
996
+
997
+ elements.forEach((element) => {
998
+ if (!(element instanceof HTMLElement)) return;
999
+ if (element instanceof HTMLTemplateElement) return;
1000
+
1001
+ const u = new Updater(element, object);
1002
+ updaters.add(u);
1003
+
1004
+ if (updaterCallbacks.length > 0) {
1005
+ for (const [name, callback] of updaterCallbacks) {
1006
+ u.setCallback(name, callback);
1007
+ }
1008
+ }
1009
+
1010
+ result.push(
1011
+ u.run().then(() => {
1012
+ if (config.eventProcessing === true) {
1013
+ u.enableEventProcessing();
1014
+ }
1015
+
1016
+ return u;
1017
+ }),
1018
+ );
1019
+ });
1020
+
1021
+ if (updaters.size > 0) {
1022
+ addToObjectLink(this, symbol, updaters);
1023
+ }
1024
+
1025
+ return result;
1027
1026
  }