@schukai/monster 3.65.20 → 3.65.21

Sign up to get free protection for your applications and to get access to all the features.
package/CHANGELOG.md CHANGED
@@ -2,55 +2,21 @@
2
2
 
3
3
 
4
4
 
5
- ## [3.65.20] - 2024-06-20
6
-
7
- ### Bug Fixes
8
-
9
- - wip new pipeline
10
- - wip new pipeline
11
-
12
-
13
-
14
- ## [3.65.19] - 2024-06-20
15
-
16
- ### Bug Fixes
17
-
18
- - wip new pipeline
19
-
20
-
21
-
22
- ## [3.65.18] - 2024-06-20
23
-
24
- ### Bug Fixes
25
-
26
- - wip new pipeline
27
-
28
-
29
-
30
- ## [3.65.17] - 2024-06-20
31
-
32
- ### Bug Fixes
33
-
34
- - wip new pipeline
35
-
36
-
37
-
38
- ## [3.65.16] - 2024-06-20
5
+ ## [3.65.21] - 2024-06-20
39
6
 
40
7
  ### Bug Fixes
41
8
 
42
- - wip new pipeline
9
+ - exchange of document.selector with function findElementWithSelectorUpwards [#199](https://gitlab.schukai.com/oss/libraries/javascript/monster/issues/199)
43
10
 
11
+ ## [3.65.20] - 2024-06-20
44
12
 
45
-
46
- ## [3.65.15] - 2024-06-20
47
-
13
+ - Changeover to new release process
48
14
 
49
15
  ## [3.65.3] - 2024-06-19
50
16
 
51
17
  ### Bug Fixes
52
18
 
53
- - switch nodejs_22 to nodejs_20
19
+ - switch nodejs_22 to nodejs_20 (segmentation fault)
54
20
 
55
21
  ## [3.65.1] - 2024-06-17
56
22
 
package/package.json CHANGED
@@ -1 +1 @@
1
- {"author":"schukai GmbH","dependencies":{"@floating-ui/dom":"^1.6.5","@popperjs/core":"^2.11.8"},"description":"Monster is a simple library for creating fast, robust and lightweight websites.","homepage":"https://monsterjs.org/","keywords":["framework","web","dom","css","sass","mobile-first","app","front-end","templates","schukai","core","shopcloud","alvine","monster","buildmap","stack","observer","observable","uuid","node","nodelist","css-in-js","logger","log","theme"],"license":"AGPL 3.0","main":"source/monster.mjs","module":"source/monster.mjs","name":"@schukai/monster","repository":{"type":"git","url":"https://gitlab.schukai.com/oss/libraries/javascript/monster.git"},"type":"module","version":"3.65.20"}
1
+ {"author":"schukai GmbH","dependencies":{"@floating-ui/dom":"^1.6.5","@popperjs/core":"^2.11.8"},"description":"Monster is a simple library for creating fast, robust and lightweight websites.","homepage":"https://monsterjs.org/","keywords":["framework","web","dom","css","sass","mobile-first","app","front-end","templates","schukai","core","shopcloud","alvine","monster","buildmap","stack","observer","observable","uuid","node","nodelist","css-in-js","logger","log","theme"],"license":"AGPL 3.0","main":"source/monster.mjs","module":"source/monster.mjs","name":"@schukai/monster","repository":{"type":"git","url":"https://gitlab.schukai.com/oss/libraries/javascript/monster.git"},"type":"module","version":"3.65.21"}
@@ -20,6 +20,7 @@ import {
20
20
  CustomElement,
21
21
  registerCustomElement,
22
22
  } from "../../dom/customelement.mjs";
23
+ import {findElementWithSelectorUpwards} from "../../dom/util.mjs";
23
24
  import { isString } from "../../types/is.mjs";
24
25
  import { State } from "../form/types/state.mjs";
25
26
  import "../form/state-button.mjs";
@@ -189,12 +190,12 @@ function initControlReferences() {
189
190
  const selector = this.getOption("dataset.selector");
190
191
 
191
192
  if (isString(selector)) {
192
- const elements = document.querySelectorAll(selector);
193
- if (elements.length !== 1) {
193
+
194
+ const element = findElementWithSelectorUpwards( this,selector);
195
+ if (element===null) {
194
196
  throw new Error("the selector must match exactly one element");
195
197
  }
196
198
 
197
- const element = elements[0];
198
199
  if (!(element instanceof HTMLElement)) {
199
200
  throw new TypeError("the element must be a dataset");
200
201
  }
@@ -205,12 +206,11 @@ function initControlReferences() {
205
206
  const selector2 = this.getOption("overlay.selector");
206
207
 
207
208
  if (isString(selector2)) {
208
- const elements = document.querySelectorAll(selector2);
209
- if (elements.length !== 1) {
209
+ const element = findElementWithSelectorUpwards( this,selector);
210
+ if (element===null) {
210
211
  throw new Error("the selector must match exactly one element");
211
212
  }
212
213
 
213
- const element = elements[0];
214
214
  if (!(element instanceof HTMLElement)) {
215
215
  throw new TypeError("the element must be a overlay");
216
216
  }
@@ -12,32 +12,33 @@
12
12
  * SPDX-License-Identifier: AGPL-3.0
13
13
  */
14
14
 
15
- import { instanceSymbol, internalSymbol } from "../../constants.mjs";
16
- import { Pathfinder } from "../../data/pathfinder.mjs";
17
- import { getLinkedObjects, hasObjectLink } from "../../dom/attributes.mjs";
18
- import { customElementUpdaterLinkSymbol } from "../../dom/constants.mjs";
15
+ import {instanceSymbol, internalSymbol} from "../../constants.mjs";
16
+ import {Pathfinder} from "../../data/pathfinder.mjs";
17
+ import {getLinkedObjects, hasObjectLink} from "../../dom/attributes.mjs";
18
+ import {customElementUpdaterLinkSymbol} from "../../dom/constants.mjs";
19
19
  import {
20
- assembleMethodSymbol,
21
- CustomElement,
22
- attributeObserverSymbol,
23
- registerCustomElement,
20
+ assembleMethodSymbol,
21
+ CustomElement,
22
+ attributeObserverSymbol,
23
+ registerCustomElement,
24
24
  } from "../../dom/customelement.mjs";
25
- import { isString } from "../../types/is.mjs";
26
- import { Observer } from "../../types/observer.mjs";
27
- import { clone } from "../../util/clone.mjs";
25
+ import {findElementWithSelectorUpwards} from "../../dom/util.mjs";
26
+ import {isString} from "../../types/is.mjs";
27
+ import {Observer} from "../../types/observer.mjs";
28
+ import {clone} from "../../util/clone.mjs";
28
29
  import {
29
- ATTRIBUTE_DATASOURCE_SELECTOR,
30
- ATTRIBUTE_DATATABLE_INDEX,
30
+ ATTRIBUTE_DATASOURCE_SELECTOR,
31
+ ATTRIBUTE_DATATABLE_INDEX,
31
32
  } from "./constants.mjs";
32
- import { Datasource } from "./datasource.mjs";
33
- import { DatasetStyleSheet } from "./stylesheet/dataset.mjs";
33
+ import {Datasource} from "./datasource.mjs";
34
+ import {DatasetStyleSheet} from "./stylesheet/dataset.mjs";
34
35
  import {
35
- handleDataSourceChanges,
36
- datasourceLinkedElementSymbol,
36
+ handleDataSourceChanges,
37
+ datasourceLinkedElementSymbol,
37
38
  } from "./util.mjs";
38
- import { FormStyleSheet } from "../stylesheet/form.mjs";
39
+ import {FormStyleSheet} from "../stylesheet/form.mjs";
39
40
 
40
- export { DataSet };
41
+ export {DataSet};
41
42
 
42
43
  /**
43
44
  * The data set component is used to show the data of a data source.
@@ -78,185 +79,184 @@ export { DataSet };
78
79
  * @summary A data set
79
80
  */
80
81
  class DataSet extends CustomElement {
81
- /**
82
- * This method is called by the `instanceof` operator.
83
- * @returns {symbol}
84
- */
85
- static get [instanceSymbol]() {
86
- return Symbol.for("@schukai/monster/components/dataset@@instance");
87
- }
88
-
89
- /**
90
- * This method determines which attributes are to be monitored by `attributeChangedCallback()`.
91
- *
92
- * @return {string[]}
93
- * @since 1.15.0
94
- */
95
- static get observedAttributes() {
96
- const attributes = super.observedAttributes;
97
- attributes.push(ATTRIBUTE_DATATABLE_INDEX);
98
- return attributes;
99
- }
100
-
101
- /**
102
- * To set the options via the html tag the attribute `data-monster-options` must be used.
103
- * @see {@link https://monsterjs.org/en/doc/#configurate-a-monster-control}
104
- *
105
- * The individual configuration values can be found in the table.
106
- *
107
- * @property {Object} templates Template definitions
108
- * @property {string} templates.main Main template
109
- * @property {object} datasource The datasource
110
- * @property {string} datasource.selector The selector of the datasource
111
- * @property {object} mapping The mapping
112
- * @property {string} mapping.data The data
113
- * @property {number} mapping.index The index
114
- * @property {Array} data The data
115
- */
116
- get defaults() {
117
- const obj = Object.assign({}, super.defaults, {
118
- templates: {
119
- main: getTemplate(),
120
- },
121
-
122
- datasource: {
123
- selector: null,
124
- },
125
-
126
- mapping: {
127
- data: "dataset",
128
- index: 0,
129
- },
130
-
131
- data: {},
132
- });
133
-
134
- updateOptionsFromArguments.call(this, obj);
135
- return obj;
136
- }
137
-
138
- /**
139
- *
140
- * @return {string}
141
- */
142
- static getTag() {
143
- return "monster-dataset";
144
- }
145
-
146
- write() {
147
- return new Promise((resolve, reject) => {
148
- if (!this[datasourceLinkedElementSymbol]) {
149
- reject(new Error("No datasource"));
150
- return;
151
- }
152
-
153
- const internalUpdateCloneData = this.getInternalUpdateCloneData();
154
- if (!internalUpdateCloneData) {
155
- reject(new Error("No update data"));
156
- return;
157
- }
158
-
159
- const internalData = internalUpdateCloneData?.["data"];
160
- if (
161
- internalData === undefined ||
162
- internalData === null ||
163
- internalData === ""
164
- ) {
165
- reject(new Error("No data"));
166
- return;
167
- }
168
-
169
- setTimeout(() => {
170
- const path = this.getOption("mapping.data");
171
- const index = this.getOption("mapping.index");
172
-
173
- let pathWithIndex;
174
-
175
- if (isString(path) && path !== "") {
176
- pathWithIndex = path + "." + index;
177
- } else {
178
- pathWithIndex = index;
179
- }
180
-
181
- const data = this[datasourceLinkedElementSymbol].data;
182
- const unref = JSON.stringify(data);
183
- const ref = JSON.parse(unref);
184
-
185
- new Pathfinder(ref).setVia(pathWithIndex, internalData);
186
-
187
- this[datasourceLinkedElementSymbol].data = ref;
188
-
189
- resolve();
190
- }, 0);
191
- });
192
- }
193
-
194
- /**
195
- * This method is responsible for assembling the component.
196
- *
197
- * It calls the parent's assemble method first, then initializes control references and event handlers.
198
- * If the `datasource.selector` option is provided and is a string, it searches for the corresponding
199
- * element in the DOM using that selector.
200
- *
201
- * If the selector matches exactly one element, it checks if the element is an instance of the `Datasource` class.
202
- *
203
- * If it is, the component's `datasourceLinkedElementSymbol` property is set to the element, and the component
204
- * attaches an observer to the datasource's changes.
205
- *
206
- * The observer is a function that calls the `handleDataSourceChanges` method in the context of the component.
207
- * Additionally, the component attaches an observer to itself, which also calls the `handleDataSourceChanges`
208
- * method in the component's context.
209
- */
210
- [assembleMethodSymbol]() {
211
- super[assembleMethodSymbol]();
212
-
213
- // initControlReferences.call(self);
214
- initEventHandler.call(this);
215
-
216
- const selector = this.getOption("datasource.selector");
217
-
218
- if (isString(selector)) {
219
- const elements = document.querySelectorAll(selector);
220
- if (elements.length !== 1) {
221
- throw new Error("the selector must match exactly one element");
222
- }
223
-
224
- const element = elements[0];
225
- if (!(element instanceof Datasource)) {
226
- throw new TypeError("the element must be a datasource");
227
- }
228
-
229
- this[datasourceLinkedElementSymbol] = element;
230
- element.datasource.attachObserver(
231
- new Observer(handleDataSourceChanges.bind(this)),
232
- );
233
- }
234
-
235
- this.attachObserver(
236
- new Observer(() => {
237
- handleDataSourceChanges.call(this);
238
- }),
239
- );
240
- }
241
-
242
- /**
243
- * @return [CSSStyleSheet]
244
- */
245
- static getCSSStyleSheet() {
246
- return [FormStyleSheet, DatasetStyleSheet];
247
- }
82
+ /**
83
+ * This method is called by the `instanceof` operator.
84
+ * @returns {symbol}
85
+ */
86
+ static get [instanceSymbol]() {
87
+ return Symbol.for("@schukai/monster/components/dataset@@instance");
88
+ }
89
+
90
+ /**
91
+ * This method determines which attributes are to be monitored by `attributeChangedCallback()`.
92
+ *
93
+ * @return {string[]}
94
+ * @since 1.15.0
95
+ */
96
+ static get observedAttributes() {
97
+ const attributes = super.observedAttributes;
98
+ attributes.push(ATTRIBUTE_DATATABLE_INDEX);
99
+ return attributes;
100
+ }
101
+
102
+ /**
103
+ * To set the options via the html tag the attribute `data-monster-options` must be used.
104
+ * @see {@link https://monsterjs.org/en/doc/#configurate-a-monster-control}
105
+ *
106
+ * The individual configuration values can be found in the table.
107
+ *
108
+ * @property {Object} templates Template definitions
109
+ * @property {string} templates.main Main template
110
+ * @property {object} datasource The datasource
111
+ * @property {string} datasource.selector The selector of the datasource
112
+ * @property {object} mapping The mapping
113
+ * @property {string} mapping.data The data
114
+ * @property {number} mapping.index The index
115
+ * @property {Array} data The data
116
+ */
117
+ get defaults() {
118
+ const obj = Object.assign({}, super.defaults, {
119
+ templates: {
120
+ main: getTemplate(),
121
+ },
122
+
123
+ datasource: {
124
+ selector: null,
125
+ },
126
+
127
+ mapping: {
128
+ data: "dataset",
129
+ index: 0,
130
+ },
131
+
132
+ data: {},
133
+ });
134
+
135
+ updateOptionsFromArguments.call(this, obj);
136
+ return obj;
137
+ }
138
+
139
+ /**
140
+ *
141
+ * @return {string}
142
+ */
143
+ static getTag() {
144
+ return "monster-dataset";
145
+ }
146
+
147
+ write() {
148
+ return new Promise((resolve, reject) => {
149
+ if (!this[datasourceLinkedElementSymbol]) {
150
+ reject(new Error("No datasource"));
151
+ return;
152
+ }
153
+
154
+ const internalUpdateCloneData = this.getInternalUpdateCloneData();
155
+ if (!internalUpdateCloneData) {
156
+ reject(new Error("No update data"));
157
+ return;
158
+ }
159
+
160
+ const internalData = internalUpdateCloneData?.["data"];
161
+ if (
162
+ internalData === undefined ||
163
+ internalData === null ||
164
+ internalData === ""
165
+ ) {
166
+ reject(new Error("No data"));
167
+ return;
168
+ }
169
+
170
+ setTimeout(() => {
171
+ const path = this.getOption("mapping.data");
172
+ const index = this.getOption("mapping.index");
173
+
174
+ let pathWithIndex;
175
+
176
+ if (isString(path) && path !== "") {
177
+ pathWithIndex = path + "." + index;
178
+ } else {
179
+ pathWithIndex = index;
180
+ }
181
+
182
+ const data = this[datasourceLinkedElementSymbol].data;
183
+ const unref = JSON.stringify(data);
184
+ const ref = JSON.parse(unref);
185
+
186
+ new Pathfinder(ref).setVia(pathWithIndex, internalData);
187
+
188
+ this[datasourceLinkedElementSymbol].data = ref;
189
+
190
+ resolve();
191
+ }, 0);
192
+ });
193
+ }
194
+
195
+ /**
196
+ * This method is responsible for assembling the component.
197
+ *
198
+ * It calls the parent's assemble method first, then initializes control references and event handlers.
199
+ * If the `datasource.selector` option is provided and is a string, it searches for the corresponding
200
+ * element in the DOM using that selector.
201
+ *
202
+ * If the selector matches exactly one element, it checks if the element is an instance of the `Datasource` class.
203
+ *
204
+ * If it is, the component's `datasourceLinkedElementSymbol` property is set to the element, and the component
205
+ * attaches an observer to the datasource's changes.
206
+ *
207
+ * The observer is a function that calls the `handleDataSourceChanges` method in the context of the component.
208
+ * Additionally, the component attaches an observer to itself, which also calls the `handleDataSourceChanges`
209
+ * method in the component's context.
210
+ */
211
+ [assembleMethodSymbol]() {
212
+ super[assembleMethodSymbol]();
213
+
214
+ // initControlReferences.call(self);
215
+ initEventHandler.call(this);
216
+
217
+ const selector = this.getOption("datasource.selector");
218
+
219
+ if (isString(selector)) {
220
+ const element = findElementWithSelectorUpwards(this, selector);
221
+ if (element === null) {
222
+ throw new Error("the selector must match exactly one element");
223
+ }
224
+
225
+ if (!(element instanceof Datasource)) {
226
+ throw new TypeError("the element must be a datasource");
227
+ }
228
+
229
+ this[datasourceLinkedElementSymbol] = element;
230
+ element.datasource.attachObserver(
231
+ new Observer(handleDataSourceChanges.bind(this)),
232
+ );
233
+ }
234
+
235
+ this.attachObserver(
236
+ new Observer(() => {
237
+ handleDataSourceChanges.call(this);
238
+ }),
239
+ );
240
+ }
241
+
242
+ /**
243
+ * @return [CSSStyleSheet]
244
+ */
245
+ static getCSSStyleSheet() {
246
+ return [FormStyleSheet, DatasetStyleSheet];
247
+ }
248
248
  }
249
249
 
250
250
  /**
251
251
  * @private
252
252
  */
253
253
  function initEventHandler() {
254
- this[attributeObserverSymbol][ATTRIBUTE_DATATABLE_INDEX] = () => {
255
- const index = this.getAttribute(ATTRIBUTE_DATATABLE_INDEX);
256
- if (index) {
257
- this.setOption("mapping.index", parseInt(index, 10));
258
- }
259
- };
254
+ this[attributeObserverSymbol][ATTRIBUTE_DATATABLE_INDEX] = () => {
255
+ const index = this.getAttribute(ATTRIBUTE_DATATABLE_INDEX);
256
+ if (index) {
257
+ this.setOption("mapping.index", parseInt(index, 10));
258
+ }
259
+ };
260
260
  }
261
261
 
262
262
  /**
@@ -264,17 +264,17 @@ function initEventHandler() {
264
264
  * @param {Object} options
265
265
  */
266
266
  function updateOptionsFromArguments(options) {
267
- const index = this.getAttribute(ATTRIBUTE_DATATABLE_INDEX);
267
+ const index = this.getAttribute(ATTRIBUTE_DATATABLE_INDEX);
268
268
 
269
- if (index !== null && index !== undefined) {
270
- options.mapping.index = parseInt(index, 10);
271
- }
269
+ if (index !== null && index !== undefined) {
270
+ options.mapping.index = parseInt(index, 10);
271
+ }
272
272
 
273
- const selector = this.getAttribute(ATTRIBUTE_DATASOURCE_SELECTOR);
273
+ const selector = this.getAttribute(ATTRIBUTE_DATASOURCE_SELECTOR);
274
274
 
275
- if (selector) {
276
- options.datasource.selector = selector;
277
- }
275
+ if (selector) {
276
+ options.datasource.selector = selector;
277
+ }
278
278
  }
279
279
 
280
280
  /**
@@ -282,8 +282,8 @@ function updateOptionsFromArguments(options) {
282
282
  * @return {string}
283
283
  */
284
284
  function getTemplate() {
285
- // language=HTML
286
- return `
285
+ // language=HTML
286
+ return `
287
287
  <div data-monster-role="control" part="control">
288
288
  <slot></slot>
289
289
  </div>
@@ -511,8 +511,7 @@ function getFilterConfigKey() {
511
511
  * @returns {Promise}
512
512
  */
513
513
  function getHostConfig(callback) {
514
- const document = getDocument();
515
- const host = document.querySelector("monster-host");
514
+ const host = findElementWithSelectorUpwards( this,"monster-host");
516
515
 
517
516
  if (!(host && this.id)) {
518
517
  return Promise.resolve({});
@@ -608,8 +607,7 @@ function updateConfigColumnBar() {
608
607
  map[option.name] = option.visible;
609
608
  }
610
609
 
611
- const document = getDocument();
612
- const host = document.querySelector("monster-host");
610
+ const host = findElementWithSelectorUpwards( this,"monster-host");
613
611
  if (!(host && this.id)) {
614
612
  return;
615
613
  }
@@ -816,8 +814,7 @@ function storeOrderStatement(doFetch) {
816
814
  const statement = createOrderStatement(headers);
817
815
  setDataSource.call(this, { orderBy: statement }, doFetch);
818
816
 
819
- const document = getDocument();
820
- const host = document.querySelector("monster-host");
817
+ const host = findElementWithSelectorUpwards( this,"monster-host");
821
818
  if (!(host && this.id)) {
822
819
  return;
823
820
  }
@@ -726,8 +726,7 @@ function initTabEvents() {
726
726
  }
727
727
  }
728
728
 
729
- const document = getDocument();
730
- const host = document.querySelector("monster-host");
729
+ const host = findElementWithSelectorUpwards( this,"monster-host");
731
730
  if (!(host && this.id)) {
732
731
  return;
733
732
  }
@@ -768,8 +767,7 @@ function updateFilterTabs() {
768
767
  return;
769
768
  }
770
769
 
771
- const document = getDocument();
772
- const host = document.querySelector("monster-host");
770
+ const host = findElementWithSelectorUpwards( this,"monster-host");
773
771
  if (!(host && this.id)) {
774
772
  return;
775
773
  }
@@ -1067,8 +1065,7 @@ function getControlValuesFromLabel(label) {
1067
1065
  * @returns {Promise<unknown>}
1068
1066
  */
1069
1067
  function initFromConfig() {
1070
- const document = getDocument();
1071
- const host = document.querySelector("monster-host");
1068
+ const host = findElementWithSelectorUpwards( this,"monster-host");
1072
1069
 
1073
1070
  if (!(isInstance(host, Host) && this.id)) {
1074
1071
  return Promise.resolve();
@@ -1111,8 +1108,7 @@ function initFromConfig() {
1111
1108
  * @private
1112
1109
  */
1113
1110
  function updateConfig() {
1114
- const document = getDocument();
1115
- const host = document.querySelector("monster-host");
1111
+ const host = findElementWithSelectorUpwards( this,"monster-host");
1116
1112
  if (!(host && this.id)) {
1117
1113
  return;
1118
1114
  }
@@ -17,6 +17,7 @@ import {
17
17
  CustomElement,
18
18
  registerCustomElement,
19
19
  } from "../../dom/customelement.mjs";
20
+ import {findElementWithSelectorUpwards} from "../../dom/util.mjs";
20
21
  import { ThemeStyleSheet } from "../stylesheet/theme.mjs";
21
22
  import { ATTRIBUTE_DATASOURCE_SELECTOR } from "./constants.mjs";
22
23
  import { Datasource } from "./datasource.mjs";
@@ -188,12 +189,11 @@ class Pagination extends CustomElement {
188
189
  const selector = this.getOption("datasource.selector", "");
189
190
 
190
191
  if (isString(selector)) {
191
- const elements = document.querySelectorAll(selector);
192
- if (elements.length !== 1) {
192
+ const element = findElementWithSelectorUpwards( this,selector);
193
+ if (element===null) {
193
194
  throw new Error("the selector must match exactly one element");
194
195
  }
195
-
196
- const element = elements[0];
196
+
197
197
  if (!(element instanceof Datasource)) {
198
198
  throw new TypeError("the element must be a datasource");
199
199
  }
@@ -22,6 +22,7 @@ import {
22
22
  attributeObserverSymbol,
23
23
  registerCustomElement,
24
24
  } from "../../dom/customelement.mjs";
25
+ import {findElementWithSelectorUpwards} from "../../dom/util.mjs";
25
26
  import { isString, isArray } from "../../types/is.mjs";
26
27
  import { Observer } from "../../types/observer.mjs";
27
28
  import { TokenList } from "../../types/tokenlist.mjs";
@@ -154,12 +155,12 @@ class SaveButton extends CustomElement {
154
155
  const selector = this.getOption("datasource.selector");
155
156
 
156
157
  if (isString(selector)) {
157
- const elements = document.querySelectorAll(selector);
158
- if (elements.length !== 1) {
158
+
159
+ const element = findElementWithSelectorUpwards( this,selector);
160
+ if (element===null) {
159
161
  throw new Error("the selector must match exactly one element");
160
162
  }
161
-
162
- const element = elements[0];
163
+
163
164
  if (!(element instanceof Datasource)) {
164
165
  throw new TypeError("the element must be a datasource");
165
166
  }
@@ -17,6 +17,7 @@ import {
17
17
  CustomElement,
18
18
  registerCustomElement,
19
19
  } from "../../dom/customelement.mjs";
20
+ import {findElementWithSelectorUpwards} from "../../dom/util.mjs";
20
21
  import { ThemeStyleSheet } from "../stylesheet/theme.mjs";
21
22
  import { Datasource } from "./datasource.mjs";
22
23
  import { SpinnerStyleSheet } from "../stylesheet/spinner.mjs";
@@ -174,12 +175,12 @@ function initEventHandler() {
174
175
  const self = this;
175
176
 
176
177
  if (isString(selector)) {
177
- const elements = document.querySelectorAll(selector);
178
- if (elements.length !== 1) {
178
+
179
+ const element = findElementWithSelectorUpwards( this,selector);
180
+ if (element===null) {
179
181
  throw new Error("the selector must match exactly one element");
180
182
  }
181
-
182
- const element = elements[0];
183
+
183
184
  if (!(element instanceof Datasource)) {
184
185
  throw new TypeError("the element must be a datasource");
185
186
  }
@@ -12,11 +12,12 @@
12
12
  * SPDX-License-Identifier: AGPL-3.0
13
13
  */
14
14
 
15
- import { instanceSymbol } from "../../constants.mjs";
16
- import { isObject } from "../../types/is.mjs";
17
- import { Datasource } from "../datasource.mjs";
15
+ import {instanceSymbol} from "../../constants.mjs";
16
+ import {findElementWithSelectorUpwards} from "../../dom/util.mjs";
17
+ import {isObject} from "../../types/is.mjs";
18
+ import {Datasource} from "../datasource.mjs";
18
19
 
19
- export { DomStorage };
20
+ export {DomStorage};
20
21
 
21
22
  /**
22
23
  * The DomStorage is a class that stores data in memory.
@@ -26,93 +27,93 @@ export { DomStorage };
26
27
  * @memberOf Monster.Data.Datasource
27
28
  */
28
29
  class DomStorage extends Datasource {
29
- /**
30
- * @param {Object} [options] options contains definitions for the datasource.
31
- */
32
- constructor(options) {
33
- super();
30
+ /**
31
+ * @param {Object} [options] options contains definitions for the datasource.
32
+ */
33
+ constructor(options) {
34
+ super();
34
35
 
35
- if (isObject(options)) {
36
- this.setOptions(options);
37
- }
38
- }
36
+ if (isObject(options)) {
37
+ this.setOptions(options);
38
+ }
39
+ }
39
40
 
40
- /**
41
- * This method is called by the `instanceof` operator.
42
- * @returns {symbol}
43
- */
44
- static get [instanceSymbol]() {
45
- return Symbol.for("@schukai/monster/data/datasource/storage/dom-storage");
46
- }
41
+ /**
42
+ * This method is called by the `instanceof` operator.
43
+ * @returns {symbol}
44
+ */
45
+ static get [instanceSymbol]() {
46
+ return Symbol.for("@schukai/monster/data/datasource/storage/dom-storage");
47
+ }
47
48
 
48
- /**
49
- * @property {Object} defaults
50
- * @property {Object} defaults.read
51
- * @property {string} defaults.read.selector
52
- * @property {Object} defaults.write
53
- * @property {string} defaults.write.selector
54
- */
55
- get defaults() {
56
- return Object.assign({}, super.defaults, {
57
- read: {
58
- selector: undefined,
59
- },
60
- write: {
61
- selector: undefined,
62
- },
63
- });
64
- }
49
+ /**
50
+ * @property {Object} defaults
51
+ * @property {Object} defaults.read
52
+ * @property {string} defaults.read.selector
53
+ * @property {Object} defaults.write
54
+ * @property {string} defaults.write.selector
55
+ */
56
+ get defaults() {
57
+ return Object.assign({}, super.defaults, {
58
+ read: {
59
+ selector: undefined,
60
+ },
61
+ write: {
62
+ selector: undefined,
63
+ },
64
+ });
65
+ }
65
66
 
66
- /**
67
- * @return {Promise}
68
- * @throws {Error} The read selector is not defined
69
- * @throws {Error} There are no storage element
70
- */
71
- read() {
72
- const selector = this.getOption("read.selector", undefined);
73
- if (!selector) {
74
- throw new Error("The read selector is not defined");
75
- }
67
+ /**
68
+ * @return {Promise}
69
+ * @throws {Error} The read selector is not defined
70
+ * @throws {Error} There are no storage element
71
+ */
72
+ read() {
73
+ const selector = this.getOption("read.selector", undefined);
74
+ if (!selector) {
75
+ throw new Error("The read selector is not defined");
76
+ }
76
77
 
77
- const storage = document.querySelector(selector);
78
- if (!storage) {
79
- throw new Error("There are no storage element");
80
- }
78
+ const storage = findElementWithSelectorUpwards(this, selector);
79
+ if (!storage) {
80
+ throw new Error("There is no storage element");
81
+ }
81
82
 
82
- return new Promise((resolve, reject) => {
83
- try {
84
- const data = JSON.parse(storage.innerHTML);
85
- this.set(data);
86
- resolve(data);
87
- } catch (e) {
88
- reject(e);
89
- }
90
- });
91
- }
83
+ return new Promise((resolve, reject) => {
84
+ try {
85
+ const data = JSON.parse(storage.innerHTML);
86
+ this.set(data);
87
+ resolve(data);
88
+ } catch (e) {
89
+ reject(e);
90
+ }
91
+ });
92
+ }
92
93
 
93
- /**
94
- * @return {Promise}
95
- * @throws {Error} The write selector is not defined
96
- * @throws {Error} There are no storage element
97
- */
98
- write() {
99
- const selector = this.getOption("write.selector");
100
- if (!selector) {
101
- throw new Error("The write selector is not defined");
102
- }
94
+ /**
95
+ * @return {Promise}
96
+ * @throws {Error} The write selector is not defined
97
+ * @throws {Error} There are no storage element
98
+ */
99
+ write() {
100
+ const selector = this.getOption("write.selector");
101
+ if (!selector) {
102
+ throw new Error("The option write.selector is not defined");
103
+ }
103
104
 
104
- const storage = document.querySelector(selector);
105
- if (!storage) {
106
- throw new Error("There are no storage element");
107
- }
105
+ const storage = findElementWithSelectorUpwards(this, selector);
106
+ if (!storage) {
107
+ throw new Error("There is no storage element");
108
+ }
108
109
 
109
- return new Promise((resolve, reject) => {
110
- try {
111
- storage.innerHTML = JSON.stringify(this.get());
112
- resolve(storage);
113
- } catch (e) {
114
- reject(e);
115
- }
116
- });
117
- }
110
+ return new Promise((resolve, reject) => {
111
+ try {
112
+ storage.innerHTML = JSON.stringify(this.get());
113
+ resolve(storage);
114
+ } catch (e) {
115
+ reject(e);
116
+ }
117
+ });
118
+ }
118
119
  }
@@ -12,26 +12,28 @@
12
12
  * SPDX-License-Identifier: AGPL-3.0
13
13
  */
14
14
 
15
- import { internalStateSymbol } from "../../constants.mjs";
16
- import { extend } from "../../data/extend.mjs";
17
- import { getGlobalFunction } from "../../types/global.mjs";
15
+ import {internalStateSymbol} from "../../constants.mjs";
16
+ import {extend} from "../../data/extend.mjs";
17
+ import {getGlobalFunction} from "../../types/global.mjs";
18
+ import {addAttributeToken} from "../attributes.mjs";
18
19
  import {
19
- ATTRIBUTE_CLASS,
20
- ATTRIBUTE_ERRORMESSAGE,
21
- ATTRIBUTE_ID,
22
- ATTRIBUTE_SRC,
23
- ATTRIBUTE_TITLE,
24
- ATTRIBUTE_TYPE,
25
- TAG_SCRIPT,
20
+ ATTRIBUTE_CLASS,
21
+ ATTRIBUTE_ERRORMESSAGE,
22
+ ATTRIBUTE_ID,
23
+ ATTRIBUTE_SRC,
24
+ ATTRIBUTE_TITLE,
25
+ ATTRIBUTE_TYPE,
26
+ TAG_SCRIPT,
26
27
  } from "../constants.mjs";
27
28
  import {
28
- KEY_DOCUMENT,
29
- KEY_QUERY,
30
- referenceSymbol,
31
- Resource,
29
+ KEY_DOCUMENT,
30
+ KEY_QUERY,
31
+ referenceSymbol,
32
+ Resource,
32
33
  } from "../resource.mjs";
33
- import { instanceSymbol } from "../../constants.mjs";
34
- export { Data };
34
+ import {instanceSymbol} from "../../constants.mjs";
35
+
36
+ export {Data};
35
37
 
36
38
  /**
37
39
  * This class is used by the resource manager to embed data.
@@ -43,58 +45,59 @@ export { Data };
43
45
  * @summary A Data Resource class
44
46
  */
45
47
  class Data extends Resource {
46
- /**
47
- * @property {string} mode=cors https://developer.mozilla.org/en-US/docs/Web/API/fetch
48
- * @property {string} credentials=same-origin https://developer.mozilla.org/en-US/docs/Web/API/fetch
49
- * @property {string} type=application/json {@link https://developer.mozilla.org/en-US/docs/Web/HTML/Element/script#attr-type}
50
- */
51
- get defaults() {
52
- return extend({}, super.defaults, {
53
- mode: "cors",
54
- credentials: "same-origin",
55
- type: "application/json",
56
- });
57
- }
58
-
59
- /**
60
- *
61
- * @return {Monster.DOM.Resource.Data}
62
- */
63
- create() {
64
- createElement.call(this);
65
- return this;
66
- }
67
-
68
- /**
69
- * This method appends the HTMLElement to the specified document
70
- *
71
- * throws {Error} target not found
72
- * @return {Monster.DOM.Resource}
73
- */
74
- connect() {
75
- if (!(this[referenceSymbol] instanceof HTMLElement)) {
76
- this.create();
77
- }
78
-
79
- appendToDocument.call(this);
80
- return this;
81
- }
82
-
83
- /**
84
- * This method is called by the `instanceof` operator.
85
- * @returns {symbol}
86
- * @since 2.1.0
87
- */
88
- static get [instanceSymbol]() {
89
- return Symbol.for("@schukai/monster/dom/resource/data");
90
- }
91
-
92
- /**
93
- * @return {string}
94
- */
95
- static getURLAttribute() {
96
- return ATTRIBUTE_SRC;
97
- }
48
+ /**
49
+ * @property {string} mode=cors https://developer.mozilla.org/en-US/docs/Web/API/fetch
50
+ * @property {string} credentials=same-origin https://developer.mozilla.org/en-US/docs/Web/API/fetch
51
+ * @property {string} type=application/json {@link https://developer.mozilla.org/en-US/docs/Web/HTML/Element/script#attr-type}
52
+ */
53
+ get defaults() {
54
+ return extend({}, super.defaults, {
55
+ mode: "cors",
56
+ credentials: "same-origin",
57
+ type: "application/json",
58
+ });
59
+ }
60
+
61
+ /**
62
+ *
63
+ * @return {Monster.DOM.Resource.Data}
64
+ */
65
+ create() {
66
+ createElement.call(this);
67
+ return this;
68
+ }
69
+
70
+ /**
71
+ * This method appends the HTMLElement to the specified document
72
+ *
73
+ * throws {Error} target not found
74
+ * @return {Monster.DOM.Resource}
75
+ */
76
+ connect() {
77
+ const self = this;
78
+ if (!(this[referenceSymbol] instanceof HTMLElement)) {
79
+ this.create();
80
+ }
81
+
82
+ appendToDocument.call(this);
83
+ return this;
84
+ }
85
+
86
+ /**
87
+ * This method is called by the `instanceof` operator.
88
+ * @returns {symbol}
89
+ * @since 2.1.0
90
+ */
91
+ static get [instanceSymbol]() {
92
+ return Symbol.for("@schukai/monster/dom/resource/data");
93
+ }
94
+
95
+ /**
96
+ * @return {string}
97
+ */
98
+ static getURLAttribute() {
99
+ return ATTRIBUTE_SRC;
100
+ }
98
101
  }
99
102
 
100
103
  /**
@@ -102,21 +105,21 @@ class Data extends Resource {
102
105
  * @return {Monster.DOM.Resource.Data}
103
106
  */
104
107
  function createElement() {
105
- const document = this.getOption(KEY_DOCUMENT);
106
- this[referenceSymbol] = document.createElement(TAG_SCRIPT);
107
-
108
- for (const key of [
109
- ATTRIBUTE_TYPE,
110
- ATTRIBUTE_ID,
111
- ATTRIBUTE_CLASS,
112
- ATTRIBUTE_TITLE,
113
- ]) {
114
- if (this.getOption(key) !== undefined) {
115
- this[referenceSymbol][key] = this.getOption(key);
116
- }
117
- }
118
-
119
- return this;
108
+ const document = this.getOption(KEY_DOCUMENT);
109
+ this[referenceSymbol] = document.createElement(TAG_SCRIPT);
110
+
111
+ for (const key of [
112
+ ATTRIBUTE_TYPE,
113
+ ATTRIBUTE_ID,
114
+ ATTRIBUTE_CLASS,
115
+ ATTRIBUTE_TITLE,
116
+ ]) {
117
+ if (this.getOption(key) !== undefined) {
118
+ this[referenceSymbol][key] = this.getOption(key);
119
+ }
120
+ }
121
+
122
+ return this;
120
123
  }
121
124
 
122
125
  /**
@@ -125,41 +128,41 @@ function createElement() {
125
128
  * throws {Error} target not found
126
129
  */
127
130
  function appendToDocument() {
128
- const targetNode = document.querySelector(this.getOption(KEY_QUERY, "head"));
129
- if (!(targetNode instanceof HTMLElement)) {
130
- throw new Error("target not found");
131
- }
132
-
133
- targetNode.appendChild(this[referenceSymbol]);
134
-
135
- getGlobalFunction("fetch")(this.getOption(ATTRIBUTE_SRC), {
136
- method: "GET", // *GET, POST, PUT, DELETE, etc.
137
- mode: this.getOption("mode", "cors"), // no-cors, *cors, same-origin
138
- cache: "no-cache", // *default, no-cache, reload, force-cache, only-if-cached
139
- credentials: this.getOption("credentials", "same-origin"), // include, *same-origin, omit
140
- headers: {
141
- Accept: this.getOption("type", "application/json"),
142
- },
143
- redirect: "follow", // manual, *follow, error
144
- referrerPolicy: "no-referrer", // no-referrer,
145
- })
146
- .then((response) => {
147
- return response.text();
148
- })
149
- .then((text) => {
150
- const textNode = document.createTextNode(text);
151
- this[referenceSymbol].appendChild(textNode);
152
-
153
- this[internalStateSymbol].getSubject()["loaded"] = true;
154
- })
155
- .catch((e) => {
156
- this[internalStateSymbol].setSubject({
157
- loaded: true,
158
- error: e.toString(),
159
- });
160
-
161
- targetNode.setAttribute(ATTRIBUTE_ERRORMESSAGE, e.toString());
162
- });
163
-
164
- return this;
131
+ const targetNode = document.querySelector(this.getOption(KEY_QUERY, "head"));
132
+ if (!(targetNode instanceof HTMLElement)) {
133
+ throw new Error("target not found");
134
+ }
135
+
136
+ targetNode.appendChild(this[referenceSymbol]);
137
+
138
+ getGlobalFunction("fetch")(this.getOption(ATTRIBUTE_SRC), {
139
+ method: "GET", // *GET, POST, PUT, DELETE, etc.
140
+ mode: this.getOption("mode", "cors"), // no-cors, *cors, same-origin
141
+ cache: "no-cache", // *default, no-cache, reload, force-cache, only-if-cached
142
+ credentials: this.getOption("credentials", "same-origin"), // include, *same-origin, omit
143
+ headers: {
144
+ Accept: this.getOption("type", "application/json"),
145
+ },
146
+ redirect: "follow", // manual, *follow, error
147
+ referrerPolicy: "no-referrer", // no-referrer,
148
+ })
149
+ .then((response) => {
150
+ return response.text();
151
+ })
152
+ .then((text) => {
153
+ const textNode = document.createTextNode(text);
154
+ this[referenceSymbol].appendChild(textNode);
155
+
156
+ this[internalStateSymbol].getSubject()["loaded"] = true;
157
+ })
158
+ .catch((e) => {
159
+ this[internalStateSymbol].setSubject({
160
+ loaded: true,
161
+ error: e.toString(),
162
+ });
163
+
164
+ targetNode.setAttribute(ATTRIBUTE_ERRORMESSAGE, e.toString());
165
+ });
166
+
167
+ return this;
165
168
  }
@@ -242,7 +242,6 @@ function addEvents() {
242
242
  this[referenceSymbol].removeEventListener("error", onError);
243
243
  this[referenceSymbol].removeEventListener("load", onLoad);
244
244
  this[internalStateSymbol].getSubject()["loaded"] = true;
245
- return;
246
245
  };
247
246
 
248
247
  this[referenceSymbol].addEventListener("load", onLoad, false);