@schukai/monster 1.13.0 → 1.15.2

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 (155) hide show
  1. package/CHANGELOG +46 -1
  2. package/README.md +5 -5
  3. package/dist/modules/constants.js +2 -2
  4. package/dist/modules/constraints/abstract.js +2 -2
  5. package/dist/modules/constraints/abstractoperator.js +2 -2
  6. package/dist/modules/constraints/andoperator.js +2 -2
  7. package/dist/modules/constraints/invalid.js +2 -2
  8. package/dist/modules/constraints/isarray.js +2 -2
  9. package/dist/modules/constraints/isobject.js +2 -2
  10. package/dist/modules/constraints/namespace.js +1 -1
  11. package/dist/modules/constraints/oroperator.js +2 -2
  12. package/dist/modules/constraints/valid.js +2 -2
  13. package/dist/modules/data/buildmap.js +2 -2
  14. package/dist/modules/data/diff.js +2 -2
  15. package/dist/modules/data/extend.js +2 -2
  16. package/dist/modules/data/namespace.js +1 -1
  17. package/dist/modules/data/pathfinder.js +2 -2
  18. package/dist/modules/data/pipe.js +2 -2
  19. package/dist/modules/data/transformer.js +2 -2
  20. package/dist/modules/dom/assembler.js +2 -2
  21. package/dist/modules/dom/attributes.js +2 -2
  22. package/dist/modules/dom/constants.js +2 -2
  23. package/dist/modules/dom/customcontrol.js +2 -0
  24. package/dist/modules/dom/customelement.js +2 -2
  25. package/dist/modules/dom/events.js +2 -2
  26. package/dist/modules/dom/locale.js +2 -2
  27. package/dist/modules/dom/namespace.js +1 -1
  28. package/dist/modules/dom/template.js +2 -2
  29. package/dist/modules/dom/theme.js +2 -2
  30. package/dist/modules/dom/updater.js +2 -2
  31. package/dist/modules/dom/util.js +2 -2
  32. package/dist/modules/i18n/locale.js +2 -2
  33. package/dist/modules/i18n/namespace.js +1 -1
  34. package/dist/modules/i18n/provider.js +2 -2
  35. package/dist/modules/i18n/providers/fetch.js +2 -2
  36. package/dist/modules/i18n/providers/namespace.js +1 -1
  37. package/dist/modules/i18n/translations.js +2 -2
  38. package/dist/modules/logging/handler/console.js +2 -2
  39. package/dist/modules/logging/handler/namespace.js +1 -1
  40. package/dist/modules/logging/handler.js +2 -2
  41. package/dist/modules/logging/logentry.js +2 -2
  42. package/dist/modules/logging/logger.js +2 -2
  43. package/dist/modules/logging/namespace.js +1 -1
  44. package/dist/modules/math/namespace.js +1 -1
  45. package/dist/modules/math/random.js +2 -2
  46. package/dist/modules/monster.js +2 -2
  47. package/dist/modules/namespace.js +2 -2
  48. package/dist/modules/text/formatter.js +2 -2
  49. package/dist/modules/text/namespace.js +1 -1
  50. package/dist/modules/types/base.js +2 -2
  51. package/dist/modules/types/basewithoptions.js +2 -2
  52. package/dist/modules/types/global.js +2 -2
  53. package/dist/modules/types/id.js +2 -2
  54. package/dist/modules/types/is.js +2 -2
  55. package/dist/modules/types/namespace.js +1 -1
  56. package/dist/modules/types/observer.js +2 -2
  57. package/dist/modules/types/observerlist.js +2 -2
  58. package/dist/modules/types/proxyobserver.js +2 -2
  59. package/dist/modules/types/queue.js +2 -2
  60. package/dist/modules/types/randomid.js +2 -2
  61. package/dist/modules/types/stack.js +2 -2
  62. package/dist/modules/types/tokenlist.js +2 -2
  63. package/dist/modules/types/typeof.js +2 -2
  64. package/dist/modules/types/uniquequeue.js +2 -2
  65. package/dist/modules/types/validate.js +2 -2
  66. package/dist/modules/types/version.js +2 -2
  67. package/dist/modules/util/clone.js +2 -2
  68. package/dist/modules/util/comparator.js +2 -2
  69. package/dist/modules/util/freeze.js +2 -2
  70. package/dist/modules/util/namespace.js +1 -1
  71. package/dist/monster.dev.js +8622 -7709
  72. package/dist/monster.dev.js.map +1 -1
  73. package/dist/monster.js +2 -9
  74. package/package.json +1 -1
  75. package/source/constants.js +7 -6
  76. package/source/constraints/abstract.js +2 -2
  77. package/source/constraints/abstractoperator.js +4 -4
  78. package/source/constraints/andoperator.js +8 -8
  79. package/source/constraints/invalid.js +6 -6
  80. package/source/constraints/isarray.js +7 -7
  81. package/source/constraints/isobject.js +7 -7
  82. package/source/constraints/namespace.js +2 -2
  83. package/source/constraints/oroperator.js +8 -8
  84. package/source/constraints/valid.js +7 -7
  85. package/source/data/buildmap.js +15 -15
  86. package/source/data/diff.js +9 -9
  87. package/source/data/extend.js +55 -13
  88. package/source/data/namespace.js +2 -2
  89. package/source/data/pathfinder.js +13 -14
  90. package/source/data/pipe.js +8 -8
  91. package/source/data/transformer.js +11 -11
  92. package/source/dom/assembler.js +7 -7
  93. package/source/dom/attributes.js +89 -46
  94. package/source/dom/constants.js +9 -2
  95. package/source/dom/customcontrol.js +299 -0
  96. package/source/dom/customelement.js +181 -66
  97. package/source/dom/events.js +58 -8
  98. package/source/dom/locale.js +5 -5
  99. package/source/dom/namespace.js +2 -2
  100. package/source/dom/template.js +24 -19
  101. package/source/dom/theme.js +8 -9
  102. package/source/dom/updater.js +46 -24
  103. package/source/dom/util.js +10 -10
  104. package/source/i18n/locale.js +7 -7
  105. package/source/i18n/namespace.js +1 -1
  106. package/source/i18n/provider.js +6 -6
  107. package/source/i18n/providers/fetch.js +10 -10
  108. package/source/i18n/translations.js +5 -5
  109. package/source/logging/handler/console.js +5 -5
  110. package/source/logging/handler/namespace.js +1 -1
  111. package/source/logging/handler.js +8 -8
  112. package/source/logging/logentry.js +5 -5
  113. package/source/logging/logger.js +5 -5
  114. package/source/logging/namespace.js +2 -2
  115. package/source/math/namespace.js +2 -2
  116. package/source/math/random.js +5 -5
  117. package/source/monster.js +48 -44
  118. package/source/namespace.js +2 -2
  119. package/source/text/formatter.js +6 -7
  120. package/source/text/namespace.js +1 -1
  121. package/source/types/base.js +4 -5
  122. package/source/types/basewithoptions.js +10 -9
  123. package/source/types/global.js +7 -7
  124. package/source/types/id.js +7 -7
  125. package/source/types/is.js +22 -22
  126. package/source/types/namespace.js +2 -2
  127. package/source/types/observer.js +7 -7
  128. package/source/types/observerlist.js +4 -4
  129. package/source/types/proxyobserver.js +32 -26
  130. package/source/types/queue.js +13 -7
  131. package/source/types/randomid.js +6 -6
  132. package/source/types/stack.js +11 -4
  133. package/source/types/tokenlist.js +9 -9
  134. package/source/types/typeof.js +5 -5
  135. package/source/types/uniquequeue.js +14 -7
  136. package/source/types/validate.js +27 -27
  137. package/source/types/version.js +9 -9
  138. package/source/util/clone.js +6 -6
  139. package/source/util/comparator.js +7 -7
  140. package/source/util/freeze.js +7 -7
  141. package/source/util/namespace.js +2 -2
  142. package/test/cases/data/extend.js +66 -13
  143. package/test/cases/dom/attributes.js +56 -1
  144. package/test/cases/dom/customcontrol.js +264 -0
  145. package/test/cases/dom/customelement.js +112 -51
  146. package/test/cases/dom/events.js +32 -14
  147. package/test/cases/dom/template.js +40 -1
  148. package/test/cases/monster.js +1 -1
  149. package/test/cases/types/proxyobserver.js +9 -0
  150. package/test/util/jsdom.js +3 -0
  151. package/test/web/import.js +1 -0
  152. package/test/web/monster-dev.html +3 -3
  153. package/test/web/monster.html +2 -2
  154. package/test/web/test.html +3 -3
  155. package/test/web/tests.js +3 -3
