@schukai/monster 1.12.0 → 1.15.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG +40 -1
- package/README.md +5 -5
- package/dist/modules/constants.js +2 -0
- 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 -0
- 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 -0
- package/dist/modules/i18n/namespace.js +2 -0
- package/dist/modules/i18n/provider.js +2 -0
- package/dist/modules/i18n/providers/fetch.js +2 -0
- package/dist/modules/i18n/providers/namespace.js +2 -0
- package/dist/modules/i18n/translations.js +2 -0
- 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 +1 -1
- 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 -0
- 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 +8692 -6669
- package/dist/monster.dev.js.map +1 -1
- package/dist/monster.js +3 -3
- package/package.json +1 -1
- package/source/constants.js +22 -0
- package/source/constraints/abstract.js +2 -2
- package/source/constraints/abstractoperator.js +3 -3
- package/source/constraints/andoperator.js +7 -7
- package/source/constraints/invalid.js +6 -6
- package/source/constraints/isarray.js +6 -6
- package/source/constraints/isobject.js +6 -6
- package/source/constraints/namespace.js +2 -0
- package/source/constraints/oroperator.js +8 -8
- package/source/constraints/valid.js +6 -6
- package/source/data/buildmap.js +15 -15
- package/source/data/diff.js +6 -6
- package/source/data/extend.js +55 -13
- package/source/data/namespace.js +2 -0
- package/source/data/pathfinder.js +6 -7
- package/source/data/pipe.js +5 -5
- package/source/data/transformer.js +6 -6
- package/source/dom/assembler.js +5 -5
- package/source/dom/attributes.js +89 -45
- package/source/dom/constants.js +8 -9
- package/source/dom/customcontrol.js +301 -0
- package/source/dom/customelement.js +149 -31
- package/source/dom/events.js +58 -8
- package/source/dom/locale.js +59 -0
- package/source/dom/namespace.js +2 -0
- package/source/dom/template.js +7 -7
- package/source/dom/theme.js +6 -6
- package/source/dom/updater.js +38 -11
- package/source/dom/util.js +10 -10
- package/source/i18n/locale.js +322 -0
- package/source/i18n/namespace.js +15 -0
- package/source/i18n/provider.js +58 -0
- package/source/i18n/providers/fetch.js +121 -0
- package/source/i18n/providers/namespace.js +15 -0
- package/source/i18n/translations.js +209 -0
- package/source/logging/handler/console.js +4 -4
- package/source/logging/handler.js +4 -4
- package/source/logging/logentry.js +4 -4
- package/source/logging/logger.js +4 -4
- package/source/logging/namespace.js +2 -0
- package/source/math/namespace.js +2 -0
- package/source/math/random.js +5 -5
- package/source/monster.js +26 -16
- package/source/namespace.js +10 -8
- package/source/text/formatter.js +4 -5
- package/source/text/namespace.js +1 -1
- package/source/types/base.js +4 -7
- package/source/types/basewithoptions.js +97 -0
- package/source/types/global.js +6 -6
- package/source/types/id.js +6 -6
- package/source/types/is.js +22 -22
- package/source/types/namespace.js +3 -1
- package/source/types/observer.js +5 -5
- 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 +5 -5
- package/source/types/stack.js +11 -4
- package/source/types/tokenlist.js +4 -4
- package/source/types/typeof.js +5 -5
- package/source/types/uniquequeue.js +11 -4
- package/source/types/validate.js +22 -22
- package/source/types/version.js +9 -9
- package/source/util/clone.js +4 -4
- package/source/util/comparator.js +6 -6
- package/source/util/freeze.js +4 -4
- package/source/util/namespace.js +2 -0
- 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/locale.js +44 -0
- package/test/cases/i18n/locale.js +80 -0
- package/test/cases/i18n/provider.js +15 -0
- package/test/cases/i18n/providers/fetch.js +65 -0
- package/test/cases/i18n/translations.js +57 -0
- package/test/cases/monster.js +3 -1
- package/test/cases/{util → text}/formatter.js +2 -0
- package/test/cases/types/basewithoptions.js +25 -0
- package/test/cases/types/proxyobserver.js +9 -0
- package/test/cases/{text → util}/clone.js +0 -0
- package/test/cases/{text → util}/comparator.js +0 -0
- package/test/util/jsdom.js +4 -0
- package/test/web/import.js +10 -3
- package/test/web/monster-dev.html +3 -3
- package/test/web/monster.html +3 -3
- package/test/web/test.html +3 -3
- 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 {
|
|
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,
|
|
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 {
|
|
19
|
+
import {PROPERTY_KEY_INTERNALDATA} from "../constants.js";
|
|
17
20
|
|
|
18
21
|
/**
|
|
19
22
|
* @private
|
|
20
23
|
* @type {symbol}
|
|
21
24
|
*/
|
|
22
|
-
const
|
|
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.
|
|
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.
|
|
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[
|
|
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[
|
|
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,
|
|
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
|
|
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.
|
|
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
|
|
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
|
-
|
|
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
|
|
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
|
-
|
|
576
|
+
assignToNamespace('Monster.DOM', CustomElement, registerCustomElement);
|
|
459
577
|
export {Monster, registerCustomElement, CustomElement, initMethodSymbol, assembleMethodSymbol}
|