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