@@ -0,0 +1,299 @@
1
+ 'use strict';
2
+
3
+ import {extend} from "../data/extend.js";
4
+ /**
5
+ * @author schukai GmbH
6
+ */
7
+ import {assignToNamespace, Monster} from '../namespace.js';
8
+ import {CustomElement} from "./customelement.js";
9
+
10
+
11
+ /**
12
+ * @private
13
+ * @type {symbol}
14
+ */
15
+ const internalSymbol = Symbol('internalSymbol');
16
+
17
+ /**
18
+ * To define a new HTML control we need the power of CustomElement
19
+ *
20
+ * IMPORTANT: after defining a `CustomElement`, the `registerCustomElement` method must be called
21
+ * with the new class name. only then will the tag defined via the `getTag` method be made known to the DOM.
22
+ *
23
+ * This control uses `attachInternals()` to integrate the control into a form.
24
+ * If the target environment does not support this method, the [polyfill](https://www.npmjs.com/package/element-internals-polyfill ) can be used.
25
+ *
26
+ * You can create the object via the monster namespace `new Monster.DOM.CustomControl()`.
27
+ *
28
+ * ```
29
+ * <script type="module">
30
+ * import {Monster} from 'https://cdn.jsdelivr.net/npm/@schukai/monster@1.15.2/dist/modules/dom/customcontrol.js';
31
+ * console.log(new Monster.DOM.CustomControl())
32
+ * </script>
33
+ * ```
34
+ *
35
+ * Alternatively, you can also integrate this function individually.
36
+ *
37
+ * ```
38
+ * <script type="module">
39
+ * import {CustomControl} from 'https://cdn.jsdelivr.net/npm/@schukai/monster@1.15.2/dist/modules/dom/customcontrol.js';
40
+ * console.log(new CustomControl())
41
+ * </script>
42
+ * ```
43
+ *
44
+ * @see https://www.npmjs.com/package/element-internals-polyfill
45
+ * @see https://github.com/WICG/webcomponents
46
+ * @see https://html.spec.whatwg.org/multipage/custom-elements.html#custom-elements
47
+ * @since 1.14.0
48
+ * @copyright schukai GmbH
49
+ * @memberOf Monster/DOM
50
+ */
51
+ class CustomControl extends CustomElement {
52
+
53
+ /**
54
+ *
55
+ * @throws {Error} the ElementInternals is not supported and a polyfill is necessary
56
+ */
57
+ constructor() {
58
+ super();
59
+
60
+ if (typeof this['attachInternals'] === 'function') {
61
+ // currently only supported by chrome
62
+ this[internalSymbol] = this.attachInternals();
63
+ }
64
+
65
+ }
66
+
67
+ /**
68
+ *
69
+ * @see https://developer.mozilla.org/en-US/docs/Web/API/HTMLElement/attachInternals
70
+ * @since 1.14.0
71
+ * @return {boolean}
72
+ */
73
+ static get formAssociated() {
74
+ return true;
75
+ }
76
+
77
+ /**
78
+ * | option | description |
79
+ * |----------------|---------------------------------|
80
+ * | | |
81
+ *
82
+ * Derived classes can override and extend this method as follows.
83
+ *
84
+ * ```
85
+ * get defaults() {
86
+ * return extends{}, super.defaults, {
87
+ * myValue:true
88
+ * });
89
+ * }
90
+ * ```
91
+ *
92
+ * @see https://html.spec.whatwg.org/multipage/custom-elements.html#custom-elements-face-example
93
+ * @see https://developer.mozilla.org/en-US/docs/Web/API/HTMLElement/attachInternals
94
+ * @return {object}
95
+ * @since 1.14.0
96
+ */
97
+ get defaults() {
98
+ return extend({}, super.defaults);
99
+ }
100
+
101
+ /**
102
+ * Must be overridden by a derived class and return the value of the control.
103
+ *
104
+ * This is a method of [internal api](https://developer.mozilla.org/en-US/docs/Web/API/ElementInternals)
105
+ *
106
+ * @since 1.14.0
107
+ * @throws {Error} the value getter must be overwritten by the derived class
108
+ */
109
+ get value() {
110
+ throw Error('the value getter must be overwritten by the derived class');
111
+ }
112
+
113
+ /**
114
+ * Must be overridden by a derived class and return the value of the control.
115
+ *
116
+ * This is a method of [internal api](https://developer.mozilla.org/en-US/docs/Web/API/ElementInternals)
117
+ *
118
+ * @param {*} value
119
+ * @since 1.14.0
120
+ * @throws {Error} the value setter must be overwritten by the derived class
121
+ */
122
+ set value(value) {
123
+ throw Error('the value setter must be overwritten by the derived class');
124
+ }
125
+
126
+ /**
127
+ * This is a method of [internal api](https://developer.mozilla.org/en-US/docs/Web/API/ElementInternals)
128
+ *
129
+ * @return {NodeList}
130
+ * @since 1.14.0
131
+ * @see https://developer.mozilla.org/en-US/docs/Web/API/ElementInternals/labels
132
+ * @throws {Error} the ElementInternals is not supported and a polyfill is necessary
133
+ */
134
+ get labels() {
135
+ return getInternal.call(this)?.labels;
136
+ }
137
+
138
+ /**
139
+ * This is a method of [internal api](https://developer.mozilla.org/en-US/docs/Web/API/ElementInternals)
140
+ *
141
+ * @return {string|null}
142
+ */
143
+ get name() {
144
+ return this.getAttribute('name');
145
+ }
146
+
147
+ /**
148
+ * This is a method of [internal api](https://developer.mozilla.org/en-US/docs/Web/API/ElementInternals)
149
+ *
150
+ * @return {string}
151
+ */
152
+ get type() {
153
+ return this.constructor.getTag();
154
+ }
155
+
156
+ /**
157
+ * This is a method of [internal api](https://developer.mozilla.org/en-US/docs/Web/API/ElementInternals)
158
+ *
159
+ * @return {ValidityState}
160
+ * @throws {Error} the ElementInternals is not supported and a polyfill is necessary
161
+ * @see https://developer.mozilla.org/en-US/docs/Web/API/ValidityState
162
+ * @see https://developer.mozilla.org/en-US/docs/Web/API/validity
163
+ */
164
+ get validity() {
165
+ return getInternal.call(this)?.validity;
166
+ }
167
+
168
+ /**
169
+ * This is a method of [internal api](https://developer.mozilla.org/en-US/docs/Web/API/ElementInternals)
170
+ *
171
+ * @return {string}
172
+ * @since 1.14.0
173
+ * @see https://developer.mozilla.org/en-US/docs/Web/API/ElementInternals/validationMessage
174
+ * @throws {Error} the ElementInternals is not supported and a polyfill is necessary
175
+ */
176
+ get validationMessage() {
177
+ return getInternal.call(this)?.validationMessage;
178
+ }
179
+
180
+ /**
181
+ * This is a method of [internal api](https://developer.mozilla.org/en-US/docs/Web/API/ElementInternals)
182
+ *
183
+ * @return {boolean}
184
+ * @since 1.14.0
185
+ * @see https://developer.mozilla.org/en-US/docs/Web/API/ElementInternals/willValidate
186
+ * @throws {Error} the ElementInternals is not supported and a polyfill is necessary
187
+ */
188
+ get willValidate() {
189
+ return getInternal.call(this)?.willValidate;
190
+ }
191
+
192
+ /**
193
+ * This is a method of [internal api](https://developer.mozilla.org/en-US/docs/Web/API/ElementInternals)
194
+ *
195
+ * @return {CustomStateSet}
196
+ * @since 1.14.0
197
+ * @see https://developer.mozilla.org/en-US/docs/Web/API/ElementInternals/states
198
+ * @throws {Error} the ElementInternals is not supported and a polyfill is necessary
199
+ */
200
+ get states() {
201
+ return getInternal.call(this)?.states;
202
+ }
203
+
204
+ /**
205
+ * This is a method of [internal api](https://developer.mozilla.org/en-US/docs/Web/API/ElementInternals)
206
+ *
207
+ * @return {HTMLFontElement|null}
208
+ * @since 1.14.0
209
+ * @see https://developer.mozilla.org/en-US/docs/Web/API/ElementInternals/form
210
+ * @throws {Error} the ElementInternals is not supported and a polyfill is necessary
211
+ */
212
+ get form() {
213
+ return getInternal.call(this)?.form;
214
+ }
215
+
216
+ /**
217
+ * This is a method of [internal api](https://developer.mozilla.org/en-US/docs/Web/API/ElementInternals)
218
+ *
219
+ * ```
220
+ * // Use the control's name as the base name for submitted data
221
+ * const n = this.getAttribute('name');
222
+ * const entries = new FormData();
223
+ * entries.append(n + '-first-name', this.firstName_);
224
+ * entries.append(n + '-last-name', this.lastName_);
225
+ * this.setFormValue(entries);
226
+ * ```
227
+ *
228
+ * @param {File|string|FormData} value
229
+ * @param {File|string|FormData} state
230
+ * @since 1.14.0
231
+ * @return {undefined}
232
+ * @throws {DOMException} NotSupportedError
233
+ * @throws {Error} the ElementInternals is not supported and a polyfill is necessary
234
+ * @see https://developer.mozilla.org/en-US/docs/Web/API/ElementInternals/setFormValue
235
+ */
236
+ setFormValue(value, state) {
237
+ getInternal.call(this).setFormValue(value, state);
238
+ }
239
+
240
+ /**
241
+ *
242
+ * @param {object} flags
243
+ * @param {string|undefined} message
244
+ * @param {HTMLElement} anchor
245
+ * @see https://developer.mozilla.org/en-US/docs/Web/API/ElementInternals/setValidity
246
+ * @since 1.14.0
247
+ * @return {undefined}
248
+ * @throws {DOMException} NotSupportedError
249
+ * @throws {Error} the ElementInternals is not supported and a polyfill is necessary
250
+ */
251
+ setValidity(flags, message, anchor) {
252
+ getInternal.call(this).setValidity(flags, message, anchor);
253
+ }
254
+
255
+ /**
256
+ * This is a method of [internal api](https://developer.mozilla.org/en-US/docs/Web/API/ElementInternals)
257
+ *
258
+ * @see https://developer.mozilla.org/en-US/docs/Web/API/ElementInternals/checkValidity
259
+ * @since 1.14.0
260
+ * @return {boolean}
261
+ * @throws {DOMException} NotSupportedError
262
+ * @throws {Error} the ElementInternals is not supported and a polyfill is necessary
263
+ */
264
+ checkValidity() {
265
+ return getInternal.call(this)?.checkValidity();
266
+ }
267
+
268
+ /**
269
+ * This is a method of [internal api](https://developer.mozilla.org/en-US/docs/Web/API/ElementInternals)
270
+ *
271
+ * @return {boolean}
272
+ * @since 1.14.0
273
+ * @see https://developer.mozilla.org/en-US/docs/Web/API/ElementInternals/reportValidity
274
+ * @throws {Error} the ElementInternals is not supported and a polyfill is necessary
275
+ * @throws {DOMException} NotSupportedError
276
+ */
277
+ reportValidity() {
278
+ return getInternal.call(this)?.reportValidity();
279
+ }
280
+
281
+ }
282
+
283
+ /**
284
+ * @private
285
+ * @return {object}
286
+ * @throws {Error} the ElementInternals is not supported and a polyfill is necessary
287
+ */
288
+ function getInternal() {
289
+ const self = this;
290
+
291
+ if (!(internalSymbol in this)) {
292
+ throw new Error('ElementInternals is not supported and a polyfill is necessary');
293
+ }
294
+
295
+ return this[internalSymbol];
296
+ }
297
+
298
+ assignToNamespace('Monster.DOM', CustomControl);
299
+ export {Monster, CustomControl}
@@ -1,26 +1,28 @@
1
1
  'use strict';
