@schukai/monster 3.97.1 → 3.98.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.
Files changed (30) hide show
  1. package/CHANGELOG.md +12 -0
  2. package/package.json +1 -1
  3. package/source/components/accessibility/locale-picker.mjs +549 -543
  4. package/source/components/datatable/columnbar.mjs +50 -3
  5. package/source/components/datatable/constants.mjs +7 -0
  6. package/source/components/datatable/datatable/header.mjs +1 -0
  7. package/source/components/datatable/datatable.mjs +1168 -934
  8. package/source/components/datatable/filter/date-range.mjs +145 -14
  9. package/source/components/datatable/filter/input.mjs +50 -3
  10. package/source/components/datatable/filter/range.mjs +92 -7
  11. package/source/components/datatable/filter-button.mjs +46 -3
  12. package/source/components/datatable/filter.mjs +95 -10
  13. package/source/components/datatable/pagination.mjs +82 -7
  14. package/source/components/datatable/save-button.mjs +46 -3
  15. package/source/components/datatable/style/datatable.pcss +1 -0
  16. package/source/components/datatable/stylesheet/datatable.mjs +7 -14
  17. package/source/components/form/field-set.mjs +77 -6
  18. package/source/components/form/select.mjs +149 -30
  19. package/source/components/layout/details.mjs +50 -3
  20. package/source/components/layout/tabs.mjs +50 -3
  21. package/source/components/notify/monitor-attribute-errors.mjs +235 -0
  22. package/source/components/notify/style/monitor-attribute-errors.pcss +0 -0
  23. package/source/components/notify/stylesheet/monitor-attribute-errors.mjs +38 -0
  24. package/source/dom/customelement.mjs +3 -3
  25. package/source/i18n/util.mjs +122 -122
  26. package/source/types/version.mjs +1 -1
  27. package/test/cases/monster.mjs +1 -1
  28. package/test/web/import.js +1 -0
  29. package/test/web/test.html +2 -2
  30. package/test/web/tests.js +432 -13
@@ -28,6 +28,7 @@ import { isFunction } from "../../types/is.mjs";
28
28
  import { FieldSetStyleSheet } from "./stylesheet/field-set.mjs";
29
29
  import "../layout/collapse.mjs";
30
30
  import "./toggle-switch.mjs";
31
+ import {getLocaleOfDocument} from "../../dom/locale.mjs";
31
32
 
32
33
  export { FieldSet };
33
34
 
