@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
package/.eslintignore
CHANGED
package/CHANGELOG.md
CHANGED
|
@@ -3,6 +3,25 @@
|
|
|
3
3
|
All notable changes to this project will be documented in this file.
|
|
4
4
|
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
|
|
5
5
|
|
|
6
|
+
# [1.1.0](https://github.com/SAP/ui5-webcomponents/compare/v1.0.2...v1.1.0) (2022-01-21)
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
### Bug Fixes
|
|
10
|
+
|
|
11
|
+
* **framework:** correct scoping issues ([#4573](https://github.com/SAP/ui5-webcomponents/issues/4573)) ([4e430d3](https://github.com/SAP/ui5-webcomponents/commit/4e430d3))
|
|
12
|
+
* **framework:** prevent runtime error on malformed custom theme object ([#4375](https://github.com/SAP/ui5-webcomponents/issues/4375)) ([3215c7d](https://github.com/SAP/ui5-webcomponents/commit/3215c7d))
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
### Features
|
|
16
|
+
|
|
17
|
+
* **framework:** implement F6 Navigation Helper ([#4490](https://github.com/SAP/ui5-webcomponents/issues/4490)) ([60d0dc1](https://github.com/SAP/ui5-webcomponents/commit/60d0dc1))
|
|
18
|
+
* **framework:** add support for `stable-dom-ref` for abstract items ([#4604](https://github.com/SAP/ui5-webcomponents/issues/4604)) ([5526dea](https://github.com/SAP/ui5-webcomponents/commit/5526dea))
|
|
19
|
+
* **framework:** introduce runtime and version info ([#4491](https://github.com/SAP/ui5-webcomponents/issues/4491)) ([757577f](https://github.com/SAP/ui5-webcomponents/commit/757577f))
|
|
20
|
+
|
|
21
|
+
|
|
22
|
+
|
|
23
|
+
|
|
24
|
+
|
|
6
25
|
## [1.0.2](https://github.com/SAP/ui5-webcomponents/compare/v1.0.1...v1.0.2) (2021-11-29)
|
|
7
26
|
|
|
8
27
|
|
package/dist/Boot.js
CHANGED
|
@@ -4,9 +4,10 @@ import insertFontFace from "./FontFace.js";
|
|
|
4
4
|
import insertSystemCSSVars from "./SystemCSSVars.js";
|
|
5
5
|
import { getTheme } from "./config/Theme.js";
|
|
6
6
|
import applyTheme from "./theming/applyTheme.js";
|
|
7
|
+
import { registerCurrentRuntime } from "./Runtimes.js";
|
|
7
8
|
import { getFeature } from "./FeaturesRegistry.js";
|
|
8
9
|
|
|
9
|
-
let
|
|
10
|
+
let bootPromise;
|
|
10
11
|
const eventProvider = new EventProvider();
|
|
11
12
|
|
|
12
13
|
/**
|
|
@@ -19,22 +20,39 @@ const attachBoot = listener => {
|
|
|
19
20
|
};
|
|
20
21
|
|
|
21
22
|
const boot = async () => {
|
|
22
|
-
if (
|
|
23
|
-
return;
|
|
23
|
+
if (bootPromise) {
|
|
24
|
+
return bootPromise;
|
|
24
25
|
}
|
|
25
26
|
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
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();
|
|
35
|
+
|
|
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 */
|
|
30
54
|
|
|
31
|
-
|
|
32
|
-
await applyTheme(getTheme());
|
|
33
|
-
OpenUI5Support && OpenUI5Support.attachListeners();
|
|
34
|
-
insertFontFace();
|
|
35
|
-
insertSystemCSSVars();
|
|
36
|
-
await eventProvider.fireEventAsync("boot");
|
|
37
|
-
booted = true;
|
|
55
|
+
return bootPromise;
|
|
38
56
|
};
|
|
39
57
|
|
|
40
58
|
export {
|
|
@@ -1,11 +1,18 @@
|
|
|
1
1
|
import setToArray from "./util/setToArray.js";
|
|
2
|
+
import getSharedResource from "./getSharedResource.js";
|
|
3
|
+
import { getCurrentRuntimeIndex, compareRuntimes, getAllRuntimes } from "./Runtimes.js";
|
|
4
|
+
|
|
5
|
+
const Tags = getSharedResource("Tags", new Map());
|
|
2
6
|
|
|
3
7
|
const Definitions = new Set();
|
|
4
|
-
|
|
8
|
+
let Failures = {};
|
|
5
9
|
let failureTimeout;
|
|
6
10
|
|
|
11
|
+
const UNKNOWN_RUNTIME = "unknown";
|
|
12
|
+
|
|
7
13
|
const registerTag = tag => {
|
|
8
14
|
Definitions.add(tag);
|
|
15
|
+
Tags.set(tag, getCurrentRuntimeIndex());
|
|
9
16
|
};
|
|
10
17
|
|
|
11
18
|
const isTagRegistered = tag => {
|
|
@@ -17,18 +24,67 @@ const getAllRegisteredTags = () => {
|
|
|
17
24
|
};
|
|
18
25
|
|
|
19
26
|
const recordTagRegistrationFailure = tag => {
|
|
20
|
-
|
|
27
|
+
let tagRegRuntimeIndex = Tags.get(tag);
|
|
28
|
+
if (tagRegRuntimeIndex === undefined) {
|
|
29
|
+
tagRegRuntimeIndex = UNKNOWN_RUNTIME; // If the tag is taken, but not registered in Tags, then a version before 1.1.0 defined it => use the "unknown" key
|
|
30
|
+
}
|
|
31
|
+
Failures[tagRegRuntimeIndex] = Failures[tagRegRuntimeIndex] || new Set();
|
|
32
|
+
Failures[tagRegRuntimeIndex].add(tag);
|
|
33
|
+
|
|
21
34
|
if (!failureTimeout) {
|
|
22
35
|
failureTimeout = setTimeout(() => {
|
|
23
36
|
displayFailedRegistrations();
|
|
37
|
+
Failures = {};
|
|
24
38
|
failureTimeout = undefined;
|
|
25
39
|
}, 1000);
|
|
26
40
|
}
|
|
27
41
|
};
|
|
28
42
|
|
|
29
43
|
const displayFailedRegistrations = () => {
|
|
30
|
-
|
|
31
|
-
|
|
44
|
+
const allRuntimes = getAllRuntimes();
|
|
45
|
+
const currentRuntimeIndex = getCurrentRuntimeIndex();
|
|
46
|
+
const currentRuntime = allRuntimes[currentRuntimeIndex];
|
|
47
|
+
|
|
48
|
+
let message = `Multiple UI5 Web Components instances detected.`;
|
|
49
|
+
|
|
50
|
+
if (allRuntimes.length > 1) {
|
|
51
|
+
message = `${message}\nLoading order (versions before 1.1.0 not listed): ${allRuntimes.map(runtime => `\n${runtime.description} ${runtime.url}`).join("")}`;
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
Object.keys(Failures).forEach(otherRuntimeIndex => {
|
|
55
|
+
let comparison;
|
|
56
|
+
let otherRuntime;
|
|
57
|
+
|
|
58
|
+
if (otherRuntimeIndex === UNKNOWN_RUNTIME) { // version < 1.1.0 defined the tag
|
|
59
|
+
comparison = 1; // the current runtime is considered newer
|
|
60
|
+
otherRuntime = {
|
|
61
|
+
description: `Older unknown runtime`,
|
|
62
|
+
};
|
|
63
|
+
} else {
|
|
64
|
+
comparison = compareRuntimes(currentRuntimeIndex, otherRuntimeIndex);
|
|
65
|
+
otherRuntime = allRuntimes[otherRuntimeIndex];
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
let compareWord;
|
|
69
|
+
if (comparison > 0) {
|
|
70
|
+
compareWord = "an older";
|
|
71
|
+
} else if (comparison < 0) {
|
|
72
|
+
compareWord = "a newer";
|
|
73
|
+
} else {
|
|
74
|
+
compareWord = "the same";
|
|
75
|
+
}
|
|
76
|
+
message = `${message}\n\n"${currentRuntime.description}" failed to define ${Failures[otherRuntimeIndex].size} tag(s) as they were defined by a runtime of ${compareWord} version "${otherRuntime.description}": ${setToArray(Failures[otherRuntimeIndex]).sort().join(", ")}.`;
|
|
77
|
+
|
|
78
|
+
if (comparison > 0) {
|
|
79
|
+
message = `${message}\nWARNING! If your code uses features of the above web components, unavailable in ${otherRuntime.description}, it might not work as expected!`;
|
|
80
|
+
} else {
|
|
81
|
+
message = `${message}\nSince the above web components were defined by the same or newer version runtime, they should be compatible with your code.`;
|
|
82
|
+
}
|
|
83
|
+
});
|
|
84
|
+
|
|
85
|
+
message = `${message}\n\nTo prevent other runtimes from defining tags that you use, consider using scoping or have third-party libraries use scoping: https://github.com/SAP/ui5-webcomponents/blob/master/docs/2-advanced/03-scoping.md.`;
|
|
86
|
+
|
|
87
|
+
console.warn(message); // eslint-disable-line
|
|
32
88
|
};
|
|
33
89
|
|
|
34
90
|
export {
|
package/dist/Device.js
CHANGED
|
@@ -5,6 +5,7 @@ const chrome = !ie && /(Chrome|CriOS)/.test(ua);
|
|
|
5
5
|
const safari = !ie && !chrome && /(Version|PhantomJS)\/(\d+\.\d+).*Safari/.test(ua);
|
|
6
6
|
const webkit = !ie && /webkit/.test(ua);
|
|
7
7
|
const windows = navigator.platform.indexOf("Win") !== -1;
|
|
8
|
+
const iOS = navigator.platform.match(/iPhone|iPad|iPod/) || (navigator.userAgent.match(/Mac/) && "ontouchend" in document);
|
|
8
9
|
const android = !windows && /Android/.test(ua);
|
|
9
10
|
const androidPhone = android && /(?=android)(?=.*mobile)/i.test(ua);
|
|
10
11
|
const ipad = /ipad/i.test(ua);
|
|
@@ -95,6 +96,10 @@ const isCombi = () => {
|
|
|
95
96
|
return isTablet() && isDesktop();
|
|
96
97
|
};
|
|
97
98
|
|
|
99
|
+
const isIOS = () => {
|
|
100
|
+
return iOS;
|
|
101
|
+
};
|
|
102
|
+
|
|
98
103
|
export {
|
|
99
104
|
supportsTouch,
|
|
100
105
|
isIE,
|
|
@@ -104,4 +109,5 @@ export {
|
|
|
104
109
|
isTablet,
|
|
105
110
|
isDesktop,
|
|
106
111
|
isCombi,
|
|
112
|
+
isIOS,
|
|
107
113
|
};
|
package/dist/FeaturesRegistry.js
CHANGED
package/dist/Keys.js
CHANGED
|
@@ -131,6 +131,10 @@ const isUpShift = event => (event.key ? (event.key === "ArrowUp" || event.key ==
|
|
|
131
131
|
|
|
132
132
|
const isDownShift = event => (event.key ? (event.key === "ArrowDown" || event.key === "Down") : event.keyCode === KeyCodes.ARROW_DOWN) && checkModifierKeys(event, false, false, true);
|
|
133
133
|
|
|
134
|
+
const isUpAlt = event => (event.key ? (event.key === "ArrowUp" || event.key === "Up") : event.keyCode === KeyCodes.ARROW_UP) && checkModifierKeys(event, false, true, false);
|
|
135
|
+
|
|
136
|
+
const isDownAlt = event => (event.key ? (event.key === "ArrowDown" || event.key === "Down") : event.keyCode === KeyCodes.ARROW_DOWN) && checkModifierKeys(event, false, true, false);
|
|
137
|
+
|
|
134
138
|
const isLeftShift = event => (event.key ? (event.key === "ArrowLeft" || event.key === "Left") : event.keyCode === KeyCodes.ARROW_LEFT) && checkModifierKeys(event, false, false, true);
|
|
135
139
|
|
|
136
140
|
const isRightShift = event => (event.key ? (event.key === "ArrowRight" || event.key === "Right") : event.keyCode === KeyCodes.ARROW_RIGHT) && checkModifierKeys(event, false, false, true);
|
|
@@ -191,12 +195,20 @@ const isF4 = event => {
|
|
|
191
195
|
|
|
192
196
|
const isF4Shift = event => (event.key ? event.key === "F4" : event.keyCode === KeyCodes.F4) && checkModifierKeys(event, false, false, true);
|
|
193
197
|
|
|
198
|
+
const isF6Next = event => ((event.key ? event.key === "F6" : event.keyCode === KeyCodes.F6) && checkModifierKeys(event, false, false, false))
|
|
199
|
+
|| ((event.key ? (event.key === "ArrowDown" || event.key === "Down") : event.keyCode === KeyCodes.ARROW_DOWN) && checkModifierKeys(event, true, true, false));
|
|
200
|
+
|
|
201
|
+
const isF6Previous = event => ((event.key ? event.key === "F6" : event.keyCode === KeyCodes.F6) && checkModifierKeys(event, false, false, true))
|
|
202
|
+
|| ((event.key ? (event.key === "ArrowUp" || event.key === "Up") : event.keyCode === KeyCodes.ARROW_Up) && checkModifierKeys(event, true, true, false));
|
|
203
|
+
|
|
194
204
|
const isF7 = event => (event.key ? event.key === "F7" : event.keyCode === KeyCodes.F7) && !hasModifierKeys(event);
|
|
195
205
|
|
|
196
206
|
const isShowByArrows = event => {
|
|
197
207
|
return ((event.key === "ArrowDown" || event.key === "Down") || (event.key === "ArrowUp" || event.key === "Up")) && checkModifierKeys(event, /* Ctrl */ false, /* Alt */ true, /* Shift */ false);
|
|
198
208
|
};
|
|
199
209
|
|
|
210
|
+
const isShift = event => event.key === "Shift" || event.keyCode === KeyCodes.SHIFT;
|
|
211
|
+
|
|
200
212
|
const hasModifierKeys = event => event.shiftKey || event.altKey || getCtrlKey(event);
|
|
201
213
|
|
|
202
214
|
const getCtrlKey = event => !!(event.metaKey || event.ctrlKey); // double negation doesn't have effect on boolean but ensures null and undefined are equivalent to false.
|
|
@@ -218,6 +230,8 @@ export {
|
|
|
218
230
|
isDownCtrl,
|
|
219
231
|
isUpShift,
|
|
220
232
|
isDownShift,
|
|
233
|
+
isUpAlt,
|
|
234
|
+
isDownAlt,
|
|
221
235
|
isLeftShift,
|
|
222
236
|
isRightShift,
|
|
223
237
|
isUpShiftCtrl,
|
|
@@ -236,6 +250,8 @@ export {
|
|
|
236
250
|
isShow,
|
|
237
251
|
isF4,
|
|
238
252
|
isF4Shift,
|
|
253
|
+
isF6Previous,
|
|
254
|
+
isF6Next,
|
|
239
255
|
isF7,
|
|
240
256
|
isPageUp,
|
|
241
257
|
isPageDown,
|
|
@@ -245,4 +261,5 @@ export {
|
|
|
245
261
|
isPageDownAlt,
|
|
246
262
|
isPageUpShiftCtrl,
|
|
247
263
|
isPageDownShiftCtrl,
|
|
264
|
+
isShift,
|
|
248
265
|
};
|
package/dist/Runtimes.js
ADDED
|
@@ -0,0 +1,109 @@
|
|
|
1
|
+
import VersionInfo from "./generated/VersionInfo.js";
|
|
2
|
+
import getSharedResource from "./getSharedResource.js";
|
|
3
|
+
import metaUrl from "./util/metaUrl.js"; // eslint-disable-line
|
|
4
|
+
|
|
5
|
+
let currentRuntimeIndex;
|
|
6
|
+
let currentRuntimeAlias = "";
|
|
7
|
+
|
|
8
|
+
const compareCache = new Map();
|
|
9
|
+
|
|
10
|
+
/**
|
|
11
|
+
* Central registry where all runtimes register themselves by pushing an object.
|
|
12
|
+
* The index in the registry servers as an ID for the runtime.
|
|
13
|
+
* @type {*}
|
|
14
|
+
*/
|
|
15
|
+
const Runtimes = getSharedResource("Runtimes", []);
|
|
16
|
+
|
|
17
|
+
/**
|
|
18
|
+
* Registers the current runtime in the shared runtimes resource registry
|
|
19
|
+
*/
|
|
20
|
+
const registerCurrentRuntime = () => {
|
|
21
|
+
if (currentRuntimeIndex === undefined) {
|
|
22
|
+
currentRuntimeIndex = Runtimes.length;
|
|
23
|
+
Runtimes.push({
|
|
24
|
+
...VersionInfo,
|
|
25
|
+
url: metaUrl,
|
|
26
|
+
alias: currentRuntimeAlias,
|
|
27
|
+
description: `Runtime ${currentRuntimeIndex} - ver ${VersionInfo.version}${currentRuntimeAlias ? ` (${currentRuntimeAlias})` : ""}`,
|
|
28
|
+
});
|
|
29
|
+
}
|
|
30
|
+
};
|
|
31
|
+
|
|
32
|
+
/**
|
|
33
|
+
* Returns the index of the current runtime's object in the shared runtimes resource registry
|
|
34
|
+
* @returns {*}
|
|
35
|
+
*/
|
|
36
|
+
const getCurrentRuntimeIndex = () => {
|
|
37
|
+
return currentRuntimeIndex;
|
|
38
|
+
};
|
|
39
|
+
|
|
40
|
+
/**
|
|
41
|
+
* Compares two runtimes and returns 1 if the first is of a bigger version, -1 if the second is of a bigger version, and 0 if equal
|
|
42
|
+
* @param index1 The index of the first runtime to compare
|
|
43
|
+
* @param index2 The index of the second runtime to compare
|
|
44
|
+
* @returns {number}
|
|
45
|
+
*/
|
|
46
|
+
const compareRuntimes = (index1, index2) => {
|
|
47
|
+
const cacheIndex = `${index1},${index2}`;
|
|
48
|
+
if (compareCache.has(cacheIndex)) {
|
|
49
|
+
return compareCache.get(cacheIndex);
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
const runtime1 = Runtimes[index1];
|
|
53
|
+
const runtime2 = Runtimes[index2];
|
|
54
|
+
|
|
55
|
+
if (!runtime1 || !runtime2) {
|
|
56
|
+
throw new Error("Invalid runtime index supplied");
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
// If any of the two is a next version, bigger buildTime wins
|
|
60
|
+
if (runtime1.isNext || runtime2.isNext) {
|
|
61
|
+
return runtime1.buildTime - runtime2.buildTime;
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
// If major versions differ, bigger one wins
|
|
65
|
+
const majorDiff = runtime1.major - runtime2.major;
|
|
66
|
+
if (majorDiff) {
|
|
67
|
+
return majorDiff;
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
// If minor versions differ, bigger one wins
|
|
71
|
+
const minorDiff = runtime1.minor - runtime2.minor;
|
|
72
|
+
if (minorDiff) {
|
|
73
|
+
return minorDiff;
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
// If patch versions differ, bigger one wins
|
|
77
|
+
const patchDiff = runtime1.patch - runtime2.patch;
|
|
78
|
+
if (patchDiff) {
|
|
79
|
+
return patchDiff;
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
// Bigger suffix wins, f.e. rc10 > rc9
|
|
83
|
+
// Important: suffix is alphanumeric, must use natural compare
|
|
84
|
+
const collator = new Intl.Collator(undefined, { numeric: true, sensitivity: "base" });
|
|
85
|
+
const result = collator.compare(runtime1.suffix, runtime2.suffix);
|
|
86
|
+
|
|
87
|
+
compareCache.set(cacheIndex, result);
|
|
88
|
+
return result;
|
|
89
|
+
};
|
|
90
|
+
|
|
91
|
+
/**
|
|
92
|
+
* Set an alias for the the current app/library/microfrontend which will appear in debug messages and console warnings
|
|
93
|
+
* @param alias
|
|
94
|
+
*/
|
|
95
|
+
const setRuntimeAlias = alias => {
|
|
96
|
+
currentRuntimeAlias = alias;
|
|
97
|
+
};
|
|
98
|
+
|
|
99
|
+
const getAllRuntimes = () => {
|
|
100
|
+
return Runtimes;
|
|
101
|
+
};
|
|
102
|
+
|
|
103
|
+
export {
|
|
104
|
+
getCurrentRuntimeIndex,
|
|
105
|
+
registerCurrentRuntime,
|
|
106
|
+
compareRuntimes,
|
|
107
|
+
setRuntimeAlias,
|
|
108
|
+
getAllRuntimes,
|
|
109
|
+
};
|
package/dist/StaticAreaItem.js
CHANGED
|
@@ -25,6 +25,9 @@ class StaticAreaItem extends HTMLElement {
|
|
|
25
25
|
setOwnerElement(ownerElement) {
|
|
26
26
|
this.ownerElement = ownerElement;
|
|
27
27
|
this.classList.add(this.ownerElement._id); // used for getting the popover in the tests
|
|
28
|
+
if (this.ownerElement.hasAttribute("data-ui5-static-stable")) {
|
|
29
|
+
this.setAttribute("data-ui5-stable", this.ownerElement.getAttribute("data-ui5-static-stable")); // stable selector
|
|
30
|
+
}
|
|
28
31
|
}
|
|
29
32
|
|
|
30
33
|
/**
|
package/dist/UI5Element.js
CHANGED
|
@@ -101,6 +101,9 @@ class UI5Element extends HTMLElement {
|
|
|
101
101
|
*/
|
|
102
102
|
async connectedCallback() {
|
|
103
103
|
this.setAttribute(this.constructor.getMetadata().getPureTag(), "");
|
|
104
|
+
if (this.constructor.getMetadata().supportsF6FastNavigation()) {
|
|
105
|
+
this.setAttribute("data-sap-ui-fastnavgroup", "true");
|
|
106
|
+
}
|
|
104
107
|
|
|
105
108
|
const slotsAreManaged = this.constructor.getMetadata().slotsAreManaged();
|
|
106
109
|
|
|
@@ -251,7 +254,8 @@ class UI5Element extends HTMLElement {
|
|
|
251
254
|
|
|
252
255
|
// Listen for any invalidation on the child if invalidateOnChildChange is true or an object (ignore when false or not set)
|
|
253
256
|
if (child.isUI5Element && slotData.invalidateOnChildChange) {
|
|
254
|
-
child.attachInvalidate
|
|
257
|
+
const method = (child.attachInvalidate || child._attachChange).bind(child);
|
|
258
|
+
method(this._getChildChangeListener(slotName));
|
|
255
259
|
}
|
|
256
260
|
|
|
257
261
|
// Listen for the slotchange event if the child is a slot itself
|
|
@@ -311,7 +315,8 @@ class UI5Element extends HTMLElement {
|
|
|
311
315
|
|
|
312
316
|
children.forEach(child => {
|
|
313
317
|
if (child && child.isUI5Element) {
|
|
314
|
-
child.detachInvalidate
|
|
318
|
+
const method = (child.detachInvalidate || child._detachChange).bind(child);
|
|
319
|
+
method(this._getChildChangeListener(slotName));
|
|
315
320
|
}
|
|
316
321
|
|
|
317
322
|
if (isSlot(child)) {
|
|
@@ -188,6 +188,14 @@ class UI5ElementMetadata {
|
|
|
188
188
|
return !!this.metadata.managedSlots;
|
|
189
189
|
}
|
|
190
190
|
|
|
191
|
+
/**
|
|
192
|
+
* Determines whether this control supports F6 fast navigation
|
|
193
|
+
* @public
|
|
194
|
+
*/
|
|
195
|
+
supportsF6FastNavigation() {
|
|
196
|
+
return !!this.metadata.fastNavigation;
|
|
197
|
+
}
|
|
198
|
+
|
|
191
199
|
/**
|
|
192
200
|
* Returns an object with key-value pairs of properties and their metadata definitions
|
|
193
201
|
* @public
|
|
@@ -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;
|