@ui5/webcomponents-base 1.0.2 → 1.1.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/.eslintignore +1 -0
- package/CHANGELOG.md +19 -0
- package/dist/Boot.js +32 -14
- package/dist/CustomElementsRegistry.js +60 -4
- package/dist/Device.js +6 -0
- package/dist/FeaturesRegistry.js +4 -1
- package/dist/Keys.js +17 -0
- package/dist/Runtimes.js +109 -0
- package/dist/StaticAreaItem.js +3 -0
- package/dist/UI5Element.js +7 -2
- package/dist/UI5ElementMetadata.js +8 -0
- package/dist/features/F6Navigation.js +106 -0
- package/dist/generated/VersionInfo.js +10 -0
- package/dist/resources/bundle.esm.js +8 -8
- package/dist/resources/bundle.esm.js.map +1 -1
- package/dist/sap/base/security/encodeCSS.js +14 -0
- package/dist/sap/base/security/encodeXML.js +23 -0
- package/dist/sap/base/strings/toHex.js +8 -0
- package/dist/util/FocusableElements.js +8 -6
- package/dist/util/generateHighlightedMarkup.js +1 -1
- package/dist/util/isNodeHidden.js +1 -1
- package/dist/util/metaUrl.js +3 -0
- package/hash.txt +1 -1
- package/lib/generate-version-info/index.js +27 -0
- package/package-scripts.js +3 -1
- package/package.json +3 -3
- package/src/Boot.js +32 -14
- package/src/CustomElementsRegistry.js +60 -4
- package/src/Device.js +6 -0
- package/src/FeaturesRegistry.js +4 -1
- package/src/Keys.js +17 -0
- package/src/Runtimes.js +109 -0
- package/src/StaticAreaItem.js +3 -0
- package/src/UI5Element.js +7 -2
- package/src/UI5ElementMetadata.js +8 -0
- package/src/features/F6Navigation.js +106 -0
- package/src/util/FocusableElements.js +8 -6
- package/src/util/generateHighlightedMarkup.js +1 -1
- package/src/util/isNodeHidden.js +1 -1
- package/src/util/metaUrl.js +3 -0
- package/used-modules.txt +4 -1
- package/dist/util/encodeCSS.js +0 -24
- package/dist/util/encodeXML.js +0 -35
- package/src/util/encodeCSS.js +0 -24
- package/src/util/encodeXML.js +0 -35
|
@@ -0,0 +1,106 @@
|
|
|
1
|
+
import { registerFeature } from "../../dist/FeaturesRegistry.js";
|
|
2
|
+
import { isF6Next, isF6Previous } from "../../dist/Keys.js";
|
|
3
|
+
import { getFirstFocusableElement } from "../../dist/util/FocusableElements.js";
|
|
4
|
+
|
|
5
|
+
class F6Navigation {
|
|
6
|
+
init() {
|
|
7
|
+
this.keydownHandler = this._keydownHandler.bind(this);
|
|
8
|
+
this.attachEventListeners();
|
|
9
|
+
this.selectedGroup = null;
|
|
10
|
+
this.groups = [];
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
attachEventListeners() {
|
|
14
|
+
document.addEventListener("keydown", this.keydownHandler);
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
async _keydownHandler(event) {
|
|
18
|
+
if (isF6Next(event)) {
|
|
19
|
+
this.updateGroups();
|
|
20
|
+
if (this.groups.length < 1) {
|
|
21
|
+
return;
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
const nextIndex = this.groups.indexOf(this.selectedGroup);
|
|
25
|
+
let nextElement = null;
|
|
26
|
+
|
|
27
|
+
if (nextIndex > -1) {
|
|
28
|
+
if (nextIndex + 1 >= this.groups.length) {
|
|
29
|
+
nextElement = this.groups[0];
|
|
30
|
+
} else {
|
|
31
|
+
nextElement = this.groups[nextIndex + 1];
|
|
32
|
+
}
|
|
33
|
+
} else {
|
|
34
|
+
nextElement = this.groups[0];
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
const elementToFocus = await getFirstFocusableElement(nextElement.isUI5Element ? nextElement.getDomRef() : nextElement, true);
|
|
38
|
+
elementToFocus.focus();
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
if (isF6Previous(event)) {
|
|
42
|
+
this.updateGroups();
|
|
43
|
+
if (this.groups.length < 1) {
|
|
44
|
+
return;
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
const nextIndex = this.groups.indexOf(this.selectedGroup);
|
|
48
|
+
let nextElement = null;
|
|
49
|
+
|
|
50
|
+
if (nextIndex > -1) {
|
|
51
|
+
if (nextIndex - 1 < 0) {
|
|
52
|
+
nextElement = this.groups[this.groups.length - 1];
|
|
53
|
+
} else {
|
|
54
|
+
// Handle the situation where the first focusable element of two neighbor groups is the same
|
|
55
|
+
// For example:
|
|
56
|
+
// <ui5-flexible-column-layout>
|
|
57
|
+
// <ui5-list>
|
|
58
|
+
// <ui5-li>List Item</ui5-li>
|
|
59
|
+
// </ui5-list>
|
|
60
|
+
// </ui5-flexible-column-layout>
|
|
61
|
+
// Here for both FCL & List the firstFoccusableElement is the same (the ui5-li)
|
|
62
|
+
|
|
63
|
+
const firstFocusable = await getFirstFocusableElement(this.groups[nextIndex - 1], true);
|
|
64
|
+
const shouldSkipParent = firstFocusable === await getFirstFocusableElement(this.groups[nextIndex], true);
|
|
65
|
+
|
|
66
|
+
nextElement = this.groups[shouldSkipParent ? nextIndex - 2 : nextIndex - 1];
|
|
67
|
+
}
|
|
68
|
+
} else {
|
|
69
|
+
nextElement = this.groups[this.groups.length - 1];
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
const elementToFocus = await getFirstFocusableElement(nextElement.isUI5Element ? nextElement.getDomRef() : nextElement, true);
|
|
73
|
+
elementToFocus.focus();
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
removeEventListeners() {
|
|
78
|
+
document.removeEventListener("keydown", this.keydownHandler);
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
updateGroups() {
|
|
82
|
+
this.setSelectedGroup(document.activeElement);
|
|
83
|
+
this.setGroups();
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
setGroups() {
|
|
87
|
+
this.groups = Array.from(document.querySelectorAll("[data-sap-ui-fastnavgroup='true']")).filter(group => group.clientWidth && window.getComputedStyle(group).visibility !== "hidden");
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
setSelectedGroup(element) {
|
|
91
|
+
while (element && element.getAttribute("data-sap-ui-fastnavgroup") !== "true" && element !== document.querySelector("html")) {
|
|
92
|
+
element = element.parentElement ? element.parentNode : element.parentNode.host;
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
this.selectedGroup = element;
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
destroy() {
|
|
99
|
+
this.removeEventListeners();
|
|
100
|
+
}
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
const F6HelperInstance = new F6Navigation();
|
|
104
|
+
registerFeature("F6Navigation", F6HelperInstance);
|
|
105
|
+
|
|
106
|
+
export default F6Navigation;
|
|
@@ -5,27 +5,27 @@ const isFocusTrap = el => {
|
|
|
5
5
|
return el.hasAttribute("data-ui5-focus-trap");
|
|
6
6
|
};
|
|
7
7
|
|
|
8
|
-
const getFirstFocusableElement = async container => {
|
|
8
|
+
const getFirstFocusableElement = async (container, startFromContainer) => {
|
|
9
9
|
if (!container || isNodeHidden(container)) {
|
|
10
10
|
return null;
|
|
11
11
|
}
|
|
12
12
|
|
|
13
|
-
return findFocusableElement(container, true);
|
|
13
|
+
return findFocusableElement(container, true, startFromContainer);
|
|
14
14
|
};
|
|
15
15
|
|
|
16
|
-
const getLastFocusableElement = async container => {
|
|
16
|
+
const getLastFocusableElement = async (container, startFromContainer) => {
|
|
17
17
|
if (!container || isNodeHidden(container)) {
|
|
18
18
|
return null;
|
|
19
19
|
}
|
|
20
20
|
|
|
21
|
-
return findFocusableElement(container, false);
|
|
21
|
+
return findFocusableElement(container, false, startFromContainer);
|
|
22
22
|
};
|
|
23
23
|
|
|
24
24
|
const isElemFocusable = el => {
|
|
25
25
|
return el.hasAttribute("data-ui5-focus-redirect") || !isNodeHidden(el);
|
|
26
26
|
};
|
|
27
27
|
|
|
28
|
-
const findFocusableElement = async (container, forward) => {
|
|
28
|
+
const findFocusableElement = async (container, forward, startFromContainer) => {
|
|
29
29
|
let child;
|
|
30
30
|
|
|
31
31
|
if (container.shadowRoot) {
|
|
@@ -33,8 +33,10 @@ const findFocusableElement = async (container, forward) => {
|
|
|
33
33
|
} else if (container.assignedNodes && container.assignedNodes()) {
|
|
34
34
|
const assignedElements = container.assignedNodes();
|
|
35
35
|
child = forward ? assignedElements[0] : assignedElements[assignedElements.length - 1];
|
|
36
|
+
} else if (startFromContainer) {
|
|
37
|
+
child = container;
|
|
36
38
|
} else {
|
|
37
|
-
child = forward ? container.
|
|
39
|
+
child = forward ? container.firstElementChild : container.lastElementChild;
|
|
38
40
|
}
|
|
39
41
|
|
|
40
42
|
let focusableDescendant;
|
package/src/util/isNodeHidden.js
CHANGED
|
@@ -3,7 +3,7 @@ const isNodeHidden = node => {
|
|
|
3
3
|
return false;
|
|
4
4
|
}
|
|
5
5
|
|
|
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");
|
|
7
7
|
};
|
|
8
8
|
|
|
9
9
|
export default isNodeHidden;
|
package/used-modules.txt
CHANGED
package/dist/util/encodeCSS.js
DELETED
|
@@ -1,24 +0,0 @@
|
|
|
1
|
-
const rCSS = /[\x00-\x2f\x3a-\x40\x5b-\x60\x7b-\xff\u2028\u2029][0-9A-Fa-f]?/g; // eslint-disable-line
|
|
2
|
-
|
|
3
|
-
const toHex = (iChar, iLength) => {
|
|
4
|
-
let sHex = iChar.toString(16);
|
|
5
|
-
if (iLength) {
|
|
6
|
-
sHex = sHex.padStart(iLength, "0");
|
|
7
|
-
}
|
|
8
|
-
return sHex;
|
|
9
|
-
};
|
|
10
|
-
|
|
11
|
-
const fnCSS = sChar => {
|
|
12
|
-
const iChar = sChar.charCodeAt(0);
|
|
13
|
-
if (sChar.length === 1) {
|
|
14
|
-
return `\\${toHex(iChar)}`;
|
|
15
|
-
}
|
|
16
|
-
|
|
17
|
-
return `\\${toHex(iChar)} ${sChar.substr(1)}`;
|
|
18
|
-
};
|
|
19
|
-
|
|
20
|
-
const encodeCSS = string => {
|
|
21
|
-
return string.replace(rCSS, fnCSS);
|
|
22
|
-
};
|
|
23
|
-
|
|
24
|
-
export default encodeCSS;
|
package/dist/util/encodeXML.js
DELETED
|
@@ -1,35 +0,0 @@
|
|
|
1
|
-
const fnToHex = (iChar, iLength) => {
|
|
2
|
-
let sHex = iChar.toString(16);
|
|
3
|
-
if (iLength) {
|
|
4
|
-
sHex = sHex.padStart(iLength, "0");
|
|
5
|
-
}
|
|
6
|
-
return sHex;
|
|
7
|
-
};
|
|
8
|
-
|
|
9
|
-
const rHtml = /[\x00-\x2b\x2f\x3a-\x40\x5b-\x5e\x60\x7b-\xff\u2028\u2029]/g, // eslint-disable-line no-control-regex
|
|
10
|
-
rHtmlReplace = /[\x00-\x08\x0b\x0c\x0e-\x1f\x7f-\x9f]/, // eslint-disable-line no-control-regex
|
|
11
|
-
mHtmlLookup = {
|
|
12
|
-
"<": "<",
|
|
13
|
-
">": ">",
|
|
14
|
-
"&": "&",
|
|
15
|
-
"\"": """,
|
|
16
|
-
};
|
|
17
|
-
|
|
18
|
-
const fnHtml = sChar => {
|
|
19
|
-
let sEncoded = mHtmlLookup[sChar];
|
|
20
|
-
if (!sEncoded) {
|
|
21
|
-
if (rHtmlReplace.test(sChar)) {
|
|
22
|
-
sEncoded = "�";
|
|
23
|
-
} else {
|
|
24
|
-
sEncoded = `&#x${fnToHex(sChar.charCodeAt(0))};`;
|
|
25
|
-
}
|
|
26
|
-
mHtmlLookup[sChar] = sEncoded;
|
|
27
|
-
}
|
|
28
|
-
return sEncoded;
|
|
29
|
-
};
|
|
30
|
-
|
|
31
|
-
const fnEncodeXML = sString => {
|
|
32
|
-
return sString.replace(rHtml, fnHtml);
|
|
33
|
-
};
|
|
34
|
-
|
|
35
|
-
export default fnEncodeXML;
|
package/src/util/encodeCSS.js
DELETED
|
@@ -1,24 +0,0 @@
|
|
|
1
|
-
const rCSS = /[\x00-\x2f\x3a-\x40\x5b-\x60\x7b-\xff\u2028\u2029][0-9A-Fa-f]?/g; // eslint-disable-line
|
|
2
|
-
|
|
3
|
-
const toHex = (iChar, iLength) => {
|
|
4
|
-
let sHex = iChar.toString(16);
|
|
5
|
-
if (iLength) {
|
|
6
|
-
sHex = sHex.padStart(iLength, "0");
|
|
7
|
-
}
|
|
8
|
-
return sHex;
|
|
9
|
-
};
|
|
10
|
-
|
|
11
|
-
const fnCSS = sChar => {
|
|
12
|
-
const iChar = sChar.charCodeAt(0);
|
|
13
|
-
if (sChar.length === 1) {
|
|
14
|
-
return `\\${toHex(iChar)}`;
|
|
15
|
-
}
|
|
16
|
-
|
|
17
|
-
return `\\${toHex(iChar)} ${sChar.substr(1)}`;
|
|
18
|
-
};
|
|
19
|
-
|
|
20
|
-
const encodeCSS = string => {
|
|
21
|
-
return string.replace(rCSS, fnCSS);
|
|
22
|
-
};
|
|
23
|
-
|
|
24
|
-
export default encodeCSS;
|
package/src/util/encodeXML.js
DELETED
|
@@ -1,35 +0,0 @@
|
|
|
1
|
-
const fnToHex = (iChar, iLength) => {
|
|
2
|
-
let sHex = iChar.toString(16);
|
|
3
|
-
if (iLength) {
|
|
4
|
-
sHex = sHex.padStart(iLength, "0");
|
|
5
|
-
}
|
|
6
|
-
return sHex;
|
|
7
|
-
};
|
|
8
|
-
|
|
9
|
-
const rHtml = /[\x00-\x2b\x2f\x3a-\x40\x5b-\x5e\x60\x7b-\xff\u2028\u2029]/g, // eslint-disable-line no-control-regex
|
|
10
|
-
rHtmlReplace = /[\x00-\x08\x0b\x0c\x0e-\x1f\x7f-\x9f]/, // eslint-disable-line no-control-regex
|
|
11
|
-
mHtmlLookup = {
|
|
12
|
-
"<": "<",
|
|
13
|
-
">": ">",
|
|
14
|
-
"&": "&",
|
|
15
|
-
"\"": """,
|
|
16
|
-
};
|
|
17
|
-
|
|
18
|
-
const fnHtml = sChar => {
|
|
19
|
-
let sEncoded = mHtmlLookup[sChar];
|
|
20
|
-
if (!sEncoded) {
|
|
21
|
-
if (rHtmlReplace.test(sChar)) {
|
|
22
|
-
sEncoded = "�";
|
|
23
|
-
} else {
|
|
24
|
-
sEncoded = `&#x${fnToHex(sChar.charCodeAt(0))};`;
|
|
25
|
-
}
|
|
26
|
-
mHtmlLookup[sChar] = sEncoded;
|
|
27
|
-
}
|
|
28
|
-
return sEncoded;
|
|
29
|
-
};
|
|
30
|
-
|
|
31
|
-
const fnEncodeXML = sString => {
|
|
32
|
-
return sString.replace(rHtml, fnHtml);
|
|
33
|
-
};
|
|
34
|
-
|
|
35
|
-
export default fnEncodeXML;
|