2
2
 
3
+ import {PROPERTY_KEY_INTERNALDATA} from "../constants.js";
4
+ import {extend} from "../data/extend.js";
5
+ import {Pathfinder} from "../data/pathfinder.js";
3
6
  /**
4
7
  * @author schukai GmbH
5
8
  */
6
-
7
- import {Monster, Updater} from "./updater.js";
8
- import {extend} from "../data/extend.js";
9
- import {Pathfinder} from "../data/pathfinder.js";
10
- import {ATTRIBUTE_OPTIONS, OBJECTLINK_KEY_UPDATER} from "./constants.js";
11
- import {findDocumentTemplate, Template} from "./template.js";
12
- import {addToObjectLink, hasObjectLink} from "./attributes.js";
9
+ import {assignToNamespace, Monster} from '../namespace.js';
13
10
  import {getGlobalObject} from "../types/global.js";
14
- import {validateFunction, validateObject} from "../types/validate.js";
15
11
  import {isString} from "../types/is.js";
16
- import {getDocument} from "./util.js";
17
- import {PROPERTY_KEY_OPTIONS} from "../constants.js";
12
+ import {Observer} from "../types/observer.js";
13
+ import {ProxyObserver} from "../types/proxyobserver.js";
14
+ import {validateFunction, validateObject} from "../types/validate.js";
15
+ import {clone} from "../util/clone.js";
16
+ import {addToObjectLink, getLinkedObjects, hasObjectLink} from "./attributes.js";
17
+ import {ATTRIBUTE_OPTIONS, OBJECTLINK_KEY_UPDATER} from "./constants.js";
18
+ import {findDocumentTemplate, Template} from "./template.js";
19
+ import {Updater} from "./updater.js";
18
20
 
