@schukai/monster 4.54.1 → 4.55.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
package/package.json
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"author":"schukai GmbH","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.
|
|
1
|
+
{"author":"schukai GmbH","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.55.0"}
|
package/source/dom/updater.mjs
CHANGED
|
@@ -71,6 +71,7 @@ const pendingDiffsSymbol = Symbol("pendingDiffs");
|
|
|
71
71
|
* @type {symbol}
|
|
72
72
|
*/
|
|
73
73
|
const processingSymbol = Symbol("processing");
|
|
74
|
+
const updaterRootSymbol = Symbol.for("@schukai/monster/dom/@@updater-root");
|
|
74
75
|
|
|
75
76
|
/**
|
|
76
77
|
* The updater class connects an object with the DOM. In this way, structures and contents in the DOM can be
|
|
@@ -123,6 +124,7 @@ class Updater extends Base {
|
|
|
123
124
|
eventTypes: ["keyup", "click", "change", "drop", "touchend", "input"],
|
|
124
125
|
subject: subject,
|
|
125
126
|
};
|
|
127
|
+
this[internalSymbol].element[updaterRootSymbol] = true;
|
|
126
128
|
|
|
127
129
|
this[internalSymbol].callbacks.set(
|
|
128
130
|
"checkstate",
|
|
@@ -137,6 +139,9 @@ class Updater extends Base {
|
|
|
137
139
|
const real = this[internalSymbol].subject.getRealSubject();
|
|
138
140
|
const diffResult = diff(this[internalSymbol].last, real);
|
|
139
141
|
this[internalSymbol].last = clone(real);
|
|
142
|
+
if (diffResult.length === 0) {
|
|
143
|
+
return Promise.resolve();
|
|
144
|
+
}
|
|
140
145
|
this[pendingDiffsSymbol].push(diffResult);
|
|
141
146
|
return this.#processQueue();
|
|
142
147
|
}),
|
|
@@ -343,6 +348,10 @@ function getControlEventHandler() {
|
|
|
343
348
|
* @param {Event} event
|
|
344
349
|
*/
|
|
345
350
|
this[symbol] = (event) => {
|
|
351
|
+
const root = findClosestUpdaterRootFromEvent(event);
|
|
352
|
+
if (root !== this[internalSymbol].element) {
|
|
353
|
+
return;
|
|
354
|
+
}
|
|
346
355
|
const element = findTargetElementFromEvent(event, ATTRIBUTE_UPDATER_BIND);
|
|
347
356
|
|
|
348
357
|
if (element === undefined) {
|
|
@@ -370,6 +379,27 @@ function getControlEventHandler() {
|
|
|
370
379
|
return this[symbol];
|
|
371
380
|
}
|
|
372
381
|
|
|
382
|
+
/**
|
|
383
|
+
* @private
|
|
384
|
+
* @param {Event} event
|
|
385
|
+
* @return {HTMLElement|undefined}
|
|
386
|
+
*/
|
|
387
|
+
function findClosestUpdaterRootFromEvent(event) {
|
|
388
|
+
if (typeof event?.composedPath !== "function") {
|
|
389
|
+
return undefined;
|
|
390
|
+
}
|
|
391
|
+
|
|
392
|
+
const path = event.composedPath();
|
|
393
|
+
for (let i = 0; i < path.length; i++) {
|
|
394
|
+
const node = path[i];
|
|
395
|
+
if (node instanceof HTMLElement && node[updaterRootSymbol] === true) {
|
|
396
|
+
return node;
|
|
397
|
+
}
|
|
398
|
+
}
|
|
399
|
+
|
|
400
|
+
return undefined;
|
|
401
|
+
}
|
|
402
|
+
|
|
373
403
|
/**
|
|
374
404
|
* @throws {Error} the bind argument must start as a value with a path
|
|
375
405
|
* @param {HTMLElement} element
|
|
@@ -247,7 +247,7 @@ function getHandler() {
|
|
|
247
247
|
|
|
248
248
|
// https://262.ecma-international.org/9.0/#sec-proxy-object-internal-methods-and-internal-slots-setprototypeof-v
|
|
249
249
|
setPrototypeOf: function (target, key) {
|
|
250
|
-
const result = Reflect.setPrototypeOf(
|
|
250
|
+
const result = Reflect.setPrototypeOf(target, key);
|
|
251
251
|
|
|
252
252
|
if (typeof key !== "symbol") {
|
|
253
253
|
proxy.observers.notify(proxy);
|
|
@@ -109,6 +109,15 @@ let html4 = `
|
|
|
109
109
|
|
|
110
110
|
`;
|
|
111
111
|
|
|
112
|
+
let htmlNested = `
|
|
113
|
+
<div id="parent">
|
|
114
|
+
<input id="parent-input" type="text" data-monster-bind="path:parentVal">
|
|
115
|
+
<div id="child">
|
|
116
|
+
<input id="child-input" type="text" data-monster-bind="path:childVal">
|
|
117
|
+
</div>
|
|
118
|
+
</div>
|
|
119
|
+
`;
|
|
120
|
+
|
|
112
121
|
describe("DOM", function () {
|
|
113
122
|
let Updater = null;
|
|
114
123
|
|
|
@@ -525,6 +534,117 @@ describe("DOM", function () {
|
|
|
525
534
|
});
|
|
526
535
|
});
|
|
527
536
|
|
|
537
|
+
describe("Updater()", function () {
|
|
538
|
+
beforeEach(() => {
|
|
539
|
+
let mocks = document.getElementById("mocks");
|
|
540
|
+
mocks.innerHTML = htmlNested;
|
|
541
|
+
});
|
|
542
|
+
|
|
543
|
+
describe("Nested Eventhandling", function () {
|
|
544
|
+
it("should not propagate child events to parent updater", function (done) {
|
|
545
|
+
const parentObserver = new ProxyObserver({});
|
|
546
|
+
const childObserver = new ProxyObserver({});
|
|
547
|
+
const parentUpdater = new Updater(
|
|
548
|
+
document.getElementById("parent"),
|
|
549
|
+
parentObserver,
|
|
550
|
+
);
|
|
551
|
+
const childUpdater = new Updater(
|
|
552
|
+
document.getElementById("child"),
|
|
553
|
+
childObserver,
|
|
554
|
+
);
|
|
555
|
+
|
|
556
|
+
parentUpdater.enableEventProcessing();
|
|
557
|
+
childUpdater.enableEventProcessing();
|
|
558
|
+
|
|
559
|
+
let parentNotified = false;
|
|
560
|
+
parentObserver.attachObserver(
|
|
561
|
+
new Observer(function () {
|
|
562
|
+
parentNotified = true;
|
|
563
|
+
}),
|
|
564
|
+
);
|
|
565
|
+
|
|
566
|
+
childObserver.attachObserver(
|
|
567
|
+
new Observer(function () {
|
|
568
|
+
try {
|
|
569
|
+
expect(childUpdater.getSubject()["childVal"]).to.equal("child");
|
|
570
|
+
expect(parentUpdater.getSubject()).to.not.have.property(
|
|
571
|
+
"childVal",
|
|
572
|
+
);
|
|
573
|
+
setTimeout(() => {
|
|
574
|
+
if (parentNotified) {
|
|
575
|
+
done(
|
|
576
|
+
new Error(
|
|
577
|
+
"parent updater should not react to child bind events",
|
|
578
|
+
),
|
|
579
|
+
);
|
|
580
|
+
} else {
|
|
581
|
+
done();
|
|
582
|
+
}
|
|
583
|
+
}, 10);
|
|
584
|
+
} catch (e) {
|
|
585
|
+
done(e);
|
|
586
|
+
}
|
|
587
|
+
}),
|
|
588
|
+
);
|
|
589
|
+
|
|
590
|
+
const childInput = document.getElementById("child-input");
|
|
591
|
+
childInput.value = "child";
|
|
592
|
+
childInput.click();
|
|
593
|
+
});
|
|
594
|
+
|
|
595
|
+
it("should handle parent events without triggering child updater", function (done) {
|
|
596
|
+
const parentObserver = new ProxyObserver({});
|
|
597
|
+
const childObserver = new ProxyObserver({});
|
|
598
|
+
const parentUpdater = new Updater(
|
|
599
|
+
document.getElementById("parent"),
|
|
600
|
+
parentObserver,
|
|
601
|
+
);
|
|
602
|
+
const childUpdater = new Updater(
|
|
603
|
+
document.getElementById("child"),
|
|
604
|
+
childObserver,
|
|
605
|
+
);
|
|
606
|
+
|
|
607
|
+
parentUpdater.enableEventProcessing();
|
|
608
|
+
childUpdater.enableEventProcessing();
|
|
609
|
+
|
|
610
|
+
let childNotified = false;
|
|
611
|
+
childObserver.attachObserver(
|
|
612
|
+
new Observer(function () {
|
|
613
|
+
childNotified = true;
|
|
614
|
+
}),
|
|
615
|
+
);
|
|
616
|
+
|
|
617
|
+
parentObserver.attachObserver(
|
|
618
|
+
new Observer(function () {
|
|
619
|
+
try {
|
|
620
|
+
expect(parentUpdater.getSubject()["parentVal"]).to.equal("parent");
|
|
621
|
+
expect(childUpdater.getSubject()).to.not.have.property(
|
|
622
|
+
"parentVal",
|
|
623
|
+
);
|
|
624
|
+
setTimeout(() => {
|
|
625
|
+
if (childNotified) {
|
|
626
|
+
done(
|
|
627
|
+
new Error(
|
|
628
|
+
"child updater should not react to parent bind events",
|
|
629
|
+
),
|
|
630
|
+
);
|
|
631
|
+
} else {
|
|
632
|
+
done();
|
|
633
|
+
}
|
|
634
|
+
}, 10);
|
|
635
|
+
} catch (e) {
|
|
636
|
+
done(e);
|
|
637
|
+
}
|
|
638
|
+
}),
|
|
639
|
+
);
|
|
640
|
+
|
|
641
|
+
const parentInput = document.getElementById("parent-input");
|
|
642
|
+
parentInput.value = "parent";
|
|
643
|
+
parentInput.click();
|
|
644
|
+
});
|
|
645
|
+
});
|
|
646
|
+
});
|
|
647
|
+
|
|
528
648
|
describe("Updater()", function () {
|
|
529
649
|
beforeEach(() => {
|
|
530
650
|
let mocks = document.getElementById("mocks");
|
|
@@ -216,5 +216,18 @@ describe('ProxyObserver', function () {
|
|
|
216
216
|
});
|
|
217
217
|
});
|
|
218
218
|
|
|
219
|
-
|
|
219
|
+
describe('setPrototypeOf', function () {
|
|
220
|
+
it('should allow setPrototypeOf and notify observer', function (done) {
|
|
221
|
+
const proxy = new ProxyObserver({});
|
|
222
|
+
const observer = new Observer(function () {
|
|
223
|
+
done();
|
|
224
|
+
});
|
|
225
|
+
proxy.attachObserver(observer);
|
|
226
|
+
|
|
227
|
+
const proto = {flag: true};
|
|
228
|
+
Object.setPrototypeOf(proxy.getSubject(), proto);
|
|
229
|
+
expect(Object.getPrototypeOf(proxy.getSubject())).to.equal(proto);
|
|
230
|
+
});
|
|
231
|
+
});
|
|
220
232
|
|
|
233
|
+
})
|