Skip to content

Commit

Permalink
fix(framework): relative paths for external themes (#6799)
Browse files Browse the repository at this point in the history
  • Loading branch information
nnaydenow authored Mar 30, 2023
1 parent 1174b48 commit df1ddfc
Show file tree
Hide file tree
Showing 5 changed files with 59 additions and 18 deletions.
10 changes: 10 additions & 0 deletions docs/3-customizing/01-theme.md
Original file line number Diff line number Diff line change
Expand Up @@ -86,4 +86,14 @@ setTheme("sap_fiori_3_dark");

For more on configuring themes, see [Configuration](../2-advanced/01-configuration.md).

## Load external theme
To load an external theme, you have to specify where the theme resources are located in the theme URL parameter. For example:
```
index.html?sap-ui-theme=mytheme@https://my-example-host.com/
```

In this example, "mytheme" theme will be applied and its resources (CSS variables specific to the theme) will be loaded from https://my-example-host.com/UI5/Base/baseLib/mytheme/css_variables.css.

**Note:** When an external theme is loaded some security restrictions will apply. Absolute URLs to a different origin than the current page will return the current page as an origin. To allow certain origins, you have to use `<meta name="sap-allowedThemeOrigins" content="https://my-example-host.com/">` tag inside the head of the page.

Next: [Custom Fonts](./02-fonts.md)
2 changes: 2 additions & 0 deletions packages/base/bundle.esm.js
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@ import { getAnimationMode } from "./dist/config/AnimationMode.js";
import { getLanguage, setLanguage } from "./dist/config/Language.js";
import { getCalendarType } from "./dist/config/CalendarType.js";
import { getTheme, setTheme } from "./dist/config/Theme.js";
import { getThemeRoot } from "./dist/config/ThemeRoots";
import { getNoConflict, setNoConflict } from "./dist/config/NoConflict.js";
import { getRTL } from "./dist/config/RTL.js";
import { getFirstDayOfWeek, getLegacyDateCalendarCustomizing } from "./dist/config/FormatSettings.js";
Expand All @@ -44,6 +45,7 @@ window["sap-ui-webcomponents-bundle"] = {
getLanguage,
setLanguage,
getTheme,
getThemeRoot,
setTheme,
getNoConflict,
setNoConflict,
Expand Down
30 changes: 14 additions & 16 deletions packages/base/src/validateThemeRoot.ts
Original file line number Diff line number Diff line change
Expand Up @@ -20,29 +20,27 @@ const buildCorrectUrl = (oldUrl: string, newOrigin: string) => {
};

const validateThemeRoot = (themeRoot: string) => {
let themeRootURL,
resultUrl;
let resultUrl;

try {
themeRootURL = new URL(themeRoot);

const origin = themeRootURL.origin;

themeRootURL = themeRootURL.toString();

if (themeRootURL.startsWith(".") || themeRootURL.startsWith("/")) {
if (themeRoot.startsWith(".") || themeRoot.startsWith("/")) {
// Handle relative url
// new URL("/newExmPath", "http://example.com/exmPath") => http://example.com/newExmPath
// new URL("./newExmPath", "http://example.com/exmPath") => http://example.com/exmPath/newExmPath
// new URL("../newExmPath", "http://example.com/exmPath") => http://example.com/newExmPath
resultUrl = new URL(themeRootURL, window.location.href).toString();
} else if (origin && validateThemeOrigin(origin)) {
// If origin is allowed, use it
resultUrl = themeRootURL.toString();
resultUrl = new URL(themeRoot, window.location.href).toString();
} else {
// If origin is not allow and the URL is not relative, we have to replace the origin
// with current location
resultUrl = buildCorrectUrl(themeRootURL, window.location.href);
const themeRootURL = new URL(themeRoot);
const origin = themeRootURL.origin;

if (origin && validateThemeOrigin(origin)) {
// If origin is allowed, use it
resultUrl = themeRootURL.toString();
} else {
// If origin is not allow and the URL is not relative, we have to replace the origin
// with current location
resultUrl = buildCorrectUrl(themeRootURL.toString(), window.location.href);
}
}

if (!resultUrl.endsWith("/")) {
Expand Down
1 change: 1 addition & 0 deletions packages/base/test/pages/Configuration.html
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
<html>
<head>
<meta charset="utf-8">
<meta name="sap-allowedThemeOrigins" content="https://example.com">

<title>Base package default test page</title>

Expand Down
34 changes: 32 additions & 2 deletions packages/base/test/specs/ConfigurationURL.spec.js
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
const assert = require("chai").assert;

describe("Some settings can be set via SAP UI URL params", () => {
before(async () => {
await browser.url("test/pages/Configuration.html?sap-ui-rtl=true&sap-ui-language=ja&sap-ui-calendarType=Japanese&sap-ui-theme=sap_belize_hcb&sap-ui-animationMode=basic");
beforeEach(async () => {
await browser.url("test/pages/Configuration.html?sap-ui-rtl=true&sap-ui-language=ja&sap-ui-calendarType=Japanese&sap-ui-theme=sap_belize_hcb@https://example.com&sap-ui-animationMode=basic");
});

it("Tests that RTL is applied", async () => {
Expand Down Expand Up @@ -37,6 +37,36 @@ describe("Some settings can be set via SAP UI URL params", () => {
assert.strictEqual(res, 'sap_belize_hcb', "Thems is HCB");
});

it("Tests that theme root is applied", async () => {
let location;
let res = await browser.executeAsync(done => {
const config = window['sap-ui-webcomponents-bundle'].configuration;
done(config.getThemeRoot());
});
assert.strictEqual(res, 'https://example.com/UI5/', "Theme root is https://example.com/UI5");

await browser.url("test/pages/Configuration.html?sap-ui-theme=sap_belize_hcb@https://another-example.com");

res = await browser.executeAsync(done => {
const config = window['sap-ui-webcomponents-bundle'].configuration;
done(config.getThemeRoot());
});
location = await browser.executeAsync(done => {
done(window.location);
});

assert.strictEqual(res, `${location.origin}/UI5/`, `Theme root is ${location.origin}/UI5/`);

await browser.url("test/pages/Configuration.html?sap-ui-theme=sap_belize_hcb@./test");

res = await browser.executeAsync(done => {
const config = window['sap-ui-webcomponents-bundle'].configuration;
done(config.getThemeRoot());
});

assert.ok(res.endsWith("/test/UI5/"), `Theme root is set correctly with relative url`);
});

it("Tests that animationMode is applied", async () => {
const res = await browser.executeAsync(done => {
const config = window['sap-ui-webcomponents-bundle'].configuration;
Expand Down

0 comments on commit df1ddfc

Please sign in to comment.