19
21
  /**
20
22
  * @private
21
23
  * @type {symbol}
22
24
  */
23
- const optionsSymbol = Symbol.for(PROPERTY_KEY_OPTIONS);
25
+ const internalDataSymbol = Symbol.for(PROPERTY_KEY_INTERNALDATA);
24
26
 
25
27
  /**
26
28
  * @private
@@ -38,12 +40,6 @@ const initMethodSymbol = Symbol('initMethodSymbol');
38
40
  */
39
41
  const assembleMethodSymbol = Symbol('assembleMethodSymbol');
40
42
 
41
- /**
42
- * @private
43
- * @type {Document}
44
- */
45
- const document = getDocument();
46
-
47
43
  /**
48
44
  * To define a new HTML element we need the power of CustomElement
49
45
  *
@@ -54,7 +50,7 @@ const document = getDocument();
54
50
  *
55
51
  * ```
56
52
  * <script type="module">
57
- * import {CustomElement} from 'https://cdn.jsdelivr.net/npm/@schukai/monster@1.13.0/dist/modules/dom/customelement.js';
53
+ * import {CustomElement} from 'https://cdn.jsdelivr.net/npm/@schukai/monster@1.15.2/dist/modules/dom/customelement.js';
58
54
  * console.log(new Monster.DOM.CustomElement())
59
55
  * </script>
60
56
  * ```
@@ -63,7 +59,7 @@ const document = getDocument();
63
59
  *
64
60
  * ```
65
61
  * <script type="module">
66
- * import {CustomElement} from 'https://cdn.jsdelivr.net/npm/@schukai/monster@1.13.0/dist/modules/dom/customelement.js';
62
+ * import {CustomElement} from 'https://cdn.jsdelivr.net/npm/@schukai/monster@1.15.2/dist/modules/dom/customelement.js';
67
63
  * console.log(new CustomElement())
68
64
  * </script>
69
65
  * ```
@@ -161,10 +157,21 @@ class CustomElement extends HTMLElement {
161
157
  */
