@schukai/monster 3.73.3 → 3.73.4

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/CHANGELOG.md CHANGED
@@ -2,33 +2,38 @@
2
2
 
3
3
 
4
4
 
5
- ## [3.73.3] - 2024-07-01
5
+ ## [3.73.4] - 2024-07-02
6
6
 
7
7
  ### Bug Fixes
8
8
 
9
- - debouncing form handling
9
+ - eventprocessing is now only active in selected controls: form, filter. [#224](https://gitlab.schukai.com/oss/libraries/javascript/monster/issues/224)
10
10
 
11
11
 
12
12
 
13
- ## [3.73.2] - 2024-07-01
13
+ ## [3.73.3] - 2024-07-01
14
14
 
15
15
  ### Bug Fixes
16
16
 
17
- - id not defined
17
+ - debouncing form handling
18
18
 
19
+ ## [3.73.2] - 2024-07-01
19
20
 
21
+ ### Bug Fixes
22
+
23
+ - id not defined
20
24
 
21
25
  ## [3.73.1] - 2024-06-30
22
26
 
23
27
  ### Bug Fixes
24
28
 
25
- - update deadman switch assignment
29
+ - update dead man switch assignment
30
+
26
31
  ### Changes
27
32
 
28
33
  - update issues
29
34
  - remove node debug flag
30
35
  - tidy changelog
31
- - new task create documentation fragments and optimize create class task
36
+ - new task creates documentation fragments and optimizes creates a class task
32
37
  - cleanup code
33
38
 
34
39
  ## [3.73.0] - 2024-06-28
package/package.json CHANGED
@@ -1 +1 @@
1
- {"author":"schukai GmbH","dependencies":{"@floating-ui/dom":"^1.6.6","@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.73.3"}
1
+ {"author":"schukai GmbH","dependencies":{"@floating-ui/dom":"^1.6.7","@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.73.4"}
@@ -210,7 +210,12 @@ class DataSet extends CustomElement {
210
210
  pathWithIndex = String(index);
211
211
  }
212
212
 
213
- const data = this[datasourceLinkedElementSymbol].data;
213
+ const data = this[datasourceLinkedElementSymbol]?.data;
214
+ if (!data) {
215
+ reject(new Error("No data"));
216
+ return;
217
+ }
218
+
214
219
  const unref = JSON.stringify(data);
215
220
  const ref = JSON.parse(unref);
216
221
 
@@ -244,24 +249,26 @@ class DataSet extends CustomElement {
244
249
 
245
250
  initEventHandler.call(this);
246
251
 
247
- const selector = this.getOption("datasource.selector");
252
+ if (!this[datasourceLinkedElementSymbol]) {
253
+ const selector = this.getOption("datasource.selector");
248
254
 
249
- if (isString(selector)) {
250
- const element = findElementWithSelectorUpwards(this, selector);
251
- if (element === null) {
252
- throw new Error("the selector must match exactly one element");
253
- }
255
+ if (isString(selector)) {
256
+ const element = findElementWithSelectorUpwards(this, selector);
257
+ if (element === null) {
258
+ throw new Error("the selector must match exactly one element");
259
+ }
254
260
 
255
- if (!(element instanceof Datasource)) {
256
- throw new TypeError("the element must be a datasource");
257
- }
261
+ if (!(element instanceof Datasource)) {
262
+ throw new TypeError("the element must be a datasource");
263
+ }
258
264
 
259
- this[datasourceLinkedElementSymbol] = element;
260
- element.datasource.attachObserver(
261
- new Observer(handleDataSourceChanges.bind(this)),
262
- );
263
- } else {
264
- throw new Error("the selector must be a string");
265
+ this[datasourceLinkedElementSymbol] = element;
266
+ element.datasource.attachObserver(
267
+ new Observer(handleDataSourceChanges.bind(this)),
268
+ );
269
+ } else {
270
+ throw new Error("the selector must be a string");
271
+ }
265
272
  }
266
273
 
267
274
  if (
@@ -274,6 +274,7 @@ class Filter extends CustomElement {
274
274
 
275
275
  query: undefined,
276
276
  defaultQuery: "",
277
+ eventProcessing: true,
277
278
  });
278
279
  }
279
280
 
@@ -201,7 +201,6 @@ class ContextError extends Popper {
201
201
  }
202
202
 
203
203
  if (c === "<slot></slot>") {
204
-
205
204
  const sr = this.shadowRoot;
206
205
  if (!sr) {
207
206
  return false;
@@ -12,28 +12,18 @@
12
12
  * SPDX-License-Identifier: AGPL-3.0
13
13
  */
14
14
 
15
- import {internalSymbol} from "../../constants.mjs";
16
- import {Pathfinder} from "../../data/pathfinder.mjs";
15
+ import { Datasource } from "../../data/datasource.mjs";
16
+ import { DeadMansSwitch } from "../../util/deadmansswitch.mjs";
17
+ import { DataSet } from "../datatable/dataset.mjs";
17
18
  import {
18
- ATTRIBUTE_FORM_BIND,
19
- ATTRIBUTE_FORM_BIND_TYPE,
20
- ATTRIBUTE_UPDATER_BIND,
21
- } from "../../dom/constants.mjs";
22
- import {findTargetElementFromEvent} from "../../dom/events.mjs";
23
- import {ID} from "../../types/id.mjs";
24
- import {clone} from "../../util/clone.mjs";
25
- import {DeadMansSwitch} from "../../util/deadmansswitch.mjs";
26
- import {DataSet} from "../datatable/dataset.mjs";
27
- import {
28
- assembleMethodSymbol,
29
- registerCustomElement,
30
- getSlottedElements,
19
+ assembleMethodSymbol,
20
+ registerCustomElement,
21
+ getSlottedElements,
31
22
  } from "../../dom/customelement.mjs";
32
- import {FormStyleSheet} from "./stylesheet/form.mjs";
33
- import {diff} from "../../data/diff.mjs";
34
- import {isString} from "../../types/is.mjs";
23
+ import { datasourceLinkedElementSymbol } from "../datatable/util.mjs";
24
+ import { FormStyleSheet } from "./stylesheet/form.mjs";
35
25
 
36
- export {Form};
26
+ export { Form };
37
27
 
38
28
  /**
39
29
  * @private
@@ -48,198 +38,159 @@ const debounceWriteBackSymbol = Symbol("debounceWriteBack");
48
38
  const debounceBindSymbol = Symbol("debounceBind");
49
39
 
50
40
  class Form extends DataSet {
51
- /**
52
- *
53
- * @property {Object} templates Template definitions
54
- * @property {string} templates.main Main template
55
- * @property {Object} classes Class definitions
56
- * @property {string} classes.form Form class
57
- * @property {Object} writeBack Write back definitions
58
- * @property {string[]} writeBack.events Write back events
59
- * @property {Object} bind Bind definitions
60
- * @property {string[]} bind.events Bind events
61
- * @property {Object} reportValidity Report validity definitions
62
- * @property {string} reportValidity.selector Report validity selector
63
- * @property {boolean} features.mutationObserver Mutation observer feature
64
- * @property {boolean} features.writeBack Write back feature
65
- * @property {boolean} features.bind Bind feature
66
- */
67
- get defaults() {
68
- const obj = Object.assign({}, super.defaults, {
69
- templates: {
70
- main: getTemplate(),
71
- },
72
-
73
- classes: {
74
- form: "",
75
- },
76
-
77
- writeBack: {
78
- events: ["keyup", "click", "change", "drop", "touchend", "input"]
79
- },
80
-
81
- bind: {
82
- events: ["keyup", "click", "change", "drop", "touchend", "input"]
83
- },
84
-
85
- reportValidity: {
86
- selector: "input,select,textarea",
87
- },
88
- });
89
-
90
- obj["features"]["mutationObserver"] = false;
91
- obj["features"]["writeBack"] = true;
92
- obj["features"]["bind"] = true;
93
-
94
- return obj;
95
- }
96
-
97
- /**
98
- *
99
- * @return {string}
100
- */
101
- static getTag() {
102
- return "monster-form";
103
- }
104
-
105
- /**
106
- * @return {CSSStyleSheet[]}
107
- */
108
- static getCSSStyleSheet() {
109
- return [FormStyleSheet];
110
- }
111
-
112
- /**
113
- *
114
- */
115
- [assembleMethodSymbol]() {
116
- super[assembleMethodSymbol]();
117
-
118
- initControlReferences.call(this);
119
- initEventHandler.call(this);
120
- initDataSourceHandler.call(this);
121
- }
122
-
123
- /**
124
- * This method is called when the component is created.
125
- * @since 3.70.0
126
- * @returns {DataSet}
127
- */
128
- refresh() {
129
- this.write();
130
- super.refresh();
131
- return this;
132
- }
133
-
134
- /**
135
- * Run reportValidation on all child html form controls.
136
- *
137
- * @since 2.10.0
138
- * @returns {boolean}
139
- */
140
- reportValidity() {
141
- let valid = true;
142
-
143
- const selector = this.getOption("reportValidity.selector");
144
- const nodes = getSlottedElements.call(this, selector);
145
-
146
- nodes.forEach((node) => {
147
- if (typeof node.reportValidity === "function") {
148
- if (node.reportValidity() === false) {
149
- valid = false;
150
- }
151
- }
152
- });
153
-
154
- return valid;
155
- }
41
+ /**
42
+ *
43
+ * @property {Object} templates Template definitions
44
+ * @property {string} templates.main Main template
45
+ * @property {Object} classes Class definitions
46
+ * @property {string} classes.form Form class
47
+ * @property {Object} writeBack Write back definitions
48
+ * @property {string[]} writeBack.events Write back events
49
+ * @property {Object} bind Bind definitions
50
+ * @property {Object} reportValidity Report validity definitions
51
+ * @property {string} reportValidity.selector Report validity selector
52
+ * @property {boolean} features.mutationObserver Mutation observer feature
53
+ * @property {boolean} features.writeBack Write back feature
54
+ * @property {boolean} features.bind Bind feature
55
+ */
56
+ get defaults() {
57
+ const obj = Object.assign({}, super.defaults, {
58
+ templates: {
59
+ main: getTemplate(),
60
+ },
61
+
62
+ classes: {
63
+ form: "",
64
+ },
65
+
66
+ writeBack: {
67
+ events: ["keyup", "click", "change", "drop", "touchend", "input"],
68
+ },
69
+
70
+ reportValidity: {
71
+ selector: "input,select,textarea",
72
+ },
73
+
74
+ eventProcessing: true,
75
+ });
76
+
77
+ obj["features"]["mutationObserver"] = false;
78
+ obj["features"]["writeBack"] = true;
79
+
80
+ return obj;
81
+ }
82
+
83
+ /**
84
+ *
85
+ * @return {string}
86
+ */
87
+ static getTag() {
88
+ return "monster-form";
89
+ }
90
+
91
+ /**
92
+ * @return {CSSStyleSheet[]}
93
+ */
94
+ static getCSSStyleSheet() {
95
+ return [FormStyleSheet];
96
+ }
97
+
98
+ /**
99
+ *
100
+ */
101
+ [assembleMethodSymbol]() {
102
+ const selector = this.getOption("datasource.selector");
103
+
104
+ if (!selector) {
105
+ this[datasourceLinkedElementSymbol] = new Datasource(this);
106
+ }
107
+
108
+ super[assembleMethodSymbol]();
109
+
110
+ initControlReferences.call(this);
111
+ initEventHandler.call(this);
112
+ initDataSourceHandler.call(this);
113
+ }
114
+
115
+ /**
116
+ * This method is called when the component is created.
117
+ * @since 3.70.0
118
+ * @returns {DataSet}
119
+ */
120
+ refresh() {
121
+ this.write();
122
+ super.refresh();
123
+ return this;
124
+ }
125
+
126
+ /**
127
+ * Run reportValidation on all child html form controls.
128
+ *
129
+ * @since 2.10.0
130
+ * @returns {boolean}
131
+ */
132
+ reportValidity() {
133
+ let valid = true;
134
+
135
+ const selector = this.getOption("reportValidity.selector");
136
+ const nodes = getSlottedElements.call(this, selector);
137
+
138
+ nodes.forEach((node) => {
139
+ if (typeof node.reportValidity === "function") {
140
+ if (node.reportValidity() === false) {
141
+ valid = false;
142
+ }
143
+ }
144
+ });
145
+
146
+ return valid;
147
+ }
156
148
  }
157
149
 
158
- function initDataSourceHandler() {
159
- }
150
+ function initDataSourceHandler() {}
160
151
 
161
152
  /**
162
153
  * @private
163
154
  * @returns {initEventHandler}
164
155
  */
165
156
  function initEventHandler() {
166
- this[debounceBindSymbol] = {};
167
-
168
- if (this.getOption("features.bind") === true) {
169
- const events = this.getOption("bind.events");
170
-
171
- for (const event of events) {
172
- this.addEventListener(event, (e) => {
173
- const element = findTargetElementFromEvent(e, ATTRIBUTE_FORM_BIND);
174
-
175
- if (!(element instanceof HTMLElement)) {
176
- return;
177
- }
178
-
179
- let elementID
180
- if (!element.hasAttribute("data-monster-debounce-id")) {
181
- elementID = new ID('debounce').toString();
182
- element.setAttribute("data-monster-debounce-id", elementID);
183
- } else {
184
- elementID = element.getAttribute("data-monster-debounce-id");
185
- }
186
-
187
- if (this[debounceBindSymbol][elementID] instanceof DeadMansSwitch) {
188
- try {
189
- this[debounceBindSymbol][elementID].touch();
190
- return;
191
- } catch (e) {
192
- if (e.message !== "has already run") {
193
- throw e;
194
- }
195
-
196
- delete this[debounceBindSymbol][elementID];
197
- }
198
- }
199
-
200
- this[debounceBindSymbol][elementID] = new DeadMansSwitch(200, () => {
201
- delete this[debounceBindSymbol][elementID];
202
- retrieveAndSetValue.call(this, element);
203
- });
204
- });
205
- }
206
- }
207
-
208
- if (this.getOption("features.writeBack") === true) {
209
- const events = this.getOption("writeBack.events");
210
- for (const event of events) {
211
- this.addEventListener(event, (e) => {
212
- if (!this.reportValidity()) {
213
- this.classList.add("invalid");
214
- setTimeout(() => {
215
- this.classList.remove("invalid");
216
- }, 1000);
217
-
218
- return;
219
- }
220
-
221
- if (this[debounceWriteBackSymbol] instanceof DeadMansSwitch) {
222
- try {
223
- this[debounceWriteBackSymbol].touch();
224
- return;
225
- } catch (e) {
226
- if (e.message !== "has already run") {
227
- throw e;
228
- }
229
- delete this[debounceWriteBackSymbol];
230
- }
231
- }
232
-
233
- this[debounceWriteBackSymbol] = new DeadMansSwitch(200, () => {
234
- setTimeout(() => {
235
- this.write();
236
- }, 0);
237
- });
238
- });
239
- }
240
- }
241
-
242
- return this;
157
+ this[debounceBindSymbol] = {};
158
+
159
+ if (this.getOption("features.writeBack") === true) {
160
+ const events = this.getOption("writeBack.events");
161
+ for (const event of events) {
162
+ this.addEventListener(event, (e) => {
163
+ if (!this.reportValidity()) {
164
+ this.classList.add("invalid");
165
+ setTimeout(() => {
166
+ this.classList.remove("invalid");
167
+ }, 1000);
168
+
169
+ return;
170
+ }
171
+
172
+ if (this[debounceWriteBackSymbol] instanceof DeadMansSwitch) {
173
+ try {
174
+ this[debounceWriteBackSymbol].touch();
175
+ return;
176
+ } catch (e) {
177
+ if (e.message !== "has already run") {
178
+ throw e;
179
+ }
180
+ delete this[debounceWriteBackSymbol];
181
+ }
182
+ }
183
+
184
+ this[debounceWriteBackSymbol] = new DeadMansSwitch(200, () => {
185
+ setTimeout(() => {
186
+ this.write();
187
+ }, 0);
188
+ });
189
+ });
190
+ }
191
+ }
192
+
193
+ return this;
243
194
  }
244
195
 
245
196
  /**
@@ -247,115 +198,10 @@ function initEventHandler() {
247
198
  * @return {FilterButton}
248
199
  */
249
200
  function initControlReferences() {
250
- if (!this.shadowRoot) {
251
- throw new Error("no shadow-root is defined");
252
- }
253
- return this;
254
- }
255
-
256
- /**
257
- * @throws {Error} the bind argument must start as a value with a path
258
- * @param {HTMLElement} element
259
- * @return void
260
- * @memberOf Monster.DOM
261
- * @private
262
- */
263
- function retrieveAndSetValue(element) {
264
- let path = element.getAttribute(ATTRIBUTE_FORM_BIND);
265
- if (path === null)
266
- throw new Error("the bind argument must start as a value with a path");
267
-
268
- if (path.indexOf("path:") !== 0) {
269
- throw new Error("the bind argument must start as a value with a path");
270
- }
271
-
272
- path = path.substring(5); // remove path: from the string
273
-
274
- let value;
275
-
276
- if (element instanceof HTMLInputElement) {
277
- switch (element.type) {
278
- case "checkbox":
279
- value = element.checked ? element.value : undefined;
280
- break;
281
- default:
282
- value = element.value;
283
- break;
284
- }
285
- } else if (element instanceof HTMLTextAreaElement) {
286
- value = element.value;
287
- } else if (element instanceof HTMLSelectElement) {
288
- switch (element.type) {
289
- case "select-one":
290
- value = element.value;
291
- break;
292
- case "select-multiple":
293
- value = element.value;
294
-
295
- let options = element?.selectedOptions;
296
- if (options === undefined)
297
- options = element.querySelectorAll(":scope option:checked");
298
- value = Array.from(options).map(({value}) => value);
299
-
300
- break;
301
- }
302
-
303
- // values from custom elements
304
- } else if (
305
- (element?.constructor?.prototype &&
306
- !!Object.getOwnPropertyDescriptor(
307
- element.constructor.prototype,
308
- "value",
309
- )?.["get"]) ||
310
- element.hasOwnProperty("value")
311
- ) {
312
- value = element?.["value"];
313
- } else {
314
- throw new Error("unsupported object");
315
- }
316
-
317
- if (isString(value)) {
318
- const type = element.getAttribute(ATTRIBUTE_FORM_BIND_TYPE);
319
- switch (type) {
320
- case "number":
321
- case "int":
322
- case "float":
323
- case "integer":
324
- value = Number(value);
325
- if (isNaN(value)) {
326
- value = 0;
327
- }
328
- break;
329
- case "boolean":
330
- case "bool":
331
- case "checkbox":
332
- value = value === "true" || value === "1" || value === "on";
333
- break;
334
- case "array":
335
- case "list":
336
- value = value.split(",");
337
- break;
338
- case "object":
339
- case "json":
340
- value = JSON.parse(value);
341
- break;
342
- default:
343
- break;
344
- }
345
- }
346
-
347
- const copy = clone(this[internalSymbol].getRealSubject()?.options);
348
-
349
- const pf = new Pathfinder(copy);
350
- pf.setVia(path, value);
351
-
352
- const diffResult = diff(copy, this[internalSymbol].getRealSubject()?.options);
353
-
354
- if (diffResult.length > 0) {
355
- setTimeout(() => {
356
- this.setOption(path, value);
357
- }, 50);
358
- }
201
+ if (!this.shadowRoot) {
202
+ throw new Error("no shadow-root is defined");
203
+ }
204
+ return this;
359
205
  }
360
206
 
361
207
  /**
@@ -363,8 +209,8 @@ function retrieveAndSetValue(element) {
363
209
  * @return {string}
364
210
  */
365
211
  function getTemplate() {
366
- // language=HTML
367
- return `
212
+ // language=HTML
213
+ return `
368
214
  <div data-monster-role="control" part="control">
369
215
  <form data-monster-attributes="disabled path:disabled | if:true, class path:classes.form"
370
216
  data-monster-role="form"
@@ -327,6 +327,7 @@ class CustomElement extends HTMLElement {
327
327
  * @property {Object} templates Specifies the templates used by the control.
328
328
  * @property {string} templates.main=undefined Specifies the main template used by the control.
329
329
  * @property {Object} templateMapping Specifies the mapping of templates.
330
+ * @property {Boolean} eventProcessing=false Specifies whether the control processes events.
330
331
  * @since 1.8.0
331
332
  */
332
333
  get defaults() {
@@ -338,6 +339,8 @@ class CustomElement extends HTMLElement {
338
339
  main: undefined,
339
340
  },
340
341
  templateMapping: {},
342
+
343
+ eventProcessing: false,
341
344
  };
342
345
  }
343
346
 
@@ -644,11 +647,17 @@ class CustomElement extends HTMLElement {
644
647
  this[internalSymbol].getRealSubject()["options"],
645
648
  );
646
649
 
650
+ const cfg = {};
651
+ if (this.getOption("eventProcessing") === true) {
652
+ cfg.eventProcessing = true;
653
+ }
654
+
647
655
  addObjectWithUpdaterToElement.call(
648
656
  this,
649
657
  nodeList,
650
658
  customElementUpdaterLinkSymbol,
651
659
  this[updateCloneDataSymbol],
660
+ cfg,
652
661
  );
653
662
 
654
663
  // Attach a mutation observer to observe changes to the attributes of the element