Skip to content

Commit

Permalink
Add stepped class in wizard/tabs
Browse files Browse the repository at this point in the history
  • Loading branch information
Pavitra Khatri authored and ci-build committed Dec 9, 2024
1 parent 07639b3 commit 628c889
Show file tree
Hide file tree
Showing 17 changed files with 279 additions and 21 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -42,11 +42,13 @@
static cssClasses = {
button: {
disabled: "cmp-accordion__button--disabled",
expanded: "cmp-accordion__button--expanded"
expanded: "cmp-accordion__button--expanded",
stepped: "cmp-accordion__button--stepped"
},
panel: {
hidden: "cmp-accordion__panel--hidden",
expanded: "cmp-accordion__panel--expanded"
expanded: "cmp-accordion__panel--expanded",
stepped: "cmp-accordion__panel--stepped"
}
};

Expand Down Expand Up @@ -239,6 +241,11 @@
item.removeAttribute(this.constructor.dataAttributes.item.expanded);
var button = this.getCachedButtons()[index];
var panel = this.getCachedPanels()[index];
if (button.classList.contains(this.constructor.cssClasses.button.expanded)) {
// Only apply `stepped` class if the tab was previously expanded
button.classList.add(this.constructor.cssClasses.button.stepped);
panel.classList.add(this.constructor.cssClasses.panel.stepped);
}
button.classList.remove(this.constructor.cssClasses.button.expanded);
// used to fix some known screen readers issues in reading the correct state of the 'aria-expanded' attribute
// e.g. https://bugs.webkit.org/show_bug.cgi?id=210934
Expand All @@ -250,8 +257,9 @@
panel.setAttribute("aria-hidden", true);
}
}
}
};
}


window.Forms = window.Forms || {};
window.Forms.CoreComponentsCommons = window.Forms.CoreComponentsCommons || {};
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -258,6 +258,12 @@
}
this.expandItem(itemDivToExpand);
this.collapseAllOtherItems(itemDivToExpand.id);

const cachedItems = this.getCachedItems();
const newIndex = cachedItems.indexOf(itemDivToExpand);
this.getCachedButtons()[newIndex].classList.remove(this.constructor.cssClasses.button.stepped);
this.getCachedPanels()[newIndex].classList.remove(this.constructor.cssClasses.panel.stepped);

