@schukai/monster 1.25.0 → 1.28.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.
Files changed (200) hide show
  1. package/CHANGELOG +43 -0
  2. package/README.md +4 -4
  3. package/dist/modules/constants.js +1 -1
  4. package/dist/modules/constraints/abstract.js +1 -1
  5. package/dist/modules/constraints/abstractoperator.js +1 -1
  6. package/dist/modules/constraints/andoperator.js +1 -1
  7. package/dist/modules/constraints/invalid.js +1 -1
  8. package/dist/modules/constraints/isarray.js +1 -1
  9. package/dist/modules/constraints/isobject.js +1 -1
  10. package/dist/modules/constraints/namespace.js +1 -1
  11. package/dist/modules/constraints/oroperator.js +1 -1
  12. package/dist/modules/constraints/valid.js +1 -1
  13. package/dist/modules/data/buildmap.js +2 -2
  14. package/dist/modules/data/buildtree.js +2 -0
  15. package/dist/modules/data/datasource/namespace.js +1 -1
  16. package/dist/modules/data/datasource/restapi/writeerror.js +1 -1
  17. package/dist/modules/data/datasource/restapi.js +1 -1
  18. package/dist/modules/data/datasource/storage/localstorage.js +1 -1
  19. package/dist/modules/data/datasource/storage/namespace.js +1 -1
  20. package/dist/modules/data/datasource/storage/sessionstorage.js +1 -1
  21. package/dist/modules/data/datasource/storage.js +1 -1
  22. package/dist/modules/data/datasource.js +1 -1
  23. package/dist/modules/data/diff.js +1 -1
  24. package/dist/modules/data/extend.js +1 -1
  25. package/dist/modules/data/namespace.js +1 -1
  26. package/dist/modules/data/pathfinder.js +1 -1
  27. package/dist/modules/data/pipe.js +1 -1
  28. package/dist/modules/data/transformer.js +1 -1
  29. package/dist/modules/dom/assembler.js +1 -1
  30. package/dist/modules/dom/attributes.js +2 -2
  31. package/dist/modules/dom/constants.js +2 -2
  32. package/dist/modules/dom/customcontrol.js +1 -1
  33. package/dist/modules/dom/customelement.js +1 -1
  34. package/dist/modules/dom/events.js +1 -1
  35. package/dist/modules/dom/focusmanager.js +1 -1
  36. package/dist/modules/dom/locale.js +1 -1
  37. package/dist/modules/dom/namespace.js +1 -1
  38. package/dist/modules/dom/resource/data.js +1 -1
  39. package/dist/modules/dom/resource/link/stylesheet.js +1 -1
  40. package/dist/modules/dom/resource/link.js +1 -1
  41. package/dist/modules/dom/resource/script.js +1 -1
  42. package/dist/modules/dom/resource.js +1 -1
  43. package/dist/modules/dom/resourcemanager.js +1 -1
  44. package/dist/modules/dom/template.js +2 -2
  45. package/dist/modules/dom/theme.js +1 -1
  46. package/dist/modules/dom/updater.js +2 -2
  47. package/dist/modules/dom/util.js +1 -1
  48. package/dist/modules/dom/worker/factory.js +1 -1
  49. package/dist/modules/i18n/formatter.js +2 -0
  50. package/dist/modules/i18n/locale.js +1 -1
  51. package/dist/modules/i18n/namespace.js +1 -1
  52. package/dist/modules/i18n/provider.js +1 -1
  53. package/dist/modules/i18n/providers/fetch.js +1 -1
  54. package/dist/modules/i18n/providers/namespace.js +1 -1
  55. package/dist/modules/i18n/translations.js +1 -1
  56. package/dist/modules/logging/handler/console.js +1 -1
  57. package/dist/modules/logging/handler/namespace.js +1 -1
  58. package/dist/modules/logging/handler.js +1 -1
  59. package/dist/modules/logging/logentry.js +1 -1
  60. package/dist/modules/logging/logger.js +1 -1
  61. package/dist/modules/logging/namespace.js +1 -1
  62. package/dist/modules/math/namespace.js +1 -1
  63. package/dist/modules/math/random.js +1 -1
  64. package/dist/modules/monster.js +1 -1
  65. package/dist/modules/namespace.js +1 -1
  66. package/dist/modules/text/formatter.js +2 -2
  67. package/dist/modules/text/namespace.js +1 -1
  68. package/dist/modules/types/base.js +1 -1
  69. package/dist/modules/types/basewithoptions.js +1 -1
  70. package/dist/modules/types/binary.js +1 -1
  71. package/dist/modules/types/dataurl.js +1 -1
  72. package/dist/modules/types/global.js +1 -1
  73. package/dist/modules/types/id.js +1 -1
  74. package/dist/modules/types/is.js +2 -2
  75. package/dist/modules/types/mediatype.js +1 -1
  76. package/dist/modules/types/namespace.js +1 -1
  77. package/dist/modules/types/node.js +2 -0
  78. package/dist/modules/types/nodelist.js +2 -0
  79. package/dist/modules/types/noderecursiveiterator.js +2 -0
  80. package/dist/modules/types/observer.js +1 -1
  81. package/dist/modules/types/observerlist.js +1 -1
  82. package/dist/modules/types/proxyobserver.js +1 -1
  83. package/dist/modules/types/queue.js +1 -1
  84. package/dist/modules/types/randomid.js +1 -1
  85. package/dist/modules/types/regex.js +2 -0
  86. package/dist/modules/types/stack.js +1 -1
  87. package/dist/modules/types/tokenlist.js +1 -1
  88. package/dist/modules/types/typeof.js +1 -1
  89. package/dist/modules/types/uniquequeue.js +1 -1
  90. package/dist/modules/types/uuid.js +1 -1
  91. package/dist/modules/types/validate.js +1 -1
  92. package/dist/modules/types/version.js +2 -2
  93. package/dist/modules/util/clone.js +1 -1
  94. package/dist/modules/util/comparator.js +1 -1
  95. package/dist/modules/util/freeze.js +1 -1
  96. package/dist/modules/util/namespace.js +1 -1
  97. package/dist/modules/util/processing.js +1 -1
  98. package/dist/modules/util/trimspaces.js +1 -1
  99. package/dist/monster.dev.js +1181 -708
  100. package/dist/monster.dev.js.map +1 -1
  101. package/dist/monster.js +2 -2
  102. package/package.json +13 -2
  103. package/source/constraints/abstract.js +5 -0
  104. package/source/constraints/abstractoperator.js +5 -0
  105. package/source/constraints/andoperator.js +10 -5
  106. package/source/constraints/invalid.js +8 -3
  107. package/source/constraints/isarray.js +9 -4
  108. package/source/constraints/isobject.js +8 -3
  109. package/source/constraints/oroperator.js +10 -5
  110. package/source/constraints/valid.js +8 -3
  111. package/source/data/buildmap.js +27 -13
  112. package/source/data/buildtree.js +129 -0
  113. package/source/data/datasource/restapi.js +3 -3
  114. package/source/data/datasource/storage/localstorage.js +2 -2
  115. package/source/data/datasource/storage/sessionstorage.js +2 -2
  116. package/source/data/datasource/storage.js +3 -3
  117. package/source/data/datasource.js +3 -3
  118. package/source/data/diff.js +3 -3
  119. package/source/data/extend.js +2 -2
  120. package/source/data/pathfinder.js +4 -4
  121. package/source/data/pipe.js +3 -3
  122. package/source/data/transformer.js +3 -3
  123. package/source/dom/assembler.js +2 -2
  124. package/source/dom/attributes.js +111 -28
  125. package/source/dom/constants.js +17 -1
  126. package/source/dom/customcontrol.js +1 -1
  127. package/source/dom/customelement.js +1 -1
  128. package/source/dom/events.js +6 -7
  129. package/source/dom/focusmanager.js +6 -7
  130. package/source/dom/locale.js +8 -4
  131. package/source/dom/resource/data.js +2 -2
  132. package/source/dom/resource/link/stylesheet.js +2 -2
  133. package/source/dom/resource/link.js +2 -2
  134. package/source/dom/resource/script.js +2 -2
  135. package/source/dom/resource.js +2 -2
  136. package/source/dom/resourcemanager.js +2 -2
  137. package/source/dom/template.js +55 -15
  138. package/source/dom/theme.js +3 -3
  139. package/source/dom/updater.js +158 -98
  140. package/source/dom/util.js +6 -6
  141. package/source/dom/worker/factory.js +2 -2
  142. package/source/i18n/formatter.js +140 -0
  143. package/source/i18n/locale.js +6 -4
  144. package/source/i18n/provider.js +2 -2
  145. package/source/i18n/providers/fetch.js +18 -3
  146. package/source/i18n/translations.js +18 -9
  147. package/source/logging/handler/console.js +2 -2
  148. package/source/logging/handler.js +2 -2
  149. package/source/logging/logentry.js +2 -2
  150. package/source/logging/logger.js +2 -2
  151. package/source/math/random.js +2 -2
  152. package/source/namespace.js +1 -1
  153. package/source/text/formatter.js +190 -48
  154. package/source/types/base.js +2 -2
  155. package/source/types/basewithoptions.js +2 -2
  156. package/source/types/binary.js +4 -4
  157. package/source/types/dataurl.js +4 -4
  158. package/source/types/global.js +4 -4
  159. package/source/types/id.js +6 -3
  160. package/source/types/is.js +100 -82
  161. package/source/types/mediatype.js +4 -4
  162. package/source/types/node.js +210 -0
  163. package/source/types/nodelist.js +129 -0
  164. package/source/types/noderecursiveiterator.js +148 -0
  165. package/source/types/observer.js +3 -3
  166. package/source/types/observerlist.js +2 -2
  167. package/source/types/proxyobserver.js +5 -5
  168. package/source/types/queue.js +4 -4
  169. package/source/types/randomid.js +2 -2
  170. package/source/types/regex.js +49 -0
  171. package/source/types/stack.js +2 -2
  172. package/source/types/tokenlist.js +2 -2
  173. package/source/types/typeof.js +3 -3
  174. package/source/types/uniquequeue.js +2 -2
  175. package/source/types/uuid.js +2 -2
  176. package/source/types/validate.js +20 -20
  177. package/source/types/version.js +6 -6
  178. package/source/util/clone.js +2 -2
  179. package/source/util/comparator.js +3 -3
  180. package/source/util/freeze.js +2 -2
  181. package/source/util/processing.js +3 -3
  182. package/source/util/trimspaces.js +2 -2
  183. package/test/cases/data/buildtree.js +212 -0
  184. package/test/cases/dom/attributes.js +46 -19
  185. package/test/cases/dom/resource/link/stylesheet.js +1 -1
  186. package/test/cases/dom/template.js +72 -14
  187. package/test/cases/dom/updater.js +102 -75
  188. package/test/cases/i18n/formatter.js +66 -0
  189. package/test/cases/monster.js +1 -1
  190. package/test/cases/text/formatter.js +36 -5
  191. package/test/cases/types/node.js +252 -0
  192. package/test/cases/types/nodelist.js +71 -0
  193. package/test/cases/types/noderecursiveiterator.js +75 -0
  194. package/test/cases/types/regex.js +32 -0
  195. package/test/util/jsdom.js +0 -1
  196. package/test/web/import.js +6 -0
  197. package/test/web/monster-dev.html +3 -3
  198. package/test/web/monster.html +2 -2
  199. package/test/web/test.html +3 -3
  200. package/test/web/tests.js +3 -3
