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