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