this.#showHideRepeatableButtons(childView.getInstanceManager());
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,7 @@ BLOCK cmp-tabs
ELEMENT cmp-tabs__tablist
ELEMENT cmp-tabs__tab
MOD cmp-tabs__tab--active
MOD cmp-tabs__tab--stepped
ELEMENT cmp-tabs__title
ELEMENT cmp-tabs__icon
ELEMENT cmp-tabs__label
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,10 @@
tab: "cmp-tabs__tab--active",
tabpanel: "cmp-tabs__tabpanel--active"
},
stepped: {
tab: "cmp-tabs__tab--stepped",
tabpanel: "cmp-tabs__tabpanel--stepped"
},
label: `.${Tabs.bemBlock}__label`,
description: `.${Tabs.bemBlock}__longdescription`,
qm: `.${Tabs.bemBlock}__questionmark`,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,7 @@ BLOCK cmp-verticaltabs
ELEMENT cmp-verticaltabs__label-container
ELEMENT cmp-verticaltabs__tab
MOD cmp-verticaltabs__tab--active
MOD cmp-verticaltabs__tab--stepped
ELEMENT cmp-verticaltabs__title
ELEMENT cmp-verticaltabs__icon
ELEMENT cmp-verticaltabs__label
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,10 @@
tab: "cmp-verticaltabs__tab--active",
tabpanel: "cmp-verticaltabs__tabpanel--active"
},
stepped: {
tab: "cmp-verticaltabs__tab--stepped",
tabpanel: "cmp-verticaltabs__tabpanel--stepped"
},
label: `.${VerticalTabs.bemBlock}__label`,
description: `.${VerticalTabs.bemBlock}__longdescription`,
qm: `.${VerticalTabs.bemBlock}__questionmark`,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -46,8 +46,10 @@ It is already included by its edit and policy dialogs.
```
BLOCK cmp-adaptiveform-wizard
ELEMENT cmp-adaptiveform-wizard__label
ELEMENT cmp-adaptiveform-wizard__label-container
ELEMENT cmp-adaptiveform-wizard__label-container
ELEMENT cmp-adaptiveform-wizard__tab
MOD cmp-adaptiveform-wizard__tab--active
MOD cmp-adaptiveform-wizard__tab--stepped
ELEMENT cmp-adaptiveform-wizard__wizardpanel
ELEMENT cmp-adaptiveform-wizard__previousNav
ELEMENT cmp-adaptiveform-wizard__nextNav
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,11 @@
active: {
tab: "cmp-adaptiveform-wizard__tab--active",
wizardpanel: "cmp-adaptiveform-wizard__wizardpanel--active"
}
},
stepped: {
tab: "cmp-adaptiveform-wizard__tab--stepped",
wizardpanel: "cmp-adaptiveform-wizard__wizardpanel--stepped",
}
};

_active;
Expand Down Expand Up @@ -72,6 +76,48 @@
}
}

addSteppedClass() {
const tabs = this.getCachedTabs();
const wizardPanels = this.getCachedWizardPanels();
const activeChildId = this.getActiveWizardTabId(tabs)
const activeTab = this.getTabNavElementById(activeChildId);
if (activeTab.classList.contains(this.constructor.selectors.active.tab)) {
activeTab.classList.add(this.constructor.selectors.stepped.tab);

const correspondingPanel = Array.from(wizardPanels).find(panel =>
panel.getAttribute("aria-labelledby") === activeTab.id
);

if (correspondingPanel) {
correspondingPanel.classList.add(this.constructor.selectors.stepped.wizardpanel);
}
}
}

getTabNavElementById(tabId) {
let tabs = this.getCachedTabs();
if (tabs) {
for (let i = 0; i < tabs.length; i++) {
if (tabs[i].id === tabId) {
return tabs[i];
}
}
}
}

getActiveWizardTabId(tabs) {
if (tabs) {
var result = tabs[0].id;
for (var i = 0; i < tabs.length; i++) {
if (tabs[i].classList.contains(this.constructor.selectors.active.tab)) {
result = tabs[i].id;
break;
}
}
return result;
}
}

/**
* Returns the index of the active tab, if no tab is active returns 0
*
Expand Down Expand Up @@ -105,6 +151,7 @@
*/
navigate(index) {
this._active = index;
this.addSteppedClass();
this.refreshActive();
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,10 @@
tab: "cmp-adaptiveform-wizard__tab--active",
wizardpanel: "cmp-adaptiveform-wizard__wizardpanel--active"
},
stepped: {
tab: "cmp-adaptiveform-wizard__tab--stepped",
wizardpanel: "cmp-adaptiveform-wizard__wizardpanel--stepped",
},
label: `.${Wizard.bemBlock}__label`,
description: `.${Wizard.bemBlock}__longdescription`,
qm: `.${Wizard.bemBlock}__questionmark`,
Expand Down Expand Up @@ -331,7 +335,7 @@
this.navigate(index);
this.focusWithoutScroll(this.getCachedTabs()[index]);
}

#syncWizardNavLabels() {
const tabs = this.getCachedTabs();
const wizardPanels = this.getCachedWizardPanels();
Expand Down Expand Up @@ -382,12 +386,21 @@
}
} else {
let beforeTabNavElementId = childView.getInstanceManager().children[instanceIndex - 1].element.id + Wizard.#tabIdSuffix
let beforeElement = this.#getTabNavElementById(beforeTabNavElementId);
let beforeElement = this.getTabNavElementById(beforeTabNavElementId);
beforeElement.after(navigationTabToBeRepeated);
}
this.cacheElements(this._elements.self);
let repeatedWizardPanel = this.#getWizardPanelElementById(childView.id + Wizard.#wizardPanelIdSuffix);
repeatedWizardPanel.setAttribute("aria-labelledby", childView.id + Wizard.#tabIdSuffix);

const steppedTabClass = Array.from(navigationTabToBeRepeated.classList).find(cls => cls.includes('--stepped'));
if (steppedTabClass) {
navigationTabToBeRepeated.classList.remove(steppedTabClass);
}
const steppedWizardPanelClass = Array.from(repeatedWizardPanel.classList).find(cls => cls.includes('--stepped'));
if (steppedWizardPanelClass) {
repeatedWizardPanel.classList.remove(steppedWizardPanelClass);
}
this.refreshActive();
this.#getTabIndexById();
if (childView.getInstanceManager().getModel().minOccur != undefined && childView.getInstanceManager().children.length > childView.getInstanceManager().getModel().minOccur) {
Expand All @@ -400,7 +413,7 @@
let removedTabPanelId = removedInstanceView.element.id + Wizard.#wizardPanelIdSuffix;
let removedTabNavId = removedTabPanelId.substring(0, removedTabPanelId.lastIndexOf("__")) + Wizard.#tabIdSuffix;
let wizardPanelElement = this.#getWizardPanelElementById(removedTabPanelId);
let tabNavElement = this.#getTabNavElementById(removedTabNavId);
let tabNavElement = this.getTabNavElementById(removedTabNavId);
tabNavElement.remove();
wizardPanelElement.remove();
this.children.splice(this.children.indexOf(removedInstanceView), 1);
Expand Down Expand Up @@ -448,25 +461,14 @@
let tabId = childView.element.id + Wizard.#tabIdSuffix;
let wizardPanelId = childView.element.id + Wizard.#wizardPanelIdSuffix;
let instanceManagerId = childView.getInstanceManager().getId();
let navigationTabToBeRepeated = this.#getTabNavElementById(tabId);
let navigationTabToBeRepeated = this.getTabNavElementById(tabId);
let wizardPanelToBeRepeated = this.#getWizardPanelElementById(wizardPanelId)
this._templateHTML[instanceManagerId] = {};
this._templateHTML[instanceManagerId]['navigationTab'] = navigationTabToBeRepeated;
this._templateHTML[instanceManagerId]['targetWizardPanel'] = wizardPanelToBeRepeated;
}
}

#getTabNavElementById(tabId) {
let tabs = this.getCachedTabs();
if (tabs) {
for (let i = 0; i < tabs.length; i++) {
if (tabs[i].id === tabId) {
return tabs[i];
}
}
}
}

#getWizardPanelElementById(wizardPanelId) {
let wizardPanels = this.getCachedWizardPanels();
if (wizardPanels) {
Expand Down Expand Up @@ -516,7 +518,7 @@
}

updateChildVisibility(visible, state) {
this.updateVisibilityOfNavigationElement(this.#getTabNavElementById(state.id + Wizard.#tabIdSuffix), visible);
this.updateVisibilityOfNavigationElement(this.getTabNavElementById(state.id + Wizard.#tabIdSuffix), visible);
let activeTabNavElement = this.getCachedTabs()[this._active];
this.#setNavigationRange();
this.#hideUnhideNavButtons(this._active);
Expand Down
28 changes: 28 additions & 0 deletions ui.frontend/src/view/FormTabs.js
Original file line number Diff line number Diff line change
Expand Up @@ -286,9 +286,29 @@ class FormTabs extends FormPanel {
*/
navigate(tabId) {
this.#_active = tabId;
this.addSteppedClass(tabId);
this.#refreshActive();
}


addSteppedClass(tabId) {
var tabs = this.#getCachedTabs();
var tabpanels= this.#getCachedTabPanels();
const activeTabId = this.getActiveTabId(tabs);
const activeTabElement = this.#getTabNavElementById(activeTabId);
if (activeTabElement.classList.contains(this.#_selectors.active.tab)) {
activeTabElement.classList.add(this.#_selectors.stepped.tab);

const correspondingPanel = Array.from(tabpanels).find(panel =>
panel.getAttribute("aria-labelledby") === activeTabElement.id
);

if (correspondingPanel) {
correspondingPanel.classList.add(this.#_selectors.stepped.tabpanel);
}
}
}

/**
* Returns the id of the active tab, if no tab is active returns 0th element id
*
Expand Down Expand Up @@ -384,6 +404,14 @@ class FormTabs extends FormPanel {
this.#cacheElements(this._elements.self);
var repeatedTabPanel = this.#getTabPanelElementById(childView.id + this.#tabPanelIdSuffix);
repeatedTabPanel.setAttribute("aria-labelledby", childView.id + this.#tabIdSuffix);
const steppedTabClass = Array.from(navigationTabToBeRepeated.classList).find(cls => cls.includes('--stepped'));
if (steppedTabClass) {
navigationTabToBeRepeated.classList.remove(steppedTabClass);
}
const steppedTabpanelClass = Array.from(repeatedTabPanel.classList).find(cls => cls.includes('--stepped'));
if (steppedTabpanelClass) {
repeatedTabPanel.classList.remove(steppedTabpanelClass);
}
this.#bindEventsToTab(navigationTabToBeRepeated.id);
this.#refreshActive();
if (childView.getInstanceManager().getModel().minOccur != undefined && childView.getInstanceManager().children.length > childView.getInstanceManager().getModel().minOccur) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -212,6 +212,41 @@ describe("Form with Accordion Container with repeatable elements", () => {
getAccordionButtons().should('have.length', 8);
})
});

it("if item-1 is repeated, the repeated instance should not have stepped class", () => {
getItemDivs().should('have.length', 5);
getAccordionPanels().should('have.length', 5);
getAccordionButtons().should('have.length', 5);
getExpandedPanelDiv().should('have.length', 1);
getExpandedButtonDiv().should('have.length', 1);
getAccordionButtonsAtIndex(0).should('have.class', 'cmp-accordion__button--expanded');
getAccordionPanelsAtIndex(0).should('have.class', 'cmp-accordion__panel--expanded');
cy.get("button").contains("+RP1").click().then(() => {
getItemDivs().should('have.length', 6);
getAccordionPanels().should('have.length', 6);
getAccordionButtons().should('have.length', 6);
getExpandedPanelDiv().should('have.length', 1);
getExpandedButtonDiv().should('have.length', 1);
getAccordionButtonsAtIndex(1).should('have.class', 'cmp-accordion__button--expanded');
getAccordionPanelsAtIndex(1).should('have.class', 'cmp-accordion__panel--expanded');
getAccordionButtonsAtIndex(0).should('have.class', 'cmp-accordion__button--stepped');
getAccordionPanelsAtIndex(0).should('have.class', 'cmp-accordion__panel--stepped');
});
cy.get("button").contains("+RP1").click().then(() => {
getItemDivs().should('have.length', 7);
getAccordionPanels().should('have.length', 7);
getAccordionButtons().should('have.length', 7);
getExpandedPanelDiv().should('have.length', 1);
getExpandedButtonDiv().should('have.length', 1);
getAccordionButtonsAtIndex(2).should('have.class', 'cmp-accordion__button--expanded');
getAccordionPanelsAtIndex(2).should('have.class', 'cmp-accordion__panel--expanded');
getAccordionButtonsAtIndex(1).should('have.class', 'cmp-accordion__button--stepped');
getAccordionPanelsAtIndex(1).should('have.class', 'cmp-accordion__panel--stepped');
getAccordionButtonsAtIndex(0).should('have.class', 'cmp-accordion__button--stepped');
getAccordionPanelsAtIndex(0).should('have.class', 'cmp-accordion__panel--stepped');
});
cy.expectNoConsoleErrors();
})
})

describe("Form with Accordion Container with nested repeatable elements", () => {
Expand Down
3 changes: 3 additions & 0 deletions ui.tests/test-module/specs/tabsontop/tabsontop.runtime.cy.js
Original file line number Diff line number Diff line change
Expand Up @@ -90,10 +90,13 @@ describe("Form with Panel Container", () => {
tab2().should('have.class', 'cmp-tabs__tab--active');
tab2().should('have.attr', 'aria-selected', 'true');
tab1().should('have.attr', 'aria-selected', 'false');
tab1().should('have.class', 'cmp-tabs__tab--stepped');
tab1().click();
tab1().should('have.class', 'cmp-tabs__tab--active');
tab1().should('have.class', 'cmp-tabs__tab--stepped');
tab1().should('have.attr', 'aria-selected', 'true');
tab2().should('have.attr', 'aria-selected', 'false');
tab2().should('have.class', 'cmp-tabs__tab--stepped');
});

it("switch tab in runtime using keyboard", () => {
Expand Down
Loading

0 comments on commit 628c889

Please sign in to comment.