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