@schukai/monster 1.12.0 → 1.15.0

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