@schukai/monster 3.48.0 → 3.50.0
Sign up to get free protection for your applications and to get access to all the features.
- 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
|
+
}
|