Skip to content

Commit 60d0dc1

Browse files
authored
feat: implement F6 Navigation Helper (#4490)
1 parent b646157 commit 60d0dc1

28 files changed

+844
-27
lines changed

.travis.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@ before_install:
1515
- gem install jekyll-seo-tag
1616

1717
script:
18-
- DEPLOY_PUBLIC_PATH=/resources/ yarn build
18+
- DEPLOY_PUBLIC_PATH=/resources/ ENABLE_CLDR=1 yarn build
1919
- yarn test
2020

2121
deploy:

packages/base/hash.txt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1 +1 @@
1-
LwpwazozKyw2R4uvmZVLv5VZq7E=
1+
35rcbBXTa7Q432kQnojY0s3empY=

packages/base/src/Boot.js

Lines changed: 30 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ import applyTheme from "./theming/applyTheme.js";
77
import { registerCurrentRuntime } from "./Runtimes.js";
88
import { getFeature } from "./FeaturesRegistry.js";
99

10-
let booted = false;
10+
let bootPromise;
1111
const eventProvider = new EventProvider();
1212

1313
/**
@@ -20,24 +20,39 @@ const attachBoot = listener => {
2020
};
2121

2222
const boot = async () => {
23-
if (booted) {
24-
return;
23+
if (bootPromise) {
24+
return bootPromise;
2525
}
2626

27-
registerCurrentRuntime();
27+
/* eslint-disable no-alert, no-async-promise-executor */
28+
/*
29+
Note(since we disable eslint rule):
30+
If an async executor function throws an error, the error will be lost and won't cause the newly-constructed Promise to reject.
31+
This could make it difficult to debug and handle some errors.
32+
*/
33+
bootPromise = new Promise(async resolve => {
34+
registerCurrentRuntime();
2835

29-
const OpenUI5Support = getFeature("OpenUI5Support");
30-
if (OpenUI5Support) {
31-
await OpenUI5Support.init();
32-
}
36+
const OpenUI5Support = getFeature("OpenUI5Support");
37+
const F6Navigation = getFeature("F6Navigation");
38+
if (OpenUI5Support) {
39+
await OpenUI5Support.init();
40+
} else if (F6Navigation) {
41+
F6Navigation.init();
42+
}
43+
44+
await whenDOMReady();
45+
await applyTheme(getTheme());
46+
OpenUI5Support && OpenUI5Support.attachListeners();
47+
insertFontFace();
48+
insertSystemCSSVars();
49+
await eventProvider.fireEventAsync("boot");
50+
51+
resolve();
52+
});
53+
/* eslint-enable no-alert, no-async-promise-executor */
3354

34-
await whenDOMReady();
35-
await applyTheme(getTheme());
36-
OpenUI5Support && OpenUI5Support.attachListeners();
37-
insertFontFace();
38-
insertSystemCSSVars();
39-
await eventProvider.fireEventAsync("boot");
40-
booted = true;
55+
return bootPromise;
4156
};
4257

