@ui5/webcomponents-base 1.0.1 → 1.1.2
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 +55 -0
- package/dist/Boot.js +32 -14
- package/dist/CustomElementsRegistry.js +60 -4
- package/dist/Device.js +10 -1
- package/dist/FeaturesRegistry.js +4 -1
- package/dist/Keys.js +23 -0
- package/dist/Runtimes.js +107 -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/theming/applyTheme.js +8 -4
- package/dist/theming/getThemeDesignerTheme.js +24 -5
- package/dist/util/FocusableElements.js +8 -6
- package/dist/util/generateHighlightedMarkup.js +1 -1
- package/dist/util/isNodeHidden.js +1 -1
- 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 +10 -1
- package/src/FeaturesRegistry.js +4 -1
- package/src/Keys.js +23 -0
- package/src/Runtimes.js +107 -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/theming/applyTheme.js +8 -4
- package/src/theming/getThemeDesignerTheme.js +24 -5
- package/src/util/FocusableElements.js +8 -6
- package/src/util/generateHighlightedMarkup.js +1 -1
- package/src/util/isNodeHidden.js +1 -1
- 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,14 @@
|
|
|
1
|
+
import toHex from '../strings/toHex.js';
|
|
2
|
+
var rCSS = /[\x00-\x2f\x3a-\x40\x5b-\x60\x7b-\xff\u2028\u2029][0-9A-Fa-f]?/g;
|
|
3
|
+
var fnCSS = function (sChar) {
|
|
4
|
+
var iChar = sChar.charCodeAt(0);
|
|
5
|
+
if (sChar.length === 1) {
|
|
6
|
+
return '\\' + toHex(iChar);
|
|
7
|
+
} else {
|
|
8
|
+
return '\\' + toHex(iChar) + ' ' + sChar.substr(1);
|
|
9
|
+
}
|
|
10
|
+
};
|
|
11
|
+
var fnEncodeCSS = function (sString) {
|
|
12
|
+
return sString.replace(rCSS, fnCSS);
|
|
13
|
+
};
|
|
14
|
+
export default fnEncodeCSS;
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
import toHex from '../strings/toHex.js';
|
|
2
|
+
var rHtml = /[\x00-\x2b\x2f\x3a-\x40\x5b-\x5e\x60\x7b-\xff\u2028\u2029]/g, rHtmlReplace = /[\x00-\x08\x0b\x0c\x0e-\x1f\x7f-\x9f]/, mHtmlLookup = {
|
|
3
|
+
'<': '<',
|
|
4
|
+
'>': '>',
|
|
5
|
+
'&': '&',
|
|
6
|
+
'"': '"'
|
|
7
|
+
};
|
|
8
|
+
var fnHtml = function (sChar) {
|
|
9
|
+
var sEncoded = mHtmlLookup[sChar];
|
|
10
|
+
if (!sEncoded) {
|
|
11
|
+
if (rHtmlReplace.test(sChar)) {
|
|
12
|
+
sEncoded = '�';
|
|
13
|
+
} else {
|
|
14
|
+
sEncoded = '&#x' + toHex(sChar.charCodeAt(0)) + ';';
|
|
15
|
+
}
|
|
16
|
+
mHtmlLookup[sChar] = sEncoded;
|
|
17
|
+
}
|
|
18
|
+
return sEncoded;
|
|
19
|
+
};
|
|
20
|
+
var fnEncodeXML = function (sString) {
|
|
21
|
+
return sString.replace(rHtml, fnHtml);
|
|
22
|
+
};
|
|
23
|
+
export default fnEncodeXML;
|
|
@@ -16,8 +16,10 @@ const loadThemeBase = async theme => {
|
|
|
16
16
|
return;
|
|
17
17
|
}
|
|
18
18
|
|
|
19
|
-
const
|
|
20
|
-
|
|
19
|
+
const cssData = await getThemeProperties(BASE_THEME_PACKAGE, theme);
|
|
20
|
+
if (cssData) {
|
|
21
|
+
createOrUpdateStyle(cssData, "data-ui5-theme-properties", BASE_THEME_PACKAGE);
|
|
22
|
+
}
|
|
21
23
|
};
|
|
22
24
|
|
|
23
25
|
const deleteThemeBase = () => {
|
|
@@ -31,8 +33,10 @@ const loadComponentPackages = async theme => {
|
|
|
31
33
|
return;
|
|
32
34
|
}
|
|
33
35
|
|
|
34
|
-
const
|
|
35
|
-
|
|
36
|
+
const cssData = await getThemeProperties(packageName, theme);
|
|
37
|
+
if (cssData) {
|
|
38
|
+
createOrUpdateStyle(cssData, "data-ui5-theme-properties", packageName);
|
|
39
|
+
}
|
|
36
40
|
});
|
|
37
41
|
};
|
|
38
42
|
|
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
const warnings = new Set();
|
|
2
|
+
|
|
1
3
|
const getThemeMetadata = () => {
|
|
2
4
|
// Check if the class was already applied, most commonly to the link/style tag with the CSS Variables
|
|
3
5
|
let el = document.querySelector(".sapThemeMetaData-Base-baseLib") || document.querySelector(".sapThemeMetaData-UI5-sap-ui-core");
|
|
@@ -7,10 +9,18 @@ const getThemeMetadata = () => {
|
|
|
7
9
|
|
|
8
10
|
el = document.createElement("span");
|
|
9
11
|
el.style.display = "none";
|
|
12
|
+
|
|
13
|
+
// Try with sapThemeMetaData-Base-baseLib first
|
|
10
14
|
el.classList.add("sapThemeMetaData-Base-baseLib");
|
|
11
|
-
el.classList.add("sapThemeMetaData-UI5-sap-ui-core");
|
|
12
15
|
document.body.appendChild(el);
|
|
13
|
-
|
|
16
|
+
let metadata = getComputedStyle(el).backgroundImage;
|
|
17
|
+
|
|
18
|
+
// Try with sapThemeMetaData-UI5-sap-ui-core only if the previous selector was not found
|
|
19
|
+
if (metadata === "none") {
|
|
20
|
+
el.classList.add("sapThemeMetaData-UI5-sap-ui-core");
|
|
21
|
+
metadata = getComputedStyle(el).backgroundImage;
|
|
22
|
+
}
|
|
23
|
+
|
|
14
24
|
document.body.removeChild(el);
|
|
15
25
|
|
|
16
26
|
return metadata;
|
|
@@ -25,14 +35,20 @@ const parseThemeMetadata = metadataString => {
|
|
|
25
35
|
try {
|
|
26
36
|
paramsString = decodeURIComponent(paramsString);
|
|
27
37
|
} catch (ex) {
|
|
28
|
-
|
|
38
|
+
if (!warnings.has("decode")) {
|
|
39
|
+
console.warn("Malformed theme metadata string, unable to decodeURIComponent"); // eslint-disable-line
|
|
40
|
+
warnings.add("decode");
|
|
41
|
+
}
|
|
29
42
|
return;
|
|
30
43
|
}
|
|
31
44
|
}
|
|
32
45
|
try {
|
|
33
46
|
return JSON.parse(paramsString);
|
|
34
47
|
} catch (ex) {
|
|
35
|
-
|
|
48
|
+
if (!warnings.has("parse")) {
|
|
49
|
+
console.warn("Malformed theme metadata string, unable to parse JSON"); // eslint-disable-line
|
|
50
|
+
warnings.add("parse");
|
|
51
|
+
}
|
|
36
52
|
}
|
|
37
53
|
}
|
|
38
54
|
};
|
|
@@ -45,7 +61,10 @@ const processThemeMetadata = metadata => {
|
|
|
45
61
|
themeName = metadata.Path.match(/\.([^.]+)\.css_variables$/)[1];
|
|
46
62
|
baseThemeName = metadata.Extends[0];
|
|
47
63
|
} catch (ex) {
|
|
48
|
-
|
|
64
|
+
if (!warnings.has("object")) {
|
|
65
|
+
console.warn("Malformed theme metadata Object", metadata); // eslint-disable-line
|
|
66
|
+
warnings.add("object");
|
|
67
|
+
}
|
|
49
68
|
return;
|
|
50
69
|
}
|
|
51
70
|
|
|
@@ -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;
|
|
@@ -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/hash.txt
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
|
|
1
|
+
8tp6F3Mz0kW7xUTtxVN0BiPw7WM=
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
const fs = require('fs');
|
|
2
|
+
const mkdirp = require('mkdirp');
|
|
3
|
+
|
|
4
|
+
const version = JSON.parse(fs.readFileSync("package.json")).version;
|
|
5
|
+
|
|
6
|
+
// Parse version
|
|
7
|
+
const matches = version.match(/^([0-9]+)\.([0-9]+)\.([0-9]+)(.*)$/);
|
|
8
|
+
if (!matches) {
|
|
9
|
+
throw new Error("Unsupported version format");
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
const isNext = version.match(/[a-f0-9]{9}$/);
|
|
13
|
+
const buildTime = Math.floor(new Date().getTime() / 1000);
|
|
14
|
+
|
|
15
|
+
const fileContent = `const VersionInfo = {
|
|
16
|
+
version: "${version}",
|
|
17
|
+
major: ${matches[1]},
|
|
18
|
+
minor: ${matches[2]},
|
|
19
|
+
patch: ${matches[3]},
|
|
20
|
+
suffix: "${matches[4]}",
|
|
21
|
+
isNext: ${isNext ? "true" : "false"},
|
|
22
|
+
buildTime: ${buildTime},
|
|
23
|
+
};
|
|
24
|
+
export default VersionInfo;`;
|
|
25
|
+
|
|
26
|
+
mkdirp.sync("dist/generated/");
|
|
27
|
+
fs.writeFileSync("dist/generated/VersionInfo.js", fileContent);
|
package/package-scripts.js
CHANGED
|
@@ -2,6 +2,7 @@ const resolve = require("resolve");
|
|
|
2
2
|
|
|
3
3
|
const assetParametersScript = resolve.sync("@ui5/webcomponents-base/lib/generate-asset-parameters/index.js");
|
|
4
4
|
const stylesScript = resolve.sync("@ui5/webcomponents-base/lib/generate-styles/index.js");
|
|
5
|
+
const versionScript = resolve.sync("@ui5/webcomponents-base/lib/generate-version-info/index.js");
|
|
5
6
|
const serve = resolve.sync("@ui5/webcomponents-tools/lib/serve/index.js");
|
|
6
7
|
const generateHash = resolve.sync("@ui5/webcomponents-tools/lib/hash/generate.js");
|
|
7
8
|
const hashIsUpToDate = resolve.sync("@ui5/webcomponents-tools/lib/hash/upToDate.js");
|
|
@@ -13,7 +14,7 @@ const UP_TO_DATE = `node "${hashIsUpToDate}" dist/ hash.txt && echo "Up to date.
|
|
|
13
14
|
const scripts = {
|
|
14
15
|
clean: "rimraf dist && rimraf .port",
|
|
15
16
|
lint: "eslint . --config config/.eslintrc.js",
|
|
16
|
-
prepare: "nps clean integrate copy generateAssetParameters generateStyles",
|
|
17
|
+
prepare: "nps clean integrate copy generateAssetParameters generateVersionInfo generateStyles",
|
|
17
18
|
integrate: {
|
|
18
19
|
default: "nps integrate.copy-used-modules integrate.copy-overlay integrate.replace-amd integrate.replace-export-true integrate.replace-export-false integrate.amd-to-es6 integrate.replace-global-core-usage integrate.esm-abs-to-rel integrate.third-party",
|
|
19
20
|
"copy-used-modules": `node "${copyUsedModules}" ./used-modules.txt dist/`,
|
|
@@ -40,6 +41,7 @@ const scripts = {
|
|
|
40
41
|
test: `copy-and-watch "test/**/*.*" dist/test-resources`,
|
|
41
42
|
},
|
|
42
43
|
generateAssetParameters: `node "${assetParametersScript}"`,
|
|
44
|
+
generateVersionInfo: `node "${versionScript}"`,
|
|
43
45
|
generateStyles: `node "${stylesScript}"`,
|
|
44
46
|
watch: {
|
|
45
47
|
default: 'concurrently "nps watch.test" "nps watch.src" "nps watch.bundle" "nps watch.styles"',
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@ui5/webcomponents-base",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.1.2",
|
|
4
4
|
"description": "UI5 Web Components: webcomponents.base",
|
|
5
5
|
"author": "SAP SE (https://www.sap.com)",
|
|
6
6
|
"license": "Apache-2.0",
|
|
@@ -37,8 +37,8 @@
|
|
|
37
37
|
"devDependencies": {
|
|
38
38
|
"@buxlabs/amd-to-es6": "0.16.1",
|
|
39
39
|
"@openui5/sap.ui.core": "1.94.0",
|
|
40
|
-
"@ui5/webcomponents-tools": "1.
|
|
41
|
-
"chromedriver": "
|
|
40
|
+
"@ui5/webcomponents-tools": "1.1.2",
|
|
41
|
+
"chromedriver": "96.0.0",
|
|
42
42
|
"clean-css": "^5.2.2",
|
|
43
43
|
"copy-and-watch": "^0.1.5",
|
|
44
44
|
"eslint": "^7.22.0",
|
package/src/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}`).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/src/Device.js
CHANGED
|
@@ -5,9 +5,13 @@ 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
|
-
const ipad = /ipad/i.test(ua);
|
|
11
|
+
const ipad = /ipad/i.test(ua) || (/Macintosh/i.test(ua) && "ontouchend" in document);
|
|
12
|
+
// With iOS 13 the string 'iPad' was removed from the user agent string through a browser setting, which is applied on all sites by default:
|
|
13
|
+
// "Request Desktop Website -> All websites" (for more infos see: https://forums.developer.apple.com/thread/119186).
|
|
14
|
+
// Therefore the OS is detected as MACINTOSH instead of iOS and the device is a tablet if the Device.support.touch is true.
|
|
11
15
|
|
|
12
16
|
let windowsVersion;
|
|
13
17
|
let webkitVersion;
|
|
@@ -95,6 +99,10 @@ const isCombi = () => {
|
|
|
95
99
|
return isTablet() && isDesktop();
|
|
96
100
|
};
|
|
97
101
|
|
|
102
|
+
const isIOS = () => {
|
|
103
|
+
return iOS;
|
|
104
|
+
};
|
|
105
|
+
|
|
98
106
|
export {
|
|
99
107
|
supportsTouch,
|
|
100
108
|
isIE,
|
|
@@ -104,4 +112,5 @@ export {
|
|
|
104
112
|
isTablet,
|
|
105
113
|
isDesktop,
|
|
106
114
|
isCombi,
|
|
115
|
+
isIOS,
|
|
107
116
|
};
|
package/src/FeaturesRegistry.js
CHANGED
package/src/Keys.js
CHANGED
|
@@ -131,10 +131,18 @@ 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);
|
|
137
141
|
|
|
142
|
+
const isLeftShiftCtrl = event => (event.key ? (event.key === "ArrowLeft" || event.key === "Left") : event.keyCode === KeyCodes.ARROW_LEFT) && checkModifierKeys(event, true, false, true);
|
|
143
|
+
|
|
144
|
+
const isRightShiftCtrl = event => (event.key ? (event.key === "ArrowRight" || event.key === "Right") : event.keyCode === KeyCodes.ARROW_RIGHT) && checkModifierKeys(event, true, false, true);
|
|
145
|
+
|
|
138
146
|
const isUpShiftCtrl = event => (event.key ? (event.key === "ArrowUp" || event.key === "Up") : event.keyCode === KeyCodes.ARROW_UP) && checkModifierKeys(event, true, false, true);
|
|
139
147
|
|
|
140
148
|
const isDownShiftCtrl = event => (event.key ? (event.key === "ArrowDown" || event.key === "Down") : event.keyCode === KeyCodes.ARROW_DOWN) && checkModifierKeys(event, true, false, true);
|
|
@@ -191,12 +199,20 @@ const isF4 = event => {
|
|
|
191
199
|
|
|
192
200
|
const isF4Shift = event => (event.key ? event.key === "F4" : event.keyCode === KeyCodes.F4) && checkModifierKeys(event, false, false, true);
|
|
193
201
|
|
|
202
|
+
const isF6Next = event => ((event.key ? event.key === "F6" : event.keyCode === KeyCodes.F6) && checkModifierKeys(event, false, false, false))
|
|
203
|
+
|| ((event.key ? (event.key === "ArrowDown" || event.key === "Down") : event.keyCode === KeyCodes.ARROW_DOWN) && checkModifierKeys(event, true, true, false));
|
|
204
|
+
|
|
205
|
+
const isF6Previous = event => ((event.key ? event.key === "F6" : event.keyCode === KeyCodes.F6) && checkModifierKeys(event, false, false, true))
|
|
206
|
+
|| ((event.key ? (event.key === "ArrowUp" || event.key === "Up") : event.keyCode === KeyCodes.ARROW_Up) && checkModifierKeys(event, true, true, false));
|
|
207
|
+
|
|
194
208
|
const isF7 = event => (event.key ? event.key === "F7" : event.keyCode === KeyCodes.F7) && !hasModifierKeys(event);
|
|
195
209
|
|
|
196
210
|
const isShowByArrows = event => {
|
|
197
211
|
return ((event.key === "ArrowDown" || event.key === "Down") || (event.key === "ArrowUp" || event.key === "Up")) && checkModifierKeys(event, /* Ctrl */ false, /* Alt */ true, /* Shift */ false);
|
|
198
212
|
};
|
|
199
213
|
|
|
214
|
+
const isShift = event => event.key === "Shift" || event.keyCode === KeyCodes.SHIFT;
|
|
215
|
+
|
|
200
216
|
const hasModifierKeys = event => event.shiftKey || event.altKey || getCtrlKey(event);
|
|
201
217
|
|
|
202
218
|
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,8 +234,12 @@ export {
|
|
|
218
234
|
isDownCtrl,
|
|
219
235
|
isUpShift,
|
|
220
236
|
isDownShift,
|
|
237
|
+
isUpAlt,
|
|
238
|
+
isDownAlt,
|
|
221
239
|
isLeftShift,
|
|
222
240
|
isRightShift,
|
|
241
|
+
isLeftShiftCtrl,
|
|
242
|
+
isRightShiftCtrl,
|
|
223
243
|
isUpShiftCtrl,
|
|
224
244
|
isDownShiftCtrl,
|
|
225
245
|
isHome,
|
|
@@ -236,6 +256,8 @@ export {
|
|
|
236
256
|
isShow,
|
|
237
257
|
isF4,
|
|
238
258
|
isF4Shift,
|
|
259
|
+
isF6Previous,
|
|
260
|
+
isF6Next,
|
|
239
261
|
isF7,
|
|
240
262
|
isPageUp,
|
|
241
263
|
isPageDown,
|
|
@@ -245,4 +267,5 @@ export {
|
|
|
245
267
|
isPageDownAlt,
|
|
246
268
|
isPageUpShiftCtrl,
|
|
247
269
|
isPageDownShiftCtrl,
|
|
270
|
+
isShift,
|
|
248
271
|
};
|
package/src/Runtimes.js
ADDED
|
@@ -0,0 +1,107 @@
|
|
|
1
|
+
import VersionInfo from "./generated/VersionInfo.js";
|
|
2
|
+
import getSharedResource from "./getSharedResource.js";
|
|
3
|
+
|
|
4
|
+
let currentRuntimeIndex;
|
|
5
|
+
let currentRuntimeAlias = "";
|
|
6
|
+
|
|
7
|
+
const compareCache = new Map();
|
|
8
|
+
|
|
9
|
+
/**
|
|
10
|
+
* Central registry where all runtimes register themselves by pushing an object.
|
|
11
|
+
* The index in the registry servers as an ID for the runtime.
|
|
12
|
+
* @type {*}
|
|
13
|
+
*/
|
|
14
|
+
const Runtimes = getSharedResource("Runtimes", []);
|
|
15
|
+
|
|
16
|
+
/**
|
|
17
|
+
* Registers the current runtime in the shared runtimes resource registry
|
|
18
|
+
*/
|
|
19
|
+
const registerCurrentRuntime = () => {
|
|
20
|
+
if (currentRuntimeIndex === undefined) {
|
|
21
|
+
currentRuntimeIndex = Runtimes.length;
|
|
22
|
+
Runtimes.push({
|
|
23
|
+
...VersionInfo,
|
|
24
|
+
alias: currentRuntimeAlias,
|
|
25
|
+
description: `Runtime ${currentRuntimeIndex} - ver ${VersionInfo.version}${currentRuntimeAlias ? ` (${currentRuntimeAlias})` : ""}`,
|
|
26
|
+
});
|
|
27
|
+
}
|
|
28
|
+
};
|
|
29
|
+
|
|
30
|
+
/**
|
|
31
|
+
* Returns the index of the current runtime's object in the shared runtimes resource registry
|
|
32
|
+
* @returns {*}
|
|
33
|
+
*/
|
|
34
|
+
const getCurrentRuntimeIndex = () => {
|
|
35
|
+
return currentRuntimeIndex;
|
|
36
|
+
};
|
|
37
|
+
|
|
38
|
+
/**
|
|
39
|
+
* 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
|
|
40
|
+
* @param index1 The index of the first runtime to compare
|
|
41
|
+
* @param index2 The index of the second runtime to compare
|
|
42
|
+
* @returns {number}
|
|
43
|
+
*/
|
|
44
|
+
const compareRuntimes = (index1, index2) => {
|
|
45
|
+
const cacheIndex = `${index1},${index2}`;
|
|
46
|
+
if (compareCache.has(cacheIndex)) {
|
|
47
|
+
return compareCache.get(cacheIndex);
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
const runtime1 = Runtimes[index1];
|
|
51
|
+
const runtime2 = Runtimes[index2];
|
|
52
|
+
|
|
53
|
+
if (!runtime1 || !runtime2) {
|
|
54
|
+
throw new Error("Invalid runtime index supplied");
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
// If any of the two is a next version, bigger buildTime wins
|
|
58
|
+
if (runtime1.isNext || runtime2.isNext) {
|
|
59
|
+
return runtime1.buildTime - runtime2.buildTime;
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
// If major versions differ, bigger one wins
|
|
63
|
+
const majorDiff = runtime1.major - runtime2.major;
|
|
64
|
+
if (majorDiff) {
|
|
65
|
+
return majorDiff;
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
// If minor versions differ, bigger one wins
|
|
69
|
+
const minorDiff = runtime1.minor - runtime2.minor;
|
|
70
|
+
if (minorDiff) {
|
|
71
|
+
return minorDiff;
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
// If patch versions differ, bigger one wins
|
|
75
|
+
const patchDiff = runtime1.patch - runtime2.patch;
|
|
76
|
+
if (patchDiff) {
|
|
77
|
+
return patchDiff;
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
// Bigger suffix wins, f.e. rc10 > rc9
|
|
81
|
+
// Important: suffix is alphanumeric, must use natural compare
|
|
82
|
+
const collator = new Intl.Collator(undefined, { numeric: true, sensitivity: "base" });
|
|
83
|
+
const result = collator.compare(runtime1.suffix, runtime2.suffix);
|
|
84
|
+
|
|
85
|
+
compareCache.set(cacheIndex, result);
|
|
86
|
+
return result;
|
|
87
|
+
};
|
|
88
|
+
|
|
89
|
+
/**
|
|
90
|
+
* Set an alias for the the current app/library/microfrontend which will appear in debug messages and console warnings
|
|
91
|
+
* @param alias
|
|
92
|
+
*/
|
|
93
|
+
const setRuntimeAlias = alias => {
|
|
94
|
+
currentRuntimeAlias = alias;
|
|
95
|
+
};
|
|
96
|
+
|
|
97
|
+
const getAllRuntimes = () => {
|
|
98
|
+
return Runtimes;
|
|
99
|
+
};
|
|
100
|
+
|
|
101
|
+
export {
|
|
102
|
+
getCurrentRuntimeIndex,
|
|
103
|
+
registerCurrentRuntime,
|
|
104
|
+
compareRuntimes,
|
|
105
|
+
setRuntimeAlias,
|
|
106
|
+
getAllRuntimes,
|
|
107
|
+
};
|
package/src/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
|
/**
|