162
158
  constructor() {
163
159
  super();
164
- this[optionsSymbol] = extend({}, this.defaults, getOptionsFromAttributes.call(this));
160
+ this[internalDataSymbol] = new ProxyObserver({'options': extend({}, this.defaults, getOptionsFromAttributes.call(this))});
161
+ initOptionObserver.call(this);
165
162
  this[initMethodSymbol]();
166
163
  }
167
164
 
165
+ /**
166
+ * This method determines which attributes are to be monitored by `attributeChangedCallback()`.
167
+ *
168
+ * @return {string[]}
169
+ * @since 1.15.0
170
+ */
171
+ static get observedAttributes() {
172
+ return [ATTRIBUTE_OPTIONS];
173
+ }
174
+
168
175
  /**
169
176
  * | option | description |
170
177
  * |----------------|----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
@@ -196,6 +203,75 @@ class CustomElement extends HTMLElement {
196
203
  };
197
204
  }
198
205
 
206
+ /**
207
+ * There is no check on the name by this class. the developer is responsible for assigning an appropriate tag.
208
+ * if the name is not valid, registerCustomElement() will issue an error
209
+ *
210
+ * @link https://html.spec.whatwg.org/multipage/custom-elements.html#valid-custom-element-name
211
+ * @return {string}
212
+ * @throws {Error} the method getTag must be overwritten by the derived class.
213
+ * @since 1.7.0
214
+ */
215
+ static getTag() {
216
+ throw new Error("the method getTag must be overwritten by the derived class.");
217
+ }
218
+
219
+ /**
220
+ * At this point a `CSSStyleSheet` object can be returned. If the environment does not
221
+ * support a constructor, then an object can also be built using the following detour.
222
+ *
223
+ * If `undefined` is returned then the shadowRoot does not get a stylesheet.
224
+ *
225
+ * ```
226
+ * const doc = document.implementation.createHTMLDocument('title');
227
+ *
228
+ * let style = doc.createElement("style");
229
+ * style.innerHTML="p{color:red;}";
230
+ *
231
+ * // WebKit Hack
232
+ * style.appendChild(document.createTextNode(""));
233
+ * // Add the <style> element to the page
234
+ * doc.head.appendChild(style);
235
+ * return doc.styleSheets[0];
236
+ * ;
237
+ * ```
238
+ *
239
+ * @return {CSSStyleSheet|undefined}
240
+ */
241
+ static getCSSStyleSheet() {
242
+ return undefined;
243
+ }
244
+
245
+ /**
246
+ * attach a new observer
247
+ *
248
+ * @param {Observer} observer
249
+ * @returns {CustomElement}
250
+ */
251
+ attachObserver(observer) {
252
+ this[internalDataSymbol].attachObserver(observer)
253
+ return this;
254
+ }
255
+
256
+ /**
257
+ * detach a observer
258
+ *
259
+ * @param {Observer} observer
260
+ * @returns {CustomElement}
261
+ */
262
+ detachObserver(observer) {
263
+ this[internalDataSymbol].detachObserver(observer)
264
+ return this;
265
+ }
266
+
267
+ /**
268
+ * @param {Observer} observer
269
+ * @returns {ProxyObserver}
270
+ */
271
+ containsObserver(observer) {
272
+ return this[internalDataSymbol].containsObserver(observer)
273
+ }
274
+
199
275
  /**
200
276
  * nested options can be specified by path `a.b.c`
201
277
  *
@@ -208,7 +284,7 @@ class CustomElement extends HTMLElement {
208
284
  let value;
209
285
 
210
286
  try {
211
- value = new Pathfinder(this[optionsSymbol]).getVia(path);
287
+ value = new Pathfinder(this[internalDataSymbol].getRealSubject()['options']).getVia(path);
212
288
  } catch (e) {
213
289
 
214
290
  }
@@ -217,6 +293,38 @@ class CustomElement extends HTMLElement {
217
293
  return value;
218
294
  }
219
295
 
296
+ /**
297
+ * Set option and inform elements
298
+ *
299
+ * @param {string} path
300
+ * @param {*} value
301
+ * @return {CustomElement}
302
+ * @since 1.14.0
303
+ */
304
+ setOption(path, value) {
305
+ new Pathfinder(this[internalDataSymbol].getSubject()['options']).setVia(path, value);
306
+ //this[internalDataSymbol].notifyObservers();
307
+ return this;
308
+ }
309
+
310
+ /**
311
+ * @since 1.15.0
312
+ * @param {string|object} options
313
+ * @return {CustomElement}
314
+ */
315
+ setOptions(options) {
316
+
317
+ if (isString(options)) {
318
+ options = parseOptionsJSON(options)
319
+ }
320
+
321
+ const self = this;
322
+ extend(self[internalDataSymbol].getSubject()['options'], self.defaults, options);
323
+ //this[internalDataSymbol].notifyObservers();
324
+
325
+ return self;
326
+ }
327
+
220
328
  /**
221
329
  *
222
330
  * @return {CustomElement}
@@ -256,8 +364,8 @@ class CustomElement extends HTMLElement {
256
364
  for (const [, element] of Object.entries(elements)) {
257
365
 
258
366
  if (!(element instanceof HTMLElement)) continue;
259
-
260
- const u = new Updater(element, this[optionsSymbol])
367
+ if ((element instanceof HTMLTemplateElement)) continue;
368
+ const u = new Updater(element, clone(self[internalDataSymbol].getRealSubject()['options']))
261
369
  updater.add(u);
262
370
 
263
371
  u.run().then(() => {
@@ -266,7 +374,6 @@ class CustomElement extends HTMLElement {
266
374
 
267
375
  }
268
376
 
269
-
270
377
  return this;
271
378
  }
272
379
 
@@ -308,58 +415,53 @@ class CustomElement extends HTMLElement {
308
415
 
309
416
  /**
310
417
  * Called when an observed attribute has been added, removed, updated, or replaced. Also called for initial
311
- * values when an element is created by the parser, or upgraded. Note: only attributes listed in the observedAttributes property will receive this callback.
418
+ * values when an element is created by the parser, or upgraded. Note: only attributes listed in the observedAttributes
419
+ * property will receive this callback.
312
420
  *
313
421
  * @param {string} attrName
314
422
  * @param {string} oldVal
315
423
  * @param {string} newVal
316
424
  * @return {void}
317
- * @since 1.7.0
425
+ * @since 1.15.0
318
426
  */