@@ -4,6 +4,7 @@
4
4
  * @author schukai GmbH
5
5
  */
6
6
 
7
+ import {internalSymbol} from "../constants.js";
7
8
  import {diff} from "../data/diff.js";
8
9
  import {Pathfinder} from "../data/pathfinder.js";
9
10
  import {Pipe} from "../data/pipe.js";
@@ -14,7 +15,8 @@ import {
14
15
  ATTRIBUTE_UPDATER_INSERT,
15
16
  ATTRIBUTE_UPDATER_INSERT_REFERENCE,
16
17
  ATTRIBUTE_UPDATER_REMOVE,
17
- ATTRIBUTE_UPDATER_REPLACE
18
+ ATTRIBUTE_UPDATER_REPLACE,
19
+ ATTRIBUTE_UPDATER_SELECT_THIS
18
20
  } from "../dom/constants.js";
19
21
  import {assignToNamespace, Monster} from '../namespace.js';
20
22
  import {Base} from "../types/base.js";
@@ -24,6 +26,7 @@ import {ProxyObserver} from "../types/proxyobserver.js";
24
26
  import {validateArray, validateInstance} from "../types/validate.js";
25
27
  import {clone} from "../util/clone.js";
26
28
  import {trimSpaces} from "../util/trimspaces.js";
