@schukai/monster 3.48.0 → 3.50.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/package.json +1 -1
- package/source/data/datasource/server/restapi/data-fetch-error.mjs +1 -2
- package/source/data/datasource/server/restapi.mjs +10 -7
- package/source/data/transformer.mjs +18 -0
- package/source/dom/constants.mjs +2 -2
- package/source/dom/customcontrol.mjs +63 -66
- package/source/dom/customelement.mjs +157 -172
- package/source/dom/dimension.mjs +1 -3
- package/source/dom/util/extract-keys.mjs +10 -6
- package/source/dom/util/init-options-from-attributes.mjs +14 -16
- package/source/dom/util/set-option-from-attribute.mjs +14 -16
- package/source/dom/util.mjs +11 -4
- package/source/logging/handler/console.mjs +0 -4
- package/source/text/bracketed-key-value-hash.mjs +23 -31
- package/source/text/util.mjs +1 -2
- package/source/types/version.mjs +1 -1
- package/test/cases/data/transformer.mjs +3 -0
- package/test/cases/dom/customcontrol.mjs +21 -45
- package/test/cases/dom/customelement.mjs +2 -1
- package/test/cases/monster.mjs +1 -1
|
@@ -5,37 +5,37 @@
|
|
|
5
5
|
* License text available at https://www.gnu.org/licenses/agpl-3.0.en.html
|
|
6
6
|
*/
|
|
7
7
|
|
|
8
|
-
import {findElementWithIdUpwards} from "./util.mjs";
|
|
9
|
-
import {internalSymbol} from "../constants.mjs";
|
|
10
|
-
import {extend} from "../data/extend.mjs";
|
|
11
|
-
import {Pathfinder} from "../data/pathfinder.mjs";
|
|
12
|
-
import {Formatter} from "../text/formatter.mjs";
|
|
13
|
-
|
|
14
|
-
import {parseDataURL} from "../types/dataurl.mjs";
|
|
15
|
-
import {getGlobalObject} from "../types/global.mjs";
|
|
16
|
-
import {isArray, isFunction, isIterable, isObject, isString} from "../types/is.mjs";
|
|
17
|
-
import {Observer} from "../types/observer.mjs";
|
|
18
|
-
import {ProxyObserver} from "../types/proxyobserver.mjs";
|
|
19
|
-
import {validateFunction, validateInstance, validateObject, validateString} from "../types/validate.mjs";
|
|
20
|
-
import {clone} from "../util/clone.mjs";
|
|
21
|
-
import {addAttributeToken, getLinkedObjects, hasObjectLink} from "./attributes.mjs";
|
|
8
|
+
import { findElementWithIdUpwards } from "./util.mjs";
|
|
9
|
+
import { internalSymbol } from "../constants.mjs";
|
|
10
|
+
import { extend } from "../data/extend.mjs";
|
|
11
|
+
import { Pathfinder } from "../data/pathfinder.mjs";
|
|
12
|
+
import { Formatter } from "../text/formatter.mjs";
|
|
13
|
+
|
|
14
|
+
import { parseDataURL } from "../types/dataurl.mjs";
|
|
15
|
+
import { getGlobalObject } from "../types/global.mjs";
|
|
16
|
+
import { isArray, isFunction, isIterable, isObject, isString } from "../types/is.mjs";
|
|
17
|
+
import { Observer } from "../types/observer.mjs";
|
|
18
|
+
import { ProxyObserver } from "../types/proxyobserver.mjs";
|
|
19
|
+
import { validateFunction, validateInstance, validateObject, validateString } from "../types/validate.mjs";
|
|
20
|
+
import { clone } from "../util/clone.mjs";
|
|
21
|
+
import { addAttributeToken, getLinkedObjects, hasObjectLink } from "./attributes.mjs";
|
|
22
22
|
import {
|
|
23
23
|
ATTRIBUTE_DISABLED,
|
|
24
24
|
ATTRIBUTE_ERRORMESSAGE,
|
|
25
25
|
ATTRIBUTE_OPTIONS,
|
|
26
|
-
|
|
26
|
+
ATTRIBUTE_INIT_CALLBACK,
|
|
27
27
|
ATTRIBUTE_OPTIONS_SELECTOR,
|
|
28
28
|
ATTRIBUTE_SCRIPT_HOST,
|
|
29
29
|
customElementUpdaterLinkSymbol,
|
|
30
|
-
initControlCallbackName
|
|
30
|
+
initControlCallbackName,
|
|
31
31
|
} from "./constants.mjs";
|
|
32
|
-
import {findDocumentTemplate, Template} from "./template.mjs";
|
|
33
|
-
import {addObjectWithUpdaterToElement} from "./updater.mjs";
|
|
34
|
-
import {instanceSymbol} from "../constants.mjs";
|
|
35
|
-
import {getDocumentTranslations, Translations} from "../i18n/translations.mjs";
|
|
36
|
-
import {getSlottedElements} from "./slotted.mjs";
|
|
37
|
-
import {initOptionsFromAttributes} from "./util/init-options-from-attributes.mjs";
|
|
38
|
-
import {setOptionFromAttribute} from "./util/set-option-from-attribute.mjs";
|
|
32
|
+
import { findDocumentTemplate, Template } from "./template.mjs";
|
|
33
|
+
import { addObjectWithUpdaterToElement } from "./updater.mjs";
|
|
34
|
+
import { instanceSymbol } from "../constants.mjs";
|
|
35
|
+
import { getDocumentTranslations, Translations } from "../i18n/translations.mjs";
|
|
36
|
+
import { getSlottedElements } from "./slotted.mjs";
|
|
37
|
+
import { initOptionsFromAttributes } from "./util/init-options-from-attributes.mjs";
|
|
38
|
+
import { setOptionFromAttribute } from "./util/set-option-from-attribute.mjs";
|
|
39
39
|
|
|
40
40
|
export {
|
|
41
41
|
CustomElement,
|
|
@@ -121,15 +121,12 @@ const scriptHostElementSymbol = Symbol("scriptHostElement");
|
|
|
121
121
|
*/
|
|
122
122
|
|
|
123
123
|
/**
|
|
124
|
-
*
|
|
124
|
+
* The `CustomElement` class provides a way to define a new HTML element using the power of Custom Elements.
|
|
125
125
|
*
|
|
126
|
-
* IMPORTANT
|
|
127
|
-
*
|
|
128
|
-
*
|
|
129
|
-
* <img src="./images/customelement-class.png">
|
|
130
|
-
*
|
|
131
|
-
* You can create the object via the function `document.createElement()`.
|
|
126
|
+
* **IMPORTANT:** After defining a `CustomElement`, the `registerCustomElement` method must be called with the new class name
|
|
127
|
+
* to make the tag defined via the `getTag` method known to the DOM.
|
|
132
128
|
*
|
|
129
|
+
* You can create an instance of the object via the `document.createElement()` function.
|
|
133
130
|
*
|
|
134
131
|
* ## Interaction
|
|
135
132
|
*
|
|
@@ -137,15 +134,13 @@ const scriptHostElementSymbol = Symbol("scriptHostElement");
|
|
|
137
134
|
*
|
|
138
135
|
* ## Styling
|
|
139
136
|
*
|
|
140
|
-
*
|
|
137
|
+
* To display custom elements optimally, the `:defined` pseudo-class can be used. To prevent custom elements from being displayed and flickering until the control is registered,
|
|
138
|
+
* it is recommended to create a CSS directive.
|
|
141
139
|
*
|
|
142
|
-
*
|
|
140
|
+
* In the simplest case, you can simply hide the control:
|
|
143
141
|
*
|
|
144
|
-
*
|
|
145
|
-
*
|
|
146
|
-
* ```
|
|
142
|
+
* ```html
|
|
147
143
|
* <style>
|
|
148
|
-
*
|
|
149
144
|
* my-custom-element:not(:defined) {
|
|
150
145
|
* display: none;
|
|
151
146
|
* }
|
|
@@ -153,63 +148,65 @@ const scriptHostElementSymbol = Symbol("scriptHostElement");
|
|
|
153
148
|
* my-custom-element:defined {
|
|
154
149
|
* display: flex;
|
|
155
150
|
* }
|
|
156
|
-
*
|
|
157
151
|
* </style>
|
|
158
152
|
* ```
|
|
159
153
|
*
|
|
160
|
-
* Alternatively you can
|
|
154
|
+
* Alternatively, you can display a loader:
|
|
161
155
|
*
|
|
162
|
-
* ```
|
|
156
|
+
* ```css
|
|
163
157
|
* my-custom-element:not(:defined) {
|
|
164
|
-
*
|
|
165
|
-
*
|
|
166
|
-
*
|
|
167
|
-
*
|
|
168
|
-
*
|
|
169
|
-
*
|
|
170
|
-
*
|
|
158
|
+
* display: flex;
|
|
159
|
+
* box-shadow: 0 4px 10px 0 rgba(33, 33, 33, 0.15);
|
|
160
|
+
* border-radius: 4px;
|
|
161
|
+
* height: 200px;
|
|
162
|
+
* position: relative;
|
|
163
|
+
* overflow: hidden;
|
|
164
|
+
* }
|
|
171
165
|
*
|
|
172
166
|
* my-custom-element:not(:defined)::before {
|
|
173
|
-
*
|
|
174
|
-
*
|
|
175
|
-
*
|
|
176
|
-
*
|
|
177
|
-
*
|
|
178
|
-
*
|
|
179
|
-
*
|
|
180
|
-
*
|
|
181
|
-
*
|
|
182
|
-
*
|
|
167
|
+
* content: '';
|
|
168
|
+
* display: block;
|
|
169
|
+
* position: absolute;
|
|
170
|
+
* left: -150px;
|
|
171
|
+
* top: 0;
|
|
172
|
+
* height: 100%;
|
|
173
|
+
* width: 150px;
|
|
174
|
+
* background: linear-gradient(to right, transparent 0%, #E8E8E8 50%, transparent 100%);
|
|
175
|
+
* animation: load 1s cubic-bezier(0.4, 0.0, 0.2, 1) infinite;
|
|
176
|
+
* }
|
|
183
177
|
*
|
|
184
178
|
* @keyframes load {
|
|
185
|
-
*
|
|
186
|
-
*
|
|
187
|
-
*
|
|
188
|
-
*
|
|
189
|
-
*
|
|
190
|
-
*
|
|
191
|
-
*
|
|
179
|
+
* from {
|
|
180
|
+
* left: -150px;
|
|
181
|
+
* }
|
|
182
|
+
* to {
|
|
183
|
+
* left: 100%;
|
|
184
|
+
* }
|
|
185
|
+
* }
|
|
192
186
|
*
|
|
193
187
|
* my-custom-element:defined {
|
|
194
|
-
*
|
|
195
|
-
*
|
|
188
|
+
* display: flex;
|
|
189
|
+
* }
|
|
196
190
|
* ```
|
|
197
191
|
*
|
|
192
|
+
* More information about Custom Elements can be found in the [MDN Web Docs](https://developer.mozilla.org/en-US/docs/Web/Web_Components/Using_custom_elements).
|
|
193
|
+
* And in the [HTML Standard](https://html.spec.whatwg.org/multipage/custom-elements.html#custom-elements) or in the [WHATWG Wiki](https://wiki.whatwg.org/wiki/Custom_Elements).
|
|
194
|
+
*
|
|
198
195
|
* @externalExample ../../example/dom/theme.mjs
|
|
199
|
-
* @see https://github.com/WICG/webcomponents
|
|
200
|
-
* @see https://html.spec.whatwg.org/multipage/custom-elements.html#custom-elements
|
|
201
196
|
* @license AGPLv3
|
|
202
197
|
* @since 1.7.0
|
|
203
198
|
* @copyright schukai GmbH
|
|
204
199
|
* @memberOf Monster.DOM
|
|
205
200
|
* @extends external:HTMLElement
|
|
206
|
-
* @summary A base class for HTML5
|
|
201
|
+
* @summary A base class for HTML5 custom controls.
|
|
207
202
|
*/
|
|
208
203
|
class CustomElement extends HTMLElement {
|
|
209
204
|
/**
|
|
210
205
|
* A new object is created. First the `initOptions` method is called. Here the
|
|
211
206
|
* options can be defined in derived classes. Subsequently, the shadowRoot is initialized.
|
|
212
207
|
*
|
|
208
|
+
* IMPORTANT: CustomControls instances are not created via the constructor, but either via a tag in the HTML or via <code>document.createElement()</code>.
|
|
209
|
+
*
|
|
213
210
|
* @throws {Error} the options attribute does not contain a valid json definition.
|
|
214
211
|
* @since 1.7.0
|
|
215
212
|
*/
|
|
@@ -223,7 +220,6 @@ class CustomElement extends HTMLElement {
|
|
|
223
220
|
this[initMethodSymbol]();
|
|
224
221
|
initOptionObserver.call(this);
|
|
225
222
|
this[scriptHostElementSymbol] = [];
|
|
226
|
-
|
|
227
223
|
}
|
|
228
224
|
|
|
229
225
|
/**
|
|
@@ -270,53 +266,25 @@ class CustomElement extends HTMLElement {
|
|
|
270
266
|
}
|
|
271
267
|
|
|
272
268
|
/**
|
|
273
|
-
*
|
|
269
|
+
* The `defaults` property defines the default values for a control. If you want to override these,
|
|
270
|
+
* you can use various methods, which are described in the documentation available at
|
|
271
|
+
* {@link https://monsterjs.orgendocconfigurate-a-monster-control}.
|
|
274
272
|
*
|
|
275
|
-
*
|
|
276
|
-
* get defaults() {
|
|
277
|
-
* return Object.assign({}, super.defaults, {
|
|
278
|
-
* myValue:true
|
|
279
|
-
* });
|
|
280
|
-
* }
|
|
281
|
-
* ```
|
|
282
|
-
*
|
|
283
|
-
* To set the options via the html tag the attribute data-monster-options must be set.
|
|
284
|
-
* As value a JSON object with the desired values must be defined.
|
|
285
|
-
*
|
|
286
|
-
* Since 1.18.0 the JSON can be specified as a DataURI.
|
|
287
|
-
*
|
|
288
|
-
* ```
|
|
289
|
-
* new Monster.Types.DataUrl(btoa(JSON.stringify({
|
|
290
|
-
* shadowMode: 'open',
|
|
291
|
-
* delegatesFocus: true,
|
|
292
|
-
* templates: {
|
|
293
|
-
* main: undefined
|
|
294
|
-
* }
|
|
295
|
-
* })),'application/json',true).toString()
|
|
296
|
-
* ```
|
|
273
|
+
* The individual configuration values are listed below:
|
|
297
274
|
*
|
|
298
|
-
*
|
|
275
|
+
* More information about the shadowRoot can be found in the [MDN Web Docs](https://developer.mozilla.org/en-US/docs/Web/API/Element/attachShadow),
|
|
276
|
+
* in the [HTML Standard](https://html.spec.whatwg.org/multipage/custom-elements.html#custom-elements) or in the [WHATWG Wiki](https://wiki.whatwg.org/wiki/Custom_Elements).
|
|
299
277
|
*
|
|
300
|
-
*
|
|
278
|
+
* More information about the template element can be found in the [MDN Web Docs](https://developer.mozilla.org/en-US/docs/Web/HTML/Element/template).
|
|
301
279
|
*
|
|
302
|
-
*
|
|
303
|
-
* <script id="id-for-this-config" type="application/json">
|
|
304
|
-
* {
|
|
305
|
-
* "config-key": "config-value"
|
|
306
|
-
* }
|
|
307
|
-
* </script>
|
|
308
|
-
* ```
|
|
309
|
-
*
|
|
310
|
-
* The individual configuration values can be found in the table.
|
|
311
|
-
*
|
|
312
|
-
* @property {boolean} disabled=false Object The Boolean disabled attribute, when present, makes the element not mutable, focusable, or even submitted with the form.
|
|
313
|
-
* @property {string} shadowMode=open `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
|
|
314
|
-
* @property {Boolean} delegatesFocus=true 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.
|
|
315
|
-
* @property {Object} templates Templates
|
|
316
|
-
* @property {string} templates.main=undefined Main template
|
|
317
|
-
* @property {Object} templateMapping Template mapping
|
|
280
|
+
* More information about the slot element can be found in the [MDN Web Docs](https://developer.mozilla.org/en-US/docs/Web/HTML/Element/slot).
|
|
318
281
|
*
|
|
319
|
-
* @
|
|
282
|
+
* @property {boolean} disabled=false Specifies whether the control is disabled. When present, it makes the element non-mutable, non-focusable, and non-submittable with the form.
|
|
283
|
+
* @property {string} shadowMode=open Specifies the mode of the shadow root. When set to `open`, elements in the shadow root are accessible from JavaScript outside the root, while setting it to `closed` denies access to the root's nodes from JavaScript outside it.
|
|
284
|
+
* @property {Boolean} delegatesFocus=true Specifies the behavior of the control with respect to focusability. When set to `true`, it 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.
|
|
285
|
+
* @property {Object} templates Specifies the templates used by the control.
|
|
286
|
+
* @property {string} templates.main=undefined Specifies the main template used by the control.
|
|
287
|
+
* @property {Object} templateMapping Specifies the mapping of templates.
|
|
320
288
|
* @since 1.8.0
|
|
321
289
|
*/
|
|
322
290
|
get defaults() {
|
|
@@ -383,39 +351,51 @@ class CustomElement extends HTMLElement {
|
|
|
383
351
|
}
|
|
384
352
|
|
|
385
353
|
/**
|
|
386
|
-
*
|
|
387
|
-
*
|
|
354
|
+
* The `getTag()` method returns the tag name associated with the custom element. This method should be overwritten
|
|
355
|
+
* by the derived class.
|
|
388
356
|
*
|
|
389
|
-
*
|
|
390
|
-
*
|
|
391
|
-
*
|
|
357
|
+
* Note that there is no check on the name of the tag in this class. It is the responsibility of
|
|
358
|
+
* the developer to assign an appropriate tag name. If the name is not valid, the
|
|
359
|
+
* `registerCustomElement()` method will issue an error.
|
|
360
|
+
*
|
|
361
|
+
* @see https://html.spec.whatwg.org/multipage/custom-elements.html#valid-custom-element-name
|
|
362
|
+
* @throws {Error} This method must be overridden by the derived class.
|
|
363
|
+
* @return {string} The tag name associated with the custom element.
|
|
392
364
|
* @since 1.7.0
|
|
393
365
|
*/
|
|
394
366
|
static getTag() {
|
|
395
|
-
throw new Error("
|
|
367
|
+
throw new Error("The method `getTag()` must be overridden by the derived class.");
|
|
396
368
|
}
|
|
397
369
|
|
|
398
370
|
/**
|
|
399
|
-
*
|
|
400
|
-
* support
|
|
371
|
+
* The `getCSSStyleSheet()` method returns a `CSSStyleSheet` object that defines the styles for the custom element.
|
|
372
|
+
* If the environment does not support the `CSSStyleSheet` constructor, then an object can be built using the provided detour.
|
|
373
|
+
*
|
|
374
|
+
* If `undefined` is returned, then the shadow root does not receive a stylesheet.
|
|
401
375
|
*
|
|
402
|
-
*
|
|
376
|
+
* Example usage:
|
|
403
377
|
*
|
|
378
|
+
* ```js
|
|
379
|
+
* static getCSSStyleSheet() {
|
|
380
|
+
* const sheet = new CSSStyleSheet();
|
|
381
|
+
* sheet.replaceSync("p { color: red; }");
|
|
382
|
+
* return sheet;
|
|
383
|
+
* }
|
|
404
384
|
* ```
|
|
405
|
-
* const doc = document.implementation.createHTMLDocument('title');
|
|
406
385
|
*
|
|
407
|
-
*
|
|
408
|
-
*
|
|
386
|
+
* If the environment does not support the `CSSStyleSheet` constructor,
|
|
387
|
+
* you can use the following workaround to create the stylesheet:
|
|
409
388
|
*
|
|
410
|
-
*
|
|
389
|
+
* ```js
|
|
390
|
+
* const doc = document.implementation.createHTMLDocument('title');
|
|
391
|
+
* let style = doc.createElement("style");
|
|
392
|
+
* style.innerHTML = "p { color: red; }";
|
|
411
393
|
* style.appendChild(document.createTextNode(""));
|
|
412
|
-
* // Add the <style> element to the page
|
|
413
394
|
* doc.head.appendChild(style);
|
|
414
395
|
* return doc.styleSheets[0];
|
|
415
|
-
* ;
|
|
416
396
|
* ```
|
|
417
397
|
*
|
|
418
|
-
* @return {CSSStyleSheet|CSSStyleSheet[]|string|undefined}
|
|
398
|
+
* @return {CSSStyleSheet|CSSStyleSheet[]|string|undefined} A `CSSStyleSheet` object or an array of such objects that define the styles for the custom element, or `undefined` if no stylesheet should be applied.
|
|
419
399
|
*/
|
|
420
400
|
static getCSSStyleSheet() {
|
|
421
401
|
return undefined;
|
|
@@ -464,8 +444,7 @@ class CustomElement extends HTMLElement {
|
|
|
464
444
|
|
|
465
445
|
try {
|
|
466
446
|
value = new Pathfinder(this[internalSymbol].getRealSubject()["options"]).getVia(path);
|
|
467
|
-
} catch (e) {
|
|
468
|
-
}
|
|
447
|
+
} catch (e) {}
|
|
469
448
|
|
|
470
449
|
if (value === undefined) return defaultValue;
|
|
471
450
|
return value;
|
|
@@ -511,9 +490,14 @@ class CustomElement extends HTMLElement {
|
|
|
511
490
|
}
|
|
512
491
|
|
|
513
492
|
/**
|
|
514
|
-
*
|
|
493
|
+
* This method is called once when the object is included in the DOM for the first time. It performs the following actions:
|
|
494
|
+
* 1. Extracts the options from the attributes and the script tag of the element and sets them.
|
|
495
|
+
* 2. Initializes the shadow root and its CSS stylesheet (if specified).
|
|
496
|
+
* 3. Initializes the HTML content of the element.
|
|
497
|
+
* 4. Initializes the custom elements inside the shadow root and the slotted elements.
|
|
498
|
+
* 5. Attaches a mutation observer to observe changes to the attributes of the element.
|
|
515
499
|
*
|
|
516
|
-
* @return {CustomElement}
|
|
500
|
+
* @return {CustomElement} - The updated custom element.
|
|
517
501
|
* @since 1.8.0
|
|
518
502
|
*/
|
|
519
503
|
[assembleMethodSymbol]() {
|
|
@@ -521,22 +505,25 @@ class CustomElement extends HTMLElement {
|
|
|
521
505
|
let elements;
|
|
522
506
|
let nodeList;
|
|
523
507
|
|
|
508
|
+
// Extract options from attributes and set them
|
|
524
509
|
const AttributeOptions = getOptionsFromAttributes.call(self);
|
|
525
510
|
if (isObject(AttributeOptions) && Object.keys(AttributeOptions).length > 0) {
|
|
526
511
|
self.setOptions(AttributeOptions);
|
|
527
512
|
}
|
|
528
513
|
|
|
514
|
+
// Extract options from script tag and set them
|
|
529
515
|
const ScriptOptions = getOptionsFromScriptTag.call(self);
|
|
530
516
|
if (isObject(ScriptOptions) && Object.keys(ScriptOptions).length > 0) {
|
|
531
517
|
self.setOptions(ScriptOptions);
|
|
532
518
|
}
|
|
533
519
|
|
|
534
|
-
|
|
520
|
+
// Initialize the shadow root and its CSS stylesheet
|
|
535
521
|
if (self.getOption("shadowMode", false) !== false) {
|
|
536
522
|
try {
|
|
537
523
|
initShadowRoot.call(self);
|
|
538
524
|
elements = self.shadowRoot.childNodes;
|
|
539
525
|
} catch (e) {
|
|
526
|
+
addAttributeToken(self, ATTRIBUTE_ERRORMESSAGE, e.toString());
|
|
540
527
|
}
|
|
541
528
|
|
|
542
529
|
try {
|
|
@@ -546,21 +533,19 @@ class CustomElement extends HTMLElement {
|
|
|
546
533
|
}
|
|
547
534
|
}
|
|
548
535
|
|
|
536
|
+
// If the elements are not found inside the shadow root, initialize the HTML content of the element
|
|
549
537
|
if (!(elements instanceof NodeList)) {
|
|
550
|
-
|
|
551
|
-
|
|
552
|
-
elements = this.childNodes;
|
|
553
|
-
}
|
|
538
|
+
initHtmlContent.call(this);
|
|
539
|
+
elements = this.childNodes;
|
|
554
540
|
}
|
|
555
541
|
|
|
542
|
+
// Initialize the custom elements inside the shadow root and the slotted elements
|
|
556
543
|
initFromCallbackHost.call(this);
|
|
557
|
-
|
|
558
544
|
try {
|
|
559
545
|
nodeList = new Set([...elements, ...getSlottedElements.call(self)]);
|
|
560
546
|
} catch (e) {
|
|
561
547
|
nodeList = elements;
|
|
562
548
|
}
|
|
563
|
-
|
|
564
549
|
addObjectWithUpdaterToElement.call(
|
|
565
550
|
self,
|
|
566
551
|
nodeList,
|
|
@@ -568,24 +553,28 @@ class CustomElement extends HTMLElement {
|
|
|
568
553
|
clone(self[internalSymbol].getRealSubject()["options"]),
|
|
569
554
|
);
|
|
570
555
|
|
|
556
|
+
// Attach a mutation observer to observe changes to the attributes of the element
|
|
571
557
|
attachAttributeChangeMutationObserver.call(this);
|
|
572
558
|
|
|
573
559
|
return self;
|
|
574
560
|
}
|
|
575
561
|
|
|
576
562
|
/**
|
|
577
|
-
*
|
|
578
|
-
*
|
|
563
|
+
* This method is called every time the element is inserted into the DOM. It checks if the custom element
|
|
564
|
+
* has already been initialized and if not, calls the assembleMethod to initialize it.
|
|
579
565
|
*
|
|
580
566
|
* @return {void}
|
|
581
567
|
* @since 1.7.0
|
|
568
|
+
* @see https://developer.mozilla.org/en-US/docs/Web/API/Element/connectedCallback
|
|
582
569
|
*/
|
|
583
570
|
connectedCallback() {
|
|
584
|
-
|
|
571
|
+
const self = this;
|
|
572
|
+
|
|
573
|
+
// Check if the object has already been initialized
|
|
585
574
|
if (!hasObjectLink(self, customElementUpdaterLinkSymbol)) {
|
|
575
|
+
// If not, call the assembleMethod to initialize the object
|
|
586
576
|
self[assembleMethodSymbol]();
|
|
587
577
|
}
|
|
588
|
-
|
|
589
578
|
}
|
|
590
579
|
|
|
591
580
|
/**
|
|
@@ -594,8 +583,7 @@ class CustomElement extends HTMLElement {
|
|
|
594
583
|
* @return {void}
|
|
595
584
|
* @since 1.7.0
|
|
596
585
|
*/
|
|
597
|
-
disconnectedCallback() {
|
|
598
|
-
}
|
|
586
|
+
disconnectedCallback() {}
|
|
599
587
|
|
|
600
588
|
/**
|
|
601
589
|
* The custom element has been moved into a new document (e.g. someone called document.adoptNode(el)).
|
|
@@ -603,8 +591,7 @@ class CustomElement extends HTMLElement {
|
|
|
603
591
|
* @return {void}
|
|
604
592
|
* @since 1.7.0
|
|
605
593
|
*/
|
|
606
|
-
adoptedCallback() {
|
|
607
|
-
}
|
|
594
|
+
adoptedCallback() {}
|
|
608
595
|
|
|
609
596
|
/**
|
|
610
597
|
* Called when an observed attribute has been added, removed, updated, or replaced. Also called for initial
|
|
@@ -621,7 +608,7 @@ class CustomElement extends HTMLElement {
|
|
|
621
608
|
const self = this;
|
|
622
609
|
|
|
623
610
|
if (attrName.startsWith("data-monster-option-")) {
|
|
624
|
-
setOptionFromAttribute(self, attrName, this[internalSymbol].getSubject()["options"])
|
|
611
|
+
setOptionFromAttribute(self, attrName, this[internalSymbol].getSubject()["options"]);
|
|
625
612
|
}
|
|
626
613
|
|
|
627
614
|
const callback = self[attributeObserverSymbol]?.[attrName];
|
|
@@ -631,7 +618,6 @@ class CustomElement extends HTMLElement {
|
|
|
631
618
|
} catch (e) {
|
|
632
619
|
addAttributeToken(self, ATTRIBUTE_ERRORMESSAGE, e.toString());
|
|
633
620
|
}
|
|
634
|
-
|
|
635
621
|
}
|
|
636
622
|
}
|
|
637
623
|
|
|
@@ -658,7 +644,7 @@ class CustomElement extends HTMLElement {
|
|
|
658
644
|
|
|
659
645
|
/**
|
|
660
646
|
* Calls a callback function if it exists.
|
|
661
|
-
*
|
|
647
|
+
*
|
|
662
648
|
* @param {string} name
|
|
663
649
|
* @param {*} args
|
|
664
650
|
* @returns {*}
|
|
@@ -667,8 +653,6 @@ class CustomElement extends HTMLElement {
|
|
|
667
653
|
const self = this;
|
|
668
654
|
return callControlCallback.call(self, name, ...args);
|
|
669
655
|
}
|
|
670
|
-
|
|
671
|
-
|
|
672
656
|
}
|
|
673
657
|
|
|
674
658
|
/**
|
|
@@ -685,7 +669,6 @@ function callControlCallback(callBackFunctionName, ...args) {
|
|
|
685
669
|
|
|
686
670
|
if (callBackFunctionName in self) {
|
|
687
671
|
return self[callBackFunctionName](self, ...args);
|
|
688
|
-
|
|
689
672
|
}
|
|
690
673
|
|
|
691
674
|
if (!self.hasAttribute(ATTRIBUTE_SCRIPT_HOST)) {
|
|
@@ -693,13 +676,12 @@ function callControlCallback(callBackFunctionName, ...args) {
|
|
|
693
676
|
}
|
|
694
677
|
|
|
695
678
|
if (self[scriptHostElementSymbol].length === 0) {
|
|
696
|
-
|
|
697
679
|
const targetId = self.getAttribute(ATTRIBUTE_SCRIPT_HOST);
|
|
698
680
|
if (!targetId) {
|
|
699
681
|
return;
|
|
700
682
|
}
|
|
701
683
|
|
|
702
|
-
const list = targetId.split(",")
|
|
684
|
+
const list = targetId.split(",");
|
|
703
685
|
for (const id of list) {
|
|
704
686
|
const host = findElementWithIdUpwards(self, targetId);
|
|
705
687
|
if (!(host instanceof HTMLElement)) {
|
|
@@ -721,33 +703,34 @@ function callControlCallback(callBackFunctionName, ...args) {
|
|
|
721
703
|
}
|
|
722
704
|
|
|
723
705
|
addAttributeToken(self, ATTRIBUTE_ERRORMESSAGE, `callback ${callBackFunctionName} not found`);
|
|
724
|
-
|
|
725
706
|
}
|
|
726
707
|
|
|
727
708
|
/**
|
|
728
|
-
*
|
|
729
|
-
*
|
|
730
|
-
* It looks for the attribute `data-monster-option-callback`. Is this attribute is not set, the default callback
|
|
731
|
-
* `initCustomControlCallback` is called.
|
|
732
|
-
*
|
|
733
|
-
* The callback is searched in this element and in the host element. If the callback is found, it is called with the
|
|
734
|
-
* element as parameter.
|
|
709
|
+
* Initializes the custom element based on the provided callback function.
|
|
735
710
|
*
|
|
736
|
-
*
|
|
711
|
+
* This function is called when the element is attached to the DOM. It checks if the
|
|
712
|
+
* `data-monster-option-callback` attribute is set, and if not, the default callback
|
|
713
|
+
* `initCustomControlCallback` is called. The callback function is searched for in this
|
|
714
|
+
* element and in the host element. If the callback is found, it is called with the element
|
|
715
|
+
* as a parameter.
|
|
737
716
|
*
|
|
738
717
|
* @this CustomElement
|
|
718
|
+
* @see https://developer.mozilla.org/en-US/docs/Web/API/CustomElementRegistry/define#providing_a_construction_callback
|
|
719
|
+
* @since 1.8.0
|
|
739
720
|
*/
|
|
740
721
|
function initFromCallbackHost() {
|
|
741
722
|
const self = this;
|
|
742
723
|
|
|
743
|
-
|
|
744
|
-
|
|
745
|
-
|
|
724
|
+
// Set the default callback function name
|
|
725
|
+
let callBackFunctionName = initControlCallbackName;
|
|
726
|
+
|
|
727
|
+
// If the `data-monster-option-callback` attribute is set, use its value as the callback function name
|
|
728
|
+
if (self.hasAttribute(ATTRIBUTE_INIT_CALLBACK)) {
|
|
729
|
+
callBackFunctionName = self.getAttribute(ATTRIBUTE_INIT_CALLBACK);
|
|
746
730
|
}
|
|
747
731
|
|
|
732
|
+
// Call the callback function with the element as a parameter if it exists
|
|
748
733
|
callControlCallback.call(self, callBackFunctionName);
|
|
749
|
-
|
|
750
|
-
|
|
751
734
|
}
|
|
752
735
|
|
|
753
736
|
/**
|
|
@@ -766,7 +749,11 @@ function attachAttributeChangeMutationObserver() {
|
|
|
766
749
|
self[attributeMutationObserverSymbol] = new MutationObserver(function (mutations, observer) {
|
|
767
750
|
for (const mutation of mutations) {
|
|
768
751
|
if (mutation.type === "attributes") {
|
|
769
|
-
self.attributeChangedCallback(
|
|
752
|
+
self.attributeChangedCallback(
|
|
753
|
+
mutation.attributeName,
|
|
754
|
+
mutation.oldValue,
|
|
755
|
+
mutation.target.getAttribute(mutation.attributeName),
|
|
756
|
+
);
|
|
770
757
|
}
|
|
771
758
|
}
|
|
772
759
|
});
|
|
@@ -776,7 +763,6 @@ function attachAttributeChangeMutationObserver() {
|
|
|
776
763
|
attributes: true,
|
|
777
764
|
attributeOldValue: true,
|
|
778
765
|
});
|
|
779
|
-
|
|
780
766
|
} catch (e) {
|
|
781
767
|
addAttributeToken(self, ATTRIBUTE_ERRORMESSAGE, e.toString());
|
|
782
768
|
}
|
|
@@ -974,8 +960,7 @@ function parseOptionsJSON(data) {
|
|
|
974
960
|
try {
|
|
975
961
|
let dataUrl = parseDataURL(data);
|
|
976
962
|
data = dataUrl.content;
|
|
977
|
-
} catch (e) {
|
|
978
|
-
}
|
|
963
|
+
} catch (e) {}
|
|
979
964
|
|
|
980
965
|
try {
|
|
981
966
|
obj = JSON.parse(data);
|
package/source/dom/dimension.mjs
CHANGED
|
@@ -75,10 +75,8 @@ function getDeviceDPI() {
|
|
|
75
75
|
*/
|
|
76
76
|
|
|
77
77
|
function convertToPixels(value, parentElement = document.documentElement, fontSizeElement = document.documentElement) {
|
|
78
|
-
|
|
79
78
|
validateString(value);
|
|
80
|
-
|
|
81
|
-
|
|
79
|
+
|
|
82
80
|
const regex = /^(-?[\d.]+)(.*)$/;
|
|
83
81
|
const matchResult = value.match(regex);
|
|
84
82
|
|
|
@@ -5,7 +5,7 @@
|
|
|
5
5
|
* License text available at https://www.gnu.org/licenses/agpl-3.0.en.html
|
|
6
6
|
*/
|
|
7
7
|
|
|
8
|
-
export {extractKeys}
|
|
8
|
+
export { extractKeys };
|
|
9
9
|
|
|
10
10
|
/**
|
|
11
11
|
* Extracts the keys from the given object and returns a map with the keys and values.
|
|
@@ -17,17 +17,21 @@ export {extractKeys}
|
|
|
17
17
|
* @param {string} valueSeparator
|
|
18
18
|
* @returns {Map<any, any>}
|
|
19
19
|
*/
|
|
20
|
-
function extractKeys(obj, keyPrefix =
|
|
20
|
+
function extractKeys(obj, keyPrefix = "", keySeparator = "-", valueSeparator = ".") {
|
|
21
21
|
const resultMap = new Map();
|
|
22
22
|
|
|
23
23
|
function helper(currentObj, currentKeyPrefix, currentValuePrefix) {
|
|
24
24
|
for (const key in currentObj) {
|
|
25
|
-
if (typeof currentObj[key] ===
|
|
26
|
-
const newKeyPrefix = currentKeyPrefix
|
|
25
|
+
if (typeof currentObj[key] === "object" && !Array.isArray(currentObj[key])) {
|
|
26
|
+
const newKeyPrefix = currentKeyPrefix
|
|
27
|
+
? currentKeyPrefix + keySeparator + key.toLowerCase()
|
|
28
|
+
: key.toLowerCase();
|
|
27
29
|
const newValuePrefix = currentValuePrefix ? currentValuePrefix + valueSeparator + key : key;
|
|
28
30
|
helper(currentObj[key], newKeyPrefix, newValuePrefix);
|
|
29
31
|
} else {
|
|
30
|
-
const finalKey = currentKeyPrefix
|
|
32
|
+
const finalKey = currentKeyPrefix
|
|
33
|
+
? currentKeyPrefix + keySeparator + key.toLowerCase()
|
|
34
|
+
: key.toLowerCase();
|
|
31
35
|
const finalValue = currentValuePrefix ? currentValuePrefix + valueSeparator + key : key;
|
|
32
36
|
resultMap.set(finalKey, finalValue);
|
|
33
37
|
}
|
|
@@ -36,4 +40,4 @@ function extractKeys(obj, keyPrefix = '', keySeparator = '-', valueSeparator = '
|
|
|
36
40
|
|
|
37
41
|
helper(obj, keyPrefix, keyPrefix);
|
|
38
42
|
return resultMap;
|
|
39
|
-
}
|
|
43
|
+
}
|