@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.
- package/CHANGELOG +46 -1
- package/README.md +5 -5
- package/dist/modules/constants.js +2 -2
- package/dist/modules/constraints/abstract.js +2 -2
- package/dist/modules/constraints/abstractoperator.js +2 -2
- package/dist/modules/constraints/andoperator.js +2 -2
- package/dist/modules/constraints/invalid.js +2 -2
- package/dist/modules/constraints/isarray.js +2 -2
- package/dist/modules/constraints/isobject.js +2 -2
- package/dist/modules/constraints/namespace.js +1 -1
- package/dist/modules/constraints/oroperator.js +2 -2
- package/dist/modules/constraints/valid.js +2 -2
- package/dist/modules/data/buildmap.js +2 -2
- package/dist/modules/data/diff.js +2 -2
- package/dist/modules/data/extend.js +2 -2
- package/dist/modules/data/namespace.js +1 -1
- package/dist/modules/data/pathfinder.js +2 -2
- package/dist/modules/data/pipe.js +2 -2
- package/dist/modules/data/transformer.js +2 -2
- package/dist/modules/dom/assembler.js +2 -2
- package/dist/modules/dom/attributes.js +2 -2
- package/dist/modules/dom/constants.js +2 -2
- package/dist/modules/dom/customcontrol.js +2 -0
- package/dist/modules/dom/customelement.js +2 -2
- package/dist/modules/dom/events.js +2 -2
- package/dist/modules/dom/locale.js +2 -2
- package/dist/modules/dom/namespace.js +1 -1
- package/dist/modules/dom/template.js +2 -2
- package/dist/modules/dom/theme.js +2 -2
- package/dist/modules/dom/updater.js +2 -2
- package/dist/modules/dom/util.js +2 -2
- package/dist/modules/i18n/locale.js +2 -2
- package/dist/modules/i18n/namespace.js +1 -1
- package/dist/modules/i18n/provider.js +2 -2
- package/dist/modules/i18n/providers/fetch.js +2 -2
- package/dist/modules/i18n/providers/namespace.js +1 -1
- package/dist/modules/i18n/translations.js +2 -2
- package/dist/modules/logging/handler/console.js +2 -2
- package/dist/modules/logging/handler/namespace.js +1 -1
- package/dist/modules/logging/handler.js +2 -2
- package/dist/modules/logging/logentry.js +2 -2
- package/dist/modules/logging/logger.js +2 -2
- package/dist/modules/logging/namespace.js +1 -1
- package/dist/modules/math/namespace.js +1 -1
- package/dist/modules/math/random.js +2 -2
- package/dist/modules/monster.js +2 -2
- package/dist/modules/namespace.js +2 -2
- package/dist/modules/text/formatter.js +2 -2
- package/dist/modules/text/namespace.js +1 -1
- package/dist/modules/types/base.js +2 -2
- package/dist/modules/types/basewithoptions.js +2 -2
- package/dist/modules/types/global.js +2 -2
- package/dist/modules/types/id.js +2 -2
- package/dist/modules/types/is.js +2 -2
- package/dist/modules/types/namespace.js +1 -1
- package/dist/modules/types/observer.js +2 -2
- package/dist/modules/types/observerlist.js +2 -2
- package/dist/modules/types/proxyobserver.js +2 -2
- package/dist/modules/types/queue.js +2 -2
- package/dist/modules/types/randomid.js +2 -2
- package/dist/modules/types/stack.js +2 -2
- package/dist/modules/types/tokenlist.js +2 -2
- package/dist/modules/types/typeof.js +2 -2
- package/dist/modules/types/uniquequeue.js +2 -2
- package/dist/modules/types/validate.js +2 -2
- package/dist/modules/types/version.js +2 -2
- package/dist/modules/util/clone.js +2 -2
- package/dist/modules/util/comparator.js +2 -2
- package/dist/modules/util/freeze.js +2 -2
- package/dist/modules/util/namespace.js +1 -1
- package/dist/monster.dev.js +8622 -7709
- package/dist/monster.dev.js.map +1 -1
- package/dist/monster.js +2 -9
- package/package.json +1 -1
- package/source/constants.js +7 -6
- package/source/constraints/abstract.js +2 -2
- package/source/constraints/abstractoperator.js +4 -4
- package/source/constraints/andoperator.js +8 -8
- package/source/constraints/invalid.js +6 -6
- package/source/constraints/isarray.js +7 -7
- package/source/constraints/isobject.js +7 -7
- package/source/constraints/namespace.js +2 -2
- package/source/constraints/oroperator.js +8 -8
- package/source/constraints/valid.js +7 -7
- package/source/data/buildmap.js +15 -15
- package/source/data/diff.js +9 -9
- package/source/data/extend.js +55 -13
- package/source/data/namespace.js +2 -2
- package/source/data/pathfinder.js +13 -14
- package/source/data/pipe.js +8 -8
- package/source/data/transformer.js +11 -11
- package/source/dom/assembler.js +7 -7
- package/source/dom/attributes.js +89 -46
- package/source/dom/constants.js +9 -2
- package/source/dom/customcontrol.js +299 -0
- package/source/dom/customelement.js +181 -66
- package/source/dom/events.js +58 -8
- package/source/dom/locale.js +5 -5
- package/source/dom/namespace.js +2 -2
- package/source/dom/template.js +24 -19
- package/source/dom/theme.js +8 -9
- package/source/dom/updater.js +46 -24
- package/source/dom/util.js +10 -10
- package/source/i18n/locale.js +7 -7
- package/source/i18n/namespace.js +1 -1
- package/source/i18n/provider.js +6 -6
- package/source/i18n/providers/fetch.js +10 -10
- package/source/i18n/translations.js +5 -5
- package/source/logging/handler/console.js +5 -5
- package/source/logging/handler/namespace.js +1 -1
- package/source/logging/handler.js +8 -8
- package/source/logging/logentry.js +5 -5
- package/source/logging/logger.js +5 -5
- package/source/logging/namespace.js +2 -2
- package/source/math/namespace.js +2 -2
- package/source/math/random.js +5 -5
- package/source/monster.js +48 -44
- package/source/namespace.js +2 -2
- package/source/text/formatter.js +6 -7
- package/source/text/namespace.js +1 -1
- package/source/types/base.js +4 -5
- package/source/types/basewithoptions.js +10 -9
- package/source/types/global.js +7 -7
- package/source/types/id.js +7 -7
- package/source/types/is.js +22 -22
- package/source/types/namespace.js +2 -2
- package/source/types/observer.js +7 -7
- package/source/types/observerlist.js +4 -4
- package/source/types/proxyobserver.js +32 -26
- package/source/types/queue.js +13 -7
- package/source/types/randomid.js +6 -6
- package/source/types/stack.js +11 -4
- package/source/types/tokenlist.js +9 -9
- package/source/types/typeof.js +5 -5
- package/source/types/uniquequeue.js +14 -7
- package/source/types/validate.js +27 -27
- package/source/types/version.js +9 -9
- package/source/util/clone.js +6 -6
- package/source/util/comparator.js +7 -7
- package/source/util/freeze.js +7 -7
- package/source/util/namespace.js +2 -2
- package/test/cases/data/extend.js +66 -13
- package/test/cases/dom/attributes.js +56 -1
- package/test/cases/dom/customcontrol.js +264 -0
- package/test/cases/dom/customelement.js +112 -51
- package/test/cases/dom/events.js +32 -14
- package/test/cases/dom/template.js +40 -1
- package/test/cases/monster.js +1 -1
- package/test/cases/types/proxyobserver.js +9 -0
- package/test/util/jsdom.js +3 -0
- package/test/web/import.js +1 -0
- package/test/web/monster-dev.html +3 -3
- package/test/web/monster.html +2 -2
- package/test/web/test.html +3 -3
- 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 {
|
|
17
|
-
import {
|
|
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
|
|
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.
|
|
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.
|
|
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[
|
|
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[
|
|
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,
|
|
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
|
|
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.
|
|
425
|
+
* @since 1.15.0
|
|
318
426
|
*/
|
|
319
427
|
attributeChangedCallback(attrName, oldVal, newVal) {
|
|
320
|
-
|
|
428
|
+
const self = this;
|
|
321
429
|
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
|
|
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
|
-
|
|
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
|
|
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
|
-
|
|
576
|
+
assignToNamespace('Monster.DOM', CustomElement, registerCustomElement);
|
|
462
577
|
export {Monster, registerCustomElement, CustomElement, initMethodSymbol, assembleMethodSymbol}
|