@schukai/monster 4.139.1 → 4.140.1
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/form/control-bar-spacer.mjs +85 -0
- package/source/components/form/control-bar.mjs +77 -0
- package/source/components/form/style/control-bar-spacer.pcss +28 -0
- package/source/components/form/style/control-bar.pcss +14 -0
- package/source/components/form/stylesheet/control-bar-spacer.mjs +38 -0
- package/source/components/form/stylesheet/control-bar.mjs +1 -1
- package/source/components/layout/tabs.mjs +384 -68
- package/source/components/layout/utils/attach-tabs-hash-sync.mjs +10 -5
- package/source/components/tree-menu/style/tree-menu.pcss +23 -0
- package/source/components/tree-menu/stylesheet/tree-menu.mjs +1 -1
- package/source/monster.mjs +2 -1
- package/test/cases/components/form/control-bar-spacer.mjs +51 -0
- package/test/cases/components/form/control-bar.mjs +181 -2
- package/test/cases/components/layout/tabs.mjs +323 -0
|
@@ -122,6 +122,12 @@ const closeEventHandler = Symbol("closeEventHandler");
|
|
|
122
122
|
*/
|
|
123
123
|
const mutationObserverSymbol = Symbol("mutationObserver");
|
|
124
124
|
|
|
125
|
+
/**
|
|
126
|
+
* @private
|
|
127
|
+
* @type {symbol}
|
|
128
|
+
*/
|
|
129
|
+
const tabListMutationObserverSymbol = Symbol("tabListMutationObserver");
|
|
130
|
+
|
|
125
131
|
/**
|
|
126
132
|
* @private
|
|
127
133
|
* @type {symbol}
|
|
@@ -141,6 +147,13 @@ const timerCallbackSymbol = Symbol("timerCallback");
|
|
|
141
147
|
*/
|
|
142
148
|
const resizeObserverSymbol = Symbol("resizeObserver");
|
|
143
149
|
|
|
150
|
+
/**
|
|
151
|
+
* local symbol
|
|
152
|
+
* @private
|
|
153
|
+
* @type {symbol}
|
|
154
|
+
*/
|
|
155
|
+
const activeReferenceSymbol = Symbol("activeReference");
|
|
156
|
+
|
|
144
157
|
/**
|
|
145
158
|
* A Tabs Control
|
|
146
159
|
*
|
|
@@ -183,6 +196,22 @@ class Tabs extends CustomElement {
|
|
|
183
196
|
* @property {number} features.openDelay=500 Open delay in milliseconds
|
|
184
197
|
* @property {string} features.removeBehavior Remove behavior, auto, next, previous and none
|
|
185
198
|
* @property {boolean} features.openFirst Open the first tab when no active tab is set
|
|
199
|
+
* @property {boolean} features.deriveLabelFromContent=true Generate labels from panel text when no `data-monster-button-label` is set
|
|
200
|
+
*
|
|
201
|
+
* Tab panels can use `data-monster-name` as stable public identity, while
|
|
202
|
+
* DOM ids remain the internal button reference. `data-monster-tab-available`
|
|
203
|
+
* controls whether a panel participates in the tab control. Missing or
|
|
204
|
+
* `"true"` means available; `"false"` or an empty attribute means unavailable.
|
|
205
|
+
* `data-monster-tab-disabled="true"` keeps a button visible but prevents
|
|
206
|
+
* activation. `data-monster-tab-disabled-reason` is exposed on the disabled
|
|
207
|
+
* button as contextual help. `data-monster-tab-kind`,
|
|
208
|
+
* `data-monster-tab-priority`, and `data-monster-tab-group` are copied into
|
|
209
|
+
* button metadata and tab event details.
|
|
210
|
+
*
|
|
211
|
+
* @fires monster-tab-change
|
|
212
|
+
* @fires monster-tab-changed
|
|
213
|
+
* @fires monster-tab-remove
|
|
214
|
+
* @fires monster-tab-availability-changed
|
|
186
215
|
* @property {Object} fetch Fetch [see Using Fetch mozilla.org](https://developer.mozilla.org/en-US/docs/Web/API/Fetch_API/Using_Fetch)
|
|
187
216
|
* @property {String} fetch.redirect=error
|
|
188
217
|
* @property {String} fetch.method=GET
|
|
@@ -220,6 +249,7 @@ class Tabs extends CustomElement {
|
|
|
220
249
|
openDelay: null,
|
|
221
250
|
removeBehavior: "auto",
|
|
222
251
|
openFirst: true,
|
|
252
|
+
deriveLabelFromContent: true,
|
|
223
253
|
},
|
|
224
254
|
|
|
225
255
|
classes: {
|
|
@@ -272,13 +302,13 @@ class Tabs extends CustomElement {
|
|
|
272
302
|
this[dimensionsSymbol] = new Pathfinder({ data: {} });
|
|
273
303
|
|
|
274
304
|
initEventHandler.call(this);
|
|
305
|
+
attachTabChangeObserver.call(this);
|
|
275
306
|
|
|
276
307
|
// setup structure
|
|
277
308
|
initTabButtons.call(this).then(() => {
|
|
278
309
|
initPopperSwitch.call(this);
|
|
279
310
|
initPopper.call(this);
|
|
280
311
|
attachResizeObserver.call(this);
|
|
281
|
-
attachTabChangeObserver.call(this);
|
|
282
312
|
});
|
|
283
313
|
}
|
|
284
314
|
|
|
@@ -306,7 +336,7 @@ class Tabs extends CustomElement {
|
|
|
306
336
|
* @returns {Tabs}
|
|
307
337
|
*/
|
|
308
338
|
removeTab(tabId) {
|
|
309
|
-
const tabs =
|
|
339
|
+
const tabs = getAllTabPanels.call(this);
|
|
310
340
|
for (const tab of tabs) {
|
|
311
341
|
if (
|
|
312
342
|
(tab.getAttribute("id") === tabId ||
|
|
@@ -326,14 +356,7 @@ class Tabs extends CustomElement {
|
|
|
326
356
|
* @returns {[]}
|
|
327
357
|
*/
|
|
328
358
|
getTabs() {
|
|
329
|
-
|
|
330
|
-
const tabs = [];
|
|
331
|
-
for (const node of nodes) {
|
|
332
|
-
if (node instanceof HTMLElement) {
|
|
333
|
-
tabs.push(node);
|
|
334
|
-
}
|
|
335
|
-
}
|
|
336
|
-
return tabs;
|
|
359
|
+
return getAllTabPanels.call(this).filter((node) => isTabAvailable(node));
|
|
337
360
|
}
|
|
338
361
|
|
|
339
362
|
/**
|
|
@@ -365,7 +388,7 @@ class Tabs extends CustomElement {
|
|
|
365
388
|
}
|
|
366
389
|
|
|
367
390
|
// check if id is already used
|
|
368
|
-
const existingTabs =
|
|
391
|
+
const existingTabs = getAllTabPanels.call(this);
|
|
369
392
|
for (const existingTab of existingTabs) {
|
|
370
393
|
if (
|
|
371
394
|
existingTab.getAttribute("id") === tabId ||
|
|
@@ -398,43 +421,80 @@ class Tabs extends CustomElement {
|
|
|
398
421
|
}
|
|
399
422
|
|
|
400
423
|
/**
|
|
401
|
-
*
|
|
424
|
+
* Rebuild tab buttons and synchronize the active tab.
|
|
402
425
|
*
|
|
403
|
-
*
|
|
426
|
+
* @return {Promise<Tabs>}
|
|
427
|
+
*/
|
|
428
|
+
refreshTabs() {
|
|
429
|
+
this[dimensionsSymbol].setVia("data.calculated", false);
|
|
430
|
+
return initTabButtons.call(this).then(() => this);
|
|
431
|
+
}
|
|
432
|
+
|
|
433
|
+
/**
|
|
434
|
+
* Alias for refreshTabs().
|
|
404
435
|
*
|
|
405
|
-
* @
|
|
406
|
-
* @return {Tabs} - The current instance
|
|
436
|
+
* @return {Promise<Tabs>}
|
|
407
437
|
*/
|
|
408
|
-
|
|
409
|
-
|
|
438
|
+
syncTabs() {
|
|
439
|
+
return this.refreshTabs();
|
|
440
|
+
}
|
|
410
441
|
|
|
411
|
-
|
|
412
|
-
|
|
413
|
-
|
|
442
|
+
/**
|
|
443
|
+
* Hide a tab from the control without removing its panel.
|
|
444
|
+
*
|
|
445
|
+
* @param {string} idOrName
|
|
446
|
+
* @return {Tabs}
|
|
447
|
+
*/
|
|
448
|
+
hideTab(idOrName) {
|
|
449
|
+
const tab = findTabPanel.call(this, idOrName, { availableOnly: false });
|
|
450
|
+
if (tab instanceof HTMLElement) {
|
|
451
|
+
const previousAvailable = isTabAvailable(tab);
|
|
452
|
+
tab.setAttribute("data-monster-tab-available", "false");
|
|
453
|
+
if (!hasObjectLink(tab, mutationObserverSymbol)) {
|
|
454
|
+
emitAvailabilityChanged.call(this, tab, previousAvailable, false);
|
|
414
455
|
}
|
|
456
|
+
}
|
|
457
|
+
return this;
|
|
458
|
+
}
|
|
415
459
|
|
|
416
|
-
|
|
417
|
-
|
|
418
|
-
|
|
419
|
-
|
|
420
|
-
|
|
421
|
-
|
|
422
|
-
|
|
423
|
-
|
|
424
|
-
|
|
460
|
+
/**
|
|
461
|
+
* Show a tab in the control.
|
|
462
|
+
*
|
|
463
|
+
* @param {string} idOrName
|
|
464
|
+
* @return {Tabs}
|
|
465
|
+
*/
|
|
466
|
+
showTab(idOrName) {
|
|
467
|
+
const tab = findTabPanel.call(this, idOrName, { availableOnly: false });
|
|
468
|
+
if (tab instanceof HTMLElement) {
|
|
469
|
+
const previousAvailable = isTabAvailable(tab);
|
|
470
|
+
tab.setAttribute("data-monster-tab-available", "true");
|
|
471
|
+
if (!hasObjectLink(tab, mutationObserverSymbol)) {
|
|
472
|
+
emitAvailabilityChanged.call(this, tab, previousAvailable, true);
|
|
425
473
|
}
|
|
474
|
+
}
|
|
475
|
+
return this;
|
|
476
|
+
}
|
|
426
477
|
|
|
427
|
-
|
|
428
|
-
|
|
429
|
-
|
|
430
|
-
|
|
478
|
+
/**
|
|
479
|
+
* A function that activates a tab based on the provided name.
|
|
480
|
+
*
|
|
481
|
+
* The tabs have to be named with the `data-monster-name` attribute.
|
|
482
|
+
*
|
|
483
|
+
* @param {type} idOrName - the name or id of the tab to activate
|
|
484
|
+
* @return {Tabs} - The current instance
|
|
485
|
+
*/
|
|
486
|
+
activeTab(idOrName) {
|
|
487
|
+
const node = findTabPanel.call(this, idOrName, {
|
|
488
|
+
availableOnly: true,
|
|
489
|
+
enabledOnly: true,
|
|
490
|
+
});
|
|
431
491
|
|
|
432
|
-
|
|
433
|
-
|
|
434
|
-
|
|
435
|
-
|
|
492
|
+
if (node instanceof HTMLElement) {
|
|
493
|
+
const tabControl = findButtonElement.call(this, node.getAttribute("id"));
|
|
494
|
+
if (tabControl instanceof HTMLButtonElement) {
|
|
495
|
+
tabControl.click();
|
|
436
496
|
}
|
|
437
|
-
}
|
|
497
|
+
}
|
|
438
498
|
|
|
439
499
|
return this;
|
|
440
500
|
}
|
|
@@ -492,6 +552,7 @@ class Tabs extends CustomElement {
|
|
|
492
552
|
}
|
|
493
553
|
|
|
494
554
|
this[popperInstanceSymbol]?.destroy();
|
|
555
|
+
this[tabListMutationObserverSymbol]?.disconnect();
|
|
495
556
|
}
|
|
496
557
|
}
|
|
497
558
|
|
|
@@ -542,6 +603,173 @@ function getTranslations() {
|
|
|
542
603
|
}
|
|
543
604
|
}
|
|
544
605
|
|
|
606
|
+
/**
|
|
607
|
+
* @private
|
|
608
|
+
* @return {HTMLElement[]}
|
|
609
|
+
*/
|
|
610
|
+
function getAllTabPanels() {
|
|
611
|
+
const nodes = getSlottedElements.call(this);
|
|
612
|
+
const tabs = [];
|
|
613
|
+
for (const node of nodes) {
|
|
614
|
+
if (node instanceof HTMLElement) {
|
|
615
|
+
tabs.push(node);
|
|
616
|
+
}
|
|
617
|
+
}
|
|
618
|
+
return tabs;
|
|
619
|
+
}
|
|
620
|
+
|
|
621
|
+
/**
|
|
622
|
+
* @private
|
|
623
|
+
* @param {HTMLElement} node
|
|
624
|
+
* @return {boolean}
|
|
625
|
+
*/
|
|
626
|
+
function isTabAvailable(node) {
|
|
627
|
+
if (!node.hasAttribute("data-monster-tab-available")) {
|
|
628
|
+
return true;
|
|
629
|
+
}
|
|
630
|
+
return node.getAttribute("data-monster-tab-available") === "true";
|
|
631
|
+
}
|
|
632
|
+
|
|
633
|
+
/**
|
|
634
|
+
* @private
|
|
635
|
+
* @param {string|null} value
|
|
636
|
+
* @return {boolean}
|
|
637
|
+
*/
|
|
638
|
+
function parseTabAvailableValue(value) {
|
|
639
|
+
if (value === null) {
|
|
640
|
+
return true;
|
|
641
|
+
}
|
|
642
|
+
return value === "true";
|
|
643
|
+
}
|
|
644
|
+
|
|
645
|
+
/**
|
|
646
|
+
* @private
|
|
647
|
+
* @param {HTMLElement} node
|
|
648
|
+
* @return {boolean}
|
|
649
|
+
*/
|
|
650
|
+
function isTabDisabled(node) {
|
|
651
|
+
return (
|
|
652
|
+
node.hasAttribute("disabled") ||
|
|
653
|
+
node.disabled === true ||
|
|
654
|
+
node.getAttribute("data-monster-tab-disabled") === "true"
|
|
655
|
+
);
|
|
656
|
+
}
|
|
657
|
+
|
|
658
|
+
/**
|
|
659
|
+
* @private
|
|
660
|
+
* @param {HTMLElement} node
|
|
661
|
+
* @return {string|null}
|
|
662
|
+
*/
|
|
663
|
+
function getTabName(node) {
|
|
664
|
+
if (node.hasAttribute("data-monster-name")) {
|
|
665
|
+
return node.getAttribute("data-monster-name");
|
|
666
|
+
}
|
|
667
|
+
return null;
|
|
668
|
+
}
|
|
669
|
+
|
|
670
|
+
/**
|
|
671
|
+
* @private
|
|
672
|
+
* @param {HTMLElement} node
|
|
673
|
+
* @return {string|null}
|
|
674
|
+
*/
|
|
675
|
+
function getTabReference(node) {
|
|
676
|
+
return node.getAttribute("id");
|
|
677
|
+
}
|
|
678
|
+
|
|
679
|
+
/**
|
|
680
|
+
* @private
|
|
681
|
+
* @param {HTMLElement} node
|
|
682
|
+
* @return {string|null}
|
|
683
|
+
*/
|
|
684
|
+
function getTabPublicReference(node) {
|
|
685
|
+
return getTabName(node) || getTabReference(node);
|
|
686
|
+
}
|
|
687
|
+
|
|
688
|
+
/**
|
|
689
|
+
* @private
|
|
690
|
+
* @param {HTMLElement} node
|
|
691
|
+
* @return {Object}
|
|
692
|
+
*/
|
|
693
|
+
function getTabMetadata(node) {
|
|
694
|
+
const metadata = {};
|
|
695
|
+
for (const key of ["kind", "priority", "group"]) {
|
|
696
|
+
const attr = `data-monster-tab-${key}`;
|
|
697
|
+
if (node.hasAttribute(attr)) {
|
|
698
|
+
metadata[key] = node.getAttribute(attr);
|
|
699
|
+
}
|
|
700
|
+
}
|
|
701
|
+
return metadata;
|
|
702
|
+
}
|
|
703
|
+
|
|
704
|
+
/**
|
|
705
|
+
* @private
|
|
706
|
+
* @param {HTMLElement} node
|
|
707
|
+
* @return {Object}
|
|
708
|
+
*/
|
|
709
|
+
function getTabEventDetail(node) {
|
|
710
|
+
return {
|
|
711
|
+
reference: getTabReference(node),
|
|
712
|
+
name: getTabName(node),
|
|
713
|
+
tab: getTabPublicReference(node),
|
|
714
|
+
metadata: getTabMetadata(node),
|
|
715
|
+
};
|
|
716
|
+
}
|
|
717
|
+
|
|
718
|
+
/**
|
|
719
|
+
* @private
|
|
720
|
+
* @param {string} idOrName
|
|
721
|
+
* @param {Object} options
|
|
722
|
+
* @return {HTMLElement|null}
|
|
723
|
+
*/
|
|
724
|
+
function findTabPanel(
|
|
725
|
+
idOrName,
|
|
726
|
+
{ availableOnly = false, enabledOnly = false } = {},
|
|
727
|
+
) {
|
|
728
|
+
const tabs = getAllTabPanels.call(this);
|
|
729
|
+
for (const node of tabs) {
|
|
730
|
+
if (availableOnly === true && isTabAvailable(node) !== true) {
|
|
731
|
+
continue;
|
|
732
|
+
}
|
|
733
|
+
if (enabledOnly === true && isTabDisabled(node) === true) {
|
|
734
|
+
continue;
|
|
735
|
+
}
|
|
736
|
+
if (getTabName(node) === idOrName) {
|
|
737
|
+
return node;
|
|
738
|
+
}
|
|
739
|
+
}
|
|
740
|
+
|
|
741
|
+
for (const node of tabs) {
|
|
742
|
+
if (availableOnly === true && isTabAvailable(node) !== true) {
|
|
743
|
+
continue;
|
|
744
|
+
}
|
|
745
|
+
if (enabledOnly === true && isTabDisabled(node) === true) {
|
|
746
|
+
continue;
|
|
747
|
+
}
|
|
748
|
+
if (getTabReference(node) === idOrName) {
|
|
749
|
+
return node;
|
|
750
|
+
}
|
|
751
|
+
}
|
|
752
|
+
|
|
753
|
+
return null;
|
|
754
|
+
}
|
|
755
|
+
|
|
756
|
+
/**
|
|
757
|
+
* @private
|
|
758
|
+
* @param {HTMLElement} tab
|
|
759
|
+
* @param {boolean} previousAvailable
|
|
760
|
+
* @param {boolean} available
|
|
761
|
+
*/
|
|
762
|
+
function emitAvailabilityChanged(tab, previousAvailable, available) {
|
|
763
|
+
if (previousAvailable === available) {
|
|
764
|
+
return;
|
|
765
|
+
}
|
|
766
|
+
|
|
767
|
+
fireCustomEvent(this, "monster-tab-availability-changed", {
|
|
768
|
+
...getTabEventDetail(tab),
|
|
769
|
+
available,
|
|
770
|
+
});
|
|
771
|
+
}
|
|
772
|
+
|
|
545
773
|
/**
|
|
546
774
|
* @private
|
|
547
775
|
*/
|
|
@@ -661,7 +889,7 @@ function attachResizeObserver() {
|
|
|
661
889
|
*/
|
|
662
890
|
function attachTabChangeObserver() {
|
|
663
891
|
// against flickering
|
|
664
|
-
new MutationObserver((mutations) => {
|
|
892
|
+
this[tabListMutationObserverSymbol] = new MutationObserver((mutations) => {
|
|
665
893
|
let runUpdate = false;
|
|
666
894
|
|
|
667
895
|
for (const mutation of mutations) {
|
|
@@ -680,7 +908,9 @@ function attachTabChangeObserver() {
|
|
|
680
908
|
this[dimensionsSymbol].setVia("data.calculated", false);
|
|
681
909
|
initTabButtons.call(this);
|
|
682
910
|
}
|
|
683
|
-
})
|
|
911
|
+
});
|
|
912
|
+
|
|
913
|
+
this[tabListMutationObserverSymbol].observe(this, {
|
|
684
914
|
childList: true,
|
|
685
915
|
});
|
|
686
916
|
}
|
|
@@ -744,11 +974,16 @@ function show(element, options = {}) {
|
|
|
744
974
|
const id = node.getAttribute("id");
|
|
745
975
|
|
|
746
976
|
if (id === reference) {
|
|
977
|
+
if (isTabAvailable(node) !== true || isTabDisabled(node) === true) {
|
|
978
|
+
continue;
|
|
979
|
+
}
|
|
980
|
+
|
|
747
981
|
node.classList.add("active");
|
|
982
|
+
this[activeReferenceSymbol] = reference;
|
|
748
983
|
|
|
749
984
|
if (emitEvents) {
|
|
750
985
|
fireCustomEvent(this, "monster-tab-change", {
|
|
751
|
-
|
|
986
|
+
...getTabEventDetail(node),
|
|
752
987
|
});
|
|
753
988
|
}
|
|
754
989
|
|
|
@@ -774,6 +1009,9 @@ function show(element, options = {}) {
|
|
|
774
1009
|
"data-monster-button-label",
|
|
775
1010
|
"data-monster-objectlink",
|
|
776
1011
|
"data-monster-role",
|
|
1012
|
+
"data-monster-tab-available",
|
|
1013
|
+
"data-monster-tab-disabled",
|
|
1014
|
+
"data-monster-tab-disabled-reason",
|
|
777
1015
|
];
|
|
778
1016
|
|
|
779
1017
|
for (const [, attr] of Object.entries(node.attributes)) {
|
|
@@ -798,7 +1036,7 @@ function show(element, options = {}) {
|
|
|
798
1036
|
.then(() => {
|
|
799
1037
|
if (emitEvents) {
|
|
800
1038
|
fireCustomEvent(this, "monster-tab-changed", {
|
|
801
|
-
|
|
1039
|
+
...getTabEventDetail(node),
|
|
802
1040
|
});
|
|
803
1041
|
}
|
|
804
1042
|
})
|
|
@@ -808,7 +1046,7 @@ function show(element, options = {}) {
|
|
|
808
1046
|
} else {
|
|
809
1047
|
if (emitEvents) {
|
|
810
1048
|
fireCustomEvent(this, "monster-tab-changed", {
|
|
811
|
-
|
|
1049
|
+
...getTabEventDetail(node),
|
|
812
1050
|
data,
|
|
813
1051
|
});
|
|
814
1052
|
}
|
|
@@ -883,10 +1121,13 @@ function initEventHandler() {
|
|
|
883
1121
|
activeReference = activeButton?.reference || null;
|
|
884
1122
|
}
|
|
885
1123
|
|
|
886
|
-
const nodes = getSlottedElements.call(this);
|
|
887
1124
|
const orderedTabs = [];
|
|
888
|
-
for (const node of
|
|
889
|
-
if (
|
|
1125
|
+
for (const node of getAllTabPanels.call(this)) {
|
|
1126
|
+
if (
|
|
1127
|
+
node instanceof HTMLElement &&
|
|
1128
|
+
isTabAvailable(node) === true &&
|
|
1129
|
+
isTabDisabled(node) !== true
|
|
1130
|
+
) {
|
|
890
1131
|
orderedTabs.push(node);
|
|
891
1132
|
}
|
|
892
1133
|
}
|
|
@@ -951,7 +1192,7 @@ function initEventHandler() {
|
|
|
951
1192
|
self.activeTab(targetReference);
|
|
952
1193
|
}
|
|
953
1194
|
fireCustomEvent(this, "monster-tab-remove", {
|
|
954
|
-
|
|
1195
|
+
...getTabEventDetail(container),
|
|
955
1196
|
});
|
|
956
1197
|
}
|
|
957
1198
|
}
|
|
@@ -1013,7 +1254,15 @@ function attachTabMutationObserver(observedNode) {
|
|
|
1013
1254
|
const observer = new MutationObserver(function (mutations) {
|
|
1014
1255
|
if (isArray(mutations)) {
|
|
1015
1256
|
const mutation = mutations.pop();
|
|
1016
|
-
if (mutation
|
|
1257
|
+
if (mutation?.type === "attributes") {
|
|
1258
|
+
if (mutation.attributeName === "data-monster-tab-available") {
|
|
1259
|
+
emitAvailabilityChanged.call(
|
|
1260
|
+
self,
|
|
1261
|
+
observedNode,
|
|
1262
|
+
parseTabAvailableValue(mutation.oldValue),
|
|
1263
|
+
isTabAvailable(observedNode),
|
|
1264
|
+
);
|
|
1265
|
+
}
|
|
1017
1266
|
initTabButtons.call(self);
|
|
1018
1267
|
}
|
|
1019
1268
|
}
|
|
@@ -1022,6 +1271,7 @@ function attachTabMutationObserver(observedNode) {
|
|
|
1022
1271
|
observer.observe(observedNode, {
|
|
1023
1272
|
childList: false,
|
|
1024
1273
|
attributes: true,
|
|
1274
|
+
attributeOldValue: true,
|
|
1025
1275
|
subtree: false,
|
|
1026
1276
|
attributeFilter: [
|
|
1027
1277
|
"disabled",
|
|
@@ -1029,6 +1279,12 @@ function attachTabMutationObserver(observedNode) {
|
|
|
1029
1279
|
`${ATTRIBUTE_PREFIX}button-icon`,
|
|
1030
1280
|
"data-monster-tab-error",
|
|
1031
1281
|
"data-monster-tab-error-message",
|
|
1282
|
+
"data-monster-tab-available",
|
|
1283
|
+
"data-monster-tab-disabled",
|
|
1284
|
+
"data-monster-tab-disabled-reason",
|
|
1285
|
+
"data-monster-tab-kind",
|
|
1286
|
+
"data-monster-tab-priority",
|
|
1287
|
+
"data-monster-tab-group",
|
|
1032
1288
|
],
|
|
1033
1289
|
});
|
|
1034
1290
|
|
|
@@ -1071,6 +1327,8 @@ function initTabButtons() {
|
|
|
1071
1327
|
}
|
|
1072
1328
|
|
|
1073
1329
|
let activeReference;
|
|
1330
|
+
let invalidActive = false;
|
|
1331
|
+
const previousActiveReference = this[activeReferenceSymbol] || null;
|
|
1074
1332
|
|
|
1075
1333
|
const dimensionsCalculated = this[dimensionsSymbol].getVia(
|
|
1076
1334
|
"data.calculated",
|
|
@@ -1078,25 +1336,34 @@ function initTabButtons() {
|
|
|
1078
1336
|
);
|
|
1079
1337
|
|
|
1080
1338
|
const buttons = [];
|
|
1081
|
-
const nodes =
|
|
1339
|
+
const nodes = getAllTabPanels.call(this);
|
|
1082
1340
|
|
|
1083
1341
|
for (const node of nodes) {
|
|
1084
1342
|
if (!(node instanceof HTMLElement)) continue;
|
|
1085
|
-
|
|
1343
|
+
const wasActive = node.matches(".active") === true;
|
|
1086
1344
|
|
|
1087
|
-
|
|
1088
|
-
|
|
1089
|
-
reference = node.getAttribute("id");
|
|
1345
|
+
if (!node.hasAttribute("id")) {
|
|
1346
|
+
node.setAttribute("id", new ID("tab").toString());
|
|
1090
1347
|
}
|
|
1091
1348
|
|
|
1092
|
-
|
|
1093
|
-
|
|
1094
|
-
|
|
1349
|
+
attachTabMutationObserver.call(this, node);
|
|
1350
|
+
|
|
1351
|
+
if (isTabAvailable(node) !== true) {
|
|
1352
|
+
if (wasActive === true) {
|
|
1353
|
+
invalidActive = true;
|
|
1354
|
+
node.classList.remove("active");
|
|
1355
|
+
}
|
|
1356
|
+
continue;
|
|
1095
1357
|
}
|
|
1096
1358
|
|
|
1097
|
-
|
|
1098
|
-
|
|
1099
|
-
|
|
1359
|
+
let label = getButtonLabel.call(this, node);
|
|
1360
|
+
|
|
1361
|
+
let reference = node.getAttribute("id");
|
|
1362
|
+
|
|
1363
|
+
let disabled = isTabDisabled(node);
|
|
1364
|
+
if (wasActive === true && disabled === true) {
|
|
1365
|
+
invalidActive = true;
|
|
1366
|
+
node.classList.remove("active");
|
|
1100
1367
|
}
|
|
1101
1368
|
|
|
1102
1369
|
if (node.hasAttribute(`${ATTRIBUTE_PREFIX}button-icon`)) {
|
|
@@ -1114,32 +1381,47 @@ function initTabButtons() {
|
|
|
1114
1381
|
|
|
1115
1382
|
if (node.matches(".active") === true && disabled !== true) {
|
|
1116
1383
|
activeReference = reference;
|
|
1384
|
+
this[activeReferenceSymbol] = reference;
|
|
1117
1385
|
}
|
|
1118
1386
|
|
|
1119
1387
|
const state = "";
|
|
1120
1388
|
const classes = dimensionsCalculated ? "" : "invisible";
|
|
1389
|
+
const disabledReason = node.getAttribute(
|
|
1390
|
+
"data-monster-tab-disabled-reason",
|
|
1391
|
+
);
|
|
1392
|
+
const metadata = getTabMetadata(node);
|
|
1121
1393
|
|
|
1122
1394
|
buttons.push({
|
|
1123
1395
|
reference,
|
|
1396
|
+
name: getTabName(node),
|
|
1397
|
+
tab: getTabPublicReference(node),
|
|
1124
1398
|
label,
|
|
1125
1399
|
error: errorMarkup,
|
|
1126
1400
|
state,
|
|
1127
1401
|
class: classes,
|
|
1128
1402
|
disabled,
|
|
1403
|
+
title: disabled === true ? disabledReason : null,
|
|
1404
|
+
"aria-label": disabled === true ? disabledReason : null,
|
|
1129
1405
|
remove,
|
|
1406
|
+
kind: metadata.kind,
|
|
1407
|
+
priority: metadata.priority,
|
|
1408
|
+
group: metadata.group,
|
|
1130
1409
|
});
|
|
1131
|
-
|
|
1132
|
-
attachTabMutationObserver.call(this, node);
|
|
1133
1410
|
}
|
|
1134
1411
|
|
|
1135
1412
|
setButtonCollections.call(this, buttons, []);
|
|
1136
1413
|
this.setOption("marker", random());
|
|
1137
1414
|
|
|
1138
1415
|
return adjustButtonVisibility.call(this).then(() => {
|
|
1139
|
-
if (
|
|
1140
|
-
|
|
1141
|
-
|
|
1142
|
-
|
|
1416
|
+
if (
|
|
1417
|
+
!activeReference &&
|
|
1418
|
+
(invalidActive === true ||
|
|
1419
|
+
previousActiveReference !== null ||
|
|
1420
|
+
this.getOption("features.openFirst") === true)
|
|
1421
|
+
) {
|
|
1422
|
+
const firstButton = this.getOption("buttons.standard")
|
|
1423
|
+
.concat(this.getOption("buttons.popper"))
|
|
1424
|
+
.find((button) => button.disabled !== true);
|
|
1143
1425
|
if (firstButton) {
|
|
1144
1426
|
activeReference = firstButton.reference;
|
|
1145
1427
|
}
|
|
@@ -1152,6 +1434,8 @@ function initTabButtons() {
|
|
|
1152
1434
|
);
|
|
1153
1435
|
if (button instanceof HTMLButtonElement && button.disabled !== true) {
|
|
1154
1436
|
show.call(this, button, { emitEvents: false });
|
|
1437
|
+
} else {
|
|
1438
|
+
this[activeReferenceSymbol] = null;
|
|
1155
1439
|
}
|
|
1156
1440
|
})
|
|
1157
1441
|
.run(undefined)
|
|
@@ -1161,10 +1445,32 @@ function initTabButtons() {
|
|
|
1161
1445
|
});
|
|
1162
1446
|
}
|
|
1163
1447
|
|
|
1448
|
+
clearActiveTabs.call(this);
|
|
1164
1449
|
return Promise.resolve();
|
|
1165
1450
|
});
|
|
1166
1451
|
}
|
|
1167
1452
|
|
|
1453
|
+
/**
|
|
1454
|
+
* @private
|
|
1455
|
+
*/
|
|
1456
|
+
function clearActiveTabs() {
|
|
1457
|
+
this[activeReferenceSymbol] = null;
|
|
1458
|
+
|
|
1459
|
+
for (const node of getAllTabPanels.call(this)) {
|
|
1460
|
+
node.classList.remove("active");
|
|
1461
|
+
}
|
|
1462
|
+
|
|
1463
|
+
const standardButtons = this.getOption("buttons.standard");
|
|
1464
|
+
for (const index in standardButtons) {
|
|
1465
|
+
this.setOption(`buttons.standard.${index}.state`, "inactive");
|
|
1466
|
+
}
|
|
1467
|
+
|
|
1468
|
+
const popperButtons = this.getOption("buttons.popper");
|
|
1469
|
+
for (const index in popperButtons) {
|
|
1470
|
+
this.setOption(`buttons.popper.${index}.state`, "inactive");
|
|
1471
|
+
}
|
|
1472
|
+
}
|
|
1473
|
+
|
|
1168
1474
|
function checkAndRearrangeButtons() {
|
|
1169
1475
|
if (this[dimensionsSymbol].getVia("data.calculated", false) !== true) {
|
|
1170
1476
|
calculateNavigationButtonsDimensions.call(this);
|
|
@@ -1416,8 +1722,12 @@ function getButtonLabel(node) {
|
|
|
1416
1722
|
if (node.hasAttribute(ATTRIBUTE_BUTTON_LABEL)) {
|
|
1417
1723
|
label = node.getAttribute(ATTRIBUTE_BUTTON_LABEL);
|
|
1418
1724
|
} else {
|
|
1419
|
-
|
|
1420
|
-
|
|
1725
|
+
if (this.getOption("features.deriveLabelFromContent") === false) {
|
|
1726
|
+
label = this.getOption("labels.new-tab-label", "New Tab");
|
|
1727
|
+
} else {
|
|
1728
|
+
label = node.innerText;
|
|
1729
|
+
setLabel = true;
|
|
1730
|
+
}
|
|
1421
1731
|
}
|
|
1422
1732
|
|
|
1423
1733
|
if (!isString(label)) {
|
|
@@ -1514,7 +1824,13 @@ function getTemplate() {
|
|
|
1514
1824
|
data-monster-attributes="
|
|
1515
1825
|
class path:classes.button,
|
|
1516
1826
|
data-monster-state path:buttons.state,
|
|
1517
|
-
disabled path:buttons.disabled | if:true,
|
|
1827
|
+
disabled path:buttons.disabled | if:true,
|
|
1828
|
+
title path:buttons.title,
|
|
1829
|
+
aria-label path:buttons.aria-label,
|
|
1830
|
+
data-monster-tab-name path:buttons.name,
|
|
1831
|
+
data-monster-tab-kind path:buttons.kind,
|
|
1832
|
+
data-monster-tab-priority path:buttons.priority,
|
|
1833
|
+
data-monster-tab-group path:buttons.group,
|
|
1518
1834
|
data-monster-tab-reference path:buttons.reference"><span part="label"
|
|
1519
1835
|
data-monster-replace="path:buttons.label"></span><div part="error"
|
|
1520
1836
|
data-monster-replace="path:buttons.error"></div><span part="remove-tab"
|