@@ -120,12 +121,7 @@ class FieldSet extends CustomControl {
120
121
  templates: {
121
122
  main: getTemplate(),
122
123
  },
123
- labels: {
124
- toggleSwitchOn: "✔",
125
- toggleSwitchOff: "✖",
126
- toggleSwitchLabel: "Expand",
127
- title: "",
128
- },
124
+ labels:getTranslations(),
129
125
  classes: {},
130
126
  disabled: false,
131
127
  features: {
@@ -246,6 +242,81 @@ class FieldSet extends CustomControl {
246
242
  }
247
243
  }
248
244
 
245
+ /**
246
+ * @private
247
+ * @returns {object}
248
+ */
249
+ function getTranslations() {
250
+ const locale = getLocaleOfDocument();
251
+ switch (locale.language) {
252
+ case 'de':
253
+ return {
254
+ toggleSwitchOn: "✔",
255
+ toggleSwitchOff: "✖",
256
+ toggleSwitchLabel: "Erweitern",
257
+ title: ""
258
+ };
259
+ case 'fr':
260
+ return {
261
+ toggleSwitchOn: "✔",
262
+ toggleSwitchOff: "✖",
263
+ toggleSwitchLabel: "Développer",
264
+ title: ""
265
+ };
266
+ case 'sp':
267
+ return {
268
+ toggleSwitchOn: "✔",
269
+ toggleSwitchOff: "✖",
270
+ toggleSwitchLabel: "Expandir",
271
+ title: ""
272
+ };
273
+ case 'it':
274
+ return {
275
+ toggleSwitchOn: "✔",
276
+ toggleSwitchOff: "✖",
277
+ toggleSwitchLabel: "Espandi",
278
+ title: ""
279
+ };
280
+ case 'pl':
281
+ return {
282
+ toggleSwitchOn: "✔",
283
+ toggleSwitchOff: "✖",
284
+ toggleSwitchLabel: "Rozwiń",
285
+ title: ""
286
+ };
287
+ case 'no':
288
+ return {
289
+ toggleSwitchOn: "✔",
290
+ toggleSwitchOff: "✖",
291
+ toggleSwitchLabel: "Utvid",
292
+ title: ""
293
+ };
294
+ case 'dk':
295
+ return {
296
+ toggleSwitchOn: "✔",
297
+ toggleSwitchOff: "✖",
298
+ toggleSwitchLabel: "Udvid",
299
+ title: ""
300
+ };
301
+ case 'sw':
302
+ return {
303
+ toggleSwitchOn: "✔",
304
+ toggleSwitchOff: "✖",
305
+ toggleSwitchLabel: "Expandera",
306
+ title: ""
307
+ };
308
+ default:
309
+ case 'en':
310
+ return {
311
+ toggleSwitchOn: "✔",
312
+ toggleSwitchOff: "✖",
313
+ toggleSwitchLabel: "Expand",
314
+ title: ""
315
+ };
316
+ }
317
+ }
318
+
319
+
249
320
  /**
250
321
  * @private
251
322
  */
@@ -61,6 +61,7 @@ import {
61
61
  getDocumentTranslations,
62
62
  Translations,
63
63
  } from "../../i18n/translations.mjs";
64
+ import {getLocaleOfDocument} from "../../dom/locale.mjs";
64
65
 
65
66
  export {
66
67
  Select,
@@ -69,18 +70,6 @@ export {
69
70
  getSelectionTemplate,
70
71
  };
71
72
 
72
- /**
73
- * @private
74
- * @type {string}
75
- */
76
- const noOptionsAvailableMessage = "No options available.";
77
-
78
- /**
79
- * @private
80
- * @type {string}
81
- */
82
- const clickToLoadOptionsMessage = "Click to load options.";
83
-
84
73
  /**
85
74
  * @private
86
75
  * @type {Symbol}
@@ -438,22 +427,7 @@ class Select extends CustomControl {
438
427
  url: null,
439
428
  grouping: false,
440
429
  },
441
- labels: {
442
- "cannot-be-loaded": "Cannot be loaded",
443
- "no-options-available": noOptionsAvailableMessage,
444
- "click-to-load-options": clickToLoadOptionsMessage,
445
- "select-an-option": "Select an option",
446
- "summary-text": {
447
- zero: "No entries were selected",
448
- one: '<span class="monster-badge-primary-pill">1</span> entry was selected',
449
- other:
450
- '<span class="monster-badge-primary-pill">${count}</span> entries were selected',
451
- },
452
- "no-options":
453
- "Unfortunately, there are no options available in the list.",
454
- "no-options-found":
455
- "No options are available in the list. Please consider modifying the filter.",
456
- },
430
+ labels: getTranslations(),
457
431
  messages: {
458
432
  control: null,
459
433
  selected: null,
@@ -778,6 +752,147 @@ class Select extends CustomControl {
778
752
  }
779
753
  }
780
754
 
755
+ /**
756
+ * @private
757
+ * @returns {object}
758
+ */
759
+ function getTranslations() {
760
+ const locale = getLocaleOfDocument();
761
+ switch (locale.language) {
762
+ case 'de':
763
+ return {
764
+ "cannot-be-loaded": "Kann nicht geladen werden",
765
+ "no-options-available": "Keine Optionen verfügbar.",
766
+ "click-to-load-options": "Klicken, um Optionen zu laden.",
767
+ "select-an-option": "Wähle eine Option",
768
+ "summary-text": {
769
+ zero: "Keine Einträge ausgewählt",
770
+ one: '<span class="monster-badge-primary-pill">1</span> Eintrag ausgewählt',
771
+ other: '<span class="monster-badge-primary-pill">${count}</span> Einträge ausgewählt',
772
+ },
773
+ "no-options": "Leider gibt es keine Optionen in der Liste.",
774
+ "no-options-found": "Keine Optionen in der Liste verfügbar. Bitte ändern Sie den Filter."
775
+ };
776
+ case 'fr':
777
+ return {
778
+ "cannot-be-loaded": "Impossible de charger",
779
+ "no-options-available": "Aucune option disponible.",
780
+ "click-to-load-options": "Cliquez pour charger les options.",
781
+ "select-an-option": "Sélectionnez une option",
782
+ "summary-text": {
783
+ zero: "Aucune entrée sélectionnée",
784
+ one: '<span class="monster-badge-primary-pill">1</span> entrée sélectionnée',
785
+ other: '<span class="monster-badge-primary-pill">${count}</span> entrées sélectionnées',
786
+ },
787
+ "no-options": "Malheureusement, il n'y a pas d'options disponibles dans la liste.",
788
+ "no-options-found": "Aucune option disponible dans la liste. Veuillez modifier le filtre."
789
+ };
790
+
791
+ case 'sp':
792
+ return {
793
+ "cannot-be-loaded": "No se puede cargar",
794
+ "no-options-available": "No hay opciones disponibles.",
795
+ "click-to-load-options": "Haga clic para cargar opciones.",
796
+ "select-an-option": "Seleccione una opción",
797
+ "summary-text": {
798
+ zero: "No se seleccionaron entradas",
799
+ one: '<span class="monster-badge-primary-pill">1</span> entrada seleccionada',
800
+ other: '<span class="monster-badge-primary-pill">${count}</span> entradas seleccionadas',
801
+ },
802
+ "no-options": "Desafortunadamente, no hay opciones disponibles en la lista.",
803
+ "no-options-found": "No hay opciones disponibles en la lista. Considere modificar el filtro."
804
+ };
805
+ case 'it':
806
+ return {
807
+ "cannot-be-loaded": "Non può essere caricato",
808
+ "no-options-available": "Nessuna opzione disponibile.",
809
+ "click-to-load-options": "Clicca per caricare le opzioni.",
810
+ "select-an-option": "Seleziona un'opzione",
811
+ "summary-text": {
812
+ zero: "Nessuna voce selezionata",
813
+ one: '<span class="monster-badge-primary-pill">1</span> voce selezionata',
814
+ other: '<span class="monster-badge-primary-pill">${count}</span> voci selezionate',
815
+ },
816
+ "no-options": "Purtroppo, non ci sono opzioni disponibili nella lista.",
817
+ "no-options-found": "Nessuna opzione disponibile nella lista. Si prega di modificare il filtro."
818
+ };
819
+ case 'pl':
820
+ return {
821
+ "cannot-be-loaded": "Nie można załadować",
822
+ "no-options-available": "Brak dostępnych opcji.",
823
+ "click-to-load-options": "Kliknij, aby załadować opcje.",
824
+ "select-an-option": "Wybierz opcję",
825
+ "summary-text": {
826
+ zero: "Nie wybrano żadnych wpisów",
827
+ one: '<span class="monster-badge-primary-pill">1</span> wpis został wybrany',
828
+ other: '<span class="monster-badge-primary-pill">${count}</span> wpisy zostały wybrane',
829
+ },
830
+ "no-options": "Niestety, nie ma dostępnych opcji na liście.",
831
+ "no-options-found": "Brak dostępnych opcji na liście. Rozważ zmianę filtra."
832
+ };
833
+ case 'no':
834
+ return {
835
+ "cannot-be-loaded": "Kan ikke lastes",
836
+ "no-options-available": "Ingen alternativer tilgjengelig.",
837
+ "click-to-load-options": "Klikk for å laste alternativer.",
838
+ "select-an-option": "Velg et alternativ",
839
+ "summary-text": {
840
+ zero: "Ingen oppføringer ble valgt",
841
+ one: '<span class="monster-badge-primary-pill">1</span> oppføring valgt',
842
+ other: '<span class="monster-badge-primary-pill">${count}</span> oppføringer valgt',
843
+ },
844
+ "no-options": "Dessverre er det ingen alternativer tilgjengelig i listen.",
845
+ "no-options-found": "Ingen alternativer tilgjengelig på listen. Vurder å endre filteret."
846
+ };
847
+
848
+ case 'dk':
849
+ return {
850
+ "cannot-be-loaded": "Kan ikke indlæses",
851
+ "no-options-available": "Ingen muligheder tilgængelige.",
852
+ "click-to-load-options": "Klik for at indlæse muligheder.",
853
+ "select-an-option": "Vælg en mulighed",
854
+ "summary-text": {
855
+ zero: "Ingen indlæg blev valgt",
856
+ one: '<span class="monster-badge-primary-pill">1</span> indlæg blev valgt',
857
+ other: '<span class="monster-badge-primary-pill">${count}</span> indlæg blev valgt',
858
+ },
859
+ "no-options": "Desværre er der ingen muligheder tilgængelige på listen.",
860
+ "no-options-found": "Ingen muligheder tilgængelige på listen. Overvej at ændre filteret."
861
+ };
862
+ case 'sw':
863
+ return {
864
+ "cannot-be-loaded": "Kan inte laddas",
865
+ "no-options-available": "Inga alternativ tillgängliga.",
866
+ "click-to-load-options": "Klicka för att ladda alternativ.",
867
+ "select-an-option": "Välj ett alternativ",
868
+ "summary-text": {
869
+ zero: "Inga poster valdes",
870
+ one: '<span class="monster-badge-primary-pill">1</span> post valdes',
871
+ other: '<span class="monster-badge-primary-pill">${count}</span> poster valdes',
872
+ },
873
+ "no-options": "Tyvärr finns det inga alternativ tillgängliga i listan.",
874
+ "no-options-found": "Inga alternativ finns tillgängliga i listan. Överväg att modifiera filtret."
875
+ };
876
+
877
+ default:
878
+ case 'en':
879
+ return {
880
+ "cannot-be-loaded": "Cannot be loaded",
881
+ "no-options-available": "No options available.",
882
+ "click-to-load-options": "Click to load options.",
883
+ "select-an-option": "Select an option",
884
+ "summary-text": {
885
+ zero: "No entries were selected",
886
+ one: '<span class="monster-badge-primary-pill">1</span> entry was selected',
887
+ other: '<span class="monster-badge-primary-pill">${count}</span> entries were selected',
888
+ },
889
+ "no-options": "Unfortunately, there are no options available in the list.",
890
+ "no-options-found": "No options are available in the list. Please consider modifying the filter."
891
+ };
892
+ }
893
+ }
894
+
895
+
781
896
  /**
782
897
  * @private
783
898
  */
@@ -1192,6 +1307,10 @@ function initOptionObserver() {
1192
1307
  );
1193
1308
  }
1194
1309
 
1310
+ /**
1311
+ * @private
1312
+ * @returns {Translations}
1313
+ */
1195
1314
  function getDefaultTranslation() {
1196
1315
  const translation = new Translations("en").assignTranslations(
1197
1316
  this.getOption("labels", {}),
@@ -1906,7 +2025,7 @@ function areOptionsAvailableAndInit() {
1906
2025
  if (this.getOption("features.emptyValueIfNoOptions") === true) {
1907
2026
  this.value = "";
1908
2027
  }
1909
- addAttributeToken(this, ATTRIBUTE_ERRORMESSAGE, noOptionsAvailableMessage);
2028
+ addAttributeToken(this, ATTRIBUTE_ERRORMESSAGE, "No options available.");
1910
2029
  return false;
1911
2030
  }
1912
2031
 
@@ -1958,7 +2077,7 @@ function areOptionsAvailableAndInit() {
1958
2077
 
1959
2078
  setStatusOrRemoveBadges.call(this);
1960
2079
 
1961
- removeAttributeToken(this, ATTRIBUTE_ERRORMESSAGE, noOptionsAvailableMessage);
2080
+ removeAttributeToken(this, ATTRIBUTE_ERRORMESSAGE, "No options available.");
1962
2081
  return true;
1963
2082
  }
1964
2083
 
@@ -22,6 +22,7 @@ import { isString } from "../../types/is.mjs";
22
22
  import { generateUniqueConfigKey } from "../host/util.mjs";
23
23
  import { Collapse, nameSymbol } from "./collapse.mjs";
24
24
  import { instanceSymbol } from "../../constants.mjs";
25
+ import {getLocaleOfDocument} from "../../dom/locale.mjs";
25
26
 
26
27
  export { Details };
27
28
 
@@ -86,9 +87,7 @@ class Details extends Collapse {
86
87
  templates: {
87
88
  main: getTemplate(),
88
89
  },
89
- labels: {
90
- button: "Details",
91
- },
90
+ labels: getTranslations(),
92
91
  });
93
92
  }
94
93
 
@@ -136,6 +135,54 @@ class Details extends Collapse {
136
135
  }
137
136
  }