29
+ import {findTargetElementFromEvent} from "./events.js";
27
30
  import {findDocumentTemplate} from "./template.js";
28
31
  import {getDocument} from "./util.js";
29
32
 
@@ -34,11 +37,14 @@ import {getDocument} from "./util.js";
34
37
  * For example, to include a string from an object, the attribute `data-monster-replace` can be used.
35
38
  * a further explanation can be found under {@tutorial dom-based-templating-implementation}.
36
39
  *
40
+ * Changes to attributes are made only when the direct values are changed. If you want to assign changes to other values
41
+ * as well, you have to insert the attribute `data-monster-select-this`. This should be done with care, as it can reduce performance.
42
+ *
37
43
  * You can create an object of this class using the monster namespace `new Monster.DOM.Updater()`.
38
44
  *
39
45
  * ```
40
46
  * <script type="module">
41
- * import {Monster} from 'https://cdn.jsdelivr.net/npm/@schukai/monster@1.25.0/dist/modules/dom/updater.js';
47
+ * import {Monster} from 'https://cdn.jsdelivr.net/npm/@schukai/monster@1.28.0/dist/monster.js';
42
48
  * new Monster.DOM.Updater()
43
49
  * </script>
44
50
  * ```
@@ -47,14 +53,14 @@ import {getDocument} from "./util.js";
47
53
  *
48
54
  * ```
49
55
  * <script type="module">
50
- * import {Updater} from 'https://cdn.jsdelivr.net/npm/@schukai/monster@1.25.0/dist/modules/dom/updater.js';
56
+ * import {Updater} from 'https://cdn.jsdelivr.net/npm/@schukai/monster@1.28.0/dist/modules/dom/updater.js';
51
57
  * new Updater()
52
58
  * </script>
53
59
  * ```
