Skip to content

Commit 20ddad4

Browse files
Pavitra Khatrici-build
Pavitra Khatri
authored and
ci-build
committed
Focus on first visible field in form and in navigable layouts
1 parent ce75e29 commit 20ddad4

File tree

9 files changed

+112
-11
lines changed

9 files changed

+112
-11
lines changed

ui.af.apps/src/main/content/jcr_root/apps/core/fd/components/form/accordion/v1/accordion/clientlibs/commons/js/common.js

+12-1
Original file line numberDiff line numberDiff line change
@@ -87,7 +87,7 @@
8787
}
8888
}
8989

90-
90+
9191
/**
9292
* Returns all expanded items.
9393
*
@@ -225,6 +225,17 @@
225225
panel.classList.add(this.constructor.cssClasses.panel.expanded);
226226
panel.classList.remove(this.constructor.cssClasses.panel.hidden);
227227
panel.setAttribute("aria-hidden", false);
228+
229+
if (document.activeElement === button) {
230+
setTimeout(() => {
231+
let id = panel.id.replace(this.constructor.idSuffixes.panel, "");
232+
const form = this.formContainer.getModel();
233+
const field = form.getElement(id);
234+
if (field) {
235+
form.setFocus(field);
236+
}
237+
}, 0)
238+
}
228239
}
229240
}
230241

ui.af.apps/src/main/content/jcr_root/apps/core/fd/components/form/accordion/v1/accordion/clientlibs/site/js/accordionview.js

-7
Original file line numberDiff line numberDiff line change
@@ -89,13 +89,6 @@
8989
return this.element.querySelector(Accordion.selectors.qm);
9090
}
9191

92-
setFocus(id) {
93-
super.setFocus(id);
94-
this.setActive();
95-
this.#collapseAllItems();
96-
const item = this.getItemById(id + '-item');
97-
this.expandItem(item)
98-
}
9992

10093

10194
#collapseAllItems() {

ui.af.apps/src/main/content/jcr_root/apps/core/fd/components/form/container/v2/container/clientlibs/site/js/formcontainerview.js

+11
Original file line numberDiff line numberDiff line change
@@ -124,6 +124,17 @@
124124
let formContainer = e.detail;
125125
let formEl = formContainer.getFormElement();
126126
formContainer.initialiseHamburgerMenu();
127+
128+
const fields = formEl.querySelectorAll("[data-cmp-is]");
129+
const firstVisibleField = Array.from(fields).find(field => {
130+
return field.getAttribute("data-cmp-visible") === "true" && field.getAttribute("data-cmp-enabled") === "true" && !field.closest("[data-cmp-visible='false']");
131+
});
132+
133+
const form = formContainer.getModel();
134+
const field = form?.getElement(firstVisibleField?.id);
135+
if (form && field) {
136+
form.setFocus(field);
137+
}
127138
setTimeout(() => {
128139
let loaderToRemove = document.querySelector("[data-cmp-adaptiveform-container-loader='"+ formEl.id + "']");
129140
if(loaderToRemove){

ui.af.apps/src/main/content/jcr_root/apps/core/fd/components/form/wizard/v1/wizard/clientlibs/site/js/wizardview.js

+8
Original file line numberDiff line numberDiff line change
@@ -199,6 +199,12 @@
199199
}
200200

201201

202+
getFocusElementId() {
203+
const activeIndex = this._active;
204+
const activeTabElement = this.getCachedTabs()[activeIndex];
205+
return activeTabElement.id.substring(0, activeTabElement.id.lastIndexOf(Wizard.#tabIdSuffix));
206+
}
207+
202208
#navigateToNextTab() {
203209
const activeIndex = this._active;
204210
const activeTabElement = this.getCachedTabs()[activeIndex];
@@ -334,6 +340,8 @@
334340
#navigateAndFocusTab(index) {
335341
this.navigate(index);
336342
this.focusWithoutScroll(this.getCachedTabs()[index]);
343+
const id = this.getFocusElementId();
344+
this.focusToFirstVisibleField(id);
337345
}
338346

339347
#syncWizardNavLabels() {

ui.frontend/src/view/FormPanel.js

+8
Original file line numberDiff line numberDiff line change
@@ -76,6 +76,14 @@ class FormPanel extends FormFieldBase {
7676
}
7777
}
7878

79+
focusToFirstVisibleField(id) {
80+
const form = this.formContainer.getModel();
81+
const field = form.getElement(id);
82+
if (field) {
83+
form.setFocus(field);
84+
}
85+
}
86+
7987
/**
8088
* Adds a child view to the FormPanel.
8189
* @param {Object} childView - The child view to be added.

ui.frontend/src/view/FormTabs.js

+2-2
Original file line numberDiff line numberDiff line change
@@ -249,11 +249,12 @@ class FormTabs extends FormPanel {
249249
if (this.#_active !== tabId) {
250250
this.navigate(tabId);
251251
this.focusWithoutScroll(this.#getTabNavElementById(tabId));
252+
const id = this.getActiveTabId(this.#getCachedTabs()).replace(this.#tabIdSuffix,"");
253+
this.focusToFirstVisibleField(id);
252254
}
253255
}
254256

255257

256-
257258
#getTabNavElementById(tabId) {
258259
var tabs = this.#getCachedTabs();
259260
if (tabs) {
@@ -328,7 +329,6 @@ class FormTabs extends FormPanel {
328329
}
329330
}
330331

331-
332332
/**
333333
* Synchronizes tab labels with their corresponding tab panels.
334334
* Updates the ID and aria-controls attribute of each tab label.

ui.tests/test-module/specs/accordion/accordion.runtime.cy.js

+21-1
Original file line numberDiff line numberDiff line change
@@ -197,7 +197,6 @@ describe("Form with Accordion Layout Container with focus", () => {
197197
cy.get(`#${secondChildComponentButtonId}`).should('have.class', 'cmp-accordion__button--expanded');
198198
cy.get(`#${firstChildComponentButtonId}`).should('not.have.class', 'cmp-accordion__button--expanded');
199199
cy.get(`#${firstChildComponentPanelId}`).should('not.have.class', 'cmp-accordion__panel--expanded');
200-
201200
cy.get(`#${firstChildComponentButtonId}`).then(() => {
202201
formContainer.setFocus(id);
203202
cy.get(`#${firstChildComponentButtonId}`).isElementInViewport().should("eq", true);
@@ -212,6 +211,27 @@ describe("Form with Accordion Layout Container with focus", () => {
212211
});
213212
});
214213
});
214+
215+
it("on clicking of expand button, focus should be visible on first component in the current tab ", () => {
216+
const [id, fieldView] = Object.entries(formContainer._fields)[0];
217+
const firstChildComponentId = formContainer._model.items[0].items[0].id;
218+
const firstChildComponentButtonId = firstChildComponentId + "-button";
219+
const firstChildComponentPanelId = firstChildComponentId + "-panel";
220+
221+
const secondChildComponentId = formContainer._model.items[0].items[1].id;
222+
const secondChildComponentButtonId = secondChildComponentId + "-button";
223+
const secondChildComponentPanelId = secondChildComponentId + "-panel";
224+
225+
cy.get(`#${secondChildComponentButtonId}`).click({force: true}).then(() => {
226+
cy.get('input[name="textinputfa2"]').should('be.focused');
227+
cy.get(`#${secondChildComponentPanelId}`).should('have.class', 'cmp-accordion__panel--expanded');
228+
})
229+
230+
cy.get(`#${firstChildComponentButtonId}`).click({force: true}).then(() => {
231+
cy.get('input[name="textinputfa1"]').should('be.focused');
232+
cy.get(`#${firstChildComponentPanelId}`).should('have.class', 'cmp-accordion__panel--expanded');
233+
})
234+
})
215235
});
216236

217237
describe("Form with Accordion Layout Container with Hidden Children", () => {

ui.tests/test-module/specs/tabsontop/tabsontop.runtime.cy.js

+25
Original file line numberDiff line numberDiff line change
@@ -67,6 +67,7 @@ describe("Form with Panel Container", () => {
6767

6868
it(" model's changes are reflected in the html ", () => {
6969
const tabId = formContainer._model.items[0].items[0].id;
70+
console.log(tabId, 'test-id')
7071
const model = formContainer._model.getElement(tabId);
7172
const tabView = formContainer.getAllFields()[tabId];
7273
const count = 2;
@@ -167,6 +168,30 @@ describe("Form with Tabsontop Layout Container with focus", () => {
167168

168169
});
169170

171+
it("first component should always be focused in the form", () => {
172+
const [id, fieldView] = Object.entries(formContainer._fields)[0];
173+
tab1().should('have.class', 'cmp-tabs__tab--active');
174+
tab1().should('have.attr', 'aria-selected', 'true');
175+
tab2().should('have.attr', 'aria-selected', 'false');
176+
cy.get('input[name="textinputft1"]').should('be.focused');
177+
})
178+
179+
it("focus should be on the first component when navigated to the next tab", () => {
180+
const [id, fieldView] = Object.entries(formContainer._fields)[0];
181+
tab2().click().then(() => {
182+
tab2().should('have.class', 'cmp-tabs__tab--active');
183+
tab2().should('have.attr', 'aria-selected', 'true');
184+
cy.get('input[name="textinputft2"]').should('be.focused');
185+
tab1().should('have.attr', 'aria-selected', 'false');
186+
});
187+
tab1().click().then(() => {
188+
tab1().should('have.class', 'cmp-tabs__tab--active');
189+
tab1().should('have.attr', 'aria-selected', 'true');
190+
cy.get('input[name="textinputft1"]').should('be.focused');
191+
tab2().should('have.attr', 'aria-selected', 'false');
192+
});
193+
})
194+
170195

171196
});
172197
describe("Form with TabsOnTop Layout Container with Hidden Children", () => {

ui.tests/test-module/specs/wizard/wizard.runtime.cy.js

+25
Original file line numberDiff line numberDiff line change
@@ -273,6 +273,29 @@ describe("Form with Wizard Layout Container with focus", () => {
273273
});
274274
});
275275

276+
it("First component should always have focus", () => {
277+
const [id, fieldView] = Object.entries(formContainer._fields)[0];
278+
cy.get(".cmp-adaptiveform-wizard__tab").eq(0).should('have.class', 'cmp-adaptiveform-wizard__tab--active');
279+
cy.get(".cmp-adaptiveform-wizard__tab").eq(1).should('not.have.class', 'cmp-adaptiveform-wizard__tab--active');
280+
cy.get(".cmp-adaptiveform-wizard__wizardpanel").eq(0).should('have.class', 'cmp-adaptiveform-wizard__wizardpanel--active');
281+
cy.get(".cmp-adaptiveform-wizard__wizardpanel").eq(1).should('not.have.class', 'cmp-adaptiveform-wizard__wizardpanel--active');
282+
cy.get('input[name="textinputfw1"]').should('be.focused');
283+
cy.get(".cmp-adaptiveform-wizard__nav--next").click({force: true}).then(() => {
284+
cy.get(".cmp-adaptiveform-wizard__tab").eq(0).should('not.have.class', 'cmp-adaptiveform-wizard__tab--active');
285+
cy.get(".cmp-adaptiveform-wizard__tab").eq(1).should('have.class', 'cmp-adaptiveform-wizard__tab--active');
286+
cy.get(".cmp-adaptiveform-wizard__wizardpanel").eq(0).should('not.have.class', 'cmp-adaptiveform-wizard__wizardpanel--active');
287+
cy.get(".cmp-adaptiveform-wizard__wizardpanel").eq(1).should('have.class', 'cmp-adaptiveform-wizard__wizardpanel--active');
288+
cy.get('input[name="textinputfw2"]').should('be.focused');
289+
});
290+
cy.get(".cmp-adaptiveform-wizard__nav--previous").click({force: true}).then(() => {
291+
cy.get(".cmp-adaptiveform-wizard__tab").eq(0).should('have.class', 'cmp-adaptiveform-wizard__tab--active');
292+
cy.get(".cmp-adaptiveform-wizard__tab").eq(1).should('not.have.class', 'cmp-adaptiveform-wizard__tab--active');
293+
cy.get(".cmp-adaptiveform-wizard__wizardpanel").eq(0).should('have.class', 'cmp-adaptiveform-wizard__wizardpanel--active');
294+
cy.get(".cmp-adaptiveform-wizard__wizardpanel").eq(1).should('not.have.class', 'cmp-adaptiveform-wizard__wizardpanel--active');
295+
cy.get('input[name="textinputfw1"]').should('be.focused');
296+
});
297+
})
298+
276299
});
277300

278301
describe("Form with wizard Layout Container with Hidden Children", () => {
@@ -290,8 +313,10 @@ describe("Form with wizard Layout Container with Hidden Children", () => {
290313

291314
const firstItemNavOfWizardId = formContainer._model.items[0].items[0].id + "_wizard-item-nav";
292315
const firstItemOfWizardId = formContainer._model.items[0].items[0].id + "__wizardpanel";
316+
console.log(firstItemOfWizardId, 'item-id')
293317
const secondItemNavOfWizardId = formContainer._model.items[0].items[1].id + "_wizard-item-nav";
294318
const secondItemOfWizardId = formContainer._model.items[0].items[1].id + "__wizardpanel";
319+
console.log(secondItemOfWizardId, 'second-id')
295320

296321
cy.get(`#${firstItemNavOfWizardId}`).should('have.attr', 'data-cmp-visible', 'false');
297322
cy.get(`#${firstItemOfWizardId}`).should('have.attr', 'aria-hidden', 'true');

0 commit comments

Comments
 (0)