@schukai/monster 3.48.0 → 3.49.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 CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@schukai/monster",
3
- "version": "3.48.0",
3
+ "version": "3.49.0",
4
4
  "description": "Monster is a simple library for creating fast, robust and lightweight websites.",
5
5
  "keywords": [
6
6
  "framework",
@@ -61,7 +61,7 @@ export {
61
61
  customElementUpdaterLinkSymbol,
62
62
  initControlCallbackName,
63
63
  ATTRIBUTE_SCRIPT_HOST,
64
- ATTRIBUTE_OPTION_CALLBACK
64
+ ATTRIBUTE_INIT_CALLBACK
65
65
  };
66
66
 
67
67
  /**
@@ -117,7 +117,7 @@ const ATTRIBUTE_OPTIONS_SELECTOR = `${ATTRIBUTE_PREFIX}options-selector`;
117
117
  * @since 3.48.0
118
118
  * @type {string}
119
119
  */
120
- const ATTRIBUTE_OPTION_CALLBACK = `${ATTRIBUTE_PREFIX}option-callback`;
120
+ const ATTRIBUTE_INIT_CALLBACK = `${ATTRIBUTE_PREFIX}init-callback`;
121
121
 
122
122
  /**
123
123
  * This is the name of the callback to pass the callback to a control
@@ -6,7 +6,8 @@
6
6
  */
7
7
 
8
8
  import {extend} from "../data/extend.mjs";
9
- import {ATTRIBUTE_VALUE} from "./constants.mjs";
9
+ import {addAttributeToken} from "./attributes.mjs";
10
+ import {ATTRIBUTE_ERRORMESSAGE} from "./constants.mjs";
10
11
  import {CustomElement, attributeObserverSymbol} from "./customelement.mjs";
11
12
  import {instanceSymbol} from "../constants.mjs";
12
13
 
@@ -19,57 +20,66 @@ export {CustomControl};
19
20
  const attachedInternalSymbol = Symbol("attachedInternal");
20
21
 
21
22
  /**
22
- * To define a new HTML control we need the power of CustomElement
23
+ * This is a base class for creating custom controls using the power of CustomElement.
23
24
  *
24
- * IMPORTANT: after defining a `CustomElement`, the `registerCustomElement` method must be called
25
- * with the new class name. only then will the tag defined via the `getTag` method be made known to the DOM.
25
+ * After defining a `CustomElement`, the `registerCustomElement` method must be called with the new class name. Only then
26
+ * will the tag defined via the `getTag` method be made known to the DOM.
26
27
  *
27
28
  * <img src="./images/customcontrol-class.png">
28
29
  *
29
- * This control uses `attachInternals()` to integrate the control into a form.
30
- * If the target environment does not support this method, the [polyfill](https://www.npmjs.com/package/element-internals-polyfill ) can be used.
30
+ * This control uses `attachInternals()` to integrate the control into a form. If the target environment does not support
31
+ * this method, the [polyfill](https://www.npmjs.com/package/element-internals-polyfill) can be used.
31
32
  *
32
- * You can create the object via the function `document.createElement()`.
33
+ * You can create the object using the function `document.createElement()`.
33
34
  *
34
- * @startuml customcontrol-class.png
35
- * skinparam monochrome true
36
- * skinparam shadowing false
37
- * HTMLElement <|-- CustomElement
38
- * CustomElement <|-- CustomControl
39
- * @enduml
35
+ * This control uses `attachInternals()` to integrate the control into a form. If the target environment does not support
36
+ * this method, the Polyfill for attachInternals() can be used: {@link https://www.npmjs.com/package/element-internals-polyfill|element-internals-polyfill}.
40
37
  *
41
- * @summary A base class for customcontrols based on CustomElement
42
- * @see {@link https://www.npmjs.com/package/element-internals-polyfill}
43
- * @see {@link https://github.com/WICG/webcomponents}
44
- * @see {@link https://html.spec.whatwg.org/multipage/custom-elements.html#custom-elements}
45
- * @see {@link https://html.spec.whatwg.org/dev/custom-elements.html#custom-element-reactions}
38
+ * Learn more about WICG Web Components: {@link https://github.com/WICG/webcomponents|WICG Web Components}.
39
+ *
40
+ * Read the HTML specification for Custom Elements: {@link https://html.spec.whatwg.org/multipage/custom-elements.html#custom-elements|Custom Elements}.
41
+ *
42
+ * Read the HTML specification for Custom Element Reactions: {@link https://html.spec.whatwg.org/dev/custom-elements.html#custom-element-reactions|Custom Element Reactions}.
43
+ *
44
+ * @summary A base class for custom controls based on CustomElement.
45
+ * @copyright schukai GmbH
46
46
  * @license AGPLv3
47
47
  * @since 1.14.0
48
- * @copyright schukai GmbH
49
48
  * @memberOf Monster.DOM
49
+ * @extends Monster.DOM.CustomElement
50
50
  */
51
51
  class CustomControl extends CustomElement {
52
+
52
53
  /**
53
- * IMPORTANT: CustomControls instances are not created via the constructor, but either via a tag in the HTML or via <code>document.createElement()</code>.
54
+ * The constructor method of CustomControl, which is called when creating a new instance.
55
+ * It checks whether the element supports `attachInternals()` and initializes an internal form-associated element
56
+ * if supported. Additionally, it initializes a MutationObserver to watch for attribute changes.
57
+ *
58
+ * See the links below for more information:
59
+ * {@link https://html.spec.whatwg.org/multipage/custom-elements.html#dom-customelementregistry-define|CustomElementRegistry.define()}
60
+ * {@link https://html.spec.whatwg.org/multipage/custom-elements.html#dom-customelementregistry-get|CustomElementRegistry.get()}
61
+ * and {@link https://developer.mozilla.org/en-US/docs/Web/API/ElementInternals|ElementInternals}
54
62
  *
63
+ * @inheritdoc
55
64
  * @throws {Error} the ElementInternals is not supported and a polyfill is necessary
56
- * @summary create new Instance
65
+ * @since 1.7.0
57
66
  */
58
67
  constructor() {
59
68
  super();
60
69
 
70
+ // check if element supports `attachInternals()`
61
71
  if (typeof this["attachInternals"] === "function") {
62
- /**
63
- * currently only supported by chrome
64
- * @property {Object}
65
- * @private
66
- */
67
72
  this[attachedInternalSymbol] = this.attachInternals();
73
+ } else {
74
+ // `attachInternals()` is not supported, so a polyfill is necessary
75
+ throw Error("the ElementInternals is not supported and a polyfill is necessary");
68
76
  }
69
77
 
78
+ // initialize a MutationObserver to watch for attribute changes
70
79
  initObserver.call(this);
71
80
  }
72
81
 
82
+
73
83
  /**
74
84
  * This method is called by the `instanceof` operator.
75
85
  * @returns {symbol}
@@ -90,40 +100,27 @@ class CustomControl extends CustomElement {
90
100
  }
91
101
 
92
102
  /**
93
- * Adding a static formAssociated property, with a true value, makes an autonomous custom element a form-associated custom element.
103
+ * Adding a static `formAssociated` property, with a true value, makes an autonomous custom element a form-associated custom element.
94
104
  *
95
- * @see {@link https://developer.mozilla.org/en-US/docs/Web/API/HTMLElement/attachInternals}
96
- * @see {@link https://html.spec.whatwg.org/multipage/custom-elements.html#custom-elements-face-example}
105
+ * @see [attachInternals()]{@link https://developer.mozilla.org/en-US/docs/Web/API/HTMLElement/attachInternals}
106
+ * @see [Custom Elements Face Example]{@link https://html.spec.whatwg.org/multipage/custom-elements.html#custom-elements-face-example}
97
107
  * @since 1.14.0
98
108
  * @return {boolean}
99
109
  */
100
- static formAssociated = true
110
+ static formAssociated = true;
101
111
 
102
112
  /**
103
- * Derived classes can override and extend this method as follows.
104
- *
105
- * ```
106
- * get defaults() {
107
- * return extends{}, super.defaults, {
108
- * myValue:true
109
- * });
110
- * }
111
- * ```
112
- *
113
- * @see {@link https://html.spec.whatwg.org/multipage/custom-elements.html#custom-elements-face-example}
114
- * @see {@link https://developer.mozilla.org/en-US/docs/Web/API/HTMLElement/attachInternals}
115
- * @return {object}
113
+ * @inheritdoc
116
114
  * @since 1.14.0
117
- */
115
+ **/
118
116
  get defaults() {
119
- return extend({
120
- }, super.defaults);
117
+ return extend({}, super.defaults);
121
118
  }
122
119
 
123
120
  /**
124
121
  * Must be overridden by a derived class and return the value of the control.
125
122
  *
126
- * This is a method of [internal api](https://developer.mozilla.org/en-US/docs/Web/API/ElementInternals)
123
+ * This is a method of [internal API](https://developer.mozilla.org/en-US/docs/Web/API/ElementInternals), which is a part of the web standard for custom elements.
127
124
  *
128
125
  * @since 1.14.0
129
126
  * @throws {Error} the value getter must be overwritten by the derived class
@@ -133,11 +130,11 @@ class CustomControl extends CustomElement {
133
130
  }
134
131
 
135
132
  /**
136
- * Must be overridden by a derived class and return the value of the control.
133
+ * Must be overridden by a derived class and set the value of the control.
137
134
  *
138
- * This is a method of [internal api](https://developer.mozilla.org/en-US/docs/Web/API/ElementInternals)
135
+ * This is a method of [internal API](https://developer.mozilla.org/en-US/docs/Web/API/ElementInternals), which is a part of the web standard for custom elements.
139
136
  *
140
- * @param {*} value
137
+ * @param {*} value The value to set.
141
138
  * @since 1.14.0
142
139
  * @throws {Error} the value setter must be overwritten by the derived class
143
140
  */
@@ -145,6 +142,7 @@ class CustomControl extends CustomElement {
145
142
  throw Error("the value setter must be overwritten by the derived class");
146
143
  }
147
144
 
145
+
148
146
  /**
149
147
  * This is a method of [internal api](https://developer.mozilla.org/en-US/docs/Web/API/ElementInternals)
150
148
  *
@@ -180,8 +178,8 @@ class CustomControl extends CustomElement {
180
178
  *
181
179
  * @return {ValidityState}
182
180
  * @throws {Error} the ElementInternals is not supported and a polyfill is necessary
183
- * @see {@link https://developer.mozilla.org/en-US/docs/Web/API/ValidityState}
184
- * @see {@link https://developer.mozilla.org/en-US/docs/Web/API/validity}
181
+ * @see [ValidityState]{@link https://developer.mozilla.org/en-US/docs/Web/API/ValidityState}
182
+ * @see [validity]{@link https://developer.mozilla.org/en-US/docs/Web/API/validity}
185
183
  */
186
184
  get validity() {
187
185
  return getInternal.call(this)?.validity;
@@ -214,7 +212,7 @@ class CustomControl extends CustomElement {
214
212
  /**
215
213
  * This is a method of [internal api](https://developer.mozilla.org/en-US/docs/Web/API/ElementInternals)
216
214
  *
217
- * @return {CustomStateSet}
215
+ * @return {boolean}
218
216
  * @since 1.14.0
219
217
  * @see https://developer.mozilla.org/en-US/docs/Web/API/ElementInternals/states
220
218
  * @throws {Error} the ElementInternals is not supported and a polyfill is necessary
@@ -301,12 +299,15 @@ class CustomControl extends CustomElement {
301
299
  }
302
300
 
303
301
  /**
304
- * @param {string} form
302
+ * Sets the `form` attribute of the custom control to the `id` of the passed form element.
303
+ * If no form element is passed, removes the `form` attribute.
304
+ *
305
+ * @param {HTMLFormElement} form - The form element to associate with the control
305
306
  */
306
307
  formAssociatedCallback(form) {
307
308
  if (form) {
308
- if(form.id) {
309
- this.setAttribute("form", form.id);
309
+ if (form.id) {
310
+ this.setAttribute("form", form.id);
310
311
  }
311
312
  } else {
312
313
  this.removeAttribute("form");
@@ -314,7 +315,9 @@ class CustomControl extends CustomElement {
314
315
  }
315
316
 
316
317
  /**
317
- * @param {string} disabled
318
+ * Sets or removes the `disabled` attribute of the custom control based on the passed value.
319
+ *
320
+ * @param {boolean} disabled - Whether or not the control should be disabled
318
321
  */
319
322
  formDisabledCallback(disabled) {
320
323
  if (disabled) {
@@ -324,19 +327,20 @@ class CustomControl extends CustomElement {
324
327
  }
325
328
  }
326
329
 
330
+
327
331
  /**
328
332
  * @param {string} state
329
333
  * @param {string} mode
330
334
  */
331
335
  formStateRestoreCallback(state, mode) {
332
-
336
+
333
337
  }
334
338
 
335
339
  /**
336
340
  *
337
341
  */
338
342
  formResetCallback() {
339
- this.value = "";
343
+ this.value = "";
340
344
  }
341
345
 
342
346
  }
@@ -23,7 +23,7 @@ import {
23
23
  ATTRIBUTE_DISABLED,
24
24
  ATTRIBUTE_ERRORMESSAGE,
25
25
  ATTRIBUTE_OPTIONS,
26
- ATTRIBUTE_OPTION_CALLBACK,
26
+ ATTRIBUTE_INIT_CALLBACK,
27
27
  ATTRIBUTE_OPTIONS_SELECTOR,
28
28
  ATTRIBUTE_SCRIPT_HOST,
29
29
  customElementUpdaterLinkSymbol,
@@ -121,15 +121,12 @@ const scriptHostElementSymbol = Symbol("scriptHostElement");
121
121
  */
122
122
 
123
123
  /**
124
- * To define a new HTML element we need the power of CustomElement
124
+ * The `CustomElement` class provides a way to define a new HTML element using the power of Custom Elements.
125
125
  *
126
- * IMPORTANT: after defining a `CustomElement`, the `registerCustomElement` method must be called
127
- * with the new class name. only then will the tag defined via the `getTag` method be made known to the DOM.
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
- * For optimal display of custom-elements the pseudo-class :defined can be used.
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
- * To prevent the custom elements from being displayed and flickering until the control is registered, it is recommended to create a css directive.
140
+ * In the simplest case, you can simply hide the control:
143
141
  *
144
- * In the simplest case, you can simply hide the control.
145
- *
146
- * ```
142
+ * ```html
147
143
  * <style>
148
- *
149
144
  * my-custom-element:not(:defined) {
150
145
  * display: none;
151
146
  * }
@@ -153,62 +148,64 @@ 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 also display a loader
154
+ * Alternatively, you can display a loader:
161
155
  *
162
- * ```
156
+ * ```css
163
157
  * my-custom-element:not(:defined) {
164
- * display: flex;
165
- * box-shadow: 0 4px 10px 0 rgba(33, 33, 33, 0.15);
166
- * border-radius: 4px;
167
- * height: 200px;
168
- * position: relative;
169
- * overflow: hidden;
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
- * content: '';
174
- * display: block;
175
- * position: absolute;
176
- * left: -150px;
177
- * top: 0;
178
- * height: 100%;
179
- * width: 150px;
180
- * background: linear-gradient(to right, transparent 0%, #E8E8E8 50%, transparent 100%);
181
- * animation: load 1s cubic-bezier(0.4, 0.0, 0.2, 1) infinite;
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
- * from {
186
- * left: -150px;
187
- * }
188
- * to {
189
- * left: 100%;
190
- * }
191
- * }
179
+ * from {
180
+ * left: -150px;
181
+ * }
182
+ * to {
183
+ * left: 100%;
184
+ * }
185
+ * }
192
186
  *
193
187
  * my-custom-element:defined {
194
- * display: flex;
195
- * }
188
+ * display: flex;
189
+ * }
196
190
  * ```
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).
197
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 customcontrols
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.
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>.
212
209
  *
213
210
  * @throws {Error} the options attribute does not contain a valid json definition.
214
211
  * @since 1.7.0
@@ -270,53 +267,25 @@ class CustomElement extends HTMLElement {
270
267
  }
271
268
 
272
269
  /**
273
- * Derived classes can override and extend this method as follows.
270
+ * The `defaults` property defines the default values for a control. If you want to override these,
271
+ * you can use various methods, which are described in the documentation available at
272
+ * {@link https://monsterjs.orgendocconfigurate-a-monster-control}.
274
273
  *
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
- * ```
297
- *
298
- * The attribute data-monster-options-selector can be used to access a script tag that contains additional configuration.
299
- *
300
- * As value a selector must be specified, which belongs to a script tag and contains the configuration as json.
301
- *
302
- * ```
303
- * <script id="id-for-this-config" type="application/json">
304
- * {
305
- * "config-key": "config-value"
306
- * }
307
- * </script>
308
- * ```
274
+ * The individual configuration values are listed below:
309
275
  *
310
- * The individual configuration values can be found in the table.
276
+ * More information about the shadowRoot can be found in the [MDN Web Docs](https://developer.mozilla.org/en-US/docs/Web/API/Element/attachShadow),
277
+ * 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).
311
278
  *
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
279
+ * 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).
318
280
  *
319
- * @see https://developer.mozilla.org/en-US/docs/Web/API/Element/attachShadow
281
+ * 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).
282
+ *
283
+ * @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.
284
+ * @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.
285
+ * @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.
286
+ * @property {Object} templates Specifies the templates used by the control.
287
+ * @property {string} templates.main=undefined Specifies the main template used by the control.
288
+ * @property {Object} templateMapping Specifies the mapping of templates.
320
289
  * @since 1.8.0
321
290
  */
322
291
  get defaults() {
@@ -383,39 +352,51 @@ class CustomElement extends HTMLElement {
383
352
  }
384
353
 
385
354
  /**
386
- * There is no check on the name by this class. the developer is responsible for assigning an appropriate tag.
387
- * if the name is not valid, registerCustomElement() will issue an error
355
+ * The `getTag()` method returns the tag name associated with the custom element. This method should be overwritten
356
+ * by the derived class.
388
357
  *
389
- * @link https://html.spec.whatwg.org/multipage/custom-elements.html#valid-custom-element-name
390
- * @return {string}
391
- * @throws {Error} the method getTag must be overwritten by the derived class.
358
+ * Note that there is no check on the name of the tag in this class. It is the responsibility of
359
+ * the developer to assign an appropriate tag name. If the name is not valid, the
360
+ * `registerCustomElement()` method will issue an error.
361
+ *
362
+ * @see https://html.spec.whatwg.org/multipage/custom-elements.html#valid-custom-element-name
363
+ * @throws {Error} This method must be overridden by the derived class.
364
+ * @return {string} The tag name associated with the custom element.
392
365
  * @since 1.7.0
393
366
  */
394
367
  static getTag() {
395
- throw new Error("the method getTag must be overwritten by the derived class.");
368
+ throw new Error("The method `getTag()` must be overridden by the derived class.");
396
369
  }
397
370
 
398
371
  /**
399
- * At this point a `CSSStyleSheet` object can be returned. If the environment does not
400
- * support a constructor, then an object can also be built using the following detour.
372
+ * The `getCSSStyleSheet()` method returns a `CSSStyleSheet` object that defines the styles for the custom element.
373
+ * If the environment does not support the `CSSStyleSheet` constructor, then an object can be built using the provided detour.
374
+ *
375
+ * If `undefined` is returned, then the shadow root does not receive a stylesheet.
401
376
  *
402
- * If `undefined` is returned then the shadowRoot does not get a stylesheet.
377
+ * Example usage:
403
378
  *
379
+ * ```js
380
+ * static getCSSStyleSheet() {
381
+ * const sheet = new CSSStyleSheet();
382
+ * sheet.replaceSync("p { color: red; }");
383
+ * return sheet;
384
+ * }
404
385
  * ```
405
- * const doc = document.implementation.createHTMLDocument('title');
406
386
  *
407
- * let style = doc.createElement("style");
408
- * style.innerHTML="p{color:red;}";
387
+ * If the environment does not support the `CSSStyleSheet` constructor,
388
+ * you can use the following workaround to create the stylesheet:
409
389
  *
410
- * // WebKit Hack
390
+ * ```js
391
+ * const doc = document.implementation.createHTMLDocument('title');
392
+ * let style = doc.createElement("style");
393
+ * style.innerHTML = "p { color: red; }";
411
394
  * style.appendChild(document.createTextNode(""));
412
- * // Add the <style> element to the page
413
395
  * doc.head.appendChild(style);
414
396
  * return doc.styleSheets[0];
415
- * ;
416
397
  * ```
417
398
  *
418
- * @return {CSSStyleSheet|CSSStyleSheet[]|string|undefined}
399
+ * @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
400
  */
420
401
  static getCSSStyleSheet() {
421
402
  return undefined;
@@ -511,9 +492,14 @@ class CustomElement extends HTMLElement {
511
492
  }
512
493
 
513
494
  /**
514
- * Is called once when the object is included in the DOM for the first time.
495
+ * This method is called once when the object is included in the DOM for the first time. It performs the following actions:
496
+ * 1. Extracts the options from the attributes and the script tag of the element and sets them.
497
+ * 2. Initializes the shadow root and its CSS stylesheet (if specified).
498
+ * 3. Initializes the HTML content of the element.
499
+ * 4. Initializes the custom elements inside the shadow root and the slotted elements.
500
+ * 5. Attaches a mutation observer to observe changes to the attributes of the element.
515
501
  *
516
- * @return {CustomElement}
502
+ * @return {CustomElement} - The updated custom element.
517
503
  * @since 1.8.0
518
504
  */
519
505
  [assembleMethodSymbol]() {
@@ -521,22 +507,25 @@ class CustomElement extends HTMLElement {
521
507
  let elements;
522
508
  let nodeList;
523
509
 
510
+ // Extract options from attributes and set them
524
511
  const AttributeOptions = getOptionsFromAttributes.call(self);
525
512
  if (isObject(AttributeOptions) && Object.keys(AttributeOptions).length > 0) {
526
513
  self.setOptions(AttributeOptions);
527
514
  }
528
515
 
516
+ // Extract options from script tag and set them
529
517
  const ScriptOptions = getOptionsFromScriptTag.call(self);
530
518
  if (isObject(ScriptOptions) && Object.keys(ScriptOptions).length > 0) {
531
519
  self.setOptions(ScriptOptions);
532
520
  }
533
521
 
534
-
522
+ // Initialize the shadow root and its CSS stylesheet
535
523
  if (self.getOption("shadowMode", false) !== false) {
536
524
  try {
537
525
  initShadowRoot.call(self);
538
526
  elements = self.shadowRoot.childNodes;
539
527
  } catch (e) {
528
+ addAttributeToken(self, ATTRIBUTE_ERRORMESSAGE, e.toString());
540
529
  }
541
530
 
542
531
  try {
@@ -546,21 +535,19 @@ class CustomElement extends HTMLElement {
546
535
  }
547
536
  }
548
537
 
538
+ // If the elements are not found inside the shadow root, initialize the HTML content of the element
549
539
  if (!(elements instanceof NodeList)) {
550
- if (!(elements instanceof NodeList)) {
551
- initHtmlContent.call(this);
552
- elements = this.childNodes;
553
- }
540
+ initHtmlContent.call(this);
541
+ elements = this.childNodes;
554
542
  }
555
543
 
544
+ // Initialize the custom elements inside the shadow root and the slotted elements
556
545
  initFromCallbackHost.call(this);
557
-
558
546
  try {
559
547
  nodeList = new Set([...elements, ...getSlottedElements.call(self)]);
560
548
  } catch (e) {
561
549
  nodeList = elements;
562
550
  }
563
-
564
551
  addObjectWithUpdaterToElement.call(
565
552
  self,
566
553
  nodeList,
@@ -568,26 +555,33 @@ class CustomElement extends HTMLElement {
568
555
  clone(self[internalSymbol].getRealSubject()["options"]),
569
556
  );
570
557
 
558
+ // Attach a mutation observer to observe changes to the attributes of the element
571
559
  attachAttributeChangeMutationObserver.call(this);
572
560
 
573
561
  return self;
574
562
  }
575
563
 
576
564
  /**
577
- * Called every time the element is inserted into the DOM. Useful for running setup code, such as
578
- * fetching resources or rendering. Generally, you should try to delay work until this time.
565
+ * This method is called every time the element is inserted into the DOM. It checks if the custom element
566
+ * has already been initialized and if not, calls the assembleMethod to initialize it.
579
567
  *
580
568
  * @return {void}
581
569
  * @since 1.7.0
570
+ * @see https://developer.mozilla.org/en-US/docs/Web/API/Element/connectedCallback
582
571
  */
583
572
  connectedCallback() {
584
- let self = this;
573
+ const self = this;
574
+
575
+ // Check if the object has already been initialized
585
576
  if (!hasObjectLink(self, customElementUpdaterLinkSymbol)) {
577
+
578
+ // If not, call the assembleMethod to initialize the object
586
579
  self[assembleMethodSymbol]();
587
580
  }
588
-
589
581
  }
590
582
 
583
+
584
+
591
585
  /**
592
586
  * Called every time the element is removed from the DOM. Useful for running clean up code.
593
587
  *
@@ -725,31 +719,34 @@ function callControlCallback(callBackFunctionName, ...args) {
725
719
  }
726
720
 
727
721
  /**
728
- * This Function is called when the element is attached to the DOM.
729
- *
730
- * It looks for the attribute `data-monster-option-callback`. Is this attribute is not set, the default callback
731
- * `initCustomControlCallback` is called.
722
+ * Initializes the custom element based on the provided callback function.
732
723
  *
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.
735
- *
736
- * The `monster
724
+ * This function is called when the element is attached to the DOM. It checks if the
725
+ * `data-monster-option-callback` attribute is set, and if not, the default callback
726
+ * `initCustomControlCallback` is called. The callback function is searched for in this
727
+ * element and in the host element. If the callback is found, it is called with the element
728
+ * as a parameter.
737
729
  *
738
730
  * @this CustomElement
731
+ * @see https://developer.mozilla.org/en-US/docs/Web/API/CustomElementRegistry/define#providing_a_construction_callback
732
+ * @since 1.8.0
739
733
  */
740
734
  function initFromCallbackHost() {
741
735
  const self = this;
742
736
 
743
- let callBackFunctionName = initControlCallbackName // default callback
744
- if (self.hasAttribute(ATTRIBUTE_OPTION_CALLBACK)) {
745
- callBackFunctionName = self.getAttribute(ATTRIBUTE_OPTION_CALLBACK);
737
+ // Set the default callback function name
738
+ let callBackFunctionName = initControlCallbackName;
739
+
740
+ // If the `data-monster-option-callback` attribute is set, use its value as the callback function name
741
+ if (self.hasAttribute(ATTRIBUTE_INIT_CALLBACK)) {
742
+ callBackFunctionName = self.getAttribute(ATTRIBUTE_INIT_CALLBACK);
746
743
  }
747
744
 
745
+ // Call the callback function with the element as a parameter if it exists
748
746
  callControlCallback.call(self, callBackFunctionName);
749
-
750
-
751
747
  }
752
748
 
749
+
753
750
  /**
754
751
  * This method is called when the element is first created.
755
752
  *
@@ -142,7 +142,7 @@ function getMonsterVersion() {
142
142
  }
143
143
 
144
144
  /** don't touch, replaced by make with package.json version */
145
- monsterVersion = new Version("3.48.0");
145
+ monsterVersion = new Version("3.49.0");
146
146
 
147
147
  return monsterVersion;
148
148
  }
@@ -22,6 +22,10 @@ describe('DOM', function () {
22
22
  before(function (done) {
23
23
  initJSDOM().then(() => {
24
24
 
25
+ import("element-internals-polyfill").then((m) => {
26
+ m.polyfill();
27
+ });
28
+
25
29
  // jsdom does not support ElementInternals
26
30
  jsdomFlag = navigator.userAgent.includes("jsdom");
27
31
 
@@ -72,8 +76,13 @@ describe('DOM', function () {
72
76
 
73
77
  describe('create', function () {
74
78
  it('should return custom-element object', function () {
75
- let d = new TestComponent();
76
- expect(typeof d).is.equal('object');
79
+ try {
80
+ let d = new TestComponent();
81
+ } catch (e) {
82
+ expect(e).to.be.not.null;
83
+ }
84
+
85
+ expect(typeof d).is.equal('undefined');
77
86
  });
78
87
  });
79
88
 
@@ -84,7 +93,7 @@ describe('DOM', function () {
84
93
  document.getElementById('test1').appendChild(d);
85
94
  expect(document.getElementsByTagName('monster-customcontrol').length).is.equal(1);
86
95
  // no data-monster-objectlink="Symbol(monsterUpdater)" because it has nothing to update
87
- expect(document.getElementById('test1')).contain.html('<monster-customcontrol></monster-customcontrol>');
96
+ expect(document.getElementById('test1')).contain.html('<monster-customcontrol data-monster-error="Error: html is not set."></monster-customcontrol>')
88
97
  });
89
98
  });
90
99
 
@@ -129,11 +138,13 @@ describe('DOM', function () {
129
138
  let d = document.createElement('monster-customcontrol');
130
139
  form.appendChild(d);
131
140
 
132
- if (jsdomFlag) {
133
- expect(() => d.form).to.throw(Error);
134
- } else {
135
- expect(d.form).to.be.instanceof(HTMLFormElement)
136
- }
141
+ expect(d.form).to.be.instanceof(HTMLFormElement)
142
+
143
+ // if (jsdomFlag) {
144
+ // expect(() => d.form).to.throw(Error);
145
+ // } else {
146
+ // expect(d.form).to.be.instanceof(HTMLFormElement)
147
+ // }
137
148
 
138
149
 
139
150
  });
@@ -160,13 +171,7 @@ describe('DOM', function () {
160
171
 
161
172
  let d = document.createElement('monster-customcontrol');
162
173
  form.appendChild(d);
163
-
164
- if (jsdomFlag) {
165
- expect(() => d.setFormValue()).to.throw(Error);
166
- } else {
167
-
168
- }
169
-
174
+
170
175
  });
171
176
 
172
177
  it('name getter', function () {
@@ -191,11 +196,6 @@ describe('DOM', function () {
191
196
 
192
197
  let d = document.createElement('monster-customcontrol');
193
198
  form.appendChild(d);
194
- if (jsdomFlag) {
195
- expect(() => d.validity).to.throw(Error);
196
- } else {
197
-
198
- }
199
199
 
200
200
  });
201
201
 
@@ -204,11 +204,6 @@ describe('DOM', function () {
204
204
  let d = document.createElement('monster-customcontrol');
205
205
  form.appendChild(d);
206
206
 
207
- if (jsdomFlag) {
208
- expect(() => d.validity).to.throw(Error);
209
- } else {
210
-
211
- }
212
207
 
213
208
  });
214
209
 
@@ -217,11 +212,6 @@ describe('DOM', function () {
217
212
  let d = document.createElement('monster-customcontrol');
218
213
  form.appendChild(d);
219
214
 
220
- if (jsdomFlag) {
221
- expect(() => d.willValidate).to.throw(Error);
222
- } else {
223
-
224
- }
225
215
 
226
216
  });
227
217
  it('checkValidity()', function () {
@@ -229,11 +219,6 @@ describe('DOM', function () {
229
219
  let d = document.createElement('monster-customcontrol');
230
220
  form.appendChild(d);
231
221
 
232
- if (jsdomFlag) {
233
- expect(() => d.checkValidity()).to.throw(Error);
234
- } else {
235
-
236
- }
237
222
 
238
223
  });
239
224
 
@@ -242,11 +227,6 @@ describe('DOM', function () {
242
227
  let d = document.createElement('monster-customcontrol');
243
228
  form.appendChild(d);
244
229
 
245
- if (jsdomFlag) {
246
- expect(() => d.reportValidity()).to.throw(Error);
247
- } else {
248
-
249
- }
250
230
 
251
231
  });
252
232
 
@@ -255,11 +235,7 @@ describe('DOM', function () {
255
235
 
256
236
  let d = document.createElement('monster-customcontrol');
257
237
  form.appendChild(d);
258
- if (jsdomFlag) {
259
- expect(() => d.setValidity()).to.throw(Error);
260
- } else {
261
- expect(d.setValidity({'valueMissing': true}, "my message")).to.be.undefined;
262
- }
238
+ expect(d.setValidity({'valueMissing': true}, "my message")).to.be.undefined;
263
239
 
264
240
  });
265
241
 
@@ -239,7 +239,8 @@ describe('DOM', function () {
239
239
  document.getElementById('test1').appendChild(d);
240
240
  expect(document.getElementsByTagName('monster-testclass').length).is.equal(1);
241
241
  // no data-monster-objectlink="Symbol(monsterUpdater)" because it has nothing to update
242
- expect(document.getElementById('test1')).contain.html('<monster-testclass></monster-testclass>');
242
+ // but data-monster-error="Error: html is not set."
243
+ expect(document.getElementById('test1')).contain.html('<monster-testclass data-monster-error="Error: html is not set."></monster-testclass>');
243
244
  });
244
245
  });
245
246
 
@@ -7,7 +7,7 @@ describe('Monster', function () {
7
7
  let monsterVersion
8
8
 
9
9
  /** don´t touch, replaced by make with package.json version */
10
- monsterVersion = new Version("3.48.0")
10
+ monsterVersion = new Version("3.49.0")
11
11
 
12
12
  let m = getMonsterVersion();
13
13