@schukai/monster 3.57.0 → 3.58.0

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