@schukai/monster 3.4.2 → 3.7.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/example/i18n/providers/embed.mjs +5 -0
- package/package.json +1 -1
- package/source/constants.mjs +4 -9
- package/source/constraints/abstract.mjs +4 -6
- package/source/constraints/abstractoperator.mjs +6 -12
- package/source/constraints/andoperator.mjs +3 -6
- package/source/constraints/invalid.mjs +3 -6
- package/source/constraints/isarray.mjs +6 -9
- package/source/constraints/isobject.mjs +4 -7
- package/source/constraints/namespace.mjs +1 -3
- package/source/constraints/oroperator.mjs +26 -25
- package/source/constraints/valid.mjs +3 -6
- package/source/data/buildmap.mjs +20 -36
- package/source/data/buildtree.mjs +29 -29
- package/source/data/datasource/namespace.mjs +1 -1
- package/source/data/datasource/server/restapi/writeerror.mjs +6 -6
- package/source/data/datasource/server/restapi.mjs +51 -65
- package/source/data/datasource/server/webconnect.mjs +26 -35
- package/source/data/datasource/server.mjs +17 -21
- package/source/data/datasource/storage/localstorage.mjs +8 -11
- package/source/data/datasource/storage/sessionstorage.mjs +8 -10
- package/source/data/datasource/storage.mjs +18 -22
- package/source/data/datasource.mjs +27 -43
- package/source/data/diff.mjs +20 -32
- package/source/data/extend.mjs +20 -14
- package/source/data/namespace.mjs +1 -3
- package/source/data/pathfinder.mjs +40 -67
- package/source/data/pipe.mjs +6 -10
- package/source/data/transformer.mjs +141 -157
- package/source/dom/assembler.mjs +6 -9
- package/source/dom/attributes.mjs +36 -48
- package/source/dom/constants.mjs +55 -71
- package/source/dom/customcontrol.mjs +16 -21
- package/source/dom/customelement.mjs +140 -164
- package/source/dom/events.mjs +17 -24
- package/source/dom/focusmanager.mjs +30 -48
- package/source/dom/locale.mjs +41 -10
- package/source/dom/namespace.mjs +1 -1
- package/source/dom/ready.mjs +7 -10
- package/source/dom/resource/data.mjs +38 -46
- package/source/dom/resource/link/namespace.mjs +1 -3
- package/source/dom/resource/link/stylesheet.mjs +7 -11
- package/source/dom/resource/link.mjs +36 -17
- package/source/dom/resource/namespace.mjs +1 -1
- package/source/dom/resource/script.mjs +23 -13
- package/source/dom/resource.mjs +47 -60
- package/source/dom/resourcemanager.mjs +36 -43
- package/source/dom/template.mjs +17 -24
- package/source/dom/theme.mjs +8 -12
- package/source/dom/updater.mjs +150 -196
- package/source/dom/util.mjs +11 -12
- package/source/dom/worker/factory.mjs +21 -25
- package/source/dom/worker/namespace.mjs +1 -1
- package/source/i18n/formatter.mjs +20 -24
- package/source/i18n/locale.mjs +40 -42
- package/source/i18n/namespace.mjs +1 -1
- package/source/i18n/provider.mjs +4 -7
- package/source/i18n/providers/embed.mjs +115 -0
- package/source/i18n/providers/fetch.mjs +33 -38
- package/source/i18n/translations.mjs +16 -20
- package/source/logging/handler/console.mjs +6 -10
- package/source/logging/handler.mjs +15 -18
- package/source/logging/logentry.mjs +8 -9
- package/source/logging/logger.mjs +73 -55
- package/source/logging/namespace.mjs +1 -1
- package/source/math/namespace.mjs +1 -1
- package/source/math/random.mjs +13 -14
- package/source/monster.mjs +132 -100
- package/source/net/namespace.mjs +1 -3
- package/source/net/webconnect/message.mjs +6 -8
- package/source/net/webconnect/namespace.mjs +1 -3
- package/source/net/webconnect.mjs +28 -39
- package/source/text/formatter.mjs +44 -55
- package/source/types/base.mjs +16 -26
- package/source/types/basewithoptions.mjs +8 -14
- package/source/types/binary.mjs +4 -5
- package/source/types/dataurl.mjs +19 -27
- package/source/types/global.mjs +14 -26
- package/source/types/id.mjs +4 -6
- package/source/types/is.mjs +11 -16
- package/source/types/mediatype.mjs +29 -44
- package/source/types/namespace.mjs +0 -1
- package/source/types/node.mjs +16 -22
- package/source/types/nodelist.mjs +10 -14
- package/source/types/noderecursiveiterator.mjs +11 -14
- package/source/types/observablequeue.mjs +13 -16
- package/source/types/observer.mjs +16 -23
- package/source/types/observerlist.mjs +18 -21
- package/source/types/proxyobserver.mjs +24 -37
- package/source/types/queue.mjs +8 -13
- package/source/types/randomid.mjs +10 -10
- package/source/types/regex.mjs +3 -5
- package/source/types/stack.mjs +4 -8
- package/source/types/tokenlist.mjs +24 -31
- package/source/types/typeof.mjs +5 -7
- package/source/types/uniquequeue.mjs +8 -13
- package/source/types/uuid.mjs +18 -25
- package/source/types/validate.mjs +26 -27
- package/source/types/version.mjs +17 -25
- package/source/util/clone.mjs +23 -32
- package/source/util/comparator.mjs +7 -15
- package/source/util/deadmansswitch.mjs +16 -23
- package/source/util/freeze.mjs +5 -7
- package/source/util/namespace.mjs +1 -1
- package/source/util/processing.mjs +33 -39
- package/source/util/trimspaces.mjs +17 -24
- package/test/cases/dom/locale.mjs +15 -0
- package/test/cases/i18n/providers/embed.mjs +72 -0
- package/test/cases/monster.mjs +1 -1
package/source/dom/updater.mjs
CHANGED
|
@@ -5,10 +5,10 @@
|
|
|
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
13
|
ATTRIBUTE_ERRORMESSAGE,
|
|
14
14
|
ATTRIBUTE_UPDATER_ATTRIBUTES,
|
|
@@ -17,22 +17,23 @@ import {
|
|
|
17
17
|
ATTRIBUTE_UPDATER_INSERT_REFERENCE,
|
|
18
18
|
ATTRIBUTE_UPDATER_REMOVE,
|
|
19
19
|
ATTRIBUTE_UPDATER_REPLACE,
|
|
20
|
-
ATTRIBUTE_UPDATER_SELECT_THIS,
|
|
20
|
+
ATTRIBUTE_UPDATER_SELECT_THIS,
|
|
21
|
+
customElementUpdaterLinkSymbol,
|
|
21
22
|
} from "../dom/constants.mjs";
|
|
22
23
|
|
|
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";
|
|
33
|
-
import {getDocument} from "./util.mjs";
|
|
24
|
+
import { Base } from "../types/base.mjs";
|
|
25
|
+
import { isArray, isInstance, isIterable } from "../types/is.mjs";
|
|
26
|
+
import { Observer } from "../types/observer.mjs";
|
|
27
|
+
import { ProxyObserver } from "../types/proxyobserver.mjs";
|
|
28
|
+
import { validateArray, validateInstance } from "../types/validate.mjs";
|
|
29
|
+
import { 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";
|
|
34
|
+
import { getDocument } from "./util.mjs";
|
|
34
35
|
|
|
35
|
-
export {Updater, addObjectWithUpdaterToElement}
|
|
36
|
+
export { Updater, addObjectWithUpdaterToElement };
|
|
36
37
|
|
|
37
38
|
/**
|
|
38
39
|
* The updater class connects an object with the dom. In this way, structures and contents in the DOM can be programmatically adapted via attributes.
|
|
@@ -57,7 +58,6 @@ export {Updater, addObjectWithUpdaterToElement}
|
|
|
57
58
|
* @summary The updater class connects an object with the dom
|
|
58
59
|
*/
|
|
59
60
|
class Updater extends Base {
|
|
60
|
-
|
|
61
61
|
/**
|
|
62
62
|
* @since 1.8.0
|
|
63
63
|
* @param {HTMLElement} element
|
|
@@ -72,7 +72,7 @@ class Updater extends Base {
|
|
|
72
72
|
/**
|
|
73
73
|
* @type {HTMLElement}
|
|
74
74
|
*/
|
|
75
|
-
if (subject === undefined) subject = {}
|
|
75
|
+
if (subject === undefined) subject = {};
|
|
76
76
|
if (!isInstance(subject, ProxyObserver)) {
|
|
77
77
|
subject = new ProxyObserver(subject);
|
|
78
78
|
}
|
|
@@ -81,27 +81,27 @@ class Updater extends Base {
|
|
|
81
81
|
element: validateInstance(element, HTMLElement),
|
|
82
82
|
last: {},
|
|
83
83
|
callbacks: new Map(),
|
|
84
|
-
eventTypes: [
|
|
85
|
-
subject: subject
|
|
86
|
-
}
|
|
87
|
-
|
|
88
|
-
this[internalSymbol].callbacks.set('checkstate', getCheckStateCallback.call(this));
|
|
89
|
-
|
|
90
|
-
this[internalSymbol].subject.attachObserver(new Observer(() => {
|
|
84
|
+
eventTypes: ["keyup", "click", "change", "drop", "touchend", "input"],
|
|
85
|
+
subject: subject,
|
|
86
|
+
};
|
|
91
87
|
|
|
92
|
-
|
|
88
|
+
this[internalSymbol].callbacks.set("checkstate", getCheckStateCallback.call(this));
|
|
93
89
|
|
|
94
|
-
|
|
95
|
-
|
|
90
|
+
this[internalSymbol].subject.attachObserver(
|
|
91
|
+
new Observer(() => {
|
|
92
|
+
const s = this[internalSymbol].subject.getRealSubject();
|
|
96
93
|
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
insertElement.call(this, change);
|
|
100
|
-
updateContent.call(this, change);
|
|
101
|
-
updateAttributes.call(this, change);
|
|
102
|
-
}
|
|
103
|
-
}));
|
|
94
|
+
const diffResult = diff(this[internalSymbol].last, s);
|
|
95
|
+
this[internalSymbol].last = clone(s);
|
|
104
96
|
|
|
97
|
+
for (const [, change] of Object.entries(diffResult)) {
|
|
98
|
+
removeElement.call(this, change);
|
|
99
|
+
insertElement.call(this, change);
|
|
100
|
+
updateContent.call(this, change);
|
|
101
|
+
updateAttributes.call(this, change);
|
|
102
|
+
}
|
|
103
|
+
}),
|
|
104
|
+
);
|
|
105
105
|
}
|
|
106
106
|
|
|
107
107
|
/**
|
|
@@ -137,12 +137,11 @@ class Updater extends Base {
|
|
|
137
137
|
// @see https://developer.mozilla.org/en-US/docs/Web/API/EventTarget/addEventListener
|
|
138
138
|
this[internalSymbol].element.addEventListener(type, getControlEventHandler.call(this), {
|
|
139
139
|
capture: true,
|
|
140
|
-
passive: true
|
|
140
|
+
passive: true,
|
|
141
141
|
});
|
|
142
142
|
}
|
|
143
143
|
|
|
144
144
|
return this;
|
|
145
|
-
|
|
146
145
|
}
|
|
147
146
|
|
|
148
147
|
/**
|
|
@@ -152,13 +151,11 @@ class Updater extends Base {
|
|
|
152
151
|
* @return {Updater}
|
|
153
152
|
*/
|
|
154
153
|
disableEventProcessing() {
|
|
155
|
-
|
|
156
154
|
for (const type of this[internalSymbol].eventTypes) {
|
|
157
155
|
this[internalSymbol].element.removeEventListener(type, getControlEventHandler.call(this));
|
|
158
156
|
}
|
|
159
157
|
|
|
160
158
|
return this;
|
|
161
|
-
|
|
162
159
|
}
|
|
163
160
|
|
|
164
161
|
/**
|
|
@@ -175,9 +172,9 @@ class Updater extends Base {
|
|
|
175
172
|
* @return {Promise}
|
|
176
173
|
*/
|
|
177
174
|
run() {
|
|
178
|
-
// the key __init__has no further meaning and is only
|
|
175
|
+
// the key __init__has no further meaning and is only
|
|
179
176
|
// used to create the diff for empty objects.
|
|
180
|
-
this[internalSymbol].last = {
|
|
177
|
+
this[internalSymbol].last = { __init__: true };
|
|
181
178
|
return this[internalSymbol].subject.notifyObservers();
|
|
182
179
|
}
|
|
183
180
|
|
|
@@ -219,7 +216,6 @@ class Updater extends Base {
|
|
|
219
216
|
this[internalSymbol].callbacks.set(name, callback);
|
|
220
217
|
return this;
|
|
221
218
|
}
|
|
222
|
-
|
|
223
219
|
}
|
|
224
220
|
|
|
225
221
|
/**
|
|
@@ -233,27 +229,25 @@ function getCheckStateCallback() {
|
|
|
233
229
|
const self = this;
|
|
234
230
|
|
|
235
231
|
return function (current) {
|
|
236
|
-
|
|
237
232
|
// this is a reference to the current object (therefore no array function here)
|
|
238
233
|
if (this instanceof HTMLInputElement) {
|
|
239
|
-
if ([
|
|
240
|
-
return
|
|
234
|
+
if (["radio", "checkbox"].indexOf(this.type) !== -1) {
|
|
235
|
+
return `${this.value}` === `${current}` ? "true" : undefined;
|
|
241
236
|
}
|
|
242
237
|
} else if (this instanceof HTMLOptionElement) {
|
|
243
|
-
|
|
244
238
|
if (isArray(current) && current.indexOf(this.value) !== -1) {
|
|
245
|
-
return
|
|
239
|
+
return "true";
|
|
246
240
|
}
|
|
247
241
|
|
|
248
242
|
return undefined;
|
|
249
243
|
}
|
|
250
|
-
}
|
|
244
|
+
};
|
|
251
245
|
}
|
|
252
246
|
|
|
253
247
|
/**
|
|
254
248
|
* @private
|
|
255
249
|
*/
|
|
256
|
-
const symbol = Symbol(
|
|
250
|
+
const symbol = Symbol("@schukai/monster/updater@@EventHandler");
|
|
257
251
|
|
|
258
252
|
/**
|
|
259
253
|
* @private
|
|
@@ -262,7 +256,6 @@ const symbol = Symbol('@schukai/monster/updater@@EventHandler');
|
|
|
262
256
|
* @throws {Error} the bind argument must start as a value with a path
|
|
263
257
|
*/
|
|
264
258
|
function getControlEventHandler() {
|
|
265
|
-
|
|
266
259
|
const self = this;
|
|
267
260
|
|
|
268
261
|
if (self[symbol]) {
|
|
@@ -282,12 +275,9 @@ function getControlEventHandler() {
|
|
|
282
275
|
}
|
|
283
276
|
|
|
284
277
|
retrieveAndSetValue.call(self, element);
|
|
285
|
-
|
|
286
|
-
}
|
|
278
|
+
};
|
|
287
279
|
|
|
288
280
|
return self[symbol];
|
|
289
|
-
|
|
290
|
-
|
|
291
281
|
}
|
|
292
282
|
|
|
293
283
|
/**
|
|
@@ -298,15 +288,14 @@ function getControlEventHandler() {
|
|
|
298
288
|
* @private
|
|
299
289
|
*/
|
|
300
290
|
function retrieveAndSetValue(element) {
|
|
301
|
-
|
|
302
291
|
const self = this;
|
|
303
292
|
|
|
304
293
|
const pathfinder = new Pathfinder(self[internalSymbol].subject.getSubject());
|
|
305
294
|
|
|
306
295
|
let path = element.getAttribute(ATTRIBUTE_UPDATER_BIND);
|
|
307
296
|
|
|
308
|
-
if (path.indexOf(
|
|
309
|
-
throw new Error(
|
|
297
|
+
if (path.indexOf("path:") !== 0) {
|
|
298
|
+
throw new Error("the bind argument must start as a value with a path");
|
|
310
299
|
}
|
|
311
300
|
|
|
312
301
|
path = path.substring(5);
|
|
@@ -315,39 +304,37 @@ function retrieveAndSetValue(element) {
|
|
|
315
304
|
|
|
316
305
|
if (element instanceof HTMLInputElement) {
|
|
317
306
|
switch (element.type) {
|
|
318
|
-
|
|
319
|
-
case 'checkbox':
|
|
307
|
+
case "checkbox":
|
|
320
308
|
value = element.checked ? element.value : undefined;
|
|
321
309
|
break;
|
|
322
310
|
default:
|
|
323
311
|
value = element.value;
|
|
324
312
|
break;
|
|
325
|
-
|
|
326
|
-
|
|
327
313
|
}
|
|
328
314
|
} else if (element instanceof HTMLTextAreaElement) {
|
|
329
315
|
value = element.value;
|
|
330
|
-
|
|
331
316
|
} else if (element instanceof HTMLSelectElement) {
|
|
332
|
-
|
|
333
317
|
switch (element.type) {
|
|
334
|
-
case
|
|
318
|
+
case "select-one":
|
|
335
319
|
value = element.value;
|
|
336
320
|
break;
|
|
337
|
-
case
|
|
321
|
+
case "select-multiple":
|
|
338
322
|
value = element.value;
|
|
339
323
|
|
|
340
324
|
let options = element?.selectedOptions;
|
|
341
325
|
if (options === undefined) options = element.querySelectorAll(":scope option:checked");
|
|
342
|
-
value = Array.from(options).map(({value}) => value);
|
|
326
|
+
value = Array.from(options).map(({ value }) => value);
|
|
343
327
|
|
|
344
328
|
break;
|
|
345
329
|
}
|
|
346
330
|
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
|
|
331
|
+
// values from customelements
|
|
332
|
+
} else if (
|
|
333
|
+
(element?.constructor?.prototype &&
|
|
334
|
+
!!Object.getOwnPropertyDescriptor(element.constructor.prototype, "value")?.["get"]) ||
|
|
335
|
+
element.hasOwnProperty("value")
|
|
336
|
+
) {
|
|
337
|
+
value = element?.["value"];
|
|
351
338
|
} else {
|
|
352
339
|
throw new Error("unsupported object");
|
|
353
340
|
}
|
|
@@ -372,14 +359,13 @@ function retrieveAndSetValue(element) {
|
|
|
372
359
|
function retrieveFromBindings() {
|
|
373
360
|
const self = this;
|
|
374
361
|
|
|
375
|
-
if (self[internalSymbol].element.matches(
|
|
376
|
-
retrieveAndSetValue.call(self, self[internalSymbol].element)
|
|
362
|
+
if (self[internalSymbol].element.matches(`[${ATTRIBUTE_UPDATER_BIND}]`)) {
|
|
363
|
+
retrieveAndSetValue.call(self, self[internalSymbol].element);
|
|
377
364
|
}
|
|
378
365
|
|
|
379
|
-
for (const [, element] of self[internalSymbol].element.querySelectorAll(
|
|
380
|
-
retrieveAndSetValue.call(self, element)
|
|
366
|
+
for (const [, element] of self[internalSymbol].element.querySelectorAll(`[${ATTRIBUTE_UPDATER_BIND}]`).entries()) {
|
|
367
|
+
retrieveAndSetValue.call(self, element);
|
|
381
368
|
}
|
|
382
|
-
|
|
383
369
|
}
|
|
384
370
|
|
|
385
371
|
/**
|
|
@@ -392,7 +378,9 @@ function retrieveFromBindings() {
|
|
|
392
378
|
function removeElement(change) {
|
|
393
379
|
const self = this;
|
|
394
380
|
|
|
395
|
-
for (const [, element] of self[internalSymbol].element
|
|
381
|
+
for (const [, element] of self[internalSymbol].element
|
|
382
|
+
.querySelectorAll(`:scope [${ATTRIBUTE_UPDATER_REMOVE}]`)
|
|
383
|
+
.entries()) {
|
|
396
384
|
element.parentNode.removeChild(element);
|
|
397
385
|
}
|
|
398
386
|
}
|
|
@@ -414,7 +402,7 @@ function insertElement(change) {
|
|
|
414
402
|
const subject = self[internalSymbol].subject.getRealSubject();
|
|
415
403
|
const document = getDocument();
|
|
416
404
|
|
|
417
|
-
let mem = new WeakSet;
|
|
405
|
+
let mem = new WeakSet();
|
|
418
406
|
let wd = 0;
|
|
419
407
|
|
|
420
408
|
const container = self[internalSymbol].element;
|
|
@@ -423,21 +411,19 @@ function insertElement(change) {
|
|
|
423
411
|
let found = false;
|
|
424
412
|
wd++;
|
|
425
413
|
|
|
426
|
-
let p = clone(change?.[
|
|
414
|
+
let p = clone(change?.["path"]);
|
|
427
415
|
if (!isArray(p)) return self;
|
|
428
416
|
|
|
429
417
|
while (p.length > 0) {
|
|
430
|
-
const current = p.join(
|
|
418
|
+
const current = p.join(".");
|
|
431
419
|
|
|
432
|
-
let iterator = new Set;
|
|
433
|
-
const query =
|
|
420
|
+
let iterator = new Set();
|
|
421
|
+
const query = `[${ATTRIBUTE_UPDATER_INSERT}*="path:${current}"]`;
|
|
434
422
|
|
|
435
423
|
const e = container.querySelectorAll(query);
|
|
436
424
|
|
|
437
425
|
if (e.length > 0) {
|
|
438
|
-
iterator = new Set(
|
|
439
|
-
[...e]
|
|
440
|
-
)
|
|
426
|
+
iterator = new Set([...e]);
|
|
441
427
|
}
|
|
442
428
|
|
|
443
429
|
if (container.matches(query)) {
|
|
@@ -445,38 +431,37 @@ function insertElement(change) {
|
|
|
445
431
|
}
|
|
446
432
|
|
|
447
433
|
for (const [, containerElement] of iterator.entries()) {
|
|
448
|
-
|
|
449
434
|
if (mem.has(containerElement)) continue;
|
|
450
|
-
mem.add(containerElement)
|
|
435
|
+
mem.add(containerElement);
|
|
451
436
|
|
|
452
437
|
found = true;
|
|
453
438
|
|
|
454
439
|
const attributes = containerElement.getAttribute(ATTRIBUTE_UPDATER_INSERT);
|
|
455
440
|
let def = trimSpaces(attributes);
|
|
456
|
-
let i = def.indexOf(
|
|
441
|
+
let i = def.indexOf(" ");
|
|
457
442
|
let key = trimSpaces(def.substr(0, i));
|
|
458
|
-
let refPrefix = key
|
|
443
|
+
let refPrefix = `${key}-`;
|
|
459
444
|
let cmd = trimSpaces(def.substr(i));
|
|
460
445
|
|
|
461
446
|
// this case is actually excluded by the query but is nevertheless checked again here
|
|
462
|
-
if (cmd.indexOf(
|
|
447
|
+
if (cmd.indexOf("|") > 0) {
|
|
463
448
|
throw new Error("pipes are not allowed when cloning a node.");
|
|
464
449
|
}
|
|
465
450
|
|
|
466
451
|
let pipe = new Pipe(cmd);
|
|
467
452
|
self[internalSymbol].callbacks.forEach((f, n) => {
|
|
468
453
|
pipe.setCallback(n, f);
|
|
469
|
-
})
|
|
454
|
+
});
|
|
470
455
|
|
|
471
|
-
let value
|
|
456
|
+
let value;
|
|
472
457
|
try {
|
|
473
458
|
containerElement.removeAttribute(ATTRIBUTE_ERRORMESSAGE);
|
|
474
|
-
value = pipe.run(subject)
|
|
459
|
+
value = pipe.run(subject);
|
|
475
460
|
} catch (e) {
|
|
476
461
|
containerElement.setAttribute(ATTRIBUTE_ERRORMESSAGE, e.message);
|
|
477
462
|
}
|
|
478
463
|
|
|
479
|
-
let dataPath = cmd.split(
|
|
464
|
+
let dataPath = cmd.split(":").pop();
|
|
480
465
|
|
|
481
466
|
let insertPoint;
|
|
482
467
|
if (containerElement.hasChildNodes()) {
|
|
@@ -484,17 +469,17 @@ function insertElement(change) {
|
|
|
484
469
|
}
|
|
485
470
|
|
|
486
471
|
if (!isIterable(value)) {
|
|
487
|
-
throw new Error(
|
|
472
|
+
throw new Error("the value is not iterable");
|
|
488
473
|
}
|
|
489
474
|
|
|
490
|
-
let available = new Set;
|
|
475
|
+
let available = new Set();
|
|
491
476
|
|
|
492
477
|
for (const [i, obj] of Object.entries(value)) {
|
|
493
478
|
let ref = refPrefix + i;
|
|
494
|
-
let currentPath = dataPath
|
|
479
|
+
let currentPath = `${dataPath}.${i}`;
|
|
495
480
|
|
|
496
481
|
available.add(ref);
|
|
497
|
-
let refElement = containerElement.querySelector(
|
|
482
|
+
let refElement = containerElement.querySelector(`[${ATTRIBUTE_UPDATER_INSERT_REFERENCE}="${ref}"]`);
|
|
498
483
|
|
|
499
484
|
if (refElement instanceof HTMLElement) {
|
|
500
485
|
insertPoint = refElement;
|
|
@@ -504,15 +489,19 @@ function insertElement(change) {
|
|
|
504
489
|
appendNewDocumentFragment(containerElement, key, ref, currentPath);
|
|
505
490
|
}
|
|
506
491
|
|
|
507
|
-
let nodes = containerElement.querySelectorAll(
|
|
492
|
+
let nodes = containerElement.querySelectorAll(
|
|
493
|
+
`[${ATTRIBUTE_UPDATER_INSERT_REFERENCE}*="${refPrefix}"]`,
|
|
494
|
+
);
|
|
508
495
|
for (const [, node] of Object.entries(nodes)) {
|
|
509
496
|
if (!available.has(node.getAttribute(ATTRIBUTE_UPDATER_INSERT_REFERENCE))) {
|
|
510
497
|
try {
|
|
511
498
|
containerElement.removeChild(node);
|
|
512
499
|
} catch (e) {
|
|
513
|
-
containerElement.setAttribute(
|
|
500
|
+
containerElement.setAttribute(
|
|
501
|
+
ATTRIBUTE_ERRORMESSAGE,
|
|
502
|
+
`${containerElement.getAttribute(ATTRIBUTE_ERRORMESSAGE)}, ${e.message}`.trim(),
|
|
503
|
+
);
|
|
514
504
|
}
|
|
515
|
-
|
|
516
505
|
}
|
|
517
506
|
}
|
|
518
507
|
}
|
|
@@ -522,9 +511,8 @@ function insertElement(change) {
|
|
|
522
511
|
|
|
523
512
|
if (found === false) break;
|
|
524
513
|
if (wd++ > 200) {
|
|
525
|
-
throw new Error(
|
|
514
|
+
throw new Error("the maximum depth for the recursion is reached.");
|
|
526
515
|
}
|
|
527
|
-
|
|
528
516
|
}
|
|
529
517
|
}
|
|
530
518
|
|
|
@@ -540,13 +528,11 @@ function insertElement(change) {
|
|
|
540
528
|
* @throws {Error} no template was found with the specified key.
|
|
541
529
|
*/
|
|
542
530
|
function appendNewDocumentFragment(container, key, ref, path) {
|
|
543
|
-
|
|
544
531
|
let template = findDocumentTemplate(key, container);
|
|
545
532
|
|
|
546
533
|
let nodes = template.createDocumentFragment();
|
|
547
534
|
for (const [, node] of Object.entries(nodes.childNodes)) {
|
|
548
535
|
if (node instanceof HTMLElement) {
|
|
549
|
-
|
|
550
536
|
applyRecursive(node, key, path);
|
|
551
537
|
node.setAttribute(ATTRIBUTE_UPDATER_INSERT_REFERENCE, ref);
|
|
552
538
|
}
|
|
@@ -565,17 +551,15 @@ function appendNewDocumentFragment(container, key, ref, path) {
|
|
|
565
551
|
* @return {void}
|
|
566
552
|
*/
|
|
567
553
|
function applyRecursive(node, key, path) {
|
|
568
|
-
|
|
569
554
|
if (node instanceof HTMLElement) {
|
|
570
|
-
|
|
571
555
|
if (node.hasAttribute(ATTRIBUTE_UPDATER_REPLACE)) {
|
|
572
556
|
let value = node.getAttribute(ATTRIBUTE_UPDATER_REPLACE);
|
|
573
|
-
node.setAttribute(ATTRIBUTE_UPDATER_REPLACE, value.replaceAll(
|
|
557
|
+
node.setAttribute(ATTRIBUTE_UPDATER_REPLACE, value.replaceAll(`path:${key}`, `path:${path}`));
|
|
574
558
|
}
|
|
575
559
|
|
|
576
560
|
if (node.hasAttribute(ATTRIBUTE_UPDATER_ATTRIBUTES)) {
|
|
577
561
|
let value = node.getAttribute(ATTRIBUTE_UPDATER_ATTRIBUTES);
|
|
578
|
-
node.setAttribute(ATTRIBUTE_UPDATER_ATTRIBUTES, value.replaceAll(
|
|
562
|
+
node.setAttribute(ATTRIBUTE_UPDATER_ATTRIBUTES, value.replaceAll(`path:${key}`, `path:${path}`));
|
|
579
563
|
}
|
|
580
564
|
|
|
581
565
|
for (const [, child] of Object.entries(node.childNodes)) {
|
|
@@ -596,10 +580,10 @@ function updateContent(change) {
|
|
|
596
580
|
const self = this;
|
|
597
581
|
const subject = self[internalSymbol].subject.getRealSubject();
|
|
598
582
|
|
|
599
|
-
let p = clone(change?.[
|
|
583
|
+
let p = clone(change?.["path"]);
|
|
600
584
|
runUpdateContent.call(this, this[internalSymbol].element, p, subject);
|
|
601
585
|
|
|
602
|
-
const slots = this[internalSymbol].element.querySelectorAll(
|
|
586
|
+
const slots = this[internalSymbol].element.querySelectorAll("slot");
|
|
603
587
|
if (slots.length > 0) {
|
|
604
588
|
for (const [, slot] of Object.entries(slots)) {
|
|
605
589
|
for (const [, element] of Object.entries(slot.assignedNodes())) {
|
|
@@ -623,19 +607,17 @@ function runUpdateContent(container, parts, subject) {
|
|
|
623
607
|
if (!(container instanceof HTMLElement)) return;
|
|
624
608
|
parts = clone(parts);
|
|
625
609
|
|
|
626
|
-
let mem = new WeakSet;
|
|
610
|
+
let mem = new WeakSet();
|
|
627
611
|
|
|
628
612
|
while (parts.length > 0) {
|
|
629
|
-
const current = parts.join(
|
|
613
|
+
const current = parts.join(".");
|
|
630
614
|
parts.pop();
|
|
631
615
|
|
|
632
616
|
// Unfortunately, static data is always changed as well, since it is not possible to react to changes here.
|
|
633
|
-
const query =
|
|
634
|
-
const e = container.querySelectorAll(
|
|
617
|
+
const query = `[${ATTRIBUTE_UPDATER_REPLACE}^="path:${current}"], [${ATTRIBUTE_UPDATER_REPLACE}^="static:"]`;
|
|
618
|
+
const e = container.querySelectorAll(`${query}`);
|
|
635
619
|
|
|
636
|
-
const iterator = new Set([
|
|
637
|
-
...e
|
|
638
|
-
])
|
|
620
|
+
const iterator = new Set([...e]);
|
|
639
621
|
|
|
640
622
|
if (container.matches(query)) {
|
|
641
623
|
iterator.add(container);
|
|
@@ -645,22 +627,21 @@ function runUpdateContent(container, parts, subject) {
|
|
|
645
627
|
* @type {HTMLElement}
|
|
646
628
|
*/
|
|
647
629
|
for (const [element] of iterator.entries()) {
|
|
648
|
-
|
|
649
630
|
if (mem.has(element)) return;
|
|
650
|
-
mem.add(element)
|
|
631
|
+
mem.add(element);
|
|
651
632
|
|
|
652
|
-
const attributes = element.getAttribute(ATTRIBUTE_UPDATER_REPLACE)
|
|
633
|
+
const attributes = element.getAttribute(ATTRIBUTE_UPDATER_REPLACE);
|
|
653
634
|
let cmd = trimSpaces(attributes);
|
|
654
635
|
|
|
655
636
|
let pipe = new Pipe(cmd);
|
|
656
637
|
this[internalSymbol].callbacks.forEach((f, n) => {
|
|
657
638
|
pipe.setCallback(n, f);
|
|
658
|
-
})
|
|
639
|
+
});
|
|
659
640
|
|
|
660
|
-
let value
|
|
641
|
+
let value;
|
|
661
642
|
try {
|
|
662
643
|
element.removeAttribute(ATTRIBUTE_ERRORMESSAGE);
|
|
663
|
-
value = pipe.run(subject)
|
|
644
|
+
value = pipe.run(subject);
|
|
664
645
|
} catch (e) {
|
|
665
646
|
element.setAttribute(ATTRIBUTE_ERRORMESSAGE, e.message);
|
|
666
647
|
}
|
|
@@ -673,18 +654,16 @@ function runUpdateContent(container, parts, subject) {
|
|
|
673
654
|
try {
|
|
674
655
|
element.appendChild(value);
|
|
675
656
|
} catch (e) {
|
|
676
|
-
element.setAttribute(
|
|
657
|
+
element.setAttribute(
|
|
658
|
+
ATTRIBUTE_ERRORMESSAGE,
|
|
659
|
+
`${element.getAttribute(ATTRIBUTE_ERRORMESSAGE)}, ${e.message}`.trim(),
|
|
660
|
+
);
|
|
677
661
|
}
|
|
678
|
-
|
|
679
662
|
} else {
|
|
680
663
|
element.innerHTML = value;
|
|
681
664
|
}
|
|
682
|
-
|
|
683
665
|
}
|
|
684
|
-
|
|
685
|
-
|
|
686
666
|
}
|
|
687
|
-
|
|
688
667
|
}
|
|
689
668
|
|
|
690
669
|
/**
|
|
@@ -697,7 +676,7 @@ function runUpdateContent(container, parts, subject) {
|
|
|
697
676
|
*/
|
|
698
677
|
function updateAttributes(change) {
|
|
699
678
|
const subject = this[internalSymbol].subject.getRealSubject();
|
|
700
|
-
let p = clone(change?.[
|
|
679
|
+
let p = clone(change?.["path"]);
|
|
701
680
|
runUpdateAttributes.call(this, this[internalSymbol].element, p, subject);
|
|
702
681
|
}
|
|
703
682
|
|
|
@@ -710,28 +689,25 @@ function updateAttributes(change) {
|
|
|
710
689
|
* @this Updater
|
|
711
690
|
*/
|
|
712
691
|
function runUpdateAttributes(container, parts, subject) {
|
|
713
|
-
|
|
714
692
|
const self = this;
|
|
715
693
|
|
|
716
694
|
if (!isArray(parts)) return;
|
|
717
695
|
parts = clone(parts);
|
|
718
696
|
|
|
719
|
-
let mem = new WeakSet;
|
|
697
|
+
let mem = new WeakSet();
|
|
720
698
|
|
|
721
699
|
while (parts.length > 0) {
|
|
722
|
-
const current = parts.join(
|
|
700
|
+
const current = parts.join(".");
|
|
723
701
|
parts.pop();
|
|
724
702
|
|
|
725
|
-
let iterator = new Set;
|
|
703
|
+
let iterator = new Set();
|
|
726
704
|
|
|
727
|
-
const query =
|
|
705
|
+
const query = `[${ATTRIBUTE_UPDATER_SELECT_THIS}], [${ATTRIBUTE_UPDATER_ATTRIBUTES}*="path:${current}"], [${ATTRIBUTE_UPDATER_ATTRIBUTES}^="static:"]`;
|
|
728
706
|
|
|
729
707
|
const e = container.querySelectorAll(query);
|
|
730
708
|
|
|
731
709
|
if (e.length > 0) {
|
|
732
|
-
iterator = new Set(
|
|
733
|
-
[...e]
|
|
734
|
-
)
|
|
710
|
+
iterator = new Set([...e]);
|
|
735
711
|
}
|
|
736
712
|
|
|
737
713
|
if (container.matches(query)) {
|
|
@@ -739,15 +715,14 @@ function runUpdateAttributes(container, parts, subject) {
|
|
|
739
715
|
}
|
|
740
716
|
|
|
741
717
|
for (const [element] of iterator.entries()) {
|
|
742
|
-
|
|
743
718
|
if (mem.has(element)) return;
|
|
744
|
-
mem.add(element)
|
|
719
|
+
mem.add(element);
|
|
745
720
|
|
|
746
|
-
const attributes = element.getAttribute(ATTRIBUTE_UPDATER_ATTRIBUTES)
|
|
721
|
+
const attributes = element.getAttribute(ATTRIBUTE_UPDATER_ATTRIBUTES);
|
|
747
722
|
|
|
748
|
-
for (let [, def] of Object.entries(attributes.split(
|
|
723
|
+
for (let [, def] of Object.entries(attributes.split(","))) {
|
|
749
724
|
def = trimSpaces(def);
|
|
750
|
-
let i = def.indexOf(
|
|
725
|
+
let i = def.indexOf(" ");
|
|
751
726
|
let name = trimSpaces(def.substr(0, i));
|
|
752
727
|
let cmd = trimSpaces(def.substr(i));
|
|
753
728
|
|
|
@@ -755,30 +730,26 @@ function runUpdateAttributes(container, parts, subject) {
|
|
|
755
730
|
|
|
756
731
|
self[internalSymbol].callbacks.forEach((f, n) => {
|
|
757
732
|
pipe.setCallback(n, f, element);
|
|
758
|
-
})
|
|
733
|
+
});
|
|
759
734
|
|
|
760
|
-
let value
|
|
735
|
+
let value;
|
|
761
736
|
try {
|
|
762
737
|
element.removeAttribute(ATTRIBUTE_ERRORMESSAGE);
|
|
763
|
-
value = pipe.run(subject)
|
|
738
|
+
value = pipe.run(subject);
|
|
764
739
|
} catch (e) {
|
|
765
740
|
element.setAttribute(ATTRIBUTE_ERRORMESSAGE, e.message);
|
|
766
741
|
}
|
|
767
742
|
|
|
768
|
-
|
|
769
743
|
if (value === undefined) {
|
|
770
|
-
element.removeAttribute(name)
|
|
771
|
-
|
|
744
|
+
element.removeAttribute(name);
|
|
772
745
|
} else if (element.getAttribute(name) !== value) {
|
|
773
746
|
element.setAttribute(name, value);
|
|
774
747
|
}
|
|
775
748
|
|
|
776
749
|
handleInputControlAttributeUpdate.call(this, element, name, value);
|
|
777
|
-
|
|
778
750
|
}
|
|
779
751
|
}
|
|
780
752
|
}
|
|
781
|
-
|
|
782
753
|
}
|
|
783
754
|
|
|
784
755
|
/**
|
|
@@ -794,11 +765,8 @@ function handleInputControlAttributeUpdate(element, name, value) {
|
|
|
794
765
|
const self = this;
|
|
795
766
|
|
|
796
767
|
if (element instanceof HTMLSelectElement) {
|
|
797
|
-
|
|
798
|
-
|
|
799
768
|
switch (element.type) {
|
|
800
|
-
case
|
|
801
|
-
|
|
769
|
+
case "select-multiple":
|
|
802
770
|
for (const [index, opt] of Object.entries(element.options)) {
|
|
803
771
|
if (value.indexOf(opt.value) !== -1) {
|
|
804
772
|
opt.selected = true;
|
|
@@ -808,7 +776,7 @@ function handleInputControlAttributeUpdate(element, name, value) {
|
|
|
808
776
|
}
|
|
809
777
|
|
|
810
778
|
break;
|
|
811
|
-
case
|
|
779
|
+
case "select-one":
|
|
812
780
|
// Only one value may be selected
|
|
813
781
|
|
|
814
782
|
for (const [index, opt] of Object.entries(element.options)) {
|
|
@@ -820,14 +788,10 @@ function handleInputControlAttributeUpdate(element, name, value) {
|
|
|
820
788
|
|
|
821
789
|
break;
|
|
822
790
|
}
|
|
823
|
-
|
|
824
|
-
|
|
825
791
|
} else if (element instanceof HTMLInputElement) {
|
|
826
792
|
switch (element.type) {
|
|
827
|
-
|
|
828
|
-
|
|
829
|
-
if (name === 'checked') {
|
|
830
|
-
|
|
793
|
+
case "radio":
|
|
794
|
+
if (name === "checked") {
|
|
831
795
|
if (value !== undefined) {
|
|
832
796
|
element.checked = true;
|
|
833
797
|
} else {
|
|
@@ -837,10 +801,8 @@ function handleInputControlAttributeUpdate(element, name, value) {
|
|
|
837
801
|
|
|
838
802
|
break;
|
|
839
803
|
|
|
840
|
-
case
|
|
841
|
-
|
|
842
|
-
if (name === 'checked') {
|
|
843
|
-
|
|
804
|
+
case "checkbox":
|
|
805
|
+
if (name === "checked") {
|
|
844
806
|
if (value !== undefined) {
|
|
845
807
|
element.checked = true;
|
|
846
808
|
} else {
|
|
@@ -849,26 +811,21 @@ function handleInputControlAttributeUpdate(element, name, value) {
|
|
|
849
811
|
}
|
|
850
812
|
|
|
851
813
|
break;
|
|
852
|
-
case
|
|
814
|
+
case "text":
|
|
853
815
|
default:
|
|
854
|
-
if (name ===
|
|
855
|
-
element.value =
|
|
816
|
+
if (name === "value") {
|
|
817
|
+
element.value = value === undefined ? "" : value;
|
|
856
818
|
}
|
|
857
819
|
|
|
858
820
|
break;
|
|
859
|
-
|
|
860
|
-
|
|
861
821
|
}
|
|
862
822
|
} else if (element instanceof HTMLTextAreaElement) {
|
|
863
|
-
if (name ===
|
|
864
|
-
element.value =
|
|
823
|
+
if (name === "value") {
|
|
824
|
+
element.value = value === undefined ? "" : value;
|
|
865
825
|
}
|
|
866
826
|
}
|
|
867
|
-
|
|
868
827
|
}
|
|
869
828
|
|
|
870
|
-
|
|
871
|
-
|
|
872
829
|
/**
|
|
873
830
|
* @param {NodeList|HTMLElement|Set<HTMLElement>} elements
|
|
874
831
|
* @param {Symbol} symbol
|
|
@@ -881,44 +838,41 @@ function handleInputControlAttributeUpdate(element, name, value) {
|
|
|
881
838
|
* @throws {TypeError} the context of the function is not an instance of HTMLElement
|
|
882
839
|
* @throws {TypeError} symbol must be an instance of Symbol
|
|
883
840
|
*/
|
|
884
|
-
function addObjectWithUpdaterToElement
|
|
841
|
+
function addObjectWithUpdaterToElement(elements, symbol, object) {
|
|
885
842
|
const self = this;
|
|
886
843
|
if (!(self instanceof HTMLElement)) {
|
|
887
|
-
throw new TypeError(
|
|
844
|
+
throw new TypeError("the context of this function must be an instance of HTMLElement");
|
|
888
845
|
}
|
|
889
|
-
|
|
890
|
-
if (!(typeof symbol ===
|
|
891
|
-
throw new TypeError(
|
|
846
|
+
|
|
847
|
+
if (!(typeof symbol === "symbol")) {
|
|
848
|
+
throw new TypeError("symbol must be an instance of Symbol");
|
|
892
849
|
}
|
|
893
850
|
|
|
894
|
-
const updaters = new Set;
|
|
851
|
+
const updaters = new Set();
|
|
895
852
|
|
|
896
853
|
if (elements instanceof NodeList) {
|
|
897
|
-
elements = new Set([
|
|
898
|
-
...elements
|
|
899
|
-
])
|
|
854
|
+
elements = new Set([...elements]);
|
|
900
855
|
} else if (elements instanceof HTMLElement) {
|
|
901
|
-
elements = new Set([
|
|
902
|
-
elements
|
|
903
|
-
])
|
|
856
|
+
elements = new Set([elements]);
|
|
904
857
|
} else if (elements instanceof Set) {
|
|
905
858
|
} else {
|
|
906
|
-
throw new TypeError(
|
|
859
|
+
throw new TypeError(`elements is not a valid type. (actual: ${typeof elements})`);
|
|
907
860
|
}
|
|
908
861
|
|
|
909
862
|
let result = [];
|
|
910
863
|
|
|
911
864
|
elements.forEach((element) => {
|
|
912
865
|
if (!(element instanceof HTMLElement)) return;
|
|
913
|
-
if (
|
|
866
|
+
if (element instanceof HTMLTemplateElement) return;
|
|
914
867
|
|
|
915
|
-
const u = new Updater(element, object)
|
|
868
|
+
const u = new Updater(element, object);
|
|
916
869
|
updaters.add(u);
|
|
917
870
|
|
|
918
|
-
result.push(
|
|
919
|
-
|
|
920
|
-
|
|
921
|
-
|
|
871
|
+
result.push(
|
|
872
|
+
u.run().then(() => {
|
|
873
|
+
return u.enableEventProcessing();
|
|
874
|
+
}),
|
|
875
|
+
);
|
|
922
876
|
});
|
|
923
877
|
|
|
924
878
|
if (updaters.size > 0) {
|