@schukai/monster 4.128.2 → 4.129.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/package.json +1 -1
- package/source/components/content/stylesheet/camera-capture.mjs +1 -1
- package/source/components/content/stylesheet/copy.mjs +1 -1
- package/source/components/content/viewer/stylesheet/message.mjs +1 -1
- package/source/components/datatable/columnbar.mjs +30 -3
- package/source/components/datatable/datatable.mjs +29 -1
- package/source/components/datatable/pagination.mjs +39 -1
- package/source/components/datatable/stylesheet/filter-controls-defaults.mjs +1 -1
- package/source/components/form/login.mjs +197 -0
- package/source/components/form/select.mjs +4 -4
- package/source/components/form/stylesheet/button-bar.mjs +1 -1
- package/source/components/form/stylesheet/confirm-button.mjs +1 -1
- package/source/components/form/stylesheet/context-error.mjs +1 -1
- package/source/components/form/stylesheet/context-help.mjs +1 -1
- package/source/components/form/stylesheet/digits.mjs +1 -1
- package/source/components/form/stylesheet/field-set.mjs +1 -1
- package/source/components/form/stylesheet/login.mjs +1 -1
- package/source/components/form/stylesheet/popper-button.mjs +1 -1
- package/source/components/form/stylesheet/select.mjs +1 -1
- package/source/components/form/tree-select.mjs +2 -2
- package/source/components/layout/stylesheet/popper.mjs +1 -1
- package/source/components/style/floating-ui.css +7 -0
- package/source/dom/customcontrol.mjs +1 -1
- package/source/dom/customelement.mjs +218 -16
- package/source/dom/updater.mjs +32 -12
- package/source/types/is.mjs +3 -0
- package/source/types/proxyobserver.mjs +10 -13
- package/source/types/version.mjs +1 -1
- package/test/cases/components/content/image-editor.mjs +98 -0
- package/test/cases/components/datatable/drag-scroll.mjs +218 -14
- package/test/cases/components/form/login.mjs +168 -0
- package/test/cases/components/form/select.mjs +94 -32
- package/test/cases/components/form/tree-select.mjs +22 -1
- package/test/cases/dom/customcontrol.mjs +44 -10
- package/test/cases/dom/customelement-initfromscripthost.mjs +22 -1
- package/test/cases/dom/customelement.mjs +83 -0
- package/test/cases/dom/updater.mjs +98 -0
- package/test/cases/monster.mjs +1 -1
- package/test/cases/types/proxyobserver.mjs +31 -0
- package/test/web/import.js +4 -0
- package/test/web/puppeteer.mjs +94 -71
- package/test/web/test.html +29 -2
- package/test/web/tests.js +28297 -15864
|
@@ -117,6 +117,9 @@ const updateCloneDataSymbol = Symbol("@schukai/monster/dom/@@updateCloneData");
|
|
|
117
117
|
* @type {symbol}
|
|
118
118
|
*/
|
|
119
119
|
const scriptHostElementSymbol = Symbol("scriptHostElement");
|
|
120
|
+
const managedShadowRootSymbol = Symbol("managedShadowRoot");
|
|
121
|
+
const visibilityStateSymbol = Symbol("visibilityState");
|
|
122
|
+
let hostVisibilityStyleSheet = null;
|
|
120
123
|
|
|
121
124
|
/**
|
|
122
125
|
* The `CustomElement` class provides a way to define a new HTML element using the power of Custom Elements.
|
|
@@ -277,6 +280,24 @@ class CustomElement extends HTMLElement {
|
|
|
277
280
|
return this;
|
|
278
281
|
}
|
|
279
282
|
|
|
283
|
+
/**
|
|
284
|
+
* Returns whether the host element is currently visible.
|
|
285
|
+
*
|
|
286
|
+
* @returns {boolean}
|
|
287
|
+
*/
|
|
288
|
+
get visible() {
|
|
289
|
+
return !this.hidden;
|
|
290
|
+
}
|
|
291
|
+
|
|
292
|
+
/**
|
|
293
|
+
* Alias for the current host visibility state.
|
|
294
|
+
*
|
|
295
|
+
* @returns {boolean}
|
|
296
|
+
*/
|
|
297
|
+
get isVisible() {
|
|
298
|
+
return this.visible;
|
|
299
|
+
}
|
|
300
|
+
|
|
280
301
|
/**
|
|
281
302
|
* The `customization` property allows overwriting the defaults.
|
|
282
303
|
* Unlike the defaults that expect an object, the customization is a Map.
|
|
@@ -540,6 +561,54 @@ class CustomElement extends HTMLElement {
|
|
|
540
561
|
return this;
|
|
541
562
|
}
|
|
542
563
|
|
|
564
|
+
/**
|
|
565
|
+
* Shows the host element.
|
|
566
|
+
*
|
|
567
|
+
* @returns {CustomElement}
|
|
568
|
+
*/
|
|
569
|
+
show() {
|
|
570
|
+
return this.setVisible(true);
|
|
571
|
+
}
|
|
572
|
+
|
|
573
|
+
/**
|
|
574
|
+
* Hides the host element.
|
|
575
|
+
*
|
|
576
|
+
* @returns {CustomElement}
|
|
577
|
+
*/
|
|
578
|
+
hide() {
|
|
579
|
+
return this.setVisible(false);
|
|
580
|
+
}
|
|
581
|
+
|
|
582
|
+
/**
|
|
583
|
+
* Sets the host visibility.
|
|
584
|
+
*
|
|
585
|
+
* @param {boolean} visible
|
|
586
|
+
* @returns {CustomElement}
|
|
587
|
+
*/
|
|
588
|
+
setVisible(visible) {
|
|
589
|
+
if (visible) {
|
|
590
|
+
this.removeAttribute("hidden");
|
|
591
|
+
} else {
|
|
592
|
+
this.setAttribute("hidden", "");
|
|
593
|
+
}
|
|
594
|
+
|
|
595
|
+
return this;
|
|
596
|
+
}
|
|
597
|
+
|
|
598
|
+
/**
|
|
599
|
+
* Toggles the host visibility.
|
|
600
|
+
*
|
|
601
|
+
* @param {boolean} [force]
|
|
602
|
+
* @returns {CustomElement}
|
|
603
|
+
*/
|
|
604
|
+
toggleVisibility(force) {
|
|
605
|
+
if (typeof force === "boolean") {
|
|
606
|
+
return this.setVisible(force);
|
|
607
|
+
}
|
|
608
|
+
|
|
609
|
+
return this.setVisible(!this.visible);
|
|
610
|
+
}
|
|
611
|
+
|
|
543
612
|
/**
|
|
544
613
|
* Is called once via the constructor
|
|
545
614
|
*
|
|
@@ -623,7 +692,7 @@ class CustomElement extends HTMLElement {
|
|
|
623
692
|
if (this.getOption("shadowMode", false) !== false) {
|
|
624
693
|
try {
|
|
625
694
|
initShadowRoot.call(this);
|
|
626
|
-
elements = this
|
|
695
|
+
elements = getManagedShadowRoot.call(this)?.childNodes;
|
|
627
696
|
} catch (e) {
|
|
628
697
|
addErrorAttribute(this, e);
|
|
629
698
|
}
|
|
@@ -673,6 +742,8 @@ class CustomElement extends HTMLElement {
|
|
|
673
742
|
this[internalSymbol].syncDisabledState();
|
|
674
743
|
}
|
|
675
744
|
|
|
745
|
+
syncVisibilityState.call(this);
|
|
746
|
+
|
|
676
747
|
return this;
|
|
677
748
|
}
|
|
678
749
|
|
|
@@ -746,6 +817,10 @@ class CustomElement extends HTMLElement {
|
|
|
746
817
|
);
|
|
747
818
|
}
|
|
748
819
|
|
|
820
|
+
if (attrName === "hidden") {
|
|
821
|
+
syncVisibilityState.call(this);
|
|
822
|
+
}
|
|
823
|
+
|
|
749
824
|
const callback = this[attributeObserverSymbol]?.[attrName];
|
|
750
825
|
if (isFunction(callback)) {
|
|
751
826
|
try {
|
|
@@ -770,11 +845,12 @@ class CustomElement extends HTMLElement {
|
|
|
770
845
|
return true;
|
|
771
846
|
}
|
|
772
847
|
|
|
773
|
-
|
|
848
|
+
const shadowRoot = getManagedShadowRoot.call(this);
|
|
849
|
+
if (!(shadowRoot instanceof ShadowRoot)) {
|
|
774
850
|
return false;
|
|
775
851
|
}
|
|
776
852
|
|
|
777
|
-
return containChildNode.call(
|
|
853
|
+
return containChildNode.call(shadowRoot, node);
|
|
778
854
|
}
|
|
779
855
|
|
|
780
856
|
/**
|
|
@@ -815,7 +891,7 @@ function callControlCallback(callBackFunctionName, ...args) {
|
|
|
815
891
|
|
|
816
892
|
const list = targetId.split(",");
|
|
817
893
|
for (const id of list) {
|
|
818
|
-
const host = findElementWithIdUpwards(this,
|
|
894
|
+
const host = findElementWithIdUpwards(this, id.trim());
|
|
819
895
|
if (!(host instanceof HTMLElement)) {
|
|
820
896
|
continue;
|
|
821
897
|
}
|
|
@@ -878,8 +954,14 @@ function attachAttributeChangeMutationObserver() {
|
|
|
878
954
|
|
|
879
955
|
self[attributeMutationObserverSymbol] = new MutationObserver(
|
|
880
956
|
function (mutations, observer) {
|
|
957
|
+
const observedAttributes = new Set(
|
|
958
|
+
self.constructor.observedAttributes || [],
|
|
959
|
+
);
|
|
881
960
|
for (const mutation of mutations) {
|
|
882
961
|
if (mutation.type === "attributes") {
|
|
962
|
+
if (observedAttributes.has(mutation.attributeName)) {
|
|
963
|
+
continue;
|
|
964
|
+
}
|
|
883
965
|
self.attributeChangedCallback(
|
|
884
966
|
mutation.attributeName,
|
|
885
967
|
mutation.oldValue,
|
|
@@ -1014,7 +1096,8 @@ function initOptionObserver() {
|
|
|
1014
1096
|
return;
|
|
1015
1097
|
}
|
|
1016
1098
|
|
|
1017
|
-
|
|
1099
|
+
const shadowRoot = getManagedShadowRoot.call(self);
|
|
1100
|
+
if (!(shadowRoot instanceof ShadowRoot) && !self.childNodes.length) {
|
|
1018
1101
|
return;
|
|
1019
1102
|
}
|
|
1020
1103
|
|
|
@@ -1024,8 +1107,8 @@ function initOptionObserver() {
|
|
|
1024
1107
|
"button, command, fieldset, keygen, optgroup, option, select, textarea, input, [data-monster-objectlink]";
|
|
1025
1108
|
|
|
1026
1109
|
let elements = [];
|
|
1027
|
-
if (
|
|
1028
|
-
elements =
|
|
1110
|
+
if (shadowRoot instanceof ShadowRoot) {
|
|
1111
|
+
elements = shadowRoot.querySelectorAll(query);
|
|
1029
1112
|
}
|
|
1030
1113
|
|
|
1031
1114
|
let nodeList;
|
|
@@ -1235,6 +1318,16 @@ function parseOptionsJSON(data) {
|
|
|
1235
1318
|
return validateObject(obj);
|
|
1236
1319
|
}
|
|
1237
1320
|
|
|
1321
|
+
function getManagedShadowRoot() {
|
|
1322
|
+
if (this[managedShadowRootSymbol] instanceof ShadowRoot) {
|
|
1323
|
+
return this[managedShadowRootSymbol];
|
|
1324
|
+
}
|
|
1325
|
+
if (this.shadowRoot instanceof ShadowRoot) {
|
|
1326
|
+
return this.shadowRoot;
|
|
1327
|
+
}
|
|
1328
|
+
return null;
|
|
1329
|
+
}
|
|
1330
|
+
|
|
1238
1331
|
/**
|
|
1239
1332
|
* @private
|
|
1240
1333
|
* @param html
|
|
@@ -1277,6 +1370,73 @@ function initHtmlContent() {
|
|
|
1277
1370
|
return this;
|
|
1278
1371
|
}
|
|
1279
1372
|
|
|
1373
|
+
/**
|
|
1374
|
+
* @private
|
|
1375
|
+
* @returns {void}
|
|
1376
|
+
*/
|
|
1377
|
+
function syncVisibilityState() {
|
|
1378
|
+
const visible = !this.hidden;
|
|
1379
|
+
if (typeof this[visibilityStateSymbol] === "undefined") {
|
|
1380
|
+
this[visibilityStateSymbol] = visible;
|
|
1381
|
+
if (!visible) {
|
|
1382
|
+
blurFocusedElement.call(this);
|
|
1383
|
+
}
|
|
1384
|
+
return;
|
|
1385
|
+
}
|
|
1386
|
+
|
|
1387
|
+
if (this[visibilityStateSymbol] === visible) {
|
|
1388
|
+
return;
|
|
1389
|
+
}
|
|
1390
|
+
|
|
1391
|
+
if (!visible) {
|
|
1392
|
+
blurFocusedElement.call(this);
|
|
1393
|
+
}
|
|
1394
|
+
|
|
1395
|
+
this[visibilityStateSymbol] = visible;
|
|
1396
|
+
dispatchVisibilityChangedEvent.call(this, visible);
|
|
1397
|
+
}
|
|
1398
|
+
|
|
1399
|
+
/**
|
|
1400
|
+
* @private
|
|
1401
|
+
* @returns {void}
|
|
1402
|
+
*/
|
|
1403
|
+
function blurFocusedElement() {
|
|
1404
|
+
const shadowRoot = getManagedShadowRoot.call(this);
|
|
1405
|
+
const activeShadowElement = shadowRoot?.activeElement;
|
|
1406
|
+
|
|
1407
|
+
if (activeShadowElement instanceof HTMLElement) {
|
|
1408
|
+
activeShadowElement.blur();
|
|
1409
|
+
}
|
|
1410
|
+
|
|
1411
|
+
if (document.activeElement === this && typeof this.blur === "function") {
|
|
1412
|
+
this.blur();
|
|
1413
|
+
}
|
|
1414
|
+
|
|
1415
|
+
if (shadowRoot?.activeElement instanceof HTMLElement) {
|
|
1416
|
+
const body = getDocument()?.body;
|
|
1417
|
+
if (body instanceof HTMLElement) {
|
|
1418
|
+
body.setAttribute("tabindex", "-1");
|
|
1419
|
+
body.focus();
|
|
1420
|
+
body.removeAttribute("tabindex");
|
|
1421
|
+
}
|
|
1422
|
+
}
|
|
1423
|
+
}
|
|
1424
|
+
|
|
1425
|
+
/**
|
|
1426
|
+
* @private
|
|
1427
|
+
* @param {boolean} visible
|
|
1428
|
+
* @returns {void}
|
|
1429
|
+
*/
|
|
1430
|
+
function dispatchVisibilityChangedEvent(visible) {
|
|
1431
|
+
this.dispatchEvent(
|
|
1432
|
+
new CustomEvent("monster-visibility-changed", {
|
|
1433
|
+
bubbles: true,
|
|
1434
|
+
composed: true,
|
|
1435
|
+
detail: { visible },
|
|
1436
|
+
}),
|
|
1437
|
+
);
|
|
1438
|
+
}
|
|
1439
|
+
|
|
1280
1440
|
/**
|
|
1281
1441
|
* @private
|
|
1282
1442
|
* @return {CustomElement}
|
|
@@ -1286,25 +1446,29 @@ function initHtmlContent() {
|
|
|
1286
1446
|
* @throws {TypeError} value is not an instance of
|
|
1287
1447
|
*/
|
|
1288
1448
|
function initCSSStylesheet() {
|
|
1289
|
-
|
|
1449
|
+
const shadowRoot = getManagedShadowRoot.call(this);
|
|
1450
|
+
if (!(shadowRoot instanceof ShadowRoot)) {
|
|
1290
1451
|
return this;
|
|
1291
1452
|
}
|
|
1453
|
+
const visibilityStyleSheet = getHostVisibilityStyleSheet();
|
|
1292
1454
|
|
|
1293
1455
|
const styleSheet = this.constructor.getCSSStyleSheet();
|
|
1294
1456
|
|
|
1295
1457
|
if (styleSheet instanceof CSSStyleSheet) {
|
|
1296
1458
|
if (styleSheet.cssRules.length > 0) {
|
|
1297
|
-
|
|
1459
|
+
shadowRoot.adoptedStyleSheets = [visibilityStyleSheet, styleSheet];
|
|
1460
|
+
} else {
|
|
1461
|
+
shadowRoot.adoptedStyleSheets = [visibilityStyleSheet];
|
|
1298
1462
|
}
|
|
1299
1463
|
} else if (isArray(styleSheet)) {
|
|
1300
|
-
const assign = [];
|
|
1464
|
+
const assign = [visibilityStyleSheet];
|
|
1301
1465
|
for (const s of styleSheet) {
|
|
1302
1466
|
if (isString(s)) {
|
|
1303
1467
|
const trimedStyleSheet = s.trim();
|
|
1304
1468
|
if (trimedStyleSheet !== "") {
|
|
1305
1469
|
const style = document.createElement("style");
|
|
1306
1470
|
style.innerHTML = trimedStyleSheet;
|
|
1307
|
-
|
|
1471
|
+
shadowRoot.prepend(style);
|
|
1308
1472
|
}
|
|
1309
1473
|
continue;
|
|
1310
1474
|
}
|
|
@@ -1317,20 +1481,56 @@ function initCSSStylesheet() {
|
|
|
1317
1481
|
}
|
|
1318
1482
|
|
|
1319
1483
|
if (assign.length > 0) {
|
|
1320
|
-
|
|
1484
|
+
shadowRoot.adoptedStyleSheets = assign;
|
|
1321
1485
|
}
|
|
1322
1486
|
} else if (isString(styleSheet)) {
|
|
1487
|
+
shadowRoot.adoptedStyleSheets = [visibilityStyleSheet];
|
|
1323
1488
|
const trimedStyleSheet = styleSheet.trim();
|
|
1324
1489
|
if (trimedStyleSheet !== "") {
|
|
1325
1490
|
const style = document.createElement("style");
|
|
1326
1491
|
style.innerHTML = styleSheet;
|
|
1327
|
-
|
|
1492
|
+
shadowRoot.prepend(style);
|
|
1328
1493
|
}
|
|
1494
|
+
} else {
|
|
1495
|
+
shadowRoot.adoptedStyleSheets = [visibilityStyleSheet];
|
|
1329
1496
|
}
|
|
1330
1497
|
|
|
1331
1498
|
return this;
|
|
1332
1499
|
}
|
|
1333
1500
|
|
|
1501
|
+
/**
|
|
1502
|
+
* @private
|
|
1503
|
+
* @returns {CSSStyleSheet}
|
|
1504
|
+
*/
|
|
1505
|
+
function getHostVisibilityStyleSheet() {
|
|
1506
|
+
if (hostVisibilityStyleSheet instanceof CSSStyleSheet) {
|
|
1507
|
+
return hostVisibilityStyleSheet;
|
|
1508
|
+
}
|
|
1509
|
+
|
|
1510
|
+
hostVisibilityStyleSheet = new CSSStyleSheet();
|
|
1511
|
+
hostVisibilityStyleSheet.replaceSync(
|
|
1512
|
+
":host([hidden]){display:none !important}",
|
|
1513
|
+
);
|
|
1514
|
+
|
|
1515
|
+
return hostVisibilityStyleSheet;
|
|
1516
|
+
}
|
|
1517
|
+
|
|
1518
|
+
/**
|
|
1519
|
+
* @private
|
|
1520
|
+
* @param {ShadowRoot} shadowRoot
|
|
1521
|
+
* @returns {void}
|
|
1522
|
+
*/
|
|
1523
|
+
function appendVisibilityHostStyle(shadowRoot) {
|
|
1524
|
+
if (!(shadowRoot instanceof ShadowRoot)) {
|
|
1525
|
+
return;
|
|
1526
|
+
}
|
|
1527
|
+
|
|
1528
|
+
const style = document.createElement("style");
|
|
1529
|
+
style.setAttribute("data-monster-host-visibility", "true");
|
|
1530
|
+
style.textContent = ":host([hidden]){display:none !important}";
|
|
1531
|
+
shadowRoot.prepend(style);
|
|
1532
|
+
}
|
|
1533
|
+
|
|
1334
1534
|
/**
|
|
1335
1535
|
* @private
|
|
1336
1536
|
* @return {CustomElement}
|
|
@@ -1352,13 +1552,15 @@ function initShadowRoot() {
|
|
|
1352
1552
|
}
|
|
1353
1553
|
}
|
|
1354
1554
|
|
|
1355
|
-
this.attachShadow({
|
|
1555
|
+
this[managedShadowRootSymbol] = this.attachShadow({
|
|
1356
1556
|
mode: this.getOption("shadowMode", "open"),
|
|
1357
1557
|
delegatesFocus: this.getOption("delegatesFocus", true),
|
|
1358
1558
|
});
|
|
1359
1559
|
|
|
1360
1560
|
if (template instanceof Template) {
|
|
1361
|
-
this.
|
|
1561
|
+
this[managedShadowRootSymbol].appendChild(
|
|
1562
|
+
template.createDocumentFragment(),
|
|
1563
|
+
);
|
|
1362
1564
|
return this;
|
|
1363
1565
|
}
|
|
1364
1566
|
|
|
@@ -1374,7 +1576,7 @@ function initShadowRoot() {
|
|
|
1374
1576
|
html = formatter.format(html);
|
|
1375
1577
|
}
|
|
1376
1578
|
|
|
1377
|
-
this.
|
|
1579
|
+
this[managedShadowRootSymbol].innerHTML = substituteI18n.call(this, html);
|
|
1378
1580
|
return this;
|
|
1379
1581
|
}
|
|
1380
1582
|
|
package/source/dom/updater.mjs
CHANGED
|
@@ -88,6 +88,7 @@ const updaterRootSymbol = Symbol.for("@schukai/monster/dom/@@updater-root");
|
|
|
88
88
|
const disposedSymbol = Symbol("disposed");
|
|
89
89
|
const subjectObserverSymbol = Symbol("subjectObserver");
|
|
90
90
|
const patchNodeKeySymbol = Symbol("patchNodeKey");
|
|
91
|
+
const queuedSnapshotSymbol = Symbol("queuedSnapshot");
|
|
91
92
|
|
|
92
93
|
/**
|
|
93
94
|
* The updater class connects an object with the DOM. In this way, structures and contents in the DOM can be
|
|
@@ -155,6 +156,7 @@ class Updater extends Base {
|
|
|
155
156
|
this[pendingDiffsSymbol] = [];
|
|
156
157
|
this[processingSymbol] = false;
|
|
157
158
|
this[disposedSymbol] = false;
|
|
159
|
+
this[queuedSnapshotSymbol] = clone(this[internalSymbol].last);
|
|
158
160
|
|
|
159
161
|
this[subjectObserverSymbol] = new Observer(() => {
|
|
160
162
|
if (this[disposedSymbol] === true) {
|
|
@@ -162,12 +164,13 @@ class Updater extends Base {
|
|
|
162
164
|
}
|
|
163
165
|
|
|
164
166
|
const real = this[internalSymbol].subject.getRealSubject();
|
|
165
|
-
const diffResult = diff(this[
|
|
166
|
-
this[internalSymbol].last = clone(real);
|
|
167
|
+
const diffResult = diff(this[queuedSnapshotSymbol], real);
|
|
167
168
|
if (diffResult.length === 0) {
|
|
168
169
|
return Promise.resolve();
|
|
169
170
|
}
|
|
170
|
-
|
|
171
|
+
const snapshot = clone(real);
|
|
172
|
+
this[queuedSnapshotSymbol] = snapshot;
|
|
173
|
+
this[pendingDiffsSymbol].push({ diffResult, snapshot });
|
|
171
174
|
return this[processQueueSymbol]();
|
|
172
175
|
});
|
|
173
176
|
this[internalSymbol].subject.attachObserver(this[subjectObserverSymbol]);
|
|
@@ -194,7 +197,7 @@ class Updater extends Base {
|
|
|
194
197
|
return Promise.resolve();
|
|
195
198
|
}
|
|
196
199
|
|
|
197
|
-
const diffResult = this[pendingDiffsSymbol].shift();
|
|
200
|
+
const { diffResult, snapshot } = this[pendingDiffsSymbol].shift();
|
|
198
201
|
if (this[internalSymbol].features.batchUpdates === true) {
|
|
199
202
|
const updatePaths = new Map();
|
|
200
203
|
for (const change of Object.values(diffResult)) {
|
|
@@ -225,6 +228,7 @@ class Updater extends Base {
|
|
|
225
228
|
await this[applyChangeSymbol](change);
|
|
226
229
|
}
|
|
227
230
|
}
|
|
231
|
+
this[internalSymbol].last = clone(snapshot);
|
|
228
232
|
}
|
|
229
233
|
} catch (err) {
|
|
230
234
|
addErrorAttribute(this[internalSymbol]?.element, err);
|
|
@@ -371,6 +375,7 @@ class Updater extends Base {
|
|
|
371
375
|
// the key __init__has no further meaning and is only
|
|
372
376
|
// used to create the diff for empty objects.
|
|
373
377
|
this[internalSymbol].last = { __init__: true };
|
|
378
|
+
this[queuedSnapshotSymbol] = clone(this[internalSymbol].last);
|
|
374
379
|
return this[internalSymbol].subject.notifyObservers();
|
|
375
380
|
}
|
|
376
381
|
|
|
@@ -597,12 +602,17 @@ function retrieveAndSetValue(element) {
|
|
|
597
602
|
switch (type) {
|
|
598
603
|
case "integer?":
|
|
599
604
|
case "int?":
|
|
600
|
-
case "number?":
|
|
605
|
+
case "number?": {
|
|
606
|
+
const empty =
|
|
607
|
+
value === undefined ||
|
|
608
|
+
value === null ||
|
|
609
|
+
(isString(value) && value.trim() === "");
|
|
601
610
|
value = Number(value);
|
|
602
|
-
if (
|
|
611
|
+
if (empty || isNaN(value)) {
|
|
603
612
|
value = undefined;
|
|
604
613
|
}
|
|
605
614
|
break;
|
|
615
|
+
}
|
|
606
616
|
|
|
607
617
|
case "number":
|
|
608
618
|
case "int":
|
|
@@ -1055,7 +1065,7 @@ function runUpdateContent(container, parts, subject) {
|
|
|
1055
1065
|
* @type {HTMLElement}
|
|
1056
1066
|
*/
|
|
1057
1067
|
for (const [element] of iterator.entries()) {
|
|
1058
|
-
if (mem.has(element))
|
|
1068
|
+
if (mem.has(element)) continue;
|
|
1059
1069
|
mem.add(element);
|
|
1060
1070
|
|
|
1061
1071
|
const attributes = element.getAttribute(ATTRIBUTE_UPDATER_REPLACE);
|
|
@@ -1113,7 +1123,7 @@ function runUpdatePatch(container, parts, subject) {
|
|
|
1113
1123
|
}
|
|
1114
1124
|
|
|
1115
1125
|
for (const [element] of iterator.entries()) {
|
|
1116
|
-
if (mem.has(element))
|
|
1126
|
+
if (mem.has(element)) continue;
|
|
1117
1127
|
mem.add(element);
|
|
1118
1128
|
|
|
1119
1129
|
const attributes = element.getAttribute(ATTRIBUTE_UPDATER_PATCH);
|
|
@@ -1501,7 +1511,7 @@ function runUpdateAttributes(container, parts, subject) {
|
|
|
1501
1511
|
}
|
|
1502
1512
|
|
|
1503
1513
|
for (const [element] of iterator.entries()) {
|
|
1504
|
-
if (mem.has(element))
|
|
1514
|
+
if (mem.has(element)) continue;
|
|
1505
1515
|
mem.add(element);
|
|
1506
1516
|
|
|
1507
1517
|
// this case occurs when the ATTRIBUTE_UPDATER_SELECT_THIS attribute is set
|
|
@@ -1576,7 +1586,7 @@ function runUpdateProperties(container, parts, subject) {
|
|
|
1576
1586
|
}
|
|
1577
1587
|
|
|
1578
1588
|
for (const [element] of iterator.entries()) {
|
|
1579
|
-
if (mem.has(element))
|
|
1589
|
+
if (mem.has(element)) continue;
|
|
1580
1590
|
mem.add(element);
|
|
1581
1591
|
|
|
1582
1592
|
// this case occurs when the ATTRIBUTE_UPDATER_SELECT_THIS attribute is set
|
|
@@ -1625,14 +1635,24 @@ function handleInputControlAttributeUpdate(element, name, value) {
|
|
|
1625
1635
|
if (element instanceof HTMLSelectElement) {
|
|
1626
1636
|
switch (element.type) {
|
|
1627
1637
|
case "select-multiple":
|
|
1628
|
-
|
|
1629
|
-
|
|
1638
|
+
const selectedValues = isArray(value)
|
|
1639
|
+
? value
|
|
1640
|
+
: value === undefined || value === null
|
|
1641
|
+
? []
|
|
1642
|
+
: [`${value}`];
|
|
1643
|
+
for (const [, opt] of Object.entries(element.options)) {
|
|
1644
|
+
opt.selected = selectedValues.indexOf(opt.value) !== -1;
|
|
1630
1645
|
}
|
|
1631
1646
|
|
|
1632
1647
|
break;
|
|
1633
1648
|
case "select-one":
|
|
1634
1649
|
// Only one value may be selected
|
|
1650
|
+
if (value === undefined || value === null) {
|
|
1651
|
+
element.selectedIndex = -1;
|
|
1652
|
+
break;
|
|
1653
|
+
}
|
|
1635
1654
|
|
|
1655
|
+
element.selectedIndex = -1;
|
|
1636
1656
|
for (const [index, opt] of Object.entries(element.options)) {
|
|
1637
1657
|
if (opt.value === value) {
|
|
1638
1658
|
element.selectedIndex = index;
|
package/source/types/is.mjs
CHANGED
|
@@ -209,22 +209,19 @@ function getHandler() {
|
|
|
209
209
|
return true;
|
|
210
210
|
}
|
|
211
211
|
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
if (descriptor === undefined) {
|
|
216
|
-
descriptor = {
|
|
217
|
-
writable: true,
|
|
218
|
-
enumerable: true,
|
|
219
|
-
configurable: true,
|
|
220
|
-
};
|
|
212
|
+
const result = Reflect.set(target, key, value, receiver);
|
|
213
|
+
if (result !== true) {
|
|
214
|
+
return result;
|
|
221
215
|
}
|
|
222
216
|
|
|
223
|
-
descriptor["value"] = value;
|
|
224
|
-
result = Reflect.defineProperty(target, key, descriptor);
|
|
225
|
-
|
|
226
217
|
if (typeof key !== "symbol") {
|
|
227
|
-
|
|
218
|
+
let next = Reflect.get(target, key, receiver);
|
|
219
|
+
if (proxy.proxyMap.has(next)) {
|
|
220
|
+
next = proxy.proxyMap.get(next);
|
|
221
|
+
}
|
|
222
|
+
if (next !== current) {
|
|
223
|
+
proxy.observers.notify(proxy);
|
|
224
|
+
}
|
|
228
225
|
}
|
|
229
226
|
|
|
230
227
|
return result;
|
package/source/types/version.mjs
CHANGED
|
@@ -0,0 +1,98 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
import * as chai from 'chai';
|
|
4
|
+
import {getDocument} from "../../../../source/dom/util.mjs";
|
|
5
|
+
import {chaiDom} from "../../../util/chai-dom.mjs";
|
|
6
|
+
import {initJSDOM} from "../../../util/jsdom.mjs";
|
|
7
|
+
|
|
8
|
+
let expect = chai.expect;
|
|
9
|
+
chai.use(chaiDom);
|
|
10
|
+
|
|
11
|
+
describe('ImageEditor', function () {
|
|
12
|
+
|
|
13
|
+
let ImageEditor, document;
|
|
14
|
+
let registerCustomElement;
|
|
15
|
+
let CustomElement;
|
|
16
|
+
let assembleMethodSymbol;
|
|
17
|
+
|
|
18
|
+
before(function (done) {
|
|
19
|
+
initJSDOM({}).then(() => {
|
|
20
|
+
import("../../../../source/dom/customelement.mjs").then((domModule) => {
|
|
21
|
+
registerCustomElement = domModule['registerCustomElement'];
|
|
22
|
+
CustomElement = domModule['CustomElement'];
|
|
23
|
+
assembleMethodSymbol = domModule['assembleMethodSymbol'];
|
|
24
|
+
return import("../../../../source/components/content/image-editor.mjs");
|
|
25
|
+
}).then((m) => {
|
|
26
|
+
try {
|
|
27
|
+
ImageEditor = m['ImageEditor'];
|
|
28
|
+
document = getDocument();
|
|
29
|
+
done();
|
|
30
|
+
} catch (e) {
|
|
31
|
+
done(e);
|
|
32
|
+
}
|
|
33
|
+
}).catch((e) => done(e));
|
|
34
|
+
});
|
|
35
|
+
});
|
|
36
|
+
|
|
37
|
+
beforeEach(() => {
|
|
38
|
+
let mocks = document.getElementById('mocks');
|
|
39
|
+
mocks.innerHTML = '<div id="target"></div>';
|
|
40
|
+
});
|
|
41
|
+
|
|
42
|
+
afterEach(() => {
|
|
43
|
+
let mocks = document.getElementById('mocks');
|
|
44
|
+
mocks.innerHTML = '';
|
|
45
|
+
});
|
|
46
|
+
|
|
47
|
+
it('should not double-call attributeChangedCallback for readonly', function (done) {
|
|
48
|
+
const htmlTAG = 'monster-image-editor-observed-test';
|
|
49
|
+
|
|
50
|
+
class ObservedImageEditor extends ImageEditor {
|
|
51
|
+
static getTag() {
|
|
52
|
+
return htmlTAG;
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
get defaults() {
|
|
56
|
+
return Object.assign({}, super.defaults, {
|
|
57
|
+
shadowMode: false,
|
|
58
|
+
templates: {
|
|
59
|
+
main: '<div id="image-editor-test"></div>'
|
|
60
|
+
}
|
|
61
|
+
});
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
[assembleMethodSymbol]() {
|
|
65
|
+
return CustomElement.prototype[assembleMethodSymbol].call(this);
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
constructor() {
|
|
69
|
+
super();
|
|
70
|
+
this.attributeChangedCalls = [];
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
attributeChangedCallback(name, oldValue, newValue) {
|
|
74
|
+
this.attributeChangedCalls.push([name, oldValue, newValue]);
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
registerCustomElement(ObservedImageEditor);
|
|
79
|
+
|
|
80
|
+
let element = document.createElement(htmlTAG);
|
|
81
|
+
document.getElementById('target').appendChild(element);
|
|
82
|
+
|
|
83
|
+
element.attributeChangedCalls = [];
|
|
84
|
+
element.setAttribute('data-monster-readonly', '');
|
|
85
|
+
|
|
86
|
+
setTimeout(function () {
|
|
87
|
+
try {
|
|
88
|
+
const readonlyCalls = element.attributeChangedCalls.filter(
|
|
89
|
+
([name]) => name === 'data-monster-readonly',
|
|
90
|
+
);
|
|
91
|
+
expect(readonlyCalls).to.have.length(1);
|
|
92
|
+
done();
|
|
93
|
+
} catch (e) {
|
|
94
|
+
done(e);
|
|
95
|
+
}
|
|
96
|
+
}, 20);
|
|
97
|
+
});
|
|
98
|
+
});
|