4358
export {

packages/base/src/FeaturesRegistry.js

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,4 +8,7 @@ const getFeature = name => {
88
return features.get(name);
99
};
1010

11-
export { registerFeature, getFeature };
11+
export {
12+
registerFeature,
13+
getFeature,
14+
};

packages/base/src/Keys.js

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -191,6 +191,12 @@ const isF4 = event => {
191191

192192
const isF4Shift = event => (event.key ? event.key === "F4" : event.keyCode === KeyCodes.F4) && checkModifierKeys(event, false, false, true);
193193

194+
const isF6Next = event => ((event.key ? event.key === "F6" : event.keyCode === KeyCodes.F6) && checkModifierKeys(event, false, false, false))
195+
|| ((event.key ? (event.key === "ArrowDown" || event.key === "Down") : event.keyCode === KeyCodes.ARROW_DOWN) && checkModifierKeys(event, true, true, false));
196+
197+
const isF6Previous = event => ((event.key ? event.key === "F6" : event.keyCode === KeyCodes.F6) && checkModifierKeys(event, false, false, true))
198+
|| ((event.key ? (event.key === "ArrowUp" || event.key === "Up") : event.keyCode === KeyCodes.ARROW_Up) && checkModifierKeys(event, true, true, false));
199+
194200
const isF7 = event => (event.key ? event.key === "F7" : event.keyCode === KeyCodes.F7) && !hasModifierKeys(event);
195201

196202
const isShowByArrows = event => {
@@ -236,6 +242,8 @@ export {
236242
isShow,
237243
isF4,
238244
isF4Shift,
245+
isF6Previous,
246+
isF6Next,
239247
isF7,
240248
isPageUp,
241249
isPageDown,

packages/base/src/UI5Element.js

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -101,6 +101,9 @@ class UI5Element extends HTMLElement {
101101
*/
102102
async connectedCallback() {
103103
this.setAttribute(this.constructor.getMetadata().getPureTag(), "");
104+
if (this.constructor.getMetadata().supportsF6FastNavigation()) {
105+
this.setAttribute("data-sap-ui-fastnavgroup", "true");
106+
}
104107

105108
const slotsAreManaged = this.constructor.getMetadata().slotsAreManaged();
106109

packages/base/src/UI5ElementMetadata.js

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -188,6 +188,14 @@ class UI5ElementMetadata {
188188
return !!this.metadata.managedSlots;
189189
}
190190

191+
/**
192+
* Determines whether this control supports F6 fast navigation
193+
* @public
194+
*/
195+
supportsF6FastNavigation() {
196+
return !!this.metadata.fastNavigation;
197+
}
198+
191199
/**
192200
* Returns an object with key-value pairs of properties and their metadata definitions
193201
* @public

packages/base/src/util/FocusableElements.js

Lines changed: 8 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -5,36 +5,38 @@ const isFocusTrap = el => {
55
return el.hasAttribute("data-ui5-focus-trap");
66
};
77

8-
const getFirstFocusableElement = async container => {
8+
const getFirstFocusableElement = async (container, startFromContainer) => {
99
if (!container || isNodeHidden(container)) {
1010
return null;
1111
}
1212

13-
return findFocusableElement(container, true);
13+
return findFocusableElement(container, true, startFromContainer);
1414
};
1515

16-
const getLastFocusableElement = async container => {
16+
const getLastFocusableElement = async (container, startFromContainer) => {
1717
if (!container || isNodeHidden(container)) {
1818
return null;
1919
}
2020

21-
return findFocusableElement(container, false);
21+
return findFocusableElement(container, false, startFromContainer);
2222
};
2323

2424
const isElemFocusable = el => {
2525
return el.hasAttribute("data-ui5-focus-redirect") || !isNodeHidden(el);
2626
};
2727

28-
const findFocusableElement = async (container, forward) => {
28+
const findFocusableElement = async (container, forward, startFromContainer) => {
2929
let child;
3030

3131
if (container.shadowRoot) {
3232
child = forward ? container.shadowRoot.firstChild : container.shadowRoot.lastChild;
3333
} else if (container.assignedNodes && container.assignedNodes()) {
3434
const assignedElements = container.assignedNodes();
3535
child = forward ? assignedElements[0] : assignedElements[assignedElements.length - 1];
36+
} else if (startFromContainer) {
37+
child = container;
3638
} else {
37-
child = forward ? container.firstChild : container.lastChild;
39+
child = forward ? container.firstElementChild : container.lastElementChild;
3840
}
3941

4042
let focusableDescendant;

packages/base/src/util/isNodeHidden.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@ const isNodeHidden = node => {
33
return false;
44
}
55

6-
return (node.offsetWidth <= 0 && node.offsetHeight <= 0) || node.style.visibility === "hidden";
6+
return (node.offsetWidth <= 0 && node.offsetHeight <= 0) || (node.style && node.style.visibility === "hidden");
77
};
88

99
export default isNodeHidden;

packages/fiori/src/Bar.js

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ import BarCss from "./generated/themes/Bar.css.js";
1313
const metadata = {
1414
tag: "ui5-bar",
1515
managedSlots: true,
16+
fastNavigation: true,
1617
properties: /** @lends sap.ui.webcomponents.fiori.Bar.prototype */ {
1718
/**
1819
* Defines the <code>ui5-bar</code> design.

packages/fiori/src/FlexibleColumnLayout.js

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,7 @@ import FlexibleColumnLayoutCss from "./generated/themes/FlexibleColumnLayout.css
3939
*/
4040
const metadata = {
4141
tag: "ui5-flexible-column-layout",
42+
fastNavigation: true,
4243
properties: /** @lends sap.ui.webcomponents.fiori.FlexibleColumnLayout.prototype */ {
4344
/**
4445
* Defines the columns layout and their proportion.

packages/fiori/src/ShellBar.js

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,7 @@ const HANDLE_RESIZE_DEBOUNCE_RATE = 200; // ms
4242
const metadata = {
4343
tag: "ui5-shellbar",
4444
languageAware: true,
45+
fastNavigation: true,
4546
properties: /** @lends sap.ui.webcomponents.fiori.ShellBar.prototype */ {
4647

4748
/**

packages/fiori/src/SideNavigation.js

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@ import SideNavigationPopoverCss from "./generated/themes/SideNavigationPopover.c
1818
const metadata = {
1919
tag: "ui5-side-navigation",
2020
managedSlots: true,
21+
fastNavigation: true,
2122
properties: /** @lends sap.ui.webcomponents.fiori.SideNavigation.prototype */ {
2223
/**
2324
* Defines whether the <code>ui5-side-navigation</code> is expanded or collapsed.

packages/fiori/src/Wizard.js

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -56,6 +56,7 @@ const STEP_SWITCH_THRESHOLDS = {
5656
const metadata = {
5757
tag: "ui5-wizard",
5858
managedSlots: true,
59+
fastNavigation: true,
5960
properties: /** @lends sap.ui.webcomponents.fiori.Wizard.prototype */ {
6061
/**
6162
* Defines the width of the <code>ui5-wizard</code>.

0 commit comments

Comments
 (0)