319
427
  attributeChangedCallback(attrName, oldVal, newVal) {
320
- }
428
+ const self = this;
321
429
 
322
- /**
323
- * There is no check on the name by this class. the developer is responsible for assigning an appropriate tag.
324
- * if the name is not valid, registerCustomElement() will issue an erro
325
- *
326
- * @link https://html.spec.whatwg.org/multipage/custom-elements.html#valid-custom-element-name
327
- * @return {string}
328
- * @throws {Error} the method getTag must be overwritten by the derived class.
329
- * @since 1.7.0
330
- */
331
- static getTag() {
332
- throw new Error("the method getTag must be overwritten by the derived class.");
333
- }
430
+ if (attrName === ATTRIBUTE_OPTIONS) {
431
+ self.setOptions(newVal);
432
+ }
334
433
 
335
- /**
336
- * At this point a `CSSStyleSheet` object can be returned. If the environment does not
337
- * support a constructor, then an object can also be built using the following detour.
338
- *
339
- * If `undefined` is returned then the shadowRoot does not get a stylesheet.
340
- *
341
- * ```
342
- * const doc = document.implementation.createHTMLDocument('title');
343
- *
344
- * let style = doc.createElement("style");
345
- * style.innerHTML="p{color:red;}";
346
- *
347
- * // WebKit Hack
348
- * style.appendChild(document.createTextNode(""));
349
- * // Add the <style> element to the page
350
- * doc.head.appendChild(style);
351
- * return doc.styleSheets[0];
352
- * ;
353
- * ```
354
- *
355
- * @return {CSSStyleSheet|undefined}
356
- */
357
- static getCSSStyleSheet() {
358
- return undefined;
359
434
  }
