@schukai/monster 3.73.8 → 3.74.0

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