138
137
 
138
+ /**
139
+ * @private
140
+ * @returns {object}
141
+ */
142
+ function getTranslations() {
143
+ const locale = getLocaleOfDocument();
144
+ switch (locale.language) {
145
+ case 'de':
146
+ return {
147
+ button: "Details"
148
+ };
149
+ case 'fr':
150
+ return {
151
+ button: "Détails"
152
+ };
153
+ case 'sp':
154
+ return {
155
+ button: "Detalles"
156
+ };
157
+ case 'it':
158
+ return {
159
+ button: "Dettagli"
160
+ };
161
+ case 'pl':
162
+ return {
163
+ button: "Szczegóły"
164
+ };
165
+ case 'no':
166
+ return {
167
+ button: "Detaljer"
168
+ };
169
+ case 'dk':
170
+ return {
171
+ button: "Detaljer"
172
+ };
173
+ case 'sw':
174
+ return {
175
+ button: "Detaljer"
176
+ };
177
+ default:
178
+ case 'en':
179
+ return {
180
+ button: "Details"
181
+ };
182
+ }
183
+ }
184
+
185
+
139
186
  /**
140
187
  * @private
141
188
  * @return {Select}
@@ -59,6 +59,7 @@ import {
59
59
  popperInstanceSymbol,
60
60
  setEventListenersModifiers,
61
61
  } from "../form/util/popper.mjs";
62
+ import {getLocaleOfDocument} from "../../dom/locale.mjs";
62
63
 
63
64
  export { Tabs };
64
65
 
@@ -195,9 +196,7 @@ class Tabs extends CustomElement {
195
196
  templates: {
196
197
  main: getTemplate(),
197
198
  },
198
- labels: {
199
- "new-tab-label": "New Tab",
200
- },
199
+ labels: getTranslations(),
201
200
  buttons: {
202
201
  standard: [],
203
202
  popper: [],
@@ -374,6 +373,54 @@ class Tabs extends CustomElement {
374
373
  }
375
374
  }
376
375
 
376
+ /**
377
+ * @private
378
+ * @returns {object}
379
+ */
380
+ function getTranslations() {
381
+ const locale = getLocaleOfDocument();
382
+ switch (locale.language) {
383
+ case 'de':
384
+ return {
385
+ "new-tab-label": "Neuer Tab"
386
+ };
387
+ case 'fr':
388
+ return {
389
+ "new-tab-label": "Nouvel Onglet"
390
+ };
391
+ case 'sp':
392
+ return {
393
+ "new-tab-label": "Nueva Pestaña"
394
+ };
395
+ case 'it':
396
+ return {
397
+ "new-tab-label": "Nuova Scheda"
398
+ };
399
+ case 'pl':
400
+ return {
401
+ "new-tab-label": "Nowa Karta"
402
+ };
403
+ case 'no':
404
+ return {
405
+ "new-tab-label": "Ny Fane"
406
+ };
407
+ case 'dk':
408
+ return {
409
+ "new-tab-label": "Ny Fane"
410
+ };
411
+ case 'sw':
412
+ return {
413
+ "new-tab-label": "Ny Flik"
414
+ };
415
+ default:
416
+ case 'en':
417
+ return {
418
+ "new-tab-label": "New Tab"
419
+ };
420
+ }
421
+ }
422
+
423
+
377
424
  /**
378
425
  * @private
379
426
  */