360
435
 
361
436
  }
362
437
 
438
+ /**
439
+ * @since 1.15.0
440
+ * @private
441
+ */
442
+ function initOptionObserver() {
443
+ const self = this;
444
+
445
+ self.attachObserver(new Observer(function () {
446
+
447
+ // not initialised
448
+ if (!hasObjectLink(self, Symbol.for(OBJECTLINK_KEY_UPDATER))) {
449
+ return;
450
+ }
451
+ // inform every element
452
+ const updaters = getLinkedObjects(self, Symbol.for(OBJECTLINK_KEY_UPDATER));
453
+
454
+ for (const list of updaters) {
455
+ for (const updater of list) {
456
+ let d = clone(self[internalDataSymbol].getRealSubject()['options']);
457
+ Object.assign(updater.getSubject(), d);
458
+ }
459
+ }
460
+
461
+ }));
462
+
463
+ }
464
+
363
465
  /**
364
466
  * @private
365
467
  * @return {object}
@@ -368,11 +470,24 @@ class CustomElement extends HTMLElement {
368
470
  function getOptionsFromAttributes() {
369
471
  if (this.hasAttribute(ATTRIBUTE_OPTIONS)) {
370
472
  try {
371
- let obj = JSON.parse(this.getAttribute(ATTRIBUTE_OPTIONS))
473
+ return parseOptionsJSON(this.getAttribute(ATTRIBUTE_OPTIONS))
474
+ } catch (e) {
475
+ throw new Error('the options attribute ' + ATTRIBUTE_OPTIONS + ' does not contain a valid json definition (actual: ' + this.getAttribute(ATTRIBUTE_OPTIONS) + ').');
476
+ }
477
+ }
478
+
479
+ return {};
480
+ }
481
+
482
+
483
+ function parseOptionsJSON(data) {
484
+ if (isString(data)) {
485
+ try {
486
+ let obj = JSON.parse(data);
372
487
  validateObject(obj);
373
488
  return obj;
374
489
  } catch (e) {
375
- throw new Error('the options attribute ' + ATTRIBUTE_OPTIONS + ' does not contain a valid json definition (actual: ' + this.getAttribute(ATTRIBUTE_OPTIONS) + ').');
490
+ throw new Error('the options does not contain a valid json definition (actual: ' + data + ').');
376
491
  }
377
492
  }
378
493
 
@@ -458,5 +573,5 @@ function registerCustomElement(element) {
458
573
  getGlobalObject('customElements').define(element.getTag(), element);
459
574
  }
460
575
 
461
- Monster.assignToNamespace('Monster.DOM', CustomElement, registerCustomElement);
576
+ assignToNamespace('Monster.DOM', CustomElement, registerCustomElement);
462
577
  export {Monster, registerCustomElement, CustomElement, initMethodSymbol, assembleMethodSymbol}