@schukai/monster 3.53.0 → 3.55.0

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