@@ -0,0 +1,235 @@
1
+ /**
2
+ * Copyright © schukai GmbH and all contributing authors, {{copyRightYear}}. All rights reserved.
3
+ * Node module: @schukai/monster
4
+ *
5
+ * This source code is licensed under the GNU Affero General Public License version 3 (AGPLv3).
6
+ * The full text of the license can be found at: https://www.gnu.org/licenses/agpl-3.0.en.html
7
+ *
8
+ * For those who do not wish to adhere to the AGPLv3, a commercial license is available.
9
+ * Acquiring a commercial license allows you to use this software without complying with the AGPLv3 terms.
10
+ * For more information about purchasing a commercial license, please contact schukai GmbH.
11
+ */
12
+
13
+ import {instanceSymbol} from "../../constants.mjs";
14
+ import {addAttributeToken, hasObjectLink} from "../../dom/attributes.mjs";
15
+ import {
16
+ ATTRIBUTE_ERRORMESSAGE,
17
+ ATTRIBUTE_ROLE,
18
+ customElementUpdaterLinkSymbol,
19
+ } from "../../dom/constants.mjs";
20
+ import {CustomControl} from "../../dom/customcontrol.mjs";
21
+ import {CustomElement} from "../../dom/customelement.mjs";
22
+ import {
23
+ assembleMethodSymbol,
24
+ registerCustomElement,
25
+ } from "../../dom/customelement.mjs";
26
+ import {findTargetElementFromEvent} from "../../dom/events.mjs";
27
+ import {isFunction} from "../../types/is.mjs";
28
+ import {MonitorAttributeErrorsStyleSheet} from "./stylesheet/monitor-attribute-errors.mjs";
29
+ import {fireCustomEvent} from "../../dom/events.mjs";
30
+ import {getDocument} from "../../dom/util.mjs";
31
+ import {clone} from "../../util/clone.mjs";
32
+
33
+ export {MonitorAttributeErrors};
34
+
35
+ /**
36
+ * @private
37
+ * @type {symbol}
38
+ */
39
+ const mutationObserversSymbol = Symbol("mutationObservers");
40
+
41
+ /**
42
+ * A MonitorAttributeErrors
43
+ *
44
+ * @fragments /fragments/components/notify/monitor-attribute-errors/
45
+ *
46
+ * @example /examples/components/notify/monitor-attribute-errors-simple
47
+ *
48
+ * @since 3.98.0
49
+ * @copyright schukai GmbH
50
+ * @summary A beautiful MonitorAttributeErrors that can make your life easier and also looks good.
51
+ */
52
+ class MonitorAttributeErrors extends CustomElement {
53
+ /**
54
+ * This method is called by the `instanceof` operator.
55
+ * @returns {symbol}
56
+ */
57
+ static get [instanceSymbol]() {
58
+ return Symbol.for(
59
+ "@schukai/monster/components/notify/monitor-attribute-errors@@instance",
60
+ );
61
+ }
62
+
63
+ /**
64
+ *
65
+ * @return {Components.Notify.MonitorAttributeErrors
66
+ */
67
+ [assembleMethodSymbol]() {
68
+ super[assembleMethodSymbol]();
69
+ return this;
70
+ }
71
+
72
+ /**
73
+ * @return {void}
74
+ */
75
+ connectedCallback() {
76
+ super.connectedCallback();
77
+ setupMutationObserver.call(this, getDocument());
78
+ }
79
+
80
+ /**
81
+ * @return {void}
82
+ */
83
+ disconnectedCallback() {
84
+ super.disconnectedCallback();
85
+ deactivateAllObservers.call(this);
86
+ }
87
+
88
+ /**
89
+ * To set the options via the HTML Tag, the attribute `data-monster-options` must be used.
90
+ * @see {@link https://monsterjs.org/en/doc/#configurate-a-monster-control}
91
+ *
92
+ * The individual configuration values can be found in the table.
93
+ *
94
+ * @property {Object} templates Template definitions
95
+ * @property {string} templates.main Main template
96
+ * @property {Object} features Features
97
+ * @property {boolean} features.notifyUser Notify user (monster-notify control is required)
98
+ * @property {Object} notifyUser Notify user
99
+ * @property {string} notifyUser.selector Selector for the notify user control (feature notifyUser must be enabled)
100
+ */
101
+ get defaults() {
102
+ return Object.assign({}, super.defaults, {
103
+ templates: {
104
+ main: getTemplate(),
105
+ },
106
+ features: {
107
+ notifyUser: false,
108
+ },
109
+
110
+ notifyUser: {
111
+ selector: "monster-notify",
112
+ },
113
+
114
+ actions: {
115
+ click: () => {
116
+ throw new Error("the click action is not defined");
117
+ },
118
+ },
119
+ });
120
+ }
121
+
122
+ /**
123
+ * @return {string}
124
+ */
125
+ static getTag() {
126
+ return "monster-monitor-attribute-errors";
127
+ }
128
+
129
+ /**
130
+ * @return {CSSStyleSheet[]}
131
+ */
132
+ static getCSSStyleSheet() {
133
+ return [MonitorAttributeErrorsStyleSheet];
134
+ }
135
+ }
136
+
137
+ /**
138
+ * @private
139
+ * @param root
140
+ */
141
+ function setupMutationObserver(root) {
142
+ const self = this;
143
+
144
+ if (!this?.[mutationObserversSymbol]) {
145
+ this[mutationObserversSymbol] = [];
146
+ }
147
+
148
+ const config = {
149
+ childList: true,
150
+ subtree: true,
151
+ attributes: true,
152
+ attributeFilter: ["data-monster-error"],
153
+ };
154
+
155
+ const callback = (mutationsList, observer) => {
156
+ for (const mutation of mutationsList) {
157
+ if (mutation.type === "childList") {
158
+ mutation.addedNodes.forEach((node) => {
159
+ checkNodeForErrors(node);
160
+ observeShadowRoots(node);
161
+ });
162
+ }
163
+ if (
164
+ mutation.type === "attributes" &&
165
+ mutation.attributeName === "data-monster-error"
166
+ ) {
167
+ const node = mutation.target;
168
+
169
+ checkNodeForErrors(node);
170
+ }
171
+ }
172
+ };
173
+
174
+ const observer = new MutationObserver(callback);
175
+ observer.observe(root, config);
176
+ this[mutationObserversSymbol].push(observer); // Speichert den Observer
177
+
178
+ root.querySelectorAll("*").forEach((node) => {
179
+ checkNodeForErrors(node);
180
+ observeShadowRoots(node);
181
+ });
182
+
183
+ function checkNodeForErrors(node) {
184
+ if (node.nodeType === 1 && node.hasAttribute("data-monster-error")) {
185
+
186
+ const fktOpen = console.groupCollapsed || console.group || console.log || function () {
187
+ };
188
+ const fktLog = console.log || function () {
189
+ };
190
+ const fktClose = console.groupEnd || function () {
191
+ };
192
+
193
+ fktOpen("MonitorAttributeErrors " + node.tagName);
194
+ fktLog(node);
195
+ fktLog(node.getAttribute('data-monster-error'));
196
+ fktClose();
197
+
198
+ if (self.getOption("features.notifyUser")) {
199
+ const notifyUser = getDocument().querySelector(self.getOption("notifyUser.selector"));
200
+ if (notifyUser) {
201
+ notifyUser.push(node.getAttribute('data-monster-error'));
202
+ }
203
+ }
204
+
205
+ }
206
+ }
207
+
208
+ function observeShadowRoots(node) {
209
+ if (
210
+ node.nodeType === 1 &&
211
+ node.shadowRoot &&
212
+ node.shadowRoot.mode === "open"
213
+ ) {
214
+ setupMutationObserver.call(self, node.shadowRoot);
215
+ }
216
+ }
217
+ }
218
+
219
+ function deactivateAllObservers() {
220
+ this[mutationObserversSymbol].forEach((observer) => {
221
+ observer.disconnect();
222
+ });
223
+ this[mutationObserversSymbol] = [];
224
+ }
225
+
226
+ /**
227
+ * @private
228
+ * @return {string}
229
+ */
230
+ function getTemplate() {
231
+ // language=HTML
232
+ return `<div></div>`;
233
+ }
234
+
235
+ registerCustomElement(MonitorAttributeErrors);