54
60
  *
55
61
  * @example
56
62
  *
57
- * import {Updater} from 'https://cdn.jsdelivr.net/npm/@schukai/monster@1.25.0/dist/modules/dom/updater.js';
63
+ * import {Updater} from 'https://cdn.jsdelivr.net/npm/@schukai/monster@1.28.0/dist/modules/dom/updater.js';
58
64
  *
59
65
  * // First we prepare the html document.
60
66
  * // This is done here via script, but can also be inserted into the document as pure html.
@@ -68,7 +74,7 @@ import {getDocument} from "./util.js";
68
74
  * let obj = {
69
75
  * headline: "Hello World",
70
76
  * };
71
- *
77
+ *
72
78
  * // Now comes the real magic. we pass the updater the parent HTMLElement
73
79
  * // and the desired data structure.
74
80
  * const updater = new Updater(body, obj);
@@ -105,27 +111,27 @@ class Updater extends Base {
105
111
  /**
106
112
  * @type {HTMLElement}
107
113
  */
108
- this.element = validateInstance(element, HTMLElement);
109
-
110
114
  if (subject === undefined) subject = {}
111
- let a = subject;
112
115
  if (!isInstance(subject, ProxyObserver)) {
113
116
  subject = new ProxyObserver(subject);
114
117
  }
115
118
 
116
- this.last = {};
117
- this.callbacks = new Map();
118
- this.callbacks.set('checkstate', getCheckStateCallback.call(this));
119
+ this[internalSymbol] = {
120
+ element: validateInstance(element, HTMLElement),
121
+ last: {},
122
+ callbacks: new Map(),
123
+ eventTypes: ['keyup', 'click', 'change', 'drop', 'touchend', 'input'],
124
+ subject: subject
125
+ }
119
126
 
120
- /**
121
- * @type {object}
122
- */
123
- this.subject = subject.attachObserver(new Observer(() => {
127
+ this[internalSymbol].callbacks.set('checkstate', getCheckStateCallback.call(this));
128
+
129
+ this[internalSymbol].subject.attachObserver(new Observer(() => {
124
130
 
125
- const s = this.subject.getRealSubject();
131
+ const s = this[internalSymbol].subject.getRealSubject();
126
132
 
127
- const diffResult = diff(this.last, s)
128
- this.last = clone(s);
133
+ const diffResult = diff(this[internalSymbol].last, s)
134
+ this[internalSymbol].last = clone(s);
129
135
 
130
136
  for (const [, change] of Object.entries(diffResult)) {
131
137
  removeElement.call(this, change);
@@ -135,8 +141,6 @@ class Updater extends Base {
135
141
  }
136
142
  }));
137
143
 
138
- this.eventTypes = ['keyup', 'click', 'change', 'drop', 'touchend', 'input'];
139
-
140
144
  }
141
145
 
142
146
  /**
@@ -148,7 +152,7 @@ class Updater extends Base {
148
152
  * @return {Updater}
149
153
  */
150
154
  setEventTypes(types) {
151
- this.eventTypes = validateArray(types);
155
+ this[internalSymbol].eventTypes = validateArray(types);
152
156
  return this;
153
157
  }
154
158
 
@@ -163,12 +167,17 @@ class Updater extends Base {
163
167
  *
164
168
  * @since 1.9.0
165
169
  * @return {Updater}
170
+ * @throws {Error} the bind argument must start as a value with a path
166
171
  */
167
172
  enableEventProcessing() {
168
173
  this.disableEventProcessing();
169
174
 
170
- for (const type of this.eventTypes) {
171
- this.element.addEventListener(type, getControlEventHandler.call(this));
175
+ for (const type of this[internalSymbol].eventTypes) {
176
+ // @see https://developer.mozilla.org/en-US/docs/Web/API/EventTarget/addEventListener
177
+ this[internalSymbol].element.addEventListener(type, getControlEventHandler.call(this), {
178
+ capture: true,
179
+ passive: true
180
+ });
172
181
  }
173
182
 
174
183
  return this;
@@ -183,8 +192,8 @@ class Updater extends Base {
183
192
  */
184
193
  disableEventProcessing() {
185
194
 
186
- for (const type of this.eventTypes) {
187
- this.element.removeEventListener(type, getControlEventHandler.call(this));
195
+ for (const type of this[internalSymbol].eventTypes) {
196
+ this[internalSymbol].element.removeEventListener(type, getControlEventHandler.call(this));
188
197
  }
189
198
 
190
199
  return this;
@@ -207,8 +216,19 @@ class Updater extends Base {
207
216
  run() {
208
217
  // the key __init__has no further meaning and is only
209
218
  // used to create the diff for empty objects.
210
- this.last = {'__init__': true};
211
- return this.subject.notifyObservers();
219
+ this[internalSymbol].last = {'__init__': true};
220
+ return this[internalSymbol].subject.notifyObservers();
221
+ }
222
+
223
+ /**
224
+ * Gets the values of bound elements and changes them in subject
225
+ *
226
+ * @since 1.27.0
227
+ * @return {Monster.DOM.Updater}
228
+ */
229
+ retrieve() {
230
+ retrieveFromBindings.call(this);
231
+ return this;
212
232
  }
213
233
 
214
234
  /**
@@ -221,7 +241,7 @@ class Updater extends Base {
221
241
  * @return {Proxy}
222
242
  */
223
243
  getSubject() {
224
- return this.subject.getSubject();
244
+ return this[internalSymbol].subject.getSubject();
225
245
  }
226
246
 
227
247
  /**
@@ -235,7 +255,7 @@ class Updater extends Base {
235
255
  * @throws {TypeError} value is not a function
236
256
  */
237
257
  setCallback(name, callback) {
238
- this.callbacks.set(name, callback);
258
+ this[internalSymbol].callbacks.set(name, callback);
239
259
  return this;
240
260
  }
241
261
 
@@ -252,6 +272,7 @@ function getCheckStateCallback() {
252
272
 
253
273
  return function (current) {
254
274
 
275
+ // this is a reference to the current object (therefore no array function here)
255
276
  if (this instanceof HTMLInputElement) {
256
277
  if (['radio', 'checkbox'].indexOf(this.type) !== -1) {
257
278
  return (this.value + "" === current + "") ? 'true' : undefined
@@ -261,9 +282,8 @@ function getCheckStateCallback() {
261
282
  if (isArray(current) && current.indexOf(this.value) !== -1) {
262
283
  return 'true'
263
284
  }
264
- return undefined;
265
-
266
285
 
286
+ return undefined;
267
287
  }
268
288
  }
269
289
  }
@@ -277,6 +297,7 @@ const symbol = Symbol('EventHandler');
277
297
  * @private
278
298
  * @return {function}
279
299
  * @this Updater
300
+ * @throws {Error} the bind argument must start as a value with a path
280
301
  */
281
302
  function getControlEventHandler() {
282
303
 
@@ -286,83 +307,112 @@ function getControlEventHandler() {
286
307
  return self[symbol];
287
308
  }
288
309
 
289
- const pathfinder = new Pathfinder(this.subject.getSubject());
290
-
291
310
  /**
292
311
  * @throws {Error} the bind argument must start as a value with a path.
293
312
  * @throws {Error} unsupported object
294
313
  * @param {Event} event
295
314
  */
296
315
  self[symbol] = (event) => {
297
- const element = event.target;
316
+ const element = findTargetElementFromEvent(event, ATTRIBUTE_UPDATER_BIND);
298
317
 
299
- if (!element.hasAttribute(ATTRIBUTE_UPDATER_BIND)) {
318
+ if (element === undefined) {
300
319
  return;
301
320
  }
302
321
 
303
- let path = element.getAttribute(ATTRIBUTE_UPDATER_BIND);
322
+ retrieveAndSetValue.call(self, element);
304
323
 
305
- if (path.indexOf('path:') !== 0) {
306
- throw new Error('the bind argument must start as a value with a path.');
307
- }
324
+ }
308
325
 
309
- path = path.substr(5);
326
+ return self[symbol];
310
327
 
311
- let value;
312
328
 
313
- if (element instanceof HTMLInputElement) {
314
- switch (element.type) {
329
+ }
315
330
 
316
- case 'checkbox':
317
- value = element.checked ? element.value : undefined;
318
- break;
319
- default:
320
- value = element.value;
321
- break;
331
+ /**
332
+ * @throws {Error} the bind argument must start as a value with a path
333
+ * @param {HTMLElement} element
334
+ * @return void
335
+ */
336
+ function retrieveAndSetValue(element) {
322
337
 
338
+ const self = this;
323
339
 
324
- }
325
- } else if (element instanceof HTMLTextAreaElement) {
326
- value = element.value;
340
+ const pathfinder = new Pathfinder(self[internalSymbol].subject.getSubject());
327
341
 
328
- } else if (element instanceof HTMLSelectElement) {
342
+ let path = element.getAttribute(ATTRIBUTE_UPDATER_BIND);
329
343
 
330
- switch (element.type) {
331
- case 'select-one':
332
- value = element.value;
333
- break;
334
- case 'select-multiple':
335
- value = element.value;
344
+ if (path.indexOf('path:') !== 0) {
345
+ throw new Error('the bind argument must start as a value with a path');
346
+ }
336
347
 
337
- let options = element?.selectedOptions;
338
- if (options === undefined) options = element.querySelectorAll(":scope option:checked");
339
- value = Array.from(options).map(({value}) => value);
348
+ path = path.substr(5);
340
349
 
341
- break;
342
- }
350
+ let value;
351
+
352
+ if (element instanceof HTMLInputElement) {
353
+ switch (element.type) {
354
+
355
+ case 'checkbox':
356
+ value = element.checked ? element.value : undefined;
357
+ break;
358
+ default:
359
+ value = element.value;
360
+ break;
343
361
 
344
362
 
345
- // values from customelements
346
- } else if ((element?.constructor?.prototype && !!Object.getOwnPropertyDescriptor(element.constructor.prototype, 'value')?.['get']) || element.hasOwnProperty('value')) {
347
- value = element?.['value'];
348
- } else {
349
- throw new Error("unsupported object");
350
363
  }
364
+ } else if (element instanceof HTMLTextAreaElement) {
365
+ value = element.value;
366
+
367
+ } else if (element instanceof HTMLSelectElement) {
351
368
 
352
- const copy = clone(self.subject.getRealSubject());
353
- const pf = new Pathfinder(copy);
354
- pf.setVia(path, value);
369
+ switch (element.type) {
370
+ case 'select-one':
371
+ value = element.value;
372
+ break;
373
+ case 'select-multiple':
374
+ value = element.value;
355
375
 
356
- const diffResult = diff(copy, self.subject.getRealSubject());
376
+ let options = element?.selectedOptions;
377
+ if (options === undefined) options = element.querySelectorAll(":scope option:checked");
378
+ value = Array.from(options).map(({value}) => value);
357
379
 
358
- if (diffResult.length > 0) {
359
- pathfinder.setVia(path, value);
380
+ break;
360
381
  }
361
382
 
383
+
384
+ // values from customelements
385
+ } else if ((element?.constructor?.prototype && !!Object.getOwnPropertyDescriptor(element.constructor.prototype, 'value')?.['get']) || element.hasOwnProperty('value')) {
386
+ value = element?.['value'];
387
+ } else {
388
+ throw new Error("unsupported object");
362
389
  }
363
390
 
364
- return self[symbol];
391
+ const copy = clone(self[internalSymbol].subject.getRealSubject());
392
+ const pf = new Pathfinder(copy);
393
+ pf.setVia(path, value);
394
+
395
+ const diffResult = diff(copy, self[internalSymbol].subject.getRealSubject());
396
+
397
+ if (diffResult.length > 0) {
398
+ pathfinder.setVia(path, value);
399
+ }
400
+ }
401
+
402
+ /**
403
+ * @since 1.27.0
404
+ * @return void
405
+ */
406
+ function retrieveFromBindings() {
407
+ const self = this;
408
+
409
+ if (self[internalSymbol].element.matches('[' + ATTRIBUTE_UPDATER_BIND + ']')) {
410
+ retrieveAndSetValue.call(self, element)
411
+ }
365
412
 
413
+ for (const [, element] of self[internalSymbol].element.querySelectorAll('[' + ATTRIBUTE_UPDATER_BIND + ']').entries()) {
414
+ retrieveAndSetValue.call(self, element)
415
+ }
366
416
 
367
417
  }
368
418
 
@@ -373,7 +423,9 @@ function getControlEventHandler() {
373
423
  * @return {void}
374
424
  */
375
425
  function removeElement(change) {
376
- for (const [, element] of this.element.querySelectorAll(':scope [' + ATTRIBUTE_UPDATER_REMOVE + ']').entries()) {
426
+ const self = this;
427
+
428
+ for (const [, element] of self[internalSymbol].element.querySelectorAll(':scope [' + ATTRIBUTE_UPDATER_REMOVE + ']').entries()) {
377
429
  element.parentNode.removeChild(element);
378
430
  }
379
431
  }
@@ -391,7 +443,7 @@ function removeElement(change) {
391
443
  */
392
444
  function insertElement(change) {
393
445
  const self = this;
394
- const subject = self.subject.getRealSubject();
446
+ const subject = self[internalSymbol].subject.getRealSubject();
395
447
  const document = getDocument();
396
448
 
397
449
  let mem = new WeakSet;
@@ -407,7 +459,7 @@ function insertElement(change) {
407
459
 
408
460
  while (p.length > 0) {
409
461
  const current = p.join('.');
410
- const list = this.element.querySelectorAll(':scope [' + ATTRIBUTE_UPDATER_INSERT + '*="path:' + current + '"]').entries()
462
+ const list = this[internalSymbol].element.querySelectorAll(':scope [' + ATTRIBUTE_UPDATER_INSERT + '*="path:' + current + '"]').entries()
411
463
 
412
464
  for (const [, containerElement] of list) {
413
465
 
@@ -429,7 +481,7 @@ function insertElement(change) {
429
481
  }
430
482
 
431
483
  let pipe = new Pipe(cmd);
432
- this.callbacks.forEach((f, n) => {
484
+ this[internalSymbol].callbacks.forEach((f, n) => {
433
485
  pipe.setCallback(n, f);
434
486
  })
435
487
 
@@ -530,12 +582,12 @@ function applyRecursive(node, key, path) {
530
582
 
531
583
  if (node.hasAttribute(ATTRIBUTE_UPDATER_REPLACE)) {
532
584
  let value = node.getAttribute(ATTRIBUTE_UPDATER_REPLACE);
533
- node.setAttribute(ATTRIBUTE_UPDATER_REPLACE, value.replace("path:" + key, "path:" + path));
585
+ node.setAttribute(ATTRIBUTE_UPDATER_REPLACE, value.replaceAll("path:" + key, "path:" + path));
534
586
  }
535
587
 
536
588
  if (node.hasAttribute(ATTRIBUTE_UPDATER_ATTRIBUTES)) {
537
589
  let value = node.getAttribute(ATTRIBUTE_UPDATER_ATTRIBUTES);
538
- node.setAttribute(ATTRIBUTE_UPDATER_ATTRIBUTES, value.replace("path:" + key, "path:" + path));
590
+ node.setAttribute(ATTRIBUTE_UPDATER_ATTRIBUTES, value.replaceAll("path:" + key, "path:" + path));
539
591
  }
540
592
 
541
593
  for (const [, child] of Object.entries(node.childNodes)) {
@@ -553,12 +605,12 @@ function applyRecursive(node, key, path) {
553
605
  */
554
606
  function updateContent(change) {
555
607
  const self = this;
556
- const subject = self.subject.getRealSubject();
608
+ const subject = self[internalSymbol].subject.getRealSubject();
557
609
 
558
610
  let p = clone(change?.['path']);
559
- runUpdateContent.call(this, this.element, p, subject);
611
+ runUpdateContent.call(this, this[internalSymbol].element, p, subject);
560
612
 
561
- const slots = this.element.querySelectorAll('slot');
613
+ const slots = this[internalSymbol].element.querySelectorAll('slot');
562
614
  if (slots.length > 0) {
563
615
  for (const [, slot] of Object.entries(slots)) {
564
616
  for (const [, element] of Object.entries(slot.assignedNodes())) {
@@ -610,7 +662,7 @@ function runUpdateContent(container, parts, subject) {
610
662
  let cmd = trimSpaces(attributes);
611
663
 
612
664
  let pipe = new Pipe(cmd);
613
- this.callbacks.forEach((f, n) => {
665
+ this[internalSymbol].callbacks.forEach((f, n) => {
614
666
  pipe.setCallback(n, f);
615
667
  })
616
668
 
@@ -646,9 +698,9 @@ function runUpdateContent(container, parts, subject) {
646
698
  * @return {void}
647
699
  */
648
700
  function updateAttributes(change) {
649
- const subject = this.subject.getRealSubject();
701
+ const subject = this[internalSymbol].subject.getRealSubject();
650
702
  let p = clone(change?.['path']);
651
- runUpdateAttributes.call(this, this.element, p, subject);
703
+ runUpdateAttributes.call(this, this[internalSymbol].element, p, subject);
652
704
  }
653
705
 
654
706
  /**
@@ -674,7 +726,8 @@ function runUpdateAttributes(container, parts, subject) {
674
726
 
675
727
  let iterator = new Set;
676
728
 
677
- const query = '[' + ATTRIBUTE_UPDATER_ATTRIBUTES + '*="path:' + current + '"], [' + ATTRIBUTE_UPDATER_ATTRIBUTES + '^="static:"]';
729
+ const query = '[' + ATTRIBUTE_UPDATER_SELECT_THIS + '], [' + ATTRIBUTE_UPDATER_ATTRIBUTES + '*="path:' + current + '"], [' + ATTRIBUTE_UPDATER_ATTRIBUTES + '^="static:"]';
730
+
678
731
  const e = container.querySelectorAll(query);
679
732
 
680
733
  if (e.length > 0) {
@@ -702,7 +755,7 @@ function runUpdateAttributes(container, parts, subject) {
702
755
 
703
756
  let pipe = new Pipe(cmd);
704
757
 
705
- self.callbacks.forEach((f, n) => {
758
+ self[internalSymbol].callbacks.forEach((f, n) => {
706
759
  pipe.setCallback(n, f, element);
707
760
  })
708
761
 
@@ -776,19 +829,26 @@ function handleInputControlAttributeUpdate(element, name, value) {
776
829
  switch (element.type) {
777
830
 
778
831
  case 'radio':
779
- if (name === 'checked' && value !== undefined) {
780
- element.checked = true;
781
- } else {
782
- element.checked = false;
832
+ if (name === 'checked') {
833
+
834
+ if (value !== undefined) {
835
+ element.checked = true;
836
+ } else {
837
+ element.checked = false;
838
+ }
783
839
  }
784
840
 
785
841
  break;
786
842
 
787
843
  case 'checkbox':
788
- if (name === 'checked' && value !== undefined) {
789
- element.checked = true;
790
- } else {
791
- element.checked = false;
844
+
845
+ if (name === 'checked') {
846
+
847
+ if (value !== undefined) {
848
+ element.checked = true;
849
+ } else {
850
+ element.checked = false;
851
+ }
792
852
  }
793
853
 
794
854
  break;
@@ -13,7 +13,7 @@ import {validateString} from "../types/validate.js";
13
13
  *
14
14
  * ```
15
15
  * <script type="module">
16
- * import {Monster} from 'https://cdn.jsdelivr.net/npm/@schukai/monster@1.25.0/dist/modules/dom/util.js';
16
+ * import {Monster} from 'https://cdn.jsdelivr.net/npm/@schukai/monster@1.28.0/dist/monster.js';
17
17
  * console.log(Monster.DOM.getDocument())
18
18
  * </script>
19
19
  * ```
@@ -22,7 +22,7 @@ import {validateString} from "../types/validate.js";
22
22
  *
23
23
  * ```
24
24
  * <script type="module">
25
- * import {getDocument} from 'https://cdn.jsdelivr.net/npm/@schukai/monster@1.25.0/dist/modules/dom/util.js';
25
+ * import {getDocument} from 'https://cdn.jsdelivr.net/npm/@schukai/monster@1.28.0/dist/modules/dom/util.js';
26
26
  * console.log(getDocument())
27
27
  * </script>
28
28
  * ```
@@ -74,7 +74,7 @@ function getDocument() {
74
74
  *
75
75
  * ```
76
76
  * <script type="module">
77
- * import {Monster} from 'https://cdn.jsdelivr.net/npm/@schukai/monster@1.25.0/dist/modules/dom/util.js';
77
+ * import {Monster} from 'https://cdn.jsdelivr.net/npm/@schukai/monster@1.28.0/dist/monster.js';
78
78
  * console.log(Monster.DOM.getWindow())
79
79
  * </script>
80
80
  * ```
@@ -83,7 +83,7 @@ function getDocument() {
83
83
  *
84
84
  * ```
85
85
  * <script type="module">
86
- * import {getWindow} from 'https://cdn.jsdelivr.net/npm/@schukai/monster@1.25.0/dist/modules/dom/util.js';
86
+ * import {getWindow} from 'https://cdn.jsdelivr.net/npm/@schukai/monster@1.28.0/dist/modules/dom/util.js';
87
87
  * console.log(getWindow(null))
88
88
  * </script>
89
89
  * ```
@@ -140,7 +140,7 @@ function getWindow() {
140
140
  *
141
141
  * ```
142
142
  * <script type="module">
143
- * import {Monster} from 'https://cdn.jsdelivr.net/npm/@schukai/monster@1.25.0/dist/modules/dom/util.js';
143
+ * import {Monster} from 'https://cdn.jsdelivr.net/npm/@schukai/monster@1.28.0/dist/monster.js';
144
144
  * console.log(Monster.DOM.getDocumentFragmentFromString())
145
145
  * </script>
146
146
  * ```
@@ -149,7 +149,7 @@ function getWindow() {
149
149
  *
150
150
  * ```
151
151
  * <script type="module">
152
- * import {getDocumentFragmentFromString} from 'https://cdn.jsdelivr.net/npm/@schukai/monster@1.25.0/dist/modules/dom/util.js';
152
+ * import {getDocumentFragmentFromString} from 'https://cdn.jsdelivr.net/npm/@schukai/monster@1.28.0/dist/modules/dom/util.js';
153
153
  * console.log(getDocumentFragmentFromString('<div></div>'))
154
154
  * </script>
155
155
  * ```
@@ -20,7 +20,7 @@ import {validateInstance, validateString} from "../../types/validate.js";
20
20
  *
21
21
  * ```
22
22
  * <script type="module">
23
- * import {Monster} from 'https://cdn.jsdelivr.net/npm/@schukai/monster@1.25.0/dist/modules/dom/worker/factory.js';
23
+ * import {Monster} from 'https://cdn.jsdelivr.net/npm/@schukai/monster@1.28.0/dist/monster.js';
24
24
  * console.log(new Monster.DOM.Worker.Factory())
25
25
  * </script>
26
26
  * ```
@@ -29,7 +29,7 @@ import {validateInstance, validateString} from "../../types/validate.js";
29
29
  *
30
30
  * ```
31
31
  * <script type="module">
32
- * import {Factory} from 'https://cdn.jsdelivr.net/npm/@schukai/monster@1.25.0/dist/modules/dom/worker/factory.js';
32
+ * import {Factory} from 'https://cdn.jsdelivr.net/npm/@schukai/monster@1.28.0/dist/modules/dom/worker/factory.js';
33
33
  * console.log(new Factory())
34
34
  * </script>
35
35
  * ```