@schukai/monster 4.85.2 → 4.87.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/CHANGELOG.md CHANGED
@@ -2,6 +2,25 @@
2
2
 
3
3
 
4
4
 
5
+ ## [4.87.0] - 2026-01-11
6
+
7
+ ### Add Features
8
+
9
+ - Add functionality for change events in text fields for issue [#371](https://gitlab.schukai.com/oss/libraries/javascript/monster/issues/371)
10
+
11
+
12
+
13
+ ## [4.86.0] - 2026-01-10
14
+
15
+ ### Add Features
16
+
17
+ - Add investigation for form writeback and control ([#370](https://gitlab.schukai.com/oss/libraries/javascript/monster/issues/370))
18
+ ### Changes
19
+
20
+ - close issue
21
+
22
+
23
+
5
24
  ## [4.85.2] - 2026-01-08
6
25
 
7
26
  ### Bug Fixes
package/package.json CHANGED
@@ -1 +1 @@
1
- {"author":"Volker Schukai","dependencies":{"@floating-ui/dom":"^1.7.4","@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":"4.85.2"}
1
+ {"author":"Volker Schukai","dependencies":{"@floating-ui/dom":"^1.7.4","@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":"4.87.0"}
@@ -14,14 +14,24 @@
14
14
 
15
15
  import { instanceSymbol } from "../../constants.mjs";
16
16
  import { diff } from "../../data/diff.mjs";
17
- import { addAttributeToken } from "../../dom/attributes.mjs";
18
- import { ATTRIBUTE_ERRORMESSAGE } from "../../dom/constants.mjs";
17
+ import {
18
+ addAttributeToken,
19
+ getLinkedObjects,
20
+ hasObjectLink,
21
+ } from "../../dom/attributes.mjs";
22
+ import {
23
+ ATTRIBUTE_ERRORMESSAGE,
24
+ customElementUpdaterLinkSymbol,
25
+ } from "../../dom/constants.mjs";
19
26
  import {
20
27
  assembleMethodSymbol,
21
28
  CustomElement,
22
29
  registerCustomElement,
23
30
  } from "../../dom/customelement.mjs";
24
- import { findElementWithSelectorUpwards } from "../../dom/util.mjs";
31
+ import {
32
+ findElementWithSelectorUpwards,
33
+ getDocument,
34
+ } from "../../dom/util.mjs";
25
35
  import { isString, isArray } from "../../types/is.mjs";
26
36
  import { Observer } from "../../types/observer.mjs";
27
37
  import { TokenList } from "../../types/tokenlist.mjs";
@@ -346,8 +356,8 @@ function initEventHandler() {
346
356
  this[saveInFlightSymbol] = true;
347
357
  this[stateButtonElementSymbol].setOption("disabled", true);
348
358
 
349
- this[datasourceLinkedElementSymbol]
350
- .write()
359
+ flushLinkedForms.call(this)
360
+ .then(() => this[datasourceLinkedElementSymbol].write())
351
361
  .then(() => {
352
362
  this[originValuesSymbol] = null;
353
363
  this[originValuesSymbol] = clone(
@@ -378,6 +388,49 @@ function initEventHandler() {
378
388
  });
379
389
  }
380
390
 
391
+ /**
392
+ * @private
393
+ * @return {Promise<void>}
394
+ */
395
+ function flushLinkedForms() {
396
+ const datasource = this[datasourceLinkedElementSymbol];
397
+ if (!datasource) {
398
+ return Promise.resolve();
399
+ }
400
+
401
+ const doc = getDocument();
402
+ const forms = doc.querySelectorAll("monster-form");
403
+ const writes = [];
404
+
405
+ for (const form of forms) {
406
+ if (!(form instanceof HTMLElement)) {
407
+ continue;
408
+ }
409
+ if (form[datasourceLinkedElementSymbol] !== datasource) {
410
+ continue;
411
+ }
412
+
413
+ if (hasObjectLink(form, customElementUpdaterLinkSymbol)) {
414
+ const updaters = getLinkedObjects(form, customElementUpdaterLinkSymbol);
415
+ for (const list of updaters) {
416
+ for (const updater of list) {
417
+ updater.retrieve();
418
+ }
419
+ }
420
+ }
421
+
422
+ if (typeof form.write === "function") {
423
+ writes.push(form.write());
424
+ }
425
+ }
426
+
427
+ if (writes.length === 0) {
428
+ return Promise.resolve();
429
+ }
430
+
431
+ return Promise.all(writes).then(() => {});
432
+ }
433
+
381
434
  /**
382
435
  * @private
383
436
  */
@@ -189,6 +189,12 @@ function initEventHandler() {
189
189
  const events = this.getOption("writeBack.events");
190
190
  for (const event of events) {
191
191
  this.addEventListener(event, (e) => {
192
+ const target = e?.target;
193
+ const targetTag = target?.tagName?.toLowerCase?.();
194
+ if (targetTag === "monster-select" && e.type !== "change") {
195
+ return;
196
+ }
197
+
192
198
  if (e?.target && typeof e.target.setCustomValidity === "function") {
193
199
  e.target.setCustomValidity("");
194
200
  e.target.removeAttribute("data-monster-validation-error");
@@ -3241,6 +3241,40 @@ function isValueIsEmptyThenGetNormalize(value) {
3241
3241
  return value;
3242
3242
  }
3243
3243
 
3244
+ /**
3245
+ * @private
3246
+ * @param {Array} current
3247
+ * @param {Array} next
3248
+ * @returns {boolean}
3249
+ */
3250
+ function areSelectionValuesEqual(current, next) {
3251
+ if (!isArray(current) || !isArray(next)) {
3252
+ return false;
3253
+ }
3254
+
3255
+ if (current.length !== next.length) {
3256
+ return false;
3257
+ }
3258
+
3259
+ const toValue = (item) => {
3260
+ if (isObject(item) && Object.prototype.hasOwnProperty.call(item, "value")) {
3261
+ return `${item.value}`;
3262
+ }
3263
+ return `${item}`;
3264
+ };
3265
+
3266
+ const currentValues = current.map(toValue).sort();
3267
+ const nextValues = next.map(toValue).sort();
3268
+
3269
+ for (let i = 0; i < currentValues.length; i++) {
3270
+ if (currentValues[i] !== nextValues[i]) {
3271
+ return false;
3272
+ }
3273
+ }
3274
+
3275
+ return true;
3276
+ }
3277
+
3244
3278
  /**
3245
3279
  * @private
3246
3280
  * @param selection
@@ -3280,27 +3314,34 @@ function setSelection(selection) {
3280
3314
 
3281
3315
  selection = resultSelection;
3282
3316
 
3317
+ const previousSelection = this.getOption("selection", []);
3318
+ const valuesChanged = !areSelectionValuesEqual(previousSelection, selection);
3319
+
3283
3320
  if (!isInteger(this[selectionVersionSymbol])) {
3284
3321
  this[selectionVersionSymbol] = 0;
3285
3322
  }
3286
- this[selectionVersionSymbol] += 1;
3323
+ if (valuesChanged) {
3324
+ this[selectionVersionSymbol] += 1;
3325
+ }
3287
3326
 
3288
3327
  this.setOption("selection", selection);
3289
3328
 
3290
3329
  checkOptionState.call(this);
3291
3330
  setSummaryAndControlText.call(this);
3292
3331
 
3293
- try {
3294
- this?.setFormValue(this.value);
3295
- } catch (e) {
3296
- addErrorAttribute(this, e);
3297
- }
3332
+ if (valuesChanged) {
3333
+ try {
3334
+ this?.setFormValue(this.value);
3335
+ } catch (e) {
3336
+ addErrorAttribute(this, e);
3337
+ }
3298
3338
 
3299
- fireCustomEvent(this, "monster-selected", {
3300
- selection,
3301
- });
3339
+ fireCustomEvent(this, "monster-selected", {
3340
+ selection,
3341
+ });
3302
3342
 
3303
- fireEvent(this, "change"); // https://gitlab.schukai.com/oss/libraries/javascript/monster/-/issues/291
3343
+ fireEvent(this, "change"); // https://gitlab.schukai.com/oss/libraries/javascript/monster/-/issues/291
3344
+ }
3304
3345
 
3305
3346
  if (this[runLookupOnceSymbol] !== true && selection.length > 0) {
3306
3347
  this[runLookupOnceSymbol] = true;